Version 2.6.0-dev.0.0
Merge commit 'f1f709ec1121113e52ec7f7e9cd2bf5a33fe5c37' into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c048c13..c6555d2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -22,7 +22,7 @@
```dart
// Example: these are now valid constants.
-const i = 3;
+const Object i = 3;
const list = [i as int];
const set = {if (list is List<int>) ...list};
const map = {if (i is int) i : "int"};
@@ -161,11 +161,14 @@
#### Linter
-The Linter was updated to `0.1.96`, which includes:
+The Linter was updated to `0.1.97+1`, which includes:
-* fixed false positives in `unnecessary_parens`
-* various changes to migrate to preferred analyzer APIs
-* rule test fixes
+* internal migration away from using analyzer `resolutionMap`
+* various fixes and improvements to anticipate support for extension-methods
+* new lint: `camel_case_extensions`
+* rule template generation improvements
+* new lint: `avoid_equals_and_hash_code_on_mutable_classes`
+* extended `avoid_slow_async_io` to flag async `Directory` methods
#### Dartdoc
@@ -188,6 +191,15 @@
[37551]: https://github.com/dart-lang/sdk/issues/37551
[35121]: https://github.com/dart-lang/sdk/issues/35121
+### Dart Dev Compiler (DDC)
+
+Callbacks passed to JS and wrapped with `allowInterop` or
+`allowInteropCaptureThis` are now strict about argument counts and argument
+types. This may mean that tests which were previously passing and relying on
+loose argument checking (too many or too few arguments, or arguments with too
+specific types like `List<Something>` instead of `List<dynamic>`) may start
+failing. This changes makes DDC behave more like dart2js with the default flags.
+
## 2.4.0 - 2019-06-27
### Core libraries
diff --git a/DEPS b/DEPS
index 94d2e6e..6033eca 100644
--- a/DEPS
+++ b/DEPS
@@ -54,7 +54,7 @@
"gperftools_revision": "e9ab4c53041ac62feefbbb076d326e9a77dd1567",
# Revisions of /third_party/* dependencies.
- "args_tag": "1.4.4",
+ "args_tag": "1.5.0",
"async_tag": "2.0.8",
"bazel_worker_tag": "bazel_worker-v0.1.20",
"benchmark_harness_tag": "81641290dea44c34138a109a37e215482f405f81",
@@ -84,7 +84,7 @@
# For more details, see https://github.com/dart-lang/sdk/issues/30164
"dart_style_tag": "1.2.8", # Please see the note above before updating.
- "dartdoc_tag" : "0.28.4",
+ "dartdoc_rev" : "6934accd88c29a73cae26d0c4def3323efc2119c",
"fixnum_tag": "0.10.9",
"glob_tag": "1.1.7",
"html_tag" : "0.14.0+1",
@@ -99,7 +99,7 @@
"intl_tag": "0.15.7",
"jinja2_rev": "2222b31554f03e62600cd7e383376a7c187967a1",
"json_rpc_2_tag": "2.0.9",
- "linter_tag": "0.1.96",
+ "linter_tag": "0.1.97+1",
"logging_tag": "0.11.3+2",
"markupsafe_rev": "8f45f5cfa0009d2a70589bcda0349b8cb2b72783",
"markdown_tag": "2.0.3",
@@ -138,7 +138,7 @@
"term_glyph_tag": "1.0.1",
"test_reflective_loader_tag": "0.1.8",
"test_tag": "test-v1.6.4",
- "tflite_native_rev": "65889224d8ee32ceaf4f78d8d29fd59750e1b817",
+ "tflite_native_rev": "06e533a9747306d1114c53427cc67eda080f51f9",
"typed_data_tag": "1.1.6",
"unittest_rev": "2b8375bc98bb9dc81c539c91aaea6adce12e1072",
"usage_tag": "3.4.0",
@@ -276,7 +276,7 @@
Var("dart_root") + "/third_party/pkg/dart2js_info":
Var("dart_git") + "dart2js_info.git" + "@" + Var("dart2js_info_tag"),
Var("dart_root") + "/third_party/pkg/dartdoc":
- Var("dart_git") + "dartdoc.git" + "@" + Var("dartdoc_tag"),
+ Var("dart_git") + "dartdoc.git" + "@" + Var("dartdoc_rev"),
Var("dart_root") + "/third_party/pkg/fixnum":
Var("dart_git") + "fixnum.git" + "@" + Var("fixnum_tag"),
Var("dart_root") + "/third_party/pkg/glob":
@@ -448,6 +448,16 @@
"dep_type": "cipd",
},
+ Var("dart_root") + "/pkg/front_end/test/fasta/types/benchmark_data": {
+ "packages": [
+ {
+ "package": "dart/cfe/benchmark_data",
+ "version": "sha1sum:4168b133ab7bce01c91311a8d4f25d4d6cb026f3",
+ }
+ ],
+ "dep_type": "cipd",
+ },
+
# TODO(37531): Remove these cipd packages and build with sdk instead when
# benchmark runner gets support for that.
Var("dart_root") + "/benchmarks/FfiBoringssl/dart/native/out/": {
@@ -517,21 +527,6 @@
],
},
{
- "name": "front_end_benchmark_data",
- "pattern": ".",
- "action": [
- "download_from_google_storage",
- "--no_auth",
- "--no_resume",
- "--bucket",
- "dart-dependencies",
- "--recursive",
- "--extract",
- "--directory",
- Var('dart_root') + "/pkg/front_end/test/fasta/types",
- ],
- },
- {
# Pull Debian wheezy sysroot for i386 Linux
'name': 'sysroot_i386',
'pattern': '.',
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 26354c4..7beb3f8 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -13,7 +13,10 @@
import scm
import subprocess
import tempfile
+import platform
+def is_cpp_file(path):
+ return path.endswith('.cc') or path.endswith('.h')
def _CheckFormat(input_api,
identification,
@@ -199,9 +202,6 @@
"""
# Run only if .cc or .h file was modified.
- def is_cpp_file(path):
- return path.endswith('.cc') or path.endswith('.h')
-
if all(not is_cpp_file(f.LocalPath()) for f in input_api.AffectedFiles()):
return []
@@ -219,15 +219,47 @@
else:
return []
+def _CheckClangTidy(input_api, output_api):
+ """Run clang-tidy on VM changes."""
+
+ # Only run clang-tidy on linux x64.
+ if platform.system() != 'Linux' or platform.machine() != 'x86_64':
+ return []
+
+ # Run only for modified .cc or .h files.
+ files = []
+ for f in input_api.AffectedFiles():
+ path = f.LocalPath()
+ if is_cpp_file(path): files.append(path)
+
+ if not files:
+ return []
+
+ args = [
+ 'tools/sdks/dart-sdk/bin/dart',
+ 'runtime/tools/run_clang_tidy.dart',
+ ]
+ args.extend(files)
+ stdout = input_api.subprocess.check_output(args).strip()
+ if not stdout:
+ return []
+
+ return [
+ output_api.PresubmitError(
+ 'The `clang-tidy` linter revealed issues:',
+ long_text=stdout)
+ ]
def CheckChangeOnCommit(input_api, output_api):
return (_CheckValidHostsInDEPS(input_api, output_api) + _CheckBuildStatus(
input_api, output_api) + _CheckDartFormat(input_api, output_api) +
_CheckStatusFiles(input_api, output_api) + _CheckLayering(
+ input_api, output_api) + _CheckClangTidy(
input_api, output_api))
def CheckChangeOnUpload(input_api, output_api):
return (_CheckValidHostsInDEPS(input_api, output_api) + _CheckDartFormat(
input_api, output_api) + _CheckStatusFiles(input_api, output_api) +
- _CheckLayering(input_api, output_api))
+ _CheckLayering(input_api, output_api) + _CheckClangTidy(
+ input_api, output_api))
diff --git a/benchmarks/Isolate/dart/Isolate.dart b/benchmarks/Isolate/dart/Isolate.dart
new file mode 100644
index 0000000..465d56a
--- /dev/null
+++ b/benchmarks/Isolate/dart/Isolate.dart
@@ -0,0 +1,186 @@
+// Copyright (c) 2019, 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:isolate';
+import 'dart:typed_data';
+
+import 'package:benchmark_harness/benchmark_harness.dart'
+ show PrintEmitter, ScoreEmitter;
+import 'package:meta/meta.dart';
+
+class SendReceiveBytes extends AsyncBenchmarkBase {
+ SendReceiveBytes(String name,
+ {@required int this.size, @required bool this.useTransferable})
+ : super(name);
+
+ @override
+ Future<void> run() async {
+ await helper.run();
+ }
+
+ @override
+ Future<void> setup() async {
+ helper = SendReceiveHelper(size, useTransferable: useTransferable);
+ await helper.setup();
+ }
+
+ @override
+ Future<void> teardown() async {
+ await helper.finalize();
+ }
+
+ final bool useTransferable;
+ final int size;
+ SendReceiveHelper helper;
+}
+
+// Identical to BenchmarkBase from package:benchmark_harness but async.
+abstract class AsyncBenchmarkBase {
+ final String name;
+ final ScoreEmitter emitter;
+
+ Future<void> run();
+ Future<void> setup();
+ Future<void> teardown();
+
+ const AsyncBenchmarkBase(this.name, {this.emitter = const PrintEmitter()});
+
+ // Returns the number of microseconds per call.
+ Future<double> measureFor(int minimumMillis) async {
+ final minimumMicros = minimumMillis * 1000;
+ int iter = 0;
+ final watch = Stopwatch();
+ watch.start();
+ int elapsed = 0;
+ while (elapsed < minimumMicros) {
+ await run();
+ elapsed = watch.elapsedMicroseconds;
+ iter++;
+ }
+ return elapsed / iter;
+ }
+
+ // Measures the score for the benchmark and returns it.
+ Future<double> measure() async {
+ await setup();
+ await measureFor(500); // warm-up
+ final result = await measureFor(4000); // actual measurement
+ await teardown();
+ return result;
+ }
+
+ Future<void> report() async {
+ emitter.emit(name, await measure());
+ }
+}
+
+class StartMessage {
+ final SendPort sendPort;
+ final bool useTransferable;
+ final int size;
+
+ StartMessage(this.sendPort, this.useTransferable, this.size);
+}
+
+// Measures how long sending and receiving of [size]-length Uint8List takes.
+class SendReceiveHelper {
+ SendReceiveHelper(this.size, {@required bool this.useTransferable});
+
+ Future<void> setup() async {
+ data = new Uint8List(size);
+
+ port = ReceivePort();
+ inbox = StreamIterator<dynamic>(port);
+ workerCompleted = Completer<bool>();
+ workerExitedPort = ReceivePort()
+ ..listen((_) => workerCompleted.complete(true));
+ worker = await Isolate.spawn(
+ isolate, StartMessage(port.sendPort, useTransferable, size),
+ onExit: workerExitedPort.sendPort);
+ await inbox.moveNext();
+ outbox = inbox.current;
+ }
+
+ Future<void> finalize() async {
+ outbox.send(null);
+ await workerCompleted.future;
+ workerExitedPort.close();
+ port.close();
+ }
+
+ // Send data to worker, wait for an answer.
+ Future<void> run() async {
+ outbox.send(packageList(data, useTransferable));
+ await inbox.moveNext();
+ final received = inbox.current;
+ if (useTransferable) {
+ final TransferableTypedData transferable = received;
+ transferable.materialize();
+ }
+ }
+
+ Uint8List data;
+ ReceivePort port;
+ StreamIterator<dynamic> inbox;
+ SendPort outbox;
+ Isolate worker;
+ Completer<bool> workerCompleted;
+ ReceivePort workerExitedPort;
+ final int size;
+ final bool useTransferable;
+}
+
+packageList(Uint8List data, bool useTransferable) =>
+ useTransferable ? TransferableTypedData.fromList(<Uint8List>[data]) : data;
+
+Future<void> isolate(StartMessage startMessage) async {
+ final port = ReceivePort();
+ final inbox = StreamIterator<dynamic>(port);
+ final data = Uint8List.view(new Uint8List(startMessage.size).buffer);
+
+ startMessage.sendPort.send(port.sendPort);
+ while (true) {
+ await inbox.moveNext();
+ final received = inbox.current;
+ if (received == null) {
+ break;
+ }
+ if (startMessage.useTransferable) {
+ final TransferableTypedData transferable = received;
+ transferable.materialize();
+ }
+ startMessage.sendPort.send(packageList(data, startMessage.useTransferable));
+ }
+ port.close();
+}
+
+class SizeName {
+ const SizeName(this.size, this.name);
+
+ final int size;
+ final String name;
+}
+
+final List<SizeName> sizes = <SizeName>[
+ SizeName(1 * 1024, "1KB"),
+ SizeName(10 * 1024, "10KB"),
+ SizeName(100 * 1024, "100KB"),
+ SizeName(1 * 1024 * 1024, "1MB"),
+ SizeName(10 * 1024 * 1024, "10MB"),
+ SizeName(100 * 1024 * 1024, "100MB")
+];
+
+Future<void> main() async {
+ for (SizeName sizeName in sizes) {
+ await SendReceiveBytes("Isolate.SendReceiveBytes${sizeName.name}",
+ size: sizeName.size, useTransferable: false)
+ .report();
+ await SendReceiveBytes(
+ "Isolate.SendReceiveBytesTransferable${sizeName.name}",
+ size: sizeName.size,
+ useTransferable: true)
+ .report();
+ }
+}
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index f073da1..d205e966 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -247,8 +247,6 @@
# Linux-specific compiler flags setup.
# ------------------------------------
if (is_linux) {
- cflags += [ "-pthread" ]
- ldflags += [ "-pthread" ]
if (is_clang) {
if (current_cpu == "arm") {
cflags += [ "--target=armv7-linux-gnueabihf" ]
diff --git a/build/config/linux/BUILD.gn b/build/config/linux/BUILD.gn
index 62f7524..0db95b7 100644
--- a/build/config/linux/BUILD.gn
+++ b/build/config/linux/BUILD.gn
@@ -5,9 +5,26 @@
import("//build/config/sysroot.gni")
config("sdk") {
+ # Don't allow visible symbols from libc++ to be re-exported.
+ ldflags = [
+ "-nodefaultlibs",
+ "-lc++",
+ "-lc",
+ "-lm",
+ "-lclang_rt.builtins",
+ "-Wl,--exclude-libs=libc++.a",
+ ]
+
+ if (is_asan) {
+ ldflags += [
+ "-lpthread",
+ "-lrt",
+ ]
+ }
+
if (sysroot != "") {
cflags = [ "--sysroot=" + sysroot ]
- ldflags = [ "--sysroot=" + sysroot ]
+ ldflags += [ "--sysroot=" + sysroot ]
# Need to get some linker flags out of the sysroot.
ldflags += [ exec_script("sysroot_ld_path.py",
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index c65ccb2..5bf0c26 100644
--- a/pkg/analysis_server/doc/api.html
+++ b/pkg/analysis_server/doc/api.html
@@ -109,7 +109,7 @@
<body>
<h1>Analysis Server API Specification</h1>
<h1 style="color:#999999">Version
- 1.27.2
+ 1.27.3
</h1>
<p>
This document contains a specification of the API provided by the
@@ -373,6 +373,7 @@
+
<h3>Requests</h3><dl><dt class="request"><a name="request_server.getVersion">server.getVersion</a></dt><dd><div class="box"><pre>request: {
"id": String
"method": "server.getVersion"
@@ -3007,6 +3008,8 @@
+
+
<dl><dt class="typeDefinition"><a name="type_AddContentOverlay">AddContentOverlay: object</a></dt><dd>
<p>
A directive to begin overlaying the contents of a file. The supplied
@@ -5500,7 +5503,7 @@
An enumeration of the services provided by the server domain.
</p>
- <dl><dt class="value">STATUS</dt></dl></dd><dt class="typeDefinition"><a name="type_SourceChange">SourceChange: object</a></dt><dd>
+ <dl><dt class="value">LOG</dt><dt class="value">STATUS</dt></dl></dd><dt class="typeDefinition"><a name="type_SourceChange">SourceChange: object</a></dt><dd>
<p>
A description of a set of edits that implement a single conceptual change.
</p>
@@ -5996,7 +5999,7 @@
TODO: TBD
</p>
<h2 class="domain"><a name="index">Index</a></h2>
-<h3>Domains</h3><h4>server (<a href="#domain_server">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_server.getVersion">getVersion</a></li><li><a href="#request_server.shutdown">shutdown</a></li><li><a href="#request_server.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_server.connected">connected</a></li><li><a href="#notification_server.error">error</a></li><li><a href="#notification_server.status">status</a></li></ul></div></div><h4>analysis (<a href="#domain_analysis">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_analysis.getErrors">getErrors</a></li><li><a href="#request_analysis.getHover">getHover</a></li><li><a href="#request_analysis.getLibraryDependencies">getLibraryDependencies</a></li><li><a href="#request_analysis.getNavigation">getNavigation</a></li><li><a href="#request_analysis.getReachableSources">getReachableSources</a></li><li><a href="#request_analysis.reanalyze">reanalyze</a></li><li><a href="#request_analysis.setAnalysisRoots">setAnalysisRoots</a></li><li><a href="#request_analysis.setGeneralSubscriptions">setGeneralSubscriptions</a></li><li><a href="#request_analysis.setPriorityFiles">setPriorityFiles</a></li><li><a href="#request_analysis.setSubscriptions">setSubscriptions</a></li><li><a href="#request_analysis.updateContent">updateContent</a></li><li><a href="#request_analysis.updateOptions">updateOptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_analysis.analyzedFiles">analyzedFiles</a></li><li><a href="#notification_analysis.closingLabels">closingLabels</a></li><li><a href="#notification_analysis.errors">errors</a></li><li><a href="#notification_analysis.flushResults">flushResults</a></li><li><a href="#notification_analysis.folding">folding</a></li><li><a href="#notification_analysis.highlights">highlights</a></li><li><a href="#notification_analysis.implemented">implemented</a></li><li><a href="#notification_analysis.invalidate">invalidate</a></li><li><a href="#notification_analysis.navigation">navigation</a></li><li><a href="#notification_analysis.occurrences">occurrences</a></li><li><a href="#notification_analysis.outline">outline</a></li><li><a href="#notification_analysis.overrides">overrides</a></li></ul></div></div><h4>completion (<a href="#domain_completion">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_completion.getSuggestions">getSuggestions</a></li><li><a href="#request_completion.setSubscriptions">setSubscriptions</a></li><li><a href="#request_completion.registerLibraryPaths">registerLibraryPaths</a></li><li><a href="#request_completion.getSuggestionDetails">getSuggestionDetails</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_completion.results">results</a></li><li><a href="#notification_completion.availableSuggestions">availableSuggestions</a></li><li><a href="#notification_completion.existingImports">existingImports</a></li></ul></div></div><h4>search (<a href="#domain_search">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_search.findElementReferences">findElementReferences</a></li><li><a href="#request_search.findMemberDeclarations">findMemberDeclarations</a></li><li><a href="#request_search.findMemberReferences">findMemberReferences</a></li><li><a href="#request_search.findTopLevelDeclarations">findTopLevelDeclarations</a></li><li><a href="#request_search.getTypeHierarchy">getTypeHierarchy</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_search.results">results</a></li></ul></div></div><h4>edit (<a href="#domain_edit">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_edit.format">format</a></li><li><a href="#request_edit.getAssists">getAssists</a></li><li><a href="#request_edit.getAvailableRefactorings">getAvailableRefactorings</a></li><li><a href="#request_edit.getFixes">getFixes</a></li><li><a href="#request_edit.getPostfixCompletion">getPostfixCompletion</a></li><li><a href="#request_edit.getRefactoring">getRefactoring</a></li><li><a href="#request_edit.sortMembers">sortMembers</a></li><li><a href="#request_edit.organizeDirectives">organizeDirectives</a></li></ul></div><h4>execution (<a href="#domain_execution">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_execution.createContext">createContext</a></li><li><a href="#request_execution.deleteContext">deleteContext</a></li><li><a href="#request_execution.getSuggestions">getSuggestions</a></li><li><a href="#request_execution.mapUri">mapUri</a></li><li><a href="#request_execution.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_execution.launchData">launchData</a></li></ul></div></div><h4>diagnostic (<a href="#domain_diagnostic">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_diagnostic.getDiagnostics">getDiagnostics</a></li><li><a href="#request_diagnostic.getServerPort">getServerPort</a></li></ul></div><h4>flutter (<a href="#domain_flutter">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_flutter.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_flutter.outline">outline</a></li></ul></div></div><h3>Types (<a href="#types">↑</a>)</h3><div class="subindex"><ul><li><a href="#type_AddContentOverlay">AddContentOverlay</a></li><li><a href="#type_AnalysisError">AnalysisError</a></li><li><a href="#type_AnalysisErrorFixes">AnalysisErrorFixes</a></li><li><a href="#type_AnalysisErrorSeverity">AnalysisErrorSeverity</a></li><li><a href="#type_AnalysisErrorType">AnalysisErrorType</a></li><li><a href="#type_AnalysisOptions">AnalysisOptions</a></li><li><a href="#type_AnalysisService">AnalysisService</a></li><li><a href="#type_AnalysisStatus">AnalysisStatus</a></li><li><a href="#type_AvailableSuggestion">AvailableSuggestion</a></li><li><a href="#type_AvailableSuggestionRelevanceTag">AvailableSuggestionRelevanceTag</a></li><li><a href="#type_AvailableSuggestionSet">AvailableSuggestionSet</a></li><li><a href="#type_ChangeContentOverlay">ChangeContentOverlay</a></li><li><a href="#type_ClosingLabel">ClosingLabel</a></li><li><a href="#type_CompletionId">CompletionId</a></li><li><a href="#type_CompletionService">CompletionService</a></li><li><a href="#type_CompletionSuggestion">CompletionSuggestion</a></li><li><a href="#type_CompletionSuggestionKind">CompletionSuggestionKind</a></li><li><a href="#type_ContextData">ContextData</a></li><li><a href="#type_DiagnosticMessage">DiagnosticMessage</a></li><li><a href="#type_Element">Element</a></li><li><a href="#type_ElementDeclaration">ElementDeclaration</a></li><li><a href="#type_ElementKind">ElementKind</a></li><li><a href="#type_ExecutableFile">ExecutableFile</a></li><li><a href="#type_ExecutableKind">ExecutableKind</a></li><li><a href="#type_ExecutionContextId">ExecutionContextId</a></li><li><a href="#type_ExecutionService">ExecutionService</a></li><li><a href="#type_ExistingImport">ExistingImport</a></li><li><a href="#type_ExistingImports">ExistingImports</a></li><li><a href="#type_FileKind">FileKind</a></li><li><a href="#type_FilePath">FilePath</a></li><li><a href="#type_FlutterOutline">FlutterOutline</a></li><li><a href="#type_FlutterOutlineAttribute">FlutterOutlineAttribute</a></li><li><a href="#type_FlutterOutlineKind">FlutterOutlineKind</a></li><li><a href="#type_FlutterService">FlutterService</a></li><li><a href="#type_FlutterWidgetProperty">FlutterWidgetProperty</a></li><li><a href="#type_FlutterWidgetPropertyEditor">FlutterWidgetPropertyEditor</a></li><li><a href="#type_FlutterWidgetPropertyEditorKind">FlutterWidgetPropertyEditorKind</a></li><li><a href="#type_FlutterWidgetPropertyValue">FlutterWidgetPropertyValue</a></li><li><a href="#type_FlutterWidgetPropertyValueEnumItem">FlutterWidgetPropertyValueEnumItem</a></li><li><a href="#type_FoldingKind">FoldingKind</a></li><li><a href="#type_FoldingRegion">FoldingRegion</a></li><li><a href="#type_GeneralAnalysisService">GeneralAnalysisService</a></li><li><a href="#type_HighlightRegion">HighlightRegion</a></li><li><a href="#type_HighlightRegionType">HighlightRegionType</a></li><li><a href="#type_HoverInformation">HoverInformation</a></li><li><a href="#type_ImplementedClass">ImplementedClass</a></li><li><a href="#type_ImplementedMember">ImplementedMember</a></li><li><a href="#type_ImportedElementSet">ImportedElementSet</a></li><li><a href="#type_ImportedElements">ImportedElements</a></li><li><a href="#type_IncludedSuggestionRelevanceTag">IncludedSuggestionRelevanceTag</a></li><li><a href="#type_IncludedSuggestionSet">IncludedSuggestionSet</a></li><li><a href="#type_KytheEntry">KytheEntry</a></li><li><a href="#type_KytheVName">KytheVName</a></li><li><a href="#type_LibraryPathSet">LibraryPathSet</a></li><li><a href="#type_LinkedEditGroup">LinkedEditGroup</a></li><li><a href="#type_LinkedEditSuggestion">LinkedEditSuggestion</a></li><li><a href="#type_LinkedEditSuggestionKind">LinkedEditSuggestionKind</a></li><li><a href="#type_Location">Location</a></li><li><a href="#type_NavigationRegion">NavigationRegion</a></li><li><a href="#type_NavigationTarget">NavigationTarget</a></li><li><a href="#type_Occurrences">Occurrences</a></li><li><a href="#type_Outline">Outline</a></li><li><a href="#type_OverriddenMember">OverriddenMember</a></li><li><a href="#type_Override">Override</a></li><li><a href="#type_Position">Position</a></li><li><a href="#type_PostfixTemplateDescriptor">PostfixTemplateDescriptor</a></li><li><a href="#type_PubStatus">PubStatus</a></li><li><a href="#type_RefactoringFeedback">RefactoringFeedback</a></li><li><a href="#type_RefactoringKind">RefactoringKind</a></li><li><a href="#type_RefactoringMethodParameter">RefactoringMethodParameter</a></li><li><a href="#type_RefactoringMethodParameterKind">RefactoringMethodParameterKind</a></li><li><a href="#type_RefactoringOptions">RefactoringOptions</a></li><li><a href="#type_RefactoringProblem">RefactoringProblem</a></li><li><a href="#type_RefactoringProblemSeverity">RefactoringProblemSeverity</a></li><li><a href="#type_RemoveContentOverlay">RemoveContentOverlay</a></li><li><a href="#type_RequestError">RequestError</a></li><li><a href="#type_RequestErrorCode">RequestErrorCode</a></li><li><a href="#type_RuntimeCompletionExpression">RuntimeCompletionExpression</a></li><li><a href="#type_RuntimeCompletionExpressionType">RuntimeCompletionExpressionType</a></li><li><a href="#type_RuntimeCompletionExpressionTypeKind">RuntimeCompletionExpressionTypeKind</a></li><li><a href="#type_RuntimeCompletionVariable">RuntimeCompletionVariable</a></li><li><a href="#type_SearchId">SearchId</a></li><li><a href="#type_SearchResult">SearchResult</a></li><li><a href="#type_SearchResultKind">SearchResultKind</a></li><li><a href="#type_ServerService">ServerService</a></li><li><a href="#type_SourceChange">SourceChange</a></li><li><a href="#type_SourceEdit">SourceEdit</a></li><li><a href="#type_SourceFileEdit">SourceFileEdit</a></li><li><a href="#type_TypeHierarchyItem">TypeHierarchyItem</a></li></ul></div><h3>Refactorings (<a href="#refactorings">↑</a>)</h3><div class="subindex"><ul><li><a href="#refactoring_CONVERT_GETTER_TO_METHOD">CONVERT_GETTER_TO_METHOD</a></li><li><a href="#refactoring_CONVERT_METHOD_TO_GETTER">CONVERT_METHOD_TO_GETTER</a></li><li><a href="#refactoring_EXTRACT_LOCAL_VARIABLE">EXTRACT_LOCAL_VARIABLE</a></li><li><a href="#refactoring_EXTRACT_METHOD">EXTRACT_METHOD</a></li><li><a href="#refactoring_EXTRACT_WIDGET">EXTRACT_WIDGET</a></li><li><a href="#refactoring_INLINE_LOCAL_VARIABLE">INLINE_LOCAL_VARIABLE</a></li><li><a href="#refactoring_INLINE_METHOD">INLINE_METHOD</a></li><li><a href="#refactoring_MOVE_FILE">MOVE_FILE</a></li><li><a href="#refactoring_RENAME">RENAME</a></li></ul></div>
+<h3>Domains</h3><h4>server (<a href="#domain_server">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_server.getVersion">getVersion</a></li><li><a href="#request_server.shutdown">shutdown</a></li><li><a href="#request_server.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_server.connected">connected</a></li><li><a href="#notification_server.error">error</a></li><li><a href="#notification_server.log">log</a></li><li><a href="#notification_server.status">status</a></li></ul></div></div><h4>analysis (<a href="#domain_analysis">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_analysis.getErrors">getErrors</a></li><li><a href="#request_analysis.getHover">getHover</a></li><li><a href="#request_analysis.getLibraryDependencies">getLibraryDependencies</a></li><li><a href="#request_analysis.getNavigation">getNavigation</a></li><li><a href="#request_analysis.getReachableSources">getReachableSources</a></li><li><a href="#request_analysis.reanalyze">reanalyze</a></li><li><a href="#request_analysis.setAnalysisRoots">setAnalysisRoots</a></li><li><a href="#request_analysis.setGeneralSubscriptions">setGeneralSubscriptions</a></li><li><a href="#request_analysis.setPriorityFiles">setPriorityFiles</a></li><li><a href="#request_analysis.setSubscriptions">setSubscriptions</a></li><li><a href="#request_analysis.updateContent">updateContent</a></li><li><a href="#request_analysis.updateOptions">updateOptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_analysis.analyzedFiles">analyzedFiles</a></li><li><a href="#notification_analysis.closingLabels">closingLabels</a></li><li><a href="#notification_analysis.errors">errors</a></li><li><a href="#notification_analysis.flushResults">flushResults</a></li><li><a href="#notification_analysis.folding">folding</a></li><li><a href="#notification_analysis.highlights">highlights</a></li><li><a href="#notification_analysis.implemented">implemented</a></li><li><a href="#notification_analysis.invalidate">invalidate</a></li><li><a href="#notification_analysis.navigation">navigation</a></li><li><a href="#notification_analysis.occurrences">occurrences</a></li><li><a href="#notification_analysis.outline">outline</a></li><li><a href="#notification_analysis.overrides">overrides</a></li></ul></div></div><h4>completion (<a href="#domain_completion">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_completion.getSuggestions">getSuggestions</a></li><li><a href="#request_completion.setSubscriptions">setSubscriptions</a></li><li><a href="#request_completion.registerLibraryPaths">registerLibraryPaths</a></li><li><a href="#request_completion.getSuggestionDetails">getSuggestionDetails</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_completion.results">results</a></li><li><a href="#notification_completion.availableSuggestions">availableSuggestions</a></li><li><a href="#notification_completion.existingImports">existingImports</a></li></ul></div></div><h4>search (<a href="#domain_search">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_search.findElementReferences">findElementReferences</a></li><li><a href="#request_search.findMemberDeclarations">findMemberDeclarations</a></li><li><a href="#request_search.findMemberReferences">findMemberReferences</a></li><li><a href="#request_search.findTopLevelDeclarations">findTopLevelDeclarations</a></li><li><a href="#request_search.getTypeHierarchy">getTypeHierarchy</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_search.results">results</a></li></ul></div></div><h4>edit (<a href="#domain_edit">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_edit.format">format</a></li><li><a href="#request_edit.getAssists">getAssists</a></li><li><a href="#request_edit.getAvailableRefactorings">getAvailableRefactorings</a></li><li><a href="#request_edit.getFixes">getFixes</a></li><li><a href="#request_edit.getPostfixCompletion">getPostfixCompletion</a></li><li><a href="#request_edit.getRefactoring">getRefactoring</a></li><li><a href="#request_edit.sortMembers">sortMembers</a></li><li><a href="#request_edit.organizeDirectives">organizeDirectives</a></li></ul></div><h4>execution (<a href="#domain_execution">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_execution.createContext">createContext</a></li><li><a href="#request_execution.deleteContext">deleteContext</a></li><li><a href="#request_execution.getSuggestions">getSuggestions</a></li><li><a href="#request_execution.mapUri">mapUri</a></li><li><a href="#request_execution.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_execution.launchData">launchData</a></li></ul></div></div><h4>diagnostic (<a href="#domain_diagnostic">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_diagnostic.getDiagnostics">getDiagnostics</a></li><li><a href="#request_diagnostic.getServerPort">getServerPort</a></li></ul></div><h4>flutter (<a href="#domain_flutter">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_flutter.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_flutter.outline">outline</a></li></ul></div></div><h3>Types (<a href="#types">↑</a>)</h3><div class="subindex"><ul><li><a href="#type_AddContentOverlay">AddContentOverlay</a></li><li><a href="#type_AnalysisError">AnalysisError</a></li><li><a href="#type_AnalysisErrorFixes">AnalysisErrorFixes</a></li><li><a href="#type_AnalysisErrorSeverity">AnalysisErrorSeverity</a></li><li><a href="#type_AnalysisErrorType">AnalysisErrorType</a></li><li><a href="#type_AnalysisOptions">AnalysisOptions</a></li><li><a href="#type_AnalysisService">AnalysisService</a></li><li><a href="#type_AnalysisStatus">AnalysisStatus</a></li><li><a href="#type_AvailableSuggestion">AvailableSuggestion</a></li><li><a href="#type_AvailableSuggestionRelevanceTag">AvailableSuggestionRelevanceTag</a></li><li><a href="#type_AvailableSuggestionSet">AvailableSuggestionSet</a></li><li><a href="#type_ChangeContentOverlay">ChangeContentOverlay</a></li><li><a href="#type_ClosingLabel">ClosingLabel</a></li><li><a href="#type_CompletionId">CompletionId</a></li><li><a href="#type_CompletionService">CompletionService</a></li><li><a href="#type_CompletionSuggestion">CompletionSuggestion</a></li><li><a href="#type_CompletionSuggestionKind">CompletionSuggestionKind</a></li><li><a href="#type_ContextData">ContextData</a></li><li><a href="#type_DiagnosticMessage">DiagnosticMessage</a></li><li><a href="#type_Element">Element</a></li><li><a href="#type_ElementDeclaration">ElementDeclaration</a></li><li><a href="#type_ElementKind">ElementKind</a></li><li><a href="#type_ExecutableFile">ExecutableFile</a></li><li><a href="#type_ExecutableKind">ExecutableKind</a></li><li><a href="#type_ExecutionContextId">ExecutionContextId</a></li><li><a href="#type_ExecutionService">ExecutionService</a></li><li><a href="#type_ExistingImport">ExistingImport</a></li><li><a href="#type_ExistingImports">ExistingImports</a></li><li><a href="#type_FileKind">FileKind</a></li><li><a href="#type_FilePath">FilePath</a></li><li><a href="#type_FlutterOutline">FlutterOutline</a></li><li><a href="#type_FlutterOutlineAttribute">FlutterOutlineAttribute</a></li><li><a href="#type_FlutterOutlineKind">FlutterOutlineKind</a></li><li><a href="#type_FlutterService">FlutterService</a></li><li><a href="#type_FlutterWidgetProperty">FlutterWidgetProperty</a></li><li><a href="#type_FlutterWidgetPropertyEditor">FlutterWidgetPropertyEditor</a></li><li><a href="#type_FlutterWidgetPropertyEditorKind">FlutterWidgetPropertyEditorKind</a></li><li><a href="#type_FlutterWidgetPropertyValue">FlutterWidgetPropertyValue</a></li><li><a href="#type_FlutterWidgetPropertyValueEnumItem">FlutterWidgetPropertyValueEnumItem</a></li><li><a href="#type_FoldingKind">FoldingKind</a></li><li><a href="#type_FoldingRegion">FoldingRegion</a></li><li><a href="#type_GeneralAnalysisService">GeneralAnalysisService</a></li><li><a href="#type_HighlightRegion">HighlightRegion</a></li><li><a href="#type_HighlightRegionType">HighlightRegionType</a></li><li><a href="#type_HoverInformation">HoverInformation</a></li><li><a href="#type_ImplementedClass">ImplementedClass</a></li><li><a href="#type_ImplementedMember">ImplementedMember</a></li><li><a href="#type_ImportedElementSet">ImportedElementSet</a></li><li><a href="#type_ImportedElements">ImportedElements</a></li><li><a href="#type_IncludedSuggestionRelevanceTag">IncludedSuggestionRelevanceTag</a></li><li><a href="#type_IncludedSuggestionSet">IncludedSuggestionSet</a></li><li><a href="#type_KytheEntry">KytheEntry</a></li><li><a href="#type_KytheVName">KytheVName</a></li><li><a href="#type_LibraryPathSet">LibraryPathSet</a></li><li><a href="#type_LinkedEditGroup">LinkedEditGroup</a></li><li><a href="#type_LinkedEditSuggestion">LinkedEditSuggestion</a></li><li><a href="#type_LinkedEditSuggestionKind">LinkedEditSuggestionKind</a></li><li><a href="#type_Location">Location</a></li><li><a href="#type_NavigationRegion">NavigationRegion</a></li><li><a href="#type_NavigationTarget">NavigationTarget</a></li><li><a href="#type_Occurrences">Occurrences</a></li><li><a href="#type_Outline">Outline</a></li><li><a href="#type_OverriddenMember">OverriddenMember</a></li><li><a href="#type_Override">Override</a></li><li><a href="#type_Position">Position</a></li><li><a href="#type_PostfixTemplateDescriptor">PostfixTemplateDescriptor</a></li><li><a href="#type_PubStatus">PubStatus</a></li><li><a href="#type_RefactoringFeedback">RefactoringFeedback</a></li><li><a href="#type_RefactoringKind">RefactoringKind</a></li><li><a href="#type_RefactoringMethodParameter">RefactoringMethodParameter</a></li><li><a href="#type_RefactoringMethodParameterKind">RefactoringMethodParameterKind</a></li><li><a href="#type_RefactoringOptions">RefactoringOptions</a></li><li><a href="#type_RefactoringProblem">RefactoringProblem</a></li><li><a href="#type_RefactoringProblemSeverity">RefactoringProblemSeverity</a></li><li><a href="#type_RemoveContentOverlay">RemoveContentOverlay</a></li><li><a href="#type_RequestError">RequestError</a></li><li><a href="#type_RequestErrorCode">RequestErrorCode</a></li><li><a href="#type_RuntimeCompletionExpression">RuntimeCompletionExpression</a></li><li><a href="#type_RuntimeCompletionExpressionType">RuntimeCompletionExpressionType</a></li><li><a href="#type_RuntimeCompletionExpressionTypeKind">RuntimeCompletionExpressionTypeKind</a></li><li><a href="#type_RuntimeCompletionVariable">RuntimeCompletionVariable</a></li><li><a href="#type_SearchId">SearchId</a></li><li><a href="#type_SearchResult">SearchResult</a></li><li><a href="#type_SearchResultKind">SearchResultKind</a></li><li><a href="#type_ServerService">ServerService</a></li><li><a href="#type_SourceChange">SourceChange</a></li><li><a href="#type_SourceEdit">SourceEdit</a></li><li><a href="#type_SourceFileEdit">SourceFileEdit</a></li><li><a href="#type_TypeHierarchyItem">TypeHierarchyItem</a></li></ul></div><h3>Refactorings (<a href="#refactorings">↑</a>)</h3><div class="subindex"><ul><li><a href="#refactoring_CONVERT_GETTER_TO_METHOD">CONVERT_GETTER_TO_METHOD</a></li><li><a href="#refactoring_CONVERT_METHOD_TO_GETTER">CONVERT_METHOD_TO_GETTER</a></li><li><a href="#refactoring_EXTRACT_LOCAL_VARIABLE">EXTRACT_LOCAL_VARIABLE</a></li><li><a href="#refactoring_EXTRACT_METHOD">EXTRACT_METHOD</a></li><li><a href="#refactoring_EXTRACT_WIDGET">EXTRACT_WIDGET</a></li><li><a href="#refactoring_INLINE_LOCAL_VARIABLE">INLINE_LOCAL_VARIABLE</a></li><li><a href="#refactoring_INLINE_METHOD">INLINE_METHOD</a></li><li><a href="#refactoring_MOVE_FILE">MOVE_FILE</a></li><li><a href="#refactoring_RENAME">RENAME</a></li></ul></div>
</body></html>
\ No newline at end of file
diff --git a/pkg/analysis_server/lib/protocol/protocol_constants.dart b/pkg/analysis_server/lib/protocol/protocol_constants.dart
index f51b81c..686011c 100644
--- a/pkg/analysis_server/lib/protocol/protocol_constants.dart
+++ b/pkg/analysis_server/lib/protocol/protocol_constants.dart
@@ -6,7 +6,7 @@
// To regenerate the file, use the script
// "pkg/analysis_server/tool/spec/generate_files".
-const String PROTOCOL_VERSION = '1.27.2';
+const String PROTOCOL_VERSION = '1.27.3';
const String ANALYSIS_NOTIFICATION_ANALYZED_FILES = 'analysis.analyzedFiles';
const String ANALYSIS_NOTIFICATION_ANALYZED_FILES_DIRECTORIES = 'directories';
@@ -341,6 +341,8 @@
const String SERVER_NOTIFICATION_ERROR_IS_FATAL = 'isFatal';
const String SERVER_NOTIFICATION_ERROR_MESSAGE = 'message';
const String SERVER_NOTIFICATION_ERROR_STACK_TRACE = 'stackTrace';
+const String SERVER_NOTIFICATION_LOG = 'server.log';
+const String SERVER_NOTIFICATION_LOG_ENTRY = 'entry';
const String SERVER_NOTIFICATION_STATUS = 'server.status';
const String SERVER_NOTIFICATION_STATUS_ANALYSIS = 'analysis';
const String SERVER_NOTIFICATION_STATUS_PUB = 'pub';
diff --git a/pkg/analysis_server/lib/protocol/protocol_generated.dart b/pkg/analysis_server/lib/protocol/protocol_generated.dart
index b00966b..46ed75f 100644
--- a/pkg/analysis_server/lib/protocol/protocol_generated.dart
+++ b/pkg/analysis_server/lib/protocol/protocol_generated.dart
@@ -22728,21 +22728,330 @@
}
/**
+ * ServerLogEntry
+ *
+ * {
+ * "time": int
+ * "kind": ServerLogEntryKind
+ * "data": String
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class ServerLogEntry implements HasToJson {
+ int _time;
+
+ ServerLogEntryKind _kind;
+
+ String _data;
+
+ /**
+ * The time (milliseconds since epoch) at which the server created this log
+ * entry.
+ */
+ int get time => _time;
+
+ /**
+ * The time (milliseconds since epoch) at which the server created this log
+ * entry.
+ */
+ void set time(int value) {
+ assert(value != null);
+ this._time = value;
+ }
+
+ /**
+ * The kind of the entry, used to determine how to interpret the "data"
+ * field.
+ */
+ ServerLogEntryKind get kind => _kind;
+
+ /**
+ * The kind of the entry, used to determine how to interpret the "data"
+ * field.
+ */
+ void set kind(ServerLogEntryKind value) {
+ assert(value != null);
+ this._kind = value;
+ }
+
+ /**
+ * The payload of the entry, the actual format is determined by the "kind"
+ * field.
+ */
+ String get data => _data;
+
+ /**
+ * The payload of the entry, the actual format is determined by the "kind"
+ * field.
+ */
+ void set data(String value) {
+ assert(value != null);
+ this._data = value;
+ }
+
+ ServerLogEntry(int time, ServerLogEntryKind kind, String data) {
+ this.time = time;
+ this.kind = kind;
+ this.data = data;
+ }
+
+ factory ServerLogEntry.fromJson(
+ JsonDecoder jsonDecoder, String jsonPath, Object json) {
+ if (json == null) {
+ json = {};
+ }
+ if (json is Map) {
+ int time;
+ if (json.containsKey("time")) {
+ time = jsonDecoder.decodeInt(jsonPath + ".time", json["time"]);
+ } else {
+ throw jsonDecoder.mismatch(jsonPath, "time");
+ }
+ ServerLogEntryKind kind;
+ if (json.containsKey("kind")) {
+ kind = new ServerLogEntryKind.fromJson(
+ jsonDecoder, jsonPath + ".kind", json["kind"]);
+ } else {
+ throw jsonDecoder.mismatch(jsonPath, "kind");
+ }
+ String data;
+ if (json.containsKey("data")) {
+ data = jsonDecoder.decodeString(jsonPath + ".data", json["data"]);
+ } else {
+ throw jsonDecoder.mismatch(jsonPath, "data");
+ }
+ return new ServerLogEntry(time, kind, data);
+ } else {
+ throw jsonDecoder.mismatch(jsonPath, "ServerLogEntry", json);
+ }
+ }
+
+ @override
+ Map<String, dynamic> toJson() {
+ Map<String, dynamic> result = {};
+ result["time"] = time;
+ result["kind"] = kind.toJson();
+ result["data"] = data;
+ return result;
+ }
+
+ @override
+ String toString() => json.encode(toJson());
+
+ @override
+ bool operator ==(other) {
+ if (other is ServerLogEntry) {
+ return time == other.time && kind == other.kind && data == other.data;
+ }
+ return false;
+ }
+
+ @override
+ int get hashCode {
+ int hash = 0;
+ hash = JenkinsSmiHash.combine(hash, time.hashCode);
+ hash = JenkinsSmiHash.combine(hash, kind.hashCode);
+ hash = JenkinsSmiHash.combine(hash, data.hashCode);
+ return JenkinsSmiHash.finish(hash);
+ }
+}
+
+/**
+ * ServerLogEntryKind
+ *
+ * enum {
+ * NOTIFICATION
+ * RAW
+ * REQUEST
+ * RESPONSE
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class ServerLogEntryKind implements Enum {
+ /**
+ * A notification from the server, such as "analysis.highlights". The "data"
+ * field contains a JSON object with abbreviated notification.
+ */
+ static const ServerLogEntryKind NOTIFICATION =
+ const ServerLogEntryKind._("NOTIFICATION");
+
+ /**
+ * Arbitrary string, describing some event that happened in the server, e.g.
+ * starting a file analysis, and details which files were accessed. These
+ * entries are not structured, but provide context information about requests
+ * and notification, and can be related by "time" for further manual
+ * analysis.
+ */
+ static const ServerLogEntryKind RAW = const ServerLogEntryKind._("RAW");
+
+ /**
+ * A request from the client, as the server views it, e.g. "edit.getAssists".
+ * The "data" field contains a JSON object with abbreviated request.
+ */
+ static const ServerLogEntryKind REQUEST =
+ const ServerLogEntryKind._("REQUEST");
+
+ /**
+ * Various counters and measurements related to execution of a request. The
+ * "data" field contains a JSON object with following fields:
+ *
+ * - "id" - the id of the request - copied from the request.
+ * - "method" - the method of the request, e.g. "edit.getAssists".
+ * - "clientRequestTime" - the time (milliseconds since epoch) at which the
+ * client made the request - copied from the request.
+ * - "serverRequestTime" - the time (milliseconds since epoch) at which the
+ * server received and decoded the JSON request.
+ * - "responseTime" - the time (milliseconds since epoch) at which the server
+ * created the response to be encoded into JSON and sent to the client.
+ */
+ static const ServerLogEntryKind RESPONSE =
+ const ServerLogEntryKind._("RESPONSE");
+
+ /**
+ * A list containing all of the enum values that are defined.
+ */
+ static const List<ServerLogEntryKind> VALUES = const <ServerLogEntryKind>[
+ NOTIFICATION,
+ RAW,
+ REQUEST,
+ RESPONSE
+ ];
+
+ @override
+ final String name;
+
+ const ServerLogEntryKind._(this.name);
+
+ factory ServerLogEntryKind(String name) {
+ switch (name) {
+ case "NOTIFICATION":
+ return NOTIFICATION;
+ case "RAW":
+ return RAW;
+ case "REQUEST":
+ return REQUEST;
+ case "RESPONSE":
+ return RESPONSE;
+ }
+ throw new Exception('Illegal enum value: $name');
+ }
+
+ factory ServerLogEntryKind.fromJson(
+ JsonDecoder jsonDecoder, String jsonPath, Object json) {
+ if (json is String) {
+ try {
+ return new ServerLogEntryKind(json);
+ } catch (_) {
+ // Fall through
+ }
+ }
+ throw jsonDecoder.mismatch(jsonPath, "ServerLogEntryKind", json);
+ }
+
+ @override
+ String toString() => "ServerLogEntryKind.$name";
+
+ String toJson() => name;
+}
+
+/**
+ * server.log params
+ *
+ * {
+ * "entry": ServerLogEntry
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class ServerLogParams implements HasToJson {
+ ServerLogEntry _entry;
+
+ ServerLogEntry get entry => _entry;
+
+ void set entry(ServerLogEntry value) {
+ assert(value != null);
+ this._entry = value;
+ }
+
+ ServerLogParams(ServerLogEntry entry) {
+ this.entry = entry;
+ }
+
+ factory ServerLogParams.fromJson(
+ JsonDecoder jsonDecoder, String jsonPath, Object json) {
+ if (json == null) {
+ json = {};
+ }
+ if (json is Map) {
+ ServerLogEntry entry;
+ if (json.containsKey("entry")) {
+ entry = new ServerLogEntry.fromJson(
+ jsonDecoder, jsonPath + ".entry", json["entry"]);
+ } else {
+ throw jsonDecoder.mismatch(jsonPath, "entry");
+ }
+ return new ServerLogParams(entry);
+ } else {
+ throw jsonDecoder.mismatch(jsonPath, "server.log params", json);
+ }
+ }
+
+ factory ServerLogParams.fromNotification(Notification notification) {
+ return new ServerLogParams.fromJson(
+ new ResponseDecoder(null), "params", notification.params);
+ }
+
+ @override
+ Map<String, dynamic> toJson() {
+ Map<String, dynamic> result = {};
+ result["entry"] = entry.toJson();
+ return result;
+ }
+
+ Notification toNotification() {
+ return new Notification("server.log", toJson());
+ }
+
+ @override
+ String toString() => json.encode(toJson());
+
+ @override
+ bool operator ==(other) {
+ if (other is ServerLogParams) {
+ return entry == other.entry;
+ }
+ return false;
+ }
+
+ @override
+ int get hashCode {
+ int hash = 0;
+ hash = JenkinsSmiHash.combine(hash, entry.hashCode);
+ return JenkinsSmiHash.finish(hash);
+ }
+}
+
+/**
* ServerService
*
* enum {
+ * LOG
* STATUS
* }
*
* Clients may not extend, implement or mix-in this class.
*/
class ServerService implements Enum {
+ static const ServerService LOG = const ServerService._("LOG");
+
static const ServerService STATUS = const ServerService._("STATUS");
/**
* A list containing all of the enum values that are defined.
*/
- static const List<ServerService> VALUES = const <ServerService>[STATUS];
+ static const List<ServerService> VALUES = const <ServerService>[LOG, STATUS];
@override
final String name;
@@ -22751,6 +23060,8 @@
factory ServerService(String name) {
switch (name) {
+ case "LOG":
+ return LOG;
case "STATUS":
return STATUS;
}
@@ -23071,6 +23382,7 @@
* "lexeme": String
* "type": optional String
* "validElementKinds": optional List<String>
+ * "offset": int
* }
*
* Clients may not extend, implement or mix-in this class.
@@ -23082,6 +23394,8 @@
List<String> _validElementKinds;
+ int _offset;
+
/**
* The token's lexeme.
*/
@@ -23127,10 +23441,27 @@
this._validElementKinds = value;
}
- TokenDetails(String lexeme, {String type, List<String> validElementKinds}) {
+ /**
+ * The offset of the first character of the token in the file which it
+ * originated from.
+ */
+ int get offset => _offset;
+
+ /**
+ * The offset of the first character of the token in the file which it
+ * originated from.
+ */
+ void set offset(int value) {
+ assert(value != null);
+ this._offset = value;
+ }
+
+ TokenDetails(String lexeme, int offset,
+ {String type, List<String> validElementKinds}) {
this.lexeme = lexeme;
this.type = type;
this.validElementKinds = validElementKinds;
+ this.offset = offset;
}
factory TokenDetails.fromJson(
@@ -23156,7 +23487,13 @@
json["validElementKinds"],
jsonDecoder.decodeString);
}
- return new TokenDetails(lexeme,
+ int offset;
+ if (json.containsKey("offset")) {
+ offset = jsonDecoder.decodeInt(jsonPath + ".offset", json["offset"]);
+ } else {
+ throw jsonDecoder.mismatch(jsonPath, "offset");
+ }
+ return new TokenDetails(lexeme, offset,
type: type, validElementKinds: validElementKinds);
} else {
throw jsonDecoder.mismatch(jsonPath, "TokenDetails", json);
@@ -23173,6 +23510,7 @@
if (validElementKinds != null) {
result["validElementKinds"] = validElementKinds;
}
+ result["offset"] = offset;
return result;
}
@@ -23185,7 +23523,8 @@
return lexeme == other.lexeme &&
type == other.type &&
listEqual(validElementKinds, other.validElementKinds,
- (String a, String b) => a == b);
+ (String a, String b) => a == b) &&
+ offset == other.offset;
}
return false;
}
@@ -23196,6 +23535,7 @@
hash = JenkinsSmiHash.combine(hash, lexeme.hashCode);
hash = JenkinsSmiHash.combine(hash, type.hashCode);
hash = JenkinsSmiHash.combine(hash, validElementKinds.hashCode);
+ hash = JenkinsSmiHash.combine(hash, offset.hashCode);
return JenkinsSmiHash.finish(hash);
}
}
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index bd6fa83..1949461 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -49,6 +49,7 @@
import 'package:analysis_server/src/utilities/file_string_sink.dart';
import 'package:analysis_server/src/utilities/null_string_sink.dart';
import 'package:analysis_server/src/utilities/request_statistics.dart';
+import 'package:analysis_server/src/utilities/tee_string_sink.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/exception/exception.dart';
@@ -204,9 +205,11 @@
} else if (name.startsWith('file:')) {
String path = name.substring('file:'.length);
sink = FileStringSink(path);
- requestStatistics?.sink = sink;
}
}
+ if (requestStatistics != null) {
+ sink = TeeStringSink(sink, requestStatistics.perfLoggerStringSink);
+ }
_analysisPerformanceLogger = new PerformanceLog(sink);
}
diff --git a/pkg/analysis_server/lib/src/channel/byte_stream_channel.dart b/pkg/analysis_server/lib/src/channel/byte_stream_channel.dart
index 72f127d..4f8f13a 100644
--- a/pkg/analysis_server/lib/src/channel/byte_stream_channel.dart
+++ b/pkg/analysis_server/lib/src/channel/byte_stream_channel.dart
@@ -93,7 +93,9 @@
ByteStreamServerChannel(
this._input, this._output, this._instrumentationService,
{RequestStatisticsHelper requestStatistics})
- : _requestStatistics = requestStatistics;
+ : _requestStatistics = requestStatistics {
+ _requestStatistics?.serverChannel = this;
+ }
/**
* Future that will be completed when the input stream is closed.
@@ -132,8 +134,10 @@
ServerPerformanceStatistics.serverChannel.makeCurrentWhile(() {
String jsonEncoding = json.encode(notification.toJson());
_outputLine(jsonEncoding);
- _instrumentationService.logNotification(jsonEncoding);
- _requestStatistics?.logNotification(notification);
+ if (!identical(notification.event, 'server.log')) {
+ _instrumentationService.logNotification(jsonEncoding);
+ _requestStatistics?.logNotification(notification);
+ }
});
}
diff --git a/pkg/analysis_server/lib/src/computer/computer_highlights2.dart b/pkg/analysis_server/lib/src/computer/computer_highlights2.dart
index 7b4eee3..c3a610b 100644
--- a/pkg/analysis_server/lib/src/computer/computer_highlights2.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_highlights2.dart
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
@@ -425,10 +424,8 @@
}
static bool _isDynamicExpression(Expression e) {
- if (e is SimpleIdentifier && e.staticElement is PrefixElement) {
- return false;
- }
- return resolutionMap.staticTypeForExpression(e).isDynamic;
+ var type = e.staticType;
+ return type != null && type.isDynamic;
}
}
diff --git a/pkg/analysis_server/lib/src/domain_server.dart b/pkg/analysis_server/lib/src/domain_server.dart
index c7d5f28..5c60f3b 100644
--- a/pkg/analysis_server/lib/src/domain_server.dart
+++ b/pkg/analysis_server/lib/src/domain_server.dart
@@ -59,6 +59,10 @@
new ServerSetSubscriptionsParams.fromRequest(request)
.subscriptions
.toSet();
+
+ server.requestStatistics?.isNotificationSubscribed =
+ server.serverServices.contains(ServerService.LOG);
+
return new ServerSetSubscriptionsResult().toResponse(request.id);
}
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_document_symbols.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_document_symbols.dart
index 3de909c..2df189b 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_document_symbols.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_document_symbols.dart
@@ -14,6 +14,7 @@
import 'package:analysis_server/src/protocol_server.dart' show Outline;
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/source/line_info.dart';
+import 'package:analyzer_plugin/protocol/protocol_common.dart' show ElementKind;
// If the client does not provide capabilities.documentSymbol.symbolKind.valueSet
// then we must never send a kind that's not in this list.
@@ -77,8 +78,13 @@
LineInfo lineInfo,
Outline outline,
) {
+ final name = outline.element.name != null && outline.element.name != ""
+ ? outline.element.name
+ : (outline.element.kind == ElementKind.EXTENSION
+ ? "<unnamed extension>"
+ : "<unnamed>");
return new DocumentSymbol(
- outline.element.name,
+ name,
outline.element.parameters,
elementKindToSymbolKind(clientSupportedSymbolKinds, outline.element.kind),
outline.element.isDeprecated,
diff --git a/pkg/analysis_server/lib/src/lsp/mapping.dart b/pkg/analysis_server/lib/src/lsp/mapping.dart
index 8088f62..eea32fe 100644
--- a/pkg/analysis_server/lib/src/lsp/mapping.dart
+++ b/pkg/analysis_server/lib/src/lsp/mapping.dart
@@ -313,6 +313,8 @@
case server.ElementKind.ENUM:
case server.ElementKind.ENUM_CONSTANT:
return const [lsp.SymbolKind.Enum];
+ case server.ElementKind.EXTENSION:
+ return const [lsp.SymbolKind.Namespace];
case server.ElementKind.FIELD:
return const [lsp.SymbolKind.Field];
case server.ElementKind.FILE:
@@ -357,7 +359,10 @@
}
}
- return getKindPreferences().firstWhere(isSupported, orElse: () => null);
+ // LSP requires we specify *some* kind, so in the case where the above code doesn't
+ // match we'll just have to send a value to avoid a crash.
+ return getKindPreferences()
+ .firstWhere(isSupported, orElse: () => lsp.SymbolKind.Obj);
}
String getCompletionDetail(
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index eb35df8..f6febdc 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -310,14 +310,6 @@
static const String TRAIN_USING = "train-using";
/**
- * The name of the flag to include into the analysis driver log all
- * communications with the client - requests, responses, shortened
- * notifications.
- */
- static const String INCLUDE_PROTOCOL_TO_DRIVER_LOG =
- "include-protocol-to-driver-log";
-
- /**
* The instrumentation server that is to be used by the analysis server.
*/
InstrumentationServer instrumentationServer;
@@ -475,11 +467,6 @@
}
}
- RequestStatisticsHelper requestStatisticsHelper;
- if (results[INCLUDE_PROTOCOL_TO_DRIVER_LOG] == true) {
- requestStatisticsHelper = RequestStatisticsHelper();
- }
-
CompilerContext.runWithDefaultOptions((_) async {
if (analysisServerOptions.useLanguageServerProtocol) {
startLspServer(results, analysisServerOptions, dartSdkManager,
@@ -491,7 +478,7 @@
parser,
dartSdkManager,
instrumentationService,
- requestStatisticsHelper,
+ RequestStatisticsHelper(),
analytics,
diagnosticServerPort);
}
@@ -810,9 +797,6 @@
parser.addOption(TRAIN_USING,
help: "Pass in a directory to analyze for purposes of training an "
"analysis server snapshot.");
- parser.addFlag(INCLUDE_PROTOCOL_TO_DRIVER_LOG,
- defaultsTo: false,
- help: "Whether to use include protocol into the driver log");
return parser;
}
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
index 27b6639..9e1113b 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
@@ -269,6 +269,18 @@
}
}
}
+
+ if (containingNode is VariableDeclaration &&
+ containingNode.equals != null &&
+ target.offset >= containingNode.equals.end) {
+ var parent = containingNode.parent;
+ if (parent is VariableDeclarationList) {
+ var type = parent.type?.type;
+ if (type is InterfaceType) {
+ addTypeTag(type);
+ }
+ }
+ }
}
static List<String> _ensureList(Map<String, List<String>> map, String key) {
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/completion_ranking_internal.dart b/pkg/analysis_server/lib/src/services/completion/dart/completion_ranking_internal.dart
index b552cf6..318736e 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/completion_ranking_internal.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/completion_ranking_internal.dart
@@ -116,7 +116,7 @@
bool testInsideQuotes(DartCompletionRequest request) {
final token = getCurrentToken(request);
- if (token.isSynthetic) {
+ if (token == null || token.isSynthetic) {
return false;
}
@@ -136,7 +136,7 @@
}
bool isTokenDot(Token token) {
- return !token.isSynthetic && token.lexeme.endsWith('.');
+ return token != null && !token.isSynthetic && token.lexeme.endsWith('.');
}
bool testFollowingDot(DartCompletionRequest request) {
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart
index ab489ad..f2815f2 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart
@@ -41,8 +41,10 @@
if (elem is ClassElement) {
// Suggestions provided by StaticMemberContributor
return const <CompletionSuggestion>[];
- }
- if (elem is PrefixElement) {
+ } else if (elem is ExtensionElement) {
+ // Suggestions provided by StaticMemberContributor
+ return const <CompletionSuggestion>[];
+ } else if (elem is PrefixElement) {
// Suggestions provided by LibraryMemberContributor
return const <CompletionSuggestion>[];
}
@@ -52,6 +54,13 @@
_addInstanceMembers(expression.staticElement);
} else {
var type = expression.staticType;
+ if (type == null) {
+ // Without a type we cannot find the extensions that apply.
+ // We shouldn't get to this point, but there's an NPE if we invoke
+ // `_resolveExtendedType` when `type` is `null`, so we guard against it
+ // to ensure that we can return the suggestions from other providers.
+ return const <CompletionSuggestion>[];
+ }
LibraryScope nameScope = new LibraryScope(containingLibrary);
for (var extension in nameScope.extensions) {
var typeSystem = containingLibrary.context.typeSystem;
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/inherited_reference_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/inherited_reference_contributor.dart
index 2afa953..897f2c2 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/inherited_reference_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/inherited_reference_contributor.dart
@@ -8,7 +8,6 @@
import 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart';
import 'package:analysis_server/src/utilities/flutter.dart';
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer_plugin/src/utilities/completion/completion_target.dart';
@@ -67,11 +66,9 @@
}
containingLibrary = request.libraryElement;
if (classDecl is ClassDeclaration) {
- return _computeSuggestionsForClass2(
- resolutionMap.elementDeclaredByClassDeclaration(classDecl), request);
+ return _computeSuggestionsForClass2(classDecl.declaredElement, request);
} else if (classDecl is MixinDeclaration) {
- return _computeSuggestionsForClass2(
- resolutionMap.elementDeclaredByMixinDeclaration(classDecl), request);
+ return _computeSuggestionsForClass2(classDecl.declaredElement, request);
}
return const <CompletionSuggestion>[];
}
@@ -109,17 +106,11 @@
}
List<CompletionSuggestion> _computeSuggestionsForClass2(
- ClassElement classElement, DartCompletionRequest request,
- {bool skipChildClass = true}) {
+ ClassElement classElement, DartCompletionRequest request) {
bool isFunctionalArgument = request.target.isFunctionalArgument();
kind = isFunctionalArgument
? CompletionSuggestionKind.IDENTIFIER
: CompletionSuggestionKind.INVOCATION;
- if (!skipChildClass) {
- _addSuggestionsForType(classElement.type, request,
- isFunctionalArgument: isFunctionalArgument);
- }
-
for (InterfaceType type in classElement.allSupertypes) {
_addSuggestionsForType(type, request,
isFunctionalArgument: isFunctionalArgument);
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
index 4ef2e9f..d3300ce 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
@@ -647,6 +647,12 @@
}
@override
+ visitSwitchCase(SwitchCase node) {
+ _addStatementKeywords(node);
+ return super.visitSwitchCase(node);
+ }
+
+ @override
visitTryStatement(TryStatement node) {
var obj = entity;
if (obj is CatchClause ||
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/local_constructor_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/local_constructor_contributor.dart
index 9e548cc..3e3cf86 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/local_constructor_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/local_constructor_contributor.dart
@@ -12,7 +12,6 @@
import 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart';
import 'package:analysis_server/src/services/completion/dart/utilities.dart';
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart' as protocol
show Element, ElementKind;
@@ -112,8 +111,7 @@
ClassDeclaration classDecl, ConstructorDeclaration constructorDecl) {
String completion = classDecl.name.name;
- ClassElement classElement =
- resolutionMap.elementDeclaredByClassDeclaration(classDecl);
+ ClassElement classElement = classDecl.declaredElement;
int relevance = optype.returnValueSuggestionsFilter(
classElement?.type, DART_RELEVANCE_DEFAULT);
if (constructorDecl != null) {
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
index c058170..f5b9ff3 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
@@ -12,7 +12,6 @@
import 'package:analysis_server/src/services/completion/dart/utilities.dart';
import 'package:analysis_server/src/services/correction/strings.dart';
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
@@ -444,8 +443,7 @@
{bool isAbstract = false,
bool isDeprecated = false,
int relevance = DART_RELEVANCE_DEFAULT}) {
- ClassElement classElement =
- resolutionMap.elementDeclaredByEnumDeclaration(enumDeclaration);
+ ClassElement classElement = enumDeclaration.declaredElement;
relevance =
optype.returnValueSuggestionsFilter(classElement?.type, relevance);
if (relevance != null) {
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/static_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/static_member_contributor.dart
index 26a7ce5..bef2ef6 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/static_member_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/static_member_contributor.dart
@@ -25,7 +25,7 @@
Expression targetId = request.dotTarget;
if (targetId is Identifier && !request.target.isCascade) {
Element elem = targetId.staticElement;
- if (elem is ClassElement) {
+ if (elem is ClassElement || elem is ExtensionElement) {
LibraryElement containingLibrary = request.libraryElement;
// Gracefully degrade if the library could not be determined
// e.g. detached part file or source change
@@ -75,6 +75,11 @@
}
@override
+ visitExtensionElement(ExtensionElement element) {
+ element.visitChildren(this);
+ }
+
+ @override
visitFieldElement(FieldElement element) {
if (element.isStatic) {
_addSuggestion(element);
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
index 327aca1..1c90f7b 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
@@ -215,6 +215,13 @@
}
@override
+ visitExtensionElement(ExtensionElement element) {
+ if (!instCreation) {
+ addSuggestion(element);
+ }
+ }
+
+ @override
visitFunctionElement(FunctionElement element) {
if (!typesOnly) {
int relevance = element.library == containingLibrary
diff --git a/pkg/analysis_server/lib/src/services/completion/token_details/token_detail_builder.dart b/pkg/analysis_server/lib/src/services/completion/token_details/token_detail_builder.dart
index 3d225b5..fbde099 100644
--- a/pkg/analysis_server/lib/src/services/completion/token_details/token_detail_builder.dart
+++ b/pkg/analysis_server/lib/src/services/completion/token_details/token_detail_builder.dart
@@ -54,8 +54,8 @@
/// Create the details for a single [token], using the given list of [kinds].
void _createDetails(Token token, String type, List<String> kinds) {
- details.add(
- new TokenDetails(token.lexeme, type: type, validElementKinds: kinds));
+ details.add(new TokenDetails(token.lexeme, token.offset,
+ type: type, validElementKinds: kinds));
}
/// Return a unique identifier for the type of the given [expression].
diff --git a/pkg/analysis_server/lib/src/services/correction/assist.dart b/pkg/analysis_server/lib/src/services/correction/assist.dart
index 52641ae..9cb8c62 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist.dart
@@ -32,11 +32,7 @@
*/
class DartAssistKind {
static const ADD_TYPE_ANNOTATION = const AssistKind(
- 'dart.assist.addTypeAnnotation', 30, "Add type annotation",
- associatedErrorCodes: <String>[
- 'always_specify_types',
- 'type_annotate_public_apis'
- ]);
+ 'dart.assist.addTypeAnnotation', 30, "Add type annotation");
static const ASSIGN_TO_LOCAL_VARIABLE = const AssistKind(
'dart.assist.assignToVariable', 30, "Assign value to new local variable");
static const CONVERT_CLASS_TO_MIXIN = const AssistKind(
@@ -48,18 +44,15 @@
static const CONVERT_DOCUMENTATION_INTO_LINE = const AssistKind(
'dart.assist.convert.lineComment',
30,
- "Convert to line documentation comment",
- associatedErrorCodes: <String>['slash_for_doc_comments']);
+ "Convert to line documentation comment");
static const CONVERT_INTO_ASYNC_BODY = const AssistKind(
'dart.assist.convert.bodyToAsync', 29, "Convert to async function body");
static const CONVERT_INTO_BLOCK_BODY = const AssistKind(
'dart.assist.convert.bodyToBlock', 30, "Convert to block body");
static const CONVERT_INTO_EXPRESSION_BODY = const AssistKind(
- 'dart.assist.convert.bodyToExpression', 30, "Convert to expression body",
- associatedErrorCodes: <String>['prefer_expression_function_bodies']);
+ 'dart.assist.convert.bodyToExpression', 30, "Convert to expression body");
static const CONVERT_INTO_FINAL_FIELD = const AssistKind(
- 'dart.assist.convert.getterToFinalField', 30, "Convert to final field",
- associatedErrorCodes: <String>['prefer_final_fields']);
+ 'dart.assist.convert.getterToFinalField', 30, "Convert to final field");
static const CONVERT_INTO_FOR_INDEX = const AssistKind(
'dart.assist.convert.forEachToForIndex', 30, "Convert to for-index loop");
static const CONVERT_INTO_GENERIC_FUNCTION_SYNTAX = const AssistKind(
@@ -72,6 +65,7 @@
const AssistKind('dart.assist.convert.isNot', 30, "Convert to is!");
static const CONVERT_INTO_IS_NOT_EMPTY = const AssistKind(
'dart.assist.convert.isNotEmpty', 30, "Convert to 'isNotEmpty'",
+ // todo (pq): unify w/ fix
associatedErrorCodes: <String>['prefer_is_not_empty']);
static const CONVERT_PART_OF_TO_URI = const AssistKind(
'dart.assist.convert.partOfToPartUri', 30, "Convert to use a URI");
@@ -84,18 +78,11 @@
30,
"Convert to field formal parameter");
static const CONVERT_TO_FOR_ELEMENT = const AssistKind(
- 'dart.assist.convertToForElement', 30, "Convert to a 'for' element",
- associatedErrorCodes: <String>[
- 'prefer_for_elements_to_map_fromIterable'
- ]);
+ 'dart.assist.convertToForElement', 30, "Convert to a 'for' element");
static const CONVERT_TO_IF_ELEMENT = const AssistKind(
- 'dart.assist.convertToIfElement', 30, "Convert to an 'if' element",
- associatedErrorCodes: <String>[
- 'prefer_if_elements_to_conditional_expressions'
- ]);
+ 'dart.assist.convertToIfElement', 30, "Convert to an 'if' element");
static const CONVERT_TO_INT_LITERAL = const AssistKind(
- 'dart.assist.convert.toIntLiteral', 30, "Convert to an int literal",
- associatedErrorCodes: <String>['prefer_int_literals']);
+ 'dart.assist.convert.toIntLiteral', 30, "Convert to an int literal");
static const CONVERT_TO_LIST_LITERAL = const AssistKind(
'dart.assist.convert.toListLiteral', 30, "Convert to list literal",
// todo (brianwilkerson): unify w/ fix
@@ -113,12 +100,12 @@
30,
"Convert to normal parameter");
static const CONVERT_TO_NULL_AWARE = const AssistKind(
- 'dart.assist.convert.toNullAware', 30, "Convert to use '?.'",
- associatedErrorCodes: <String>['prefer_null_aware_operators']);
+ 'dart.assist.convert.toNullAware', 30, "Convert to use '?.'");
static const CONVERT_TO_PACKAGE_IMPORT = const AssistKind(
'dart.assist.convert.relativeToPackageImport',
30,
"Convert to 'package:' import",
+ // todo (pq): migrate to (conditional) fix
associatedErrorCodes: <String>['avoid_relative_lib_imports']);
static const CONVERT_TO_SET_LITERAL = const AssistKind(
'dart.assist.convert.toSetLiteral', 30, "Convert to set literal",
@@ -128,10 +115,12 @@
'dart.assist.convert.toSingleQuotedString',
30,
"Convert to single quoted string",
+ // todo (pq): migrate to (conditional) fix
associatedErrorCodes: <String>['prefer_single_quotes']);
- static const CONVERT_TO_SPREAD = const AssistKind(
- 'dart.assist.convertToSpread', 30, "Convert to a spread",
- associatedErrorCodes: <String>['prefer_spread_collections']);
+ static const CONVERT_TO_SPREAD =
+ const AssistKind('dart.assist.convertToSpread', 30, "Convert to a spread",
+ // todo (pq): migrate to (conditional) fix
+ associatedErrorCodes: <String>['prefer_spread_collections']);
static const ENCAPSULATE_FIELD =
const AssistKind('dart.assist.encapsulateField', 30, "Encapsulate field");
static const EXCHANGE_OPERANDS =
@@ -172,9 +161,10 @@
'dart.assist.flutter.wrap.streamBuilder', 30, "Wrap with StreamBuilder");
static const IMPORT_ADD_SHOW = const AssistKind(
'dart.assist.addShowCombinator', 30, "Add explicit 'show' combinator");
- static const INLINE_INVOCATION = const AssistKind(
- 'dart.assist.inline', 30, "Inline invocation of '{0}'",
- associatedErrorCodes: <String>['prefer_inlined_adds']);
+ static const INLINE_INVOCATION =
+ const AssistKind('dart.assist.inline', 30, "Inline invocation of '{0}'",
+ // todo (pq): migrate to (conditional) fix
+ associatedErrorCodes: <String>['prefer_inlined_adds']);
static const INTRODUCE_LOCAL_CAST_TYPE = const AssistKind(
'dart.assist.introduceLocalCast',
30,
@@ -193,6 +183,7 @@
'dart.assist.joinVariableDeclaration', 30, "Join variable declaration");
static const REMOVE_TYPE_ANNOTATION = const AssistKind(
'dart.assist.removeTypeAnnotation', 29, "Remove type annotation",
+ // todo (pq): migrate to (conditional) fix
associatedErrorCodes: <String>[
'avoid_return_types_on_setters',
'type_init_formals'
@@ -209,6 +200,7 @@
'dart.assist.sort.child.properties.last',
30,
"Move child property to end of arguments",
+ // todo (pq): migrate to (conditional) fix
associatedErrorCodes: <String>[
'sort_child_properties_last',
]);
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 9dc704e..f3ba612 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -8,26 +8,22 @@
import 'package:analysis_server/plugin/edit/assist/assist_core.dart';
import 'package:analysis_server/plugin/edit/assist/assist_dart.dart';
import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analysis_server/src/services/correction/base_processor.dart';
import 'package:analysis_server/src/services/correction/name_suggestion.dart';
import 'package:analysis_server/src/services/correction/selection_analyzer.dart';
import 'package:analysis_server/src/services/correction/statement_analyzer.dart';
import 'package:analysis_server/src/services/correction/util.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analysis_server/src/services/search/hierarchy.dart';
-import 'package:analysis_server/src/utilities/flutter.dart';
-import 'package:analyzer/dart/analysis/session.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/precedence.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/dart/analysis/experiments.dart';
-import 'package:analyzer/src/dart/analysis/session_helper.dart';
import 'package:analyzer/src/dart/ast/token.dart';
import 'package:analyzer/src/dart/ast/utilities.dart';
-import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
import 'package:analyzer/src/generated/java_core.dart';
-import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart' hide Element;
import 'package:analyzer_plugin/src/utilities/change_builder/change_builder_dart.dart';
@@ -36,67 +32,42 @@
import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
import 'package:analyzer_plugin/utilities/range_factory.dart';
import 'package:meta/meta.dart';
-import 'package:path/path.dart';
+import 'package:path/path.dart' hide context;
typedef _SimpleIdentifierVisitor(SimpleIdentifier node);
/**
* The computer for Dart assists.
*/
-class AssistProcessor {
+class AssistProcessor extends BaseProcessor {
final DartAssistContext context;
- final int selectionOffset;
- final int selectionLength;
- final int selectionEnd;
-
- final AnalysisSession session;
- final AnalysisSessionHelper sessionHelper;
- final TypeProvider typeProvider;
- final String file;
- final CorrectionUtils utils;
- final Flutter flutter;
-
final List<Assist> assists = <Assist>[];
- AstNode node;
-
AssistProcessor(this.context)
- : selectionOffset = context.selectionOffset,
- selectionLength = context.selectionLength,
- selectionEnd = context.selectionOffset + context.selectionLength,
- session = context.resolveResult.session,
- sessionHelper = AnalysisSessionHelper(context.resolveResult.session),
- typeProvider = context.resolveResult.typeProvider,
- file = context.resolveResult.path,
- utils = new CorrectionUtils(context.resolveResult),
- flutter = Flutter.of(context.resolveResult);
-
- /**
- * Returns the EOL to use for this [CompilationUnit].
- */
- String get eol => utils.endOfLine;
-
- /**
- * Return the status of the known experiments.
- */
- ExperimentStatus get experimentStatus =>
- (session.analysisContext.analysisOptions as AnalysisOptionsImpl)
- .experimentStatus;
+ : super(
+ selectionOffset: context.selectionOffset,
+ selectionLength: context.selectionLength,
+ resolvedResult: context.resolveResult,
+ workspace: context.workspace,
+ );
Future<List<Assist>> compute() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
- if (!_setupCompute()) {
+ if (!setupCompute()) {
return assists;
}
-
- await _addProposal_addTypeAnnotation_DeclaredIdentifier();
- await _addProposal_addTypeAnnotation_SimpleFormalParameter();
- await _addProposal_addTypeAnnotation_VariableDeclaration();
+ if (!_containsErrorCode(
+ {LintNames.always_specify_types, LintNames.type_annotate_public_apis},
+ )) {
+ await _addProposals_addTypeAnnotation();
+ }
await _addProposal_assignToLocalVariable();
await _addProposal_convertClassToMixin();
await _addProposal_convertDocumentationIntoBlock();
- await _addProposal_convertDocumentationIntoLine();
+ if (!_containsErrorCode(
+ {LintNames.slash_for_doc_comments},
+ )) {
+ await _addProposal_convertDocumentationIntoLine();
+ }
await _addProposal_convertIntoFinalField();
await _addProposal_convertIntoGetter();
await _addProposal_convertListConstructorToListLiteral();
@@ -107,17 +78,29 @@
await _addProposal_convertToAsyncFunctionBody();
await _addProposal_convertToBlockFunctionBody();
await _addProposal_convertToDoubleQuotedString();
- await _addProposal_convertToExpressionFunctionBody();
+ if (!_containsErrorCode(
+ {LintNames.prefer_expression_function_bodies},
+ )) {
+ await _addProposal_convertToExpressionFunctionBody();
+ }
await _addProposal_convertToFieldParameter();
await _addProposal_convertToForIndexLoop();
await _addProposal_convertToGenericFunctionSyntax();
- await _addProposal_convertToIntLiteral();
+ if (!_containsErrorCode(
+ {LintNames.prefer_int_literals},
+ )) {
+ await _addProposal_convertToIntLiteral();
+ }
await _addProposal_convertToIsNot_onIs();
await _addProposal_convertToIsNot_onNot();
await _addProposal_convertToIsNotEmpty();
await _addProposal_convertToMultilineString();
await _addProposal_convertToNormalParameter();
- await _addProposal_convertToNullAware();
+ if (!_containsErrorCode(
+ {LintNames.prefer_null_aware_operators},
+ )) {
+ await _addProposal_convertToNullAware();
+ }
await _addProposal_convertToPackageImport();
await _addProposal_convertToSingleQuotedString();
await _addProposal_encapsulateField();
@@ -149,11 +132,23 @@
await _addProposal_splitAndCondition();
await _addProposal_splitVariableDeclaration();
await _addProposal_surroundWith();
- await _addProposal_useCurlyBraces();
+ if (!_containsErrorCode(
+ {LintNames.curly_braces_in_flow_control_structures},
+ )) {
+ await _addProposal_useCurlyBraces();
+ }
if (experimentStatus.control_flow_collections) {
- await _addProposal_convertConditionalExpressionToIfElement();
- await _addProposal_convertMapFromIterableToForLiteral();
+ if (!_containsErrorCode(
+ {LintNames.prefer_if_elements_to_conditional_expressions},
+ )) {
+ await _addProposal_convertConditionalExpressionToIfElement();
+ }
+ if (!_containsErrorCode(
+ {LintNames.prefer_for_elements_to_map_fromIterable},
+ )) {
+ await _addProposal_convertMapFromIterableToForLiteral();
+ }
}
if (experimentStatus.spread_collections) {
await _addProposal_convertAddAllToSpread();
@@ -163,7 +158,7 @@
}
Future<List<Assist>> computeAssist(AssistKind assistKind) async {
- if (!_setupCompute()) {
+ if (!setupCompute()) {
return assists;
}
@@ -188,41 +183,11 @@
return assists;
}
- FunctionBody getEnclosingFunctionBody() {
- // TODO(brianwilkerson) Determine whether there is a reason why this method
- // isn't just "return node.getAncestor((node) => node is FunctionBody);"
- {
- FunctionExpression function =
- node.thisOrAncestorOfType<FunctionExpression>();
- if (function != null) {
- return function.body;
- }
- }
- {
- FunctionDeclaration function =
- node.thisOrAncestorOfType<FunctionDeclaration>();
- if (function != null) {
- return function.functionExpression.body;
- }
- }
- {
- ConstructorDeclaration constructor =
- node.thisOrAncestorOfType<ConstructorDeclaration>();
- if (constructor != null) {
- return constructor.body;
- }
- }
- {
- MethodDeclaration method = node.thisOrAncestorOfType<MethodDeclaration>();
- if (method != null) {
- return method.body;
- }
- }
- return null;
- }
-
void _addAssistFromBuilder(DartChangeBuilder builder, AssistKind kind,
{List args = null}) {
+ if (builder == null) {
+ return;
+ }
SourceChange change = builder.sourceChange;
if (change.edits.isEmpty) {
_coverageMarker();
@@ -233,169 +198,7 @@
assists.add(new Assist(kind, change));
}
- Future<void> _addProposal_addTypeAnnotation_DeclaredIdentifier() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
- DeclaredIdentifier declaredIdentifier =
- node.thisOrAncestorOfType<DeclaredIdentifier>();
- if (declaredIdentifier == null) {
- ForStatement forEach = node.thisOrAncestorMatching(
- (node) => node is ForStatement && node.forLoopParts is ForEachParts);
- ForEachParts forEachParts = forEach?.forLoopParts;
- int offset = node.offset;
- if (forEach != null &&
- forEachParts.iterable != null &&
- offset < forEachParts.iterable.offset) {
- declaredIdentifier = forEachParts is ForEachPartsWithDeclaration
- ? forEachParts.loopVariable
- : null;
- }
- }
- if (declaredIdentifier == null) {
- _coverageMarker();
- return;
- }
- // Ensure that there isn't already a type annotation.
- if (declaredIdentifier.type != null) {
- _coverageMarker();
- return;
- }
- DartType type = declaredIdentifier.identifier.staticType;
- if (type is! InterfaceType && type is! FunctionType) {
- _coverageMarker();
- return;
- }
- _configureTargetLocation(node);
-
- var changeBuilder = _newDartChangeBuilder();
- bool validChange = true;
- await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
- Token keyword = declaredIdentifier.keyword;
- if (keyword.keyword == Keyword.VAR) {
- builder.addReplacement(range.token(keyword), (DartEditBuilder builder) {
- validChange = builder.writeType(type);
- });
- } else {
- builder.addInsertion(declaredIdentifier.identifier.offset,
- (DartEditBuilder builder) {
- validChange = builder.writeType(type);
- builder.write(' ');
- });
- }
- });
- if (validChange) {
- _addAssistFromBuilder(changeBuilder, DartAssistKind.ADD_TYPE_ANNOTATION);
- }
- }
-
- Future<void> _addProposal_addTypeAnnotation_SimpleFormalParameter() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
- AstNode node = this.node;
- // should be the name of a simple parameter
- if (node is! SimpleIdentifier || node.parent is! SimpleFormalParameter) {
- _coverageMarker();
- return;
- }
- SimpleIdentifier name = node;
- SimpleFormalParameter parameter = node.parent;
- // the parameter should not have a type
- if (parameter.type != null) {
- _coverageMarker();
- return;
- }
- // prepare the type
- DartType type = parameter.declaredElement.type;
- // TODO(scheglov) If the parameter is in a method declaration, and if the
- // method overrides a method that has a type for the corresponding
- // parameter, it would be nice to copy down the type from the overridden
- // method.
- if (type is! InterfaceType) {
- _coverageMarker();
- return;
- }
- // prepare type source
- _configureTargetLocation(node);
-
- var changeBuilder = _newDartChangeBuilder();
- bool validChange = true;
- await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
- builder.addInsertion(name.offset, (DartEditBuilder builder) {
- validChange = builder.writeType(type);
- builder.write(' ');
- });
- });
- if (validChange) {
- _addAssistFromBuilder(changeBuilder, DartAssistKind.ADD_TYPE_ANNOTATION);
- }
- }
-
- Future<void> _addProposal_addTypeAnnotation_VariableDeclaration() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
- AstNode node = this.node;
- // prepare VariableDeclarationList
- VariableDeclarationList declarationList =
- node.thisOrAncestorOfType<VariableDeclarationList>();
- if (declarationList == null) {
- _coverageMarker();
- return;
- }
- // may be has type annotation already
- if (declarationList.type != null) {
- _coverageMarker();
- return;
- }
- // prepare single VariableDeclaration
- List<VariableDeclaration> variables = declarationList.variables;
- if (variables.length != 1) {
- _coverageMarker();
- return;
- }
- VariableDeclaration variable = variables[0];
- // must be not after the name of the variable
- if (selectionOffset > variable.name.end) {
- _coverageMarker();
- return;
- }
- // we need an initializer to get the type from
- Expression initializer = variable.initializer;
- if (initializer == null) {
- _coverageMarker();
- return;
- }
- DartType type = initializer.staticType;
- // prepare type source
- if ((type is! InterfaceType || type.isDartCoreNull) &&
- type is! FunctionType) {
- _coverageMarker();
- return;
- }
- _configureTargetLocation(node);
-
- var changeBuilder = _newDartChangeBuilder();
- bool validChange = true;
- await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
- Token keyword = declarationList.keyword;
- if (keyword?.keyword == Keyword.VAR) {
- builder.addReplacement(range.token(keyword), (DartEditBuilder builder) {
- validChange = builder.writeType(type);
- });
- } else {
- builder.addInsertion(variable.offset, (DartEditBuilder builder) {
- validChange = builder.writeType(type);
- builder.write(' ');
- });
- }
- });
- if (validChange) {
- _addAssistFromBuilder(changeBuilder, DartAssistKind.ADD_TYPE_ANNOTATION);
- }
- }
-
Future<void> _addProposal_assignToLocalVariable() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
// prepare enclosing ExpressionStatement
ExpressionStatement expressionStatement;
for (AstNode node = this.node; node != null; node = node.parent) {
@@ -585,43 +388,12 @@
}
Future<void> _addProposal_convertConditionalExpressionToIfElement() async {
- AstNode node = this.node.thisOrAncestorOfType<ConditionalExpression>();
- if (node == null) {
- _coverageMarker();
- return;
- }
- AstNode nodeToReplace = node;
- AstNode parent = node.parent;
- while (parent is ParenthesizedExpression) {
- nodeToReplace = parent;
- parent = parent.parent;
- }
- if (parent is ListLiteral || (parent is SetOrMapLiteral && parent.isSet)) {
- ConditionalExpression conditional = node;
- Expression condition = conditional.condition.unParenthesized;
- Expression thenExpression = conditional.thenExpression.unParenthesized;
- Expression elseExpression = conditional.elseExpression.unParenthesized;
-
- DartChangeBuilder changeBuilder = _newDartChangeBuilder();
- await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
- builder.addReplacement(range.node(nodeToReplace),
- (DartEditBuilder builder) {
- builder.write('if (');
- builder.write(utils.getNodeText(condition));
- builder.write(') ');
- builder.write(utils.getNodeText(thenExpression));
- builder.write(' else ');
- builder.write(utils.getNodeText(elseExpression));
- });
- });
- _addAssistFromBuilder(
- changeBuilder, DartAssistKind.CONVERT_TO_IF_ELEMENT);
- }
+ final changeBuilder =
+ await createBuilder_convertConditionalExpressionToIfElement();
+ _addAssistFromBuilder(changeBuilder, DartAssistKind.CONVERT_TO_IF_ELEMENT);
}
Future<void> _addProposal_convertDocumentationIntoBlock() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
Comment comment = node.thisOrAncestorOfType<Comment>();
if (comment == null || !comment.isDocumentation) {
return;
@@ -653,73 +425,12 @@
}
Future<void> _addProposal_convertDocumentationIntoLine() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
- Comment comment = node.thisOrAncestorOfType<Comment>();
- if (comment == null ||
- !comment.isDocumentation ||
- comment.tokens.length != 1) {
- _coverageMarker();
- return;
- }
- Token token = comment.tokens.first;
- if (token.type != TokenType.MULTI_LINE_COMMENT) {
- _coverageMarker();
- return;
- }
- String text = token.lexeme;
- List<String> lines = text.split('\n');
- String prefix = utils.getNodePrefix(comment);
- List<String> newLines = <String>[];
- bool firstLine = true;
- String linePrefix = '';
- for (String line in lines) {
- if (firstLine) {
- firstLine = false;
- String expectedPrefix = '/**';
- if (!line.startsWith(expectedPrefix)) {
- _coverageMarker();
- return;
- }
- line = line.substring(expectedPrefix.length).trim();
- if (line.isNotEmpty) {
- newLines.add('/// $line');
- linePrefix = eol + prefix;
- }
- } else {
- if (line.startsWith(prefix + ' */')) {
- break;
- }
- String expectedPrefix = prefix + ' *';
- if (!line.startsWith(expectedPrefix)) {
- _coverageMarker();
- return;
- }
- line = line.substring(expectedPrefix.length);
- if (line.isEmpty) {
- newLines.add('$linePrefix///');
- } else {
- newLines.add('$linePrefix///$line');
- }
- linePrefix = eol + prefix;
- }
- }
-
- var changeBuilder = _newDartChangeBuilder();
- await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
- builder.addReplacement(range.node(comment), (DartEditBuilder builder) {
- for (String newLine in newLines) {
- builder.write(newLine);
- }
- });
- });
+ final changeBuilder = await createBuilder_convertDocumentationIntoLine();
_addAssistFromBuilder(
changeBuilder, DartAssistKind.CONVERT_DOCUMENTATION_INTO_LINE);
}
Future<void> _addProposal_convertIntoFinalField() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
// Find the enclosing getter.
MethodDeclaration getter;
for (AstNode n = node; n != null; n = n.parent) {
@@ -789,8 +500,6 @@
}
Future<void> _addProposal_convertIntoGetter() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
// Find the enclosing field declaration.
FieldDeclaration fieldDeclaration;
for (AstNode n = node; n != null; n = n.parent) {
@@ -962,166 +671,12 @@
}
Future<void> _addProposal_convertMapFromIterableToForLiteral() async {
- //
- // Ensure that the selection is inside an invocation of Map.fromIterable.
- //
- InstanceCreationExpression creation =
- node.thisOrAncestorOfType<InstanceCreationExpression>();
- if (creation == null) {
- _coverageMarker();
- return;
- }
- ConstructorElement element = creation.staticElement;
- if (element == null ||
- element.name != 'fromIterable' ||
- element.enclosingElement != typeProvider.mapType.element) {
- _coverageMarker();
- return;
- }
- //
- // Ensure that the arguments have the right form.
- //
- NodeList<Expression> arguments = creation.argumentList.arguments;
- if (arguments.length != 3) {
- _coverageMarker();
- return;
- }
- Expression iterator = arguments[0].unParenthesized;
- Expression secondArg = arguments[1];
- Expression thirdArg = arguments[2];
-
- Expression extractBody(FunctionExpression expression) {
- FunctionBody body = expression.body;
- if (body is ExpressionFunctionBody) {
- return body.expression;
- } else if (body is BlockFunctionBody) {
- NodeList<Statement> statements = body.block.statements;
- if (statements.length == 1) {
- Statement statement = statements[0];
- if (statement is ReturnStatement) {
- return statement.expression;
- }
- }
- }
- return null;
- }
-
- FunctionExpression extractClosure(String name, Expression argument) {
- if (argument is NamedExpression && argument.name.label.name == name) {
- Expression expression = argument.expression.unParenthesized;
- if (expression is FunctionExpression) {
- NodeList<FormalParameter> parameters =
- expression.parameters.parameters;
- if (parameters.length == 1 && parameters[0].isRequiredPositional) {
- if (extractBody(expression) != null) {
- return expression;
- }
- }
- }
- }
- return null;
- }
-
- FunctionExpression keyClosure =
- extractClosure('key', secondArg) ?? extractClosure('key', thirdArg);
- FunctionExpression valueClosure =
- extractClosure('value', thirdArg) ?? extractClosure('value', secondArg);
- if (keyClosure == null || valueClosure == null) {
- _coverageMarker();
- return;
- }
- //
- // Compute the loop variable name and convert the key and value closures if
- // necessary.
- //
- SimpleFormalParameter keyParameter = keyClosure.parameters.parameters[0];
- String keyParameterName = keyParameter.identifier.name;
- SimpleFormalParameter valueParameter =
- valueClosure.parameters.parameters[0];
- String valueParameterName = valueParameter.identifier.name;
- Expression keyBody = extractBody(keyClosure);
- String keyExpressionText = utils.getNodeText(keyBody);
- Expression valueBody = extractBody(valueClosure);
- String valueExpressionText = utils.getNodeText(valueBody);
-
- String loopVariableName;
- if (keyParameterName == valueParameterName) {
- loopVariableName = keyParameterName;
- } else {
- _ParameterReferenceFinder keyFinder =
- new _ParameterReferenceFinder(keyParameter.declaredElement);
- keyBody.accept(keyFinder);
-
- _ParameterReferenceFinder valueFinder =
- new _ParameterReferenceFinder(valueParameter.declaredElement);
- valueBody.accept(valueFinder);
-
- String computeUnusedVariableName() {
- String candidate = 'e';
- var index = 1;
- while (keyFinder.referencesName(candidate) ||
- valueFinder.referencesName(candidate)) {
- candidate = 'e${index++}';
- }
- return candidate;
- }
-
- if (valueFinder.isParameterUnreferenced) {
- if (valueFinder.referencesName(keyParameterName)) {
- // The name of the value parameter is not used, but we can't use the
- // name of the key parameter because doing so would hide a variable
- // referenced in the value expression.
- loopVariableName = computeUnusedVariableName();
- keyExpressionText = keyFinder.replaceName(
- keyExpressionText, loopVariableName, keyBody.offset);
- } else {
- loopVariableName = keyParameterName;
- }
- } else if (keyFinder.isParameterUnreferenced) {
- if (keyFinder.referencesName(valueParameterName)) {
- // The name of the key parameter is not used, but we can't use the
- // name of the value parameter because doing so would hide a variable
- // referenced in the key expression.
- loopVariableName = computeUnusedVariableName();
- valueExpressionText = valueFinder.replaceName(
- valueExpressionText, loopVariableName, valueBody.offset);
- } else {
- loopVariableName = valueParameterName;
- }
- } else {
- // The names are different and both are used. We need to find a name
- // that would not change the resolution of any other identifiers in
- // either the key or value expressions.
- loopVariableName = computeUnusedVariableName();
- keyExpressionText = keyFinder.replaceName(
- keyExpressionText, loopVariableName, keyBody.offset);
- valueExpressionText = valueFinder.replaceName(
- valueExpressionText, loopVariableName, valueBody.offset);
- }
- }
- //
- // Construct the edit.
- //
- DartChangeBuilder changeBuilder = _newDartChangeBuilder();
- await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
- builder.addReplacement(range.node(creation), (DartEditBuilder builder) {
- builder.write('{ for (var ');
- builder.write(loopVariableName);
- builder.write(' in ');
- builder.write(utils.getNodeText(iterator));
- builder.write(') ');
- builder.write(keyExpressionText);
- builder.write(' : ');
- builder.write(valueExpressionText);
- builder.write(' }');
- });
- });
+ final changeBuilder =
+ await createBuilder_convertMapFromIterableToForLiteral();
_addAssistFromBuilder(changeBuilder, DartAssistKind.CONVERT_TO_FOR_ELEMENT);
}
Future<void> _addProposal_convertPartOfToUri() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
PartOfDirective directive = node.thisOrAncestorOfType<PartOfDirective>();
if (directive == null || directive.libraryName == null) {
return;
@@ -1267,8 +822,6 @@
}
Future<void> _addProposal_convertToBlockFunctionBody() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
FunctionBody body = getEnclosingFunctionBody();
// prepare expression body
if (body is! ExpressionFunctionBody || body.isGenerator) {
@@ -1312,67 +865,16 @@
}
Future<void> _addProposal_convertToDoubleQuotedString() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
await _convertQuotes(false, DartAssistKind.CONVERT_TO_DOUBLE_QUOTED_STRING);
}
Future<void> _addProposal_convertToExpressionFunctionBody() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
- // prepare current body
- FunctionBody body = getEnclosingFunctionBody();
- if (body is! BlockFunctionBody || body.isGenerator) {
- _coverageMarker();
- return;
- }
- // prepare return statement
- List<Statement> statements = (body as BlockFunctionBody).block.statements;
- if (statements.length != 1) {
- _coverageMarker();
- return;
- }
- Statement onlyStatement = statements.first;
- // prepare returned expression
- Expression returnExpression;
- if (onlyStatement is ReturnStatement) {
- returnExpression = onlyStatement.expression;
- } else if (onlyStatement is ExpressionStatement) {
- returnExpression = onlyStatement.expression;
- }
- if (returnExpression == null) {
- _coverageMarker();
- return;
- }
-
- // Return expressions can be quite large, e.g. Flutter build() methods.
- // It is surprising to see this Quick Assist deep in the function body.
- if (selectionOffset >= returnExpression.offset) {
- _coverageMarker();
- return;
- }
-
- var changeBuilder = _newDartChangeBuilder();
- await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
- builder.addReplacement(range.node(body), (DartEditBuilder builder) {
- if (body.isAsynchronous) {
- builder.write('async ');
- }
- builder.write('=> ');
- builder.write(_getNodeText(returnExpression));
- if (body.parent is! FunctionExpression ||
- body.parent.parent is FunctionDeclaration) {
- builder.write(';');
- }
- });
- });
+ final changeBuilder = await createBuilder_convertToExpressionFunctionBody();
_addAssistFromBuilder(
changeBuilder, DartAssistKind.CONVERT_INTO_EXPRESSION_BODY);
}
Future<void> _addProposal_convertToFieldParameter() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (node == null) {
return;
}
@@ -1465,8 +967,6 @@
}
Future<void> _addProposal_convertToForIndexLoop() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
// find enclosing ForEachStatement
ForStatement forEachStatement = node.thisOrAncestorMatching(
(node) => node is ForStatement && node.forLoopParts is ForEachParts);
@@ -1549,8 +1049,6 @@
}
Future<void> _addProposal_convertToGenericFunctionSyntax() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
AstNode node = this.node;
while (node != null) {
if (node is FunctionTypeAlias) {
@@ -1569,35 +1067,11 @@
}
Future<void> _addProposal_convertToIntLiteral() async {
- if (node is! DoubleLiteral) {
- _coverageMarker();
- return;
- }
- DoubleLiteral literal = node;
- int intValue;
- try {
- intValue = literal.value?.truncate();
- } catch (e) {
- // Double cannot be converted to int
- }
- if (intValue == null || intValue != literal.value) {
- _coverageMarker();
- return;
- }
-
- var changeBuilder = _newDartChangeBuilder();
- await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
- builder.addReplacement(new SourceRange(literal.offset, literal.length),
- (DartEditBuilder builder) {
- builder.write('$intValue');
- });
- });
+ final changeBuilder = await createBuilder_convertToIntLiteral();
_addAssistFromBuilder(changeBuilder, DartAssistKind.CONVERT_TO_INT_LITERAL);
}
Future<void> _addProposal_convertToIsNot_onIs() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
// may be child of "is"
AstNode node = this.node;
while (node != null && node is! IsExpression) {
@@ -1649,8 +1123,6 @@
}
Future<void> _addProposal_convertToIsNot_onNot() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
// may be () in prefix expression
AstNode node = this.node;
if (node is ParenthesizedExpression && node.parent is PrefixExpression) {
@@ -1706,8 +1178,6 @@
* Converts "!isEmpty" -> "isNotEmpty" if possible.
*/
Future<void> _addProposal_convertToIsNotEmpty() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
// prepare "expr.isEmpty"
AstNode isEmptyAccess = null;
SimpleIdentifier isEmptyIdentifier = null;
@@ -1796,8 +1266,6 @@
}
Future<void> _addProposal_convertToNormalParameter() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (node is SimpleIdentifier &&
node.parent is FieldFormalParameter &&
node.parent.parent is FormalParameterList &&
@@ -1837,92 +1305,8 @@
}
Future<void> _addProposal_convertToNullAware() async {
- AstNode node = this.node;
- if (node is! ConditionalExpression) {
- _coverageMarker();
- return;
- }
- ConditionalExpression conditional = node;
- Expression condition = conditional.condition.unParenthesized;
- SimpleIdentifier identifier;
- Expression nullExpression;
- Expression nonNullExpression;
- int periodOffset;
-
- if (condition is BinaryExpression) {
- //
- // Identify the variable being compared to `null`, or return if the
- // condition isn't a simple comparison of `null` to a variable's value.
- //
- Expression leftOperand = condition.leftOperand;
- Expression rightOperand = condition.rightOperand;
- if (leftOperand is NullLiteral && rightOperand is SimpleIdentifier) {
- identifier = rightOperand;
- } else if (rightOperand is NullLiteral &&
- leftOperand is SimpleIdentifier) {
- identifier = leftOperand;
- } else {
- _coverageMarker();
- return;
- }
- if (identifier.staticElement is! LocalElement) {
- _coverageMarker();
- return;
- }
- //
- // Identify the expression executed when the variable is `null` and when
- // it is non-`null`. Return if the `null` expression isn't a null literal
- // or if the non-`null` expression isn't a method invocation whose target
- // is the save variable being compared to `null`.
- //
- if (condition.operator.type == TokenType.EQ_EQ) {
- nullExpression = conditional.thenExpression;
- nonNullExpression = conditional.elseExpression;
- } else if (condition.operator.type == TokenType.BANG_EQ) {
- nonNullExpression = conditional.thenExpression;
- nullExpression = conditional.elseExpression;
- }
- if (nullExpression == null || nonNullExpression == null) {
- _coverageMarker();
- return;
- }
- if (nullExpression.unParenthesized is! NullLiteral) {
- _coverageMarker();
- return;
- }
- Expression unwrappedExpression = nonNullExpression.unParenthesized;
- Expression target;
- Token operator;
- if (unwrappedExpression is MethodInvocation) {
- target = unwrappedExpression.target;
- operator = unwrappedExpression.operator;
- } else if (unwrappedExpression is PrefixedIdentifier) {
- target = unwrappedExpression.prefix;
- operator = unwrappedExpression.period;
- } else {
- _coverageMarker();
- return;
- }
- if (operator.type != TokenType.PERIOD) {
- _coverageMarker();
- return;
- }
- if (!(target is SimpleIdentifier &&
- target.staticElement == identifier.staticElement)) {
- _coverageMarker();
- return;
- }
- periodOffset = operator.offset;
-
- DartChangeBuilder changeBuilder = _newDartChangeBuilder();
- await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
- builder.addDeletion(range.startStart(node, nonNullExpression));
- builder.addSimpleInsertion(periodOffset, '?');
- builder.addDeletion(range.endEnd(nonNullExpression, node));
- });
- _addAssistFromBuilder(
- changeBuilder, DartAssistKind.CONVERT_TO_NULL_AWARE);
- }
+ final changeBuilder = await createBuilder_convertToNullAware();
+ _addAssistFromBuilder(changeBuilder, DartAssistKind.CONVERT_TO_NULL_AWARE);
}
Future<void> _addProposal_convertToPackageImport() async {
@@ -1968,14 +1352,10 @@
}
Future<void> _addProposal_convertToSingleQuotedString() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
await _convertQuotes(true, DartAssistKind.CONVERT_TO_SINGLE_QUOTED_STRING);
}
Future<void> _addProposal_encapsulateField() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
// find FieldDeclaration
FieldDeclaration fieldDeclaration =
node.thisOrAncestorOfType<FieldDeclaration>();
@@ -2075,8 +1455,6 @@
}
Future<void> _addProposal_exchangeOperands() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
// check that user invokes quick assist on binary expression
if (node is! BinaryExpression) {
_coverageMarker();
@@ -2132,8 +1510,6 @@
}
Future<void> _addProposal_flutterConvertToChildren() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
// Find "child: widget" under selection.
NamedExpression namedExp;
{
@@ -2401,8 +1777,6 @@
}
Future<void> _addProposal_flutterMoveWidgetDown() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
var widget = flutter.identifyWidgetExpression(node);
if (widget == null) {
return;
@@ -2435,8 +1809,6 @@
}
Future<void> _addProposal_flutterMoveWidgetUp() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
var widget = flutter.identifyWidgetExpression(node);
if (widget == null) {
return;
@@ -2468,8 +1840,6 @@
}
Future<void> _addProposal_flutterRemoveWidget_multipleChildren() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
var widgetCreation = flutter.identifyNewExpression(node);
if (widgetCreation == null) {
return;
@@ -2508,8 +1878,6 @@
}
Future<void> _addProposal_flutterRemoveWidget_singleChild() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
var widgetCreation = flutter.identifyNewExpression(node);
if (widgetCreation == null) {
return;
@@ -2535,8 +1903,6 @@
}
Future<void> _addProposal_flutterSwapWithChild() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
InstanceCreationExpression parent = flutter.identifyNewExpression(node);
if (!flutter.isWidgetCreation(parent)) {
_coverageMarker();
@@ -2556,8 +1922,6 @@
}
Future<void> _addProposal_flutterSwapWithParent() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
InstanceCreationExpression child = flutter.identifyNewExpression(node);
if (!flutter.isWidgetCreation(child)) {
_coverageMarker();
@@ -2635,8 +1999,6 @@
}
Future<void> _addProposal_flutterWrapWidget() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
await _addProposal_flutterWrapWidgetImpl();
await _addProposal_flutterWrapWidgetImpl(
kind: DartAssistKind.FLUTTER_WRAP_CENTER,
@@ -2668,8 +2030,6 @@
String parentLibraryUri,
String parentClassName,
List<String> leadingLines = const []}) async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
Expression widgetExpr = flutter.identifyWidgetExpression(node);
if (widgetExpr == null) {
_coverageMarker();
@@ -2730,8 +2090,6 @@
}
Future<void> _addProposal_flutterWrapWidgets() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
var selectionRange = new SourceRange(selectionOffset, selectionLength);
var analyzer = new SelectionAnalyzer(selectionRange);
context.resolveResult.unit.accept(analyzer);
@@ -2763,8 +2121,6 @@
{@required AssistKind kind,
@required String parentLibraryUri,
@required String parentClassName}) async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
ClassElement parentClassElement =
await sessionHelper.getClass(parentLibraryUri, parentClassName);
ClassElement widgetClassElement =
@@ -2819,8 +2175,6 @@
}
Future<void> _addProposal_importAddShow() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
// prepare ImportDirective
ImportDirective importDirective =
node.thisOrAncestorOfType<ImportDirective>();
@@ -2906,8 +2260,6 @@
}
Future<void> _addProposal_introduceLocalTestedType() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
AstNode node = this.node;
if (node is IfStatement) {
node = (node as IfStatement).condition;
@@ -2979,8 +2331,6 @@
}
Future<void> _addProposal_invertIf() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (node is! IfStatement) {
return;
}
@@ -3007,8 +2357,6 @@
}
Future<void> _addProposal_joinIfStatementInner() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
// climb up condition to the (supposedly) "if" statement
AstNode node = this.node;
while (node is Expression) {
@@ -3069,8 +2417,6 @@
}
Future<void> _addProposal_joinIfStatementOuter() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
// climb up condition to the (supposedly) "if" statement
AstNode node = this.node;
while (node is Expression) {
@@ -3135,8 +2481,6 @@
}
Future<void> _addProposal_joinVariableDeclaration_onAssignment() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
// check that node is LHS in assignment
if (node is SimpleIdentifier &&
node.parent is AssignmentExpression &&
@@ -3213,8 +2557,6 @@
}
Future<void> _addProposal_joinVariableDeclaration_onDeclaration() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
// prepare enclosing VariableDeclarationList
VariableDeclarationList declList =
node.thisOrAncestorOfType<VariableDeclarationList>();
@@ -3283,8 +2625,6 @@
}
Future<void> _addProposal_removeTypeAnnotation() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
VariableDeclarationList declarationList =
node.thisOrAncestorOfType<VariableDeclarationList>();
if (declarationList == null) {
@@ -3329,8 +2669,6 @@
}
Future<void> _addProposal_reparentFlutterList() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (node is! ListLiteral) {
return;
}
@@ -3377,8 +2715,6 @@
}
Future<void> _addProposal_replaceConditionalWithIfElse() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
ConditionalExpression conditional = null;
// may be on Statement with Conditional
Statement statement = node.thisOrAncestorOfType<Statement>();
@@ -3483,8 +2819,6 @@
}
Future<void> _addProposal_replaceIfElseWithConditional() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
// should be "if"
if (node is! IfStatement) {
_coverageMarker();
@@ -3592,8 +2926,6 @@
}
Future<void> _addProposal_splitAndCondition() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
// check that user invokes quick assist on binary expression
if (node is! BinaryExpression) {
_coverageMarker();
@@ -3733,8 +3065,6 @@
}
Future<void> _addProposal_surroundWith() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
// prepare selected statements
List<Statement> selectedStatements;
{
@@ -3949,129 +3279,21 @@
}
Future<void> _addProposal_useCurlyBraces() async {
- Future<void> doStatement(DoStatement node) async {
- var body = node.body;
- if (body is Block) return;
+ final changeBuilder = await createBuilder_useCurlyBraces();
+ _addAssistFromBuilder(changeBuilder, DartAssistKind.USE_CURLY_BRACES);
+ }
- var prefix = utils.getLinePrefix(node.offset);
- var indent = prefix + utils.getIndent(1);
+ Future<void> _addProposals_addTypeAnnotation() async {
+ var changeBuilder =
+ await createBuilder_addTypeAnnotation_DeclaredIdentifier();
+ _addAssistFromBuilder(changeBuilder, DartAssistKind.ADD_TYPE_ANNOTATION);
- var changeBuilder = _newDartChangeBuilder();
- await changeBuilder.addFileEdit(file, (builder) {
- builder.addSimpleReplacement(
- range.endStart(node.doKeyword, body),
- ' {$eol$indent',
- );
- builder.addSimpleReplacement(
- range.endStart(body, node.whileKeyword),
- '$eol$prefix} ',
- );
- });
+ changeBuilder =
+ await createBuilder_addTypeAnnotation_SimpleFormalParameter();
+ _addAssistFromBuilder(changeBuilder, DartAssistKind.ADD_TYPE_ANNOTATION);
- _addAssistFromBuilder(changeBuilder, DartAssistKind.USE_CURLY_BRACES);
- }
-
- Future<void> forStatement(ForStatement node) async {
- var body = node.body;
- if (body is Block) return;
-
- var prefix = utils.getLinePrefix(node.offset);
- var indent = prefix + utils.getIndent(1);
-
- var changeBuilder = _newDartChangeBuilder();
- await changeBuilder.addFileEdit(file, (builder) {
- builder.addSimpleReplacement(
- range.endStart(node.rightParenthesis, body),
- ' {$eol$indent',
- );
- builder.addSimpleInsertion(body.end, '$eol$prefix}');
- });
-
- _addAssistFromBuilder(changeBuilder, DartAssistKind.USE_CURLY_BRACES);
- }
-
- Future<void> ifStatement(IfStatement node, Statement thenOrElse) async {
- var prefix = utils.getLinePrefix(node.offset);
- var indent = prefix + utils.getIndent(1);
-
- var changeBuilder = _newDartChangeBuilder();
- await changeBuilder.addFileEdit(file, (builder) {
- var thenStatement = node.thenStatement;
- if (thenStatement is! Block &&
- (thenOrElse == null || thenOrElse == thenStatement)) {
- builder.addSimpleReplacement(
- range.endStart(node.rightParenthesis, thenStatement),
- ' {$eol$indent',
- );
- if (node.elseKeyword != null) {
- builder.addSimpleReplacement(
- range.endStart(thenStatement, node.elseKeyword),
- '$eol$prefix} ',
- );
- } else {
- builder.addSimpleInsertion(thenStatement.end, '$eol$prefix}');
- }
- }
-
- var elseStatement = node.elseStatement;
- if (elseStatement != null &&
- elseStatement is! Block &&
- (thenOrElse == null || thenOrElse == elseStatement)) {
- builder.addSimpleReplacement(
- range.endStart(node.elseKeyword, elseStatement),
- ' {$eol$indent',
- );
- builder.addSimpleInsertion(elseStatement.end, '$eol$prefix}');
- }
- });
-
- _addAssistFromBuilder(changeBuilder, DartAssistKind.USE_CURLY_BRACES);
- }
-
- Future<void> whileStatement(WhileStatement node) async {
- var body = node.body;
- if (body is Block) return;
-
- var prefix = utils.getLinePrefix(node.offset);
- var indent = prefix + utils.getIndent(1);
-
- var changeBuilder = _newDartChangeBuilder();
- await changeBuilder.addFileEdit(file, (builder) {
- builder.addSimpleReplacement(
- range.endStart(node.rightParenthesis, body),
- ' {$eol$indent',
- );
- builder.addSimpleInsertion(body.end, '$eol$prefix}');
- });
-
- _addAssistFromBuilder(changeBuilder, DartAssistKind.USE_CURLY_BRACES);
- }
-
- var statement = this.node.thisOrAncestorOfType<Statement>();
- var parent = statement?.parent;
-
- if (statement is DoStatement) {
- return doStatement(statement);
- } else if (parent is DoStatement) {
- return doStatement(parent);
- } else if (statement is ForStatement) {
- return forStatement(statement);
- } else if (parent is ForStatement) {
- return forStatement(parent);
- } else if (statement is IfStatement) {
- if (statement.elseKeyword != null &&
- range.token(statement.elseKeyword).contains(selectionOffset)) {
- return ifStatement(statement, statement.elseStatement);
- } else {
- return ifStatement(statement, null);
- }
- } else if (parent is IfStatement) {
- return ifStatement(parent, statement);
- } else if (statement is WhileStatement) {
- return whileStatement(statement);
- } else if (parent is WhileStatement) {
- return whileStatement(parent);
- }
+ changeBuilder = await createBuilder_addTypeAnnotation_VariableDeclaration();
+ _addAssistFromBuilder(changeBuilder, DartAssistKind.ADD_TYPE_ANNOTATION);
}
/**
@@ -4094,18 +3316,20 @@
return true;
}
- /**
- * Configures [utils] using given [target].
- */
- void _configureTargetLocation(Object target) {
- utils.targetClassElement = null;
- if (target is AstNode) {
- ClassDeclaration targetClassDeclaration =
- target.thisOrAncestorOfType<ClassDeclaration>();
- if (targetClassDeclaration != null) {
- utils.targetClassElement = targetClassDeclaration.declaredElement;
+ bool _containsErrorCode(Set<String> errorCodes) {
+ final fileOffset = node.offset;
+ for (var error in context.resolveResult.errors) {
+ final errorSource = error.source;
+ if (file == errorSource.fullName) {
+ if (fileOffset >= error.offset &&
+ fileOffset <= error.offset + error.length) {
+ if (errorCodes.contains(error.errorCode.name)) {
+ return true;
+ }
+ }
}
}
+ return false;
}
void _convertFlutterChildToChildren(
@@ -4153,8 +3377,6 @@
Future<void> _convertFunctionTypeAliasToGenericTypeAlias(
FunctionTypeAlias node) async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (!_allParametersHaveTypes(node.parameters)) {
return;
}
@@ -4184,8 +3406,6 @@
Future<void> _convertFunctionTypedFormalParameterToSimpleFormalParameter(
FunctionTypedFormalParameter node) async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (!_allParametersHaveTypes(node.parameters)) {
return;
}
@@ -4212,8 +3432,6 @@
}
Future<void> _convertQuotes(bool fromDouble, AssistKind kind) async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (node is SimpleStringLiteral) {
SimpleStringLiteral literal = node;
if (fromDouble ? !literal.isSingleQuoted : literal.isSingleQuoted) {
@@ -4313,16 +3531,8 @@
return new DartChangeBuilderImpl.forWorkspace(context.workspace);
}
- bool _setupCompute() {
- var locator = new NodeLocator(selectionOffset, selectionEnd);
- node = locator.searchWithin(context.resolveResult.unit);
- return node != null;
- }
-
Future<void> _swapParentAndChild(InstanceCreationExpression parent,
InstanceCreationExpression child, AssistKind kind) async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
// The child must have its own child.
if (flutter.findChildArgument(child) == null) {
_coverageMarker();
@@ -4457,70 +3667,6 @@
}
}
-/**
- * A visitor that can be used to find references to a parameter.
- */
-class _ParameterReferenceFinder extends RecursiveAstVisitor<void> {
- /**
- * The parameter for which references are being sought, or `null` if we are
- * just accumulating a list of referenced names.
- */
- final ParameterElement parameter;
-
- /**
- * A list of the simple identifiers that reference the [parameter].
- */
- final List<SimpleIdentifier> references = <SimpleIdentifier>[];
-
- /**
- * A collection of the names of other simple identifiers that were found. We
- * need to know these in order to ensure that the selected loop variable does
- * not hide a name from an enclosing scope that is already being referenced.
- */
- final Set<String> otherNames = new Set<String>();
-
- /**
- * Initialize a newly created finder to find references to the [parameter].
- */
- _ParameterReferenceFinder(this.parameter) : assert(parameter != null);
-
- /**
- * Return `true` if the parameter is unreferenced in the nodes that have been
- * visited.
- */
- bool get isParameterUnreferenced => references.isEmpty;
-
- /**
- * Return `true` is the given name (assumed to be different than the name of
- * the parameter) is references in the nodes that have been visited.
- */
- bool referencesName(String name) => otherNames.contains(name);
-
- /**
- * Replace all of the references to the parameter in the given [source] with
- * the [newName]. The [offset] is the offset of the first character of the
- * [source] relative to the start of the file.
- */
- String replaceName(String source, String newName, int offset) {
- int oldLength = parameter.name.length;
- for (int i = references.length - 1; i >= 0; i--) {
- int oldOffset = references[i].offset - offset;
- source = source.replaceRange(oldOffset, oldOffset + oldLength, newName);
- }
- return source;
- }
-
- @override
- void visitSimpleIdentifier(SimpleIdentifier node) {
- if (node.staticElement == parameter) {
- references.add(node);
- } else if (!node.isQualified) {
- // Only non-prefixed identifiers can be hidden.
- otherNames.add(node.name);
- }
- }
-}
-
class _SimpleIdentifierRecursiveAstVisitor extends RecursiveAstVisitor {
final _SimpleIdentifierVisitor visitor;
diff --git a/pkg/analysis_server/lib/src/services/correction/base_processor.dart b/pkg/analysis_server/lib/src/services/correction/base_processor.dart
new file mode 100644
index 0000000..a67b7ca
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/correction/base_processor.dart
@@ -0,0 +1,882 @@
+// Copyright (c) 2019, 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/util.dart';
+import 'package:analysis_server/src/utilities/flutter.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/dart/ast/token.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/source/source_range.dart';
+import 'package:analyzer/src/dart/analysis/experiments.dart';
+import 'package:analyzer/src/dart/analysis/session_helper.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
+import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
+import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer_plugin/src/utilities/change_builder/change_builder_dart.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_workspace.dart';
+import 'package:analyzer_plugin/utilities/range_factory.dart';
+import 'package:meta/meta.dart';
+
+/// Base class for common processor functionality.
+abstract class BaseProcessor {
+ final int selectionOffset;
+ final int selectionLength;
+ final int selectionEnd;
+
+ final CorrectionUtils utils;
+ final String file;
+
+ final TypeProvider typeProvider;
+ final Flutter flutter;
+
+ final AnalysisSession session;
+ final AnalysisSessionHelper sessionHelper;
+ final ResolvedUnitResult resolvedResult;
+ final ChangeWorkspace workspace;
+
+ AstNode node;
+
+ BaseProcessor({
+ this.selectionOffset = -1,
+ this.selectionLength = 0,
+ @required this.resolvedResult,
+ @required this.workspace,
+ }) : file = resolvedResult.path,
+ flutter = Flutter.of(resolvedResult),
+ session = resolvedResult.session,
+ sessionHelper = AnalysisSessionHelper(resolvedResult.session),
+ typeProvider = resolvedResult.typeProvider,
+ selectionEnd = (selectionOffset ?? 0) + (selectionLength ?? 0),
+ utils = CorrectionUtils(resolvedResult);
+
+ /// Returns the EOL to use for this [CompilationUnit].
+ String get eol => utils.endOfLine;
+
+ /// Return the status of known experiments.
+ ExperimentStatus get experimentStatus =>
+ (session.analysisContext.analysisOptions as AnalysisOptionsImpl)
+ .experimentStatus;
+
+ Future<ChangeBuilder>
+ createBuilder_addTypeAnnotation_DeclaredIdentifier() async {
+ DeclaredIdentifier declaredIdentifier =
+ node.thisOrAncestorOfType<DeclaredIdentifier>();
+ if (declaredIdentifier == null) {
+ ForStatement forEach = node.thisOrAncestorMatching(
+ (node) => node is ForStatement && node.forLoopParts is ForEachParts);
+ ForEachParts forEachParts = forEach?.forLoopParts;
+ int offset = node.offset;
+ if (forEach != null &&
+ forEachParts.iterable != null &&
+ offset < forEachParts.iterable.offset) {
+ declaredIdentifier = forEachParts is ForEachPartsWithDeclaration
+ ? forEachParts.loopVariable
+ : null;
+ }
+ }
+ if (declaredIdentifier == null) {
+ _coverageMarker();
+ return null;
+ }
+ // Ensure that there isn't already a type annotation.
+ if (declaredIdentifier.type != null) {
+ _coverageMarker();
+ return null;
+ }
+ DartType type = declaredIdentifier.identifier.staticType;
+ if (type is! InterfaceType && type is! FunctionType) {
+ _coverageMarker();
+ return null;
+ }
+ _configureTargetLocation(node);
+
+ var changeBuilder = _newDartChangeBuilder();
+ bool validChange = true;
+ await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+ Token keyword = declaredIdentifier.keyword;
+ if (keyword.keyword == Keyword.VAR) {
+ builder.addReplacement(range.token(keyword), (DartEditBuilder builder) {
+ validChange = builder.writeType(type);
+ });
+ } else {
+ builder.addInsertion(declaredIdentifier.identifier.offset,
+ (DartEditBuilder builder) {
+ validChange = builder.writeType(type);
+ builder.write(' ');
+ });
+ }
+ });
+ return validChange ? changeBuilder : null;
+ }
+
+ Future<ChangeBuilder>
+ createBuilder_addTypeAnnotation_SimpleFormalParameter() async {
+ AstNode node = this.node;
+ // should be the name of a simple parameter
+ if (node is! SimpleIdentifier || node.parent is! SimpleFormalParameter) {
+ _coverageMarker();
+ return null;
+ }
+ SimpleIdentifier name = node;
+ SimpleFormalParameter parameter = node.parent;
+ // the parameter should not have a type
+ if (parameter.type != null) {
+ _coverageMarker();
+ return null;
+ }
+ // prepare the type
+ DartType type = parameter.declaredElement.type;
+ // TODO(scheglov) If the parameter is in a method declaration, and if the
+ // method overrides a method that has a type for the corresponding
+ // parameter, it would be nice to copy down the type from the overridden
+ // method.
+ if (type is! InterfaceType) {
+ _coverageMarker();
+ return null;
+ }
+ // prepare type source
+ _configureTargetLocation(node);
+
+ var changeBuilder = _newDartChangeBuilder();
+ bool validChange = true;
+ await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+ builder.addInsertion(name.offset, (DartEditBuilder builder) {
+ validChange = builder.writeType(type);
+ builder.write(' ');
+ });
+ });
+ return validChange ? changeBuilder : null;
+ }
+
+ Future<ChangeBuilder> createBuilder_convertToNullAware() async {
+ AstNode node = this.node;
+ if (node is! ConditionalExpression) {
+ _coverageMarker();
+ return null;
+ }
+ ConditionalExpression conditional = node;
+ Expression condition = conditional.condition.unParenthesized;
+ SimpleIdentifier identifier;
+ Expression nullExpression;
+ Expression nonNullExpression;
+ int periodOffset;
+
+ if (condition is BinaryExpression) {
+ //
+ // Identify the variable being compared to `null`, or return if the
+ // condition isn't a simple comparison of `null` to a variable's value.
+ //
+ Expression leftOperand = condition.leftOperand;
+ Expression rightOperand = condition.rightOperand;
+ if (leftOperand is NullLiteral && rightOperand is SimpleIdentifier) {
+ identifier = rightOperand;
+ } else if (rightOperand is NullLiteral &&
+ leftOperand is SimpleIdentifier) {
+ identifier = leftOperand;
+ } else {
+ _coverageMarker();
+ return null;
+ }
+ if (identifier.staticElement is! LocalElement) {
+ _coverageMarker();
+ return null;
+ }
+ //
+ // Identify the expression executed when the variable is `null` and when
+ // it is non-`null`. Return if the `null` expression isn't a null literal
+ // or if the non-`null` expression isn't a method invocation whose target
+ // is the save variable being compared to `null`.
+ //
+ if (condition.operator.type == TokenType.EQ_EQ) {
+ nullExpression = conditional.thenExpression;
+ nonNullExpression = conditional.elseExpression;
+ } else if (condition.operator.type == TokenType.BANG_EQ) {
+ nonNullExpression = conditional.thenExpression;
+ nullExpression = conditional.elseExpression;
+ }
+ if (nullExpression == null || nonNullExpression == null) {
+ _coverageMarker();
+ return null;
+ }
+ if (nullExpression.unParenthesized is! NullLiteral) {
+ _coverageMarker();
+ return null;
+ }
+ Expression unwrappedExpression = nonNullExpression.unParenthesized;
+ Expression target;
+ Token operator;
+ if (unwrappedExpression is MethodInvocation) {
+ target = unwrappedExpression.target;
+ operator = unwrappedExpression.operator;
+ } else if (unwrappedExpression is PrefixedIdentifier) {
+ target = unwrappedExpression.prefix;
+ operator = unwrappedExpression.period;
+ } else {
+ _coverageMarker();
+ return null;
+ }
+ if (operator.type != TokenType.PERIOD) {
+ _coverageMarker();
+ return null;
+ }
+ if (!(target is SimpleIdentifier &&
+ target.staticElement == identifier.staticElement)) {
+ _coverageMarker();
+ return null;
+ }
+ periodOffset = operator.offset;
+
+ DartChangeBuilder changeBuilder = _newDartChangeBuilder();
+ await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+ builder.addDeletion(range.startStart(node, nonNullExpression));
+ builder.addSimpleInsertion(periodOffset, '?');
+ builder.addDeletion(range.endEnd(nonNullExpression, node));
+ });
+ return changeBuilder;
+ }
+ return null;
+ }
+
+ Future<ChangeBuilder> createBuilder_convertToExpressionFunctionBody() async {
+ // prepare current body
+ FunctionBody body = getEnclosingFunctionBody();
+ if (body is! BlockFunctionBody || body.isGenerator) {
+ _coverageMarker();
+ return null;
+ }
+ // prepare return statement
+ List<Statement> statements = (body as BlockFunctionBody).block.statements;
+ if (statements.length != 1) {
+ _coverageMarker();
+ return null;
+ }
+ Statement onlyStatement = statements.first;
+ // prepare returned expression
+ Expression returnExpression;
+ if (onlyStatement is ReturnStatement) {
+ returnExpression = onlyStatement.expression;
+ } else if (onlyStatement is ExpressionStatement) {
+ returnExpression = onlyStatement.expression;
+ }
+ if (returnExpression == null) {
+ _coverageMarker();
+ return null;
+ }
+
+ // Return expressions can be quite large, e.g. Flutter build() methods.
+ // It is surprising to see this Quick Assist deep in the function body.
+ if (selectionOffset >= returnExpression.offset) {
+ _coverageMarker();
+ return null;
+ }
+
+ var changeBuilder = _newDartChangeBuilder();
+ await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+ builder.addReplacement(range.node(body), (DartEditBuilder builder) {
+ if (body.isAsynchronous) {
+ builder.write('async ');
+ }
+ builder.write('=> ');
+ builder.write(_getNodeText(returnExpression));
+ if (body.parent is! FunctionExpression ||
+ body.parent.parent is FunctionDeclaration) {
+ builder.write(';');
+ }
+ });
+ });
+ return changeBuilder;
+ }
+
+ /// Returns the text of the given node in the unit.
+ String /* TODO (pq): make visible */ _getNodeText(AstNode node) =>
+ utils.getNodeText(node);
+
+ FunctionBody getEnclosingFunctionBody() {
+ // TODO(brianwilkerson) Determine whether there is a reason why this method
+ // isn't just "return node.getAncestor((node) => node is FunctionBody);"
+ {
+ FunctionExpression function =
+ node.thisOrAncestorOfType<FunctionExpression>();
+ if (function != null) {
+ return function.body;
+ }
+ }
+ {
+ FunctionDeclaration function =
+ node.thisOrAncestorOfType<FunctionDeclaration>();
+ if (function != null) {
+ return function.functionExpression.body;
+ }
+ }
+ {
+ ConstructorDeclaration constructor =
+ node.thisOrAncestorOfType<ConstructorDeclaration>();
+ if (constructor != null) {
+ return constructor.body;
+ }
+ }
+ {
+ MethodDeclaration method = node.thisOrAncestorOfType<MethodDeclaration>();
+ if (method != null) {
+ return method.body;
+ }
+ }
+ return null;
+ }
+
+ Future<ChangeBuilder>
+ createBuilder_addTypeAnnotation_VariableDeclaration() async {
+ AstNode node = this.node;
+ // prepare VariableDeclarationList
+ VariableDeclarationList declarationList =
+ node.thisOrAncestorOfType<VariableDeclarationList>();
+ if (declarationList == null) {
+ _coverageMarker();
+ return null;
+ }
+ // may be has type annotation already
+ if (declarationList.type != null) {
+ _coverageMarker();
+ return null;
+ }
+ // prepare single VariableDeclaration
+ List<VariableDeclaration> variables = declarationList.variables;
+ if (variables.length != 1) {
+ _coverageMarker();
+ return null;
+ }
+ VariableDeclaration variable = variables[0];
+ // must be not after the name of the variable
+ if (selectionOffset > variable.name.end) {
+ _coverageMarker();
+ return null;
+ }
+ // we need an initializer to get the type from
+ Expression initializer = variable.initializer;
+ if (initializer == null) {
+ _coverageMarker();
+ return null;
+ }
+ DartType type = initializer.staticType;
+ // prepare type source
+ if ((type is! InterfaceType || type.isDartCoreNull) &&
+ type is! FunctionType) {
+ _coverageMarker();
+ return null;
+ }
+ _configureTargetLocation(node);
+
+ var changeBuilder = _newDartChangeBuilder();
+ bool validChange = true;
+ await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+ Token keyword = declarationList.keyword;
+ if (keyword?.keyword == Keyword.VAR) {
+ builder.addReplacement(range.token(keyword), (DartEditBuilder builder) {
+ validChange = builder.writeType(type);
+ });
+ } else {
+ builder.addInsertion(variable.offset, (DartEditBuilder builder) {
+ validChange = builder.writeType(type);
+ builder.write(' ');
+ });
+ }
+ });
+ return validChange ? changeBuilder : null;
+ }
+
+ Future<ChangeBuilder>
+ createBuilder_convertConditionalExpressionToIfElement() async {
+ AstNode node = this.node.thisOrAncestorOfType<ConditionalExpression>();
+ if (node == null) {
+ _coverageMarker();
+ return null;
+ }
+ AstNode nodeToReplace = node;
+ AstNode parent = node.parent;
+ while (parent is ParenthesizedExpression) {
+ nodeToReplace = parent;
+ parent = parent.parent;
+ }
+ if (parent is ListLiteral || (parent is SetOrMapLiteral && parent.isSet)) {
+ ConditionalExpression conditional = node;
+ Expression condition = conditional.condition.unParenthesized;
+ Expression thenExpression = conditional.thenExpression.unParenthesized;
+ Expression elseExpression = conditional.elseExpression.unParenthesized;
+
+ DartChangeBuilder changeBuilder = _newDartChangeBuilder();
+ await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+ builder.addReplacement(range.node(nodeToReplace),
+ (DartEditBuilder builder) {
+ builder.write('if (');
+ builder.write(utils.getNodeText(condition));
+ builder.write(') ');
+ builder.write(utils.getNodeText(thenExpression));
+ builder.write(' else ');
+ builder.write(utils.getNodeText(elseExpression));
+ });
+ });
+ return changeBuilder;
+ }
+
+ return null;
+ }
+
+ Future<ChangeBuilder> createBuilder_convertDocumentationIntoLine() async {
+ Comment comment = node.thisOrAncestorOfType<Comment>();
+ if (comment == null ||
+ !comment.isDocumentation ||
+ comment.tokens.length != 1) {
+ _coverageMarker();
+ return null;
+ }
+ Token token = comment.tokens.first;
+ if (token.type != TokenType.MULTI_LINE_COMMENT) {
+ _coverageMarker();
+ return null;
+ }
+ String text = token.lexeme;
+ List<String> lines = text.split('\n');
+ String prefix = utils.getNodePrefix(comment);
+ List<String> newLines = <String>[];
+ bool firstLine = true;
+ String linePrefix = '';
+ for (String line in lines) {
+ if (firstLine) {
+ firstLine = false;
+ String expectedPrefix = '/**';
+ if (!line.startsWith(expectedPrefix)) {
+ _coverageMarker();
+ return null;
+ }
+ line = line.substring(expectedPrefix.length).trim();
+ if (line.isNotEmpty) {
+ newLines.add('/// $line');
+ linePrefix = eol + prefix;
+ }
+ } else {
+ if (line.startsWith(prefix + ' */')) {
+ break;
+ }
+ String expectedPrefix = prefix + ' *';
+ if (!line.startsWith(expectedPrefix)) {
+ _coverageMarker();
+ return null;
+ }
+ line = line.substring(expectedPrefix.length);
+ if (line.isEmpty) {
+ newLines.add('$linePrefix///');
+ } else {
+ newLines.add('$linePrefix///$line');
+ }
+ linePrefix = eol + prefix;
+ }
+ }
+
+ var changeBuilder = _newDartChangeBuilder();
+ await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+ builder.addReplacement(range.node(comment), (DartEditBuilder builder) {
+ for (String newLine in newLines) {
+ builder.write(newLine);
+ }
+ });
+ });
+ return changeBuilder;
+ }
+
+ Future<ChangeBuilder>
+ createBuilder_convertMapFromIterableToForLiteral() async {
+ //
+ // Ensure that the selection is inside an invocation of Map.fromIterable.
+ //
+ InstanceCreationExpression creation =
+ node.thisOrAncestorOfType<InstanceCreationExpression>();
+ if (creation == null) {
+ _coverageMarker();
+ return null;
+ }
+ ConstructorElement element = creation.staticElement;
+ if (element == null ||
+ element.name != 'fromIterable' ||
+ element.enclosingElement != typeProvider.mapType.element) {
+ _coverageMarker();
+ return null;
+ }
+ //
+ // Ensure that the arguments have the right form.
+ //
+ NodeList<Expression> arguments = creation.argumentList.arguments;
+ if (arguments.length != 3) {
+ _coverageMarker();
+ return null;
+ }
+ Expression iterator = arguments[0].unParenthesized;
+ Expression secondArg = arguments[1];
+ Expression thirdArg = arguments[2];
+
+ Expression extractBody(FunctionExpression expression) {
+ FunctionBody body = expression.body;
+ if (body is ExpressionFunctionBody) {
+ return body.expression;
+ } else if (body is BlockFunctionBody) {
+ NodeList<Statement> statements = body.block.statements;
+ if (statements.length == 1) {
+ Statement statement = statements[0];
+ if (statement is ReturnStatement) {
+ return statement.expression;
+ }
+ }
+ }
+ return null;
+ }
+
+ FunctionExpression extractClosure(String name, Expression argument) {
+ if (argument is NamedExpression && argument.name.label.name == name) {
+ Expression expression = argument.expression.unParenthesized;
+ if (expression is FunctionExpression) {
+ NodeList<FormalParameter> parameters =
+ expression.parameters.parameters;
+ if (parameters.length == 1 && parameters[0].isRequiredPositional) {
+ if (extractBody(expression) != null) {
+ return expression;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ FunctionExpression keyClosure =
+ extractClosure('key', secondArg) ?? extractClosure('key', thirdArg);
+ FunctionExpression valueClosure =
+ extractClosure('value', thirdArg) ?? extractClosure('value', secondArg);
+ if (keyClosure == null || valueClosure == null) {
+ _coverageMarker();
+ return null;
+ }
+ //
+ // Compute the loop variable name and convert the key and value closures if
+ // necessary.
+ //
+ SimpleFormalParameter keyParameter = keyClosure.parameters.parameters[0];
+ String keyParameterName = keyParameter.identifier.name;
+ SimpleFormalParameter valueParameter =
+ valueClosure.parameters.parameters[0];
+ String valueParameterName = valueParameter.identifier.name;
+ Expression keyBody = extractBody(keyClosure);
+ String keyExpressionText = utils.getNodeText(keyBody);
+ Expression valueBody = extractBody(valueClosure);
+ String valueExpressionText = utils.getNodeText(valueBody);
+
+ String loopVariableName;
+ if (keyParameterName == valueParameterName) {
+ loopVariableName = keyParameterName;
+ } else {
+ _ParameterReferenceFinder keyFinder =
+ new _ParameterReferenceFinder(keyParameter.declaredElement);
+ keyBody.accept(keyFinder);
+
+ _ParameterReferenceFinder valueFinder =
+ new _ParameterReferenceFinder(valueParameter.declaredElement);
+ valueBody.accept(valueFinder);
+
+ String computeUnusedVariableName() {
+ String candidate = 'e';
+ var index = 1;
+ while (keyFinder.referencesName(candidate) ||
+ valueFinder.referencesName(candidate)) {
+ candidate = 'e${index++}';
+ }
+ return candidate;
+ }
+
+ if (valueFinder.isParameterUnreferenced) {
+ if (valueFinder.referencesName(keyParameterName)) {
+ // The name of the value parameter is not used, but we can't use the
+ // name of the key parameter because doing so would hide a variable
+ // referenced in the value expression.
+ loopVariableName = computeUnusedVariableName();
+ keyExpressionText = keyFinder.replaceName(
+ keyExpressionText, loopVariableName, keyBody.offset);
+ } else {
+ loopVariableName = keyParameterName;
+ }
+ } else if (keyFinder.isParameterUnreferenced) {
+ if (keyFinder.referencesName(valueParameterName)) {
+ // The name of the key parameter is not used, but we can't use the
+ // name of the value parameter because doing so would hide a variable
+ // referenced in the key expression.
+ loopVariableName = computeUnusedVariableName();
+ valueExpressionText = valueFinder.replaceName(
+ valueExpressionText, loopVariableName, valueBody.offset);
+ } else {
+ loopVariableName = valueParameterName;
+ }
+ } else {
+ // The names are different and both are used. We need to find a name
+ // that would not change the resolution of any other identifiers in
+ // either the key or value expressions.
+ loopVariableName = computeUnusedVariableName();
+ keyExpressionText = keyFinder.replaceName(
+ keyExpressionText, loopVariableName, keyBody.offset);
+ valueExpressionText = valueFinder.replaceName(
+ valueExpressionText, loopVariableName, valueBody.offset);
+ }
+ }
+ //
+ // Construct the edit.
+ //
+ DartChangeBuilder changeBuilder = _newDartChangeBuilder();
+ await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+ builder.addReplacement(range.node(creation), (DartEditBuilder builder) {
+ builder.write('{ for (var ');
+ builder.write(loopVariableName);
+ builder.write(' in ');
+ builder.write(utils.getNodeText(iterator));
+ builder.write(') ');
+ builder.write(keyExpressionText);
+ builder.write(' : ');
+ builder.write(valueExpressionText);
+ builder.write(' }');
+ });
+ });
+ return changeBuilder;
+ }
+
+ Future<ChangeBuilder> createBuilder_convertToIntLiteral() async {
+ if (node is! DoubleLiteral) {
+ _coverageMarker();
+ return null;
+ }
+ DoubleLiteral literal = node;
+ int intValue;
+ try {
+ intValue = literal.value?.truncate();
+ } catch (e) {
+ // Double cannot be converted to int
+ }
+ if (intValue == null || intValue != literal.value) {
+ _coverageMarker();
+ return null;
+ }
+
+ var changeBuilder = _newDartChangeBuilder();
+ await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+ builder.addReplacement(new SourceRange(literal.offset, literal.length),
+ (DartEditBuilder builder) {
+ builder.write('$intValue');
+ });
+ });
+ return changeBuilder;
+ }
+
+ @protected
+ Future<ChangeBuilder> createBuilder_useCurlyBraces() async {
+ Future<ChangeBuilder> doStatement(DoStatement node) async {
+ var body = node.body;
+ if (body is Block) return null;
+
+ var prefix = utils.getLinePrefix(node.offset);
+ var indent = prefix + utils.getIndent(1);
+
+ var changeBuilder = _newDartChangeBuilder();
+ await changeBuilder.addFileEdit(file, (builder) {
+ builder.addSimpleReplacement(
+ range.endStart(node.doKeyword, body),
+ ' {$eol$indent',
+ );
+ builder.addSimpleReplacement(
+ range.endStart(body, node.whileKeyword),
+ '$eol$prefix} ',
+ );
+ });
+ return changeBuilder;
+ }
+
+ Future<ChangeBuilder> forStatement(ForStatement node) async {
+ var body = node.body;
+ if (body is Block) return null;
+
+ var prefix = utils.getLinePrefix(node.offset);
+ var indent = prefix + utils.getIndent(1);
+
+ var changeBuilder = _newDartChangeBuilder();
+ await changeBuilder.addFileEdit(file, (builder) {
+ builder.addSimpleReplacement(
+ range.endStart(node.rightParenthesis, body),
+ ' {$eol$indent',
+ );
+ builder.addSimpleInsertion(body.end, '$eol$prefix}');
+ });
+
+ return changeBuilder;
+ }
+
+ Future<ChangeBuilder> ifStatement(
+ IfStatement node, Statement thenOrElse) async {
+ var prefix = utils.getLinePrefix(node.offset);
+ var indent = prefix + utils.getIndent(1);
+
+ var changeBuilder = _newDartChangeBuilder();
+ await changeBuilder.addFileEdit(file, (builder) {
+ var thenStatement = node.thenStatement;
+ if (thenStatement is! Block &&
+ (thenOrElse == null || thenOrElse == thenStatement)) {
+ builder.addSimpleReplacement(
+ range.endStart(node.rightParenthesis, thenStatement),
+ ' {$eol$indent',
+ );
+ if (node.elseKeyword != null) {
+ builder.addSimpleReplacement(
+ range.endStart(thenStatement, node.elseKeyword),
+ '$eol$prefix} ',
+ );
+ } else {
+ builder.addSimpleInsertion(thenStatement.end, '$eol$prefix}');
+ }
+ }
+
+ var elseStatement = node.elseStatement;
+ if (elseStatement != null &&
+ elseStatement is! Block &&
+ (thenOrElse == null || thenOrElse == elseStatement)) {
+ builder.addSimpleReplacement(
+ range.endStart(node.elseKeyword, elseStatement),
+ ' {$eol$indent',
+ );
+ builder.addSimpleInsertion(elseStatement.end, '$eol$prefix}');
+ }
+ });
+
+ return changeBuilder;
+ }
+
+ Future<ChangeBuilder> whileStatement(WhileStatement node) async {
+ var body = node.body;
+ if (body is Block) return null;
+
+ var prefix = utils.getLinePrefix(node.offset);
+ var indent = prefix + utils.getIndent(1);
+
+ var changeBuilder = _newDartChangeBuilder();
+ await changeBuilder.addFileEdit(file, (builder) {
+ builder.addSimpleReplacement(
+ range.endStart(node.rightParenthesis, body),
+ ' {$eol$indent',
+ );
+ builder.addSimpleInsertion(body.end, '$eol$prefix}');
+ });
+ return changeBuilder;
+ }
+
+ var statement = this.node.thisOrAncestorOfType<Statement>();
+ var parent = statement?.parent;
+
+ if (statement is DoStatement) {
+ return doStatement(statement);
+ } else if (parent is DoStatement) {
+ return doStatement(parent);
+ } else if (statement is ForStatement) {
+ return forStatement(statement);
+ } else if (parent is ForStatement) {
+ return forStatement(parent);
+ } else if (statement is IfStatement) {
+ if (statement.elseKeyword != null &&
+ range.token(statement.elseKeyword).contains(selectionOffset)) {
+ return ifStatement(statement, statement.elseStatement);
+ } else {
+ return ifStatement(statement, null);
+ }
+ } else if (parent is IfStatement) {
+ return ifStatement(parent, statement);
+ } else if (statement is WhileStatement) {
+ return whileStatement(statement);
+ } else if (parent is WhileStatement) {
+ return whileStatement(parent);
+ }
+ return null;
+ }
+
+ @protected
+ bool setupCompute() {
+ final locator = NodeLocator(selectionOffset, selectionEnd);
+ node = locator.searchWithin(resolvedResult.unit);
+ return node != null;
+ }
+
+ /// Configures [utils] using given [target].
+ void _configureTargetLocation(Object target) {
+ utils.targetClassElement = null;
+ if (target is AstNode) {
+ ClassDeclaration targetClassDeclaration =
+ target.thisOrAncestorOfType<ClassDeclaration>();
+ if (targetClassDeclaration != null) {
+ utils.targetClassElement = targetClassDeclaration.declaredElement;
+ }
+ }
+ }
+
+ DartChangeBuilder _newDartChangeBuilder() =>
+ DartChangeBuilderImpl.forWorkspace(workspace);
+
+ /// This method does nothing, but we invoke it in places where Dart VM
+ /// coverage agent fails to provide coverage information - such as almost
+ /// all "return" statements.
+ ///
+ /// https://code.google.com/p/dart/issues/detail?id=19912
+ static void _coverageMarker() {}
+}
+
+/// A visitor that can be used to find references to a parameter.
+class _ParameterReferenceFinder extends RecursiveAstVisitor<void> {
+ /// The parameter for which references are being sought, or `null` if we are
+ /// just accumulating a list of referenced names.
+ final ParameterElement parameter;
+
+ /// A list of the simple identifiers that reference the [parameter].
+ final List<SimpleIdentifier> references = <SimpleIdentifier>[];
+
+ /// A collection of the names of other simple identifiers that were found. We
+ /// need to know these in order to ensure that the selected loop variable does
+ /// not hide a name from an enclosing scope that is already being referenced.
+ final Set<String> otherNames = new Set<String>();
+
+ /// Initialize a newly created finder to find references to the [parameter].
+ _ParameterReferenceFinder(this.parameter) : assert(parameter != null);
+
+ /// Return `true` if the parameter is unreferenced in the nodes that have been
+ /// visited.
+ bool get isParameterUnreferenced => references.isEmpty;
+
+ /// Return `true` is the given name (assumed to be different than the name of
+ /// the parameter) is references in the nodes that have been visited.
+ bool referencesName(String name) => otherNames.contains(name);
+
+ /// Replace all of the references to the parameter in the given [source] with
+ /// the [newName]. The [offset] is the offset of the first character of the
+ /// [source] relative to the start of the file.
+ String replaceName(String source, String newName, int offset) {
+ int oldLength = parameter.name.length;
+ for (int i = references.length - 1; i >= 0; i--) {
+ int oldOffset = references[i].offset - offset;
+ source = source.replaceRange(oldOffset, oldOffset + oldLength, newName);
+ }
+ return source;
+ }
+
+ @override
+ void visitSimpleIdentifier(SimpleIdentifier node) {
+ if (node.staticElement == parameter) {
+ references.add(node);
+ } else if (!node.isQualified) {
+ // Only non-prefixed identifiers can be hidden.
+ otherNames.add(node.name);
+ }
+ }
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index adfc446..ff70d93 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -4,7 +4,7 @@
import 'package:analysis_server/plugin/edit/fix/fix_dart.dart';
import 'package:analysis_server/src/services/correction/fix/dart/top_level_declarations.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+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/src/error/codes.dart';
@@ -16,8 +16,6 @@
bool hasFix(ErrorCode errorCode) =>
errorCode == StaticWarningCode.UNDEFINED_CLASS_BOOLEAN ||
errorCode == StaticWarningCode.CONCRETE_CLASS_WITH_ABSTRACT_MEMBER ||
- errorCode == StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS ||
- errorCode == StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED ||
errorCode == StaticWarningCode.NEW_WITH_UNDEFINED_CONSTRUCTOR ||
errorCode ==
StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE ||
@@ -32,7 +30,6 @@
.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FIVE_PLUS ||
errorCode == StaticWarningCode.CAST_TO_NON_TYPE ||
errorCode == StaticWarningCode.TYPE_TEST_WITH_UNDEFINED_NAME ||
- errorCode == StaticWarningCode.UNDEFINED_CLASS ||
errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED ||
errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_1 ||
errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_2 ||
@@ -141,6 +138,10 @@
static const ADD_EXPLICIT_CAST = const FixKind(
'ADD_EXPLICIT_CAST', 50, "Add cast",
appliedTogetherMessage: "Add all casts in file");
+ static const ADD_CONST =
+ const FixKind('ADD_CONST', 50, "Add 'const' modifier");
+ static const ADD_CURLY_BRACES =
+ const FixKind('ADD_CURLY_BRACES', 50, "Add curly braces");
static const ADD_FIELD_FORMAL_PARAMETERS = const FixKind(
'ADD_FIELD_FORMAL_PARAMETERS', 70, "Add final field formal parameters");
static const ADD_MISSING_ENUM_CASE_CLAUSES = const FixKind(
@@ -167,6 +168,8 @@
'ADD_SUPER_CONSTRUCTOR_INVOCATION',
50,
"Add super constructor {0} invocation");
+ static const ADD_TYPE_ANNOTATION =
+ const FixKind('ADD_TYPE_ANNOTATION', 50, "Add type annotation");
static const CHANGE_ARGUMENT_NAME =
const FixKind('CHANGE_ARGUMENT_NAME', 60, "Change to '{0}'");
static const CHANGE_TO = const FixKind('CHANGE_TO', 51, "Change to '{0}'");
@@ -182,8 +185,20 @@
const FixKind('CONVERT_FLUTTER_CHILD', 50, "Convert to children:");
static const CONVERT_FLUTTER_CHILDREN =
const FixKind('CONVERT_FLUTTER_CHILDREN', 50, "Convert to child:");
+ static const CONVERT_INTO_EXPRESSION_BODY = const FixKind(
+ 'CONVERT_INTO_EXPRESSION_BODY', 50, "Convert to expression body");
+ static const CONVERT_TO_FOR_ELEMENT =
+ const FixKind('CONVERT_TO_FOR_ELEMENT', 50, "Convert to a 'for' element");
+ static const CONVERT_TO_IF_ELEMENT =
+ const FixKind('CONVERT_TO_IF_ELEMENT', 50, "Convert to an 'if' element");
+ static const CONVERT_TO_INT_LITERAL =
+ const FixKind('CONVERT_TO_INT_LITERAL', 50, "Convert to an int literal");
+ static const CONVERT_TO_LINE_COMMENT = const FixKind(
+ 'CONVERT_TO_LINE_COMMENT', 50, "Convert to line documentation comment");
static const CONVERT_TO_NAMED_ARGUMENTS = const FixKind(
'CONVERT_TO_NAMED_ARGUMENTS', 50, "Convert to named arguments");
+ static const CONVERT_TO_NULL_AWARE =
+ const FixKind('CONVERT_TO_NULL_AWARE', 50, "Convert to use '?.'");
static const CREATE_CLASS =
const FixKind('CREATE_CLASS', 50, "Create class '{0}'");
static const CREATE_CONSTRUCTOR =
@@ -212,6 +227,8 @@
const FixKind('CREATE_MIXIN', 50, "Create mixin '{0}'");
static const CREATE_NO_SUCH_METHOD = const FixKind(
'CREATE_NO_SUCH_METHOD', 49, "Create 'noSuchMethod' method");
+ static const CREATE_SETTER =
+ const FixKind('CREATE_SETTER', 50, "Create setter '{0}'");
static const EXTEND_CLASS_FOR_MIXIN =
const FixKind('EXTEND_CLASS_FOR_MIXIN', 50, "Extend the class '{0}'");
static const IMPORT_ASYNC =
@@ -239,6 +256,8 @@
'MOVE_TYPE_ARGUMENTS_TO_CLASS',
50,
"Move type arguments to after class name");
+ static const MAKE_VARIABLE_NOT_FINAL = const FixKind(
+ 'MAKE_VARIABLE_NOT_FINAL', 50, "Make variable '{0}' not final");
static const REMOVE_ANNOTATION =
const FixKind('REMOVE_ANNOTATION', 50, "Remove the '{0}' annotation");
static const REMOVE_AWAIT = const FixKind('REMOVE_AWAIT', 50, "Remove await");
@@ -301,6 +320,8 @@
const FixKind('REPLACE_COLON_WITH_EQUALS', 50, "Replace ':' with '='");
static const REPLACE_FINAL_WITH_CONST = const FixKind(
'REPLACE_FINAL_WITH_CONST', 50, "Replace 'final' with 'const'");
+ static const REPLACE_NEW_WITH_CONST =
+ const FixKind('REPLACE_NEW_WITH_CONST', 50, "Replace 'new' with 'const'");
static const REPLACE_NULL_WITH_CLOSURE = const FixKind(
'REPLACE_NULL_WITH_CLOSURE', 50, "Replace 'null' with a closure");
static const REPLACE_RETURN_TYPE_FUTURE = const FixKind(
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/dart/top_level_declarations.dart b/pkg/analysis_server/lib/src/services/correction/fix/dart/top_level_declarations.dart
index 9169ba1..5c51d43 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/dart/top_level_declarations.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/dart/top_level_declarations.dart
@@ -35,7 +35,7 @@
/// Kind of a top-level declaration.
///
/// We don't need it to be precise, just enough to support quick fixes.
-enum TopLevelDeclarationKind { type, function, variable }
+enum TopLevelDeclarationKind { type, extension, function, variable }
class TopLevelDeclarationsProvider {
final DeclarationsTracker tracker;
@@ -94,6 +94,9 @@
case DeclarationKind.MIXIN:
return TopLevelDeclarationKind.type;
break;
+ case DeclarationKind.EXTENSION:
+ return TopLevelDeclarationKind.extension;
+ break;
case DeclarationKind.FUNCTION:
return TopLevelDeclarationKind.function;
break;
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 d2cd3f5..0a857ce 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -9,18 +9,17 @@
import 'package:analysis_server/plugin/edit/fix/fix_core.dart';
import 'package:analysis_server/plugin/edit/fix/fix_dart.dart';
import 'package:analysis_server/src/services/completion/dart/utilities.dart';
+import 'package:analysis_server/src/services/correction/base_processor.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analysis_server/src/services/correction/fix/dart/top_level_declarations.dart';
import 'package:analysis_server/src/services/correction/levenshtein.dart';
import 'package:analysis_server/src/services/correction/namespace.dart';
import 'package:analysis_server/src/services/correction/strings.dart';
import 'package:analysis_server/src/services/correction/util.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analysis_server/src/services/search/hierarchy.dart';
-import 'package:analysis_server/src/utilities/flutter.dart';
-import 'package:analyzer/dart/analysis/session.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/precedence.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
@@ -63,8 +62,6 @@
class DartFixContributor implements FixContributor {
@override
Future<List<Fix>> computeFixes(DartFixContext context) async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
try {
FixProcessor processor = new FixProcessor(context);
List<Fix> fixes = await processor.compute();
@@ -77,8 +74,6 @@
Future<List<Fix>> _computeFixAllFixes(
DartFixContext context, List<Fix> fixes) async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
final analysisError = context.error;
final allAnalysisErrors = context.resolveResult.errors.toList();
@@ -165,21 +160,15 @@
/**
* The computer for Dart fixes.
*/
-class FixProcessor {
+class FixProcessor extends BaseProcessor {
static const int MAX_LEVENSHTEIN_DISTANCE = 3;
final DartFixContext context;
final ResourceProvider resourceProvider;
- final AnalysisSession session;
- final AnalysisSessionHelper sessionHelper;
- final TypeProvider typeProvider;
final TypeSystem typeSystem;
- final String file;
final LibraryElement unitLibraryElement;
final CompilationUnit unit;
- final CorrectionUtils utils;
- final Flutter flutter;
final AnalysisError error;
final int errorOffset;
@@ -187,31 +176,23 @@
final List<Fix> fixes = <Fix>[];
- AstNode node;
AstNode coveredNode;
FixProcessor(this.context)
: resourceProvider = context.resolveResult.session.resourceProvider,
- session = context.resolveResult.session,
- sessionHelper = AnalysisSessionHelper(context.resolveResult.session),
- typeProvider = context.resolveResult.typeProvider,
typeSystem = context.resolveResult.typeSystem,
- file = context.resolveResult.path,
unitLibraryElement = context.resolveResult.libraryElement,
unit = context.resolveResult.unit,
- utils = CorrectionUtils(context.resolveResult),
- flutter = Flutter.of(context.resolveResult),
error = context.error,
errorOffset = context.error.offset,
- errorLength = context.error.length;
+ errorLength = context.error.length,
+ super(
+ resolvedResult: context.resolveResult,
+ workspace: context.workspace,
+ );
DartType get coreTypeBool => _getCoreType('bool');
- /**
- * Returns the EOL to use for this [CompilationUnit].
- */
- String get eol => utils.endOfLine;
-
Future<List<Fix>> compute() async {
node = new NodeLocator2(errorOffset).searchWithin(unit);
coveredNode = new NodeLocator2(errorOffset, errorOffset + errorLength - 1)
@@ -316,7 +297,9 @@
if (errorCode == HintCode.INVALID_FACTORY_ANNOTATION ||
errorCode == HintCode.INVALID_IMMUTABLE_ANNOTATION ||
errorCode == HintCode.INVALID_LITERAL_ANNOTATION ||
- errorCode == HintCode.INVALID_REQUIRED_PARAM ||
+ errorCode == HintCode.INVALID_REQUIRED_NAMED_PARAM ||
+ errorCode == HintCode.INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM ||
+ errorCode == HintCode.INVALID_REQUIRED_POSITIONAL_PARAM ||
errorCode == HintCode.INVALID_SEALED_ANNOTATION) {
await _addFix_removeAnnotation();
}
@@ -414,15 +397,15 @@
if (errorCode == StaticWarningCode.ASSIGNMENT_TO_FINAL) {
await _addFix_makeFieldNotFinal();
}
+ if (errorCode == StaticWarningCode.ASSIGNMENT_TO_FINAL_LOCAL) {
+ await _addFix_makeVariableNotFinal();
+ }
if (errorCode == StaticWarningCode.CONCRETE_CLASS_WITH_ABSTRACT_MEMBER) {
await _addFix_makeEnclosingClassAbstract();
}
if (errorCode == CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS ||
- errorCode == StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS ||
errorCode ==
- CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED ||
- errorCode ==
- StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED) {
+ CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED) {
await _addFix_createConstructor_insteadOfSyntheticDefault();
await _addFix_addMissingParameter();
}
@@ -452,17 +435,14 @@
if (errorCode == CompileTimeErrorCode.UNDEFINED_CLASS ||
errorCode == StaticWarningCode.CAST_TO_NON_TYPE ||
errorCode == StaticWarningCode.NOT_A_TYPE ||
- errorCode == StaticWarningCode.TYPE_TEST_WITH_UNDEFINED_NAME ||
- errorCode == StaticWarningCode.UNDEFINED_CLASS) {
+ errorCode == StaticWarningCode.TYPE_TEST_WITH_UNDEFINED_NAME) {
await _addFix_importLibrary_withType();
await _addFix_createClass();
await _addFix_createMixin();
await _addFix_undefinedClass_useSimilar();
}
if (errorCode ==
- CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED ||
- errorCode ==
- StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED) {
+ CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED) {
await _addFix_convertToNamedArgument();
}
if (errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED) {
@@ -481,13 +461,14 @@
await _addFix_createGetter();
await _addFix_createFunction_forFunctionType();
await _addFix_createMixin();
+ await _addFix_createSetter();
await _addFix_importLibrary_withType();
+ await _addFix_importLibrary_withExtension();
await _addFix_importLibrary_withFunction();
await _addFix_importLibrary_withTopLevelVariable();
await _addFix_createLocalVariable();
}
- if (errorCode == CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER ||
- errorCode == StaticWarningCode.UNDEFINED_NAMED_PARAMETER) {
+ if (errorCode == CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER) {
await _addFix_addMissingParameterNamed();
await _addFix_changeArgumentName();
}
@@ -515,6 +496,7 @@
}
if (errorCode == StaticTypeWarningCode.UNDEFINED_FUNCTION) {
await _addFix_createClass();
+ await _addFix_importLibrary_withExtension();
await _addFix_importLibrary_withFunction();
await _addFix_importLibrary_withType();
await _addFix_undefinedFunction_useSimilar();
@@ -533,20 +515,32 @@
await _addFix_importLibrary_withTopLevelVariable();
await _addFix_importLibrary_withType();
}
+ if (errorCode == CompileTimeErrorCode.UNDEFINED_EXTENSION_GETTER) {
+ await _addFix_undefinedClassAccessor_useSimilar();
+ await _addFix_createGetter();
+ }
if (errorCode == StaticTypeWarningCode.UNDEFINED_METHOD) {
await _addFix_createClass();
await _addFix_importLibrary_withFunction();
await _addFix_importLibrary_withType();
await _addFix_undefinedMethod_useSimilar();
- await _addFix_undefinedMethod_create();
+ await _addFix_createMethod();
await _addFix_undefinedFunction_create();
}
+ if (errorCode == CompileTimeErrorCode.UNDEFINED_EXTENSION_METHOD) {
+ await _addFix_undefinedMethod_useSimilar();
+ await _addFix_createMethod();
+ }
if (errorCode == StaticTypeWarningCode.UNDEFINED_SETTER) {
await _addFix_undefinedClassAccessor_useSimilar();
await _addFix_createField();
+ await _addFix_createSetter();
}
- if (errorCode == CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER ||
- errorCode == StaticWarningCode.UNDEFINED_NAMED_PARAMETER) {
+ if (errorCode == CompileTimeErrorCode.UNDEFINED_EXTENSION_SETTER) {
+ await _addFix_undefinedClassAccessor_useSimilar();
+ await _addFix_createSetter();
+ }
+ if (errorCode == CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER) {
await _addFix_convertFlutterChild();
await _addFix_convertFlutterChildren();
}
@@ -572,6 +566,10 @@
// lints
if (errorCode is LintCode) {
String name = errorCode.name;
+ if (name == LintNames.always_specify_types ||
+ name == LintNames.type_annotate_public_apis) {
+ await _addFix_addTypeAnnotation();
+ }
if (name == LintNames.always_require_non_null_named_parameters) {
await _addFix_addRequiredAnnotation();
}
@@ -596,6 +594,9 @@
if (name == LintNames.await_only_futures) {
await _addFix_removeAwait();
}
+ if (name == LintNames.curly_braces_in_flow_control_structures) {
+ await _addFix_addCurlyBraces();
+ }
if (name == LintNames.empty_catches) {
await _addFix_removeEmptyCatch();
}
@@ -620,6 +621,12 @@
if (errorCode.name == LintNames.prefer_const_declarations) {
await _addFix_replaceFinalWithConst();
}
+ if (errorCode.name == LintNames.prefer_expression_function_bodies) {
+ await _addFix_convertToExpressionBody();
+ }
+ if (errorCode.name == LintNames.prefer_for_elements_to_map_fromIterable) {
+ await _addFix_convertMapFromIterableToForLiteral();
+ }
if (errorCode.name == LintNames.prefer_equal_for_default_values) {
await _addFix_replaceColonWithEquals();
}
@@ -629,12 +636,29 @@
if (name == LintNames.prefer_final_locals) {
await _addFix_makeVariableFinal();
}
+ if (errorCode.name ==
+ LintNames.prefer_if_elements_to_conditional_expressions) {
+ await _addFix_convertConditionalToIfElement();
+ }
+ if (name == LintNames.prefer_int_literals) {
+ await _addFix_convertToIntLiteral();
+ }
if (name == LintNames.prefer_is_empty) {
await _addFix_replaceWithIsEmpty();
}
if (name == LintNames.prefer_is_not_empty) {
await _addFix_isNotEmpty();
}
+ if (errorCode.name == LintNames.prefer_const_constructors) {
+ await _addFix_addConst();
+ await _addFix_replaceNewWithConst();
+ }
+ if (name == LintNames.prefer_null_aware_operators) {
+ await _addFix_convertToNullAware();
+ }
+ if (errorCode.name == LintNames.slash_for_doc_comments) {
+ await _addFix_convertDocumentationIntoLine();
+ }
if (name == LintNames.type_init_formals) {
await _addFix_removeTypeAnnotation();
}
@@ -674,8 +698,6 @@
}
Future<void> _addFix_addAsync() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
FunctionBody body = node.thisOrAncestorOfType<FunctionBody>();
if (body != null && body.keyword == null) {
TypeProvider typeProvider = this.typeProvider;
@@ -695,9 +717,33 @@
_addFixFromBuilder(changeBuilder, DartFixKind.ADD_AWAIT);
}
+ Future<void> _addFix_addConst() async {
+ var node = coveredNode;
+ if (node is ConstructorName) {
+ node = node.parent;
+ }
+ if (node is InstanceCreationExpression) {
+ if ((node as InstanceCreationExpression).keyword == null) {
+ final changeBuilder = _newDartChangeBuilder();
+ await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+ builder.addSimpleInsertion(node.offset, 'const ');
+ });
+ _addFixFromBuilder(changeBuilder, DartFixKind.ADD_CONST);
+ }
+ }
+ }
+
+ Future<void> _addFix_addCurlyBraces() async {
+ final changeBuilder = await createBuilder_useCurlyBraces();
+ _addFixFromBuilder(changeBuilder, DartFixKind.ADD_CURLY_BRACES);
+ }
+
+ Future<void> _addFix_convertToNullAware() async {
+ final changeBuilder = await createBuilder_convertToNullAware();
+ _addFixFromBuilder(changeBuilder, DartFixKind.CONVERT_TO_NULL_AWARE);
+ }
+
Future<void> _addFix_addExplicitCast() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (coveredNode is! Expression) {
return;
}
@@ -860,8 +906,6 @@
}
Future<void> _addFix_addMissingParameter() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
// The error is reported on ArgumentList.
if (node is! ArgumentList) {
return;
@@ -884,8 +928,6 @@
Future<void> addParameter(
FixKind kind, int offset, String prefix, String suffix) async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (offset != null) {
var changeBuilder = _newDartChangeBuilder();
await changeBuilder.addFileEdit(context.file, (builder) {
@@ -990,8 +1032,6 @@
}
Future<void> _addFix_addMissingRequiredArgument() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
InstanceCreationExpression creation;
Element targetElement;
ArgumentList argumentList;
@@ -1062,8 +1102,6 @@
}
Future<void> _addFix_addOverrideAnnotation() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
ClassMember member = node.thisOrAncestorOfType<ClassMember>();
if (member == null) {
return;
@@ -1089,8 +1127,6 @@
}
Future<void> _addFix_addRequiredAnnotation() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
var changeBuilder = _newDartChangeBuilder();
await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
builder.addSimpleInsertion(node.parent.offset, '@required ');
@@ -1099,8 +1135,6 @@
}
Future<void> _addFix_addStatic() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
FieldDeclaration declaration =
node.thisOrAncestorOfType<FieldDeclaration>();
var changeBuilder = _newDartChangeBuilder();
@@ -1110,9 +1144,20 @@
_addFixFromBuilder(changeBuilder, DartFixKind.ADD_STATIC);
}
+ Future<void> _addFix_addTypeAnnotation() async {
+ var changeBuilder =
+ await createBuilder_addTypeAnnotation_DeclaredIdentifier();
+ _addFixFromBuilder(changeBuilder, DartFixKind.ADD_TYPE_ANNOTATION);
+
+ changeBuilder =
+ await createBuilder_addTypeAnnotation_SimpleFormalParameter();
+ _addFixFromBuilder(changeBuilder, DartFixKind.ADD_TYPE_ANNOTATION);
+
+ changeBuilder = await createBuilder_addTypeAnnotation_VariableDeclaration();
+ _addFixFromBuilder(changeBuilder, DartFixKind.ADD_TYPE_ANNOTATION);
+ }
+
Future<void> _addFix_boolInsteadOfBoolean() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
var changeBuilder = _newDartChangeBuilder();
await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
builder.addSimpleReplacement(range.error(error), 'bool');
@@ -1121,8 +1166,6 @@
}
Future<void> _addFix_canBeNullAfterNullAware() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
AstNode node = coveredNode;
if (node is Expression) {
var changeBuilder = _newDartChangeBuilder();
@@ -1212,8 +1255,6 @@
}
Future<void> _addFix_changeTypeAnnotation() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
AstNode declaration = coveredNode.parent;
if (declaration is VariableDeclaration &&
declaration.initializer == coveredNode) {
@@ -1234,19 +1275,26 @@
});
});
_addFixFromBuilder(
- changeBuilder, DartFixKind.CHANGE_TYPE_ANNOTATION, args: [
- resolutionMap.typeForTypeName(typeNode),
- newType.displayName
- ]);
+ changeBuilder, DartFixKind.CHANGE_TYPE_ANNOTATION,
+ args: [typeNode.type, newType.displayName]);
}
}
}
}
}
+ Future<void> _addFix_convertConditionalToIfElement() async {
+ final changeBuilder =
+ await createBuilder_convertConditionalExpressionToIfElement();
+ _addFixFromBuilder(changeBuilder, DartFixKind.CONVERT_TO_IF_ELEMENT);
+ }
+
+ Future<void> _addFix_convertDocumentationIntoLine() async {
+ final changeBuilder = await createBuilder_convertDocumentationIntoLine();
+ _addFixFromBuilder(changeBuilder, DartFixKind.CONVERT_TO_LINE_COMMENT);
+ }
+
Future<void> _addFix_convertFlutterChild() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
NamedExpression named = flutter.findNamedExpression(node, 'child');
if (named == null) {
return;
@@ -1287,8 +1335,6 @@
}
Future<void> _addFix_convertFlutterChildren() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
AstNode node = this.node;
if (node is SimpleIdentifier &&
node.name == 'children' &&
@@ -1316,27 +1362,44 @@
}
}
+ Future<void> _addFix_convertMapFromIterableToForLiteral() async {
+ final changeBuilder =
+ await createBuilder_convertMapFromIterableToForLiteral();
+ _addFixFromBuilder(changeBuilder, DartFixKind.CONVERT_TO_FOR_ELEMENT);
+ }
+
+ Future<void> _addFix_convertToExpressionBody() async {
+ final changeBuilder = await createBuilder_convertToExpressionFunctionBody();
+ _addFixFromBuilder(changeBuilder, DartFixKind.CONVERT_INTO_EXPRESSION_BODY);
+ }
+
+ Future<void> _addFix_convertToIntLiteral() async {
+ final changeBuilder = await createBuilder_convertToIntLiteral();
+ _addFixFromBuilder(changeBuilder, DartFixKind.CONVERT_TO_INT_LITERAL);
+ }
+
Future<void> _addFix_convertToNamedArgument() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
var argumentList = this.node;
if (argumentList is ArgumentList) {
- // Prepare ExecutableElement.
- ExecutableElement executable;
+ // Prepare parameters.
+ List<ParameterElement> parameters;
var parent = argumentList.parent;
if (parent is InstanceCreationExpression) {
- executable = parent.staticElement;
+ parameters = parent.staticElement?.parameters;
} else if (parent is MethodInvocation) {
- executable = parent.methodName.staticElement;
+ var invokeType = parent.staticInvokeType;
+ if (invokeType is FunctionType) {
+ parameters = invokeType.parameters;
+ }
}
- if (executable == null) {
+ if (parameters == null) {
return;
}
// Prepare named parameters.
int numberOfPositionalParameters = 0;
var namedParameters = <ParameterElement>[];
- for (var parameter in executable.parameters) {
+ for (var parameter in parameters) {
if (parameter.isNamed) {
namedParameters.add(parameter);
} else {
@@ -1387,8 +1450,6 @@
}
Future<void> _addFix_createClass() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
Element prefixElement = null;
String name = null;
SimpleIdentifier nameNode;
@@ -1473,8 +1534,6 @@
* class has uninitialized final fields.
*/
Future<void> _addFix_createConstructor_forUninitializedFinalFields() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (node is! SimpleIdentifier || node.parent is! VariableDeclaration) {
return;
}
@@ -1551,8 +1610,6 @@
}
Future<void> _addFix_createConstructor_insteadOfSyntheticDefault() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (node is! ArgumentList) {
return;
}
@@ -1601,8 +1658,6 @@
}
Future<void> _addFix_createConstructor_named() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
SimpleIdentifier name = null;
ConstructorName constructorName = null;
InstanceCreationExpression instanceCreation = null;
@@ -1666,8 +1721,6 @@
}
Future<void> _addFix_createConstructorSuperExplicit() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (node.parent is! ConstructorDeclaration ||
node.parent.parent is! ClassDeclaration) {
return;
@@ -1737,8 +1790,6 @@
}
Future<void> _addFix_createConstructorSuperImplicit() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
ClassDeclaration targetClassNode =
node.thisOrAncestorOfType<ClassDeclaration>();
ClassElement targetClassElement = targetClassNode.declaredElement;
@@ -1807,8 +1858,6 @@
}
Future<void> _addFix_createField() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (node is! SimpleIdentifier) {
return;
}
@@ -1886,8 +1935,6 @@
}
Future<void> _addFix_createField_initializingFormal() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
//
// Ensure that we are in an initializing formal parameter.
//
@@ -1922,8 +1969,6 @@
}
Future<void> _addFix_createFunction_forFunctionType() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (node is SimpleIdentifier) {
SimpleIdentifier nameNode = node as SimpleIdentifier;
// prepare argument expression (to get parameter)
@@ -1972,8 +2017,6 @@
}
Future<void> _addFix_createGetter() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (node is! SimpleIdentifier) {
return;
}
@@ -1982,7 +2025,7 @@
if (!nameNode.inGetterContext()) {
return;
}
- // prepare target Expression
+ // prepare target
Expression target;
{
AstNode nameParent = nameNode.parent;
@@ -1992,16 +2035,22 @@
target = nameParent.realTarget;
}
}
- // prepare target ClassElement
+ // prepare target element
bool staticModifier = false;
- ClassElement targetClassElement;
- if (target != null) {
+ Element targetElement;
+ if (target is ExtensionOverride) {
+ targetElement = target.staticElement;
+ } else if (target is Identifier &&
+ target.staticElement is ExtensionElement) {
+ targetElement = target.staticElement;
+ staticModifier = true;
+ } else if (target != null) {
// prepare target interface type
DartType targetType = target.staticType;
if (targetType is! InterfaceType) {
return;
}
- targetClassElement = targetType.element;
+ targetElement = targetType.element;
// maybe static
if (target is Identifier) {
Identifier targetIdentifier = target;
@@ -2009,29 +2058,30 @@
staticModifier = targetElement?.kind == ElementKind.CLASS;
}
} else {
- targetClassElement = getEnclosingClassElement(node);
- if (targetClassElement == null) {
+ targetElement =
+ getEnclosingClassElement(node) ?? getEnclosingExtensionElement(node);
+ if (targetElement == null) {
return;
}
staticModifier = _inStaticContext();
}
- if (targetClassElement.librarySource.isInSystemLibrary) {
+ if (targetElement.librarySource.isInSystemLibrary) {
return;
}
- utils.targetClassElement = targetClassElement;
- // prepare target ClassOrMixinDeclaration
+ // prepare target declaration
var targetDeclarationResult =
- await sessionHelper.getElementDeclaration(targetClassElement);
- if (targetDeclarationResult.node is! ClassOrMixinDeclaration) {
+ await sessionHelper.getElementDeclaration(targetElement);
+ if (targetDeclarationResult.node is! ClassOrMixinDeclaration &&
+ targetDeclarationResult.node is! ExtensionDeclaration) {
return;
}
- ClassOrMixinDeclaration targetNode = targetDeclarationResult.node;
+ CompilationUnitMember targetNode = targetDeclarationResult.node;
// prepare location
ClassMemberLocation targetLocation =
CorrectionUtils(targetDeclarationResult.resolvedUnit)
.prepareNewGetterLocation(targetNode);
// build method source
- Source targetSource = targetClassElement.source;
+ Source targetSource = targetElement.source;
String targetFile = targetSource.fullName;
var changeBuilder = _newDartChangeBuilder();
await changeBuilder.addFileEdit(targetFile, (DartFileEditBuilder builder) {
@@ -2051,8 +2101,6 @@
}
Future<void> _addFix_createImportUri() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
// TODO(brianwilkerson) Generalize this to allow other valid string literals.
// TODO(brianwilkerson) Support the case where the node's parent is a Configuration.
if (node is SimpleStringLiteral && node.parent is ImportDirective) {
@@ -2076,8 +2124,6 @@
}
Future<void> _addFix_createLocalVariable() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (node is! SimpleIdentifier) {
return;
}
@@ -2124,9 +2170,104 @@
args: [name]);
}
+ Future<void> _addFix_createMethod() async {
+ if (node is! SimpleIdentifier || node.parent is! MethodInvocation) {
+ return;
+ }
+ String name = (node as SimpleIdentifier).name;
+ MethodInvocation invocation = node.parent as MethodInvocation;
+ // prepare environment
+ Element targetElement;
+ bool staticModifier = false;
+
+ CompilationUnitMember targetNode;
+ Expression target = invocation.realTarget;
+ CorrectionUtils utils = this.utils;
+ if (target is ExtensionOverride) {
+ targetElement = target.staticElement;
+ targetNode = await _getExtensionDeclaration(targetElement);
+ if (targetNode == null) {
+ return;
+ }
+ } else if (target is Identifier &&
+ target.staticElement is ExtensionElement) {
+ targetElement = target.staticElement;
+ targetNode = await _getExtensionDeclaration(targetElement);
+ if (targetNode == null) {
+ return;
+ }
+ staticModifier = true;
+ } else if (target == null) {
+ targetElement = unit.declaredElement;
+ ClassMember enclosingMember = node.thisOrAncestorOfType<ClassMember>();
+ if (enclosingMember == null) {
+ // If the undefined identifier isn't inside a class member, then it
+ // doesn't make sense to create a method.
+ return;
+ }
+ targetNode = enclosingMember.parent;
+ staticModifier = _inStaticContext();
+ } else {
+ // prepare target interface type
+ DartType targetType = target.staticType;
+ if (targetType is! InterfaceType) {
+ return;
+ }
+ ClassElement targetClassElement = targetType.element as ClassElement;
+ if (targetClassElement.librarySource.isInSystemLibrary) {
+ return;
+ }
+ targetElement = targetClassElement;
+ // prepare target ClassDeclaration
+ targetNode = await _getClassDeclaration(targetClassElement);
+ if (targetNode == null) {
+ return;
+ }
+ // maybe static
+ if (target is Identifier) {
+ staticModifier = target.staticElement.kind == ElementKind.CLASS;
+ }
+ // use different utils
+ var targetPath = targetClassElement.source.fullName;
+ var targetResolveResult = await session.getResolvedUnit(targetPath);
+ utils = CorrectionUtils(targetResolveResult);
+ }
+ ClassMemberLocation targetLocation =
+ utils.prepareNewMethodLocation(targetNode);
+ String targetFile = targetElement.source.fullName;
+ // build method source
+ var changeBuilder = _newDartChangeBuilder();
+ await changeBuilder.addFileEdit(targetFile, (DartFileEditBuilder builder) {
+ builder.addInsertion(targetLocation.offset, (DartEditBuilder builder) {
+ builder.write(targetLocation.prefix);
+ // maybe "static"
+ if (staticModifier) {
+ builder.write('static ');
+ }
+ // append return type
+ {
+ DartType type = _inferUndefinedExpressionType(invocation);
+ if (builder.writeType(type, groupName: 'RETURN_TYPE')) {
+ builder.write(' ');
+ }
+ }
+ // append name
+ builder.addLinkedEdit('NAME', (DartLinkedEditBuilder builder) {
+ builder.write(name);
+ });
+ builder.write('(');
+ builder.writeParametersMatchingArguments(invocation.argumentList);
+ builder.write(') {}');
+ builder.write(targetLocation.suffix);
+ });
+ if (targetFile == file) {
+ builder.addLinkedPosition(range.node(node), 'NAME');
+ }
+ });
+ _addFixFromBuilder(changeBuilder, DartFixKind.CREATE_METHOD, args: [name]);
+ }
+
Future<void> _addFix_createMissingOverrides() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (node.parent is! ClassDeclaration) {
return;
}
@@ -2294,8 +2435,6 @@
}
Future<void> _addFix_createNoSuchMethod() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (node.parent is! ClassDeclaration) {
return;
}
@@ -2322,8 +2461,6 @@
}
Future<void> _addFix_createPartUri() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
// TODO(brianwilkerson) Generalize this to allow other valid string literals.
if (node is SimpleStringLiteral && node.parent is PartDirective) {
PartDirective partDirective = node.parent;
@@ -2342,6 +2479,91 @@
}
}
+ Future<void> _addFix_createSetter() async {
+ if (node is! SimpleIdentifier) {
+ return;
+ }
+ SimpleIdentifier nameNode = node;
+ if (!nameNode.inSetterContext()) {
+ return;
+ }
+ // prepare target
+ Expression target;
+ {
+ AstNode nameParent = nameNode.parent;
+ if (nameParent is PrefixedIdentifier) {
+ target = nameParent.prefix;
+ } else if (nameParent is PropertyAccess) {
+ target = nameParent.realTarget;
+ }
+ }
+ // prepare target element
+ bool staticModifier = false;
+ Element targetElement;
+ if (target is ExtensionOverride) {
+ targetElement = target.staticElement;
+ } else if (target is Identifier &&
+ target.staticElement is ExtensionElement) {
+ targetElement = target.staticElement;
+ staticModifier = true;
+ } else if (target != null) {
+ // prepare target interface type
+ DartType targetType = target.staticType;
+ if (targetType is! InterfaceType) {
+ return;
+ }
+ targetElement = targetType.element;
+ // maybe static
+ if (target is Identifier) {
+ Identifier targetIdentifier = target;
+ Element targetElement = targetIdentifier.staticElement;
+ staticModifier = targetElement?.kind == ElementKind.CLASS;
+ }
+ } else {
+ targetElement =
+ getEnclosingClassElement(node) ?? getEnclosingExtensionElement(node);
+ if (targetElement == null) {
+ return;
+ }
+ staticModifier = _inStaticContext();
+ }
+ if (targetElement.librarySource.isInSystemLibrary) {
+ return;
+ }
+ // prepare target declaration
+ var targetDeclarationResult =
+ await sessionHelper.getElementDeclaration(targetElement);
+ if (targetDeclarationResult.node is! ClassOrMixinDeclaration &&
+ targetDeclarationResult.node is! ExtensionDeclaration) {
+ return;
+ }
+ CompilationUnitMember targetNode = targetDeclarationResult.node;
+ // prepare location
+ ClassMemberLocation targetLocation = CorrectionUtils(
+ targetDeclarationResult.resolvedUnit)
+ .prepareNewGetterLocation(targetNode); // Rename to "AccessorLocation"
+ // build method source
+ Source targetSource = targetElement.source;
+ String targetFile = targetSource.fullName;
+ String name = nameNode.name;
+ var changeBuilder = _newDartChangeBuilder();
+ await changeBuilder.addFileEdit(targetFile, (DartFileEditBuilder builder) {
+ builder.addInsertion(targetLocation.offset, (DartEditBuilder builder) {
+ Expression parameterTypeNode = climbPropertyAccess(nameNode);
+ DartType parameterType =
+ _inferUndefinedExpressionType(parameterTypeNode);
+ builder.write(targetLocation.prefix);
+ builder.writeSetterDeclaration(name,
+ isStatic: staticModifier,
+ nameGroupName: 'NAME',
+ parameterType: parameterType,
+ parameterTypeGroupName: 'TYPE');
+ builder.write(targetLocation.suffix);
+ });
+ });
+ _addFixFromBuilder(changeBuilder, DartFixKind.CREATE_SETTER, args: [name]);
+ }
+
Future<void> _addFix_extendClassForMixin() async {
ClassDeclaration declaration =
node.thisOrAncestorOfType<ClassDeclaration>();
@@ -2364,8 +2586,6 @@
}
Future<void> _addFix_illegalAsyncReturnType() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
// prepare the existing type
TypeAnnotation typeName = node.thisOrAncestorOfType<TypeAnnotation>();
TypeProvider typeProvider = this.typeProvider;
@@ -2383,8 +2603,6 @@
Future<void> _addFix_importLibrary(FixKind kind, Uri library,
[String relativeURI = null]) async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
String uriText;
var changeBuilder = _newDartChangeBuilder();
await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
@@ -2407,8 +2625,6 @@
String name,
List<ElementKind> elementKinds,
List<TopLevelDeclarationKind> kinds2) async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
// ignore if private
if (name.startsWith('_')) {
return;
@@ -2508,9 +2724,15 @@
}
}
+ Future<void> _addFix_importLibrary_withExtension() async {
+ String extensionName = (node as SimpleIdentifier).name;
+ await _addFix_importLibrary_withElement(
+ extensionName,
+ const [ElementKind.EXTENSION],
+ const [TopLevelDeclarationKind.extension]);
+ }
+
Future<void> _addFix_importLibrary_withFunction() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (node is SimpleIdentifier) {
if (node.parent is MethodInvocation) {
MethodInvocation invocation = node.parent as MethodInvocation;
@@ -2531,8 +2753,6 @@
}
Future<void> _addFix_importLibrary_withTopLevelVariable() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (node is SimpleIdentifier) {
String name = (node as SimpleIdentifier).name;
await _addFix_importLibrary_withElement(
@@ -2543,8 +2763,6 @@
}
Future<void> _addFix_importLibrary_withType() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (_mayBeTypeIdentifier(node)) {
String typeName = (node as SimpleIdentifier).name;
await _addFix_importLibrary_withElement(
@@ -2559,8 +2777,6 @@
}
Future<void> _addFix_insertSemicolon() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (error.message.contains("';'")) {
if (_isAwaitNode()) {
return;
@@ -2575,8 +2791,6 @@
}
Future<void> _addFix_isNotEmpty() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (node is! PrefixExpression) {
return;
}
@@ -2603,8 +2817,6 @@
}
Future<void> _addFix_isNotNull() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (coveredNode is IsExpression) {
IsExpression isExpression = coveredNode as IsExpression;
var changeBuilder = _newDartChangeBuilder();
@@ -2620,8 +2832,6 @@
}
Future<void> _addFix_isNull() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (coveredNode is IsExpression) {
IsExpression isExpression = coveredNode as IsExpression;
var changeBuilder = _newDartChangeBuilder();
@@ -2637,8 +2847,6 @@
}
Future<void> _addFix_makeEnclosingClassAbstract() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
ClassDeclaration enclosingClass =
node.thisOrAncestorOfType<ClassDeclaration>();
if (enclosingClass == null) {
@@ -2655,8 +2863,6 @@
}
Future<void> _addFix_makeFieldNotFinal() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
AstNode node = this.node;
if (node is SimpleIdentifier &&
node.staticElement is PropertyAccessorElement) {
@@ -2700,8 +2906,6 @@
}
Future<void> _addFix_makeVariableFinal() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
AstNode node = this.node;
if (node is SimpleIdentifier && node.parent is VariableDeclaration) {
VariableDeclaration declaration = node.parent;
@@ -2720,6 +2924,37 @@
}
}
+ Future<void> _addFix_makeVariableNotFinal() async {
+ AstNode node = this.node;
+ if (node is SimpleIdentifier &&
+ node.staticElement is LocalVariableElement) {
+ LocalVariableElement variable = node.staticElement;
+ var id = NodeLocator(variable.nameOffset).searchWithin(unit);
+ var decl = id?.parent;
+ if (decl is VariableDeclaration &&
+ decl.parent is VariableDeclarationList) {
+ VariableDeclarationList declarationList = decl.parent;
+ var keywordToken = declarationList.keyword;
+ if (declarationList.variables.length == 1 &&
+ keywordToken.keyword == Keyword.FINAL) {
+ var changeBuilder = _newDartChangeBuilder();
+ await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+ if (declarationList.type != null) {
+ builder.addDeletion(
+ range.startStart(keywordToken, declarationList.type));
+ } else {
+ builder.addSimpleReplacement(range.token(keywordToken), 'var');
+ }
+ });
+ declarationList.variables[0].name.name;
+ var varName = declarationList.variables[0].name.name;
+ _addFixFromBuilder(changeBuilder, DartFixKind.MAKE_VARIABLE_NOT_FINAL,
+ args: [varName]);
+ }
+ }
+ }
+ }
+
Future<void> _addFix_moveTypeArgumentsToClass() async {
if (coveredNode is TypeArgumentList) {
TypeArgumentList typeArguments = coveredNode;
@@ -2748,8 +2983,6 @@
}
Future<void> _addFix_nonBoolCondition_addNotNull() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
var changeBuilder = _newDartChangeBuilder();
await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
builder.addSimpleInsertion(error.offset + error.length, ' != null');
@@ -2801,8 +3034,6 @@
}
Future<void> _addFix_removeAwait() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
final awaitExpression = node;
if (awaitExpression is AwaitExpression) {
final awaitToken = awaitExpression.awaitKeyword;
@@ -2890,8 +3121,6 @@
}
Future<void> _addFix_removeEmptyCatch() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
var changeBuilder = _newDartChangeBuilder();
await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
builder.addDeletion(utils.getLinesRange(range.node(node.parent)));
@@ -2900,8 +3129,6 @@
}
Future<void> _addFix_removeEmptyConstructorBody() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
var changeBuilder = _newDartChangeBuilder();
await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
builder.addSimpleReplacement(
@@ -2912,8 +3139,6 @@
}
Future<void> _addFix_removeEmptyElse() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
IfStatement ifStatement = node.parent;
var changeBuilder = _newDartChangeBuilder();
await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
@@ -2924,8 +3149,6 @@
}
Future<void> _addFix_removeEmptyStatement() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
EmptyStatement emptyStatement = node;
if (emptyStatement.parent is Block) {
var changeBuilder = _newDartChangeBuilder();
@@ -2947,8 +3170,6 @@
}
Future<void> _addFix_removeInitializer() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
// Retrieve the linted node.
VariableDeclaration ancestor =
node.thisOrAncestorOfType<VariableDeclaration>();
@@ -2963,8 +3184,6 @@
}
Future<void> _addFix_removeInterpolationBraces() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
AstNode node = this.node;
if (node is InterpolationExpression) {
Token right = node.rightBracket;
@@ -2982,8 +3201,6 @@
}
Future<void> _addFix_removeMethodDeclaration() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
MethodDeclaration declaration =
node.thisOrAncestorOfType<MethodDeclaration>();
if (declaration != null) {
@@ -3070,8 +3287,6 @@
}
Future<void> _addFix_removeParameters_inGetterDeclaration() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (node is MethodDeclaration) {
// Support for the analyzer error.
MethodDeclaration method = node as MethodDeclaration;
@@ -3097,8 +3312,6 @@
}
Future<void> _addFix_removeParentheses_inGetterInvocation() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (node is SimpleIdentifier && node.parent is MethodInvocation) {
MethodInvocation invocation = node.parent as MethodInvocation;
if (invocation.methodName == node && invocation.target != null) {
@@ -3113,8 +3326,6 @@
}
Future<void> _addFix_removeThisExpression() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
final thisExpression = node is ThisExpression
? node
: node.thisOrAncestorOfType<ThisExpression>();
@@ -3135,8 +3346,6 @@
}
Future<void> _addFix_removeTypeAnnotation() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
final TypeAnnotation type = node.thisOrAncestorOfType<TypeAnnotation>();
if (type != null) {
var changeBuilder = _newDartChangeBuilder();
@@ -3159,8 +3368,6 @@
}
Future<void> _addFix_removeUnnecessaryCast() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (coveredNode is! AsExpression) {
return;
}
@@ -3177,8 +3384,6 @@
}
Future<void> _addFix_removeUnusedCatchClause() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (node is SimpleIdentifier) {
AstNode catchClause = node.parent;
if (catchClause is CatchClause &&
@@ -3195,8 +3400,6 @@
}
Future<void> _addFix_removeUnusedCatchStack() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (node is SimpleIdentifier) {
AstNode catchClause = node.parent;
if (catchClause is CatchClause &&
@@ -3214,8 +3417,6 @@
}
Future<void> _addFix_removeUnusedImport() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
// prepare ImportDirective
ImportDirective importDirective =
node.thisOrAncestorOfType<ImportDirective>();
@@ -3231,8 +3432,6 @@
}
Future<void> _addFix_renameToCamelCase() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (node is! SimpleIdentifier) {
return;
}
@@ -3286,8 +3485,6 @@
}
Future<void> _addFix_replaceFinalWithConst() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (node is VariableDeclarationList) {
var changeBuilder = _newDartChangeBuilder();
await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
@@ -3298,6 +3495,23 @@
}
}
+ Future<void> _addFix_replaceNewWithConst() async {
+ var node = coveredNode;
+ if (node is ConstructorName) {
+ node = node.parent;
+ }
+ if (node is InstanceCreationExpression) {
+ final keyword = node.keyword;
+ if (keyword != null) {
+ final changeBuilder = _newDartChangeBuilder();
+ await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+ builder.addSimpleReplacement(range.token(keyword), 'const');
+ });
+ _addFixFromBuilder(changeBuilder, DartFixKind.REPLACE_NEW_WITH_CONST);
+ }
+ }
+ }
+
Future<void> _addFix_replaceNullWithClosure() async {
var nodeToFix;
var parameters = const <ParameterElement>[];
@@ -3332,8 +3546,6 @@
}
Future<void> _addFix_replaceVarWithDynamic() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
var changeBuilder = _newDartChangeBuilder();
await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
builder.addSimpleReplacement(range.error(error), 'dynamic');
@@ -3342,8 +3554,6 @@
}
Future<void> _addFix_replaceWithConditionalAssignment() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
IfStatement ifStatement =
node is IfStatement ? node : node.thisOrAncestorOfType<IfStatement>();
if (ifStatement == null) {
@@ -3378,8 +3588,6 @@
}
Future<void> _addFix_replaceWithConstInstanceCreation() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (coveredNode is InstanceCreationExpression) {
var instanceCreation = coveredNode as InstanceCreationExpression;
var changeBuilder = _newDartChangeBuilder();
@@ -3397,8 +3605,6 @@
}
Future<void> _addFix_replaceWithIdentifier() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
final FunctionTypedFormalParameter functionTyped =
node.thisOrAncestorOfType<FunctionTypedFormalParameter>();
if (functionTyped != null) {
@@ -3518,16 +3724,12 @@
}
Future<void> _addFix_replaceWithTearOff() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
FunctionExpression ancestor =
node.thisOrAncestorOfType<FunctionExpression>();
if (ancestor == null) {
return;
}
Future<void> addFixOfExpression(InvocationExpression expression) async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
var changeBuilder = _newDartChangeBuilder();
await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
builder.addReplacement(range.node(ancestor), (DartEditBuilder builder) {
@@ -3558,8 +3760,6 @@
}
Future<void> _addFix_undefinedClass_useSimilar() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
AstNode node = this.node;
// Prepare the optional import prefix name.
String prefixName = null;
@@ -3609,15 +3809,14 @@
}
Future<void> _addFix_undefinedClassAccessor_useSimilar() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
AstNode node = this.node;
if (node is SimpleIdentifier) {
// prepare target
Expression target = null;
if (node.parent is PrefixedIdentifier) {
- PrefixedIdentifier invocation = node.parent as PrefixedIdentifier;
- target = invocation.prefix;
+ target = (node.parent as PrefixedIdentifier).prefix;
+ } else if (node.parent is PropertyAccess) {
+ target = (node.parent as PropertyAccess).target;
}
// find getter
if (node.inGetterContext()) {
@@ -3640,8 +3839,6 @@
Future<void> _addFix_undefinedClassMember_useSimilar(
Expression target, ElementPredicate predicate) async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (node is SimpleIdentifier) {
String name = (node as SimpleIdentifier).name;
_ClosestElementFinder finder =
@@ -3653,6 +3850,11 @@
ClassElement classElement = clazz.declaredElement;
_updateFinderWithClassMembers(finder, classElement);
}
+ } else if (target is ExtensionOverride) {
+ _updateFinderWithExtensionMembers(finder, target.staticElement);
+ } else if (target is Identifier &&
+ target.staticElement is ExtensionElement) {
+ _updateFinderWithExtensionMembers(finder, target.staticElement);
} else {
DartType type = target.staticType;
if (type is InterfaceType) {
@@ -3662,7 +3864,7 @@
}
// if we have close enough element, suggest to use it
if (finder._element != null) {
- String closestName = finder._element.name;
+ String closestName = finder._element.displayName;
var changeBuilder = _newDartChangeBuilder();
await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
builder.addSimpleReplacement(range.node(node), closestName);
@@ -3674,8 +3876,6 @@
}
Future<void> _addFix_undefinedFunction_create() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
// should be the name of the invocation
if (node is SimpleIdentifier && node.parent is MethodInvocation) {
} else {
@@ -3723,8 +3923,6 @@
}
Future<void> _addFix_undefinedFunction_useSimilar() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
AstNode node = this.node;
if (node is SimpleIdentifier) {
// Prepare the optional import prefix name.
@@ -3770,98 +3968,7 @@
}
}
- Future<void> _addFix_undefinedMethod_create() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
- if (node is SimpleIdentifier && node.parent is MethodInvocation) {
- String name = (node as SimpleIdentifier).name;
- MethodInvocation invocation = node.parent as MethodInvocation;
- // prepare environment
- Element targetElement;
- bool staticModifier = false;
-
- ClassOrMixinDeclaration targetClassNode;
- Expression target = invocation.realTarget;
- CorrectionUtils utils = this.utils;
- if (target == null) {
- targetElement = unit.declaredElement;
- ClassMember enclosingMember = node.thisOrAncestorOfType<ClassMember>();
- if (enclosingMember == null) {
- // If the undefined identifier isn't inside a class member, then it
- // doesn't make sense to create a method.
- return;
- }
- targetClassNode = enclosingMember.parent;
- utils.targetClassElement = targetClassNode.declaredElement;
- staticModifier = _inStaticContext();
- } else {
- // prepare target interface type
- DartType targetType = target.staticType;
- if (targetType is! InterfaceType) {
- return;
- }
- ClassElement targetClassElement = targetType.element as ClassElement;
- if (targetClassElement.librarySource.isInSystemLibrary) {
- return;
- }
- targetElement = targetClassElement;
- // prepare target ClassDeclaration
- targetClassNode = await _getClassDeclaration(targetClassElement);
- if (targetClassNode == null) {
- return;
- }
- // maybe static
- if (target is Identifier) {
- staticModifier =
- resolutionMap.staticElementForIdentifier(target).kind ==
- ElementKind.CLASS;
- }
- // use different utils
- var targetPath = targetClassElement.source.fullName;
- var targetResolveResult = await session.getResolvedUnit(targetPath);
- utils = CorrectionUtils(targetResolveResult);
- }
- ClassMemberLocation targetLocation =
- utils.prepareNewMethodLocation(targetClassNode);
- String targetFile = targetElement.source.fullName;
- // build method source
- var changeBuilder = _newDartChangeBuilder();
- await changeBuilder.addFileEdit(targetFile,
- (DartFileEditBuilder builder) {
- builder.addInsertion(targetLocation.offset, (DartEditBuilder builder) {
- builder.write(targetLocation.prefix);
- // maybe "static"
- if (staticModifier) {
- builder.write('static ');
- }
- // append return type
- {
- DartType type = _inferUndefinedExpressionType(invocation);
- if (builder.writeType(type, groupName: 'RETURN_TYPE')) {
- builder.write(' ');
- }
- }
- // append name
- builder.addLinkedEdit('NAME', (DartLinkedEditBuilder builder) {
- builder.write(name);
- });
- builder.write('(');
- builder.writeParametersMatchingArguments(invocation.argumentList);
- builder.write(') {}');
- builder.write(targetLocation.suffix);
- });
- if (targetFile == file) {
- builder.addLinkedPosition(range.node(node), 'NAME');
- }
- });
- _addFixFromBuilder(changeBuilder, DartFixKind.CREATE_METHOD,
- args: [name]);
- }
- }
-
Future<void> _addFix_undefinedMethod_useSimilar() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (node.parent is MethodInvocation) {
MethodInvocation invocation = node.parent as MethodInvocation;
await _addFix_undefinedClassMember_useSimilar(invocation.realTarget,
@@ -3874,8 +3981,6 @@
* final fields.
*/
Future<void> _addFix_updateConstructor_forUninitializedFinalFields() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (node is! SimpleIdentifier || node.parent is! ConstructorDeclaration) {
return;
}
@@ -3982,8 +4087,6 @@
}
Future<void> _addFix_useEffectiveIntegerDivision() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
for (AstNode n = node; n != null; n = n.parent) {
if (n is MethodInvocation &&
n.offset == errorOffset &&
@@ -4026,8 +4129,6 @@
}
Future<void> _addFix_useStaticAccess_method() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (node is SimpleIdentifier && node.parent is MethodInvocation) {
MethodInvocation invocation = node.parent as MethodInvocation;
if (invocation.methodName == node) {
@@ -4039,8 +4140,6 @@
}
Future<void> _addFix_useStaticAccess_property() async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
if (node is SimpleIdentifier && node.parent is PrefixedIdentifier) {
PrefixedIdentifier prefixed = node.parent as PrefixedIdentifier;
if (prefixed.identifier == node) {
@@ -4053,6 +4152,7 @@
void _addFixFromBuilder(ChangeBuilder builder, FixKind kind,
{List args = null, bool importsOnly = false}) {
+ if (builder == null) return;
SourceChange change = builder.sourceChange;
if (change.edits.isEmpty && !importsOnly) {
return;
@@ -4075,8 +4175,6 @@
String sourcePrefix,
String sourceSuffix,
Element target) async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
// build method source
var changeBuilder = _newDartChangeBuilder();
await changeBuilder.addFileEdit(targetFile, (DartFileEditBuilder builder) {
@@ -4138,8 +4236,6 @@
*/
Future<void> _addProposal_createFunction_function(
FunctionType functionType) async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
String name = (node as SimpleIdentifier).name;
// prepare environment
int insertOffset = unit.end;
@@ -4167,8 +4263,6 @@
*/
Future<void> _addProposal_createFunction_method(
ClassElement targetClassElement, FunctionType functionType) async {
- // TODO(brianwilkerson) Determine whether this await is necessary.
- await null;
String name = (node as SimpleIdentifier).name;
// prepare environment
Source targetSource = targetClassElement.source;
@@ -4200,9 +4294,7 @@
_addFixFromBuilder(changeBuilder, DartFixKind.CREATE_METHOD, args: [name]);
}
- /**
- * Returns the [ClassOrMixinDeclaration] for the given [element].
- */
+ /// Return the class, enum or mixin declaration for the given [element].
Future<ClassOrMixinDeclaration> _getClassDeclaration(
ClassElement element) async {
var result = await sessionHelper.getElementDeclaration(element);
@@ -4245,6 +4337,16 @@
return null;
}
+ /// Return the extension declaration for the given [element].
+ Future<ExtensionDeclaration> _getExtensionDeclaration(
+ ExtensionElement element) async {
+ var result = await sessionHelper.getElementDeclaration(element);
+ if (result.node is ExtensionDeclaration) {
+ return result.node;
+ }
+ return null;
+ }
+
/**
* Return the relative uri from the passed [library] to the given [path].
* If the [path] is not in the LibraryElement, `null` is returned.
@@ -4516,6 +4618,13 @@
}
}
+ void _updateFinderWithExtensionMembers(
+ _ClosestElementFinder finder, ExtensionElement element) {
+ if (element != null) {
+ finder._updateList(getExtensionMembers(element));
+ }
+ }
+
static bool _isNameOfType(String name) {
if (name.isEmpty) {
return false;
@@ -4563,51 +4672,6 @@
}
/**
- * An enumeration of lint names.
- */
-class LintNames {
- static const String always_require_non_null_named_parameters =
- 'always_require_non_null_named_parameters';
- static const String annotate_overrides = 'annotate_overrides';
- static const String avoid_annotating_with_dynamic =
- 'avoid_annotating_with_dynamic';
- static const String avoid_empty_else = 'avoid_empty_else';
- static const String avoid_init_to_null = 'avoid_init_to_null';
- static const String avoid_return_types_on_setters =
- 'avoid_return_types_on_setters';
- static const String avoid_types_on_closure_parameters =
- 'avoid_types_on_closure_parameters';
- static const String await_only_futures = 'await_only_futures';
- static const String empty_catches = 'empty_catches';
- static const String empty_constructor_bodies = 'empty_constructor_bodies';
- static const String empty_statements = 'empty_statements';
- static const String no_duplicate_case_values = 'no_duplicate_case_values';
- static const String non_constant_identifier_names =
- 'non_constant_identifier_names';
- static const String null_closures = 'null_closures';
- static const String prefer_collection_literals = 'prefer_collection_literals';
- static const String prefer_conditional_assignment =
- 'prefer_conditional_assignment';
- static const String prefer_const_declarations = 'prefer_const_declarations';
- static const String prefer_equal_for_default_values =
- 'prefer_equal_for_default_values';
- static const String prefer_final_fields = 'prefer_final_fields';
- static const String prefer_final_locals = 'prefer_final_locals';
- static const String prefer_is_empty = 'prefer_is_empty';
- static const String prefer_is_not_empty = 'prefer_is_not_empty';
- static const String type_init_formals = 'type_init_formals';
- static const String unawaited_futures = 'unawaited_futures';
- static const String unnecessary_brace_in_string_interps =
- 'unnecessary_brace_in_string_interps';
- static const String unnecessary_const = 'unnecessary_const';
- static const String unnecessary_lambdas = 'unnecessary_lambdas';
- static const String unnecessary_new = 'unnecessary_new';
- static const String unnecessary_overrides = 'unnecessary_overrides';
- static const String unnecessary_this = 'unnecessary_this';
- static const String use_rethrow_when_possible = 'use_rethrow_when_possible';
-}
-
-/**
* Helper for finding [Element] with name closest to the given.
*/
class _ClosestElementFinder {
diff --git a/pkg/analysis_server/lib/src/services/correction/namespace.dart b/pkg/analysis_server/lib/src/services/correction/namespace.dart
index 878ed69..70e5683 100644
--- a/pkg/analysis_server/lib/src/services/correction/namespace.dart
+++ b/pkg/analysis_server/lib/src/services/correction/namespace.dart
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/dart/resolver/scope.dart';
@@ -127,8 +126,7 @@
// prepare environment
AstNode parent = prefixNode.parent;
CompilationUnit unit = prefixNode.thisOrAncestorOfType<CompilationUnit>();
- LibraryElement libraryElement =
- resolutionMap.elementDeclaredByCompilationUnit(unit).library;
+ LibraryElement libraryElement = unit.declaredElement.library;
// prepare used element
Element usedElement = null;
if (parent is PrefixedIdentifier) {
diff --git a/pkg/analysis_server/lib/src/services/correction/util.dart b/pkg/analysis_server/lib/src/services/correction/util.dart
index 1fcc638..4519397 100644
--- a/pkg/analysis_server/lib/src/services/correction/util.dart
+++ b/pkg/analysis_server/lib/src/services/correction/util.dart
@@ -232,18 +232,10 @@
}
}
-/**
- * If the given [AstNode] is in a [ClassOrMixinDeclaration], returns the
- * [ClassElement]. Otherwise returns `null`.
- */
-ClassElement getEnclosingClassElement(AstNode node) {
- ClassOrMixinDeclaration enclosingClassNode =
- node.thisOrAncestorOfType<ClassOrMixinDeclaration>();
- if (enclosingClassNode != null) {
- return enclosingClassNode.declaredElement;
- }
- return null;
-}
+/// If the given [node] is in a class, enum or mixin declaration, return the
+/// declared [ClassElement]. Otherwise return `null`.
+ClassElement getEnclosingClassElement(AstNode node) =>
+ node.thisOrAncestorOfType<ClassOrMixinDeclaration>()?.declaredElement;
/**
* Returns a class or an unit member enclosing the given [node].
@@ -301,6 +293,11 @@
return null;
}
+/// If the given [node] is in an extension, return the declared
+/// [ExtensionElement]. Otherwise return `null`.
+ExtensionElement getEnclosingExtensionElement(AstNode node) =>
+ node.thisOrAncestorOfType<ExtensionDeclaration>()?.declaredElement;
+
/**
* Returns [getExpressionPrecedence] for the parent of [node], or
* ASSIGNMENT_PRECEDENCE if the parent node is a [ParenthesizedExpression].
@@ -1042,22 +1039,22 @@
}
/**
- * @return the source of the inverted condition for the given logical expression.
+ * Return the source of the inverted condition for the given logical expression.
*/
String invertCondition(Expression expression) =>
_invertCondition0(expression)._source;
/**
- * Return `true` if the given [classDeclaration] has open '{' and close '}'
- * at the same line, e.g. `class X {}`.
+ * Return `true` if the given class, mixin, enum or extension [declaration]
+ * has open '{' and close '}' on the same line, e.g. `class X {}`.
*/
- bool isClassWithEmptyBody(ClassOrMixinDeclaration classDeclaration) {
- return getLineThis(classDeclaration.leftBracket.offset) ==
- getLineThis(classDeclaration.rightBracket.offset);
+ bool isClassWithEmptyBody(CompilationUnitMember declaration) {
+ return getLineThis(_getLeftBracket(declaration).offset) ==
+ getLineThis(_getRightBracket(declaration).offset);
}
/**
- * @return <code>true</code> if selection range contains only whitespace or comments
+ * Return <code>true</code> if [range] contains only whitespace or comments.
*/
bool isJustWhitespaceOrComment(SourceRange range) {
String trimmedText = getRangeText(range).trim();
@@ -1070,12 +1067,15 @@
}
ClassMemberLocation prepareNewClassMemberLocation(
- ClassOrMixinDeclaration classDeclaration,
+ CompilationUnitMember declaration,
bool shouldSkip(ClassMember existingMember)) {
String indent = getIndent(1);
// Find the last target member.
ClassMember targetMember = null;
- List<ClassMember> members = classDeclaration.members;
+ List<ClassMember> members = _getMembers(declaration);
+ if (members == null) {
+ return null;
+ }
for (ClassMember member in members) {
if (shouldSkip(member)) {
targetMember = member;
@@ -1089,11 +1089,11 @@
endOfLine + endOfLine + indent, targetMember.end, '');
}
// At the beginning of the class.
- String suffix = members.isNotEmpty || isClassWithEmptyBody(classDeclaration)
+ String suffix = members.isNotEmpty || isClassWithEmptyBody(declaration)
? endOfLine
: '';
return new ClassMemberLocation(
- endOfLine + indent, classDeclaration.leftBracket.end, suffix);
+ endOfLine + indent, _getLeftBracket(declaration).end, suffix);
}
ClassMemberLocation prepareNewConstructorLocation(
@@ -1105,15 +1105,15 @@
}
ClassMemberLocation prepareNewFieldLocation(
- ClassOrMixinDeclaration classDeclaration) {
+ CompilationUnitMember declaration) {
return prepareNewClassMemberLocation(
- classDeclaration, (member) => member is FieldDeclaration);
+ declaration, (member) => member is FieldDeclaration);
}
ClassMemberLocation prepareNewGetterLocation(
- ClassOrMixinDeclaration classDeclaration) {
+ CompilationUnitMember declaration) {
return prepareNewClassMemberLocation(
- classDeclaration,
+ declaration,
(member) =>
member is FieldDeclaration ||
member is ConstructorDeclaration ||
@@ -1121,9 +1121,9 @@
}
ClassMemberLocation prepareNewMethodLocation(
- ClassOrMixinDeclaration classDeclaration) {
+ CompilationUnitMember declaration) {
return prepareNewClassMemberLocation(
- classDeclaration,
+ declaration,
(member) =>
member is FieldDeclaration ||
member is ConstructorDeclaration ||
@@ -1236,6 +1236,33 @@
return null;
}
+ Token _getLeftBracket(CompilationUnitMember declaration) {
+ if (declaration is ClassOrMixinDeclaration) {
+ return declaration.leftBracket;
+ } else if (declaration is ExtensionDeclaration) {
+ return declaration.leftBracket;
+ }
+ return null;
+ }
+
+ List<ClassMember> _getMembers(CompilationUnitMember declaration) {
+ if (declaration is ClassOrMixinDeclaration) {
+ return declaration.members;
+ } else if (declaration is ExtensionDeclaration) {
+ return declaration.members;
+ }
+ return null;
+ }
+
+ Token _getRightBracket(CompilationUnitMember declaration) {
+ if (declaration is ClassOrMixinDeclaration) {
+ return declaration.rightBracket;
+ } else if (declaration is ExtensionDeclaration) {
+ return declaration.rightBracket;
+ }
+ return null;
+ }
+
/**
* @return the [InvertedCondition] for the given logical expression.
*/
@@ -1358,6 +1385,17 @@
* Utilities to work with [Token]s.
*/
class TokenUtils {
+ static List<Token> getNodeTokens(AstNode node) {
+ var result = <Token>[];
+ for (var token = node.beginToken;; token = token.next) {
+ result.add(token);
+ if (token == node.endToken) {
+ break;
+ }
+ }
+ return result;
+ }
+
/**
* @return [Token]s of the given Dart source, not <code>null</code>, may be empty if no
* tokens or some exception happens.
diff --git a/pkg/analysis_server/lib/src/services/kythe/kythe_visitors.dart b/pkg/analysis_server/lib/src/services/kythe/kythe_visitors.dart
index 0758a37..e9346c0 100644
--- a/pkg/analysis_server/lib/src/services/kythe/kythe_visitors.dart
+++ b/pkg/analysis_server/lib/src/services/kythe/kythe_visitors.dart
@@ -5,7 +5,6 @@
import 'dart:convert';
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/ast/syntactic_entity.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
@@ -353,8 +352,7 @@
// Don't use visitLibraryDirective as this won't generate a package
// VName for libraries that don't have a library directive.
- var libraryElement =
- resolutionMap.elementDeclaredByCompilationUnit(node).library;
+ var libraryElement = node.declaredElement.library;
if (libraryElement.definingCompilationUnit == node.declaredElement) {
LibraryDirective libraryDirective;
for (var directive in node.directives) {
@@ -433,8 +431,7 @@
@override
visitDeclaredIdentifier(DeclaredIdentifier node) {
_handleVariableDeclaration(node.declaredElement, node.identifier,
- subKind: schema.LOCAL_SUBKIND,
- type: resolutionMap.elementDeclaredByDeclaredIdentifier(node).type);
+ subKind: schema.LOCAL_SUBKIND, type: node.declaredElement.type);
// no children
}
@@ -638,8 +635,7 @@
// constructorName
//
var constructorName = node.constructorName;
- var constructorElement =
- resolutionMap.staticElementForConstructorReference(constructorName);
+ var constructorElement = constructorName.staticElement;
if (constructorElement != null) {
// anchor- ref/call
_handleRefCallEdge(constructorElement,
@@ -786,11 +782,8 @@
}
// type
- addEdge(
- paramVName,
- schema.TYPED_EDGE,
- _vNameFromType(
- resolutionMap.elementDeclaredByFormalParameter(node).type));
+ addEdge(paramVName, schema.TYPED_EDGE,
+ _vNameFromType(node.declaredElement.type));
// visit children
_safelyVisit(node.documentationComment);
@@ -851,7 +844,7 @@
// variable
_handleVariableDeclaration(node.declaredElement, node.name,
subKind: isLocal ? schema.LOCAL_SUBKIND : schema.FIELD_SUBKIND,
- type: resolutionMap.elementDeclaredByVariableDeclaration(node).type);
+ type: node.declaredElement.type);
// visit children
_safelyVisit(node.initializer);
@@ -1239,7 +1232,7 @@
if (returnNode is TypeName) {
// MethodDeclaration and FunctionDeclaration both return a TypeName from
// returnType
- if (resolutionMap.typeForTypeName(returnNode).isVoid) {
+ if (returnNode.type.isVoid) {
returnTypeVName = voidBuiltin;
} else {
returnTypeVName =
@@ -1247,7 +1240,7 @@
}
} else if (returnNode is Identifier) {
// ConstructorDeclaration returns an Identifier from returnType
- if (resolutionMap.staticTypeForExpression(returnNode).isVoid) {
+ if (returnNode.staticType.isVoid) {
returnTypeVName = voidBuiltin;
} else {
returnTypeVName =
@@ -1264,16 +1257,9 @@
if (paramNodes != null) {
for (FormalParameter paramNode in paramNodes.parameters) {
var paramTypeVName = dynamicBuiltin;
- if (!resolutionMap
- .elementDeclaredByFormalParameter(paramNode)
- .type
- .isDynamic) {
+ if (!paramNode.declaredElement.type.isDynamic) {
paramTypeVName = _vNameFromElement(
- resolutionMap
- .elementDeclaredByFormalParameter(paramNode)
- .type
- .element,
- schema.TAPP_KIND);
+ paramNode.declaredElement.type.element, schema.TAPP_KIND);
}
addEdge(funcTypeVName, schema.PARAM_EDGE, paramTypeVName,
ordinalIntValue: i++);
diff --git a/pkg/analysis_server/lib/src/services/linter/lint_names.dart b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
new file mode 100644
index 0000000..c52000b
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
@@ -0,0 +1,61 @@
+// Copyright (c) 2019, 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.
+
+/// An enumeration of lint names.
+class LintNames {
+ static const String always_require_non_null_named_parameters =
+ 'always_require_non_null_named_parameters';
+ static const String always_specify_types = 'always_specify_types';
+ static const String annotate_overrides = 'annotate_overrides';
+ static const String avoid_annotating_with_dynamic =
+ 'avoid_annotating_with_dynamic';
+ static const String avoid_empty_else = 'avoid_empty_else';
+ static const String avoid_init_to_null = 'avoid_init_to_null';
+ static const String avoid_return_types_on_setters =
+ 'avoid_return_types_on_setters';
+ static const String avoid_types_on_closure_parameters =
+ 'avoid_types_on_closure_parameters';
+ static const String await_only_futures = 'await_only_futures';
+ static const String curly_braces_in_flow_control_structures =
+ 'curly_braces_in_flow_control_structures';
+ static const String empty_catches = 'empty_catches';
+ static const String empty_constructor_bodies = 'empty_constructor_bodies';
+ static const String empty_statements = 'empty_statements';
+ static const String no_duplicate_case_values = 'no_duplicate_case_values';
+ static const String non_constant_identifier_names =
+ 'non_constant_identifier_names';
+ static const String null_closures = 'null_closures';
+ static const String prefer_collection_literals = 'prefer_collection_literals';
+ static const String prefer_conditional_assignment =
+ 'prefer_conditional_assignment';
+ static const String prefer_const_constructors = 'prefer_const_constructors';
+ static const String prefer_const_declarations = 'prefer_const_declarations';
+ static const String prefer_equal_for_default_values =
+ 'prefer_equal_for_default_values';
+ static const String prefer_expression_function_bodies =
+ 'prefer_expression_function_bodies';
+ static const String prefer_final_fields = 'prefer_final_fields';
+ static const String prefer_final_locals = 'prefer_final_locals';
+ static const String prefer_for_elements_to_map_fromIterable =
+ 'prefer_for_elements_to_map_fromIterable';
+ static const String prefer_int_literals = 'prefer_int_literals';
+ static const String prefer_if_elements_to_conditional_expressions =
+ 'prefer_if_elements_to_conditional_expressions';
+ static const String prefer_is_empty = 'prefer_is_empty';
+ static const String prefer_is_not_empty = 'prefer_is_not_empty';
+ static const String prefer_null_aware_operators =
+ 'prefer_null_aware_operators';
+ static const String slash_for_doc_comments = 'slash_for_doc_comments';
+ static const String type_annotate_public_apis = 'type_annotate_public_apis';
+ static const String type_init_formals = 'type_init_formals';
+ static const String unawaited_futures = 'unawaited_futures';
+ static const String unnecessary_brace_in_string_interps =
+ 'unnecessary_brace_in_string_interps';
+ static const String unnecessary_const = 'unnecessary_const';
+ static const String unnecessary_lambdas = 'unnecessary_lambdas';
+ static const String unnecessary_new = 'unnecessary_new';
+ static const String unnecessary_overrides = 'unnecessary_overrides';
+ static const String unnecessary_this = 'unnecessary_this';
+ static const String use_rethrow_when_possible = 'use_rethrow_when_possible';
+}
diff --git a/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart b/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
index 1886f88..6c0b9d4 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
@@ -7,10 +7,10 @@
import 'package:analysis_server/src/protocol_server.dart' hide Element;
import 'package:analysis_server/src/services/correction/name_suggestion.dart';
-import 'package:analysis_server/src/services/correction/selection_analyzer.dart';
import 'package:analysis_server/src/services/correction/status.dart';
import 'package:analysis_server/src/services/correction/strings.dart';
import 'package:analysis_server/src/services/correction/util.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analysis_server/src/services/refactoring/naming_conventions.dart';
import 'package:analysis_server/src/services/refactoring/refactoring.dart';
import 'package:analysis_server/src/services/refactoring/refactoring_internal.dart';
@@ -46,9 +46,8 @@
final List<int> offsets = <int>[];
final List<int> lengths = <int>[];
- Expression rootExpression;
+ FunctionBody coveringFunctionBody;
Expression singleExpression;
- bool wholeStatementExpression = false;
String stringLiteralPart;
final List<SourceRange> occurrences = <SourceRange>[];
final Map<Element, int> elementIds = <Element, int>{};
@@ -70,8 +69,10 @@
CompilationUnitElement get unitElement => unit.declaredElement;
String get _declarationKeyword {
- if (_isPartOfConstantExpression(rootExpression)) {
+ if (_isPartOfConstantExpression(singleExpression)) {
return "const";
+ } else if (_isLintEnabled(LintNames.prefer_final_locals)) {
+ return "final";
} else {
return "var";
}
@@ -127,7 +128,8 @@
occurrences.sort((a, b) => a.offset - b.offset);
// If the whole expression of a statement is selected, like '1 + 2',
// then convert it into a variable declaration statement.
- if (wholeStatementExpression && occurrences.length == 1) {
+ if (singleExpression?.parent is ExpressionStatement &&
+ occurrences.length == 1) {
String keyword = _declarationKeyword;
String declarationSource = '$keyword $name = ';
SourceEdit edit =
@@ -234,20 +236,42 @@
'The selection end offset must be less then the length of the file.');
}
- String selectionStr;
+ var selectionStr = utils.getRangeText(selectionRange);
+
// exclude whitespaces
{
- selectionStr = utils.getRangeText(selectionRange);
int numLeading = countLeadingWhitespaces(selectionStr);
int numTrailing = countTrailingWhitespaces(selectionStr);
int offset = selectionRange.offset + numLeading;
int end = selectionRange.end - numTrailing;
selectionRange = new SourceRange(offset, end - offset);
}
+
// get covering node
AstNode coveringNode =
new NodeLocator(selectionRange.offset, selectionRange.end)
.searchWithin(unit);
+
+ // We need an enclosing function.
+ // If it has a block body, we can add a new variable declaration statement
+ // into this block. If it has an expression body, we can convert it into
+ // the block body first.
+ coveringFunctionBody = coveringNode?.thisOrAncestorOfType<FunctionBody>();
+ if (coveringFunctionBody == null) {
+ return new RefactoringStatus.fatal(
+ 'An expression inside a function must be selected '
+ 'to activate this refactoring.');
+ }
+
+ // part of string literal
+ if (coveringNode is StringLiteral) {
+ if (selectionRange.length != 0 &&
+ selectionRange.offset > coveringNode.offset &&
+ selectionRange.end < coveringNode.end) {
+ stringLiteralPart = selectionStr;
+ return new RefactoringStatus();
+ }
+ }
// compute covering expressions
for (AstNode node = coveringNode; node != null; node = node.parent) {
AstNode parent = node.parent;
@@ -259,7 +283,7 @@
continue;
}
if (node is ConstructorName || node is Label || node is TypeName) {
- rootExpression = null;
+ singleExpression = null;
coveringExpressionOffsets.clear();
coveringExpressionLengths.clear();
continue;
@@ -280,7 +304,7 @@
if (element is ExecutableElement &&
element.returnType != null &&
element.returnType.isVoid) {
- if (rootExpression == null) {
+ if (singleExpression == null) {
return new RefactoringStatus.fatal(
'Cannot extract the void expression.',
newLocation_fromNode(node));
@@ -308,37 +332,16 @@
}
}
// set selected expression
- if (coveringExpressionOffsets.isEmpty) {
- rootExpression = node;
+ if (singleExpression == null) {
+ singleExpression = node;
}
// add the expression range
coveringExpressionOffsets.add(node.offset);
coveringExpressionLengths.add(node.length);
}
- // We need an enclosing function.
- // If it has a block body, we can add a new variable declaration statement
- // into this block. If it has an expression body, we can convert it into
- // the block body first.
- if (coveringNode == null ||
- coveringNode.thisOrAncestorOfType<FunctionBody>() == null) {
- return new RefactoringStatus.fatal(
- 'An expression inside a function must be selected '
- 'to activate this refactoring.');
- }
- // part of string literal
- if (coveringNode is StringLiteral) {
- if (selectionRange.length != 0 &&
- selectionRange.offset > coveringNode.offset &&
- selectionRange.end < coveringNode.end) {
- stringLiteralPart = selectionStr;
- return new RefactoringStatus();
- }
- }
// single node selected
- if (rootExpression != null) {
- singleExpression = rootExpression;
+ if (singleExpression != null) {
selectionRange = range.node(singleExpression);
- wholeStatementExpression = singleExpression.parent is ExpressionStatement;
return new RefactoringStatus();
}
// invalid selection
@@ -452,13 +455,9 @@
return null;
}
- /**
- * Checks if it is OK to extract the node with the given [SourceRange].
- */
- bool _isExtractable(SourceRange range) {
- _ExtractExpressionAnalyzer analyzer = new _ExtractExpressionAnalyzer(range);
- utils.unit.accept(analyzer);
- return analyzer.status.isOK;
+ bool _isLintEnabled(String name) {
+ var analysisOptions = unitElement.context.analysisOptions;
+ return analysisOptions.isLintEnabled(name);
}
bool _isPartOfConstantExpression(AstNode node) {
@@ -500,24 +499,15 @@
void _prepareOccurrences() {
occurrences.clear();
elementIds.clear();
+
// prepare selection
String selectionSource;
- {
- String rawSelectionSource = utils.getRangeText(selectionRange);
- List<Token> selectionTokens =
- TokenUtils.getTokens(rawSelectionSource, unit.featureSet);
- selectionSource =
- _encodeExpressionTokens(rootExpression, selectionTokens);
- }
- // prepare enclosing function
- AstNode enclosingFunction;
- {
- AstNode selectionNode =
- new NodeLocator(selectionOffset).searchWithin(unit);
- enclosingFunction = getEnclosingExecutableNode(selectionNode);
+ if (singleExpression != null) {
+ var tokens = TokenUtils.getNodeTokens(singleExpression);
+ selectionSource = _encodeExpressionTokens(singleExpression, tokens);
}
// visit function
- enclosingFunction.accept(new _OccurrencesVisitor(
+ coveringFunctionBody.accept(new _OccurrencesVisitor(
this, occurrences, selectionSource, unit.featureSet));
}
@@ -531,79 +521,6 @@
}
}
-/**
- * [SelectionAnalyzer] for [ExtractLocalRefactoringImpl].
- */
-class _ExtractExpressionAnalyzer extends SelectionAnalyzer {
- final RefactoringStatus status = new RefactoringStatus();
-
- _ExtractExpressionAnalyzer(SourceRange selection) : super(selection);
-
- /**
- * Records fatal error with given message.
- */
- void invalidSelection(String message) {
- _invalidSelection(message, null);
- }
-
- @override
- Object visitAssignmentExpression(AssignmentExpression node) {
- super.visitAssignmentExpression(node);
- Expression lhs = node.leftHandSide;
- if (_isFirstSelectedNode(lhs)) {
- _invalidSelection('Cannot extract the left-hand side of an assignment.',
- newLocation_fromNode(lhs));
- }
- return null;
- }
-
- @override
- Object visitSimpleIdentifier(SimpleIdentifier node) {
- super.visitSimpleIdentifier(node);
- if (_isFirstSelectedNode(node)) {
- // name of declaration
- if (node.inDeclarationContext()) {
- invalidSelection('Cannot extract the name part of a declaration.');
- }
- // method name
- Element element = node.staticElement;
- if (element is FunctionElement || element is MethodElement) {
- invalidSelection('Cannot extract a single method name.');
- }
- // name in property access
- AstNode parent = node.parent;
- if (parent is PrefixedIdentifier && identical(parent.identifier, node)) {
- invalidSelection('Cannot extract name part of a property access.');
- }
- if (parent is PropertyAccess && identical(parent.propertyName, node)) {
- invalidSelection('Cannot extract name part of a property access.');
- }
- }
- return null;
- }
-
- /**
- * Records fatal error with given [message] and [location].
- */
- void _invalidSelection(String message, Location location) {
- status.addFatalError(message, location);
- reset();
- }
-
- bool _isFirstSelectedNode(AstNode node) => node == firstSelectedNode;
-}
-
-class _HasStatementVisitor extends GeneralizingAstVisitor {
- bool result = false;
-
- _HasStatementVisitor();
-
- @override
- visitStatement(Statement node) {
- result = true;
- }
-}
-
class _OccurrencesVisitor extends GeneralizingAstVisitor<void> {
final ExtractLocalRefactoringImpl ref;
final List<SourceRange> occurrences;
@@ -614,20 +531,19 @@
this.ref, this.occurrences, this.selectionSource, this.featureSet);
@override
- void visitBinaryExpression(BinaryExpression node) {
- if (!_hasStatements(node)) {
- _tryToFindOccurrenceFragments(node);
- return;
- }
- super.visitBinaryExpression(node);
+ void visitExpression(Expression node) {
+ _tryToFindOccurrence(node);
+ super.visitExpression(node);
}
@override
- void visitExpression(Expression node) {
- if (ref._isExtractable(range.node(node))) {
- _tryToFindOccurrence(node);
+ void visitSimpleIdentifier(SimpleIdentifier node) {
+ var parent = node.parent;
+ if (parent is VariableDeclaration && parent.name == node ||
+ parent is AssignmentExpression && parent.leftHandSide == node) {
+ return;
}
- super.visitExpression(node);
+ super.visitSimpleIdentifier(node);
}
@override
@@ -659,48 +575,13 @@
}
}
- bool _hasStatements(AstNode root) {
- _HasStatementVisitor visitor = new _HasStatementVisitor();
- root.accept(visitor);
- return visitor.result;
- }
-
void _tryToFindOccurrence(Expression node) {
- String nodeSource = ref.utils.getNodeText(node);
- List<Token> nodeTokens = TokenUtils.getTokens(nodeSource, featureSet);
- nodeSource = ref._encodeExpressionTokens(node, nodeTokens);
+ var nodeTokens = TokenUtils.getNodeTokens(node);
+ var nodeSource = ref._encodeExpressionTokens(node, nodeTokens);
if (nodeSource == selectionSource) {
_addOccurrence(range.node(node));
}
}
-
- void _tryToFindOccurrenceFragments(Expression node) {
- int nodeOffset = node.offset;
- String nodeSource = ref.utils.getNodeText(node);
- List<Token> nodeTokens = TokenUtils.getTokens(nodeSource, featureSet);
- nodeSource = ref._encodeExpressionTokens(node, nodeTokens);
- // find "selection" in "node" tokens
- int lastIndex = 0;
- while (true) {
- // find next occurrence
- int index = nodeSource.indexOf(selectionSource, lastIndex);
- if (index == -1) {
- break;
- }
- lastIndex = index + selectionSource.length;
- // find start/end tokens
- int startTokenIndex =
- countMatches(nodeSource.substring(0, index), _TOKEN_SEPARATOR);
- int endTokenIndex =
- countMatches(nodeSource.substring(0, lastIndex), _TOKEN_SEPARATOR);
- Token startToken = nodeTokens[startTokenIndex];
- Token endToken = nodeTokens[endTokenIndex - 1];
- // add occurrence range
- int start = nodeOffset + startToken.offset;
- int end = nodeOffset + endToken.end;
- _addOccurrence(range.startOffsetEndOffset(start, end));
- }
- }
}
class _TokenLocalElementVisitor extends RecursiveAstVisitor {
diff --git a/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart b/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
index 233123c..a495f56 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
@@ -20,7 +20,6 @@
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
@@ -452,8 +451,7 @@
AstNode parent = _parentMember.parent;
// top-level function
if (parent is CompilationUnit) {
- LibraryElement libraryElement =
- resolutionMap.elementDeclaredByCompilationUnit(parent).library;
+ LibraryElement libraryElement = parent.declaredElement.library;
return validateCreateFunction(searchEngine, libraryElement, name);
}
// method of class
diff --git a/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart b/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart
index 63a2193..a43fac9 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart
@@ -15,6 +15,7 @@
import 'package:analysis_server/src/services/refactoring/move_file.dart';
import 'package:analysis_server/src/services/refactoring/rename_class_member.dart';
import 'package:analysis_server/src/services/refactoring/rename_constructor.dart';
+import 'package:analysis_server/src/services/refactoring/rename_extension_member.dart';
import 'package:analysis_server/src/services/refactoring/rename_import.dart';
import 'package:analysis_server/src/services/refactoring/rename_label.dart';
import 'package:analysis_server/src/services/refactoring/rename_library.dart';
@@ -484,6 +485,9 @@
if (element.enclosingElement is ClassElement) {
return new RenameClassMemberRefactoringImpl(workspace, session, element);
}
+ if (element.enclosingElement is ExtensionElement) {
+ return RenameExtensionMemberRefactoringImpl(workspace, session, element);
+ }
return null;
}
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_extension_member.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_extension_member.dart
new file mode 100644
index 0000000..f8b7eb2
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_extension_member.dart
@@ -0,0 +1,227 @@
+// Copyright (c) 2019, 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 'package:analysis_server/src/protocol_server.dart'
+ hide Element, ElementKind;
+import 'package:analysis_server/src/services/correction/status.dart';
+import 'package:analysis_server/src/services/correction/util.dart';
+import 'package:analysis_server/src/services/refactoring/naming_conventions.dart';
+import 'package:analysis_server/src/services/refactoring/refactoring.dart';
+import 'package:analysis_server/src/services/refactoring/rename.dart';
+import 'package:analysis_server/src/services/refactoring/visible_ranges_computer.dart';
+import 'package:analysis_server/src/services/search/hierarchy.dart';
+import 'package:analysis_server/src/services/search/search_engine.dart';
+import 'package:analyzer/dart/analysis/session.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/analysis/session_helper.dart';
+import 'package:analyzer/src/generated/java_core.dart';
+import 'package:analyzer/src/generated/source.dart';
+
+/**
+ * A [Refactoring] for renaming extension member [Element]s.
+ */
+class RenameExtensionMemberRefactoringImpl extends RenameRefactoringImpl {
+ final AnalysisSessionHelper sessionHelper;
+
+ _ExtensionMemberValidator _validator;
+
+ RenameExtensionMemberRefactoringImpl(
+ RefactoringWorkspace workspace, AnalysisSession session, Element element)
+ : sessionHelper = AnalysisSessionHelper(session),
+ super(workspace, element);
+
+ @override
+ String get refactoringName {
+ if (element is TypeParameterElement) {
+ return "Rename Type Parameter";
+ }
+ if (element is FieldElement) {
+ return "Rename Field";
+ }
+ return "Rename Method";
+ }
+
+ @override
+ Future<RefactoringStatus> checkFinalConditions() {
+ _validator = _ExtensionMemberValidator.forRename(
+ searchEngine, sessionHelper, element, newName);
+ return _validator.validate();
+ }
+
+ @override
+ Future<RefactoringStatus> checkInitialConditions() async {
+ RefactoringStatus result = await super.checkInitialConditions();
+ if (element is MethodElement && (element as MethodElement).isOperator) {
+ result.addFatalError('Cannot rename operator.');
+ }
+ return Future<RefactoringStatus>.value(result);
+ }
+
+ @override
+ RefactoringStatus checkNewName() {
+ RefactoringStatus result = super.checkNewName();
+ if (element is FieldElement) {
+ result.addStatus(validateFieldName(newName));
+ }
+ if (element is MethodElement) {
+ result.addStatus(validateMethodName(newName));
+ }
+ return result;
+ }
+
+ @override
+ Future<void> fillChange() async {
+ var processor = RenameProcessor(workspace, change, newName);
+
+ // Update the declaration.
+ var renameElement = element;
+ if (renameElement.isSynthetic && renameElement is FieldElement) {
+ processor.addDeclarationEdit(renameElement.getter);
+ processor.addDeclarationEdit(renameElement.setter);
+ } else {
+ processor.addDeclarationEdit(renameElement);
+ }
+
+ // Update references.
+ processor.addReferenceEdits(_validator.references);
+ }
+}
+
+/**
+ * Helper to check if the created or renamed [Element] will cause any conflicts.
+ */
+class _ExtensionMemberValidator {
+ final SearchEngine searchEngine;
+ final AnalysisSessionHelper sessionHelper;
+ final LibraryElement library;
+ final Element element;
+ final ExtensionElement elementExtension;
+ final ElementKind elementKind;
+ final String name;
+ final bool isRename;
+
+ final RefactoringStatus result = RefactoringStatus();
+ final List<SearchMatch> references = <SearchMatch>[];
+
+ _ExtensionMemberValidator.forRename(
+ this.searchEngine, this.sessionHelper, Element element, this.name)
+ : isRename = true,
+ library = element.library,
+ element = element,
+ elementExtension = element.enclosingElement,
+ elementKind = element.kind;
+
+ Future<RefactoringStatus> validate() async {
+ // Check if there is a member with "newName" in the extension.
+ for (Element newNameMember in getChildren(elementExtension, name)) {
+ result.addError(
+ format(
+ "Extension '{0}' already declares {1} with name '{2}'.",
+ elementExtension.displayName,
+ getElementKindName(newNameMember),
+ name,
+ ),
+ newLocation_fromElement(newNameMember),
+ );
+ }
+
+ await _prepareReferences();
+
+ // usage of the renamed Element is shadowed by a local element
+ {
+ _MatchShadowedByLocal conflict = await _getShadowingLocalElement();
+ if (conflict != null) {
+ LocalElement localElement = conflict.localElement;
+ result.addError(
+ format(
+ "Usage of renamed {0} will be shadowed by {1} '{2}'.",
+ elementKind.displayName,
+ getElementKindName(localElement),
+ localElement.displayName,
+ ),
+ newLocation_fromMatch(conflict.match),
+ );
+ }
+ }
+
+ return result;
+ }
+
+ Future<_MatchShadowedByLocal> _getShadowingLocalElement() async {
+ var localElementMap = <CompilationUnitElement, List<LocalElement>>{};
+ var visibleRangeMap = <LocalElement, SourceRange>{};
+
+ Future<List<LocalElement>> getLocalElements(Element element) async {
+ var unitElement = element.getAncestor((e) => e is CompilationUnitElement);
+ var localElements = localElementMap[unitElement];
+
+ if (localElements == null) {
+ var result = await sessionHelper.getResolvedUnitByElement(element);
+ var unit = result.unit;
+
+ var collector = _LocalElementsCollector(name);
+ unit.accept(collector);
+ localElements = collector.elements;
+ localElementMap[unitElement] = localElements;
+
+ visibleRangeMap.addAll(VisibleRangesComputer.forNode(unit));
+ }
+
+ return localElements;
+ }
+
+ for (SearchMatch match in references) {
+ // Qualified reference cannot be shadowed by local elements.
+ if (match.isQualified) {
+ continue;
+ }
+ // Check local elements that might shadow the reference.
+ var localElements = await getLocalElements(match.element);
+ for (LocalElement localElement in localElements) {
+ SourceRange elementRange = visibleRangeMap[localElement];
+ if (elementRange != null &&
+ elementRange.intersects(match.sourceRange)) {
+ return _MatchShadowedByLocal(match, localElement);
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Fills [references] with references to the [element].
+ */
+ Future<void> _prepareReferences() async {
+ if (!isRename) return;
+
+ references.addAll(
+ await searchEngine.searchReferences(element),
+ );
+ }
+}
+
+class _LocalElementsCollector extends GeneralizingAstVisitor<void> {
+ final String name;
+ final List<LocalElement> elements = [];
+
+ _LocalElementsCollector(this.name);
+
+ visitSimpleIdentifier(SimpleIdentifier node) {
+ Element element = node.staticElement;
+ if (element is LocalElement && element.name == name) {
+ elements.add(element);
+ }
+ }
+}
+
+class _MatchShadowedByLocal {
+ final SearchMatch match;
+ final LocalElement localElement;
+
+ _MatchShadowedByLocal(this.match, this.localElement);
+}
diff --git a/pkg/analysis_server/lib/src/services/search/hierarchy.dart b/pkg/analysis_server/lib/src/services/search/hierarchy.dart
index bbac8d1..9d157a5 100644
--- a/pkg/analysis_server/lib/src/services/search/hierarchy.dart
+++ b/pkg/analysis_server/lib/src/services/search/hierarchy.dart
@@ -64,6 +64,28 @@
return matches.map((match) => match.element).cast<ClassElement>().toSet();
}
+/// Return the non-synthetic children of the given [extension]. This includes
+/// fields, accessors and methods, but excludes synthetic elements.
+List<Element> getExtensionMembers(ExtensionElement extension, [String name]) {
+ List<Element> members = <Element>[];
+ visitChildren(extension, (Element element) {
+ if (element.isSynthetic) {
+ return false;
+ }
+ if (name != null && element.displayName != name) {
+ return false;
+ }
+ if (element is ExecutableElement) {
+ members.add(element);
+ }
+ if (element is FieldElement) {
+ members.add(element);
+ }
+ return false;
+ });
+ return members;
+}
+
/**
* @return all implementations of the given {@link ClassMemberElement} is its superclasses and
* their subclasses.
diff --git a/pkg/analysis_server/lib/src/status/diagnostics.dart b/pkg/analysis_server/lib/src/status/diagnostics.dart
index 57d8ac6..112ee48 100644
--- a/pkg/analysis_server/lib/src/status/diagnostics.dart
+++ b/pkg/analysis_server/lib/src/status/diagnostics.dart
@@ -895,7 +895,7 @@
);
ul([
'what you were doing',
- 'what occured',
+ 'what occurred',
'what you think the expected behavior should have been',
], (line) => buf.writeln(line));
diff --git a/pkg/analysis_server/lib/src/utilities/flutter.dart b/pkg/analysis_server/lib/src/utilities/flutter.dart
index 3eb7abb..eccd264 100644
--- a/pkg/analysis_server/lib/src/utilities/flutter.dart
+++ b/pkg/analysis_server/lib/src/utilities/flutter.dart
@@ -334,6 +334,9 @@
if (parent is ArgumentList ||
parent is ExpressionFunctionBody && parent.expression == node ||
+ parent is ForElement && parent.body == node ||
+ parent is IfElement && parent.thenElement == node ||
+ parent is IfElement && parent.elseElement == node ||
parent is ListLiteral ||
parent is NamedExpression && parent.expression == node ||
parent is Statement) {
diff --git a/pkg/analysis_server/lib/src/utilities/request_statistics.dart b/pkg/analysis_server/lib/src/utilities/request_statistics.dart
index bffd70f..b9e3b4b 100644
--- a/pkg/analysis_server/lib/src/utilities/request_statistics.dart
+++ b/pkg/analysis_server/lib/src/utilities/request_statistics.dart
@@ -5,6 +5,8 @@
import 'dart:convert';
import 'package:analysis_server/protocol/protocol.dart';
+import 'package:analysis_server/protocol/protocol_generated.dart';
+import 'package:analysis_server/src/channel/byte_stream_channel.dart';
/// Helper for tracking request handling statistics.
///
@@ -12,9 +14,31 @@
class RequestStatisticsHelper {
final Map<String, _RequestStatistics> _statisticsMap = {};
- /// The sink to write statistics to.
- /// It is set externally when we get to `AnalysisServer` instance.
- StringSink sink;
+ /// The [StringSink] to which performance logger should copy its output.
+ _ServerLogStringSink _perfLoggerStringSink;
+
+ /// The channel to send 'server.log' notifications to.
+ ByteStreamServerChannel _serverChannel;
+
+ /// Is `true` if the client subscribed for "server.log" notification.
+ bool _isNotificationSubscribed = false;
+
+ RequestStatisticsHelper() {
+ _perfLoggerStringSink = _ServerLogStringSink(this);
+ }
+
+ /// Set whether the client subscribed for "server.log" notification.
+ set isNotificationSubscribed(bool value) {
+ _isNotificationSubscribed = value;
+ }
+
+ /// The [StringSink] to which performance logger should copy its output.
+ StringSink get perfLoggerStringSink => _perfLoggerStringSink;
+
+ /// The channel sets itself using this method.
+ set serverChannel(ByteStreamServerChannel serverChannel) {
+ _serverChannel = serverChannel;
+ }
/// Add a time marker item to the data associated with the [request].
void addItemTimeNow(Request request, String name) {
@@ -58,25 +82,20 @@
/// The server finished processing a request, and sends the [response].
/// Record the time when the response is about to be sent to the client.
void addResponse(Response response) {
+ if (!_isNotificationSubscribed) return;
+ if (_serverChannel == null) return;
+
var id = response.id;
var stat = _statisticsMap.remove(id);
if (stat != null) {
stat.responseTime = DateTime.now();
-
- if (sink != null) {
- sink.writeln(
- json.encode(
- {
- 'requestStatistics': stat.toJson(),
- },
- ),
- );
- }
+ _sendLogEntry(ServerLogEntryKind.RESPONSE, stat.toJson());
}
}
void logNotification(Notification notification) {
- if (sink == null) return;
+ if (!_isNotificationSubscribed) return;
+ if (_serverChannel == null) return;
var event = notification.event;
@@ -105,15 +124,12 @@
}
}
- sink.writeln(
- json.encode({
- 'notification': map,
- }),
- );
+ _sendLogEntry(ServerLogEntryKind.NOTIFICATION, map);
}
void _logRequest(Request request) {
- if (sink == null) return;
+ if (!_isNotificationSubscribed) return;
+ if (_serverChannel == null) return;
var method = request.method;
var map = <String, Object>{
@@ -137,10 +153,22 @@
map = request.toJson();
}
- sink.writeln(
- json.encode({
- 'request': map,
- }),
+ _sendLogEntry(ServerLogEntryKind.REQUEST, map);
+ }
+
+ void _sendLogEntry(ServerLogEntryKind kind, Object data) {
+ if (!_isNotificationSubscribed) return;
+ if (_serverChannel == null) return;
+
+ _serverChannel.sendNotification(
+ Notification(
+ 'server.log',
+ <String, Object>{
+ 'time': DateTime.now().millisecondsSinceEpoch,
+ 'kind': kind.toJson(),
+ 'data': data,
+ },
+ ),
);
}
}
@@ -161,16 +189,15 @@
);
Map<String, Object> toJson() {
- var baseTime = clientRequestTime.millisecondsSinceEpoch;
var map = {
'id': id,
'method': method,
- 'clientRequestTime': baseTime,
- 'serverRequestTime': serverRequestTime.millisecondsSinceEpoch - baseTime,
- 'responseTime': responseTime.millisecondsSinceEpoch - baseTime,
+ 'clientRequestTime': clientRequestTime.millisecondsSinceEpoch,
+ 'serverRequestTime': serverRequestTime.millisecondsSinceEpoch,
+ 'responseTime': responseTime.millisecondsSinceEpoch,
};
if (items.isNotEmpty) {
- map['items'] = items.map((item) => item.toJson(baseTime)).toList();
+ map['items'] = items.map((item) => item.toJson()).toList();
}
return map;
}
@@ -188,13 +215,35 @@
_RequestStatisticsItem(this.name, {this.timeValue});
- Map<String, Object> toJson(int baseTimeMillis) {
+ Map<String, Object> toJson() {
if (timeValue != null) {
return {
'name': name,
- 'timeValue': timeValue.millisecondsSinceEpoch - baseTimeMillis,
+ 'timeValue': timeValue.millisecondsSinceEpoch,
};
}
throw StateError('Unknown value: $name');
}
}
+
+class _ServerLogStringSink implements StringSink {
+ final RequestStatisticsHelper helper;
+
+ _ServerLogStringSink(this.helper);
+
+ void write(Object obj) {
+ throw UnimplementedError();
+ }
+
+ void writeAll(Iterable objects, [String separator = '']) {
+ throw UnimplementedError();
+ }
+
+ void writeCharCode(int charCode) {
+ throw UnimplementedError();
+ }
+
+ void writeln([Object obj = '']) {
+ helper._sendLogEntry(ServerLogEntryKind.RAW, '$obj');
+ }
+}
diff --git a/pkg/analysis_server/lib/src/utilities/tee_string_sink.dart b/pkg/analysis_server/lib/src/utilities/tee_string_sink.dart
new file mode 100644
index 0000000..0180b9d
--- /dev/null
+++ b/pkg/analysis_server/lib/src/utilities/tee_string_sink.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2019, 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 [StringSink] that writes into two other [StringSink]s.
+ */
+class TeeStringSink implements StringSink {
+ final StringSink sink1;
+ final StringSink sink2;
+
+ TeeStringSink(this.sink1, this.sink2);
+
+ void write(Object obj) {
+ sink1.write(obj);
+ sink2.write(obj);
+ }
+
+ void writeAll(Iterable objects, [String separator = ""]) {
+ sink1.writeAll(objects, separator);
+ sink2.writeAll(objects, separator);
+ }
+
+ void writeCharCode(int charCode) {
+ sink1.writeCharCode(charCode);
+ sink2.writeCharCode(charCode);
+ }
+
+ void writeln([Object obj = ""]) {
+ sink1.writeln(obj);
+ sink2.writeln(obj);
+ }
+}
diff --git a/pkg/analysis_server/pubspec.yaml b/pkg/analysis_server/pubspec.yaml
index 3850a81..20a9e0e 100644
--- a/pkg/analysis_server/pubspec.yaml
+++ b/pkg/analysis_server/pubspec.yaml
@@ -2,7 +2,7 @@
publish_to: none
environment:
- sdk: '>=2.1.0-dev.5.0 <3.0.0'
+ sdk: '>=2.2.2 <3.0.0'
dependencies:
analyzer: any
diff --git a/pkg/analysis_server/test/abstract_context.dart b/pkg/analysis_server/test/abstract_context.dart
index 5a29769..6ec7193 100644
--- a/pkg/analysis_server/test/abstract_context.dart
+++ b/pkg/analysis_server/test/abstract_context.dart
@@ -19,6 +19,7 @@
import 'package:analyzer/src/generated/source_io.dart';
import 'package:analyzer/src/test_utilities/mock_sdk.dart';
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
+import 'package:linter/src/rules.dart';
import 'src/utilities/mock_packages.dart';
@@ -129,8 +130,10 @@
}
/// Create an analysis options file based on the given arguments.
- void createAnalysisOptionsFile({List<String> experiments}) {
+ void createAnalysisOptionsFile(
+ {List<String> experiments, List<String> lints}) {
StringBuffer buffer = new StringBuffer();
+
if (experiments != null) {
buffer.writeln('analyzer:');
buffer.writeln(' enable-experiment:');
@@ -138,6 +141,15 @@
buffer.writeln(' - $experiment');
}
}
+
+ if (lints != null) {
+ buffer.writeln('linter:');
+ buffer.writeln(' rules:');
+ for (String lint in lints) {
+ buffer.writeln(' - $lint');
+ }
+ }
+
newFile(analysisOptionsPath, content: buffer.toString());
if (_driver != null) {
createAnalysisContexts();
@@ -166,6 +178,8 @@
}
void setUp() {
+ registerLintRules();
+
setupResourceProvider();
overlayResourceProvider = OverlayResourceProvider(resourceProvider);
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index dc47e1d..28a5b6e 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -892,38 +892,38 @@
class C implements B {}
class D with C {}
''', [
- token('class', null, null),
- token('A', 'Type',
- ['declaration']), //token('A', 'dart:core;Type', ['declaration']),
- token('{', null, null),
- token('}', null, null),
- token('class', null, null),
- token('B', 'Type',
- ['declaration']), //token('B', 'dart:core;Type', ['declaration']),
- token('extends', null, null),
- token('A', 'dart:core;Type<A>', [
+ token('class', 0, null, null),
+ token('A', 6, 'Type',
+ ['declaration']), //token('A', 6, 'dart:core;Type', ['declaration']),
+ token('{', 8, null, null),
+ token('}', 9, null, null),
+ token('class', 11, null, null),
+ token('B', 17, 'Type',
+ ['declaration']), //token('B', 17, 'dart:core;Type', ['declaration']),
+ token('extends', 19, null, null),
+ token('A', 27, 'dart:core;Type<A>', [
'reference'
- ]), //token('A', 'dart:core;Type<$testFileUri;A>', ['reference']),
- token('{', null, null),
- token('}', null, null),
- token('class', null, null),
- token('C', 'Type',
- ['declaration']), //token('C', 'dart:core;Type', ['declaration']),
- token('implements', null, null),
- token('B', 'dart:core;Type<B>', [
+ ]), //token('A', 27, 'dart:core;Type<$testFileUri;A>', ['reference']),
+ token('{', 29, null, null),
+ token('}', 30, null, null),
+ token('class', 32, null, null),
+ token('C', 38, 'Type',
+ ['declaration']), //token('C', 38, 'dart:core;Type', ['declaration']),
+ token('implements', 40, null, null),
+ token('B', 51, 'dart:core;Type<B>', [
'reference'
- ]), //token('B', 'dart:core;Type<$testFileUri;B>', ['reference']),
- token('{', null, null),
- token('}', null, null),
- token('class', null, null),
- token('D', 'Type',
- ['declaration']), //token('D', 'dart:core;Type', ['declaration']),
- token('with', null, null),
- token('C', 'dart:core;Type<C>', [
+ ]), //token('B', 51, 'dart:core;Type<$testFileUri;B>', ['reference']),
+ token('{', 53, null, null),
+ token('}', 54, null, null),
+ token('class', 56, null, null),
+ token('D', 62, 'Type',
+ ['declaration']), //token('D', 62, 'dart:core;Type', ['declaration']),
+ token('with', 64, null, null),
+ token('C', 69, 'dart:core;Type<C>', [
'reference'
- ]), //token('C', 'dart:core;Type<$testFileUri;C>', ['reference']),
- token('{', null, null),
- token('}', null, null),
+ ]), //token('C', 69, 'dart:core;Type<$testFileUri;C>', ['reference']),
+ token('{', 71, null, null),
+ token('}', 72, null, null),
]);
}
@@ -931,19 +931,19 @@
await expectTokens('''
List<int> x = null;
''', [
- token('List', 'dart:core;Type<List>', [
+ token('List', 0, 'dart:core;Type<List>', [
'reference'
- ]), //token('List', 'dart:core;Type<dart:core;List>', ['reference']),
- token('<', null, null),
- token('int', 'dart:core;Type<int>', [
+ ]), //token('List', 0, 'dart:core;Type<dart:core;List>', ['reference']),
+ token('<', 4, null, null),
+ token('int', 5, 'dart:core;Type<int>', [
'reference'
- ]), //token('int', 'dart:core;Type<dart:core;int>', ['reference']),
- token('>', null, null),
- token('x', 'List',
- ['declaration']), //token('x', 'dart:core;List', ['declaration']),
- token('=', null, null),
- token('null', null, null),
- token(';', null, null),
+ ]), //token('int', 5, 'dart:core;Type<dart:core;int>', ['reference']),
+ token('>', 8, null, null),
+ token('x', 10, 'List',
+ ['declaration']), //token('x', 10, 'dart:core;List', ['declaration']),
+ token('=', 12, null, null),
+ token('null', 14, null, null),
+ token(';', 18, null, null),
]);
}
@@ -951,15 +951,16 @@
await expectTokens('''
var x = 'a'.length;
''', [
- token('var', null, null),
- token('x', 'int',
- ['declaration']), //token('x', 'dart:core;int', ['declaration']),
- token('=', null, null),
- token("'a'", 'String', null), //token("'a'", 'dart:core;String', null),
- token('.', null, null),
- token('length', 'int',
- ['reference']), //token('length', 'dart:core;int', ['reference']),
- token(';', null, null),
+ token('var', 0, null, null),
+ token('x', 4, 'int',
+ ['declaration']), //token('x', 4, 'dart:core;int', ['declaration']),
+ token('=', 6, null, null),
+ token("'a'", 8, 'String',
+ null), //token("'a'", 8, 'dart:core;String', null),
+ token('.', 11, null, null),
+ token('length', 12, 'int',
+ ['reference']), //token('length', 12, 'dart:core;int', ['reference']),
+ token(';', 18, null, null),
]);
}
@@ -967,12 +968,13 @@
await expectTokens('''
var x = true;
''', [
- token('var', null, null),
- token('x', 'bool',
- ['declaration']), //token('x', 'dart:core;bool', ['declaration']),
- token('=', null, null),
- token('true', 'bool', null), //token('true', 'dart:core;bool', null),
- token(';', null, null),
+ token('var', 0, null, null),
+ token('x', 4, 'bool',
+ ['declaration']), //token('x', 4, 'dart:core;bool', ['declaration']),
+ token('=', 6, null, null),
+ token(
+ 'true', 8, 'bool', null), //token('true', 8, 'dart:core;bool', null),
+ token(';', 12, null, null),
]);
}
@@ -980,12 +982,14 @@
await expectTokens('''
var x = 3.4;
''', [
- token('var', null, null),
- token('x', 'double',
- ['declaration']), //token('x', 'dart:core;double', ['declaration']),
- token('=', null, null),
- token('3.4', 'double', null), //token('3.4', 'dart:core;double', null),
- token(';', null, null),
+ token('var', 0, null, null),
+ token('x', 4, 'double', [
+ 'declaration'
+ ]), //token('x', 4, 'dart:core;double', ['declaration']),
+ token('=', 6, null, null),
+ token('3.4', 8, 'double',
+ null), //token('3.4', 8, 'dart:core;double', null),
+ token(';', 11, null, null),
]);
}
@@ -993,12 +997,12 @@
await expectTokens('''
var x = 7;
''', [
- token('var', null, null),
- token('x', 'int',
- ['declaration']), //token('x', 'dart:core;int', ['declaration']),
- token('=', null, null),
- token('7', 'int', null), //token('7', 'dart:core;int', null),
- token(';', null, null),
+ token('var', 0, null, null),
+ token('x', 4, 'int',
+ ['declaration']), //token('x', 4, 'dart:core;int', ['declaration']),
+ token('=', 6, null, null),
+ token('7', 8, 'int', null), //token('7', 8, 'dart:core;int', null),
+ token(';', 9, null, null),
]);
}
@@ -1006,18 +1010,18 @@
await expectTokens('''
var x = <int>[];
''', [
- token('var', null, null),
- token('x', 'List',
- ['declaration']), //token('x', 'dart:core;List', ['declaration']),
- token('=', null, null),
- token('<', null, null),
- token("int", 'dart:core;Type<int>', [
+ token('var', 0, null, null),
+ token('x', 4, 'List',
+ ['declaration']), //token('x', 4, 'dart:core;List', ['declaration']),
+ token('=', 6, null, null),
+ token('<', 8, null, null),
+ token("int", 9, 'dart:core;Type<int>', [
'reference'
- ]), //token("int", 'dart:core;Type<dart:core;int>', ['reference']),
- token('>', null, null),
- token('[', null, null),
- token(']', null, null),
- token(';', null, null),
+ ]), //token("int", 9, 'dart:core;Type<dart:core;int>', ['reference']),
+ token('>', 12, null, null),
+ token('[', 13, null, null),
+ token(']', 14, null, null),
+ token(';', 15, null, null),
]);
}
@@ -1025,22 +1029,22 @@
await expectTokens('''
var x = <int, int>{};
''', [
- token('var', null, null),
- token('x', 'Map',
- ['declaration']), //token('x', 'dart:core;Map', ['declaration']),
- token('=', null, null),
- token('<', null, null),
- token("int", 'dart:core;Type<int>', [
+ token('var', 0, null, null),
+ token('x', 4, 'Map',
+ ['declaration']), //token('x', 4, 'dart:core;Map', ['declaration']),
+ token('=', 6, null, null),
+ token('<', 8, null, null),
+ token("int", 9, 'dart:core;Type<int>', [
'reference'
- ]), //token("int", 'dart:core;Type<dart:core;int>', ['reference']),
+ ]), //token("int", 9, 'dart:core;Type<dart:core;int>', ['reference']),
// token(',', null, null),
- token("int", 'dart:core;Type<int>', [
+ token("int", 14, 'dart:core;Type<int>', [
'reference'
- ]), //token("int", 'dart:core;Type<dart:core;int>', ['reference']),
- token('>', null, null),
- token('{', null, null),
- token('}', null, null),
- token(';', null, null),
+ ]), //token("int", 14, 'dart:core;Type<dart:core;int>', ['reference']),
+ token('>', 17, null, null),
+ token('{', 18, null, null),
+ token('}', 19, null, null),
+ token(';', 20, null, null),
]);
}
@@ -1048,11 +1052,11 @@
await expectTokens('''
var x = null;
''', [
- token('var', null, null),
- token('x', 'dynamic', ['declaration']),
- token('=', null, null),
- token('null', null, null),
- token(';', null, null),
+ token('var', 0, null, null),
+ token('x', 4, 'dynamic', ['declaration']),
+ token('=', 6, null, null),
+ token('null', 8, null, null),
+ token(';', 12, null, null),
]);
}
@@ -1060,18 +1064,18 @@
await expectTokens('''
var x = <int>{};
''', [
- token('var', null, null),
- token('x', 'Set',
- ['declaration']), //token('x', 'dart:core;Set', ['declaration']),
- token('=', null, null),
- token('<', null, null),
- token("int", 'dart:core;Type<int>', [
+ token('var', 0, null, null),
+ token('x', 4, 'Set',
+ ['declaration']), //token('x', 4, 'dart:core;Set', ['declaration']),
+ token('=', 6, null, null),
+ token('<', 8, null, null),
+ token("int", 9, 'dart:core;Type<int>', [
'reference'
- ]), //token("int", 'dart:core;Type<dart:core;int>', ['reference']),
- token('>', null, null),
- token('{', null, null),
- token('}', null, null),
- token(';', null, null),
+ ]), //token("int", 9, 'dart:core;Type<dart:core;int>', ['reference']),
+ token('>', 12, null, null),
+ token('{', 13, null, null),
+ token('}', 14, null, null),
+ token(';', 15, null, null),
]);
}
@@ -1079,12 +1083,14 @@
await expectTokens('''
var x = 'a';
''', [
- token('var', null, null),
- token('x', 'String',
- ['declaration']), //token('x', 'dart:core;String', ['declaration']),
- token('=', null, null),
- token("'a'", 'String', null), //token("'a'", 'dart:core;String', null),
- token(';', null, null),
+ token('var', 0, null, null),
+ token('x', 4, 'String', [
+ 'declaration'
+ ]), //token('x', 4, 'dart:core;String', ['declaration']),
+ token('=', 6, null, null),
+ token("'a'", 8, 'String',
+ null), //token("'a'", 8, 'dart:core;String', null),
+ token(';', 11, null, null),
]);
}
@@ -1094,32 +1100,32 @@
String c(int x, int y) {}
}
''', [
- token('class', null, null),
- token('A', 'Type',
- ['declaration']), //token('A', 'dart:core;Type', ['declaration']),
- token('{', null, null),
- token('String', 'dart:core;Type<String>', [
+ token('class', 0, null, null),
+ token('A', 6, 'Type',
+ ['declaration']), //token('A', 6, 'dart:core;Type', ['declaration']),
+ token('{', 8, null, null),
+ token('String', 12, 'dart:core;Type<String>', [
'reference'
- ]), //token('String', 'dart:core;Type<dart:core;String>', ['reference']),
- token('c',
+ ]), //token('String', 12, 'dart:core;Type<dart:core;String>', ['reference']),
+ token('c', 19,
'String Function(int, int)', //'dart:core;String Function(dart:core;int, dart:core;int)',
['declaration']),
- token('(', null, null),
- token('int', 'dart:core;Type<int>', [
+ token('(', 20, null, null),
+ token('int', 21, 'dart:core;Type<int>', [
'reference'
- ]), //token('int', 'dart:core;Type<dart:core;int>', ['reference']),
- token('x', 'int',
- ['declaration']), //token('x', 'dart:core;int', ['declaration']),
+ ]), //token('int', 21, 'dart:core;Type<dart:core;int>', ['reference']),
+ token('x', 25, 'int',
+ ['declaration']), //token('x', 25, 'dart:core;int', ['declaration']),
// token(',', null, null),
- token('int', 'dart:core;Type<int>', [
+ token('int', 28, 'dart:core;Type<int>', [
'reference'
- ]), //token('int', 'dart:core;Type<dart:core;int>', ['reference']),
- token('y', 'int',
- ['declaration']), //token('y', 'dart:core;int', ['declaration']),
- token(')', null, null),
- token('{', null, null),
- token('}', null, null),
- token('}', null, null),
+ ]), //token('int', 28, 'dart:core;Type<dart:core;int>', ['reference']),
+ token('y', 32, 'int',
+ ['declaration']), //token('y', 32, 'dart:core;int', ['declaration']),
+ token(')', 33, null, null),
+ token('{', 35, null, null),
+ token('}', 36, null, null),
+ token('}', 38, null, null),
]);
}
@@ -1127,22 +1133,23 @@
await expectTokens('''
var x = 'radar'.indexOf('r', 1);
''', [
- token('var', null, null),
- token('x', 'int',
- ['declaration']), //token('x', 'dart:core;int', ['declaration']),
- token('=', null, null),
- token("'radar'", 'String',
- null), //token("'radar'", 'dart:core;String', null),
- token('.', null, null),
- token('indexOf',
+ token('var', 0, null, null),
+ token('x', 4, 'int',
+ ['declaration']), //token('x', 4, 'dart:core;int', ['declaration']),
+ token('=', 6, null, null),
+ token("'radar'", 8, 'String',
+ null), //token("'radar'", 8, 'dart:core;String', null),
+ token('.', 15, null, null),
+ token('indexOf', 16,
'int Function(Pattern, int)', //'dart:core;int Function(dart:core;Pattern, dart:core;int)',
['reference']),
- token('(', null, null),
- token("'r'", 'String', null), //token("'r'", 'dart:core;String', null),
+ token('(', 23, null, null),
+ token("'r'", 24, 'String',
+ null), //token("'r'", 24, 'dart:core;String', null),
// token(',', null, null),
- token('1', 'int', null), //token('1', 'dart:core;int', null),
- token(')', null, null),
- token(';', null, null),
+ token('1', 29, 'int', null), //token('1', 29, 'dart:core;int', null),
+ token(')', 30, null, null),
+ token(';', 31, null, null),
]);
}
@@ -1152,29 +1159,29 @@
class B {}
mixin D on A implements B {}
''', [
- token('class', null, null),
- token('A', 'Type',
- ['declaration']), //token('A', 'dart:core;Type', ['declaration']),
- token('{', null, null),
- token('}', null, null),
- token('class', null, null),
- token('B', 'Type',
- ['declaration']), //token('B', 'dart:core;Type', ['declaration']),
- token('{', null, null),
- token('}', null, null),
- token('mixin', null, null),
- token('D', 'Type',
- ['declaration']), //token('D', 'dart:core;Type', ['declaration']),
- token('on', null, null),
- token('A', 'dart:core;Type<A>', [
+ token('class', 0, null, null),
+ token('A', 6, 'Type',
+ ['declaration']), //token('A', 6, 'dart:core;Type', ['declaration']),
+ token('{', 8, null, null),
+ token('}', 9, null, null),
+ token('class', 11, null, null),
+ token('B', 17, 'Type',
+ ['declaration']), //token('B', 17, 'dart:core;Type', ['declaration']),
+ token('{', 19, null, null),
+ token('}', 20, null, null),
+ token('mixin', 22, null, null),
+ token('D', 28, 'Type',
+ ['declaration']), //token('D', 28, 'dart:core;Type', ['declaration']),
+ token('on', 30, null, null),
+ token('A', 33, 'dart:core;Type<A>', [
'reference'
- ]), //token('A', 'dart:core;Type<$testFileUri;A>', ['reference']),
- token('implements', null, null),
- token('B', 'dart:core;Type<B>', [
+ ]), //token('A', 33, 'dart:core;Type<$testFileUri;A>', ['reference']),
+ token('implements', 35, null, null),
+ token('B', 46, 'dart:core;Type<B>', [
'reference'
]), //token('B', 'dart:core;Type<$testFileUri;B>', ['reference']),
- token('{', null, null),
- token('}', null, null),
+ token('{', 48, null, null),
+ token('}', 49, null, null),
]);
}
@@ -1184,25 +1191,25 @@
return p;
}
''', [
- token('int', 'dart:core;Type<int>', [
+ token('int', 0, 'dart:core;Type<int>', [
'reference'
- ]), //token('int', 'dart:core;Type<dart:core;int>', ['reference']),
- token('f', 'int Function(int)', [
+ ]), //token('int', 0, 'dart:core;Type<dart:core;int>', ['reference']),
+ token('f', 4, 'int Function(int)', [
'declaration'
- ]), //token('f', 'dart:core;int Function(dart:core;int)', ['declaration']),
- token('(', null, null),
- token('int', 'dart:core;Type<int>', [
+ ]), //token('f', 4, 'dart:core;int Function(dart:core;int)', ['declaration']),
+ token('(', 5, null, null),
+ token('int', 6, 'dart:core;Type<int>', [
'reference'
- ]), //token('int', 'dart:core;Type<dart:core;int>', ['reference']),
- token('p', 'int',
- ['declaration']), //token('p', 'dart:core;int', ['declaration']),
- token(')', null, null),
- token('{', null, null),
- token('return', null, null),
- token('p', 'int',
- ['reference']), //token('p', 'dart:core;int', ['reference']),
- token(';', null, null),
- token('}', null, null),
+ ]), //token('int', 6, 'dart:core;Type<dart:core;int>', ['reference']),
+ token('p', 10, 'int',
+ ['declaration']), //token('p', 10, 'dart:core;int', ['declaration']),
+ token(')', 11, null, null),
+ token('{', 13, null, null),
+ token('return', 17, null, null),
+ token('p', 24, 'int',
+ ['reference']), //token('p', 24, 'dart:core;int', ['reference']),
+ token(';', 25, null, null),
+ token('}', 27, null, null),
]);
}
@@ -1211,17 +1218,19 @@
/// Doc comment [x] with reference.
int x;
''', [
- token('int', 'dart:core;Type<int>', [
+ token('int', 36, 'dart:core;Type<int>', [
'reference'
- ]), //token('int', 'dart:core;Type<dart:core;int>', ['reference']),
- token('x', 'int',
- ['declaration']), //token('x', 'dart:core;int', ['declaration']),
- token(';', null, null),
+ ]), //token('int', 36, 'dart:core;Type<dart:core;int>', ['reference']),
+ token('x', 40, 'int',
+ ['declaration']), //token('x', 40, 'dart:core;int', ['declaration']),
+ token(';', 41, null, null),
]);
}
- TokenDetails token(String lexeme, String type, List<String> kinds) {
- return new TokenDetails(lexeme, type: type, validElementKinds: kinds);
+ TokenDetails token(
+ String lexeme, int offset, String type, List<String> kinds) {
+ return new TokenDetails(lexeme, offset,
+ type: type, validElementKinds: kinds);
}
void _compareTokens(List<Map<String, dynamic>> actualTokens,
@@ -1237,6 +1246,11 @@
'expected "${expected.lexeme}", '
'actual "${actual['lexeme']}"');
}
+ if (actual['offset'] != expected.offset) {
+ errors.add('Offset at $i: ("${expected.lexeme}"): '
+ 'expected "${expected.offset}", '
+ 'actual "${actual['offset']}"');
+ }
if (actual['type'] != expected.type) {
errors.add('Type at $i ("${expected.lexeme}"): '
'expected "${expected.type}", '
@@ -1284,3 +1298,4 @@
return new Future.value();
}
}
+
diff --git a/pkg/analysis_server/test/edit/fixes_test.dart b/pkg/analysis_server/test/edit/fixes_test.dart
index 22a7245..37bb83e 100644
--- a/pkg/analysis_server/test/edit/fixes_test.dart
+++ b/pkg/analysis_server/test/edit/fixes_test.dart
@@ -44,9 +44,6 @@
List<AnalysisErrorFixes> errorFixes =
await _getFixesAt('Completer<String>');
expect(errorFixes, hasLength(1));
- AnalysisError error = errorFixes[0].error;
- expect(error.severity, AnalysisErrorSeverity.ERROR);
- expect(error.type, AnalysisErrorType.STATIC_WARNING);
List<SourceChange> fixes = errorFixes[0].fixes;
expect(fixes, hasLength(3));
expect(fixes[0].message, matches('Import library'));
diff --git a/pkg/analysis_server/test/integration/coverage.md b/pkg/analysis_server/test/integration/coverage.md
index ae82a71..20ee12c 100644
--- a/pkg/analysis_server/test/integration/coverage.md
+++ b/pkg/analysis_server/test/integration/coverage.md
@@ -82,6 +82,7 @@
- [x] server.setSubscriptions
- [ ] server.connected
- [ ] server.error
+- [ ] server.log
- [x] server.status
## analytics domain
diff --git a/pkg/analysis_server/test/integration/linter/lint_names_test.dart b/pkg/analysis_server/test/integration/linter/lint_names_test.dart
index 929a9c0..b6ebf92 100644
--- a/pkg/analysis_server/test/integration/linter/lint_names_test.dart
+++ b/pkg/analysis_server/test/integration/linter/lint_names_test.dart
@@ -30,11 +30,11 @@
/// Ensure server lint name representations correspond w/ actual lint rules.
/// See, e.g., https://dart-review.googlesource.com/c/sdk/+/95743.
group('lint_names', () {
- var fixFileContents = new File(path.join(pathPrefix, 'lib', 'src',
- 'services', 'correction', 'fix_internal.dart'))
+ var fixFileContents = new File(path.join(
+ pathPrefix, 'lib', 'src', 'services', 'linter', 'lint_names.dart'))
.readAsStringSync();
var parser = new CompilationUnitParser();
- var cu = parser.parse(contents: fixFileContents, name: 'fix_internal.dart');
+ var cu = parser.parse(contents: fixFileContents, name: 'lint_names.dart');
var lintNamesClass = cu.declarations
.firstWhere((m) => m is ClassDeclaration && m.name.name == 'LintNames');
diff --git a/pkg/analysis_server/test/integration/support/integration_test_methods.dart b/pkg/analysis_server/test/integration/support/integration_test_methods.dart
index 3516f8b..1440fe3 100644
--- a/pkg/analysis_server/test/integration/support/integration_test_methods.dart
+++ b/pkg/analysis_server/test/integration/support/integration_test_methods.dart
@@ -135,6 +135,20 @@
StreamController<ServerErrorParams> _onServerError;
/**
+ * The stream of entries describing events happened in the server.
+ *
+ * Parameters
+ *
+ * entry: ServerLogEntry
+ */
+ Stream<ServerLogParams> onServerLog;
+
+ /**
+ * Stream controller for [onServerLog].
+ */
+ StreamController<ServerLogParams> _onServerLog;
+
+ /**
* Reports the current status of the server. Parameters are omitted if there
* has been no change in the status represented by that parameter.
*
@@ -2739,6 +2753,8 @@
onServerConnected = _onServerConnected.stream.asBroadcastStream();
_onServerError = new StreamController<ServerErrorParams>(sync: true);
onServerError = _onServerError.stream.asBroadcastStream();
+ _onServerLog = new StreamController<ServerLogParams>(sync: true);
+ onServerLog = _onServerLog.stream.asBroadcastStream();
_onServerStatus = new StreamController<ServerStatusParams>(sync: true);
onServerStatus = _onServerStatus.stream.asBroadcastStream();
_onAnalysisAnalyzedFiles =
@@ -2815,6 +2831,11 @@
_onServerError
.add(new ServerErrorParams.fromJson(decoder, 'params', params));
break;
+ case "server.log":
+ outOfTestExpect(params, isServerLogParams);
+ _onServerLog
+ .add(new ServerLogParams.fromJson(decoder, 'params', params));
+ break;
case "server.status":
outOfTestExpect(params, isServerStatusParams);
_onServerStatus
diff --git a/pkg/analysis_server/test/integration/support/protocol_matchers.dart b/pkg/analysis_server/test/integration/support/protocol_matchers.dart
index 358108e..61edec1 100644
--- a/pkg/analysis_server/test/integration/support/protocol_matchers.dart
+++ b/pkg/analysis_server/test/integration/support/protocol_matchers.dart
@@ -1704,13 +1704,41 @@
]);
/**
+ * ServerLogEntry
+ *
+ * {
+ * "time": int
+ * "kind": ServerLogEntryKind
+ * "data": String
+ * }
+ */
+final Matcher isServerLogEntry = new LazyMatcher(() => new MatchesJsonObject(
+ "ServerLogEntry",
+ {"time": isInt, "kind": isServerLogEntryKind, "data": isString}));
+
+/**
+ * ServerLogEntryKind
+ *
+ * enum {
+ * NOTIFICATION
+ * RAW
+ * REQUEST
+ * RESPONSE
+ * }
+ */
+final Matcher isServerLogEntryKind = new MatchesEnum(
+ "ServerLogEntryKind", ["NOTIFICATION", "RAW", "REQUEST", "RESPONSE"]);
+
+/**
* ServerService
*
* enum {
+ * LOG
* STATUS
* }
*/
-final Matcher isServerService = new MatchesEnum("ServerService", ["STATUS"]);
+final Matcher isServerService =
+ new MatchesEnum("ServerService", ["LOG", "STATUS"]);
/**
* SourceChange
@@ -1767,11 +1795,13 @@
* "lexeme": String
* "type": optional String
* "validElementKinds": optional List<String>
+ * "offset": int
* }
*/
final Matcher isTokenDetails = new LazyMatcher(() => new MatchesJsonObject(
"TokenDetails", {
- "lexeme": isString
+ "lexeme": isString,
+ "offset": isInt
}, optionalFields: {
"type": isString,
"validElementKinds": isListOf(isString)
@@ -3511,6 +3541,16 @@
new MatchesJsonObject("server.getVersion result", {"version": isString}));
/**
+ * server.log params
+ *
+ * {
+ * "entry": ServerLogEntry
+ * }
+ */
+final Matcher isServerLogParams = new LazyMatcher(() =>
+ new MatchesJsonObject("server.log params", {"entry": isServerLogEntry}));
+
+/**
* server.setSubscriptions params
*
* {
diff --git a/pkg/analysis_server/test/services/completion/dart/extension_member_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/extension_member_contributor_test.dart
index 1e42d22..2439e91 100644
--- a/pkg/analysis_server/test/services/completion/dart/extension_member_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/extension_member_contributor_test.dart
@@ -26,6 +26,17 @@
super.setUp();
}
+ test_extension() async {
+ addTestSource('''
+extension E on int {}
+void f() {
+ E.a^
+}
+''');
+ await computeSuggestions();
+ assertNoSuggestions();
+ }
+
test_extensionOverride_doesNotMatch() async {
addTestSource('''
extension E on int {
diff --git a/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart
index b4d1d0c..c42a1b6 100644
--- a/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart
@@ -174,6 +174,44 @@
Keyword.WHILE
];
+ List<Keyword> get statementStartInSwitchCaseInClass => [
+ Keyword.ASSERT,
+ Keyword.BREAK,
+ Keyword.CONST,
+ Keyword.DO,
+ Keyword.FINAL,
+ Keyword.FOR,
+ Keyword.IF,
+ Keyword.NEW,
+ Keyword.RETURN,
+ Keyword.SUPER,
+ Keyword.THIS,
+ Keyword.SWITCH,
+ Keyword.THROW,
+ Keyword.TRY,
+ Keyword.VAR,
+ Keyword.VOID,
+ Keyword.WHILE
+ ];
+
+ List<Keyword> get statementStartInSwitchCaseOutsideClass => [
+ Keyword.ASSERT,
+ Keyword.BREAK,
+ Keyword.CONST,
+ Keyword.DO,
+ Keyword.FINAL,
+ Keyword.FOR,
+ Keyword.IF,
+ Keyword.NEW,
+ Keyword.RETURN,
+ Keyword.SWITCH,
+ Keyword.THROW,
+ Keyword.TRY,
+ Keyword.VAR,
+ Keyword.VOID,
+ Keyword.WHILE
+ ];
+
List<Keyword> get statementStartInSwitchInClass => [
Keyword.ASSERT,
Keyword.BREAK,
@@ -1983,6 +2021,18 @@
relevance: DART_RELEVANCE_HIGH);
}
+ test_switch_statement_case_break_insideClass() async {
+ addTestSource('class A{foo() {switch(1) {case 1: b^}}}');
+ await computeSuggestions();
+ assertSuggestKeywords(statementStartInSwitchCaseInClass);
+ }
+
+ test_switch_statement_case_break_outsideClass() async {
+ addTestSource('foo() {switch(1) {case 1: b^}}');
+ await computeSuggestions();
+ assertSuggestKeywords(statementStartInSwitchCaseOutsideClass);
+ }
+
test_switch_statement_insideClass() async {
addTestSource('class A{foo() {switch(1) {case 1:^}}}');
await computeSuggestions();
@@ -2158,6 +2208,14 @@
super.statementStartInLoopOutsideClass..add(Keyword.LATE);
@override
+ List<Keyword> get statementStartInSwitchCaseInClass =>
+ super.statementStartInSwitchCaseInClass..add(Keyword.LATE);
+
+ @override
+ List<Keyword> get statementStartInSwitchCaseOutsideClass =>
+ super.statementStartInSwitchCaseOutsideClass..add(Keyword.LATE);
+
+ @override
List<Keyword> get statementStartInSwitchInClass =>
super.statementStartInSwitchInClass..add(Keyword.LATE);
diff --git a/pkg/analysis_server/test/services/completion/dart/library_member_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/library_member_contributor_test.dart
index e13ad70..cfc022f 100644
--- a/pkg/analysis_server/test/services/completion/dart/library_member_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/library_member_contributor_test.dart
@@ -4,6 +4,7 @@
import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
import 'package:analysis_server/src/services/completion/dart/library_member_contributor.dart';
+import 'package:analyzer/src/dart/analysis/experiments.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -11,7 +12,8 @@
main() {
defineReflectiveSuite(() {
- defineReflectiveTests(LibraryMemberContributorTest);
+// defineReflectiveTests(LibraryMemberContributorTest);
+ defineReflectiveTests(LibraryMemberContributorWithExtensionMethodsTest);
});
}
@@ -280,3 +282,30 @@
assertNoSuggestions();
}
}
+
+@reflectiveTest
+class LibraryMemberContributorWithExtensionMethodsTest
+ extends DartCompletionContributorTest {
+ @override
+ DartCompletionContributor createContributor() {
+ return new LibraryMemberContributor();
+ }
+
+ @override
+ void setupResourceProvider() {
+ super.setupResourceProvider();
+ createAnalysisOptionsFile(experiments: [EnableString.extension_methods]);
+ }
+
+ test_extension() async {
+ // SimpleIdentifier PrefixedIdentifier ExpressionStatement
+ addSource('/home/test/lib/b.dart', '''
+extension MyExt on int {}
+''');
+ addTestSource('''
+ import "b.dart" as b;
+ main() {b.^}''');
+ await computeSuggestions();
+ assertSuggest('MyExt');
+ }
+}
diff --git a/pkg/analysis_server/test/services/completion/dart/static_member_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/static_member_contributor_test.dart
index 1d3e804..1faf68d 100644
--- a/pkg/analysis_server/test/services/completion/dart/static_member_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/static_member_contributor_test.dart
@@ -4,6 +4,7 @@
import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
import 'package:analysis_server/src/services/completion/dart/static_member_contributor.dart';
+import 'package:analyzer/src/dart/analysis/experiments.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -12,6 +13,7 @@
main() {
defineReflectiveSuite(() {
defineReflectiveTests(StaticMemberContributorTest);
+ defineReflectiveTests(StaticMemberContributorWithExtensionMethodsTest);
});
}
@@ -304,3 +306,32 @@
assertNotSuggested('==');
}
}
+
+@reflectiveTest
+class StaticMemberContributorWithExtensionMethodsTest
+ extends DartCompletionContributorTest {
+ @override
+ DartCompletionContributor createContributor() {
+ return new StaticMemberContributor();
+ }
+
+ @override
+ void setupResourceProvider() {
+ super.setupResourceProvider();
+ createAnalysisOptionsFile(experiments: [EnableString.extension_methods]);
+ }
+
+ test_extension() async {
+ addTestSource('''
+extension E on Object {
+ static int i;
+ static String s;
+}
+main() {E.^}
+''');
+ await computeSuggestions();
+ assertNotSuggested('E');
+ assertSuggestField('i', 'int');
+ assertSuggestField('s', 'String');
+ }
+}
diff --git a/pkg/analysis_server/test/services/refactoring/extract_local_test.dart b/pkg/analysis_server/test/services/refactoring/extract_local_test.dart
index 5725680..4d8e897 100644
--- a/pkg/analysis_server/test/services/refactoring/extract_local_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/extract_local_test.dart
@@ -6,6 +6,7 @@
import 'dart:convert';
import 'package:analysis_server/src/services/correction/status.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analysis_server/src/services/refactoring/extract_local.dart';
import 'package:analysis_server/src/services/refactoring/refactoring.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
@@ -90,9 +91,11 @@
test_checkInitialConditions_namePartOfDeclaration_function() async {
await indexTestUnit('''
-void main() {}
+void main() {
+ void foo() {}
+}
''');
- _createRefactoringWithSuffix('main', '()');
+ _createRefactoringWithSuffix('foo', '()');
// check conditions
RefactoringStatus status = await refactoring.checkAllConditions();
assertRefactoringStatus(status, RefactoringProblemSeverity.FATAL,
@@ -734,6 +737,23 @@
expect(refactoring.isAvailable(), isTrue);
}
+ test_lint_prefer_final_locals() async {
+ createAnalysisOptionsFile(lints: [LintNames.prefer_final_locals]);
+ await indexTestUnit('''
+main() {
+ print(1 + 2);
+}
+''');
+ _createRefactoringForString('1 + 2');
+ // apply refactoring
+ return _assertSuccessfulRefactoring('''
+main() {
+ final res = 1 + 2;
+ print(res);
+}
+''');
+ }
+
test_occurrences_differentName_samePrefix() async {
await indexTestUnit('''
void main(A a) {
diff --git a/pkg/analysis_server/test/services/refactoring/rename_extension_member_test.dart b/pkg/analysis_server/test/services/refactoring/rename_extension_member_test.dart
new file mode 100644
index 0000000..c5db8e1
--- /dev/null
+++ b/pkg/analysis_server/test/services/refactoring/rename_extension_member_test.dart
@@ -0,0 +1,338 @@
+// Copyright (c) 2019, 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/status.dart';
+import 'package:analyzer_plugin/protocol/protocol_common.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'abstract_rename.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(RenameExtensionMemberTest);
+ });
+}
+
+@reflectiveTest
+class RenameExtensionMemberTest extends RenameRefactoringTest {
+ void setUp() {
+ createAnalysisOptionsFile(experiments: ['extension-methods']);
+ super.setUp();
+ }
+
+ test_checkFinalConditions_hasMember_MethodElement() async {
+ await indexTestUnit('''
+extension E on int {
+ test() {}
+ newName() {} // existing
+}
+''');
+ createRenameRefactoringAtString('test() {}');
+ // check status
+ refactoring.newName = 'newName';
+ RefactoringStatus status = await refactoring.checkFinalConditions();
+ assertRefactoringStatus(status, RefactoringProblemSeverity.ERROR,
+ expectedMessage:
+ "Extension 'E' already declares method with name 'newName'.",
+ expectedContextSearch: 'newName() {} // existing');
+ }
+
+ test_checkFinalConditions_OK_dropSuffix() async {
+ await indexTestUnit(r'''
+extension E on int {
+ void testOld() {}
+}
+''');
+ createRenameRefactoringAtString('testOld() {}');
+ // check status
+ refactoring.newName = 'test';
+ RefactoringStatus status = await refactoring.checkFinalConditions();
+ assertRefactoringStatusOK(status);
+ }
+
+ test_checkFinalConditions_shadowed_byLocalFunction_inExtension() async {
+ await indexTestUnit('''
+extension E on int {
+ test() {}
+ main() {
+ newName() {}
+ test(); // marker
+ }
+}
+''');
+ createRenameRefactoringAtString('test() {}');
+ // check status
+ refactoring.newName = 'newName';
+ RefactoringStatus status = await refactoring.checkFinalConditions();
+ assertRefactoringStatus(
+ status,
+ RefactoringProblemSeverity.ERROR,
+ expectedMessage:
+ "Usage of renamed method will be shadowed by function 'newName'.",
+ expectedContextSearch: 'test(); // marker',
+ );
+ }
+
+ test_checkFinalConditions_shadowed_byLocalVariable_inExtension() async {
+ await indexTestUnit('''
+extension E on int {
+ test() {}
+ main() {
+ var newName;
+ test(); // marker
+ }
+}
+''');
+ createRenameRefactoringAtString('test() {}');
+ // check status
+ refactoring.newName = 'newName';
+ RefactoringStatus status = await refactoring.checkFinalConditions();
+ assertRefactoringStatus(
+ status,
+ RefactoringProblemSeverity.ERROR,
+ expectedMessage:
+ "Usage of renamed method will be shadowed by local variable 'newName'.",
+ expectedContextSearch: 'test(); // marker',
+ );
+ }
+
+ test_checkFinalConditions_shadowed_byParameter_inExtension() async {
+ await indexTestUnit('''
+extension E on int {
+ test() {}
+ main(newName) {
+ test(); // marker
+ }
+}
+''');
+ createRenameRefactoringAtString('test() {}');
+ // check status
+ refactoring.newName = 'newName';
+ RefactoringStatus status = await refactoring.checkFinalConditions();
+ assertRefactoringStatus(
+ status,
+ RefactoringProblemSeverity.ERROR,
+ expectedMessage:
+ "Usage of renamed method will be shadowed by parameter 'newName'.",
+ expectedContextSearch: 'test(); // marker',
+ );
+ }
+
+ test_checkInitialConditions_operator() async {
+ await indexTestUnit('''
+extension E on int {
+ operator -(other) => null;
+}
+''');
+ createRenameRefactoringAtString('-(other)');
+ // check status
+ refactoring.newName = 'newName';
+ RefactoringStatus status = await refactoring.checkInitialConditions();
+ assertRefactoringStatus(status, RefactoringProblemSeverity.FATAL);
+ }
+
+ test_checkNewName_FieldElement() async {
+ await indexTestUnit('''
+extension E on int {
+ int get test => 0;
+}
+''');
+ createRenameRefactoringAtString('test =>');
+ // null
+ refactoring.newName = null;
+ assertRefactoringStatus(
+ refactoring.checkNewName(),
+ RefactoringProblemSeverity.FATAL,
+ expectedMessage: "Field name must not be null.",
+ );
+
+ // OK
+ refactoring.newName = 'newName';
+ assertRefactoringStatusOK(refactoring.checkNewName());
+ }
+
+ test_checkNewName_MethodElement() async {
+ await indexTestUnit('''
+extension E on int {
+ void test() {}
+}
+''');
+ createRenameRefactoringAtString('test() {}');
+
+ // null
+ refactoring.newName = null;
+ assertRefactoringStatus(
+ refactoring.checkNewName(),
+ RefactoringProblemSeverity.FATAL,
+ expectedMessage: "Method name must not be null.",
+ );
+
+ // empty
+ refactoring.newName = '';
+ assertRefactoringStatus(
+ refactoring.checkNewName(),
+ RefactoringProblemSeverity.FATAL,
+ expectedMessage: "Method name must not be empty.",
+ );
+
+ // same
+ refactoring.newName = 'test';
+ assertRefactoringStatus(
+ refactoring.checkNewName(),
+ RefactoringProblemSeverity.FATAL,
+ expectedMessage: "The new name must be different than the current name.",
+ );
+
+ // OK
+ refactoring.newName = 'newName';
+ assertRefactoringStatusOK(refactoring.checkNewName());
+ }
+
+ test_createChange_MethodElement_instance() async {
+ await indexTestUnit('''
+class A {}
+
+extension E on A {
+ test() {} // marker
+}
+
+main() {
+ var a = A();
+ a.test();
+ E(a).test();
+}
+''');
+ // configure refactoring
+ createRenameRefactoringAtString('test() {} // marker');
+ expect(refactoring.refactoringName, 'Rename Method');
+ expect(refactoring.elementKindName, 'method');
+ expect(refactoring.oldName, 'test');
+ refactoring.newName = 'newName';
+ // validate change
+ return assertSuccessfulRefactoring('''
+class A {}
+
+extension E on A {
+ newName() {} // marker
+}
+
+main() {
+ var a = A();
+ a.newName();
+ E(a).newName();
+}
+''');
+ }
+
+ test_createChange_PropertyAccessorElement_getter() async {
+ await indexTestUnit('''
+extension E on int {
+ get test {} // marker
+ set test(x) {}
+ main() {
+ test;
+ test = 1;
+ }
+}
+main() {
+ 0.test;
+ 0.test = 2;
+
+ E(0).test;
+ E(0).test = 3;
+}
+''');
+ // configure refactoring
+ createRenameRefactoringAtString('test {} // marker');
+ expect(refactoring.refactoringName, 'Rename Field');
+ expect(refactoring.oldName, 'test');
+ refactoring.newName = 'newName';
+ // validate change
+ return assertSuccessfulRefactoring('''
+extension E on int {
+ get newName {} // marker
+ set newName(x) {}
+ main() {
+ newName;
+ newName = 1;
+ }
+}
+main() {
+ 0.newName;
+ 0.newName = 2;
+
+ E(0).newName;
+ E(0).newName = 3;
+}
+''');
+ }
+
+ test_createChange_PropertyAccessorElement_setter() async {
+ await indexTestUnit('''
+extension E on int {
+ get test {}
+ set test(x) {} // marker
+ main() {
+ test;
+ test = 1;
+ }
+}
+main() {
+ 0.test;
+ 0.test = 2;
+
+ E(0).test;
+ E(0).test = 3;
+}
+''');
+ // configure refactoring
+ createRenameRefactoringAtString('test(x) {} // marker');
+ expect(refactoring.refactoringName, 'Rename Field');
+ expect(refactoring.oldName, 'test');
+ refactoring.newName = 'newName';
+ // validate change
+ return assertSuccessfulRefactoring('''
+extension E on int {
+ get newName {}
+ set newName(x) {} // marker
+ main() {
+ newName;
+ newName = 1;
+ }
+}
+main() {
+ 0.newName;
+ 0.newName = 2;
+
+ E(0).newName;
+ E(0).newName = 3;
+}
+''');
+ }
+
+ test_createChange_TypeParameterElement() async {
+ await indexTestUnit('''
+extension E<Test> on int {
+ Test get g1 => null;
+ List<Test> get g2 => null;
+ Test m(Test p) => null;
+}
+''');
+ // configure refactoring
+ createRenameRefactoringAtString('Test> on int {');
+ expect(refactoring.refactoringName, 'Rename Type Parameter');
+ expect(refactoring.elementKindName, 'type parameter');
+ expect(refactoring.oldName, 'Test');
+ refactoring.newName = 'NewName';
+ // validate change
+ return assertSuccessfulRefactoring('''
+extension E<NewName> on int {
+ NewName get g1 => null;
+ List<NewName> get g2 => null;
+ NewName m(NewName p) => null;
+}
+''');
+ }
+}
diff --git a/pkg/analysis_server/test/services/refactoring/test_all.dart b/pkg/analysis_server/test/services/refactoring/test_all.dart
index a63865d..17ce7af 100644
--- a/pkg/analysis_server/test/services/refactoring/test_all.dart
+++ b/pkg/analysis_server/test/services/refactoring/test_all.dart
@@ -15,6 +15,7 @@
import 'naming_conventions_test.dart' as naming_conventions_test;
import 'rename_class_member_test.dart' as rename_class_member_test;
import 'rename_constructor_test.dart' as rename_constructor_test;
+import 'rename_extension_member_test.dart' as rename_extension_member_test;
import 'rename_import_test.dart' as rename_import_test;
import 'rename_label_test.dart' as rename_label_test;
import 'rename_library_test.dart' as rename_library_test;
@@ -35,6 +36,7 @@
naming_conventions_test.main();
rename_class_member_test.main();
rename_constructor_test.main();
+ rename_extension_member_test.main();
rename_import_test.main();
rename_label_test.main();
rename_library_test.main();
diff --git a/pkg/analysis_server/test/src/computer/highlights2_computer_test.dart b/pkg/analysis_server/test/src/computer/highlights2_computer_test.dart
index bda2825..4dbd8be 100644
--- a/pkg/analysis_server/test/src/computer/highlights2_computer_test.dart
+++ b/pkg/analysis_server/test/src/computer/highlights2_computer_test.dart
@@ -38,6 +38,18 @@
_check(HighlightRegionType.BUILT_IN, 'on');
}
+ test_methodInvocation_ofExtensionOverride_unresolved() async {
+ createAnalysisOptionsFile(experiments: ['extension-methods']);
+ await _computeHighlights('''
+extension E on int {}
+
+main() {
+ E(0).foo();
+}
+''', hasErrors: true);
+ _check(HighlightRegionType.IDENTIFIER_DEFAULT, 'foo');
+ }
+
void _check(HighlightRegionType expectedType, String expectedText) {
for (var region in highlights) {
if (region.type == expectedType) {
@@ -52,11 +64,20 @@
fail('Expected region of type $expectedType with text "$expectedText"');
}
- Future<void> _computeHighlights(String content) async {
+ Future<void> _computeHighlights(
+ String content, {
+ bool hasErrors = false,
+ }) async {
this.content = content;
newFile(sourcePath, content: content);
ResolvedUnitResult result = await session.getResolvedUnit(sourcePath);
- expect(result.errors, hasLength(0));
+
+ if (hasErrors) {
+ expect(result.errors, isNotEmpty);
+ } else {
+ expect(result.errors, isEmpty);
+ }
+
DartUnitHighlightsComputer2 computer =
new DartUnitHighlightsComputer2(result.unit);
highlights = computer.compute();
diff --git a/pkg/analysis_server/test/src/computer/highlights_computer_test.dart b/pkg/analysis_server/test/src/computer/highlights_computer_test.dart
index ab5d0ab..bdba0de 100644
--- a/pkg/analysis_server/test/src/computer/highlights_computer_test.dart
+++ b/pkg/analysis_server/test/src/computer/highlights_computer_test.dart
@@ -38,6 +38,18 @@
_check(HighlightRegionType.BUILT_IN, 'on');
}
+ test_methodInvocation_ofExtensionOverride_unresolved() async {
+ createAnalysisOptionsFile(experiments: ['extension-methods']);
+ await _computeHighlights('''
+extension E on int {}
+
+main() {
+ E(0).foo();
+}
+''', hasErrors: true);
+ _check(HighlightRegionType.IDENTIFIER_DEFAULT, 'foo');
+ }
+
void _check(HighlightRegionType expectedType, String expectedText) {
for (var region in highlights) {
if (region.type == expectedType) {
@@ -52,11 +64,20 @@
fail('Expected region of type $expectedType with text "$expectedText"');
}
- Future<void> _computeHighlights(String content) async {
+ Future<void> _computeHighlights(
+ String content, {
+ bool hasErrors = false,
+ }) async {
this.content = content;
newFile(sourcePath, content: content);
ResolvedUnitResult result = await session.getResolvedUnit(sourcePath);
- expect(result.errors, hasLength(0));
+
+ if (hasErrors) {
+ expect(result.errors, isNotEmpty);
+ } else {
+ expect(result.errors, isEmpty);
+ }
+
DartUnitHighlightsComputer computer =
new DartUnitHighlightsComputer(result.unit);
highlights = computer.compute();
diff --git a/pkg/analysis_server/test/src/domains/completion/available_suggestion_sets_test.dart b/pkg/analysis_server/test/src/domains/completion/available_suggestion_sets_test.dart
index a6f62cf..6e8af8e 100644
--- a/pkg/analysis_server/test/src/domains/completion/available_suggestion_sets_test.dart
+++ b/pkg/analysis_server/test/src/domains/completion/available_suggestion_sets_test.dart
@@ -100,6 +100,10 @@
},
"parameterNames": [],
"parameterTypes": [],
+ "relevanceTags": [
+ "package:test/a.dart::A",
+ "a"
+ ],
"requiredParameterCount": 0
}
''');
diff --git a/pkg/analysis_server/test/src/domains/completion/get_suggestions_available_test.dart b/pkg/analysis_server/test/src/domains/completion/get_suggestions_available_test.dart
index 824d864..e6704f8 100644
--- a/pkg/analysis_server/test/src/domains/completion/get_suggestions_available_test.dart
+++ b/pkg/analysis_server/test/src/domains/completion/get_suggestions_available_test.dart
@@ -300,6 +300,26 @@
''');
}
+ test_relevanceTags_location_initializer() async {
+ addTestFile(r'''
+int v = // ref;
+''');
+
+ var results = await _getSuggestions(
+ testFile,
+ testCode.indexOf(' // ref'),
+ );
+
+ assertJsonText(results.includedSuggestionRelevanceTags, r'''
+[
+ {
+ "tag": "dart:core::int",
+ "relevanceBoost": 10
+ }
+]
+''');
+ }
+
test_relevanceTags_location_listLiteral() async {
addTestFile(r'''
main() {
diff --git a/pkg/analysis_server/test/src/services/correction/assist/add_type_annotation_test.dart b/pkg/analysis_server/test/src/services/correction/assist/add_type_annotation_test.dart
index 7019111..736d455 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/add_type_annotation_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/add_type_annotation_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/assist/assist.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -19,6 +20,17 @@
@override
AssistKind get kind => DartAssistKind.ADD_TYPE_ANNOTATION;
+ test_classField_final_noAssistWithLint() async {
+ createAnalysisOptionsFile(lints: [LintNames.always_specify_types]);
+ verifyNoTestUnitErrors = false;
+ await resolveTestUnit('''
+class A {
+ /*caret*/final f = 0;
+}
+''');
+ await assertNoAssist();
+ }
+
test_classField_final() async {
await resolveTestUnit('''
class A {
diff --git a/pkg/analysis_server/test/src/services/correction/assist/convert_documentation_into_line_test.dart b/pkg/analysis_server/test/src/services/correction/assist/convert_documentation_into_line_test.dart
index b13e269..eb40c88 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/convert_documentation_into_line_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/convert_documentation_into_line_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/assist/assist.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -90,6 +91,22 @@
''');
}
+ test_onText_noAssistWithLint() async {
+ createAnalysisOptionsFile(lints: [LintNames.slash_for_doc_comments]);
+ verifyNoTestUnitErrors = false;
+ await resolveTestUnit('''
+class A {
+ /**
+ * AAAAAAA [int] AAAAAAA
+ * BBBBBBBB BBBB BBBB
+ * CCC [A] CCCCCCCCCCC
+ */
+ mmm() {}
+}
+''');
+ await assertNoAssist();
+ }
+
test_onText_hasFirstLine() async {
await resolveTestUnit('''
class A {
diff --git a/pkg/analysis_server/test/src/services/correction/assist/convert_into_expression_body_test.dart b/pkg/analysis_server/test/src/services/correction/assist/convert_into_expression_body_test.dart
index cb7e2e2..c5cb328 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/convert_into_expression_body_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/convert_into_expression_body_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/assist/assist.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -41,6 +42,20 @@
''');
}
+ test_async_noAssistWithLint() async {
+ createAnalysisOptionsFile(
+ lints: [LintNames.prefer_expression_function_bodies]);
+ verifyNoTestUnitErrors = false;
+ await resolveTestUnit('''
+class A {
+ mmm() async {
+ return 42;
+ }
+}
+''');
+ await assertNoAssist();
+ }
+
test_closure() async {
await resolveTestUnit('''
setup(x) {}
diff --git a/pkg/analysis_server/test/src/services/correction/assist/convert_to_for_element_test.dart b/pkg/analysis_server/test/src/services/correction/assist/convert_to_for_element_test.dart
index 0a53680..9d00d66 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/convert_to_for_element_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/convert_to_for_element_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer/src/dart/analysis/experiments.dart';
import 'package:analyzer_plugin/utilities/assist/assist.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -65,6 +66,19 @@
''');
}
+ test_mapFromIterable_differentParameterNames_usedInKey_conflictInValue_noAssistWithLint() async {
+ createAnalysisOptionsFile(
+ lints: [LintNames.prefer_for_elements_to_map_fromIterable]);
+ verifyNoTestUnitErrors = false;
+ await resolveTestUnit('''
+f(Iterable<int> i) {
+ var k = 3;
+ return Map.fromIt/*caret*/erable(i, key: (k) => k * 2, value: (v) => k);
+}
+''');
+ await assertNoAssist();
+ }
+
test_mapFromIterable_differentParameterNames_usedInKey_noConflictInValue() async {
await resolveTestUnit('''
f(Iterable<int> i) {
diff --git a/pkg/analysis_server/test/src/services/correction/assist/convert_to_if_element_test.dart b/pkg/analysis_server/test/src/services/correction/assist/convert_to_if_element_test.dart
index 5caae77..a718b6a 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/convert_to_if_element_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/convert_to_if_element_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer/src/dart/analysis/experiments.dart';
import 'package:analyzer_plugin/utilities/assist/assist.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -52,6 +53,18 @@
''');
}
+ test_conditional_list_noAssistWithLint() async {
+ createAnalysisOptionsFile(
+ lints: [LintNames.prefer_if_elements_to_conditional_expressions]);
+ verifyNoTestUnitErrors = false;
+ await resolveTestUnit('''
+f(bool b) {
+ return ['a', b /*caret*/? 'c' : 'd', 'e'];
+}
+''');
+ await assertNoAssist();
+ }
+
test_conditional_list_withParentheses() async {
await resolveTestUnit('''
f(bool b) {
diff --git a/pkg/analysis_server/test/src/services/correction/assist/convert_to_int_literal_test.dart b/pkg/analysis_server/test/src/services/correction/assist/convert_to_int_literal_test.dart
index 79859c4..b1137ac 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/convert_to_int_literal_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/convert_to_int_literal_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/assist/assist.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -28,6 +29,15 @@
''');
}
+ test_decimal_noAssistWithLint() async {
+ createAnalysisOptionsFile(lints: [LintNames.prefer_int_literals]);
+ verifyNoTestUnitErrors = false;
+ await resolveTestUnit('''
+const double myDouble = /*caret*/42.0;
+''');
+ await assertNoAssist();
+ }
+
test_notDouble() async {
await resolveTestUnit('''
const double myDouble = /*caret*/42;
diff --git a/pkg/analysis_server/test/src/services/correction/assist/convert_to_null_aware_test.dart b/pkg/analysis_server/test/src/services/correction/assist/convert_to_null_aware_test.dart
index 5677205..dfe8b4e 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/convert_to_null_aware_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/convert_to_null_aware_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/assist/assist.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -95,6 +96,18 @@
''');
}
+ test_equal_nullOnLeft_noAssistWithLint() async {
+ createAnalysisOptionsFile(lints: [LintNames.prefer_null_aware_operators]);
+ verifyNoTestUnitErrors = false;
+ await resolveTestUnit('''
+abstract class A {
+ int m();
+}
+int f(A a) => null == a ? null : a.m();
+''');
+ await assertNoAssist();
+ }
+
test_equal_nullOnRight() async {
await resolveTestUnit('''
abstract class A {
diff --git a/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_column_test.dart b/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_column_test.dart
index 6e668f3..c22ea1d9 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_column_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_column_test.dart
@@ -19,6 +19,40 @@
@override
AssistKind get kind => DartAssistKind.FLUTTER_WRAP_COLUMN;
+ test_controlFlowCollections_if() async {
+ addFlutterPackage();
+ await resolveTestUnit('''
+import 'package:flutter/widgets.dart';
+
+Widget build(bool b) {
+ return Row(
+ children: [
+ Text('aaa'),
+ if (b) /*caret*/Text('bbb'),
+ Text('ccc'),
+ ],
+ );
+}
+''');
+ await assertHasAssist('''
+import 'package:flutter/widgets.dart';
+
+Widget build(bool b) {
+ return Row(
+ children: [
+ Text('aaa'),
+ if (b) Column(
+ children: <Widget>[
+ Text('bbb'),
+ ],
+ ),
+ Text('ccc'),
+ ],
+ );
+}
+''');
+ }
+
test_coveredByWidget() async {
addFlutterPackage();
await resolveTestUnit('''
diff --git a/pkg/analysis_server/test/src/services/correction/assist/use_curly_braces_test.dart b/pkg/analysis_server/test/src/services/correction/assist/use_curly_braces_test.dart
index f3e6589..650dfd0 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/use_curly_braces_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/use_curly_braces_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/assist/assist.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -355,6 +356,18 @@
''');
}
+ test_noAssistWithLint() async {
+ createAnalysisOptionsFile(
+ lints: [LintNames.curly_braces_in_flow_control_structures]);
+ verifyNoTestUnitErrors = false;
+ await resolveTestUnit('''
+main() {
+ do print/*caret*/(0); while (true);
+}
+''');
+ await assertNoAssist();
+ }
+
test_while_body_end() async {
await resolveTestUnit('''
main() {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_await_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_await_test.dart
index 1391007..aee1f1c 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_await_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_await_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_const_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_const_test.dart
new file mode 100644
index 0000000..8ed3a7f
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_const_test.dart
@@ -0,0 +1,57 @@
+// Copyright (c) 2019, 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.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(AddConstTest);
+ });
+}
+
+@reflectiveTest
+class AddConstTest extends FixProcessorLintTest {
+ @override
+ FixKind get kind => DartFixKind.ADD_CONST;
+
+ @override
+ String get lintCode => LintNames.prefer_const_constructors;
+
+ test_basic() async {
+ await resolveTestUnit('''
+class C {
+ const C();
+}
+main() {
+ var c = C/*LINT*/();
+}
+''');
+ await assertHasFix('''
+class C {
+ const C();
+}
+main() {
+ var c = const C/*LINT*/();
+}
+''');
+ }
+
+ test_not_present() async {
+ await resolveTestUnit('''
+class C {
+ const C();
+}
+main() {
+ var c = new C/*LINT*/();
+}
+''');
+ // handled by REPLACE_NEW_WITH_CONST
+ await assertNoFix();
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_curly_braces_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_curly_braces_test.dart
new file mode 100644
index 0000000..ae04af5
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_curly_braces_test.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2019, 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.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(AddCurlyBracesTest);
+ });
+}
+
+@reflectiveTest
+class AddCurlyBracesTest extends FixProcessorLintTest {
+ @override
+ FixKind get kind => DartFixKind.ADD_CURLY_BRACES;
+
+ @override
+ String get lintCode => LintNames.curly_braces_in_flow_control_structures;
+
+ // More coverage in the `use_curly_braces_test.dart` assist test.
+ test_do_block() async {
+ await resolveTestUnit('''
+main() {
+ do /*LINT*/print(0); while (true);
+}
+''');
+ await assertHasFix('''
+main() {
+ do {
+ print(0);
+ } while (true);
+}
+''');
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_override_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_override_test.dart
index 8a1cf11..229c280 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_override_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_override_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
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 eae5d92..5698974 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
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_type_annotation_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_type_annotation_test.dart
new file mode 100644
index 0000000..a7b406c
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_type_annotation_test.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2019, 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.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(AddTypeAnnotationTest);
+ });
+}
+
+@reflectiveTest
+class AddTypeAnnotationTest extends FixProcessorLintTest {
+ @override
+ FixKind get kind => DartFixKind.ADD_TYPE_ANNOTATION;
+
+ @override
+ String get lintCode => LintNames.always_specify_types;
+
+ // More coverage in the `add_type_annotation_test.dart` assist test.
+ test_do_block() async {
+ await resolveTestUnit('''
+class A {
+ /*LINT*/final f = 0;
+}
+''');
+ await assertHasFix('''
+class A {
+ /*LINT*/final int f = 0;
+}
+''');
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/change_to_test.dart b/pkg/analysis_server/test/src/services/correction/fix/change_to_test.dart
index 553d1e5..0a30962 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/change_to_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/change_to_test.dart
@@ -11,6 +11,7 @@
main() {
defineReflectiveSuite(() {
defineReflectiveTests(ChangeToTest);
+ defineReflectiveTests(ChangeToWithExtensionMethodsTest);
});
}
@@ -19,7 +20,7 @@
@override
FixKind get kind => DartFixKind.CHANGE_TO;
- test_undefinedClass_fromImport() async {
+ test_class_fromImport() async {
await resolveTestUnit('''
main() {
Stirng s = 'abc';
@@ -34,7 +35,7 @@
''');
}
- test_undefinedClass_fromThisLibrary() async {
+ test_class_fromThisLibrary() async {
await resolveTestUnit('''
class MyClass {}
main() {
@@ -51,7 +52,7 @@
''');
}
- test_undefinedClass_prefixed() async {
+ test_class_prefixed() async {
await resolveTestUnit('''
import 'dart:async' as c;
main() {
@@ -68,7 +69,7 @@
''');
}
- test_undefinedFunction_fromImport() async {
+ test_function_fromImport() async {
await resolveTestUnit('''
main() {
pritn(0);
@@ -81,7 +82,7 @@
''');
}
- test_undefinedFunction_prefixed_fromImport() async {
+ test_function_prefixed_fromImport() async {
await resolveTestUnit('''
import 'dart:core' as c;
main() {
@@ -96,7 +97,7 @@
''');
}
- test_undefinedFunction_prefixed_ignoreLocal() async {
+ test_function_prefixed_ignoreLocal() async {
await resolveTestUnit('''
import 'dart:async' as c;
main() {
@@ -106,7 +107,7 @@
await assertNoFix();
}
- test_undefinedFunction_thisLibrary() async {
+ test_function_thisLibrary() async {
await resolveTestUnit('''
myFunction() {}
main() {
@@ -121,7 +122,7 @@
''');
}
- test_undefinedGetter_hint() async {
+ test_getter_hint() async {
await resolveTestUnit('''
class A {
int myField;
@@ -142,7 +143,7 @@
''');
}
- test_undefinedGetter_qualified() async {
+ test_getter_qualified() async {
await resolveTestUnit('''
class A {
int myField;
@@ -161,7 +162,7 @@
''');
}
- test_undefinedGetter_qualified_static() async {
+ test_getter_qualified_static() async {
await resolveTestUnit('''
class A {
static int MY_NAME = 1;
@@ -180,7 +181,7 @@
''');
}
- test_undefinedGetter_unqualified() async {
+ test_getter_unqualified() async {
await resolveTestUnit('''
class A {
int myField;
@@ -199,7 +200,7 @@
''');
}
- test_undefinedMethod_ignoreOperators() async {
+ test_method_ignoreOperators() async {
await resolveTestUnit('''
main(Object object) {
object.then();
@@ -208,7 +209,7 @@
await assertNoFix();
}
- test_undefinedMethod_qualified() async {
+ test_method_qualified() async {
await resolveTestUnit('''
class A {
myMethod() {}
@@ -229,7 +230,7 @@
''');
}
- test_undefinedMethod_unqualified_superClass() async {
+ test_method_unqualified_superClass() async {
await resolveTestUnit('''
class A {
myMethod() {}
@@ -252,7 +253,7 @@
''');
}
- test_undefinedMethod_unqualified_thisClass() async {
+ test_method_unqualified_thisClass() async {
await resolveTestUnit('''
class A {
myMethod() {}
@@ -271,7 +272,7 @@
''');
}
- test_undefinedSetter_hint() async {
+ test_setter_hint() async {
await resolveTestUnit('''
class A {
int myField;
@@ -292,7 +293,7 @@
''');
}
- test_undefinedSetter_qualified() async {
+ test_setter_qualified() async {
await resolveTestUnit('''
class A {
int myField;
@@ -311,7 +312,7 @@
''');
}
- test_undefinedSetter_unqualified() async {
+ test_setter_unqualified() async {
await resolveTestUnit('''
class A {
int myField;
@@ -330,3 +331,128 @@
''');
}
}
+
+@reflectiveTest
+class ChangeToWithExtensionMethodsTest extends FixProcessorTest {
+ @override
+ FixKind get kind => DartFixKind.CHANGE_TO;
+
+ void setUp() {
+ createAnalysisOptionsFile(experiments: ['extension-methods']);
+ super.setUp();
+ }
+
+ test_getter_override() async {
+ await resolveTestUnit('''
+extension E on int {
+ int get myGetter => 0;
+}
+void f() {
+ E(1).myGeter;
+}
+''');
+ await assertHasFix('''
+extension E on int {
+ int get myGetter => 0;
+}
+void f() {
+ E(1).myGetter;
+}
+''');
+ }
+
+ test_getter_static() async {
+ await resolveTestUnit('''
+extension E on int {
+ static int get myGetter => 0;
+}
+void f() {
+ E.myGeter;
+}
+''');
+ await assertHasFix('''
+extension E on int {
+ static int get myGetter => 0;
+}
+void f() {
+ E.myGetter;
+}
+''');
+ }
+
+ test_method_override() async {
+ await resolveTestUnit('''
+extension E on int {
+ int myMethod() => 0;
+}
+void f() {
+ E(1).myMetod();
+}
+''');
+ await assertHasFix('''
+extension E on int {
+ int myMethod() => 0;
+}
+void f() {
+ E(1).myMethod();
+}
+''');
+ }
+
+ test_method_static() async {
+ await resolveTestUnit('''
+extension E on int {
+ static int myMethod() => 0;
+}
+void f() {
+ E.myMetod();
+}
+''');
+ await assertHasFix('''
+extension E on int {
+ static int myMethod() => 0;
+}
+void f() {
+ E.myMethod();
+}
+''');
+ }
+
+ test_setter_override() async {
+ await resolveTestUnit('''
+extension E on int {
+ void set mySetter(int i) {}
+}
+void f() {
+ E(1).mySeter = 0;
+}
+''');
+ await assertHasFix('''
+extension E on int {
+ void set mySetter(int i) {}
+}
+void f() {
+ E(1).mySetter = 0;
+}
+''');
+ }
+
+ test_setter_static() async {
+ await resolveTestUnit('''
+extension E on int {
+ static void set mySetter(int i) {}
+}
+void f() {
+ E.mySeter = 0;
+}
+''');
+ await assertHasFix('''
+extension E on int {
+ static void set mySetter(int i) {}
+}
+void f() {
+ E.mySetter = 0;
+}
+''');
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_documentation_into_line_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_documentation_into_line_test.dart
new file mode 100644
index 0000000..8acb794
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_documentation_into_line_test.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2019, 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.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(ConvertDocumentationIntoLineTest);
+ });
+}
+
+@reflectiveTest
+class ConvertDocumentationIntoLineTest extends FixProcessorLintTest {
+ @override
+ FixKind get kind => DartFixKind.CONVERT_TO_LINE_COMMENT;
+
+ @override
+ String get lintCode => LintNames.slash_for_doc_comments;
+
+ // More coverage in the `convert_to_documentation_line_test.dart` assist test.
+ test_onText() async {
+ await resolveTestUnit('''
+class A {
+ /**
+ * /*LINT*/AAAAAAA [int] AAAAAAA
+ * BBBBBBBB BBBB BBBB
+ * CCC [A] CCCCCCCCCCC
+ */
+ mmm() {}
+}
+''');
+ await assertHasFix('''
+class A {
+ /// /*LINT*/AAAAAAA [int] AAAAAAA
+ /// BBBBBBBB BBBB BBBB
+ /// CCC [A] CCCCCCCCCCC
+ mmm() {}
+}
+''');
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_into_expression_body_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_into_expression_body_test.dart
new file mode 100644
index 0000000..6ec1ad1
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_into_expression_body_test.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2019, 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.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(ConvertIntoExpressionBodyTest);
+ });
+}
+
+@reflectiveTest
+class ConvertIntoExpressionBodyTest extends FixProcessorLintTest {
+ @override
+ FixKind get kind => DartFixKind.CONVERT_INTO_EXPRESSION_BODY;
+
+ @override
+ String get lintCode => LintNames.prefer_expression_function_bodies;
+
+ /// More coverage in the `convert_into_expression_body_test.dart` assist test.
+ test_async() async {
+ await resolveTestUnit('''
+class A {
+ mmm() async {
+ return 42; /*LINT*/
+ }
+}
+''');
+ await assertHasFix('''
+class A {
+ mmm() async => 42;
+}
+''');
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_for_element_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_for_element_test.dart
new file mode 100644
index 0000000..d2a6bd9
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_for_element_test.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2019, 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.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(ConvertToForElementTest);
+ });
+}
+
+@reflectiveTest
+class ConvertToForElementTest extends FixProcessorLintTest {
+ @override
+ FixKind get kind => DartFixKind.CONVERT_TO_FOR_ELEMENT;
+
+ @override
+ String get lintCode => LintNames.prefer_for_elements_to_map_fromIterable;
+
+ // More coverage in the `convert_to_for_element_line_test.dart` assist test.
+ test_mapFromIterable_differentParameterNames_usedInKey_conflictInValue() async {
+ await resolveTestUnit('''
+f(Iterable<int> i) {
+ var k = 3;
+ return Map.fromIterable/*LINT*/(i, key: (k) => k * 2, value: (v) => k);
+}
+''');
+ await assertHasFix('''
+f(Iterable<int> i) {
+ var k = 3;
+ return { for (var e in i) e * 2 : k };
+}
+''');
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_if_element_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_if_element_test.dart
new file mode 100644
index 0000000..c99a0be
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_if_element_test.dart
@@ -0,0 +1,40 @@
+// Copyright (c) 2019, 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.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(ConvertToIfElementTest);
+ });
+}
+
+@reflectiveTest
+class ConvertToIfElementTest extends FixProcessorLintTest {
+ @override
+ FixKind get kind => DartFixKind.CONVERT_TO_IF_ELEMENT;
+
+ @override
+ String get lintCode =>
+ LintNames.prefer_if_elements_to_conditional_expressions;
+
+ // More coverage in the `convert_to_if_element_test.dart` assist test.
+ test_conditional_list() async {
+ await resolveTestUnit('''
+f(bool b) {
+ return ['a', b /*LINT*/? 'c' : 'd', 'e'];
+}
+''');
+ await assertHasFix('''
+f(bool b) {
+ return ['a', if (b) 'c' else 'd', 'e'];
+}
+''');
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_int_literal_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_int_literal_test.dart
new file mode 100644
index 0000000..8c75087
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_int_literal_test.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2019, 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.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(ConvertToIntLiteralTest);
+ });
+}
+
+@reflectiveTest
+class ConvertToIntLiteralTest extends FixProcessorLintTest {
+ @override
+ FixKind get kind => DartFixKind.CONVERT_TO_INT_LITERAL;
+
+ @override
+ String get lintCode => LintNames.prefer_int_literals;
+
+ /// More coverage in the `convert_to_int_literal_test.dart` assist test.
+ test_decimal() async {
+ await resolveTestUnit('''
+const double myDouble = /*LINT*/42.0;
+''');
+ await assertHasFix('''
+const double myDouble = /*LINT*/42;
+''');
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_named_arguments_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_named_arguments_test.dart
index de9c388..b61d6ef 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/convert_to_named_arguments_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_named_arguments_test.dart
@@ -95,6 +95,44 @@
''');
}
+ test_methodInvocation_functionTypedGetter() async {
+ await resolveTestUnit('''
+class A {
+ void Function({int aaa}) get g => null;
+}
+
+main(A a) {
+ a.g(0);
+}
+''');
+ await assertHasFix('''
+class A {
+ void Function({int aaa}) get g => null;
+}
+
+main(A a) {
+ a.g(aaa: 0);
+}
+''');
+ }
+
+ test_methodInvocation_functionTypedVariable() async {
+ await resolveTestUnit('''
+typedef F = void Function({int aaa});
+
+main(F f) {
+ f(0);
+}
+''');
+ await assertHasFix('''
+typedef F = void Function({int aaa});
+
+main(F f) {
+ f(aaa: 0);
+}
+''');
+ }
+
test_noCompatibleParameter() async {
await resolveTestUnit('''
class A {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_null_aware_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_null_aware_test.dart
new file mode 100644
index 0000000..3f8d5e6
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_null_aware_test.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2019, 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.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(ConvertToNullAwareTest);
+ });
+}
+
+@reflectiveTest
+class ConvertToNullAwareTest extends FixProcessorLintTest {
+ @override
+ FixKind get kind => DartFixKind.CONVERT_TO_NULL_AWARE;
+
+ @override
+ String get lintCode => LintNames.prefer_null_aware_operators;
+
+ /// More coverage in the `convert_to_null_aware_test.dart` assist test.
+ test_equal_nullOnLeft() async {
+ await resolveTestUnit('''
+abstract class A {
+ int m();
+}
+int f(A a) => null == a /*LINT*/? null : a.m();
+''');
+ await assertHasFix('''
+abstract class A {
+ int m();
+}
+int f(A a) => a?.m();
+''');
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/create_getter_test.dart b/pkg/analysis_server/test/src/services/correction/fix/create_getter_test.dart
index 85941b0..e324763 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/create_getter_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/create_getter_test.dart
@@ -12,6 +12,7 @@
defineReflectiveSuite(() {
defineReflectiveTests(CreateGetterTest);
defineReflectiveTests(CreateGetterMixinTest);
+ defineReflectiveTests(CreateGetterWithExtensionMethodsTest);
});
}
@@ -361,3 +362,88 @@
''');
}
}
+
+@reflectiveTest
+class CreateGetterWithExtensionMethodsTest extends FixProcessorTest {
+ @override
+ FixKind get kind => DartFixKind.CREATE_GETTER;
+
+ void setUp() {
+ createAnalysisOptionsFile(experiments: ['extension-methods']);
+ super.setUp();
+ }
+
+ test_internal_instance() async {
+ await resolveTestUnit('''
+extension E on String {
+ int m() => g;
+}
+''');
+ await assertHasFix('''
+extension E on String {
+ get g => null;
+
+ int m() => g;
+}
+''');
+ }
+
+ test_internal_static() async {
+ await resolveTestUnit('''
+extension E on String {
+ static int m() => g;
+}
+''');
+ await assertHasFix('''
+extension E on String {
+ static get g => null;
+
+ static int m() => g;
+}
+''');
+ }
+
+ test_override() async {
+ await resolveTestUnit('''
+extension E on String {
+}
+
+main(String s) {
+ int v = E(s).test;
+ print(v);
+}
+''');
+ await assertHasFix('''
+extension E on String {
+ int get test => null;
+}
+
+main(String s) {
+ int v = E(s).test;
+ print(v);
+}
+''');
+ }
+
+ test_static() async {
+ await resolveTestUnit('''
+extension E on String {
+}
+
+main(String s) {
+ int v = E.test;
+ print(v);
+}
+''');
+ await assertHasFix('''
+extension E on String {
+ static int get test => null;
+}
+
+main(String s) {
+ int v = E.test;
+ print(v);
+}
+''');
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/create_method_test.dart b/pkg/analysis_server/test/src/services/correction/fix/create_method_test.dart
index bf502f1..3c76f45 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/create_method_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/create_method_test.dart
@@ -13,6 +13,7 @@
defineReflectiveSuite(() {
defineReflectiveTests(CreateMethodTest);
defineReflectiveTests(CreateMethodMixinTest);
+ defineReflectiveTests(CreateMethodWithExtensionMethodsTest);
});
}
@@ -703,3 +704,82 @@
await assertNoFix();
}
}
+
+@reflectiveTest
+class CreateMethodWithExtensionMethodsTest extends FixProcessorTest {
+ @override
+ FixKind get kind => DartFixKind.CREATE_METHOD;
+
+ void setUp() {
+ createAnalysisOptionsFile(experiments: ['extension-methods']);
+ super.setUp();
+ }
+
+ test_internal_instance() async {
+ await resolveTestUnit('''
+extension E on String {
+ int m() => n();
+}
+''');
+ await assertHasFix('''
+extension E on String {
+ int m() => n();
+
+ n() {}
+}
+''');
+ }
+
+ test_internal_static() async {
+ await resolveTestUnit('''
+extension E on String {
+ static int m() => n();
+}
+''');
+ await assertHasFix('''
+extension E on String {
+ static int m() => n();
+
+ static n() {}
+}
+''');
+ }
+
+ test_override() async {
+ await resolveTestUnit('''
+extension E on String {}
+
+void f() {
+ E('a').m();
+}
+''');
+ await assertHasFix('''
+extension E on String {
+ void m() {}
+}
+
+void f() {
+ E('a').m();
+}
+''');
+ }
+
+ test_static() async {
+ await resolveTestUnit('''
+extension E on String {}
+
+void f() {
+ E.m();
+}
+''');
+ await assertHasFix('''
+extension E on String {
+ static void m() {}
+}
+
+void f() {
+ E.m();
+}
+''');
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/create_setter_test.dart b/pkg/analysis_server/test/src/services/correction/fix/create_setter_test.dart
new file mode 100644
index 0000000..2edc875
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/create_setter_test.dart
@@ -0,0 +1,387 @@
+// Copyright (c) 2019, 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.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(CreateSetterTest);
+ defineReflectiveTests(CreateSetterMixinTest);
+ defineReflectiveTests(CreateSetterWithExtensionMethodsTest);
+ });
+}
+
+@reflectiveTest
+class CreateSetterMixinTest extends FixProcessorTest {
+ @override
+ FixKind get kind => DartFixKind.CREATE_SETTER;
+
+ test_qualified_instance() async {
+ await resolveTestUnit('''
+mixin M {
+}
+
+main(M m) {
+ m.test = 0;
+}
+''');
+ await assertHasFix('''
+mixin M {
+ set test(int test) {}
+}
+
+main(M m) {
+ m.test = 0;
+}
+''');
+ }
+
+ test_unqualified_instance_assignmentLhs() async {
+ await resolveTestUnit('''
+mixin M {
+ main() {
+ test = 0;
+ }
+}
+''');
+ await assertHasFix('''
+mixin M {
+ set test(int test) {}
+
+ main() {
+ test = 0;
+ }
+}
+''');
+ }
+
+ test_unqualified_instance_assignmentRhs() async {
+ await resolveTestUnit('''
+mixin M {
+ main() {
+ test;
+ }
+}
+''');
+ await assertNoFix();
+ }
+}
+
+@reflectiveTest
+class CreateSetterTest extends FixProcessorTest {
+ @override
+ FixKind get kind => DartFixKind.CREATE_SETTER;
+
+ test_getterContext() async {
+ await resolveTestUnit('''
+class A {
+}
+main(A a) {
+ a.test;
+}
+''');
+ await assertNoFix();
+ }
+
+ test_inferredTargetType() async {
+ await resolveTestUnit('''
+class A {
+}
+main(A a) {
+ var x = a;
+ x.test = 0;
+}
+''');
+ await assertHasFix('''
+class A {
+ set test(int test) {}
+}
+main(A a) {
+ var x = a;
+ x.test = 0;
+}
+''');
+ }
+
+ test_inSDK() async {
+ await resolveTestUnit('''
+main(List p) {
+ p.foo = 0;
+}
+''');
+ await assertNoFix();
+ }
+
+ test_location_afterLastAccessor() async {
+ await resolveTestUnit('''
+class A {
+ int existingField;
+
+ int get existingGetter => null;
+
+ existingMethod() {}
+}
+main(A a) {
+ a.test = 0;
+}
+''');
+ await assertHasFix('''
+class A {
+ int existingField;
+
+ int get existingGetter => null;
+
+ set test(int test) {}
+
+ existingMethod() {}
+}
+main(A a) {
+ a.test = 0;
+}
+''');
+ }
+
+ test_multiLevel() async {
+ await resolveTestUnit('''
+class A {
+}
+class B {
+ A a;
+}
+class C {
+ B b;
+}
+main(C c) {
+ c.b.a.test = 0;
+}
+''');
+ await assertHasFix('''
+class A {
+ set test(int test) {}
+}
+class B {
+ A a;
+}
+class C {
+ B b;
+}
+main(C c) {
+ c.b.a.test = 0;
+}
+''');
+ }
+
+ test_qualified_instance() async {
+ await resolveTestUnit('''
+class A {
+}
+main(A a) {
+ a.test = 0;
+}
+''');
+ await assertHasFix('''
+class A {
+ set test(int test) {}
+}
+main(A a) {
+ a.test = 0;
+}
+''');
+ }
+
+ test_qualified_instance_differentLibrary() async {
+ addSource('/home/test/lib/other.dart', '''
+/**
+ * A comment to push the offset of the braces for the following class
+ * declaration past the end of the content of the test file. Used to catch an
+ * index out of bounds exception that occurs when using the test source instead
+ * of the target source to compute the location at which to insert the field.
+ */
+class A {
+}
+''');
+
+ await resolveTestUnit('''
+import 'package:test/other.dart';
+
+main(A a) {
+ a.test = 0;
+}
+''');
+
+ await assertHasFix('''
+/**
+ * A comment to push the offset of the braces for the following class
+ * declaration past the end of the content of the test file. Used to catch an
+ * index out of bounds exception that occurs when using the test source instead
+ * of the target source to compute the location at which to insert the field.
+ */
+class A {
+ set test(int test) {}
+}
+''', target: '/home/test/lib/other.dart');
+ }
+
+ test_qualified_instance_dynamicType() async {
+ await resolveTestUnit('''
+class A {
+ B b;
+ void f(p) {
+ b.test = p;
+ }
+}
+class B {
+}
+''');
+ await assertHasFix('''
+class A {
+ B b;
+ void f(p) {
+ b.test = p;
+ }
+}
+class B {
+ set test(test) {}
+}
+''');
+ }
+
+ test_qualified_propagatedType() async {
+ await resolveTestUnit('''
+class A {
+ A get self => this;
+}
+main() {
+ var a = new A();
+ a.self.test = 0;
+}
+''');
+ await assertHasFix('''
+class A {
+ A get self => this;
+
+ set test(int test) {}
+}
+main() {
+ var a = new A();
+ a.self.test = 0;
+}
+''');
+ }
+
+ test_unqualified_instance_assignmentLhs() async {
+ await resolveTestUnit('''
+class A {
+ main() {
+ test = 0;
+ }
+}
+''');
+ await assertHasFix('''
+class A {
+ set test(int test) {}
+
+ main() {
+ test = 0;
+ }
+}
+''');
+ }
+
+ test_unqualified_instance_assignmentRhs() async {
+ await resolveTestUnit('''
+class A {
+ main() {
+ test;
+ }
+}
+''');
+ await assertNoFix();
+ }
+}
+
+@reflectiveTest
+class CreateSetterWithExtensionMethodsTest extends FixProcessorTest {
+ @override
+ FixKind get kind => DartFixKind.CREATE_SETTER;
+
+ void setUp() {
+ createAnalysisOptionsFile(experiments: ['extension-methods']);
+ super.setUp();
+ }
+
+ test_internal_instance() async {
+ await resolveTestUnit('''
+extension E on String {
+ int m(int x) => s = x;
+}
+''');
+ await assertHasFix('''
+extension E on String {
+ set s(int s) {}
+
+ int m(int x) => s = x;
+}
+''');
+ }
+
+ test_internal_static() async {
+ await resolveTestUnit('''
+extension E on String {
+ static int m(int x) => s = x;
+}
+''');
+ await assertHasFix('''
+extension E on String {
+ static set s(int s) {}
+
+ static int m(int x) => s = x;
+}
+''');
+ }
+
+ test_override() async {
+ await resolveTestUnit('''
+extension E on String {
+}
+
+main(String s) {
+ E(s).test = '0';
+}
+''');
+ await assertHasFix('''
+extension E on String {
+ set test(String test) {}
+}
+
+main(String s) {
+ E(s).test = '0';
+}
+''');
+ }
+
+ test_static() async {
+ await resolveTestUnit('''
+extension E on String {
+}
+
+main(String s) {
+ E.test = 0;
+}
+''');
+ await assertHasFix('''
+extension E on String {
+ static set test(int test) {}
+}
+
+main(String s) {
+ E.test = 0;
+}
+''');
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/import_library_prefix_test.dart b/pkg/analysis_server/test/src/services/correction/fix/import_library_prefix_test.dart
index af0bbbe..3e3a04a 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/import_library_prefix_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/import_library_prefix_test.dart
@@ -11,6 +11,7 @@
main() {
defineReflectiveSuite(() {
defineReflectiveTests(ImportLibraryPrefixTest);
+ defineReflectiveTests(ImportLibraryPrefixWithExtensionMethodsTest);
});
}
@@ -55,3 +56,35 @@
''');
}
}
+
+@reflectiveTest
+class ImportLibraryPrefixWithExtensionMethodsTest extends FixProcessorTest {
+ @override
+ FixKind get kind => DartFixKind.IMPORT_LIBRARY_PREFIX;
+
+ void setUp() {
+ createAnalysisOptionsFile(experiments: ['extension-methods']);
+ super.setUp();
+ }
+
+ test_withExtension() async {
+ addSource('/home/test/lib/lib.dart', '''
+class C {}
+extension E on int {
+ static String m() => '';
+}
+''');
+ await resolveTestUnit('''
+import 'lib.dart' as p;
+void f(p.C c) {
+ print(E.m());
+}
+''');
+ await assertHasFix('''
+import 'lib.dart' as p;
+void f(p.C c) {
+ print(p.E.m());
+}
+''');
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/import_library_project_test.dart b/pkg/analysis_server/test/src/services/correction/fix/import_library_project_test.dart
index 8119ac1..be7b39a 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/import_library_project_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/import_library_project_test.dart
@@ -12,12 +12,52 @@
main() {
defineReflectiveSuite(() {
defineReflectiveTests(ImportLibraryProject1Test);
+ defineReflectiveTests(ImportLibraryProject1WithExtensionMethodsTest);
defineReflectiveTests(ImportLibraryProject2Test);
+ defineReflectiveTests(ImportLibraryProject2WithExtensionMethodsTest);
defineReflectiveTests(ImportLibraryProject3Test);
+ defineReflectiveTests(ImportLibraryProject3WithExtensionMethodsTest);
});
}
@reflectiveTest
+class ImportLibraryProject1WithExtensionMethodsTest extends FixProcessorTest {
+ @override
+ FixKind get kind => DartFixKind.IMPORT_LIBRARY_PROJECT1;
+
+ void setUp() {
+ createAnalysisOptionsFile(experiments: ['extension-methods']);
+ super.setUp();
+ }
+
+ test_lib() async {
+ addPackageFile('my_pkg', 'a.dart', '''
+extension E on int {
+ static String m() => '';
+}
+''');
+ newFile('/home/test/pubspec.yaml', content: r'''
+dependencies:
+ my_pkg: any
+''');
+
+ await resolveTestUnit('''
+f() {
+ print(E.m());
+}
+''');
+
+ await assertHasFix('''
+import 'package:my_pkg/a.dart';
+
+f() {
+ print(E.m());
+}
+''', expectedNumberOfFixesForKind: 1);
+ }
+}
+
+@reflectiveTest
class ImportLibraryProject1Test extends FixProcessorTest {
@override
FixKind get kind => DartFixKind.IMPORT_LIBRARY_PROJECT1;
@@ -386,11 +426,8 @@
''');
}
- test_withFunction_identifier() async {
- addSource('/home/test/lib/lib.dart', '''
-library lib;
-myFunction() {}
-''');
+ test_withFunction_functionTopLevelVariableIdentifier() async {
+ addSource('/home/test/lib/lib.dart', 'var myFunction = () {};');
await resolveTestUnit('''
main() {
myFunction;
@@ -405,8 +442,11 @@
''');
}
- test_withFunction_functionTopLevelVariableIdentifier() async {
- addSource('/home/test/lib/lib.dart', 'var myFunction = () {};');
+ test_withFunction_identifier() async {
+ addSource('/home/test/lib/lib.dart', '''
+library lib;
+myFunction() {}
+''');
await resolveTestUnit('''
main() {
myFunction;
@@ -488,7 +528,7 @@
class X = Object with Test;
''', errorFilter: (error) {
- return error.errorCode == StaticWarningCode.UNDEFINED_CLASS;
+ return error.errorCode == CompileTimeErrorCode.UNDEFINED_CLASS;
});
}
@@ -513,6 +553,42 @@
}
@reflectiveTest
+class ImportLibraryProject2WithExtensionMethodsTest extends FixProcessorTest {
+ @override
+ FixKind get kind => DartFixKind.IMPORT_LIBRARY_PROJECT2;
+
+ void setUp() {
+ createAnalysisOptionsFile(experiments: ['extension-methods']);
+ super.setUp();
+ }
+
+ test_lib_src() async {
+ addPackageFile('my_pkg', 'a.dart', "export 'src/b.dart';");
+ addPackageFile('my_pkg', 'src/b.dart', '''
+extension E on int {
+ static String m() => '';
+}
+''');
+ newFile('/home/test/pubspec.yaml', content: r'''
+dependencies:
+ my_pkg: any
+''');
+ await resolveTestUnit('''
+f() {
+ print(E.m());
+}
+''');
+ await assertHasFix('''
+import 'package:my_pkg/a.dart';
+
+f() {
+ print(E.m());
+}
+''');
+ }
+}
+
+@reflectiveTest
class ImportLibraryProject2Test extends FixProcessorTest {
@override
FixKind get kind => DartFixKind.IMPORT_LIBRARY_PROJECT2;
@@ -565,6 +641,37 @@
}
@reflectiveTest
+class ImportLibraryProject3WithExtensionMethodsTest extends FixProcessorTest {
+ @override
+ FixKind get kind => DartFixKind.IMPORT_LIBRARY_PROJECT3;
+
+ void setUp() {
+ createAnalysisOptionsFile(experiments: ['extension-methods']);
+ super.setUp();
+ }
+
+ test_inLibSrc_thisContextRoot() async {
+ addSource('/home/test/lib/src/lib.dart', '''
+extension E on int {
+ static String m() => '';
+}
+''');
+ await resolveTestUnit('''
+f() {
+ print(E.m());
+}
+''');
+ await assertHasFix('''
+import 'package:test/src/lib.dart';
+
+f() {
+ print(E.m());
+}
+''');
+ }
+}
+
+@reflectiveTest
class ImportLibraryProject3Test extends FixProcessorTest {
@override
FixKind get kind => DartFixKind.IMPORT_LIBRARY_PROJECT3;
diff --git a/pkg/analysis_server/test/src/services/correction/fix/import_library_show_test.dart b/pkg/analysis_server/test/src/services/correction/fix/import_library_show_test.dart
index 4f3885f..acf4b72 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/import_library_show_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/import_library_show_test.dart
@@ -11,6 +11,7 @@
main() {
defineReflectiveSuite(() {
defineReflectiveTests(ImportLibraryShowTest);
+ defineReflectiveTests(ImportLibraryShowWithExtensionMethodsTest);
});
}
@@ -24,39 +25,92 @@
class A {}
class B {}
''');
- await resolveTestUnit('''
+ await resolveTestUnit(r'''
import 'lib.dart' show A;
main() {
A a;
B b;
- print('\$a \$b');
+ print('$a $b');
}
''');
- await assertHasFix('''
+ await assertHasFix(r'''
import 'lib.dart' show A, B;
main() {
A a;
B b;
- print('\$a \$b');
+ print('$a $b');
}
''');
}
test_sdk() async {
- await resolveTestUnit('''
+ await resolveTestUnit(r'''
import 'dart:collection' show HashMap;
main() {
HashMap s = null;
LinkedHashMap f = null;
- print('\$s \$f');
+ print('$s $f');
}
''');
- await assertHasFix('''
+ await assertHasFix(r'''
import 'dart:collection' show HashMap, LinkedHashMap;
main() {
HashMap s = null;
LinkedHashMap f = null;
- print('\$s \$f');
+ print('$s $f');
+}
+''');
+ }
+}
+
+@reflectiveTest
+class ImportLibraryShowWithExtensionMethodsTest extends FixProcessorTest {
+ @override
+ FixKind get kind => DartFixKind.IMPORT_LIBRARY_SHOW;
+
+ void setUp() {
+ createAnalysisOptionsFile(experiments: ['extension-methods']);
+ super.setUp();
+ }
+
+ test_override_samePackage() async {
+ addSource('/home/test/lib/lib.dart', '''
+class A {}
+extension E on int {
+ String m() => '';
+}
+''');
+ await resolveTestUnit(r'''
+import 'lib.dart' show A;
+void f(A a) {
+ print('$a ${E(3).m()}');
+}
+''');
+ await assertHasFix(r'''
+import 'lib.dart' show A, E;
+void f(A a) {
+ print('$a ${E(3).m()}');
+}
+''');
+ }
+
+ test_static_samePackage() async {
+ addSource('/home/test/lib/lib.dart', '''
+class A {}
+extension E on int {
+ static String m() => '';
+}
+''');
+ await resolveTestUnit(r'''
+import 'lib.dart' show A;
+void f(A a) {
+ print('$a ${E.m()}');
+}
+''');
+ await assertHasFix(r'''
+import 'lib.dart' show A, E;
+void f(A a) {
+ print('$a ${E.m()}');
}
''');
}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/make_final_test.dart b/pkg/analysis_server/test/src/services/correction/fix/make_final_test.dart
index 31bc18d..1336479 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/make_final_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/make_final_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/make_variable_not_final_test.dart b/pkg/analysis_server/test/src/services/correction/fix/make_variable_not_final_test.dart
new file mode 100644
index 0000000..3c210a0
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/make_variable_not_final_test.dart
@@ -0,0 +1,55 @@
+// Copyright (c) 2019, 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.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(MakeVariableNotFinalTest);
+ });
+}
+
+@reflectiveTest
+class MakeVariableNotFinalTest extends FixProcessorTest {
+ @override
+ FixKind get kind => DartFixKind.MAKE_VARIABLE_NOT_FINAL;
+
+ test_hasType() async {
+ await resolveTestUnit('''
+main() {
+ final int fff = 1;
+ fff = 2;
+ print(fff);
+}
+''');
+ await assertHasFix('''
+main() {
+ int fff = 1;
+ fff = 2;
+ print(fff);
+}
+''');
+ }
+
+ test_noType() async {
+ await resolveTestUnit('''
+main() {
+ final fff = 1;
+ fff = 2;
+ print(fff);
+}
+''');
+ await assertHasFix('''
+main() {
+ var fff = 1;
+ fff = 2;
+ print(fff);
+}
+''');
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_await_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_await_test.dart
index 6121171..d275386 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_await_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_await_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_duplicate_case_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_duplicate_case_test.dart
index 0f1f928..3cd7576 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_duplicate_case_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_duplicate_case_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_empty_catch_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_empty_catch_test.dart
index b5784b8..317e9a1 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_empty_catch_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_empty_catch_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_empty_constructor_body_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_empty_constructor_body_test.dart
index 3030ea2..93f33be 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_empty_constructor_body_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_empty_constructor_body_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_empty_else_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_empty_else_test.dart
index 1019af5..f65b70e 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_empty_else_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_empty_else_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_empty_statement_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_empty_statement_test.dart
index 18a278c..74e9b9f 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_empty_statement_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_empty_statement_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_initializer_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_initializer_test.dart
index b686d62..5266d462 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_initializer_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_initializer_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_interpolation_braces_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_interpolation_braces_test.dart
index b48e7d8..4dfe93a 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_interpolation_braces_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_interpolation_braces_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_method_declaration_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_method_declaration_test.dart
index 666a59c..730249c 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_method_declaration_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_method_declaration_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_this_expression_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_this_expression_test.dart
index 5ea13d4..d9c73d5 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_this_expression_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_this_expression_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_type_annotation_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_type_annotation_test.dart
index 54deb8b..5517927 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_type_annotation_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_type_annotation_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_const_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_const_test.dart
index 440b948..a42b897 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_const_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_const_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_new_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_new_test.dart
index b1cad87..a29dacf 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_new_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_new_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/rename_to_camel_case_test.dart b/pkg/analysis_server/test/src/services/correction/fix/rename_to_camel_case_test.dart
index 45f6677..8afc1c4 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/rename_to_camel_case_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/rename_to_camel_case_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_colon_with_equals_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_colon_with_equals_test.dart
index 85e0bb6..2bf65bf 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_colon_with_equals_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_colon_with_equals_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_final_with_const_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_final_with_const_test.dart
index 77fa5a7..9c05196 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_final_with_const_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_final_with_const_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_new_with_const_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_new_with_const_test.dart
new file mode 100644
index 0000000..e59a3a0
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_new_with_const_test.dart
@@ -0,0 +1,57 @@
+// Copyright (c) 2019, 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.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(ReplaceNewWithConstTest);
+ });
+}
+
+@reflectiveTest
+class ReplaceNewWithConstTest extends FixProcessorLintTest {
+ @override
+ FixKind get kind => DartFixKind.REPLACE_NEW_WITH_CONST;
+
+ @override
+ String get lintCode => LintNames.prefer_const_constructors;
+
+ test_basic() async {
+ await resolveTestUnit('''
+class C {
+ const C();
+}
+main() {
+ var c = new C/*LINT*/();
+}
+''');
+ await assertHasFix('''
+class C {
+ const C();
+}
+main() {
+ var c = const C/*LINT*/();
+}
+''');
+ }
+
+ test_not_present() async {
+ await resolveTestUnit('''
+class C {
+ const C();
+}
+main() {
+ var c = C/*LINT*/();
+}
+''');
+ // handled by ADD_CONST
+ await assertNoFix();
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_null_with_closure_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_null_with_closure_test.dart
index 4ada2dd..1f733fe 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_null_with_closure_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_null_with_closure_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_with_brackets_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_with_brackets_test.dart
index 93cae94..bac5617 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_with_brackets_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_with_brackets_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_with_conditional_assignment_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_with_conditional_assignment_test.dart
index e5baaec..32be5b7 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_with_conditional_assignment_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_with_conditional_assignment_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_with_identifier_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_with_identifier_test.dart
index 6dfc38c..82152f7 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_with_identifier_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_with_identifier_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_with_is_empty_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_with_is_empty_test.dart
index ef13aa9..8548cc2 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_with_is_empty_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_with_is_empty_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_with_is_not_empty_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_with_is_not_empty_test.dart
index 9b621d9..91c556e 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_with_is_not_empty_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_with_is_not_empty_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_with_tear_off_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_with_tear_off_test.dart
index ccc757a..f246605 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_with_tear_off_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_with_tear_off_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
index de8cd2a..67efef9 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
@@ -6,6 +6,8 @@
import 'add_async_test.dart' as add_async;
import 'add_await_test.dart' as add_await;
+import 'add_const_test.dart' as add_const;
+import 'add_curly_braces_test.dart' as add_curly_braces;
import 'add_explicit_cast_test.dart' as add_explicit_cast;
import 'add_field_formal_parameters_test.dart' as add_field_formal_parameters;
import 'add_missing_enum_case_clauses_test.dart'
@@ -23,6 +25,7 @@
import 'add_static_test.dart' as add_static;
import 'add_super_constructor_invocation_test.dart'
as add_super_constructor_invocation;
+import 'add_type_annotation_test.dart' as add_type_annotation;
import 'analysis_options/test_all.dart' as analysis_options;
import 'change_argument_name_test.dart' as change_argument_name;
import 'change_to_nearest_precise_value_test.dart'
@@ -30,9 +33,16 @@
import 'change_to_static_access_test.dart' as change_to_static_access;
import 'change_to_test.dart' as change_to;
import 'change_type_annotation_test.dart' as change_type_annotation;
+import 'convert_documentation_into_line_test.dart'
+ as convert_documentation_into_line;
import 'convert_flutter_child_test.dart' as convert_flutter_child;
import 'convert_flutter_children_test.dart' as convert_flutter_children;
+import 'convert_into_expression_body_test.dart' as convert_into_expression_body;
+import 'convert_to_for_element_test.dart' as convert_to_for_element;
+import 'convert_to_if_element_test.dart' as convert_to_if_element;
+import 'convert_to_int_literal_test.dart' as convert_to_int_literal;
import 'convert_to_named_arguments_test.dart' as convert_to_named_arguments;
+import 'convert_to_null_aware_test.dart' as convert_to_null_aware;
import 'create_class_test.dart' as create_class;
import 'create_constructor_for_final_fields_test.dart'
as create_constructor_for_final_field;
@@ -47,6 +57,7 @@
import 'create_missing_overrides_test.dart' as create_missing_overrides;
import 'create_mixin_test.dart' as create_mixin;
import 'create_no_such_method_test.dart' as create_no_such_method;
+import 'create_setter_test.dart' as create_setter;
import 'extend_class_for_mixin_test.dart' as extend_class_for_mixin;
import 'fix_test.dart' as fix;
import 'import_async_test.dart' as import_async;
@@ -58,6 +69,7 @@
import 'make_class_abstract_test.dart' as make_class_abstract;
import 'make_field_not_final_test.dart' as make_field_not_final;
import 'make_final_test.dart' as make_final;
+import 'make_variable_not_final_test.dart' as make_variable_not_final;
import 'move_type_arguments_to_class_test.dart' as move_type_arguments_to_class;
import 'remove_annotation_test.dart' as remove_annotation;
import 'remove_await_test.dart' as remove_await;
@@ -89,6 +101,7 @@
import 'replace_boolean_with_bool_test.dart' as replace_boolean_with_bool;
import 'replace_colon_with_equals_test.dart' as replace_colon_with_equals;
import 'replace_final_with_const_test.dart' as replace_final_with_const;
+import 'replace_new_with_const_test.dart' as replace_new_with_const;
import 'replace_null_with_closure_test.dart' as replace_null_with_closure;
import 'replace_return_type_future_test.dart' as replace_return_type_future;
import 'replace_var_with_dynamic_test.dart' as replace_var_with_dynamic;
@@ -113,6 +126,8 @@
defineReflectiveSuite(() {
add_async.main();
add_await.main();
+ add_const.main();
+ add_curly_braces.main();
add_explicit_cast.main();
add_field_formal_parameters.main();
add_missing_enum_case_clauses.main();
@@ -125,15 +140,22 @@
add_required.main();
add_static.main();
add_super_constructor_invocation.main();
+ add_type_annotation.main();
analysis_options.main();
change_argument_name.main();
change_to.main();
change_to_nearest_precise_value.main();
change_to_static_access.main();
change_type_annotation.main();
+ convert_documentation_into_line.main();
convert_flutter_child.main();
convert_flutter_children.main();
+ convert_into_expression_body.main();
+ convert_to_for_element.main();
+ convert_to_if_element.main();
+ convert_to_int_literal.main();
convert_to_named_arguments.main();
+ convert_to_null_aware.main();
create_class.main();
create_constructor_for_final_field.main();
create_constructor_super.main();
@@ -147,6 +169,7 @@
create_missing_overrides.main();
create_mixin.main();
create_no_such_method.main();
+ create_setter.main();
extend_class_for_mixin.main();
fix.main();
import_async.main();
@@ -158,6 +181,7 @@
make_class_abstract.main();
make_field_not_final.main();
make_final.main();
+ make_variable_not_final.main();
move_type_arguments_to_class.main();
remove_annotation.main();
remove_await.main();
@@ -186,6 +210,7 @@
replace_boolean_with_bool.main();
replace_colon_with_equals.main();
replace_final_with_const.main();
+ replace_new_with_const.main();
replace_null_with_closure.main();
replace_return_type_future.main();
replace_var_with_dynamic.main();
diff --git a/pkg/analysis_server/test/src/services/correction/fix/use_is_not_empty_test.dart b/pkg/analysis_server/test/src/services/correction/fix/use_is_not_empty_test.dart
index ab2da21..1d3a8ca 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/use_is_not_empty_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/use_is_not_empty_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/use_rethrow_test.dart b/pkg/analysis_server/test/src/services/correction/fix/use_rethrow_test.dart
index 5a49867..6ad46df 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/use_rethrow_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/use_rethrow_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/src/utilities/flutter_test.dart b/pkg/analysis_server/test/src/utilities/flutter_test.dart
index cad467a..76ce8fe 100644
--- a/pkg/analysis_server/test/src/utilities/flutter_test.dart
+++ b/pkg/analysis_server/test/src/utilities/flutter_test.dart
@@ -331,6 +331,44 @@
expect(flutter.identifyWidgetExpression(expression), expression);
}
+ test_identifyWidgetExpression_parent_forElement() async {
+ await resolveTestUnit('''
+import 'package:flutter/widgets.dart';
+
+main(bool b) {
+ [
+ for (var v in [0, 1, 2]) Container()
+ ];
+}
+
+void useWidget(Widget w) {}
+''');
+ var expression = findNode.instanceCreation('Container()');
+ expect(flutter.identifyWidgetExpression(expression), expression);
+ }
+
+ test_identifyWidgetExpression_parent_ifElement() async {
+ await resolveTestUnit('''
+import 'package:flutter/widgets.dart';
+
+main(bool b) {
+ [
+ if (b)
+ Text('then')
+ else
+ Text('else')
+ ];
+}
+
+void useWidget(Widget w) {}
+''');
+ var thenExpression = findNode.instanceCreation("Text('then')");
+ expect(flutter.identifyWidgetExpression(thenExpression), thenExpression);
+
+ var elseExpression = findNode.instanceCreation("Text('else')");
+ expect(flutter.identifyWidgetExpression(elseExpression), elseExpression);
+ }
+
test_identifyWidgetExpression_parent_listLiteral() async {
await resolveTestUnit('''
import 'package:flutter/widgets.dart';
diff --git a/pkg/analysis_server/test/src/utilities/mock_packages.dart b/pkg/analysis_server/test/src/utilities/mock_packages.dart
index 929127f..81647c3 100644
--- a/pkg/analysis_server/test/src/utilities/mock_packages.dart
+++ b/pkg/analysis_server/test/src/utilities/mock_packages.dart
@@ -5,7 +5,8 @@
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 'package:front_end/src/testing/package_root.dart' as package_root;
+
+import '../../utils/package_root.dart' as package_root;
/// Helper for copying files from "tests/mock_packages" to memory file system.
class MockPackages {
diff --git a/pkg/front_end/lib/src/testing/package_root.dart b/pkg/analysis_server/test/utils/package_root.dart
similarity index 100%
copy from pkg/front_end/lib/src/testing/package_root.dart
copy to pkg/analysis_server/test/utils/package_root.dart
diff --git a/pkg/analysis_server/test/verify_tests_test.dart b/pkg/analysis_server/test/verify_tests_test.dart
index e11636e..69bd9ac 100644
--- a/pkg/analysis_server/test/verify_tests_test.dart
+++ b/pkg/analysis_server/test/verify_tests_test.dart
@@ -9,10 +9,11 @@
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:front_end/src/testing/package_root.dart' as package_root;
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);
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/ServerLogEntry.java b/pkg/analysis_server/tool/spec/generated/java/types/ServerLogEntry.java
new file mode 100644
index 0000000..c590fe5
--- /dev/null
+++ b/pkg/analysis_server/tool/spec/generated/java/types/ServerLogEntry.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2019, 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.
+ *
+ * This file has been automatically generated. Please do not edit it manually.
+ * To regenerate the file, use the script "pkg/analysis_server/tool/spec/generate_files".
+ */
+package org.dartlang.analysis.server.protocol;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import com.google.common.collect.Lists;
+import com.google.dart.server.utilities.general.JsonUtilities;
+import com.google.dart.server.utilities.general.ObjectUtilities;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonPrimitive;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import java.util.ArrayList;
+import java.util.Iterator;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * A log entry from the server.
+ *
+ * @coverage dart.server.generated.types
+ */
+@SuppressWarnings("unused")
+public class ServerLogEntry {
+
+ public static final ServerLogEntry[] EMPTY_ARRAY = new ServerLogEntry[0];
+
+ public static final List<ServerLogEntry> EMPTY_LIST = Lists.newArrayList();
+
+ /**
+ * The time (milliseconds since epoch) at which the server created this log entry.
+ */
+ private final int time;
+
+ /**
+ * The kind of the entry, used to determine how to interpret the "data" field.
+ */
+ private final String kind;
+
+ /**
+ * The payload of the entry, the actual format is determined by the "kind" field.
+ */
+ private final String data;
+
+ /**
+ * Constructor for {@link ServerLogEntry}.
+ */
+ public ServerLogEntry(int time, String kind, String data) {
+ this.time = time;
+ this.kind = kind;
+ this.data = data;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof ServerLogEntry) {
+ ServerLogEntry other = (ServerLogEntry) obj;
+ return
+ other.time == time &&
+ ObjectUtilities.equals(other.kind, kind) &&
+ ObjectUtilities.equals(other.data, data);
+ }
+ return false;
+ }
+
+ public static ServerLogEntry fromJson(JsonObject jsonObject) {
+ int time = jsonObject.get("time").getAsInt();
+ String kind = jsonObject.get("kind").getAsString();
+ String data = jsonObject.get("data").getAsString();
+ return new ServerLogEntry(time, kind, data);
+ }
+
+ public static List<ServerLogEntry> fromJsonArray(JsonArray jsonArray) {
+ if (jsonArray == null) {
+ return EMPTY_LIST;
+ }
+ ArrayList<ServerLogEntry> list = new ArrayList<ServerLogEntry>(jsonArray.size());
+ Iterator<JsonElement> iterator = jsonArray.iterator();
+ while (iterator.hasNext()) {
+ list.add(fromJson(iterator.next().getAsJsonObject()));
+ }
+ return list;
+ }
+
+ /**
+ * The payload of the entry, the actual format is determined by the "kind" field.
+ */
+ public String getData() {
+ return data;
+ }
+
+ /**
+ * The kind of the entry, used to determine how to interpret the "data" field.
+ */
+ public String getKind() {
+ return kind;
+ }
+
+ /**
+ * The time (milliseconds since epoch) at which the server created this log entry.
+ */
+ public int getTime() {
+ return time;
+ }
+
+ @Override
+ public int hashCode() {
+ HashCodeBuilder builder = new HashCodeBuilder();
+ builder.append(time);
+ builder.append(kind);
+ builder.append(data);
+ return builder.toHashCode();
+ }
+
+ public JsonObject toJson() {
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("time", time);
+ jsonObject.addProperty("kind", kind);
+ jsonObject.addProperty("data", data);
+ return jsonObject;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("[");
+ builder.append("time=");
+ builder.append(time + ", ");
+ builder.append("kind=");
+ builder.append(kind + ", ");
+ builder.append("data=");
+ builder.append(data);
+ builder.append("]");
+ return builder.toString();
+ }
+
+}
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/ServerLogEntryKind.java b/pkg/analysis_server/tool/spec/generated/java/types/ServerLogEntryKind.java
new file mode 100644
index 0000000..9964b6f
--- /dev/null
+++ b/pkg/analysis_server/tool/spec/generated/java/types/ServerLogEntryKind.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2019, 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.
+ *
+ * This file has been automatically generated. Please do not edit it manually.
+ * To regenerate the file, use the script "pkg/analysis_server/tool/spec/generate_files".
+ */
+package org.dartlang.analysis.server.protocol;
+
+/**
+ * An enumeration of the kinds of server long entries.
+ *
+ * @coverage dart.server.generated.types
+ */
+public class ServerLogEntryKind {
+
+ /**
+ * A notification from the server, such as "analysis.highlights". The "data" field contains a JSON
+ * object with abbreviated notification.
+ */
+ public static final String NOTIFICATION = "NOTIFICATION";
+
+ /**
+ * Arbitrary string, describing some event that happened in the server, e.g. starting a file
+ * analysis, and details which files were accessed. These entries are not structured, but provide
+ * context information about requests and notification, and can be related by "time" for further
+ * manual analysis.
+ */
+ public static final String RAW = "RAW";
+
+ /**
+ * A request from the client, as the server views it, e.g. "edit.getAssists". The "data" field
+ * contains a JSON object with abbreviated request.
+ */
+ public static final String REQUEST = "REQUEST";
+
+ /**
+ * Various counters and measurements related to execution of a request. The "data" field contains a
+ * JSON object with following fields:
+ *
+ * - "id" - the id of the request - copied from the request.
+ * - "method" - the method of the request, e.g. "edit.getAssists".
+ * - "clientRequestTime" - the time (milliseconds since epoch) at which the client made the request
+ * - copied from the request.
+ * - "serverRequestTime" - the time (milliseconds since epoch) at which the server received and
+ * decoded the JSON request.
+ * - "responseTime" - the time (milliseconds since epoch) at which the server created the response
+ * to be encoded into JSON and sent to the client.
+ */
+ public static final String RESPONSE = "RESPONSE";
+
+}
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/ServerService.java b/pkg/analysis_server/tool/spec/generated/java/types/ServerService.java
index fed7a98..99f51b9 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/ServerService.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/ServerService.java
@@ -15,6 +15,8 @@
*/
public class ServerService {
+ public static final String LOG = "LOG";
+
public static final String STATUS = "STATUS";
}
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/TokenDetails.java b/pkg/analysis_server/tool/spec/generated/java/types/TokenDetails.java
index b9cc17e..71b5f70 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/TokenDetails.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/TokenDetails.java
@@ -54,12 +54,18 @@
private final List<String> validElementKinds;
/**
+ * The offset of the first character of the token in the file which it originated from.
+ */
+ private final int offset;
+
+ /**
* Constructor for {@link TokenDetails}.
*/
- public TokenDetails(String lexeme, String type, List<String> validElementKinds) {
+ public TokenDetails(String lexeme, String type, List<String> validElementKinds, int offset) {
this.lexeme = lexeme;
this.type = type;
this.validElementKinds = validElementKinds;
+ this.offset = offset;
}
@Override
@@ -69,7 +75,8 @@
return
ObjectUtilities.equals(other.lexeme, lexeme) &&
ObjectUtilities.equals(other.type, type) &&
- ObjectUtilities.equals(other.validElementKinds, validElementKinds);
+ ObjectUtilities.equals(other.validElementKinds, validElementKinds) &&
+ other.offset == offset;
}
return false;
}
@@ -78,7 +85,8 @@
String lexeme = jsonObject.get("lexeme").getAsString();
String type = jsonObject.get("type") == null ? null : jsonObject.get("type").getAsString();
List<String> validElementKinds = jsonObject.get("validElementKinds") == null ? null : JsonUtilities.decodeStringList(jsonObject.get("validElementKinds").getAsJsonArray());
- return new TokenDetails(lexeme, type, validElementKinds);
+ int offset = jsonObject.get("offset").getAsInt();
+ return new TokenDetails(lexeme, type, validElementKinds, offset);
}
public static List<TokenDetails> fromJsonArray(JsonArray jsonArray) {
@@ -101,6 +109,13 @@
}
/**
+ * The offset of the first character of the token in the file which it originated from.
+ */
+ public int getOffset() {
+ return offset;
+ }
+
+ /**
* A unique id for the type of the identifier. Omitted if the token is not an identifier in a
* reference position.
*/
@@ -123,6 +138,7 @@
builder.append(lexeme);
builder.append(type);
builder.append(validElementKinds);
+ builder.append(offset);
return builder.toHashCode();
}
@@ -139,6 +155,7 @@
}
jsonObject.add("validElementKinds", jsonArrayValidElementKinds);
}
+ jsonObject.addProperty("offset", offset);
return jsonObject;
}
@@ -151,7 +168,9 @@
builder.append("type=");
builder.append(type + ", ");
builder.append("validElementKinds=");
- builder.append(StringUtils.join(validElementKinds, ", "));
+ builder.append(StringUtils.join(validElementKinds, ", ") + ", ");
+ builder.append("offset=");
+ builder.append(offset);
builder.append("]");
return builder.toString();
}
diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html
index 3a635e1..712bdc4 100644
--- a/pkg/analysis_server/tool/spec/spec_input.html
+++ b/pkg/analysis_server/tool/spec/spec_input.html
@@ -7,7 +7,7 @@
<body>
<h1>Analysis Server API Specification</h1>
<h1 style="color:#999999">Version
- <version>1.27.2</version>
+ <version>1.27.3</version>
</h1>
<p>
This document contains a specification of the API provided by the
@@ -311,6 +311,16 @@
</field>
</params>
</notification>
+ <notification event="log" experimental="true">
+ <p>
+ The stream of entries describing events happened in the server.
+ </p>
+ <params>
+ <field name="entry">
+ <ref>ServerLogEntry</ref>
+ </field>
+ </params>
+ </notification>
<notification event="status">
<p>
Reports the current status of the server. Parameters are
@@ -4096,6 +4106,13 @@
Omitted if the token is not an identifier.
</p>
</field>
+ <field name="offset">
+ <ref>int</ref>
+ <p>
+ The offset of the first character of the token in the file which it
+ originated from.
+ </p>
+ </field>
</object>
</type>
<type name="ExecutionService">
@@ -5234,6 +5251,7 @@
An enumeration of the services provided by the server domain.
</p>
<enum>
+ <value><code>LOG</code></value>
<value><code>STATUS</code></value>
</enum>
</type>
@@ -5308,6 +5326,94 @@
</field>
</object>
</type>
+ <type name="ServerLogEntry" experimental="true">
+ <p>
+ A log entry from the server.
+ </p>
+ <object>
+ <field name="time">
+ <ref>int</ref>
+ <p>
+ The time (milliseconds since epoch) at which the server created
+ this log entry.
+ </p>
+ </field>
+ <field name="kind" >
+ <ref>ServerLogEntryKind</ref>
+ <p>
+ The kind of the entry, used to determine how to interpret the "data"
+ field.
+ </p>
+ </field>
+ <field name="data">
+ <ref>String</ref>
+ <p>
+ The payload of the entry, the actual format is determined by the
+ "kind" field.
+ </p>
+ </field>
+ </object>
+ </type>
+ <type name="ServerLogEntryKind" experimental="true">
+ <p>
+ An enumeration of the kinds of server long entries.
+ </p>
+ <enum>
+ <value>
+ <code>NOTIFICATION</code>
+ <p>
+ A notification from the server, such as "analysis.highlights".
+ The "data" field contains a JSON object with abbreviated notification.
+ </p>
+ </value>
+ <value>
+ <code>RAW</code>
+ <p>
+ Arbitrary string, describing some event that happened in the server,
+ e.g. starting a file analysis, and details which files were accessed.
+ These entries are not structured, but provide context information
+ about requests and notification, and can be related by "time" for
+ further manual analysis.
+ </p>
+ </value>
+ <value>
+ <code>REQUEST</code>
+ <p>
+ A request from the client, as the server views it, e.g.
+ "edit.getAssists". The "data" field contains a JSON object with
+ abbreviated request.
+ </p>
+ </value>
+ <value>
+ <code>RESPONSE</code>
+ <p>
+ Various counters and measurements related to execution of a request.
+ The "data" field contains a JSON object with following fields:
+ </p>
+ <ul>
+ <li>
+ "id" - the id of the request - copied from the request.
+ </li>
+ <li>
+ "method" - the method of the request, e.g. "edit.getAssists".
+ </li>
+ <li>
+ "clientRequestTime" - the time (milliseconds since epoch) at which
+ the client made the request - copied from the request.
+ </li>
+ <li>
+ "serverRequestTime" - the time (milliseconds since epoch) at which
+ the server received and decoded the JSON request.
+ </li>
+ <li>
+ "responseTime" - the time (milliseconds since epoch) at which the
+ server created the response to be encoded into JSON and sent to the
+ client.
+ </li>
+ </ul>
+ </value>
+ </enum>
+ </type>
</types>
<refactorings>
<h2><a name="refactorings">Refactorings</a></h2>
diff --git a/pkg/analysis_server_client/lib/handler/notification_handler.dart b/pkg/analysis_server_client/lib/handler/notification_handler.dart
index b85aa31..cd9b88f 100644
--- a/pkg/analysis_server_client/lib/handler/notification_handler.dart
+++ b/pkg/analysis_server_client/lib/handler/notification_handler.dart
@@ -101,6 +101,9 @@
onServerError(
new ServerErrorParams.fromJson(decoder, 'params', params));
break;
+ case SERVER_NOTIFICATION_LOG:
+ onServerLog(new ServerLogParams.fromJson(decoder, 'params', params));
+ break;
case SERVER_NOTIFICATION_STATUS:
onServerStatus(
new ServerStatusParams.fromJson(decoder, 'params', params));
@@ -279,6 +282,9 @@
/// notification.
void onServerError(ServerErrorParams params) {}
+ /// The stream of entries describing events happened in the server.
+ void onServerLog(ServerLogParams params) {}
+
/// Reports the current status of the server. Parameters are
/// omitted if there has been no change in the status
/// represented by that parameter.
diff --git a/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart b/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart
index f51b81c..686011c 100644
--- a/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart
+++ b/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart
@@ -6,7 +6,7 @@
// To regenerate the file, use the script
// "pkg/analysis_server/tool/spec/generate_files".
-const String PROTOCOL_VERSION = '1.27.2';
+const String PROTOCOL_VERSION = '1.27.3';
const String ANALYSIS_NOTIFICATION_ANALYZED_FILES = 'analysis.analyzedFiles';
const String ANALYSIS_NOTIFICATION_ANALYZED_FILES_DIRECTORIES = 'directories';
@@ -341,6 +341,8 @@
const String SERVER_NOTIFICATION_ERROR_IS_FATAL = 'isFatal';
const String SERVER_NOTIFICATION_ERROR_MESSAGE = 'message';
const String SERVER_NOTIFICATION_ERROR_STACK_TRACE = 'stackTrace';
+const String SERVER_NOTIFICATION_LOG = 'server.log';
+const String SERVER_NOTIFICATION_LOG_ENTRY = 'entry';
const String SERVER_NOTIFICATION_STATUS = 'server.status';
const String SERVER_NOTIFICATION_STATUS_ANALYSIS = 'analysis';
const String SERVER_NOTIFICATION_STATUS_PUB = 'pub';
diff --git a/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart b/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart
index 80ae759..d0c24a3 100644
--- a/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart
+++ b/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart
@@ -22728,21 +22728,330 @@
}
/**
+ * ServerLogEntry
+ *
+ * {
+ * "time": int
+ * "kind": ServerLogEntryKind
+ * "data": String
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class ServerLogEntry implements HasToJson {
+ int _time;
+
+ ServerLogEntryKind _kind;
+
+ String _data;
+
+ /**
+ * The time (milliseconds since epoch) at which the server created this log
+ * entry.
+ */
+ int get time => _time;
+
+ /**
+ * The time (milliseconds since epoch) at which the server created this log
+ * entry.
+ */
+ void set time(int value) {
+ assert(value != null);
+ this._time = value;
+ }
+
+ /**
+ * The kind of the entry, used to determine how to interpret the "data"
+ * field.
+ */
+ ServerLogEntryKind get kind => _kind;
+
+ /**
+ * The kind of the entry, used to determine how to interpret the "data"
+ * field.
+ */
+ void set kind(ServerLogEntryKind value) {
+ assert(value != null);
+ this._kind = value;
+ }
+
+ /**
+ * The payload of the entry, the actual format is determined by the "kind"
+ * field.
+ */
+ String get data => _data;
+
+ /**
+ * The payload of the entry, the actual format is determined by the "kind"
+ * field.
+ */
+ void set data(String value) {
+ assert(value != null);
+ this._data = value;
+ }
+
+ ServerLogEntry(int time, ServerLogEntryKind kind, String data) {
+ this.time = time;
+ this.kind = kind;
+ this.data = data;
+ }
+
+ factory ServerLogEntry.fromJson(
+ JsonDecoder jsonDecoder, String jsonPath, Object json) {
+ if (json == null) {
+ json = {};
+ }
+ if (json is Map) {
+ int time;
+ if (json.containsKey("time")) {
+ time = jsonDecoder.decodeInt(jsonPath + ".time", json["time"]);
+ } else {
+ throw jsonDecoder.mismatch(jsonPath, "time");
+ }
+ ServerLogEntryKind kind;
+ if (json.containsKey("kind")) {
+ kind = new ServerLogEntryKind.fromJson(
+ jsonDecoder, jsonPath + ".kind", json["kind"]);
+ } else {
+ throw jsonDecoder.mismatch(jsonPath, "kind");
+ }
+ String data;
+ if (json.containsKey("data")) {
+ data = jsonDecoder.decodeString(jsonPath + ".data", json["data"]);
+ } else {
+ throw jsonDecoder.mismatch(jsonPath, "data");
+ }
+ return new ServerLogEntry(time, kind, data);
+ } else {
+ throw jsonDecoder.mismatch(jsonPath, "ServerLogEntry", json);
+ }
+ }
+
+ @override
+ Map<String, dynamic> toJson() {
+ Map<String, dynamic> result = {};
+ result["time"] = time;
+ result["kind"] = kind.toJson();
+ result["data"] = data;
+ return result;
+ }
+
+ @override
+ String toString() => json.encode(toJson());
+
+ @override
+ bool operator ==(other) {
+ if (other is ServerLogEntry) {
+ return time == other.time && kind == other.kind && data == other.data;
+ }
+ return false;
+ }
+
+ @override
+ int get hashCode {
+ int hash = 0;
+ hash = JenkinsSmiHash.combine(hash, time.hashCode);
+ hash = JenkinsSmiHash.combine(hash, kind.hashCode);
+ hash = JenkinsSmiHash.combine(hash, data.hashCode);
+ return JenkinsSmiHash.finish(hash);
+ }
+}
+
+/**
+ * ServerLogEntryKind
+ *
+ * enum {
+ * NOTIFICATION
+ * RAW
+ * REQUEST
+ * RESPONSE
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class ServerLogEntryKind implements Enum {
+ /**
+ * A notification from the server, such as "analysis.highlights". The "data"
+ * field contains a JSON object with abbreviated notification.
+ */
+ static const ServerLogEntryKind NOTIFICATION =
+ const ServerLogEntryKind._("NOTIFICATION");
+
+ /**
+ * Arbitrary string, describing some event that happened in the server, e.g.
+ * starting a file analysis, and details which files were accessed. These
+ * entries are not structured, but provide context information about requests
+ * and notification, and can be related by "time" for further manual
+ * analysis.
+ */
+ static const ServerLogEntryKind RAW = const ServerLogEntryKind._("RAW");
+
+ /**
+ * A request from the client, as the server views it, e.g. "edit.getAssists".
+ * The "data" field contains a JSON object with abbreviated request.
+ */
+ static const ServerLogEntryKind REQUEST =
+ const ServerLogEntryKind._("REQUEST");
+
+ /**
+ * Various counters and measurements related to execution of a request. The
+ * "data" field contains a JSON object with following fields:
+ *
+ * - "id" - the id of the request - copied from the request.
+ * - "method" - the method of the request, e.g. "edit.getAssists".
+ * - "clientRequestTime" - the time (milliseconds since epoch) at which the
+ * client made the request - copied from the request.
+ * - "serverRequestTime" - the time (milliseconds since epoch) at which the
+ * server received and decoded the JSON request.
+ * - "responseTime" - the time (milliseconds since epoch) at which the server
+ * created the response to be encoded into JSON and sent to the client.
+ */
+ static const ServerLogEntryKind RESPONSE =
+ const ServerLogEntryKind._("RESPONSE");
+
+ /**
+ * A list containing all of the enum values that are defined.
+ */
+ static const List<ServerLogEntryKind> VALUES = const <ServerLogEntryKind>[
+ NOTIFICATION,
+ RAW,
+ REQUEST,
+ RESPONSE
+ ];
+
+ @override
+ final String name;
+
+ const ServerLogEntryKind._(this.name);
+
+ factory ServerLogEntryKind(String name) {
+ switch (name) {
+ case "NOTIFICATION":
+ return NOTIFICATION;
+ case "RAW":
+ return RAW;
+ case "REQUEST":
+ return REQUEST;
+ case "RESPONSE":
+ return RESPONSE;
+ }
+ throw new Exception('Illegal enum value: $name');
+ }
+
+ factory ServerLogEntryKind.fromJson(
+ JsonDecoder jsonDecoder, String jsonPath, Object json) {
+ if (json is String) {
+ try {
+ return new ServerLogEntryKind(json);
+ } catch (_) {
+ // Fall through
+ }
+ }
+ throw jsonDecoder.mismatch(jsonPath, "ServerLogEntryKind", json);
+ }
+
+ @override
+ String toString() => "ServerLogEntryKind.$name";
+
+ String toJson() => name;
+}
+
+/**
+ * server.log params
+ *
+ * {
+ * "entry": ServerLogEntry
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class ServerLogParams implements HasToJson {
+ ServerLogEntry _entry;
+
+ ServerLogEntry get entry => _entry;
+
+ void set entry(ServerLogEntry value) {
+ assert(value != null);
+ this._entry = value;
+ }
+
+ ServerLogParams(ServerLogEntry entry) {
+ this.entry = entry;
+ }
+
+ factory ServerLogParams.fromJson(
+ JsonDecoder jsonDecoder, String jsonPath, Object json) {
+ if (json == null) {
+ json = {};
+ }
+ if (json is Map) {
+ ServerLogEntry entry;
+ if (json.containsKey("entry")) {
+ entry = new ServerLogEntry.fromJson(
+ jsonDecoder, jsonPath + ".entry", json["entry"]);
+ } else {
+ throw jsonDecoder.mismatch(jsonPath, "entry");
+ }
+ return new ServerLogParams(entry);
+ } else {
+ throw jsonDecoder.mismatch(jsonPath, "server.log params", json);
+ }
+ }
+
+ factory ServerLogParams.fromNotification(Notification notification) {
+ return new ServerLogParams.fromJson(
+ new ResponseDecoder(null), "params", notification.params);
+ }
+
+ @override
+ Map<String, dynamic> toJson() {
+ Map<String, dynamic> result = {};
+ result["entry"] = entry.toJson();
+ return result;
+ }
+
+ Notification toNotification() {
+ return new Notification("server.log", toJson());
+ }
+
+ @override
+ String toString() => json.encode(toJson());
+
+ @override
+ bool operator ==(other) {
+ if (other is ServerLogParams) {
+ return entry == other.entry;
+ }
+ return false;
+ }
+
+ @override
+ int get hashCode {
+ int hash = 0;
+ hash = JenkinsSmiHash.combine(hash, entry.hashCode);
+ return JenkinsSmiHash.finish(hash);
+ }
+}
+
+/**
* ServerService
*
* enum {
+ * LOG
* STATUS
* }
*
* Clients may not extend, implement or mix-in this class.
*/
class ServerService implements Enum {
+ static const ServerService LOG = const ServerService._("LOG");
+
static const ServerService STATUS = const ServerService._("STATUS");
/**
* A list containing all of the enum values that are defined.
*/
- static const List<ServerService> VALUES = const <ServerService>[STATUS];
+ static const List<ServerService> VALUES = const <ServerService>[LOG, STATUS];
@override
final String name;
@@ -22751,6 +23060,8 @@
factory ServerService(String name) {
switch (name) {
+ case "LOG":
+ return LOG;
case "STATUS":
return STATUS;
}
@@ -23071,6 +23382,7 @@
* "lexeme": String
* "type": optional String
* "validElementKinds": optional List<String>
+ * "offset": int
* }
*
* Clients may not extend, implement or mix-in this class.
@@ -23082,6 +23394,8 @@
List<String> _validElementKinds;
+ int _offset;
+
/**
* The token's lexeme.
*/
@@ -23127,10 +23441,27 @@
this._validElementKinds = value;
}
- TokenDetails(String lexeme, {String type, List<String> validElementKinds}) {
+ /**
+ * The offset of the first character of the token in the file which it
+ * originated from.
+ */
+ int get offset => _offset;
+
+ /**
+ * The offset of the first character of the token in the file which it
+ * originated from.
+ */
+ void set offset(int value) {
+ assert(value != null);
+ this._offset = value;
+ }
+
+ TokenDetails(String lexeme, int offset,
+ {String type, List<String> validElementKinds}) {
this.lexeme = lexeme;
this.type = type;
this.validElementKinds = validElementKinds;
+ this.offset = offset;
}
factory TokenDetails.fromJson(
@@ -23156,7 +23487,13 @@
json["validElementKinds"],
jsonDecoder.decodeString);
}
- return new TokenDetails(lexeme,
+ int offset;
+ if (json.containsKey("offset")) {
+ offset = jsonDecoder.decodeInt(jsonPath + ".offset", json["offset"]);
+ } else {
+ throw jsonDecoder.mismatch(jsonPath, "offset");
+ }
+ return new TokenDetails(lexeme, offset,
type: type, validElementKinds: validElementKinds);
} else {
throw jsonDecoder.mismatch(jsonPath, "TokenDetails", json);
@@ -23173,6 +23510,7 @@
if (validElementKinds != null) {
result["validElementKinds"] = validElementKinds;
}
+ result["offset"] = offset;
return result;
}
@@ -23185,7 +23523,8 @@
return lexeme == other.lexeme &&
type == other.type &&
listEqual(validElementKinds, other.validElementKinds,
- (String a, String b) => a == b);
+ (String a, String b) => a == b) &&
+ offset == other.offset;
}
return false;
}
@@ -23196,6 +23535,7 @@
hash = JenkinsSmiHash.combine(hash, lexeme.hashCode);
hash = JenkinsSmiHash.combine(hash, type.hashCode);
hash = JenkinsSmiHash.combine(hash, validElementKinds.hashCode);
+ hash = JenkinsSmiHash.combine(hash, offset.hashCode);
return JenkinsSmiHash.finish(hash);
}
}
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index 29ba4a7..6c308d7 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -1,8 +1,15 @@
-## 0.38.2-dev
+## 0.38.2
* The type of `FunctionTypeAlias.declaredElement` has been refined to
`FunctionTypeAliasElement`. Since the new type is a refinement of
the old one, the only effect on clients should be to make certain
casts unnecessary.
+* Deprecated `HintCode.INVALID_REQUIRED_PARAM` and replaced it with more
+ specific hints, `HintCode.INVALID_REQUIRED_NAMED_PARAM`,
+ `HintCode.INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM`, and
+ `HintCode.INVALID_REQUIRED_POSITIONAL_PARAM` to address #36966.
+* Deprecated `CompileTimeErrorCode.NOT_ENOUGH_REQUIRED_ARGUMENTS`. It
+ has been renamed to
+ `CompileTimeErrorCode.NOT_ENOUGH_POSITIONAL_ARGUMENTS`.
## 0.38.1
* LinterVistor support for extension method AST nodes.
diff --git a/pkg/analyzer/lib/dart/ast/ast.dart b/pkg/analyzer/lib/dart/ast/ast.dart
index 79c25fc..1b18be9 100644
--- a/pkg/analyzer/lib/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/dart/ast/ast.dart
@@ -4787,6 +4787,9 @@
/// The spread operator, either '...' or '...?'.
Token get spreadOperator;
+
+ /// Whether this is a null-aware spread, as opposed to a non-null spread.
+ bool get isNullAware;
}
/// A node that represents a statement.
diff --git a/pkg/analyzer/lib/dart/element/element.dart b/pkg/analyzer/lib/dart/element/element.dart
index da6c473..0eda2b3 100644
--- a/pkg/analyzer/lib/dart/element/element.dart
+++ b/pkg/analyzer/lib/dart/element/element.dart
@@ -1389,14 +1389,7 @@
/// A local variable.
///
/// Clients may not extend, implement or mix-in this class.
-abstract class LocalVariableElement implements LocalElement, VariableElement {
- /// Return `true` if this local variable uses late evaluation semantics.
- ///
- /// This will always return `false` unless the experiment 'non-nullable' is
- /// enabled.
- @experimental
- bool get isLate;
-}
+abstract class LocalVariableElement implements LocalElement, VariableElement {}
/// An element that represents a method defined within a class.
///
@@ -1602,13 +1595,6 @@
/// will be synthetic.
PropertyAccessorElement get getter;
- /// Return `true` if this variable uses late evaluation semantics.
- ///
- /// This will always return `false` unless the experiment 'non-nullable' is
- /// enabled.
- @experimental
- bool get isLate;
-
/// Return the propagated type of this variable, or `null` if type propagation
/// has not been performed, for example because the variable is not final.
@deprecated
@@ -1745,6 +1731,13 @@
/// even though they are implicitly final.
bool get isFinal;
+ /// Return `true` if this variable uses late evaluation semantics.
+ ///
+ /// This will always return `false` unless the experiment 'non-nullable' is
+ /// enabled.
+ @experimental
+ bool get isLate;
+
/// Return `true` if this variable is potentially mutated somewhere in a
/// closure. This information is only available for local variables (including
/// parameters) and only after the compilation unit containing the variable
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index fde3636..94175cc 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -73,6 +73,7 @@
CompileTimeErrorCode.ANNOTATION_WITH_TYPE_ARGUMENTS,
CompileTimeErrorCode.ASYNC_FOR_IN_WRONG_CONTEXT,
CompileTimeErrorCode.AWAIT_IN_WRONG_CONTEXT,
+ CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_EXTENSION_NAME,
CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_PREFIX_NAME,
CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE,
CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPEDEF_NAME,
@@ -136,10 +137,8 @@
CompileTimeErrorCode.EXTENDS_DEFERRED_CLASS,
CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS,
CompileTimeErrorCode.EXTENDS_NON_CLASS,
+ CompileTimeErrorCode.EXTENSION_AS_EXPRESSION,
CompileTimeErrorCode.EXTENSION_CONFLICTING_STATIC_AND_INSTANCE,
- CompileTimeErrorCode.EXTENSION_DECLARES_ABSTRACT_MEMBER,
- CompileTimeErrorCode.EXTENSION_DECLARES_CONSTRUCTOR,
- CompileTimeErrorCode.EXTENSION_DECLARES_INSTANCE_FIELD,
CompileTimeErrorCode.EXTENSION_DECLARES_MEMBER_OF_OBJECT,
CompileTimeErrorCode.EXTENSION_OVERRIDE_ACCESS_TO_STATIC_MEMBER,
CompileTimeErrorCode.EXTENSION_OVERRIDE_ARGUMENT_NOT_ASSIGNABLE,
@@ -246,6 +245,8 @@
CompileTimeErrorCode.NON_SYNC_FACTORY,
CompileTimeErrorCode.NOT_ASSIGNED_POTENTIALLY_NON_NULLABLE_LOCAL_VARIABLE,
CompileTimeErrorCode.NOT_ENOUGH_POSITIONAL_ARGUMENTS,
+ // ignore: deprecated_member_use_from_same_package
+ CompileTimeErrorCode.NOT_ENOUGH_REQUIRED_ARGUMENTS,
CompileTimeErrorCode.NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD,
CompileTimeErrorCode.NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD_CONSTRUCTOR,
CompileTimeErrorCode.NOT_INITIALIZED_NON_NULLABLE_VARIABLE,
@@ -337,7 +338,11 @@
HintCode.INVALID_FACTORY_METHOD_IMPL,
HintCode.INVALID_IMMUTABLE_ANNOTATION,
HintCode.INVALID_LITERAL_ANNOTATION,
+ HintCode.INVALID_REQUIRED_NAMED_PARAM,
+ HintCode.INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM,
+ // ignore: deprecated_member_use_from_same_package
HintCode.INVALID_REQUIRED_PARAM,
+ HintCode.INVALID_REQUIRED_POSITIONAL_PARAM,
HintCode.INVALID_SEALED_ANNOTATION,
HintCode.INVALID_USE_OF_PROTECTED_MEMBER,
HintCode.INVALID_USE_OF_VISIBLE_FOR_TEMPLATE_MEMBER,
@@ -458,6 +463,9 @@
ParserErrorCode.EXPECTED_TYPE_NAME,
ParserErrorCode.EXPERIMENT_NOT_ENABLED,
ParserErrorCode.EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE,
+ ParserErrorCode.EXTENSION_DECLARES_ABSTRACT_MEMBER,
+ ParserErrorCode.EXTENSION_DECLARES_CONSTRUCTOR,
+ ParserErrorCode.EXTENSION_DECLARES_INSTANCE_FIELD,
ParserErrorCode.EXTERNAL_AFTER_CONST,
ParserErrorCode.EXTERNAL_AFTER_FACTORY,
ParserErrorCode.EXTERNAL_AFTER_STATIC,
@@ -537,6 +545,7 @@
ParserErrorCode.MISSING_TYPEDEF_PARAMETERS,
ParserErrorCode.MISSING_VARIABLE_IN_FOR_EACH,
ParserErrorCode.MIXED_PARAMETER_GROUPS,
+ ParserErrorCode.MIXIN_DECLARES_CONSTRUCTOR,
ParserErrorCode.MODIFIER_OUT_OF_ORDER,
ParserErrorCode.MULTIPLE_EXTENDS_CLAUSES,
ParserErrorCode.MULTIPLE_ON_CLAUSES,
@@ -657,7 +666,9 @@
StaticWarningCode.CONCRETE_CLASS_WITH_ABSTRACT_MEMBER,
StaticWarningCode.CONST_WITH_ABSTRACT_CLASS,
StaticWarningCode.EXPORT_DUPLICATED_LIBRARY_NAMED,
+ // ignore: deprecated_member_use_from_same_package
StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS,
+ // ignore: deprecated_member_use_from_same_package
StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED,
StaticWarningCode.FIELD_INITIALIZED_IN_INITIALIZER_AND_DECLARATION,
StaticWarningCode.FINAL_INITIALIZED_IN_DECLARATION_AND_CONSTRUCTOR,
@@ -668,6 +679,7 @@
StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_2,
StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_3_PLUS,
StaticWarningCode.IMPORT_DUPLICATED_LIBRARY_NAMED,
+ // ignore: deprecated_member_use_from_same_package
StaticWarningCode.IMPORT_OF_NON_LIBRARY,
StaticWarningCode.INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_NAMED,
StaticWarningCode.INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_POSITIONAL,
@@ -691,11 +703,14 @@
StaticWarningCode.NON_VOID_RETURN_FOR_OPERATOR,
StaticWarningCode.NON_VOID_RETURN_FOR_SETTER,
StaticWarningCode.NOT_A_TYPE,
+ // ignore: deprecated_member_use_from_same_package
StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS,
StaticWarningCode.PART_OF_DIFFERENT_LIBRARY,
StaticWarningCode.REDIRECT_TO_INVALID_FUNCTION_TYPE,
StaticWarningCode.REDIRECT_TO_INVALID_RETURN_TYPE,
+ // ignore: deprecated_member_use_from_same_package
StaticWarningCode.REDIRECT_TO_MISSING_CONSTRUCTOR,
+ // ignore: deprecated_member_use_from_same_package
StaticWarningCode.REDIRECT_TO_NON_CLASS,
StaticWarningCode.RETURN_WITHOUT_VALUE,
StaticWarningCode.SET_ELEMENT_TYPE_NOT_ASSIGNABLE,
@@ -706,10 +721,12 @@
StaticWarningCode.TYPE_TEST_WITH_NON_TYPE,
StaticWarningCode.TYPE_TEST_WITH_UNDEFINED_NAME,
StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE,
+ // ignore: deprecated_member_use_from_same_package
StaticWarningCode.UNDEFINED_CLASS,
StaticWarningCode.UNDEFINED_CLASS_BOOLEAN,
StaticWarningCode.UNDEFINED_IDENTIFIER,
StaticWarningCode.UNDEFINED_IDENTIFIER_AWAIT,
+ // ignore: deprecated_member_use_from_same_package
StaticWarningCode.UNDEFINED_NAMED_PARAMETER,
StaticWarningCode.UNNECESSARY_NON_NULL_ASSERTION,
StaticWarningCode.UNNECESSARY_NULL_AWARE_CALL,
diff --git a/pkg/analyzer/lib/instrumentation/instrumentation.dart b/pkg/analyzer/lib/instrumentation/instrumentation.dart
index bcf859c..63920eb 100644
--- a/pkg/analyzer/lib/instrumentation/instrumentation.dart
+++ b/pkg/analyzer/lib/instrumentation/instrumentation.dart
@@ -5,8 +5,6 @@
import 'dart:async';
import 'dart:convert';
-import 'package:analyzer/src/task/api/model.dart';
-
/**
* A container with analysis performance constants.
*/
@@ -123,17 +121,6 @@
String get _timestamp => new DateTime.now().millisecondsSinceEpoch.toString();
/**
- * Log that the given analysis [task] is being performed in the given
- * [context].
- */
- void logAnalysisTask(String context, AnalysisTask task) {
- if (_instrumentationServer != null) {
- _instrumentationServer
- .log(_join([TAG_ANALYSIS_TASK, context, task.description]));
- }
- }
-
- /**
* Log the fact that an error, described by the given [message], has occurred.
*/
void logError(String message) {
diff --git a/pkg/analyzer/lib/src/context/cache.dart b/pkg/analyzer/lib/src/context/cache.dart
index 65349a0..e0b4d6a 100644
--- a/pkg/analyzer/lib/src/context/cache.dart
+++ b/pkg/analyzer/lib/src/context/cache.dart
@@ -2,1544 +2,17 @@
// 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:collection';
-
-import 'package:analyzer/exception/exception.dart';
-import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/utilities_collection.dart';
-import 'package:analyzer/src/task/api/model.dart';
-import 'package:analyzer/src/task/model.dart';
-/**
- * The cache results visiting function type.
- */
-typedef void CacheResultVisitor(AnalysisTarget target, ResultData data);
-
-/**
- * Return `true` if the [result] of the [target] should be flushed.
- */
-typedef bool FlushResultFilter<V>(
- AnalysisTarget target, ResultDescriptor<V> result);
-
-/**
- * Return `true` if the given [target] is a priority one.
- */
-typedef bool IsPriorityAnalysisTarget(AnalysisTarget target);
-
-/**
- * An LRU cache of results produced by analysis.
- */
class AnalysisCache {
- /**
- * A flag used to control whether trace information should be produced when
- * the content of the cache is modified.
- */
- static bool _TRACE_CHANGES = false;
-
- /**
- * An array containing the partitions of which this cache is comprised.
- */
- final List<CachePartition> _partitions;
-
- /**
- * The [StreamController] reporting [InvalidatedResult]s.
- */
- final ReentrantSynchronousStream<InvalidatedResult> onResultInvalidated =
- new ReentrantSynchronousStream<InvalidatedResult>();
-
- final List<ReentrantSynchronousStreamSubscription>
- onResultInvalidatedPartitionSubscriptions =
- <ReentrantSynchronousStreamSubscription>[];
-
- /**
- * Initialize a newly created cache to have the given [_partitions]. The
- * partitions will be searched in the order in which they appear in the array,
- * so the most specific partition (usually an [SdkCachePartition]) should be
- * first and the most general (usually a [UniversalCachePartition]) last.
- */
- AnalysisCache(this._partitions) {
- for (CachePartition partition in _partitions) {
- partition.containingCaches.add(this);
- ReentrantSynchronousStreamSubscription<InvalidatedResult> subscription =
- partition.onResultInvalidated.listen((InvalidatedResult event) {
- onResultInvalidated.add(event);
- });
- onResultInvalidatedPartitionSubscriptions.add(subscription);
- }
- }
-
- /**
- * Return an iterator returning all of the [Source] targets.
- */
- Iterable<Source> get sources {
- return _partitions
- .map((CachePartition partition) => partition.sources)
- .expand((Iterable<Source> sources) => sources);
- }
-
- // TODO(brianwilkerson) Implement or delete this.
-// /**
-// * Return information about each of the partitions in this cache.
-// */
-// List<AnalysisContextStatistics_PartitionData> get partitionData {
-// int count = _partitions.length;
-// List<AnalysisContextStatistics_PartitionData> data =
-// new List<AnalysisContextStatistics_PartitionData>(count);
-// for (int i = 0; i < count; i++) {
-// CachePartition partition = _partitions[i];
-// data[i] = new AnalysisContextStatisticsImpl_PartitionDataImpl(
-// partition.astSize,
-// partition.map.length);
-// }
-// return data;
-// }
-
- /**
- * Free any allocated resources and references.
- */
- void dispose() {
- for (ReentrantSynchronousStreamSubscription subscription
- in onResultInvalidatedPartitionSubscriptions) {
- subscription.cancel();
- }
- for (CachePartition partition in _partitions) {
- partition.containingCaches.remove(this);
- }
- }
-
- /**
- * Flush results that satisfy the given [filter].
- */
- void flush(FlushResultFilter filter) {
- for (CachePartition partition in _partitions) {
- partition.flush(filter);
- }
- }
-
- /**
- * Return the entry associated with the given [target].
- */
- CacheEntry get(AnalysisTarget target) {
- int count = _partitions.length;
- for (int i = 0; i < count; i++) {
- CachePartition partition = _partitions[i];
- if (partition.isResponsibleFor(target)) {
- return partition.get(target);
- }
- }
- //
- // We should never get to this point because the last partition should
- // always be a universal partition, except in the case of the SDK context,
- // in which case the target should always be part of the SDK.
- //
- return null;
- }
-
- /**
- * Return the context to which the given [target] was explicitly added.
- */
- InternalAnalysisContext getContextFor(AnalysisTarget target) {
- int count = _partitions.length;
- for (int i = 0; i < count; i++) {
- CachePartition partition = _partitions[i];
- if (partition.isResponsibleFor(target)) {
- return partition.context;
- }
- }
- //
- // We should never get to this point because the last partition should
- // always be a universal partition, except in the case of the SDK context,
- // in which case the target should always be part of the SDK.
- //
- // TODO(brianwilkerson) Throw an exception here.
- AnalysisEngine.instance.logger.logInformation(
- 'Could not find context for $target',
- new CaughtException(new AnalysisException(), null));
- return null;
- }
-
- /**
- * Return [Source]s whose full path is equal to the given [path].
- * Maybe empty, but not `null`.
- */
- List<Source> getSourcesWithFullName(String path) {
- List<Source> sources = <Source>[];
- for (CachePartition partition in _partitions) {
- List<Source> partitionSources = partition.getSourcesWithFullName(path);
- sources.addAll(partitionSources);
- }
- return sources;
- }
-
- /**
- * Return the state of the given [result] for the given [target].
- *
- * It does not update the cache, if the corresponding [CacheEntry] does not
- * exist, then [CacheState.INVALID] is returned.
- */
- CacheState getState(AnalysisTarget target, ResultDescriptor result) {
- CacheEntry entry = get(target);
- if (entry == null) {
- return CacheState.INVALID;
- }
- return entry.getState(result);
- }
-
- /**
- * Return the value of the given [result] for the given [target].
- *
- * It does not update the cache, if the corresponding [CacheEntry] does not
- * exist, then the default value is returned.
- */
- V getValue<V>(AnalysisTarget target, ResultDescriptor<V> result) {
- CacheEntry entry = get(target);
- if (entry == null) {
- return result.defaultValue;
- }
- return entry.getValue(result);
- }
-
- /**
- * Return an iterator returning all of the map entries mapping targets to
- * cache entries. If the [context] is not `null`, then only entries that are
- * owned by the given context will be returned.
- */
- MapIterator<AnalysisTarget, CacheEntry> iterator(
- {InternalAnalysisContext context: null}) {
- List<Map<AnalysisTarget, CacheEntry>> maps =
- <Map<AnalysisTarget, CacheEntry>>[];
- for (CachePartition partition in _partitions) {
- if (context == null || partition.context == context) {
- maps.add(partition.entryMap);
- }
- }
- return new MultipleMapIterator<AnalysisTarget, CacheEntry>(maps);
- }
-
- /**
- * Puts the given [entry] into the cache.
- */
- void put(CacheEntry entry) {
- AnalysisTarget target = entry.target;
- entry.fixExceptionState();
- int count = _partitions.length;
- for (int i = 0; i < count; i++) {
- CachePartition partition = _partitions[i];
- if (partition.isResponsibleFor(target)) {
- if (_TRACE_CHANGES) {
- CacheEntry oldEntry = partition.get(target);
- if (oldEntry == null) {
- AnalysisEngine.instance.logger
- .logInformation('Added a cache entry for $target.');
- } else {
- AnalysisEngine.instance.logger
- .logInformation('Modified the cache entry for $target.');
-// 'Diff = ${entry.getDiff(oldEntry)}');
- }
- }
- partition.put(entry);
- return;
- }
- }
- // TODO(brianwilkerson) Handle the case where no partition was found,
- // possibly by throwing an exception.
- }
-
- /**
- * Remove all information related to the given [target] from this cache.
- * Return the entry associated with the target, or `null` if there was cache
- * entry for the target.
- */
- CacheEntry remove(AnalysisTarget target) {
- int count = _partitions.length;
- for (int i = 0; i < count; i++) {
- CachePartition partition = _partitions[i];
- if (partition.isResponsibleFor(target)) {
- if (_TRACE_CHANGES) {
- AnalysisEngine.instance.logger
- .logInformation('Removed the cache entry for $target.');
- }
- CacheEntry entry = partition.remove(target);
- if (entry != null) {
- entry.dispose();
- }
- return entry;
- }
- }
- return null;
- }
-
- /**
- * Return the number of targets that are mapped to cache entries.
- */
- int size() {
- int size = 0;
- int count = _partitions.length;
- for (int i = 0; i < count; i++) {
- size += _partitions[i].size();
- }
- return size;
- }
+ AnalysisCache(List<CachePartition> partitions);
}
-/**
- * The information cached by an analysis context about an individual target.
- */
-class CacheEntry {
- /**
- * The index of the flag indicating whether the source was explicitly added to
- * the context or whether the source was implicitly added because it was
- * referenced by another source.
- */
- static int _EXPLICITLY_ADDED_FLAG = 0;
-
- /**
- * The next visit process identifier.
- */
- static int nextVisitId = 0;
-
- /**
- * A table containing the number of times the value of a result descriptor was
- * recomputed after having been flushed.
- */
- static final Map<ResultDescriptor, int> recomputedCounts =
- new HashMap<ResultDescriptor, int>();
-
- /**
- * The target this entry is about.
- */
- final AnalysisTarget target;
-
- /**
- * The partition that is responsible for this entry.
- */
- CachePartition _partition;
-
- /**
- * The most recent time at which the state of the target matched the state
- * represented by this entry, `-1` if the target does not exist.
- */
- int modificationTime = -1;
-
- /**
- * The exception that caused one or more values to have a state of
- * [CacheState.ERROR].
- */
- CaughtException _exception;
-
- /**
- * A bit-encoding of boolean flags associated with this entry's target.
- */
- int _flags = 0;
-
- /**
- * A table mapping result descriptors to the cached values of those results.
- */
- Map<ResultDescriptor, ResultData> _resultMap =
- new HashMap<ResultDescriptor, ResultData>();
-
- CacheEntry(this.target);
-
- /**
- * The exception that caused one or more values to have a state of
- * [CacheState.ERROR].
- */
- CaughtException get exception => _exception;
-
- /**
- * Return `true` if the source was explicitly added to the context or `false`
- * if the source was implicitly added because it was referenced by another
- * source.
- */
- bool get explicitlyAdded => _getFlag(_EXPLICITLY_ADDED_FLAG);
-
- /**
- * Set whether the source was explicitly added to the context to match the
- * [explicitlyAdded] flag.
- */
- void set explicitlyAdded(bool explicitlyAdded) {
- _setFlag(_EXPLICITLY_ADDED_FLAG, explicitlyAdded);
- }
-
- /**
- * Return a list of result descriptors for results whose state is not
- * [CacheState.INVALID].
- */
- List<ResultDescriptor> get nonInvalidResults => _resultMap.keys.toList();
-
- /**
- * Notifies the entry that the client is going to stop using it.
- */
- void dispose() {
- _resultMap.forEach((ResultDescriptor descriptor, ResultData data) {
- TargetedResult result = new TargetedResult(target, descriptor);
- for (TargetedResult dependedOnResult in data.dependedOnResults) {
- for (AnalysisCache cache in _partition.containingCaches) {
- CacheEntry entry = cache.get(dependedOnResult.target);
- if (entry != null) {
- ResultData data =
- entry.getResultDataOrNull(dependedOnResult.result);
- if (data != null) {
- data.dependentResults.remove(result);
- }
- }
- }
- }
- });
- _resultMap.clear();
- }
-
- /**
- * Fix the state of the [exception] to match the current state of the entry.
- */
- void fixExceptionState() {
- if (!hasErrorState()) {
- _exception = null;
- }
- }
-
- /**
- * Flush results that satisfy the given [filter].
- */
- void flush(FlushResultFilter filter) {
- _resultMap.forEach((ResultDescriptor result, ResultData data) {
- if (filter(target, result)) {
- data.flush();
- }
- });
- }
-
- /**
- * Return the result data associated with the [descriptor], creating one if it
- * isn't there.
- */
- ResultData getResultData(ResultDescriptor descriptor) {
- return _resultMap.putIfAbsent(descriptor, () => new ResultData(descriptor));
- }
-
- /**
- * Return the result data associated with the [descriptor], or `null` if there
- * is no data currently associated with the descriptor.
- */
- ResultData getResultDataOrNull(ResultDescriptor descriptor) =>
- _resultMap[descriptor];
-
- /**
- * Return the state of the result represented by the given [descriptor].
- */
- CacheState getState(ResultDescriptor descriptor) {
- ResultData data = _resultMap[descriptor];
- if (data == null) {
- return CacheState.INVALID;
- }
- return data.state;
- }
-
- /**
- * Return the value of the result represented by the given [descriptor], or
- * the default value for the result if this entry does not have a valid value.
- */
- V getValue<V>(ResultDescriptor<V> descriptor) {
- ResultData data = _resultMap[descriptor];
- if (data == null) {
- return descriptor.defaultValue;
- }
- if (_partition != null) {
- _partition.resultAccessed(target, descriptor);
- }
- return data.value as V;
- }
-
- /**
- * Return `true` if the state of any data value is [CacheState.ERROR].
- */
- bool hasErrorState() {
- for (ResultData data in _resultMap.values) {
- if (data.state == CacheState.ERROR) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Invalidate all of the information associated with this entry's target.
- */
- void invalidateAllInformation() {
- _resultMap.clear();
- _exception = null;
- }
-
- /**
- * Return `true` if the state of the result represented by the given
- * [descriptor] is [CacheState.INVALID].
- */
- bool isInvalid(ResultDescriptor descriptor) =>
- getState(descriptor) == CacheState.INVALID;
-
- /**
- * Return `true` if the state of the result represented by the given
- * [descriptor] is [CacheState.VALID].
- */
- bool isValid(ResultDescriptor descriptor) =>
- getState(descriptor) == CacheState.VALID;
-
- /**
- * For each of the given [descriptors], set their states to
- * [CacheState.ERROR], their values to the corresponding default values, and
- * remember the [exception] that caused this state.
- */
- void setErrorState(
- CaughtException exception, List<ResultDescriptor> descriptors) {
- if (descriptors == null || descriptors.isEmpty) {
- throw new ArgumentError('at least one descriptor is expected');
- }
- if (exception == null) {
- throw new ArgumentError('an exception is expected');
- }
- this._exception = exception;
- for (ResultDescriptor descriptor in descriptors) {
- _setErrorState(descriptor, exception);
- }
- }
-
- /**
- * Set the state of the result represented by the given [descriptor] to the
- * given [state].
- */
- void setState(ResultDescriptor descriptor, CacheState state, {Delta delta}) {
- if (state == CacheState.ERROR) {
- throw new ArgumentError('use setErrorState() to set the state to ERROR');
- }
- if (state == CacheState.VALID) {
- throw new ArgumentError('use setValue() to set the state to VALID');
- }
- _validateStateChange(descriptor, state);
- if (state == CacheState.INVALID) {
- ResultData data = _resultMap[descriptor];
- if (data != null) {
- bool canUseDelta =
- _gatherResultsInvalidatedByDelta(descriptor, delta, 0);
- if (!canUseDelta) {
- delta = null;
- }
- _invalidate(nextVisitId++, descriptor, delta, 0);
- }
- } else {
- ResultData data = getResultData(descriptor);
- data.state = state;
- if (state != CacheState.IN_PROCESS) {
- //
- // If the state is in-process, we can leave the current value in the
- // cache for any 'get' methods to access.
- //
- data.value = descriptor.defaultValue;
- }
- }
- }
-
- /**
- * Set the value of the result represented by the given [descriptor] to the
- * given [value].
- */
- void setValue<V>(ResultDescriptor<V> descriptor, V value,
- List<TargetedResult> dependedOn) {
-// {
-// String valueStr = '$value';
-// if (valueStr.length > 20) {
-// valueStr = valueStr.substring(0, 20) + '...';
-// }
-// valueStr = valueStr.replaceAll('\n', '\\n');
-// print(
-// 'setValue $descriptor for $target value=$valueStr dependedOn=$dependedOn');
-// }
- _validateStateChange(descriptor, CacheState.VALID);
- TargetedResult thisResult = new TargetedResult(target, descriptor);
- if (_partition != null) {
- _partition.resultStored(thisResult, value);
- }
- ResultData data = getResultData(descriptor);
- _setDependedOnResults(data, thisResult, dependedOn);
- if (data.state == CacheState.FLUSHED) {
- int count = recomputedCounts[descriptor] ?? 0;
- recomputedCounts[descriptor] = count + 1;
- }
- data.state = CacheState.VALID;
- data.value = value ?? descriptor.defaultValue;
- }
-
- /**
- * If the result represented by the given [descriptor] is valid, set
- * it to the given [value], keep its dependency, and if [invalidateDependent]
- * invalidate all the dependent result.
- */
- void setValueIncremental(
- ResultDescriptor descriptor, dynamic value, bool invalidateDependent) {
- ResultData data = getResultData(descriptor);
- if (data.state == CacheState.VALID || data.state == CacheState.FLUSHED) {
- data.value = value;
- }
- if (invalidateDependent) {
- _invalidateDependentResults(nextVisitId++, data, null, 0);
- }
- }
-
- @override
- String toString() {
- StringBuffer buffer = new StringBuffer();
- _writeOn(buffer);
- return buffer.toString();
- }
-
- /**
- * Visit the given [result] and all results that depend on it, and
- * ask [delta] to gather changes. Return `true` if the [delta] can be used
- * to perform limited invalidation, or `false` if the changes collection
- * process does not stop (should not happen).
- */
- bool _gatherResultsInvalidatedByDelta(
- ResultDescriptor result, Delta delta, int level) {
- if (delta == null) {
- return false;
- }
- if (!delta.shouldGatherChanges) {
- return true;
- }
- for (int i = 0; i < 64; i++) {
- bool hasVisitChanges = false;
- _visitResults(nextVisitId++, result,
- (AnalysisTarget target, ResultData data) {
- bool hasDeltaChanges = delta.gatherChanges(
- _partition.context, target, data.descriptor, data.value);
- if (hasDeltaChanges) {
- hasVisitChanges = true;
- }
- });
- delta.gatherEnd();
- if (!hasVisitChanges) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Return the value of the flag with the given [index].
- */
- bool _getFlag(int index) => BooleanArray.get(_flags, index);
-
- /**
- * Invalidate the result represented by the given [descriptor] and propagate
- * invalidation to other results that depend on it.
- */
- void _invalidate(
- int id, ResultDescriptor descriptor, Delta delta, int level) {
- ResultData thisData = _resultMap[descriptor];
- if (thisData == null) {
- return;
- }
- // Stop if already validated.
- if (delta != null) {
- if (thisData.visitId == id) {
- return;
- }
- thisData.visitId = id;
- }
- // Ask the delta to validate.
- DeltaResult deltaResult = null;
- if (delta != null) {
- deltaResult = delta.validate(
- _partition.context, target, descriptor, thisData.value);
- if (deltaResult == DeltaResult.STOP) {
- return;
- }
- }
-// if (deltaResult != null) {
-// String indent = ' ' * level;
-// String deltaResultName = deltaResult.toString().split('.').last;
-// print('[$id]$indent$deltaResultName $descriptor for $target');
-// }
- if (deltaResult == DeltaResult.INVALIDATE_NO_DELTA) {
- delta = null;
- }
- if (deltaResult == DeltaResult.INVALIDATE_KEEP_DEPENDENCIES) {
- thisData.value = descriptor.defaultValue;
- thisData.state = CacheState.INVALID;
- } else if (deltaResult == null ||
- deltaResult == DeltaResult.INVALIDATE ||
- deltaResult == DeltaResult.INVALIDATE_NO_DELTA) {
- _resultMap.remove(descriptor);
- // Stop depending on other results.
- {
- TargetedResult thisResult = new TargetedResult(target, descriptor);
- List<AnalysisCache> caches = _partition.containingCaches;
- int cacheLength = caches.length;
- List<TargetedResult> results = thisData.dependedOnResults;
- int resultLength = results.length;
- for (int i = 0; i < resultLength; i++) {
- TargetedResult dependedOnResult = results[i];
- for (int j = 0; j < cacheLength; j++) {
- AnalysisCache cache = caches[j];
- CacheEntry entry = cache.get(dependedOnResult.target);
- if (entry != null) {
- ResultData data =
- entry.getResultDataOrNull(dependedOnResult.result);
- if (data != null) {
- data.dependentResults.remove(thisResult);
- }
- }
- }
- }
- }
-// if (deltaResult == null) {
-// String indent = ' ' * level;
-// print('[$id]$indent invalidate $descriptor for $target');
-// }
- }
- // Invalidate results that depend on this result.
- _invalidateDependentResults(id, thisData, delta, level + 1);
- // If empty and not explicitly added, remove the entry altogether.
- if (_resultMap.isEmpty && !explicitlyAdded) {
- CacheEntry entry = _partition.entryMap.remove(target);
- if (entry != null) {
- entry.dispose();
- }
- _partition._removeIfSource(target);
- }
- // Notify controller.
- if (deltaResult != DeltaResult.KEEP_CONTINUE) {
- _partition.onResultInvalidated
- .add(new InvalidatedResult(this, descriptor, thisData.value));
- }
- }
-
- /**
- * Invalidates all the results of this entry, with propagation.
- */
- void _invalidateAll() {
- List<ResultDescriptor> results = _resultMap.keys.toList();
- int length = results.length;
- for (int i = 0; i < length; i++) {
- ResultDescriptor result = results[i];
- _invalidate(nextVisitId++, result, null, 0);
- }
- }
-
- /**
- * Invalidate results that depend on [thisData].
- */
- void _invalidateDependentResults(
- int id, ResultData thisData, Delta delta, int level) {
- // It is necessary to copy the results to a list to avoid a concurrent
- // modification of the set of dependent results.
- List<AnalysisCache> caches = _partition.containingCaches;
- int cacheLength = caches.length;
- List<TargetedResult> dependentResults = thisData.dependentResults.toList();
- int resultLength = dependentResults.length;
- for (int i = 0; i < resultLength; i++) {
- TargetedResult dependentResult = dependentResults[i];
- for (int j = 0; j < cacheLength; j++) {
- AnalysisCache cache = caches[j];
- CacheEntry entry = cache.get(dependentResult.target);
- if (entry != null) {
- entry._invalidate(id, dependentResult.result, delta, level);
- }
- }
- }
- }
-
- /**
- * Set the [dependedOn] on which this result depends.
- */
- void _setDependedOnResults(ResultData thisData, TargetedResult thisResult,
- List<TargetedResult> dependedOn) {
- List<AnalysisCache> caches = _partition.containingCaches;
- int cacheLength = caches.length;
-
- List<TargetedResult> oldResults = thisData.dependedOnResults;
- int oldLength = oldResults.length;
- for (int i = 0; i < oldLength; i++) {
- TargetedResult dependedOnResult = oldResults[i];
- for (int j = 0; j < cacheLength; j++) {
- AnalysisCache cache = caches[j];
- CacheEntry entry = cache.get(dependedOnResult.target);
- if (entry != null) {
- ResultData data = entry.getResultDataOrNull(dependedOnResult.result);
- if (data != null) {
- data.dependentResults.remove(thisResult);
- }
- }
- }
- }
- thisData.dependedOnResults = dependedOn;
- int newLength = dependedOn.length;
- for (int i = 0; i < newLength; i++) {
- TargetedResult dependedOnResult = dependedOn[i];
- for (int j = 0; j < cacheLength; j++) {
- AnalysisCache cache = caches[j];
- CacheEntry entry = cache.get(dependedOnResult.target);
- if (entry != null) {
- ResultData data = entry.getResultData(dependedOnResult.result);
- data.dependentResults.add(thisResult);
- }
- }
- }
- }
-
- /**
- * Set states of the given and dependent results to [CacheState.ERROR] and
- * their values to the corresponding default values
- */
- void _setErrorState(ResultDescriptor descriptor, CaughtException exception) {
- ResultData thisData = getResultData(descriptor);
- // Set the error state.
- _exception = exception;
- thisData.state = CacheState.ERROR;
- thisData.value = descriptor.defaultValue;
- // Propagate the error state.
- List<AnalysisCache> caches = _partition.containingCaches;
- int cacheLength = caches.length;
- thisData.dependentResults.forEach((TargetedResult dependentResult) {
- for (int i = 0; i < cacheLength; i++) {
- AnalysisCache cache = caches[i];
- CacheEntry entry = cache.get(dependentResult.target);
- if (entry != null) {
- entry._setErrorState(dependentResult.result, exception);
- }
- }
- });
- }
-
- /**
- * Set the value of the flag with the given [index] to the given [value].
- */
- void _setFlag(int index, bool value) {
- _flags = BooleanArray.set(_flags, index, value);
- }
-
- /**
- * If the state of the value described by the given [descriptor] is changing
- * from ERROR to anything else, capture the information. This is an attempt to
- * discover the underlying cause of a long-standing bug.
- */
- void _validateStateChange(ResultDescriptor descriptor, CacheState newState) {
- // TODO(brianwilkerson) Decide whether we still want to capture this data.
-// if (descriptor != CONTENT) {
-// return;
-// }
-// ResultData data = resultMap[CONTENT];
-// if (data != null && data.state == CacheState.ERROR) {
-// String message =
-// 'contentState changing from ${data.state} to $newState';
-// InstrumentationBuilder builder =
-// Instrumentation.builder2('CacheEntry-validateStateChange');
-// builder.data3('message', message);
-// //builder.data('source', source.getFullName());
-// builder.record(new CaughtException(new AnalysisException(message), null));
-// builder.log();
-// }
- }
-
- /**
- * Call [visitor] for the result described by the given [descriptor] and all
- * results that depend on directly or indirectly. Each result is visited
- * only once.
- */
- void _visitResults(
- int id, ResultDescriptor descriptor, CacheResultVisitor visitor) {
- ResultData thisData = _resultMap[descriptor];
- if (thisData == null) {
- return;
- }
- // Stop if already visited.
- if (thisData.visitId == id) {
- return;
- }
- thisData.visitId = id;
- // Visit this result.
- visitor(target, thisData);
- // Visit results that depend on this result.
- List<AnalysisCache> caches = _partition.containingCaches;
- int cacheLength = caches.length;
- List<TargetedResult> dependentResults = thisData.dependentResults.toList();
- int resultLength = dependentResults.length;
- for (int i = 0; i < resultLength; i++) {
- TargetedResult dependentResult = dependentResults[i];
- for (int j = 0; j < cacheLength; j++) {
- AnalysisCache cache = caches[j];
- CacheEntry entry = cache.get(dependentResult.target);
- if (entry != null) {
- entry._visitResults(id, dependentResult.result, visitor);
- }
- }
- }
- }
-
- /**
- * Write a textual representation of this entry to the given [buffer]. The
- * result should only be used for debugging purposes.
- */
- void _writeOn(StringBuffer buffer) {
- buffer.write('time = ');
- buffer.write(modificationTime);
- List<ResultDescriptor> results = _resultMap.keys.toList();
- results.sort((ResultDescriptor first, ResultDescriptor second) =>
- first.toString().compareTo(second.toString()));
- for (ResultDescriptor result in results) {
- ResultData data = _resultMap[result];
- buffer.write('; ');
- buffer.write(result.toString());
- buffer.write(' = ');
- buffer.write(data.state);
- }
- }
-}
-
-/**
- * An object that controls flushing of analysis results from the cache.
- */
-class CacheFlushManager<T> {
- final IsPriorityAnalysisTarget isPriorityAnalysisTarget;
- final ResultCachingPolicy policy;
- final int maxActiveSize;
- final int maxIdleSize;
-
- /**
- * A map of the stored [TargetedResult] to their sizes.
- */
- final HashMap<TargetedResult, int> resultSizeMap =
- new HashMap<TargetedResult, int>();
-
- /**
- * A linked set containing the most recently accessed results with the most
- * recently used at the end of the list. When more results are added than the
- * maximum size allowed then the least recently used results will be flushed
- * from the cache.
- */
- final LinkedHashSet<TargetedResult> recentlyUsed =
- new LinkedHashSet<TargetedResult>();
-
- /**
- * The current size of stored results.
- */
- int currentSize = 0;
-
- /**
- * The current maximum cache size.
- */
- int maxSize;
-
- CacheFlushManager(ResultCachingPolicy policy, this.isPriorityAnalysisTarget)
- : policy = policy,
- maxActiveSize = policy.maxActiveSize,
- maxIdleSize = policy.maxIdleSize,
- maxSize = policy.maxActiveSize;
-
- /**
- * If [currentSize] is already less than [maxSize], returns an empty list.
- * Otherwise returns [TargetedResult]s to flush from the cache to make
- * [currentSize] less or equal to [maxSize].
- *
- * Results for priority files are never flushed, so this method might leave
- * [currentSize] greater than [maxSize].
- */
- List<TargetedResult> flushToSize() {
- // If still under the cap, done.
- if (currentSize <= maxSize) {
- return const <TargetedResult>[];
- }
- // Flush results until we are under the cap.
- List<TargetedResult> resultsToFlush = <TargetedResult>[];
- for (TargetedResult result in recentlyUsed) {
- if (isPriorityAnalysisTarget(result.target)) {
- continue;
- }
- resultsToFlush.add(result);
- int size = resultSizeMap.remove(result);
- assert(size != null);
- currentSize -= size;
- if (currentSize <= maxSize) {
- break;
- }
- }
- recentlyUsed.removeAll(resultsToFlush);
- return resultsToFlush;
- }
-
- /**
- * Notifies this manager that the corresponding analysis context is active.
- */
- void madeActive() {
- maxSize = maxActiveSize;
- }
-
- /**
- * Notifies this manager that the corresponding analysis context is idle.
- * Returns [TargetedResult]s that should be flushed from the cache.
- */
- List<TargetedResult> madeIdle() {
- maxSize = maxIdleSize;
- return flushToSize();
- }
-
- /**
- * Records that the given [result] was just read from the cache.
- */
- void resultAccessed(TargetedResult result) {
- if (recentlyUsed.remove(result)) {
- recentlyUsed.add(result);
- }
- }
-
- /**
- * Records that the given [newResult] and [newValue] were stored to the cache.
- * Returns [TargetedResult]s that should be flushed from the cache.
- */
- List<TargetedResult> resultStored(TargetedResult newResult, T newValue) {
- if (!recentlyUsed.remove(newResult)) {
- int size = policy.measure(newValue);
- resultSizeMap[newResult] = size;
- currentSize += size;
- }
- recentlyUsed.add(newResult);
- return flushToSize();
- }
-
- /**
- * Records that the given [target] was just removed from to the cache.
- */
- void targetRemoved(AnalysisTarget target) {
- List<TargetedResult> resultsToRemove = <TargetedResult>[];
- for (TargetedResult result in recentlyUsed) {
- if (result.target == target) {
- resultsToRemove.add(result);
- int size = resultSizeMap.remove(result);
- assert(size != null);
- currentSize -= size;
- }
- }
- recentlyUsed.removeAll(resultsToRemove);
- }
-}
-
-/**
- * A single partition in an LRU cache of information related to analysis.
- */
abstract class CachePartition {
- /**
- * The context that owns this partition. Multiple contexts can reference a
- * partition, but only one context can own it.
- */
final InternalAnalysisContext context;
-
- /**
- * A list of the caches that contain this partition. This includes the cache
- * associated with the context that owns this partition.
- */
- final List<AnalysisCache> containingCaches = <AnalysisCache>[];
-
- /**
- * A table mapping caching policies to the cache flush managers.
- */
- final HashMap<ResultCachingPolicy, CacheFlushManager> _flushManagerMap =
- new HashMap<ResultCachingPolicy, CacheFlushManager>();
-
- /**
- * The [StreamController] reporting [InvalidatedResult]s.
- */
- final ReentrantSynchronousStream<InvalidatedResult> onResultInvalidated =
- new ReentrantSynchronousStream<InvalidatedResult>();
-
- /**
- * A table mapping the targets belonging to this partition to the information
- * known about those targets.
- */
- final HashMap<AnalysisTarget, CacheEntry> entryMap =
- new HashMap<AnalysisTarget, CacheEntry>();
-
- /**
- * A set of the [Source] targets.
- */
- final HashSet<Source> sources = new HashSet<Source>();
-
- /**
- * A table mapping full paths to lists of [Source]s with these full paths.
- */
- final Map<String, List<Source>> pathToSource = <String, List<Source>>{};
-
- /**
- * Initialize a newly created cache partition, belonging to the given
- * [context].
- */
CachePartition(this.context);
-
- /**
- * Specify whether a context that uses this partition is being analyzed.
- */
- set isActive(bool active) {
- for (CacheFlushManager manager in _flushManagerMap.values) {
- if (active) {
- manager.madeActive();
- } else {
- List<TargetedResult> resultsToFlush = manager.madeIdle();
- _flushResults(resultsToFlush);
- }
- }
- }
-
- /**
- * Notifies the partition that the client is going to stop using it.
- */
- void dispose() {
- for (CacheEntry entry in entryMap.values) {
- entry.dispose();
- }
- entryMap.clear();
- sources.clear();
- pathToSource.clear();
- }
-
- /**
- * Flush results that satisfy the given [filter].
- */
- void flush(FlushResultFilter filter) {
- for (CacheEntry entry in entryMap.values) {
- entry.flush(filter);
- }
- }
-
- /**
- * Return the entry associated with the given [target].
- */
- CacheEntry get(AnalysisTarget target) => entryMap[target];
-
- /**
- * Return [Source]s whose full path is equal to the given [path].
- * Maybe empty, but not `null`.
- */
- List<Source> getSourcesWithFullName(String path) {
- List<Source> sources = pathToSource[path];
- return sources ?? const <Source>[];
- }
-
- /**
- * Return `true` if this partition is responsible for the given [target].
- */
- bool isResponsibleFor(AnalysisTarget target);
-
- /**
- * Return an iterator returning all of the map entries mapping targets to
- * cache entries.
- */
- MapIterator<AnalysisTarget, CacheEntry> iterator() =>
- new SingleMapIterator<AnalysisTarget, CacheEntry>(entryMap);
-
- /**
- * Puts the given [entry] into the partition.
- */
- void put(CacheEntry entry) {
- AnalysisTarget target = entry.target;
- if (entry._partition != null) {
- throw new StateError(
- 'The entry for $target is already in ${entry._partition}');
- }
- entry._partition = this;
- entry.fixExceptionState();
- entryMap[target] = entry;
- _addIfSource(target);
- }
-
- /**
- * Remove all information related to the given [target] from this partition.
- * Return the entry associated with the target, or `null` if there was cache
- * entry for the target.
- */
- CacheEntry remove(AnalysisTarget target) {
- for (CacheFlushManager flushManager in _flushManagerMap.values) {
- flushManager.targetRemoved(target);
- }
- CacheEntry entry = entryMap.remove(target);
- if (entry != null) {
- entry._invalidateAll();
- }
- _removeIfSource(target);
- return entry;
- }
-
- /**
- * Records that a value of the result described by the given [descriptor]
- * for the given [target] was just read from the cache.
- */
- void resultAccessed(AnalysisTarget target, ResultDescriptor descriptor) {
- CacheFlushManager flushManager = _getFlushManager(descriptor);
- TargetedResult result = new TargetedResult(target, descriptor);
- flushManager.resultAccessed(result);
- }
-
- /**
- * Records that the given [result] was just stored into the cache.
- */
- void resultStored(TargetedResult result, Object value) {
- CacheFlushManager flushManager = _getFlushManager(result.result);
- List<TargetedResult> resultsToFlush =
- flushManager.resultStored(result, value);
- _flushResults(resultsToFlush);
- }
-
- /**
- * Return the number of targets that are mapped to cache entries.
- */
- int size() => entryMap.length;
-
- /**
- * If the given [target] is a [Source], adds it to [sources].
- */
- void _addIfSource(AnalysisTarget target) {
- if (target is Source) {
- sources.add(target);
- String fullName = target.fullName;
- pathToSource.putIfAbsent(fullName, () => <Source>[]).add(target);
- }
- }
-
- /**
- * Flush the given [resultsToFlush].
- */
- void _flushResults(List<TargetedResult> resultsToFlush) {
- for (TargetedResult result in resultsToFlush) {
- CacheEntry entry = get(result.target);
- if (entry != null) {
- ResultData data = entry._resultMap[result.result];
- if (data != null) {
- data.flush();
- }
- }
- }
- }
-
- /**
- * Return the [CacheFlushManager] for the given [descriptor], not `null`.
- */
- CacheFlushManager _getFlushManager(ResultDescriptor descriptor) {
- ResultCachingPolicy policy = descriptor.cachingPolicy;
- if (identical(policy, DEFAULT_CACHING_POLICY) ||
- context.analysisOptions.disableCacheFlushing) {
- return UnlimitedCacheFlushManager.INSTANCE;
- }
- CacheFlushManager manager = _flushManagerMap[policy];
- if (manager == null) {
- manager = new CacheFlushManager(policy, _isPriorityAnalysisTarget);
- _flushManagerMap[policy] = manager;
- }
- return manager;
- }
-
- bool _isPriorityAnalysisTarget(AnalysisTarget target) {
- Source source = target.source;
- return source != null && context.prioritySources.contains(source);
- }
-
- /**
- * If the given [target] is a [Source], remove it from the list of [sources].
- */
- void _removeIfSource(AnalysisTarget target) {
- if (target is Source) {
- sources.remove(target);
- String path = target.fullName;
- List<Source> pathSources = pathToSource[path];
- if (pathSources != null) {
- pathSources.remove(target);
- if (pathSources.isEmpty) {
- pathToSource.remove(path);
- }
- }
- }
- }
}
-/**
- * The description for a change.
- */
-class Delta {
- final Source source;
-
- Delta(this.source);
-
- /**
- * Return `true` if this delta needs cache walking to gather additional
- * changes before it can be used to [validate]. In this case [gatherChanges]
- * is invoked for every targeted result in transitive dependencies, and
- * [gatherEnd] is invoked after cache walking is done.
- */
- bool get shouldGatherChanges => false;
-
- /**
- * This method is called during a cache walk, so that the delta can gather
- * additional changes to which are caused by the changes it already knows
- * about. Return `true` if a new change was added, so that one more cache
- * walk will be performed (to include changes that depend on results which we
- * decided to be changed later in the previous cache walk).
- */
- bool gatherChanges(InternalAnalysisContext context, AnalysisTarget target,
- ResultDescriptor descriptor, Object value) {
- return false;
- }
-
- /**
- * The current cache results visit is done.
- */
- void gatherEnd() {}
-
- /**
- * Check whether this delta affects the result described by the given
- * [descriptor] and [target]. The current [value] of the result is provided.
- */
- DeltaResult validate(InternalAnalysisContext context, AnalysisTarget target,
- ResultDescriptor descriptor, Object value) {
- return DeltaResult.INVALIDATE;
- }
-}
-
-/**
- * The possible results of validating analysis results against a [Delta].
- */
-enum DeltaResult {
- /**
- * Invalidate this result and continue visiting dependent results
- * with this [Delta]. Remove the result and all its dependencies.
- */
- INVALIDATE,
-
- /**
- * Invalidate this result and continue visiting dependent results
- * with this [Delta]. Keep the dependencies of this result.
- */
- INVALIDATE_KEEP_DEPENDENCIES,
-
- /**
- * Invalidate this result and stop using this [Delta], so unconditionally
- * invalidate all the dependent results.
- */
- INVALIDATE_NO_DELTA,
-
- /**
- * Keep this result and continue validating dependent results
- * with this [Delta].
- */
- KEEP_CONTINUE,
-
- /**
- * Keep this result and stop visiting results that depend on this one.
- */
- STOP
-}
-
-/**
- * [InvalidatedResult] describes an invalidated result.
- */
-class InvalidatedResult<V> {
- /**
- * The target in which the result was invalidated.
- */
- final CacheEntry entry;
-
- /**
- * The descriptor of the result which was invalidated.
- */
- final ResultDescriptor<V> descriptor;
-
- /**
- * The value of the result before it was invalidated, may be the default
- * value if the result was flushed.
- */
- final V value;
-
- InvalidatedResult(this.entry, this.descriptor, this.value);
-
- @override
- String toString() => '$descriptor of ${entry.target}';
-}
-
-/**
- * A cache partition that contains all of the targets in a single package.
- */
-class PackageCachePartition extends CachePartition {
- /**
- * The root of the directory representing the package.
- */
- final Folder packageRoot;
-
- /**
- * Initialize a newly created cache partition, belonging to the given
- * [context].
- */
- PackageCachePartition(InternalAnalysisContext context, this.packageRoot)
- : super(context);
-
- @override
- bool isResponsibleFor(AnalysisTarget target) {
- Source source = target.source;
- return source != null && packageRoot.contains(source.fullName);
- }
-}
-
-/**
- * A Stream-like interface, which broadcasts events synchronously.
- * If a second event is fired while delivering a first event, then the second
- * event will be delivered first, and then delivering of the first will be
- * continued.
- */
-class ReentrantSynchronousStream<T> {
- final List<Function> listeners = <Function>[];
-
- /**
- * Send the given [event] to the stream.
- */
- void add(T event) {
- List<Function> listeners = this.listeners.toList();
- for (Function listener in listeners) {
- listener(event);
- }
- }
-
- /**
- * Listen for the events in this stream.
- * Note that if the [listener] fires a new event, then the [listener] will be
- * invoked again before returning from the [add] invocation.
- */
- ReentrantSynchronousStreamSubscription<T> listen(void listener(T event)) {
- listeners.add(listener);
- return new ReentrantSynchronousStreamSubscription<T>(this, listener);
- }
-}
-
-/**
- * A subscription on events from a [ReentrantSynchronousStream].
- */
-class ReentrantSynchronousStreamSubscription<T> {
- final ReentrantSynchronousStream<T> _stream;
- final Function _listener;
-
- ReentrantSynchronousStreamSubscription(this._stream, this._listener);
-
- /**
- * Cancels this subscription.
- * It will no longer receive events.
- */
- void cancel() {
- _stream.listeners.remove(_listener);
- }
-}
-
-/**
- * The data about a single analysis result that is stored in a [CacheEntry].
- */
-// TODO(brianwilkerson) Consider making this a generic class so that the value
-// can be typed.
-class ResultData {
- /**
- * The [ResultDescriptor] this result is for.
- */
- final ResultDescriptor descriptor;
-
- /**
- * The state of the cached value.
- */
- CacheState state;
-
- /**
- * The value being cached, or the default value for the result if there is no
- * value (for example, when the [state] is [CacheState.INVALID]).
- */
- Object value;
-
- /**
- * The identifier of the most recent visiting process. We use it to visit
- * every result only once.
- */
- int visitId = -1;
-
- /**
- * A list of the results on which this result depends.
- */
- List<TargetedResult> dependedOnResults = <TargetedResult>[];
-
- /**
- * A list of the results that depend on this result.
- */
- Set<TargetedResult> dependentResults = new Set<TargetedResult>();
-
- /**
- * Initialize a newly created result holder to represent the value of data
- * described by the given [descriptor].
- */
- ResultData(this.descriptor) {
- state = CacheState.INVALID;
- value = descriptor.defaultValue;
- }
-
- /**
- * Flush this value.
- */
- void flush() {
- state = CacheState.FLUSHED;
- value = descriptor.defaultValue;
- }
-}
-
-/**
- * A cache partition that contains all of the targets in the SDK.
- */
class SdkCachePartition extends CachePartition {
- /**
- * Initialize a newly created cache partition, belonging to the given
- * [context].
- */
SdkCachePartition(InternalAnalysisContext context) : super(context);
-
- @override
- bool isResponsibleFor(AnalysisTarget target) {
- if (target is AnalysisContextTarget) {
- return true;
- }
- Source source = target.source;
- return source != null && source.isInSystemLibrary;
- }
-}
-
-/**
- * A cache partition that contains all targets not contained in other partitions.
- */
-class UniversalCachePartition extends CachePartition {
- /**
- * Initialize a newly created cache partition, belonging to the given
- * [context].
- */
- UniversalCachePartition(InternalAnalysisContext context) : super(context);
-
- @override
- bool isResponsibleFor(AnalysisTarget target) => true;
-}
-
-/**
- * [CacheFlushManager] that does nothing, results are never flushed.
- */
-class UnlimitedCacheFlushManager extends CacheFlushManager {
- static final CacheFlushManager INSTANCE = new UnlimitedCacheFlushManager();
-
- UnlimitedCacheFlushManager() : super(DEFAULT_CACHING_POLICY, (_) => false);
-
- @override
- void resultAccessed(TargetedResult result) {}
-
- @override
- List<TargetedResult> resultStored(TargetedResult newResult, newValue) {
- return const <TargetedResult>[];
- }
-
- @override
- void targetRemoved(AnalysisTarget target) {}
}
diff --git a/pkg/analyzer/lib/src/context/context.dart b/pkg/analyzer/lib/src/context/context.dart
index 418bb41..876243d 100644
--- a/pkg/analyzer/lib/src/context/context.dart
+++ b/pkg/analyzer/lib/src/context/context.dart
@@ -17,7 +17,6 @@
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/plugin/resolver_provider.dart';
import 'package:analyzer/src/task/api/model.dart';
-import 'package:analyzer/src/task/driver.dart';
/**
* An [AnalysisContext] in which analysis can be performed.
@@ -46,23 +45,6 @@
*/
DeclaredVariables _declaredVariables = new DeclaredVariables();
- @override
- final ReentrantSynchronousStream<InvalidatedResult> onResultInvalidated =
- new ReentrantSynchronousStream<InvalidatedResult>();
-
- ReentrantSynchronousStreamSubscription onResultInvalidatedSubscription = null;
-
- /**
- * A list of all [WorkManager]s used by this context.
- */
- @override
- final List<WorkManager> workManagers = <WorkManager>[];
-
- /**
- * The analysis driver used to perform analysis.
- */
- AnalysisDriver driver;
-
/**
* The [TypeProvider] for this context, `null` if not yet created.
*/
@@ -198,11 +180,6 @@
}
@override
- Stream<SourcesChangedEvent> get onSourcesChanged {
- throw UnimplementedError();
- }
-
- @override
List<Source> get prioritySources {
throw UnimplementedError();
}
@@ -263,11 +240,6 @@
}
@override
- bool aboutToComputeResult(CacheEntry entry, ResultDescriptor result) {
- throw UnimplementedError();
- }
-
- @override
void addListener(AnalysisListener listener) {
throw UnimplementedError();
}
@@ -323,11 +295,6 @@
throw UnimplementedError();
}
- @override
- V computeResult<V>(AnalysisTarget target, ResultDescriptor<V> descriptor) {
- throw UnimplementedError();
- }
-
/**
* Create an analysis cache based on the given source [factory].
*/
@@ -349,22 +316,11 @@
}
@override
- CacheEntry getCacheEntry(AnalysisTarget target) {
- throw UnimplementedError();
- }
-
- @override
CompilationUnitElement getCompilationUnitElement(
Source unitSource, Source librarySource) {
throw UnimplementedError();
}
- @deprecated
- @override
- V getConfigurationData<V>(ResultDescriptor<V> key) {
- throw UnimplementedError();
- }
-
@override
TimestampedData<String> getContents(Source source) {
throw UnimplementedError();
@@ -456,11 +412,6 @@
}
@override
- V getResult<V>(AnalysisTarget target, ResultDescriptor<V> result) {
- throw UnimplementedError();
- }
-
- @override
List<Source> getSourcesWithFullName(String path) {
throw UnimplementedError();
}
@@ -495,17 +446,6 @@
}
@override
- Stream<ResultChangedEvent> onResultChanged(ResultDescriptor descriptor) {
- throw UnimplementedError();
- }
-
- @override
- @deprecated
- Stream<ComputedResult> onResultComputed(ResultDescriptor descriptor) {
- throw UnimplementedError();
- }
-
- @override
CompilationUnit parseCompilationUnit(Source source) {
throw UnimplementedError();
}
@@ -543,12 +483,6 @@
throw UnimplementedError();
}
- @deprecated
- @override
- void setConfigurationData(ResultDescriptor key, Object data) {
- throw UnimplementedError();
- }
-
@override
void setContents(Source source, String contents) {
throw UnimplementedError();
diff --git a/pkg/analyzer/lib/src/dart/analysis/ddc.dart b/pkg/analyzer/lib/src/dart/analysis/ddc.dart
index ef6dceb..f526171 100644
--- a/pkg/analyzer/lib/src/dart/analysis/ddc.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/ddc.dart
@@ -10,6 +10,7 @@
import 'package:analyzer/src/dart/analysis/file_state.dart';
import 'package:analyzer/src/dart/analysis/restricted_analysis_context.dart';
import 'package:analyzer/src/dart/analysis/session.dart';
+import 'package:analyzer/src/dart/element/type_provider.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
@@ -20,7 +21,6 @@
import 'package:analyzer/src/summary/resynthesize.dart';
import 'package:analyzer/src/summary/summarize_ast.dart';
import 'package:analyzer/src/summary/summarize_elements.dart';
-import 'package:analyzer/src/summary/summary_sdk.dart';
import 'package:analyzer/src/summary2/informative_data.dart';
import 'package:analyzer/src/summary2/link.dart' as summary2;
import 'package:analyzer/src/summary2/linked_bundle_context.dart' as summary2;
@@ -247,9 +247,7 @@
var dartCore = elementFactory.libraryOfUri('dart:core');
var dartAsync = elementFactory.libraryOfUri('dart:async');
- var typeProvider = SummaryTypeProvider()
- ..initializeCore(dartCore)
- ..initializeAsync(dartAsync);
+ var typeProvider = TypeProviderImpl(dartCore, dartAsync);
context.typeProvider = typeProvider;
dartCore.createLoadLibraryFunction(typeProvider);
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index d9adea9..a637158 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -96,7 +96,7 @@
static int allowedNumberOfContextsToWrite = 10;
/// Whether summary2 should be used to resynthesize elements.
- static bool useSummary2 = false;
+ static bool useSummary2 = true;
/// The scheduler that schedules analysis work in this, and possibly other
/// analysis drivers.
diff --git a/pkg/analyzer/lib/src/dart/analysis/index.dart b/pkg/analyzer/lib/src/dart/analysis/index.dart
index 8d45ba7..02b4b51 100644
--- a/pkg/analyzer/lib/src/dart/analysis/index.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/index.dart
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
@@ -555,10 +554,7 @@
visitClassDeclaration(ClassDeclaration node) {
_addSubtypeForClassDeclaration(node);
if (node.extendsClause == null) {
- ClassElement objectElement = resolutionMap
- .elementDeclaredByClassDeclaration(node)
- .supertype
- ?.element;
+ ClassElement objectElement = node.declaredElement.supertype?.element;
recordRelationOffset(objectElement, IndexRelationKind.IS_EXTENDED_BY,
node.name.offset, 0, true);
}
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
index 3a8ad34..a8c8650 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -22,6 +22,8 @@
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/handle.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/resolver/ast_rewrite.dart';
import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
import 'package:analyzer/src/dart/resolver/legacy_type_asserter.dart';
@@ -68,7 +70,7 @@
final AnalysisContext _context;
final ElementResynthesizer _resynthesizer;
final LinkedElementFactory _elementFactory;
- TypeProvider _typeProvider;
+ TypeProviderImpl _typeProvider;
final TypeSystem _typeSystem;
LibraryElement _libraryElement;
@@ -134,13 +136,9 @@
FeatureSet featureSet = units[_library].featureSet;
_typeProvider = _context.typeProvider;
if (featureSet.isEnabled(Feature.non_nullable)) {
- if (_typeProvider is! NonNullableTypeProvider) {
- _typeProvider = NonNullableTypeProvider.from(_typeProvider);
- }
+ _typeProvider = _typeProvider.withNullability(NullabilitySuffix.none);
} else {
- if (_typeProvider is NonNullableTypeProvider) {
- _typeProvider = TypeProviderImpl.from(_typeProvider);
- }
+ _typeProvider = _typeProvider.withNullability(NullabilitySuffix.star);
}
units.forEach((file, unit) {
_validateFeatureSet(unit, featureSet);
@@ -537,11 +535,10 @@
directive.prefix?.staticElement = importElement.prefix;
Source source = importElement.importedLibrary?.source;
if (source != null && !_isLibrarySource(source)) {
- ErrorCode errorCode = importElement.isDeferred
- ? StaticWarningCode.IMPORT_OF_NON_LIBRARY
- : CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY;
libraryErrorReporter.reportErrorForNode(
- errorCode, directive.uri, [directive.uri]);
+ CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY,
+ directive.uri,
+ [directive.uri]);
}
}
}
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_context.dart b/pkg/analyzer/lib/src/dart/analysis/library_context.dart
index 99bfc35..56a3aed 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_context.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_context.dart
@@ -15,6 +15,7 @@
import 'package:analyzer/src/dart/analysis/session.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
+import 'package:analyzer/src/dart/element/type_provider.dart';
import 'package:analyzer/src/generated/engine.dart'
show AnalysisContext, AnalysisOptions;
import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
@@ -24,7 +25,6 @@
import 'package:analyzer/src/summary/link.dart';
import 'package:analyzer/src/summary/package_bundle_reader.dart';
import 'package:analyzer/src/summary/resynthesize.dart';
-import 'package:analyzer/src/summary/summary_sdk.dart';
import 'package:analyzer/src/summary2/link.dart' as link2;
import 'package:analyzer/src/summary2/linked_bundle_context.dart';
import 'package:analyzer/src/summary2/linked_element_factory.dart';
@@ -416,9 +416,7 @@
var dartCore = elementFactory.libraryOfUri('dart:core');
var dartAsync = elementFactory.libraryOfUri('dart:async');
- var typeProvider = SummaryTypeProvider()
- ..initializeCore(dartCore)
- ..initializeAsync(dartAsync);
+ var typeProvider = TypeProviderImpl(dartCore, dartAsync);
analysisContext.typeProvider = typeProvider;
dartCore.createLoadLibraryFunction(typeProvider);
diff --git a/pkg/analyzer/lib/src/dart/analysis/results.dart b/pkg/analyzer/lib/src/dart/analysis/results.dart
index 9da05f9..da2e4d0 100644
--- a/pkg/analyzer/lib/src/dart/analysis/results.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/results.dart
@@ -290,6 +290,12 @@
}
}
}
+ } else if (element is ExtensionElement) {
+ if (node is ExtensionDeclaration) {
+ if (_hasOffset(node.name)) {
+ result = node;
+ }
+ }
} else if (element is FieldElement) {
if (node is EnumConstantDeclaration) {
if (_hasOffset(node.name)) {
diff --git a/pkg/analyzer/lib/src/dart/analysis/session.dart b/pkg/analyzer/lib/src/dart/analysis/session.dart
index 6b75d09..2857311 100644
--- a/pkg/analyzer/lib/src/dart/analysis/session.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/session.dart
@@ -13,6 +13,7 @@
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/dart/analysis/driver.dart' as driver;
import 'package:analyzer/src/dart/analysis/uri_converter.dart';
+import 'package:analyzer/src/dart/element/type_provider.dart';
import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/source.dart';
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index fc942c1..2b09546 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -9189,6 +9189,10 @@
}
@override
+ bool get isNullAware =>
+ spreadOperator.type == TokenType.PERIOD_PERIOD_PERIOD_QUESTION;
+
+ @override
E accept<E>(AstVisitor<E> visitor) {
return visitor.visitSpreadElement(this);
}
diff --git a/pkg/analyzer/lib/src/dart/constant/evaluation.dart b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
index 53e8356..dd26599 100644
--- a/pkg/analyzer/lib/src/dart/constant/evaluation.dart
+++ b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
@@ -111,7 +111,7 @@
if (arguments[0] is NamedExpression) {
return false;
}
- if (!identical(argumentValues[0].type, typeProvider.stringType)) {
+ if (argumentValues[0].type != typeProvider.stringType) {
return false;
}
if (argumentCount == 2) {
@@ -122,8 +122,8 @@
}
ParameterizedType defaultValueType =
namedArgumentValues[_DEFAULT_VALUE_PARAM].type;
- if (!(identical(defaultValueType, expectedDefaultValueType) ||
- identical(defaultValueType, typeProvider.nullType))) {
+ if (!(defaultValueType == expectedDefaultValueType ||
+ defaultValueType == typeProvider.nullType)) {
return false;
}
} else {
@@ -148,7 +148,7 @@
if (arguments[0] is NamedExpression) {
return false;
}
- if (!identical(argumentValues[0].type, typeProvider.stringType)) {
+ if (argumentValues[0].type != typeProvider.stringType) {
return false;
}
String name = argumentValues[0].toStringValue();
@@ -831,7 +831,7 @@
if (!constructor.isFactory) {
return null;
}
- if (identical(constructor.enclosingElement.type, typeProvider.symbolType)) {
+ if (constructor.enclosingElement.type == typeProvider.symbolType) {
// The dart:core.Symbol has a const factory constructor that redirects
// to dart:_internal.Symbol. That in turn redirects to an external
// const constructor, which we won't be able to evaluate.
diff --git a/pkg/analyzer/lib/src/dart/constant/utilities.dart b/pkg/analyzer/lib/src/dart/constant/utilities.dart
index e99b3c5..225fb0a 100644
--- a/pkg/analyzer/lib/src/dart/constant/utilities.dart
+++ b/pkg/analyzer/lib/src/dart/constant/utilities.dart
@@ -5,7 +5,6 @@
import 'dart:collection';
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
@@ -226,9 +225,7 @@
@override
void visitClassDeclaration(ClassDeclaration node) {
bool prevTreatFinalInstanceVarAsConst = treatFinalInstanceVarAsConst;
- if (resolutionMap
- .elementDeclaredByClassDeclaration(node)
- .constructors
+ if (node.declaredElement.constructors
.any((ConstructorElement e) => e.isConst)) {
// Instance vars marked "final" need to be included in the dependency
// graph, since constant constructors implicitly use the values in their
@@ -259,8 +256,7 @@
super.visitDefaultFormalParameter(node);
Expression defaultValue = node.defaultValue;
if (defaultValue != null && node.declaredElement != null) {
- constantsToCompute
- .add(resolutionMap.elementDeclaredByFormalParameter(node));
+ constantsToCompute.add(node.declaredElement);
}
}
diff --git a/pkg/analyzer/lib/src/dart/element/builder.dart b/pkg/analyzer/lib/src/dart/element/builder.dart
index 9d3103e..b6c9ab4 100644
--- a/pkg/analyzer/lib/src/dart/element/builder.dart
+++ b/pkg/analyzer/lib/src/dart/element/builder.dart
@@ -992,11 +992,8 @@
offset = uriLiteral.offset;
length = uriLiteral.length;
}
- ErrorCode errorCode = importElement.isDeferred
- ? StaticWarningCode.IMPORT_OF_NON_LIBRARY
- : CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY;
errors.add(new AnalysisError(libraryElement.source, offset, length,
- errorCode, [uriLiteral.toSource()]));
+ CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY, [uriLiteral.toSource()]));
}
}
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 8cf7577..59e5cff 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -2786,6 +2786,16 @@
appendToWithName(buffer, name);
}
+ /// Ensures that dependencies of this constructor, such as default values
+ /// of formal parameters, are evaluated.
+ void computeConstantDependencies() {
+ if (!isConstantEvaluated) {
+ AnalysisOptionsImpl analysisOptions = context.analysisOptions;
+ computeConstants(context.typeProvider, context.typeSystem,
+ context.declaredVariables, [this], analysisOptions.experimentStatus);
+ }
+ }
+
@deprecated
@override
ConstructorDeclaration computeNode() =>
@@ -7526,50 +7536,6 @@
return getTypeFromParts(className, _definingCompilationUnit, _parts);
}
- /// Given an update to this library which may have added or deleted edges
- /// in the import/export graph originating from this node only, remove any
- /// cached library cycles in the element model which may have been
- /// invalidated.
- void invalidateLibraryCycles() {
- // If we have pre-computed library cycle information, then we must
- // invalidate the information both on this element, and on certain
- // other elements. Edges originating at this node may have been
- // added or deleted. A deleted edge that points outside of this cycle
- // cannot change the cycle information for anything outside of this cycle,
- // and so it is sufficient to delete the cached library information on this
- // cycle. An added edge which points to another node within the cycle
- // only invalidates the cycle. An added edge which points to a node earlier
- // in the topological sort of cycles induces no invalidation (since there
- // are by definition no back edges from earlier cycles in the topological
- // order, and hence no possible cycle can have been introduced. The only
- // remaining case is that we have added an edge to a node which is later
- // in the topological sort of cycles. This can induce cycles, since it
- // represents a new back edge. It would be sufficient to invalidate the
- // cycle information for all nodes that are between the target and the
- // node in the topological order. For simplicity, we simply invalidate
- // all nodes which are reachable from the source node.
- // Note that in the invalidation phase, we do not cut off when we encounter
- // a node with no library cycle information, since we do not know whether
- // we are in the case where invalidation has already been performed, or we
- // are in the case where library cycles have simply never been computed from
- // a newly reachable node.
- Set<LibraryElementImpl> active = new HashSet();
- void invalidate(LibraryElement element) {
- LibraryElementImpl library =
- element is LibraryElementHandle ? element.actualElement : element;
- if (active.add(library)) {
- if (library._libraryCycle != null) {
- library._libraryCycle.forEach(invalidate);
- library._libraryCycle = null;
- }
- library.exportedLibraries.forEach(invalidate);
- library.importedLibraries.forEach(invalidate);
- }
- }
-
- invalidate(this);
- }
-
/// Set whether the library has the given [capability] to
/// correspond to the given [value].
void setResolutionCapability(
@@ -8915,6 +8881,9 @@
bool get isInitializingFormal => false;
@override
+ bool get isLate => false;
+
+ @override
bool get isPotentiallyMutatedInClosure => true;
@override
diff --git a/pkg/analyzer/lib/src/dart/element/handle.dart b/pkg/analyzer/lib/src/dart/element/handle.dart
index ab33e17..e13d565 100644
--- a/pkg/analyzer/lib/src/dart/element/handle.dart
+++ b/pkg/analyzer/lib/src/dart/element/handle.dart
@@ -993,9 +993,6 @@
super.actualElement as LocalVariableElement;
@override
- bool get isLate => actualElement.isLate;
-
- @override
ElementKind get kind => ElementKind.LOCAL_VARIABLE;
@override
@@ -1181,9 +1178,6 @@
@override
bool get isConstantEvaluated => actualElement.isConstantEvaluated;
- @override
- bool get isLate => actualElement.isLate;
-
@deprecated
@override
DartType get propagatedType => null;
@@ -1277,6 +1271,9 @@
@override
bool get isFinal => actualElement.isFinal;
+ @override
+ bool get isLate => actualElement.isLate;
+
@deprecated
@override
bool get isPotentiallyMutatedInClosure =>
diff --git a/pkg/analyzer/lib/src/dart/element/member.dart b/pkg/analyzer/lib/src/dart/element/member.dart
index d763f18..fda6a4d 100644
--- a/pkg/analyzer/lib/src/dart/element/member.dart
+++ b/pkg/analyzer/lib/src/dart/element/member.dart
@@ -297,9 +297,6 @@
@override
bool get isEnumConstant => baseElement.isEnumConstant;
- @override
- bool get isLate => baseElement.isLate;
-
@deprecated
@override
bool get isVirtual => baseElement.isVirtual;
@@ -343,6 +340,16 @@
Substitution.fromInterfaceType(definingType),
);
}
+
+ static FieldElement from2(
+ FieldElement element,
+ MapSubstitution substitution,
+ ) {
+ if (substitution.map.isEmpty) {
+ return element;
+ }
+ return FieldMember(element, substitution);
+ }
}
/**
@@ -646,6 +653,16 @@
Substitution.fromInterfaceType(definingType),
);
}
+
+ static MethodElement from2(
+ MethodElement element,
+ MapSubstitution substitution,
+ ) {
+ if (substitution.map.isEmpty) {
+ return element;
+ }
+ return MethodMember(element, substitution);
+ }
}
/**
@@ -1024,6 +1041,9 @@
bool get isFinal => baseElement.isFinal;
@override
+ bool get isLate => baseElement.isLate;
+
+ @override
@deprecated
bool get isPotentiallyMutatedInClosure =>
baseElement.isPotentiallyMutatedInClosure;
diff --git a/pkg/analyzer/lib/src/dart/element/type_provider.dart b/pkg/analyzer/lib/src/dart/element/type_provider.dart
new file mode 100644
index 0000000..0f4a101
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/element/type_provider.dart
@@ -0,0 +1,298 @@
+// Copyright (c) 2019, 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/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/constant/value.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+
+/// Provide common functionality shared by the various TypeProvider
+/// implementations.
+abstract class TypeProviderBase implements TypeProvider {
+ @override
+ List<InterfaceType> get nonSubtypableTypes => <InterfaceType>[
+ boolType,
+ doubleType,
+ intType,
+ nullType,
+ numType,
+ stringType
+ ];
+
+ @override
+ bool isObjectGetter(String id) {
+ PropertyAccessorElement element = objectType.element.getGetter(id);
+ return (element != null && !element.isStatic);
+ }
+
+ @override
+ bool isObjectMember(String id) {
+ return isObjectGetter(id) || isObjectMethod(id);
+ }
+
+ @override
+ bool isObjectMethod(String id) {
+ MethodElement element = objectType.element.getMethod(id);
+ return (element != null && !element.isStatic);
+ }
+}
+
+class TypeProviderImpl extends TypeProviderBase {
+ final NullabilitySuffix _nullabilitySuffix;
+ final LibraryElement _coreLibrary;
+ final LibraryElement _asyncLibrary;
+
+ InterfaceType _boolType;
+ InterfaceType _deprecatedType;
+ InterfaceType _doubleType;
+ InterfaceType _functionType;
+ InterfaceType _futureDynamicType;
+ InterfaceType _futureNullType;
+ InterfaceType _futureOrNullType;
+ InterfaceType _futureOrType;
+ InterfaceType _futureType;
+ InterfaceType _intType;
+ InterfaceType _iterableDynamicType;
+ InterfaceType _iterableObjectType;
+ InterfaceType _iterableType;
+ InterfaceType _listType;
+ InterfaceType _mapType;
+ InterfaceType _mapObjectObjectType;
+ DartObjectImpl _nullObject;
+ InterfaceType _nullType;
+ InterfaceType _numType;
+ InterfaceType _objectType;
+ InterfaceType _setType;
+ InterfaceType _stackTraceType;
+ InterfaceType _streamDynamicType;
+ InterfaceType _streamType;
+ InterfaceType _stringType;
+ InterfaceType _symbolType;
+ InterfaceType _typeType;
+
+ /// Initialize a newly created type provider to provide the types defined in
+ /// the given [coreLibrary] and [asyncLibrary].
+ TypeProviderImpl(
+ LibraryElement coreLibrary,
+ LibraryElement asyncLibrary, {
+ NullabilitySuffix nullabilitySuffix = NullabilitySuffix.star,
+ }) : _nullabilitySuffix = nullabilitySuffix,
+ _coreLibrary = coreLibrary,
+ _asyncLibrary = asyncLibrary;
+
+ @override
+ InterfaceType get boolType {
+ _boolType ??= _getType(_coreLibrary, "bool");
+ return _boolType;
+ }
+
+ @override
+ DartType get bottomType {
+ if (_nullabilitySuffix == NullabilitySuffix.none) {
+ return BottomTypeImpl.instance;
+ }
+ return BottomTypeImpl.instanceLegacy;
+ }
+
+ @override
+ InterfaceType get deprecatedType {
+ _deprecatedType ??= _getType(_coreLibrary, "Deprecated");
+ return _deprecatedType;
+ }
+
+ @override
+ InterfaceType get doubleType {
+ _doubleType ??= _getType(_coreLibrary, "double");
+ return _doubleType;
+ }
+
+ @override
+ DartType get dynamicType => DynamicTypeImpl.instance;
+
+ @override
+ InterfaceType get functionType {
+ _functionType ??= _getType(_coreLibrary, "Function");
+ return _functionType;
+ }
+
+ @override
+ InterfaceType get futureDynamicType {
+ _futureDynamicType ??= futureType.instantiate(<DartType>[dynamicType]);
+ return _futureDynamicType;
+ }
+
+ @override
+ InterfaceType get futureNullType {
+ _futureNullType ??= futureType.instantiate(<DartType>[nullType]);
+ return _futureNullType;
+ }
+
+ @override
+ InterfaceType get futureOrNullType {
+ _futureOrNullType ??= futureOrType.instantiate(<DartType>[nullType]);
+ return _futureOrNullType;
+ }
+
+ @override
+ InterfaceType get futureOrType {
+ _futureOrType ??= _getType(_asyncLibrary, "FutureOr");
+ return _futureOrType;
+ }
+
+ @override
+ InterfaceType get futureType {
+ _futureType ??= _getType(_asyncLibrary, "Future");
+ return _futureType;
+ }
+
+ @override
+ InterfaceType get intType {
+ _intType ??= _getType(_coreLibrary, "int");
+ return _intType;
+ }
+
+ @override
+ InterfaceType get iterableDynamicType {
+ _iterableDynamicType ??= iterableType.instantiate(<DartType>[dynamicType]);
+ return _iterableDynamicType;
+ }
+
+ @override
+ InterfaceType get iterableObjectType {
+ _iterableObjectType ??= iterableType.instantiate(<DartType>[objectType]);
+ return _iterableObjectType;
+ }
+
+ @override
+ InterfaceType get iterableType {
+ _iterableType ??= _getType(_coreLibrary, "Iterable");
+ return _iterableType;
+ }
+
+ @override
+ InterfaceType get listType {
+ _listType ??= _getType(_coreLibrary, "List");
+ return _listType;
+ }
+
+ @override
+ InterfaceType get mapObjectObjectType {
+ return _mapObjectObjectType ??=
+ mapType.instantiate(<DartType>[objectType, objectType]);
+ }
+
+ @override
+ InterfaceType get mapType {
+ _mapType ??= _getType(_coreLibrary, "Map");
+ return _mapType;
+ }
+
+ @override
+ DartType get neverType => BottomTypeImpl.instance;
+
+ @override
+ DartObjectImpl get nullObject {
+ if (_nullObject == null) {
+ _nullObject = new DartObjectImpl(nullType, NullState.NULL_STATE);
+ }
+ return _nullObject;
+ }
+
+ @override
+ InterfaceType get nullType {
+ _nullType ??= _getType(_coreLibrary, "Null");
+ return _nullType;
+ }
+
+ @override
+ InterfaceType get numType {
+ _numType ??= _getType(_coreLibrary, "num");
+ return _numType;
+ }
+
+ @override
+ InterfaceType get objectType {
+ _objectType ??= _getType(_coreLibrary, "Object");
+ return _objectType;
+ }
+
+ @override
+ InterfaceType get setType {
+ return _setType ??= _getType(_coreLibrary, "Set");
+ }
+
+ @override
+ InterfaceType get stackTraceType {
+ _stackTraceType ??= _getType(_coreLibrary, "StackTrace");
+ return _stackTraceType;
+ }
+
+ @override
+ InterfaceType get streamDynamicType {
+ _streamDynamicType ??= streamType.instantiate(<DartType>[dynamicType]);
+ return _streamDynamicType;
+ }
+
+ @override
+ InterfaceType get streamType {
+ _streamType ??= _getType(_asyncLibrary, "Stream");
+ return _streamType;
+ }
+
+ @override
+ InterfaceType get stringType {
+ _stringType ??= _getType(_coreLibrary, "String");
+ return _stringType;
+ }
+
+ @override
+ InterfaceType get symbolType {
+ _symbolType ??= _getType(_coreLibrary, "Symbol");
+ return _symbolType;
+ }
+
+ @override
+ InterfaceType get typeType {
+ _typeType ??= _getType(_coreLibrary, "Type");
+ return _typeType;
+ }
+
+ @override
+ VoidType get voidType => VoidTypeImpl.instance;
+
+ TypeProviderImpl withNullability(NullabilitySuffix nullabilitySuffix) {
+ if (_nullabilitySuffix == nullabilitySuffix) {
+ return this;
+ }
+ return TypeProviderImpl(_coreLibrary, _asyncLibrary,
+ nullabilitySuffix: nullabilitySuffix);
+ }
+
+ /// Return the type with the given [name] from the given [library], or
+ /// throw a [StateError] if there is no class with the given name.
+ InterfaceType _getType(LibraryElement library, String name) {
+ var element = library.getType(name);
+ if (element == null) {
+ throw StateError('No definition of type $name');
+ }
+
+ var typeArguments = const <DartType>[];
+ var typeParameters = element.typeParameters;
+ if (typeParameters.isNotEmpty) {
+ typeArguments = typeParameters.map((e) {
+ return TypeParameterTypeImpl(
+ e,
+ nullabilitySuffix: _nullabilitySuffix,
+ );
+ }).toList(growable: false);
+ }
+
+ return InterfaceTypeImpl.explicit(
+ element,
+ typeArguments,
+ nullabilitySuffix: _nullabilitySuffix,
+ );
+ }
+}
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
index ae53a87..76ba63d 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
@@ -3,12 +3,13 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/error/error.dart';
+import 'package:analyzer/src/error/analyzer_error_code.dart';
/**
* The hints and coding recommendations for best practices which are not
* mentioned in the Dart Language Specification.
*/
-class HintCode extends ErrorCode {
+class HintCode extends AnalyzerErrorCode {
/**
* When the target expression uses '?.' operator, it can be `null`, so all the
* subsequent invocations should also use '?.' operator.
@@ -82,7 +83,8 @@
static const HintCode DEPRECATED_MEMBER_USE = const HintCode(
'DEPRECATED_MEMBER_USE', "'{0}' is deprecated and shouldn't be used.",
correction: "Try replacing the use of the deprecated member with the "
- "replacement.");
+ "replacement.",
+ hasPublishedDocs: true);
/**
* Parameters:
@@ -112,7 +114,8 @@
const HintCode('DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE',
"'{0}' is deprecated and shouldn't be used.",
correction: "Try replacing the use of the deprecated member with the "
- "replacement.");
+ "replacement.",
+ hasPublishedDocs: true);
/**
* Users should not create a class named `Function` anymore.
@@ -308,7 +311,36 @@
// ```
static const HintCode INVALID_LITERAL_ANNOTATION = const HintCode(
'INVALID_LITERAL_ANNOTATION',
- "Only const constructors can have the `@literal` annotation.");
+ "Only const constructors can have the `@literal` annotation.",
+ hasPublishedDocs: true);
+
+ /**
+ * This hint is generated anywhere where `@required` annotates a named
+ * parameter with a default value.
+ *
+ * Parameters:
+ * 0: the name of the member
+ */
+ static const HintCode INVALID_REQUIRED_NAMED_PARAM = const HintCode(
+ 'INVALID_REQUIRED_NAMED_PARAM',
+ "The type parameter '{0}' is annotated with @required but only named "
+ "parameters without a default value can be annotated with it.",
+ correction: "Remove @required.");
+
+ /**
+ * This hint is generated anywhere where `@required` annotates an optional
+ * positional parameter.
+ *
+ * Parameters:
+ * 0: the name of the member
+ */
+ static const HintCode INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM =
+ const HintCode(
+ 'INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM',
+ "Incorrect use of the annotation @required on the optional "
+ "positional parameter '{0}'. Optional positional parameters "
+ "cannot be required.",
+ correction: "Remove @required.");
/**
* This hint is generated anywhere where `@required` annotates a non named
@@ -316,7 +348,12 @@
*
* Parameters:
* 0: the name of the member
+ *
+ * Deprecated: Use the more specific [INVALID_REQUIRED_NAMED_PARAM],
+ * [INVALID_REQUIRED_OPTIONAL_POSITION_PARAM], and
+ * [INVALID_REQUIRED_POSITION_PARAM]
*/
+ @deprecated
static const HintCode INVALID_REQUIRED_PARAM = const HintCode(
'INVALID_REQUIRED_PARAM',
"The type parameter '{0}' is annotated with @required but only named "
@@ -324,6 +361,19 @@
correction: "Remove @required.");
/**
+ * This hint is generated anywhere where `@required` annotates a non optional
+ * positional parameter.
+ *
+ * Parameters:
+ * 0: the name of the member
+ */
+ static const HintCode INVALID_REQUIRED_POSITIONAL_PARAM = const HintCode(
+ 'INVALID_REQUIRED_POSITIONAL_PARAM',
+ "Redundant use of the annotation @required on the required positional "
+ "parameter '{0}'.",
+ correction: "Remove @required.");
+
+ /**
* This hint is generated anywhere where `@sealed` annotates something other
* than a class.
*
@@ -485,7 +535,8 @@
"This function has a return type of '{0}', but doesn't end with a "
"return statement.",
correction: "Try adding a return statement, "
- "or changing the return type to 'void'.");
+ "or changing the return type to 'void'.",
+ hasPublishedDocs: true);
/**
* This hint is generated anywhere where a `@sealed` class is used as a
@@ -754,7 +805,8 @@
'SDK_VERSION_SET_LITERAL',
"Set literals weren't supported until version 2.2, but this code is "
"required to be able to run on earlier versions.",
- correction: "Try updating the SDK constraints.");
+ correction: "Try updating the SDK constraints.",
+ hasPublishedDocs: true);
/**
* The type Never is being used in code that is expected to run on versions of
@@ -929,7 +981,8 @@
// If the declaration was intended to be used, then add the missing code.
static const HintCode UNUSED_ELEMENT = const HintCode(
'UNUSED_ELEMENT', "The declaration '{0}' isn't referenced.",
- correction: "Try removing the declaration of '{0}'.");
+ correction: "Try removing the declaration of '{0}'.",
+ hasPublishedDocs: true);
/**
* Parameters:
@@ -957,7 +1010,8 @@
// If the field was intended to be used, then add the missing code.
static const HintCode UNUSED_FIELD = const HintCode(
'UNUSED_FIELD', "The value of the field '{0}' isn't used.",
- correction: "Try removing the field, or using it.");
+ correction: "Try removing the field, or using it.",
+ hasPublishedDocs: true);
/**
* Parameters:
@@ -976,8 +1030,7 @@
// ```dart
// import [!'dart:async'!];
//
- // void main() {
- // }
+ // void main() {}
// ```
//
// #### Common fixes
@@ -988,7 +1041,7 @@
// code.
static const HintCode UNUSED_IMPORT = const HintCode(
'UNUSED_IMPORT', "Unused import: '{0}'.",
- correction: "Try removing the import directive.");
+ correction: "Try removing the import directive.", hasPublishedDocs: true);
/**
* Unused labels are labels that are never referenced in either a 'break' or
@@ -1026,7 +1079,8 @@
static const HintCode UNUSED_LOCAL_VARIABLE = const HintCode(
'UNUSED_LOCAL_VARIABLE',
"The value of the local variable '{0}' isn't used.",
- correction: "Try removing the variable, or using it.");
+ correction: "Try removing the variable, or using it.",
+ hasPublishedDocs: true);
/**
* Unused shown names are names shown on imports which are never used.
diff --git a/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart b/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart
index a5d6149..5ad92c2 100644
--- a/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart
+++ b/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart
@@ -207,6 +207,15 @@
static const ParserErrorCode EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE =
_EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE;
+ static const ParserErrorCode EXTENSION_DECLARES_ABSTRACT_MEMBER =
+ _EXTENSION_DECLARES_ABSTRACT_MEMBER;
+
+ static const ParserErrorCode EXTENSION_DECLARES_CONSTRUCTOR =
+ _EXTENSION_DECLARES_CONSTRUCTOR;
+
+ static const ParserErrorCode EXTENSION_DECLARES_INSTANCE_FIELD =
+ _EXTENSION_DECLARES_INSTANCE_FIELD;
+
static const ParserErrorCode EXTERNAL_AFTER_CONST = _MODIFIER_OUT_OF_ORDER;
static const ParserErrorCode EXTERNAL_AFTER_FACTORY = _MODIFIER_OUT_OF_ORDER;
@@ -530,6 +539,9 @@
"Can't have both positional and named parameters in a single parameter list.",
correction: "Try choosing a single style of optional parameters.");
+ static const ParserErrorCode MIXIN_DECLARES_CONSTRUCTOR =
+ _MIXIN_DECLARES_CONSTRUCTOR;
+
static const ParserErrorCode MODIFIER_OUT_OF_ORDER = _MODIFIER_OUT_OF_ORDER;
static const ParserErrorCode MULTIPLE_EXTENDS_CLAUSES =
diff --git a/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart b/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
index ca2f7b9..abde3d8 100644
--- a/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
+++ b/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
@@ -99,6 +99,10 @@
_VAR_AND_TYPE,
_INVALID_INITIALIZER,
_ANNOTATION_WITH_TYPE_ARGUMENTS,
+ _EXTENSION_DECLARES_CONSTRUCTOR,
+ _EXTENSION_DECLARES_INSTANCE_FIELD,
+ _EXTENSION_DECLARES_ABSTRACT_MEMBER,
+ _MIXIN_DECLARES_CONSTRUCTOR,
];
const ParserErrorCode _ABSTRACT_CLASS_MEMBER = const ParserErrorCode(
@@ -244,6 +248,21 @@
correction:
"Try moving the export directives before the part directives.");
+const ParserErrorCode _EXTENSION_DECLARES_ABSTRACT_MEMBER =
+ const ParserErrorCode('EXTENSION_DECLARES_ABSTRACT_MEMBER',
+ r"Extensions can't declare abstract members.",
+ correction: "Try providing an implementation for the member.");
+
+const ParserErrorCode _EXTENSION_DECLARES_CONSTRUCTOR = const ParserErrorCode(
+ 'EXTENSION_DECLARES_CONSTRUCTOR', r"Extensions can't declare constructors.",
+ correction: "Try removing the constructor declaration.");
+
+const ParserErrorCode _EXTENSION_DECLARES_INSTANCE_FIELD =
+ const ParserErrorCode('EXTENSION_DECLARES_INSTANCE_FIELD',
+ r"Extensions can't declare instance fields",
+ correction:
+ "Try removing the field declaration or making it a static field");
+
const ParserErrorCode _EXTERNAL_CLASS = const ParserErrorCode(
'EXTERNAL_CLASS', r"Classes can't be declared to be 'external'.",
correction: "Try removing the keyword 'external'.");
@@ -422,6 +441,9 @@
const ParserErrorCode _MISSING_STATEMENT =
const ParserErrorCode('MISSING_STATEMENT', r"Expected a statement.");
+const ParserErrorCode _MIXIN_DECLARES_CONSTRUCTOR = const ParserErrorCode(
+ 'MIXIN_DECLARES_CONSTRUCTOR', r"Mixins can't declare constructors.");
+
const ParserErrorCode _MODIFIER_OUT_OF_ORDER = const ParserErrorCode(
'MODIFIER_OUT_OF_ORDER',
r"The modifier '#string' should be before the modifier '#string2'.",
diff --git a/pkg/analyzer/lib/src/dart/resolver/extension_member_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/extension_member_resolver.dart
index 0147fc7..931287a 100644
--- a/pkg/analyzer/lib/src/dart/resolver/extension_member_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/extension_member_resolver.dart
@@ -31,26 +31,30 @@
TypeSystem get _typeSystem => _resolver.typeSystem;
/// Return the most specific extension in the current scope for this [type],
- /// that defines the member with the the [name] and [kind].
+ /// that defines the member with the given [name].
///
- /// If no applicable extensions, return `null`.
+ /// If no applicable extensions, return [ResolutionResult.none].
///
- /// If the match is ambiguous, report an error and return `null`.
+ /// If the match is ambiguous, report an error and return
+ /// [ResolutionResult.ambiguous].
ResolutionResult findExtension(
- DartType type, String name, Expression target, ElementKind kind) {
- var extensions = _getApplicable(type, name, kind);
+ DartType type,
+ String name,
+ Expression target,
+ ) {
+ var extensions = _getApplicable(type, name);
if (extensions.isEmpty) {
return ResolutionResult.none;
}
if (extensions.length == 1) {
- return ResolutionResult(extensions[0].instantiatedMember);
+ return extensions[0].asResolutionResult;
}
var extension = _chooseMostSpecific(extensions);
if (extension != null) {
- return ResolutionResult(extension.instantiatedMember);
+ return extension.asResolutionResult;
}
_errorReporter.reportErrorForNode(
@@ -58,29 +62,33 @@
target,
[
name,
- extensions[0].element.name,
- extensions[1].element.name,
+ extensions[0].extension.name,
+ extensions[1].extension.name,
],
);
return ResolutionResult.ambiguous;
}
- /// Return the member with the [name] (without `=`) of the given [kind].
+ /// Return the member with the [name] (without `=`).
///
/// The [node] is fully resolved, and its type arguments are set.
ExecutableElement getOverrideMember(
- ExtensionOverride node, String name, ElementKind kind) {
+ ExtensionOverride node,
+ String name, {
+ bool setter = false,
+ }) {
ExtensionElement element = node.extensionName.staticElement;
ExecutableElement member;
- if (kind == ElementKind.GETTER) {
- member = element.getGetter(name);
- } else if (kind == ElementKind.METHOD) {
- member = element.getMethod(name);
- } else if (kind == ElementKind.SETTER) {
+ if (setter) {
member = element.getSetter(name);
+ } else {
+ member = element.getGetter(name) ?? element.getMethod(name);
}
- if (member == null) return null;
+
+ if (member == null) {
+ return null;
+ }
return ExecutableMember.from2(
member,
@@ -211,27 +219,6 @@
/// identified.
_InstantiatedExtension _chooseMostSpecific(
List<_InstantiatedExtension> extensions) {
- //
- // https://github.com/dart-lang/language/blob/master/accepted/future-releases/static-extension-methods/feature-specification.md#extension-conflict-resolution:
- //
- // If more than one extension applies to a specific member invocation, then
- // we resort to a heuristic to choose one of the extensions to apply. If
- // exactly one of them is "more specific" than all the others, that one is
- // chosen. Otherwise it is a compile-time error.
- //
- // An extension with on type clause T1 is more specific than another
- // extension with on type clause T2 iff
- //
- // 1. T2 is declared in a platform library, and T1 is not, or
- // 2. they are both declared in platform libraries or both declared in
- // non-platform libraries, and
- // 3. the instantiated type (the type after applying type inference from the
- // receiver) of T1 is a subtype of the instantiated type of T2 and either
- // not vice versa, or
- // 4. the instantiate-to-bounds type of T1 is a subtype of the
- // instantiate-to-bounds type of T2 and not vice versa.
- //
-
for (var i = 0; i < extensions.length; i++) {
var e1 = extensions[i];
var isMoreSpecific = true;
@@ -253,9 +240,8 @@
/// Return extensions for the [type] that match the given [name] in the
/// current scope.
- List<_InstantiatedExtension> _getApplicable(
- DartType type, String name, ElementKind kind) {
- var candidates = _getExtensionsWithMember(name, kind);
+ List<_InstantiatedExtension> _getApplicable(DartType type, String name) {
+ var candidates = _getExtensionsWithMember(name);
var instantiatedExtensions = <_InstantiatedExtension>[];
for (var candidate in candidates) {
@@ -287,14 +273,7 @@
}
instantiatedExtensions.add(
- _InstantiatedExtension(
- candidate.extension,
- extendedType,
- ExecutableMember.from2(
- candidate.member,
- substitution,
- ),
- ),
+ _InstantiatedExtension(candidate, substitution, extendedType),
);
}
@@ -302,54 +281,27 @@
}
/// Return extensions from the current scope, that define a member with the
- /// given[name].
- List<_CandidateExtension> _getExtensionsWithMember(
- String name,
- ElementKind kind,
- ) {
+ /// given [name].
+ List<_CandidateExtension> _getExtensionsWithMember(String name) {
var candidates = <_CandidateExtension>[];
- /// Return `true` if the [elementName] matches the target [name], taking
- /// into account the `=` on the end of the names of setters.
- bool matchesName(String elementName) {
- if (elementName.endsWith('=') && !name.endsWith('=')) {
- elementName = elementName.substring(0, elementName.length - 1);
- }
- return elementName == name;
- }
-
/// Add the given [extension] to the list of [candidates] if it defined a
/// member whose name matches the target [name].
void checkExtension(ExtensionElement extension) {
- if (kind == ElementKind.GETTER) {
- for (var accessor in extension.accessors) {
- if (accessor.isGetter && matchesName(accessor.name)) {
- candidates.add(_CandidateExtension(extension, accessor));
- return;
- }
+ for (var field in extension.fields) {
+ if (field.name == name) {
+ candidates.add(
+ _CandidateExtension(extension, field: field),
+ );
+ return;
}
- } else if (kind == ElementKind.SETTER) {
- for (var accessor in extension.accessors) {
- if (accessor.isSetter && matchesName(accessor.name)) {
- candidates.add(_CandidateExtension(extension, accessor));
- return;
- }
- }
- } else if (kind == ElementKind.METHOD) {
- for (var method in extension.methods) {
- if (matchesName(method.name)) {
- candidates.add(_CandidateExtension(extension, method));
- return;
- }
- }
- // Check for a getter that matches a function type.
- for (var accessor in extension.accessors) {
- if (accessor.type is FunctionType &&
- accessor.isGetter &&
- matchesName(accessor.name)) {
- candidates.add(_CandidateExtension(extension, accessor));
- return;
- }
+ }
+ for (var method in extension.methods) {
+ if (method.name == name) {
+ candidates.add(
+ _CandidateExtension(extension, method: method),
+ );
+ return;
}
}
}
@@ -418,42 +370,39 @@
/// Return `true` is [e1] is more specific than [e2].
bool _isMoreSpecific(_InstantiatedExtension e1, _InstantiatedExtension e2) {
// 1. The latter extension is declared in a platform library, and the
- // former extension is not.
- var e1_isInSdk = e1.element.library.isInSdk;
- var e2_isInSdk = e2.element.library.isInSdk;
+ // former extension is not.
+ // 2. They are both declared in platform libraries, or both declared in
+ // non-platform libraries.
+ var e1_isInSdk = e1.extension.library.isInSdk;
+ var e2_isInSdk = e2.extension.library.isInSdk;
if (e1_isInSdk && !e2_isInSdk) {
return false;
} else if (!e1_isInSdk && e2_isInSdk) {
return true;
}
- var extendedType1 = e1._extendedType;
- var extendedType2 = e2._extendedType;
+ var extendedType1 = e1.extendedType;
+ var extendedType2 = e2.extendedType;
- // 2. they are both declared in platform libraries or both declared in
- // non-platform libraries, and
- if (_isSubtypeAndNotViceVersa(extendedType1, extendedType2)) {
- // 3. the instantiated type (the type after applying type inference from
- // the receiver) of T1 is a subtype of the instantiated type of T2 and
- // either not vice versa
+ // 3. The instantiated type (the type after applying type inference from
+ // the receiver) of T1 is a subtype of the instantiated type of T2,
+ // and either...
+ if (!_isSubtypeOf(extendedType1, extendedType2)) {
+ return false;
+ }
+
+ // 4. ...not vice versa, or...
+ if (!_isSubtypeOf(extendedType2, extendedType1)) {
return true;
}
+ // 5. ...the instantiate-to-bounds type of T1 is a subtype of the
+ // instantiate-to-bounds type of T2 and not vice versa.
// TODO(scheglov) store instantiated types
- var extendedTypeBound1 = _instantiateToBounds(e1.element);
- var extendedTypeBound2 = _instantiateToBounds(e2.element);
- if (_isSubtypeAndNotViceVersa(extendedTypeBound1, extendedTypeBound2)) {
- // or:
- // 4. the instantiate-to-bounds type of T1 is a subtype of the
- // instantiate-to-bounds type of T2 and not vice versa.
- return true;
- }
-
- return false;
- }
-
- bool _isSubtypeAndNotViceVersa(DartType t1, DartType t2) {
- return _isSubtypeOf(t1, t2) && !_isSubtypeOf(t2, t1);
+ var extendedTypeBound1 = _instantiateToBounds(e1.extension);
+ var extendedTypeBound2 = _instantiateToBounds(e2.extension);
+ return _isSubtypeOf(extendedTypeBound1, extendedTypeBound2) &&
+ !_isSubtypeOf(extendedTypeBound2, extendedTypeBound1);
}
/// Ask the type system for a subtype check.
@@ -479,19 +428,37 @@
class _CandidateExtension {
final ExtensionElement extension;
- final ExecutableElement member;
+ final FieldElement field;
+ final MethodElement method;
- _CandidateExtension(this.extension, this.member);
+ _CandidateExtension(this.extension, {this.field, this.method})
+ : assert(field != null || method != null);
}
class _InstantiatedExtension {
- final ExtensionElement element;
- final DartType _extendedType;
- final ExecutableElement instantiatedMember;
+ final _CandidateExtension candidate;
+ final MapSubstitution substitution;
+ final DartType extendedType;
- _InstantiatedExtension(
- this.element,
- this._extendedType,
- this.instantiatedMember,
- );
+ _InstantiatedExtension(this.candidate, this.substitution, this.extendedType);
+
+ ResolutionResult get asResolutionResult {
+ return ResolutionResult(function: method, property: field);
+ }
+
+ ExtensionElement get extension => candidate.extension;
+
+ FieldElement get field {
+ if (candidate.field == null) {
+ return null;
+ }
+ return FieldMember.from2(candidate.field, substitution);
+ }
+
+ MethodElement get method {
+ if (candidate.method == null) {
+ return null;
+ }
+ return MethodMember.from2(candidate.method, substitution);
+ }
}
diff --git a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
index 24b4dd6..8fc4935 100644
--- a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_ast_factory.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
@@ -45,8 +44,6 @@
/// code that are independent from visiting AST during resolution, so can
/// be extracted.
class FlowAnalysisHelper {
- static final _trueLiteral = astFactory.booleanLiteral(null, true);
-
/// The reused instance for creating new [FlowAnalysis] instances.
final NodeOperations<Expression> _nodeOperations;
@@ -124,6 +121,42 @@
}
}
+ void breakStatement(BreakStatement node) {
+ var target = getLabelTarget(node, node.label?.staticElement);
+ flow.handleBreak(target);
+ }
+
+ /// Mark the [node] as unreachable if it is not covered by another node that
+ /// is already known to be unreachable.
+ void checkUnreachableNode(AstNode node) {
+ if (flow == null) return;
+ if (flow.isReachable) return;
+
+ if (result != null) {
+ // Ignore the [node] if it is fully covered by the last unreachable.
+ if (result.unreachableNodes.isNotEmpty) {
+ var last = result.unreachableNodes.last;
+ if (node.offset >= last.offset && node.end <= last.end) return;
+ }
+
+ result.unreachableNodes.add(node);
+ }
+ }
+
+ void continueStatement(ContinueStatement node) {
+ var target = getLabelTarget(node, node.label?.staticElement);
+ flow.handleContinue(target);
+ }
+
+ void for_bodyBegin(AstNode node, Expression condition) {
+ flow.for_bodyBegin(node is Statement ? node : null, condition);
+ }
+
+ void for_conditionBegin(AstNode node, Expression condition) {
+ var assigned = assignedVariables.writtenInNode(node);
+ flow.for_conditionBegin(assigned);
+ }
+
void functionBody_enter(FunctionBody node) {
_blockFunctionBodyLevel++;
@@ -165,47 +198,6 @@
flow.finish();
}
- void breakStatement(BreakStatement node) {
- var target = getLabelTarget(node, node.label?.staticElement);
- flow.handleBreak(target);
- }
-
- /// Mark the [node] as unreachable if it is not covered by another node that
- /// is already known to be unreachable.
- void checkUnreachableNode(AstNode node) {
- if (flow == null) return;
- if (flow.isReachable) return;
-
- if (result != null) {
- // Ignore the [node] if it is fully covered by the last unreachable.
- if (result.unreachableNodes.isNotEmpty) {
- var last = result.unreachableNodes.last;
- if (node.offset >= last.offset && node.end <= last.end) return;
- }
-
- result.unreachableNodes.add(node);
- }
- }
-
- void continueStatement(ContinueStatement node) {
- var target = getLabelTarget(node, node.label?.staticElement);
- flow.handleContinue(target);
- }
-
- void for_bodyBegin(AstNode node, Expression condition) {
- flow.for_bodyBegin(
- node is Statement ? node : null, condition ?? _trueLiteral);
- }
-
- void for_conditionBegin(AstNode node, Expression condition) {
- if (condition != null) {
- var assigned = assignedVariables[node];
- flow.for_conditionBegin(assigned);
- } else {
- flow.booleanLiteral(_trueLiteral, true);
- }
- }
-
void isExpression(IsExpression node) {
if (flow == null) return;
@@ -364,9 +356,9 @@
@override
void visitDoStatement(DoStatement node) {
- assignedVariables.beginStatementOrElement();
+ assignedVariables.beginNode();
super.visitDoStatement(node);
- assignedVariables.endStatementOrElement(node);
+ assignedVariables.endNode(node);
}
@override
@@ -386,32 +378,32 @@
expression.accept(this);
- assignedVariables.beginStatementOrElement();
+ assignedVariables.beginNode();
members.accept(this);
- assignedVariables.endStatementOrElement(node);
+ assignedVariables.endNode(node);
}
@override
void visitTryStatement(TryStatement node) {
- assignedVariables.beginStatementOrElement();
+ assignedVariables.beginNode();
node.body.accept(this);
- assignedVariables.endStatementOrElement(node.body);
+ assignedVariables.endNode(node.body);
node.catchClauses.accept(this);
var finallyBlock = node.finallyBlock;
if (finallyBlock != null) {
- assignedVariables.beginStatementOrElement();
+ assignedVariables.beginNode();
finallyBlock.accept(this);
- assignedVariables.endStatementOrElement(finallyBlock);
+ assignedVariables.endNode(finallyBlock);
}
}
@override
void visitWhileStatement(WhileStatement node) {
- assignedVariables.beginStatementOrElement();
+ assignedVariables.beginNode();
super.visitWhileStatement(node);
- assignedVariables.endStatementOrElement(node);
+ assignedVariables.endNode(node);
}
void _handleFor(AstNode node, ForLoopParts forLoopParts, AstNode body) {
@@ -424,19 +416,19 @@
throw new StateError('Unrecognized for loop parts');
}
- assignedVariables.beginStatementOrElement();
+ assignedVariables.beginNode();
forLoopParts.condition?.accept(this);
body.accept(this);
forLoopParts.updaters?.accept(this);
- assignedVariables.endStatementOrElement(node);
+ assignedVariables.endNode(node);
} else if (forLoopParts is ForEachParts) {
var iterable = forLoopParts.iterable;
iterable.accept(this);
- assignedVariables.beginStatementOrElement();
+ assignedVariables.beginNode();
body.accept(this);
- assignedVariables.endStatementOrElement(node);
+ assignedVariables.endNode(node);
} else {
throw new StateError('Unrecognized for loop parts');
}
diff --git a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
index d85976c..39a27a4 100644
--- a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
@@ -160,11 +160,10 @@
MethodElement callMethod =
type.lookUpMethod(FunctionElement.CALL_METHOD_NAME, _definingLibrary);
if (callMethod != null) {
- return _resolveArgumentsToFunction(false, argumentList, callMethod);
+ return _resolveArgumentsToFunction(argumentList, callMethod);
}
} else if (type is FunctionType) {
- return _resolveArgumentsToParameters(
- false, argumentList, type.parameters);
+ return _resolveArgumentsToParameters(argumentList, type.parameters);
}
return null;
}
@@ -283,34 +282,28 @@
}
/// Given an [argumentList] and the [executableElement] that will be invoked
- /// using those argument, compute the list of parameters that correspond to the
- /// list of arguments. An error will be reported if any of the arguments cannot
- /// be matched to a parameter. The flag [reportAsError] should be `true` if a
- /// compile-time error should be reported; or `false` if a compile-time warning
- /// should be reported. Return the parameters that correspond to the arguments,
- /// or `null` if no correspondence could be computed.
- List<ParameterElement> _resolveArgumentsToFunction(bool reportAsError,
+ /// using those argument, compute the list of parameters that correspond to
+ /// the list of arguments. An error will be reported if any of the arguments
+ /// cannot be matched to a parameter. Return the parameters that correspond to
+ /// the arguments, or `null` if no correspondence could be computed.
+ List<ParameterElement> _resolveArgumentsToFunction(
ArgumentList argumentList, ExecutableElement executableElement) {
if (executableElement == null) {
return null;
}
List<ParameterElement> parameters = executableElement.parameters;
- return _resolveArgumentsToParameters(
- reportAsError, argumentList, parameters);
+ return _resolveArgumentsToParameters(argumentList, parameters);
}
/// Given an [argumentList] and the [parameters] related to the element that
/// will be invoked using those arguments, compute the list of parameters that
/// correspond to the list of arguments. An error will be reported if any of
- /// the arguments cannot be matched to a parameter. The flag [reportAsError]
- /// should be `true` if a compile-time error should be reported; or `false` if
- /// a compile-time warning should be reported. Return the parameters that
+ /// the arguments cannot be matched to a parameter. Return the parameters that
/// correspond to the arguments.
- List<ParameterElement> _resolveArgumentsToParameters(bool reportAsError,
+ List<ParameterElement> _resolveArgumentsToParameters(
ArgumentList argumentList, List<ParameterElement> parameters) {
return ResolverVisitor.resolveArgumentsToParameters(
- argumentList, parameters, _resolver.errorReporter.reportErrorForNode,
- reportAsError: reportAsError);
+ argumentList, parameters, _resolver.errorReporter.reportErrorForNode);
}
/// Given that we are accessing a property of the given [classElement] with the
@@ -349,7 +342,6 @@
receiverType,
name,
nameNode,
- ElementKind.METHOD,
);
if (!result.isSingle) {
@@ -357,7 +349,7 @@
return result;
}
- ExecutableElement member = result.element;
+ ExecutableElement member = result.getter;
nameNode.staticElement = member;
if (member.isStatic) {
@@ -399,10 +391,7 @@
void _resolveExtensionOverride(MethodInvocation node,
ExtensionOverride override, SimpleIdentifier nameNode, String name) {
- var member = _extensionResolver.getOverrideMember(
- override, name, ElementKind.METHOD) ??
- _extensionResolver.getOverrideMember(
- override, name, ElementKind.GETTER);
+ var member = _extensionResolver.getOverrideMember(override, name);
if (member == null) {
_setDynamicResolution(node);
@@ -446,11 +435,11 @@
return;
}
- ResolutionResult result = _extensionResolver.findExtension(
- receiverType, name, nameNode, ElementKind.METHOD);
+ ResolutionResult result =
+ _extensionResolver.findExtension(receiverType, name, nameNode);
if (result.isSingle) {
- nameNode.staticElement = result.element;
- var calleeType = _getCalleeType(node, result.element);
+ nameNode.staticElement = result.getter;
+ var calleeType = _getCalleeType(node, result.getter);
return _setResolution(node, calleeType);
} else if (result.isAmbiguous) {
return;
@@ -585,10 +574,9 @@
return;
}
- var result = _extensionResolver.findExtension(
- receiverType, name, nameNode, ElementKind.METHOD);
+ var result = _extensionResolver.findExtension(receiverType, name, nameNode);
if (result.isSingle) {
- var target = result.element;
+ var target = result.getter;
if (target != null) {
nameNode.staticElement = target;
var calleeType = _getCalleeType(node, target);
@@ -751,9 +739,9 @@
var call = _inheritance.getMember(type, _nameCall);
if (call == null) {
var result = _extensionResolver.findExtension(
- type, _nameCall.name, node.methodName, ElementKind.METHOD);
+ type, _nameCall.name, node.methodName);
if (result.isSingle) {
- call = result.element;
+ call = result.function;
} else if (result.isAmbiguous) {
return;
}
diff --git a/pkg/analyzer/lib/src/dart/resolver/resolution_result.dart b/pkg/analyzer/lib/src/dart/resolver/resolution_result.dart
index 1d91bf8..d3b7288 100644
--- a/pkg/analyzer/lib/src/dart/resolver/resolution_result.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/resolution_result.dart
@@ -17,18 +17,27 @@
/// The state of the result.
final _ResolutionResultState state;
- /// The element that was found, or `null` if the [state] is not
- /// [_ResolutionResultState.single].
- final ExecutableElement element;
+ /// The function that was found, or `null` if the [state] is not
+ /// [_ResolutionResultState.single], or a [property] was found.
+ final ExecutableElement function;
+
+ /// The property that was found, or `null` if the [state] is not
+ /// [_ResolutionResultState.single], or a [function] was found.
+ final PropertyInducingElement property;
/// Initialize a newly created result to represent resolving to a single
- /// [element].
- ResolutionResult(this.element)
- : assert(element != null),
+ /// [function] or [property].
+ ResolutionResult({this.function, this.property})
+ : assert(function != null || property != null),
state = _ResolutionResultState.single;
/// Initialize a newly created result with no element and the given [state].
- const ResolutionResult._(this.state) : element = null;
+ const ResolutionResult._(this.state)
+ : function = null,
+ property = null;
+
+ /// Return the getter of the [property], or the [function].
+ ExecutableElement get getter => function ?? property?.getter;
/// Return `true` if this result represents the case where multiple ambiguous
/// elements were found.
@@ -41,6 +50,17 @@
/// Return `true` if this result represents the case where a single element
/// was found.
bool get isSingle => state == _ResolutionResultState.single;
+
+ /// If this is a property, return `true` is the property is static.
+ /// If this is a function, return `true` is the function is static.
+ /// Otherwise return `false`.
+ bool get isStatic {
+ return function?.isStatic ?? property?.isStatic ?? false;
+ }
+
+ /// Return the setter of the [property], or `null` if this is not a property,
+ /// or the property does not have a setter.
+ ExecutableElement get setter => property?.setter;
}
/// The state of a [ResolutionResult].
diff --git a/pkg/analyzer/lib/src/dart/resolver/scope.dart b/pkg/analyzer/lib/src/dart/resolver/scope.dart
index 655059b..ef8de3a 100644
--- a/pkg/analyzer/lib/src/dart/resolver/scope.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/scope.dart
@@ -407,12 +407,14 @@
List<ExtensionElement> get extensions {
if (_extensions == null) {
_extensions = [];
- for (var namespace in _importedNamespaces) {
- for (var element in namespace.definedNames.values) {
- if (element is ExtensionElement &&
- element.name.isNotEmpty /* named */ &&
- !_extensions.contains(element)) {
- _extensions.add(element);
+ List<ImportElement> imports = _definingLibrary.imports;
+ int count = imports.length;
+ for (int i = 0; i < count; i++) {
+ if (imports[i].prefix == null) {
+ for (var element in imports[i].namespace.definedNames.values) {
+ if (element is ExtensionElement && !_extensions.contains(element)) {
+ _extensions.add(element);
+ }
}
}
}
@@ -807,7 +809,7 @@
*/
void _addIfPublic(Map<String, Element> definedNames, Element element) {
String name = element.name;
- if (name != null && !Scope.isPrivateName(name)) {
+ if (name != null && name.isNotEmpty && !Scope.isPrivateName(name)) {
definedNames[name] = element;
}
}
@@ -890,9 +892,9 @@
}
}
_addAllFromNamespace(
- definedNames,
- (library.context as InternalAnalysisContext)
- .getPublicNamespace(library));
+ definedNames,
+ createPublicNamespaceForLibrary(library),
+ );
return definedNames;
} finally {
visitedElements.remove(library);
diff --git a/pkg/analyzer/lib/src/error/analyzer_error_code.dart b/pkg/analyzer/lib/src/error/analyzer_error_code.dart
new file mode 100644
index 0000000..29bcc8c
--- /dev/null
+++ b/pkg/analyzer/lib/src/error/analyzer_error_code.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2019, 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/error/error.dart';
+
+/// A superclass for error codes that can have a url associated with them.
+abstract class AnalyzerErrorCode extends ErrorCode {
+ /// Initialize a newly created error code.
+ const AnalyzerErrorCode.temporary(String name, String message,
+ {String correction, bool hasPublishedDocs, bool isUnresolvedIdentifier})
+ : super.temporary(name, message,
+ correction: correction,
+ hasPublishedDocs: hasPublishedDocs ?? false,
+ isUnresolvedIdentifier: isUnresolvedIdentifier ?? false);
+
+ String get url {
+ if (hasPublishedDocs) {
+ return 'https://dart.dev/tools/diagnostic-messages#${name.toLowerCase()}';
+ }
+ return null;
+ }
+}
diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
index fe637f4..49aa71d 100644
--- a/pkg/analyzer/lib/src/error/codes.dart
+++ b/pkg/analyzer/lib/src/error/codes.dart
@@ -5,6 +5,8 @@
import 'package:analyzer/error/error.dart';
import 'package:analyzer/src/dart/error/syntactic_errors.dart';
+import 'analyzer_error_code.dart';
+
export 'package:analyzer/src/analysis_options/error/option_codes.dart';
export 'package:analyzer/src/dart/error/hint_codes.dart';
export 'package:analyzer/src/dart/error/lint_codes.dart';
@@ -18,7 +20,7 @@
* treat these errors differently depending whether it is compiling it "checked"
* mode).
*/
-class CheckedModeCompileTimeErrorCode extends ErrorCode {
+class CheckedModeCompileTimeErrorCode extends AnalyzerErrorCode {
// TODO(paulberry): improve the text of these error messages so that it's
// clear to the user that the error is coming from constant evaluation (and
// hence the constant needs to be a subtype of the annotated type) as opposed
@@ -102,7 +104,7 @@
* error to be generated and for the error message to explain what is wrong and,
* when appropriate, how the problem can be corrected.
*/
-class CompileTimeErrorCode extends ErrorCode {
+class CompileTimeErrorCode extends AnalyzerErrorCode {
/**
* Member lookups ignore abstract declarations, which means that there will
* be a compile-time error if the targeted member `m` is abstract, as well as
@@ -219,7 +221,8 @@
"a map or a set.",
correction:
"Try removing or changing some of the elements so that all of "
- "the elements are consistent.");
+ "the elements are consistent.",
+ hasPublishedDocs: true);
/**
* No parameters.
@@ -299,7 +302,8 @@
"have enough information for type inference to work.",
correction:
"Try adding type arguments to the literal (one for sets, two "
- "for maps).");
+ "for maps).",
+ hasPublishedDocs: true);
/**
* 15 Metadata: The constant expression given in an annotation is type checked
@@ -350,6 +354,18 @@
"Try marking the function body with either 'async' or 'async*'.");
/**
+ * It is a compile-time error if a built-in identifier is used as the declared
+ * name of an extension.
+ *
+ * Parameters:
+ * 0: the built-in identifier that is being used
+ */
+ static const CompileTimeErrorCode BUILT_IN_IDENTIFIER_AS_EXTENSION_NAME =
+ const CompileTimeErrorCode('BUILT_IN_IDENTIFIER_AS_EXTENSION_NAME',
+ "The built-in identifier '{0}' can't be used as an extension name.",
+ correction: "Try choosing a different name for the extension.");
+
+ /**
* 16.33 Identifier Reference: It is a compile-time error if a built-in
* identifier is used as the declared name of a prefix, class, type parameter
* or type alias.
@@ -693,7 +709,8 @@
const CompileTimeErrorCode('CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE',
"Const variables must be initialized with a constant value.",
correction:
- "Try changing the initializer to be a constant expression.");
+ "Try changing the initializer to be a constant expression.",
+ hasPublishedDocs: true);
/**
* 5 Variables: A constant variable must be initialized to a compile-time
@@ -1131,7 +1148,9 @@
// ```
static const CompileTimeErrorCode EQUAL_KEYS_IN_CONST_MAP =
const CompileTimeErrorCode('EQUAL_KEYS_IN_CONST_MAP',
- "Two keys in a constant map literal can't be equal.");
+ "Two keys in a constant map literal can't be equal.",
+ correction: "Change or remove the duplicate key.",
+ hasPublishedDocs: true);
/**
* 16.11 Sets: It is a compile-time error if two elements of a constant set
@@ -1193,7 +1212,8 @@
'EXPRESSION_IN_MAP', "Expressions can't be used in a map literal.",
correction:
"Try removing the expression or converting it to be a map "
- "entry.");
+ "entry.",
+ hasPublishedDocs: true);
/**
* 7.9 Superclasses: It is a compile-time error if the extends clause of a
@@ -1260,6 +1280,15 @@
"removing the extends clause.");
/**
+ * Parameters:
+ * 0: the name of the extension
+ */
+ static const CompileTimeErrorCode EXTENSION_AS_EXPRESSION =
+ const CompileTimeErrorCode('EXTENSION_AS_EXPRESSION',
+ "Extension '{0}' can't be used as an expression.",
+ correction: "Try replacing it with a valid expression.");
+
+ /**
* It is for an extension to define a static member and an instance member
* with the same base name.
*
@@ -1278,32 +1307,6 @@
/**
* No parameters.
*/
- static const CompileTimeErrorCode EXTENSION_DECLARES_ABSTRACT_MEMBER =
- const CompileTimeErrorCode('EXTENSION_DECLARES_ABSTRACT_MEMBER',
- "Extensions can't declare abstract members.",
- correction: "Try providing an implementation for the member.");
-
- /**
- * No parameters.
- */
- static const CompileTimeErrorCode EXTENSION_DECLARES_CONSTRUCTOR =
- const CompileTimeErrorCode('EXTENSION_DECLARES_CONSTRUCTOR',
- "Extensions can't declare constructors.",
- correction: "Try removing the constructor declaration.");
-
- /**
- * No parameters.
- */
- static const CompileTimeErrorCode EXTENSION_DECLARES_INSTANCE_FIELD =
- const CompileTimeErrorCode('EXTENSION_DECLARES_INSTANCE_FIELD',
- "Extensions can't declare instance fields.",
- correction:
- "Try removing the field declaration or making it a static "
- "field.");
-
- /**
- * No parameters.
- */
static const CompileTimeErrorCode EXTENSION_DECLARES_MEMBER_OF_OBJECT =
const CompileTimeErrorCode(
'EXTENSION_DECLARES_MEMBER_OF_OBJECT',
@@ -1586,8 +1589,6 @@
*
* Parameters:
* 0: the uri pointing to a non-library declaration
- *
- * See [StaticWarningCode.IMPORT_OF_NON_LIBRARY].
*/
static const CompileTimeErrorCode IMPORT_OF_NON_LIBRARY =
const CompileTimeErrorCode('IMPORT_OF_NON_LIBRARY',
@@ -2503,8 +2504,8 @@
//
// The analyzer produces this diagnostic when an element in a constant list
// literal isn't a constant value. The list literal can be constant either
- // explicitly (because it's prefixed by the keyword `const`) or implicitly
- // (because it appears in a <a href=”#constant-context”>constant context</a>).
+ // explicitly (because it's prefixed by the `const` keyword) or implicitly
+ // (because it appears in a [constant context](#constant-context)).
//
// #### Example
//
@@ -2519,8 +2520,8 @@
// #### Common fixes
//
// If the list needs to be a constant list, then convert the element to be a
- // constant. In the example above, you might add the keyword `const`
- // to the declaration of `x`:
+ // constant. In the example above, you might add the `const` keyword to the
+ // declaration of `x`:
//
// ```dart
// const int x = 2;
@@ -2539,8 +2540,8 @@
static const CompileTimeErrorCode NON_CONSTANT_LIST_ELEMENT =
const CompileTimeErrorCode('NON_CONSTANT_LIST_ELEMENT',
"The values in a const list literal must be constants.",
- correction:
- "Try removing the keyword 'const' from the list literal.");
+ correction: "Try removing the keyword 'const' from the list literal.",
+ hasPublishedDocs: true);
/**
* 12.6 Lists: It is a compile time error if an element of a constant list
@@ -2674,6 +2675,10 @@
"{0} positional argument(s) expected, but {1} found.",
correction: "Try adding the missing arguments.");
+ @Deprecated('Use CompileTimeErrorCode NOT_ENOUGH_POSITIONAL_ARGUMENTS')
+ static const CompileTimeErrorCode NOT_ENOUGH_REQUIRED_ARGUMENTS =
+ NOT_ENOUGH_POSITIONAL_ARGUMENTS;
+
/**
* It is an error if an instance field with potentially non-nullable type has
* no initializer expression and is not initialized in a constructor via an
@@ -2752,7 +2757,8 @@
// ```
static const CompileTimeErrorCode NOT_ITERABLE_SPREAD =
const CompileTimeErrorCode('NOT_ITERABLE_SPREAD',
- "Spread elements in list or set literals must implement 'Iterable'.");
+ "Spread elements in list or set literals must implement 'Iterable'.",
+ hasPublishedDocs: true);
static const CompileTimeErrorCode NOT_MAP_SPREAD = const CompileTimeErrorCode(
'NOT_MAP_SPREAD',
@@ -3073,6 +3079,7 @@
//
// ```dart
// C f() {}
+ //
// class C {
// factory C() = [!f!];
// }
@@ -3091,6 +3098,7 @@
//
// ```dart
// C f() {}
+ //
// class C {
// factory C() => f();
// }
@@ -3100,7 +3108,8 @@
'REDIRECT_TO_NON_CLASS',
"The name '{0}' isn't a type and can't be used in a redirected "
"constructor.",
- correction: "Try redirecting to a different constructor.");
+ correction: "Try redirecting to a different constructor.",
+ hasPublishedDocs: true);
/**
* 7.6.2 Factories: It is a compile-time error if <i>k</i> is prefixed with
@@ -3263,6 +3272,7 @@
//
// ```dart
// class A<E extends num> {}
+ //
// var a = A<[!String!]>();
// ```
//
@@ -3272,12 +3282,14 @@
//
// ```dart
// class A<E extends num> {}
+ //
// var a = A<int>();
// ```
static const CompileTimeErrorCode TYPE_ARGUMENT_NOT_MATCHING_BOUNDS =
const CompileTimeErrorCode(
'TYPE_ARGUMENT_NOT_MATCHING_BOUNDS', "'{0}' doesn't extend '{1}'.",
- correction: "Try using a type that is or is a subclass of '{1}'.");
+ correction: "Try using a type that is or is a subclass of '{1}'.",
+ hasPublishedDocs: true);
/**
* It is a compile-time error if a generic function type is used as a bound
@@ -3336,12 +3348,50 @@
isUnresolvedIdentifier: true);
/**
- * 16.12.2 Const: It is a compile-time error if <i>T</i> is not a class
- * accessible in the current scope, optionally followed by type arguments.
+ * Parameters:
+ * 0: the name of the undefined class
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when it encounters an identifier that
+ // appears to be the name of a class but either isn't defined or isn't visible
+ // in the scope in which it's being referenced.
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic:
+ //
+ // ```dart
+ // class Point {}
+ //
+ // void main() {
+ // [!Piont!] p;
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // If the identifier isn't defined, then either define it or replace it with
+ // the name of a class that is defined. The example above can be corrected by
+ // fixing the spelling of the class:
+ //
+ // ```dart
+ // class Point {}
+ //
+ // void main() {
+ // Point p;
+ // }
+ // ```
+ //
+ // If the class is defined but isn't visible, then you probably need to add an
+ // import.
static const CompileTimeErrorCode UNDEFINED_CLASS =
const CompileTimeErrorCode('UNDEFINED_CLASS', "Undefined class '{0}'.",
- correction: "Try defining the class.", isUnresolvedIdentifier: true);
+ correction:
+ "Try changing the name to the name of an existing class, or "
+ "creating a class with the name '{0}'.",
+ hasPublishedDocs: true,
+ isUnresolvedIdentifier: true);
/**
* 7.6.1 Generative Constructors: Let <i>C</i> be the class in which the
@@ -3414,23 +3464,79 @@
"defining a setter named '{0}'.");
/**
- * 12.14.2 Binding Actuals to Formals: Furthermore, each <i>q<sub>i</sub></i>,
- * <i>1<=i<=l</i>, must have a corresponding named parameter in the set
- * {<i>p<sub>n+1</sub></i> ... <i>p<sub>n+k</sub></i>} or a static warning
- * occurs.
- *
- * 16.12.2 Const: It is a compile-time error if evaluation of a constant
- * object results in an uncaught exception being thrown.
- *
* Parameters:
* 0: the name of the requested named parameter
*/
+ // #### Description
+ //
+ // The analyzer produces this diagnostic when a method or function invocation
+ // has a named argument, but the method or function being invoked doesn’t
+ // define a parameter with the same name.
+ //
+ // #### Example
+ //
+ // The following code produces this diagnostic:
+ //
+ // ```dart
+ // class C {
+ // m({int b}) {}
+ // }
+ //
+ // void f(C c) {
+ // c.m([!a!]: 1);
+ // }
+ // ```
+ //
+ // #### Common fixes
+ //
+ // If the argument name is mistyped, then replace it with the correct name.
+ // The example above can be fixed by changing `a` to `b`:
+ //
+ // ```dart
+ // class C {
+ // m({int b}) {}
+ // }
+ //
+ // void f(C c) {
+ // c.m(b: 1);
+ // }
+ // ```
+ //
+ // If a subclass adds a parameter with the name in question, then cast the
+ // target to the subclass:
+ //
+ // ```dart
+ // class C {
+ // m({int b}) {}
+ // }
+ //
+ // class D extends C {
+ // m({int a, int b}) {}
+ // }
+ //
+ // void f(C c) {
+ // (c as D).m(a: 1);
+ // }
+ // ```
+ //
+ // If the parameter should be added to the function, then add it:
+ //
+ // ```dart
+ // class C {
+ // m({int a, int b}) {}
+ // }
+ //
+ // void f(C c) {
+ // c.m(a: 1);
+ // }
+ // ```
static const CompileTimeErrorCode UNDEFINED_NAMED_PARAMETER =
const CompileTimeErrorCode('UNDEFINED_NAMED_PARAMETER',
"The named parameter '{0}' isn't defined.",
correction:
"Try correcting the name to an existing named parameter's name, "
- "or defining a named parameter with the name '{0}'.");
+ "or defining a named parameter with the name '{0}'.",
+ hasPublishedDocs: true);
/**
* Parameters:
@@ -3459,7 +3565,8 @@
const CompileTimeErrorCode(
'URI_DOES_NOT_EXIST', "Target of URI doesn't exist: '{0}'.",
correction: "Try creating the file referenced by the URI, or "
- "Try using a URI for a file that does exist.");
+ "Try using a URI for a file that does exist.",
+ hasPublishedDocs: true);
/**
* Parameters:
@@ -3498,7 +3605,8 @@
const CompileTimeErrorCode('URI_HAS_NOT_BEEN_GENERATED',
"Target of URI hasn't been generated: '{0}'.",
correction: "Try running the generator that will generate the file "
- "referenced by the URI.");
+ "referenced by the URI.",
+ hasPublishedDocs: true);
/**
* 14.1 Imports: It is a compile-time error if <i>x</i> is not a compile-time
@@ -3622,7 +3730,7 @@
* error to be generated and for the error message to explain what is wrong and,
* when appropriate, how the problem can be corrected.
*/
-class StaticTypeWarningCode extends ErrorCode {
+class StaticTypeWarningCode extends AnalyzerErrorCode {
/**
* 12.7 Lists: A fresh instance (7.6.1) <i>a</i>, of size <i>n</i>, whose
* class implements the built-in class <i>List<E></i> is allocated.
@@ -3755,6 +3863,7 @@
//
// ```dart
// typedef Binary = int Function(int, int);
+ //
// int f() {
// return [!Binary!](1, 2);
// }
@@ -3770,7 +3879,8 @@
// better error and correction messages.
correction:
"Try correcting the name to match an existing function, or "
- "define a method or function named '{0}'.");
+ "define a method or function named '{0}'.",
+ hasPublishedDocs: true);
/**
* 12.14.4 Function Expression Invocation: A function expression invocation
@@ -3870,6 +3980,7 @@
"The name '{0}' isn't a type so it can't be used as a type argument.",
correction: "Try correcting the name to an existing type, or "
"defining a type named '{0}'.",
+ hasPublishedDocs: true,
isUnresolvedIdentifier: true);
/**
@@ -3950,6 +4061,7 @@
//
// ```dart
// List<int> empty() => [];
+ //
// void main() {
// print([!emty!]());
// }
@@ -3963,6 +4075,7 @@
//
// ```dart
// List<int> empty() => [];
+ //
// void main() {
// print(empty());
// }
@@ -3976,6 +4089,7 @@
correction: "Try importing the library that defines '{0}', "
"correcting the name to the name of an existing function, or "
"defining a function named '{0}'.",
+ hasPublishedDocs: true,
isUnresolvedIdentifier: true);
/**
@@ -3994,12 +4108,7 @@
// The following code produces this diagnostic:
//
// ```dart
- // class Point {
- // final int x;
- // final int y;
- // Point(this.x, this.y);
- // operator +(Point other) => Point(x + other.x, y + other.[!z!]);
- // }
+ // int f(String s) => s.[!len!];
// ```
//
// #### Common fix
@@ -4009,12 +4118,7 @@
// fixing the spelling of the getter:
//
// ```dart
- // class Point {
- // final int x;
- // final int y;
- // Point(this.x, this.y);
- // operator +(Point other) => Point(x + other.x, y + other.y);
- // }
+ // int f(String s) => s.length;
// ```
static const StaticTypeWarningCode UNDEFINED_GETTER =
// TODO(brianwilkerson) When the "target" is an enum, report
@@ -4023,7 +4127,8 @@
"The getter '{0}' isn't defined for the class '{1}'.",
correction: "Try importing the library that defines '{0}', "
"correcting the name to the name of an existing getter, or "
- "defining a getter or field named '{0}'.");
+ "defining a getter or field named '{0}'.",
+ hasPublishedDocs: true);
/**
* Parameters:
@@ -4058,7 +4163,8 @@
"The method '{0}' isn't defined for the class '{1}'.",
correction:
"Try correcting the name to the name of an existing method, or "
- "defining a method named '{0}'.");
+ "defining a method named '{0}'.",
+ hasPublishedDocs: true);
/**
* 12.18 Assignment: Evaluation of an assignment of the form
@@ -4143,7 +4249,8 @@
"The setter '{0}' isn't defined for the class '{1}'.",
correction: "Try importing the library that defines '{0}', "
"correcting the name to the name of an existing setter, or "
- "defining a setter or field named '{0}'.");
+ "defining a setter or field named '{0}'.",
+ hasPublishedDocs: true);
/**
* 12.17 Getter Invocation: Let <i>T</i> be the static type of <i>e</i>. It is
@@ -4367,7 +4474,7 @@
* to be generated and for the error message to explain what is wrong and, when
* appropriate, how the problem can be corrected.
*/
-class StaticWarningCode extends ErrorCode {
+class StaticWarningCode extends AnalyzerErrorCode {
/**
* 14.1 Imports: If a name <i>N</i> is referenced by a library <i>L</i> and
* <i>N</i> is introduced into the top level scope <i>L</i> by more than one
@@ -4444,7 +4551,8 @@
const StaticWarningCode(
'ARGUMENT_TYPE_NOT_ASSIGNABLE',
"The argument type '{0}' can't be assigned to the parameter type "
- "'{1}'.");
+ "'{1}'.",
+ hasPublishedDocs: true);
/**
* 5 Variables: Attempting to assign to a final variable elsewhere will cause
@@ -4582,32 +4690,14 @@
correction:
"Try adding a hide clause to one of the export directives.");
- /**
- * 12.14.2 Binding Actuals to Formals: It is a static warning if <i>m <
- * h</i> or if <i>m > n</i>.
- *
- * Parameters:
- * 0: the maximum number of positional arguments
- * 1: the actual number of positional arguments given
- */
- static const StaticWarningCode EXTRA_POSITIONAL_ARGUMENTS =
- const StaticWarningCode('EXTRA_POSITIONAL_ARGUMENTS',
- "Too many positional arguments: {0} expected, but {1} found.",
- correction: "Try removing the extra positional arguments.");
+ @Deprecated('Use CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS')
+ static const CompileTimeErrorCode EXTRA_POSITIONAL_ARGUMENTS =
+ CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS;
- /**
- * 12.14.2 Binding Actuals to Formals: It is a static warning if <i>m <
- * h</i> or if <i>m > n</i>.
- *
- * Parameters:
- * 0: the maximum number of positional arguments
- * 1: the actual number of positional arguments given
- */
- static const StaticWarningCode EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED =
- const StaticWarningCode('EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED',
- "Too many positional arguments: {0} expected, but {1} found.",
- correction: "Try removing the extra positional arguments, "
- "or specifying the name for named arguments.");
+ @Deprecated(
+ 'Use CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED')
+ static const CompileTimeErrorCode EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED =
+ CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED;
/**
* 5. Variables: It is a static warning if a final instance variable that has
@@ -4764,19 +4854,9 @@
"'{2}'.",
correction: "Try adding a hide clause to one of the imports.");
- /**
- * 14.1 Imports: It is a static warning if the specified URI of a deferred
- * import does not refer to a library declaration.
- *
- * Parameters:
- * 0: the uri pointing to a non-library declaration
- *
- * See [CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY].
- */
- static const StaticWarningCode IMPORT_OF_NON_LIBRARY =
- const StaticWarningCode('IMPORT_OF_NON_LIBRARY',
- "The imported library '{0}' can't have a part-of directive.",
- correction: "Try importing the library that the part is a part of.");
+ @Deprecated('Use CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY')
+ static const CompileTimeErrorCode IMPORT_OF_NON_LIBRARY =
+ CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY;
/**
* 7.1 Instance Methods: It is a static warning if an instance method
@@ -5194,20 +5274,12 @@
// Replace the name with the name of a type.
static const StaticWarningCode NOT_A_TYPE = const StaticWarningCode(
'NOT_A_TYPE', "{0} isn't a type.",
- correction: "Try correcting the name to match an existing type.");
+ correction: "Try correcting the name to match an existing type.",
+ hasPublishedDocs: true);
- /**
- * 12.14.2 Binding Actuals to Formals: It is a static warning if <i>m <
- * h</i> or if <i>m > n</i>.
- *
- * Parameters:
- * 0: the expected number of required arguments
- * 1: the actual number of positional arguments given
- */
- static const StaticWarningCode NOT_ENOUGH_REQUIRED_ARGUMENTS =
- const StaticWarningCode('NOT_ENOUGH_REQUIRED_ARGUMENTS',
- "{0} required argument(s) expected, but {1} found.",
- correction: "Try adding the additional required arguments.");
+ @Deprecated('Use CompileTimeErrorCode.NOT_ENOUGH_POSITIONAL_ARGUMENTS')
+ static const CompileTimeErrorCode NOT_ENOUGH_REQUIRED_ARGUMENTS =
+ CompileTimeErrorCode.NOT_ENOUGH_POSITIONAL_ARGUMENTS;
/**
* 14.3 Parts: It is a static warning if the referenced part declaration
@@ -5258,31 +5330,13 @@
"invoking the desired constructor rather than redirecting to "
"it.");
- /**
- * 7.6.2 Factories: It is a static warning if type does not denote a class
- * accessible in the current scope; if type does denote such a class <i>C</i>
- * it is a static warning if the referenced constructor (be it <i>type</i> or
- * <i>type.id</i>) is not a constructor of <i>C</i>.
- */
- static const StaticWarningCode REDIRECT_TO_MISSING_CONSTRUCTOR =
- const StaticWarningCode('REDIRECT_TO_MISSING_CONSTRUCTOR',
- "The constructor '{0}' couldn't be found in '{1}'.",
- correction:
- "Try correcting the constructor name to an existing constructor, "
- "or defining the constructor in '{1}'.");
+ @Deprecated('Use CompileTimeErrorCode.REDIRECT_TO_MISSING_CONSTRUCTOR')
+ static const CompileTimeErrorCode REDIRECT_TO_MISSING_CONSTRUCTOR =
+ CompileTimeErrorCode.REDIRECT_TO_MISSING_CONSTRUCTOR;
- /**
- * 7.6.2 Factories: It is a static warning if type does not denote a class
- * accessible in the current scope; if type does denote such a class <i>C</i>
- * it is a static warning if the referenced constructor (be it <i>type</i> or
- * <i>type.id</i>) is not a constructor of <i>C</i>.
- */
- static const StaticWarningCode REDIRECT_TO_NON_CLASS =
- const StaticWarningCode(
- 'REDIRECT_TO_NON_CLASS',
- "The name '{0}' isn't a type and can't be used in a redirected "
- "constructor.",
- correction: "Try correcting the name to match an existing class.");
+ @Deprecated('Use CompileTimeErrorCode.REDIRECT_TO_NON_CLASS')
+ static const CompileTimeErrorCode REDIRECT_TO_NON_CLASS =
+ CompileTimeErrorCode.REDIRECT_TO_NON_CLASS;
/**
* 13.12 Return: Let <i>f</i> be the function immediately enclosing a return
@@ -5378,50 +5432,13 @@
correction: "Try removing the reference to the type parameter, or "
"making the member an instance member.");
- /**
- * Parameters:
- * 0: the name of the undefined class
- */
- // #### Description
- //
- // The analyzer produces this diagnostic when it encounters an identifier that
- // appears to be the name of a class but either isn't defined or isn't visible
- // in the scope in which it's being referenced.
- //
- // #### Example
- //
- // The following code produces this diagnostic:
- //
- // ```dart
- // class Point {}
- // void main() {
- // [!Piont!] p;
- // }
- // ```
- //
- // #### Common fixes
- //
- // If the identifier isn't defined, then either define it or replace it with
- // the name of a class that is defined. The example above can be corrected by
- // fixing the spelling of the class:
- //
- // ```dart
- // class Point {}
- // void main() {
- // Point p;
- // }
- // ```
- //
- // If the class is defined but isn't visible, then you probably need to add an
- // import.
- static const StaticWarningCode UNDEFINED_CLASS = const StaticWarningCode(
- 'UNDEFINED_CLASS', "Undefined class '{0}'.",
- correction: "Try changing the name to the name of an existing class, or "
- "creating a class with the name '{0}'.",
- isUnresolvedIdentifier: true);
+ @Deprecated('Use CompileTimeErrorCode.UNDEFINED_CLASS')
+ static const CompileTimeErrorCode UNDEFINED_CLASS =
+ CompileTimeErrorCode.UNDEFINED_CLASS;
/**
- * Same as [UNDEFINED_CLASS], but to catch using "boolean" instead of "bool".
+ * Same as [CompileTimeErrorCode.UNDEFINED_CLASS], but to catch using
+ * "boolean" instead of "bool".
*/
static const StaticWarningCode UNDEFINED_CLASS_BOOLEAN =
const StaticWarningCode(
@@ -5462,6 +5479,7 @@
const StaticWarningCode('UNDEFINED_IDENTIFIER', "Undefined name '{0}'.",
correction: "Try correcting the name to one that is defined, or "
"defining the name.",
+ hasPublishedDocs: true,
isUnresolvedIdentifier: true);
/**
@@ -5474,74 +5492,9 @@
"defining the name, or "
"adding 'async' to the enclosing function body.");
- /**
- * Parameters:
- * 0: the name of the requested named parameter
- */
- // #### Description
- //
- // The analyzer produces this diagnostic when a method or function invocation
- // has a named argument, but the method or function being invoked doesn’t
- // define a parameter with the same name.
- //
- // #### Example
- //
- // The following code produces this diagnostic:
- //
- // ```dart
- // class C {
- // m({int b}) {}
- // }
- // void f(C c) {
- // c.m([!a!]: 1);
- // }
- // ```
- //
- // #### Common fixes
- //
- // If the argument name is mistyped, then replace it with the correct name.
- // The example above can be fixed by changing `a` to `b`:
- //
- // ```dart
- // class C {
- // m({int b}) {}
- // }
- // void f(C c) {
- // c.m(b: 1);
- // }
- // ```
- //
- // If a subclass adds a parameter with the name in question, then cast the
- // target to the subclass:
- //
- // ```dart
- // class C {
- // m({int b}) {}
- // }
- // class D extends C {
- // m({int a, int b}) {}
- // }
- // void f(C c) {
- // (c as D).m(a: 1);
- // }
- // ```
- //
- // If the parameter should be added to the function, then add it:
- //
- // ```dart
- // class C {
- // m({int a, int b}) {}
- // }
- // void f(C c) {
- // c.m(a: 1);
- // }
- // ```
- static const StaticWarningCode UNDEFINED_NAMED_PARAMETER =
- const StaticWarningCode('UNDEFINED_NAMED_PARAMETER',
- "The named parameter '{0}' isn't defined.",
- correction:
- "Try correcting the name to an existing named parameter, or "
- "defining a new parameter with this name.");
+ @Deprecated('Use CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER')
+ static const CompileTimeErrorCode UNDEFINED_NAMED_PARAMETER =
+ CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER;
/**
* For the purposes of experimenting with potential non-null type semantics.
diff --git a/pkg/analyzer/lib/src/error/literal_element_verifier.dart b/pkg/analyzer/lib/src/error/literal_element_verifier.dart
index 1e9916c..5e2e26c 100644
--- a/pkg/analyzer/lib/src/error/literal_element_verifier.dart
+++ b/pkg/analyzer/lib/src/error/literal_element_verifier.dart
@@ -86,8 +86,7 @@
CompileTimeErrorCode.MAP_ENTRY_NOT_IN_MAP, element);
}
} else if (element is SpreadElement) {
- var isNullAware = element.spreadOperator.type ==
- TokenType.PERIOD_PERIOD_PERIOD_QUESTION;
+ var isNullAware = element.isNullAware;
Expression expression = element.expression;
if (forList || forSet) {
_verifySpreadForListOrSet(isNullAware, expression);
diff --git a/pkg/analyzer/lib/src/error/type_arguments_verifier.dart b/pkg/analyzer/lib/src/error/type_arguments_verifier.dart
index 634f41a..3d1dfab 100644
--- a/pkg/analyzer/lib/src/error/type_arguments_verifier.dart
+++ b/pkg/analyzer/lib/src/error/type_arguments_verifier.dart
@@ -352,7 +352,7 @@
//
// <TFrom, TTo extends TFrom>
// <TFrom, TTo extends Iterable<TFrom>>
- // <T extends Clonable<T>>
+ // <T extends Cloneable<T>>
//
DartType argType = typeArgs[i];
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index e270587..f45a35a 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -15,7 +15,6 @@
CompilationUnitImpl,
ExtensionDeclarationImpl,
MixinDeclarationImpl;
-import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/fasta/error_converter.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:front_end/src/fasta/messages.dart'
@@ -37,7 +36,6 @@
messageInvalidThisInInitializer,
messageMissingAssignableSelector,
messageNativeClauseShouldBeAnnotation,
- messageStaticConstructor,
messageTypedefNotFunction,
templateDuplicateLabelInSwitchStatement,
templateExpectedButGot,
@@ -47,7 +45,7 @@
import 'package:front_end/src/fasta/parser.dart'
show
Assert,
- ClassKind,
+ DeclarationKind,
FormalParameterKind,
IdentifierContext,
MemberKind,
@@ -277,11 +275,7 @@
: (mixinDeclaration != null
? mixinDeclaration.name.name
: extensionDeclaration.name?.name);
- if (name?.lexeme == className && getOrSet == null) {
- // This error is also reported in OutlineBuilder.beginMethod
- handleRecoverableError(
- messageStaticConstructor, staticToken, staticToken);
- } else {
+ if (name?.lexeme != className || getOrSet != null) {
modifiers.staticKeyword = staticToken;
}
}
@@ -649,8 +643,8 @@
}
@override
- void endClassOrMixinBody(
- ClassKind kind, int memberCount, Token leftBracket, Token rightBracket) {
+ void endClassOrMixinBody(DeclarationKind kind, int memberCount,
+ Token leftBracket, Token rightBracket) {
// TODO(danrubel): consider renaming endClassOrMixinBody
// to endClassOrMixinOrExtensionBody
assert(optional('{', leftBracket));
@@ -834,11 +828,11 @@
}
@override
- void endFactoryMethod(
+ void endClassFactoryMethod(
Token beginToken, Token factoryKeyword, Token endToken) {
assert(optional('factory', factoryKeyword));
assert(optional(';', endToken) || optional('}', endToken));
- debugEvent("FactoryMethod");
+ debugEvent("ClassFactoryMethod");
FunctionBody body;
Token separator;
@@ -885,15 +879,6 @@
ast.simpleIdentifier(typeName.identifier.token, isDeclaration: true);
}
- if (extensionDeclaration != null) {
- // TODO(brianwilkerson) Decide how to handle constructor and field
- // declarations within extensions. They are invalid, but we might want to
- // resolve them in order to get navigation, search, etc.
- errorReporter.errorReporter.reportErrorForNode(
- CompileTimeErrorCode.EXTENSION_DECLARES_CONSTRUCTOR,
- name ?? returnType);
- return;
- }
currentDeclarationMembers.add(ast.constructorDeclaration(
comment,
metadata,
@@ -910,6 +895,71 @@
body));
}
+ @override
+ void endMixinFactoryMethod(
+ Token beginToken, Token factoryKeyword, Token endToken) {
+ debugEvent("MixinFactoryMethod");
+ endClassFactoryMethod(beginToken, factoryKeyword, endToken);
+ }
+
+ @override
+ void endExtensionFactoryMethod(
+ Token beginToken, Token factoryKeyword, Token endToken) {
+ assert(optional('factory', factoryKeyword));
+ assert(optional(';', endToken) || optional('}', endToken));
+ debugEvent("ExtensionFactoryMethod");
+
+ Object bodyObject = pop();
+ FormalParameterList parameters = pop();
+ TypeParameterList typeParameters = pop();
+ Object constructorName = pop();
+ _Modifiers modifiers = pop();
+ List<Annotation> metadata = pop();
+
+ FunctionBody body;
+ if (bodyObject is FunctionBody) {
+ body = bodyObject;
+ } else if (bodyObject is _RedirectingFactoryBody) {
+ body = ast.emptyFunctionBody(endToken);
+ } else {
+ // Unhandled situation which should never happen.
+ // Since this event handler is just a recovery attempt,
+ // don't bother adding this declaration to the AST.
+ return;
+ }
+ Comment comment = _findComment(metadata, beginToken);
+
+ assert(parameters != null);
+
+ // Constructor declarations within extensions are invalid and the parser
+ // has already reported an error at this point, but we include them in as
+ // a method declaration in order to get navigation, search, etc.
+
+ SimpleIdentifier methodName;
+ if (constructorName is SimpleIdentifier) {
+ methodName = constructorName;
+ } else if (constructorName is PrefixedIdentifier) {
+ methodName = constructorName.identifier;
+ } else {
+ // Unsure what the method name should be in this situation.
+ // Since this event handler is just a recovery attempt,
+ // don't bother adding this declaration to the AST.
+ return;
+ }
+ currentDeclarationMembers.add(ast.methodDeclaration(
+ comment,
+ metadata,
+ modifiers?.externalKeyword,
+ modifiers?.abstractKeyword ?? modifiers?.staticKeyword,
+ null, // returnType
+ null, // getOrSet
+ null, // operatorKeyword
+ methodName,
+ typeParameters,
+ parameters,
+ body));
+ }
+
void endFieldInitializer(Token assignment, Token token) {
assert(optional('=', assignment));
debugEvent("FieldInitializer");
@@ -920,7 +970,7 @@
}
@override
- void endFields(Token staticToken, Token covariantToken, Token lateToken,
+ void endClassFields(Token staticToken, Token covariantToken, Token lateToken,
Token varFinalOrConst, int count, Token beginToken, Token semicolon) {
assert(optional(';', semicolon));
debugEvent("Fields");
@@ -936,17 +986,6 @@
Token covariantKeyword = covariantToken;
List<Annotation> metadata = pop();
Comment comment = _findComment(metadata, beginToken);
- if (extensionDeclaration != null && staticToken == null) {
- // TODO(brianwilkerson) Decide how to handle constructor and field
- // declarations within extensions. They are invalid, but we might want to
- // resolve them in order to get navigation, search, etc.
- for (VariableDeclaration variable in variables) {
- errorReporter.errorReporter.reportErrorForNode(
- CompileTimeErrorCode.EXTENSION_DECLARES_INSTANCE_FIELD,
- variable.name);
- }
- return;
- }
currentDeclarationMembers.add(ast.fieldDeclaration2(
comment: comment,
metadata: metadata,
@@ -957,6 +996,32 @@
}
@override
+ void endMixinFields(Token staticToken, Token covariantToken, Token lateToken,
+ Token varFinalOrConst, int count, Token beginToken, Token endToken) {
+ endClassFields(staticToken, covariantToken, lateToken, varFinalOrConst,
+ count, beginToken, endToken);
+ }
+
+ @override
+ void endExtensionFields(
+ Token staticToken,
+ Token covariantToken,
+ Token lateToken,
+ Token varFinalOrConst,
+ int count,
+ Token beginToken,
+ Token endToken) {
+ if (staticToken == null) {
+ // TODO(danrubel) Decide how to handle instance field declarations
+ // within extensions. They are invalid and the parser has already reported
+ // an error at this point, but we include them in order to get navigation,
+ // search, etc.
+ }
+ endClassFields(staticToken, covariantToken, lateToken, varFinalOrConst,
+ count, beginToken, endToken);
+ }
+
+ @override
void endForControlFlow(Token token) {
debugEvent("endForControlFlow");
var entry = pop();
@@ -1499,12 +1564,90 @@
}
@override
- void endMethod(Token getOrSet, Token beginToken, Token beginParam,
+ void endClassMethod(Token getOrSet, Token beginToken, Token beginParam,
Token beginInitializers, Token endToken) {
assert(getOrSet == null ||
optional('get', getOrSet) ||
optional('set', getOrSet));
- debugEvent("Method");
+ debugEvent("ClassMethod");
+
+ var bodyObject = pop();
+ pop(); // initializers
+ pop(); // separator
+ FormalParameterList parameters = pop();
+ TypeParameterList typeParameters = pop();
+ var name = pop();
+ TypeAnnotation returnType = pop();
+ _Modifiers modifiers = pop();
+ List<Annotation> metadata = pop();
+ Comment comment = _findComment(metadata, beginToken);
+
+ assert(parameters != null || optional('get', getOrSet));
+
+ FunctionBody body;
+ if (bodyObject is FunctionBody) {
+ body = bodyObject;
+ } else if (bodyObject is _RedirectingFactoryBody) {
+ body = ast.emptyFunctionBody(endToken);
+ } else {
+ unhandled("${bodyObject.runtimeType}", "bodyObject",
+ beginToken.charOffset, uri);
+ }
+
+ Token operatorKeyword;
+ SimpleIdentifier nameId;
+ if (name is SimpleIdentifier) {
+ nameId = name;
+ } else if (name is _OperatorName) {
+ operatorKeyword = name.operatorKeyword;
+ nameId = name.name;
+ } else {
+ throw new UnimplementedError();
+ }
+
+ if (modifiers?.constKeyword != null) {
+ // This error is also reported in OutlineBuilder.endMethod
+ handleRecoverableError(
+ messageConstMethod, modifiers.constKeyword, modifiers.constKeyword);
+ }
+ checkFieldFormalParameters(parameters);
+ currentDeclarationMembers.add(ast.methodDeclaration(
+ comment,
+ metadata,
+ modifiers?.externalKeyword,
+ modifiers?.abstractKeyword ?? modifiers?.staticKeyword,
+ returnType,
+ getOrSet,
+ operatorKeyword,
+ nameId,
+ typeParameters,
+ parameters,
+ body));
+ }
+
+ @override
+ void endMixinMethod(Token getOrSet, Token beginToken, Token beginParam,
+ Token beginInitializers, Token endToken) {
+ debugEvent("MixinMethod");
+ endClassMethod(
+ getOrSet, beginToken, beginParam, beginInitializers, endToken);
+ }
+
+ @override
+ void endExtensionMethod(Token getOrSet, Token beginToken, Token beginParam,
+ Token beginInitializers, Token endToken) {
+ debugEvent("ExtensionMethod");
+ endClassMethod(
+ getOrSet, beginToken, beginParam, beginInitializers, endToken);
+ }
+
+ @override
+ void endClassConstructor(Token getOrSet, Token beginToken, Token beginParam,
+ Token beginInitializers, Token endToken) {
+ assert(getOrSet == null ||
+ optional('get', getOrSet) ||
+ optional('set', getOrSet));
+ debugEvent("ClassConstructor");
var bodyObject = pop();
List<ConstructorInitializer> initializers = pop() ?? const [];
@@ -1532,97 +1675,78 @@
beginToken.charOffset, uri);
}
- void constructor(
- SimpleIdentifier prefixOrName, Token period, SimpleIdentifier name) {
- if (typeParameters != null) {
- // Outline builder also reports this error message.
- handleRecoverableError(messageConstructorWithTypeParameters,
- typeParameters.beginToken, typeParameters.endToken);
- }
- if (modifiers?.constKeyword != null &&
- body != null &&
- (body.length > 1 || body.beginToken?.lexeme != ';')) {
- // This error is also reported in BodyBuilder.finishFunction
- Token bodyToken = body.beginToken ?? modifiers.constKeyword;
- handleRecoverableError(
- messageConstConstructorWithBody, bodyToken, bodyToken);
- }
- if (returnType != null) {
- // This error is also reported in OutlineBuilder.endMethod
- handleRecoverableError(messageConstructorWithReturnType,
- returnType.beginToken, returnType.beginToken);
- }
- ConstructorDeclaration constructor = ast.constructorDeclaration(
- comment,
- metadata,
- modifiers?.externalKeyword,
- modifiers?.finalConstOrVarKeyword,
- null,
- // TODO(paulberry): factoryKeyword
- ast.simpleIdentifier(prefixOrName.token),
- period,
- name,
- parameters,
- separator,
- initializers,
- redirectedConstructor,
- body);
- if (extensionDeclaration != null) {
- // TODO(brianwilkerson) Decide how to handle constructor and field
- // declarations within extensions. They are invalid, but we might want
- // to resolve them in order to get navigation, search, etc.
- errorReporter.errorReporter.reportErrorForNode(
- CompileTimeErrorCode.EXTENSION_DECLARES_CONSTRUCTOR,
- name ?? prefixOrName);
- return;
- }
- currentDeclarationMembers.add(constructor);
- if (mixinDeclaration != null) {
- // TODO (danrubel): Report an error if this is a mixin declaration.
- }
- }
-
- void method(Token operatorKeyword, SimpleIdentifier name) {
- if (modifiers?.constKeyword != null) {
- // This error is also reported in OutlineBuilder.endMethod
- handleRecoverableError(
- messageConstMethod, modifiers.constKeyword, modifiers.constKeyword);
- }
- checkFieldFormalParameters(parameters);
- if (extensionDeclaration != null && body is EmptyFunctionBody) {
- errorReporter.errorReporter.reportErrorForNode(
- CompileTimeErrorCode.EXTENSION_DECLARES_ABSTRACT_MEMBER, name);
- return;
- }
- currentDeclarationMembers.add(ast.methodDeclaration(
- comment,
- metadata,
- modifiers?.externalKeyword,
- modifiers?.abstractKeyword ?? modifiers?.staticKeyword,
- returnType,
- getOrSet,
- operatorKeyword,
- name,
- typeParameters,
- parameters,
- body));
- }
-
+ SimpleIdentifier prefixOrName;
+ Token period;
+ SimpleIdentifier nameOrNull;
if (name is SimpleIdentifier) {
- if (name.name == currentDeclarationName?.name && getOrSet == null) {
- constructor(name, null, null);
- } else if (initializers.isNotEmpty && getOrSet == null) {
- constructor(name, null, null);
- } else {
- method(null, name);
- }
- } else if (name is _OperatorName) {
- method(name.operatorKeyword, name.name);
+ prefixOrName = name;
} else if (name is PrefixedIdentifier) {
- constructor(name.prefix, name.period, name.identifier);
+ prefixOrName = name.prefix;
+ period = name.period;
+ nameOrNull = name.identifier;
} else {
throw new UnimplementedError();
}
+
+ if (typeParameters != null) {
+ // Outline builder also reports this error message.
+ handleRecoverableError(messageConstructorWithTypeParameters,
+ typeParameters.beginToken, typeParameters.endToken);
+ }
+ if (modifiers?.constKeyword != null &&
+ body != null &&
+ (body.length > 1 || body.beginToken?.lexeme != ';')) {
+ // This error is also reported in BodyBuilder.finishFunction
+ Token bodyToken = body.beginToken ?? modifiers.constKeyword;
+ handleRecoverableError(
+ messageConstConstructorWithBody, bodyToken, bodyToken);
+ }
+ if (returnType != null) {
+ // This error is also reported in OutlineBuilder.endMethod
+ handleRecoverableError(messageConstructorWithReturnType,
+ returnType.beginToken, returnType.beginToken);
+ }
+ ConstructorDeclaration constructor = ast.constructorDeclaration(
+ comment,
+ metadata,
+ modifiers?.externalKeyword,
+ modifiers?.finalConstOrVarKeyword,
+ null,
+ // TODO(paulberry): factoryKeyword
+ ast.simpleIdentifier(prefixOrName.token),
+ period,
+ nameOrNull,
+ parameters,
+ separator,
+ initializers,
+ redirectedConstructor,
+ body);
+ currentDeclarationMembers.add(constructor);
+ if (mixinDeclaration != null) {
+ // TODO (danrubel): Report an error if this is a mixin declaration.
+ }
+ }
+
+ @override
+ void endMixinConstructor(Token getOrSet, Token beginToken, Token beginParam,
+ Token beginInitializers, Token endToken) {
+ debugEvent("MixinConstructor");
+ // TODO(danrubel) Decide how to handle constructor declarations within
+ // mixins. They are invalid, but we include them in order to get navigation,
+ // search, etc. Currently the error is reported by multiple listeners,
+ // but should be moved into the parser.
+ endClassConstructor(
+ getOrSet, beginToken, beginParam, beginInitializers, endToken);
+ }
+
+ @override
+ void endExtensionConstructor(Token getOrSet, Token beginToken,
+ Token beginParam, Token beginInitializers, Token endToken) {
+ debugEvent("ExtensionConstructor");
+ // TODO(danrubel) Decide how to handle constructor declarations within
+ // extensions. They are invalid and the parser has already reported an
+ // error at this point. In the future, we should include them in order
+ // to get navigation, search, etc.
}
@override
diff --git a/pkg/analyzer/lib/src/generated/declaration_resolver.dart b/pkg/analyzer/lib/src/generated/declaration_resolver.dart
index 0ffaae8..6184e13 100644
--- a/pkg/analyzer/lib/src/generated/declaration_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/declaration_resolver.dart
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_ast_factory.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
@@ -299,6 +298,14 @@
_walk(new ElementWalker.forGenericFunctionType(element), () {
super.visitGenericFunctionType(node);
});
+ } else {
+ var builder = new LocalElementBuilder(ElementHolder(), _enclosingUnit);
+ node.accept(builder);
+
+ var nodeImpl = node as GenericFunctionTypeImpl;
+ _enclosingUnit.encloseElement(
+ nodeImpl.declaredElement as GenericFunctionTypeElementImpl,
+ );
}
}
}
@@ -561,168 +568,6 @@
_walker = outerWalker;
}
- /// Apply the [type] that is created by the [constructorName] and the
- /// [constructorElement] it references.
- static void applyConstructorElement(
- LibraryElement enclosingLibraryElement,
- PrefixElement prefixElement,
- ConstructorElement constructorElement,
- DartType type,
- ConstructorName constructorName) {
- constructorName.staticElement = constructorElement;
-
- ClassElement classElement = constructorElement?.enclosingElement;
-
- Identifier typeIdentifier = constructorName.type.name;
- if (prefixElement != null) {
- PrefixedIdentifier prefixedTypeIdentifier = typeIdentifier;
- prefixedTypeIdentifier.staticType = type;
-
- prefixedTypeIdentifier.prefix.staticElement = prefixElement;
-
- SimpleIdentifier classNode = prefixedTypeIdentifier.identifier;
- classNode.staticElement = classElement;
- classNode.staticType = type;
- } else {
- if (typeIdentifier is SimpleIdentifier) {
- typeIdentifier.staticElement = classElement;
- typeIdentifier.staticType = type;
- } else if (typeIdentifier is PrefixedIdentifier) {
- constructorName.type = astFactory.typeName(typeIdentifier.prefix, null);
- constructorName.period = typeIdentifier.period;
- constructorName.name = typeIdentifier.identifier;
- }
- }
-
- constructorName.name?.staticElement = constructorElement;
-
- DeclarationResolver.applyToTypeAnnotation(
- enclosingLibraryElement, type, constructorName.type);
- }
-
- /// Apply the types of the [parameterElements] to the [parameterList] that
- /// have an explicit type annotation.
- static void applyParameters(
- LibraryElement enclosingLibraryElement,
- List<ParameterElement> parameterElements,
- FormalParameterList parameterList) {
- List<FormalParameter> parameters = parameterList.parameters;
-
- int length = parameterElements.length;
- if (parameters.length != length) {
- throw new StateError('Parameter counts do not match');
- }
- for (int i = 0; i < length; i++) {
- ParameterElementImpl element = parameterElements[i];
- FormalParameter parameter = parameters[i];
-
- DeclarationResolver.resolveMetadata(
- parameter, parameter.metadata, element);
-
- NormalFormalParameter normalParameter;
- if (parameter is NormalFormalParameter) {
- normalParameter = parameter;
- } else if (parameter is DefaultFormalParameter) {
- normalParameter = parameter.parameter;
- }
- assert(normalParameter != null);
-
- if (normalParameter is SimpleFormalParameterImpl) {
- normalParameter.declaredElement = element;
- }
-
- if (normalParameter.identifier != null) {
- element.nameOffset = normalParameter.identifier.offset;
- normalParameter.identifier.staticElement = element;
- normalParameter.identifier.staticType = element.type;
- }
-
- // Apply the type or the return type, if a function typed parameter.
- TypeAnnotation functionReturnType;
- FormalParameterList functionParameterList;
- if (normalParameter is SimpleFormalParameter) {
- applyToTypeAnnotation(
- enclosingLibraryElement, element.type, normalParameter.type);
- } else if (normalParameter is FunctionTypedFormalParameter) {
- functionReturnType = normalParameter.returnType;
- functionParameterList = normalParameter.parameters;
- } else if (normalParameter is FieldFormalParameter) {
- if (normalParameter.parameters == null) {
- applyToTypeAnnotation(
- enclosingLibraryElement, element.type, normalParameter.type);
- } else {
- functionReturnType = normalParameter.type;
- functionParameterList = normalParameter.parameters;
- }
- }
-
- if (functionParameterList != null) {
- FunctionType elementType = element.type;
- if (functionReturnType != null) {
- applyToTypeAnnotation(enclosingLibraryElement, elementType.returnType,
- functionReturnType);
- }
- applyParameters(enclosingLibraryElement, elementType.parameters,
- functionParameterList);
- }
- }
- }
-
- /// Apply the [type] to the [typeAnnotation] by setting the type of the
- /// [typeAnnotation] to the [type] and recursively applying each of the type
- /// arguments of the [type] to the corresponding type arguments of the
- /// [typeAnnotation].
- static void applyToTypeAnnotation(LibraryElement enclosingLibraryElement,
- DartType type, TypeAnnotation typeAnnotation) {
- if (typeAnnotation is GenericFunctionTypeImpl) {
- if (type is! FunctionType) {
- throw new StateError('Non-function type ($type) '
- 'for generic function annotation ($typeAnnotation)');
- }
- FunctionType functionType = type;
- typeAnnotation.type = type;
- applyToTypeAnnotation(enclosingLibraryElement, functionType.returnType,
- typeAnnotation.returnType);
- applyParameters(enclosingLibraryElement, functionType.parameters,
- typeAnnotation.parameters);
- } else if (typeAnnotation is TypeNameImpl) {
- typeAnnotation.type = type;
-
- Identifier typeIdentifier = typeAnnotation.name;
- SimpleIdentifier typeName;
- if (typeIdentifier is PrefixedIdentifier) {
- if (enclosingLibraryElement != null) {
- String prefixName = typeIdentifier.prefix.name;
- for (var import in enclosingLibraryElement.imports) {
- if (import.prefix?.name == prefixName) {
- typeIdentifier.prefix.staticElement = import.prefix;
- break;
- }
- }
- }
- typeName = typeIdentifier.identifier;
- } else {
- typeName = typeIdentifier;
- }
-
- Element typeElement = type.element;
- if (typeElement is GenericFunctionTypeElement &&
- typeElement.enclosingElement is GenericTypeAliasElement) {
- typeElement = typeElement.enclosingElement;
- }
-
- typeName.staticElement = typeElement;
- typeName.staticType = type;
- }
- if (typeAnnotation is NamedType) {
- TypeArgumentList typeArguments = typeAnnotation.typeArguments;
- if (typeArguments != null) {
- _applyTypeArgumentsToList(
- enclosingLibraryElement, type, typeArguments.arguments);
- }
- }
- }
-
/// Associate each of the annotation [nodes] with the corresponding
/// [ElementAnnotation] in [annotations]. If there is a problem, report it
/// against the given [parent] node.
@@ -752,31 +597,6 @@
}
}
- /// Recursively apply each of the type arguments of the [type] to the
- /// corresponding type arguments of the [typeArguments].
- static void _applyTypeArgumentsToList(LibraryElement enclosingLibraryElement,
- DartType type, List<TypeAnnotation> typeArguments) {
- if (type != null && type.isDynamic) {
- for (TypeAnnotation argument in typeArguments) {
- applyToTypeAnnotation(enclosingLibraryElement, type, argument);
- }
- } else if (type is ParameterizedType) {
- List<DartType> argumentTypes = type.typeArguments;
- int argumentCount = argumentTypes.length;
- if (argumentCount != typeArguments.length) {
- throw new StateError('Found $argumentCount argument types '
- 'for ${typeArguments.length} type arguments');
- }
- for (int i = 0; i < argumentCount; i++) {
- applyToTypeAnnotation(
- enclosingLibraryElement, argumentTypes[i], typeArguments[i]);
- }
- } else {
- throw new StateError('Attempting to apply a non-parameterized type '
- '(${type.runtimeType}) to type arguments');
- }
- }
-
static bool _isBodyToCreateElementsFor(FunctionBody node) {
AstNode parent = node.parent;
return parent is ConstructorDeclaration ||
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index 7653e61..8518284 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -114,6 +114,7 @@
InterfaceType _typeType;
/// Whether constant evaluation errors should be reported during resolution.
+ @Deprecated('This field is no longer used')
final bool reportConstEvaluationErrors;
/// Helper for extension method resolution.
@@ -174,7 +175,7 @@
// side to the operator.
ResolutionResult result =
_lookUpMethod(leftHandSide, staticType, methodName, leftHandSide);
- node.staticElement = result.element;
+ node.staticElement = result.function;
if (_shouldReportInvalidMember(staticType, result)) {
_recordUndefinedToken(
staticType.element,
@@ -271,8 +272,7 @@
memberElement = element.getNamedConstructor(name.name);
if (memberElement == null) {
memberElement =
- _lookUpSetter(prefix, element.type, name.name, name)
- .element;
+ _lookUpSetter(prefix, element.type, name.name, name).setter;
}
}
if (memberElement == null) {
@@ -405,8 +405,7 @@
Expression function = node.function;
DartType functionType;
if (function is ExtensionOverride) {
- var member = _extensionResolver.getOverrideMember(
- function, 'call', ElementKind.METHOD);
+ var member = _extensionResolver.getOverrideMember(function, 'call');
if (member != null && member.isStatic) {
_resolver.errorReporter.reportErrorForNode(
CompileTimeErrorCode.EXTENSION_OVERRIDE_ACCESS_TO_STATIC_MEMBER,
@@ -485,7 +484,7 @@
ResolutionResult setterResult =
_lookUpMethod(target, staticType, setterMethodName, target);
// set setter element
- node.staticElement = setterResult.element;
+ node.staticElement = setterResult.function;
// generate undefined method warning
_checkForUndefinedIndexOperator(
node, target, setterMethodName, setterResult, staticType);
@@ -494,7 +493,7 @@
_lookUpMethod(target, staticType, getterMethodName, target);
// set getter element
AuxiliaryElements auxiliaryElements =
- new AuxiliaryElements(getterResult.element, null);
+ new AuxiliaryElements(getterResult.function, null);
node.auxiliaryElements = auxiliaryElements;
// generate undefined method warning
_checkForUndefinedIndexOperator(
@@ -504,7 +503,7 @@
ResolutionResult methodResult =
_lookUpMethod(target, staticType, getterMethodName, target);
// set getter element
- node.staticElement = methodResult.element;
+ node.staticElement = methodResult.function;
// generate undefined method warning
_checkForUndefinedIndexOperator(
node, target, getterMethodName, methodResult, staticType);
@@ -513,7 +512,7 @@
ResolutionResult methodResult =
_lookUpMethod(target, staticType, setterMethodName, target);
// set setter element
- node.staticElement = methodResult.element;
+ node.staticElement = methodResult.function;
// generate undefined method warning
_checkForUndefinedIndexOperator(
node, target, setterMethodName, methodResult, staticType);
@@ -525,10 +524,8 @@
ConstructorElement invokedConstructor = node.constructorName.staticElement;
node.staticElement = invokedConstructor;
ArgumentList argumentList = node.argumentList;
- List<ParameterElement> parameters = _resolveArgumentsToFunction(
- reportConstEvaluationErrors && node.isConst,
- argumentList,
- invokedConstructor);
+ List<ParameterElement> parameters =
+ _resolveArgumentsToFunction(argumentList, invokedConstructor);
if (parameters != null) {
argumentList.correspondingStaticParameters = parameters;
}
@@ -573,7 +570,7 @@
// the operator.
ResolutionResult result =
_lookUpMethod(operand, staticType, methodName, operand);
- node.staticElement = result.element;
+ node.staticElement = result.function;
if (_shouldReportInvalidMember(staticType, result)) {
if (operand is SuperExpression) {
_recordUndefinedToken(
@@ -681,7 +678,7 @@
// the operator.
ResolutionResult result =
_lookUpMethod(operand, staticType, methodName, operand);
- node.staticElement = result.element;
+ node.staticElement = result.function;
if (_shouldReportInvalidMember(staticType, result)) {
if (operand is SuperExpression) {
_recordUndefinedToken(
@@ -717,7 +714,10 @@
ExecutableElement member;
if (propertyName.inSetterContext()) {
member = _extensionResolver.getOverrideMember(
- target, memberName, ElementKind.SETTER);
+ target,
+ memberName,
+ setter: true,
+ );
if (member == null) {
_resolver.errorReporter.reportErrorForNode(
CompileTimeErrorCode.UNDEFINED_EXTENSION_SETTER,
@@ -725,8 +725,8 @@
[memberName, element.name]);
}
if (propertyName.inGetterContext()) {
- PropertyAccessorElement getter = _extensionResolver.getOverrideMember(
- target, memberName, ElementKind.GETTER);
+ PropertyAccessorElement getter =
+ _extensionResolver.getOverrideMember(target, memberName);
if (getter == null) {
_resolver.errorReporter.reportErrorForNode(
CompileTimeErrorCode.UNDEFINED_EXTENSION_GETTER,
@@ -736,10 +736,7 @@
propertyName.auxiliaryElements = AuxiliaryElements(getter, null);
}
} else if (propertyName.inGetterContext()) {
- member = _extensionResolver.getOverrideMember(
- target, memberName, ElementKind.GETTER) ??
- _extensionResolver.getOverrideMember(
- target, memberName, ElementKind.METHOD);
+ member = _extensionResolver.getOverrideMember(target, memberName);
if (member == null) {
_resolver.errorReporter.reportErrorForNode(
CompileTimeErrorCode.UNDEFINED_EXTENSION_GETTER,
@@ -786,7 +783,7 @@
node.staticElement = element;
ArgumentList argumentList = node.argumentList;
List<ParameterElement> parameters =
- _resolveArgumentsToFunction(false, argumentList, element);
+ _resolveArgumentsToFunction(argumentList, element);
if (parameters != null) {
argumentList.correspondingStaticParameters = parameters;
}
@@ -878,7 +875,7 @@
enclosingClass != null) {
InterfaceType enclosingType = enclosingClass.type;
AuxiliaryElements auxiliaryElements = new AuxiliaryElements(
- _lookUpGetter(null, enclosingType, node.name, node).element, null);
+ _lookUpGetter(null, enclosingType, node.name, node).getter, null);
node.auxiliaryElements = auxiliaryElements;
}
//
@@ -939,8 +936,8 @@
return;
}
ArgumentList argumentList = node.argumentList;
- List<ParameterElement> parameters = _resolveArgumentsToFunction(
- isInConstConstructor, argumentList, element);
+ List<ParameterElement> parameters =
+ _resolveArgumentsToFunction(argumentList, element);
if (parameters != null) {
argumentList.correspondingStaticParameters = parameters;
}
@@ -1020,11 +1017,10 @@
if (type is InterfaceType) {
MethodElement callMethod = invocation.staticElement;
if (callMethod != null) {
- return _resolveArgumentsToFunction(false, argumentList, callMethod);
+ return _resolveArgumentsToFunction(argumentList, callMethod);
}
} else if (type is FunctionType) {
- return _resolveArgumentsToParameters(
- false, argumentList, type.parameters);
+ return _resolveArgumentsToParameters(argumentList, type.parameters);
}
return null;
}
@@ -1229,12 +1225,8 @@
}
var result = _extensionResolver.findExtension(
- type,
- FunctionElement.CALL_METHOD_NAME,
- node,
- ElementKind.METHOD,
- );
- var instantiatedMember = result.element;
+ type, FunctionElement.CALL_METHOD_NAME, node);
+ var instantiatedMember = result.function;
if (instantiatedMember is MethodElement) {
return instantiatedMember;
}
@@ -1256,7 +1248,7 @@
var getter = type.lookUpInheritedGetter(name,
library: _definingLibrary, thisType: target is! SuperExpression);
if (getter != null) {
- result = ResolutionResult(getter);
+ result = ResolutionResult(property: getter.variable);
}
}
@@ -1268,8 +1260,7 @@
return ResolutionResult.none;
}
if (result.isNone) {
- result = _extensionResolver.findExtension(
- type, name, nameNode, ElementKind.GETTER);
+ result = _extensionResolver.findExtension(type, name, nameNode);
}
return result;
}
@@ -1302,7 +1293,7 @@
var method = type.lookUpInheritedMethod(name,
library: _definingLibrary, thisType: target is! SuperExpression);
if (method != null) {
- result = ResolutionResult(method);
+ result = ResolutionResult(function: method);
}
}
@@ -1314,8 +1305,7 @@
return ResolutionResult.none;
}
if (result.isNone) {
- result = _extensionResolver.findExtension(
- type, name, nameNode, ElementKind.METHOD);
+ result = _extensionResolver.findExtension(type, name, nameNode);
}
return result;
}
@@ -1334,7 +1324,7 @@
var setter = type.lookUpInheritedSetter(name,
library: _definingLibrary, thisType: target is! SuperExpression);
if (setter != null) {
- result = ResolutionResult(setter);
+ result = ResolutionResult(property: setter.variable);
}
}
@@ -1346,8 +1336,7 @@
return ResolutionResult.none;
}
if (result.isNone) {
- result = _extensionResolver.findExtension(
- type, name, nameNode, ElementKind.SETTER);
+ result = _extensionResolver.findExtension(type, name, nameNode);
}
return result;
}
@@ -1401,7 +1390,7 @@
}
// resolve arguments to parameters
List<ParameterElement> parameters =
- _resolveArgumentsToFunction(true, argumentList, constructor);
+ _resolveArgumentsToFunction(argumentList, constructor);
if (parameters != null) {
argumentList.correspondingStaticParameters = parameters;
}
@@ -1543,35 +1532,29 @@
* Given an [argumentList] and the [executableElement] that will be invoked
* using those argument, compute the list of parameters that correspond to the
* list of arguments. An error will be reported if any of the arguments cannot
- * be matched to a parameter. The flag [reportAsError] should be `true` if a
- * compile-time error should be reported; or `false` if a compile-time warning
- * should be reported. Return the parameters that correspond to the arguments,
- * or `null` if no correspondence could be computed.
+ * be matched to a parameter. Return the parameters that correspond to the
+ * arguments, or `null` if no correspondence could be computed.
*/
- List<ParameterElement> _resolveArgumentsToFunction(bool reportAsError,
+ List<ParameterElement> _resolveArgumentsToFunction(
ArgumentList argumentList, ExecutableElement executableElement) {
if (executableElement == null) {
return null;
}
List<ParameterElement> parameters = executableElement.parameters;
- return _resolveArgumentsToParameters(
- reportAsError, argumentList, parameters);
+ return _resolveArgumentsToParameters(argumentList, parameters);
}
/**
* Given an [argumentList] and the [parameters] related to the element that
* will be invoked using those arguments, compute the list of parameters that
* correspond to the list of arguments. An error will be reported if any of
- * the arguments cannot be matched to a parameter. The flag [reportAsError]
- * should be `true` if a compile-time error should be reported; or `false` if
- * a compile-time warning should be reported. Return the parameters that
+ * the arguments cannot be matched to a parameter. Return the parameters that
* correspond to the arguments.
*/
- List<ParameterElement> _resolveArgumentsToParameters(bool reportAsError,
+ List<ParameterElement> _resolveArgumentsToParameters(
ArgumentList argumentList, List<ParameterElement> parameters) {
return ResolverVisitor.resolveArgumentsToParameters(
- argumentList, parameters, _resolver.errorReporter.reportErrorForNode,
- reportAsError: reportAsError);
+ argumentList, parameters, _resolver.errorReporter.reportErrorForNode);
}
void _resolveBinaryExpression(BinaryExpression node, String methodName) {
@@ -1601,7 +1584,7 @@
forSuper: isSuper,
);
if (invokeElement != null) {
- result = ResolutionResult(invokeElement);
+ result = ResolutionResult(function: invokeElement);
}
}
@@ -1612,12 +1595,11 @@
}
if (result.isNone) {
- result = _extensionResolver.findExtension(
- leftType, methodName, node, ElementKind.METHOD);
+ result = _extensionResolver.findExtension(leftType, methodName, node);
}
- node.staticElement = result.element;
- node.staticInvokeType = result.element?.type;
+ node.staticElement = result.function;
+ node.staticInvokeType = result.function?.type;
if (_shouldReportInvalidMember(leftType, result)) {
if (isSuper) {
_recordUndefinedToken(
@@ -1678,23 +1660,28 @@
* Given that we are accessing a property of the given [classElement] with the
* given [propertyName], return the element that represents the property.
*/
- Element _resolveElement(
+ ResolutionResult _resolveElement(
ClassElement classElement, SimpleIdentifier propertyName) {
String name = propertyName.name;
- Element element = null;
if (propertyName.inSetterContext()) {
- element = classElement.getSetter(name);
+ var element = classElement.getSetter(name);
+ if (element != null && element.isAccessibleIn(_definingLibrary)) {
+ return ResolutionResult(property: element.variable);
+ }
}
- if (element == null) {
- element = classElement.getGetter(name);
+ {
+ var element = classElement.getGetter(name);
+ if (element != null && element.isAccessibleIn(_definingLibrary)) {
+ return ResolutionResult(property: element.variable);
+ }
}
- if (element == null) {
- element = classElement.getMethod(name);
+ {
+ var element = classElement.getMethod(name);
+ if (element != null && element.isAccessibleIn(_definingLibrary)) {
+ return ResolutionResult(function: element);
+ }
}
- if (element != null && element.isAccessibleIn(_definingLibrary)) {
- return element;
- }
- return null;
+ return ResolutionResult.none;
}
/**
@@ -1765,7 +1752,11 @@
[memberName]);
}
if (staticElement != null) {
- result = ResolutionResult(staticElement);
+ if (staticElement is PropertyAccessorElement) {
+ result = ResolutionResult(property: staticElement.variable);
+ } else if (staticElement is MethodElement) {
+ result = ResolutionResult(function: staticElement);
+ }
}
}
//
@@ -1775,18 +1766,15 @@
// does not apply to conditional property accesses (i.e. 'C?.m').
//
if (result.isNone) {
- Element staticElement;
ClassElement typeReference = getTypeReference(target);
if (typeReference != null) {
if (isCascaded) {
typeReference = _typeType.element;
}
- staticElement = _resolveElement(typeReference, propertyName);
- if (staticElement != null) {
- result = ResolutionResult(staticElement);
- }
+ result = _resolveElement(typeReference, propertyName);
} else {
if (target is SuperExpression) {
+ ExecutableElement staticElement;
if (staticType is InterfaceTypeImpl) {
staticElement = staticType.lookUpInheritedMember(
propertyName.name, _definingLibrary,
@@ -1814,8 +1802,10 @@
}
}
}
- if (staticElement != null) {
- result = ResolutionResult(staticElement);
+ if (staticElement is PropertyAccessorElement) {
+ result = ResolutionResult(property: staticElement.variable);
+ } else if (staticElement is MethodElement) {
+ result = ResolutionResult(function: staticElement);
}
} else {
result = _resolveProperty(target, staticType, propertyName);
@@ -1826,11 +1816,13 @@
// Error was already reported in validateAnnotationElement().
if (target.parent.parent is Annotation) {
if (result.isSingle) {
- propertyName.staticElement = result.element;
+ propertyName.staticElement = result.getter;
}
return;
}
- propertyName.staticElement = result.element;
+ propertyName.staticElement =
+ (propertyName.inSetterContext() ? result.setter : null) ??
+ result.getter;
if (_shouldReportInvalidMember(staticType, result)) {
if (staticType is FunctionType &&
propertyName.name == FunctionElement.CALL_METHOD_NAME) {
@@ -1917,7 +1909,7 @@
if (enclosingClass != null) {
setter = _lookUpSetter(
null, enclosingClass.type, identifier.name, identifier)
- .element;
+ .setter;
}
}
if (setter != null) {
@@ -1957,17 +1949,17 @@
identifier.parent is CommentReference)) {
element =
_lookUpSetter(null, enclosingType, identifier.name, identifier)
- .element;
+ .setter;
}
if (element == null && identifier.inGetterContext()) {
element =
_lookUpGetter(null, enclosingType, identifier.name, identifier)
- .element;
+ .getter;
}
if (element == null) {
element =
_lookUpMethod(null, enclosingType, identifier.name, identifier)
- .element;
+ .getter;
}
}
}
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index fd4540d..dd79796 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -30,7 +30,6 @@
import 'package:analyzer/src/services/lint.dart';
import 'package:analyzer/src/summary/api_signature.dart';
import 'package:analyzer/src/task/api/model.dart';
-import 'package:analyzer/src/task/manager.dart';
import 'package:front_end/src/fasta/scanner/token.dart';
import 'package:path/path.dart' as pathos;
import 'package:pub_semver/pub_semver.dart';
@@ -144,10 +143,6 @@
/// [name].
set name(String name);
- /// The stream that is notified when sources have been added or removed,
- /// or the source's content has changed.
- Stream<SourcesChangedEvent> get onSourcesChanged;
-
/// Return the source factory used to create the sources that can be analyzed
/// in this context.
SourceFactory get sourceFactory;
@@ -255,10 +250,6 @@
CancelableFuture<CompilationUnit> computeResolvedCompilationUnitAsync(
Source source, Source librarySource);
- /// Perform work until the given [result] has been computed for the given
- /// [target]. Return the computed value.
- V computeResult<V>(AnalysisTarget target, ResultDescriptor<V> result);
-
/// Notifies the context that the client is going to stop using this context.
void dispose();
@@ -277,13 +268,6 @@
CompilationUnitElement getCompilationUnitElement(
Source unitSource, Source librarySource);
- /// Return configuration data associated with the given key or the [key]'s
- /// default value if no state has been associated.
- ///
- /// See [setConfigurationData].
- @deprecated
- V getConfigurationData<V>(ResultDescriptor<V> key);
-
/// Return the contents and timestamp of the given [source].
///
/// This method should be used rather than the method [Source.getContents]
@@ -379,12 +363,6 @@
CompilationUnit getResolvedCompilationUnit2(
Source unitSource, Source librarySource);
- /// Return the value of the given [result] for the given [target].
- ///
- /// If the corresponding [target] does not exist, or the [result] is not
- /// computed yet, then the default value is returned.
- V getResult<V>(AnalysisTarget target, ResultDescriptor<V> result);
-
/// Return a list of the sources being analyzed in this context whose full path
/// is equal to the given [path].
List<Source> getSourcesWithFullName(String path);
@@ -412,15 +390,6 @@
/// or if we do not know whether it can be run on the server.
bool isServerLibrary(Source librarySource);
- /// Return the stream that is notified when a result with the given
- /// [descriptor] is changed, e.g. computed or invalidated.
- Stream<ResultChangedEvent> onResultChanged(ResultDescriptor descriptor);
-
- /// Return the stream that is notified when a new value for the given
- /// [descriptor] is computed.
- @deprecated
- Stream<ComputedResult> onResultComputed(ResultDescriptor descriptor);
-
/// Parse the content of the given [source] to produce an AST structure. The
/// resulting AST structure may or may not be resolved, and may have a slightly
/// different structure depending upon whether it is resolved.
@@ -482,12 +451,6 @@
void setChangedContents(
Source source, String contents, int offset, int oldLength, int newLength);
- /// Associate this configuration [data] object with the given descriptor [key].
- ///
- /// See [getConfigurationData].
- @deprecated
- void setConfigurationData(ResultDescriptor key, Object data);
-
/// Set the contents of the given [source] to the given [contents] and mark the
/// source as having changed. This has the effect of overriding the default
/// contents of the source. If the contents are `null` the override is removed
@@ -597,9 +560,6 @@
/// The partition manager being used to manage the shared partitions.
final PartitionManager partitionManager = new PartitionManager();
- /// The task manager used to manage the tasks used to analyze code.
- TaskManager _taskManager;
-
AnalysisEngine._();
/// Return the instrumentation service that is to be used by this analysis
@@ -626,14 +586,6 @@
this._logger = logger ?? Logger.NULL;
}
- /// Return the task manager used to manage the tasks used to analyze code.
- TaskManager get taskManager {
- if (_taskManager == null) {
- _taskManager = new TaskManager();
- }
- return _taskManager;
- }
-
/// Clear any caches holding on to analysis results so that a full re-analysis
/// will be performed the next time an analysis context is created.
void clearCaches() {
@@ -938,6 +890,9 @@
/// Return `true` if analyzer should use the Dart 2.0 Front End parser.
bool get useFastaParser;
+ /// Return `true` the lint with the given [name] is enabled.
+ bool isLintEnabled(String name);
+
/// Reset the state of this set of analysis options to its original state.
void resetToDefaults();
@@ -1350,6 +1305,11 @@
}
@override
+ bool isLintEnabled(String name) {
+ return lintRules.any((rule) => rule.name == name);
+ }
+
+ @override
void resetToDefaults() {
dart2jsHint = false;
disableCacheFlushing = false;
@@ -1800,27 +1760,6 @@
this.contents, this.offset, this.oldLength, this.newLength);
}
-/// [ComputedResult] describes a value computed for a [ResultDescriptor].
-@deprecated
-class ComputedResult<V> {
- /// The context in which the value was computed.
- final AnalysisContext context;
-
- /// The descriptor of the result which was computed.
- final ResultDescriptor<V> descriptor;
-
- /// The target for which the result was computed.
- final AnalysisTarget target;
-
- /// The computed value.
- final V value;
-
- ComputedResult(this.context, this.descriptor, this.target, this.value);
-
- @override
- String toString() => 'Computed $descriptor of $target in $context';
-}
-
/// An event indicating when a source either starts or stops being implicitly
/// analyzed.
class ImplicitAnalysisEvent {
@@ -1867,10 +1806,6 @@
/// Specify whether the context is active, i.e. is being analyzed now.
set isActive(bool value);
- /// Return the [StreamController] reporting [InvalidatedResult]s for everything
- /// in this context's cache.
- ReentrantSynchronousStream<InvalidatedResult> get onResultInvalidated;
-
/// Return a list containing all of the sources that have been marked as
/// priority sources. Clients must not modify the returned list.
List<Source> get prioritySources;
@@ -1885,19 +1820,6 @@
/// Sets the [TypeProvider] for this context.
void set typeProvider(TypeProvider typeProvider);
- /// A list of all [WorkManager]s used by this context.
- List<WorkManager> get workManagers;
-
- /// This method is invoked when the state of the [result] of the [entry] is
- /// [CacheState.INVALID], so it is about to be computed.
- ///
- /// If the context knows how to provide the value, it sets the value into
- /// the [entry] with all required dependencies, and returns `true`.
- ///
- /// Otherwise, it returns `false` to indicate that the result should be
- /// computed as usually.
- bool aboutToComputeResult(CacheEntry entry, ResultDescriptor result);
-
/// Return a list containing the sources of the libraries that are exported by
/// the library with the given [source]. The list will be empty if the given
/// source is invalid, if the given source does not represent a library, or if
@@ -1921,9 +1843,6 @@
/// will be eventually returned to the client from [performAnalysisTask].
List<CompilationUnit> ensureResolvedDartUnits(Source source);
- /// Return the cache entry associated with the given [target].
- CacheEntry getCacheEntry(AnalysisTarget target);
-
/// Return context that owns the given [source].
InternalAnalysisContext getContextFor(Source source);
@@ -2190,80 +2109,3 @@
node.accept(eraser);
}
}
-
-/// [ResultChangedEvent] describes a change to an analysis result.
-class ResultChangedEvent<V> {
- /// The context in which the result was changed.
- final AnalysisContext context;
-
- /// The target for which the result was changed.
- final AnalysisTarget target;
-
- /// The descriptor of the result which was changed.
- final ResultDescriptor<V> descriptor;
-
- /// If the result [wasComputed], the new value of the result. If the result
- /// [wasInvalidated], the value of before it was invalidated, may be the
- /// default value if the result was flushed.
- final V value;
-
- /// Is `true` if the result was computed, or `false` is is was invalidated.
- final bool _wasComputed;
-
- ResultChangedEvent(this.context, this.target, this.descriptor, this.value,
- this._wasComputed);
-
- /// Returns `true` if the result was computed.
- bool get wasComputed => _wasComputed;
-
- /// Returns `true` if the result was invalidated.
- bool get wasInvalidated => !_wasComputed;
-
- @override
- String toString() {
- String operation = _wasComputed ? 'Computed' : 'Invalidated';
- return '$operation $descriptor of $target in $context';
- }
-}
-
-/// [SourcesChangedEvent] indicates which sources have been added, removed,
-/// or whose contents have changed.
-class SourcesChangedEvent {
- /// The internal representation of what has changed. Clients should not access
- /// this field directly.
- final ChangeSet _changeSet;
-
- /// Construct an instance representing the given changes.
- SourcesChangedEvent(ChangeSet changeSet) : _changeSet = changeSet;
-
- /// Construct an instance representing a source content change.
- factory SourcesChangedEvent.changedContent(Source source, String contents) {
- ChangeSet changeSet = new ChangeSet();
- changeSet.changedContent(source, contents);
- return new SourcesChangedEvent(changeSet);
- }
-
- /// Construct an instance representing a source content change.
- factory SourcesChangedEvent.changedRange(Source source, String contents,
- int offset, int oldLength, int newLength) {
- ChangeSet changeSet = new ChangeSet();
- changeSet.changedRange(source, contents, offset, oldLength, newLength);
- return new SourcesChangedEvent(changeSet);
- }
-
- /// Return the collection of sources for which content has changed.
- Iterable<Source> get changedSources {
- List<Source> changedSources = new List.from(_changeSet.changedSources);
- changedSources.addAll(_changeSet.changedContents.keys);
- changedSources.addAll(_changeSet.changedRanges.keys);
- return changedSources;
- }
-
- /// Return `true` if any sources were added.
- bool get wereSourcesAdded => _changeSet.addedSources.isNotEmpty;
-
- /// Return `true` if any sources were removed or deleted.
- bool get wereSourcesRemoved =>
- _changeSet.removedSources.isNotEmpty ||
- _changeSet.removedContainers.isNotEmpty;
-}
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 63c5052..3b1fd26 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -6,7 +6,6 @@
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
@@ -419,7 +418,6 @@
operatorType == TokenType.QUESTION_QUESTION_EQ) {
_checkForInvalidAssignment(lhs, rhs);
} else {
- _checkForInvalidCompoundAssignment(node, lhs, rhs);
_checkForArgumentTypeNotAssignableForArgument(rhs);
_checkForNullableDereference(lhs);
}
@@ -620,7 +618,6 @@
_checkForConstConstructorWithNonConstSuper(node);
_checkForAllFinalInitializedErrorCodes(node);
_checkForRedirectingConstructorErrorCodes(node);
- _checkForMixinDeclaresConstructor(node);
_checkForMultipleSuperInitializers(node);
_checkForRecursiveConstructorRedirect(node, constructorElement);
if (!_checkForRecursiveFactoryRedirect(node, constructorElement)) {
@@ -733,7 +730,13 @@
void visitExtensionDeclaration(ExtensionDeclaration node) {
_enclosingExtension = node.declaredElement;
_duplicateDefinitionVerifier.checkExtension(node);
+ _checkForFinalNotInitializedInClass(node.members);
_checkForMismatchedAccessorTypesInExtension(node);
+ final name = node.name;
+ if (name != null) {
+ _checkForBuiltInIdentifierAsName(
+ name, CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_EXTENSION_NAME);
+ }
super.visitExtensionDeclaration(node);
_enclosingExtension = null;
}
@@ -926,8 +929,7 @@
// we can get the function element via `node?.element?.type?.element` but
// it doesn't have hasImplicitReturnType set correctly.
if (!_options.implicitDynamic && node.returnType == null) {
- DartType parameterType =
- resolutionMap.elementDeclaredByFormalParameter(node).type;
+ DartType parameterType = node.declaredElement.type;
if (parameterType is FunctionType &&
parameterType.returnType.isDynamic) {
_errorReporter.reportErrorForNode(
@@ -994,7 +996,10 @@
@override
void visitIndexExpression(IndexExpression node) {
_checkForArgumentTypeNotAssignableForArgument(node.index);
- _checkForNullableDereference(node.target);
+ if (node.leftBracket.type !=
+ TokenType.QUESTION_PERIOD_OPEN_SQUARE_BRACKET) {
+ _checkForNullableDereference(node.target);
+ }
super.visitIndexExpression(node);
}
@@ -1295,7 +1300,7 @@
@override
void visitSpreadElement(SpreadElement node) {
- if (node.spreadOperator.type != TokenType.PERIOD_PERIOD_PERIOD_QUESTION) {
+ if (!node.isNullAware) {
_checkForNullableDereference(node.expression);
} else {
_checkForUnnecessaryNullAware(node.expression, node.spreadOperator);
@@ -1757,10 +1762,6 @@
/**
* Check for errors related to the redirected constructors.
- *
- * See [StaticWarningCode.REDIRECT_TO_INVALID_RETURN_TYPE],
- * [StaticWarningCode.REDIRECT_TO_INVALID_FUNCTION_TYPE], and
- * [StaticWarningCode.REDIRECT_TO_MISSING_CONSTRUCTOR].
*/
void _checkForAllRedirectConstructorErrorCodes(
ConstructorDeclaration declaration) {
@@ -1785,10 +1786,9 @@
if (redirectedConstructor.name != null) {
constructorStrName += ".${redirectedConstructor.name.name}";
}
- ErrorCode errorCode = (declaration.constKeyword != null
- ? CompileTimeErrorCode.REDIRECT_TO_MISSING_CONSTRUCTOR
- : StaticWarningCode.REDIRECT_TO_MISSING_CONSTRUCTOR);
- _errorReporter.reportErrorForNode(errorCode, redirectedConstructor,
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.REDIRECT_TO_MISSING_CONSTRUCTOR,
+ redirectedConstructor,
[constructorStrName, redirectedType.displayName]);
}
return;
@@ -1797,8 +1797,7 @@
DartType redirectedReturnType = redirectedType.returnType;
// Report specific problem when return type is incompatible
- FunctionType constructorType =
- resolutionMap.elementDeclaredByConstructorDeclaration(declaration).type;
+ FunctionType constructorType = declaration.declaredElement.type;
DartType constructorReturnType = constructorType.returnType;
if (!_typeSystem.isAssignableTo(redirectedReturnType, constructorReturnType,
featureSet: _featureSet)) {
@@ -2088,7 +2087,7 @@
if (element.isConst) {
_errorReporter.reportErrorForNode(
StaticWarningCode.ASSIGNMENT_TO_CONST, expression);
- } else if (element.isFinal) {
+ } else if (element.isFinal && !element.isLate) {
if (element is FieldElementImpl) {
if (element.setter == null && element.isSynthetic) {
_errorReporter.reportErrorForNode(
@@ -2159,7 +2158,8 @@
* Verify that the given [identifier] is not a keyword, and generates the
* given [errorCode] on the identifier if it is a keyword.
*
- * See [CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE_NAME],
+ * See [CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_EXTENSION_NAME],
+ * [CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE_NAME],
* [CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE_PARAMETER_NAME], and
* [CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPEDEF_NAME].
*/
@@ -3473,27 +3473,6 @@
}
/**
- * Given an [assignment] using a compound assignment operator, this verifies
- * that the given assignment is valid. The [lhs] is the left hand side
- * expression. The [rhs] is the right hand side expression.
- *
- * See [StaticTypeWarningCode.INVALID_ASSIGNMENT].
- */
- void _checkForInvalidCompoundAssignment(
- AssignmentExpression assignment, Expression lhs, Expression rhs) {
- if (lhs == null) {
- return;
- }
- DartType leftType = getStaticType(lhs);
- DartType rightType = getStaticType(assignment);
- if (!_typeSystem.isAssignableTo(rightType, leftType,
- featureSet: _featureSet)) {
- _errorReporter.reportTypeErrorForNode(
- StaticTypeWarningCode.INVALID_ASSIGNMENT, rhs, [rightType, leftType]);
- }
- }
-
- /**
* Check the given [initializer] to ensure that the field being initialized is
* a valid field. The [fieldName] is the field name from the
* [ConstructorFieldInitializer]. The [staticElement] is the static element
@@ -3794,7 +3773,7 @@
}
void _checkForMissingJSLibAnnotation(Annotation node) {
- if (resolutionMap.elementAnnotationForAnnotation(node)?.isJS ?? false) {
+ if (node.elementAnnotation?.isJS ?? false) {
if (_currentLibrary.hasJS != true) {
_errorReporter.reportErrorForNode(
HintCode.MISSING_JS_LIB_ANNOTATION, node);
@@ -3847,13 +3826,6 @@
return false;
}
- void _checkForMixinDeclaresConstructor(ConstructorDeclaration node) {
- if (_enclosingClass.isMixin) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.MIXIN_DECLARES_CONSTRUCTOR, node.returnType);
- }
- }
-
/**
* Verify that the given mixin has the 'Object' superclass. The [mixinName] is
* the node to report problem on. The [mixinElement] is the mixing to
@@ -4321,6 +4293,10 @@
return;
}
+ if (node.isLate) {
+ return;
+ }
+
if (node.type == null) {
return;
}
@@ -4358,13 +4334,7 @@
StaticWarningCode code = expression.staticType == _typeProvider.nullType
? StaticWarningCode.INVALID_USE_OF_NULL_VALUE
: StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE;
-
- if (expression is MethodInvocation) {
- SimpleIdentifier methodName = expression.methodName;
- _errorReporter.reportErrorForNode(code, methodName, []);
- } else {
- _errorReporter.reportErrorForNode(code, expression, []);
- }
+ _errorReporter.reportErrorForNode(code, expression, []);
return true;
}
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index 2504097..8e6d623 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -5643,7 +5643,7 @@
/// Create and return a new token with the given [type]. The token will
/// replace the first portion of the given [token], so it will have the same
- /// offset and will have any comments that might have preceeded the token.
+ /// offset and will have any comments that might have preceded the token.
Token _createToken(Token token, TokenType type, {bool isBegin: false}) {
CommentToken comments = token.precedingComments;
if (comments == null) {
@@ -7437,7 +7437,7 @@
return null;
}
//
- // We can't skip a type parameter because it can be preceeded by metadata,
+ // We can't skip a type parameter because it can be preceded by metadata,
// so we just assume that everything before the matching end token is valid.
//
int depth = 1;
diff --git a/pkg/analyzer/lib/src/generated/parser_fasta.dart b/pkg/analyzer/lib/src/generated/parser_fasta.dart
index 5f560dd..e5b6f3d 100644
--- a/pkg/analyzer/lib/src/generated/parser_fasta.dart
+++ b/pkg/analyzer/lib/src/generated/parser_fasta.dart
@@ -132,7 +132,9 @@
<ClassMember>[],
null /* rightBracket */,
);
- currentToken = fastaParser.parseClassOrMixinMember(currentToken);
+ // TODO(danrubel): disambiguate between class and mixin
+ currentToken = fastaParser.parseClassMember(currentToken, className);
+ //currentToken = fastaParser.parseMixinMember(currentToken);
ClassDeclaration declaration = astBuilder.classDeclaration;
astBuilder.classDeclaration = null;
return declaration.members.isNotEmpty ? declaration.members[0] : null;
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 5d454a5..3f2e838 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -7,7 +7,6 @@
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/ast_factory.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
@@ -35,7 +34,6 @@
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/static_type_analyzer.dart';
-import 'package:analyzer/src/generated/testing/element_factory.dart';
import 'package:analyzer/src/generated/type_promotion_manager.dart';
import 'package:analyzer/src/generated/type_system.dart';
import 'package:analyzer/src/generated/variable_type_provider.dart';
@@ -73,10 +71,6 @@
/// The type [Null].
final InterfaceType _nullType;
- /// The type Future<Null>, which is needed for determining whether it is safe
- /// to have a bare "return;" in an async method.
- final InterfaceType _futureNullType;
-
/// The type system primitives
final TypeSystem _typeSystem;
@@ -94,6 +88,9 @@
/// The [LinterContext] used for possible const calculations.
LinterContext _linterContext;
+ /// Is `true` if NNBD is enabled for the library being analyzed.
+ final bool _isNonNullable;
+
/// Create a new instance of the [BestPracticesVerifier].
///
/// @param errorReporter the error reporter
@@ -109,8 +106,8 @@
DeclaredVariables declaredVariables,
AnalysisOptions analysisOptions,
}) : _nullType = typeProvider.nullType,
- _futureNullType = typeProvider.futureNullType,
_typeSystem = typeSystem ?? new Dart2TypeSystem(typeProvider),
+ _isNonNullable = unit.featureSet.isEnabled(Feature.non_nullable),
_inheritanceManager = inheritanceManager,
_invalidAccessVerifier =
new _InvalidAccessVerifier(_errorReporter, _currentLibrary) {
@@ -133,8 +130,7 @@
@override
void visitAnnotation(Annotation node) {
- ElementAnnotation element =
- resolutionMap.elementAnnotationForAnnotation(node);
+ ElementAnnotation element = node.elementAnnotation;
AstNode parent = node.parent;
if (element?.isFactory == true) {
if (parent is MethodDeclaration) {
@@ -261,7 +257,7 @@
@override
void visitConstructorDeclaration(ConstructorDeclaration node) {
- if (resolutionMap.elementDeclaredByConstructorDeclaration(node).isFactory) {
+ if (node.declaredElement.isFactory) {
if (node.body is BlockFunctionBody) {
// Check the block for a return statement, if not, create the hint.
if (!ExitDetector.exits(node.body)) {
@@ -576,8 +572,7 @@
} else if (displayName == FunctionElement.CALL_METHOD_NAME &&
node is MethodInvocation &&
node.staticInvokeType is InterfaceType) {
- DartType staticInvokeType =
- resolutionMap.staticInvokeTypeForInvocationExpression(node);
+ DartType staticInvokeType = node.staticInvokeType;
displayName = "${staticInvokeType.displayName}.${element.displayName}";
}
LibraryElement library =
@@ -921,6 +916,10 @@
/// Produce several null-aware related hints.
void _checkForNullAwareHints(Expression node, Token operator) {
+ if (_isNonNullable) {
+ return;
+ }
+
if (operator == null || operator.type != TokenType.QUESTION_PERIOD) {
return;
}
@@ -1089,17 +1088,25 @@
final requiredParameters =
node.parameters.where((p) => p.declaredElement?.hasRequired == true);
final nonNamedParamsWithRequired =
- requiredParameters.where((p) => !p.isNamed);
+ requiredParameters.where((p) => p.isPositional);
final namedParamsWithRequiredAndDefault = requiredParameters
.where((p) => p.isNamed)
.where((p) => p.declaredElement.defaultValueCode != null);
- final paramsToHint = [
- nonNamedParamsWithRequired,
- namedParamsWithRequiredAndDefault
- ].expand((e) => e);
- for (final param in paramsToHint) {
+ for (final param in nonNamedParamsWithRequired.where((p) => p.isOptional)) {
_errorReporter.reportErrorForNode(
- HintCode.INVALID_REQUIRED_PARAM, param, [param.identifier.name]);
+ HintCode.INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM,
+ param,
+ [param.identifier.name]);
+ }
+ for (final param in nonNamedParamsWithRequired.where((p) => p.isRequired)) {
+ _errorReporter.reportErrorForNode(
+ HintCode.INVALID_REQUIRED_POSITIONAL_PARAM,
+ param,
+ [param.identifier.name]);
+ }
+ for (final param in namedParamsWithRequiredAndDefault) {
+ _errorReporter.reportErrorForNode(HintCode.INVALID_REQUIRED_NAMED_PARAM,
+ param, [param.identifier.name]);
}
}
@@ -1789,8 +1796,7 @@
@override
void visitCompilationUnit(CompilationUnit node) {
- _enclosingLibrary =
- resolutionMap.elementDeclaredByCompilationUnit(node).library;
+ _enclosingLibrary = node.declaredElement.library;
for (Directive directive in node.directives) {
directive.accept(this);
}
@@ -1839,14 +1845,11 @@
if (importedTime >= 0 &&
importSourceKindMap[importedSource] != SourceKind.LIBRARY) {
StringLiteral uriLiteral = node.uri;
- ErrorCode errorCode = element.isDeferred
- ? StaticWarningCode.IMPORT_OF_NON_LIBRARY
- : CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY;
errors.add(new AnalysisError(
_enclosingLibrary.source,
uriLiteral.offset,
uriLiteral.length,
- errorCode,
+ CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY,
[uriLiteral.toSource()]));
}
}
@@ -2755,33 +2758,6 @@
}
}
-/// A type provider that returns non-nullable versions of the SDK types.
-class NonNullableTypeProvider extends TypeProviderImpl {
- NonNullableTypeProvider(
- LibraryElement coreLibrary, LibraryElement asyncLibrary)
- : super(coreLibrary, asyncLibrary);
-
- /// Return a type provider initialized from the same library elements as the
- /// [baseProvider].
- factory NonNullableTypeProvider.from(TypeProvider baseProvider) {
- return NonNullableTypeProvider(baseProvider.boolType.element.library,
- baseProvider.streamType.element.library);
- }
-
- @override
- DartType get bottomType => BottomTypeImpl.instance;
-
- @override
- InterfaceType _getType(Namespace namespace, String typeName) {
- InterfaceType type = super._getType(namespace, typeName);
- if (type == null) {
- return null;
- }
- return (type as TypeImpl).withNullability(NullabilitySuffix.none)
- as InterfaceType;
- }
-}
-
/// Instances of the class `OverrideVerifier` visit all of the declarations in a
/// compilation unit to verify that if they have an override annotation it is
/// being used correctly.
@@ -2965,35 +2941,6 @@
}
}
-/// Kind of the redirecting constructor.
-class RedirectingConstructorKind
- implements Comparable<RedirectingConstructorKind> {
- static const RedirectingConstructorKind CONST =
- const RedirectingConstructorKind('CONST', 0);
-
- static const RedirectingConstructorKind NORMAL =
- const RedirectingConstructorKind('NORMAL', 1);
-
- static const List<RedirectingConstructorKind> values = const [CONST, NORMAL];
-
- /// The name of this redirecting constructor kind.
- final String name;
-
- /// The ordinal value of the redirecting constructor kind.
- final int ordinal;
-
- const RedirectingConstructorKind(this.name, this.ordinal);
-
- @override
- int get hashCode => ordinal;
-
- @override
- int compareTo(RedirectingConstructorKind other) => ordinal - other.ordinal;
-
- @override
- String toString() => name;
-}
-
/// The enumeration `ResolverErrorCode` defines the error codes used for errors
/// detected by the resolver. The convention for this class is for the name of
/// the error code to indicate the problem that caused the error to be generated
@@ -3707,8 +3654,7 @@
@override
void visitDefaultFormalParameter(DefaultFormalParameter node) {
- InferenceContext.setType(node.defaultValue,
- resolutionMap.elementDeclaredByFormalParameter(node.parameter)?.type);
+ InferenceContext.setType(node.defaultValue, node.declaredElement?.type);
super.visitDefaultFormalParameter(node);
ParameterElement element = node.declaredElement;
@@ -3736,7 +3682,7 @@
_flowAnalysis?.flow?.doStatement_bodyBegin(
node,
- _flowAnalysis?.assignedVariables[node],
+ _flowAnalysis.assignedVariables.writtenInNode(node),
);
visitStatementInScope(body);
@@ -3893,8 +3839,8 @@
iterable?.accept(this);
_flowAnalysis?.loopVariable(loopVariable);
loopVariable?.accept(this);
- _flowAnalysis?.flow
- ?.forEach_bodyBegin(_flowAnalysis?.assignedVariables[node]);
+ _flowAnalysis?.flow?.forEach_bodyBegin(
+ _flowAnalysis.assignedVariables.writtenInNode(node));
node.body?.accept(this);
_flowAnalysis?.flow?.forEach_end();
@@ -3971,7 +3917,7 @@
loopVariable?.accept(this);
_flowAnalysis?.flow?.forEach_bodyBegin(
- _flowAnalysis?.assignedVariables[node],
+ _flowAnalysis.assignedVariables.writtenInNode(node),
);
Statement body = node.body;
@@ -4317,8 +4263,7 @@
// because it needs to be visited in the context of the constructor
// invocation.
//
- InferenceContext.setType(node.argumentList,
- resolutionMap.staticElementForConstructorReference(node)?.type);
+ InferenceContext.setType(node.argumentList, node.staticElement?.type);
node.argumentList?.accept(this);
node.accept(elementResolver);
node.accept(typeAnalyzer);
@@ -4426,8 +4371,7 @@
// because it needs to be visited in the context of the constructor
// invocation.
//
- InferenceContext.setType(node.argumentList,
- resolutionMap.staticElementForConstructorReference(node)?.type);
+ InferenceContext.setType(node.argumentList, node.staticElement?.type);
node.argumentList?.accept(this);
node.accept(elementResolver);
node.accept(typeAnalyzer);
@@ -4454,7 +4398,8 @@
if (_flowAnalysis != null) {
var flow = _flowAnalysis.flow;
- var assignedInCases = _flowAnalysis.assignedVariables[node];
+ var assignedInCases =
+ _flowAnalysis.assignedVariables.writtenInNode(node);
flow.switchStatement_expressionEnd(node);
@@ -4462,20 +4407,17 @@
var members = node.members;
for (var member in members) {
flow.switchStatement_beginCase(
- member.labels.isNotEmpty
- ? assignedInCases
- : _flowAnalysis.assignedVariables.emptySet,
+ member.labels.isNotEmpty,
+ assignedInCases,
);
member.accept(this);
- // Implicit `break` at the end of `default`.
if (member is SwitchDefault) {
hasDefault = true;
- flow.handleBreak(node);
}
}
- flow.switchStatement_end(node, hasDefault);
+ flow.switchStatement_end(hasDefault);
} else {
node.members.accept(this);
}
@@ -4510,7 +4452,7 @@
flow.tryCatchStatement_bodyBegin();
body.accept(this);
flow.tryCatchStatement_bodyEnd(
- _flowAnalysis.assignedVariables[body],
+ _flowAnalysis.assignedVariables.writtenInNode(body),
);
var catchLength = catchClauses.length;
@@ -4531,11 +4473,11 @@
if (finallyBlock != null) {
flow.tryFinallyStatement_finallyBegin(
- _flowAnalysis.assignedVariables[body],
+ _flowAnalysis.assignedVariables.writtenInNode(body),
);
finallyBlock.accept(this);
flow.tryFinallyStatement_end(
- _flowAnalysis.assignedVariables[finallyBlock],
+ _flowAnalysis.assignedVariables.writtenInNode(finallyBlock),
);
}
}
@@ -4566,8 +4508,7 @@
void visitVariableDeclarationList(VariableDeclarationList node) {
_flowAnalysis?.variableDeclarationList(node);
for (VariableDeclaration decl in node.variables) {
- VariableElement variableElement =
- resolutionMap.elementDeclaredByVariableDeclaration(decl);
+ VariableElement variableElement = decl.declaredElement;
InferenceContext.setType(decl, variableElement?.type);
}
super.visitVariableDeclarationList(node);
@@ -4587,7 +4528,7 @@
InferenceContext.setType(condition, typeProvider.boolType);
_flowAnalysis?.flow?.whileStatement_conditionBegin(
- _flowAnalysis?.assignedVariables[node],
+ _flowAnalysis.assignedVariables.writtenInNode(node),
);
condition?.accept(this);
@@ -4849,8 +4790,7 @@
return;
}
- ConstructorElement originalElement =
- resolutionMap.staticElementForConstructorReference(constructor);
+ ConstructorElement originalElement = constructor.staticElement;
FunctionType inferred;
// If the constructor is generic, we'll have a ConstructorMember that
// substitutes in type arguments (possibly `dynamic`) from earlier in
@@ -4987,16 +4927,13 @@
/// An error will be reported to [onError] if any of the arguments cannot be
/// matched to a parameter. onError can be null to ignore the error.
///
- /// The flag [reportAsError] should be `true` if a compile-time error should
- /// be reported; or `false` if a compile-time warning should be reported.
- ///
/// Returns the parameters that correspond to the arguments. If no parameter
/// matched an argument, that position will be `null` in the list.
static List<ParameterElement> resolveArgumentsToParameters(
ArgumentList argumentList,
List<ParameterElement> parameters,
- void onError(ErrorCode errorCode, AstNode node, [List<Object> arguments]),
- {bool reportAsError: false}) {
+ void onError(ErrorCode errorCode, AstNode node,
+ [List<Object> arguments])) {
if (parameters.isEmpty && argumentList.arguments.isEmpty) {
return const <ParameterElement>[];
}
@@ -5035,11 +4972,9 @@
ParameterElement element =
namedParameters != null ? namedParameters[name] : null;
if (element == null) {
- ErrorCode errorCode = (reportAsError
- ? CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER
- : StaticWarningCode.UNDEFINED_NAMED_PARAMETER);
if (onError != null) {
- onError(errorCode, nameNode, [name]);
+ onError(CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER, nameNode,
+ [name]);
}
} else {
resolvedParameters[i] = element;
@@ -5063,12 +4998,9 @@
}
}
if (positionalArgumentCount < requiredParameterCount && noBlankArguments) {
- ErrorCode errorCode = (reportAsError
- ? CompileTimeErrorCode.NOT_ENOUGH_POSITIONAL_ARGUMENTS
- : StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS);
if (onError != null) {
- onError(errorCode, argumentList,
- [requiredParameterCount, positionalArgumentCount]);
+ onError(CompileTimeErrorCode.NOT_ENOUGH_POSITIONAL_ARGUMENTS,
+ argumentList, [requiredParameterCount, positionalArgumentCount]);
}
} else if (positionalArgumentCount > unnamedParameterCount &&
noBlankArguments) {
@@ -5076,13 +5008,10 @@
int namedParameterCount = namedParameters?.length ?? 0;
int namedArgumentCount = usedNames?.length ?? 0;
if (namedParameterCount > namedArgumentCount) {
- errorCode = (reportAsError
- ? CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED
- : StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED);
+ errorCode =
+ CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED;
} else {
- errorCode = (reportAsError
- ? CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS
- : StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS);
+ errorCode = CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS;
}
if (onError != null) {
onError(errorCode, argumentList,
@@ -6040,7 +5969,6 @@
// identifier being used as a class name.
// See CompileTimeErrorCodeTest.test_builtInIdentifierAsType().
SimpleIdentifier typeNameSimple = _getTypeSimpleIdentifier(typeName);
- RedirectingConstructorKind redirectingConstructorKind;
if (_isBuiltInIdentifier(node) && _isTypeAnnotation(node)) {
reportErrorForNode(CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE,
typeName, [typeName.name]);
@@ -6056,14 +5984,9 @@
} else if (_isTypeNameInIsExpression(node)) {
reportErrorForNode(StaticWarningCode.TYPE_TEST_WITH_UNDEFINED_NAME,
typeName, [typeName.name]);
- } else if ((redirectingConstructorKind =
- _getRedirectingConstructorKind(node)) !=
- null) {
- ErrorCode errorCode =
- (redirectingConstructorKind == RedirectingConstructorKind.CONST
- ? CompileTimeErrorCode.REDIRECT_TO_NON_CLASS
- : StaticWarningCode.REDIRECT_TO_NON_CLASS);
- reportErrorForNode(errorCode, typeName, [typeName.name]);
+ } else if (_isRedirectingConstructor(node)) {
+ reportErrorForNode(CompileTimeErrorCode.REDIRECT_TO_NON_CLASS, typeName,
+ [typeName.name]);
} else if (_isTypeNameInTypeArgumentList(node)) {
reportErrorForNode(StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT,
typeName, [typeName.name]);
@@ -6114,11 +6037,11 @@
}
} else {
reportErrorForNode(
- StaticWarningCode.UNDEFINED_CLASS, typeName, [typeName.name]);
+ CompileTimeErrorCode.UNDEFINED_CLASS, typeName, [typeName.name]);
}
} else {
reportErrorForNode(
- StaticWarningCode.UNDEFINED_CLASS, typeName, [typeName.name]);
+ CompileTimeErrorCode.UNDEFINED_CLASS, typeName, [typeName.name]);
}
}
if (!elementValid) {
@@ -6153,7 +6076,6 @@
type = _getTypeWhenMultiplyDefined(elements) as TypeImpl;
} else {
// The name does not represent a type.
- RedirectingConstructorKind redirectingConstructorKind;
if (_isTypeNameInCatchClause(node)) {
reportErrorForNode(StaticWarningCode.NON_TYPE_IN_CATCH_CLAUSE, typeName,
[typeName.name]);
@@ -6163,14 +6085,9 @@
} else if (_isTypeNameInIsExpression(node)) {
reportErrorForNode(StaticWarningCode.TYPE_TEST_WITH_NON_TYPE, typeName,
[typeName.name]);
- } else if ((redirectingConstructorKind =
- _getRedirectingConstructorKind(node)) !=
- null) {
- ErrorCode errorCode =
- (redirectingConstructorKind == RedirectingConstructorKind.CONST
- ? CompileTimeErrorCode.REDIRECT_TO_NON_CLASS
- : StaticWarningCode.REDIRECT_TO_NON_CLASS);
- reportErrorForNode(errorCode, typeName, [typeName.name]);
+ } else if (_isRedirectingConstructor(node)) {
+ reportErrorForNode(CompileTimeErrorCode.REDIRECT_TO_NON_CLASS, typeName,
+ [typeName.name]);
} else if (_isTypeNameInTypeArgumentList(node)) {
reportErrorForNode(StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT,
typeName, [typeName.name]);
@@ -6282,23 +6199,6 @@
return nullability;
}
- /// Checks if the given [typeName] is the target in a redirected constructor.
- RedirectingConstructorKind _getRedirectingConstructorKind(TypeName typeName) {
- AstNode parent = typeName.parent;
- if (parent is ConstructorName) {
- AstNode grandParent = parent.parent;
- if (grandParent is ConstructorDeclaration) {
- if (identical(grandParent.redirectedConstructor, parent)) {
- if (grandParent.constKeyword != null) {
- return RedirectingConstructorKind.CONST;
- }
- return RedirectingConstructorKind.NORMAL;
- }
- }
- }
- return null;
- }
-
/// Return the type represented by the given type [annotation].
DartType _getType(TypeAnnotation annotation) {
DartType type = annotation.type;
@@ -6378,6 +6278,21 @@
return null;
}
+ /// Return `true` if the given [typeName] is the target in a redirected
+ /// constructor.
+ bool _isRedirectingConstructor(TypeName typeName) {
+ AstNode parent = typeName.parent;
+ if (parent is ConstructorName) {
+ AstNode grandParent = parent.parent;
+ if (grandParent is ConstructorDeclaration) {
+ if (identical(grandParent.redirectedConstructor, parent)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
/// Checks if the given [typeName] is used as the type in an as expression.
bool _isTypeNameInAsExpression(TypeName typeName) {
AstNode parent = typeName.parent;
@@ -6792,301 +6707,6 @@
bool isObjectMethod(String id);
}
-/// Provide common functionality shared by the various TypeProvider
-/// implementations.
-abstract class TypeProviderBase implements TypeProvider {
- @override
- List<InterfaceType> get nonSubtypableTypes => <InterfaceType>[
- boolType,
- doubleType,
- intType,
- nullType,
- numType,
- stringType
- ];
-
- @override
- bool isObjectGetter(String id) {
- PropertyAccessorElement element = objectType.element.getGetter(id);
- return (element != null && !element.isStatic);
- }
-
- @override
- bool isObjectMember(String id) {
- return isObjectGetter(id) || isObjectMethod(id);
- }
-
- @override
- bool isObjectMethod(String id) {
- MethodElement element = objectType.element.getMethod(id);
- return (element != null && !element.isStatic);
- }
-}
-
-/// Instances of the class `TypeProviderImpl` provide access to types defined by
-/// the language by looking for those types in the element model for the core
-/// library.
-class TypeProviderImpl extends TypeProviderBase {
- /// The type representing the built-in type 'bool'.
- InterfaceType _boolType;
-
- /// The type representing the built-in type 'double'.
- InterfaceType _doubleType;
-
- /// The type representing the built-in type 'Deprecated'.
- InterfaceType _deprecatedType;
-
- /// The type representing the built-in type 'Function'.
- InterfaceType _functionType;
-
- /// The type representing 'Future<dynamic>'.
- InterfaceType _futureDynamicType;
-
- /// The type representing 'Future<Null>'.
- InterfaceType _futureNullType;
-
- /// The type representing 'FutureOr<Null>'.
- InterfaceType _futureOrNullType;
-
- /// The type representing the built-in type 'FutureOr'.
- InterfaceType _futureOrType;
-
- /// The type representing the built-in type 'Future'.
- InterfaceType _futureType;
-
- /// The type representing the built-in type 'int'.
- InterfaceType _intType;
-
- /// The type representing 'Iterable<dynamic>'.
- InterfaceType _iterableDynamicType;
-
- /// The type representing 'Iterable<Object>'.
- InterfaceType _iterableObjectType;
-
- /// The type representing the built-in type 'Iterable'.
- InterfaceType _iterableType;
-
- /// The type representing the built-in type 'List'.
- InterfaceType _listType;
-
- /// The type representing the built-in type 'Map'.
- InterfaceType _mapType;
-
- /// The type representing the built-in type 'Map<Object, Object>'.
- InterfaceType _mapObjectObjectType;
-
- /// An shared object representing the value 'null'.
- DartObjectImpl _nullObject;
-
- /// The type representing the type 'Null'.
- InterfaceType _nullType;
-
- /// The type representing the built-in type 'num'.
- InterfaceType _numType;
-
- /// The type representing the built-in type 'Object'.
- InterfaceType _objectType;
-
- /// The type representing the type 'Set'.
- InterfaceType _setType;
-
- /// The type representing the built-in type 'StackTrace'.
- InterfaceType _stackTraceType;
-
- /// The type representing 'Stream<dynamic>'.
- InterfaceType _streamDynamicType;
-
- /// The type representing the built-in type 'Stream'.
- InterfaceType _streamType;
-
- /// The type representing the built-in type 'String'.
- InterfaceType _stringType;
-
- /// The type representing the built-in type 'Symbol'.
- InterfaceType _symbolType;
-
- /// The type representing the built-in type 'Type'.
- InterfaceType _typeType;
-
- /// Initialize a newly created type provider to provide the types defined in
- /// the given [coreLibrary] and [asyncLibrary].
- TypeProviderImpl(LibraryElement coreLibrary, LibraryElement asyncLibrary) {
- _initializeFrom(coreLibrary, asyncLibrary);
- }
-
- /// Return a type provider initialized from the same library elements as the
- /// [baseProvider].
- factory TypeProviderImpl.from(TypeProvider baseProvider) {
- return TypeProviderImpl(baseProvider.boolType.element.library,
- baseProvider.streamType.element.library);
- }
-
- @override
- InterfaceType get boolType => _boolType;
-
- @override
- DartType get bottomType => BottomTypeImpl.instanceLegacy;
-
- @override
- InterfaceType get deprecatedType => _deprecatedType;
-
- @override
- InterfaceType get doubleType => _doubleType;
-
- @override
- DartType get dynamicType => DynamicTypeImpl.instance;
-
- @override
- InterfaceType get functionType => _functionType;
-
- @override
- InterfaceType get futureDynamicType => _futureDynamicType;
-
- @override
- InterfaceType get futureNullType => _futureNullType;
-
- @override
- InterfaceType get futureOrNullType => _futureOrNullType;
-
- @override
- InterfaceType get futureOrType => _futureOrType;
-
- @override
- InterfaceType get futureType => _futureType;
-
- @override
- InterfaceType get intType => _intType;
-
- @override
- InterfaceType get iterableDynamicType => _iterableDynamicType;
-
- @override
- InterfaceType get iterableObjectType => _iterableObjectType;
-
- @override
- InterfaceType get iterableType => _iterableType;
-
- @override
- InterfaceType get listType => _listType;
-
- @override
- InterfaceType get mapObjectObjectType => _mapObjectObjectType;
-
- @override
- InterfaceType get mapType => _mapType;
-
- @override
- DartType get neverType => BottomTypeImpl.instance;
-
- @override
- DartObjectImpl get nullObject {
- if (_nullObject == null) {
- _nullObject = new DartObjectImpl(nullType, NullState.NULL_STATE);
- }
- return _nullObject;
- }
-
- @override
- InterfaceType get nullType => _nullType;
-
- @override
- InterfaceType get numType => _numType;
-
- @override
- InterfaceType get objectType => _objectType;
-
- @override
- InterfaceType get setType => _setType;
-
- @override
- InterfaceType get stackTraceType => _stackTraceType;
-
- @override
- InterfaceType get streamDynamicType => _streamDynamicType;
-
- @override
- InterfaceType get streamType => _streamType;
-
- @override
- InterfaceType get stringType => _stringType;
-
- @override
- InterfaceType get symbolType => _symbolType;
-
- @override
- InterfaceType get typeType => _typeType;
-
- @override
- VoidType get voidType => VoidTypeImpl.instance;
-
- /// Return the type with the given [typeName] from the given [namespace], or
- /// `null` if there is no class with the given name.
- InterfaceType _getType(Namespace namespace, String typeName) {
- Element element = namespace.get(typeName);
- if (element == null) {
- AnalysisEngine.instance.logger
- .logInformation("No definition of type $typeName");
- return null;
- }
- return (element as ClassElement).type;
- }
-
- /// Initialize the types provided by this type provider from the given
- /// [Namespace]s.
- void _initializeFrom(
- LibraryElement coreLibrary, LibraryElement asyncLibrary) {
- Namespace coreNamespace =
- new NamespaceBuilder().createPublicNamespaceForLibrary(coreLibrary);
- Namespace asyncNamespace =
- new NamespaceBuilder().createPublicNamespaceForLibrary(asyncLibrary);
-
- _boolType = _getType(coreNamespace, 'bool');
- _deprecatedType = _getType(coreNamespace, 'Deprecated');
- _doubleType = _getType(coreNamespace, 'double');
- _functionType = _getType(coreNamespace, 'Function');
- _futureOrType = _getType(asyncNamespace, 'FutureOr');
- _futureType = _getType(asyncNamespace, 'Future');
- _intType = _getType(coreNamespace, 'int');
- _iterableType = _getType(coreNamespace, 'Iterable');
- _listType = _getType(coreNamespace, 'List');
- _mapType = _getType(coreNamespace, 'Map');
- _nullType = _getType(coreNamespace, 'Null');
- _numType = _getType(coreNamespace, 'num');
- _objectType = _getType(coreNamespace, 'Object');
- _setType = _getType(coreNamespace, 'Set');
- _stackTraceType = _getType(coreNamespace, 'StackTrace');
- _streamType = _getType(asyncNamespace, 'Stream');
- _stringType = _getType(coreNamespace, 'String');
- _symbolType = _getType(coreNamespace, 'Symbol');
- _typeType = _getType(coreNamespace, 'Type');
- _futureDynamicType = _futureType.instantiate(<DartType>[dynamicType]);
- _futureNullType = _futureType.instantiate(<DartType>[_nullType]);
- _iterableDynamicType = _iterableType.instantiate(<DartType>[dynamicType]);
- _iterableObjectType = _iterableType.instantiate(<DartType>[_objectType]);
- _mapObjectObjectType =
- _mapType.instantiate(<DartType>[_objectType, _objectType]);
- _streamDynamicType = _streamType.instantiate(<DartType>[dynamicType]);
- // FutureOr<T> is still fairly new, so if we're analyzing an SDK that
- // doesn't have it yet, create an element for it.
- _futureOrType ??= createPlaceholderFutureOr(_futureType, _objectType);
- _futureOrNullType = _futureOrType.instantiate(<DartType>[_nullType]);
- }
-
- /// Create an [InterfaceType] that can be used for `FutureOr<T>` if the SDK
- /// being analyzed does not contain its own `FutureOr<T>`. This ensures that
- /// we can analyze older SDKs.
- static InterfaceType createPlaceholderFutureOr(
- InterfaceType futureType, InterfaceType objectType) {
- // TODO(brianwilkerson) Remove this method now that the class has been
- // defined.
- var compilationUnit =
- futureType.element.getAncestor((e) => e is CompilationUnitElement);
- var element = ElementFactory.classElement('FutureOr', objectType, ['T']);
- element.enclosingElement = compilationUnit;
- return element.type;
- }
-}
-
/// Modes in which [TypeResolverVisitor] works.
enum TypeResolverMode {
/// Resolve all names types of all nodes.
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 73b881c..3a98084 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -4,7 +4,6 @@
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
@@ -323,16 +322,28 @@
operator == TokenType.BAR_BAR_EQ) {
_recordStaticType(node, _nonNullable(_typeProvider.boolType));
} else {
- ExecutableElement staticMethodElement = node.staticElement;
- DartType staticType = _computeStaticReturnType(staticMethodElement);
- staticType = _typeSystem.refineBinaryExpressionType(
- _getStaticType(node.leftHandSide, read: true),
- operator,
- node.rightHandSide.staticType,
- staticType,
- _featureSet);
- _recordStaticType(node, staticType);
+ var operatorElement = node.staticElement;
+ var type = operatorElement?.returnType ?? _dynamicType;
+ type = _typeSystem.refineBinaryExpressionType(
+ _getStaticType(node.leftHandSide, read: true),
+ operator,
+ node.rightHandSide.staticType,
+ type,
+ _featureSet,
+ );
+ _recordStaticType(node, type);
+
+ var leftWriteType = _getStaticType(node.leftHandSide);
+ if (!_typeSystem.isAssignableTo(type, leftWriteType,
+ featureSet: _featureSet)) {
+ _resolver.errorReporter.reportTypeErrorForNode(
+ StaticTypeWarningCode.INVALID_ASSIGNMENT,
+ node.rightHandSide,
+ [type, leftWriteType],
+ );
+ }
}
+ _nullShortingTermination(node);
}
/**
@@ -594,15 +605,20 @@
*/
@override
void visitIndexExpression(IndexExpression node) {
+ DartType type;
if (node.inSetterContext()) {
- ExecutableElement staticMethodElement = node.staticElement;
- DartType staticType = _computeArgumentType(staticMethodElement);
- _recordStaticType(node, staticType);
+ var parameters = node.staticElement?.parameters;
+ if (parameters?.length == 2) {
+ type = parameters[1].type;
+ }
} else {
- ExecutableElement staticMethodElement = node.staticElement;
- DartType staticType = _computeStaticReturnType(staticMethodElement);
- _recordStaticType(node, staticType);
+ type = node.staticElement?.returnType;
}
+
+ type ??= _dynamicType;
+
+ _recordStaticType(node, type);
+ _nullShortingTermination(node);
}
/**
@@ -839,6 +855,12 @@
void visitPrefixedIdentifier(PrefixedIdentifier node) {
SimpleIdentifier prefixedIdentifier = node.identifier;
Element staticElement = prefixedIdentifier.staticElement;
+
+ if (staticElement is ExtensionElement) {
+ _setExtensionIdentifierType(node);
+ return;
+ }
+
DartType staticType = _dynamicType;
if (staticElement is ClassElement) {
if (_isNotTypeLiteral(node)) {
@@ -953,15 +975,12 @@
// TODO(brianwilkerson) Report this internal error.
}
- if (node.operator.type == TokenType.QUESTION_PERIOD &&
- _nonNullableEnabled) {
- staticType = _typeSystem.makeNullable(staticType);
- }
staticType = _inferTearOff(node, node.propertyName, staticType);
if (!_inferObjectAccess(node, staticType, propertyName)) {
_recordStaticType(propertyName, staticType);
_recordStaticType(node, staticType);
+ _nullShortingTermination(node);
}
}
@@ -1072,6 +1091,12 @@
@override
void visitSimpleIdentifier(SimpleIdentifier node) {
Element element = node.staticElement;
+
+ if (element is ExtensionElement) {
+ _setExtensionIdentifierType(node);
+ return;
+ }
+
DartType staticType = _dynamicType;
if (element is ClassElement) {
if (_isNotTypeLiteral(node)) {
@@ -1131,7 +1156,8 @@
@override
void visitSuperExpression(SuperExpression node) {
- if (thisType == null) {
+ if (thisType == null ||
+ node.thisOrAncestorOfType<ExtensionDeclaration>() != null) {
// TODO(brianwilkerson) Report this error if it hasn't already been
// reported.
_recordStaticType(node, _dynamicType);
@@ -1225,22 +1251,6 @@
}
}
- /**
- * Record that the static type of the given node is the type of the second argument to the method
- * represented by the given element.
- *
- * @param element the element representing the method invoked by the given node
- */
- DartType _computeArgumentType(ExecutableElement element) {
- if (element != null) {
- List<ParameterElement> parameters = element.parameters;
- if (parameters != null && parameters.length == 2) {
- return parameters[1].type;
- }
- }
- return _dynamicType;
- }
-
DartType _computeElementType(CollectionElement element) {
if (element is ForElement) {
return _computeElementType(element.body);
@@ -1268,9 +1278,7 @@
}
} else if (expressionType.isDynamic) {
return expressionType;
- } else if (isNull &&
- element.spreadOperator.type ==
- TokenType.PERIOD_PERIOD_PERIOD_QUESTION) {
+ } else if (isNull && element.isNullAware) {
return expressionType;
}
// TODO(brianwilkerson) Report this as an error.
@@ -1538,9 +1546,7 @@
elementType: expressionType,
keyType: expressionType,
valueType: expressionType);
- } else if (isNull &&
- element.spreadOperator.type ==
- TokenType.PERIOD_PERIOD_PERIOD_QUESTION) {
+ } else if (isNull && element.isNullAware) {
return _InferredCollectionElementTypeInformation(
elementType: expressionType,
keyType: expressionType,
@@ -1764,7 +1770,7 @@
AstNode parent = node.parent;
if (initializer != null) {
if (parent is VariableDeclarationList && parent.type == null) {
- DartType type = resolutionMap.staticTypeForExpression(initializer);
+ DartType type = initializer.staticType;
if (type != null && !type.isBottom && !type.isDartCoreNull) {
VariableElement element = node.declaredElement;
if (element is LocalVariableElementImpl) {
@@ -2002,6 +2008,25 @@
return type;
}
+ /// If we reached a null-shorting termination, and the [node] has null
+ /// shorting, make the type of the [node] nullable.
+ void _nullShortingTermination(Expression node) {
+ if (!_nonNullableEnabled) return;
+
+ var parent = node.parent;
+ if (parent is AssignmentExpression && parent.leftHandSide == node) {
+ return;
+ }
+ if (parent is PropertyAccess) {
+ return;
+ }
+
+ if (_hasNullShorting(node)) {
+ var type = node.staticType;
+ node.staticType = _typeSystem.makeNullable(type);
+ }
+ }
+
/**
* Record that the static type of the given node is the given type.
*
@@ -2016,6 +2041,40 @@
}
}
+ void _setExtensionIdentifierType(Identifier node) {
+ if (node is SimpleIdentifier && node.inDeclarationContext()) {
+ return;
+ }
+
+ var parent = node.parent;
+
+ if (parent is PrefixedIdentifier && parent.identifier == node) {
+ node = parent;
+ parent = node.parent;
+ }
+
+ if (parent is CommentReference ||
+ parent is ExtensionOverride && parent.extensionName == node ||
+ parent is MethodInvocation && parent.target == node ||
+ parent is PrefixedIdentifier && parent.prefix == node ||
+ parent is PropertyAccess && parent.target == node) {
+ return;
+ }
+
+ _resolver.errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.EXTENSION_AS_EXPRESSION,
+ node,
+ [node.name],
+ );
+
+ if (node is PrefixedIdentifier) {
+ node.identifier.staticType = _dynamicType;
+ node.staticType = _dynamicType;
+ } else if (node is SimpleIdentifier) {
+ node.staticType = _dynamicType;
+ }
+ }
+
DartType _toMapType(SetOrMapLiteral node, DartType contextType,
List<_InferredCollectionElementTypeInformation> inferredTypes) {
DartType dynamicType = _typeProvider.dynamicType;
@@ -2116,6 +2175,23 @@
return type;
}
}
+
+ /// Return `true` if the [node] has null-aware shorting, e.g. `foo?.bar`.
+ static bool _hasNullShorting(Expression node) {
+ if (node is AssignmentExpression) {
+ return _hasNullShorting(node.leftHandSide);
+ }
+ if (node is IndexExpression) {
+ return node.leftBracket.type ==
+ TokenType.QUESTION_PERIOD_OPEN_SQUARE_BRACKET ||
+ _hasNullShorting(node.target);
+ }
+ if (node is PropertyAccess) {
+ return node.operator.type == TokenType.QUESTION_PERIOD ||
+ _hasNullShorting(node.target);
+ }
+ return false;
+ }
}
class _InferredCollectionElementTypeInformation {
diff --git a/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart b/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
index 8627558..5d27b81 100644
--- a/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
+++ b/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
@@ -2,797 +2,61 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/dart/analysis/driver.dart';
-import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/constant.dart';
+import 'package:analyzer/src/dart/element/type_provider.dart';
import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
-import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/sdk.dart' show DartSdk;
import 'package:analyzer/src/generated/source.dart' show Source;
-import 'package:analyzer/src/generated/testing/ast_test_factory.dart';
-import 'package:analyzer/src/generated/testing/element_factory.dart';
-import 'package:analyzer/src/string_source.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/test_utilities/mock_sdk_elements.dart';
/**
* A type provider that can be used by tests without creating the element model
* for the core library.
*/
-class TestTypeProvider extends TypeProviderBase {
- final bool _isNonNullableByDefault;
+class TestTypeProvider extends TypeProviderImpl {
+ factory TestTypeProvider([
+ AnalysisContext context,
+ Object analysisDriver,
+ NullabilitySuffix nullabilitySuffix = NullabilitySuffix.star,
+ ]) {
+ context ??= _MockAnalysisContext();
+ var sdkElements = MockSdkElements(context, nullabilitySuffix);
+ return TestTypeProvider._(
+ sdkElements.coreLibrary,
+ sdkElements.asyncLibrary,
+ );
+ }
- /**
- * The type representing the built-in type 'bool'.
- */
- InterfaceType _boolType;
+ TestTypeProvider._(LibraryElement coreLibrary, LibraryElement asyncLibrary)
+ : super(coreLibrary, asyncLibrary);
+}
- /**
- * The type representing the type 'bottom'.
- */
- DartType _bottomType;
+class _MockAnalysisContext implements AnalysisContext {
+ @override
+ final SourceFactory sourceFactory = _MockSourceFactory();
- /**
- * The type representing the built-in type 'double'.
- */
- InterfaceType _doubleType;
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
- /**
- * The type representing the built-in type 'deprecated'.
- */
- InterfaceType _deprecatedType;
+class _MockSource implements Source {
+ @override
+ final Uri uri;
- /**
- * The type representing the built-in type 'dynamic'.
- */
- DartType _dynamicType;
-
- /**
- * The type representing the built-in type 'Function'.
- */
- InterfaceType _functionType;
-
- /**
- * The type representing 'Future<dynamic>'
- */
- InterfaceType _futureDynamicType;
-
- /**
- * The type representing 'Future<Null>'
- */
- InterfaceType _futureNullType;
-
- /**
- * The type representing the built-in type 'FutureOr'
- */
- InterfaceType _futureOrNullType;
-
- /**
- * The type representing the built-in type 'FutureOr'
- */
- InterfaceType _futureOrType;
-
- /**
- * The type representing the built-in type 'Future'
- */
- InterfaceType _futureType;
-
- /**
- * The type representing the built-in type 'int'.
- */
- InterfaceType _intType;
-
- /**
- * The type representing 'Iterable<dynamic>'
- */
- InterfaceType _iterableDynamicType;
-
- /**
- * The type representing 'Iterable<Object>'
- */
- InterfaceType _iterableObjectType;
-
- /**
- * The type representing the built-in type 'Iterable'.
- */
- InterfaceType _iterableType;
-
- /**
- * The type representing the built-in type 'Iterator'.
- */
- InterfaceType _iteratorType;
-
- /**
- * The type representing the built-in type 'List'.
- */
- InterfaceType _listType;
-
- /**
- * The type representing the built-in type 'Map'.
- */
- InterfaceType _mapType;
-
- /**
- * The type representing the built-in type 'Map<Object, Object>'.
- */
- InterfaceType _mapObjectObjectType;
-
- /**
- * An shared object representing the value 'null'.
- */
- DartObjectImpl _nullObject;
-
- /**
- * The type representing the built-in type 'Null'.
- */
- InterfaceType _nullType;
-
- /**
- * The type representing the built-in type 'num'.
- */
- InterfaceType _numType;
-
- /**
- * The type representing the built-in type 'Object'.
- */
- InterfaceType _objectType;
-
- /**
- * The type representing the built-in type 'Set'.
- */
- InterfaceType _setType;
-
- /**
- * The type representing the built-in type 'StackTrace'.
- */
- InterfaceType _stackTraceType;
-
- /**
- * The type representing 'Stream<dynamic>'.
- */
- InterfaceType _streamDynamicType;
-
- /**
- * The type representing the built-in type 'Stream'.
- */
- InterfaceType _streamType;
-
- /**
- * The type representing the built-in type 'String'.
- */
- InterfaceType _stringType;
-
- /**
- * The type representing the built-in type 'Symbol'.
- */
- InterfaceType _symbolType;
-
- /**
- * The type representing the built-in type 'Type'.
- */
- InterfaceType _typeType;
-
- /**
- * The analysis context, if any. Used to create an appropriate 'dart:async'
- * library to back `Future<T>`.
- */
- AnalysisContext _context;
-
- /**
- * The analysis driver, if any. Used to create an appropriate 'dart:async'
- * library to back `Future<T>`.
- */
- AnalysisDriver _driver;
-
- /// TODO(paulberry): rework API and make _isNonNullableByDefault required.
- TestTypeProvider(
- [this._context, this._driver, this._isNonNullableByDefault = false]);
+ _MockSource(this.uri);
@override
- InterfaceType get boolType {
- if (_boolType == null) {
- ClassElementImpl boolElement = ElementFactory.classElement2("bool");
- _boolType = boolElement.type;
- ConstructorElementImpl fromEnvironment =
- ElementFactory.constructorElement(
- boolElement, "fromEnvironment", true);
- fromEnvironment.parameters = <ParameterElement>[
- ElementFactory.requiredParameter2("name", stringType),
- ElementFactory.namedParameter3("defaultValue",
- type: _boolType,
- initializer: AstTestFactory.booleanLiteral(false),
- initializerCode: 'false')
- ];
- fromEnvironment.factory = true;
- fromEnvironment.isCycleFree = true;
- boolElement.constructors = <ConstructorElement>[fromEnvironment];
- }
- return _boolType;
- }
+ String get encoding => '$uri';
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class _MockSourceFactory implements SourceFactory {
@override
- DartType get bottomType {
- if (_bottomType == null) {
- _bottomType = BottomTypeImpl.instance;
- }
- return _bottomType;
+ Source forUri(String uriStr) {
+ var uri = Uri.parse(uriStr);
+ return _MockSource(uri);
}
- @override
- InterfaceType get deprecatedType {
- if (_deprecatedType == null) {
- ClassElementImpl deprecatedElement =
- ElementFactory.classElement2("Deprecated");
- FieldElementImpl expiresField = ElementFactory.fieldElement(
- 'expires', false, true, false, stringType);
- deprecatedElement.fields = <FieldElement>[expiresField];
- deprecatedElement.accessors = <PropertyAccessorElement>[
- expiresField.getter
- ];
- ConstructorElementImpl constructor = ElementFactory.constructorElement(
- deprecatedElement, '', true, [stringType]);
- (constructor.parameters[0] as ParameterElementImpl).name = 'expires';
- ConstructorFieldInitializer expiresInit =
- AstTestFactory.constructorFieldInitializer(
- true, 'expires', AstTestFactory.identifier3('expires'));
- expiresInit.fieldName.staticElement = expiresField;
- (expiresInit.expression as SimpleIdentifier).staticElement =
- constructor.parameters[0];
- constructor.constantInitializers = <ConstructorInitializer>[expiresInit];
- deprecatedElement.constructors = <ConstructorElement>[constructor];
- _deprecatedType = deprecatedElement.type;
- }
- return _deprecatedType;
- }
-
- @override
- InterfaceType get doubleType {
- if (_doubleType == null) {
- _initializeNumericTypes();
- }
- return _doubleType;
- }
-
- @override
- DartType get dynamicType {
- if (_dynamicType == null) {
- _dynamicType = DynamicTypeImpl.instance;
- }
- return _dynamicType;
- }
-
- @override
- InterfaceType get functionType {
- if (_functionType == null) {
- ClassElementImpl functionClass = ElementFactory.classElement2("Function");
- functionClass.constructors = <ConstructorElement>[
- ElementFactory.constructorElement(functionClass, null, false)
- ];
- _functionType = functionClass.type;
- }
- return _functionType;
- }
-
- @override
- InterfaceType get futureDynamicType {
- if (_futureDynamicType == null) {
- _futureDynamicType = futureType.instantiate(<DartType>[dynamicType]);
- }
- return _futureDynamicType;
- }
-
- @override
- InterfaceType get futureNullType {
- if (_futureNullType == null) {
- _futureNullType = futureType.instantiate(<DartType>[nullType]);
- }
- return _futureNullType;
- }
-
- @override
- InterfaceType get futureOrNullType {
- if (_futureOrNullType == null) {
- _futureOrNullType = futureOrType.instantiate(<DartType>[nullType]);
- }
- return _futureOrNullType;
- }
-
- @override
- InterfaceType get futureOrType {
- if (_futureOrType == null) {
- _initDartAsync();
- }
- return _futureOrType;
- }
-
- @override
- InterfaceType get futureType {
- if (_futureType == null) {
- _initDartAsync();
- }
- return _futureType;
- }
-
- @override
- InterfaceType get intType {
- if (_intType == null) {
- _initializeNumericTypes();
- }
- return _intType;
- }
-
- @override
- InterfaceType get iterableDynamicType {
- if (_iterableDynamicType == null) {
- _iterableDynamicType = iterableType.instantiate(<DartType>[dynamicType]);
- }
- return _iterableDynamicType;
- }
-
- @override
- InterfaceType get iterableObjectType {
- if (_iterableObjectType == null) {
- _iterableObjectType = iterableType.instantiate(<DartType>[objectType]);
- }
- return _iterableObjectType;
- }
-
- @override
- InterfaceType get iterableType {
- if (_iterableType == null) {
- ClassElementImpl iterableElement =
- ElementFactory.classElement2("Iterable", ["E"]);
- _iterableType = iterableElement.type;
- DartType eType = iterableElement.typeParameters[0].type;
- _setAccessors(iterableElement, <PropertyAccessorElement>[
- ElementFactory.getterElement(
- "iterator", false, iteratorType.instantiate(<DartType>[eType])),
- ElementFactory.getterElement("last", false, eType)
- ]);
- iterableElement.constructors = <ConstructorElement>[
- ElementFactory.constructorElement(iterableElement, '', true)
- ..isCycleFree = true
- ];
- _propagateTypeArguments(iterableElement);
- }
- return _iterableType;
- }
-
- InterfaceType get iteratorType {
- if (_iteratorType == null) {
- ClassElementImpl iteratorElement =
- ElementFactory.classElement2("Iterator", ["E"]);
- _iteratorType = iteratorElement.type;
- DartType eType = iteratorElement.typeParameters[0].type;
- _setAccessors(iteratorElement, <PropertyAccessorElement>[
- ElementFactory.getterElement("current", false, eType)
- ]);
- iteratorElement.constructors = <ConstructorElement>[
- ElementFactory.constructorElement(iteratorElement, null, false)
- ];
- _propagateTypeArguments(iteratorElement);
- }
- return _iteratorType;
- }
-
- @override
- InterfaceType get listType {
- if (_listType == null) {
- ClassElementImpl listElement =
- ElementFactory.classElement2("List", ["E"]);
- listElement.constructors = <ConstructorElement>[
- ElementFactory.constructorElement2(listElement, null)
- ];
- _listType = listElement.type;
- DartType eType = listElement.typeParameters[0].type;
- InterfaceType iterableType =
- this.iterableType.instantiate(<DartType>[eType]);
- listElement.interfaces = <InterfaceType>[iterableType];
- _setAccessors(listElement, <PropertyAccessorElement>[
- ElementFactory.getterElement("length", false, intType)
- ]);
- listElement.methods = <MethodElement>[
- ElementFactory.methodElement("[]", eType, [intType]),
- ElementFactory.methodElement(
- "[]=", VoidTypeImpl.instance, [intType, eType]),
- ElementFactory.methodElement("add", VoidTypeImpl.instance, [eType])
- ];
- _propagateTypeArguments(listElement);
- }
- return _listType;
- }
-
- @override
- InterfaceType get mapObjectObjectType {
- if (_mapObjectObjectType == null) {
- _mapObjectObjectType =
- mapType.instantiate(<DartType>[objectType, objectType]);
- }
- return _mapObjectObjectType;
- }
-
- @override
- InterfaceType get mapType {
- if (_mapType == null) {
- ClassElementImpl mapElement =
- ElementFactory.classElement2("Map", ["K", "V"]);
- _mapType = mapElement.type;
- DartType kType = mapElement.typeParameters[0].type;
- DartType vType = mapElement.typeParameters[1].type;
- _setAccessors(mapElement, <PropertyAccessorElement>[
- ElementFactory.getterElement("length", false, intType)
- ]);
- mapElement.methods = <MethodElement>[
- ElementFactory.methodElement("[]", vType, [objectType]),
- ElementFactory.methodElement(
- "[]=", VoidTypeImpl.instance, [kType, vType])
- ];
- mapElement.constructors = <ConstructorElement>[
- ElementFactory.constructorElement(mapElement, '', false)
- ..external = true
- ..factory = true
- ];
- _propagateTypeArguments(mapElement);
- }
- return _mapType;
- }
-
- @override
- DartType get neverType {
- return BottomTypeImpl.instance;
- }
-
- @override
- DartObjectImpl get nullObject {
- if (_nullObject == null) {
- _nullObject = new DartObjectImpl(nullType, NullState.NULL_STATE);
- }
- return _nullObject;
- }
-
- @override
- InterfaceType get nullType {
- if (_nullType == null) {
- var nullElement = ElementFactory.classElement2("Null");
- nullElement.constructors = <ConstructorElement>[
- ElementFactory.constructorElement(
- nullElement, '_uninstantiatable', false)
- ..factory = true
- ];
- // Create a library element for "dart:core"
- // This enables the "isDartCoreNull" getter.
- var library = new LibraryElementImpl.forNode(
- _context,
- null,
- AstTestFactory.libraryIdentifier2(["dart.core"]),
- _isNonNullableByDefault);
- var unit = new CompilationUnitElementImpl();
- library.definingCompilationUnit = unit;
- unit.librarySource =
- unit.source = new StringSource('', null, uri: Uri.parse('dart:core'));
-
- nullElement.enclosingElement = library;
- _nullType = nullElement.type;
- }
- return _nullType;
- }
-
- @override
- InterfaceType get numType {
- if (_numType == null) {
- _initializeNumericTypes();
- }
- return _numType;
- }
-
- @override
- InterfaceType get objectType {
- if (_objectType == null) {
- ClassElementImpl objectElement = ElementFactory.object;
- _objectType = objectElement.type;
- ConstructorElementImpl constructor =
- ElementFactory.constructorElement(objectElement, '', true);
- constructor.constantInitializers = <ConstructorInitializer>[];
- objectElement.constructors = <ConstructorElement>[constructor];
- objectElement.methods = <MethodElement>[
- ElementFactory.methodElement("toString", stringType),
- ElementFactory.methodElement("==", boolType, [_objectType]),
- ElementFactory.methodElement("noSuchMethod", dynamicType, [dynamicType])
- ];
- _setAccessors(objectElement, <PropertyAccessorElement>[
- ElementFactory.getterElement("hashCode", false, intType),
- ElementFactory.getterElement("runtimeType", false, typeType)
- ]);
- }
- return _objectType;
- }
-
- @override
- InterfaceType get setType {
- if (_setType == null) {
- ClassElementImpl setElement = ElementFactory.classElement2("Set", ["E"]);
- _setType = setElement.type;
- }
- return _setType;
- }
-
- @override
- InterfaceType get stackTraceType {
- if (_stackTraceType == null) {
- ClassElementImpl stackTraceElement =
- ElementFactory.classElement2("StackTrace");
- stackTraceElement.constructors = <ConstructorElement>[
- ElementFactory.constructorElement(stackTraceElement, null, false)
- ];
- _stackTraceType = stackTraceElement.type;
- }
- return _stackTraceType;
- }
-
- @override
- InterfaceType get streamDynamicType {
- if (_streamDynamicType == null) {
- _streamDynamicType = streamType.instantiate(<DartType>[dynamicType]);
- }
- return _streamDynamicType;
- }
-
- @override
- InterfaceType get streamType {
- if (_streamType == null) {
- _streamType = ElementFactory.classElement2("Stream", ["T"]).type;
- }
- return _streamType;
- }
-
- @override
- InterfaceType get stringType {
- if (_stringType == null) {
- ClassElementImpl stringElement = ElementFactory.classElement2("String");
- _stringType = stringElement.type;
- _setAccessors(stringElement, <PropertyAccessorElement>[
- ElementFactory.getterElement("isEmpty", false, boolType),
- ElementFactory.getterElement("length", false, intType),
- ElementFactory.getterElement(
- "codeUnits", false, listType.instantiate(<DartType>[intType]))
- ]);
- stringElement.methods = <MethodElement>[
- ElementFactory.methodElement("+", _stringType, [_stringType]),
- ElementFactory.methodElement("toLowerCase", _stringType),
- ElementFactory.methodElement("toUpperCase", _stringType)
- ];
- ConstructorElementImpl fromEnvironment =
- ElementFactory.constructorElement(
- stringElement, "fromEnvironment", true);
- fromEnvironment.parameters = <ParameterElement>[
- ElementFactory.requiredParameter2("name", stringType),
- ElementFactory.namedParameter3("defaultValue", type: _stringType)
- ];
- fromEnvironment.factory = true;
- fromEnvironment.isCycleFree = true;
- stringElement.constructors = <ConstructorElement>[fromEnvironment];
- }
- return _stringType;
- }
-
- @override
- InterfaceType get symbolType {
- if (_symbolType == null) {
- ClassElementImpl symbolClass = ElementFactory.classElement2("Symbol");
- ConstructorElementImpl constructor = ElementFactory.constructorElement(
- symbolClass, '', true, [stringType]);
- constructor.factory = true;
- constructor.isCycleFree = true;
- symbolClass.constructors = <ConstructorElement>[constructor];
- _symbolType = symbolClass.type;
- }
- return _symbolType;
- }
-
- @override
- InterfaceType get typeType {
- if (_typeType == null) {
- ClassElementImpl typeClass = ElementFactory.classElement2("Type");
- typeClass.constructors = <ConstructorElement>[
- ElementFactory.constructorElement(typeClass, null, false)
- ..isSynthetic = true
- ];
- _typeType = typeClass.type;
- }
- return _typeType;
- }
-
- @override
- VoidType get voidType => VoidTypeImpl.instance;
-
- void _initDartAsync() {
- Source asyncSource;
- if (_driver != null) {
- asyncSource = _driver.sourceFactory.forUri(DartSdk.DART_ASYNC);
- } else if (_context != null) {
- asyncSource = _context.sourceFactory.forUri(DartSdk.DART_ASYNC);
- _context.setContents(asyncSource, "");
- } else {
- asyncSource = null;
- }
- CompilationUnitElementImpl asyncUnit = new CompilationUnitElementImpl();
- LibraryElementImpl asyncLibrary = new LibraryElementImpl.forNode(
- _context,
- null,
- AstTestFactory.libraryIdentifier2(["dart.async"]),
- _isNonNullableByDefault);
- asyncLibrary.definingCompilationUnit = asyncUnit;
- asyncUnit.librarySource = asyncUnit.source = asyncSource;
-
- ClassElementImpl future = ElementFactory.classElement2("Future", ["T"]);
- _futureType = future.type;
- asyncUnit.types = <ClassElement>[future];
- ClassElementImpl futureOr = ElementFactory.classElement2("FutureOr", ["T"]);
- _futureOrType = futureOr.type;
- asyncUnit.types = <ClassElement>[future, futureOr];
- }
-
- /**
- * Initialize the numeric types. They are created as a group so that we can
- * (a) create the right hierarchy and (b) add members to them.
- */
- void _initializeNumericTypes() {
- //
- // Create the type hierarchy.
- //
- ClassElementImpl numElement = ElementFactory.classElement2("num");
- _numType = numElement.type;
- ClassElementImpl intElement = ElementFactory.classElement("int", _numType);
- _intType = intElement.type;
- ClassElementImpl doubleElement =
- ElementFactory.classElement("double", _numType);
- _doubleType = doubleElement.type;
- //
- // Force the referenced types to be cached.
- //
- objectType;
- boolType;
- nullType;
- stringType;
- //
- // Add the methods.
- //
- numElement.methods = <MethodElement>[
- ElementFactory.methodElement("+", _numType, [_numType]),
- ElementFactory.methodElement("-", _numType, [_numType]),
- ElementFactory.methodElement("*", _numType, [_numType]),
- ElementFactory.methodElement("%", _numType, [_numType]),
- ElementFactory.methodElement("/", _doubleType, [_numType]),
- ElementFactory.methodElement("~/", _numType, [_numType]),
- ElementFactory.methodElement("-", _numType),
- ElementFactory.methodElement("remainder", _numType, [_numType]),
- ElementFactory.methodElement("<", _boolType, [_numType]),
- ElementFactory.methodElement("<=", _boolType, [_numType]),
- ElementFactory.methodElement(">", _boolType, [_numType]),
- ElementFactory.methodElement(">=", _boolType, [_numType]),
- ElementFactory.methodElement("==", _boolType, [_objectType]),
- ElementFactory.methodElement("abs", _numType),
- ElementFactory.methodElement("floor", _numType),
- ElementFactory.methodElement("ceil", _numType),
- ElementFactory.methodElement("round", _numType),
- ElementFactory.methodElement("truncate", _numType),
- ElementFactory.methodElement("toInt", _intType),
- ElementFactory.methodElement("toDouble", _doubleType),
- ElementFactory.methodElement("toStringAsFixed", _stringType, [_intType]),
- ElementFactory.methodElement(
- "toStringAsExponential", _stringType, [_intType]),
- ElementFactory.methodElement(
- "toStringAsPrecision", _stringType, [_intType]),
- ElementFactory.methodElement("toRadixString", _stringType, [_intType])
- ];
- numElement.accessors = [
- ElementFactory.getterElement('isInfinite', false, _boolType),
- ElementFactory.getterElement('isNaN', false, _boolType),
- ElementFactory.getterElement('isNegative', false, _boolType),
- ];
- intElement.methods = <MethodElement>[
- ElementFactory.methodElement("&", _intType, [_intType]),
- ElementFactory.methodElement("|", _intType, [_intType]),
- ElementFactory.methodElement("^", _intType, [_intType]),
- ElementFactory.methodElement("~", _intType),
- ElementFactory.methodElement("<<", _intType, [_intType]),
- ElementFactory.methodElement(">>", _intType, [_intType]),
- ElementFactory.methodElement("-", _intType),
- ElementFactory.methodElement("abs", _intType),
- ElementFactory.methodElement("round", _intType),
- ElementFactory.methodElement("floor", _intType),
- ElementFactory.methodElement("ceil", _intType),
- ElementFactory.methodElement("truncate", _intType),
- ElementFactory.methodElement("toString", _stringType)
- ];
- ConstructorElementImpl fromEnvironment =
- ElementFactory.constructorElement(intElement, "fromEnvironment", true);
- fromEnvironment.parameters = <ParameterElement>[
- ElementFactory.requiredParameter2("name", stringType),
- ElementFactory.namedParameter3("defaultValue", type: _intType)
- ];
- fromEnvironment.factory = true;
- fromEnvironment.isCycleFree = true;
- numElement.constructors = <ConstructorElement>[
- ElementFactory.constructorElement(numElement, null, false)
- ..isSynthetic = true
- ];
- intElement.constructors = <ConstructorElement>[fromEnvironment];
- doubleElement.constructors = <ConstructorElement>[
- ElementFactory.constructorElement(doubleElement, null, false)
- ..isSynthetic = true
- ];
- ConstFieldElementImpl varINFINITY = ElementFactory.fieldElement(
- "INFINITY", true, false, true, _doubleType,
- initializer: AstTestFactory.doubleLiteral(double.infinity));
- varINFINITY.constantInitializer = AstTestFactory.binaryExpression(
- AstTestFactory.integer(1), TokenType.SLASH, AstTestFactory.integer(0));
- List<FieldElement> fields = <FieldElement>[
- ElementFactory.fieldElement("NAN", true, false, true, _doubleType,
- initializer: AstTestFactory.doubleLiteral(double.nan)),
- varINFINITY,
- ElementFactory.fieldElement(
- "NEGATIVE_INFINITY", true, false, true, _doubleType,
- initializer: AstTestFactory.doubleLiteral(double.negativeInfinity)),
- ElementFactory.fieldElement(
- "MIN_POSITIVE", true, false, true, _doubleType,
- initializer: AstTestFactory.doubleLiteral(double.minPositive)),
- ElementFactory.fieldElement("MAX_FINITE", true, false, true, _doubleType,
- initializer: AstTestFactory.doubleLiteral(double.maxFinite))
- ];
- doubleElement.fields = fields;
- int fieldCount = fields.length;
- List<PropertyAccessorElement> accessors =
- new List<PropertyAccessorElement>(fieldCount);
- for (int i = 0; i < fieldCount; i++) {
- accessors[i] = fields[i].getter;
- }
- doubleElement.accessors = accessors;
- doubleElement.methods = <MethodElement>[
- ElementFactory.methodElement("remainder", _doubleType, [_numType]),
- ElementFactory.methodElement("+", _doubleType, [_numType]),
- ElementFactory.methodElement("-", _doubleType, [_numType]),
- ElementFactory.methodElement("*", _doubleType, [_numType]),
- ElementFactory.methodElement("%", _doubleType, [_numType]),
- ElementFactory.methodElement("/", _doubleType, [_numType]),
- ElementFactory.methodElement("~/", _doubleType, [_numType]),
- ElementFactory.methodElement("-", _doubleType),
- ElementFactory.methodElement("abs", _doubleType),
- ElementFactory.methodElement("round", _doubleType),
- ElementFactory.methodElement("floor", _doubleType),
- ElementFactory.methodElement("ceil", _doubleType),
- ElementFactory.methodElement("truncate", _doubleType),
- ElementFactory.methodElement("toString", _stringType)
- ];
- }
-
- /**
- * Given a [classElement] representing a class with type parameters, propagate
- * those type parameters to all of the accessors, methods and constructors
- * defined for the class.
- */
- void _propagateTypeArguments(ClassElementImpl classElement) {
- for (PropertyAccessorElement accessor in classElement.accessors) {
- (accessor as ExecutableElementImpl).type = new FunctionTypeImpl(accessor);
- }
- for (MethodElement method in classElement.methods) {
- (method as ExecutableElementImpl).type = new FunctionTypeImpl(method);
- }
- }
-
- /**
- * Set the accessors for the given class [element] to the given [accessors]
- * and also set the fields to those that correspond to the accessors.
- */
- void _setAccessors(
- ClassElementImpl element, List<PropertyAccessorElement> accessors) {
- element.accessors = accessors;
- element.fields = accessors
- .map((PropertyAccessorElement accessor) => accessor.variable)
- .cast<FieldElement>()
- .toList();
- }
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
diff --git a/pkg/analyzer/lib/src/lint/linter.dart b/pkg/analyzer/lib/src/lint/linter.dart
index 5f02024..2d1444a 100644
--- a/pkg/analyzer/lib/src/lint/linter.dart
+++ b/pkg/analyzer/lib/src/lint/linter.dart
@@ -15,7 +15,9 @@
import 'package:analyzer/src/dart/ast/ast.dart';
import 'package:analyzer/src/dart/ast/token.dart';
import 'package:analyzer/src/dart/constant/potentially_constant.dart';
+import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
+import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/dart/error/lint_codes.dart';
import 'package:analyzer/src/generated/engine.dart'
show AnalysisErrorInfo, AnalysisErrorInfoImpl, AnalysisOptions, Logger;
@@ -280,6 +282,14 @@
if (element == null || !element.isConst) {
return false;
}
+
+ // Ensure that dependencies (e.g. default parameter values) are computed.
+ var implElement = element;
+ if (element is ConstructorMember) {
+ implElement = element.baseElement;
+ }
+ (implElement as ConstructorElementImpl).computeConstantDependencies();
+
//
// Verify that the evaluation of the constructor would not produce an
// exception.
diff --git a/pkg/analyzer/lib/src/plugin/task.dart b/pkg/analyzer/lib/src/plugin/task.dart
deleted file mode 100644
index 54ec75e..0000000
--- a/pkg/analyzer/lib/src/plugin/task.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2015, 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.
-
-/**
- * Support for client code that extends the analysis engine by adding new
- * analysis tasks.
- */
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/task/api/model.dart';
-
-/**
- * A function that will create a new [WorkManager] for the given [context].
- */
-typedef WorkManager WorkManagerFactory(InternalAnalysisContext context);
diff --git a/pkg/analyzer/lib/src/services/available_declarations.dart b/pkg/analyzer/lib/src/services/available_declarations.dart
index 70428bf..52439ce 100644
--- a/pkg/analyzer/lib/src/services/available_declarations.dart
+++ b/pkg/analyzer/lib/src/services/available_declarations.dart
@@ -590,7 +590,7 @@
file.path,
file.uri,
file.isLibraryDeprecated,
- file.exportedDeclarations,
+ file.exportedDeclarations ?? const [],
);
_idToLibrary[file.id] = library;
_changesController.add(
@@ -735,7 +735,7 @@
libraryFile.path,
libraryFile.uri,
libraryFile.isLibraryDeprecated,
- libraryFile.exportedDeclarations,
+ libraryFile.exportedDeclarations ?? const [],
);
_idToLibrary[library.id] = library;
changedLibraries.add(library);
@@ -824,6 +824,9 @@
case DeclarationKind.FUNCTION_TYPE_ALIAS:
var name = declaration.name;
return <String>['$uriStr::$name'];
+ case DeclarationKind.CONSTRUCTOR:
+ var className = declaration.parent.name;
+ return <String>['$uriStr::$className'];
case DeclarationKind.ENUM_CONSTANT:
var enumName = declaration.parent.name;
return <String>['$uriStr::$enumName'];
diff --git a/pkg/analyzer/lib/src/summary/link.dart b/pkg/analyzer/lib/src/summary/link.dart
index b724baf..b3e3783 100644
--- a/pkg/analyzer/lib/src/summary/link.dart
+++ b/pkg/analyzer/lib/src/summary/link.dart
@@ -70,6 +70,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/resolver/ast_rewrite.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_engine.dart';
diff --git a/pkg/analyzer/lib/src/summary/resynthesize.dart b/pkg/analyzer/lib/src/summary/resynthesize.dart
index 4601ade..4cfe876 100644
--- a/pkg/analyzer/lib/src/summary/resynthesize.dart
+++ b/pkg/analyzer/lib/src/summary/resynthesize.dart
@@ -12,6 +12,7 @@
import 'package:analyzer/src/dart/element/handle.dart';
import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/type_provider.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/source_io.dart';
@@ -20,7 +21,6 @@
import 'package:analyzer/src/summary/expr_builder.dart';
import 'package:analyzer/src/summary/format.dart';
import 'package:analyzer/src/summary/idl.dart';
-import 'package:analyzer/src/summary/summary_sdk.dart';
/**
* Expando for marking types with implicit type arguments, which are the same as
@@ -413,10 +413,7 @@
void _buildTypeProvider() {
_coreLibrary = getLibraryElement('dart:core') as LibraryElementImpl;
_asyncLibrary = getLibraryElement('dart:async') as LibraryElementImpl;
- SummaryTypeProvider summaryTypeProvider = new SummaryTypeProvider();
- summaryTypeProvider.initializeCore(_coreLibrary);
- summaryTypeProvider.initializeAsync(_asyncLibrary);
- _typeProvider = summaryTypeProvider;
+ _typeProvider = new TypeProviderImpl(_coreLibrary, _asyncLibrary);
}
/**
diff --git a/pkg/analyzer/lib/src/summary/summary_sdk.dart b/pkg/analyzer/lib/src/summary/summary_sdk.dart
index 35966b2..9cf52b7 100644
--- a/pkg/analyzer/lib/src/summary/summary_sdk.dart
+++ b/pkg/analyzer/lib/src/summary/summary_sdk.dart
@@ -2,14 +2,9 @@
// 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/element/element.dart';
-import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/file_system/file_system.dart' show ResourceProvider;
import 'package:analyzer/src/context/context.dart';
-import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart'
show DartUriResolver, Source, SourceFactory;
@@ -103,278 +98,3 @@
return _uriResolver.resolveAbsolute(uri);
}
}
-
-/**
- * Implementation of [TypeProvider] which can be initialized separately with
- * `dart:core` and `dart:async` libraries.
- */
-class SummaryTypeProvider extends TypeProviderBase {
- LibraryElement _coreLibrary;
- LibraryElement _asyncLibrary;
-
- InterfaceType _boolType;
- InterfaceType _deprecatedType;
- InterfaceType _doubleType;
- InterfaceType _functionType;
- InterfaceType _futureDynamicType;
- InterfaceType _futureNullType;
- InterfaceType _futureOrNullType;
- InterfaceType _futureOrType;
- InterfaceType _futureType;
- InterfaceType _intType;
- InterfaceType _iterableDynamicType;
- InterfaceType _iterableObjectType;
- InterfaceType _iterableType;
- InterfaceType _listType;
- InterfaceType _mapType;
- InterfaceType _mapObjectObjectType;
- DartObjectImpl _nullObject;
- InterfaceType _nullType;
- InterfaceType _numType;
- InterfaceType _objectType;
- InterfaceType _setType;
- InterfaceType _stackTraceType;
- InterfaceType _streamDynamicType;
- InterfaceType _streamType;
- InterfaceType _stringType;
- InterfaceType _symbolType;
- InterfaceType _typeType;
-
- @override
- InterfaceType get boolType {
- assert(_coreLibrary != null);
- _boolType ??= _getType(_coreLibrary, "bool");
- return _boolType;
- }
-
- @override
- DartType get bottomType => BottomTypeImpl.instanceLegacy;
-
- @override
- InterfaceType get deprecatedType {
- assert(_coreLibrary != null);
- _deprecatedType ??= _getType(_coreLibrary, "Deprecated");
- return _deprecatedType;
- }
-
- @override
- InterfaceType get doubleType {
- assert(_coreLibrary != null);
- _doubleType ??= _getType(_coreLibrary, "double");
- return _doubleType;
- }
-
- @override
- DartType get dynamicType => DynamicTypeImpl.instance;
-
- @override
- InterfaceType get functionType {
- assert(_coreLibrary != null);
- _functionType ??= _getType(_coreLibrary, "Function");
- return _functionType;
- }
-
- @override
- InterfaceType get futureDynamicType {
- assert(_asyncLibrary != null);
- _futureDynamicType ??= futureType.instantiate(<DartType>[dynamicType]);
- return _futureDynamicType;
- }
-
- @override
- InterfaceType get futureNullType {
- assert(_asyncLibrary != null);
- _futureNullType ??= futureType.instantiate(<DartType>[nullType]);
- return _futureNullType;
- }
-
- @override
- InterfaceType get futureOrNullType {
- assert(_asyncLibrary != null);
- _futureOrNullType ??= futureOrType.instantiate(<DartType>[nullType]);
- return _futureOrNullType;
- }
-
- @override
- InterfaceType get futureOrType {
- assert(_asyncLibrary != null);
- try {
- _futureOrType ??= _getType(_asyncLibrary, "FutureOr");
- } on StateError {
- // FutureOr<T> is still fairly new, so if we're analyzing an SDK that
- // doesn't have it yet, create an element for it.
- _futureOrType =
- TypeProviderImpl.createPlaceholderFutureOr(futureType, objectType);
- }
- return _futureOrType;
- }
-
- @override
- InterfaceType get futureType {
- assert(_asyncLibrary != null);
- _futureType ??= _getType(_asyncLibrary, "Future");
- return _futureType;
- }
-
- @override
- InterfaceType get intType {
- assert(_coreLibrary != null);
- _intType ??= _getType(_coreLibrary, "int");
- return _intType;
- }
-
- @override
- InterfaceType get iterableDynamicType {
- assert(_coreLibrary != null);
- _iterableDynamicType ??= iterableType.instantiate(<DartType>[dynamicType]);
- return _iterableDynamicType;
- }
-
- @override
- InterfaceType get iterableObjectType {
- assert(_coreLibrary != null);
- _iterableObjectType ??= iterableType.instantiate(<DartType>[objectType]);
- return _iterableObjectType;
- }
-
- @override
- InterfaceType get iterableType {
- assert(_coreLibrary != null);
- _iterableType ??= _getType(_coreLibrary, "Iterable");
- return _iterableType;
- }
-
- @override
- InterfaceType get listType {
- assert(_coreLibrary != null);
- _listType ??= _getType(_coreLibrary, "List");
- return _listType;
- }
-
- @override
- InterfaceType get mapObjectObjectType {
- assert(_coreLibrary != null);
- return _mapObjectObjectType ??=
- mapType.instantiate(<DartType>[objectType, objectType]);
- }
-
- @override
- InterfaceType get mapType {
- assert(_coreLibrary != null);
- _mapType ??= _getType(_coreLibrary, "Map");
- return _mapType;
- }
-
- @override
- DartType get neverType => BottomTypeImpl.instance;
-
- @override
- DartObjectImpl get nullObject {
- if (_nullObject == null) {
- _nullObject = new DartObjectImpl(nullType, NullState.NULL_STATE);
- }
- return _nullObject;
- }
-
- @override
- InterfaceType get nullType {
- assert(_coreLibrary != null);
- _nullType ??= _getType(_coreLibrary, "Null");
- return _nullType;
- }
-
- @override
- InterfaceType get numType {
- assert(_coreLibrary != null);
- _numType ??= _getType(_coreLibrary, "num");
- return _numType;
- }
-
- @override
- InterfaceType get objectType {
- assert(_coreLibrary != null);
- _objectType ??= _getType(_coreLibrary, "Object");
- return _objectType;
- }
-
- @override
- InterfaceType get setType {
- assert(_coreLibrary != null);
- return _setType ??= _getType(_coreLibrary, "Set");
- }
-
- @override
- InterfaceType get stackTraceType {
- assert(_coreLibrary != null);
- _stackTraceType ??= _getType(_coreLibrary, "StackTrace");
- return _stackTraceType;
- }
-
- @override
- InterfaceType get streamDynamicType {
- assert(_asyncLibrary != null);
- _streamDynamicType ??= streamType.instantiate(<DartType>[dynamicType]);
- return _streamDynamicType;
- }
-
- @override
- InterfaceType get streamType {
- assert(_asyncLibrary != null);
- _streamType ??= _getType(_asyncLibrary, "Stream");
- return _streamType;
- }
-
- @override
- InterfaceType get stringType {
- assert(_coreLibrary != null);
- _stringType ??= _getType(_coreLibrary, "String");
- return _stringType;
- }
-
- @override
- InterfaceType get symbolType {
- assert(_coreLibrary != null);
- _symbolType ??= _getType(_coreLibrary, "Symbol");
- return _symbolType;
- }
-
- @override
- InterfaceType get typeType {
- assert(_coreLibrary != null);
- _typeType ??= _getType(_coreLibrary, "Type");
- return _typeType;
- }
-
- @override
- VoidType get voidType => VoidTypeImpl.instance;
-
- /**
- * Initialize the `dart:async` types provided by this type provider.
- */
- void initializeAsync(LibraryElement library) {
- assert(_coreLibrary != null);
- assert(_asyncLibrary == null);
- _asyncLibrary = library;
- }
-
- /**
- * Initialize the `dart:core` types provided by this type provider.
- */
- void initializeCore(LibraryElement library) {
- assert(_coreLibrary == null);
- assert(_asyncLibrary == null);
- _coreLibrary = library;
- }
-
- /**
- * Return the type with the given [name] from the given [library], or
- * throw a [StateError] if there is no class with the given name.
- */
- InterfaceType _getType(LibraryElement library, String name) {
- Element element = library.getType(name);
- if (element == null) {
- throw new StateError("No definition of type $name");
- }
- return (element as ClassElement).type;
- }
-}
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart b/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
index 23235b0..fef52b3 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
@@ -652,8 +652,8 @@
),
metadata: _readNodeList(data.normalFormalParameter_metadata),
comment: _readDocumentationComment(data),
- type: _readNode(data.fieldFormalParameter_type),
- parameters: _readNode(data.fieldFormalParameter_formalParameters),
+ type: _readNodeLazy(data.fieldFormalParameter_type),
+ parameters: _readNodeLazy(data.fieldFormalParameter_formalParameters),
requiredKeyword:
AstBinaryFlags.isRequired(data.flags) ? _Tokens.REQUIRED : null,
);
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart b/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
index 54f48bf..7ee9b12 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
@@ -45,8 +45,19 @@
@override
LinkedNodeBuilder visitAnnotation(Annotation node) {
var elementComponents = _componentsOfElement(node.element);
+
+ LinkedNodeBuilder storedArguments;
+ var arguments = node.arguments;
+ if (arguments != null) {
+ if (arguments.arguments.every(_isSerializableExpression)) {
+ storedArguments = arguments.accept(this);
+ } else {
+ storedArguments = LinkedNodeBuilder.argumentList();
+ }
+ }
+
return LinkedNodeBuilder.annotation(
- annotation_arguments: node.arguments?.accept(this),
+ annotation_arguments: storedArguments,
annotation_constructorName: node.constructorName?.accept(this),
annotation_element: elementComponents.rawElement,
annotation_substitution: elementComponents.substitution,
@@ -1356,6 +1367,10 @@
}
}
+ if (!_isSerializableExpression(initializer)) {
+ initializer = null;
+ }
+
var builder = LinkedNodeBuilder.variableDeclaration(
informativeId: getInformativeId(node),
variableDeclaration_initializer: initializer?.accept(this),
diff --git a/pkg/analyzer/lib/src/summary2/export.dart b/pkg/analyzer/lib/src/summary2/export.dart
index 18247c3..a84d39e 100644
--- a/pkg/analyzer/lib/src/summary2/export.dart
+++ b/pkg/analyzer/lib/src/summary2/export.dart
@@ -2,13 +2,13 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import 'package:analyzer/src/summary2/builder/source_library_builder.dart';
import 'package:analyzer/src/summary2/combinator.dart';
+import 'package:analyzer/src/summary2/library_builder.dart';
import 'package:analyzer/src/summary2/reference.dart';
class Export {
- final SourceLibraryBuilder exporter;
- final SourceLibraryBuilder exported;
+ final LibraryBuilder exporter;
+ final LibraryBuilder exported;
final List<Combinator> combinators;
Export(this.exporter, this.exported, this.combinators);
diff --git a/pkg/analyzer/lib/src/summary2/function_type_builder.dart b/pkg/analyzer/lib/src/summary2/function_type_builder.dart
index 836b1cf..3153f3b 100644
--- a/pkg/analyzer/lib/src/summary2/function_type_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/function_type_builder.dart
@@ -63,18 +63,19 @@
return _type;
}
+ for (TypeParameterElementImpl typeParameter in typeFormals) {
+ typeParameter.bound = _buildType(typeParameter.bound);
+ }
+
+ for (ParameterElementImpl parameter in parameters) {
+ parameter.type = _buildType(parameter.type);
+ }
+
var builtReturnType = _buildType(returnType);
_type = FunctionTypeImpl.synthetic(
builtReturnType,
typeFormals,
- parameters.map((e) {
- return ParameterElementImpl.synthetic(
- e.name,
- _buildType(e.type),
- // ignore: deprecated_member_use_from_same_package
- e.parameterKind,
- );
- }).toList(),
+ parameters,
nullabilitySuffix: nullabilitySuffix,
);
diff --git a/pkg/analyzer/lib/src/summary2/builder/source_library_builder.dart b/pkg/analyzer/lib/src/summary2/library_builder.dart
similarity index 98%
rename from pkg/analyzer/lib/src/summary2/builder/source_library_builder.dart
rename to pkg/analyzer/lib/src/summary2/library_builder.dart
index aad7c03..f02bc83 100644
--- a/pkg/analyzer/lib/src/summary2/builder/source_library_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/library_builder.dart
@@ -24,7 +24,7 @@
import 'package:analyzer/src/summary2/scope.dart';
import 'package:analyzer/src/summary2/types_builder.dart';
-class SourceLibraryBuilder {
+class LibraryBuilder {
final Linker linker;
final Uri uri;
final Reference reference;
@@ -43,7 +43,7 @@
final List<Export> exporters = [];
- SourceLibraryBuilder(this.linker, this.uri, this.reference, this.node);
+ LibraryBuilder(this.linker, this.uri, this.reference, this.node);
void addExporters() {
var unitContext = context.units[0];
@@ -335,7 +335,7 @@
}
}
- var builder = SourceLibraryBuilder(
+ var builder = LibraryBuilder(
linker,
libraryUri,
libraryReference,
diff --git a/pkg/analyzer/lib/src/summary2/link.dart b/pkg/analyzer/lib/src/summary2/link.dart
index 9f09487..8e91cf7 100644
--- a/pkg/analyzer/lib/src/summary2/link.dart
+++ b/pkg/analyzer/lib/src/summary2/link.dart
@@ -6,15 +6,15 @@
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart' show CompilationUnit;
import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
+import 'package:analyzer/src/dart/element/type_provider.dart';
import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/type_system.dart';
import 'package:analyzer/src/summary/format.dart';
-import 'package:analyzer/src/summary/summary_sdk.dart';
import 'package:analyzer/src/summary2/ast_binary_writer.dart';
-import 'package:analyzer/src/summary2/builder/source_library_builder.dart';
+import 'package:analyzer/src/summary2/library_builder.dart';
import 'package:analyzer/src/summary2/linked_bundle_context.dart';
import 'package:analyzer/src/summary2/linked_element_factory.dart';
import 'package:analyzer/src/summary2/linking_bundle_context.dart';
@@ -44,7 +44,7 @@
LinkingBundleContext linkingBundleContext;
/// Libraries that are being linked.
- final Map<Uri, SourceLibraryBuilder> builders = {};
+ final Map<Uri, LibraryBuilder> builders = {};
InheritanceManager3 inheritance; // TODO(scheglov) cache it
@@ -75,7 +75,7 @@
void link(List<LinkInputLibrary> inputLibraries) {
for (var inputLibrary in inputLibraries) {
- SourceLibraryBuilder.build(this, inputLibrary);
+ LibraryBuilder.build(this, inputLibrary);
}
// TODO(scheglov) do in build() ?
elementFactory.addBundle(bundleContext);
@@ -122,8 +122,8 @@
library.buildInitialExportScope();
}
- var exporters = new Set<SourceLibraryBuilder>();
- var exportees = new Set<SourceLibraryBuilder>();
+ var exporters = new Set<LibraryBuilder>();
+ var exportees = new Set<LibraryBuilder>();
for (var library in builders.values) {
library.addExporters();
@@ -138,7 +138,7 @@
}
}
- var both = new Set<SourceLibraryBuilder>();
+ var both = new Set<LibraryBuilder>();
for (var exported in exportees) {
if (exporters.contains(exported)) {
both.add(exported);
@@ -212,10 +212,7 @@
var coreLib = elementFactory.libraryOfUri('dart:core');
var asyncLib = elementFactory.libraryOfUri('dart:async');
-
- analysisContext.typeProvider = SummaryTypeProvider()
- ..initializeCore(coreLib)
- ..initializeAsync(asyncLib);
+ analysisContext.typeProvider = TypeProviderImpl(coreLib, asyncLib);
inheritance = InheritanceManager3(typeSystem);
}
diff --git a/pkg/analyzer/lib/src/summary2/linked_unit_context.dart b/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
index 2b30438..801f3b0 100644
--- a/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
+++ b/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
@@ -647,7 +647,7 @@
} else if (node is ExtensionDeclaration) {
return node.typeParameters;
} else if (node is FieldFormalParameter) {
- return null;
+ return node.typeParameters;
} else if (node is FunctionDeclaration) {
LazyFunctionDeclaration.readFunctionExpression(_astReader, node);
return getTypeParameters2(node.functionExpression);
diff --git a/pkg/analyzer/lib/src/summary2/named_type_builder.dart b/pkg/analyzer/lib/src/summary2/named_type_builder.dart
index c90c6a8..ff94d7d 100644
--- a/pkg/analyzer/lib/src/summary2/named_type_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/named_type_builder.dart
@@ -185,15 +185,6 @@
}
}
- /// If the [type] is a [TypeBuilder], build it; otherwise return as is.
- DartType _buildType(DartType type) {
- if (type is TypeBuilder) {
- return type.build();
- } else {
- return type;
- }
- }
-
DartType _getRawFunctionType(GenericTypeAliasElementImpl element) {
// If the element is not being linked, there is no reason (or a way,
// because the linked node might be read only partially) to go through
@@ -218,22 +209,31 @@
);
} else if (typedefNode is GenericTypeAlias) {
var functionNode = typedefNode.functionType;
- if (functionNode != null) {
- return _buildFunctionType(
- element,
- _typeParameterTypes(typedefNode.typeParameters),
- functionNode.typeParameters,
- functionNode.returnType,
- functionNode.parameters,
+ var functionType = _buildType(functionNode?.type);
+ if (functionType is FunctionType) {
+ return FunctionTypeImpl.synthetic(
+ functionType.returnType,
+ functionType.typeFormals,
+ functionType.parameters,
+ element: element,
+ typeArguments: _typeParameterTypes(typedefNode.typeParameters),
);
- } else {
- return _dynamicType;
}
+ return _dynamicType;
} else {
throw StateError('(${element.runtimeType}) $element');
}
}
+ /// If the [type] is a [TypeBuilder], build it; otherwise return as is.
+ static DartType _buildType(DartType type) {
+ if (type is TypeBuilder) {
+ return type.build();
+ } else {
+ return type;
+ }
+ }
+
static List<DartType> _listOfDynamic(int length) {
return List<DartType>.filled(length, _dynamicType);
}
diff --git a/pkg/analyzer/lib/src/summary2/reference_resolver.dart b/pkg/analyzer/lib/src/summary2/reference_resolver.dart
index 3d780ac..3187ffa 100644
--- a/pkg/analyzer/lib/src/summary2/reference_resolver.dart
+++ b/pkg/analyzer/lib/src/summary2/reference_resolver.dart
@@ -206,9 +206,33 @@
@override
void visitFieldFormalParameter(FieldFormalParameter node) {
+ var outerScope = scope;
+ var outerReference = reference;
+
+ var name = node.identifier.name;
+ reference = reference.getChild('@parameter').getChild(name);
+ reference.node = node;
+
+ var element = ParameterElementImpl.forLinkedNode(
+ outerReference.element,
+ reference,
+ node,
+ );
+ node.identifier.staticElement = element;
+ _createTypeParameterElements(node.typeParameters);
+
+ scope = new EnclosedScope(scope);
+ for (var typeParameter in element.typeParameters) {
+ scope.define(typeParameter);
+ }
+
node.type?.accept(this);
+ node.typeParameters?.accept(this);
node.parameters?.accept(this);
nodesToBuildType.addDeclaration(node);
+
+ scope = outerScope;
+ reference = outerReference;
}
@override
diff --git a/pkg/analyzer/lib/src/summary2/simply_bounded.dart b/pkg/analyzer/lib/src/summary2/simply_bounded.dart
index e1bbe8a..3ae599f 100644
--- a/pkg/analyzer/lib/src/summary2/simply_bounded.dart
+++ b/pkg/analyzer/lib/src/summary2/simply_bounded.dart
@@ -7,8 +7,8 @@
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/summary/link.dart' as graph
show DependencyWalker, Node;
-import 'package:analyzer/src/summary2/builder/source_library_builder.dart';
import 'package:analyzer/src/summary2/lazy_ast.dart';
+import 'package:analyzer/src/summary2/library_builder.dart';
import 'package:analyzer/src/summary2/linked_bundle_context.dart';
/// Compute simple-boundedness for all classes and generic types aliases in
@@ -16,7 +16,7 @@
/// so they all should be processed simultaneously.
void computeSimplyBounded(
LinkedBundleContext bundleContext,
- Iterable<SourceLibraryBuilder> libraryBuilders,
+ Iterable<LibraryBuilder> libraryBuilders,
) {
var walker = SimplyBoundedDependencyWalker(bundleContext);
var nodes = <SimplyBoundedNode>[];
@@ -302,6 +302,8 @@
void visitParameter(FormalParameter node) {
if (node is DefaultFormalParameter) {
visitParameter(node.parameter);
+ } else if (node is FieldFormalParameter) {
+ // The spec does not allow them here, ignore.
} else if (node is FunctionTypedFormalParameter) {
addType(node.returnType);
visitParameters(node.parameters);
diff --git a/pkg/analyzer/lib/src/task/api/dart.dart b/pkg/analyzer/lib/src/task/api/dart.dart
deleted file mode 100644
index 9064e25..0000000
--- a/pkg/analyzer/lib/src/task/api/dart.dart
+++ /dev/null
@@ -1,175 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/token.dart';
-import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/error/error.dart';
-import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/utilities_general.dart';
-import 'package:analyzer/src/task/api/model.dart';
-
-/**
- * The analysis errors associated with a [Source] representing a compilation
- * unit.
- */
-final ListResultDescriptor<AnalysisError> DART_ERRORS =
- new ListResultDescriptor<AnalysisError>(
- 'DART_ERRORS', AnalysisError.NO_ERRORS);
-
-/**
- * The sources of the libraries that are explicitly imported into a library.
- *
- * The list will be empty if there are no explicit imports, but will not be
- * `null`.
- *
- * The result is only available for [Source]s representing a library.
- */
-final ListResultDescriptor<Source> EXPLICITLY_IMPORTED_LIBRARIES =
- new ListResultDescriptor<Source>(
- 'EXPLICITLY_IMPORTED_LIBRARIES', const <Source>[]);
-
-/**
- * The sources of the libraries that are exported from a library.
- *
- * The list will be empty if there are no exported libraries, but will not be
- * `null`.
- *
- * The result is only available for [Source]s representing a library.
- */
-final ListResultDescriptor<Source> EXPORTED_LIBRARIES =
- new ListResultDescriptor<Source>('EXPORTED_LIBRARIES', const <Source>[]);
-
-/**
- * The sources of the libraries that are implicitly or explicitly imported into
- * a library.
- *
- * The list will minimally contain the source for `dart:core` because it is
- * implicitly imported into every library, and therefore will never be `null`.
- *
- * The result is only available for [Source]s representing a library.
- */
-final ListResultDescriptor<Source> IMPORTED_LIBRARIES =
- new ListResultDescriptor<Source>('IMPORTED_LIBRARIES', const <Source>[]);
-
-/**
- * The sources of the parts that are included in a library.
- *
- * The list will be empty if there are no parts, but will not be `null`. The
- * list does *not* include the source for the defining compilation unit.
- *
- * The result is only available for [Source]s representing a library.
- */
-final ListResultDescriptor<Source> INCLUDED_PARTS =
- new ListResultDescriptor<Source>('INCLUDED_PARTS', const <Source>[]);
-
-/**
- * A flag specifying whether a library is launchable.
- *
- * The result is only available for [Source]s representing a library.
- */
-final ResultDescriptor<bool> IS_LAUNCHABLE =
- new ResultDescriptor<bool>('IS_LAUNCHABLE', false);
-
-/**
- * The fully built [LibraryElement] associated with a library.
- *
- * The result is only available for [Source]s representing a library.
- */
-final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT =
- new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT', null);
-
-/**
- * The compilation unit AST produced while parsing a compilation unit.
- *
- * The AST structure will not have resolution information associated with it.
- *
- * The result is only available for [Source]s representing a compilation unit.
- */
-final ResultDescriptor<CompilationUnit> PARSED_UNIT =
- new ResultDescriptor<CompilationUnit>('PARSED_UNIT', null);
-
-/**
- * The resolved [CompilationUnit] associated with a compilation unit, with
- * constants resolved.
- *
- * The result is only available for [LibrarySpecificUnit]s.
- */
-final ResultDescriptor<CompilationUnit> RESOLVED_UNIT =
- new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT', null);
-
-/**
- * The kind of a [Source].
- */
-final ResultDescriptor<SourceKind> SOURCE_KIND =
- new ResultDescriptor<SourceKind>('SOURCE_KIND', SourceKind.UNKNOWN);
-
-/**
- * The token stream produced while scanning a compilation unit.
- *
- * The value is the first token in the file, or the special end-of-file marker
- * at the end of the stream if the file does not contain any tokens.
- *
- * The result is only available for [Source]s representing a compilation unit.
- */
-final ResultDescriptor<Token> TOKEN_STREAM =
- new ResultDescriptor<Token>('TOKEN_STREAM', null);
-
-/**
- * The sources of the Dart files that a library consists of.
- *
- * The list will include the source of the defining unit and [INCLUDED_PARTS].
- * So, it is never empty or `null`.
- *
- * The result is only available for [Source]s representing a library.
- */
-final ListResultDescriptor<Source> UNITS =
- new ListResultDescriptor<Source>('UNITS', const <Source>[]);
-
-/**
- * A specific compilation unit in a specific library.
- *
- * This kind of target is associated with information about a compilation unit
- * that differs based on the library that the unit is a part of. For example,
- * the result of resolving a compilation unit depends on the imports, which can
- * change if a single part is included in more than one library.
- */
-class LibrarySpecificUnit implements AnalysisTarget {
- /**
- * The defining compilation unit of the library in which the [unit]
- * is analyzed.
- */
- final Source library;
-
- /**
- * The compilation unit which belongs to the [library].
- */
- final Source unit;
-
- /**
- * Initialize a newly created target for the [unit] in the [library].
- */
- LibrarySpecificUnit(this.library, this.unit);
-
- @override
- int get hashCode {
- return JenkinsSmiHash.combine(library.hashCode, unit.hashCode);
- }
-
- @override
- Source get librarySource => library;
-
- @override
- Source get source => unit;
-
- @override
- bool operator ==(other) {
- return other is LibrarySpecificUnit &&
- other.library == library &&
- other.unit == unit;
- }
-
- @override
- String toString() => '$unit in $library';
-}
diff --git a/pkg/analyzer/lib/src/task/api/general.dart b/pkg/analyzer/lib/src/task/api/general.dart
deleted file mode 100644
index d884116..0000000
--- a/pkg/analyzer/lib/src/task/api/general.dart
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/task/api/model.dart';
-
-/**
- * The content of a [Source].
- */
-final ResultDescriptor<String> CONTENT =
- new ResultDescriptor<String>('CONTENT', null);
-
-/**
- * The line information for a [Source].
- */
-final ResultDescriptor<LineInfo> LINE_INFO =
- new ResultDescriptor<LineInfo>('LINE_INFO', null);
-
-/**
- * The modification time of a [Source].
- */
-final ResultDescriptor<int> MODIFICATION_TIME =
- new ResultDescriptor<int>('MODIFICATION_TIME', -1);
diff --git a/pkg/analyzer/lib/src/task/api/model.dart b/pkg/analyzer/lib/src/task/api/model.dart
index 05c8b23..da0d3db 100644
--- a/pkg/analyzer/lib/src/task/api/model.dart
+++ b/pkg/analyzer/lib/src/task/api/model.dart
@@ -2,68 +2,7 @@
// 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:collection';
-import 'dart:developer';
-
-import 'package:analyzer/error/error.dart' show AnalysisError;
-import 'package:analyzer/exception/exception.dart';
-import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/utilities_general.dart';
-import 'package:analyzer/src/task/driver.dart';
-import 'package:analyzer/src/task/model.dart';
-
-/**
- * A function that converts the given [key] and [value] into a [TaskInput].
- */
-typedef TaskInput<E> BinaryFunction<K, V, E>(K key, V value);
-
-/**
- * A function that takes an analysis [context] and an analysis [target] and
- * returns an analysis task. Such functions are passed to a [TaskDescriptor] to
- * be used to create the described task.
- */
-typedef AnalysisTask BuildTask(AnalysisContext context, AnalysisTarget target);
-
-/**
- * A function that takes the target for which a task will produce results and
- * returns a map from input names to descriptions of the analysis results needed
- * by the task in order for the task to be performed. Such functions are passed
- * to a [TaskDescriptor] to be used to determine the inputs needed by the task.
- */
-typedef Map<String, TaskInput> CreateTaskInputs(AnalysisTarget target);
-
-/**
- * A function that takes the target for which a task will produce results and
- * returns an indication of how suitable the task is for the target. Such
- * functions are passed to a [TaskDescriptor] to be used to determine their
- * suitability for computing results.
- */
-typedef TaskSuitability SuitabilityFor(AnalysisTarget target);
-
-/**
- * A function that converts an object of the type [B] into a [TaskInput].
- * This is used, for example, by a [ListTaskInput] to create task inputs
- * for each value in a list of values.
- */
-typedef TaskInput<E> UnaryFunction<B, E>(B object);
-
-/**
- * An [AnalysisTarget] wrapper for an [AnalysisContext].
- */
-class AnalysisContextTarget implements AnalysisTarget {
- static final AnalysisContextTarget request = new AnalysisContextTarget(null);
-
- final AnalysisContext context;
-
- AnalysisContextTarget(this.context);
-
- @override
- Source get librarySource => null;
-
- @override
- Source get source => null;
-}
/**
* An object with which an analysis result can be associated.
@@ -85,713 +24,3 @@
*/
Source get source;
}
-
-/**
- * An object used to compute one or more analysis results associated with a
- * single target.
- *
- * Clients must extend this class when creating new tasks.
- */
-abstract class AnalysisTask {
- /**
- * A queue storing the last 10 task descriptions for diagnostic purposes.
- */
- static final LimitedQueue<String> LAST_TASKS = new LimitedQueue<String>(10);
-
- /**
- * A table mapping the types of analysis tasks to the number of times each
- * kind of task has been performed.
- */
- static final Map<Type, int> countMap = new HashMap<Type, int>();
-
- /**
- * A table mapping the types of analysis tasks to user tags used to collect
- * timing data for the Observatory.
- */
- static Map<Type, UserTag> tagMap = new HashMap<Type, UserTag>();
-
- /**
- * A table mapping the types of analysis tasks to stopwatches used to compute
- * how much time was spent executing each kind of task.
- */
- static final Map<Type, Stopwatch> stopwatchMap =
- new HashMap<Type, Stopwatch>();
-
- /**
- * The context in which the task is to be performed.
- */
- final AnalysisContext context;
-
- /**
- * The target for which result values are being produced.
- */
- final AnalysisTarget target;
-
- /**
- * A table mapping input names to input values.
- */
- Map<String, dynamic> inputs;
-
- /**
- * A table mapping result descriptors whose values are produced by this task
- * to the values that were produced.
- */
- Map<ResultDescriptor, dynamic> outputs =
- new HashMap<ResultDescriptor, dynamic>();
-
- /**
- * The exception that was thrown while performing this task, or `null` if the
- * task completed successfully.
- */
- CaughtException caughtException;
-
- /**
- * If a dependency cycle was found while computing the inputs for the task,
- * the set of [WorkItem]s contained in the cycle (if there are overlapping
- * cycles, this is the set of all [WorkItem]s in the entire strongly
- * connected component). Otherwise, `null`.
- */
- List<WorkItem> dependencyCycle;
-
- /**
- * Initialize a newly created task to perform analysis within the given
- * [context] in order to produce results for the given [target].
- */
- AnalysisTask(this.context, this.target);
-
- /**
- * Return a textual description of this task.
- */
- String get description;
-
- /**
- * Return the descriptor that describes this task.
- */
- TaskDescriptor get descriptor;
-
- /**
- * Indicates whether the task is capable of handling dependency cycles. A
- * task that overrides this getter to return `true` must be prepared for the
- * possibility that it will be invoked with a non-`null` value of
- * [dependencyCycle], and with not all of its inputs computed.
- */
- bool get handlesDependencyCycles => false;
-
- /**
- * Return the value of the input with the given [name], or `null` if the input
- * value is not defined.
- */
- Object getOptionalInput(String name) {
- if (inputs == null || !inputs.containsKey(name)) {
- return null;
- }
- return inputs[name];
- }
-
- /**
- * Return the value of the input with the given [name]. Throw an exception if
- * the input value is not defined.
- */
- E getRequiredInput<E>(String name) {
- if (inputs == null || !inputs.containsKey(name)) {
- throw new AnalysisException("Could not $description: missing $name");
- }
- if (inputs[name] is! E) {
- throw new AnalysisException(
- "Could not $description: $name is a ${inputs[name].runtimeType} rather than a $E");
- }
- return inputs[name] as E;
- }
-
- /**
- * Return the source associated with the target. Throw an exception if
- * the target is not associated with a source.
- */
- Source getRequiredSource() {
- Source source = target.source;
- if (source == null) {
- throw new AnalysisException("Could not $description: missing source");
- }
- return source;
- }
-
- /**
- * Perform this analysis task, protected by an exception handler.
- *
- * This method should throw an [AnalysisException] if an exception occurs
- * while performing the task. If other kinds of exceptions are thrown they
- * will be wrapped in an [AnalysisException].
- *
- * If no exception is thrown, this method must fully populate the [outputs]
- * map (have a key/value pair for each result that this task is expected to
- * produce).
- */
- void internalPerform();
-
- /**
- * Perform this analysis task. When this method returns, either the [outputs]
- * map should be fully populated (have a key/value pair for each result that
- * this task is expected to produce) or the [caughtException] should be set.
- *
- * Clients may not override this method.
- */
- void perform() {
- try {
- _safelyPerform();
- } on AnalysisException catch (exception, stackTrace) {
- caughtException = new CaughtException(exception, stackTrace);
- AnalysisEngine.instance.logger
- .logError("Task failed: $description", caughtException);
- }
- }
-
- @override
- String toString() => description;
-
- /**
- * Given a strongly connected component, find and return a list of
- * [TargetedResult]s that describes a cyclic path within the cycle. Returns
- * null if no cyclic path is found.
- */
- List<TargetedResult> _findCyclicPath(List<WorkItem> cycle) {
- WorkItem findInCycle(AnalysisTarget target, ResultDescriptor descriptor) {
- for (WorkItem item in cycle) {
- if (target == item.target && descriptor == item.spawningResult) {
- return item;
- }
- }
- return null;
- }
-
- HashSet<WorkItem> active = new HashSet<WorkItem>();
- List<TargetedResult> path = null;
- bool traverse(WorkItem item) {
- if (!active.add(item)) {
- // We've found a cycle
- path = <TargetedResult>[];
- return true;
- }
- for (TargetedResult result in item.inputTargetedResults) {
- WorkItem item = findInCycle(result.target, result.result);
- // Ignore edges that leave the cycle.
- if (item != null) {
- if (traverse(item)) {
- // This edge is in a cycle (or leads to a cycle) so add it to the
- // path
- path.add(result);
- return true;
- }
- }
- }
- // There was no cycle.
- return false;
- }
-
- if (cycle.isNotEmpty) {
- traverse(cycle[0]);
- }
- return path;
- }
-
- /**
- * Perform this analysis task, ensuring that all exceptions are wrapped in an
- * [AnalysisException].
- *
- * Clients may not override this method.
- */
- void _safelyPerform() {
- try {
- //
- // Store task description for diagnostics.
- //
- LAST_TASKS.add(description);
-
- //
- // Report that this task is being performed.
- //
- String contextName = context.name;
- if (contextName == null) {
- contextName = 'unnamed';
- }
- AnalysisEngine.instance.instrumentationService
- .logAnalysisTask(contextName, this);
- //
- // Gather statistics on the performance of the task.
- //
- int count = countMap[runtimeType];
- countMap[runtimeType] = count == null ? 1 : count + 1;
-// UserTag tag = tagMap.putIfAbsent(
-// runtimeType, () => new UserTag(runtimeType.toString()));
- Stopwatch stopwatch = stopwatchMap[runtimeType];
- if (stopwatch == null) {
- stopwatch = new Stopwatch();
- stopwatchMap[runtimeType] = stopwatch;
- }
-// UserTag previousTag = tag.makeCurrent();
-// try {
- stopwatch.start();
- //
- // Actually perform the task.
- //
- try {
- if (dependencyCycle != null && !handlesDependencyCycles) {
- throw new InfiniteTaskLoopException(
- this, dependencyCycle, _findCyclicPath(dependencyCycle));
- }
- internalPerform();
- } finally {
- stopwatch.stop();
- }
-// } finally {
-// previousTag.makeCurrent();
-// }
- } on AnalysisException {
- rethrow;
- } on ModificationTimeMismatchError {
- rethrow;
- } catch (exception, stackTrace) {
- throw new AnalysisException(
- 'Unexpected exception while performing $description',
- new CaughtException(exception, stackTrace));
- }
- }
-}
-
-/**
- * A description of a [List]-based analysis result that can be computed by an
- * [AnalysisTask].
- *
- * Clients may not extend, implement or mix-in this class.
- */
-abstract class ListResultDescriptor<E> implements ResultDescriptor<List<E>> {
- /**
- * Initialize a newly created analysis result to have the given [name] and
- * [defaultValue]. If a [cachingPolicy] is provided, it will control how long
- * values associated with this result will remain in the cache.
- */
- factory ListResultDescriptor(String name, List<E> defaultValue,
- {ResultCachingPolicy cachingPolicy}) = ListResultDescriptorImpl<E>;
-
- @override
- ListTaskInput<E> of(AnalysisTarget target, {bool flushOnAccess: false});
-}
-
-/**
- * A description of an input to an [AnalysisTask] that can be used to compute
- * that input.
- *
- * Clients may not extend, implement or mix-in this class.
- */
-abstract class ListTaskInput<E> implements TaskInput<List<E>> {
- /**
- * Return a task input that can be used to compute a flatten list whose
- * elements are combined [subListResult]'s associated with those elements.
- */
- ListTaskInput<V> toFlattenListOf<V>(ListResultDescriptor<V> subListResult);
-
- /**
- * Return a task input that can be used to compute a list whose elements are
- * the result of passing the elements of this input to the [mapper] function.
- */
- ListTaskInput<V> toList<V>(UnaryFunction<E, V> mapper);
-
- /**
- * Return a task input that can be used to compute a list whose elements are
- * [valueResult]'s associated with those elements.
- */
- ListTaskInput<V> toListOf<V>(ResultDescriptor<V> valueResult);
-
- /**
- * Return a task input that can be used to compute a map whose keys are the
- * elements of this input and whose values are the result of passing the
- * corresponding key to the [mapper] function.
- */
- MapTaskInput<E, V> toMap<V>(UnaryFunction<E, V> mapper);
-
- /**
- * Return a task input that can be used to compute a map whose keys are the
- * elements of this input and whose values are the [valueResult]'s associated
- * with those elements.
- */
- MapTaskInput<AnalysisTarget, V> toMapOf<V>(ResultDescriptor<V> valueResult);
-}
-
-/**
- * A description of an input with a [Map] based values.
- *
- * Clients may not extend, implement or mix-in this class.
- */
-abstract class MapTaskInput<K, V> implements TaskInput<Map<K, V>> {
- /**
- * [V] must be a [List].
- * Return a task input that can be used to compute a list whose elements are
- * the result of passing keys [K] and the corresponding elements of [V] to
- * the [mapper] function.
- */
- TaskInput<List<E>> toFlattenList<E>(
- BinaryFunction<K, dynamic /*element of V*/, E> mapper);
-}
-
-/**
- * Instances of this class are thrown when a task detects that the modification
- * time of a cache entry is not the same as the actual modification time. This
- * means that any analysis results based on the content of the target cannot be
- * used anymore and must be invalidated.
- */
-class ModificationTimeMismatchError {
- final Source source;
-
- ModificationTimeMismatchError(this.source);
-}
-
-/**
- * A policy object that can compute sizes of results and provide the maximum
- * active and idle sizes that can be kept in the cache.
- *
- * All the [ResultDescriptor]s with the same [ResultCachingPolicy] instance
- * share the same total size in a cache.
- *
- * Clients may implement this class when implementing plugins.
- */
-abstract class ResultCachingPolicy {
- /**
- * Return the maximum total size of results that can be kept in the cache
- * while analysis is in progress.
- */
- int get maxActiveSize;
-
- /**
- * Return the maximum total size of results that can be kept in the cache
- * while analysis is idle.
- */
- int get maxIdleSize;
-
- /**
- * Return the size of the given [object].
- */
- int measure(Object object);
-}
-
-/**
- * A description of an analysis result that can be computed by an [AnalysisTask].
- *
- * Clients may not extend, implement or mix-in this class.
- */
-abstract class ResultDescriptor<V> {
- /**
- * A comparator that can be used to sort result descriptors by their name.
- */
- static final Comparator<ResultDescriptor> SORT_BY_NAME =
- (ResultDescriptor first, ResultDescriptor second) =>
- first.name.compareTo(second.name);
-
- /**
- * Initialize a newly created analysis result to have the given [name] and
- * [defaultValue].
- *
- * The given [cachingPolicy] is used to limit the total size of results
- * described by this descriptor. If no policy is specified, the results are
- * never evicted from the cache, and removed only when they are invalidated.
- */
- factory ResultDescriptor(String name, V defaultValue,
- {ResultCachingPolicy cachingPolicy}) = ResultDescriptorImpl<V>;
-
- /**
- * Return the caching policy for results described by this descriptor.
- */
- ResultCachingPolicy get cachingPolicy;
-
- /**
- * Return the default value for results described by this descriptor.
- */
- V get defaultValue;
-
- /**
- * Return the name of this descriptor.
- */
- String get name;
-
- /**
- * Return a task input that can be used to compute this result for the given
- * [target]. If [flushOnAccess] is `true` then the value of this result that
- * is associated with the [target] will be flushed when it is accessed.
- */
- TaskInput<V> of(AnalysisTarget target, {bool flushOnAccess: false});
-}
-
-/**
- * A specification of the given [result] for the given [target].
- *
- * Clients may not extend, implement or mix-in this class.
- */
-class TargetedResult {
- /**
- * The target with which the result is associated.
- */
- final AnalysisTarget target;
-
- /**
- * The result associated with the target.
- */
- final ResultDescriptor result;
-
- /**
- * Initialize a new targeted result.
- */
- TargetedResult(this.target, this.result);
-
- @override
- int get hashCode {
- return JenkinsSmiHash.combine(target.hashCode, result.hashCode);
- }
-
- @override
- bool operator ==(other) {
- return other is TargetedResult &&
- other.target == target &&
- other.result == result;
- }
-
- @override
- String toString() => '$result for $target';
-}
-
-/**
- * A description of an [AnalysisTask].
- *
- * Clients may not extend, implement or mix-in this class.
- */
-abstract class TaskDescriptor {
- /**
- * Initialize a newly created task descriptor to have the given [name] and to
- * describe a task that takes the inputs built using the given [inputBuilder],
- * and produces the given [results]. The [buildTask] function will be used to
- * create the instance of [AnalysisTask] being described. If provided, the
- * [isAppropriateFor] function will be used to determine whether the task can
- * be used on a specific target.
- */
- factory TaskDescriptor(String name, BuildTask buildTask,
- CreateTaskInputs inputBuilder, List<ResultDescriptor> results,
- {SuitabilityFor suitabilityFor}) = TaskDescriptorImpl;
-
- /**
- * Return the builder used to build the inputs to the task.
- */
- CreateTaskInputs get createTaskInputs;
-
- /**
- * Return the name of the task being described.
- */
- String get name;
-
- /**
- * Return a list of the analysis results that will be computed by this task.
- */
- List<ResultDescriptor> get results;
-
- /**
- * Create and return a task that is described by this descriptor that can be
- * used to compute results based on the given [inputs].
- */
- AnalysisTask createTask(AnalysisContext context, AnalysisTarget target,
- Map<String, dynamic> inputs);
-
- /**
- * Return an indication of how suitable this task is for the given [target].
- */
- TaskSuitability suitabilityFor(AnalysisTarget target);
-}
-
-/**
- * A description of an input to an [AnalysisTask] that can be used to compute
- * that input.
- *
- * Clients may not extend, implement or mix-in this class.
- */
-abstract class TaskInput<V> {
- /**
- * Create and return a builder that can be used to build this task input.
- */
- TaskInputBuilder<V> createBuilder();
-
- /**
- * Return a task input that can be used to compute a list whose elements are
- * the result of passing the result of this input to the [mapper] function.
- */
- ListTaskInput<E> mappedToList<E>(List<E> mapper(V value));
-}
-
-/**
- * An object used to build the value associated with a single [TaskInput].
- *
- * All builders work by requesting one or more results (each result being
- * associated with a target). The interaction pattern is modeled after the class
- * [Iterator], in which the method [moveNext] is invoked to move from one result
- * request to the next. The getters [currentResult] and [currentTarget] are used
- * to get the result and target of the current request. The value of the result
- * must be supplied using the [currentValue] setter before [moveNext] can be
- * invoked to move to the next request. When [moveNext] returns `false`,
- * indicating that there are no more requests, the method [inputValue] can be
- * used to access the value of the input that was built.
- *
- * Clients may not extend, implement or mix-in this class.
- */
-abstract class TaskInputBuilder<V> {
- /**
- * Return the result that needs to be computed, or `null` if [moveNext] has
- * not been invoked or if the last invocation of [moveNext] returned `false`.
- */
- ResultDescriptor get currentResult;
-
- /**
- * Return the target for which the result needs to be computed, or `null` if
- * [moveNext] has not been invoked or if the last invocation of [moveNext]
- * returned `false`.
- */
- AnalysisTarget get currentTarget;
-
- /**
- * Set the [value] that was computed for the current result.
- *
- * Throws a [StateError] if [moveNext] has not been invoked or if the last
- * invocation of [moveNext] returned `false`.
- */
- void set currentValue(Object value);
-
- /**
- * Return `true` if the value accessed by this input builder should be flushed
- * from the cache at the time it is retrieved.
- */
- bool get flushOnAccess;
-
- /**
- * Return the [value] that was computed by this builder.
- *
- * Throws a [StateError] if [moveNext] has not been invoked or if the last
- * invocation of [moveNext] returned `true`.
- *
- * Returns `null` if no value could be computed due to a circular dependency.
- */
- V get inputValue;
-
- /**
- * Record that no value is available for the current result, due to a
- * circular dependency.
- *
- * Throws a [StateError] if [moveNext] has not been invoked or if the last
- * invocation of [moveNext] returned `false`.
- */
- void currentValueNotAvailable();
-
- /**
- * Move to the next result that needs to be computed in order to build the
- * inputs for a task. Return `true` if there is another result that needs to
- * be computed, or `false` if the inputs have been computed.
- *
- * It is safe to invoke [moveNext] after it has returned `false`. In this case
- * [moveNext] has no effect and will again return `false`.
- *
- * Throws a [StateError] if the value of the current result has not been
- * provided using [currentValue].
- */
- bool moveNext();
-}
-
-/**
- * An indication of how suitable a task is for a given target.
- */
-enum TaskSuitability { NONE, LOWEST, HIGHEST }
-
-/**
- * [WorkManager]s are used to drive analysis.
- *
- * They know specific of the targets and results they care about,
- * so they can request analysis results in optimal order.
- *
- * Clients may implement this class when implementing plugins.
- */
-abstract class WorkManager {
- /**
- * Notifies the manager about changes in the explicit source list.
- */
- void applyChange(List<Source> addedSources, List<Source> changedSources,
- List<Source> removedSources);
-
- /**
- * Notifies the managers that the given set of priority [targets] was set.
- */
- void applyPriorityTargets(List<AnalysisTarget> targets);
-
- /**
- * Return a list of all of the errors associated with the given [source].
- * The list of errors will be empty if the source is not known to the context
- * or if there are no errors in the source. The errors contained in the list
- * can be incomplete.
- */
- List<AnalysisError> getErrors(Source source);
-
- /**
- * Return the next [TargetedResult] that this work manager wants to be
- * computed, or `null` if this manager doesn't need any new results.
- *
- * Note, that it is not guaranteed that this result will be computed, it is
- * up to the work manager to check whether the result is already computed
- * (for example during the next [getNextResult] invocation) or computation
- * of the same result should be requested again.
- */
- TargetedResult getNextResult();
-
- /**
- * Return the priority if the next work order this work manager want to be
- * computed. The [AnalysisDriver] will perform the work order with
- * the highest priority.
- *
- * Even if the returned value is [WorkOrderPriority.NONE], it still does not
- * guarantee that [getNextResult] will return not `null`.
- */
- WorkOrderPriority getNextResultPriority();
-
- /**
- * Notifies the manager about analysis options changes.
- */
- void onAnalysisOptionsChanged();
-
- /**
- * Notifies the manager about [SourceFactory] changes.
- */
- void onSourceFactoryChanged();
-
- /**
- * Notifies the manager that the given [outputs] were produced for
- * the given [target].
- */
- void resultsComputed(
- AnalysisTarget target, Map<ResultDescriptor, dynamic> outputs);
-}
-
-/**
- * The priorities of work orders returned by [WorkManager]s.
- *
- * New priorities may be added with time, clients need to tolerate this.
- */
-enum WorkOrderPriority {
- /**
- * Responding to an user's action.
- */
- INTERACTIVE,
-
- /**
- * Computing information for priority sources.
- */
- PRIORITY,
-
- /**
- * A work should be done, but without any special urgency.
- */
- NORMAL,
-
- /**
- * Nothing to do.
- */
- NONE
-}
diff --git a/pkg/analyzer/lib/src/task/api/yaml.dart b/pkg/analyzer/lib/src/task/api/yaml.dart
deleted file mode 100644
index aacc75d..0000000
--- a/pkg/analyzer/lib/src/task/api/yaml.dart
+++ /dev/null
@@ -1,21 +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:analyzer/error/error.dart';
-import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/task/api/model.dart';
-import 'package:yaml/yaml.dart';
-
-/**
- * The result of parsing a YAML file.
- */
-final ResultDescriptor<YamlDocument> YAML_DOCUMENT =
- new ResultDescriptor<YamlDocument>('YAML_DOCUMENT', null);
-
-/**
- * The analysis errors associated with a [Source] representing a YAML file.
- */
-final ListResultDescriptor<AnalysisError> YAML_ERRORS =
- new ListResultDescriptor<AnalysisError>(
- 'YAML_ERRORS', AnalysisError.NO_ERRORS);
diff --git a/pkg/analyzer/lib/src/task/driver.dart b/pkg/analyzer/lib/src/task/driver.dart
deleted file mode 100644
index 843041d..0000000
--- a/pkg/analyzer/lib/src/task/driver.dart
+++ /dev/null
@@ -1,890 +0,0 @@
-// Copyright (c) 2015, 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:collection';
-
-import 'package:analyzer/exception/exception.dart';
-import 'package:analyzer/src/context/cache.dart';
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/utilities_general.dart';
-import 'package:analyzer/src/task/api/model.dart';
-import 'package:analyzer/src/task/inputs.dart';
-import 'package:analyzer/src/task/manager.dart';
-
-final PerformanceTag analysisDriverProcessOutputs =
- _taskDriverTag.createChild('processOutputs');
-
-final PerformanceTag workOrderMoveNextPerformanceTag =
- _taskDriverTag.createChild('workOrderMoveNext');
-
-final PerformanceTag _taskDriverTag =
- PerformanceStatistics.analyzer.createChild('taskDriver');
-
-/**
- * An object that is used to cause analysis to be performed until all of the
- * required analysis information has been computed.
- */
-class AnalysisDriver {
- /**
- * The task manager used to figure out how to compute analysis results.
- */
- final TaskManager taskManager;
-
- /**
- * The list of [WorkManager] used to figure out which analysis results to
- * compute.
- */
- final List<WorkManager> workManagers;
-
- /**
- * The context in which analysis is to be performed.
- */
- final InternalAnalysisContext context;
-
- /**
- * The map of [ResultChangedEvent] controllers.
- */
- final Map<ResultDescriptor, StreamController<ResultChangedEvent>>
- resultComputedControllers =
- <ResultDescriptor, StreamController<ResultChangedEvent>>{};
-
- /**
- * The work order that was previously computed but that has not yet been
- * completed.
- */
- WorkOrder currentWorkOrder;
-
- /**
- * Indicates whether any tasks are currently being performed (or building
- * their inputs). In debug builds, we use this to ensure that tasks don't
- * try to make use of the task manager in reentrant fashion.
- */
- bool isTaskRunning = false;
-
- /**
- * The controller that is notified when a task is started.
- */
- StreamController<AnalysisTask> _onTaskStartedController;
-
- /**
- * The controller that is notified when a task is complete.
- */
- StreamController<AnalysisTask> _onTaskCompletedController;
-
- /**
- * Initialize a newly created driver to use the tasks know to the given
- * [taskManager] to perform analysis in the given [context].
- */
- AnalysisDriver(this.taskManager, this.workManagers, this.context) {
- _onTaskStartedController = new StreamController.broadcast();
- _onTaskCompletedController = new StreamController.broadcast();
- }
-
- /**
- * The stream that is notified when a task is complete.
- */
- Stream<AnalysisTask> get onTaskCompleted => _onTaskCompletedController.stream;
-
- /**
- * The stream that is notified when a task is started.
- */
- Stream<AnalysisTask> get onTaskStarted => _onTaskStartedController.stream;
-
- /**
- * Perform work until the given [result] has been computed for the given
- * [target]. Return the last [AnalysisTask] that was performed.
- */
- AnalysisTask computeResult(AnalysisTarget target, ResultDescriptor result) {
- assert(!isTaskRunning);
- try {
- isTaskRunning = true;
- AnalysisTask task;
- while (true) {
- try {
- WorkOrder workOrder = createWorkOrderForResult(target, result);
- if (workOrder != null) {
- while (workOrder.moveNext()) {
- task = performWorkItem(workOrder.current);
- }
- }
- break;
- } on ModificationTimeMismatchError {
- // Cache inconsistency was detected and fixed by invalidating
- // corresponding results in cache. Computation must be restarted.
- }
- }
- return task;
- } finally {
- isTaskRunning = false;
- }
- }
-
- /**
- * Return the work order describing the work that should be getting worked on,
- * or `null` if there is currently no work to be done.
- */
- WorkOrder createNextWorkOrder() {
- while (true) {
- // Find the WorkManager with the highest priority.
- WorkOrderPriority highestPriority = null;
- WorkManager highestManager = null;
- for (WorkManager manager in workManagers) {
- WorkOrderPriority priority = manager.getNextResultPriority();
- if (highestPriority == null || highestPriority.index > priority.index) {
- highestPriority = priority;
- highestManager = manager;
- }
- }
- // Nothing to do.
- if (highestPriority == WorkOrderPriority.NONE) {
- return null;
- }
- // Create a new WorkOrder.
- TargetedResult request = highestManager.getNextResult();
-// print('request: $request');
- if (request != null) {
- WorkOrder workOrder =
- createWorkOrderForResult(request.target, request.result);
- if (workOrder != null) {
- return workOrder;
- }
- }
- }
- }
-
- /**
- * Create a work order that will produce the given [result] for the given
- * [target]. Return the work order that was created, or `null` if the result
- * has either already been computed or cannot be computed.
- */
- WorkOrder createWorkOrderForResult(
- AnalysisTarget target, ResultDescriptor result) {
- CacheEntry entry = context.getCacheEntry(target);
- CacheState state = entry.getState(result);
- if (state == CacheState.VALID ||
- state == CacheState.ERROR ||
- state == CacheState.IN_PROCESS) {
- return null;
- }
- if (context.aboutToComputeResult(entry, result)) {
- return null;
- }
- TaskDescriptor taskDescriptor = taskManager.findTask(target, result);
- if (taskDescriptor == null) {
- return null;
- }
- try {
- WorkItem workItem =
- new WorkItem._(context, target, taskDescriptor, result, 0, null);
- return new WorkOrder(taskManager, workItem);
- } catch (exception, stackTrace) {
- throw new AnalysisException(
- 'Could not create work order (target = $target; taskDescriptor = $taskDescriptor; result = $result)',
- new CaughtException(exception, stackTrace));
- }
- }
-
- /**
- * Create a work order that will produce the required analysis results for
- * the given [target]. If [isPriority] is true, then the target is a priority
- * target. Return the work order that was created, or `null` if there is no
- * further work that needs to be done for the given target.
- */
- WorkOrder createWorkOrderForTarget(AnalysisTarget target, bool isPriority) {
- for (ResultDescriptor result in taskManager.generalResults) {
- WorkOrder workOrder = createWorkOrderForResult(target, result);
- if (workOrder != null) {
- return workOrder;
- }
- }
- if (isPriority) {
- for (ResultDescriptor result in taskManager.priorityResults) {
- WorkOrder workOrder = createWorkOrderForResult(target, result);
- if (workOrder != null) {
- return workOrder;
- }
- }
- }
- return null;
- }
-
- /**
- * Return the stream that is notified when a new value for the given
- * [descriptor] is computed.
- */
- Stream<ResultChangedEvent> onResultComputed(ResultDescriptor descriptor) {
- return resultComputedControllers.putIfAbsent(descriptor, () {
- return new StreamController<ResultChangedEvent>.broadcast(sync: true);
- }).stream;
- }
-
- /**
- * Perform the next analysis task, and return `true` if there is more work to
- * be done in order to compute all of the required analysis information.
- */
- bool performAnalysisTask() {
- //
- // TODO(brianwilkerson) This implementation does not allow us to prioritize
- // work across contexts. What we need is a way for an external client to ask
- // to have all priority files analyzed for each context, then ask for normal
- // files to be analyzed. There are a couple of ways to do this.
- //
- // First, we could add a "bool priorityOnly" parameter to this method and
- // return null here when it is true.
- //
- // Second, we could add a concept of a priority order and (externally) run
- // through the priorities from highest to lowest. That would be a nice
- // generalization of the previous idea, but it isn't clear that we need the
- // generality.
- //
- // Third, we could move performAnalysisTask and createNextWorkOrder to an
- // object that knows about all sources in all contexts, so that instead of
- // the client choosing a context and telling it do to some work, the client
- // simply says "do some work", and the engine chooses the best thing to do
- // next regardless of what context it's in.
- //
- assert(!isTaskRunning);
- try {
- isTaskRunning = true;
- if (currentWorkOrder == null) {
- currentWorkOrder = createNextWorkOrder();
- } else if (currentWorkOrder.moveNext()) {
- try {
- performWorkItem(currentWorkOrder.current);
- } on ModificationTimeMismatchError {
- reset();
- return true;
- }
- } else {
- currentWorkOrder = createNextWorkOrder();
- }
- return currentWorkOrder != null;
- } finally {
- isTaskRunning = false;
- }
- }
-
- /**
- * Perform the given work item.
- * Return the performed [AnalysisTask].
- */
- AnalysisTask performWorkItem(WorkItem item) {
- if (item.exception != null) {
- // Mark all of the results that the task would have computed as being in
- // ERROR with the exception recorded on the work item.
- CacheEntry targetEntry = context.getCacheEntry(item.target);
- targetEntry.setErrorState(item.exception, item.descriptor.results);
- return null;
- }
- // Otherwise, perform the task.
- AnalysisTask task = item.buildTask();
- _onTaskStartedController.add(task);
- task.perform();
- analysisDriverProcessOutputs.makeCurrentWhile(() {
- AnalysisTarget target = task.target;
- CacheEntry entry = context.getCacheEntry(target);
- if (task.caughtException == null) {
- List<TargetedResult> dependedOn =
- context.analysisOptions.trackCacheDependencies
- ? item.inputTargetedResults.toList()
- : const <TargetedResult>[];
- Map<ResultDescriptor, dynamic> outputs = task.outputs;
- List<ResultDescriptor> results = task.descriptor.results;
- int resultLength = results.length;
- for (int i = 0; i < resultLength; i++) {
- ResultDescriptor result = results[i];
- // TODO(brianwilkerson) We could check here that a value was produced
- // and throw an exception if not (unless we want to allow null values).
- entry.setValue(result, outputs[result], dependedOn);
- }
- outputs.forEach((ResultDescriptor descriptor, value) {
- StreamController<ResultChangedEvent> controller =
- resultComputedControllers[descriptor];
- if (controller != null) {
- ResultChangedEvent event = new ResultChangedEvent(
- context, target, descriptor, value, true);
- controller.add(event);
- }
- });
- for (WorkManager manager in workManagers) {
- manager.resultsComputed(target, outputs);
- }
- } else {
- entry.setErrorState(task.caughtException, item.descriptor.results);
- }
- });
- _onTaskCompletedController.add(task);
- return task;
- }
-
- /**
- * Reset the state of the driver in response to a change in the state of one
- * or more analysis targets. This will cause any analysis that was currently
- * in process to be stopped and for analysis to resume based on the new state.
- */
- void reset() {
- currentWorkOrder = null;
- }
-}
-
-/**
- * Generic dependency walker suitable for use in the analysis task driver.
- * This class implements a variant of the path-based strong component algorithm
- * (described here: http://www.cs.colorado.edu/~hal/Papers/DFS/ipl.ps.gz), with
- * the following differences:
- *
- * - The algorithm is non-recursive so that it can be used in a coroutine
- * fashion (each call to [getNextStronglyConnectedComponent] computes a
- * single strongly connected component and then waits to be called again)
- *
- * - Instead of keeping a temporary array which maps nodes to their locations
- * in the [path] array, we simply search the array when necessary. This
- * allows us to begin finding strongly connected components without having to
- * know the size of the whole graph.
- *
- * - This algorithm does not compute all strongly connected components; only
- * those reachable from the starting point which are as yet unevaluated.
- *
- * The algorithm, in essence, is to traverse the dependency graph in
- * depth-first fashion from a starting node. If the path from the starting
- * node ever encounters the same node twice, then a cycle has been found, and
- * all the nodes comprising the cycle are (conceptually) contracted into a
- * single node. The algorithm yields possibly-collapsed nodes in proper
- * topological sort order (all the dependencies of a node are yielded before,
- * or in the same contracted component as, the node itself).
- */
-abstract class CycleAwareDependencyWalker<Node> {
- /**
- * The path through the dependency graph that is currently being considered,
- * with un-collapsed nodes.
- */
- final List<Node> _path;
-
- /**
- * For each node in [_path], a list of the unevaluated nodes which it is
- * already known to depend on.
- */
- final List<List<Node>> _provisionalDependencies;
-
- /**
- * Indices into [_path] of the nodes which begin a new strongly connected
- * component, in order. The first index in [_contractedPath] is always 0.
- *
- * For all i < contractedPath.length - 1, at least one node in the strongly
- * connected component represented by [contractedPath[i]] depends directly
- * on at least one node in the strongly connected component represented by
- * [contractedPath[i+1]].
- */
- final List<int> _contractedPath;
-
- /**
- * Index into [_path] of the nodes which we are currently in the process of
- * querying for their dependencies.
- *
- * [currentIndices.last] always refers to a member of the last strongly
- * connected component indicated by [_contractedPath].
- */
- final List<int> _currentIndices;
-
- /**
- * Begin walking dependencies starting at [startingNode].
- */
- CycleAwareDependencyWalker(Node startingNode)
- : _path = <Node>[startingNode],
- _provisionalDependencies = <List<Node>>[<Node>[]],
- _contractedPath = <int>[0],
- _currentIndices = <int>[0];
-
- /**
- * Determine the next unevaluated input for [node], skipping any inputs in
- * [skipInputs], and return it. If [node] has no further inputs, return
- * `null`.
- */
- Node getNextInput(Node node, List<Node> skipInputs);
-
- /**
- * Determine the next strongly connected component in the graph, and return
- * it. The client is expected to evaluate this component before calling
- * [getNextStronglyConnectedComponent] again.
- */
- StronglyConnectedComponent<Node> getNextStronglyConnectedComponent() {
- while (_currentIndices.isNotEmpty) {
- Node nextUnevaluatedInput = getNextInput(_path[_currentIndices.last],
- _provisionalDependencies[_currentIndices.last]);
- // If the assertion below fails, it indicates that [getNextInput] did not
- // skip an input that we asked it to skip.
- assert(!_provisionalDependencies[_currentIndices.last]
- .contains(nextUnevaluatedInput));
- if (nextUnevaluatedInput != null) {
- // TODO(paulberry): the call to _path.indexOf makes the algorithm
- // O(n^2) in the depth of the dependency graph. If this becomes a
- // problem, consider maintaining a map from node to index.
- int previousIndex = _path.indexOf(nextUnevaluatedInput);
- if (previousIndex != -1) {
- // Update contractedPath to indicate that all nodes in the path
- // between previousIndex and currentIndex are part of the same
- // strongly connected component.
- while (_contractedPath.last > previousIndex) {
- _contractedPath.removeLast();
- }
- // Store nextUnevaluatedInput as a provisional dependency so that we
- // can move on to computing other dependencies.
- _provisionalDependencies[_currentIndices.last]
- .add(nextUnevaluatedInput);
- // And loop to move on to the node's next input.
- continue;
- } else {
- // This is a brand new input and there's no reason (yet) to believe
- // that it is in the same strongly connected component as any other
- // node, so push it onto the end of the path.
- int newIndex = _path.length;
- _path.add(nextUnevaluatedInput);
- _provisionalDependencies.add(<Node>[]);
- _contractedPath.add(newIndex);
- _currentIndices.add(newIndex);
- // And loop to move on to the new node's inputs.
- continue;
- }
- } else {
- // The node has no more inputs. Figure out if there are any more nodes
- // in the current strongly connected component that need to have their
- // indices examined.
- _currentIndices.removeLast();
- if (_currentIndices.isEmpty ||
- _currentIndices.last < _contractedPath.last) {
- // No more nodes in the current strongly connected component need to
- // have their indices examined. We can now yield this component to
- // the caller.
- List<Node> nodes = _path.sublist(_contractedPath.last);
- bool containsCycle = nodes.length > 1;
- if (!containsCycle) {
- if (_provisionalDependencies.last.isNotEmpty) {
- containsCycle = true;
- }
- }
- _path.length = _contractedPath.last;
- _provisionalDependencies.length = _contractedPath.last;
- _contractedPath.removeLast();
- return new StronglyConnectedComponent<Node>(nodes, containsCycle);
- } else {
- // At least one node in the current strongly connected component
- // still needs to have its inputs examined. So loop and allow the
- // inputs to be examined.
- continue;
- }
- }
- }
- // No further strongly connected components found.
- return null;
- }
-}
-
-/**
- * A place to define the behaviors that need to be added to
- * [InternalAnalysisContext].
- */
-abstract class ExtendedAnalysisContext implements InternalAnalysisContext {
- List<AnalysisTarget> get explicitTargets;
- List<AnalysisTarget> get priorityTargets;
- void set typeProvider(TypeProvider typeProvider);
- CacheEntry getCacheEntry(AnalysisTarget target);
-}
-
-/**
- * An exception indicating that an attempt was made to perform a task on a
- * target while gathering the inputs to perform the same task for the same
- * target.
- */
-class InfiniteTaskLoopException extends AnalysisException {
- /**
- * A concrete cyclic path of [TargetedResults] within the [dependencyCycle],
- * `null` if no such path exists. All nodes in the path are in the
- * dependencyCycle, but the path is not guaranteed to cover the
- * entire cycle.
- */
- final List<TargetedResult> cyclicPath;
-
- /**
- * If a dependency cycle was found while computing the inputs for the task,
- * the set of [WorkItem]s contained in the cycle (if there are overlapping
- * cycles, this is the set of all [WorkItem]s in the entire strongly
- * connected component). Otherwise, `null`.
- */
- final List<WorkItem> dependencyCycle;
-
- /**
- * Initialize a newly created exception to represent a failed attempt to
- * perform the given [task] due to the given [dependencyCycle].
- */
- InfiniteTaskLoopException(AnalysisTask task, List<WorkItem> dependencyCycle,
- [List<TargetedResult> cyclicPath])
- : this.dependencyCycle = dependencyCycle,
- this.cyclicPath = cyclicPath,
- super(_composeMessage(task, dependencyCycle, cyclicPath));
-
- /**
- * Compose an error message based on the data we have available.
- */
- static String _composeMessage(AnalysisTask task,
- List<WorkItem> dependencyCycle, List<TargetedResult> cyclicPath) {
- StringBuffer buffer = new StringBuffer();
- buffer.write('Infinite loop while performing task ');
- buffer.write(task.descriptor.name);
- buffer.write(' for ');
- buffer.writeln(task.target);
- buffer.writeln(' Dependency Cycle:');
- for (WorkItem item in dependencyCycle) {
- buffer.write(' ');
- buffer.writeln(item);
- }
- if (cyclicPath != null) {
- buffer.writeln(' Cyclic Path:');
- for (TargetedResult result in cyclicPath) {
- buffer.write(' ');
- buffer.writeln(result);
- }
- }
- return buffer.toString();
- }
-}
-
-/**
- * Object used by [CycleAwareDependencyWalker] to report a single strongly
- * connected component of nodes.
- */
-class StronglyConnectedComponent<Node> {
- /**
- * The nodes contained in the strongly connected component.
- */
- final List<Node> nodes;
-
- /**
- * Indicates whether the strongly component contains any cycles. Note that
- * if [nodes] has multiple elements, this will always be `true`. However, if
- * [nodes] has exactly one element, this may be either `true` or `false`
- * depending on whether the node has a dependency on itself.
- */
- final bool containsCycle;
-
- StronglyConnectedComponent(this.nodes, this.containsCycle);
-}
-
-/**
- * A description of a single analysis task that can be performed to advance
- * analysis.
- */
-class WorkItem {
- /**
- * The context in which the task will be performed.
- */
- final InternalAnalysisContext context;
-
- /**
- * The target for which a task is to be performed.
- */
- final AnalysisTarget target;
-
- /**
- * A description of the task to be performed.
- */
- final TaskDescriptor descriptor;
-
- /**
- * The [ResultDescriptor] which was led to this work item being spawned.
- */
- final ResultDescriptor spawningResult;
-
- /**
- * The level of this item in its [WorkOrder].
- */
- final int level;
-
- /**
- * The work order that this item is part of, may be `null`.
- */
- WorkOrder workOrder;
-
- /**
- * An iterator used to iterate over the descriptors of the inputs to the task,
- * or `null` if all of the inputs have been collected and the task can be
- * created.
- */
- TopLevelTaskInputBuilder builder;
-
- /**
- * The [TargetedResult]s outputs of this task depends on.
- */
- final HashSet<TargetedResult> inputTargetedResults =
- new HashSet<TargetedResult>();
-
- /**
- * The inputs to the task that have been computed.
- */
- Map<String, dynamic> inputs = const <String, dynamic>{};
-
- /**
- * The exception that was found while trying to populate the inputs. If this
- * field is non-`null`, then the task cannot be performed and all of the
- * results that this task would have computed need to be marked as being in
- * ERROR with this exception.
- */
- CaughtException exception = null;
-
- /**
- * If a dependency cycle was found while computing the inputs for the task,
- * the set of [WorkItem]s contained in the cycle (if there are overlapping
- * cycles, this is the set of all [WorkItem]s in the entire strongly
- * connected component). Otherwise, `null`.
- */
- List<WorkItem> dependencyCycle;
-
- /**
- * Initialize a newly created work item to compute the inputs for the task
- * described by the given descriptor.
- */
- WorkItem._(this.context, this.target, this.descriptor, this.spawningResult,
- this.level, this.workOrder) {
- _checkInternalUseOfTaskModel();
- AnalysisTarget actualTarget =
- identical(target, AnalysisContextTarget.request)
- ? new AnalysisContextTarget(context)
- : target;
-// print('${'\t' * level}$spawningResult of $actualTarget');
- Map<String, TaskInput> inputDescriptors =
- descriptor.createTaskInputs(actualTarget);
- builder = new TopLevelTaskInputBuilder(inputDescriptors);
- if (!builder.moveNext()) {
- builder = null;
- }
- }
-
- @override
- int get hashCode =>
- JenkinsSmiHash.hash2(descriptor.hashCode, target.hashCode);
-
- @override
- bool operator ==(other) {
- if (other is WorkItem) {
- return this.descriptor == other.descriptor && this.target == other.target;
- } else {
- return false;
- }
- }
-
- /**
- * Build the task represented by this work item.
- */
- AnalysisTask buildTask() {
- if (builder != null) {
- throw new StateError("some inputs have not been computed");
- }
- AnalysisTask task = descriptor.createTask(context, target, inputs);
- task.dependencyCycle = dependencyCycle;
- return task;
- }
-
- /**
- * Gather all of the inputs needed to perform the task.
- *
- * If at least one of the inputs have not yet been computed, return a work
- * item that can be used to generate that input to indicate that the caller
- * should perform the returned item's task before returning to gathering
- * inputs for this item's task.
- *
- * If all of the inputs have been gathered, return `null` to indicate that the
- * client should build and perform the task. A value of `null` will also be
- * returned if some of the inputs cannot be computed and the task cannot be
- * performed. Callers can differentiate between these cases by checking the
- * [exception] field. If the field is `null`, then the task can be performed;
- * if the field is non-`null` then the task cannot be performed and all of the
- * tasks' results should be marked as being in ERROR.
- */
- WorkItem gatherInputs(TaskManager taskManager, List<WorkItem> skipInputs) {
- while (builder != null) {
- AnalysisTarget inputTarget = builder.currentTarget;
- ResultDescriptor inputResult = builder.currentResult;
-
- // TODO(scheglov) record information to debug
- // https://github.com/dart-lang/sdk/issues/24939
- if (inputTarget == null || inputResult == null) {
- try {
- String message =
- 'Invalid input descriptor ($inputTarget, $inputResult) for $this';
- if (workOrder != null) {
- message += '\nPath:\n' + workOrder.workItems.join('|\n');
- }
- throw new AnalysisException(message);
- } catch (exception, stackTrace) {
- this.exception = new CaughtException(exception, stackTrace);
- AnalysisEngine.instance.logger
- .logError('Task failed: $this', this.exception);
- }
- return null;
- }
-
- inputTargetedResults.add(new TargetedResult(inputTarget, inputResult));
- CacheEntry inputEntry = context.getCacheEntry(inputTarget);
- CacheState inputState = inputEntry.getState(inputResult);
- if (inputState == CacheState.ERROR) {
- exception = inputEntry.exception;
- return null;
- } else if (inputState == CacheState.IN_PROCESS) {
- //
- // TODO(brianwilkerson) Implement this case.
- //
- // One possibility would be to return a WorkItem that would perform a
- // no-op task in order to cause us to come back to this work item on the
- // next iteration. It would be more efficient, in general, to push this
- // input onto a waiting list and proceed to the next input so that work
- // could proceed, but given that the only result that can currently be
- // IN_PROCESS is CONTENT, I don't know that it's worth the extra effort
- // to implement the general solution at this point.
- //
- throw new UnimplementedError();
- } else if (inputState != CacheState.VALID) {
- if (context.aboutToComputeResult(inputEntry, inputResult)) {
- inputState = CacheState.VALID;
- builder.currentValue = inputEntry.getValue(inputResult);
- } else {
- try {
- TaskDescriptor descriptor =
- taskManager.findTask(inputTarget, inputResult);
- if (descriptor == null) {
- throw new AnalysisException(
- 'Cannot find task to build $inputResult for $inputTarget');
- }
- if (skipInputs.any((WorkItem item) =>
- item.target == inputTarget && item.descriptor == descriptor)) {
- // This input is being skipped due to a circular dependency. Tell
- // the builder that it's not available so we can move on to other
- // inputs.
- builder.currentValueNotAvailable();
- } else {
- return new WorkItem._(context, inputTarget, descriptor,
- inputResult, level + 1, workOrder);
- }
- } on AnalysisException catch (exception, stackTrace) {
- this.exception = new CaughtException(exception, stackTrace);
- return null;
- } catch (exception, stackTrace) {
- this.exception = new CaughtException(exception, stackTrace);
- throw new AnalysisException(
- 'Cannot create work order to build $inputResult for $inputTarget',
- this.exception);
- }
- }
- } else {
- builder.currentValue = inputEntry.getValue(inputResult);
- if (builder.flushOnAccess) {
- inputEntry.setState(inputResult, CacheState.FLUSHED);
- }
- }
- if (!builder.moveNext()) {
- inputs = builder.inputValue;
- builder = null;
- }
- }
- return null;
- }
-
- @override
- String toString() => 'Run $descriptor on $target';
-
- static void _checkInternalUseOfTaskModel() {
- if (!StackTrace.current.toString().contains('/analyzer/test/')) {
- throw new StateError(
- 'The analyzer task model is no longer supported. Please use the AnalysisSession API.');
- }
- }
-}
-
-/**
- * A description of the work to be done to compute a desired analysis result.
- * The class implements a lazy depth-first traversal of the work item's input.
- */
-class WorkOrder implements Iterator<WorkItem> {
- /**
- * The dependency walker which is being used to determine what work to do
- * next.
- */
- final _WorkOrderDependencyWalker _dependencyWalker;
-
- /**
- * The strongly connected component most recently returned by
- * [_dependencyWalker], minus any [WorkItem]s that the iterator has already
- * moved past.
- *
- * Null if the [_dependencyWalker] hasn't been used yet.
- */
- List<WorkItem> currentItems;
-
- /**
- * Initialize a newly created work order to compute the result described by
- * the given work item.
- */
- WorkOrder(TaskManager taskManager, WorkItem item)
- : _dependencyWalker = new _WorkOrderDependencyWalker(taskManager, item) {
- item.workOrder = this;
- }
-
- @override
- WorkItem get current {
- if (currentItems == null) {
- return null;
- } else {
- return currentItems.last;
- }
- }
-
- List<WorkItem> get workItems => _dependencyWalker._path;
-
- @override
- bool moveNext() {
- return workOrderMoveNextPerformanceTag.makeCurrentWhile(() {
- if (currentItems != null && currentItems.length > 1) {
- // Yield more items.
- currentItems.removeLast();
- return true;
- } else {
- // Get a new strongly connected component.
- StronglyConnectedComponent<WorkItem> nextStronglyConnectedComponent =
- _dependencyWalker.getNextStronglyConnectedComponent();
- if (nextStronglyConnectedComponent == null) {
- currentItems = null;
- return false;
- }
- currentItems = nextStronglyConnectedComponent.nodes;
- if (nextStronglyConnectedComponent.containsCycle) {
- // A cycle has been found.
- for (WorkItem item in currentItems) {
- item.dependencyCycle = currentItems.toList();
- }
- } else {
- assert(currentItems.length == 1);
- }
- return true;
- }
- });
- }
-}
-
-/**
- * Specialization of [CycleAwareDependencyWalker] for use by [WorkOrder].
- */
-class _WorkOrderDependencyWalker extends CycleAwareDependencyWalker<WorkItem> {
- /**
- * The task manager used to build work items.
- */
- final TaskManager taskManager;
-
- _WorkOrderDependencyWalker(this.taskManager, WorkItem startingNode)
- : super(startingNode);
-
- @override
- WorkItem getNextInput(WorkItem node, List<WorkItem> skipInputs) {
- return node.gatherInputs(taskManager, skipInputs);
- }
-}
diff --git a/pkg/analyzer/lib/src/task/general.dart b/pkg/analyzer/lib/src/task/general.dart
deleted file mode 100644
index 5fcb776..0000000
--- a/pkg/analyzer/lib/src/task/general.dart
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:analyzer/src/context/cache.dart';
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/task/api/general.dart';
-import 'package:analyzer/src/task/api/model.dart';
-
-/**
- * A task that gets the contents of the source associated with an analysis
- * target.
- */
-class GetContentTask extends SourceBasedAnalysisTask {
- /**
- * The task descriptor describing this kind of task.
- */
- static final TaskDescriptor DESCRIPTOR = new TaskDescriptor('GetContentTask',
- createTask, buildInputs, <ResultDescriptor>[CONTENT, MODIFICATION_TIME]);
-
- /**
- * Initialize a newly created task to access the content of the source
- * associated with the given [target] in the given [context].
- */
- GetContentTask(AnalysisContext context, AnalysisTarget target)
- : super(context, target);
-
- @override
- TaskDescriptor get descriptor => DESCRIPTOR;
-
- @override
- internalPerform() {
- Source source = getRequiredSource();
- String content;
- int modificationTime;
- try {
- TimestampedData<String> data = context.getContents(source);
- content = data.data;
- modificationTime = data.modificationTime;
- } catch (exception) {
- content = '';
- modificationTime = -1;
- }
- _validateModificationTime(source, modificationTime);
- outputs[CONTENT] = content;
- outputs[MODIFICATION_TIME] = modificationTime;
- }
-
- /**
- * Validate that the [target] cache entry has the same modification time
- * as the given. Otherwise throw a new [ModificationTimeMismatchError] and
- * instruct to invalidate targets content.
- */
- void _validateModificationTime(Source source, int modificationTime) {
- AnalysisContext context = this.context;
- if (context is InternalAnalysisContext) {
- CacheEntry entry = context.getCacheEntry(target);
- if (entry != null && entry.modificationTime != modificationTime) {
- entry.modificationTime = modificationTime;
- entry.setState(CONTENT, CacheState.INVALID);
- entry.setState(MODIFICATION_TIME, CacheState.INVALID);
- throw new ModificationTimeMismatchError(source);
- }
- }
- }
-
- /**
- * Return a map from the names of the inputs of this kind of task to the task
- * input descriptors describing those inputs for a task with the given [target].
- */
- static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
- return <String, TaskInput>{};
- }
-
- /**
- * Create a [GetContentTask] based on the given [target] in the given
- * [context].
- */
- static GetContentTask createTask(
- AnalysisContext context, AnalysisTarget target) {
- return new GetContentTask(context, target);
- }
-}
-
-/**
- * A base class for analysis tasks whose target is expected to be a source.
- */
-abstract class SourceBasedAnalysisTask extends AnalysisTask {
- /**
- * Initialize a newly created task to perform analysis within the given
- * [context] in order to produce results for the given [target].
- */
- SourceBasedAnalysisTask(AnalysisContext context, AnalysisTarget target)
- : super(context, target);
-
- @override
- String get description {
- Source source = target.source;
- String sourceName = source == null ? '<unknown source>' : source.fullName;
- return '${descriptor.name} for source $sourceName';
- }
-}
diff --git a/pkg/analyzer/lib/src/task/inputs.dart b/pkg/analyzer/lib/src/task/inputs.dart
deleted file mode 100644
index 30fd2446e..0000000
--- a/pkg/analyzer/lib/src/task/inputs.dart
+++ /dev/null
@@ -1,998 +0,0 @@
-// Copyright (c) 2015, 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:collection';
-
-import 'package:analyzer/src/task/api/model.dart';
-
-/**
- * A function that converts an object of the type [B] into a [TaskInput].
- * This is used, for example, by a [ListToListTaskInput] to create task inputs
- * for each value in a list of values.
- */
-typedef TaskInput<E> GenerateTaskInputs<B, E>(B object);
-
-/**
- * A function that maps one [value] to another value.
- */
-typedef R Mapper<P, R>(P value);
-
-/**
- * An input to an [AnalysisTask] that is computed by accessing a single result
- * defined on a single target.
- */
-class ConstantTaskInput<V> extends TaskInputImpl<V> {
- final V value;
-
- ConstantTaskInput(this.value);
-
- @override
- TaskInputBuilder<V> createBuilder() {
- return new ConstantTaskInputBuilder<V>(this);
- }
-}
-
-/**
- * A [TaskInputBuilder] used to build an input based on a [ConstantTaskInput].
- */
-class ConstantTaskInputBuilder<V> implements TaskInputBuilder<V> {
- final ConstantTaskInput<V> input;
-
- ConstantTaskInputBuilder(this.input);
-
- @override
- ResultDescriptor get currentResult => null;
-
- @override
- AnalysisTarget get currentTarget => null;
-
- @override
- void set currentValue(Object value) {
- throw new StateError('Only supported after moveNext() returns true');
- }
-
- @override
- bool get flushOnAccess => false;
-
- @override
- V get inputValue => input.value;
-
- @override
- void currentValueNotAvailable() {
- throw new StateError('Only supported after moveNext() returns true');
- }
-
- @override
- bool moveNext() => false;
-}
-
-/**
- * An input to an [AnalysisTask] that is computed by accessing a single result
- * defined on a single target.
- */
-class ListTaskInputImpl<E> extends SimpleTaskInput<List<E>>
- with ListTaskInputMixin<E>
- implements ListTaskInput<E> {
- /**
- * Initialize a newly created task input that computes the input by accessing
- * the given [result] associated with the given [target].
- */
- ListTaskInputImpl(AnalysisTarget target, ResultDescriptor<List<E>> result)
- : super._unflushable(target, result);
-}
-
-/**
- * A mixin-ready implementation of [ListTaskInput].
- */
-abstract class ListTaskInputMixin<E> implements ListTaskInput<E> {
- @override
- ListTaskInput<V> toFlattenListOf<V>(ListResultDescriptor<V> subListResult) {
- return new ListToFlattenListTaskInput<E, V>(
- this,
- (E element) =>
- subListResult.of(element as AnalysisTarget) as TaskInput<V>);
- }
-
- ListTaskInput<V> toList<V>(UnaryFunction<E, V> mapper) {
- return new ListToListTaskInput<E, V>(this, mapper);
- }
-
- ListTaskInput<V> toListOf<V>(ResultDescriptor<V> valueResult) {
- return (this as ListTaskInput<AnalysisTarget>).toList(valueResult.of);
- }
-
- MapTaskInput<E, V> toMap<V>(UnaryFunction<E, V> mapper) {
- return new ListToMapTaskInput<E, V>(this, mapper);
- }
-
- MapTaskInput<AnalysisTarget, V> toMapOf<V>(ResultDescriptor<V> valueResult) {
- return (this as ListTaskInputImpl<AnalysisTarget>).toMap<V>(valueResult.of);
- }
-}
-
-/**
- * An input to an [AnalysisTask] that is computed by the following steps. First
- * another (base) task input is used to compute a [List]-valued result. An input
- * generator function is then used to map each element of that list to a task
- * input. Finally, each of the task inputs are used to access analysis results,
- * and the list of the analysis results is used as the input to the task.
- */
-class ListToFlattenListTaskInput<B, E>
- extends _ListToCollectionTaskInput<B, E, List<E>>
- with ListTaskInputMixin<E>
- implements ListTaskInput<E> {
- /**
- * Initialize a result accessor to use the given [baseAccessor] to access a
- * list of values that can be passed to the given [generateTaskInputs] to
- * generate a list of task inputs that can be used to access the elements of
- * the input being accessed.
- */
- ListToFlattenListTaskInput(TaskInput<List<B>> baseAccessor,
- GenerateTaskInputs<B, E> generateTaskInputs)
- : super(baseAccessor, generateTaskInputs);
-
- @override
- TaskInputBuilder<List<E>> createBuilder() =>
- new ListToFlattenListTaskInputBuilder<B, E>(this);
-}
-
-/**
- * A [TaskInputBuilder] used to build an input based on a [ListToFlattenListTaskInput].
- */
-class ListToFlattenListTaskInputBuilder<B, E>
- extends _ListToCollectionTaskInputBuilder<B, E, List<E>> {
- /**
- * The list of values being built.
- */
- List<E> _resultValue;
-
- /**
- * Initialize a newly created task input builder that computes the result
- * specified by the given [input].
- */
- ListToFlattenListTaskInputBuilder(ListToFlattenListTaskInput<B, E> input)
- : super(input);
-
- @override
- void _addResultElement(B baseElement, E resultElement) {
- _resultValue.addAll(resultElement as Iterable<E>);
- }
-
- @override
- void _initResultValue() {
- _resultValue = <E>[];
- }
-}
-
-/**
- * An input to an [AnalysisTask] that is computed by the following steps. First
- * another (base) task input is used to compute a [List]-valued result. An input
- * generator function is then used to map each element of that list to a task
- * input. Finally, each of the task inputs are used to access analysis results,
- * and the list of the analysis results is used as the input to the task.
- */
-class ListToListTaskInput<B, E>
- extends _ListToCollectionTaskInput<B, E, List<E>>
- with ListTaskInputMixin<E> {
- /**
- * Initialize a result accessor to use the given [baseAccessor] to access a
- * list of values that can be passed to the given [generateTaskInputs] to
- * generate a list of task inputs that can be used to access the elements of
- * the input being accessed.
- */
- ListToListTaskInput(TaskInput<List<B>> baseAccessor,
- GenerateTaskInputs<B, E> generateTaskInputs)
- : super(baseAccessor, generateTaskInputs);
-
- @override
- TaskInputBuilder<List<E>> createBuilder() =>
- new ListToListTaskInputBuilder<B, E>(this);
-}
-
-/**
- * A [TaskInputBuilder] used to build an input based on a [ListToListTaskInput].
- */
-class ListToListTaskInputBuilder<B, E>
- extends _ListToCollectionTaskInputBuilder<B, E, List<E>> {
- /**
- * The list of values being built.
- */
- List<E> _resultValue;
-
- /**
- * Initialize a newly created task input builder that computes the result
- * specified by the given [input].
- */
- ListToListTaskInputBuilder(ListToListTaskInput<B, E> input) : super(input);
-
- @override
- void _addResultElement(B baseElement, E resultElement) {
- _resultValue.add(resultElement);
- }
-
- @override
- void _initResultValue() {
- _resultValue = <E>[];
- }
-}
-
-/**
- * An input to an [AnalysisTask] that is computed by the following steps. First
- * another (base) task input is used to compute a [List]-valued result. An input
- * generator function is then used to map each element of that list to a task
- * input. Finally, each of the task inputs are used to access analysis results,
- * and the map of the base elements to the analysis results is used as the
- * input to the task.
- */
-class ListToMapTaskInput<B, E>
- extends _ListToCollectionTaskInput<B, E, Map<B, E>>
- with MapTaskInputMixin<B, E> {
- /**
- * Initialize a result accessor to use the given [baseAccessor] to access a
- * list of values that can be passed to the given [generateTaskInputs] to
- * generate a list of task inputs that can be used to access the elements of
- * the input being accessed.
- */
- ListToMapTaskInput(TaskInput<List<B>> baseAccessor,
- GenerateTaskInputs<B, E> generateTaskInputs)
- : super(baseAccessor, generateTaskInputs);
-
- @override
- TaskInputBuilder<Map<B, E>> createBuilder() =>
- new ListToMapTaskInputBuilder<B, E>(this);
-}
-
-/**
- * A [TaskInputBuilder] used to build an input based on a [ListToMapTaskInput].
- */
-class ListToMapTaskInputBuilder<B, E>
- extends _ListToCollectionTaskInputBuilder<B, E, Map<B, E>> {
- /**
- * The map being built.
- */
- Map<B, E> _resultValue;
-
- /**
- * Initialize a newly created task input builder that computes the result
- * specified by the given [input].
- */
- ListToMapTaskInputBuilder(ListToMapTaskInput<B, E> input) : super(input);
-
- @override
- void _addResultElement(B baseElement, E resultElement) {
- _resultValue[baseElement] = resultElement;
- }
-
- @override
- void _initResultValue() {
- _resultValue = new HashMap<B, E>();
- }
-}
-
-/**
- * A mixin-ready implementation of [MapTaskInput].
- */
-abstract class MapTaskInputMixin<K, V> implements MapTaskInput<K, V> {
- TaskInput<List<E>> toFlattenList<E>(
- BinaryFunction<K, dynamic /*element of V*/, E> mapper) {
- return new MapToFlattenListTaskInput<K, dynamic /*element of V*/, E>(
- this as MapTaskInput<K, List /*element of V*/ >, mapper);
- }
-}
-
-/**
- * A [TaskInput] that is computed by the following steps.
- *
- * First the [base] task input is used to compute a [Map]-valued result.
- * The values of the [Map] must be [List]s.
- *
- * The given [mapper] is used to transform each key / value pair of the [Map]
- * into task inputs.
- *
- * Finally, each of the task inputs are used to access analysis results,
- * and the list of the results is used as the input.
- */
-class MapToFlattenListTaskInput<K, V, E> extends TaskInputImpl<List<E>> {
- final MapTaskInput<K, List<V>> base;
- final BinaryFunction<K, V, E> mapper;
-
- MapToFlattenListTaskInput(this.base, this.mapper);
-
- @override
- TaskInputBuilder<List<E>> createBuilder() {
- return new MapToFlattenListTaskInputBuilder<K, V, E>(base, mapper);
- }
-}
-
-/**
- * The [TaskInputBuilder] for [MapToFlattenListTaskInput].
- */
-class MapToFlattenListTaskInputBuilder<K, V, E>
- implements TaskInputBuilder<List<E>> {
- final MapTaskInput<K, List<V>> base;
- final BinaryFunction<K, V, E> mapper;
-
- TaskInputBuilder currentBuilder;
- Map<K, List<V>> baseMap;
- Iterator<K> keyIterator;
- Iterator<V> valueIterator;
-
- final List<E> inputValue = <E>[];
-
- MapToFlattenListTaskInputBuilder(this.base, this.mapper) {
- currentBuilder = base.createBuilder();
- }
-
- @override
- ResultDescriptor get currentResult {
- if (currentBuilder == null) {
- return null;
- }
- return currentBuilder.currentResult;
- }
-
- AnalysisTarget get currentTarget {
- if (currentBuilder == null) {
- return null;
- }
- return currentBuilder.currentTarget;
- }
-
- @override
- void set currentValue(Object value) {
- if (currentBuilder == null) {
- throw new StateError(
- 'Cannot set the result value when there is no current result');
- }
- currentBuilder.currentValue = value;
- }
-
- @override
- bool get flushOnAccess => currentBuilder.flushOnAccess;
-
- @override
- void currentValueNotAvailable() {
- if (currentBuilder == null) {
- throw new StateError(
- 'Cannot set the result value when there is no current result');
- }
- currentBuilder.currentValueNotAvailable();
- }
-
- @override
- bool moveNext() {
- // Prepare base Map.
- if (baseMap == null) {
- if (currentBuilder.moveNext()) {
- return true;
- }
- baseMap = currentBuilder.inputValue as Map<K, List<V>>;
- if (baseMap == null) {
- // No base map could be computed due to a circular dependency. Use an
- // empty map so that no further results will be computed.
- baseMap = {};
- }
- keyIterator = baseMap.keys.iterator;
- // Done with this builder.
- currentBuilder = null;
- }
- // Prepare the next result value.
- if (currentBuilder != null) {
- if (currentBuilder.moveNext()) {
- return true;
- }
- // Add the result value for the current Map key/value.
- E resultValue = currentBuilder.inputValue as E;
- if (resultValue != null) {
- inputValue.add(resultValue);
- }
- // Done with this builder.
- currentBuilder = null;
- }
- // Move to the next Map value.
- if (valueIterator != null && valueIterator.moveNext()) {
- K key = keyIterator.current;
- V value = valueIterator.current;
- currentBuilder = mapper(key, value).createBuilder();
- return moveNext();
- }
- // Move to the next Map key.
- if (keyIterator.moveNext()) {
- K key = keyIterator.current;
- valueIterator = baseMap[key].iterator;
- return moveNext();
- }
- // No more Map values/keys to transform.
- return false;
- }
-}
-
-/**
- * An input to an [AnalysisTask] that is computed by mapping the value of
- * another task input to a list of values.
- */
-class ObjectToListTaskInput<E> extends TaskInputImpl<List<E>>
- with ListTaskInputMixin<E>
- implements ListTaskInput<E> {
- // TODO(brianwilkerson) Add another type parameter to this class that can be
- // used as the type of the keys of [mapper].
- /**
- * The input used to compute the value to be mapped.
- */
- final TaskInput baseInput;
-
- /**
- * The function used to map the value of the base input to the list of values.
- */
- final Mapper<Object, List<E>> mapper;
-
- /**
- * Initialize a newly created task input that computes the input by accessing
- * the given [baseInput] associated with the given [mapper].
- */
- ObjectToListTaskInput(this.baseInput, this.mapper);
-
- @override
- TaskInputBuilder<List<E>> createBuilder() =>
- new ObjectToListTaskInputBuilder<E>(this);
-
- @override
- ListTaskInput<V> toFlattenListOf<V>(ListResultDescriptor<V> subListResult) {
- return new ListToFlattenListTaskInput<E, V>(
- this,
- (E element) =>
- subListResult.of(element as AnalysisTarget) as TaskInput<V>);
- }
-
- @override
- ListTaskInput<V> toListOf<V>(ResultDescriptor<V> valueResult) {
- return new ListToListTaskInput<E, V>(
- this, (E element) => valueResult.of(element as AnalysisTarget));
- }
-
- @override
- MapTaskInput<AnalysisTarget, V> toMapOf<V>(ResultDescriptor<V> valueResult) {
- return new ListToMapTaskInput<AnalysisTarget, V>(
- this as TaskInput<List<AnalysisTarget>>, valueResult.of);
- }
-}
-
-/**
- * A [TaskInputBuilder] used to build an input based on a [SimpleTaskInput].
- */
-class ObjectToListTaskInputBuilder<E> implements TaskInputBuilder<List<E>> {
- /**
- * The input being built.
- */
- final ObjectToListTaskInput<E> input;
-
- /**
- * The builder created by the input.
- */
- TaskInputBuilder builder;
-
- /**
- * The value of the input being built, or `null` if the value hasn't been set
- * yet or if no result is available ([currentValueNotAvailable] was called).
- */
- List<E> _inputValue = null;
-
- /**
- * Initialize a newly created task input builder that computes the result
- * specified by the given [input].
- */
- ObjectToListTaskInputBuilder(this.input) {
- builder = input.baseInput.createBuilder();
- }
-
- @override
- ResultDescriptor get currentResult {
- if (builder == null) {
- return null;
- }
- return builder.currentResult;
- }
-
- @override
- AnalysisTarget get currentTarget {
- if (builder == null) {
- return null;
- }
- return builder.currentTarget;
- }
-
- @override
- void set currentValue(Object value) {
- if (builder == null) {
- throw new StateError(
- 'Cannot set the result value when there is no current result');
- }
- builder.currentValue = value;
- }
-
- @override
- bool get flushOnAccess => builder.flushOnAccess;
-
- @override
- List<E> get inputValue {
- if (builder != null) {
- throw new StateError('Result value has not been created');
- }
- return _inputValue;
- }
-
- @override
- void currentValueNotAvailable() {
- if (builder == null) {
- throw new StateError(
- 'Cannot set the result value when there is no current result');
- }
- builder.currentValueNotAvailable();
- }
-
- @override
- bool moveNext() {
- if (builder == null) {
- return false;
- } else if (builder.moveNext()) {
- return true;
- } else {
- // This might not be the right semantics. If the value could not be
- // computed then we pass the resulting `null` in to the mapper function.
- // Unfortunately, we cannot tell the difference between a `null` that's
- // there because no value could be computed and a `null` that's there
- // because that's what *was* computed.
- _inputValue = input.mapper(builder.inputValue);
- builder = null;
- return false;
- }
- }
-}
-
-/**
- * An input to an [AnalysisTask] that is computed by accessing a single result
- * defined on a single target.
- */
-class SimpleTaskInput<V> extends TaskInputImpl<V> {
- /**
- * The target on which the result is defined.
- */
- final AnalysisTarget target;
-
- /**
- * The result to be accessed.
- */
- final ResultDescriptor<V> result;
-
- /**
- * Return `true` if the value accessed by this input builder should be flushed
- * from the cache at the time it is retrieved.
- */
- final bool flushOnAccess;
-
- /**
- * Initialize a newly created task input that computes the input by accessing
- * the given [result] associated with the given [target].
- */
- SimpleTaskInput(this.target, this.result, {this.flushOnAccess: false});
-
- /**
- * Initialize a newly created task input that computes the input by accessing
- * the given [result] associated with the given [target].
- */
- SimpleTaskInput._unflushable(this.target, this.result)
- : flushOnAccess = false;
-
- @override
- TaskInputBuilder<V> createBuilder() => new SimpleTaskInputBuilder<V>(this);
-}
-
-/**
- * A [TaskInputBuilder] used to build an input based on a [SimpleTaskInput].
- */
-class SimpleTaskInputBuilder<V> implements TaskInputBuilder<V> {
- /**
- * The state value indicating that the builder is positioned before the single
- * result.
- */
- static const _BEFORE = -1;
-
- /**
- * The state value indicating that the builder is positioned at the single
- * result.
- */
- static const _AT = 0;
-
- /**
- * The state value indicating that the builder is positioned after the single
- * result.
- */
- static const _AFTER = 1;
-
- /**
- * The input being built.
- */
- final SimpleTaskInput<V> input;
-
- /**
- * The value of the input being built. `null` if the value hasn't been set
- * yet, or if no result is available ([currentValueNotAvailable] was called).
- */
- V _resultValue = null;
-
- /**
- * The state of the builder.
- */
- int _state = _BEFORE;
-
- /**
- * A flag indicating whether the result value was explicitly set.
- */
- bool _resultSet = false;
-
- /**
- * Initialize a newly created task input builder that computes the result
- * specified by the given [input].
- */
- SimpleTaskInputBuilder(this.input);
-
- @override
- ResultDescriptor get currentResult => _state == _AT ? input.result : null;
-
- @override
- AnalysisTarget get currentTarget => _state == _AT ? input.target : null;
-
- @override
- void set currentValue(Object value) {
- if (_state != _AT) {
- throw new StateError(
- 'Cannot set the result value when there is no current result');
- }
- if (value is! V) {
- throw new StateError(
- 'Cannot build $input: computed ${value.runtimeType}, needed $V');
- }
- _resultValue = value as V;
- _resultSet = true;
- }
-
- @override
- bool get flushOnAccess => input.flushOnAccess;
-
- @override
- V get inputValue {
- if (_state != _AFTER) {
- throw new StateError('Result value has not been created');
- }
- return _resultValue;
- }
-
- @override
- void currentValueNotAvailable() {
- if (_state != _AT) {
- throw new StateError(
- 'Cannot set the result value when there is no current result');
- }
- _resultValue = null;
- _resultSet = true;
- }
-
- @override
- bool moveNext() {
- if (_state == _BEFORE) {
- _state = _AT;
- return true;
- } else {
- if (!_resultSet) {
- throw new StateError(
- 'The value of the current result must be set before moving to the next result.');
- }
- _state = _AFTER;
- return false;
- }
- }
-}
-
-abstract class TaskInputImpl<V> implements TaskInput<V> {
- @override
- ListTaskInput<E> mappedToList<E>(List<E> mapper(V value)) {
- return new ObjectToListTaskInput(
- this, (Object element) => mapper(element as V));
- }
-}
-
-/**
- * A [TaskInputBuilder] used to build an input based on one or more other task
- * inputs. The task inputs to be built are specified by a table mapping the name
- * of the input to the task used to access the input's value.
- */
-class TopLevelTaskInputBuilder
- implements TaskInputBuilder<Map<String, Object>> {
- /**
- * The descriptors describing the inputs to be built.
- */
- final Map<String, TaskInput> inputDescriptors;
-
- /**
- * The names of the inputs. There are the keys from the [inputDescriptors] in
- * an indexable form.
- */
- List<String> inputNames;
-
- /**
- * The index of the input name associated with the current result and target.
- */
- int nameIndex = -1;
-
- /**
- * The builder used to build the current result.
- */
- TaskInputBuilder currentBuilder;
-
- /**
- * The inputs that are being or have been built. The map will be incomplete
- * unless the method [moveNext] returns `false`.
- */
- final Map<String, Object> inputs = new HashMap<String, Object>();
-
- /**
- * Initialize a newly created task input builder to build the inputs described
- * by the given [inputDescriptors].
- */
- TopLevelTaskInputBuilder(this.inputDescriptors) {
- inputNames = inputDescriptors.keys.toList();
- }
-
- @override
- ResultDescriptor get currentResult {
- if (currentBuilder == null) {
- return null;
- }
- return currentBuilder.currentResult;
- }
-
- @override
- AnalysisTarget get currentTarget {
- if (currentBuilder == null) {
- return null;
- }
- return currentBuilder.currentTarget;
- }
-
- @override
- void set currentValue(Object value) {
- if (currentBuilder == null) {
- throw new StateError(
- 'Cannot set the result value when there is no current result');
- }
- currentBuilder.currentValue = value;
- }
-
- @override
- bool get flushOnAccess => currentBuilder.flushOnAccess;
-
- @override
- Map<String, Object> get inputValue {
- if (nameIndex < inputNames.length) {
- throw new StateError('Result value has not been created');
- }
- return inputs;
- }
-
- /**
- * Assuming that there is a current input, return its name.
- */
- String get _currentName => inputNames[nameIndex];
-
- @override
- void currentValueNotAvailable() {
- if (currentBuilder == null) {
- throw new StateError(
- 'Cannot set the result value when there is no current result');
- }
- currentBuilder.currentValueNotAvailable();
- }
-
- @override
- bool moveNext() {
- if (nameIndex >= inputNames.length) {
- // We have already computed all of the results, so just return false.
- return false;
- }
- if (nameIndex < 0) {
- // This is the first time moveNext has been invoked, so we just determine
- // whether there are any results to be computed.
- nameIndex = 0;
- } else {
- if (currentBuilder.moveNext()) {
- // We are still working on building the value associated with the
- // current name.
- return true;
- }
- if (currentBuilder.inputValue != null) {
- inputs[_currentName] = currentBuilder.inputValue;
- }
- nameIndex++;
- }
- if (nameIndex >= inputNames.length) {
- // There is no next value, so we're done.
- return false;
- }
- currentBuilder = inputDescriptors[_currentName].createBuilder();
- while (!currentBuilder.moveNext()) {
- if (currentBuilder.inputValue != null) {
- inputs[_currentName] = currentBuilder.inputValue;
- }
- nameIndex++;
- if (nameIndex >= inputNames.length) {
- // There is no next value, so we're done.
- return false;
- }
- currentBuilder = inputDescriptors[_currentName].createBuilder();
- }
- return true;
- }
-}
-
-/**
- * An input to an [AnalysisTask] that is computed by the following steps. First
- * another (base) task input is used to compute a [List]-valued result. An input
- * generator function is then used to map each element of that list to a task
- * input. Finally, each of the task inputs are used to access analysis results,
- * and a collection of the analysis results is used as the input to the task.
- */
-abstract class _ListToCollectionTaskInput<B, E, C> extends TaskInputImpl<C> {
- /**
- * The accessor used to access the list of elements being mapped.
- */
- final TaskInput<List<B>> baseAccessor;
-
- /**
- * The function used to convert an element in the list returned by the
- * [baseAccessor] to a task input.
- */
- final GenerateTaskInputs<B, E> generateTaskInputs;
-
- /**
- * Initialize a result accessor to use the given [baseAccessor] to access a
- * list of values that can be passed to the given [generateTaskInputs] to
- * generate a list of task inputs that can be used to access the elements of
- * the input being accessed.
- */
- _ListToCollectionTaskInput(this.baseAccessor, this.generateTaskInputs);
-}
-
-/**
- * A [TaskInputBuilder] used to build an [_ListToCollectionTaskInput].
- */
-abstract class _ListToCollectionTaskInputBuilder<B, E, C>
- implements TaskInputBuilder<C> {
- /**
- * The input being built.
- */
- final _ListToCollectionTaskInput<B, E, C> input;
-
- /**
- * The builder used to build the current result.
- */
- TaskInputBuilder currentBuilder;
-
- /**
- * The list of values computed by the [input]'s base accessor.
- */
- List<B> _baseList = null;
-
- /**
- * The index in the [_baseList] of the value for which a value is currently
- * being built.
- */
- int _baseListIndex = -1;
-
- /**
- * The element of the [_baseList] for which a value is currently being built.
- */
- B _baseListElement;
-
- /**
- * Initialize a newly created task input builder that computes the result
- * specified by the given [input].
- */
- _ListToCollectionTaskInputBuilder(this.input);
-
- @override
- ResultDescriptor get currentResult {
- if (currentBuilder == null) {
- return null;
- }
- return currentBuilder.currentResult;
- }
-
- @override
- AnalysisTarget get currentTarget {
- if (currentBuilder == null) {
- return null;
- }
- return currentBuilder.currentTarget;
- }
-
- @override
- void set currentValue(Object value) {
- if (currentBuilder == null) {
- throw new StateError(
- 'Cannot set the result value when there is no current result');
- }
- currentBuilder.currentValue = value;
- }
-
- @override
- bool get flushOnAccess => currentBuilder.flushOnAccess;
-
- @override
- C get inputValue {
- if (currentBuilder != null || _resultValue == null) {
- throw new StateError('Result value has not been created');
- }
- return _resultValue;
- }
-
- /**
- * The list of values being built.
- */
- C get _resultValue;
-
- @override
- void currentValueNotAvailable() {
- if (currentBuilder == null) {
- throw new StateError(
- 'Cannot set the result value when there is no current result');
- }
- currentBuilder.currentValueNotAvailable();
- }
-
- @override
- bool moveNext() {
- if (currentBuilder == null) {
- if (_resultValue == null) {
- // This is the first time moveNext has been invoked, so start by
- // computing the list of values from which the results will be derived.
- currentBuilder = input.baseAccessor.createBuilder();
- return currentBuilder.moveNext();
- } else {
- // We have already computed all of the results, so just return false.
- return false;
- }
- }
- if (currentBuilder.moveNext()) {
- return true;
- }
- if (_resultValue == null) {
- // We have finished computing the list of values from which the results
- // will be derived.
- _baseList = currentBuilder.inputValue as List<B>;
- if (_baseList == null) {
- // No base list could be computed due to a circular dependency. Use an
- // empty list so that no further results will be computed.
- _baseList = [];
- }
- _baseListIndex = 0;
- _initResultValue();
- } else {
- // We have finished computing one of the elements in the result list.
- if (currentBuilder.inputValue != null) {
- _addResultElement(_baseListElement, currentBuilder.inputValue as E);
- }
- _baseListIndex++;
- }
- if (_baseListIndex >= _baseList.length) {
- currentBuilder = null;
- return false;
- }
- _baseListElement = _baseList[_baseListIndex];
- currentBuilder = input.generateTaskInputs(_baseListElement).createBuilder();
- return currentBuilder.moveNext();
- }
-
- void _addResultElement(B baseElement, E resultElement);
- void _initResultValue();
-}
diff --git a/pkg/analyzer/lib/src/task/manager.dart b/pkg/analyzer/lib/src/task/manager.dart
deleted file mode 100644
index 009afaf..0000000
--- a/pkg/analyzer/lib/src/task/manager.dart
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright (c) 2015, 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:collection';
-
-import 'package:analyzer/exception/exception.dart';
-import 'package:analyzer/src/task/api/model.dart';
-
-/**
- * An object that manages the information about the tasks that have been
- * defined.
- */
-class TaskManager {
- /**
- * A table mapping [ResultDescriptor]s to a list of [TaskDescriptor]s
- * for the tasks that can be used to compute the result.
- */
- Map<ResultDescriptor, List<TaskDescriptor>> taskMap =
- new HashMap<ResultDescriptor, List<TaskDescriptor>>();
-
- /**
- * A list of the results that are to be computed for all sources within an
- * analysis root.
- */
- Set<ResultDescriptor> generalResults = new Set<ResultDescriptor>();
-
- /**
- * A list of the results that are to be computed for priority sources.
- */
- Set<ResultDescriptor> priorityResults = new Set<ResultDescriptor>();
-
- /**
- * Add the given [result] to the list of results that are to be computed for
- * all sources within an analysis root.
- */
- void addGeneralResult(ResultDescriptor result) {
- generalResults.add(result);
- }
-
- /**
- * Add the given [result] to the list of results that are to be computed for
- * priority sources.
- */
- void addPriorityResult(ResultDescriptor result) {
- priorityResults.add(result);
- }
-
- /**
- * Add the given [descriptor] to the list of analysis task descriptors that
- * can be used to compute analysis results.
- */
- void addTaskDescriptor(TaskDescriptor descriptor) {
- descriptor.results.forEach((ResultDescriptor result) {
- //
- // Add the result to the task map.
- //
- List<TaskDescriptor> descriptors = taskMap[result];
- if (descriptors == null) {
- descriptors = <TaskDescriptor>[];
- taskMap[result] = descriptors;
- }
- descriptors.add(descriptor);
- });
- }
-
- /**
- * Add the task descriptors in the given list of [descriptors] to the list of
- * analysis task descriptors that can be used to compute analysis results.
- */
- void addTaskDescriptors(List<TaskDescriptor> descriptors) {
- descriptors.forEach(addTaskDescriptor);
- }
-
- /**
- * Find a task that will compute the given [result] for the given [target].
- */
- TaskDescriptor findTask(AnalysisTarget target, ResultDescriptor result) {
- List<TaskDescriptor> descriptors = taskMap[result];
- if (descriptors == null) {
- throw new AnalysisException(
- 'No tasks registered to compute $result for $target');
- }
- return _findBestTask(descriptors, target);
- }
-
- /**
- * Remove the given [result] from the list of results that are to be computed
- * for all sources within an analysis root.
- */
- void removeGeneralResult(ResultDescriptor result) {
- generalResults.remove(result);
- }
-
- /**
- * Remove the given [result] from the list of results that are to be computed
- * for priority sources.
- */
- void removePriorityResult(ResultDescriptor result) {
- priorityResults.remove(result);
- }
-
- /**
- * Given a list of task [descriptors] that can be used to compute some
- * unspecified result for the given [target], return the descriptor that
- * should be used to compute the result.
- */
- TaskDescriptor _findBestTask(
- List<TaskDescriptor> descriptors, AnalysisTarget target) {
- TaskDescriptor best = null;
- for (TaskDescriptor descriptor in descriptors) {
- TaskSuitability suitability = descriptor.suitabilityFor(target);
- if (suitability == TaskSuitability.HIGHEST) {
- return descriptor;
- } else if (best == null && suitability == TaskSuitability.LOWEST) {
- best = descriptor;
- }
- }
- return best;
- }
-}
diff --git a/pkg/analyzer/lib/src/task/model.dart b/pkg/analyzer/lib/src/task/model.dart
deleted file mode 100644
index ec62312..0000000
--- a/pkg/analyzer/lib/src/task/model.dart
+++ /dev/null
@@ -1,166 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/task/api/model.dart';
-import 'package:analyzer/src/task/inputs.dart';
-
-/**
- * The default [ResultCachingPolicy], results are never flushed.
- */
-const ResultCachingPolicy DEFAULT_CACHING_POLICY =
- const SimpleResultCachingPolicy(-1, -1);
-
-/**
- * A concrete implementation of a [ListResultDescriptor].
- */
-class ListResultDescriptorImpl<E> extends ResultDescriptorImpl<List<E>>
- implements ListResultDescriptor<E> {
- /**
- * Initialize a newly created analysis result to have the given [name] and
- * [defaultValue]. If a [cachingPolicy] is provided, it will control how long
- * values associated with this result will remain in the cache.
- */
- ListResultDescriptorImpl(String name, List<E> defaultValue,
- {ResultCachingPolicy cachingPolicy: DEFAULT_CACHING_POLICY})
- : super(name, defaultValue, cachingPolicy: cachingPolicy);
-
- @override
- ListTaskInput<E> of(AnalysisTarget target, {bool flushOnAccess: false}) {
- if (flushOnAccess) {
- throw new StateError('Cannot flush a list of values');
- }
- return new ListTaskInputImpl<E>(target, this);
- }
-}
-
-/**
- * A concrete implementation of a [ResultDescriptor].
- */
-class ResultDescriptorImpl<V> implements ResultDescriptor<V> {
- static int _NEXT_HASH = 0;
-
- @override
- final hashCode = _NEXT_HASH++;
-
- /**
- * The name of the result, used for debugging.
- */
- final String name;
-
- /**
- * Return the default value for results described by this descriptor.
- */
- final V defaultValue;
-
- /**
- * The caching policy for results described by this descriptor.
- */
- final ResultCachingPolicy cachingPolicy;
-
- /**
- * Initialize a newly created analysis result to have the given [name] and
- * [defaultValue]. If a [cachingPolicy] is provided, it will control how long
- * values associated with this result will remain in the cache.
- */
- ResultDescriptorImpl(this.name, this.defaultValue,
- {this.cachingPolicy: DEFAULT_CACHING_POLICY});
-
- @override
- bool operator ==(Object other) {
- return other is ResultDescriptorImpl && other.hashCode == hashCode;
- }
-
- @override
- TaskInput<V> of(AnalysisTarget target, {bool flushOnAccess: false}) =>
- new SimpleTaskInput<V>(target, this, flushOnAccess: flushOnAccess);
-
- @override
- String toString() => name;
-}
-
-/**
- * A simple [ResultCachingPolicy] implementation that consider all the objects
- * to be of the size `1`.
- */
-class SimpleResultCachingPolicy implements ResultCachingPolicy {
- @override
- final int maxActiveSize;
-
- @override
- final int maxIdleSize;
-
- const SimpleResultCachingPolicy(this.maxActiveSize, this.maxIdleSize);
-
- @override
- int measure(Object object) => 1;
-}
-
-/**
- * A concrete implementation of a [TaskDescriptor].
- */
-class TaskDescriptorImpl implements TaskDescriptor {
- /**
- * The name of the described task, used for debugging.
- */
- final String name;
-
- /**
- * The function used to build the analysis task.
- */
- final BuildTask buildTask;
-
- /**
- * The function used to build the inputs to the task.
- */
- @override
- final CreateTaskInputs createTaskInputs;
-
- /**
- * A list of the analysis results that will be computed by the described task.
- */
- @override
- final List<ResultDescriptor> results;
-
- /**
- * The function used to determine whether the described task is suitable for
- * a given target.
- */
- final SuitabilityFor _suitabilityFor;
-
- /**
- * Initialize a newly created task descriptor to have the given [name] and to
- * describe a task that takes the inputs built using the given [inputBuilder],
- * and produces the given [results]. The [buildTask] function will be used to
- * create the instance of [AnalysisTask] being described. If provided, the
- * [isAppropriateFor] function will be used to determine whether the task can
- * be used on a specific target.
- */
- TaskDescriptorImpl(
- this.name, this.buildTask, this.createTaskInputs, this.results,
- {SuitabilityFor suitabilityFor})
- : _suitabilityFor = suitabilityFor ?? _defaultSuitability;
-
- @override
- AnalysisTask createTask(AnalysisContext context, AnalysisTarget target,
- Map<String, dynamic> inputs) {
- AnalysisTask task = buildTask(context, target);
- task.inputs = inputs;
- return task;
- }
-
- @override
- TaskSuitability suitabilityFor(AnalysisTarget target) =>
- _suitabilityFor(target);
-
- @override
- String toString() => name;
-
- /**
- * The function that will be used to determine the suitability of a task if no
- * other function is provided.
- */
- static TaskSuitability _defaultSuitability(AnalysisTarget target) =>
- TaskSuitability.LOWEST;
-}
diff --git a/pkg/analyzer/lib/src/task/strong/checker.dart b/pkg/analyzer/lib/src/task/strong/checker.dart
index bd86f884..634baf4 100644
--- a/pkg/analyzer/lib/src/task/strong/checker.dart
+++ b/pkg/analyzer/lib/src/task/strong/checker.dart
@@ -8,7 +8,6 @@
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/ast/token.dart' show TokenType;
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
@@ -582,7 +581,7 @@
@override
void visitRedirectingConstructorInvocation(
RedirectingConstructorInvocation node) {
- var type = resolutionMap.staticElementForConstructorReference(node)?.type;
+ var type = node.staticElement?.type;
// TODO(leafp): There's a TODO in visitRedirectingConstructorInvocation
// in the element_resolver to handle the case that the element is null
// and emit an error. In the meantime, just be defensive here.
@@ -657,7 +656,7 @@
void visitSuperConstructorInvocation(SuperConstructorInvocation node) {
var element = node.staticElement;
if (element != null) {
- var type = resolutionMap.staticElementForConstructorReference(node).type;
+ var type = node.staticElement.type;
checkArgumentList(node.argumentList, type);
}
node.visitChildren(this);
@@ -674,9 +673,8 @@
@override
Object visitVariableDeclaration(VariableDeclaration node) {
- VariableElement variableElement = node == null
- ? null
- : resolutionMap.elementDeclaredByVariableDeclaration(node);
+ VariableElement variableElement =
+ node == null ? null : node.declaredElement;
AstNode parent = node.parent;
if (variableElement != null &&
parent is VariableDeclarationList &&
@@ -720,7 +718,7 @@
void _checkCompoundAssignment(AssignmentExpression expr) {
var op = expr.operator.type;
assert(op.isAssignmentOperator && op != TokenType.EQ);
- var methodElement = resolutionMap.staticElementForMethodReference(expr);
+ var methodElement = expr.staticElement;
if (methodElement == null) {
// Dynamic invocation.
_recordDynamicInvoke(expr, expr.leftHandSide);
@@ -1290,9 +1288,7 @@
? node.firstTokenAfterCommentAndMetadata.offset
: node.offset;
int length = node.end - begin;
- var source = resolutionMap
- .elementDeclaredByCompilationUnit(node.root as CompilationUnit)
- .source;
+ var source = (node.root as CompilationUnit).declaredElement.source;
var error =
new AnalysisError(source, begin, length, errorCode, arguments);
reporter.onError(error);
@@ -1396,8 +1392,7 @@
_OverrideChecker(CodeChecker checker) : rules = checker.rules;
void check(Declaration node) {
- var element =
- resolutionMap.elementDeclaredByDeclaration(node) as ClassElement;
+ var element = node.declaredElement as ClassElement;
if (element.type.isObject) {
return;
}
diff --git a/pkg/analyzer/lib/src/task/yaml.dart b/pkg/analyzer/lib/src/task/yaml.dart
deleted file mode 100644
index 56ea51c..0000000
--- a/pkg/analyzer/lib/src/task/yaml.dart
+++ /dev/null
@@ -1,153 +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:analyzer/error/error.dart';
-import 'package:analyzer/exception/exception.dart';
-import 'package:analyzer/src/context/cache.dart';
-import 'package:analyzer/src/dart/scanner/scanner.dart';
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/task/api/general.dart';
-import 'package:analyzer/src/task/api/model.dart';
-import 'package:analyzer/src/task/api/yaml.dart';
-import 'package:analyzer/src/task/general.dart';
-import 'package:source_span/source_span.dart';
-import 'package:yaml/yaml.dart';
-
-/**
- * A task that scans the content of a YAML file, producing a YAML document.
- */
-class ParseYamlTask extends SourceBasedAnalysisTask {
- /**
- * The name of the input whose value is the content of the file.
- */
- static const String CONTENT_INPUT_NAME = 'CONTENT_INPUT_NAME';
-
- /**
- * The task descriptor describing this kind of task.
- */
- static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
- 'ParseYamlTask',
- createTask,
- buildInputs,
- <ResultDescriptor>[YAML_DOCUMENT, YAML_ERRORS, LINE_INFO],
- suitabilityFor: suitabilityFor);
-
- /**
- * Initialize a newly created task to access the content of the source
- * associated with the given [target] in the given [context].
- */
- ParseYamlTask(InternalAnalysisContext context, AnalysisTarget target)
- : super(context, target);
-
- @override
- TaskDescriptor get descriptor => DESCRIPTOR;
-
- @override
- void internalPerform() {
- Source source = target.source;
- String uri = source.uri.toString();
- String content = getRequiredInput(CONTENT_INPUT_NAME);
-
- if (context.getModificationStamp(source) < 0) {
- String message = 'Content could not be read';
- if (context is InternalAnalysisContext) {
- CacheEntry entry =
- (context as InternalAnalysisContext).getCacheEntry(target);
- CaughtException exception = entry.exception;
- if (exception != null) {
- message = exception.toString();
- }
- }
- //
- // Record outputs.
- //
- outputs[YAML_DOCUMENT] = loadYamlDocument('', sourceUrl: uri);
- outputs[YAML_ERRORS] = <AnalysisError>[
- new AnalysisError(
- source, 0, 0, ScannerErrorCode.UNABLE_GET_CONTENT, [message])
- ];
- outputs[LINE_INFO] = new LineInfo(<int>[0]);
- } else {
- YamlDocument document;
- List<AnalysisError> errors = <AnalysisError>[];
- try {
- document = loadYamlDocument(content, sourceUrl: uri);
- } on YamlException catch (exception) {
- SourceSpan span = exception.span;
- int offset = span.start.offset;
- int length = span.end.offset - offset;
- errors.add(new AnalysisError(source, offset, length,
- YamlErrorCode.PARSE_ERROR, [exception.message]));
- } catch (exception, stackTrace) {
- throw new AnalysisException('Error while parsing ${source.fullName}',
- new CaughtException(exception, stackTrace));
- }
- //
- // Record outputs.
- //
- outputs[YAML_DOCUMENT] = document;
- outputs[YAML_ERRORS] = errors;
- outputs[LINE_INFO] = new LineInfo.fromContent(content);
- }
- }
-
- /**
- * Return a map from the names of the inputs of this kind of task to the task
- * input descriptors describing those inputs for a task with the given
- * [source].
- */
- static Map<String, TaskInput> buildInputs(AnalysisTarget source) {
- return <String, TaskInput>{CONTENT_INPUT_NAME: CONTENT.of(source)};
- }
-
- /**
- * Create a [ParseYamlTask] based on the given [target] in the given [context].
- */
- static ParseYamlTask createTask(
- AnalysisContext context, AnalysisTarget target) {
- return new ParseYamlTask(context, target);
- }
-
- /**
- * Return an indication of how suitable this task is for the given [target].
- */
- static TaskSuitability suitabilityFor(AnalysisTarget target) {
- if (target is Source && target.shortName.endsWith('.yaml')) {
- return TaskSuitability.HIGHEST;
- }
- return TaskSuitability.NONE;
- }
-}
-
-/**
- * The error codes used for errors in YAML files.
- */
-class YamlErrorCode extends ErrorCode {
- // TODO(brianwilkerson) Move this class to error.dart.
-
- /**
- * An error code indicating that there is a syntactic error in the file.
- *
- * Parameters:
- * 0: the error message from the parse error
- */
- static const YamlErrorCode PARSE_ERROR =
- const YamlErrorCode('PARSE_ERROR', '{0}');
-
- /**
- * Initialize a newly created error code to have the given [name]. The message
- * associated with the error will be created from the given [message]
- * template. The correction associated with the error will be created from the
- * given [correction] template.
- */
- const YamlErrorCode(String name, String message, {String correction})
- : super.temporary(name, message, correction: correction);
-
- @override
- ErrorSeverity get errorSeverity => ErrorSeverity.ERROR;
-
- @override
- ErrorType get type => ErrorType.COMPILE_TIME_ERROR;
-}
diff --git a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
index ed79e1a..382edb0 100644
--- a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
+++ b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
@@ -34,7 +34,7 @@
Future<R> then<R>(FutureOr<R> onValue(T value)) => null;
Future<T> whenComplete(action());
-
+
static Future<List<T>> wait<T>(Iterable<Future<T>> futures) => null;
}
@@ -43,10 +43,12 @@
abstract class Completer<T> {
factory Completer() => null;
factory Completer.sync() => null;
+
Future<T> get future;
+ bool get isCompleted;
+
void complete([value]);
void completeError(Object error, [StackTrace stackTrace]);
- bool get isCompleted;
}
abstract class Timer {
@@ -59,27 +61,31 @@
'$sdkRoot/lib/async/stream.dart',
r'''
part of dart.async;
+
abstract class Stream<T> {
+ Stream();
+ factory Stream.fromIterable(Iterable<T> data) => null;
+
Future<T> get first;
+
StreamSubscription<T> listen(void onData(T event),
{ Function onError,
void onDone(),
bool cancelOnError});
- Stream();
- factory Stream.fromIterable(Iterable<T> data) => null;
}
abstract class StreamIterator<T> {}
abstract class StreamSubscription<T> {
+ bool get isPaused;
+
+ Future<E> asFuture<E>([E futureValue]);
Future cancel();
void onData(void handleData(T data));
void onError(Function handleError);
void onDone(void handleDone());
void pause([Future resumeSignal]);
void resume();
- bool get isPaused;
- Future<E> asFuture<E>([E futureValue]);
}
abstract class StreamTransformer<S, T> {}
@@ -106,15 +112,59 @@
'''
library dart.collection;
-abstract class HashMap<K, V> implements Map<K, V> {}
-abstract class LinkedHashMap<K, V> implements Map<K, V> {
- factory LinkedHashMap(
+abstract class HashMap<K, V> implements Map<K, V> {
+ external factory HashMap(
{bool equals(K key1, K key2),
int hashCode(K key),
- bool isValidKey(potentialKey)}) => null;
+ bool isValidKey(potentialKey)});
+
+ external factory HashMap.identity();
+
+ factory HashMap.from(Map other) => null;
+
+ factory HashMap.of(Map<K, V> other) => null;
+
+ factory HashMap.fromIterable(Iterable iterable,
+ {K key(element), V value(element)}) => null;
+
+ factory HashMap.fromIterables(Iterable<K> keys, Iterable<V> values) => null;
+
+ factory HashMap.fromEntries(Iterable<MapEntry<K, V>> entries) => null;
}
-abstract class HashSet<E> implements Set<E> {}
-abstract class LinkedHashSet<E> implements Set<E> {}
+
+abstract class LinkedHashMap<K, V> implements Map<K, V> {
+ external factory LinkedHashMap(
+ {bool equals(K key1, K key2),
+ int hashCode(K key),
+ bool isValidKey(potentialKey)});
+
+ external factory LinkedHashMap.identity();
+
+ factory LinkedHashMap.from(Map other) => null;
+
+ factory LinkedHashMap.of(Map<K, V> other) => null;
+
+ factory LinkedHashMap.fromIterable(Iterable iterable,
+ {K key(element), V value(element)}) => null;
+
+ factory LinkedHashMap.fromIterables(Iterable<K> keys, Iterable<V> values)
+ => null;
+
+ factory LinkedHashMap.fromEntries(Iterable<MapEntry<K, V>> entries) => null;
+}
+
+abstract class LinkedHashSet<E> implements Set<E> {
+ external factory LinkedHashSet(
+ {bool equals(E e1, E e2),
+ int hashCode(E e),
+ bool isValidKey(potentialKey)});
+
+ external factory LinkedHashSet.identity();
+
+ factory LinkedHashSet.from(Iterable elements) => null;
+
+ factory LinkedHashSet.of(Iterable<E> elements) => null;
+}
''',
)
]);
@@ -130,6 +180,7 @@
import 'dart:async';
abstract class Converter<S, T> implements StreamTransformer {}
+
class JsonDecoder extends Converter<String, Object> {}
''',
)
@@ -161,6 +212,7 @@
abstract class bool extends Object {
external const factory bool.fromEnvironment(String name,
{bool defaultValue: false});
+
bool operator &(bool other);
bool operator |(bool other);
bool operator ^(bool other);
@@ -197,6 +249,8 @@
double operator -(num other);
double operator -();
double operator /(num other);
+ int operator ~/(num other);
+
double abs();
int ceil();
double ceilToDouble();
@@ -207,12 +261,18 @@
double roundToDouble();
int truncate();
double truncateToDouble();
- int operator ~/(num other);
+
external static double parse(String source, [double onError(String source)]);
}
class Duration implements Comparable<Duration> {}
+class Error {
+ Error();
+ static String safeToString(Object object) => '';
+ external StackTrace get stackTrace;
+}
+
class Exception {
factory Exception([var message]) => null;
}
@@ -230,14 +290,12 @@
int operator <<(int shiftAmount);
int operator >>(int shiftAmount);
int operator ^(int other);
- String toString();
-
int operator |(int other);
-
int operator ~();
- int gcd(int other);
int abs();
+ int gcd(int other);
+ String toString();
external static int parse(String source,
{int radix, int onError(String source)});
@@ -248,11 +306,16 @@
abstract class Iterable<E> {
E get first;
bool get isEmpty;
+ bool get isNotEmpty;
Iterator<E> get iterator;
int get length;
+ bool contains(Object element);
+
Iterable<T> expand<T>(Iterable<T> f(E element));
+ E firstWhere(bool test(E element), { E orElse()});
+
R fold<R>(R initialValue, R combine(R previousValue, E element)) => null;
void forEach(void f(E element));
@@ -282,19 +345,26 @@
void add(E value) {}
void addAll(Iterable<E> iterable) {}
void clear() {}
+ int indexOf(Object element);
noSuchMethod(Invocation invocation) => null;
}
class Map<K, V> {
factory Map() => null;
+
factory Map.fromIterable(Iterable iterable,
{K key(element), V value(element)}) => null;
+
Iterable<K> get keys => null;
+ bool get isEmpty;
+ bool get isNotEmpty;
int get length => 0;
Iterable<V> get values => null;
+
V operator [](K key) => null;
void operator []=(K key, V value) {}
+
Map<RK, RV> cast<RK, RV>() => null;
bool containsKey(Object key) => false;
}
@@ -318,22 +388,26 @@
bool operator >=(num other);
int operator >>(int other);
int operator ^(int other);
+ int operator |(int other);
+ int operator ~();
+ int operator ~/(num other);
+
num abs();
int round();
double toDouble();
int toInt();
- int operator |(int other);
- int operator ~();
- int operator ~/(num other);
}
class Object {
const Object();
+
int get hashCode => 0;
Type get runtimeType => null;
+
bool operator ==(other) => identical(this, other);
- dynamic noSuchMethod(Invocation invocation) => null;
+
String toString() => 'a string';
+ dynamic noSuchMethod(Invocation invocation) => null;
}
abstract class Pattern {}
@@ -347,6 +421,7 @@
factory Set.identity() => null;
factory Set.from(Iterable elements) => null;
factory Set.of(Iterable<E> elements) => null;
+
Set<R> cast<R>();
}
@@ -355,14 +430,18 @@
abstract class String implements Comparable<String>, Pattern {
external factory String.fromCharCodes(Iterable<int> charCodes,
[int start = 0, int end]);
+
List<int> get codeUnits;
int indexOf(Pattern pattern, [int start]);
bool get isEmpty => false;
bool get isNotEmpty => false;
int get length => 0;
+
String operator +(String other) => null;
bool operator ==(Object other);
+
int codeUnitAt(int index);
+ bool contains(String other, [int startIndex = 0]);
String substring(int len) => null;
String toLowerCase();
String toUpperCase();
@@ -493,6 +572,57 @@
],
);
+final MockSdkLibrary _LIB_IO = MockSdkLibrary(
+ [
+ MockSdkLibraryUnit(
+ 'dart:io',
+ '$sdkRoot/lib/io/io.dart',
+ '''
+library dart.io;
+
+abstract class Directory implements FileSystemEntity {
+ factory Directory(String path) => null;
+
+ Future<bool> exists() async => true;
+ bool existsSync() => true;
+
+ Future<FileStat> stat() async => null;
+ FileStat statSync() => null;
+}
+
+abstract class File implements FileSystemEntity {
+ factory File(String path) => null;
+
+ Future<DateTime> lastModified();
+ DateTime lastModifiedSync();
+
+ Future<bool> exists() async => true;
+ bool existsSync() => true;
+
+ Future<FileStat> stat() async => null;
+ FileStat statSync() => null;
+}
+
+abstract class FileSystemEntity {
+ static Future<bool> isDirectory(String path) => true;
+ static bool isDirectorySync(String path) => true;
+
+ static Future<bool> isFile(String path) => true;
+ static bool isFileSync(String path) => true;
+
+ static Future<bool> isLink(String path) => true;
+ static bool isLinkSync(String path) => true;
+
+ static Future<FileSystemEntityType> type(
+ String path, {bool followLinks: true}) async => null;
+ static FileSystemEntityType typeSync(
+ String path, {bool followLinks: true}) => null;
+}
+''',
+ )
+ ],
+);
+
final MockSdkLibrary _LIB_MATH = MockSdkLibrary(
[
MockSdkLibraryUnit(
@@ -512,11 +642,13 @@
external double sin(num radians);
external double sqrt(num radians);
external double tan(num radians);
+
class Random {
bool nextBool() => true;
double nextDouble() => 2.0;
int nextInt() => 1;
}
+
class Point<T extends num> {}
''',
)
@@ -530,6 +662,7 @@
_LIB_COLLECTION,
_LIB_CONVERT,
_LIB_FOREIGN_HELPER,
+ _LIB_IO,
_LIB_MATH,
_LIB_HTML_DART2JS,
_LIB_HTML_DARTIUM,
@@ -544,6 +677,7 @@
'core': 'const LibraryInfo("core/core.dart")',
'html': 'const LibraryInfo("html/dartium/html_dartium.dart", '
'dart2jsPath: "html/dart2js/html_dart2js.dart")',
+ 'io': 'const LibraryInfo("io/io.dart")',
'math': 'const LibraryInfo("math/math.dart")',
'_foreign_helper':
'const LibraryInfo("_internal/js_runtime/lib/foreign_helper.dart")',
diff --git a/pkg/analyzer/lib/src/test_utilities/mock_sdk_elements.dart b/pkg/analyzer/lib/src/test_utilities/mock_sdk_elements.dart
new file mode 100644
index 0000000..856b19b
--- /dev/null
+++ b/pkg/analyzer/lib/src/test_utilities/mock_sdk_elements.dart
@@ -0,0 +1,1070 @@
+// Copyright (c) 2019, 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/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/generated/engine.dart' as engine;
+import 'package:analyzer/src/generated/testing/element_factory.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:meta/meta.dart';
+
+class MockSdkElements {
+ final LibraryElement coreLibrary;
+ final LibraryElement asyncLibrary;
+
+ factory MockSdkElements(
+ engine.AnalysisContext analysisContext,
+ NullabilitySuffix nullabilitySuffix,
+ ) {
+ var builder = _MockSdkElementsBuilder(analysisContext, nullabilitySuffix);
+ var coreLibrary = builder._buildCore();
+ var asyncLibrary = builder._buildAsync();
+ return MockSdkElements._(coreLibrary, asyncLibrary);
+ }
+
+ MockSdkElements._(this.coreLibrary, this.asyncLibrary);
+}
+
+class _MockSdkElementsBuilder {
+ final engine.AnalysisContext analysisContext;
+ final NullabilitySuffix nullabilitySuffix;
+
+ ClassElementImpl _boolElement;
+ ClassElementImpl _completerElement;
+ ClassElementImpl _deprecatedElement;
+ ClassElementImpl _doubleElement;
+ ClassElementImpl _functionElement;
+ ClassElementImpl _futureElement;
+ ClassElementImpl _futureOrElement;
+ ClassElementImpl _intElement;
+ ClassElementImpl _iterableElement;
+ ClassElementImpl _iteratorElement;
+ ClassElementImpl _listElement;
+ ClassElementImpl _mapElement;
+ ClassElementImpl _nullElement;
+ ClassElementImpl _numElement;
+ ClassElementImpl _objectElement;
+ ClassElementImpl _overrideElement;
+ ClassElementImpl _proxyElement;
+ ClassElementImpl _setElement;
+ ClassElementImpl _stackTraceElement;
+ ClassElementImpl _streamElement;
+ ClassElementImpl _streamSubscriptionElement;
+ ClassElementImpl _stringElement;
+ ClassElementImpl _symbolElement;
+ ClassElementImpl _typeElement;
+
+ InterfaceType _boolType;
+ InterfaceType _doubleType;
+ InterfaceType _intType;
+ InterfaceType _numType;
+ InterfaceType _objectType;
+ InterfaceType _stringType;
+ InterfaceType _typeType;
+
+ _MockSdkElementsBuilder(this.analysisContext, this.nullabilitySuffix);
+
+ ClassElementImpl get boolElement {
+ if (_boolElement != null) return _boolElement;
+
+ _boolElement = _class(name: 'bool');
+ _boolElement.supertype = objectType;
+
+ _boolElement.constructors = [
+ _constructor(
+ name: 'fromEnvironment',
+ isConst: true,
+ isFactory: true,
+ parameters: [
+ _requiredParameter('name', stringType),
+ _namedParameter('defaultValue', boolType),
+ ],
+ ),
+ ];
+
+ return _boolElement;
+ }
+
+ InterfaceType get boolType {
+ return _boolType ??= _interfaceType(boolElement);
+ }
+
+ ClassElementImpl get completerElement {
+ if (_completerElement != null) return _completerElement;
+
+ var tElement = _typeParameter('T');
+ _completerElement = _class(
+ name: 'Completer',
+ isAbstract: true,
+ typeParameters: [tElement],
+ );
+ _completerElement.supertype = objectType;
+
+ return _completerElement;
+ }
+
+ ClassElementImpl get deprecatedElement {
+ if (_deprecatedElement != null) return _deprecatedElement;
+
+ _deprecatedElement = _class(name: 'Deprecated');
+ _deprecatedElement.supertype = objectType;
+
+ _deprecatedElement.fields = <FieldElement>[
+ _field('message', stringType, isFinal: true),
+ ];
+
+ _deprecatedElement.accessors =
+ _deprecatedElement.fields.map((f) => f.getter).toList();
+
+ _deprecatedElement.constructors = [
+ _constructor(
+ isConst: true,
+ parameters: [
+ _requiredParameter('message', stringType),
+ ],
+ ),
+ ];
+
+ return _deprecatedElement;
+ }
+
+ ClassElementImpl get doubleElement {
+ if (_doubleElement != null) return _doubleElement;
+
+ _doubleElement = _class(name: 'double', isAbstract: true);
+ _doubleElement.supertype = numType;
+
+ FieldElement staticConstDoubleField(String name) {
+ return _field(name, doubleType, isStatic: true, isConst: true);
+ }
+
+ _doubleElement.fields = <FieldElement>[
+ staticConstDoubleField('nan'),
+ staticConstDoubleField('infinity'),
+ staticConstDoubleField('negativeInfinity'),
+ staticConstDoubleField('minPositive'),
+ staticConstDoubleField('maxFinite'),
+ ];
+
+ _doubleElement.accessors =
+ _doubleElement.fields.map((field) => field.getter).toList();
+
+ _doubleElement.methods = [
+ _method('+', doubleType, parameters: [
+ _requiredParameter('other', numType),
+ ]),
+ _method('*', doubleType, parameters: [
+ _requiredParameter('other', numType),
+ ]),
+ _method('-', doubleType, parameters: [
+ _requiredParameter('other', numType),
+ ]),
+ _method('%', doubleType, parameters: [
+ _requiredParameter('other', numType),
+ ]),
+ _method('/', doubleType, parameters: [
+ _requiredParameter('other', numType),
+ ]),
+ _method('~/', intType, parameters: [
+ _requiredParameter('other', numType),
+ ]),
+ _method('-', doubleType, parameters: [
+ _requiredParameter('other', numType),
+ ]),
+ _method('abs', doubleType),
+ _method('ceil', doubleType),
+ _method('floor', doubleType),
+ _method('remainder', doubleType, parameters: [
+ _requiredParameter('other', numType),
+ ]),
+ _method('round', doubleType),
+ _method('toString', stringType),
+ _method('truncate', doubleType),
+ ];
+
+ return _doubleElement;
+ }
+
+ InterfaceType get doubleType {
+ return _doubleType ??= _interfaceType(doubleElement);
+ }
+
+ DynamicTypeImpl get dynamicType => DynamicTypeImpl.instance;
+
+ ClassElementImpl get functionElement {
+ if (_functionElement != null) return _functionElement;
+
+ _functionElement = _class(name: 'Function', isAbstract: true);
+ _functionElement.supertype = objectType;
+
+ return _functionElement;
+ }
+
+ InterfaceType get functionType {
+ return _interfaceType(functionElement);
+ }
+
+ ClassElementImpl get futureElement {
+ if (_futureElement != null) return _futureElement;
+
+ var tElement = _typeParameter('T');
+ var tType = _typeParameterType(tElement);
+
+ _futureElement = _class(
+ name: 'Future',
+ isAbstract: true,
+ typeParameters: [tElement],
+ );
+ _futureElement.supertype = objectType;
+
+ // factory Future.value([FutureOr<T> value])
+ _futureElement.constructors = [
+ _constructor(
+ isFactory: true,
+ parameters: [
+ _positionalParameter('value', futureOrType(tType)),
+ ],
+ ),
+ ];
+
+ // Future<R> then<R>(FutureOr<R> onValue(T value), {Function onError})
+ var rElement = _typeParameter('R');
+ var rType = _typeParameterType(rElement);
+ _futureElement.methods = [
+ _method(
+ 'then',
+ futureType(rType),
+ parameters: [
+ _requiredParameter(
+ 'onValue',
+ _functionType(
+ returnType: futureOrType(rType),
+ parameters: [
+ _requiredParameter('value', tType),
+ ],
+ ),
+ ),
+ _positionalParameter('onError', functionType),
+ ],
+ ),
+ ];
+
+ return _futureElement;
+ }
+
+ ClassElementImpl get futureOrElement {
+ if (_futureOrElement != null) return _futureOrElement;
+
+ var tElement = _typeParameter('T');
+ _futureOrElement = _class(
+ name: 'FutureOr',
+ typeParameters: [tElement],
+ );
+ _futureOrElement.supertype = objectType;
+
+ return _futureOrElement;
+ }
+
+ ClassElementImpl get intElement {
+ if (_intElement != null) return _intElement;
+
+ _intElement = _class(name: 'int', isAbstract: true);
+ _intElement.supertype = numType;
+
+ _intElement.constructors = [
+ _constructor(
+ name: 'fromEnvironment',
+ isConst: true,
+ isFactory: true,
+ parameters: [
+ _requiredParameter('name', stringType),
+ _namedParameter('defaultValue', intType),
+ ],
+ ),
+ ];
+
+ _intElement.methods = [
+ _method('&', intType, parameters: [
+ _requiredParameter('other', intType),
+ ]),
+ _method('|', intType, parameters: [
+ _requiredParameter('other', intType),
+ ]),
+ _method('^', intType, parameters: [
+ _requiredParameter('other', intType),
+ ]),
+ _method('~', intType),
+ _method('<<', intType, parameters: [
+ _requiredParameter('shiftAmount', intType),
+ ]),
+ _method('>>', intType, parameters: [
+ _requiredParameter('shiftAmount', intType),
+ ]),
+ _method('-', intType),
+ _method('abs', intType),
+ _method('round', intType),
+ _method('floor', intType),
+ _method('ceil', intType),
+ _method('truncate', intType),
+ _method('toString', stringType),
+ ];
+
+ return _intElement;
+ }
+
+ InterfaceType get intType {
+ return _intType ??= _interfaceType(intElement);
+ }
+
+ ClassElementImpl get iterableElement {
+ if (_iterableElement != null) return _iterableElement;
+
+ var eElement = _typeParameter('E');
+ var eType = _typeParameterType(eElement);
+
+ _iterableElement = _class(
+ name: 'Iterable',
+ isAbstract: true,
+ typeParameters: [eElement],
+ );
+ _iterableElement.supertype = objectType;
+
+ _iterableElement.constructors = [
+ _constructor(isConst: true),
+ ];
+
+ _setAccessors(_iterableElement, [
+ _getter('iterator', iteratorType(eType)),
+ _getter('last', eType),
+ ]);
+
+ return _iterableElement;
+ }
+
+ ClassElementImpl get iteratorElement {
+ if (_iteratorElement != null) return _iteratorElement;
+
+ var eElement = _typeParameter('E');
+ var eType = _typeParameterType(eElement);
+
+ _iteratorElement = _class(
+ name: 'Iterator',
+ isAbstract: true,
+ typeParameters: [eElement],
+ );
+ _iteratorElement.supertype = objectType;
+
+ _setAccessors(_iterableElement, [
+ _getter('current', eType),
+ ]);
+
+ return _iteratorElement;
+ }
+
+ ClassElementImpl get listElement {
+ if (_listElement != null) return _listElement;
+
+ var eElement = _typeParameter('E');
+ var eType = _typeParameterType(eElement);
+
+ _listElement = _class(
+ name: 'List',
+ isAbstract: true,
+ typeParameters: [eElement],
+ );
+ _listElement.supertype = objectType;
+ _listElement.interfaces = [
+ iterableType(eType),
+ ];
+
+ _listElement.constructors = [
+ _constructor(isFactory: true, parameters: [
+ _positionalParameter('length', intType),
+ ]),
+ ];
+
+ _setAccessors(_listElement, [
+ _getter('length', intType),
+ ]);
+
+ _listElement.methods = [
+ _method('[]', eType, parameters: [
+ _requiredParameter('index', intType),
+ ]),
+ _method('[]=', voidType, parameters: [
+ _requiredParameter('index', intType),
+ _requiredParameter('value', eType),
+ ]),
+ _method('add', voidType, parameters: [
+ _requiredParameter('value', eType),
+ ]),
+ ];
+
+ return _listElement;
+ }
+
+ ClassElementImpl get mapElement {
+ if (_mapElement != null) return _mapElement;
+
+ var kElement = _typeParameter('K');
+ var vElement = _typeParameter('V');
+ var kType = _typeParameterType(kElement);
+ var vType = _typeParameterType(vElement);
+
+ _mapElement = _class(
+ name: 'Map',
+ isAbstract: true,
+ typeParameters: [kElement, vElement],
+ );
+ _mapElement.supertype = objectType;
+
+ _setAccessors(_mapElement, [
+ _getter('length', intType),
+ ]);
+
+ _mapElement.methods = [
+ _method('[]', vType, parameters: [
+ _requiredParameter('key', objectType),
+ ]),
+ _method('[]=', voidType, parameters: [
+ _requiredParameter('key', kType),
+ _requiredParameter('value', vType),
+ ]),
+ ];
+
+ return _mapElement;
+ }
+
+ ClassElementImpl get nullElement {
+ if (_nullElement != null) return _nullElement;
+
+ _nullElement = _class(name: 'Null');
+ _nullElement.supertype = objectType;
+
+ _nullElement.constructors = [
+ _constructor(
+ name: '_uninstantiatable',
+ isFactory: true,
+ ),
+ ];
+
+ return _nullElement;
+ }
+
+ ClassElementImpl get numElement {
+ if (_numElement != null) return _numElement;
+
+ _numElement = _class(name: 'num', isAbstract: true);
+ _numElement.supertype = objectType;
+
+ _numElement.methods = [
+ _method('+', numType, parameters: [
+ _requiredParameter('other', numType),
+ ]),
+ _method('-', numType, parameters: [
+ _requiredParameter('other', numType),
+ ]),
+ _method('*', numType, parameters: [
+ _requiredParameter('other', numType),
+ ]),
+ _method('%', numType, parameters: [
+ _requiredParameter('other', numType),
+ ]),
+ _method('/', doubleType, parameters: [
+ _requiredParameter('other', numType),
+ ]),
+ _method('~/', intType, parameters: [
+ _requiredParameter('other', numType),
+ ]),
+ _method('-', numType, parameters: [
+ _requiredParameter('other', numType),
+ ]),
+ _method('remainder', numType, parameters: [
+ _requiredParameter('other', numType),
+ ]),
+ _method('<', boolType, parameters: [
+ _requiredParameter('other', numType),
+ ]),
+ _method('<=', boolType, parameters: [
+ _requiredParameter('other', numType),
+ ]),
+ _method('>', boolType, parameters: [
+ _requiredParameter('other', numType),
+ ]),
+ _method('>=', boolType, parameters: [
+ _requiredParameter('other', numType),
+ ]),
+ _method('==', boolType, parameters: [
+ _requiredParameter('other', objectType),
+ ]),
+ _method('abs', numType),
+ _method('floor', numType),
+ _method('ceil', numType),
+ _method('round', numType),
+ _method('truncate', numType),
+ _method('toInt', intType),
+ _method('toDouble', doubleType),
+ _method('toStringAsFixed', stringType, parameters: [
+ _requiredParameter('fractionDigits', intType),
+ ]),
+ _method('toStringAsExponential', stringType, parameters: [
+ _requiredParameter('fractionDigits', intType),
+ ]),
+ _method('toStringAsPrecision', stringType, parameters: [
+ _requiredParameter('precision', intType),
+ ]),
+ ];
+
+ _setAccessors(_numElement, [
+ _getter('isInfinite', boolType),
+ _getter('isNaN', boolType),
+ _getter('isNegative', boolType),
+ ]);
+
+ return _numElement;
+ }
+
+ InterfaceType get numType {
+ return _numType ??= _interfaceType(numElement);
+ }
+
+ ClassElementImpl get objectElement {
+ if (_objectElement != null) return _objectElement;
+
+ _objectElement = ElementFactory.object;
+ _objectElement.interfaces = const <InterfaceType>[];
+ _objectElement.mixins = const <InterfaceType>[];
+ _objectElement.typeParameters = const <TypeParameterElement>[];
+ _objectElement.constructors = [
+ _constructor(isConst: true),
+ ];
+
+ _objectElement.methods = [
+ _method('toString', stringType),
+ _method('==', boolType, parameters: [
+ _requiredParameter('other', objectType),
+ ]),
+ _method('noSuchMethod', dynamicType, parameters: [
+ _requiredParameter('other', dynamicType),
+ ]),
+ ];
+
+ _setAccessors(_objectElement, [
+ _getter('hashCode', intType),
+ _getter('runtimeType', typeType),
+ ]);
+
+ return _objectElement;
+ }
+
+ InterfaceType get objectType {
+ return _objectType ??= _interfaceType(objectElement);
+ }
+
+ ClassElementImpl get overrideElement {
+ if (_overrideElement != null) return _overrideElement;
+
+ _overrideElement = _class(name: '_Override');
+ _overrideElement.supertype = objectType;
+
+ _overrideElement.constructors = [
+ _constructor(isConst: true),
+ ];
+
+ return _overrideElement;
+ }
+
+ ClassElementImpl get proxyElement {
+ if (_proxyElement != null) return _proxyElement;
+
+ _proxyElement = _class(name: '_Proxy');
+ _proxyElement.supertype = objectType;
+
+ _proxyElement.constructors = [
+ _constructor(isConst: true),
+ ];
+
+ return _proxyElement;
+ }
+
+ ClassElementImpl get setElement {
+ if (_setElement != null) return _setElement;
+
+ var eElement = _typeParameter('E');
+ var eType = _typeParameterType(eElement);
+
+ _setElement = _class(
+ name: 'Set',
+ isAbstract: true,
+ typeParameters: [eElement],
+ );
+ _setElement.supertype = objectType;
+ _setElement.interfaces = [
+ iterableType(eType),
+ ];
+
+ return _setElement;
+ }
+
+ ClassElementImpl get stackTraceElement {
+ if (_stackTraceElement != null) return _stackTraceElement;
+
+ _stackTraceElement = _class(name: 'StackTrace', isAbstract: true);
+ _stackTraceElement.supertype = objectType;
+
+ return _stackTraceElement;
+ }
+
+ ClassElementImpl get streamElement {
+ if (_streamElement != null) return _streamElement;
+
+ var tElement = _typeParameter('T');
+ var tType = _typeParameterType(tElement);
+
+ _streamElement = _class(
+ name: 'Stream',
+ isAbstract: true,
+ typeParameters: [tElement],
+ );
+ _streamElement.isAbstract = true;
+ _streamElement.supertype = objectType;
+
+ // StreamSubscription<T> listen(void onData(T event),
+ // {Function onError, void onDone(), bool cancelOnError});
+ _streamElement.methods = [
+ _method(
+ 'listen',
+ streamSubscriptionType(tType),
+ parameters: [
+ _requiredParameter(
+ 'onData',
+ _functionType(
+ returnType: voidType,
+ parameters: [
+ _requiredParameter('event', tType),
+ ],
+ ),
+ ),
+ _namedParameter('onError', functionType),
+ _namedParameter(
+ 'onDone',
+ _functionType(returnType: voidType),
+ ),
+ _namedParameter('cancelOnError', boolType),
+ ],
+ ),
+ ];
+
+ return _streamElement;
+ }
+
+ ClassElementImpl get streamSubscriptionElement {
+ if (_streamSubscriptionElement != null) return _streamSubscriptionElement;
+
+ var tElement = _typeParameter('T');
+ _streamSubscriptionElement = _class(
+ name: 'StreamSubscription',
+ isAbstract: true,
+ typeParameters: [tElement],
+ );
+ _streamSubscriptionElement.supertype = objectType;
+
+ return _streamSubscriptionElement;
+ }
+
+ ClassElementImpl get stringElement {
+ if (_stringElement != null) return _stringElement;
+
+ _stringElement = _class(name: 'String', isAbstract: true);
+ _stringElement.supertype = objectType;
+
+ _stringElement.constructors = [
+ _constructor(
+ name: 'fromEnvironment',
+ isConst: true,
+ isFactory: true,
+ parameters: [
+ _requiredParameter('name', stringType),
+ _namedParameter('defaultValue', stringType),
+ ],
+ ),
+ ];
+
+ _setAccessors(_stringElement, [
+ _getter('isEmpty', boolType),
+ _getter('length', intType),
+ _getter('codeUnits', listType(intType)),
+ ]);
+
+ _stringElement.methods = [
+ _method('+', _stringType, parameters: [
+ _requiredParameter('other', _stringType),
+ ]),
+ _method('toLowerCase', _stringType),
+ _method('toUpperCase', _stringType),
+ ];
+
+ return _stringElement;
+ }
+
+ InterfaceType get stringType {
+ return _stringType ??= _interfaceType(stringElement);
+ }
+
+ ClassElementImpl get symbolElement {
+ if (_symbolElement != null) return _symbolElement;
+
+ _symbolElement = _class(name: 'Symbol', isAbstract: true);
+ _symbolElement.supertype = objectType;
+
+ _symbolElement.constructors = [
+ _constructor(
+ isConst: true,
+ isFactory: true,
+ parameters: [
+ _requiredParameter('name', stringType),
+ ],
+ ),
+ ];
+
+ return _symbolElement;
+ }
+
+ ClassElementImpl get typeElement {
+ if (_typeElement != null) return _typeElement;
+
+ _typeElement = _class(name: 'Type', isAbstract: true);
+ _typeElement.supertype = objectType;
+
+ return _typeElement;
+ }
+
+ InterfaceType get typeType {
+ return _typeType ??= _interfaceType(typeElement);
+ }
+
+ VoidTypeImpl get voidType => VoidTypeImpl.instance;
+
+ InterfaceType futureOrType(DartType elementType) {
+ return _interfaceType(
+ futureOrElement,
+ typeArguments: [elementType],
+ );
+ }
+
+ InterfaceType futureType(DartType elementType) {
+ return _interfaceType(
+ futureElement,
+ typeArguments: [elementType],
+ );
+ }
+
+ InterfaceType iterableType(DartType elementType) {
+ return _interfaceType(
+ iterableElement,
+ typeArguments: [elementType],
+ );
+ }
+
+ InterfaceType iteratorType(DartType elementType) {
+ return _interfaceType(
+ iteratorElement,
+ typeArguments: [elementType],
+ );
+ }
+
+ InterfaceType listType(DartType elementType) {
+ return _interfaceType(
+ listElement,
+ typeArguments: [elementType],
+ );
+ }
+
+ InterfaceType streamSubscriptionType(DartType valueType) {
+ return _interfaceType(
+ streamSubscriptionElement,
+ typeArguments: [valueType],
+ );
+ }
+
+ LibraryElementImpl _buildAsync() {
+ var asyncLibrary = LibraryElementImpl(
+ analysisContext,
+ null,
+ 'dart.async',
+ 0,
+ 0,
+ nullabilitySuffix == NullabilitySuffix.none,
+ );
+
+ var asyncUnit = new CompilationUnitElementImpl();
+ var asyncSource = analysisContext.sourceFactory.forUri('dart:async');
+ asyncUnit.librarySource = asyncUnit.source = asyncSource;
+ asyncLibrary.definingCompilationUnit = asyncUnit;
+
+ asyncUnit.types = <ClassElement>[
+ completerElement,
+ futureElement,
+ futureOrElement,
+ streamElement,
+ streamSubscriptionElement
+ ];
+
+ return asyncLibrary;
+ }
+
+ LibraryElementImpl _buildCore() {
+ var coreUnit = CompilationUnitElementImpl();
+
+ var coreSource = analysisContext.sourceFactory.forUri('dart:core');
+ coreUnit.librarySource = coreUnit.source = coreSource;
+
+ coreUnit.types = <ClassElement>[
+ boolElement,
+ deprecatedElement,
+ doubleElement,
+ functionElement,
+ intElement,
+ iterableElement,
+ iteratorElement,
+ listElement,
+ mapElement,
+ nullElement,
+ numElement,
+ objectElement,
+ overrideElement,
+ proxyElement,
+ setElement,
+ stackTraceElement,
+ stringElement,
+ symbolElement,
+ typeElement,
+ ];
+
+ coreUnit.functions = <FunctionElement>[
+ _function('identical', boolType, parameters: [
+ _requiredParameter('a', objectType),
+ _requiredParameter('b', objectType),
+ ]),
+ _function('print', voidType, parameters: [
+ _requiredParameter('object', objectType),
+ ]),
+ ];
+
+ var deprecatedVariable = _topLevelVariable(
+ 'deprecated',
+ _interfaceType(deprecatedElement),
+ isConst: true,
+ );
+
+ var overrideVariable = _topLevelVariable(
+ 'override',
+ _interfaceType(overrideElement),
+ isConst: true,
+ );
+
+ var proxyVariable = _topLevelVariable(
+ 'proxy',
+ _interfaceType(proxyElement),
+ isConst: true,
+ );
+
+ coreUnit.accessors = <PropertyAccessorElement>[
+ deprecatedVariable.getter,
+ overrideVariable.getter,
+ proxyVariable.getter,
+ ];
+ coreUnit.topLevelVariables = <TopLevelVariableElement>[
+ deprecatedVariable,
+ overrideVariable,
+ proxyVariable,
+ ];
+
+ var coreLibrary = LibraryElementImpl(
+ analysisContext,
+ null,
+ 'dart.core',
+ 0,
+ 0,
+ nullabilitySuffix == NullabilitySuffix.none,
+ );
+ coreLibrary.definingCompilationUnit = coreUnit;
+
+ return coreLibrary;
+ }
+
+ ClassElementImpl _class({
+ @required String name,
+ bool isAbstract = false,
+ List<TypeParameterElement> typeParameters = const [],
+ }) {
+ var element = ClassElementImpl(name, 0);
+ element.typeParameters = typeParameters;
+ element.constructors = <ConstructorElement>[
+ _constructor(),
+ ];
+ return element;
+ }
+
+ ConstructorElement _constructor({
+ String name = '',
+ bool isConst = false,
+ bool isFactory = false,
+ List<ParameterElement> parameters = const [],
+ }) {
+ var element = ConstructorElementImpl(name, 0);
+ element.factory = isFactory;
+ element.isConst = isConst;
+ element.parameters = parameters;
+ return element;
+ }
+
+ FieldElement _field(
+ String name,
+ DartType type, {
+ bool isConst = false,
+ bool isFinal = false,
+ bool isStatic = false,
+ }) {
+ return ElementFactory.fieldElement(name, isStatic, isFinal, isConst, type);
+ }
+
+ FunctionElement _function(
+ String name,
+ DartType returnType, {
+ List<TypeParameterElement> typeFormals = const [],
+ List<ParameterElement> parameters = const [],
+ }) {
+ var element = FunctionElementImpl(name, 0)
+ ..parameters = parameters
+ ..returnType = returnType
+ ..typeParameters = typeFormals;
+ element.type = _typeOfExecutableElement(element);
+ return element;
+ }
+
+ FunctionType _functionType({
+ @required DartType returnType,
+ List<TypeParameterElement> typeFormals = const [],
+ List<ParameterElement> parameters = const [],
+ }) {
+ return FunctionTypeImpl.synthetic(returnType, typeFormals, parameters);
+ }
+
+ PropertyAccessorElement _getter(
+ String name,
+ DartType type, {
+ bool isStatic = false,
+ }) {
+ var field = FieldElementImpl(name, -1);
+ field.isFinal = true;
+ field.isStatic = isStatic;
+ field.isSynthetic = true;
+ field.type = type;
+
+ var getter = PropertyAccessorElementImpl(name, 0);
+ getter.getter = true;
+ getter.isStatic = isStatic;
+ getter.isSynthetic = false;
+ getter.returnType = type;
+ getter.type = _typeOfExecutableElement(getter);
+ getter.variable = field;
+
+ field.getter = getter;
+ return getter;
+ }
+
+ InterfaceType _interfaceType(
+ ClassElement element, {
+ List<DartType> typeArguments = const [],
+ }) {
+ return InterfaceTypeImpl.explicit(
+ element,
+ typeArguments,
+ nullabilitySuffix: nullabilitySuffix,
+ );
+ }
+
+ MethodElement _method(
+ String name,
+ DartType returnType, {
+ List<TypeParameterElement> typeFormals = const [],
+ List<ParameterElement> parameters = const [],
+ }) {
+ var element = MethodElementImpl(name, 0)
+ ..parameters = parameters
+ ..returnType = returnType
+ ..typeParameters = typeFormals;
+ element.type = _typeOfExecutableElement(element);
+ return element;
+ }
+
+ ParameterElement _namedParameter(String name, DartType type,
+ {String initializerCode}) {
+ var parameter = DefaultParameterElementImpl(name, 0);
+ parameter.parameterKind = ParameterKind.NAMED;
+ parameter.type = type;
+ parameter.defaultValueCode = initializerCode;
+ return parameter;
+ }
+
+ ParameterElement _positionalParameter(String name, DartType type) {
+ var parameter = ParameterElementImpl(name, 0);
+ parameter.parameterKind = ParameterKind.POSITIONAL;
+ parameter.type = type;
+ return parameter;
+ }
+
+ ParameterElement _requiredParameter(String name, DartType type) {
+ var parameter = ParameterElementImpl(name, 0);
+ parameter.parameterKind = ParameterKind.REQUIRED;
+ parameter.type = type;
+ return parameter;
+ }
+
+ /// Set the [accessors] and the corresponding fields for the [classElement].
+ void _setAccessors(
+ ClassElementImpl classElement,
+ List<PropertyAccessorElement> accessors,
+ ) {
+ classElement.accessors = accessors;
+ classElement.fields = accessors
+ .map((accessor) => accessor.variable)
+ .cast<FieldElement>()
+ .toList();
+ }
+
+ TopLevelVariableElement _topLevelVariable(
+ String name,
+ DartType type, {
+ bool isConst = false,
+ bool isFinal = false,
+ }) {
+ return ElementFactory.topLevelVariableElement3(
+ name, isConst, isFinal, type);
+ }
+
+ /// TODO(scheglov) We should do the opposite - build type in the element.
+ /// But build a similar synthetic / structured type.
+ FunctionType _typeOfExecutableElement(ExecutableElement element) {
+ return FunctionTypeImpl.synthetic(
+ element.returnType,
+ element.typeParameters,
+ element.parameters,
+ );
+ }
+
+ TypeParameterElementImpl _typeParameter(String name) {
+ return TypeParameterElementImpl(name, 0);
+ }
+
+ TypeParameterType _typeParameterType(TypeParameterElement element) {
+ return TypeParameterTypeImpl(
+ element,
+ nullabilitySuffix: nullabilitySuffix,
+ );
+ }
+}
diff --git a/pkg/analyzer/lib/src/util/sdk.dart b/pkg/analyzer/lib/src/util/sdk.dart
index abffd58..36ed5fd 100644
--- a/pkg/analyzer/lib/src/util/sdk.dart
+++ b/pkg/analyzer/lib/src/util/sdk.dart
@@ -19,7 +19,7 @@
// The given SDK path does not work.
// Then we're probably running on bots, in 'xcodebuild/ReleaseX64'.
- // In this case 'vm_platform.dill' is next to the 'dart'.
+ // In this case 'vm_platform_strong.dill' is next to the 'dart'.
return path.dirname(Platform.resolvedExecutable);
}
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 72a8e45..5314552 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
name: analyzer
-version: 0.38.2-dev
+version: 0.38.2
author: Dart Team <misc@dartlang.org>
description: This package provides a library that performs static analysis of Dart code.
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/analyzer
@@ -13,10 +13,10 @@
collection: ^1.10.1
convert: ^2.0.0
crypto: '>=1.1.1 <3.0.0'
- front_end: 0.1.23
+ front_end: 0.1.24
glob: ^1.0.3
html: '>=0.13.4+1 <0.15.0'
- kernel: 0.3.23
+ kernel: 0.3.24
meta: ^1.0.2
package_config: '>=0.1.5 <2.0.0'
path: '>=0.9.0 <2.0.0'
diff --git a/pkg/analyzer/test/dart/ast/ast_test.dart b/pkg/analyzer/test/dart/ast/ast_test.dart
index 585da6a..9c90698 100644
--- a/pkg/analyzer/test/dart/ast/ast_test.dart
+++ b/pkg/analyzer/test/dart/ast/ast_test.dart
@@ -30,6 +30,7 @@
defineReflectiveTests(PreviousTokenTest);
defineReflectiveTests(SimpleIdentifierTest);
defineReflectiveTests(SimpleStringLiteralTest);
+ defineReflectiveTests(SpreadElementTest);
defineReflectiveTests(StringInterpolationTest);
defineReflectiveTests(VariableDeclarationTest);
});
@@ -1189,6 +1190,21 @@
}
@reflectiveTest
+class SpreadElementTest extends ParserTestCase {
+ void test_notNullAwareSpread() {
+ final spread = AstTestFactory.spreadElement(
+ TokenType.PERIOD_PERIOD_PERIOD, AstTestFactory.nullLiteral());
+ expect(spread.isNullAware, isFalse);
+ }
+
+ void test_nullAwareSpread() {
+ final spread = AstTestFactory.spreadElement(
+ TokenType.PERIOD_PERIOD_PERIOD_QUESTION, AstTestFactory.nullLiteral());
+ expect(spread.isNullAware, isTrue);
+ }
+}
+
+@reflectiveTest
class StringInterpolationTest extends ParserTestCase {
void test_contentsOffsetEnd() {
AstTestFactory.interpolationExpression(AstTestFactory.identifier3('bb'));
diff --git a/pkg/analyzer/test/generated/analysis_context_factory.dart b/pkg/analyzer/test/generated/analysis_context_factory.dart
deleted file mode 100644
index b7ae647..0000000
--- a/pkg/analyzer/test/generated/analysis_context_factory.dart
+++ /dev/null
@@ -1,543 +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 'dart:collection';
-
-import 'package:analyzer/dart/analysis/features.dart';
-import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/token.dart';
-import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/file_system/memory_file_system.dart';
-import 'package:analyzer/src/context/context.dart';
-import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/dart/sdk/sdk.dart';
-import 'package:analyzer/src/file_system/file_system.dart';
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/sdk.dart';
-import 'package:analyzer/src/generated/source_io.dart';
-import 'package:analyzer/src/generated/testing/ast_test_factory.dart';
-import 'package:analyzer/src/generated/testing/element_factory.dart';
-import 'package:analyzer/src/generated/testing/test_type_provider.dart';
-import 'package:analyzer/src/generated/utilities_dart.dart';
-import 'package:analyzer/src/string_source.dart';
-import 'package:analyzer/src/summary/summary_sdk.dart';
-import 'package:test/test.dart';
-
-/**
- * The class `AnalysisContextFactory` defines utility methods used to create analysis contexts
- * for testing purposes.
- */
-class AnalysisContextFactory {
- static String _DART_MATH = "dart:math";
-
- static String _DART_INTERCEPTORS = "dart:_interceptors";
-
- static String _DART_JS_HELPER = "dart:_js_helper";
-
- /**
- * Create and return an analysis context that has a fake core library already
- * resolved. The given [resourceProvider] will be used when accessing the file
- * system.
- */
- static InternalAnalysisContext contextWithCore(
- {UriResolver contributedResolver,
- MemoryResourceProvider resourceProvider}) {
- AnalysisContextForTests context = new AnalysisContextForTests();
- return initContextWithCore(context, FeatureSet.forTesting(),
- contributedResolver, resourceProvider);
- }
-
- /**
- * Create and return an analysis context that uses the given [options] and has
- * a fake core library already resolved. The given [resourceProvider] will be
- * used when accessing the file system.
- */
- static InternalAnalysisContext contextWithCoreAndOptions(
- AnalysisOptions options,
- {MemoryResourceProvider resourceProvider}) {
- AnalysisContextForTests context = new AnalysisContextForTests();
- context._internalSetAnalysisOptions(options);
- return initContextWithCore(
- context, options.contextFeatures, null, resourceProvider);
- }
-
- /**
- * Create and return an analysis context that has a fake core library already
- * resolved. If not `null`, the given [packages] map will be used to create a
- * package URI resolver. The given [resourceProvider] will be used when
- * accessing the file system.
- */
- static InternalAnalysisContext contextWithCoreAndPackages(
- Map<String, String> packages,
- {MemoryResourceProvider resourceProvider}) {
- AnalysisContextForTests context = new AnalysisContextForTests();
- return initContextWithCore(context, FeatureSet.forTesting(),
- new TestPackageUriResolver(packages), resourceProvider);
- }
-
- /**
- * Initialize the given analysis [context] with a fake core library that has
- * already been resolved. If not `null`, the given [contributedResolver] will
- * be added to the context's source factory. The given [resourceProvider] will
- * be used when accessing the file system.
- */
- static InternalAnalysisContext initContextWithCore(
- InternalAnalysisContext context, FeatureSet featureSet,
- [UriResolver contributedResolver,
- MemoryResourceProvider resourceProvider]) {
- DartSdk sdk = new _AnalysisContextFactory_initContextWithCore(
- resourceProvider, resourceProvider.convertPath('/fake/sdk'));
- List<UriResolver> resolvers = <UriResolver>[
- new DartUriResolver(sdk),
- new ResourceUriResolver(resourceProvider)
- ];
- if (contributedResolver != null) {
- resolvers.add(contributedResolver);
- }
- SourceFactory sourceFactory = new SourceFactory(resolvers);
- context.sourceFactory = sourceFactory;
- AnalysisContext coreContext = sdk.context;
- //
- // dart:core
- //
- TestTypeProvider provider = new TestTypeProvider();
- CompilationUnitElementImpl coreUnit = new CompilationUnitElementImpl();
- Source coreSource = sourceFactory.forUri(DartSdk.DART_CORE);
- coreUnit.librarySource = coreUnit.source = coreSource;
- ClassElementImpl overrideClassElement =
- ElementFactory.classElement2("_Override");
- ClassElementImpl proxyClassElement = ElementFactory.classElement2("_Proxy");
- proxyClassElement.constructors = <ConstructorElement>[
- ElementFactory.constructorElement(proxyClassElement, '', true)
- ..isCycleFree = true
- ..constantInitializers = <ConstructorInitializer>[]
- ];
- ClassElement objectClassElement = provider.objectType.element;
- coreUnit.types = <ClassElement>[
- provider.boolType.element,
- provider.deprecatedType.element,
- provider.doubleType.element,
- provider.functionType.element,
- provider.intType.element,
- provider.iterableType.element,
- provider.iteratorType.element,
- provider.listType.element,
- provider.mapType.element,
- provider.nullType.element,
- provider.numType.element,
- objectClassElement,
- overrideClassElement,
- proxyClassElement,
- provider.setType.element,
- provider.stackTraceType.element,
- provider.stringType.element,
- provider.symbolType.element,
- provider.typeType.element
- ];
- coreUnit.functions = <FunctionElement>[
- ElementFactory.functionElement3("identical", provider.boolType,
- <ClassElement>[objectClassElement, objectClassElement], null),
- ElementFactory.functionElement3("print", VoidTypeImpl.instance,
- <ClassElement>[objectClassElement], null)
- ];
- TopLevelVariableElement proxyTopLevelVariableElt =
- ElementFactory.topLevelVariableElement3(
- "proxy", true, false, proxyClassElement.type);
- ConstTopLevelVariableElementImpl deprecatedTopLevelVariableElt =
- ElementFactory.topLevelVariableElement3(
- "deprecated", true, false, provider.deprecatedType);
- TopLevelVariableElement overrideTopLevelVariableElt =
- ElementFactory.topLevelVariableElement3(
- "override", true, false, overrideClassElement.type);
- {
- ClassElement deprecatedElement = provider.deprecatedType.element;
- InstanceCreationExpression initializer =
- AstTestFactory.instanceCreationExpression2(
- Keyword.CONST,
- AstTestFactory.typeName(deprecatedElement),
- [AstTestFactory.string2('next release')]);
- ConstructorElement constructor = deprecatedElement.constructors.single;
- initializer.staticElement = constructor;
- initializer.constructorName.staticElement = constructor;
- deprecatedTopLevelVariableElt.constantInitializer = initializer;
- }
- coreUnit.accessors = <PropertyAccessorElement>[
- deprecatedTopLevelVariableElt.getter,
- overrideTopLevelVariableElt.getter,
- proxyTopLevelVariableElt.getter
- ];
- coreUnit.topLevelVariables = <TopLevelVariableElement>[
- deprecatedTopLevelVariableElt,
- overrideTopLevelVariableElt,
- proxyTopLevelVariableElt
- ];
- LibraryElementImpl coreLibrary = new LibraryElementImpl.forNode(
- coreContext,
- null,
- AstTestFactory.libraryIdentifier2(["dart", "core"]),
- featureSet.isEnabled(Feature.non_nullable));
- coreLibrary.definingCompilationUnit = coreUnit;
- //
- // dart:async
- //
- LibraryElementImpl asyncLibrary = new LibraryElementImpl.forNode(
- coreContext,
- null,
- AstTestFactory.libraryIdentifier2(["dart", "async"]),
- featureSet.isEnabled(Feature.non_nullable));
- CompilationUnitElementImpl asyncUnit = new CompilationUnitElementImpl();
- Source asyncSource = sourceFactory.forUri(DartSdk.DART_ASYNC);
- asyncUnit.librarySource = asyncUnit.source = asyncSource;
- asyncLibrary.definingCompilationUnit = asyncUnit;
- // Future<T>
- ClassElementImpl futureElement =
- ElementFactory.classElement2("Future", ["T"]);
- // FutureOr<T>
- ClassElementImpl futureOrElement =
- ElementFactory.classElement2("FutureOr", ["T"]);
- futureElement.enclosingElement = asyncUnit;
- // factory Future.value([value])
- ConstructorElementImpl futureConstructor =
- ElementFactory.constructorElement2(futureElement, "value");
- futureConstructor.parameters = <ParameterElement>[
- ElementFactory.positionalParameter2("value", provider.dynamicType)
- ];
- futureConstructor.factory = true;
- futureElement.constructors = <ConstructorElement>[futureConstructor];
- // Future<R> then<R>(FutureOr<R> onValue(T value), { Function onError });
- TypeDefiningElement futureThenR = DynamicElementImpl.instance;
- DartType onValueReturnType = DynamicTypeImpl.instance;
- futureThenR = ElementFactory.typeParameterWithType('R');
- onValueReturnType = futureOrElement.type.instantiate([futureThenR.type]);
- FunctionElementImpl thenOnValue = ElementFactory.functionElement3(
- 'onValue', onValueReturnType, [futureElement.typeParameters[0]], null);
- thenOnValue.isSynthetic = true;
-
- DartType futureRType = futureElement.type.instantiate([futureThenR.type]);
- MethodElementImpl thenMethod = ElementFactory.methodElementWithParameters(
- futureElement, "then", futureRType, [
- ElementFactory.requiredParameter2("onValue", thenOnValue.type),
- ElementFactory.namedParameter2("onError", provider.functionType)
- ]);
- if (!futureThenR.type.isDynamic) {
- thenMethod.typeParameters = <TypeParameterElement>[futureThenR];
- }
- thenOnValue.enclosingElement = thenMethod;
- thenOnValue.type = new FunctionTypeImpl(thenOnValue);
- (thenMethod.parameters[0] as ParameterElementImpl).type = thenOnValue.type;
- thenMethod.type = new FunctionTypeImpl(thenMethod);
-
- futureElement.methods = <MethodElement>[thenMethod];
- // Completer
- ClassElementImpl completerElement =
- ElementFactory.classElement2("Completer", ["T"]);
- ConstructorElementImpl completerConstructor =
- ElementFactory.constructorElement2(completerElement, null);
- completerElement.constructors = <ConstructorElement>[completerConstructor];
- // StreamSubscription
- ClassElementImpl streamSubscriptionElement =
- ElementFactory.classElement2("StreamSubscription", ["T"]);
- // Stream
- ClassElementImpl streamElement =
- ElementFactory.classElement2("Stream", ["T"]);
- streamElement.isAbstract = true;
- streamElement.constructors = <ConstructorElement>[
- ElementFactory.constructorElement2(streamElement, null)
- ];
- DartType returnType = streamSubscriptionElement.type
- .instantiate(streamElement.type.typeArguments);
- FunctionElementImpl listenOnData = ElementFactory.functionElement3(
- 'onData',
- VoidTypeImpl.instance,
- <TypeDefiningElement>[streamElement.typeParameters[0]],
- null);
- listenOnData.isSynthetic = true;
- List<DartType> parameterTypes = <DartType>[
- listenOnData.type,
- ];
- // TODO(brianwilkerson) This is missing the optional parameters.
- MethodElementImpl listenMethod =
- ElementFactory.methodElement('listen', returnType, parameterTypes);
- streamElement.methods = <MethodElement>[listenMethod];
- listenMethod.type = new FunctionTypeImpl(listenMethod);
-
- FunctionElementImpl listenParamFunction = parameterTypes[0].element;
- listenParamFunction.enclosingElement = listenMethod;
- listenParamFunction.type = new FunctionTypeImpl(listenParamFunction);
- ParameterElementImpl listenParam = listenMethod.parameters[0];
- listenParam.type = listenParamFunction.type;
-
- asyncUnit.types = <ClassElement>[
- completerElement,
- futureElement,
- futureOrElement,
- streamElement,
- streamSubscriptionElement
- ];
- //
- // dart:html
- //
- CompilationUnitElementImpl htmlUnit = new CompilationUnitElementImpl();
- Source htmlSource = sourceFactory.forUri(DartSdk.DART_HTML);
- htmlUnit.librarySource = htmlUnit.source = htmlSource;
- ClassElementImpl elementElement = ElementFactory.classElement2("Element");
- InterfaceType elementType = elementElement.type;
- ClassElementImpl canvasElement =
- ElementFactory.classElement("CanvasElement", elementType);
- ClassElementImpl contextElement =
- ElementFactory.classElement2("CanvasRenderingContext");
- InterfaceType contextElementType = contextElement.type;
- ClassElementImpl context2dElement = ElementFactory.classElement(
- "CanvasRenderingContext2D", contextElementType);
- canvasElement.methods = <MethodElement>[
- ElementFactory.methodElement(
- "getContext", contextElementType, [provider.stringType])
- ];
- canvasElement.accessors = <PropertyAccessorElement>[
- ElementFactory.getterElement("context2D", false, context2dElement.type)
- ];
- canvasElement.fields = canvasElement.accessors
- .map((PropertyAccessorElement accessor) => accessor.variable)
- .cast<FieldElement>()
- .toList();
- ClassElementImpl documentElement =
- ElementFactory.classElement("Document", elementType);
- ClassElementImpl htmlDocumentElement =
- ElementFactory.classElement("HtmlDocument", documentElement.type);
- htmlDocumentElement.methods = <MethodElement>[
- ElementFactory.methodElement(
- "query", elementType, <DartType>[provider.stringType])
- ];
- htmlUnit.types = <ClassElement>[
- ElementFactory.classElement("AnchorElement", elementType),
- ElementFactory.classElement("BodyElement", elementType),
- ElementFactory.classElement("ButtonElement", elementType),
- canvasElement,
- contextElement,
- context2dElement,
- ElementFactory.classElement("DivElement", elementType),
- documentElement,
- elementElement,
- htmlDocumentElement,
- ElementFactory.classElement("InputElement", elementType),
- ElementFactory.classElement("SelectElement", elementType)
- ];
- htmlUnit.functions = <FunctionElement>[
- ElementFactory.functionElement3("query", elementElement.type,
- <ClassElement>[provider.stringType.element], const <ClassElement>[])
- ];
- TopLevelVariableElementImpl document =
- ElementFactory.topLevelVariableElement3(
- "document", false, true, htmlDocumentElement.type);
- htmlUnit.topLevelVariables = <TopLevelVariableElement>[document];
- htmlUnit.accessors = <PropertyAccessorElement>[document.getter];
- LibraryElementImpl htmlLibrary = new LibraryElementImpl.forNode(
- coreContext,
- null,
- AstTestFactory.libraryIdentifier2(["dart", "dom", "html"]),
- featureSet.isEnabled(Feature.non_nullable));
- htmlLibrary.definingCompilationUnit = htmlUnit;
- //
- // dart:math
- //
- CompilationUnitElementImpl mathUnit = new CompilationUnitElementImpl();
- Source mathSource = sourceFactory.forUri(_DART_MATH);
- mathUnit.librarySource = mathUnit.source = mathSource;
- FunctionElement cosElement = ElementFactory.functionElement3(
- "cos",
- provider.doubleType,
- <ClassElement>[provider.numType.element],
- const <ClassElement>[]);
- TopLevelVariableElement ln10Element =
- ElementFactory.topLevelVariableElement3(
- "LN10", true, false, provider.doubleType);
- TypeParameterElement maxT =
- ElementFactory.typeParameterWithType('T', provider.numType);
- FunctionElementImpl maxElement = ElementFactory.functionElement3(
- "max", maxT.type, [maxT, maxT], const <ClassElement>[]);
- maxElement.typeParameters = [maxT];
- maxElement.type = new FunctionTypeImpl(maxElement);
- TopLevelVariableElement piElement = ElementFactory.topLevelVariableElement3(
- "PI", true, false, provider.doubleType);
- ClassElementImpl randomElement = ElementFactory.classElement2("Random");
- randomElement.isAbstract = true;
- ConstructorElementImpl randomConstructor =
- ElementFactory.constructorElement2(randomElement, null);
- randomConstructor.factory = true;
- ParameterElementImpl seedParam = new ParameterElementImpl("seed", 0);
- seedParam.parameterKind = ParameterKind.POSITIONAL;
- seedParam.type = provider.intType;
- randomConstructor.parameters = <ParameterElement>[seedParam];
- randomElement.constructors = <ConstructorElement>[randomConstructor];
- FunctionElement sinElement = ElementFactory.functionElement3(
- "sin",
- provider.doubleType,
- <ClassElement>[provider.numType.element],
- const <ClassElement>[]);
- FunctionElement sqrtElement = ElementFactory.functionElement3(
- "sqrt",
- provider.doubleType,
- <ClassElement>[provider.numType.element],
- const <ClassElement>[]);
- mathUnit.accessors = <PropertyAccessorElement>[
- ln10Element.getter,
- piElement.getter
- ];
- mathUnit.functions = <FunctionElement>[
- cosElement,
- maxElement,
- sinElement,
- sqrtElement
- ];
- mathUnit.topLevelVariables = <TopLevelVariableElement>[
- ln10Element,
- piElement
- ];
- mathUnit.types = <ClassElement>[randomElement];
- LibraryElementImpl mathLibrary = new LibraryElementImpl.forNode(
- coreContext,
- null,
- AstTestFactory.libraryIdentifier2(["dart", "math"]),
- featureSet.isEnabled(Feature.non_nullable));
- mathLibrary.definingCompilationUnit = mathUnit;
- //
- // Record the elements.
- //
- Map<Source, LibraryElement> elementMap =
- new HashMap<Source, LibraryElement>();
- elementMap[coreSource] = coreLibrary;
- if (asyncSource != null) {
- elementMap[asyncSource] = asyncLibrary;
- }
- elementMap[htmlSource] = htmlLibrary;
- elementMap[mathSource] = mathLibrary;
- //
- // Set the public and export namespaces. We don't use exports in the fake
- // core library so public and export namespaces are the same.
- //
- for (LibraryElementImpl library in elementMap.values) {
- Namespace namespace =
- new NamespaceBuilder().createPublicNamespaceForLibrary(library);
- library.exportNamespace = namespace;
- library.publicNamespace = namespace;
- }
-
- context.typeProvider = SummaryTypeProvider()
- ..initializeCore(coreLibrary)
- ..initializeAsync(asyncLibrary);
-
- // Create the synthetic element for `loadLibrary`.
- for (LibraryElementImpl library in elementMap.values) {
- library.createLoadLibraryFunction(context.typeProvider);
- }
- return context;
- }
-}
-
-/**
- * An analysis context that has a fake SDK that is much smaller and faster for
- * testing purposes.
- */
-class AnalysisContextForTests extends AnalysisContextImpl {
- @override
- void set analysisOptions(AnalysisOptions options) {
- AnalysisOptions currentOptions = analysisOptions;
- bool needsRecompute = currentOptions.analyzeFunctionBodiesPredicate !=
- options.analyzeFunctionBodiesPredicate ||
- currentOptions.generateImplicitErrors !=
- options.generateImplicitErrors ||
- currentOptions.generateSdkErrors != options.generateSdkErrors ||
- currentOptions.dart2jsHint != options.dart2jsHint ||
- (currentOptions.hint && !options.hint) ||
- currentOptions.preserveComments != options.preserveComments;
- if (needsRecompute) {
- fail(
- "Cannot set options that cause the sources to be reanalyzed in a test context");
- }
- super.analysisOptions = options;
- }
-
- @override
- bool exists(Source source) =>
- super.exists(source) || sourceFactory.dartSdk.context.exists(source);
-
- @override
- TimestampedData<String> getContents(Source source) {
- if (source.isInSystemLibrary) {
- return sourceFactory.dartSdk.context.getContents(source);
- }
- return super.getContents(source);
- }
-
- @override
- int getModificationStamp(Source source) {
- if (source.isInSystemLibrary) {
- return sourceFactory.dartSdk.context.getModificationStamp(source);
- }
- return super.getModificationStamp(source);
- }
-
- /**
- * Set the analysis options, even if they would force re-analysis. This method should only be
- * invoked before the fake SDK is initialized.
- *
- * @param options the analysis options to be set
- */
- void _internalSetAnalysisOptions(AnalysisOptions options) {
- super.analysisOptions = options;
- }
-}
-
-class TestPackageUriResolver extends UriResolver {
- Map<String, Source> sourceMap = new HashMap<String, Source>();
-
- TestPackageUriResolver(Map<String, String> map) {
- map.forEach((String name, String contents) {
- sourceMap['package:$name/$name.dart'] =
- new StringSource(contents, '/$name/lib/$name.dart');
- });
- }
-
- @override
- Source resolveAbsolute(Uri uri, [Uri actualUri]) {
- String uriString = uri.toString();
- return sourceMap[uriString];
- }
-
- @override
- Uri restoreAbsolute(Source source) => throw new UnimplementedError();
-}
-
-class _AnalysisContextFactory_initContextWithCore extends FolderBasedDartSdk {
- _AnalysisContextFactory_initContextWithCore(
- ResourceProvider resourceProvider, String sdkPath)
- : super(resourceProvider, resourceProvider.getFolder(sdkPath));
-
- @override
- LibraryMap initialLibraryMap(bool useDart2jsPaths) {
- LibraryMap map = new LibraryMap();
- _addLibrary(map, DartSdk.DART_ASYNC, false, "async.dart");
- _addLibrary(map, DartSdk.DART_CORE, false, "core.dart");
- _addLibrary(map, DartSdk.DART_HTML, false, "html_dartium.dart");
- _addLibrary(map, AnalysisContextFactory._DART_MATH, false, "math.dart");
- _addLibrary(map, AnalysisContextFactory._DART_INTERCEPTORS, true,
- "_interceptors.dart");
- _addLibrary(
- map, AnalysisContextFactory._DART_JS_HELPER, true, "_js_helper.dart");
- return map;
- }
-
- void _addLibrary(LibraryMap map, String uri, bool isInternal, String path) {
- SdkLibraryImpl library = new SdkLibraryImpl(uri);
- if (isInternal) {
- library.category = "Internal";
- }
- library.path = path;
- map.setLibrary(uri, library);
- }
-}
diff --git a/pkg/analyzer/test/generated/checked_mode_compile_time_error_code_test.dart b/pkg/analyzer/test/generated/checked_mode_compile_time_error_code_test.dart
index f92a108..4a90853 100644
--- a/pkg/analyzer/test/generated/checked_mode_compile_time_error_code_test.dart
+++ b/pkg/analyzer/test/generated/checked_mode_compile_time_error_code_test.dart
@@ -55,7 +55,7 @@
}
var v = const A(null);
''', [
- error(StaticWarningCode.UNDEFINED_CLASS, 18, 10),
+ error(CompileTimeErrorCode.UNDEFINED_CLASS, 18, 10),
]);
}
@@ -245,7 +245,7 @@
}
var v = const A('foo');
''', [
- error(StaticWarningCode.UNDEFINED_CLASS, 18, 10),
+ error(CompileTimeErrorCode.UNDEFINED_CLASS, 18, 10),
]);
}
@@ -418,7 +418,7 @@
}
var v = const A('foo');
''', [
- error(StaticWarningCode.UNDEFINED_CLASS, 40, 10),
+ error(CompileTimeErrorCode.UNDEFINED_CLASS, 40, 10),
]);
}
@@ -458,7 +458,7 @@
}
var v = const A(null);
''', [
- error(StaticWarningCode.UNDEFINED_CLASS, 40, 10),
+ error(CompileTimeErrorCode.UNDEFINED_CLASS, 40, 10),
]);
}
@@ -523,7 +523,7 @@
}
var v = const A(null);
''', [
- error(StaticWarningCode.UNDEFINED_CLASS, 20, 10),
+ error(CompileTimeErrorCode.UNDEFINED_CLASS, 20, 10),
]);
}
@@ -564,7 +564,7 @@
}
var v = const A('foo');
''', [
- error(StaticWarningCode.UNDEFINED_CLASS, 20, 10),
+ error(CompileTimeErrorCode.UNDEFINED_CLASS, 20, 10),
]);
}
@@ -607,7 +607,7 @@
await assertErrorsInCode('''
const Unresolved x = null;
''', [
- error(StaticWarningCode.UNDEFINED_CLASS, 6, 10),
+ error(CompileTimeErrorCode.UNDEFINED_CLASS, 6, 10),
]);
}
@@ -624,7 +624,7 @@
await assertErrorsInCode('''
const Unresolved x = 'foo';
''', [
- error(StaticWarningCode.UNDEFINED_CLASS, 6, 10),
+ error(CompileTimeErrorCode.UNDEFINED_CLASS, 6, 10),
]);
}
}
diff --git a/pkg/analyzer/test/generated/compile_time_error_code.dart b/pkg/analyzer/test/generated/compile_time_error_code.dart
index 4e24a14..f4aad69 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code.dart
@@ -1690,10 +1690,10 @@
await assertErrorsInCode(code, [
// Due to dartbug.com/28515, some additional errors appear when using the
// new analysis driver.
- error(StaticWarningCode.UNDEFINED_CLASS, 7, 1),
+ error(CompileTimeErrorCode.UNDEFINED_CLASS, 7, 1),
error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPED_PARAM_UNSUPPORTED, 7,
11),
- error(StaticWarningCode.UNDEFINED_CLASS, 14, 1),
+ error(CompileTimeErrorCode.UNDEFINED_CLASS, 14, 1),
]);
}
}
@@ -4938,7 +4938,7 @@
return const A();
}
''', [
- error(StaticWarningCode.UNDEFINED_CLASS, 21, 1),
+ error(CompileTimeErrorCode.UNDEFINED_CLASS, 21, 1),
]);
}
diff --git a/pkg/analyzer/test/generated/element_resolver_test.dart b/pkg/analyzer/test/generated/element_resolver_test.dart
index 5a921b4..f74fe27 100644
--- a/pkg/analyzer/test/generated/element_resolver_test.dart
+++ b/pkg/analyzer/test/generated/element_resolver_test.dart
@@ -7,7 +7,6 @@
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/standard_ast_factory.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
@@ -27,16 +26,13 @@
import '../src/dart/resolution/driver_resolution.dart';
import '../util/element_type_matchers.dart';
-import '../utils.dart';
-import 'analysis_context_factory.dart';
-import 'resolver_test_case.dart';
+import 'test_analysis_context.dart';
import 'test_support.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(AnnotationElementResolverTest);
defineReflectiveTests(ElementResolverTest);
- defineReflectiveTests(PreviewDart2Test);
});
}
@@ -63,11 +59,10 @@
Element annotationElement) {
expect(name1, isNotNull);
expect(name1.staticElement, isClassElement);
- expect(resolutionMap.staticElementForIdentifier(name1).displayName, 'A');
+ expect(name1.staticElement.displayName, 'A');
expect(name2, isNotNull);
expect(name2.staticElement, isConstructorElement);
- expect(
- resolutionMap.staticElementForIdentifier(name2).displayName, 'named');
+ expect(name2.staticElement.displayName, 'named');
expect(name3, isNull);
if (annotationElement is ConstructorElement) {
expect(annotationElement, same(name2.staticElement));
@@ -93,14 +88,13 @@
Element annotationElement) {
expect(name1, isNotNull);
expect(name1.staticElement, isPrefixElement);
- expect(resolutionMap.staticElementForIdentifier(name1).displayName, 'p');
+ expect(name1.staticElement.displayName, 'p');
expect(name2, isNotNull);
expect(name2.staticElement, isClassElement);
- expect(resolutionMap.staticElementForIdentifier(name2).displayName, 'A');
+ expect(name2.staticElement.displayName, 'A');
expect(name3, isNotNull);
expect(name3.staticElement, isConstructorElement);
- expect(
- resolutionMap.staticElementForIdentifier(name3).displayName, 'named');
+ expect(name3.staticElement.displayName, 'named');
if (annotationElement is ConstructorElement) {
expect(annotationElement, same(name3.staticElement));
expect(annotationElement.enclosingElement, name2.staticElement);
@@ -125,13 +119,13 @@
Element annotationElement) {
expect(name1, isNotNull);
expect(name1.staticElement, isPrefixElement);
- expect(resolutionMap.staticElementForIdentifier(name1).displayName, 'p');
+ expect(name1.staticElement.displayName, 'p');
expect(name2, isNotNull);
expect(name2.staticElement, isClassElement);
- expect(resolutionMap.staticElementForIdentifier(name2).displayName, 'A');
+ expect(name2.staticElement.displayName, 'A');
expect(name3, isNotNull);
expect(name3.staticElement, isPropertyAccessorElement);
- expect(resolutionMap.staticElementForIdentifier(name3).displayName, 'V');
+ expect(name3.staticElement.displayName, 'V');
if (annotationElement is PropertyAccessorElement) {
expect(annotationElement, same(name3.staticElement));
expect(annotationElement.enclosingElement, name2.staticElement);
@@ -155,10 +149,10 @@
Element annotationElement) {
expect(name1, isNotNull);
expect(name1.staticElement, isPrefixElement);
- expect(resolutionMap.staticElementForIdentifier(name1).displayName, 'p');
+ expect(name1.staticElement.displayName, 'p');
expect(name2, isNotNull);
expect(name2.staticElement, isClassElement);
- expect(resolutionMap.staticElementForIdentifier(name2).displayName, 'A');
+ expect(name2.staticElement.displayName, 'A');
expect(name3, isNull);
if (annotationElement is ConstructorElement) {
expect(annotationElement.enclosingElement, name2.staticElement);
@@ -183,10 +177,10 @@
Element annotationElement) {
expect(name1, isNotNull);
expect(name1.staticElement, isClassElement);
- expect(resolutionMap.staticElementForIdentifier(name1).displayName, 'A');
+ expect(name1.staticElement.displayName, 'A');
expect(name2, isNotNull);
expect(name2.staticElement, isPropertyAccessorElement);
- expect(resolutionMap.staticElementForIdentifier(name2).displayName, 'V');
+ expect(name2.staticElement.displayName, 'V');
expect(name3, isNull);
if (annotationElement is PropertyAccessorElement) {
expect(annotationElement, same(name2.staticElement));
@@ -211,7 +205,7 @@
Element annotationElement) {
expect(name1, isNotNull);
expect(name1.staticElement, isClassElement);
- expect(resolutionMap.staticElementForIdentifier(name1).displayName, 'A');
+ expect(name1.staticElement.displayName, 'A');
expect(name2, isNull);
expect(name3, isNull);
if (annotationElement is ConstructorElement) {
@@ -235,7 +229,7 @@
Element annotationElement) {
expect(name1, isNotNull);
expect(name1.staticElement, isPropertyAccessorElement);
- expect(resolutionMap.staticElementForIdentifier(name1).displayName, 'V');
+ expect(name1.staticElement.displayName, 'V');
expect(name2, isNull);
expect(name3, isNull);
if (annotationElement is PropertyAccessorElement) {
@@ -259,10 +253,10 @@
Element annotationElement) {
expect(name1, isNotNull);
expect(name1.staticElement, isPrefixElement);
- expect(resolutionMap.staticElementForIdentifier(name1).displayName, 'p');
+ expect(name1.staticElement.displayName, 'p');
expect(name2, isNotNull);
expect(name2.staticElement, isPropertyAccessorElement);
- expect(resolutionMap.staticElementForIdentifier(name2).displayName, 'V');
+ expect(name2.staticElement.displayName, 'V');
expect(name3, isNull);
if (annotationElement is PropertyAccessorElement) {
expect(annotationElement, same(name2.staticElement));
@@ -673,8 +667,7 @@
parameterElement.type = intType;
parameter.identifier.staticElement = parameterElement;
_resolveInClass(parameter, classA);
- expect(resolutionMap.elementDeclaredByFormalParameter(parameter).type,
- same(intType));
+ expect(parameter.declaredElement.type, same(intType));
}
test_visitImportDirective_noCombinators_noPrefix() async {
@@ -727,36 +720,6 @@
_listener.assertNoErrors();
}
- test_visitIndexExpression_get() async {
- ClassElementImpl classA = ElementFactory.classElement2("A");
- InterfaceType intType = _typeProvider.intType;
- MethodElement getter =
- ElementFactory.methodElement("[]", intType, [intType]);
- classA.methods = <MethodElement>[getter];
- SimpleIdentifier array = AstTestFactory.identifier3("a");
- array.staticType = classA.type;
- IndexExpression expression =
- AstTestFactory.indexExpression(array, AstTestFactory.identifier3("i"));
- expect(_resolveIndexExpression(expression), same(getter));
- _listener.assertNoErrors();
- }
-
- test_visitIndexExpression_set() async {
- ClassElementImpl classA = ElementFactory.classElement2("A");
- InterfaceType intType = _typeProvider.intType;
- MethodElement setter =
- ElementFactory.methodElement("[]=", intType, [intType]);
- classA.methods = <MethodElement>[setter];
- SimpleIdentifier array = AstTestFactory.identifier3("a");
- array.staticType = classA.type;
- IndexExpression expression =
- AstTestFactory.indexExpression(array, AstTestFactory.identifier3("i"));
- AstTestFactory.assignmentExpression(
- expression, TokenType.EQ, AstTestFactory.integer(0));
- expect(_resolveIndexExpression(expression), same(setter));
- _listener.assertNoErrors();
- }
-
test_visitInstanceCreationExpression_named() async {
ClassElementImpl classA = ElementFactory.classElement2("A");
String constructorName = "a";
@@ -1041,7 +1004,7 @@
test_visitSimpleIdentifier_classScope() async {
InterfaceType doubleType = _typeProvider.doubleType;
- String fieldName = "NAN";
+ String fieldName = 'nan';
SimpleIdentifier node = AstTestFactory.identifier3(fieldName);
_resolveInClass(node, doubleType.element);
expect(node.staticElement, getGetter(doubleType, fieldName));
@@ -1135,8 +1098,7 @@
* Create and return the resolver used by the tests.
*/
void _createResolver() {
- InternalAnalysisContext context = AnalysisContextFactory.contextWithCore(
- resourceProvider: resourceProvider);
+ AnalysisContext context = TestAnalysisContext();
_typeProvider = context.typeProvider;
var inheritance = new InheritanceManager3(context.typeSystem);
@@ -1282,343 +1244,3 @@
}
}
}
-
-@reflectiveTest
-class PreviewDart2Test extends ResolverTestCase {
- @override
- void setUp() {
- AnalysisOptionsImpl options = new AnalysisOptionsImpl();
- resetWith(options: options);
- }
-
- /**
- * Tests and verifies that even with a explicit 'new' keyword, the
- * construction of the InstanceCreationExpression node with types and elements
- * is all correct.
- */
- test_visitMethodInvocations_explicit() async {
- String code = '''
-class A {
- A() {}
-}
-main() {
- new A();
-}
- ''';
- CompilationUnit unit = await resolveSource(code);
- var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main');
-
- ExpressionStatement statement = statements[0];
- InstanceCreationExpression creation = statement.expression;
-
- expect(creation.staticElement, isConstructorElement);
- expect(creation.staticType, isNotNull);
-
- expect(creation.constructorName.staticElement, isConstructorElement);
-
- expect(creation.constructorName.type.type, isNotNull);
- expect(creation.constructorName.type.name.staticElement, isClassElement);
-
- expect(creation.constructorName.name, isNull);
- }
-
- /**
- * Test that the call to a constructor with an implicit unnamed constructor is
- * re-written as an InstanceCreationExpression AST node from a
- * MethodInvocation.
- *
- * C()
- */
- test_visitMethodInvocations_implicit() async {
- String code = '''
-class A {
- A(a, {b}) {}
-}
-main() {
- A(0, b: 1);
-}
- ''';
- CompilationUnit unit = await resolveSource(code);
- var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main');
-
- ExpressionStatement statement = statements[0];
- InstanceCreationExpression creation = statement.expression;
- ConstructorElement constructor = creation.staticElement;
-
- expect(constructor, isConstructorElement);
- expect(creation.staticType, isNotNull);
-
- expect(creation.constructorName.staticElement, constructor);
-
- expect(creation.constructorName.type.type, isNotNull);
- expect(creation.constructorName.type.name.staticElement, isClassElement);
-
- expect(creation.constructorName.name, isNull);
-
- List<Expression> arguments = creation.argumentList.arguments;
- Expression argumentA = arguments[0];
- expect(argumentA.staticParameterElement, constructor.parameters[0]);
- NamedExpression argumentB = arguments[1];
- expect(argumentB.name.label.staticElement, constructor.parameters[1]);
- }
-
- /**
- * Test that the call to a constructor with an implicit unnamed constructor is
- * re-written as an InstanceCreationExpression AST node from a
- * MethodInvocation.
- *
- * C(), where class C has no constructors
- */
- test_visitMethodInvocations_implicit_implicit() async {
- String code = '''
-class A {}
-main() {
- A();
-}
- ''';
- CompilationUnit unit = await resolveSource(code);
- var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main');
-
- ExpressionStatement statement = statements[0];
- InstanceCreationExpression creation = statement.expression;
- ConstructorElement constructor = creation.staticElement;
-
- expect(constructor, isConstructorElement);
- expect(creation.staticType, isNotNull);
-
- expect(creation.constructorName.staticElement, constructor);
-
- expect(creation.constructorName.type.type, isNotNull);
- expect(creation.constructorName.type.name.staticElement, isClassElement);
-
- expect(creation.constructorName.name, isNull);
-
- expect(creation.argumentList.arguments, isEmpty);
- }
-
- /**
- * Test that the call to a constructor with an implicit named constructor is
- * re-written as an InstanceCreationExpression AST node from a
- * MethodInvocation.
- *
- * C.n()
- */
- test_visitMethodInvocations_implicit_named() async {
- String code = '''
-class A {
- A.named() {}
-}
-main() {
- A.named();
-}
- ''';
- CompilationUnit unit = await resolveSource(code);
- var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main');
-
- ExpressionStatement statement = statements[0];
- InstanceCreationExpression creation = statement.expression;
- ConstructorElement constructor = creation.staticElement;
-
- expect(constructor, isConstructorElement);
- expect(creation.staticType, isNotNull);
-
- expect(creation.constructorName.staticElement, constructor);
-
- expect(creation.constructorName.type.type, isNotNull);
- expect(creation.constructorName.type.name.staticElement, isClassElement);
-
- expect(creation.constructorName.name.staticElement, constructor);
- }
-
- /**
- * Test that the call to a constructor with a prefixed implicit constructor is
- * re-written as an InstanceCreationExpression AST node from a
- * MethodInvocation.
- *
- * p.C()
- */
- test_visitMethodInvocations_implicit_prefixed() async {
- addNamedSource("/fileOne.dart", r'''
-class A {
- A() {}
-}
-''');
- String code = '''
-import 'fileOne.dart' as one;
-
-main() {
- one.A();
-}
- ''';
- CompilationUnit unit = await resolveSource(code);
- var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main');
-
- ExpressionStatement statement = statements[0];
- InstanceCreationExpression creation = statement.expression;
- ConstructorElement constructor = creation.staticElement;
-
- expect(constructor, isConstructorElement);
- expect(creation.staticType, isNotNull);
-
- expect(creation.constructorName.staticElement, constructor);
-
- expect(creation.constructorName.type.type, isNotNull);
- expect(creation.constructorName.type.name.staticElement, isClassElement);
-
- expect(creation.constructorName.name, isNull);
- }
-
- /**
- * Test that the call to a constructor with a prefixed implicit named constructor is
- * re-written as an InstanceCreationExpression AST node from a
- * MethodInvocation.
- *
- * p.C.n()
- */
- test_visitMethodInvocations_implicit_prefixed_named() async {
- addNamedSource("/fileOne.dart", r'''
-class A {
- A.named(a, {b}) {}
-}
-''');
- String code = '''
-import 'fileOne.dart' as one;
-main() {
- one.A.named(0, b: 1);
-}
- ''';
- CompilationUnit unit = await resolveSource(code);
- var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main');
-
- ExpressionStatement statement = statements[0];
- InstanceCreationExpression creation = statement.expression;
- ConstructorElement constructor = creation.staticElement;
-
- expect(constructor, isConstructorElement);
- expect(creation.staticType, isNotNull);
-
- expect(creation.constructorName.staticElement, constructor);
-
- expect(creation.constructorName.type.type, isNotNull);
- expect(creation.constructorName.type.name.staticElement, isClassElement);
-
- expect(creation.constructorName.name.staticElement, constructor);
-
- List<Expression> arguments = creation.argumentList.arguments;
- Expression argumentA = arguments[0];
- expect(argumentA.staticParameterElement, constructor.parameters[0]);
- NamedExpression argumentB = arguments[1];
- expect(argumentB.name.label.staticElement, constructor.parameters[1]);
- }
-
- /**
- * Test that the call to a constructor with a prefixed implicit constructor is
- * re-written as an InstanceCreationExpression AST node from a
- * MethodInvocation.
- *
- * p.C<>()
- */
- test_visitMethodInvocations_implicit_prefixed_typeArgs() async {
- addNamedSource("/fileOne.dart", r'''
-class A<T> {
- final T x;
- A(this.x) {}
-}
-''');
- String code = '''
-import 'fileOne.dart' as one;
-
-main() {
- one.A<int>(42);
-}
- ''';
- CompilationUnit unit = await resolveSource(code);
- var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main');
-
- ExpressionStatement statement = statements[0];
- InstanceCreationExpression creation = statement.expression;
- ConstructorElement constructor = creation.staticElement;
-
- expect(constructor, isConstructorElement);
- expect(creation.staticType, isNotNull);
-
- expect(creation.constructorName.staticElement, constructor);
-
- expect(creation.constructorName.type.type, isNotNull);
- expect(creation.constructorName.type.name.staticElement, isClassElement);
-
- expect(creation.constructorName.name, isNull);
- }
-
- /**
- * Test that the call to a constructor with an implicit unnamed constructor is
- * re-written as an InstanceCreationExpression AST node from a
- * MethodInvocation.
- *
- * C<>()
- */
- test_visitMethodInvocations_implicit_typeArgs() async {
- String code = '''
-class A<T> {
- final T x;
- A(this.x) {}
-}
-main() {
- A<int>(42);
-}
- ''';
- CompilationUnit unit = await resolveSource(code);
- var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main');
-
- ExpressionStatement statement = statements[0];
- InstanceCreationExpression creation = statement.expression;
- ConstructorElement constructor = creation.staticElement;
-
- expect(constructor, isConstructorElement);
- expect(creation.staticType, isNotNull);
-
- expect(creation.constructorName.staticElement, constructor);
-
- expect(creation.constructorName.type.type, isNotNull);
- expect(creation.constructorName.type.name.staticElement, isClassElement);
-
- expect(creation.constructorName.name, isNull);
- }
-
- test_visitMethodInvocations_importPrefix_function() async {
- String code = '''
-import 'dart:math' as ma;
-main() {
- ma.max(1, 2); // marker
-}
-''';
- CompilationUnit unit = await resolveSource(code);
- var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main');
-
- ExpressionStatement statement = statements[0];
- MethodInvocation invocation = statement.expression;
-
- SimpleIdentifier prefix = invocation.target;
- expect(prefix.staticElement, isPrefixElement);
-
- expect(invocation.methodName.name, 'max');
- }
-
- /**
- * Test that the call to a static method will not be re-written as a
- * InstanceCreationExpression AST node.
- */
- test_visitMethodInvocations_not_implicit_constructor() async {
- String code = '''
-class A {
- static staticMethod() {}
-}
-main() {
- A.staticMethod(); // marker
-}
- ''';
- CompilationUnit unit = await resolveSource(code);
- AstNode node = findMarkedIdentifier(code, unit, "(); // marker");
- assert(node.parent is MethodInvocation);
- }
-}
diff --git a/pkg/analyzer/test/generated/engine_test.dart b/pkg/analyzer/test/generated/engine_test.dart
index dfd1476..c183ac8 100644
--- a/pkg/analyzer/test/generated/engine_test.dart
+++ b/pkg/analyzer/test/generated/engine_test.dart
@@ -3,15 +3,12 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/source_io.dart';
-import 'package:analyzer/src/string_source.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(AnalysisOptionsImplTest);
- defineReflectiveTests(SourcesChangedEventTest);
});
}
@@ -62,74 +59,3 @@
defaultOptions.trackCacheDependencies);
}
}
-
-@reflectiveTest
-class SourcesChangedEventTest {
- void test_added() {
- var source = new StringSource('', '/test.dart');
- var changeSet = new ChangeSet();
- changeSet.addedSource(source);
- var event = new SourcesChangedEvent(changeSet);
- assertEvent(event, wereSourcesAdded: true);
- }
-
- void test_changedContent() {
- var source = new StringSource('', '/test.dart');
- var changeSet = new ChangeSet();
- changeSet.changedContent(source, 'library A;');
- var event = new SourcesChangedEvent(changeSet);
- assertEvent(event, changedSources: [source]);
- }
-
- void test_changedContent2() {
- var source = new StringSource('', '/test.dart');
- var event = new SourcesChangedEvent.changedContent(source, 'library A;');
- assertEvent(event, changedSources: [source]);
- }
-
- void test_changedRange() {
- var source = new StringSource('', '/test.dart');
- var changeSet = new ChangeSet();
- changeSet.changedRange(source, 'library A;', 0, 0, 13);
- var event = new SourcesChangedEvent(changeSet);
- assertEvent(event, changedSources: [source]);
- }
-
- void test_changedRange2() {
- var source = new StringSource('', '/test.dart');
- var event =
- new SourcesChangedEvent.changedRange(source, 'library A;', 0, 0, 13);
- assertEvent(event, changedSources: [source]);
- }
-
- void test_changedSources() {
- var source = new StringSource('', '/test.dart');
- var changeSet = new ChangeSet();
- changeSet.changedSource(source);
- var event = new SourcesChangedEvent(changeSet);
- assertEvent(event, changedSources: [source]);
- }
-
- void test_empty() {
- var changeSet = new ChangeSet();
- var event = new SourcesChangedEvent(changeSet);
- assertEvent(event);
- }
-
- void test_removed() {
- var source = new StringSource('', '/test.dart');
- var changeSet = new ChangeSet();
- changeSet.removedSource(source);
- var event = new SourcesChangedEvent(changeSet);
- assertEvent(event, wereSourcesRemoved: true);
- }
-
- static void assertEvent(SourcesChangedEvent event,
- {bool wereSourcesAdded: false,
- List<Source> changedSources: const <Source>[],
- bool wereSourcesRemoved: false}) {
- expect(event.wereSourcesAdded, wereSourcesAdded);
- expect(event.changedSources, changedSources);
- expect(event.wereSourcesRemoved, wereSourcesRemoved);
- }
-}
diff --git a/pkg/analyzer/test/generated/inheritance_manager_test.dart b/pkg/analyzer/test/generated/inheritance_manager_test.dart
index 8673c9e..881eb2c 100644
--- a/pkg/analyzer/test/generated/inheritance_manager_test.dart
+++ b/pkg/analyzer/test/generated/inheritance_manager_test.dart
@@ -19,7 +19,7 @@
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
-import 'analysis_context_factory.dart';
+import 'test_analysis_context.dart';
main() {
defineReflectiveSuite(() {
@@ -1110,8 +1110,7 @@
*/
@deprecated
InheritanceManager _createInheritanceManager() {
- AnalysisContext context = AnalysisContextFactory.contextWithCore(
- resourceProvider: resourceProvider);
+ AnalysisContext context = TestAnalysisContext();
Source source = new FileSource(getFile("/test.dart"));
CompilationUnitElementImpl definingCompilationUnit =
new CompilationUnitElementImpl();
diff --git a/pkg/analyzer/test/generated/invalid_code_test.dart b/pkg/analyzer/test/generated/invalid_code_test.dart
index 9e7c84f..c77fa3e0 100644
--- a/pkg/analyzer/test/generated/invalid_code_test.dart
+++ b/pkg/analyzer/test/generated/invalid_code_test.dart
@@ -4,16 +4,32 @@
import 'dart:async';
+import 'package:analyzer/dart/analysis/features.dart';
+import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:analyzer/src/generated/engine.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../src/dart/resolution/driver_resolution.dart';
main() {
defineReflectiveSuite(() {
- defineReflectiveTests(InvalidCodeTest);
+ if (AnalysisDriver.useSummary2) {
+ defineReflectiveTests(InvalidCodeSummary2Test);
+ } else {
+ defineReflectiveTests(InvalidCodeTest);
+ }
+ defineReflectiveTests(InvalidCodeWithExtensionMethodsTest);
});
}
+@reflectiveTest
+class InvalidCodeSummary2Test extends InvalidCodeTest {
+ @failingTest
+ test_fuzz_12() {
+ return test_fuzz_12();
+ }
+}
+
/// Tests for various end-to-end cases when invalid code caused exceptions
/// in one or another Analyzer subsystem. We are not interested not in specific
/// errors generated, but we want to make sure that there is at least one,
@@ -115,6 +131,53 @@
''');
}
+ test_fuzz_09() async {
+ await _assertCanBeAnalyzed(r'''
+typedef void F(int a, this.b);
+''');
+ var function = findElement.genericTypeAlias('F').function;
+ assertElementTypeString(
+ function.type,
+ 'void Function(int, dynamic)',
+ );
+ }
+
+ test_fuzz_10() async {
+ await _assertCanBeAnalyzed(r'''
+void f<@A(() { Function() v; }) T>() {}
+''');
+ }
+
+ test_fuzz_11() async {
+ // Here `F` is a generic function, so it cannot be used as a bound for
+ // a type parameter. The reason it crashed was that we did not build
+ // the bound for `Y` (not `T`), because of the order in which types
+ // for `T extends F` and `typedef F` were built.
+ await _assertCanBeAnalyzed(r'''
+typedef F<X> = void Function<Y extends num>();
+class A<T extends F> {}
+''');
+ }
+
+ test_fuzz_12() async {
+ // This code crashed with summary2 because usually AST reader is lazy,
+ // so we did not read metadata `@b` for `c`. But default values must be
+ // read fully.
+ await _assertCanBeAnalyzed(r'''
+void f({a = [for (@b c = 0;;)]}) {}
+''');
+ }
+
+ test_fuzz_13() async {
+ // `x is int` promotes the type of `x` to `S extends int`, and the
+ // underlying element is `TypeParameterMember`, which by itself is
+ // questionable. But this is not a valid constant anyway, so we should
+ // not even try to serialize it.
+ await _assertCanBeAnalyzed(r'''
+const v = [<S extends num>(S x) => x is int ? x : 0];
+''');
+ }
+
test_genericFunction_asTypeArgument_ofUnresolvedClass() async {
await _assertCanBeAnalyzed(r'''
C<int Function()> c;
@@ -159,3 +222,28 @@
assertHasTestErrors();
}
}
+
+@reflectiveTest
+class InvalidCodeWithExtensionMethodsTest extends DriverResolutionTest {
+ @override
+ AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+ ..contextFeatures = new FeatureSet.forTesting(
+ sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
+
+ test_fuzz_14() async {
+ // This crashes because parser produces `ConstructorDeclaration`.
+ // So, we try to create `ConstructorElement` for it, and it wants
+ // `ClassElement` as the enclosing element. But we have `ExtensionElement`.
+ await _assertCanBeAnalyzed(r'''
+extension E {
+ factory S() {}
+}
+''');
+ }
+
+ Future<void> _assertCanBeAnalyzed(String text) async {
+ addTestFile(text);
+ await resolveTestFile();
+ assertHasTestErrors();
+ }
+}
diff --git a/pkg/analyzer/test/generated/non_error_resolver_test.dart b/pkg/analyzer/test/generated/non_error_resolver_test.dart
index 11fa1ce..729a4a0 100644
--- a/pkg/analyzer/test/generated/non_error_resolver_test.dart
+++ b/pkg/analyzer/test/generated/non_error_resolver_test.dart
@@ -6,7 +6,6 @@
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/engine.dart';
@@ -793,8 +792,7 @@
class E {}
''');
CompilationUnit unit = result.unit;
- ClassElement classC =
- resolutionMap.elementDeclaredByCompilationUnit(unit).getType('C');
+ ClassElement classC = unit.declaredElement.getType('C');
expect(classC.documentationComment, isNotNull);
}
@@ -1894,8 +1892,7 @@
class C extends A<B> with M {}
''');
CompilationUnit unit = result.unit;
- ClassElement classC =
- resolutionMap.elementDeclaredByCompilationUnit(unit).getType('C');
+ ClassElement classC = unit.declaredElement.getType('C');
expect(classC.mixins, hasLength(1));
expect(classC.mixins[0].toString(), 'M<B>');
}
@@ -1917,8 +1914,7 @@
),
]);
CompilationUnit unit = result.unit;
- ClassElement classC =
- resolutionMap.elementDeclaredByCompilationUnit(unit).getType('C');
+ ClassElement classC = unit.declaredElement.getType('C');
expect(classC.mixins, hasLength(1));
expect(classC.mixins[0].toString(), 'M<int, String>');
}
@@ -1934,8 +1930,7 @@
class C extends A<List<B>> with M {}
''');
CompilationUnit unit = result.unit;
- ClassElement classC =
- resolutionMap.elementDeclaredByCompilationUnit(unit).getType('C');
+ ClassElement classC = unit.declaredElement.getType('C');
expect(classC.mixins, hasLength(1));
expect(classC.mixins[0].toString(), 'M<B>');
}
diff --git a/pkg/analyzer/test/generated/parser_fasta_listener.dart b/pkg/analyzer/test/generated/parser_fasta_listener.dart
index dd1a16f..f3145f8 100644
--- a/pkg/analyzer/test/generated/parser_fasta_listener.dart
+++ b/pkg/analyzer/test/generated/parser_fasta_listener.dart
@@ -32,34 +32,13 @@
class ForwardingTestListener extends ForwardingListener {
final _stack = <String>[];
+ ForwardingTestListener([Listener listener]) : super(listener);
+
void begin(String event) {
expect(event, isNotNull);
_stack.add(event);
}
- void expectEmpty() {
- expect(_stack, isEmpty);
- }
-
- void expectIn(String event) {
- if (_stack.isEmpty || _stack.last != event) {
- fail('Expected $event, but found $_stack');
- }
- }
-
- void expectInOneOf(List<String> events) {
- if (_stack.isEmpty || !events.contains(_stack.last)) {
- fail('Expected one of $events, but found $_stack');
- }
- }
-
- void end(String event) {
- expectIn(event);
- _stack.removeLast();
- }
-
- ForwardingTestListener([Listener listener]) : super(listener);
-
@override
void beginArguments(Token token) {
super.beginArguments(token);
@@ -116,14 +95,14 @@
}
@override
- void beginClassOrMixinBody(ClassKind kind, Token token) {
+ void beginClassOrMixinBody(DeclarationKind kind, Token token) {
super.beginClassOrMixinBody(kind, token);
begin('ClassOrMixinBody');
}
@override
- void beginClassOrNamedMixinApplication(Token token) {
- super.beginClassOrNamedMixinApplication(token);
+ void beginClassOrNamedMixinApplicationPrelude(Token token) {
+ super.beginClassOrNamedMixinApplicationPrelude(token);
begin('ClassOrNamedMixinApplication');
}
@@ -202,6 +181,12 @@
}
@override
+ void beginExtensionDeclarationPrelude(Token extensionKeyword) {
+ super.beginExtensionDeclarationPrelude(extensionKeyword);
+ begin('ExtensionDeclarationPrelude');
+ }
+
+ @override
void beginExtensionDeclaration(Token extensionKeyword, Token name) {
super.beginExtensionDeclaration(extensionKeyword, name);
begin('ExtensionDeclaration');
@@ -558,6 +543,11 @@
begin('YieldStatement');
}
+ void end(String event) {
+ expectIn(event);
+ _stack.removeLast();
+ }
+
@override
void endArguments(int count, Token beginToken, Token endToken) {
end('Arguments');
@@ -579,13 +569,6 @@
}
@override
- void endInvalidAwaitExpression(
- Token beginToken, Token endToken, MessageCode errorCode) {
- end('InvalidAwaitExpression');
- super.endInvalidAwaitExpression(beginToken, endToken, errorCode);
- }
-
- @override
void endBlock(int count, Token beginToken, Token endToken) {
end('Block');
super.endBlock(count, beginToken, endToken);
@@ -616,6 +599,14 @@
}
@override
+ void endClassConstructor(Token getOrSet, Token beginToken, Token beginParam,
+ Token beginInitializers, Token endToken) {
+ end('Method');
+ super.endClassConstructor(
+ getOrSet, beginToken, beginParam, beginInitializers, endToken);
+ }
+
+ @override
void endClassDeclaration(Token beginToken, Token endToken) {
end('ClassDeclaration');
end('ClassOrNamedMixinApplication');
@@ -623,8 +614,32 @@
}
@override
+ void endClassFactoryMethod(
+ Token beginToken, Token factoryKeyword, Token endToken) {
+ end('FactoryMethod');
+ super.endClassFactoryMethod(beginToken, factoryKeyword, endToken);
+ }
+
+ @override
+ void endClassFields(Token staticToken, Token covariantToken, Token lateToken,
+ Token varFinalOrConst, int count, Token beginToken, Token endToken) {
+ // beginMember --> endClassFields, endMember
+ expectIn('Member');
+ super.endClassFields(staticToken, covariantToken, lateToken,
+ varFinalOrConst, count, beginToken, endToken);
+ }
+
+ @override
+ void endClassMethod(Token getOrSet, Token beginToken, Token beginParam,
+ Token beginInitializers, Token endToken) {
+ end('Method');
+ super.endClassMethod(
+ getOrSet, beginToken, beginParam, beginInitializers, endToken);
+ }
+
+ @override
void endClassOrMixinBody(
- ClassKind kind, int memberCount, Token beginToken, Token endToken) {
+ DeclarationKind kind, int memberCount, Token beginToken, Token endToken) {
end('ClassOrMixinBody');
super.endClassOrMixinBody(kind, memberCount, beginToken, endToken);
}
@@ -705,6 +720,14 @@
}
@override
+ void endExtensionConstructor(Token getOrSet, Token beginToken,
+ Token beginParam, Token beginInitializers, Token endToken) {
+ end('Method');
+ super.endExtensionConstructor(
+ getOrSet, beginToken, beginParam, beginInitializers, endToken);
+ }
+
+ @override
void endExtensionDeclaration(
Token extensionKeyword, Token onKeyword, Token token) {
super.endExtensionDeclaration(extensionKeyword, onKeyword, token);
@@ -712,10 +735,33 @@
}
@override
- void endFactoryMethod(
+ void endExtensionFactoryMethod(
Token beginToken, Token factoryKeyword, Token endToken) {
end('FactoryMethod');
- super.endFactoryMethod(beginToken, factoryKeyword, endToken);
+ super.endExtensionFactoryMethod(beginToken, factoryKeyword, endToken);
+ }
+
+ @override
+ void endExtensionFields(
+ Token staticToken,
+ Token covariantToken,
+ Token lateToken,
+ Token varFinalOrConst,
+ int count,
+ Token beginToken,
+ Token endToken) {
+ // beginMember --> endExtensionFields, endMember
+ expectIn('Member');
+ super.endExtensionFields(staticToken, covariantToken, lateToken,
+ varFinalOrConst, count, beginToken, endToken);
+ }
+
+ @override
+ void endExtensionMethod(Token getOrSet, Token beginToken, Token beginParam,
+ Token beginInitializers, Token endToken) {
+ end('Method');
+ super.endExtensionMethod(
+ getOrSet, beginToken, beginParam, beginInitializers, endToken);
}
@override
@@ -725,15 +771,6 @@
}
@override
- void endFields(Token staticToken, Token covariantToken, Token lateToken,
- Token varFinalOrConst, int count, Token beginToken, Token endToken) {
- // beginMember --> endFields, endMember
- expectIn('Member');
- super.endFields(staticToken, covariantToken, lateToken, varFinalOrConst,
- count, beginToken, endToken);
- }
-
- @override
void endForControlFlow(Token token) {
end('ForControlFlow');
super.endForControlFlow(token);
@@ -876,6 +913,13 @@
}
@override
+ void endInvalidAwaitExpression(
+ Token beginToken, Token endToken, MessageCode errorCode) {
+ end('InvalidAwaitExpression');
+ super.endInvalidAwaitExpression(beginToken, endToken, errorCode);
+ }
+
+ @override
void endLabeledStatement(int labelCount) {
end('LabeledStatement');
super.endLabeledStatement(labelCount);
@@ -924,10 +968,10 @@
}
@override
- void endMethod(Token getOrSet, Token beginToken, Token beginParam,
+ void endMixinConstructor(Token getOrSet, Token beginToken, Token beginParam,
Token beginInitializers, Token endToken) {
end('Method');
- super.endMethod(
+ super.endMixinConstructor(
getOrSet, beginToken, beginParam, beginInitializers, endToken);
}
@@ -939,6 +983,30 @@
}
@override
+ void endMixinFactoryMethod(
+ Token beginToken, Token factoryKeyword, Token endToken) {
+ end('FactoryMethod');
+ super.endMixinFactoryMethod(beginToken, factoryKeyword, endToken);
+ }
+
+ @override
+ void endMixinFields(Token staticToken, Token covariantToken, Token lateToken,
+ Token varFinalOrConst, int count, Token beginToken, Token endToken) {
+ // beginMember --> endMixinFields, endMember
+ expectIn('Member');
+ super.endMixinFields(staticToken, covariantToken, lateToken,
+ varFinalOrConst, count, beginToken, endToken);
+ }
+
+ @override
+ void endMixinMethod(Token getOrSet, Token beginToken, Token beginParam,
+ Token beginInitializers, Token endToken) {
+ end('Method');
+ super.endMixinMethod(
+ getOrSet, beginToken, beginParam, beginInitializers, endToken);
+ }
+
+ @override
void endNamedFunctionExpression(Token endToken) {
end('NamedFunctionExpression');
super.endNamedFunctionExpression(endToken);
@@ -1125,6 +1193,22 @@
super.endYieldStatement(yieldToken, starToken, endToken);
}
+ void expectEmpty() {
+ expect(_stack, isEmpty);
+ }
+
+ void expectIn(String event) {
+ if (_stack.isEmpty || _stack.last != event) {
+ fail('Expected $event, but found $_stack');
+ }
+ }
+
+ void expectInOneOf(List<String> events) {
+ if (_stack.isEmpty || !events.contains(_stack.last)) {
+ fail('Expected one of $events, but found $_stack');
+ }
+ }
+
@override
void handleClassExtends(Token extendsKeyword) {
expectIn('ClassDeclaration');
diff --git a/pkg/analyzer/test/generated/parser_fasta_test.dart b/pkg/analyzer/test/generated/parser_fasta_test.dart
index e8674b8..0bc30b6 100644
--- a/pkg/analyzer/test/generated/parser_fasta_test.dart
+++ b/pkg/analyzer/test/generated/parser_fasta_test.dart
@@ -253,9 +253,6 @@
createParser('late var f;', featureSet: nonNullable);
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
- assertErrors(errors: [
- expectedError(ParserErrorCode.CONFLICTING_MODIFIERS, 5, 3),
- ]);
expect(member, isFieldDeclaration);
FieldDeclaration field = member;
expect(field.covariantKeyword, isNull);
@@ -280,7 +277,7 @@
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertErrors(errors: [
- expectedError(ParserErrorCode.CONFLICTING_MODIFIERS, 4, 4),
+ expectedError(ParserErrorCode.MODIFIER_OUT_OF_ORDER, 4, 4),
]);
expect(member, isFieldDeclaration);
FieldDeclaration field = member;
@@ -2611,6 +2608,17 @@
parseCompilationUnit('main() { for(int? x in [7, null]) { } }');
}
+ test_fuzz_38113() async {
+ // https://github.com/dart-lang/sdk/issues/38113
+ await parseCompilationUnit(r'+t{{r?this}}', errors: [
+ expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 0, 1),
+ expectedError(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, 1, 1),
+ expectedError(ParserErrorCode.MISSING_IDENTIFIER, 6, 4),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 10, 1),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 10, 1),
+ ]);
+ }
+
void test_gft_nullable() {
parseCompilationUnit('main() { C? Function() x = 7; }');
}
@@ -2835,6 +2843,23 @@
expect(target.operator.lexeme, '!');
}
+ void test_nullCheckOnIndex2() {
+ // https://github.com/dart-lang/sdk/issues/37708
+ var unit = parseCompilationUnit('f() { obj![arg]![arg2]; }');
+ var funct = unit.declarations[0] as FunctionDeclaration;
+ var body = funct.functionExpression.body as BlockFunctionBody;
+ var statement = body.block.statements[0] as ExpressionStatement;
+ var expression = statement.expression as IndexExpression;
+ expect(expression.index.toSource(), 'arg2');
+ var target = expression.target as PostfixExpression;
+ expect(target.operator.lexeme, '!');
+ expression = target.operand as IndexExpression;
+ expect(expression.index.toSource(), 'arg');
+ target = expression.target as PostfixExpression;
+ expect(target.operator.lexeme, '!');
+ expect(target.operand.toSource(), 'obj');
+ }
+
void test_nullCheckOnLiteral_disabled() {
parseCompilationUnit('f() { var x = 0!; }',
errors: [expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 15, 1)],
@@ -2888,6 +2913,23 @@
expect(target.operator.lexeme, '!');
}
+ void test_nullCheckOnSend2() {
+ // https://github.com/dart-lang/sdk/issues/37708
+ var unit = parseCompilationUnit('f() { obj!(arg)!(arg2); }');
+ var funct = unit.declarations[0] as FunctionDeclaration;
+ var body = funct.functionExpression.body as BlockFunctionBody;
+ var statement = body.block.statements[0] as ExpressionStatement;
+ var expression = statement.expression as FunctionExpressionInvocation;
+ expect(expression.argumentList.toSource(), '(arg2)');
+ var target = expression.function as PostfixExpression;
+ expect(target.operator.lexeme, '!');
+ expression = target.operand as FunctionExpressionInvocation;
+ expect(expression.argumentList.toSource(), '(arg)');
+ target = expression.function as PostfixExpression;
+ expect(target.operator.lexeme, '!');
+ expect(target.operand.toSource(), 'obj');
+ }
+
void test_nullCheckOnSymbol() {
// Issues like this should be caught during later analysis
parseCompilationUnit('f() { var x = #seven!; }');
@@ -3299,6 +3341,17 @@
expect(declarationList.variables, hasLength(1));
}
+ void test_parseVariableDeclaration_late_var() {
+ var statement = parseStatement('late var a;', featureSet: nonNullable)
+ as VariableDeclarationStatement;
+ var declarationList = statement.variables;
+ assertNoErrors();
+ expect(declarationList.lateKeyword, isNotNull);
+ expect(declarationList.keyword?.lexeme, 'var');
+ expect(declarationList.type, isNull);
+ expect(declarationList.variables, hasLength(1));
+ }
+
void test_typeAlias_37733() {
// https://github.com/dart-lang/sdk/issues/37733
var unit = parseCompilationUnit(r'typedef K=Function(<>($', errors: [
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index cca8618..584d201 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -5083,7 +5083,7 @@
MethodInvocation methodInvocation = parseCascadeSection('..()');
expectNotNullIfNoErrors(methodInvocation);
listener.assertErrors([
- // Cascade section is preceeded by `null` in this test
+ // Cascade section is preceded by `null` in this test
// and error is reported on '('.
expectedError(ParserErrorCode.MISSING_IDENTIFIER, 6, 1)
]);
@@ -5097,7 +5097,7 @@
MethodInvocation methodInvocation = parseCascadeSection('..<E>()');
expectNotNullIfNoErrors(methodInvocation);
listener.assertErrors([
- // Cascade section is preceeded by `null` in this test
+ // Cascade section is preceded by `null` in this test
// and error is reported on '<'.
expectedError(ParserErrorCode.MISSING_IDENTIFIER, 6, 1)
]);
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index 663ec18..0b7c771 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -8,7 +8,6 @@
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/standard_ast_factory.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
@@ -17,6 +16,7 @@
import 'package:analyzer/src/dart/element/builder.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/type_provider.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/parser.dart' show ParserErrorCode;
@@ -26,15 +26,14 @@
import 'package:analyzer/src/generated/testing/element_factory.dart';
import 'package:analyzer/src/generated/testing/test_type_provider.dart';
import 'package:analyzer/src/source/source_resource.dart';
-import 'package:analyzer/src/string_source.dart';
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../src/dart/resolution/driver_resolution.dart';
-import 'analysis_context_factory.dart';
import 'parser_test.dart';
import 'resolver_test_case.dart';
+import 'test_analysis_context.dart';
import 'test_support.dart';
main() {
@@ -50,7 +49,6 @@
defineReflectiveTests(ScopeTest);
defineReflectiveTests(StrictModeTest);
defineReflectiveTests(TypePropagationTest);
- defineReflectiveTests(TypeProviderImplTest);
defineReflectiveTests(TypeResolverVisitorTest);
});
}
@@ -255,8 +253,7 @@
}
void test_creation_nonEmpty() {
- AnalysisContext context = AnalysisContextFactory.contextWithCore(
- resourceProvider: resourceProvider);
+ AnalysisContext context = TestAnalysisContext();
String importedTypeName = "A";
ClassElement importedType = new ClassElementImpl.forNode(
AstTestFactory.identifier3(importedTypeName));
@@ -276,8 +273,7 @@
}
void test_extensions_imported() {
- var context = AnalysisContextFactory.contextWithCore(
- resourceProvider: resourceProvider);
+ var context = TestAnalysisContext();
var extension = ElementFactory.extensionElement('test_extension');
@@ -304,8 +300,7 @@
}
void test_prefixedAndNonPrefixed() {
- AnalysisContext context = AnalysisContextFactory.contextWithCore(
- resourceProvider: resourceProvider);
+ AnalysisContext context = TestAnalysisContext();
String typeName = "C";
String prefixName = "p";
ClassElement prefixedType = ElementFactory.classElement2(typeName);
@@ -345,8 +340,7 @@
}
void test_creation_nonEmpty() {
- AnalysisContext context = AnalysisContextFactory.contextWithCore(
- resourceProvider: resourceProvider);
+ AnalysisContext context = TestAnalysisContext();
String importedTypeName = "A";
ClassElement importedType = new ClassElementImpl.forNode(
AstTestFactory.identifier3(importedTypeName));
@@ -382,8 +376,7 @@
}
void test_extensions_imported() {
- var context = AnalysisContextFactory.contextWithCore(
- resourceProvider: resourceProvider);
+ var context = TestAnalysisContext();
var importedUnit1 = ElementFactory.compilationUnit('/imported1.dart');
var importedExtension = ElementFactory.extensionElement('test_extension');
@@ -419,8 +412,7 @@
/// Ensure that if a library L1 defines an extension E, L2 exports L1, and L3
/// imports L2, then E is included in the list.
void test_extensions_imported_chain() {
- var context = AnalysisContextFactory.contextWithCore(
- resourceProvider: resourceProvider);
+ var context = TestAnalysisContext();
var unit1 = ElementFactory.compilationUnit('/unit1.dart');
var ext1 = ElementFactory.extensionElement('ext1');
@@ -462,8 +454,7 @@
/// imported from different libraries that they are both in the list of
/// extensions.
void test_extensions_imported_same_name() {
- var context = AnalysisContextFactory.contextWithCore(
- resourceProvider: resourceProvider);
+ var context = TestAnalysisContext();
var sharedExtensionName = 'test_ext';
@@ -507,8 +498,7 @@
/// Ensure that if there are two imports for the same library that the
/// imported extension is only in the list one time.
void test_extensions_imported_twice() {
- var context = AnalysisContextFactory.contextWithCore(
- resourceProvider: resourceProvider);
+ var context = TestAnalysisContext();
var sharedExtensionName = 'test_ext';
@@ -611,8 +601,11 @@
//
// Create a type provider and ensure that it can return the expected types.
//
- TypeProvider provider =
- new NonNullableTypeProvider(coreLibrary, asyncLibrary);
+ TypeProvider provider = new TypeProviderImpl(
+ coreLibrary,
+ asyncLibrary,
+ nullabilitySuffix: NullabilitySuffix.none,
+ );
assertNonNullable(provider.boolType);
expect(provider.bottomType, isNotNull);
assertNonNullable(provider.deprecatedType);
@@ -822,8 +815,7 @@
void visitPrefixedIdentifier(PrefixedIdentifier node) {
// In cases where we have a prefixed identifier where the prefix is dynamic,
// we don't want to assert that the node will have a type.
- if (node.staticType == null &&
- resolutionMap.staticTypeForExpression(node.prefix).isDynamic) {
+ if (node.staticType == null && node.prefix.staticType.isDynamic) {
return;
}
super.visitPrefixedIdentifier(node);
@@ -885,10 +877,7 @@
if (root is CompilationUnit) {
CompilationUnit rootCU = root;
if (rootCU.declaredElement != null) {
- return resolutionMap
- .elementDeclaredByCompilationUnit(rootCU)
- .source
- .fullName;
+ return rootCU.declaredElement.source.fullName;
} else {
return "<unknown file- CompilationUnit.getElement() returned null>";
}
@@ -1342,116 +1331,6 @@
}
@reflectiveTest
-class TypeProviderImplTest extends EngineTestCase {
- void test_creation() {
- //
- // Create a mock library element with the types expected to be in dart:core.
- // We cannot use either ElementFactory or TestTypeProvider (which uses
- // ElementFactory) because we side-effect the elements in ways that would
- // break other tests.
- //
- InterfaceType objectType = _classElement("Object", null).type;
- InterfaceType boolType = _classElement("bool", objectType).type;
- InterfaceType numType = _classElement("num", objectType).type;
- InterfaceType doubleType = _classElement("double", numType).type;
- InterfaceType functionType = _classElement("Function", objectType).type;
- InterfaceType futureType = _classElement("Future", objectType, ["T"]).type;
- InterfaceType futureOrType =
- _classElement("FutureOr", objectType, ["T"]).type;
- InterfaceType intType = _classElement("int", numType).type;
- InterfaceType iterableType =
- _classElement("Iterable", objectType, ["T"]).type;
- InterfaceType listType = _classElement("List", objectType, ["E"]).type;
- InterfaceType mapType = _classElement("Map", objectType, ["K", "V"]).type;
- InterfaceType setType = _classElement("Set", objectType, ["E"]).type;
- InterfaceType stackTraceType = _classElement("StackTrace", objectType).type;
- InterfaceType streamType = _classElement("Stream", objectType, ["T"]).type;
- InterfaceType stringType = _classElement("String", objectType).type;
- InterfaceType symbolType = _classElement("Symbol", objectType).type;
- InterfaceType typeType = _classElement("Type", objectType).type;
- CompilationUnitElementImpl coreUnit = new CompilationUnitElementImpl();
- coreUnit.types = <ClassElement>[
- boolType.element,
- doubleType.element,
- functionType.element,
- intType.element,
- iterableType.element,
- listType.element,
- mapType.element,
- setType.element,
- objectType.element,
- stackTraceType.element,
- stringType.element,
- symbolType.element,
- typeType.element
- ];
- coreUnit.source = new StringSource('', null, uri: Uri.parse('dart:core'));
- coreUnit.librarySource = coreUnit.source;
- CompilationUnitElementImpl asyncUnit = new CompilationUnitElementImpl();
- asyncUnit.types = <ClassElement>[
- futureType.element,
- futureOrType.element,
- streamType.element
- ];
-
- asyncUnit.source = new StringSource('', null, uri: Uri.parse('dart:async'));
- asyncUnit.librarySource = asyncUnit.source;
- LibraryElementImpl coreLibrary = new LibraryElementImpl.forNode(
- null, null, AstTestFactory.libraryIdentifier2(["dart.core"]), true);
- coreLibrary.definingCompilationUnit = coreUnit;
- LibraryElementImpl asyncLibrary = new LibraryElementImpl.forNode(
- null, null, AstTestFactory.libraryIdentifier2(["dart.async"]), true);
- asyncLibrary.definingCompilationUnit = asyncUnit;
- //
- // Create a type provider and ensure that it can return the expected types.
- //
- TypeProviderImpl provider = new TypeProviderImpl(coreLibrary, asyncLibrary);
- expect(provider.boolType, same(boolType));
- expect(provider.bottomType, isNotNull);
- expect(provider.doubleType, same(doubleType));
- expect(provider.dynamicType, isNotNull);
- expect(provider.functionType, same(functionType));
- expect(provider.futureType, same(futureType));
- expect(provider.futureOrType, same(futureOrType));
- expect(provider.intType, same(intType));
- expect(provider.listType, same(listType));
- expect(provider.mapType, same(mapType));
- expect(provider.objectType, same(objectType));
- expect(provider.stackTraceType, same(stackTraceType));
- expect(provider.streamType, same(streamType));
- expect(provider.stringType, same(stringType));
- expect(provider.symbolType, same(symbolType));
- expect(provider.typeType, same(typeType));
- }
-
- ClassElement _classElement(String typeName, InterfaceType superclassType,
- [List<String> parameterNames]) {
- ClassElementImpl element =
- new ClassElementImpl.forNode(AstTestFactory.identifier3(typeName));
- element.supertype = superclassType;
- if (parameterNames != null) {
- int count = parameterNames.length;
- if (count > 0) {
- List<TypeParameterElementImpl> typeParameters =
- new List<TypeParameterElementImpl>(count);
- List<TypeParameterTypeImpl> typeArguments =
- new List<TypeParameterTypeImpl>(count);
- for (int i = 0; i < count; i++) {
- TypeParameterElementImpl typeParameter =
- new TypeParameterElementImpl.forNode(
- AstTestFactory.identifier3(parameterNames[i]));
- typeParameters[i] = typeParameter;
- typeArguments[i] = new TypeParameterTypeImpl(typeParameter);
- typeParameter.type = typeArguments[i];
- }
- element.typeParameters = typeParameters;
- }
- }
- return element;
- }
-}
-
-@reflectiveTest
class TypeResolverVisitorTest extends ParserTestCase
with ResourceProviderMixin {
/**
@@ -1497,8 +1376,7 @@
void setUp({bool shouldSetElementSupertypes: false}) {
_listener = new GatheringErrorListener();
- InternalAnalysisContext context = AnalysisContextFactory.contextWithCore(
- resourceProvider: resourceProvider);
+ AnalysisContext context = TestAnalysisContext();
Source librarySource = new FileSource(getFile("/lib.dart"));
// TODO(paulberry): make it possible to override the feature set so we can
// test NNBD features.
@@ -1542,8 +1420,7 @@
// Resolve API types.
{
- InternalAnalysisContext context = AnalysisContextFactory.contextWithCore(
- resourceProvider: resourceProvider);
+ AnalysisContext context = TestAnalysisContext();
var source = getFile('/test.dart').createSource();
// TODO(paulberry): make it possible to override the feature set so we can
// test NNBD features.
@@ -2288,7 +2165,7 @@
_resolveNode(typeName, []);
expect(typeName.type, DynamicTypeImpl.instance);
expect(typeName.name.staticElement, null);
- _listener.assertErrorsWithCodes([StaticWarningCode.UNDEFINED_CLASS]);
+ _listener.assertErrorsWithCodes([CompileTimeErrorCode.UNDEFINED_CLASS]);
}
test_visitTypeName_parameters_arguments() async {
@@ -2334,7 +2211,7 @@
expect(typeName.type, DynamicTypeImpl.instance);
expect(prefix.staticElement, null);
expect(suffix.staticElement, null);
- _listener.assertErrorsWithCodes([StaticWarningCode.UNDEFINED_CLASS]);
+ _listener.assertErrorsWithCodes([CompileTimeErrorCode.UNDEFINED_CLASS]);
}
test_visitTypeName_void() async {
@@ -2423,8 +2300,7 @@
LibraryScope libraryScope;
TypeResolverVisitor visitor;
{
- InternalAnalysisContext context = AnalysisContextFactory.contextWithCore(
- resourceProvider: resourceProvider);
+ AnalysisContext context = TestAnalysisContext();
var source = getFile('/test.dart').createSource();
// TODO(paulberry): make it possible to override the feature set so we can
// test NNBD features.
diff --git a/pkg/analyzer/test/generated/resolver_test_case.dart b/pkg/analyzer/test/generated/resolver_test_case.dart
index 9c5ba4f..fdb3b15 100644
--- a/pkg/analyzer/test/generated/resolver_test_case.dart
+++ b/pkg/analyzer/test/generated/resolver_test_case.dart
@@ -7,7 +7,6 @@
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
@@ -33,7 +32,7 @@
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:test/test.dart';
-import 'analysis_context_factory.dart';
+import 'test_analysis_context.dart';
import 'test_support.dart';
const String _defaultSourceName = "/test.dart";
@@ -245,8 +244,8 @@
if (node.name == "void") {
return;
}
- if (resolutionMap.staticTypeForExpression(node) != null &&
- resolutionMap.staticTypeForExpression(node).isDynamic &&
+ if (node.staticType != null &&
+ node.staticType.isDynamic &&
node.staticElement == null) {
return;
}
@@ -285,10 +284,7 @@
if (root is CompilationUnit) {
CompilationUnit rootCU = root;
if (rootCU.declaredElement != null) {
- return resolutionMap
- .elementDeclaredByCompilationUnit(rootCU)
- .source
- .fullName;
+ return rootCU.declaredElement.source.fullName;
} else {
return "<unknown file- CompilationUnit.getElement() returned null>";
}
@@ -521,10 +517,8 @@
*
* @return the library element that was created
*/
- LibraryElementImpl createDefaultTestLibrary() => createTestLibrary(
- AnalysisContextFactory.contextWithCore(
- resourceProvider: resourceProvider),
- "test");
+ LibraryElementImpl createDefaultTestLibrary() =>
+ createTestLibrary(TestAnalysisContext(), "test");
/**
* Return a source object representing a file with the given [fileName].
diff --git a/pkg/analyzer/test/generated/static_type_analyzer_test.dart b/pkg/analyzer/test/generated/static_type_analyzer_test.dart
index aad0e06..de9c1f3 100644
--- a/pkg/analyzer/test/generated/static_type_analyzer_test.dart
+++ b/pkg/analyzer/test/generated/static_type_analyzer_test.dart
@@ -12,10 +12,8 @@
import 'package:analyzer/src/dart/ast/ast.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
-import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/error/codes.dart';
-import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/static_type_analyzer.dart';
@@ -27,8 +25,8 @@
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
-import 'analysis_context_factory.dart';
import 'resolver_test_case.dart';
+import 'test_analysis_context.dart';
import 'test_support.dart';
main() {
@@ -429,26 +427,6 @@
_listener.assertNoErrors();
}
- void test_visitAssignmentExpression_compound_II() {
- validate(TokenType operator) {
- InterfaceType numType = _typeProvider.numType;
- InterfaceType intType = _typeProvider.intType;
- SimpleIdentifier identifier = _resolvedVariable(intType, "i");
- AssignmentExpression node = AstTestFactory.assignmentExpression(
- identifier, operator, _resolvedInteger(1));
- MethodElement plusMethod = getMethod(numType, "+");
- node.staticElement = plusMethod;
- expect(_analyze(node), same(intType));
- _listener.assertNoErrors();
- }
-
- validate(TokenType.MINUS_EQ);
- validate(TokenType.PERCENT_EQ);
- validate(TokenType.PLUS_EQ);
- validate(TokenType.STAR_EQ);
- validate(TokenType.TILDE_SLASH_EQ);
- }
-
void test_visitAssignmentExpression_compound_lazy() {
validate(TokenType operator) {
InterfaceType boolType = _typeProvider.boolType;
@@ -463,46 +441,6 @@
validate(TokenType.BAR_BAR_EQ);
}
- void test_visitAssignmentExpression_compound_plusID() {
- validate(TokenType operator) {
- InterfaceType numType = _typeProvider.numType;
- InterfaceType intType = _typeProvider.intType;
- InterfaceType doubleType = _typeProvider.doubleType;
- SimpleIdentifier identifier = _resolvedVariable(intType, "i");
- AssignmentExpression node = AstTestFactory.assignmentExpression(
- identifier, operator, _resolvedDouble(1.0));
- MethodElement plusMethod = getMethod(numType, "+");
- node.staticElement = plusMethod;
- expect(_analyze(node), same(doubleType));
- _listener.assertNoErrors();
- }
-
- validate(TokenType.MINUS_EQ);
- validate(TokenType.PERCENT_EQ);
- validate(TokenType.PLUS_EQ);
- validate(TokenType.STAR_EQ);
- }
-
- void test_visitAssignmentExpression_compoundIfNull_differentTypes() {
- // double d; d ??= 0
- Expression node = AstTestFactory.assignmentExpression(
- _resolvedVariable(_typeProvider.doubleType, 'd'),
- TokenType.QUESTION_QUESTION_EQ,
- _resolvedInteger(0));
- expect(_analyze(node), _typeProvider.numType);
- _listener.assertNoErrors();
- }
-
- void test_visitAssignmentExpression_compoundIfNull_sameTypes() {
- // int i; i ??= 0
- Expression node = AstTestFactory.assignmentExpression(
- _resolvedVariable(_typeProvider.intType, 'i'),
- TokenType.QUESTION_QUESTION_EQ,
- _resolvedInteger(0));
- expect(_analyze(node), same(_typeProvider.intType));
- _listener.assertNoErrors();
- }
-
void test_visitAssignmentExpression_simple() {
// i = 0
InterfaceType intType = _typeProvider.intType;
@@ -604,7 +542,7 @@
_resolvedInteger(2), TokenType.SLASH, _resolvedInteger(2));
node.staticElement = getMethod(_typeProvider.numType, "/");
node.staticInvokeType = node.staticElement.type;
- expect(_analyze(node), same(_typeProvider.doubleType));
+ expect(_analyze(node), _typeProvider.doubleType);
_listener.assertNoErrors();
}
@@ -981,79 +919,6 @@
_listener.assertNoErrors();
}
- void test_visitIndexExpression_getter() {
- // List a;
- // a[2]
- InterfaceType listType = _typeProvider.listType;
- SimpleIdentifier identifier = _resolvedVariable(listType, "a");
- IndexExpression node =
- AstTestFactory.indexExpression(identifier, _resolvedInteger(2));
- MethodElement indexMethod = listType.element.methods[0];
- node.staticElement = indexMethod;
- expect(_analyze(node), same(listType.typeArguments[0]));
- _listener.assertNoErrors();
- }
-
- void test_visitIndexExpression_setter() {
- // List a;
- // a[2] = 0
- InterfaceType listType = _typeProvider.listType;
- SimpleIdentifier identifier = _resolvedVariable(listType, "a");
- IndexExpression node =
- AstTestFactory.indexExpression(identifier, _resolvedInteger(2));
- MethodElement indexMethod = listType.element.methods[1];
- node.staticElement = indexMethod;
- AstTestFactory.assignmentExpression(
- node, TokenType.EQ, AstTestFactory.integer(0));
- expect(_analyze(node), same(listType.typeArguments[0]));
- _listener.assertNoErrors();
- }
-
- void test_visitIndexExpression_typeParameters() {
- // List<int> list = ...
- // list[0]
- InterfaceType intType = _typeProvider.intType;
- InterfaceType listType = _typeProvider.listType;
- // (int) -> E
- MethodElement methodElement = getMethod(listType, "[]");
- // "list" has type List<int>
- SimpleIdentifier identifier = AstTestFactory.identifier3("list");
- InterfaceType listOfIntType = listType.instantiate(<DartType>[intType]);
- identifier.staticType = listOfIntType;
- // list[0] has MethodElement element (int) -> E
- IndexExpression indexExpression =
- AstTestFactory.indexExpression(identifier, AstTestFactory.integer(0));
- MethodElement indexMethod = MethodMember.from(methodElement, listOfIntType);
- indexExpression.staticElement = indexMethod;
- // analyze and assert result of the index expression
- expect(_analyze(indexExpression), same(intType));
- _listener.assertNoErrors();
- }
-
- void test_visitIndexExpression_typeParameters_inSetterContext() {
- // List<int> list = ...
- // list[0] = 0;
- InterfaceType intType = _typeProvider.intType;
- InterfaceType listType = _typeProvider.listType;
- // (int, E) -> void
- MethodElement methodElement = getMethod(listType, "[]=");
- // "list" has type List<int>
- SimpleIdentifier identifier = AstTestFactory.identifier3("list");
- InterfaceType listOfIntType = listType.instantiate(<DartType>[intType]);
- identifier.staticType = listOfIntType;
- // list[0] has MethodElement element (int) -> E
- IndexExpression indexExpression =
- AstTestFactory.indexExpression(identifier, AstTestFactory.integer(0));
- MethodElement indexMethod = MethodMember.from(methodElement, listOfIntType);
- indexExpression.staticElement = indexMethod;
- // list[0] should be in a setter context
- AstTestFactory.assignmentExpression(
- indexExpression, TokenType.EQ, AstTestFactory.integer(0));
- // analyze and assert result of the index expression
- expect(_analyze(indexExpression), same(intType));
- _listener.assertNoErrors();
- }
-
void test_visitInstanceCreationExpression_named() {
// new C.m()
ClassElementImpl classElement = ElementFactory.classElement2("C");
@@ -1150,7 +1015,6 @@
}
void test_visitListLiteral_unresolved() {
- _analyzer = _createAnalyzer(strongMode: true);
// [a] // where 'a' is not resolved
Identifier identifier = AstTestFactory.identifier3('a');
Expression node = AstTestFactory.listLiteral([identifier]);
@@ -1163,7 +1027,6 @@
}
void test_visitListLiteral_unresolved_multiple() {
- _analyzer = _createAnalyzer(strongMode: true);
// [0, a, 1] // where 'a' is not resolved
Identifier identifier = AstTestFactory.identifier3('a');
Expression node = AstTestFactory.listLiteral(
@@ -1288,7 +1151,7 @@
AstTestFactory.prefixExpression(TokenType.MINUS, _resolvedInteger(0));
MethodElement minusMethod = getMethod(_typeProvider.numType, "-");
node.staticElement = minusMethod;
- expect(_analyze(node), same(_typeProvider.numType));
+ expect(_analyze(node), _typeProvider.numType);
_listener.assertNoErrors();
}
@@ -1326,7 +1189,7 @@
AstTestFactory.prefixExpression(TokenType.TILDE, _resolvedInteger(0));
MethodElement tildeMethod = getMethod(_typeProvider.intType, "~");
node.staticElement = tildeMethod;
- expect(_analyze(node), same(_typeProvider.intType));
+ expect(_analyze(node), _typeProvider.intType);
_listener.assertNoErrors();
}
@@ -1514,16 +1377,8 @@
/**
* Create the analyzer used by the tests.
*/
- StaticTypeAnalyzer _createAnalyzer({bool strongMode: false}) {
- InternalAnalysisContext context;
- if (strongMode) {
- AnalysisOptionsImpl options = new AnalysisOptionsImpl();
- context = AnalysisContextFactory.contextWithCoreAndOptions(options,
- resourceProvider: resourceProvider);
- } else {
- context = AnalysisContextFactory.contextWithCore(
- resourceProvider: resourceProvider);
- }
+ StaticTypeAnalyzer _createAnalyzer() {
+ var context = TestAnalysisContext();
var inheritance = new InheritanceManager3(context.typeSystem);
Source source = new FileSource(getFile("/lib.dart"));
CompilationUnitElementImpl definingCompilationUnit =
diff --git a/pkg/analyzer/test/generated/static_warning_code_test.dart b/pkg/analyzer/test/generated/static_warning_code_test.dart
index 2db6cba..0cfcdb3 100644
--- a/pkg/analyzer/test/generated/static_warning_code_test.dart
+++ b/pkg/analyzer/test/generated/static_warning_code_test.dart
@@ -422,7 +422,7 @@
await assertErrorsInCode('''
f() { new C(); }
''', [
- error(StaticWarningCode.UNDEFINED_CLASS, 10, 1),
+ error(CompileTimeErrorCode.UNDEFINED_CLASS, 10, 1),
]);
}
@@ -430,7 +430,7 @@
await assertErrorsInCode('''
f() { C c; }
''', [
- error(StaticWarningCode.UNDEFINED_CLASS, 6, 1),
+ error(CompileTimeErrorCode.UNDEFINED_CLASS, 6, 1),
error(HintCode.UNUSED_LOCAL_VARIABLE, 8, 1),
]);
}
@@ -549,7 +549,7 @@
main() {
f(c: 1);
}''', [
- error(StaticWarningCode.UNDEFINED_NAMED_PARAMETER, 26, 1),
+ error(CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER, 26, 1),
]);
}
diff --git a/pkg/analyzer/test/generated/strong_mode_test.dart b/pkg/analyzer/test/generated/strong_mode_test.dart
index a8e32bf..4970fc2 100644
--- a/pkg/analyzer/test/generated/strong_mode_test.dart
+++ b/pkg/analyzer/test/generated/strong_mode_test.dart
@@ -6,7 +6,6 @@
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/analysis/driver.dart';
@@ -1821,8 +1820,7 @@
InstanceCreationExpression exp = stmt.expression;
ClassElement elementB = AstFinder.getClass(unit, "B").declaredElement;
ClassElement elementA = AstFinder.getClass(unit, "A").declaredElement;
- expect(resolutionMap.typeForTypeName(exp.constructorName.type).element,
- elementB);
+ expect(exp.constructorName.type.type.element, elementB);
_isInstantiationOf(_hasElement(elementB))(
[_isType(elementA.typeParameters[0].type)])(exp.staticType);
}
@@ -1874,8 +1872,7 @@
expect(type0.normalParameterTypes[0], typeProvider.stringType);
FunctionExpression anon1 = (statements[1] as ReturnStatement).expression;
- FunctionType type1 =
- resolutionMap.elementDeclaredByFunctionExpression(anon1).type;
+ FunctionType type1 = anon1.declaredElement.type;
expect(type1.returnType, typeProvider.intType);
expect(type1.normalParameterTypes[0], typeProvider.intType);
}
@@ -1899,7 +1896,7 @@
VariableDeclarationStatement stmt = statements[i];
VariableDeclaration decl = stmt.variables.variables[0];
FunctionExpression exp = decl.initializer;
- return resolutionMap.elementDeclaredByFunctionExpression(exp).type;
+ return exp.declaredElement.type;
}
_isFunction2Of(_isInt, _isNull)(literal(0));
@@ -1928,7 +1925,7 @@
VariableDeclarationStatement stmt = statements[i];
VariableDeclaration decl = stmt.variables.variables[0];
FunctionExpression exp = decl.initializer;
- return resolutionMap.elementDeclaredByFunctionExpression(exp).type;
+ return exp.declaredElement.type;
}
_isFunction2Of(_isInt, _isNull)(literal(0));
@@ -1993,7 +1990,7 @@
ExpressionStatement stmt = statements[i];
FunctionExpressionInvocation invk = stmt.expression;
FunctionExpression exp = invk.argumentList.arguments[0];
- return resolutionMap.elementDeclaredByFunctionExpression(exp).type;
+ return exp.declaredElement.type;
}
_isFunction2Of(_isInt, _isNull)(literal(0));
@@ -2024,7 +2021,7 @@
ExpressionStatement stmt = statements[i];
FunctionExpressionInvocation invk = stmt.expression;
FunctionExpression exp = invk.argumentList.arguments[0];
- return resolutionMap.elementDeclaredByFunctionExpression(exp).type;
+ return exp.declaredElement.type;
}
_isFunction2Of(_isInt, _isNull)(literal(0));
@@ -2053,7 +2050,7 @@
ExpressionStatement stmt = statements[i];
MethodInvocation invk = stmt.expression;
FunctionExpression exp = invk.argumentList.arguments[0];
- return resolutionMap.elementDeclaredByFunctionExpression(exp).type;
+ return exp.declaredElement.type;
}
_isFunction2Of(_isInt, _isNull)(literal(0));
@@ -2082,7 +2079,7 @@
ExpressionStatement stmt = statements[i];
MethodInvocation invk = stmt.expression;
FunctionExpression exp = invk.argumentList.arguments[0];
- return resolutionMap.elementDeclaredByFunctionExpression(exp).type;
+ return exp.declaredElement.type;
}
_isFunction2Of(_isInt, _isNull)(literal(0));
@@ -2113,7 +2110,7 @@
ExpressionStatement stmt = statements[i];
MethodInvocation invk = stmt.expression;
FunctionExpression exp = invk.argumentList.arguments[0];
- return resolutionMap.elementDeclaredByFunctionExpression(exp).type;
+ return exp.declaredElement.type;
}
_isFunction2Of(_isInt, _isNull)(literal(0));
@@ -2144,7 +2141,7 @@
ExpressionStatement stmt = statements[i];
MethodInvocation invk = stmt.expression;
FunctionExpression exp = invk.argumentList.arguments[0];
- return resolutionMap.elementDeclaredByFunctionExpression(exp).type;
+ return exp.declaredElement.type;
}
_isFunction2Of(_isInt, _isNull)(literal(0));
@@ -2847,10 +2844,8 @@
VariableDeclaration mapB = AstFinder.getFieldInClass(unit, "B", "map");
MethodDeclaration mapC = AstFinder.getMethodInClass(unit, "C", "map");
- assertMapOfIntToListOfInt(
- resolutionMap.elementDeclaredByVariableDeclaration(mapB).type);
- assertMapOfIntToListOfInt(
- resolutionMap.elementDeclaredByMethodDeclaration(mapC).returnType);
+ assertMapOfIntToListOfInt(mapB.declaredElement.type);
+ assertMapOfIntToListOfInt(mapC.declaredElement.returnType);
SetOrMapLiteral mapLiteralB = mapB.initializer;
SetOrMapLiteral mapLiteralC =
diff --git a/pkg/analyzer/test/generated/test_all.dart b/pkg/analyzer/test/generated/test_all.dart
index e6af823..f4d11a7 100644
--- a/pkg/analyzer/test/generated/test_all.dart
+++ b/pkg/analyzer/test/generated/test_all.dart
@@ -8,6 +8,7 @@
import 'checked_mode_compile_time_error_code_test.dart'
as checked_mode_compile_time_error_code;
import 'compile_time_error_code_test.dart' as compile_time_error_code;
+// ignore: deprecated_member_use_from_same_package
import 'constant_test.dart' as constant_test;
import 'declaration_resolver_test.dart' as declaration_resolver_test;
import 'element_resolver_test.dart' as element_resolver_test;
diff --git a/pkg/analyzer/test/generated/test_analysis_context.dart b/pkg/analyzer/test/generated/test_analysis_context.dart
new file mode 100644
index 0000000..3c6918f
--- /dev/null
+++ b/pkg/analyzer/test/generated/test_analysis_context.dart
@@ -0,0 +1,71 @@
+// 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:analyzer/dart/analysis/features.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/type_provider.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/source_io.dart';
+import 'package:analyzer/src/test_utilities/mock_sdk_elements.dart';
+
+class TestAnalysisContext implements AnalysisContext {
+ @override
+ final SourceFactory sourceFactory = _MockSourceFactory();
+
+ AnalysisOptions _analysisOptions;
+ TypeProvider _typeProvider;
+ TypeSystem _typeSystem;
+
+ TestAnalysisContext({FeatureSet featureSet}) {
+ _analysisOptions = AnalysisOptionsImpl()
+ ..contextFeatures = featureSet ?? FeatureSet.forTesting();
+
+ var sdkElements = MockSdkElements(
+ this,
+ analysisOptions.contextFeatures.isEnabled(Feature.non_nullable)
+ ? NullabilitySuffix.none
+ : NullabilitySuffix.star,
+ );
+
+ _typeProvider = TypeProviderImpl(
+ sdkElements.coreLibrary,
+ sdkElements.asyncLibrary,
+ );
+ _typeSystem = Dart2TypeSystem(typeProvider);
+ }
+
+ @override
+ AnalysisOptions get analysisOptions => _analysisOptions;
+
+ @override
+ TypeProvider get typeProvider => _typeProvider;
+
+ @override
+ TypeSystem get typeSystem => _typeSystem;
+
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class _MockSource implements Source {
+ @override
+ final Uri uri;
+
+ _MockSource(this.uri);
+
+ @override
+ String get encoding => '$uri';
+
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class _MockSourceFactory implements SourceFactory {
+ @override
+ Source forUri(String uriStr) {
+ var uri = Uri.parse(uriStr);
+ return _MockSource(uri);
+ }
+
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
diff --git a/pkg/analyzer/test/generated/test_support.dart b/pkg/analyzer/test/generated/test_support.dart
index 2a05d30..f85b302 100644
--- a/pkg/analyzer/test/generated/test_support.dart
+++ b/pkg/analyzer/test/generated/test_support.dart
@@ -9,7 +9,6 @@
import 'package:analyzer/error/error.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/exception/exception.dart';
-import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_engine.dart';
@@ -17,7 +16,7 @@
import 'package:analyzer/src/generated/source.dart';
import 'package:test/test.dart';
-import 'analysis_context_factory.dart';
+import 'test_analysis_context.dart';
/// The class `EngineTestCase` defines utility methods for making assertions.
class EngineTestCase {
@@ -53,8 +52,7 @@
}
AnalysisContext createAnalysisContext() {
- return AnalysisContextFactory.contextWithCore(
- resourceProvider: new MemoryResourceProvider());
+ return TestAnalysisContext();
}
/// Return the getter in the given [type] with the given [name]. Inherited
diff --git a/pkg/analyzer/test/generated/type_system_test.dart b/pkg/analyzer/test/generated/type_system_test.dart
index 16f0d8d..6e6cd92 100644
--- a/pkg/analyzer/test/generated/type_system_test.dart
+++ b/pkg/analyzer/test/generated/type_system_test.dart
@@ -10,10 +10,10 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/error/listener.dart';
-import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/src/dart/ast/token.dart' show KeywordToken;
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/type_provider.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/resolver.dart';
@@ -27,7 +27,7 @@
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
-import 'analysis_context_factory.dart';
+import 'test_analysis_context.dart';
main() {
defineReflectiveSuite(() {
@@ -380,9 +380,8 @@
DartType get voidType => VoidTypeImpl.instance;
void setUp() {
- InternalAnalysisContext context = AnalysisContextFactory.contextWithCore(
- resourceProvider: new MemoryResourceProvider());
- typeProvider = context.typeProvider;
+ var analysisContext = TestAnalysisContext();
+ typeProvider = analysisContext.typeProvider;
var simpleFunctionElement =
ElementFactory.genericTypeAliasElement('A', returnType: voidType);
simpleFunctionType = simpleFunctionElement.type;
@@ -537,10 +536,9 @@
DartType list(DartType T) => typeProvider.listType.instantiate([T]);
void setUp() {
- typeProvider = AnalysisContextFactory.contextWithCore(
- resourceProvider: new MemoryResourceProvider())
- .typeProvider;
- typeSystem = new Dart2TypeSystem(typeProvider);
+ var analysisContext = TestAnalysisContext();
+ typeProvider = analysisContext.typeProvider;
+ typeSystem = analysisContext.typeSystem;
T = _newTypeParameter('T');
}
@@ -945,19 +943,19 @@
}
void test_boundedRecursively() {
- // class Clonable<T extends Clonable<T>>
- ClassElementImpl clonable =
- ElementFactory.classElement('Clonable', objectType, ['T']);
- (clonable.typeParameters[0] as TypeParameterElementImpl).bound =
- clonable.type;
- // class Foo extends Clonable<Foo>
+ // class Cloneable<T extends Cloneable<T>>
+ ClassElementImpl cloneable =
+ ElementFactory.classElement('Cloneable', objectType, ['T']);
+ (cloneable.typeParameters[0] as TypeParameterElementImpl).bound =
+ cloneable.type;
+ // class Foo extends Cloneable<Foo>
ClassElementImpl foo = ElementFactory.classElement('Foo', null);
- foo.supertype = clonable.type.instantiate([foo.type]);
+ foo.supertype = cloneable.type.instantiate([foo.type]);
- // <S extends Clonable<S>>
+ // <S extends Cloneable<S>>
var s = TypeBuilder.variable('S');
(s.element as TypeParameterElementImpl).bound =
- clonable.type.instantiate([s]);
+ cloneable.type.instantiate([s]);
// (S, S) -> S
var clone = TypeBuilder.function(types: [s], required: [s, s], result: s);
expect(_inferCall(clone, [foo.type, foo.type]), [foo.type]);
@@ -2399,12 +2397,11 @@
class NonNullableSubtypingTest extends SubtypingTestBase {
@override
void setUp() {
- typeProvider = AnalysisContextFactory.contextWithCoreAndOptions(
- new AnalysisOptionsImpl()
- ..contextFeatures = FeatureSet.forTesting(
- additionalFeatures: [Feature.non_nullable]),
- resourceProvider: new MemoryResourceProvider())
- .typeProvider;
+ typeProvider = TestAnalysisContext(
+ featureSet: FeatureSet.forTesting(
+ additionalFeatures: [Feature.non_nullable],
+ ),
+ ).typeProvider;
// TypeSystem should use the context type provider.
typeSystem = new Dart2TypeSystem(typeProvider);
@@ -2413,7 +2410,11 @@
LibraryElement asyncLibrary = typeProvider.streamType.element.library;
// Get a non-nullable type provider for convience during the test.
- typeProvider = new NonNullableTypeProvider(coreLibrary, asyncLibrary);
+ typeProvider = TypeProviderImpl(
+ coreLibrary,
+ asyncLibrary,
+ nullabilitySuffix: NullabilitySuffix.none,
+ );
}
void test_dynamicType() {
@@ -2954,10 +2955,9 @@
DartType get voidType => VoidTypeImpl.instance;
void setUp() {
- typeProvider = AnalysisContextFactory.contextWithCore(
- resourceProvider: new MemoryResourceProvider())
- .typeProvider;
- typeSystem = new Dart2TypeSystem(typeProvider);
+ var analysisContext = TestAnalysisContext();
+ typeProvider = analysisContext.typeProvider;
+ typeSystem = analysisContext.typeSystem;
}
void _checkEquivalent(DartType type1, DartType type2) {
diff --git a/pkg/analyzer/test/src/context/cache_test.dart b/pkg/analyzer/test/src/context/cache_test.dart
deleted file mode 100644
index a689ff0..0000000
--- a/pkg/analyzer/test/src/context/cache_test.dart
+++ /dev/null
@@ -1,1333 +0,0 @@
-// Copyright (c) 2015, 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/exception/exception.dart';
-import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/file_system/physical_file_system.dart';
-import 'package:analyzer/src/context/cache.dart';
-import 'package:analyzer/src/dart/sdk/sdk.dart';
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/utilities_collection.dart';
-import 'package:analyzer/src/source/package_map_resolver.dart';
-import 'package:analyzer/src/task/api/model.dart';
-import 'package:analyzer/src/task/model.dart';
-import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
-import 'package:test/test.dart';
-import 'package:test_reflective_loader/test_reflective_loader.dart';
-
-import '../../generated/test_support.dart';
-
-main() {
- defineReflectiveSuite(() {
- defineReflectiveTests(AnalysisCacheTest);
- defineReflectiveTests(CacheEntryTest);
- defineReflectiveTests(CacheFlushManagerTest);
- defineReflectiveTests(SdkCachePartitionTest);
- defineReflectiveTests(UniversalCachePartitionTest);
- defineReflectiveTests(ResultDataTest);
- });
-}
-
-AnalysisCache createCache({AnalysisContext context}) {
- CachePartition partition = new UniversalCachePartition(context);
- return new AnalysisCache(<CachePartition>[partition]);
-}
-
-class AbstractCacheTest {
- _InternalAnalysisContextMock context;
- AnalysisCache cache;
-
- void setUp() {
- context = new _InternalAnalysisContextMock();
- context.prioritySources = [];
- cache = createCache(context: context);
- context.analysisCache = cache;
- }
-}
-
-@reflectiveTest
-class AnalysisCacheTest extends AbstractCacheTest {
- void test_creation() {
- expect(cache, isNotNull);
- }
-
- test_flush() {
- AnalysisTarget target = new TestSource();
- ResultDescriptor<String> resultA = new ResultDescriptor<String>('A', null);
- ResultDescriptor<String> resultB = new ResultDescriptor<String>('B', null);
- CacheEntry entry = new CacheEntry(target);
- cache.put(entry);
- // put values
- entry.setValue(resultA, 'a', const <TargetedResult>[]);
- entry.setValue(resultB, 'b', const <TargetedResult>[]);
- expect(cache.getState(target, resultA), CacheState.VALID);
- expect(cache.getState(target, resultB), CacheState.VALID);
- expect(cache.getValue(target, resultA), 'a');
- expect(cache.getValue(target, resultB), 'b');
- // flush A
- cache.flush((target, result) => result == resultA);
- expect(cache.getState(target, resultA), CacheState.FLUSHED);
- expect(cache.getState(target, resultB), CacheState.VALID);
- expect(cache.getValue(target, resultA), isNull);
- expect(cache.getValue(target, resultB), 'b');
- }
-
- void test_get() {
- AnalysisTarget target = new TestSource();
- expect(cache.get(target), isNull);
- }
-
- void test_getContextFor() {
- AnalysisTarget target = new TestSource();
- expect(cache.getContextFor(target), context);
- }
-
- void test_getSourcesWithFullName() {
- String filePath = '/foo/lib/file.dart';
- // no sources
- expect(cache.getSourcesWithFullName(filePath), isEmpty);
- // add source1
- TestSourceWithUri source1 =
- new TestSourceWithUri(filePath, Uri.parse('file://$filePath'));
- cache.put(new CacheEntry(source1));
- expect(cache.getSourcesWithFullName(filePath), unorderedEquals([source1]));
- // add source2
- TestSourceWithUri source2 =
- new TestSourceWithUri(filePath, Uri.parse('package:foo/file.dart'));
- cache.put(new CacheEntry(source2));
- expect(cache.getSourcesWithFullName(filePath),
- unorderedEquals([source1, source2]));
- // remove source1
- cache.remove(source1);
- expect(cache.getSourcesWithFullName(filePath), unorderedEquals([source2]));
- // remove source2
- cache.remove(source2);
- expect(cache.getSourcesWithFullName(filePath), isEmpty);
- // ignored
- cache.remove(source1);
- cache.remove(source2);
- expect(cache.getSourcesWithFullName(filePath), isEmpty);
- }
-
- void test_getState_hasEntry_flushed() {
- ResultDescriptor result = new ResultDescriptor('result', -1);
- AnalysisTarget target = new TestSource();
- CacheEntry entry = new CacheEntry(target);
- cache.put(entry);
- entry.setState(result, CacheState.FLUSHED);
- expect(cache.getState(target, result), CacheState.FLUSHED);
- }
-
- void test_getState_hasEntry_valid() {
- ResultDescriptor<String> result =
- new ResultDescriptor<String>('result', null);
- AnalysisTarget target = new TestSource();
- CacheEntry entry = new CacheEntry(target);
- cache.put(entry);
- entry.setValue(result, '', []);
- expect(cache.getState(target, result), CacheState.VALID);
- }
-
- void test_getState_noEntry() {
- ResultDescriptor result = new ResultDescriptor('result', -1);
- AnalysisTarget target = new TestSource();
- expect(cache.getState(target, result), CacheState.INVALID);
- }
-
- void test_getValue_hasEntry_valid() {
- ResultDescriptor<int> result = new ResultDescriptor<int>('result', -1);
- AnalysisTarget target = new TestSource();
- CacheEntry entry = new CacheEntry(target);
- cache.put(entry);
- entry.setValue(result, 111, []);
- expect(cache.getValue(target, result), 111);
- }
-
- void test_getValue_noEntry() {
- ResultDescriptor result = new ResultDescriptor('result', -1);
- AnalysisTarget target = new TestSource();
- expect(cache.getValue(target, result), -1);
- }
-
- void test_iterator() {
- AnalysisTarget target = new TestSource();
- CacheEntry entry = new CacheEntry(target);
- cache.put(entry);
- MapIterator<AnalysisTarget, CacheEntry> iterator = cache.iterator();
- expect(iterator.moveNext(), isTrue);
- expect(iterator.key, same(target));
- expect(iterator.value, same(entry));
- expect(iterator.moveNext(), isFalse);
- }
-
- void test_put() {
- AnalysisTarget target = new TestSource();
- CacheEntry entry = new CacheEntry(target);
- expect(cache.get(target), isNull);
- cache.put(entry);
- expect(cache.get(target), entry);
- }
-
- void test_remove() {
- AnalysisTarget target1 = new TestSource('/a.dart');
- AnalysisTarget target2 = new TestSource('/b.dart');
- AnalysisTarget target3 = new TestSource('/c.dart');
- CacheEntry entry1 = new CacheEntry(target1);
- CacheEntry entry2 = new CacheEntry(target2);
- CacheEntry entry3 = new CacheEntry(target3);
- cache.put(entry1);
- cache.put(entry2);
- cache.put(entry3);
- ResultDescriptor<int> result1 = new ResultDescriptor<int>('result1', -1);
- ResultDescriptor<int> result2 = new ResultDescriptor<int>('result2', -2);
- ResultDescriptor<int> result3 = new ResultDescriptor<int>('result3', -3);
- // set results, all of them are VALID
- entry1.setValue(result1, 111, const <TargetedResult>[]);
- entry2.setValue(result2, 222, [new TargetedResult(target1, result1)]);
- entry3.setValue(result3, 333, []);
- expect(entry1.getState(result1), CacheState.VALID);
- expect(entry2.getState(result2), CacheState.VALID);
- expect(entry3.getState(result3), CacheState.VALID);
- expect(entry1.getValue(result1), 111);
- expect(entry2.getValue(result2), 222);
- expect(entry3.getValue(result3), 333);
- // remove entry1, invalidate result2 and remove empty entry2
- expect(cache.remove(target1), entry1);
- expect(cache.get(target1), isNull);
- expect(cache.get(target2), isNull);
- expect(cache.get(target3), entry3);
- expect(entry3.getState(result3), CacheState.VALID);
- }
-
- void test_remove_invalidateResults_sameTarget() {
- AnalysisTarget target = new TestSource('/a.dart');
- CacheEntry entry = new CacheEntry(target);
- cache.put(entry);
- ResultDescriptor<int> result1 = new ResultDescriptor<int>('result1', -1);
- ResultDescriptor<int> result2 = new ResultDescriptor<int>('result2', -2);
- // set results, all of them are VALID
- entry.setValue(result1, 111, const <TargetedResult>[]);
- entry.setValue(result2, 222, [new TargetedResult(target, result1)]);
- expect(entry.getState(result1), CacheState.VALID);
- expect(entry.getState(result2), CacheState.VALID);
- expect(entry.getValue(result1), 111);
- expect(entry.getValue(result2), 222);
- // remove target, invalidate result2
- expect(cache.remove(target), entry);
- expect(cache.get(target), isNull);
- expect(entry.getState(result2), CacheState.INVALID);
- }
-
- void test_size() {
- int size = 4;
- for (int i = 0; i < size; i++) {
- AnalysisTarget target = new TestSource("/test$i.dart");
- cache.put(new CacheEntry(target));
- }
- expect(cache.size(), size);
- }
-
- void test_sources() {
- AnalysisTarget source1 = new TestSource('1.dart');
- AnalysisTarget source2 = new TestSource('2.dart');
- AnalysisTarget target1 = new _TestAnalysisTarget();
- // no entries
- expect(cache.sources, isEmpty);
- // add source1
- cache.put(new CacheEntry(source1));
- expect(cache.sources, unorderedEquals([source1]));
- // add target1
- cache.put(new CacheEntry(target1));
- expect(cache.sources, unorderedEquals([source1]));
- // add source2
- cache.put(new CacheEntry(source2));
- expect(cache.sources, unorderedEquals([source1, source2]));
- // remove source1
- cache.remove(source1);
- expect(cache.sources, unorderedEquals([source2]));
- // remove source2
- cache.remove(source2);
- expect(cache.sources, isEmpty);
- }
-}
-
-@reflectiveTest
-class CacheEntryTest extends AbstractCacheTest {
- test_dispose() {
- ResultDescriptor<int> descriptor1 =
- new ResultDescriptor<int>('result1', -1);
- ResultDescriptor<int> descriptor2 =
- new ResultDescriptor<int>('result2', -2);
- AnalysisTarget target1 = new TestSource('1.dart');
- AnalysisTarget target2 = new TestSource('2.dart');
- TargetedResult result1 = new TargetedResult(target1, descriptor1);
- TargetedResult result2 = new TargetedResult(target2, descriptor2);
- CacheEntry entry1 = new CacheEntry(target1);
- CacheEntry entry2 = new CacheEntry(target2);
- cache.put(entry1);
- cache.put(entry2);
- entry1.setValue(descriptor1, 1, const <TargetedResult>[]);
- entry2.setValue(descriptor2, 2, <TargetedResult>[result1]);
- // target2 is listed as dependent in target1
- expect(
- entry1.getResultData(descriptor1).dependentResults, contains(result2));
- // dispose entry2, result2 is removed from result1
- entry2.dispose();
- expect(entry1.getResultData(descriptor1).dependentResults, isEmpty);
- }
-
- test_explicitlyAdded() {
- AnalysisTarget target = new TestSource();
- CacheEntry entry = new CacheEntry(target);
- expect(entry.explicitlyAdded, false);
- entry.explicitlyAdded = true;
- expect(entry.explicitlyAdded, true);
- }
-
- test_fixExceptionState_error_exception() {
- AnalysisTarget target = new TestSource();
- ResultDescriptor result = new ResultDescriptor('test', null);
- CaughtException exception = new CaughtException(null, null);
- CacheEntry entry = new CacheEntry(target);
- cache.put(entry);
- entry.setErrorState(exception, <ResultDescriptor>[result]);
- entry.fixExceptionState();
- expect(entry.getState(result), CacheState.ERROR);
- expect(entry.exception, exception);
- }
-
- test_fixExceptionState_noError_exception() {
- AnalysisTarget target = new TestSource();
- ResultDescriptor<int> result = new ResultDescriptor<int>('test', null);
- CacheEntry entry = new CacheEntry(target);
- cache.put(entry);
- // set one result to ERROR
- CaughtException exception = new CaughtException(null, null);
- entry.setErrorState(exception, <ResultDescriptor>[result]);
- // set the same result to VALID
- entry.setValue(result, 1, const <TargetedResult>[]);
- // fix the exception state
- entry.fixExceptionState();
- expect(entry.exception, isNull);
- }
-
- test_fixExceptionState_noError_noException() {
- AnalysisTarget target = new TestSource();
- ResultDescriptor result = new ResultDescriptor('test', null);
- CacheEntry entry = new CacheEntry(target);
- entry.fixExceptionState();
- expect(entry.getState(result), CacheState.INVALID);
- expect(entry.exception, isNull);
- }
-
- test_flush() {
- AnalysisTarget target = new TestSource();
- ResultDescriptor<String> resultA = new ResultDescriptor<String>('A', null);
- ResultDescriptor<String> resultB = new ResultDescriptor<String>('B', null);
- CacheEntry entry = new CacheEntry(target);
- cache.put(entry);
- // put values
- entry.setValue(resultA, 'a', const <TargetedResult>[]);
- entry.setValue(resultB, 'b', const <TargetedResult>[]);
- expect(entry.getState(resultA), CacheState.VALID);
- expect(entry.getState(resultB), CacheState.VALID);
- expect(entry.getValue(resultA), 'a');
- expect(entry.getValue(resultB), 'b');
- // flush A
- entry.flush((target, result) => result == resultA);
- expect(entry.getState(resultA), CacheState.FLUSHED);
- expect(entry.getState(resultB), CacheState.VALID);
- expect(entry.getValue(resultA), isNull);
- expect(entry.getValue(resultB), 'b');
- }
-
- test_getState() {
- AnalysisTarget target = new TestSource();
- ResultDescriptor result = new ResultDescriptor('test', null);
- CacheEntry entry = new CacheEntry(target);
- expect(entry.getState(result), CacheState.INVALID);
- }
-
- test_getValue_default() {
- AnalysisTarget target = new TestSource();
- String defaultValue = 'value';
- ResultDescriptor result = new ResultDescriptor('test', defaultValue);
- CacheEntry entry = new CacheEntry(target);
- expect(entry.getValue(result), defaultValue);
- }
-
- test_getValue_flushResults() {
- ResultCachingPolicy cachingPolicy = new SimpleResultCachingPolicy(2, 2);
- ResultDescriptor<int> descriptor1 = new ResultDescriptor<int>(
- 'result1', null,
- cachingPolicy: cachingPolicy);
- ResultDescriptor<int> descriptor2 = new ResultDescriptor<int>(
- 'result2', null,
- cachingPolicy: cachingPolicy);
- ResultDescriptor<int> descriptor3 = new ResultDescriptor<int>(
- 'result3', null,
- cachingPolicy: cachingPolicy);
- AnalysisTarget target = new TestSource();
- CacheEntry entry = new CacheEntry(target);
- cache.put(entry);
- {
- entry.setValue(descriptor1, 1, const <TargetedResult>[]);
- expect(entry.getState(descriptor1), CacheState.VALID);
- }
- {
- entry.setValue(descriptor2, 2, const <TargetedResult>[]);
- expect(entry.getState(descriptor1), CacheState.VALID);
- expect(entry.getState(descriptor2), CacheState.VALID);
- }
- // get descriptor1, so that descriptor2 will be flushed
- entry.getValue(descriptor1);
- {
- entry.setValue(descriptor3, 3, const <TargetedResult>[]);
- expect(entry.getState(descriptor1), CacheState.VALID);
- expect(entry.getState(descriptor2), CacheState.FLUSHED);
- expect(entry.getState(descriptor3), CacheState.VALID);
- }
- }
-
- test_hasErrorState_false() {
- AnalysisTarget target = new TestSource();
- CacheEntry entry = new CacheEntry(target);
- expect(entry.hasErrorState(), false);
- }
-
- test_hasErrorState_true() {
- AnalysisTarget target = new TestSource();
- ResultDescriptor result = new ResultDescriptor('test', null);
- CaughtException exception = new CaughtException(null, null);
- CacheEntry entry = new CacheEntry(target);
- cache.put(entry);
- entry.setErrorState(exception, <ResultDescriptor>[result]);
- expect(entry.hasErrorState(), true);
- }
-
- test_invalidateAllInformation() {
- AnalysisTarget target = new TestSource();
- ResultDescriptor<String> result =
- new ResultDescriptor<String>('test', null);
- CacheEntry entry = new CacheEntry(target);
- cache.put(entry);
- entry.setValue(result, 'value', const <TargetedResult>[]);
- entry.invalidateAllInformation();
- expect(entry.getState(result), CacheState.INVALID);
- expect(entry.getValue(result), isNull);
- }
-
- test_setErrorState() {
- AnalysisTarget target = new TestSource();
- ResultDescriptor<int> result1 = new ResultDescriptor<int>('res1', 1);
- ResultDescriptor<int> result2 = new ResultDescriptor<int>('res2', 2);
- ResultDescriptor<int> result3 = new ResultDescriptor<int>('res3', 3);
- // prepare some good state
- CacheEntry entry = new CacheEntry(target);
- cache.put(entry);
- entry.setValue(result1, 10, const <TargetedResult>[]);
- entry.setValue(result2, 20, const <TargetedResult>[]);
- entry.setValue(result3, 30, const <TargetedResult>[]);
- // set error state
- CaughtException exception = new CaughtException(null, null);
- entry.setErrorState(exception, <ResultDescriptor>[result1, result2]);
- // verify
- expect(entry.exception, exception);
- expect(entry.getState(result1), CacheState.ERROR);
- expect(entry.getState(result2), CacheState.ERROR);
- expect(entry.getState(result3), CacheState.VALID);
- expect(entry.getValue(result1), 1);
- expect(entry.getValue(result2), 2);
- expect(entry.getValue(result3), 30);
- }
-
- test_setErrorState_invalidateDependent() {
- AnalysisTarget target1 = new TestSource('/a.dart');
- AnalysisTarget target2 = new TestSource('/b.dart');
- CacheEntry entry1 = new CacheEntry(target1);
- CacheEntry entry2 = new CacheEntry(target2);
- cache.put(entry1);
- cache.put(entry2);
- ResultDescriptor<int> result1 = new ResultDescriptor<int>('result1', -1);
- ResultDescriptor<int> result2 = new ResultDescriptor<int>('result2', -2);
- ResultDescriptor<int> result3 = new ResultDescriptor<int>('result3', -3);
- ResultDescriptor<int> result4 = new ResultDescriptor<int>('result4', -4);
- // set results, all of them are VALID
- entry1.setValue(result1, 111, const <TargetedResult>[]);
- entry2.setValue(result2, 222, [new TargetedResult(target1, result1)]);
- entry2.setValue(result3, 333, [new TargetedResult(target2, result2)]);
- entry2.setValue(result4, 444, []);
- expect(entry1.getState(result1), CacheState.VALID);
- expect(entry2.getState(result2), CacheState.VALID);
- expect(entry2.getState(result3), CacheState.VALID);
- expect(entry2.getState(result4), CacheState.VALID);
- expect(entry1.getValue(result1), 111);
- expect(entry2.getValue(result2), 222);
- expect(entry2.getValue(result3), 333);
- expect(entry2.getValue(result4), 444);
- // set error state
- CaughtException exception = new CaughtException(null, null);
- entry1.setErrorState(exception, <ResultDescriptor>[result1]);
- // result2 and result3 are invalidated, result4 is intact
- expect(entry1.getState(result1), CacheState.ERROR);
- expect(entry2.getState(result2), CacheState.ERROR);
- expect(entry2.getState(result3), CacheState.ERROR);
- expect(entry2.getState(result4), CacheState.VALID);
- expect(entry1.getValue(result1), -1);
- expect(entry2.getValue(result2), -2);
- expect(entry2.getValue(result3), -3);
- expect(entry2.getValue(result4), 444);
- expect(entry1.exception, exception);
- expect(entry2.exception, exception);
- }
-
- test_setErrorState_noDescriptors() {
- AnalysisTarget target = new TestSource();
- CaughtException exception = new CaughtException(null, null);
- CacheEntry entry = new CacheEntry(target);
- expect(() {
- entry.setErrorState(exception, <ResultDescriptor>[]);
- }, throwsArgumentError);
- }
-
- test_setErrorState_noException() {
- AnalysisTarget target = new TestSource();
- ResultDescriptor result = new ResultDescriptor('test', null);
- CacheEntry entry = new CacheEntry(target);
- expect(() {
- entry.setErrorState(null, <ResultDescriptor>[result]);
- }, throwsArgumentError);
- }
-
- test_setErrorState_nullDescriptors() {
- AnalysisTarget target = new TestSource();
- CaughtException exception = new CaughtException(null, null);
- CacheEntry entry = new CacheEntry(target);
- expect(() {
- entry.setErrorState(exception, null);
- }, throwsArgumentError);
- }
-
- test_setState_error() {
- AnalysisTarget target = new TestSource();
- ResultDescriptor<int> result = new ResultDescriptor<int>('test', null);
- CacheEntry entry = new CacheEntry(target);
- cache.put(entry);
- entry.setValue(result, 42, const <TargetedResult>[]);
- // an invalid state change
- expect(() {
- entry.setState(result, CacheState.ERROR);
- }, throwsArgumentError);
- // no changes
- expect(entry.getState(result), CacheState.VALID);
- expect(entry.getValue(result), 42);
- }
-
- test_setState_flushed() {
- AnalysisTarget target = new TestSource();
- ResultDescriptor<int> result = new ResultDescriptor<int>('test', 1);
- CacheEntry entry = new CacheEntry(target);
- cache.put(entry);
- // set VALID
- entry.setValue(result, 10, const <TargetedResult>[]);
- expect(entry.getState(result), CacheState.VALID);
- expect(entry.getValue(result), 10);
- // set FLUSHED
- entry.setState(result, CacheState.FLUSHED);
- expect(entry.getState(result), CacheState.FLUSHED);
- expect(entry.getValue(result), 1);
- }
-
- test_setState_inProcess() {
- AnalysisTarget target = new TestSource();
- ResultDescriptor<int> result = new ResultDescriptor<int>('test', 1);
- CacheEntry entry = new CacheEntry(target);
- cache.put(entry);
- // set VALID
- entry.setValue(result, 10, const <TargetedResult>[]);
- expect(entry.getState(result), CacheState.VALID);
- expect(entry.getValue(result), 10);
- // set IN_PROCESS
- entry.setState(result, CacheState.IN_PROCESS);
- expect(entry.getState(result), CacheState.IN_PROCESS);
- expect(entry.getValue(result), 10);
- }
-
- test_setState_invalid() {
- AnalysisTarget target = new TestSource();
- ResultDescriptor<int> result = new ResultDescriptor<int>('test', 1);
- CacheEntry entry = new CacheEntry(target);
- cache.put(entry);
- // set VALID
- entry.setValue(result, 10, const <TargetedResult>[]);
- expect(entry.getState(result), CacheState.VALID);
- expect(entry.getValue(result), 10);
- // listen, expect "result" invalidation event
- int numberOfEvents = 0;
- cache.onResultInvalidated.listen((event) {
- numberOfEvents++;
- expect(event.entry, same(entry));
- expect(event.descriptor, same(result));
- });
- // set INVALID
- entry.setState(result, CacheState.INVALID);
- expect(entry.getState(result), CacheState.INVALID);
- expect(entry.getValue(result), 1);
- expect(numberOfEvents, 1);
- }
-
- test_setState_invalid_dependencyCycle() {
- AnalysisTarget target1 = new TestSource('/a.dart');
- AnalysisTarget target2 = new TestSource('/b.dart');
- CacheEntry entry1 = new CacheEntry(target1);
- CacheEntry entry2 = new CacheEntry(target2);
- cache.put(entry1);
- cache.put(entry2);
- ResultDescriptor<int> result = new ResultDescriptor<int>('result', -1);
- // Set each result as VALID with a dependency on on the other.
- entry1.setValue(result, 100, [new TargetedResult(target2, result)]);
- entry2.setValue(result, 200, [new TargetedResult(target1, result)]);
- expect(entry1.getState(result), CacheState.VALID);
- expect(entry2.getState(result), CacheState.VALID);
- // Listen, expect entry1.result and entry2.result invalidation events.
- int numberOfEvents = 0;
- bool wasEntry1 = false;
- bool wasEntry2 = false;
- cache.onResultInvalidated.listen((event) {
- numberOfEvents++;
- if (event.entry == entry1) wasEntry1 = true;
- if (event.entry == entry2) wasEntry2 = true;
- expect(event.descriptor, same(result));
- });
- // Invalidate entry1.result; this should cause entry2 to be also
- // cleared without going into an infinite regress.
- entry1.setState(result, CacheState.INVALID);
- expect(cache.get(target1), isNull);
- expect(cache.get(target2), isNull);
- expect(numberOfEvents, 2);
- expect(wasEntry1, isTrue);
- expect(wasEntry2, isTrue);
- }
-
- test_setState_invalid_invalidateDependent() {
- AnalysisTarget target = new TestSource();
- CacheEntry entry = new CacheEntry(target);
- cache.put(entry);
- ResultDescriptor<int> result1 = new ResultDescriptor<int>('result1', -1);
- ResultDescriptor<int> result2 = new ResultDescriptor<int>('result2', -2);
- ResultDescriptor<int> result3 = new ResultDescriptor<int>('result3', -3);
- ResultDescriptor<int> result4 = new ResultDescriptor<int>('result4', -4);
- // set results, all of them are VALID
- entry.setValue(result1, 111, const <TargetedResult>[]);
- entry.setValue(result2, 222, [new TargetedResult(target, result1)]);
- entry.setValue(result3, 333, [new TargetedResult(target, result2)]);
- entry.setValue(result4, 444, []);
- expect(entry.getState(result1), CacheState.VALID);
- expect(entry.getState(result2), CacheState.VALID);
- expect(entry.getState(result3), CacheState.VALID);
- expect(entry.getState(result4), CacheState.VALID);
- expect(entry.getValue(result1), 111);
- expect(entry.getValue(result2), 222);
- expect(entry.getValue(result3), 333);
- expect(entry.getValue(result4), 444);
- // invalidate result1, invalidates result2 and result3, result4 is intact
- entry.setState(result1, CacheState.INVALID);
- expect(entry.getState(result1), CacheState.INVALID);
- expect(entry.getState(result2), CacheState.INVALID);
- expect(entry.getState(result3), CacheState.INVALID);
- expect(entry.getState(result4), CacheState.VALID);
- expect(entry.getValue(result1), -1);
- expect(entry.getValue(result2), -2);
- expect(entry.getValue(result3), -3);
- expect(entry.getValue(result4), 444);
- // result4 is still valid, so the entry is still in the cache
- expect(cache.get(target), entry);
- }
-
- test_setState_invalid_keepEmpty_ifExplicitlyAdded() {
- AnalysisTarget target = new TestSource('/a.dart');
- CacheEntry entry = new CacheEntry(target);
- entry.explicitlyAdded = true;
- cache.put(entry);
- ResultDescriptor<int> result = new ResultDescriptor<int>('result1', -1);
- // set results, all of them are VALID
- entry.setValue(result, 111, const <TargetedResult>[]);
- expect(entry.getState(result), CacheState.VALID);
- expect(entry.getValue(result), 111);
- // invalidate result, keep entry
- entry.setState(result, CacheState.INVALID);
- expect(cache.get(target), isNotNull);
- }
-
- test_setState_invalid_removeEmptyEntry() {
- AnalysisTarget target1 = new TestSource('/a.dart');
- AnalysisTarget target2 = new TestSource('/b.dart');
- CacheEntry entry1 = new CacheEntry(target1);
- CacheEntry entry2 = new CacheEntry(target2);
- cache.put(entry1);
- cache.put(entry2);
- ResultDescriptor<int> result1 = new ResultDescriptor<int>('result1', -1);
- ResultDescriptor<int> result2 = new ResultDescriptor<int>('result2', -2);
- ResultDescriptor<int> result3 = new ResultDescriptor<int>('result3', -3);
- // set results, all of them are VALID
- entry1.setValue(result1, 111, const <TargetedResult>[]);
- entry2.setValue(result2, 222, [new TargetedResult(target1, result1)]);
- entry2.setValue(result3, 333, [new TargetedResult(target2, result2)]);
- expect(entry1.getState(result1), CacheState.VALID);
- expect(entry2.getState(result2), CacheState.VALID);
- expect(entry2.getState(result3), CacheState.VALID);
- expect(entry1.getValue(result1), 111);
- expect(entry2.getValue(result2), 222);
- expect(entry2.getValue(result3), 333);
- // invalidate result1, remove entry1 & entry2
- entry1.setState(result1, CacheState.INVALID);
- expect(cache.get(target1), isNull);
- expect(cache.get(target2), isNull);
- }
-
- test_setState_invalid_withDelta_keepDependency() {
- Source target = new TestSource('/test.dart');
- CacheEntry entry = new CacheEntry(target);
- cache.put(entry);
- ResultDescriptor<int> result1 = new ResultDescriptor<int>('result1', -1);
- ResultDescriptor<int> result2 = new ResultDescriptor<int>('result2', -2);
- ResultDescriptor<int> result3 = new ResultDescriptor<int>('result3', -3);
- // set results, all of them are VALID
- entry.setValue(result1, 111, const <TargetedResult>[]);
- entry.setValue(result2, 222, [new TargetedResult(target, result1)]);
- entry.setValue(result3, 333, [new TargetedResult(target, result2)]);
- expect(entry.getState(result1), CacheState.VALID);
- expect(entry.getState(result2), CacheState.VALID);
- expect(entry.getState(result3), CacheState.VALID);
- // result2 depends on result1
- expect(entry.getResultData(result1).dependentResults,
- unorderedEquals([new TargetedResult(target, result2)]));
- expect(entry.getResultData(result2).dependedOnResults,
- unorderedEquals([new TargetedResult(target, result1)]));
- // record invalidated results
- Set<TargetedResult> reportedInvalidatedResults = new Set<TargetedResult>();
- cache.onResultInvalidated.listen((InvalidatedResult invalidatedResult) {
- reportedInvalidatedResults.add(new TargetedResult(
- invalidatedResult.entry.target, invalidatedResult.descriptor));
- });
- // invalidate result2 with Delta: keep result2, invalidate result3
- entry.setState(result2, CacheState.INVALID,
- delta: new _KeepContinueDelta(target, result2));
- expect(entry.getState(result1), CacheState.VALID);
- expect(entry.getState(result2), CacheState.VALID);
- expect(entry.getState(result3), CacheState.INVALID);
- // result2 still depends on result1
- expect(entry.getResultData(result1).dependentResults,
- unorderedEquals([new TargetedResult(target, result2)]));
- expect(entry.getResultData(result2).dependedOnResults,
- unorderedEquals([new TargetedResult(target, result1)]));
- // (target, result3) was reported as invalidated
- // (target, result2) was NOT reported
- expect(reportedInvalidatedResults,
- unorderedEquals([new TargetedResult(target, result3)]));
- }
-
- test_setState_valid() {
- AnalysisTarget target = new TestSource();
- ResultDescriptor result = new ResultDescriptor('test', null);
- CacheEntry entry = new CacheEntry(target);
- expect(() => entry.setState(result, CacheState.VALID), throwsArgumentError);
- }
-
- test_setValue() {
- AnalysisTarget target = new TestSource();
- ResultDescriptor<String> result =
- new ResultDescriptor<String>('test', null);
- String value = 'value';
- CacheEntry entry = new CacheEntry(target);
- cache.put(entry);
- entry.setValue(result, value, const <TargetedResult>[]);
- expect(entry.getState(result), CacheState.VALID);
- expect(entry.getValue(result), value);
- }
-
- test_setValue_flushResults() {
- ResultCachingPolicy cachingPolicy = new SimpleResultCachingPolicy(2, 2);
- ResultDescriptor<int> descriptor1 = new ResultDescriptor<int>(
- 'result1', null,
- cachingPolicy: cachingPolicy);
- ResultDescriptor<int> descriptor2 = new ResultDescriptor<int>(
- 'result2', null,
- cachingPolicy: cachingPolicy);
- ResultDescriptor<int> descriptor3 = new ResultDescriptor<int>(
- 'result3', null,
- cachingPolicy: cachingPolicy);
- AnalysisTarget target = new TestSource();
- CacheEntry entry = new CacheEntry(target);
- cache.put(entry);
- {
- entry.setValue(descriptor1, 1, const <TargetedResult>[]);
- expect(entry.getState(descriptor1), CacheState.VALID);
- }
- {
- entry.setValue(descriptor2, 2, const <TargetedResult>[]);
- expect(entry.getState(descriptor1), CacheState.VALID);
- expect(entry.getState(descriptor2), CacheState.VALID);
- }
- {
- entry.setValue(descriptor3, 3, const <TargetedResult>[]);
- expect(entry.getState(descriptor1), CacheState.FLUSHED);
- expect(entry.getState(descriptor2), CacheState.VALID);
- expect(entry.getState(descriptor3), CacheState.VALID);
- }
- }
-
- test_setValue_flushResults_keepForPrioritySources() {
- ResultCachingPolicy cachingPolicy = new SimpleResultCachingPolicy(2, 2);
- ResultDescriptor<int> newResult(String name) =>
- new ResultDescriptor<int>(name, null, cachingPolicy: cachingPolicy);
- ResultDescriptor<int> descriptor1 = newResult('result1');
- ResultDescriptor<int> descriptor2 = newResult('result2');
- ResultDescriptor<int> descriptor3 = newResult('result3');
- TestSource source1 = new TestSource('/a.dart');
- TestSource source2 = new TestSource('/b.dart');
- TestSource source3 = new TestSource('/c.dart');
- AnalysisTarget target1 =
- new _TestAnalysisTarget(librarySource: source1, source: source1);
- AnalysisTarget target2 =
- new _TestAnalysisTarget(librarySource: source2, source: source2);
- AnalysisTarget target3 =
- new _TestAnalysisTarget(librarySource: source3, source: source3);
- CacheEntry entry1 = new CacheEntry(target1);
- CacheEntry entry2 = new CacheEntry(target2);
- CacheEntry entry3 = new CacheEntry(target3);
- cache.put(entry1);
- cache.put(entry2);
- cache.put(entry3);
-
- // Set two results.
- entry1.setValue(descriptor1, 1, const <TargetedResult>[]);
- entry2.setValue(descriptor2, 2, const <TargetedResult>[]);
- expect(entry1.getState(descriptor1), CacheState.VALID);
- expect(entry2.getState(descriptor2), CacheState.VALID);
-
- // Make source1 priority, so result2 is flushed instead.
- context.prioritySources = <Source>[source1];
- entry3.setValue(descriptor3, 3, const <TargetedResult>[]);
- expect(entry1.getState(descriptor1), CacheState.VALID);
- expect(entry2.getState(descriptor2), CacheState.FLUSHED);
- expect(entry3.getState(descriptor3), CacheState.VALID);
- }
-
- test_setValue_keepDependent() {
- AnalysisTarget target = new TestSource();
- CacheEntry entry = new CacheEntry(target);
- cache.put(entry);
- ResultDescriptor<int> result1 = new ResultDescriptor<int>('result1', -1);
- ResultDescriptor<int> result2 = new ResultDescriptor<int>('result2', -2);
- // set results, all of them are VALID
- entry.setValue(result1, 111, const <TargetedResult>[]);
- entry.setValue(result2, 222, [new TargetedResult(target, result1)]);
- expect(entry.getState(result1), CacheState.VALID);
- expect(entry.getState(result2), CacheState.VALID);
- expect(entry.getValue(result1), 111);
- expect(entry.getValue(result2), 222);
- // set result1; result2 is intact
- entry.setValue(result1, 1111, const <TargetedResult>[]);
- expect(entry.getState(result1), CacheState.VALID);
- expect(entry.getState(result2), CacheState.VALID);
- expect(entry.getValue(result1), 1111);
- expect(entry.getValue(result2), 222);
- }
-
- test_setValue_userBeforeProvider_invalidateProvider_alsoUser() {
- AnalysisTarget target1 = new TestSource('/a.dart');
- AnalysisTarget target2 = new TestSource('/b.dart');
- CacheEntry entry1 = new CacheEntry(target1);
- CacheEntry entry2 = new CacheEntry(target2);
- cache.put(entry1);
- cache.put(entry2);
- ResultDescriptor<int> result1 = new ResultDescriptor<int>('result1', -1);
- ResultDescriptor<int> result2 = new ResultDescriptor<int>('result2', -2);
- // set results, all of them are VALID
- entry2.setValue(result2, 222, [new TargetedResult(target1, result1)]);
- entry1.setValue(result1, 111, const <TargetedResult>[]);
- expect(entry1.getState(result1), CacheState.VALID);
- expect(entry2.getState(result2), CacheState.VALID);
- expect(entry1.getValue(result1), 111);
- expect(entry2.getValue(result2), 222);
- // invalidate result1, should invalidate also result2
- entry1.setState(result1, CacheState.INVALID);
- expect(entry1.getState(result1), CacheState.INVALID);
- expect(entry2.getState(result2), CacheState.INVALID);
- }
-
- test_setValueIncremental() {
- AnalysisTarget target = new TestSource();
- CacheEntry entry = new CacheEntry(target);
- cache.put(entry);
- ResultDescriptor<int> result1 = new ResultDescriptor<int>('result1', -1);
- ResultDescriptor<int> result2 = new ResultDescriptor<int>('result2', -2);
- ResultDescriptor<int> result3 = new ResultDescriptor<int>('result3', -3);
- // set results, all of them are VALID
- entry.setValue(result1, 111, const <TargetedResult>[]);
- entry.setValue(result2, 222, [new TargetedResult(target, result1)]);
- entry.setValue(result3, 333, [new TargetedResult(target, result2)]);
- expect(entry.getState(result1), CacheState.VALID);
- expect(entry.getState(result2), CacheState.VALID);
- expect(entry.getState(result3), CacheState.VALID);
- expect(entry.getValue(result1), 111);
- expect(entry.getValue(result2), 222);
- expect(entry.getValue(result3), 333);
- // replace result1, keep "dependedOn", invalidate result3
- entry.setValueIncremental(result2, 2222, true);
- expect(entry.getState(result1), CacheState.VALID);
- expect(entry.getState(result2), CacheState.VALID);
- expect(entry.getState(result3), CacheState.INVALID);
- expect(entry.getValue(result1), 111);
- expect(entry.getValue(result2), 2222);
- expect(entry.getValue(result3), -3);
- expect(entry.getResultData(result1).dependentResults,
- unorderedEquals([new TargetedResult(target, result2)]));
- expect(entry.getResultData(result2).dependedOnResults,
- unorderedEquals([new TargetedResult(target, result1)]));
- }
-
- test_toString_empty() {
- AnalysisTarget target = new TestSource();
- CacheEntry entry = new CacheEntry(target);
- expect(entry.toString(), isNotNull);
- }
-
- test_toString_nonEmpty() {
- AnalysisTarget target = new TestSource();
- ResultDescriptor<int> result = new ResultDescriptor<int>('test', null);
- CacheEntry entry = new CacheEntry(target);
- cache.put(entry);
- entry.setValue(result, 42, const <TargetedResult>[]);
- expect(entry.toString(), isNotNull);
- }
-}
-
-@reflectiveTest
-class CacheFlushManagerTest {
- CacheFlushManager manager = new CacheFlushManager(
- new SimpleResultCachingPolicy(15, 3), (AnalysisTarget target) => false);
-
- test_madeActive() {
- manager.madeActive();
- expect(manager.maxSize, 15);
- }
-
- test_madeIdle() {
- manager.madeActive();
- AnalysisTarget target = new TestSource();
- // prepare TargetedResult(s)
- List<TargetedResult> results = <TargetedResult>[];
- for (int i = 0; i < 15; i++) {
- ResultDescriptor descriptor = new ResultDescriptor('result$i', null);
- results.add(new TargetedResult(target, descriptor));
- }
- // notify about storing TargetedResult(s)
- for (TargetedResult result in results) {
- manager.resultStored(result, null);
- }
- expect(manager.recentlyUsed, results);
- expect(manager.currentSize, 15);
- // make idle
- List<TargetedResult> resultsToFlush = manager.madeIdle();
- expect(manager.maxSize, 3);
- expect(manager.recentlyUsed, results.skip(15 - 3));
- expect(resultsToFlush, results.take(15 - 3));
- }
-
- test_new() {
- expect(manager.maxActiveSize, 15);
- expect(manager.maxIdleSize, 3);
- expect(manager.maxSize, 15);
- expect(manager.currentSize, 0);
- expect(manager.recentlyUsed, isEmpty);
- }
-
- test_resultAccessed() {
- ResultDescriptor descriptor1 = new ResultDescriptor('result1', null);
- ResultDescriptor descriptor2 = new ResultDescriptor('result2', null);
- ResultDescriptor descriptor3 = new ResultDescriptor('result3', null);
- AnalysisTarget target = new TestSource();
- TargetedResult result1 = new TargetedResult(target, descriptor1);
- TargetedResult result2 = new TargetedResult(target, descriptor2);
- TargetedResult result3 = new TargetedResult(target, descriptor3);
- manager.resultStored(result1, null);
- manager.resultStored(result2, null);
- manager.resultStored(result3, null);
- expect(manager.currentSize, 3);
- expect(manager.recentlyUsed, orderedEquals([result1, result2, result3]));
- // access result2
- manager.resultAccessed(result2);
- expect(manager.currentSize, 3);
- expect(manager.recentlyUsed, orderedEquals([result1, result3, result2]));
- }
-
- test_resultAccessed_negativeMaxSize() {
- manager = new CacheFlushManager(new SimpleResultCachingPolicy(-1, -1),
- (AnalysisTarget target) => false);
- ResultDescriptor descriptor1 = new ResultDescriptor('result1', null);
- ResultDescriptor descriptor2 = new ResultDescriptor('result2', null);
- AnalysisTarget target = new TestSource();
- TargetedResult result1 = new TargetedResult(target, descriptor1);
- TargetedResult result2 = new TargetedResult(target, descriptor2);
- manager.resultStored(result1, null);
- manager.resultStored(result2, null);
- expect(manager.currentSize, 0);
- expect(manager.recentlyUsed, isEmpty);
- // access result2
- manager.resultAccessed(result2);
- expect(manager.currentSize, 0);
- expect(manager.recentlyUsed, isEmpty);
- }
-
- test_resultAccessed_noSuchResult() {
- ResultDescriptor descriptor1 = new ResultDescriptor('result1', null);
- ResultDescriptor descriptor2 = new ResultDescriptor('result2', null);
- ResultDescriptor descriptor3 = new ResultDescriptor('result3', null);
- AnalysisTarget target = new TestSource();
- TargetedResult result1 = new TargetedResult(target, descriptor1);
- TargetedResult result2 = new TargetedResult(target, descriptor2);
- TargetedResult result3 = new TargetedResult(target, descriptor3);
- manager.resultStored(result1, null);
- manager.resultStored(result2, null);
- expect(manager.currentSize, 2);
- expect(manager.recentlyUsed, orderedEquals([result1, result2]));
- // access result3, no-op
- manager.resultAccessed(result3);
- expect(manager.currentSize, 2);
- expect(manager.recentlyUsed, orderedEquals([result1, result2]));
- }
-
- test_resultStored() {
- CacheFlushManager manager = new CacheFlushManager(
- new SimpleResultCachingPolicy(3, 3), (AnalysisTarget target) => false);
- ResultDescriptor descriptor1 = new ResultDescriptor('result1', null);
- ResultDescriptor descriptor2 = new ResultDescriptor('result2', null);
- ResultDescriptor descriptor3 = new ResultDescriptor('result3', null);
- ResultDescriptor descriptor4 = new ResultDescriptor('result4', null);
- AnalysisTarget target = new TestSource();
- TargetedResult result1 = new TargetedResult(target, descriptor1);
- TargetedResult result2 = new TargetedResult(target, descriptor2);
- TargetedResult result3 = new TargetedResult(target, descriptor3);
- TargetedResult result4 = new TargetedResult(target, descriptor4);
- manager.resultStored(result1, null);
- manager.resultStored(result2, null);
- manager.resultStored(result3, null);
- expect(manager.currentSize, 3);
- expect(manager.recentlyUsed, orderedEquals([result1, result2, result3]));
- // store result2 again
- {
- List<TargetedResult> resultsToFlush = manager.resultStored(result2, null);
- expect(resultsToFlush, isEmpty);
- expect(manager.currentSize, 3);
- expect(manager.recentlyUsed, orderedEquals([result1, result3, result2]));
- }
- // store result4
- {
- List<TargetedResult> resultsToFlush = manager.resultStored(result4, null);
- expect(resultsToFlush, [result1]);
- expect(manager.currentSize, 3);
- expect(manager.recentlyUsed, orderedEquals([result3, result2, result4]));
- expect(manager.resultSizeMap, {result3: 1, result2: 1, result4: 1});
- }
- }
-
- test_resultStored_negativeMaxSize() {
- manager = new CacheFlushManager(new SimpleResultCachingPolicy(-1, -1),
- (AnalysisTarget target) => false);
- ResultDescriptor descriptor1 = new ResultDescriptor('result1', null);
- ResultDescriptor descriptor2 = new ResultDescriptor('result2', null);
- AnalysisTarget target = new TestSource();
- TargetedResult result1 = new TargetedResult(target, descriptor1);
- TargetedResult result2 = new TargetedResult(target, descriptor2);
- manager.resultStored(result1, null);
- manager.resultStored(result2, null);
- expect(manager.currentSize, 0);
- expect(manager.recentlyUsed, isEmpty);
- }
-
- test_targetRemoved() {
- ResultDescriptor descriptor1 = new ResultDescriptor('result1', null);
- ResultDescriptor descriptor2 = new ResultDescriptor('result2', null);
- ResultDescriptor descriptor3 = new ResultDescriptor('result3', null);
- AnalysisTarget target1 = new TestSource('a.dart');
- AnalysisTarget target2 = new TestSource('b.dart');
- TargetedResult result1 = new TargetedResult(target1, descriptor1);
- TargetedResult result2 = new TargetedResult(target2, descriptor2);
- TargetedResult result3 = new TargetedResult(target1, descriptor3);
- manager.resultStored(result1, null);
- manager.resultStored(result2, null);
- manager.resultStored(result3, null);
- expect(manager.currentSize, 3);
- expect(manager.recentlyUsed, orderedEquals([result1, result2, result3]));
- expect(manager.resultSizeMap, {result1: 1, result2: 1, result3: 1});
- // remove target1
- {
- manager.targetRemoved(target1);
- expect(manager.currentSize, 1);
- expect(manager.recentlyUsed, orderedEquals([result2]));
- expect(manager.resultSizeMap, {result2: 1});
- }
- // remove target2
- {
- manager.targetRemoved(target2);
- expect(manager.currentSize, 0);
- expect(manager.recentlyUsed, isEmpty);
- expect(manager.resultSizeMap, isEmpty);
- }
- }
-}
-
-abstract class CachePartitionTest extends EngineTestCase {
- CachePartition createPartition();
-
- void test_creation() {
- expect(createPartition(), isNotNull);
- }
-
- void test_dispose() {
- CachePartition partition = createPartition();
- Source source1 = new TestSource('/1.dart');
- Source source2 = new TestSource('/2.dart');
- CacheEntry entry1 = new CacheEntry(source1);
- CacheEntry entry2 = new CacheEntry(source2);
- // add two sources
- partition.put(entry1);
- partition.put(entry2);
- expect(partition.entryMap, hasLength(2));
- expect(partition.pathToSource, hasLength(2));
- expect(partition.sources, unorderedEquals([source1, source2]));
- // dispose, no sources
- partition.dispose();
- expect(partition.entryMap, isEmpty);
- expect(partition.pathToSource, isEmpty);
- expect(partition.sources, isEmpty);
- }
-
- void test_entrySet() {
- CachePartition partition = createPartition();
- AnalysisTarget target = new TestSource();
- CacheEntry entry = new CacheEntry(target);
- partition.put(entry);
- Map<AnalysisTarget, CacheEntry> entryMap = partition.entryMap;
- expect(entryMap, hasLength(1));
- AnalysisTarget entryKey = entryMap.keys.first;
- expect(entryKey, target);
- expect(entryMap[entryKey], entry);
- }
-
- void test_get() {
- CachePartition partition = createPartition();
- AnalysisTarget target = new TestSource();
- expect(partition.get(target), isNull);
- }
-
- void test_put_alreadyInPartition() {
- CachePartition partition1 = createPartition();
- CachePartition partition2 = createPartition();
- AnalysisTarget target = new TestSource();
- CacheEntry entry = new CacheEntry(target);
- partition1.put(entry);
- expect(() => partition2.put(entry), throwsStateError);
- }
-
- void test_put_noFlush() {
- CachePartition partition = createPartition();
- AnalysisTarget target = new TestSource();
- CacheEntry entry = new CacheEntry(target);
- partition.put(entry);
- expect(partition.get(target), entry);
- }
-
- void test_remove_absent() {
- CachePartition partition = createPartition();
- AnalysisTarget target = new TestSource();
- expect(partition.get(target), isNull);
- expect(partition.remove(target), isNull);
- expect(partition.get(target), isNull);
- }
-
- void test_remove_present() {
- CachePartition partition = createPartition();
- AnalysisTarget target = new TestSource();
- CacheEntry entry = new CacheEntry(target);
- partition.put(entry);
- expect(partition.get(target), entry);
- expect(partition.remove(target), entry);
- expect(partition.get(target), isNull);
- }
-}
-
-@reflectiveTest
-class PackageCachePartitionTest extends CachePartitionTest
- with ResourceProviderMixin {
- Folder rootFolder;
-
- CachePartition createPartition() {
- rootFolder = newFolder('/package/root');
- return new PackageCachePartition(null, rootFolder);
- }
-
- void test_contains_false() {
- CachePartition partition = createPartition();
- AnalysisTarget target = new TestSource();
- expect(partition.isResponsibleFor(target), isFalse);
- }
-
- void test_contains_true() {
- SdkCachePartition partition = new SdkCachePartition(null);
- SourceFactory factory = new SourceFactory([
- new PackageMapUriResolver(resourceProvider, <String, List<Folder>>{
- 'root': <Folder>[rootFolder]
- })
- ]);
- AnalysisTarget target = factory.forUri("package:root/root.dart");
- expect(partition.isResponsibleFor(target), isTrue);
- }
-}
-
-@reflectiveTest
-class ResultDataTest extends EngineTestCase {
- test_creation() {
- String value = 'value';
- ResultData data = new ResultData(new ResultDescriptor('test', value));
- expect(data, isNotNull);
- expect(data.state, CacheState.INVALID);
- expect(data.value, value);
- }
-
- test_flush() {
- ResultDescriptor result = new ResultDescriptor('test', -1);
- ResultData data = new ResultData(result);
- data.state = CacheState.VALID;
- data.value = 123;
- data.flush();
- expect(data.state, CacheState.FLUSHED);
- expect(data.value, -1);
- }
-}
-
-@reflectiveTest
-class SdkCachePartitionTest extends CachePartitionTest {
- CachePartition createPartition() {
- return new SdkCachePartition(null);
- }
-
- void test_contains_false() {
- CachePartition partition = createPartition();
- AnalysisTarget target = new TestSource();
- expect(partition.isResponsibleFor(target), isFalse);
- }
-
- void test_contains_true() {
- SdkCachePartition partition = new SdkCachePartition(null);
- ResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE;
- FolderBasedDartSdk sdk = new FolderBasedDartSdk(resourceProvider,
- FolderBasedDartSdk.defaultSdkDirectory(resourceProvider));
- SourceFactory factory = new SourceFactory([new DartUriResolver(sdk)]);
- AnalysisTarget target = factory.forUri("dart:core");
- expect(partition.isResponsibleFor(target), isTrue);
- }
-}
-
-@reflectiveTest
-class UniversalCachePartitionTest extends CachePartitionTest {
- CachePartition createPartition() {
- return new UniversalCachePartition(null);
- }
-
- void test_contains() {
- UniversalCachePartition partition = new UniversalCachePartition(null);
- TestSource source = new TestSource();
- expect(partition.isResponsibleFor(source), isTrue);
- }
-
- test_dispose() {
- _InternalAnalysisContextMock context = new _InternalAnalysisContextMock();
- CachePartition partition1 = new UniversalCachePartition(context);
- CachePartition partition2 = new UniversalCachePartition(context);
- AnalysisCache cache = new AnalysisCache([partition1, partition2]);
- context.analysisCache = cache;
- // configure
- // prepare entries
- ResultDescriptor<int> descriptor1 =
- new ResultDescriptor<int>('result1', -1);
- ResultDescriptor<int> descriptor2 =
- new ResultDescriptor<int>('result2', -2);
- AnalysisTarget target1 = new TestSource('1.dart');
- AnalysisTarget target2 = new TestSource('2.dart');
- TargetedResult result1 = new TargetedResult(target1, descriptor1);
- TargetedResult result2 = new TargetedResult(target2, descriptor2);
- CacheEntry entry1 = new CacheEntry(target1);
- CacheEntry entry2 = new CacheEntry(target2);
- partition1.put(entry1);
- partition2.put(entry2);
- entry1.setValue(descriptor1, 1, const <TargetedResult>[]);
- entry2.setValue(descriptor2, 2, <TargetedResult>[result1]);
- // target2 is listed as dependent in target1
- expect(
- entry1.getResultData(descriptor1).dependentResults, contains(result2));
- // dispose
- partition2.dispose();
- expect(partition1.get(target1), same(entry1));
- expect(partition2.get(target2), isNull);
- // result2 is removed from result1
- expect(entry1.getResultData(descriptor1).dependentResults, isEmpty);
- }
-}
-
-class _InternalAnalysisContextMock implements InternalAnalysisContext {
- @override
- final AnalysisOptions analysisOptions = new AnalysisOptionsImpl();
-
- @override
- AnalysisCache analysisCache;
-
- @override
- List<Source> prioritySources = <Source>[];
-
- @override
- noSuchMethod(Invocation invocation) {
- throw new StateError('Unexpected invocation of ${invocation.memberName}');
- }
-}
-
-/**
- * Keep the given [keepDescriptor], invalidate all the other results.
- */
-class _KeepContinueDelta implements Delta {
- final Source source;
- final ResultDescriptor keepDescriptor;
-
- _KeepContinueDelta(this.source, this.keepDescriptor);
-
- @override
- bool get shouldGatherChanges => false;
-
- @override
- bool gatherChanges(InternalAnalysisContext context, AnalysisTarget target,
- ResultDescriptor descriptor, Object value) {
- return false;
- }
-
- @override
- void gatherEnd() {}
-
- @override
- DeltaResult validate(InternalAnalysisContext context, AnalysisTarget target,
- ResultDescriptor descriptor, Object value) {
- if (descriptor == keepDescriptor) {
- return DeltaResult.KEEP_CONTINUE;
- }
- return DeltaResult.INVALIDATE;
- }
-}
-
-class _TestAnalysisTarget implements AnalysisTarget {
- final Source librarySource;
- final Source source;
- _TestAnalysisTarget({this.librarySource, this.source});
-}
diff --git a/pkg/analyzer/test/src/context/test_all.dart b/pkg/analyzer/test/src/context/test_all.dart
index 5f5e2d0..ffe28aa 100644
--- a/pkg/analyzer/test/src/context/test_all.dart
+++ b/pkg/analyzer/test/src/context/test_all.dart
@@ -5,14 +5,12 @@
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'builder_test.dart' as builder_test;
-import 'cache_test.dart' as cache_test;
import 'source_test.dart' as source_test;
/// Utility for manually running all tests.
main() {
defineReflectiveSuite(() {
builder_test.main();
- cache_test.main();
source_test.main();
}, name: 'context');
}
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
index dcc2fad..dc8f58b 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
@@ -6,7 +6,6 @@
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/error/error.dart';
@@ -711,15 +710,8 @@
}
}
-/// TODO(paulberry): migrate this test away from the task model.
-/// See dartbug.com/35734.
@reflectiveTest
class AnalysisDriverTest extends BaseAnalysisDriverTest {
- void configurePreviewDart2() {
- driver.configure(
- analysisOptions: new AnalysisOptionsImpl.from(driver.analysisOptions));
- }
-
test_addedFiles() async {
var a = convertPath('/test/lib/a.dart');
var b = convertPath('/test/lib/b.dart');
@@ -1278,8 +1270,6 @@
}
test_const_implicitCreation() async {
- configurePreviewDart2();
-
var a = convertPath('/test/bin/a.dart');
var b = convertPath('/test/bin/b.dart');
newFile(a, content: r'''
@@ -1304,8 +1294,6 @@
}
test_const_implicitCreation_rewrite() async {
- configurePreviewDart2();
-
var a = convertPath('/test/bin/a.dart');
var b = convertPath('/test/bin/b.dart');
newFile(a, content: r'''
@@ -1954,10 +1942,7 @@
ResolvedUnitResult result = await driver.getResult(testFile);
expect(result.path, testFile);
// Has only exports for valid URIs.
- List<ExportElement> imports = resolutionMap
- .elementDeclaredByCompilationUnit(result.unit)
- .library
- .exports;
+ List<ExportElement> imports = result.libraryElement.exports;
expect(imports.map((import) {
return import.exportedLibrary?.source?.uri?.toString();
}), ['dart:async', null, 'dart:math']);
@@ -1974,10 +1959,7 @@
ResolvedUnitResult result = await driver.getResult(testFile);
expect(result.path, testFile);
// Has only imports for valid URIs.
- List<ImportElement> imports = resolutionMap
- .elementDeclaredByCompilationUnit(result.unit)
- .library
- .imports;
+ List<ImportElement> imports = result.libraryElement.imports;
expect(imports.map((import) {
return import.importedLibrary?.source?.uri?.toString();
}), ['dart:async', null, 'dart:math', 'dart:core']);
@@ -3452,9 +3434,8 @@
String _getClassFieldType(
CompilationUnit unit, String className, String fieldName) {
- return resolutionMap
- .elementDeclaredByVariableDeclaration(
- _getClassField(unit, className, fieldName))
+ return _getClassField(unit, className, fieldName)
+ .declaredElement
.type
.toString();
}
@@ -3474,9 +3455,8 @@
String _getClassMethodReturnType(
CompilationUnit unit, String className, String fieldName) {
- return resolutionMap
- .elementDeclaredByMethodDeclaration(
- _getClassMethod(unit, className, fieldName))
+ return _getClassMethod(unit, className, fieldName)
+ .declaredElement
.type
.returnType
.toString();
@@ -3506,10 +3486,7 @@
String _getTopLevelVarType(CompilationUnit unit, String name) {
VariableDeclaration variable = _getTopLevelVar(unit, name);
- return resolutionMap
- .elementDeclaredByVariableDeclaration(variable)
- .type
- .toString();
+ return variable.declaredElement.type.toString();
}
}
diff --git a/pkg/analyzer/test/src/dart/analysis/results_test.dart b/pkg/analyzer/test/src/dart/analysis/results_test.dart
index 06a0b47..030194c 100644
--- a/pkg/analyzer/test/src/dart/analysis/results_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/results_test.dart
@@ -2,10 +2,12 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/dart/analysis/results.dart';
+import 'package:analyzer/src/generated/engine.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -14,10 +16,32 @@
main() {
defineReflectiveSuite(() {
defineReflectiveTests(GetElementDeclarationParsedTest);
+ defineReflectiveTests(GetElementDeclarationParsedWithExtensionMethodsTest);
defineReflectiveTests(GetElementDeclarationResolvedTest);
+ defineReflectiveTests(
+ GetElementDeclarationResolvedWithExtensionMethodsTest);
});
}
+mixin ExtensionMethodsMixin implements GetElementDeclarationMixin {
+ @override
+ AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+ ..contextFeatures = new FeatureSet.forTesting(
+ sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
+
+ test_extension() async {
+ addTestFile(r'''
+extension E on int {}
+''');
+ await resolveTestFile();
+
+ var element = findNode.extensionDeclaration('E').declaredElement;
+ var result = await getElementDeclaration(element);
+ ExtensionDeclaration node = result.node;
+ expect(node.name.name, 'E');
+ }
+}
+
mixin GetElementDeclarationMixin implements DriverResolutionTest {
Future<ElementDeclarationResult> getElementDeclaration(Element element);
@@ -461,6 +485,10 @@
}
@reflectiveTest
+class GetElementDeclarationParsedWithExtensionMethodsTest
+ extends GetElementDeclarationParsedTest with ExtensionMethodsMixin {}
+
+@reflectiveTest
class GetElementDeclarationResolvedTest extends DriverResolutionTest
with GetElementDeclarationMixin {
@override
@@ -475,3 +503,7 @@
return driver.getResolvedLibrary(path);
}
}
+
+@reflectiveTest
+class GetElementDeclarationResolvedWithExtensionMethodsTest
+ extends GetElementDeclarationResolvedTest with ExtensionMethodsMixin {}
diff --git a/pkg/analyzer/test/src/dart/analysis/search_test.dart b/pkg/analyzer/test/src/dart/analysis/search_test.dart
index 8b8b2a0..f74da70 100644
--- a/pkg/analyzer/test/src/dart/analysis/search_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/search_test.dart
@@ -7,7 +7,6 @@
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/ast/ast.dart' hide Declaration;
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/dart/analysis/search.dart';
import 'package:analyzer/src/dart/ast/element_locator.dart';
@@ -349,8 +348,7 @@
ConstructorElement element = _findElementAtString('A() {}');
CompilationUnit otherUnit = (await driver.getResult(other)).unit;
- Element main =
- resolutionMap.elementDeclaredByCompilationUnit(otherUnit).functions[0];
+ Element main = otherUnit.declaredElement.functions[0];
var expected = [
new ExpectedResult(main, SearchResultKind.REFERENCE,
otherCode.indexOf('(); // in other'), 0,
diff --git a/pkg/analyzer/test/src/dart/element/element_test.dart b/pkg/analyzer/test/src/dart/element/element_test.dart
index ee62881..15d7978 100644
--- a/pkg/analyzer/test/src/dart/element/element_test.dart
+++ b/pkg/analyzer/test/src/dart/element/element_test.dart
@@ -10,7 +10,6 @@
import 'package:analyzer/src/dart/element/handle.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
-import 'package:analyzer/src/generated/source_io.dart';
import 'package:analyzer/src/generated/testing/ast_test_factory.dart';
import 'package:analyzer/src/generated/testing/element_factory.dart';
import 'package:analyzer/src/generated/testing/test_type_provider.dart';
@@ -3332,24 +3331,6 @@
unorderedEquals(<CompilationUnitElement>[unitLib, unitA, unitB]));
}
- void test_invalidateLibraryCycles_withHandle() {
- AnalysisContext context = createAnalysisContext();
- context.sourceFactory = new SourceFactory([]);
- LibraryElementImpl library = ElementFactory.library(context, "foo");
- LibraryElementImpl importedLibrary = ElementFactory.library(context, "bar");
- ElementLocation location = new ElementLocationImpl.con2('');
- TestElementResynthesizer resynthesizer =
- new TestElementResynthesizer(context, {location: importedLibrary});
- LibraryElement importedLibraryHandle =
- new LibraryElementHandle(resynthesizer, location);
- ImportElementImpl import =
- ElementFactory.importFor(importedLibraryHandle, null);
- library.imports = <ImportElement>[import];
- library.libraryCycle; // Force computation of the cycle.
-
- library.invalidateLibraryCycles();
- }
-
void test_setImports() {
AnalysisContext context = createAnalysisContext();
LibraryElementImpl library = new LibraryElementImpl.forNode(
diff --git a/pkg/analyzer/test/src/dart/resolution/assignment_test.dart b/pkg/analyzer/test/src/dart/resolution/assignment_test.dart
index d3a06ce..e75f914 100644
--- a/pkg/analyzer/test/src/dart/resolution/assignment_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/assignment_test.dart
@@ -4,6 +4,7 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/error/codes.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -131,6 +132,63 @@
assertType(right, 'int');
}
+ test_compound_refineType_int_double() async {
+ await assertErrorsInCode(r'''
+main(int i) {
+ i += 1.2;
+ i -= 1.2;
+ i *= 1.2;
+ i %= 1.2;
+}
+''', [
+ error(StaticTypeWarningCode.INVALID_ASSIGNMENT, 21, 3),
+ error(StaticTypeWarningCode.INVALID_ASSIGNMENT, 33, 3),
+ error(StaticTypeWarningCode.INVALID_ASSIGNMENT, 45, 3),
+ error(StaticTypeWarningCode.INVALID_ASSIGNMENT, 57, 3),
+ ]);
+ assertType(findNode.assignment('+='), 'double');
+ assertType(findNode.assignment('-='), 'double');
+ assertType(findNode.assignment('*='), 'double');
+ assertType(findNode.assignment('%='), 'double');
+ }
+
+ test_compound_refineType_int_int() async {
+ await assertNoErrorsInCode(r'''
+main(int i) {
+ i += 1;
+ i -= 1;
+ i *= 1;
+ i ~/= 1;
+ i %= 1;
+}
+''');
+ assertType(findNode.assignment('+='), 'int');
+ assertType(findNode.assignment('-='), 'int');
+ assertType(findNode.assignment('*='), 'int');
+ assertType(findNode.assignment('~/='), 'int');
+ assertType(findNode.assignment('%='), 'int');
+ }
+
+ test_compoundIfNull_differentTypes() async {
+ await assertErrorsInCode(r'''
+main(double a, int b) {
+ a ??= b;
+}
+''', [
+ error(StaticTypeWarningCode.INVALID_ASSIGNMENT, 32, 1),
+ ]);
+ assertType(findNode.assignment('??='), 'num');
+ }
+
+ test_compoundIfNull_sameTypes() async {
+ await assertNoErrorsInCode(r'''
+main(int a) {
+ a ??= 0;
+}
+''');
+ assertType(findNode.assignment('??='), 'int');
+ }
+
test_in_const_context() async {
addTestFile('''
void f(num x, int y) {
diff --git a/pkg/analyzer/test/src/dart/resolution/ast_rewrite_test.dart b/pkg/analyzer/test/src/dart/resolution/ast_rewrite_test.dart
index 73316d2..5cfd48d 100644
--- a/pkg/analyzer/test/src/dart/resolution/ast_rewrite_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/ast_rewrite_test.dart
@@ -382,6 +382,10 @@
@required String expectedExtendedType,
}) {
expect(override.staticElement, expectedElement);
+
+ assertTypeNull(override);
+ assertTypeNull(override.extensionName);
+
assertElementTypeStrings(
override.typeArgumentTypes,
expectedTypeArguments,
diff --git a/pkg/analyzer/test/src/dart/resolution/extension_method_test.dart b/pkg/analyzer/test/src/dart/resolution/extension_method_test.dart
index a51e157..7c00d1f 100644
--- a/pkg/analyzer/test/src/dart/resolution/extension_method_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/extension_method_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/analysis/features.dart';
-import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:analyzer/src/dart/error/syntactic_errors.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/test_utilities/mock_sdk.dart';
@@ -15,6 +15,7 @@
main() {
defineReflectiveSuite(() {
defineReflectiveTests(ExtensionMethodsDeclarationTest);
+ defineReflectiveTests(ExtensionMethodsExtendedTypeTest);
defineReflectiveTests(ExtensionMethodsExternalReferenceTest);
defineReflectiveTests(ExtensionMethodsInternalReferenceTest);
});
@@ -48,6 +49,31 @@
])
];
+ test_constructor() async {
+ await assertErrorsInCode('''
+extension E {
+ E() {}
+}
+''', [
+ error(ParserErrorCode.EXPECTED_TOKEN, 10, 1),
+ error(ParserErrorCode.EXPECTED_TYPE_NAME, 12, 1),
+ error(ParserErrorCode.EXTENSION_DECLARES_CONSTRUCTOR, 16, 1),
+ ]);
+ }
+
+ test_factory() async {
+ await assertErrorsInCode('''
+extension E {
+ factory S() {}
+}
+''', [
+ error(ParserErrorCode.EXPECTED_TOKEN, 10, 1),
+ error(CompileTimeErrorCode.UNDEFINED_CLASS, 12, 0),
+ error(ParserErrorCode.EXPECTED_TYPE_NAME, 12, 1),
+ error(ParserErrorCode.EXTENSION_DECLARES_CONSTRUCTOR, 16, 7),
+ ]);
+ }
+
test_fromPlatform() async {
await assertNoErrorsInCode('''
import 'dart:test2';
@@ -77,110 +103,6 @@
''');
}
- test_named_generic() async {
- await assertNoErrorsInCode('''
-class C<T> {}
-extension E<S> on C<S> {}
-''');
- var extendedType = findNode.typeAnnotation('C<S>');
- assertElement(extendedType, findElement.class_('C'));
- assertType(extendedType, 'C<S>');
- }
-
- test_named_onDynamic() async {
- await assertNoErrorsInCode('''
-extension E on dynamic {}
-''');
- var extendedType = findNode.typeAnnotation('dynamic');
- assertType(extendedType, 'dynamic');
- }
-
- test_named_onEnum() async {
- await assertNoErrorsInCode('''
-enum A {a, b, c}
-extension E on A {}
-''');
- var extendedType = findNode.typeAnnotation('A {}');
- assertElement(extendedType, findElement.enum_('A'));
- assertType(extendedType, 'A');
- }
-
- test_named_onFunctionType() async {
- try {
- await assertNoErrorsInCode('''
-extension E on int Function(int) {}
-''');
- var extendedType = findNode.typeAnnotation('Function');
- assertType(extendedType, 'int Function(int)');
- if (!AnalysisDriver.useSummary2) {
- throw 'Test passed - expected to fail.';
- }
- } on String {
- rethrow;
- } catch (e) {
- if (AnalysisDriver.useSummary2) {
- rethrow;
- }
- }
- }
-
- test_named_onInterface() async {
- await assertNoErrorsInCode('''
-class C { }
-extension E on C {}
-''');
- var extendedType = findNode.typeAnnotation('C {}');
- assertElement(extendedType, findElement.class_('C'));
- assertType(extendedType, 'C');
- }
-
- test_unnamed_generic() async {
- await assertNoErrorsInCode('''
-class C<T> {}
-extension<S> on C<S> {}
-''');
- var extendedType = findNode.typeAnnotation('C<S>');
- assertElement(extendedType, findElement.class_('C'));
- assertType(extendedType, 'C<S>');
- }
-
- test_unnamed_onDynamic() async {
- await assertNoErrorsInCode('''
-extension on dynamic {}
-''');
- var extendedType = findNode.typeAnnotation('dynamic');
- assertType(extendedType, 'dynamic');
- }
-
- test_unnamed_onEnum() async {
- await assertNoErrorsInCode('''
-enum A {a, b, c}
-extension on A {}
-''');
- var extendedType = findNode.typeAnnotation('A {}');
- assertElement(extendedType, findElement.enum_('A'));
- assertType(extendedType, 'A');
- }
-
- @failingTest
- test_unnamed_onFunctionType() async {
- await assertNoErrorsInCode('''
-extension on int Function(int) {}
-''');
- var extendedType = findNode.typeAnnotation('int ');
- assertType(extendedType, 'int Function(int)');
- }
-
- test_unnamed_onInterface() async {
- await assertNoErrorsInCode('''
-class C { }
-extension on C {}
-''');
- var extendedType = findNode.typeAnnotation('C {}');
- assertElement(extendedType, findElement.class_('C'));
- assertType(extendedType, 'C');
- }
-
test_visibility_hidden() async {
newFile('/test/lib/lib.dart', content: '''
class C {}
@@ -337,7 +259,6 @@
''');
}
- @failingTest
test_visibility_withPrefix() async {
newFile('/test/lib/lib.dart', content: '''
class C {}
@@ -357,6 +278,129 @@
}
}
+/// Tests that show that extension declarations support all of the possible
+/// types in the `on` clause.
+@reflectiveTest
+class ExtensionMethodsExtendedTypeTest extends BaseExtensionMethodsTest {
+ test_named_generic() async {
+ await assertNoErrorsInCode('''
+class C<T> {}
+extension E<S> on C<S> {}
+''');
+ var extendedType = findNode.typeAnnotation('C<S>');
+ assertElement(extendedType, findElement.class_('C'));
+ assertType(extendedType, 'C<S>');
+ }
+
+ test_named_onDynamic() async {
+ await assertNoErrorsInCode('''
+extension E on dynamic {}
+''');
+ var extendedType = findNode.typeAnnotation('dynamic');
+ assertType(extendedType, 'dynamic');
+ }
+
+ test_named_onEnum() async {
+ await assertNoErrorsInCode('''
+enum A {a, b, c}
+extension E on A {}
+''');
+ var extendedType = findNode.typeAnnotation('A {}');
+ assertElement(extendedType, findElement.enum_('A'));
+ assertType(extendedType, 'A');
+ }
+
+ test_named_onFunctionType() async {
+ await assertNoErrorsInCode('''
+extension E on int Function(int) {}
+''');
+ var extendedType = findNode.typeAnnotation('Function');
+ assertType(extendedType, 'int Function(int)');
+ }
+
+ test_named_onInterface() async {
+ await assertNoErrorsInCode('''
+class C { }
+extension E on C {}
+''');
+ var extendedType = findNode.typeAnnotation('C {}');
+ assertElement(extendedType, findElement.class_('C'));
+ assertType(extendedType, 'C');
+ }
+
+ test_named_onMixin() async {
+ await assertNoErrorsInCode('''
+mixin M {
+}
+extension E on M {}
+''');
+ var extendedType = findNode.typeAnnotation('M {}');
+ assertElement(extendedType, findElement.mixin('M'));
+ assertType(extendedType, 'M');
+ }
+
+ test_unnamed_generic() async {
+ await assertNoErrorsInCode('''
+class C<T> {}
+extension<S> on C<S> {}
+''');
+ var extendedType = findNode.typeAnnotation('C<S>');
+ assertElement(extendedType, findElement.class_('C'));
+ assertType(extendedType, 'C<S>');
+ }
+
+ test_unnamed_onDynamic() async {
+ await assertNoErrorsInCode('''
+extension on dynamic {}
+''');
+ var extendedType = findNode.typeAnnotation('dynamic');
+ assertType(extendedType, 'dynamic');
+ }
+
+ test_unnamed_onEnum() async {
+ await assertNoErrorsInCode('''
+enum A {a, b, c}
+extension on A {}
+''');
+ var extendedType = findNode.typeAnnotation('A {}');
+ assertElement(extendedType, findElement.enum_('A'));
+ assertType(extendedType, 'A');
+ }
+
+ test_unnamed_onFunctionType() async {
+ await assertNoErrorsInCode('''
+extension on int Function(String) {}
+''');
+ var extendedType = findNode.typeAnnotation('Function');
+ assertType(extendedType, 'int Function(String)');
+ var returnType = findNode.typeAnnotation('int');
+ assertType(returnType, 'int');
+ var parameterType = findNode.typeAnnotation('String');
+ assertType(parameterType, 'String');
+ }
+
+ test_unnamed_onInterface() async {
+ await assertNoErrorsInCode('''
+class C { }
+extension on C {}
+''');
+ var extendedType = findNode.typeAnnotation('C {}');
+ assertElement(extendedType, findElement.class_('C'));
+ assertType(extendedType, 'C');
+ }
+
+ test_unnamed_onMixin() async {
+ await assertNoErrorsInCode('''
+mixin M {
+}
+extension on M {}
+''');
+ var extendedType = findNode.typeAnnotation('M {}');
+ assertElement(extendedType, findElement.mixin('M'));
+ assertType(extendedType, 'M');
+ }
+}
+
/// Tests that extension members can be correctly resolved when referenced
/// by code external to the extension declaration.
@reflectiveTest
@@ -602,27 +646,6 @@
assertType(access, 'int');
}
- test_instance_getter_with_setter() async {
- await assertNoErrorsInCode('''
-class C {}
-
-extension E on C {
- int get a => 1;
-}
-
-extension E2 on C {
- set a(int v) { }
-}
-
-f(C c) {
- print(c.a);
-}
-''');
- var access = findNode.prefixed('c.a');
- assertElement(access, findElement.getter('a'));
- assertType(access, 'int');
- }
-
test_instance_getterInvoked_fromExtension_functionType() async {
await assertNoErrorsInCode('''
extension E on int Function(int) {
@@ -1083,27 +1106,6 @@
assertElement(access, findElement.setter('a'));
}
- test_instance_setter_with_getter() async {
- await assertNoErrorsInCode('''
-class C {}
-
-extension E on C {
- int get a => 1;
-}
-
-extension E2 on C {
- set a(int v) { }
-}
-
-f(C c) {
- print(c.a = 1);
-}
-''');
- var access = findNode.prefixed('c.a');
- assertElement(access, findElement.setter('a'));
- assertType(access, 'int');
- }
-
test_instance_tearoff_fromExtension_functionType() async {
await assertNoErrorsInCode('''
extension E on int Function(int) {
diff --git a/pkg/analyzer/test/src/dart/resolution/extension_override_test.dart b/pkg/analyzer/test/src/dart/resolution/extension_override_test.dart
index cb1bd80..e76fb1b 100644
--- a/pkg/analyzer/test/src/dart/resolution/extension_override_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/extension_override_test.dart
@@ -556,6 +556,10 @@
void validateOverride({List<DartType> typeArguments}) {
expect(extensionOverride.extensionName.staticElement, extension);
+
+ expect(extensionOverride.staticType, isNull);
+ expect(extensionOverride.extensionName.staticType, isNull);
+
if (typeArguments == null) {
expect(extensionOverride.typeArguments, isNull);
} else {
diff --git a/pkg/analyzer/test/src/dart/resolution/index_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/index_expression_test.dart
new file mode 100644
index 0000000..4a95d53
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/resolution/index_expression_test.dart
@@ -0,0 +1,282 @@
+// Copyright (c) 2018, 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/features.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'driver_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(IndexExpressionTest);
+ defineReflectiveTests(IndexExpressionWithNnbdTest);
+ });
+}
+
+@reflectiveTest
+class IndexExpressionTest extends DriverResolutionTest {
+ test_read() async {
+ await assertNoErrorsInCode(r'''
+class A {
+ bool operator[](int index) => false;
+}
+
+main(A a) {
+ a[0];
+}
+''');
+
+ var indexElement = findElement.method('[]');
+
+ var indexExpression = findNode.index('a[0]');
+ assertElement(indexExpression, indexElement);
+ assertAuxElement(indexExpression, null);
+ assertParameterElement(
+ indexExpression.index,
+ indexElement.parameters[0],
+ );
+ assertType(indexExpression, 'bool');
+ }
+
+ test_read_generic() async {
+ await assertNoErrorsInCode(r'''
+class A<T> {
+ T operator[](int index) => null;
+}
+
+main(A<double> a) {
+ a[0];
+}
+''');
+
+ var indexElement = findElement.method('[]');
+
+ var indexExpression = findNode.index('a[0]');
+ assertMember(indexExpression, indexElement, {'T': 'double'});
+ assertAuxElement(indexExpression, null);
+ assertParameterElement(
+ indexExpression.index,
+ indexElement.parameters[0],
+ );
+ assertType(indexExpression, 'double');
+ }
+
+ test_readWrite() async {
+ await assertNoErrorsInCode(r'''
+class A {
+ num operator[](int index) => 0;
+ void operator[]=(int index, num value) {}
+}
+
+main(A a) {
+ a[0] += 1.2;
+}
+''');
+
+ var indexElement = findElement.method('[]');
+ var indexEqElement = findElement.method('[]=');
+ var numPlusElement = numElement.getMethod('+');
+
+ var indexExpression = findNode.index('a[0]');
+ assertElement(indexExpression, indexEqElement);
+ assertAuxElement(indexExpression, indexElement);
+ assertParameterElement(
+ indexExpression.index,
+ indexEqElement.parameters[0],
+ );
+ assertType(indexExpression, 'num');
+
+ var assignment = indexExpression.parent as AssignmentExpression;
+ assertElement(assignment, numPlusElement);
+ assertType(assignment, 'num');
+ assertParameterElement(
+ assignment.rightHandSide,
+ numPlusElement.parameters[0],
+ );
+ }
+
+ test_readWrite_generic() async {
+ await assertNoErrorsInCode(r'''
+class A<T> {
+ T operator[](int index) => null;
+ void operator[]=(int index, T value) {}
+}
+
+main(A<double> a) {
+ a[0] += 1.2;
+}
+''');
+
+ var indexElement = findElement.method('[]');
+ var indexEqElement = findElement.method('[]=');
+ var doublePlusElement = doubleElement.getMethod('+');
+
+ var indexExpression = findNode.index('a[0]');
+ assertMember(indexExpression, indexEqElement, {'T': 'double'});
+ assertAuxMember(indexExpression, indexElement, {'T': 'double'});
+ assertParameterElement(
+ indexExpression.index,
+ indexEqElement.parameters[0],
+ );
+ assertType(indexExpression, 'double');
+
+ var assignment = indexExpression.parent as AssignmentExpression;
+ assertElement(assignment, doublePlusElement);
+ assertType(assignment, 'double');
+ assertParameterElement(
+ assignment.rightHandSide,
+ doublePlusElement.parameters[0],
+ );
+ }
+
+ test_write() async {
+ await assertNoErrorsInCode(r'''
+class A {
+ void operator[]=(int index, num value) {}
+}
+
+main(A a) {
+ a[0] = 1.2;
+}
+''');
+
+ var indexEqElement = findElement.method('[]=');
+
+ var indexExpression = findNode.index('a[0]');
+ assertElement(indexExpression, indexEqElement);
+ assertAuxElement(indexExpression, null);
+ assertParameterElement(
+ indexExpression.index,
+ indexEqElement.parameters[0],
+ );
+ assertType(indexExpression, 'num');
+
+ var assignment = indexExpression.parent as AssignmentExpression;
+ assertElement(assignment, null);
+ assertType(assignment, 'double');
+ assertParameterElement(assignment.rightHandSide, null);
+ }
+
+ test_write_generic() async {
+ await assertNoErrorsInCode(r'''
+class A<T> {
+ void operator[]=(int index, T value) {}
+}
+
+main(A<double> a) {
+ a[0] = 1.2;
+}
+''');
+
+ var indexEqElement = findElement.method('[]=');
+
+ var indexExpression = findNode.index('a[0]');
+ assertMember(indexExpression, indexEqElement, {'T': 'double'});
+ assertAuxElement(indexExpression, null);
+ assertParameterElement(
+ indexExpression.index,
+ indexEqElement.parameters[0],
+ );
+ assertType(indexExpression, 'double');
+
+ var assignment = indexExpression.parent as AssignmentExpression;
+ assertElement(assignment, null);
+ assertType(assignment, 'double');
+ assertParameterElement(assignment.rightHandSide, null);
+ }
+}
+
+@reflectiveTest
+class IndexExpressionWithNnbdTest extends IndexExpressionTest {
+ @override
+ AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+ ..contextFeatures = FeatureSet.forTesting(
+ sdkVersion: '2.3.0', additionalFeatures: [Feature.non_nullable]);
+
+ @override
+ bool get typeToStringWithNullability => true;
+
+ test_read_nullable() async {
+ await assertNoErrorsInCode(r'''
+class A {
+ bool operator[](int index) => false;
+}
+
+main(A? a) {
+ a?.[0];
+}
+''');
+
+ var indexElement = findElement.method('[]');
+
+ var indexExpression = findNode.index('a?.[0]');
+ assertElement(indexExpression, indexElement);
+ assertAuxElement(indexExpression, null);
+ assertType(indexExpression, 'bool?');
+ }
+
+ test_readWrite_nullable() async {
+ await assertNoErrorsInCode(r'''
+class A {
+ num operator[](int index) => 0;
+ void operator[]=(int index, num value) {}
+}
+
+main(A? a) {
+ a?.[0] += 1.2;
+}
+''');
+
+ var indexElement = findElement.method('[]');
+ var indexEqElement = findElement.method('[]=');
+ var numPlusElement = numElement.getMethod('+');
+
+ var indexExpression = findNode.index('a?.[0]');
+ assertElement(indexExpression, indexEqElement);
+ assertAuxElement(indexExpression, indexElement);
+ assertParameterElement(
+ indexExpression.index,
+ indexEqElement.parameters[0],
+ );
+ assertType(indexExpression, 'num');
+
+ var assignment = indexExpression.parent as AssignmentExpression;
+ assertElement(assignment, numPlusElement);
+ assertType(assignment, 'num?');
+ assertParameterElement(
+ assignment.rightHandSide,
+ numPlusElement.parameters[0],
+ );
+ }
+
+ test_write_nullable() async {
+ await assertNoErrorsInCode(r'''
+class A {
+ void operator[]=(int index, num value) {}
+}
+
+main(A? a) {
+ a?.[0] = 1.2;
+}
+''');
+
+ var indexEqElement = findElement.method('[]=');
+
+ var indexExpression = findNode.index('a?.[0]');
+ assertElement(indexExpression, indexEqElement);
+ assertAuxElement(indexExpression, null);
+ assertParameterElement(
+ indexExpression.index,
+ indexEqElement.parameters[0],
+ );
+ assertType(indexExpression, 'num');
+
+ var assignment = indexExpression.parent as AssignmentExpression;
+ assertElement(assignment, null);
+ assertType(assignment, 'double?');
+ assertParameterElement(assignment.rightHandSide, null);
+ }
+}
diff --git a/pkg/analyzer/test/src/dart/resolution/mixin_test.dart b/pkg/analyzer/test/src/dart/resolution/mixin_test.dart
index 827c61b..68895de 100644
--- a/pkg/analyzer/test/src/dart/resolution/mixin_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/mixin_test.dart
@@ -317,7 +317,7 @@
M();
}
''', [
- error(CompileTimeErrorCode.MIXIN_DECLARES_CONSTRUCTOR, 27, 1),
+ error(ParserErrorCode.MIXIN_DECLARES_CONSTRUCTOR, 27, 1),
error(StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_1, 27, 1),
]);
}
@@ -329,7 +329,7 @@
M(this.f);
}
''', [
- error(CompileTimeErrorCode.MIXIN_DECLARES_CONSTRUCTOR, 27, 1),
+ error(ParserErrorCode.MIXIN_DECLARES_CONSTRUCTOR, 27, 1),
]);
var element = findElement.mixin('M');
@@ -830,7 +830,7 @@
}
}
''', [
- error(CompileTimeErrorCode.MIXIN_DECLARES_CONSTRUCTOR, 12, 1),
+ error(ParserErrorCode.MIXIN_DECLARES_CONSTRUCTOR, 12, 1),
]);
// Even though it is an error for a mixin to declare a constructor,
@@ -879,7 +879,7 @@
new M.named();
}
''', [
- error(CompileTimeErrorCode.MIXIN_DECLARES_CONSTRUCTOR, 12, 1),
+ error(ParserErrorCode.MIXIN_DECLARES_CONSTRUCTOR, 12, 1),
error(CompileTimeErrorCode.MIXIN_INSTANTIATE, 43, 1),
]);
@@ -1240,10 +1240,10 @@
abstract class X extends A with U1, U2, M {}
''', [
- error(StaticWarningCode.UNDEFINED_CLASS, 121, 2),
+ error(CompileTimeErrorCode.UNDEFINED_CLASS, 121, 2),
error(CompileTimeErrorCode.MIXIN_OF_NON_CLASS, 121, 2),
error(CompileTimeErrorCode.MIXIN_OF_NON_CLASS, 125, 2),
- error(StaticWarningCode.UNDEFINED_CLASS, 125, 2),
+ error(CompileTimeErrorCode.UNDEFINED_CLASS, 125, 2),
error(
CompileTimeErrorCode
.MIXIN_APPLICATION_NO_CONCRETE_SUPER_INVOKED_MEMBER,
diff --git a/pkg/analyzer/test/src/dart/resolution/resolution.dart b/pkg/analyzer/test/src/dart/resolution/resolution.dart
index 3fd1ab2..bae934f 100644
--- a/pkg/analyzer/test/src/dart/resolution/resolution.dart
+++ b/pkg/analyzer/test/src/dart/resolution/resolution.dart
@@ -10,6 +10,7 @@
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/src/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/handle.dart';
import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/dart/element/type.dart';
@@ -70,6 +71,26 @@
newFile('/test/lib/test.dart', content: content);
}
+ void assertAuxElement(AstNode node, Element expected) {
+ var auxElements = getNodeAuxElements(node);
+ expect(auxElements?.staticElement, same(expected));
+ }
+
+ void assertAuxMember(
+ Expression node,
+ Element expectedBase,
+ Map<String, String> expectedSubstitution,
+ ) {
+ var actual = getNodeAuxElements(node)?.staticElement as ExecutableMember;
+
+ expect(actual.baseElement, same(expectedBase));
+
+ var actualMapString = actual.substitution.map.map(
+ (k, v) => MapEntry(k.name, '$v'),
+ );
+ expect(actualMapString, expectedSubstitution);
+ }
+
/// Assert that the given [identifier] is a reference to a class, in the
/// form that is not a separate expression, e.g. in a static method
/// invocation like `C.staticMethod()`, or a type annotation `C c = null`.
@@ -352,6 +373,13 @@
assertTestErrorsWithCodes(const <ErrorCode>[]);
}
+ void assertParameterElement(
+ Expression expression,
+ ParameterElement expected,
+ ) {
+ expect(expression.staticParameterElement, expected);
+ }
+
void assertPropertyAccess(
PropertyAccess access,
Element expectedElement,
@@ -436,6 +464,14 @@
const <ExpectedMessage>[]}) =>
ExpectedError(code, offset, length, expectedMessages: expectedMessages);
+ AuxiliaryElements getNodeAuxElements(AstNode node) {
+ if (node is IndexExpression) {
+ return node.auxiliaryElements;
+ } else {
+ fail('Unsupported node: (${node.runtimeType}) $node');
+ }
+ }
+
Element getNodeElement(AstNode node) {
if (node is Annotation) {
return node.element;
diff --git a/pkg/analyzer/test/src/dart/resolution/test_all.dart b/pkg/analyzer/test/src/dart/resolution/test_all.dart
index 8261f8b..80bb8fb 100644
--- a/pkg/analyzer/test/src/dart/resolution/test_all.dart
+++ b/pkg/analyzer/test/src/dart/resolution/test_all.dart
@@ -23,6 +23,7 @@
import 'generic_function_type_test.dart' as generic_function_type;
import 'generic_type_alias_test.dart' as generic_type_alias;
import 'import_prefix_test.dart' as import_prefix;
+import 'index_expression_test.dart' as index_expression;
import 'instance_creation_test.dart' as instance_creation;
import 'instance_member_inference_class_test.dart'
as instance_member_inference_class;
@@ -59,6 +60,7 @@
generic_function_type.main();
generic_type_alias.main();
import_prefix.main();
+ index_expression.main();
instance_creation.main();
instance_member_inference_class.main();
instance_member_inference_mixin.main();
diff --git a/pkg/analyzer/test/src/diagnostics/ambiguous_extension_member_access_test.dart b/pkg/analyzer/test/src/diagnostics/ambiguous_extension_member_access_test.dart
index 6a46b65..a6894c5 100644
--- a/pkg/analyzer/test/src/diagnostics/ambiguous_extension_member_access_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/ambiguous_extension_member_access_test.dart
@@ -40,43 +40,112 @@
]);
}
- test_getter() async {
+ test_getter_getter() async {
await assertErrorsInCode('''
-class A {}
-
-extension E1 on A {
+extension E1 on int {
void get a => 1;
}
-extension E2 on A {
+extension E2 on int {
void get a => 2;
}
-f(A a) {
- a.a;
+f() {
+ 0.a;
}
''', [
- error(CompileTimeErrorCode.AMBIGUOUS_EXTENSION_MEMBER_ACCESS, 109, 1),
+ error(CompileTimeErrorCode.AMBIGUOUS_EXTENSION_MEMBER_ACCESS, 98, 1),
]);
+ var access = findNode.propertyAccess('0.a');
+ assertElementNull(access);
+ assertTypeDynamic(access);
}
- test_method() async {
+ test_getter_method() async {
await assertErrorsInCode('''
-class A {}
+extension E on int {
+ int get a => 1;
+}
-extension E1 on A {
+extension E2 on int {
void a() {}
}
-extension E2 on A {
- void a() {}
-}
-
-f(A a) {
- a.a();
+f() {
+ 0.a;
}
''', [
- error(CompileTimeErrorCode.AMBIGUOUS_EXTENSION_MEMBER_ACCESS, 99, 1),
+ error(CompileTimeErrorCode.AMBIGUOUS_EXTENSION_MEMBER_ACCESS, 91, 1),
+ ]);
+ var access = findNode.propertyAccess('0.a');
+ assertElementNull(access);
+ assertTypeDynamic(access);
+ }
+
+ test_getter_setter() async {
+ await assertErrorsInCode('''
+extension E on int {
+ int get a => 1;
+}
+
+extension E2 on int {
+ set a(int v) { }
+}
+
+f() {
+ 0.a;
+}
+''', [
+ error(CompileTimeErrorCode.AMBIGUOUS_EXTENSION_MEMBER_ACCESS, 96, 1),
+ ]);
+ var access = findNode.propertyAccess('0.a');
+ assertElementNull(access);
+ assertTypeDynamic(access);
+ }
+
+ test_method_method() async {
+ await assertErrorsInCode('''
+extension E1 on int {
+ void a() {}
+}
+
+extension E2 on int {
+ void a() {}
+}
+
+f() {
+ 0.a();
+}
+''', [
+ error(CompileTimeErrorCode.AMBIGUOUS_EXTENSION_MEMBER_ACCESS, 88, 1),
+ ]);
+ var invocation = findNode.methodInvocation('0.a()');
+ assertElementNull(invocation);
+ assertTypeDynamic(invocation);
+ }
+
+ test_noMoreSpecificExtension() async {
+ await assertErrorsInCode(r'''
+class Target<T> {}
+
+class SubTarget<T> extends Target<T> {}
+
+extension E1 on SubTarget<Object> {
+ int get foo => 0;
+}
+
+extension E2<T> on Target<T> {
+ int get foo => 0;
+}
+
+f(SubTarget<num> t) {
+ // The instantiated on type of `E1(t)` is `SubTarget<Object>`.
+ // The instantiated on type of `E2(t)` is `Target<num>`.
+ // Neither is a subtype of the other, so the resolution is ambiguous.
+ t.foo;
+}
+''', [
+ error(CompileTimeErrorCode.AMBIGUOUS_EXTENSION_MEMBER_ACCESS, 396, 3),
]);
}
@@ -135,23 +204,24 @@
]);
}
- test_setter() async {
+ test_setter_setter() async {
await assertErrorsInCode('''
-class A {}
-
-extension E1 on A {
+extension E1 on int {
set a(x) {}
}
-extension E2 on A {
+extension E2 on int {
set a(x) {}
}
-f(A a) {
- a.a = 3;
+f() {
+ 0.a = 3;
}
''', [
- error(CompileTimeErrorCode.AMBIGUOUS_EXTENSION_MEMBER_ACCESS, 99, 1),
+ error(CompileTimeErrorCode.AMBIGUOUS_EXTENSION_MEMBER_ACCESS, 88, 1),
]);
+ var access = findNode.propertyAccess('0.a');
+ assertElementNull(access);
+ assertTypeDynamic(access);
}
}
diff --git a/pkg/analyzer/test/src/diagnostics/assignment_to_final_local_test.dart b/pkg/analyzer/test/src/diagnostics/assignment_to_final_local_test.dart
index cef7998..9b25380 100644
--- a/pkg/analyzer/test/src/diagnostics/assignment_to_final_local_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/assignment_to_final_local_test.dart
@@ -2,8 +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:analyzer/dart/analysis/features.dart';
import 'package:analyzer/src/dart/error/hint_codes.dart';
import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/engine.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/driver_resolution.dart';
@@ -11,6 +13,7 @@
main() {
defineReflectiveSuite(() {
defineReflectiveTests(AssignmentToFinalLocalTest);
+ defineReflectiveTests(AssignmentToFinalLocalWithNnbdTest);
});
}
@@ -27,6 +30,18 @@
]);
}
+ test_localVariable_inForEach() async {
+ await assertErrorsInCode('''
+f() {
+ final x = 0;
+ for (x in <int>[1, 2]) {
+ print(x);
+ }
+}''', [
+ error(StaticWarningCode.ASSIGNMENT_TO_FINAL_LOCAL, 28, 1),
+ ]);
+ }
+
test_localVariable_plusEq() async {
await assertErrorsInCode('''
f() {
@@ -113,18 +128,6 @@
]);
}
- test_localVariable_inForEach() async {
- await assertErrorsInCode('''
-f() {
- final x = 0;
- for (x in <int>[1, 2]) {
- print(x);
- }
-}''', [
- error(StaticWarningCode.ASSIGNMENT_TO_FINAL_LOCAL, 28, 1),
- ]);
- }
-
test_topLevelVariable() async {
await assertErrorsInCode('''
final x = 0;
@@ -133,3 +136,33 @@
]);
}
}
+
+@reflectiveTest
+class AssignmentToFinalLocalWithNnbdTest extends DriverResolutionTest {
+ @override
+ AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+ ..contextFeatures = new FeatureSet.forTesting(
+ sdkVersion: '2.3.0', additionalFeatures: [Feature.non_nullable]);
+
+ test_localVariable_late() async {
+ await assertNoErrorsInCode('''
+void f() {
+ late final int a;
+ late final int b = 0;
+ a = 1;
+ b = 1;
+}
+''');
+ }
+
+ test_topLevelVariable_late() async {
+ await assertNoErrorsInCode('''
+late final int a;
+late final int b = 0;
+void f() {
+ a = 1;
+ b = 1;
+}
+''');
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/assignment_to_final_test.dart b/pkg/analyzer/test/src/diagnostics/assignment_to_final_test.dart
index b2a4a05..cbe2f70 100644
--- a/pkg/analyzer/test/src/diagnostics/assignment_to_final_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/assignment_to_final_test.dart
@@ -3,11 +3,11 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/analysis/features.dart';
+import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/driver_resolution.dart';
-import 'package:analyzer/src/error/codes.dart';
main() {
defineReflectiveSuite(() {
@@ -52,24 +52,28 @@
..contextFeatures = new FeatureSet.forTesting(
sdkVersion: '2.3.0', additionalFeatures: [Feature.non_nullable]);
- @failingTest
test_field_late() async {
await assertNoErrorsInCode('''
class A {
- final a;
+ late final int a;
+ late final int b = 0;
void m() {
a = 1;
+ b = 1;
}
}
''');
}
- @failingTest
- test_localVariable_late() async {
+ test_field_static_late() async {
await assertNoErrorsInCode('''
-void f() {
- final a;
- a = 1;
+class A {
+ static late final int a;
+ static late final int b = 0;
+ void m() {
+ a = 1;
+ b = 1;
+ }
}
''');
}
diff --git a/pkg/analyzer/test/src/diagnostics/builtin_identifier_as_extension_name_test.dart b/pkg/analyzer/test/src/diagnostics/builtin_identifier_as_extension_name_test.dart
new file mode 100644
index 0000000..774ccd0
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/builtin_identifier_as_extension_name_test.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/src/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/extension_method_test.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(BuiltinIdentifierAsExtensionNameTest);
+ });
+}
+
+@reflectiveTest
+class BuiltinIdentifierAsExtensionNameTest extends BaseExtensionMethodsTest {
+ test_error_builtInIdentifierAsExtensionName() async {
+ await assertErrorsInCode(
+ r'''
+extension as on Object {}
+''',
+ [
+ error(
+ CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_EXTENSION_NAME, 10, 2),
+ ],
+ );
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/const_not_initialized_test.dart b/pkg/analyzer/test/src/diagnostics/const_not_initialized_test.dart
new file mode 100644
index 0000000..eca8efc
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/const_not_initialized_test.dart
@@ -0,0 +1,46 @@
+// Copyright (c) 2019, 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/features.dart';
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+// defineReflectiveTests(ConstNotInitializedTest);
+ defineReflectiveTests(ConstNotInitializedWithExtensionMethodsTest);
+// defineReflectiveTests(ConstNotInitializedWithNnbdTest);
+ });
+}
+
+@reflectiveTest
+class ConstNotInitializedTest extends DriverResolutionTest {}
+
+@reflectiveTest
+class ConstNotInitializedWithExtensionMethodsTest extends DriverResolutionTest {
+ @override
+ AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+ ..contextFeatures = new FeatureSet.forTesting(
+ sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
+
+ test_instance() async {
+ await assertErrorsInCode('''
+extension E on String {
+ static const F;
+}''', [
+ error(CompileTimeErrorCode.CONST_NOT_INITIALIZED, 39, 1),
+ ]);
+ }
+}
+
+@reflectiveTest
+class ConstNotInitializedWithNnbdTest extends DriverResolutionTest {
+ @override
+ AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+ ..contextFeatures = new FeatureSet.forTesting(
+ sdkVersion: '2.3.0', additionalFeatures: [Feature.non_nullable]);
+}
diff --git a/pkg/analyzer/test/src/diagnostics/extension_as_expression_test.dart b/pkg/analyzer/test/src/diagnostics/extension_as_expression_test.dart
new file mode 100644
index 0000000..cd9731d
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/extension_as_expression_test.dart
@@ -0,0 +1,48 @@
+// Copyright (c) 2019, 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/features.dart';
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(ExtensionAsExpressionTest);
+ });
+}
+
+@reflectiveTest
+class ExtensionAsExpressionTest extends DriverResolutionTest {
+ @override
+ AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+ ..contextFeatures = new FeatureSet.forTesting(
+ sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
+
+ test_prefixedIdentifier() async {
+ newFile('/test/lib/a.dart', content: r'''
+extension E on int {}
+''');
+ await assertErrorsInCode('''
+import 'a.dart' as p;
+var v = p.E;
+''', [
+ error(CompileTimeErrorCode.EXTENSION_AS_EXPRESSION, 30, 3),
+ ]);
+ assertTypeDynamic(findNode.simple('E;'));
+ assertTypeDynamic(findNode.prefixed('p.E;'));
+ }
+
+ test_simpleIdentifier() async {
+ await assertErrorsInCode('''
+extension E on int {}
+var v = E;
+''', [
+ error(CompileTimeErrorCode.EXTENSION_AS_EXPRESSION, 30, 1),
+ ]);
+ assertTypeDynamic(findNode.simple('E;'));
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/extension_declares_abstract_method_test.dart b/pkg/analyzer/test/src/diagnostics/extension_declares_abstract_method_test.dart
index 3426dd9..55c639f 100644
--- a/pkg/analyzer/test/src/diagnostics/extension_declares_abstract_method_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/extension_declares_abstract_method_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/analysis/features.dart';
-import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/dart/error/syntactic_errors.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -28,7 +28,7 @@
bool get isPalindrome;
}
''', [
- error(CompileTimeErrorCode.EXTENSION_DECLARES_ABSTRACT_MEMBER, 35, 12),
+ error(ParserErrorCode.EXTENSION_DECLARES_ABSTRACT_MEMBER, 35, 12),
]);
}
@@ -38,7 +38,7 @@
String reversed();
}
''', [
- error(CompileTimeErrorCode.EXTENSION_DECLARES_ABSTRACT_MEMBER, 33, 8),
+ error(ParserErrorCode.EXTENSION_DECLARES_ABSTRACT_MEMBER, 33, 8),
]);
}
@@ -54,7 +54,7 @@
String operator -(String otherString);
}
''', [
- error(CompileTimeErrorCode.EXTENSION_DECLARES_ABSTRACT_MEMBER, 42, 1),
+ error(ParserErrorCode.EXTENSION_DECLARES_ABSTRACT_MEMBER, 42, 1),
]);
}
@@ -64,7 +64,7 @@
set length(int newLength);
}
''', [
- error(CompileTimeErrorCode.EXTENSION_DECLARES_ABSTRACT_MEMBER, 30, 6),
+ error(ParserErrorCode.EXTENSION_DECLARES_ABSTRACT_MEMBER, 30, 6),
]);
}
}
diff --git a/pkg/analyzer/test/src/diagnostics/extension_declares_constructor_test.dart b/pkg/analyzer/test/src/diagnostics/extension_declares_constructor_test.dart
index b7d66b5..6334a96 100644
--- a/pkg/analyzer/test/src/diagnostics/extension_declares_constructor_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/extension_declares_constructor_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/analysis/features.dart';
-import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/dart/error/syntactic_errors.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -27,7 +27,7 @@
extension E on String {
E.named() : super();
}
-''', [error(CompileTimeErrorCode.EXTENSION_DECLARES_CONSTRUCTOR, 28, 5)]);
+''', [error(ParserErrorCode.EXTENSION_DECLARES_CONSTRUCTOR, 26, 1)]);
}
test_none() async {
@@ -41,6 +41,6 @@
extension E on String {
E() : super();
}
-''', [error(CompileTimeErrorCode.EXTENSION_DECLARES_CONSTRUCTOR, 26, 1)]);
+''', [error(ParserErrorCode.EXTENSION_DECLARES_CONSTRUCTOR, 26, 1)]);
}
}
diff --git a/pkg/analyzer/test/src/diagnostics/extension_declares_field_test.dart b/pkg/analyzer/test/src/diagnostics/extension_declares_field_test.dart
index f7916c2..416293a 100644
--- a/pkg/analyzer/test/src/diagnostics/extension_declares_field_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/extension_declares_field_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/analysis/features.dart';
-import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/dart/error/syntactic_errors.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -27,11 +27,7 @@
extension E on String {
String one, two, three;
}
-''', [
- error(CompileTimeErrorCode.EXTENSION_DECLARES_INSTANCE_FIELD, 33, 3),
- error(CompileTimeErrorCode.EXTENSION_DECLARES_INSTANCE_FIELD, 38, 3),
- error(CompileTimeErrorCode.EXTENSION_DECLARES_INSTANCE_FIELD, 43, 5)
- ]);
+''', [error(ParserErrorCode.EXTENSION_DECLARES_INSTANCE_FIELD, 33, 3)]);
}
test_none() async {
@@ -45,7 +41,7 @@
extension E on String {
String s;
}
-''', [error(CompileTimeErrorCode.EXTENSION_DECLARES_INSTANCE_FIELD, 33, 1)]);
+''', [error(ParserErrorCode.EXTENSION_DECLARES_INSTANCE_FIELD, 33, 1)]);
}
test_static() async {
diff --git a/pkg/analyzer/test/src/diagnostics/extra_positional_arguments_test.dart b/pkg/analyzer/test/src/diagnostics/extra_positional_arguments_test.dart
index 76dbce0..a16250c 100644
--- a/pkg/analyzer/test/src/diagnostics/extra_positional_arguments_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/extra_positional_arguments_test.dart
@@ -22,7 +22,8 @@
(int x, {int y}) {} (0, 1);
}
''', [
- error(StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED, 31, 6),
+ error(CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED, 31,
+ 6),
]);
}
@@ -33,8 +34,8 @@
f(0, 1, '2');
}
''', [
- error(
- StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED, 25, 11),
+ error(CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED, 25,
+ 11),
]);
}
}
@@ -48,7 +49,7 @@
f(0, 1, '2');
}
''', [
- error(StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS, 19, 11),
+ error(CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS, 19, 11),
]);
}
@@ -58,7 +59,7 @@
(int x) {} (0, 1);
}
''', [
- error(StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS, 22, 6),
+ error(CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS, 22, 6),
]);
}
}
diff --git a/pkg/analyzer/test/src/diagnostics/final_not_initialized_test.dart b/pkg/analyzer/test/src/diagnostics/final_not_initialized_test.dart
index 5be052f..3c0937a 100644
--- a/pkg/analyzer/test/src/diagnostics/final_not_initialized_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/final_not_initialized_test.dart
@@ -13,6 +13,7 @@
main() {
defineReflectiveSuite(() {
defineReflectiveTests(FinalNotInitializedTest);
+ defineReflectiveTests(FinalNotInitializedWithExtensionMethodsTest);
defineReflectiveTests(FinalNotInitializedWithNnbdTest);
});
}
@@ -57,6 +58,23 @@
}
@reflectiveTest
+class FinalNotInitializedWithExtensionMethodsTest extends DriverResolutionTest {
+ @override
+ AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+ ..contextFeatures = new FeatureSet.forTesting(
+ sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
+
+ test_static() async {
+ await assertErrorsInCode('''
+extension E on String {
+ static final F;
+}''', [
+ error(StaticWarningCode.FINAL_NOT_INITIALIZED, 39, 1),
+ ]);
+ }
+}
+
+@reflectiveTest
class FinalNotInitializedWithNnbdTest extends DriverResolutionTest {
@override
AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
diff --git a/pkg/analyzer/test/src/diagnostics/import_of_non_library_test.dart b/pkg/analyzer/test/src/diagnostics/import_of_non_library_test.dart
index d32baeb..c5d1d06 100644
--- a/pkg/analyzer/test/src/diagnostics/import_of_non_library_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/import_of_non_library_test.dart
@@ -25,7 +25,7 @@
import 'lib1.dart' deferred as p;
var a = new p.A();
''', [
- error(StaticWarningCode.IMPORT_OF_NON_LIBRARY, 20, 11),
+ error(CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY, 20, 11),
]);
}
}
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_required_named_param_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_required_named_param_test.dart
new file mode 100644
index 0000000..baca673
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/invalid_required_named_param_test.dart
@@ -0,0 +1,56 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/test_utilities/package_mixin.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(InvalidRequiredNamedParamTest);
+ });
+}
+
+@reflectiveTest
+class InvalidRequiredNamedParamTest extends DriverResolutionTest
+ with PackageMixin {
+ @override
+ void setUp() {
+ super.setUp();
+ addMetaPackage();
+ }
+
+ test_namedParameter_withDefault() async {
+ await assertErrorsInCode(r'''
+import 'package:meta/meta.dart';
+
+m({@required a = 1}) => null;
+''', [
+ error(HintCode.INVALID_REQUIRED_NAMED_PARAM, 37, 15),
+ ]);
+ }
+
+ test_namedParameter_withDefault_asSecond() async {
+ await assertErrorsInCode(r'''
+import 'package:meta/meta.dart';
+
+m(a, {@required b = 1}) => null;
+''', [
+ error(HintCode.INVALID_REQUIRED_NAMED_PARAM, 40, 15),
+ ]);
+ }
+
+ test_valid() async {
+ await assertNoErrorsInCode(r'''
+import 'package:meta/meta.dart';
+
+m1({a}) => null;
+m2({a = 5}) => null;
+m3({@required a}) => null;
+m4({a, @required b}) => null;
+''');
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_required_param_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_required_optional_positional_param_test.dart
similarity index 62%
rename from pkg/analyzer/test/src/diagnostics/invalid_required_param_test.dart
rename to pkg/analyzer/test/src/diagnostics/invalid_required_optional_positional_param_test.dart
index 739f3e5..5782b42 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_required_param_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_required_optional_positional_param_test.dart
@@ -10,35 +10,26 @@
main() {
defineReflectiveSuite(() {
- defineReflectiveTests(InvalidRequiredParamTest);
+ defineReflectiveTests(InvalidRequiredOptionalPositionalParamTest);
});
}
@reflectiveTest
-class InvalidRequiredParamTest extends DriverResolutionTest with PackageMixin {
+class InvalidRequiredOptionalPositionalParamTest extends DriverResolutionTest
+ with PackageMixin {
@override
void setUp() {
super.setUp();
addMetaPackage();
}
- test_namedParameter_withDefault() async {
- await assertErrorsInCode(r'''
-import 'package:meta/meta.dart';
-
-m({@required a = 1}) => null;
-''', [
- error(HintCode.INVALID_REQUIRED_PARAM, 37, 15),
- ]);
- }
-
test_positionalParameter_noDefault() async {
await assertErrorsInCode(r'''
import 'package:meta/meta.dart';
m([@required a]) => null;
''', [
- error(HintCode.INVALID_REQUIRED_PARAM, 37, 11),
+ error(HintCode.INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM, 37, 11),
]);
}
@@ -48,30 +39,35 @@
m([@required a = 1]) => null;
''', [
- error(HintCode.INVALID_REQUIRED_PARAM, 37, 15),
+ error(HintCode.INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM, 37, 15),
]);
}
- test_requiredParameter() async {
+ test_positionalParameter_noDefault_asSecond() async {
await assertErrorsInCode(r'''
import 'package:meta/meta.dart';
-m(@required a) => null;
+m(a, [@required b]) => null;
''', [
- error(HintCode.INVALID_REQUIRED_PARAM, 36, 11),
+ error(HintCode.INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM, 40, 11),
+ ]);
+ }
+
+ test_positionalParameter_withDefault_withTwo() async {
+ await assertErrorsInCode(r'''
+import 'package:meta/meta.dart';
+
+m([a, @required b = 1]) => null;
+''', [
+ error(HintCode.INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM, 40, 15),
]);
}
test_valid() async {
await assertNoErrorsInCode(r'''
-import 'package:meta/meta.dart';
-
-m1() => null;
-m2(a) => null;
-m3([a]) => null;
-m4({a}) => null;
-m5({@required a}) => null;
-m6({a, @required b}) => null;
+m1([a]) => null;
+m2([a = 1]) => null;
+m3([a, b]) => null;
''');
}
}
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_required_positional_param_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_required_positional_param_test.dart
new file mode 100644
index 0000000..5717328
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/invalid_required_positional_param_test.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/test_utilities/package_mixin.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(InvalidRequiredPositionalParamTest);
+ });
+}
+
+@reflectiveTest
+class InvalidRequiredPositionalParamTest extends DriverResolutionTest
+ with PackageMixin {
+ @override
+ void setUp() {
+ super.setUp();
+ addMetaPackage();
+ }
+
+ test_requiredPositionalParameter() async {
+ await assertErrorsInCode(r'''
+import 'package:meta/meta.dart';
+
+m(@required a) => null;
+''', [
+ error(HintCode.INVALID_REQUIRED_POSITIONAL_PARAM, 36, 11),
+ ]);
+ }
+
+ test_requiredPositionalParameter_asSecond() async {
+ await assertErrorsInCode(r'''
+import 'package:meta/meta.dart';
+
+m(a, @required b) => null;
+''', [
+ error(HintCode.INVALID_REQUIRED_POSITIONAL_PARAM, 39, 11),
+ ]);
+ }
+
+ test_valid() async {
+ await assertNoErrorsInCode(r'''
+m1() => null;
+m2(a) => null;
+m3(a, b) => null;
+''');
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_use_of_protected_member_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_use_of_protected_member_test.dart
index 0458e81..bd33642 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_use_of_protected_member_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_use_of_protected_member_test.dart
@@ -2,7 +2,9 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/test_utilities/package_mixin.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -11,6 +13,7 @@
main() {
defineReflectiveSuite(() {
defineReflectiveTests(InvalidUseOfProtectedMemberTest);
+ defineReflectiveTests(InvalidUseOfProtectedMember_InExtensionTest);
});
}
@@ -308,6 +311,9 @@
}
test_mixingIn_asParameter() async {
+ // TODO(srawlins): This test verifies that the analyzer **allows**
+ // protected members to be called from static members, which violates the
+ // protected spec.
addMetaPackage();
await assertNoErrorsInCode(r'''
import 'package:meta/meta.dart';
@@ -336,6 +342,9 @@
}
test_setter_outsideClassAndFile() async {
+ // TODO(srawlins): This test verifies that the analyzer **allows**
+ // protected members to be called on objects other than `this`, which
+ // violates the protected spec.
addMetaPackage();
newFile('/lib1.dart', content: r'''
import 'package:meta/meta.dart';
@@ -425,3 +434,35 @@
result = await resolveFile(convertPath(path));
}
}
+
+@reflectiveTest
+class InvalidUseOfProtectedMember_InExtensionTest
+ extends InvalidUseOfProtectedMemberTest {
+ @override
+ AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+ ..contextFeatures = new FeatureSet.forTesting(
+ sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
+
+ test_extension_outsideClassAndFile() async {
+ addMetaPackage();
+ newFile('/lib1.dart', content: r'''
+import 'package:meta/meta.dart';
+class A {
+ @protected
+ void a(int i) {}
+}
+''');
+ newFile('/lib2.dart', content: r'''
+import 'lib1.dart';
+extension E on A {
+ e() {
+ a(7);
+ }
+}
+''');
+
+ await _resolveTestFile('/lib1.dart');
+ await _resolveTestFile('/lib2.dart');
+ assertTestErrorsWithCodes([HintCode.INVALID_USE_OF_PROTECTED_MEMBER]);
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_use_of_visible_for_template_member_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_use_of_visible_for_template_member_test.dart
index f14c277..397fc3f 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_use_of_visible_for_template_member_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_use_of_visible_for_template_member_test.dart
@@ -2,8 +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:analyzer/dart/analysis/features.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/test_utilities/package_mixin.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -12,6 +14,7 @@
main() {
defineReflectiveSuite(() {
defineReflectiveTests(InvalidUseOfVisibleForTemplateMemberTest);
+ defineReflectiveTests(InvalidUseOfVisibleForTemplateMember_InExtensionTest);
});
}
@@ -227,3 +230,55 @@
result = await resolveFile(convertPath(path));
}
}
+
+@reflectiveTest
+class InvalidUseOfVisibleForTemplateMember_InExtensionTest
+ extends InvalidUseOfVisibleForTemplateMemberTest {
+ @override
+ AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+ ..contextFeatures = new FeatureSet.forTesting(
+ sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
+
+ test_functionInExtension() async {
+ addAngularMetaPackage();
+ newFile('/lib1.dart', content: r'''
+import 'package:angular_meta/angular_meta.dart';
+extension E on List {
+ @visibleForTemplate
+ int m() => 1;
+}
+''');
+ newFile('/lib2.dart', content: r'''
+import 'lib1.dart';
+void main() {
+ E([]).m();
+}
+''');
+
+ await _resolveTestFile('/lib1.dart');
+ await _resolveTestFile('/lib2.dart');
+ assertTestErrorsWithCodes(
+ [HintCode.INVALID_USE_OF_VISIBLE_FOR_TEMPLATE_MEMBER]);
+ }
+
+ test_functionInExtension_fromTemplate() async {
+ addAngularMetaPackage();
+ newFile('/lib1.dart', content: r'''
+import 'package:angular_meta/angular_meta.dart';
+extension E on List {
+ @visibleForTemplate
+ int m() => 1;
+}
+''');
+ newFile('/lib1.template.dart', content: r'''
+import 'lib1.dart';
+void main() {
+ E([]).m();
+}
+''');
+
+ await _resolveTestFile('/lib1.dart');
+ await _resolveTestFile('/lib1.template.dart');
+ assertNoTestErrors();
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_use_of_visible_for_testing_member_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_use_of_visible_for_testing_member_test.dart
index 984fbcf..d61d928 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_use_of_visible_for_testing_member_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_use_of_visible_for_testing_member_test.dart
@@ -2,7 +2,9 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/test_utilities/package_mixin.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -11,12 +13,18 @@
main() {
defineReflectiveSuite(() {
defineReflectiveTests(InvalidUseOfVisibleForTestingMemberTest);
+ defineReflectiveTests(InvalidUseOfVisibleForTestingMember_InExtensionTest);
});
}
@reflectiveTest
class InvalidUseOfVisibleForTestingMemberTest extends DriverResolutionTest
with PackageMixin {
+ @override
+ AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+ ..contextFeatures = new FeatureSet.forTesting(
+ sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
+
test_constructor() async {
addMetaPackage();
newFile('/lib1.dart', content: r'''
@@ -210,6 +218,29 @@
[HintCode.INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER]);
}
+ test_mixin() async {
+ addMetaPackage();
+ newFile('/lib1.dart', content: r'''
+import 'package:meta/meta.dart';
+mixin M {
+ @visibleForTesting
+ int m() => 1;
+}
+class C with M {}
+''');
+ newFile('/lib2.dart', content: r'''
+import 'lib1.dart';
+void main() {
+ C().m();
+}
+''');
+
+ await _resolveTestFile('/lib1.dart');
+ await _resolveTestFile('/lib2.dart');
+ assertTestErrorsWithCodes(
+ [HintCode.INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER]);
+ }
+
test_topLevelFunction() async {
addMetaPackage();
newFile('/lib1.dart', content: r'''
@@ -237,3 +268,55 @@
result = await resolveFile(convertPath(path));
}
}
+
+@reflectiveTest
+class InvalidUseOfVisibleForTestingMember_InExtensionTest
+ extends InvalidUseOfVisibleForTestingMemberTest {
+ @override
+ AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+ ..contextFeatures = new FeatureSet.forTesting(
+ sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
+
+ test_functionInExtension() async {
+ addMetaPackage();
+ newFile('/lib1.dart', content: r'''
+import 'package:meta/meta.dart';
+extension E on List {
+ @visibleForTesting
+ int m() => 1;
+}
+''');
+ newFile('/lib2.dart', content: r'''
+import 'lib1.dart';
+void main() {
+ E([]).m();
+}
+''');
+
+ await _resolveTestFile('/lib1.dart');
+ await _resolveTestFile('/lib2.dart');
+ assertTestErrorsWithCodes(
+ [HintCode.INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER]);
+ }
+
+ test_functionInExtension_fromTestDirectory() async {
+ addMetaPackage();
+ newFile('/lib1.dart', content: r'''
+import 'package:meta/meta.dart';
+extension E on List {
+ @visibleForTesting
+ int m() => 1;
+}
+''');
+ newFile('/test/test.dart', content: r'''
+import '../lib1.dart';
+void main() {
+ E([]).m();
+}
+''');
+
+ await _resolveTestFile('/lib1.dart');
+ await _resolveTestFile('/test/test.dart');
+ assertNoTestErrors();
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/not_a_type_test.dart b/pkg/analyzer/test/src/diagnostics/not_a_type_test.dart
index 9ff91b1..7eb1b7d 100644
--- a/pkg/analyzer/test/src/diagnostics/not_a_type_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/not_a_type_test.dart
@@ -2,7 +2,9 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/engine.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/driver_resolution.dart';
@@ -10,6 +12,7 @@
main() {
defineReflectiveSuite(() {
defineReflectiveTests(NotATypeTest);
+ defineReflectiveTests(NotATypeWithExtensionMethodsTest);
});
}
@@ -26,3 +29,19 @@
]);
}
}
+
+@reflectiveTest
+class NotATypeWithExtensionMethodsTest extends NotATypeTest {
+ @override
+ AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+ ..contextFeatures = new FeatureSet.forTesting(
+ sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
+
+ test_extension() async {
+ await assertErrorsInCode('''
+extension E on int {}
+E a;
+''', [error(StaticWarningCode.NOT_A_TYPE, 22, 1)]);
+ assertTypeDynamic(findNode.simple('E a;'));
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/not_enough_required_arguments_test.dart b/pkg/analyzer/test/src/diagnostics/not_enough_positional_arguments_test.dart
similarity index 70%
rename from pkg/analyzer/test/src/diagnostics/not_enough_required_arguments_test.dart
rename to pkg/analyzer/test/src/diagnostics/not_enough_positional_arguments_test.dart
index bea8216..8f04ad1 100644
--- a/pkg/analyzer/test/src/diagnostics/not_enough_required_arguments_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/not_enough_positional_arguments_test.dart
@@ -9,18 +9,18 @@
main() {
defineReflectiveSuite(() {
- defineReflectiveTests(NotEnoughRequiredArgumentsTest);
+ defineReflectiveTests(NotEnoughPositionalArgumentsTest);
});
}
@reflectiveTest
-class NotEnoughRequiredArgumentsTest extends DriverResolutionTest {
+class NotEnoughPositionalArgumentsTest extends DriverResolutionTest {
test_functionExpression() async {
await assertErrorsInCode('''
main() {
(int x) {} ();
}''', [
- error(StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS, 22, 2),
+ error(CompileTimeErrorCode.NOT_ENOUGH_POSITIONAL_ARGUMENTS, 22, 2),
]);
}
@@ -30,7 +30,7 @@
main() {
f();
}''', [
- error(StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS, 34, 2),
+ error(CompileTimeErrorCode.NOT_ENOUGH_POSITIONAL_ARGUMENTS, 34, 2),
]);
}
@@ -41,7 +41,7 @@
main() {
getter();
}''', [
- error(StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS, 65, 2),
+ error(CompileTimeErrorCode.NOT_ENOUGH_POSITIONAL_ARGUMENTS, 65, 2),
]);
}
}
diff --git a/pkg/analyzer/test/src/diagnostics/not_initialized_non_nullable_instance_field_test.dart b/pkg/analyzer/test/src/diagnostics/not_initialized_non_nullable_instance_field_test.dart
index ccb37f7..2e2c468 100644
--- a/pkg/analyzer/test/src/diagnostics/not_initialized_non_nullable_instance_field_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/not_initialized_non_nullable_instance_field_test.dart
@@ -86,6 +86,14 @@
]);
}
+ test_late() async {
+ await assertNoErrorsInCode('''
+class A {
+ late int x;
+}
+''');
+ }
+
test_notAllConstructors() async {
await assertErrorsInCode('''
class A {
diff --git a/pkg/analyzer/test/src/diagnostics/not_initialized_non_nullable_variable_test.dart b/pkg/analyzer/test/src/diagnostics/not_initialized_non_nullable_variable_test.dart
index ef60224..2e028b6 100644
--- a/pkg/analyzer/test/src/diagnostics/not_initialized_non_nullable_variable_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/not_initialized_non_nullable_variable_test.dart
@@ -39,6 +39,14 @@
''');
}
+ test_staticField_late() async {
+ await assertNoErrorsInCode('''
+class A {
+ static late int v;
+}
+''');
+ }
+
test_staticField_noInitializer() async {
await assertErrorsInCode('''
class A {
diff --git a/pkg/analyzer/test/src/diagnostics/redirect_to_missing_constructor_test.dart b/pkg/analyzer/test/src/diagnostics/redirect_to_missing_constructor_test.dart
index c688e3b..e181529 100644
--- a/pkg/analyzer/test/src/diagnostics/redirect_to_missing_constructor_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/redirect_to_missing_constructor_test.dart
@@ -23,7 +23,7 @@
class B {
factory B() = A.name;
}''', [
- error(StaticWarningCode.REDIRECT_TO_MISSING_CONSTRUCTOR, 59, 6),
+ error(CompileTimeErrorCode.REDIRECT_TO_MISSING_CONSTRUCTOR, 59, 6),
]);
}
@@ -35,7 +35,7 @@
class B {
factory B() = A;
}''', [
- error(StaticWarningCode.REDIRECT_TO_MISSING_CONSTRUCTOR, 64, 1),
+ error(CompileTimeErrorCode.REDIRECT_TO_MISSING_CONSTRUCTOR, 64, 1),
]);
}
}
diff --git a/pkg/analyzer/test/src/diagnostics/redirect_to_non_class_test.dart b/pkg/analyzer/test/src/diagnostics/redirect_to_non_class_test.dart
index 39c83ab..38e1b35 100644
--- a/pkg/analyzer/test/src/diagnostics/redirect_to_non_class_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/redirect_to_non_class_test.dart
@@ -21,7 +21,7 @@
int A;
factory B() = A;
}''', [
- error(StaticWarningCode.REDIRECT_TO_NON_CLASS, 35, 1),
+ error(CompileTimeErrorCode.REDIRECT_TO_NON_CLASS, 35, 1),
]);
}
@@ -30,7 +30,7 @@
class B {
factory B() = A;
}''', [
- error(StaticWarningCode.REDIRECT_TO_NON_CLASS, 26, 1),
+ error(CompileTimeErrorCode.REDIRECT_TO_NON_CLASS, 26, 1),
]);
}
}
diff --git a/pkg/analyzer/test/src/diagnostics/super_in_extension_test.dart b/pkg/analyzer/test/src/diagnostics/super_in_extension_test.dart
index b356cfd..3b26ce9 100644
--- a/pkg/analyzer/test/src/diagnostics/super_in_extension_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/super_in_extension_test.dart
@@ -23,14 +23,24 @@
sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
test_binaryOperator_inMethod() async {
- // TODO(brianwilkerson) Ensure that only one diagnostic is produced.
await assertErrorsInCode('''
extension E on int {
int plusOne() => super + 1;
}
''', [
error(CompileTimeErrorCode.SUPER_IN_EXTENSION, 40, 5),
- error(StaticTypeWarningCode.UNDEFINED_SUPER_OPERATOR, 46, 1),
+ ]);
+ }
+
+ test_binaryOperator_withGenericExtendedType() async {
+ await assertErrorsInCode('''
+extension <T> on T {
+ f() {
+ super + 1;
+ }
+}
+''', [
+ error(CompileTimeErrorCode.SUPER_IN_EXTENSION, 33, 5),
]);
}
@@ -51,7 +61,6 @@
}
test_indexOperator_inMethod() async {
- // TODO(brianwilkerson) Ensure that only one diagnostic is produced.
await assertErrorsInCode('''
class C {
int operator[](int i) => 0;
@@ -61,7 +70,6 @@
}
''', [
error(CompileTimeErrorCode.SUPER_IN_EXTENSION, 80, 5),
- error(StaticTypeWarningCode.UNDEFINED_SUPER_OPERATOR, 85, 3),
]);
}
@@ -76,7 +84,6 @@
}
test_prefixOperator_inGetter() async {
- // TODO(brianwilkerson) Ensure that only one diagnostic is produced.
await assertErrorsInCode('''
class C {
C operator-() => this;
@@ -85,7 +92,6 @@
C get negated => -super;
}
''', [
- error(StaticTypeWarningCode.UNDEFINED_SUPER_OPERATOR, 75, 1),
error(CompileTimeErrorCode.SUPER_IN_EXTENSION, 76, 5),
]);
}
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index 749012b..b953550 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -20,6 +20,8 @@
import 'assignment_to_type_test.dart' as assignment_to_type;
import 'async_keyword_used_as_identifier_test.dart'
as async_keyword_used_as_identifier;
+import 'builtin_identifier_as_extension_name_test.dart'
+ as builtin_as_extension_name;
import 'can_be_null_after_null_aware_test.dart' as can_be_null_after_null_aware;
import 'case_block_not_terminated_test.dart' as case_block_not_terminated;
import 'cast_to_non_type_test.dart' as cast_to_non_type;
@@ -34,6 +36,7 @@
import 'const_eval_throws_exception_test.dart' as const_eval_throws_exception;
import 'const_map_key_expression_type_implements_equals_test.dart'
as const_map_key_expression_type_implements_equals;
+import 'const_not_initialized_test.dart' as const_not_initialized;
import 'const_set_element_type_implements_equals_test.dart'
as const_set_element_type_implements_equals;
import 'const_spread_expected_list_or_set_test.dart'
@@ -62,6 +65,7 @@
as export_suplicated_library_named;
import 'expression_in_map_test.dart' as expression_in_map;
import 'extends_non_class_test.dart' as extends_non_class;
+import 'extension_as_expression_test.dart' as extension_as_expression;
import 'extension_conflicting_static_and_instance_test.dart'
as extension_conflicting_static_and_instance;
import 'extension_declares_abstract_method_test.dart'
@@ -121,7 +125,11 @@
as invalid_override_different_default_values_positional;
import 'invalid_override_test.dart' as invalid_override;
import 'invalid_reference_to_this_test.dart' as invalid_reference_to_this;
-import 'invalid_required_param_test.dart' as invalid_required_param;
+import 'invalid_required_named_param_test.dart' as invalid_required_named_param;
+import 'invalid_required_optional_positional_param_test.dart'
+ as invalid_required_optional_positional_param;
+import 'invalid_required_positional_param_test.dart'
+ as invalid_required_positional_param;
import 'invalid_sealed_annotation_test.dart' as invalid_sealed_annotation;
import 'invalid_use_of_covariant_in_extension_test.dart'
as invalid_use_of_covariant_in_extension;
@@ -189,8 +197,8 @@
import 'not_a_type_test.dart' as not_a_type;
import 'not_assigned_potentially_non_nullable_local_variable_test.dart'
as not_assigned_potentially_non_nullable_local_variable;
-import 'not_enough_required_arguments_test.dart'
- as not_enough_required_arguments;
+import 'not_enough_positional_arguments_test.dart'
+ as not_enough_positional_arguments;
import 'not_initialized_non_nullable_instance_field_test.dart'
as not_initialized_non_nullable_instance_field;
import 'not_initialized_non_nullable_variable_test.dart'
@@ -313,6 +321,7 @@
assignment_to_method.main();
assignment_to_type.main();
async_keyword_used_as_identifier.main();
+ builtin_as_extension_name.main();
can_be_null_after_null_aware.main();
case_block_not_terminated.main();
cast_to_non_type.main();
@@ -322,6 +331,7 @@
const_constructor_with_mixin_with_field.main();
const_eval_throws_exception.main();
const_map_key_expression_type_implements_equals.main();
+ const_not_initialized.main();
const_set_element_type_implements_equals.main();
const_spread_expected_list_or_set.main();
const_spread_expected_map.main();
@@ -344,6 +354,7 @@
export_suplicated_library_named.main();
expression_in_map.main();
extends_non_class.main();
+ extension_as_expression.main();
extension_conflicting_static_and_instance.main();
extension_declares_abstract_method.main();
extension_declares_constructor.main();
@@ -380,7 +391,9 @@
invalid_override_different_default_values_positional.main();
invalid_override.main();
invalid_reference_to_this.main();
- invalid_required_param.main();
+ invalid_required_named_param.main();
+ invalid_required_optional_positional_param.main();
+ invalid_required_positional_param.main();
invalid_sealed_annotation.main();
invalid_use_of_covariant_in_extension.main();
invalid_use_of_never_value.main();
@@ -431,7 +444,7 @@
non_void_return_for_setter.main();
not_a_type.main();
not_assigned_potentially_non_nullable_local_variable.main();
- not_enough_required_arguments.main();
+ not_enough_positional_arguments.main();
not_initialized_non_nullable_instance_field.main();
not_initialized_non_nullable_variable.main();
not_iterable_spread.main();
diff --git a/pkg/analyzer/test/src/diagnostics/unchecked_use_of_nullable_value_test.dart b/pkg/analyzer/test/src/diagnostics/unchecked_use_of_nullable_value_test.dart
index 6f2981b..a5176b9 100644
--- a/pkg/analyzer/test/src/diagnostics/unchecked_use_of_nullable_value_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/unchecked_use_of_nullable_value_test.dart
@@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/src/dart/analysis/experiments.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/engine.dart';
@@ -21,6 +22,9 @@
AnalysisOptionsImpl get analysisOptions =>
AnalysisOptionsImpl()..enabledExperiments = [EnableString.non_nullable];
+ @override
+ bool get typeToStringWithNullability => true;
+
test_and_nonNullable() async {
await assertNoErrorsInCode(r'''
m() {
@@ -70,6 +74,120 @@
]);
}
+ test_assignment_eq_propertyAccess3_short1() async {
+ await assertErrorsInCode(r'''
+class A {
+ int x;
+ A(this.x);
+}
+
+class B {
+ final A? a;
+ B(this.a);
+}
+
+m(B b) {
+ b.a?.x = 1;
+ b.a.x = 2;
+}
+''', [
+ error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 100, 3),
+ ]);
+ var assignment1 = findNode.assignment('b.a?.x = 1');
+ var assignment2 = findNode.assignment('b.a.x = 2');
+ assertType(assignment1.leftHandSide, 'int');
+ assertType(assignment2.leftHandSide, 'int');
+ assertType(assignment1, 'int?');
+ assertType(assignment2, 'int');
+ }
+
+ test_assignment_eq_simpleIdentifier() async {
+ await assertNoErrorsInCode(r'''
+m(int x, int? y) {
+ x = 0;
+ y = 0;
+}
+''');
+ var assignment1 = findNode.assignment('x =');
+ var assignment2 = findNode.assignment('y =');
+ assertType(assignment1.leftHandSide, 'int');
+ assertType(assignment2.leftHandSide, 'int?');
+ assertType(assignment1, 'int');
+ assertType(assignment2, 'int');
+ }
+
+ test_assignment_plusEq_propertyAccess3() async {
+ await assertErrorsInCode(r'''
+class A {
+ int x;
+ int? y;
+ A(this.x);
+}
+
+class B {
+ final A a;
+ B(this.a);
+}
+
+m(B b) {
+ b.a.x += 0;
+ b.a.y += 0;
+}
+''', [
+ error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 109, 5),
+ ]);
+ var assignment1 = findNode.assignment('b.a.x +=');
+ var assignment2 = findNode.assignment('b.a.y +=');
+ assertType(assignment1.leftHandSide, 'int');
+ assertType(assignment2.leftHandSide, 'int?');
+ assertType(assignment1, 'int');
+ assertType(assignment2, 'int');
+ }
+
+ test_assignment_plusEq_propertyAccess3_short1() async {
+ await assertErrorsInCode(r'''
+class A {
+ int x;
+ A(this.x);
+}
+
+class B {
+ final A? a;
+ B(this.a);
+}
+
+m(B b) {
+ b.a?.x += 1;
+ b.a.x += 2;
+}
+''', [
+ error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 101, 3),
+ ]);
+ var assignment1 = findNode.assignment('b.a?.x += 1');
+ var assignment2 = findNode.assignment('b.a.x += 2');
+ assertType(assignment1.leftHandSide, 'int');
+ assertType(assignment2.leftHandSide, 'int');
+ assertType(assignment1, 'int?');
+ assertType(assignment2, 'int');
+ }
+
+ test_assignment_plusEq_simpleIdentifier() async {
+ await assertErrorsInCode(r'''
+m(int x, int? y) {
+ x += 0;
+ y += 0;
+}
+''', [
+ error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 31, 1),
+ ]);
+ var assignment1 = findNode.assignment('x +=');
+ var assignment2 = findNode.assignment('y +=');
+ assertType(assignment1.leftHandSide, 'int');
+ assertType(assignment2.leftHandSide, 'int?');
+ assertType(assignment1, 'int');
+ assertType(assignment2, 'int');
+ }
+
test_await_nonNullable() async {
await assertNoErrorsInCode(r'''
m() async {
@@ -108,7 +226,7 @@
]);
}
- test_eq_nullable() async {
+ test_eqEq_nullable() async {
await assertNoErrorsInCode(r'''
m() {
int? x;
@@ -613,6 +731,170 @@
]);
}
+ test_read_propertyAccess2_short1() async {
+ await assertErrorsInCode(r'''
+class A {
+ final int x;
+ A(this.x);
+}
+
+m(A? a) {
+ a?.x; // 1
+ a.x; // 2
+}
+''', [
+ error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 66, 1),
+ ]);
+ var propertyAccess1 = findNode.propertyAccess('a?.x; // 1');
+ var propertyAccess2 = findNode.prefixed('a.x; // 2');
+ assertType(propertyAccess1.target, 'A?');
+ assertType(propertyAccess2.prefix, 'A?');
+
+ assertType(propertyAccess1.propertyName, 'int');
+ assertType(propertyAccess2.identifier, 'int');
+
+ assertType(propertyAccess1, 'int?');
+ assertType(propertyAccess2, 'int');
+ }
+
+ test_read_propertyAccess3_short1() async {
+ await assertErrorsInCode(r'''
+class A {
+ int x;
+ A(this.x);
+}
+
+class B {
+ final A? a;
+ B(this.a);
+}
+
+m(B b) {
+ b.a?.x; // 1
+ b.a.x; // 2
+}
+''', [
+ error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 101, 3),
+ ]);
+ var propertyAccess1 = findNode.propertyAccess('b.a?.x; // 1');
+ var propertyAccess2 = findNode.propertyAccess('b.a.x; // 2');
+ assertType(propertyAccess1.target, 'A?');
+ assertType(propertyAccess2.target, 'A?');
+
+ assertType(propertyAccess1.propertyName, 'int');
+ assertType(propertyAccess2.propertyName, 'int');
+
+ assertType(propertyAccess1, 'int?');
+ assertType(propertyAccess2, 'int');
+ }
+
+ test_read_propertyAccess3_short2() async {
+ await assertErrorsInCode(r'''
+class A {
+ int x;
+ A(this.x);
+}
+
+class B {
+ final A a;
+ B(this.a);
+}
+
+m(B? b) {
+ b?.a.x; // 1
+ b.a.x; // 2
+}
+''', [
+ error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 101, 1),
+ ]);
+ var propertyAccess1 = findNode.propertyAccess('x; // 1');
+ var propertyAccess2 = findNode.propertyAccess('x; // 2');
+ assertType(propertyAccess1.target, 'A');
+ assertType(propertyAccess2.target, 'A');
+
+ assertType(propertyAccess1.propertyName, 'int');
+ assertType(propertyAccess2.propertyName, 'int');
+
+ assertType(propertyAccess1, 'int?');
+ assertType(propertyAccess2, 'int');
+ }
+
+ test_read_propertyAccess4_short1() async {
+ await assertErrorsInCode(r'''
+class A {
+ int x;
+ A(this.x);
+}
+
+class B {
+ final A? a;
+ B(this.a);
+}
+
+class C {
+ final B b;
+ C(this.b);
+}
+
+m(C c) {
+ c.b.a?.x; // 1
+ c.b.a.x; // 2
+}
+''', [
+ error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 142, 5),
+ ]);
+ var propertyAccess1 = findNode.propertyAccess('x; // 1');
+ var propertyAccess2 = findNode.propertyAccess('x; // 2');
+ assertType(propertyAccess1.target, 'A?');
+ assertType(propertyAccess2.target, 'A?');
+
+ assertType(propertyAccess1.propertyName, 'int');
+ assertType(propertyAccess2.propertyName, 'int');
+
+ assertType(propertyAccess1, 'int?');
+ assertType(propertyAccess2, 'int');
+ }
+
+ test_read_propertyAccess4_short2() async {
+ await assertErrorsInCode(r'''
+class A {
+ final int x;
+ A(this.x);
+}
+
+class B {
+ final A a;
+ B(this.a);
+}
+
+class C {
+ final B? b;
+ C(this.b);
+}
+
+m(C c) {
+ c.b?.a.x; // 1
+ c.b.a.x; // 2
+}
+''', [
+ error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 148, 3),
+ ]);
+ var propertyAccess1 = findNode.propertyAccess('x; // 1');
+ var propertyAccess2 = findNode.propertyAccess('x; // 2');
+ PropertyAccess propertyAccess1t = propertyAccess1.target;
+ PropertyAccess propertyAccess2t = propertyAccess1.target;
+ assertType(propertyAccess1t.target, 'B?');
+ assertType(propertyAccess2t.target, 'B?');
+ assertType(propertyAccess1t, 'A');
+ assertType(propertyAccess2t, 'A');
+
+ assertType(propertyAccess1.propertyName, 'int');
+ assertType(propertyAccess2.propertyName, 'int');
+
+ assertType(propertyAccess1, 'int?');
+ assertType(propertyAccess2, 'int');
+ }
+
test_spread_nonNullable() async {
await assertNoErrorsInCode(r'''
m() {
diff --git a/pkg/analyzer/test/src/diagnostics/wrong_type_parameter_variance_in_superinterface_test.dart b/pkg/analyzer/test/src/diagnostics/wrong_type_parameter_variance_in_superinterface_test.dart
index 70860b2..840791c 100644
--- a/pkg/analyzer/test/src/diagnostics/wrong_type_parameter_variance_in_superinterface_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/wrong_type_parameter_variance_in_superinterface_test.dart
@@ -2,7 +2,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import 'package:analyzer/src/dart/analysis/driver.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -310,34 +309,16 @@
}
test_typeParameter_bound() async {
- try {
- await assertErrorsInCode(r'''
+ await assertErrorsInCode(r'''
class A<X> {}
class B<X> extends A<void Function<Y extends X>()> {}
''', [
- error(
- CompileTimeErrorCode
- .WRONG_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE,
- 22,
- 1),
- error(
- CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
- 35,
- 28),
- ]);
- if (!AnalysisDriver.useSummary2) {
- throw 'Test passed - expected to fail.';
- }
- } on String {
- rethrow;
- } catch (_) {
- // TODO(scheglov) This code crashes with summary1.
-// NoSuchMethodError: The getter 'bound' was called on null.
-// Receiver: null
-// Tried calling: bound
-// #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:50:5)
-// #1 ErrorVerifier._checkForTypeParameterSupertypeOfItsBound (error_verifier.dart:5438:30)
- if (AnalysisDriver.useSummary2) rethrow;
- }
+ error(
+ CompileTimeErrorCode.WRONG_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE,
+ 22,
+ 1),
+ error(CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
+ 35, 28),
+ ]);
}
}
diff --git a/pkg/analyzer/test/src/fasta/message_coverage_test.dart b/pkg/analyzer/test/src/fasta/message_coverage_test.dart
index 291f940..18a62fd 100644
--- a/pkg/analyzer/test/src/fasta/message_coverage_test.dart
+++ b/pkg/analyzer/test/src/fasta/message_coverage_test.dart
@@ -6,13 +6,13 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
-import 'package:front_end/src/testing/package_root.dart' as package_root;
import 'package:path/path.dart' as path;
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
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/lint/linter/linter_context_impl_test.dart b/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart
index 028dbdd..befdee3 100644
--- a/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart
+++ b/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart
@@ -206,4 +206,20 @@
''');
assertCanBeConst("A([", true);
}
+
+ void test_true_importedClass_defaultValue() async {
+ var aPath = convertPath('/test/lib/a.dart');
+ newFile(aPath, content: r'''
+class A {
+ final int a;
+ const A({int b = 1}) : a = b * 2;
+}
+''');
+ await resolve('''
+import 'a.dart';
+
+A f() => A();
+''');
+ assertCanBeConst("A();", true);
+ }
}
diff --git a/pkg/analyzer/test/src/services/available_declarations_test.dart b/pkg/analyzer/test/src/services/available_declarations_test.dart
index a80aeb9..4e70ff2 100644
--- a/pkg/analyzer/test/src/services/available_declarations_test.dart
+++ b/pkg/analyzer/test/src/services/available_declarations_test.dart
@@ -1234,6 +1234,7 @@
parameterNames: [],
parameters: '()',
parameterTypes: [],
+ relevanceTags: ['package:test/test.dart::C'],
requiredParameterCount: 0,
returnType: 'C',
);
@@ -1244,6 +1245,7 @@
parameterNames: [],
parameters: '()',
parameterTypes: [],
+ relevanceTags: ['package:test/test.dart::C'],
requiredParameterCount: 0,
returnType: 'C',
);
@@ -1255,6 +1257,7 @@
parameters: '()',
parameterNames: [],
parameterTypes: [],
+ relevanceTags: ['package:test/test.dart::C'],
requiredParameterCount: 0,
returnType: 'C',
);
@@ -1267,6 +1270,7 @@
parameters: '()',
parameterNames: [],
parameterTypes: [],
+ relevanceTags: ['package:test/test.dart::C'],
requiredParameterCount: 0,
returnType: 'C',
);
@@ -1279,6 +1283,7 @@
parameters: '(Map<String, int> p1, int p2, {double p3})',
parameterNames: ['p1', 'p2', 'p3'],
parameterTypes: ['Map<String, int>', 'int', 'double'],
+ relevanceTags: ['package:test/test.dart::C'],
requiredParameterCount: 2,
returnType: 'C',
);
@@ -1291,6 +1296,7 @@
parameters: '(this.f1, this.f2)',
parameterNames: ['f1', 'f2'],
parameterTypes: ['', ''],
+ relevanceTags: ['package:test/test.dart::C'],
requiredParameterCount: 2,
returnType: 'C',
);
diff --git a/pkg/analyzer/test/src/summary/expr_builder_test.dart b/pkg/analyzer/test/src/summary/expr_builder_test.dart
index fcdb51f3..c73bee8 100644
--- a/pkg/analyzer/test/src/summary/expr_builder_test.dart
+++ b/pkg/analyzer/test/src/summary/expr_builder_test.dart
@@ -23,7 +23,10 @@
import 'test_strategies.dart';
main() {
- if (AnalysisDriver.useSummary2) return;
+ if (AnalysisDriver.useSummary2) {
+ test('fake', () {});
+ return;
+ }
defineReflectiveSuite(() {
defineReflectiveTests(ExprBuilderTest);
defineReflectiveTests(ExprBuilderWithConstantUpdateTest);
diff --git a/pkg/analyzer/test/src/summary/linker_test.dart b/pkg/analyzer/test/src/summary/linker_test.dart
index d3dbb1d..bb34cbd 100644
--- a/pkg/analyzer/test/src/summary/linker_test.dart
+++ b/pkg/analyzer/test/src/summary/linker_test.dart
@@ -13,7 +13,10 @@
import 'test_strategies.dart';
main() {
- if (AnalysisDriver.useSummary2) return;
+ if (AnalysisDriver.useSummary2) {
+ test('fake', () {});
+ return;
+ }
defineReflectiveSuite(() {
defineReflectiveTests(LinkerUnitTest);
});
diff --git a/pkg/analyzer/test/src/summary/prelinker_test.dart b/pkg/analyzer/test/src/summary/prelinker_test.dart
index 6e932bd..aa47aaaa 100644
--- a/pkg/analyzer/test/src/summary/prelinker_test.dart
+++ b/pkg/analyzer/test/src/summary/prelinker_test.dart
@@ -3,13 +3,17 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'summary_common.dart';
import 'test_strategies.dart';
main() {
- if (AnalysisDriver.useSummary2) return;
+ if (AnalysisDriver.useSummary2) {
+ test('fake', () {});
+ return;
+ }
defineReflectiveSuite(() {
defineReflectiveTests(PrelinkerTest);
});
diff --git a/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart b/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart
index 3ab3089..6785245 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart
@@ -7,10 +7,10 @@
import 'package:analyzer/src/dart/analysis/restricted_analysis_context.dart';
import 'package:analyzer/src/dart/analysis/session.dart';
import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/type_provider.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/summary/idl.dart';
-import 'package:analyzer/src/summary/summary_sdk.dart';
import 'package:analyzer/src/summary2/informative_data.dart';
import 'package:analyzer/src/summary2/link.dart';
import 'package:analyzer/src/summary2/linked_bundle_context.dart';
@@ -124,9 +124,7 @@
if (analysisContext.typeProvider == null) {
var dartCore = elementFactory.libraryOfUri('dart:core');
var dartAsync = elementFactory.libraryOfUri('dart:async');
- var typeProvider = SummaryTypeProvider()
- ..initializeCore(dartCore)
- ..initializeAsync(dartAsync);
+ var typeProvider = TypeProviderImpl(dartCore, dartAsync);
analysisContext.typeProvider = typeProvider;
dartCore.createLoadLibraryFunction(typeProvider);
diff --git a/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart b/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
index 3f66e12..190954b 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'element_text.dart';
@@ -10,7 +11,10 @@
import 'test_strategies.dart';
main() {
- if (AnalysisDriver.useSummary2) return;
+ if (AnalysisDriver.useSummary2) {
+ test('fake', () {});
+ return;
+ }
defineReflectiveSuite(() {
defineReflectiveTests(ApplyCheckElementTextReplacements);
defineReflectiveTests(ResynthesizeAstStrongTest);
@@ -27,6 +31,13 @@
@reflectiveTest
class ResynthesizeAstStrongTest extends ResynthesizeTestStrategyTwoPhase
with ResynthesizeTestCases, GetElementTestCases, ResynthesizeTestHelpers {
+ @override
+ @failingTest
+ test_class_constructor_field_formal_functionTyped_withReturnType_generic() async {
+ await super
+ .test_class_constructor_field_formal_functionTyped_withReturnType_generic();
+ }
+
@failingTest // See dartbug.com/32290
test_const_constructor_inferred_args() =>
super.test_const_constructor_inferred_args();
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 8745996..38ce11b 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -632,6 +632,21 @@
''');
}
+ test_class_constructor_field_formal_functionTyped_withReturnType_generic() async {
+ var library = await checkLibrary(r'''
+class C {
+ Function() f;
+ C(List<U> this.f<T, U>(T t));
+}
+''');
+ checkElementText(library, r'''
+class C {
+ dynamic Function() f;
+ C(List<U> Function<T, U>(T) this.f/*(T t)*/);
+}
+''');
+ }
+
test_class_constructor_field_formal_multiple_matching_fields() async {
// This is a compile-time error but it should still analyze consistently.
var library = await checkLibrary('class C { C(this.x); int x; String x; }',
diff --git a/pkg/analyzer/test/src/summary/summarize_ast_strong_test.dart b/pkg/analyzer/test/src/summary/summarize_ast_strong_test.dart
index 3911aab..c6d4b8d 100644
--- a/pkg/analyzer/test/src/summary/summarize_ast_strong_test.dart
+++ b/pkg/analyzer/test/src/summary/summarize_ast_strong_test.dart
@@ -3,13 +3,17 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'summary_common.dart';
import 'test_strategies.dart';
main() {
- if (AnalysisDriver.useSummary2) return;
+ if (AnalysisDriver.useSummary2) {
+ test('fake', () {});
+ return;
+ }
defineReflectiveSuite(() {
defineReflectiveTests(LinkedSummarizeAstStrongTest);
});
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 7ff704f..43a4011 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
@@ -5,10 +5,10 @@
import 'dart:io';
import 'package:analyzer/file_system/physical_file_system.dart';
-import 'package:front_end/src/testing/package_root.dart' as package_root;
import 'package:test/test.dart';
import '../dart/ast/parse_base.dart';
+import '../../utils/package_root.dart' as package_root;
import 'ast_text_printer_test.dart';
main() {
diff --git a/pkg/analyzer/test/src/task/options_test.dart b/pkg/analyzer/test/src/task/options_test.dart
index 764e8b1..0c311e0 100644
--- a/pkg/analyzer/test/src/task/options_test.dart
+++ b/pkg/analyzer/test/src/task/options_test.dart
@@ -186,6 +186,14 @@
declaredNames.remove(
StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_3_PLUS.name +
'_PLUS');
+ declaredNames.remove('EXTRA_POSITIONAL_ARGUMENTS');
+ declaredNames.remove('EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED');
+ declaredNames.remove('IMPORT_OF_NON_LIBRARY');
+ declaredNames.remove('NOT_ENOUGH_REQUIRED_ARGUMENTS');
+ declaredNames.remove('REDIRECT_TO_MISSING_CONSTRUCTOR');
+ declaredNames.remove('REDIRECT_TO_NON_CLASS');
+ declaredNames.remove('UNDEFINED_CLASS');
+ declaredNames.remove('UNDEFINED_NAMED_PARAMETER');
} else if (errorType == StrongModeCode) {
void removeCode(StrongModeCode code) {
declaredNames.remove(code.name);
@@ -233,6 +241,7 @@
declaredNames.remove('TODO_REGEX');
} else if (errorType == CompileTimeErrorCode) {
declaredNames.remove('ANNOTATION_WITH_TYPE_ARGUMENTS');
+ declaredNames.remove('NOT_ENOUGH_REQUIRED_ARGUMENTS');
} else if (errorType == ParserErrorCode) {
declaredNames.remove('CONST_AFTER_FACTORY');
declaredNames.remove('CONST_AND_COVARIANT');
diff --git a/pkg/analyzer/test/src/task/strong/checker_test.dart b/pkg/analyzer/test/src/task/strong/checker_test.dart
index d8e26ac..7360730 100644
--- a/pkg/analyzer/test/src/task/strong/checker_test.dart
+++ b/pkg/analyzer/test/src/task/strong/checker_test.dart
@@ -1972,10 +1972,10 @@
// resolving these shouldn't crash.
foo/*error:EXTRA_POSITIONAL_ARGUMENTS*/(1, 2, 3);
x = foo/*error:EXTRA_POSITIONAL_ARGUMENTS*/('1', '2', '3');
- foo/*error:NOT_ENOUGH_REQUIRED_ARGUMENTS*/(1);
- x = foo/*error:NOT_ENOUGH_REQUIRED_ARGUMENTS*/('1');
+ foo/*error:NOT_ENOUGH_POSITIONAL_ARGUMENTS*/(1);
+ x = foo/*error:NOT_ENOUGH_POSITIONAL_ARGUMENTS*/('1');
x = foo/*error:EXTRA_POSITIONAL_ARGUMENTS*/(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/1, /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/2, 3);
- x = foo/*error:NOT_ENOUGH_REQUIRED_ARGUMENTS*/(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/1);
+ x = foo/*error:NOT_ENOUGH_POSITIONAL_ARGUMENTS*/(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/1);
// named arguments
bar(y: 1, x: 2, /*error:UNDEFINED_NAMED_PARAMETER*/z: 3);
@@ -2037,12 +2037,12 @@
test_genericMethodSuperSubstitute() async {
await checkFile(r'''
-class Clonable<T> {}
+class Cloneable<T> {}
class G<T> {
- create<A extends Clonable<T>, B extends Iterable<A>>() => null;
+ create<A extends Cloneable<T>, B extends Iterable<A>>() => null;
}
class H extends G<num> {
- create2() => super.create<Clonable<int>, List<Clonable<int>>>();
+ create2() => super.create<Cloneable<int>, List<Cloneable<int>>>();
}
''');
}
@@ -4899,18 +4899,18 @@
if (object is int) print(object.isEven);
if (object is String) print(/*info:DYNAMIC_INVOKE*/object./*error:UNDEFINED_METHOD*/substring(1));
}
-class Clonable<T> {}
-class SubClonable<T> extends Clonable<T> {
+class Cloneable<T> {}
+class SubCloneable<T> extends Cloneable<T> {
T m(T t) => t;
}
-void takesSubClonable<A>(SubClonable<A> t) {}
+void takesSubCloneable<A>(SubCloneable<A> t) {}
-void h<T extends Clonable<T>>(T object) {
- if (/*info:NON_GROUND_TYPE_CHECK_INFO*/object is SubClonable<T>) {
+void h<T extends Cloneable<T>>(T object) {
+ if (/*info:NON_GROUND_TYPE_CHECK_INFO*/object is SubCloneable<T>) {
print(object.m(object));
- SubClonable<T> s = object;
- takesSubClonable<T>(object);
+ SubCloneable<T> s = object;
+ takesSubCloneable<T>(object);
// Issue #35799: According to the language team, this should work, but both
// analyzer and CFE currently reject it, likely due to a strange
// representation of promoted type variables.
diff --git a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
index a3a31c2..94feba2 100644
--- a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
+++ b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
@@ -488,9 +488,9 @@
'error:TYPE_ARGUMENT_NOT_MATCHING_BOUNDS';
// if (hasExtraTaskModelPass) errors = '$errors,$errors';
var unit = await checkFile('''
-class Clonable<T> {}
+class Cloneable<T> {}
-class Pair<T extends Clonable<T>, U extends Clonable<U>> {
+class Pair<T extends Cloneable<T>, U extends Cloneable<U>> {
T t;
U u;
Pair(this.t, this.u);
@@ -503,7 +503,7 @@
}
''');
var x = findLocalVariable(unit, 'x');
- expect(x.type.toString(), 'Pair<Clonable<dynamic>, Clonable<dynamic>>');
+ expect(x.type.toString(), 'Pair<Cloneable<dynamic>, Cloneable<dynamic>>');
}
test_constructors_inferFromArguments() async {
@@ -524,7 +524,7 @@
C<num> c_num2 = (/*info:INFERRED_TYPE_ALLOCATION*/new C(456))
..t = 1.0;
- // Down't infer from explicit dynamic.
+ // Don't infer from explicit dynamic.
var c_dynamic = new C<dynamic>(42);
x.t = /*error:INVALID_ASSIGNMENT*/'hello';
}
@@ -2488,7 +2488,7 @@
''');
}
- test_inferedType_usesSyntheticFunctionType() async {
+ test_inferredType_usesSyntheticFunctionType() async {
var mainUnit = await checkFileElement('''
int f() => null;
String g() => null;
@@ -2498,7 +2498,7 @@
expect(v.type.toString(), 'List<Object Function()>');
}
- test_inferedType_usesSyntheticFunctionType_functionTypedParam() async {
+ test_inferredType_usesSyntheticFunctionType_functionTypedParam() async {
var mainUnit = await checkFileElement('''
int f(int x(String y)) => null;
String g(int x(String y)) => null;
@@ -2508,7 +2508,7 @@
expect(v.type.toString(), 'List<Object Function(int Function(String))>');
}
- test_inferedType_usesSyntheticFunctionType_namedParam() async {
+ test_inferredType_usesSyntheticFunctionType_namedParam() async {
var mainUnit = await checkFileElement('''
int f({int x}) => null;
String g({int x}) => null;
@@ -2518,7 +2518,7 @@
expect(v.type.toString(), 'List<Object Function({x: int})>');
}
- test_inferedType_usesSyntheticFunctionType_positionalParam() async {
+ test_inferredType_usesSyntheticFunctionType_positionalParam() async {
var mainUnit = await checkFileElement('''
int f([int x]) => null;
String g([int x]) => null;
@@ -2528,7 +2528,7 @@
expect(v.type.toString(), 'List<Object Function([int])>');
}
- test_inferedType_usesSyntheticFunctionType_requiredParam() async {
+ test_inferredType_usesSyntheticFunctionType_requiredParam() async {
var mainUnit = await checkFileElement('''
int f(int x) => null;
String g(int x) => null;
diff --git a/pkg/analyzer/test/src/task/strong/strong_test_helper.dart b/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
index 8fb7e6f..2edf77f 100644
--- a/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
+++ b/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
@@ -8,7 +8,6 @@
import 'dart:collection';
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/error/error.dart';
@@ -172,14 +171,13 @@
Map<List<_ErrorExpectation>, List<AnalysisError>> different) {
// Get the source code. This reads the data again, but it's safe because
// all tests use memory file system.
- var sourceCode =
- resolutionMap.elementDeclaredByCompilationUnit(unit).source.contents.data;
+ var sourceCode = unit.declaredElement.source.contents.data;
String formatActualError(AnalysisError error) {
int offset = error.offset;
int length = error.length;
- var span = _createSpanHelper(unit.lineInfo, offset,
- resolutionMap.elementDeclaredByCompilationUnit(unit).source, sourceCode,
+ var span = _createSpanHelper(
+ unit.lineInfo, offset, unit.declaredElement.source, sourceCode,
end: offset + length);
var levelName = _errorSeverity(analysisOptions, error).displayName;
return '@$offset $levelName:${error.errorCode.name}\n' +
@@ -192,10 +190,7 @@
var result = '@$offset $severity:${error.typeName}';
if (!showSource) return result;
var span = _createSpanHelper(
- unit.lineInfo,
- offset,
- resolutionMap.elementDeclaredByCompilationUnit(unit).source,
- sourceCode);
+ unit.lineInfo, offset, unit.declaredElement.source, sourceCode);
return '$result\n${span.message('')}';
}
@@ -337,8 +332,7 @@
// Extract expectations from the comments in the test files, and
// check that all errors we emit are included in the expected map.
- LibraryElement mainLibrary =
- resolutionMap.elementDeclaredByCompilationUnit(mainUnit).library;
+ LibraryElement mainLibrary = mainUnit.declaredElement.library;
Set<LibraryElement> allLibraries = _reachableLibraries(mainLibrary);
for (LibraryElement library in allLibraries) {
diff --git a/pkg/analyzer/test/utils.dart b/pkg/analyzer/test/utils.dart
index 37bc80a..9681e6c 100644
--- a/pkg/analyzer/test/utils.dart
+++ b/pkg/analyzer/test/utils.dart
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
@@ -70,7 +69,7 @@
return unitMember;
}
}
- Source source = resolutionMap.elementDeclaredByCompilationUnit(unit).source;
+ Source source = unit.declaredElement.source;
fail('No class named $className in $source');
}
diff --git a/pkg/front_end/lib/src/testing/package_root.dart b/pkg/analyzer/test/utils/package_root.dart
similarity index 100%
rename from pkg/front_end/lib/src/testing/package_root.dart
rename to pkg/analyzer/test/utils/package_root.dart
diff --git a/pkg/analyzer/test/verify_diagnostics_test.dart b/pkg/analyzer/test/verify_diagnostics_test.dart
index 8a6a460..b8ce223 100644
--- a/pkg/analyzer/test/verify_diagnostics_test.dart
+++ b/pkg/analyzer/test/verify_diagnostics_test.dart
@@ -9,12 +9,12 @@
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
-import 'package:front_end/src/testing/package_root.dart' as package_root;
import 'package:path/path.dart';
import 'package:test/test.dart';
import '../tool/diagnostics/generate.dart';
import 'src/dart/resolution/driver_resolution.dart';
+import 'utils/package_root.dart' as package_root;
/// Validate the documentation associated with the declarations of the error
/// codes.
diff --git a/pkg/analyzer/test/verify_docs_test.dart b/pkg/analyzer/test/verify_docs_test.dart
index 22c3858..09c9b4f 100644
--- a/pkg/analyzer/test/verify_docs_test.dart
+++ b/pkg/analyzer/test/verify_docs_test.dart
@@ -12,9 +12,10 @@
import 'package:analyzer/file_system/overlay_file_system.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:analyzer/src/error/codes.dart';
-import 'package:front_end/src/testing/package_root.dart' as package_root;
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 e14d258..dc8285b 100644
--- a/pkg/analyzer/test/verify_tests_test.dart
+++ b/pkg/analyzer/test/verify_tests_test.dart
@@ -9,10 +9,11 @@
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:front_end/src/testing/package_root.dart' as package_root;
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);
diff --git a/pkg/analyzer/tool/diagnostics/diagnostics.md b/pkg/analyzer/tool/diagnostics/diagnostics.md
index a8b6cde..aa77a12 100644
--- a/pkg/analyzer/tool/diagnostics/diagnostics.md
+++ b/pkg/analyzer/tool/diagnostics/diagnostics.md
@@ -23,8 +23,8 @@
region is required to be a constant. The following locations are constant
contexts:
-* Everything inside a list, map or set literal that's prefixed by the keyword
- `const`. Example:
+* Everything inside a list, map or set literal that's prefixed by the
+ `const` keyword. Example:
```dart
var l = const [/*constant context*/];
@@ -36,7 +36,7 @@
var p = const Point(/*constant context*/);
```
-* The initializer for a variable that's prefixed by the keyword `const`.
+* The initializer for a variable that's prefixed by the `const` keyword.
Example:
```dart
@@ -432,6 +432,7 @@
{% prettify dart %}
typedef Binary = int Function(int, int);
+
int f() {
return [!Binary!](1, 2);
}
@@ -477,8 +478,8 @@
The analyzer produces this diagnostic when an element in a constant list
literal isn't a constant value. The list literal can be constant either
-explicitly (because it's prefixed by the keyword `const`) or implicitly
-(because it appears in a <a href=”#constant-context”>constant context</a>).
+explicitly (because it's prefixed by the `const` keyword) or implicitly
+(because it appears in a [constant context](#constant-context)).
#### Example
@@ -493,8 +494,8 @@
#### Common fixes
If the list needs to be a constant list, then convert the element to be a
-constant. In the example above, you might add the keyword `const`
-to the declaration of `x`:
+constant. In the example above, you might add the `const` keyword to the
+declaration of `x`:
{% prettify dart %}
const int x = 2;
@@ -609,6 +610,7 @@
{% prettify dart %}
C f() {}
+
class C {
factory C() = [!f!];
}
@@ -627,6 +629,7 @@
{% prettify dart %}
C f() {}
+
class C {
factory C() => f();
}
@@ -692,6 +695,7 @@
{% prettify dart %}
class A<E extends num> {}
+
var a = A<[!String!]>();
{% endprettify %}
@@ -701,6 +705,7 @@
{% prettify dart %}
class A<E extends num> {}
+
var a = A<int>();
{% endprettify %}
@@ -720,6 +725,7 @@
{% prettify dart %}
class Point {}
+
void main() {
[!Piont!] p;
}
@@ -733,6 +739,7 @@
{% prettify dart %}
class Point {}
+
void main() {
Point p;
}
@@ -757,6 +764,7 @@
{% prettify dart %}
List<int> empty() => [];
+
void main() {
print([!emty!]());
}
@@ -770,6 +778,7 @@
{% prettify dart %}
List<int> empty() => [];
+
void main() {
print(empty());
}
@@ -793,12 +802,7 @@
The following code produces this diagnostic:
{% prettify dart %}
-class Point {
- final int x;
- final int y;
- Point(this.x, this.y);
- operator +(Point other) => Point(x + other.x, y + other.[!z!]);
-}
+int f(String s) => s.[!len!];
{% endprettify %}
#### Common fix
@@ -808,12 +812,7 @@
fixing the spelling of the getter:
{% prettify dart %}
-class Point {
- final int x;
- final int y;
- Point(this.x, this.y);
- operator +(Point other) => Point(x + other.x, y + other.y);
-}
+int f(String s) => s.length;
{% endprettify %}
### undefined_identifier
@@ -893,6 +892,7 @@
class C {
m({int b}) {}
}
+
void f(C c) {
c.m([!a!]: 1);
}
@@ -907,6 +907,7 @@
class C {
m({int b}) {}
}
+
void f(C c) {
c.m(b: 1);
}
@@ -919,9 +920,11 @@
class C {
m({int b}) {}
}
+
class D extends C {
m({int a, int b}) {}
}
+
void f(C c) {
(c as D).m(a: 1);
}
@@ -933,6 +936,7 @@
class C {
m({int a, int b}) {}
}
+
void f(C c) {
c.m(a: 1);
}
@@ -1049,8 +1053,7 @@
{% prettify dart %}
import [!'dart:async'!];
-void main() {
-}
+void main() {}
{% endprettify %}
#### Common fixes
diff --git a/pkg/analyzer/tool/diagnostics/generate.dart b/pkg/analyzer/tool/diagnostics/generate.dart
index 0c7efa6..36b166e 100644
--- a/pkg/analyzer/tool/diagnostics/generate.dart
+++ b/pkg/analyzer/tool/diagnostics/generate.dart
@@ -10,9 +10,10 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
-import 'package:front_end/src/testing/package_root.dart' as package_root;
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 {
@@ -212,8 +213,8 @@
region is required to be a constant. The following locations are constant
contexts:
-* Everything inside a list, map or set literal that's prefixed by the keyword
- `const`. Example:
+* Everything inside a list, map or set literal that's prefixed by the
+ `const` keyword. Example:
```dart
var l = const [/*constant context*/];
@@ -225,7 +226,7 @@
var p = const Point(/*constant context*/);
```
-* The initializer for a variable that's prefixed by the keyword `const`.
+* The initializer for a variable that's prefixed by the `const` keyword.
Example:
```dart
diff --git a/pkg/analyzer/tool/experiments/generate.dart b/pkg/analyzer/tool/experiments/generate.dart
index 6527331..4846520 100644
--- a/pkg/analyzer/tool/experiments/generate.dart
+++ b/pkg/analyzer/tool/experiments/generate.dart
@@ -6,10 +6,11 @@
import 'package:analysis_tool/tools.dart';
import 'package:front_end/src/fasta/scanner/characters.dart' show $MINUS, $_;
-import 'package:front_end/src/testing/package_root.dart' as pkgRoot;
import 'package:path/path.dart';
import 'package:yaml/yaml.dart' show YamlMap, loadYaml;
+import '../../test/utils/package_root.dart' as pkgRoot;
+
main() async {
await GeneratedContent.generateAll(
normalize(join(pkgRoot.packageRoot, 'analyzer')), allTargets);
diff --git a/pkg/analyzer/tool/messages/generate.dart b/pkg/analyzer/tool/messages/generate.dart
index babac722..e35adc8 100644
--- a/pkg/analyzer/tool/messages/generate.dart
+++ b/pkg/analyzer/tool/messages/generate.dart
@@ -17,11 +17,12 @@
import 'package:analyzer/error/error.dart';
import 'package:analysis_tool/tools.dart';
import 'package:analyzer/src/dart/error/syntactic_errors.dart';
-import 'package:front_end/src/testing/package_root.dart' as pkgRoot;
import 'package:front_end/src/fasta/scanner.dart';
import 'package:path/path.dart';
import 'package:yaml/yaml.dart' show loadYaml;
+import '../../test/utils/package_root.dart' as pkgRoot;
+
main() async {
String analyzerPkgPath = normalize(join(pkgRoot.packageRoot, 'analyzer'));
String frontEndPkgPath = normalize(join(pkgRoot.packageRoot, 'front_end'));
diff --git a/pkg/analyzer/tool/summary/check_test.dart b/pkg/analyzer/tool/summary/check_test.dart
index af669fb..6c4e635 100644
--- a/pkg/analyzer/tool/summary/check_test.dart
+++ b/pkg/analyzer/tool/summary/check_test.dart
@@ -3,9 +3,9 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_tool/tools.dart';
-import 'package:front_end/src/testing/package_root.dart' as package_root;
import 'package:path/path.dart';
+import '../../test/utils/package_root.dart' as package_root;
import 'generate.dart';
/**
diff --git a/pkg/analyzer/tool/summary/mini_ast.dart b/pkg/analyzer/tool/summary/mini_ast.dart
index d766655..57c11bd 100644
--- a/pkg/analyzer/tool/summary/mini_ast.dart
+++ b/pkg/analyzer/tool/summary/mini_ast.dart
@@ -216,7 +216,7 @@
@override
void endClassOrMixinBody(
- ClassKind kind, int memberCount, Token beginToken, Token endToken) {
+ DeclarationKind kind, int memberCount, Token beginToken, Token endToken) {
debugEvent("ClassOrMixinBody");
push(popList(memberCount,
new List<ClassMember>.filled(memberCount, null, growable: true)));
@@ -280,9 +280,9 @@
}
@override
- void endFactoryMethod(
+ void endClassFactoryMethod(
Token beginToken, Token factoryKeyword, Token endToken) {
- debugEvent("FactoryMethod");
+ debugEvent("ClassFactoryMethod");
pop(); // Body
pop(); // Type variables
String name = pop();
@@ -400,7 +400,7 @@
NullValue.Metadata);
}
- void endMethod(Token getOrSet, Token beginToken, Token beginParam,
+ void endClassMethod(Token getOrSet, Token beginToken, Token beginParam,
Token beginInitializers, Token endToken) {
debugEvent("Method");
pop(); // Body
diff --git a/pkg/analyzer_cli/lib/src/perf_report.dart b/pkg/analyzer_cli/lib/src/perf_report.dart
index 0463ddd..11178eb 100644
--- a/pkg/analyzer_cli/lib/src/perf_report.dart
+++ b/pkg/analyzer_cli/lib/src/perf_report.dart
@@ -7,7 +7,6 @@
import 'package:analyzer/src/generated/utilities_general.dart'
show PerformanceTag;
-import 'package:analyzer/src/task/api/model.dart' show AnalysisTask;
import 'package:analyzer_cli/src/error_formatter.dart';
import 'package:analyzer_cli/src/options.dart' show CommandLineOptions;
@@ -60,39 +59,16 @@
}
perfTagsJson['other'] = otherTime;
- // Generate task table.
- var taskRows = <_TaskRow>[];
- int totalTaskTime = 0;
- for (var key in AnalysisTask.stopwatchMap.keys) {
- var time = AnalysisTask.stopwatchMap[key].elapsedMilliseconds;
- if (time == 0) continue;
- totalTaskTime += time;
- var count = AnalysisTask.countMap[key];
- taskRows.add(new _TaskRow(key.toString(), time, count));
- }
- taskRows.sort((a, b) => b.time.compareTo(a.time));
-
var reportJson = <String, dynamic>{
'perfReportVersion': 0,
'platform': platformJson,
'options': optionsJson,
'totalElapsedTime': totalTime,
- 'totalTaskTime': totalTaskTime,
'analyzedFiles': analyzedFileCount,
'generatedDiagnostics': stats.unfilteredCount,
'reportedDiagnostics': stats.filteredCount,
'performanceTags': perfTagsJson,
- 'tasks': taskRows.map((r) => r.toJson()).toList(),
};
return _JSON.convert(reportJson);
}
-
-class _TaskRow {
- final String name;
- final int time;
- final int count;
- _TaskRow(this.name, this.time, this.count);
-
- Map toJson() => <String, dynamic>{'name': name, 'time': time, 'count': count};
-}
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 52a0e77..6e1993b 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
@@ -684,6 +684,41 @@
}
@override
+ void writeSetterDeclaration(String name,
+ {void bodyWriter(),
+ bool isStatic: false,
+ String nameGroupName,
+ DartType parameterType,
+ String parameterTypeGroupName}) {
+ if (isStatic) {
+ write(Keyword.STATIC.lexeme);
+ write(' ');
+ }
+ write(Keyword.SET.lexeme);
+ write(' ');
+ if (nameGroupName != null) {
+ addSimpleLinkedEdit(nameGroupName, name);
+ } else {
+ write(name);
+ }
+ write('(');
+ if (parameterType != null && !parameterType.isDynamic) {
+ if (writeType(parameterType, groupName: parameterTypeGroupName)) {
+ write(' ');
+ }
+ }
+ // TODO(brianwilkerson) The name of the setter is unlikely to be a good name
+ // for the parameter. We need to find a better name to produce here.
+ write(name);
+ write(') ');
+ if (bodyWriter == null) {
+ write('{}');
+ } else {
+ bodyWriter();
+ }
+ }
+
+ @override
bool writeType(DartType type,
{bool addSupertypeProposals: false,
String groupName,
diff --git a/pkg/analyzer_plugin/lib/utilities/change_builder/change_builder_dart.dart b/pkg/analyzer_plugin/lib/utilities/change_builder/change_builder_dart.dart
index 6f1d86c..7780d46 100644
--- a/pkg/analyzer_plugin/lib/utilities/change_builder/change_builder_dart.dart
+++ b/pkg/analyzer_plugin/lib/utilities/change_builder/change_builder_dart.dart
@@ -266,6 +266,24 @@
void writeReference(Element element);
/**
+ * Write the code for a declaration of a setter with the given [name]. If a
+ * [bodyWriter] is provided, it will be invoked to write the body of the
+ * setter. (The space between the name and the body will automatically be
+ * written.) If [isStatic] is `true`, then the declaration will be preceded
+ * by the `static` keyword. If a [nameGroupName] is provided, the name of the
+ * getter will be included in the linked edit group with that name. If a
+ * [parameterType] is provided, then it will be used as the type of the
+ * parameter. If a [parameterTypeGroupName] is provided, then if a parameter
+ * type was written it will be in the linked edit group with that name.
+ */
+ void writeSetterDeclaration(String name,
+ {void bodyWriter(),
+ bool isStatic: false,
+ String nameGroupName,
+ DartType parameterType,
+ String parameterTypeGroupName});
+
+ /**
* Write the code for a type annotation for the given [type]. If the [type] is
* either `null` or represents the type 'dynamic', then the behavior depends
* on whether a type is [required]. If [required] is `true`, then 'var' will
diff --git a/pkg/analyzer_plugin/lib/utilities/completion/inherited_reference_contributor.dart b/pkg/analyzer_plugin/lib/utilities/completion/inherited_reference_contributor.dart
index e3567fc..41d5c6a 100644
--- a/pkg/analyzer_plugin/lib/utilities/completion/inherited_reference_contributor.dart
+++ b/pkg/analyzer_plugin/lib/utilities/completion/inherited_reference_contributor.dart
@@ -5,7 +5,6 @@
import 'dart:async';
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/file_system/file_system.dart';
@@ -55,8 +54,8 @@
return;
}
containingLibrary = request.result.libraryElement;
- _computeSuggestionsForClass2(collector, target,
- resolutionMap.elementDeclaredByClassDeclaration(classDecl), optype);
+ _computeSuggestionsForClass2(
+ collector, target, classDecl.declaredElement, optype);
}
/**
@@ -85,7 +84,7 @@
if (classDecl == null || classDecl.declaredElement == null) {
return;
}
- classElement = resolutionMap.elementDeclaredByClassDeclaration(classDecl);
+ classElement = classDecl.declaredElement;
}
containingLibrary = request.result.libraryElement;
_computeSuggestionsForClass2(collector, target, classElement, optype,
diff --git a/pkg/analyzer_plugin/test/plugin/occurrences_mixin_test.dart b/pkg/analyzer_plugin/test/plugin/occurrences_mixin_test.dart
index cf2b96f..9fcbad9 100644
--- a/pkg/analyzer_plugin/test/plugin/occurrences_mixin_test.dart
+++ b/pkg/analyzer_plugin/test/plugin/occurrences_mixin_test.dart
@@ -62,7 +62,7 @@
return;
}
}
- fail('No occurence named $elementName');
+ fail('No occurrence named $elementName');
}
validate('method', [10, 30]);
diff --git a/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart b/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
index abf151b..a0bfa57 100644
--- a/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
+++ b/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
@@ -6,14 +6,13 @@
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/analysis/driver.dart';
import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/testing/test_type_provider.dart';
+import 'package:analyzer/src/test_utilities/find_node.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_plugin/src/utilities/change_builder/change_builder_dart.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
@@ -914,8 +913,8 @@
CompilationUnit unit = (await driver.getResult(path))?.unit;
FunctionDeclaration f = unit.declarations[0] as FunctionDeclaration;
FormalParameterList parameters = f.functionExpression.parameters;
- Iterable<ParameterElement> elements = parameters.parameters
- .map(resolutionMap.elementDeclaredByFormalParameter);
+ Iterable<ParameterElement> elements =
+ parameters.parameters.map((p) => p.declaredElement);
DartChangeBuilderImpl builder = newBuilder();
await builder.addFileEdit(path, (FileEditBuilder builder) {
@@ -935,8 +934,8 @@
CompilationUnit unit = (await driver.getResult(path))?.unit;
FunctionDeclaration f = unit.declarations[0] as FunctionDeclaration;
FormalParameterList parameters = f.functionExpression.parameters;
- Iterable<ParameterElement> elements = parameters.parameters
- .map(resolutionMap.elementDeclaredByFormalParameter);
+ Iterable<ParameterElement> elements =
+ parameters.parameters.map((p) => p.declaredElement);
DartChangeBuilderImpl builder = newBuilder();
await builder.addFileEdit(path, (FileEditBuilder builder) {
@@ -956,8 +955,8 @@
CompilationUnit unit = (await driver.getResult(path))?.unit;
FunctionDeclaration f = unit.declarations[0] as FunctionDeclaration;
FormalParameterList parameters = f.functionExpression.parameters;
- Iterable<ParameterElement> elements = parameters.parameters
- .map(resolutionMap.elementDeclaredByFormalParameter);
+ Iterable<ParameterElement> elements =
+ parameters.parameters.map((p) => p.declaredElement);
DartChangeBuilderImpl builder = newBuilder();
await builder.addFileEdit(path, (FileEditBuilder builder) {
@@ -1112,6 +1111,91 @@
expect(edits[1].replacement, equalsIgnoringWhitespace('a'));
}
+ test_writeSetterDeclaration_bodyWriter() async {
+ String path = convertPath('/home/test/lib/test.dart');
+ String content = 'class A {}';
+ addSource(path, content);
+
+ DartChangeBuilderImpl builder = newBuilder();
+ await builder.addFileEdit(path, (FileEditBuilder builder) {
+ builder.addInsertion(content.length - 1, (EditBuilder builder) {
+ (builder as DartEditBuilder).writeSetterDeclaration('s',
+ bodyWriter: () {
+ builder.write('{/* TODO */}');
+ });
+ });
+ });
+ SourceEdit edit = getEdit(builder);
+ expect(edit.replacement, equalsIgnoringWhitespace('set s(s) {/* TODO */}'));
+ }
+
+ test_writeSetterDeclaration_isStatic() async {
+ String path = convertPath('/home/test/lib/test.dart');
+ String content = 'class A {}';
+ addSource(path, content);
+
+ DartChangeBuilderImpl builder = newBuilder();
+ await builder.addFileEdit(path, (FileEditBuilder builder) {
+ builder.addInsertion(content.length - 1, (EditBuilder builder) {
+ (builder as DartEditBuilder)
+ .writeSetterDeclaration('s', isStatic: true);
+ });
+ });
+ SourceEdit edit = getEdit(builder);
+ expect(edit.replacement, equalsIgnoringWhitespace('static set s(s) {}'));
+ }
+
+ test_writeSetterDeclaration_nameGroupName() async {
+ String path = convertPath('/home/test/lib/test.dart');
+ String content = 'class A {}';
+ addSource(path, content);
+
+ DartChangeBuilderImpl builder = newBuilder();
+ await builder.addFileEdit(path, (FileEditBuilder builder) {
+ builder.addInsertion(content.length - 1, (EditBuilder builder) {
+ (builder as DartEditBuilder)
+ .writeSetterDeclaration('s', nameGroupName: 'name');
+ });
+ });
+ SourceEdit edit = getEdit(builder);
+ expect(edit.replacement, equalsIgnoringWhitespace('set s(s) {}'));
+
+ List<LinkedEditGroup> linkedEditGroups =
+ builder.sourceChange.linkedEditGroups;
+ expect(linkedEditGroups, hasLength(1));
+ LinkedEditGroup group = linkedEditGroups[0];
+ expect(group.length, 1);
+ expect(group.positions, hasLength(1));
+ Position position = group.positions[0];
+ expect(position.offset, equals(13));
+ }
+
+ test_writeSetterDeclaration_parameterType() async {
+ String path = convertPath('/home/test/lib/test.dart');
+ String content = 'class A {} class B {}';
+ addSource(path, content);
+ DartType typeA = await _getType(path, 'A');
+
+ DartChangeBuilderImpl builder = newBuilder();
+ await builder.addFileEdit(path, (FileEditBuilder builder) {
+ builder.addInsertion(content.length - 1, (EditBuilder builder) {
+ (builder as DartEditBuilder).writeSetterDeclaration('s',
+ parameterType: typeA, parameterTypeGroupName: 'returnType');
+ });
+ });
+ SourceEdit edit = getEdit(builder);
+ expect(edit.replacement, equalsIgnoringWhitespace('set s(A s) {}'));
+
+ List<LinkedEditGroup> linkedEditGroups =
+ builder.sourceChange.linkedEditGroups;
+ expect(linkedEditGroups, hasLength(1));
+ LinkedEditGroup group = linkedEditGroups[0];
+ expect(group.length, 1);
+ expect(group.positions, hasLength(1));
+ Position position = group.positions[0];
+ expect(position.offset, equals(26));
+ }
+
test_writeType_dynamic() async {
String path = convertPath('/home/test/lib/test.dart');
String content = 'class A {}';
@@ -1121,11 +1205,8 @@
DartChangeBuilderImpl builder = newBuilder();
await builder.addFileEdit(path, (FileEditBuilder builder) {
builder.addInsertion(content.length - 1, (EditBuilder builder) {
- (builder as DartEditBuilder).writeType(resolutionMap
- .elementDeclaredByCompilationUnit(unit)
- .context
- .typeProvider
- .dynamicType);
+ var typeProvider = unit.declaredElement.context.typeProvider;
+ (builder as DartEditBuilder).writeType(typeProvider.dynamicType);
});
});
SourceEdit edit = getEdit(builder);
@@ -1332,13 +1413,9 @@
DartChangeBuilderImpl builder = newBuilder();
await builder.addFileEdit(path, (FileEditBuilder builder) {
builder.addInsertion(content.length - 1, (EditBuilder builder) {
- (builder as DartEditBuilder).writeType(
- resolutionMap
- .elementDeclaredByCompilationUnit(unit)
- .context
- .typeProvider
- .dynamicType,
- required: true);
+ var typeProvider = unit.declaredElement.context.typeProvider;
+ (builder as DartEditBuilder)
+ .writeType(typeProvider.dynamicType, required: true);
});
});
SourceEdit edit = getEdit(builder);
@@ -1503,25 +1580,18 @@
@reflectiveTest
class DartFileEditBuilderImplTest extends AbstractContextTest
with DartChangeBuilderMixin {
- TypeProvider get typeProvider {
- return new TestTypeProvider(null, driver);
- }
-
test_convertFunctionFromSyncToAsync_closure() async {
String path = convertPath('/home/test/lib/test.dart');
addSource(path, '''var f = () {}''');
- CompilationUnit unit = (await driver.getResult(path))?.unit;
- TopLevelVariableDeclaration variable =
- unit.declarations[0] as TopLevelVariableDeclaration;
- FunctionBody body =
- (variable.variables.variables[0].initializer as FunctionExpression)
- .body;
+ var resolvedUnit = await driver.getResult(path);
+ var findNode = FindNode(resolvedUnit.content, resolvedUnit.unit);
+ var body = findNode.functionBody('{}');
DartChangeBuilderImpl builder = newBuilder();
await builder.addFileEdit(path, (FileEditBuilder builder) {
(builder as DartFileEditBuilder)
- .convertFunctionFromSyncToAsync(body, typeProvider);
+ .convertFunctionFromSyncToAsync(body, resolvedUnit.typeProvider);
});
List<SourceEdit> edits = getEdits(builder);
expect(edits, hasLength(1));
@@ -1532,14 +1602,14 @@
String path = convertPath('/home/test/lib/test.dart');
addSource(path, 'String f() {}');
- CompilationUnit unit = (await driver.getResult(path))?.unit;
- FunctionDeclaration function = unit.declarations[0] as FunctionDeclaration;
- FunctionBody body = function.functionExpression.body;
+ var resolvedUnit = await driver.getResult(path);
+ var findNode = FindNode(resolvedUnit.content, resolvedUnit.unit);
+ var body = findNode.functionBody('{}');
DartChangeBuilderImpl builder = newBuilder();
await builder.addFileEdit(path, (FileEditBuilder builder) {
(builder as DartFileEditBuilder)
- .convertFunctionFromSyncToAsync(body, typeProvider);
+ .convertFunctionFromSyncToAsync(body, resolvedUnit.typeProvider);
});
List<SourceEdit> edits = getEdits(builder);
expect(edits, hasLength(2));
@@ -1663,14 +1733,14 @@
String path = convertPath('/home/test/lib/test.dart');
addSource(path, 'String f() {}');
- CompilationUnit unit = (await driver.getResult(path))?.unit;
- FunctionDeclaration function = unit.declarations[0] as FunctionDeclaration;
- TypeAnnotation type = function.returnType;
+ var resolvedUnit = await driver.getResult(path);
+ var findNode = FindNode(resolvedUnit.content, resolvedUnit.unit);
+ var type = findNode.typeAnnotation('String');
DartChangeBuilderImpl builder = newBuilder();
await builder.addFileEdit(path, (FileEditBuilder builder) {
(builder as DartFileEditBuilder)
- .replaceTypeWithFuture(type, typeProvider);
+ .replaceTypeWithFuture(type, resolvedUnit.typeProvider);
});
List<SourceEdit> edits = getEdits(builder);
expect(edits, hasLength(1));
diff --git a/pkg/front_end/lib/src/testing/package_root.dart b/pkg/analyzer_plugin/test/utils/package_root.dart
similarity index 100%
copy from pkg/front_end/lib/src/testing/package_root.dart
copy to pkg/analyzer_plugin/test/utils/package_root.dart
diff --git a/pkg/analyzer_plugin/test/verify_tests_test.dart b/pkg/analyzer_plugin/test/verify_tests_test.dart
index 4aa0876..90f2856 100644
--- a/pkg/analyzer_plugin/test/verify_tests_test.dart
+++ b/pkg/analyzer_plugin/test/verify_tests_test.dart
@@ -9,10 +9,11 @@
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:front_end/src/testing/package_root.dart' as package_root;
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);
diff --git a/pkg/compiler/lib/src/common/names.dart b/pkg/compiler/lib/src/common/names.dart
index d567451..21975bf 100644
--- a/pkg/compiler/lib/src/common/names.dart
+++ b/pkg/compiler/lib/src/common/names.dart
@@ -250,6 +250,9 @@
static final Uri dart__js_embedded_names =
new Uri(scheme: 'dart', path: '_js_embedded_names');
+ /// The URI for 'dart:js'.
+ static final Uri dart_js = Uri(scheme: 'dart', path: 'js');
+
/// The URI for 'package:js'.
static final Uri package_js = new Uri(scheme: 'package', path: 'js/js.dart');
diff --git a/pkg/compiler/lib/src/common_elements.dart b/pkg/compiler/lib/src/common_elements.dart
index 3dab917..e118229 100644
--- a/pkg/compiler/lib/src/common_elements.dart
+++ b/pkg/compiler/lib/src/common_elements.dart
@@ -105,6 +105,12 @@
/// The dart:_internal library.
LibraryEntity get internalLibrary;
+ /// The dart:js library.
+ LibraryEntity get dartJsLibrary;
+
+ /// The package:js library.
+ LibraryEntity get packageJsLibrary;
+
/// The `NativeTypedData` class from dart:typed_data.
ClassEntity get typedDataClass;
@@ -541,12 +547,14 @@
ClassEntity getDefaultSuperclass(
ClassEntity cls, NativeBasicData nativeBasicData);
+
+ // From package:js
+ FunctionEntity get jsAllowInterop;
}
abstract class KCommonElements implements CommonElements {
// From package:js
ClassEntity get jsAnnotationClass;
-
ClassEntity get jsAnonymousClass;
ClassEntity get pragmaClass;
@@ -783,6 +791,16 @@
LibraryEntity get internalLibrary => _internalLibrary ??=
_env.lookupLibrary(Uris.dart__internal, required: true);
+ LibraryEntity _dartJsLibrary;
+ @override
+ LibraryEntity get dartJsLibrary =>
+ _dartJsLibrary ??= _env.lookupLibrary(Uris.dart_js);
+
+ LibraryEntity _packageJsLibrary;
+ @override
+ LibraryEntity get packageJsLibrary =>
+ _packageJsLibrary ??= _env.lookupLibrary(Uris.package_js);
+
ClassEntity _typedDataClass;
@override
ClassEntity get typedDataClass =>
@@ -1429,28 +1447,22 @@
ClassEntity get jsConstClass =>
_jsConstClass ??= _findClass(foreignLibrary, 'JS_CONST');
+ // From dart:js
+ FunctionEntity _jsAllowInterop;
+ @override
+ FunctionEntity get jsAllowInterop => _jsAllowInterop ??=
+ _findLibraryMember(dartJsLibrary, 'allowInterop', required: false);
+
// From package:js
ClassEntity _jsAnnotationClass;
@override
- ClassEntity get jsAnnotationClass {
- if (_jsAnnotationClass == null) {
- LibraryEntity library = _env.lookupLibrary(Uris.package_js);
- if (library == null) return null;
- _jsAnnotationClass = _findClass(library, 'JS');
- }
- return _jsAnnotationClass;
- }
+ ClassEntity get jsAnnotationClass => _jsAnnotationClass ??=
+ _findClass(packageJsLibrary, 'JS', required: false);
ClassEntity _jsAnonymousClass;
@override
- ClassEntity get jsAnonymousClass {
- if (_jsAnonymousClass == null) {
- LibraryEntity library = _env.lookupLibrary(Uris.package_js);
- if (library == null) return null;
- _jsAnonymousClass = _findClass(library, '_Anonymous');
- }
- return _jsAnonymousClass;
- }
+ ClassEntity get jsAnonymousClass => _jsAnonymousClass ??=
+ _findClass(packageJsLibrary, '_Anonymous', required: false);
@override
FunctionEntity findHelperFunction(String name) => _findHelperFunction(name);
diff --git a/pkg/compiler/lib/src/elements/types.dart b/pkg/compiler/lib/src/elements/types.dart
index 062985a..69425c5 100644
--- a/pkg/compiler/lib/src/elements/types.dart
+++ b/pkg/compiler/lib/src/elements/types.dart
@@ -84,7 +84,7 @@
/// Is `true` if this type is the 'Object' type defined in 'dart:core'.
bool get isObject => false;
- /// Applies [f] to each occurence of a [TypeVariableType] within this
+ /// Applies [f] to each occurrence of a [TypeVariableType] within this
/// type. This excludes function type variables, whether free or bound.
void forEachTypeVariable(f(TypeVariableType variable)) {}
diff --git a/pkg/compiler/lib/src/ir/closure.dart b/pkg/compiler/lib/src/ir/closure.dart
index 102ac3e..a1c9773 100644
--- a/pkg/compiler/lib/src/ir/closure.dart
+++ b/pkg/compiler/lib/src/ir/closure.dart
@@ -392,7 +392,7 @@
this.type, this.context, this.kind, this.typeDeclaration);
@override
- accept(ir.Visitor v) {
+ R accept<R>(ir.Visitor<R> v) {
throw new UnsupportedError('TypeVariableTypeWithContext.accept');
}
diff --git a/pkg/compiler/lib/src/ir/constants.dart b/pkg/compiler/lib/src/ir/constants.dart
index 46f1e9e..958c1ce 100644
--- a/pkg/compiler/lib/src/ir/constants.dart
+++ b/pkg/compiler/lib/src/ir/constants.dart
@@ -168,7 +168,7 @@
}
@override
- accept(ir.TreeVisitor v) {
+ R accept<R>(ir.TreeVisitor<R> v) {
throw new UnsupportedError("ConstantReference.accept");
}
diff --git a/pkg/compiler/lib/src/js/rewrite_async.dart b/pkg/compiler/lib/src/js/rewrite_async.dart
index 01cad9d..60e8c84 100644
--- a/pkg/compiler/lib/src/js/rewrite_async.dart
+++ b/pkg/compiler/lib/src/js/rewrite_async.dart
@@ -509,7 +509,7 @@
/// [fn] in that place.
withExpressions(List<js.Expression> nodes, fn(List<js.Expression> results)) {
int oldTempVarIndex = currentTempVarIndex;
- // Find last occurence of a 'transform' expression in [nodes].
+ // Find last occurrence of a 'transform' expression in [nodes].
// All expressions before that must be stored in temp-vars.
int lastTransformIndex = 0;
for (int i = nodes.length - 1; i >= 0; --i) {
diff --git a/pkg/compiler/lib/src/js_backend/backend_impact.dart b/pkg/compiler/lib/src/js_backend/backend_impact.dart
index 7742425..c755f95 100644
--- a/pkg/compiler/lib/src/js_backend/backend_impact.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_impact.dart
@@ -546,6 +546,16 @@
], fixed: true));
}
+ BackendImpact _allowInterop;
+
+ BackendImpact get allowInterop => _allowInterop ??= BackendImpact(
+ staticUses: [
+ _commonElements.jsAllowInterop,
+ ],
+ features: EnumSet<BackendFeature>.fromValues([
+ BackendFeature.needToInitializeIsolateAffinityTag,
+ ], fixed: true));
+
BackendImpact _numClasses;
BackendImpact get numClasses {
diff --git a/pkg/compiler/lib/src/js_backend/namer.dart b/pkg/compiler/lib/src/js_backend/namer.dart
index b944875..8b4374b 100644
--- a/pkg/compiler/lib/src/js_backend/namer.dart
+++ b/pkg/compiler/lib/src/js_backend/namer.dart
@@ -867,7 +867,10 @@
// apply. So we can directly grab a name.
if (element is JSEntity) {
return _disambiguateInternalMember(
- element, () => (element as JSEntity).declaredName);
+ element,
+ () => (element as JSEntity)
+ .declaredName
+ .replaceAll(_nonIdentifierRE, '_'));
}
// If the name of the field might clash with another field,
@@ -1257,7 +1260,7 @@
ClassEntity enclosingClass = element.enclosingClass;
return '${enclosingClass.name}_${element.name}';
}
- return element.name.replaceAll('+', '_');
+ return element.name.replaceAll(_nonIdentifierRE, '_');
}
String _proposeNameForLazyStaticGetter(MemberEntity element) {
diff --git a/pkg/compiler/lib/src/js_backend/native_data.dart b/pkg/compiler/lib/src/js_backend/native_data.dart
index cc517d2..1d7794a 100644
--- a/pkg/compiler/lib/src/js_backend/native_data.dart
+++ b/pkg/compiler/lib/src/js_backend/native_data.dart
@@ -46,6 +46,15 @@
/// Returns `true` if js interop features are used.
bool get isJsInteropUsed;
+ /// Returns `true` if `allowInterop()` is invoked.
+ bool get isAllowInteropUsed;
+
+ /// Marks `allowInterop()` as used.
+ ///
+ /// [isAllowInteropUsed] is initially false on the closed world, and is only
+ /// set during codegen enqueuing.
+ void registerAllowInterop();
+
/// Returns `true` if [element] is a JsInterop library.
bool isJsInteropLibrary(LibraryEntity element);
@@ -258,6 +267,7 @@
_closed = true;
return new NativeBasicDataImpl(
environment,
+ false,
nativeClassTagInfo,
jsInteropLibraries,
jsInteropClasses,
@@ -277,6 +287,8 @@
final ElementEnvironment _env;
+ bool _isAllowInteropUsed;
+
/// Tag info for native JavaScript classes names. See
/// [setNativeClassTagInfo].
final Map<ClassEntity, NativeClassTag> nativeClassTagInfo;
@@ -295,6 +307,7 @@
NativeBasicDataImpl(
this._env,
+ this._isAllowInteropUsed,
this.nativeClassTagInfo,
this.jsInteropLibraries,
this.jsInteropClasses,
@@ -329,13 +342,20 @@
jsInteropMembers[map.getMember(node)] = name;
});
- return new NativeBasicDataImpl(env, nativeClassTagInfo, jsInteropLibraries,
- jsInteropClasses, anonymousJsInteropClasses, jsInteropMembers);
+ return new NativeBasicDataImpl(
+ env,
+ false,
+ nativeClassTagInfo,
+ jsInteropLibraries,
+ jsInteropClasses,
+ anonymousJsInteropClasses,
+ jsInteropMembers);
}
factory NativeBasicDataImpl.readFromDataSource(
DataSource source, ElementEnvironment elementEnvironment) {
source.begin(tag);
+ bool isAllowInteropUsed = source.readBool();
Map<ClassEntity, NativeClassTag> nativeClassTagInfo =
source.readClassMap(() {
List<String> names = source.readStrings();
@@ -352,6 +372,7 @@
source.end(tag);
return new NativeBasicDataImpl(
elementEnvironment,
+ isAllowInteropUsed,
nativeClassTagInfo,
jsInteropLibraries,
jsInteropClasses,
@@ -362,6 +383,7 @@
@override
void writeToDataSink(DataSink sink) {
sink.begin(tag);
+ sink.writeBool(isAllowInteropUsed);
sink.writeClassMap(nativeClassTagInfo, (NativeClassTag tag) {
sink.writeStrings(tag.names);
sink.writeBool(tag.isNonLeaf);
@@ -375,6 +397,14 @@
}
@override
+ bool get isAllowInteropUsed => _isAllowInteropUsed;
+
+ @override
+ void registerAllowInterop() {
+ _isAllowInteropUsed = true;
+ }
+
+ @override
bool isNativeClass(ClassEntity element) {
if (isJsInteropClass(element)) return true;
return nativeClassTagInfo.containsKey(element);
@@ -622,6 +652,19 @@
}
@override
+ bool get _isAllowInteropUsed => _nativeBasicData._isAllowInteropUsed;
+
+ @override
+ set _isAllowInteropUsed(bool value) =>
+ _nativeBasicData._isAllowInteropUsed = value;
+
+ @override
+ bool get isAllowInteropUsed => _nativeBasicData.isAllowInteropUsed;
+
+ @override
+ void registerAllowInterop() => _nativeBasicData.registerAllowInterop();
+
+ @override
Map<LibraryEntity, String> get jsInteropLibraries =>
_nativeBasicData.jsInteropLibraries;
diff --git a/pkg/compiler/lib/src/js_backend/resolution_listener.dart b/pkg/compiler/lib/src/js_backend/resolution_listener.dart
index a6be0ee..c781753 100644
--- a/pkg/compiler/lib/src/js_backend/resolution_listener.dart
+++ b/pkg/compiler/lib/src/js_backend/resolution_listener.dart
@@ -184,6 +184,12 @@
_backendUsage.isNoSuchMethodUsed = true;
}
+ if (_nativeData.isAllowInteropUsed) {
+ _backendUsage.processBackendImpact(_impacts.allowInterop);
+ enqueuer
+ .applyImpact(_impacts.allowInterop.createImpact(_elementEnvironment));
+ }
+
if (!enqueuer.queueIsEmpty) return false;
return true;
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
index e5a9ca3..704c07a 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
@@ -254,7 +254,8 @@
List<Holder> holders = _registry.holders.toList(growable: false);
bool needsNativeSupport =
- _nativeCodegenEnqueuer.hasInstantiatedNativeClasses;
+ _nativeCodegenEnqueuer.hasInstantiatedNativeClasses ||
+ _nativeData.isAllowInteropUsed;
assert(!needsNativeSupport || nativeClasses.isNotEmpty);
diff --git a/pkg/compiler/lib/src/js_model/js_world_builder.dart b/pkg/compiler/lib/src/js_model/js_world_builder.dart
index 5aa8407..1bf43b4 100644
--- a/pkg/compiler/lib/src/js_model/js_world_builder.dart
+++ b/pkg/compiler/lib/src/js_model/js_world_builder.dart
@@ -288,6 +288,7 @@
map.toBackendMemberMap(nativeBasicData.jsInteropMembers, identity);
return new NativeBasicDataImpl(
_elementEnvironment,
+ nativeBasicData.isAllowInteropUsed,
nativeClassTagInfo,
jsInteropLibraries,
jsInteropClasses,
diff --git a/pkg/compiler/lib/src/native/enqueue.dart b/pkg/compiler/lib/src/native/enqueue.dart
index 4552d00..766bfa0 100644
--- a/pkg/compiler/lib/src/native/enqueue.dart
+++ b/pkg/compiler/lib/src/native/enqueue.dart
@@ -112,6 +112,11 @@
_dartTypes.isSubtype(type,
_elementEnvironment.getRawType(_commonElements.jsArrayClass))) {
registerInstantiation(type);
+ } else if (_dartTypes.isSubtype(
+ type,
+ _elementEnvironment
+ .getRawType(_commonElements.jsJavaScriptObjectClass))) {
+ matchingClasses.add(type.element);
}
// TODO(johnniwinther): Improve spec string precision to handle type
// arguments and implements relations that preserve generics. Currently
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index c829130..40e7469 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -107,6 +107,7 @@
Map<fe.ExperimentalFlag, bool> languageExperiments = {};
/// `true` if CFE performs constant evaluation.
+ /// TODO(johnniwinther, sigmund): Remove this and associated dead code.
bool get useCFEConstants =>
languageExperiments[fe.ExperimentalFlag.constantUpdate2018];
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 7147b77..77b1dac 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -2079,6 +2079,10 @@
List<js.Expression> arguments = visitArguments(node.inputs, start: 0);
+ if (element == _commonElements.jsAllowInterop) {
+ _nativeData.registerAllowInterop();
+ }
+
if (element == _commonElements.checkConcurrentModificationError) {
// Manually inline the [checkConcurrentModificationError] function. This
// function is only called from a for-loop update. Ideally we would just
diff --git a/pkg/dart2native/bin/dart2aot.dart b/pkg/dart2native/bin/dart2aot.dart
new file mode 100644
index 0000000..b406184
--- /dev/null
+++ b/pkg/dart2native/bin/dart2aot.dart
@@ -0,0 +1,81 @@
+#!/usr/bin/env dart
+// Copyright (c) 2019, 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:args/args.dart';
+import 'package:path/path.dart';
+
+const clearLine = '\r\x1b[2K';
+
+void aot(String sourceFile, String snapshotFile, bool enableAsserts,
+ bool buildElf, bool tfa, bool noTfa, String packages, List<String> ds) {
+ if (!FileSystemEntity.isFileSync(sourceFile)) {
+ print('Error: $sourceFile is not a file');
+ return;
+ }
+
+ String genSnapshotOption = buildElf
+ ? '--snapshot-kind=app-aot-assembly'
+ : '--snapshot-kind=app-aot-blobs';
+ String genSnapshotFilename = buildElf
+ ? '--assembly=$snapshotFile.S'
+ : '--blobs_container_filename=$snapshotFile';
+
+ String snapDir = dirname(Platform.script.path);
+ String binDir = canonicalize(join(snapDir, '..'));
+ String sdkDir = canonicalize(join(binDir, '..'));
+ String dartCommand = join(binDir, 'dart');
+ String snapshot = join(snapDir, 'gen_kernel.dart.snapshot');
+
+ stdout.write('${clearLine}Generating AOT snapshot');
+ List<String> dartArgs = <String>[
+ snapshot,
+ '--platform',
+ '${sdkDir}//lib/_internal/vm_platform_strong.dill',
+ '--aot',
+ '-Ddart.vm.product=true',
+ if (tfa) '--tfa',
+ if (noTfa) '--no-tfa',
+ ...ds,
+ if (packages != null) ...['--packages', packages],
+ '-o',
+ '$snapshotFile.dill',
+ sourceFile
+ ];
+
+ var cmdResult = Process.runSync(dartCommand, dartArgs);
+ if (cmdResult.exitCode != 0) {
+ print('\nGenerating AOT snapshot failed\n');
+ print(cmdResult.stdout);
+ print(cmdResult.stderr);
+ return;
+ }
+
+ stdout.write("${clearLine}Generating AOT .dill");
+ String genSnapshotCommand = join(binDir, 'utils', 'gen_snapshot');
+ List<String> genSnapshotArgs = [
+ genSnapshotOption,
+ genSnapshotFilename,
+ if (enableAsserts) '--enable-asserts',
+ '$snapshotFile.dill'
+ ];
+ cmdResult = Process.runSync(genSnapshotCommand, genSnapshotArgs);
+ if (cmdResult.exitCode != 0) {
+ print('\nGenerating AOT .dill failed\n');
+ print(cmdResult.stdout);
+ print(cmdResult.stderr);
+ return;
+ }
+ stdout.write("${clearLine}Done.\n");
+ stdout.flush();
+}
+
+void setupAOTArgs(ArgParser parser) {
+ parser.addFlag('build-elf');
+ parser.addFlag('enable-asserts');
+ parser.addFlag('tfa');
+ parser.addFlag('no-tfa');
+ parser.addOption('packages');
+}
diff --git a/pkg/dart2native/bin/dart2native.dart b/pkg/dart2native/bin/dart2native.dart
new file mode 100644
index 0000000..ac9cf35
--- /dev/null
+++ b/pkg/dart2native/bin/dart2native.dart
@@ -0,0 +1,70 @@
+#!/usr/bin/env dart
+// Copyright (c) 2019, 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:args/args.dart';
+import 'dart2aot.dart';
+
+typedef void Command(ArgResults args, List<String> ds);
+
+void main(List<String> args) {
+ Map<String, Command> commands = <String, Command>{};
+ commands['aot'] = callAOT;
+
+ // Read -D args that the ArgParser can't handle.
+ List<String> ds = [];
+ args = filterDArgs(args, ds);
+
+ ArgParser parser = ArgParser();
+ parser.addFlag('help');
+ ArgParser aotParser = parser.addCommand('aot');
+ setupAOTArgs(aotParser);
+
+ ArgResults result = null;
+ try {
+ result = parser.parse(args);
+ } catch (ArgParserException) {
+ // We handle this case as result == null below.
+ }
+
+ if (result == null || result.command == null || result['help']) {
+ print('dart2native <command> <args>\n');
+ print(' command: ');
+ print(' aot - Compile script into one ahead of time dart snapshot');
+ return;
+ }
+
+ if (commands.containsKey(result.command.name)) {
+ commands[result.command.name](result.command, ds);
+ return;
+ }
+}
+
+void callAOT(ArgResults args, List<String> ds) {
+ List<String> rest = args.rest;
+ if (rest.length != 2) {
+ print(
+ 'Usage: dart2native aot [options] <dart-source-file> <dart-aot-file>\n');
+ print(
+ 'Dart AOT (ahead-of-time) compile Dart source code into native machine code.');
+ return;
+ }
+
+ aot(rest[0], rest[1], args['build-elf'], args['enable-asserts'], args['tfa'],
+ args['no-tfa'], args['packages'], ds);
+}
+
+List<String> filterDArgs(List<String> args, List<String> ds) {
+ List<String> result = <String>[];
+
+ args.forEach((String arg) {
+ if (!arg.startsWith('-D')) {
+ result.add(arg);
+ } else {
+ ds.add(arg);
+ }
+ });
+
+ return result;
+}
diff --git a/pkg/dart2native/pubspec.yaml b/pkg/dart2native/pubspec.yaml
new file mode 100644
index 0000000..be267fc
--- /dev/null
+++ b/pkg/dart2native/pubspec.yaml
@@ -0,0 +1,16 @@
+name: dart2native
+version: 0.0.1
+author: Dart Team <misc@dartlang.org>
+homepage: https://github.com/dart-lang/sdk/tree/master/pkg/aot
+
+
+# Add the bin/dart2native.dart script to the scripts pub installs.
+executables:
+ dart2native:
+
+dependencies:
+ args: ^1.4.0
+ path:
+
+dev_dependencies:
+
diff --git a/pkg/dartfix/lib/src/driver.dart b/pkg/dartfix/lib/src/driver.dart
index 3908b60..fa4c91a 100644
--- a/pkg/dartfix/lib/src/driver.dart
+++ b/pkg/dartfix/lib/src/driver.dart
@@ -32,11 +32,10 @@
Ansi get ansi => logger.ansi;
Future applyFixes() async {
- showDescriptions('Recommended changes', result.suggestions);
showDescriptions('Recommended changes that cannot be automatically applied',
result.otherSuggestions);
showDetails(result.details);
- if (result.suggestions.isEmpty) {
+ if (result.edits.isEmpty) {
logger.stdout('');
logger.stdout(result.otherSuggestions.isNotEmpty
? 'None of the recommended changes can be automatically applied.'
diff --git a/pkg/dev_compiler/lib/src/analyzer/code_generator.dart b/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
index f795cfb..6ae1c24 100644
--- a/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
@@ -8,7 +8,6 @@
import 'package:analyzer/dart/analysis/declared_variables.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/standard_ast_factory.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/ast/token.dart' show Token, TokenType;
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
@@ -300,9 +299,7 @@
}
if (compilationUnits.isNotEmpty) {
_constants = ConstFieldVisitor(types, declaredVariables,
- dummySource: resolutionMap
- .elementDeclaredByCompilationUnit(compilationUnits.first)
- .source);
+ dummySource: compilationUnits.first.declaredElement.source);
}
// Add implicit dart:core dependency so it is first.
@@ -2618,7 +2615,7 @@
}
fn.sourceInformation = _functionEnd(node);
- var element = resolutionMap.elementDeclaredByFunctionDeclaration(node);
+ var element = node.declaredElement;
var nameExpr = _emitTopLevelName(element);
body.add(js.statement('# = #', [
nameExpr,
@@ -3018,7 +3015,7 @@
/// inferred generic function instantiation.
js_ast.Expression _emitSimpleIdentifier(SimpleIdentifier node,
[PrefixedIdentifier prefix]) {
- var accessor = resolutionMap.staticElementForIdentifier(node);
+ var accessor = node.staticElement;
if (accessor == null) {
return _throwUnsafe('unresolved identifier: ' + (node.name ?? '<null>'));
}
@@ -3529,7 +3526,7 @@
return _badAssignment("Unimplemented: unknown name '$node'", node, right);
}
- var accessor = resolutionMap.staticElementForIdentifier(node);
+ var accessor = node.staticElement;
if (accessor == null) return unimplemented();
// Get the original declaring element. If we had a property accessor, this
@@ -4516,7 +4513,7 @@
@override
visitInstanceCreationExpression(InstanceCreationExpression node) {
- var element = resolutionMap.staticElementForConstructorReference(node);
+ var element = node.staticElement;
var constructor = node.constructorName;
if (node.isConst &&
element?.name == 'fromEnvironment' &&
@@ -5840,7 +5837,7 @@
/// Returns a [js_ast.Expression] for each [CollectionElement] in [nodes].
///
/// Visits all [nodes] in order and nested [CollectionElement]s depth first
- /// to produce [JS.Expresison]s intended to be used when outputing a
+ /// to produce [JS.Expression]s intended to be used when outputing a
/// collection literal.
///
/// [IfElement]s and [ForElement]s will be transformed into a spread of a
@@ -6747,9 +6744,8 @@
var prefix = targetIdentifier.staticElement as PrefixElement;
// The library the prefix is referring to must come from a deferred import.
- var containingLibrary = resolutionMap
- .elementDeclaredByCompilationUnit(target.root as CompilationUnit)
- .library;
+ var containingLibrary =
+ (target.root as CompilationUnit).declaredElement.library;
var imports = containingLibrary.getImportsWithPrefix(prefix);
return imports.length == 1 && imports[0].isDeferred;
}
diff --git a/pkg/dev_compiler/lib/src/analyzer/nullable_type_inference.dart b/pkg/dev_compiler/lib/src/analyzer/nullable_type_inference.dart
index ecb118f..4aa976d 100644
--- a/pkg/dev_compiler/lib/src/analyzer/nullable_type_inference.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/nullable_type_inference.dart
@@ -3,12 +3,13 @@
// BSD-style license that can be found in the LICENSE file.
import 'dart:collection';
+
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/ast/token.dart' show TokenType;
import 'package:analyzer/dart/ast/visitor.dart' show RecursiveAstVisitor;
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
+
import 'element_helpers.dart' show getStaticType, isInlineJS, findAnnotation;
import 'js_interop.dart' show isNotNullAnnotation, isNullCheckAnnotation;
import 'js_typerep.dart';
@@ -53,7 +54,7 @@
bool _isNonNullMethodInvocation(MethodInvocation expr) {
// TODO(vsm): This logic overlaps with the resolver.
// Where is the best place to put this?
- var e = resolutionMap.staticElementForIdentifier(expr.methodName);
+ var e = expr.methodName.staticElement;
if (e == null) return false;
if (isInlineJS(e)) {
// Fix types for JS builtin calls.
@@ -220,7 +221,7 @@
return _isNullable(expr.expression, localIsNullable);
}
if (expr is InstanceCreationExpression) {
- var e = resolutionMap.staticElementForConstructorReference(expr);
+ var e = expr.staticElement;
if (e == null) return true;
// Follow redirects.
diff --git a/pkg/dev_compiler/lib/src/kernel/command.dart b/pkg/dev_compiler/lib/src/kernel/command.dart
index 6606e51..bf38ecb 100644
--- a/pkg/dev_compiler/lib/src/kernel/command.dart
+++ b/pkg/dev_compiler/lib/src/kernel/command.dart
@@ -275,6 +275,11 @@
doneInputSummaries = List<Component>(summaryModules.length);
compilerState = await fe.initializeIncrementalCompiler(
oldCompilerState,
+ {
+ "trackWidgetCreation=$trackWidgetCreation",
+ "multiRootScheme=${fileSystem.markerScheme}",
+ "multiRootRoots=${fileSystem.roots}",
+ },
doneInputSummaries,
compileSdk,
sourcePathToUri(getSdkPath()),
@@ -377,8 +382,7 @@
outFiles.add(File(outPaths.first + '.txt').writeAsString(sb.toString()));
}
- var compiler = ProgramCompiler(
- component, result.classHierarchy, options, declaredVariables);
+ var compiler = ProgramCompiler(component, result.classHierarchy, options);
var jsModule = compiler.emitModule(
component, result.inputSummaries, inputSummaries, summaryModules);
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 0cd7d86..fd5a3de 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -62,7 +62,7 @@
/// Let variables collected for the given function.
List<js_ast.TemporaryId> _letVariables;
- final _constTable = js_ast.TemporaryId("CT");
+ final _constTable = _emitTemporaryId("CT");
// Constant getters used to populate the constant table.
final _constLazyAccessors = List<js_ast.Method>();
@@ -216,10 +216,10 @@
final NullableInference _nullableInference;
factory ProgramCompiler(Component component, ClassHierarchy hierarchy,
- SharedCompilerOptions options, Map<String, String> declaredVariables) {
+ SharedCompilerOptions options) {
var coreTypes = CoreTypes(component);
var types = TypeSchemaEnvironment(coreTypes, hierarchy);
- var constants = DevCompilerConstants(types, declaredVariables);
+ var constants = DevCompilerConstants();
var nativeTypes = NativeTypeSet(coreTypes, constants);
var jsTypeRep = JSTypeRep(types, hierarchy);
return ProgramCompiler._(coreTypes, coreTypes.index, nativeTypes, constants,
@@ -503,6 +503,12 @@
}
}
+ static js_ast.Identifier _emitIdentifier(String name) =>
+ js_ast.Identifier(escapeIdentifier(name));
+
+ static js_ast.TemporaryId _emitTemporaryId(String name) =>
+ js_ast.TemporaryId(escapeIdentifier(name));
+
js_ast.Statement _emitClassDeclaration(Class c) {
// Mixins are unrolled in _defineClass.
if (c.isAnonymousMixin) return null;
@@ -518,8 +524,8 @@
// https://github.com/dart-lang/sdk/issues/31003
var className = c.typeParameters.isNotEmpty
? (c == _jsArrayClass
- ? js_ast.Identifier(c.name)
- : js_ast.TemporaryId(getLocalClassName(c)))
+ ? _emitIdentifier(c.name)
+ : _emitTemporaryId(getLocalClassName(c)))
: _emitTopLevelName(c);
var savedClassProperties = _classProperties;
@@ -586,7 +592,7 @@
jsFormals,
_typeTable.discharge(formals),
body,
- className ?? js_ast.Identifier(name)
+ className ?? _emitIdentifier(name)
]);
var genericArgs = [
@@ -610,7 +616,7 @@
.toStatement();
}
var classExpr = js_ast.ClassExpression(
- js_ast.TemporaryId(getLocalClassName(c)), heritage, methods);
+ _emitTemporaryId(getLocalClassName(c)), heritage, methods);
return js.statement('# = #;', [className, classExpr]);
}
@@ -651,10 +657,10 @@
var instanceMethods = methods.where((m) => !m.isStatic).toList();
body.add(_emitClassStatement(c, className, heritage, staticMethods));
- var superclassId = js_ast.TemporaryId(getLocalClassName(c.superclass));
+ var superclassId = _emitTemporaryId(getLocalClassName(c.superclass));
var classId = className is js_ast.Identifier
? className
- : js_ast.TemporaryId(getLocalClassName(c));
+ : _emitTemporaryId(getLocalClassName(c));
var mixinMemberClass =
js_ast.ClassExpression(classId, superclassId, instanceMethods);
@@ -819,7 +825,7 @@
mixinBody.add(runtimeStatement('applyMixin(#, #)', [
classExpr,
js_ast.ClassExpression(
- js_ast.TemporaryId(getLocalClassName(c)), mixinClass, methods)
+ _emitTemporaryId(getLocalClassName(c)), mixinClass, methods)
]));
}
@@ -837,14 +843,14 @@
var m = mixins[i];
var mixinName =
getLocalClassName(superclass) + '_' + getLocalClassName(m.classNode);
- var mixinId = js_ast.TemporaryId(mixinName + '\$');
+ var mixinId = _emitTemporaryId(mixinName + '\$');
// Bind the mixin class to a name to workaround a V8 bug with es6 classes
// and anonymous function names.
// TODO(leafp:) Eliminate this once the bug is fixed:
// https://bugs.chromium.org/p/v8/issues/detail?id=7069
body.add(js.statement("const # = #", [
mixinId,
- js_ast.ClassExpression(js_ast.TemporaryId(mixinName), baseClass, [])
+ js_ast.ClassExpression(_emitTemporaryId(mixinName), baseClass, [])
]));
emitMixinConstructors(mixinId, m);
@@ -1098,7 +1104,7 @@
if (isClassSymbol == null) {
// TODO(jmesserly): we could export these symbols, if we want to mark
// implemented interfaces for user-defined classes.
- var id = js_ast.TemporaryId("_is_${getLocalClassName(c)}_default");
+ var id = _emitTemporaryId("_is_${getLocalClassName(c)}_default");
moduleItems.add(
js.statement('const # = Symbol(#);', [id, js.string(id.name, "'")]));
isClassSymbol = id;
@@ -1831,7 +1837,7 @@
js_ast.Method(
name,
js.fun('function(x) { return super.# = #; }',
- [name, _emitCast(js_ast.Identifier('x'), setterType)]),
+ [name, _emitCast(_emitIdentifier('x'), setterType)]),
isSetter: true),
js_ast.Method(name, js.fun('function() { return super.#; }', [name]),
isGetter: true)
@@ -1852,7 +1858,7 @@
var positionalParameters = function.positionalParameters;
for (var i = 0, n = positionalParameters.length; i < n; i++) {
var param = positionalParameters[i];
- var jsParam = js_ast.Identifier(param.name);
+ var jsParam = _emitIdentifier(param.name);
jsParams.add(jsParam);
if (isCovariantParameter(param) &&
@@ -1935,7 +1941,7 @@
var args =
field.isFinal ? [js_ast.Super(), name] : [js_ast.This(), virtualField];
- js_ast.Expression value = js_ast.Identifier('value');
+ js_ast.Expression value = _emitIdentifier('value');
if (!field.isFinal && isCovariantField(field)) {
value = _emitCast(value, field.type);
}
@@ -1969,7 +1975,7 @@
// Generate setter
if (!field.isFinal) {
- var value = js_ast.TemporaryId('value');
+ var value = _emitTemporaryId('value');
fn = js_ast.Fun([value], js.block('{ this.# = #; }', [name, value]));
method = js_ast.Method(_declareMemberName(field), fn, isSetter: true);
jsMethods.add(method);
@@ -2242,7 +2248,7 @@
var parts = runtimeName.split('.');
if (parts.length < 2) return propertyName(runtimeName);
- js_ast.Expression result = js_ast.Identifier(parts[0]);
+ js_ast.Expression result = _emitIdentifier(parts[0]);
for (int i = 1; i < parts.length; i++) {
result = js_ast.PropertyAccess(result, propertyName(parts[i]));
}
@@ -2449,7 +2455,7 @@
var nameExpr = _emitTopLevelName(p);
body.add(js.statement('# = #',
- [nameExpr, js_ast.NamedFunction(js_ast.TemporaryId(p.name.name), fn)]));
+ [nameExpr, js_ast.NamedFunction(_emitTemporaryId(p.name.name), fn)]));
// Function types of top-level/static functions are only needed when
// dart:mirrors is enabled.
// TODO(jmesserly): do we even need this for mirrors, since statics are not
@@ -2503,8 +2509,7 @@
}
/// Emits a Dart [type] into code.
- js_ast.Expression _emitType(DartType type) =>
- type.accept(this) as js_ast.Expression;
+ js_ast.Expression _emitType(DartType type) => type.accept(this);
js_ast.Expression _emitInvalidNode(Node node, [String message = '']) {
if (message.isNotEmpty) message += ' ';
@@ -2748,7 +2753,7 @@
_emitTypeParameter(type.parameter);
js_ast.Identifier _emitTypeParameter(TypeParameter t) =>
- js_ast.Identifier(getTypeParameterName(t));
+ _emitIdentifier(getTypeParameterName(t));
@override
js_ast.Expression visitTypedefType(TypedefType type) =>
@@ -2799,7 +2804,7 @@
List<js_ast.Identifier> _emitTypeFormals(List<TypeParameter> typeFormals) {
return typeFormals
- .map((t) => js_ast.Identifier(getTypeParameterName(t)))
+ .map((t) => _emitIdentifier(getTypeParameterName(t)))
.toList();
}
@@ -2813,7 +2818,7 @@
emitGeneratorFn(List<js_ast.Parameter> getParameters(js_ast.Block jsBody)) {
var savedController = _asyncStarController;
_asyncStarController = function.asyncMarker == AsyncMarker.AsyncStar
- ? js_ast.TemporaryId('stream')
+ ? _emitTemporaryId('stream')
: null;
js_ast.Expression gen;
@@ -2831,7 +2836,7 @@
gen = genFn;
if (name != null) {
gen = js_ast.NamedFunction(
- js_ast.TemporaryId(
+ _emitTemporaryId(
js_ast.friendlyNameForDartOperator[name] ?? name),
genFn);
}
@@ -3004,11 +3009,11 @@
}
for (var p in f.positionalParameters.take(f.requiredParameterCount)) {
- var jsParam = js_ast.Identifier(p.name);
+ var jsParam = _emitIdentifier(p.name);
initParameter(p, jsParam);
}
for (var p in f.positionalParameters.skip(f.requiredParameterCount)) {
- var jsParam = js_ast.Identifier(p.name);
+ var jsParam = _emitIdentifier(p.name);
var defaultValue = _defaultParamValue(p);
if (defaultValue != null) {
body.add(js.statement(
@@ -3085,7 +3090,7 @@
js_ast.Statement _visitStatement(Statement s) {
if (s == null) return null;
- var result = s.accept(this) as js_ast.Statement;
+ var result = s.accept(this);
// TODO(jmesserly): is the `is! Block` still necessary?
if (s is! Block) result.sourceInformation = _nodeStart(s);
@@ -3156,7 +3161,7 @@
if (e is ConstantExpression) {
return visitConstant(e.constant);
}
- var result = e.accept(this) as js_ast.Expression;
+ var result = e.accept(this);
result.sourceInformation ??= _nodeStart(e);
return result;
}
@@ -3483,7 +3488,7 @@
}
if (variableIsReferenced(node.variable.name, iterable)) {
- var temp = js_ast.TemporaryId('iter');
+ var temp = _emitTemporaryId('iter');
return js_ast.Block([
iterable.toVariableDeclaration(temp),
js_ast.ForOf(init, temp, body)
@@ -3519,7 +3524,7 @@
.firstWhere((p) => p.isFactory && p.name.name == '')),
[_visitExpression(node.iterable)]);
- var iter = js_ast.TemporaryId('iter');
+ var iter = _emitTemporaryId('iter');
return js.statement(
'{'
' let # = #;'
@@ -3552,7 +3557,7 @@
var cases = <js_ast.SwitchCase>[];
if (_inLabeledContinueSwitch) {
- var labelState = js_ast.TemporaryId("labelState");
+ var labelState = _emitTemporaryId("labelState");
// TODO(markzipan): Retrieve the real label name with source offsets
var labelName = 'SL${_switchLabelStates.length}';
_switchLabelStates[node] = _SwitchLabelState(labelName, labelState);
@@ -3859,9 +3864,9 @@
var name = v.name;
if (name == null || name.startsWith('#')) {
name = name == null ? 't${_tempVariables.length}' : name.substring(1);
- return _tempVariables.putIfAbsent(v, () => js_ast.TemporaryId(name));
+ return _tempVariables.putIfAbsent(v, () => _emitTemporaryId(name));
}
- return js_ast.Identifier(name);
+ return _emitIdentifier(name);
}
/// Emits the declaration of a variable.
@@ -4516,21 +4521,21 @@
: 'function() { return super[#]; }',
[jsName]);
- return js_ast.Method(js_ast.TemporaryId(name), fn,
+ return js_ast.Method(_emitTemporaryId(name), fn,
isGetter: !setter, isSetter: setter);
} else {
var function = member.function;
var params = [
..._emitTypeFormals(function.typeParameters),
for (var param in function.positionalParameters)
- js_ast.Identifier(param.name),
+ _emitIdentifier(param.name),
if (function.namedParameters.isNotEmpty) namedArgumentTemp,
];
var fn = js.fun(
'function(#) { return super[#](#); }', [params, jsName, params]);
name = js_ast.friendlyNameForDartOperator[name] ?? name;
- return js_ast.Method(js_ast.TemporaryId(name), fn);
+ return js_ast.Method(_emitTemporaryId(name), fn);
}
});
return js_ast.PropertyAccess(js_ast.This(), jsMethod.name);
@@ -4766,7 +4771,9 @@
@override
js_ast.Expression visitConstructorInvocation(ConstructorInvocation node) {
var ctor = node.target;
+ var ctorClass = ctor.enclosingClass;
var args = node.arguments;
+ if (isJSAnonymousType(ctorClass)) return _emitObjectLiteral(args);
var result = js_ast.New(_emitConstructorName(node.constructedType, ctor),
_emitArgumentList(args, types: false));
@@ -4919,73 +4926,19 @@
@override
js_ast.Expression visitListConcatenation(ListConcatenation node) {
// Only occurs inside unevaluated constants.
- List<js_ast.Expression> entries = [];
- _concatenate(Expression node) {
- if (node is ListConcatenation) {
- node.lists.forEach(_concatenate);
- } else {
- node.accept(this);
- if (node is ConstantExpression) {
- var list = node.constant as ListConstant;
- entries.addAll(list.entries.map(visitConstant));
- } else if (node is ListLiteral) {
- entries.addAll(node.expressions.map(_visitExpression));
- }
- }
- }
-
- node.lists.forEach(_concatenate);
- return _emitConstList(node.typeArgument, entries);
+ throw UnsupportedError("List concatenation");
}
@override
js_ast.Expression visitSetConcatenation(SetConcatenation node) {
// Only occurs inside unevaluated constants.
- List<js_ast.Expression> entries = [];
- _concatenate(Expression node) {
- if (node is SetConcatenation) {
- node.sets.forEach(_concatenate);
- } else {
- node.accept(this);
- if (node is ConstantExpression) {
- var set = node.constant as SetConstant;
- entries.addAll(set.entries.map(visitConstant));
- } else if (node is SetLiteral) {
- entries.addAll(node.expressions.map(_visitExpression));
- }
- }
- }
-
- node.sets.forEach(_concatenate);
- return _emitConstSet(node.typeArgument, entries);
+ throw UnsupportedError("Set concatenation");
}
@override
js_ast.Expression visitMapConcatenation(MapConcatenation node) {
// Only occurs inside unevaluated constants.
- List<js_ast.Expression> entries = [];
- _concatenate(Expression node) {
- if (node is MapConcatenation) {
- node.maps.forEach(_concatenate);
- } else {
- node.accept(this);
- if (node is ConstantExpression) {
- var map = node.constant as MapConstant;
- for (var entry in map.entries) {
- entries.add(visitConstant(entry.key));
- entries.add(visitConstant(entry.value));
- }
- } else if (node is MapLiteral) {
- for (var entry in node.entries) {
- entries.add(_visitExpression(entry.key));
- entries.add(_visitExpression(entry.value));
- }
- }
- }
- }
-
- node.maps.forEach(_concatenate);
- return _emitConstMap(node.keyType, node.valueType, entries);
+ throw UnsupportedError("Map concatenation");
}
@override
@@ -4995,6 +4948,12 @@
}
@override
+ js_ast.Expression visitFileUriExpression(FileUriExpression node) {
+ // Only occurs inside unevaluated constants.
+ throw UnsupportedError("File URI expression");
+ }
+
+ @override
js_ast.Expression visitIsExpression(IsExpression node) {
return _emitIsExpression(node.operand, node.type);
}
@@ -5355,7 +5314,7 @@
}
var constAliasString = "C${constAliasCache.length}";
var constAliasProperty = propertyName(constAliasString);
- var constAliasId = js_ast.TemporaryId(constAliasString);
+ var constAliasId = _emitTemporaryId(constAliasString);
var constAccessor =
js.call("# || #.#", [constAliasId, _constTable, constAliasProperty]);
constAliasCache[node] = constAccessor;
diff --git a/pkg/dev_compiler/lib/src/kernel/constants.dart b/pkg/dev_compiler/lib/src/kernel/constants.dart
index 9044034..2059f37 100644
--- a/pkg/dev_compiler/lib/src/kernel/constants.dart
+++ b/pkg/dev_compiler/lib/src/kernel/constants.dart
@@ -2,43 +2,25 @@
// 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.
-// TODO(askesc): We should not need to call the constant evaluator
-// explicitly once constant-update-2018 is shipped.
-import 'package:front_end/src/api_prototype/constant_evaluator.dart'
- show ConstantEvaluator, SimpleErrorReporter;
-
-import 'package:kernel/core_types.dart';
import 'package:kernel/kernel.dart';
import 'package:kernel/target/targets.dart';
-import 'package:kernel/type_environment.dart';
-import 'kernel_helpers.dart';
/// Implements constant evaluation for dev compiler:
///
/// [isConstant] determines if an expression is constant.
/// [evaluate] computes the value of a constant expression, if available.
class DevCompilerConstants {
- final _ConstantVisitor _visitor;
- final ConstantEvaluator _evaluator;
-
- DevCompilerConstants(
- TypeEnvironment types, Map<String, String> declaredVariables)
- : _visitor = _ConstantVisitor(types.coreTypes),
- _evaluator = ConstantEvaluator(const DevCompilerConstantsBackend(),
- declaredVariables, types, const _ErrorReporter());
+ DevCompilerConstants();
/// Determines if an expression is constant.
- bool isConstant(Expression e) => _visitor.isConstant(e);
+ bool isConstant(Expression e) => e is ConstantExpression;
/// Evaluates [e] to find its constant value, returning `null` if evaluation
/// failed, or if the constant was unavailable.
///
/// Returns [NullConstant] to represent the `null` value.
Constant evaluate(Expression e) {
- if (e == null) return null;
-
- Constant result = _evaluator.evaluate(e);
- return result is UnevaluatedConstant ? null : result;
+ return e is ConstantExpression ? e.constant : null;
}
/// If [node] is an annotation with a field named [name], returns that field's
@@ -60,7 +42,6 @@
///
/// Given the node for `@MyAnnotation('FooBar')` this will return `'FooBar'`.
Object getFieldValueFromAnnotation(Expression node, String name) {
- node = unwrapUnevaluatedConstant(node);
if (node is ConstantExpression) {
var constant = node.constant;
if (constant is InstanceConstant) {
@@ -97,7 +78,6 @@
}
Object _evaluateAnnotationArgument(Expression node) {
- node = unwrapUnevaluatedConstant(node);
if (node is ConstantExpression) {
var constant = node.constant;
if (constant is PrimitiveConstant) return constant.value;
@@ -112,88 +92,6 @@
}
}
-/// Finds constant expressions as defined in Dart language spec 4th ed,
-/// 16.1 Constants.
-class _ConstantVisitor extends ExpressionVisitor<bool> {
- final CoreTypes coreTypes;
- _ConstantVisitor(this.coreTypes);
-
- bool isConstant(Expression e) => e.accept(this) as bool;
-
- @override
- defaultExpression(node) => false;
- @override
- defaultBasicLiteral(node) => true;
- @override
- visitTypeLiteral(node) => true; // TODO(jmesserly): deferred libraries?
- @override
- visitSymbolLiteral(node) => true;
- @override
- visitListLiteral(node) => node.isConst;
- @override
- visitMapLiteral(node) => node.isConst;
- @override
- visitStaticInvocation(node) {
- return node.isConst ||
- node.target == coreTypes.identicalProcedure &&
- node.arguments.positional.every(isConstant) ||
- isFromEnvironmentInvocation(coreTypes, node) &&
- node.arguments.positional.every(isConstant) &&
- node.arguments.named.every((n) => isConstant(n.value));
- }
-
- @override
- visitDirectMethodInvocation(node) {
- return node.receiver is BasicLiteral &&
- isOperatorMethodName(node.name.name) &&
- node.arguments.positional.every((p) => p is BasicLiteral);
- }
-
- @override
- visitMethodInvocation(node) {
- return node.receiver is BasicLiteral &&
- isOperatorMethodName(node.name.name) &&
- node.arguments.positional.every((p) => p is BasicLiteral);
- }
-
- @override
- visitConstructorInvocation(node) => node.isConst;
- @override
- visitStringConcatenation(node) =>
- node.expressions.every((e) => e is BasicLiteral);
- @override
- visitStaticGet(node) {
- var target = node.target;
- return target is Procedure || target is Field && target.isConst;
- }
-
- @override
- visitVariableGet(node) => node.variable.isConst;
- @override
- visitNot(node) {
- var operand = node.operand;
- return operand is BoolLiteral ||
- operand is DirectMethodInvocation &&
- visitDirectMethodInvocation(operand) ||
- operand is MethodInvocation && visitMethodInvocation(operand);
- }
-
- @override
- visitLogicalExpression(node) =>
- node.left is BoolLiteral && node.right is BoolLiteral;
- @override
- visitConditionalExpression(node) =>
- node.condition is BoolLiteral &&
- node.then is BoolLiteral &&
- node.otherwise is BoolLiteral;
-
- @override
- visitLet(Let node) {
- var init = node.variable.initializer;
- return (init == null || isConstant(init)) && isConstant(node.body);
- }
-}
-
/// Implement the class for compiler specific behavior.
class DevCompilerConstantsBackend extends ConstantsBackend {
const DevCompilerConstantsBackend();
@@ -218,11 +116,3 @@
}
}
}
-
-class _ErrorReporter extends SimpleErrorReporter {
- const _ErrorReporter();
-
- // Ignore reported errors.
- @override
- reportMessage(Uri uri, int offset, String message) {}
-}
diff --git a/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart b/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
index 3b3b66a..45efb1c 100644
--- a/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
+++ b/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
@@ -17,11 +17,16 @@
return null;
}
-final Pattern _syntheticTypeCharacters = RegExp('[&^#.]');
+final Pattern _syntheticTypeCharacters = RegExp('[&^#.|]');
-String _escapeIdentifier(String identifier) {
+String escapeIdentifier(String identifier) {
// Remove the special characters used to encode mixin application class names
- // which are legal in Kernel, but not in JavaScript.
+ // and extension method / parameter names which are legal in Kernel, but not
+ // in JavaScript.
+ //
+ // Note, there is an implicit assumption here that we won't have
+ // collisions since everything is mapped to \$. That may work out fine given
+ // how these are sythesized, but may need to revisit.
return identifier?.replaceAll(_syntheticTypeCharacters, r'$');
}
@@ -32,13 +37,13 @@
///
/// In the current encoding, generic classes are generated in a function scope
/// which avoids name clashes of the escaped class name.
-String getLocalClassName(Class node) => _escapeIdentifier(node.name);
+String getLocalClassName(Class node) => escapeIdentifier(node.name);
/// Returns the escaped name for the type parameter [node].
///
/// In the current encoding, generic classes are generated in a function scope
/// which avoids name clashes of the escaped parameter name.
-String getTypeParameterName(TypeParameter node) => _escapeIdentifier(node.name);
+String getTypeParameterName(TypeParameter node) => escapeIdentifier(node.name);
String getTopLevelName(NamedNode n) {
if (n is Procedure) return n.name.name;
@@ -101,7 +106,6 @@
/// This function works regardless of whether the CFE is evaluating constants,
/// or whether the constant is a field reference (such as "anonymous" above).
Class getAnnotationClass(Expression node) {
- node = unwrapUnevaluatedConstant(node);
if (node is ConstantExpression) {
var constant = node.constant;
if (constant is InstanceConstant) return constant.classNode;
@@ -114,19 +118,6 @@
return null;
}
-Expression unwrapUnevaluatedConstant(Expression node) {
- // TODO(jmesserly): see if we can configure CFE to preseve the original
- // expression, rather than wrapping in an UnevaluatedConstant and then
- // a ConstantExpression.
- if (node is ConstantExpression) {
- var constant = node.constant;
- if (constant is UnevaluatedConstant) {
- return constant.expression;
- }
- }
- return node;
-}
-
/// Returns true if [name] is an operator method that is available on primitive
/// types (`int`, `double`, `num`, `String`, `bool`).
///
diff --git a/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart b/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
index 33242c9..07810f3 100644
--- a/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
+++ b/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
@@ -53,8 +53,7 @@
void exitFunction(FunctionNode fn) => _variableInference.exitFunction(fn);
/// Returns true if [expr] can be null.
- bool isNullable(Expression expr) =>
- expr != null ? expr.accept(this) as bool : false;
+ bool isNullable(Expression expr) => expr != null ? expr.accept(this) : false;
@override
defaultExpression(Expression node) => true;
@@ -230,7 +229,7 @@
@override
visitConstantExpression(ConstantExpression node) {
var c = node.constant;
- if (c is UnevaluatedConstant) return c.expression.accept(this) as bool;
+ if (c is UnevaluatedConstant) return c.expression.accept(this);
if (c is PrimitiveConstant) return c.value == null;
return false;
}
@@ -249,7 +248,6 @@
bool _isInternalAnnotationField(
Expression node, String fieldName, String className) {
- node = unwrapUnevaluatedConstant(node);
if (node is ConstantExpression) {
var constant = node.constant;
return constant is InstanceConstant &&
diff --git a/pkg/dev_compiler/test/sourcemap/sourcemaps_ddc_suite.dart b/pkg/dev_compiler/test/sourcemap/sourcemaps_ddc_suite.dart
index d8b4fa6..fbb7af4 100644
--- a/pkg/dev_compiler/test/sourcemap/sourcemaps_ddc_suite.dart
+++ b/pkg/dev_compiler/test/sourcemap/sourcemaps_ddc_suite.dart
@@ -89,4 +89,4 @@
}
void main(List<String> arguments) =>
- runMe(arguments, createContext, "testing.json");
+ runMe(arguments, createContext, configurationPath: "testing.json");
diff --git a/pkg/dev_compiler/test/sourcemap/sourcemaps_ddk_suite.dart b/pkg/dev_compiler/test/sourcemap/sourcemaps_ddk_suite.dart
index 2aced38..cec6887 100644
--- a/pkg/dev_compiler/test/sourcemap/sourcemaps_ddk_suite.dart
+++ b/pkg/dev_compiler/test/sourcemap/sourcemaps_ddk_suite.dart
@@ -105,4 +105,4 @@
}
void main(List<String> arguments) =>
- runMe(arguments, createContext, "testing.json");
+ runMe(arguments, createContext, configurationPath: "testing.json");
diff --git a/pkg/dev_compiler/test/sourcemap/stacktrace_ddc_suite.dart b/pkg/dev_compiler/test/sourcemap/stacktrace_ddc_suite.dart
index 0ed9dfb..b2ddfde 100644
--- a/pkg/dev_compiler/test/sourcemap/stacktrace_ddc_suite.dart
+++ b/pkg/dev_compiler/test/sourcemap/stacktrace_ddc_suite.dart
@@ -22,4 +22,4 @@
}
void main(List<String> arguments) =>
- runMe(arguments, createContext, "testing.json");
+ runMe(arguments, createContext, configurationPath: "testing.json");
diff --git a/pkg/dev_compiler/test/sourcemap/stacktrace_ddk_suite.dart b/pkg/dev_compiler/test/sourcemap/stacktrace_ddk_suite.dart
index 515007e..8a23a66 100644
--- a/pkg/dev_compiler/test/sourcemap/stacktrace_ddk_suite.dart
+++ b/pkg/dev_compiler/test/sourcemap/stacktrace_ddk_suite.dart
@@ -29,4 +29,4 @@
}
void main(List<String> arguments) =>
- runMe(arguments, createContext, "testing.json");
+ runMe(arguments, createContext, configurationPath: "testing.json");
diff --git a/pkg/dev_compiler/tool/ddb b/pkg/dev_compiler/tool/ddb
index 17d5704..ff8e482 100755
--- a/pkg/dev_compiler/tool/ddb
+++ b/pkg/dev_compiler/tool/ddb
@@ -52,7 +52,11 @@
defaultsTo: '9222')
..addMultiOption('enable-experiment',
help: 'Run with specified experiments enabled.')
- ..addOption('binary', abbr: 'b', help: 'Runtime binary path.');
+ ..addOption('binary', abbr: 'b', help: 'Runtime binary path.')
+ ..addOption('mode',
+ help: 'Option to (compile|run|all). Default is all (compile and run).',
+ allowed: ['compile', 'run', 'all'],
+ defaultsTo: 'all');
var options = parser.parse(args);
if (options['help']) {
@@ -73,6 +77,9 @@
var experiments = options['enable-experiment'] as List;
var summaries = options['summary'] as List;
var port = int.parse(options['port'] as String);
+ var mode = options['mode'] as String;
+ var compile = mode == 'compile' || mode == 'all';
+ var run = mode == 'run' || mode == 'all';
var entry = p.canonicalize(options.rest.first);
var libRoot = p.dirname(entry);
@@ -157,41 +164,44 @@
dartSdk, 'lib', '_internal', kernel ? 'ddc_sdk.dill' : 'ddc_sdk.sum');
ProcessResult result;
- var ddcArgs = [
- if (kernel) '--kernel',
- if (kernel && summarizeText)
- '--summarize-text',
- '--modules=$mod',
- '--dart-sdk-summary=$ddcSdk',
- // TODO(nshahan) Cleanup when we settle on using or removing library-root.
- if (!kernel)
- '--library-root=$libRoot',
- for (var summary in summaries) '--summary=$summary',
- for (var experiment in experiments) '--enable-experiment=$experiment',
- '-o',
- p.setExtension(entry, '.js'),
- entry
- ];
+ if (compile) {
+ var ddcArgs = [
+ if (kernel) '--kernel',
+ if (kernel && summarizeText)
+ '--summarize-text',
+ '--modules=$mod',
+ '--dart-sdk-summary=$ddcSdk',
+ // TODO(nshahan) Cleanup when we settle on using or removing library-root.
+ if (!kernel)
+ '--library-root=$libRoot',
+ for (var summary in summaries) '--summary=$summary',
+ for (var experiment in experiments) '--enable-experiment=$experiment',
+ '-o',
+ p.setExtension(entry, '.js'),
+ entry
+ ];
- result = runDdc('dartdevc', ddcArgs);
- await echoResult(result);
+ result = runDdc('dartdevc', ddcArgs);
+ await echoResult(result);
+ }
- if (chrome) {
- String chromeBinary;
- if (binary != null) {
- chromeBinary = binary;
- } else if (Platform.isWindows) {
- chromeBinary =
- 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe';
- } else if (Platform.isMacOS) {
- chromeBinary =
- '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
- } else {
- // Assume Linux
- chromeBinary = 'google-chrome';
- }
+ if (run) {
+ if (chrome) {
+ String chromeBinary;
+ if (binary != null) {
+ chromeBinary = binary;
+ } else if (Platform.isWindows) {
+ chromeBinary =
+ 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe';
+ } else if (Platform.isMacOS) {
+ chromeBinary =
+ '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
+ } else {
+ // Assume Linux
+ chromeBinary = 'google-chrome';
+ }
- var html = """
+ var html = '''
<script src='$requirePath/require.js'></script>
<script>
require.config({
@@ -207,72 +217,73 @@
app.$libname.main();
});
</script>
-""";
- var htmlFile = p.setExtension(entry, '.html');
- new File(htmlFile).writeAsStringSync(html);
- var tmp = p.join(Directory.systemTemp.path, 'ddc');
+''';
+ var htmlFile = p.setExtension(entry, '.html');
+ new File(htmlFile).writeAsStringSync(html);
+ var tmp = p.join(Directory.systemTemp.path, 'ddc');
- result = Process.runSync(chromeBinary, [
- '--auto-open-devtools-for-tabs',
- '--allow-file-access-from-files',
- '--remote-debugging-port=$port',
- '--user-data-dir=$tmp',
- htmlFile
- ]);
- } else if (node) {
- var nodePath = '$sdkJsPath:$libRoot';
- var runjs = '''
- let source_maps;
- try {
- source_maps = require('source-map-support');
- source_maps.install();
- } catch(e) {
- }
- let sdk = require(\"dart_sdk\");
- let main = require(\"./$basename\").$libname.main;
- try {
- sdk._isolate_helper.startRootIsolate(main, []);
- } catch(e) {
- if (!source_maps) {
- console.log('For Dart source maps: npm install source-map-support');
- }
- sdk.core.print(sdk.dart.stackTrace(e));
- process.exit(1);
- }
- ''';
- var nodeFile = p.setExtension(entry, '.run.js');
- new File(nodeFile).writeAsStringSync(runjs);
- var nodeBinary = binary ?? 'node';
- result = Process.runSync(
- nodeBinary, ['--inspect=localhost:$port', nodeFile],
- environment: {'NODE_PATH': nodePath});
- } else if (d8) {
- // Fix SDK import. `d8` doesn't let us set paths, so we need a full path
- // to the SDK.
-
- var jsFile = File(p.setExtension(entry, '.js'));
- var jsContents = jsFile.readAsStringSync();
- jsContents = jsContents.replaceFirst(
- "from 'dart_sdk.js'", "from '$sdkJsPath/dart_sdk.js'");
- jsFile.writeAsStringSync(jsContents);
-
- var runjs = '''
- import { dart, _isolate_helper } from '$sdkJsPath/dart_sdk.js';
- import { $libname } from '$basename.js';
- let main = $libname.main;
- try {
- _isolate_helper.startRootIsolate(() => {}, []);
- main();
- } catch(e) {
- console.error(e);
- }
- ''';
- var d8File = p.setExtension(entry, '.d8.js');
- new File(d8File).writeAsStringSync(runjs);
- var d8Binary = binary ?? p.join(dartCheckoutPath, _d8executable);
- result = Process.runSync(d8Binary, ['--module', d8File]);
+ result = Process.runSync(chromeBinary, [
+ '--auto-open-devtools-for-tabs',
+ '--allow-file-access-from-files',
+ '--remote-debugging-port=$port',
+ '--user-data-dir=$tmp',
+ htmlFile
+ ]);
+ } else if (node) {
+ var nodePath = '$sdkJsPath:$libRoot';
+ var runjs = '''
+let source_maps;
+try {
+ source_maps = require('source-map-support');
+ source_maps.install();
+} catch(e) {
+}
+let sdk = require(\"dart_sdk\");
+let main = require(\"./$basename\").$libname.main;
+try {
+ sdk._isolate_helper.startRootIsolate(main, []);
+} catch(e) {
+ if (!source_maps) {
+ console.log('For Dart source maps: npm install source-map-support');
}
- await echoResult(result);
+ sdk.core.print(sdk.dart.stackTrace(e));
+ process.exit(1);
+}
+''';
+ var nodeFile = p.setExtension(entry, '.run.js');
+ new File(nodeFile).writeAsStringSync(runjs);
+ var nodeBinary = binary ?? 'node';
+ result = Process.runSync(
+ nodeBinary, ['--inspect=localhost:$port', nodeFile],
+ environment: {'NODE_PATH': nodePath});
+ } else if (d8) {
+ // Fix SDK import. `d8` doesn't let us set paths, so we need a full path
+ // to the SDK.
+
+ var jsFile = File(p.setExtension(entry, '.js'));
+ var jsContents = jsFile.readAsStringSync();
+ jsContents = jsContents.replaceFirst(
+ "from 'dart_sdk.js'", "from '$sdkJsPath/dart_sdk.js'");
+ jsFile.writeAsStringSync(jsContents);
+
+ var runjs = '''
+import { dart, _isolate_helper } from '$sdkJsPath/dart_sdk.js';
+import { $libname } from '$basename.js';
+let main = $libname.main;
+try {
+ _isolate_helper.startRootIsolate(() => {}, []);
+ main();
+} catch(e) {
+ console.error(e);
+}
+''';
+ var d8File = p.setExtension(entry, '.d8.js');
+ new File(d8File).writeAsStringSync(runjs);
+ var d8Binary = binary ?? p.join(dartCheckoutPath, _d8executable);
+ result = Process.runSync(d8Binary, ['--module', d8File]);
+ }
+ await echoResult(result);
+ }
}
String get _d8executable {
diff --git a/pkg/dev_compiler/tool/kernel_sdk.dart b/pkg/dev_compiler/tool/kernel_sdk.dart
index 11e2a33..004097b 100755
--- a/pkg/dev_compiler/tool/kernel_sdk.dart
+++ b/pkg/dev_compiler/tool/kernel_sdk.dart
@@ -75,11 +75,9 @@
File(librarySpecPath)
.copySync(p.join(p.dirname(outputDir), p.basename(librarySpecPath)));
- var jsModule = ProgramCompiler(
- component,
- compilerResult.classHierarchy,
- SharedCompilerOptions(moduleName: 'dart_sdk'),
- {}).emitModule(component, [], [], {});
+ var jsModule = ProgramCompiler(component, compilerResult.classHierarchy,
+ SharedCompilerOptions(moduleName: 'dart_sdk'))
+ .emitModule(component, [], [], {});
var moduleFormats = {
'amd': ModuleFormat.amd,
'common': ModuleFormat.common,
diff --git a/pkg/expect/lib/expect.dart b/pkg/expect/lib/expect.dart
index df8bffa..954a653 100644
--- a/pkg/expect/lib/expect.dart
+++ b/pkg/expect/lib/expect.dart
@@ -85,12 +85,12 @@
* This finds the first point where two strings differ, and returns
* a text describing the difference.
*
- * For small strings (length less than 20) nothing is done, and null is
+ * For small strings (length less than 20) nothing is done, and "" is
* returned. Small strings can be compared visually, but for longer strings
* only a slice containing the first difference will be shown.
*/
static String _stringDifference(String expected, String actual) {
- if (expected.length < 20 && actual.length < 20) return null;
+ if (expected.length < 20 && actual.length < 20) return "";
for (int i = 0; i < expected.length && i < actual.length; i++) {
if (expected.codeUnitAt(i) != actual.codeUnitAt(i)) {
int start = i;
@@ -106,18 +106,18 @@
"Found: <$truncActual>";
}
}
- return null;
+ return "";
}
/**
* Checks whether the expected and actual values are equal (using `==`).
*/
- static void equals(var expected, var actual, [String reason = null]) {
+ static void equals(var expected, var actual, [String reason = ""]) {
if (expected == actual) return;
String msg = _getMessage(reason);
if (expected is String && actual is String) {
String stringDifference = _stringDifference(expected, actual);
- if (stringDifference != null) {
+ if (stringDifference.isNotEmpty) {
_fail("Expect.equals($stringDifference$msg) fails.");
}
_fail("Expect.equals(expected: <${_escapeString(expected)}>"
@@ -129,7 +129,7 @@
/**
* Checks whether the actual value is a bool and its value is true.
*/
- static void isTrue(var actual, [String reason = null]) {
+ static void isTrue(var actual, [String reason = ""]) {
if (_identical(actual, true)) return;
String msg = _getMessage(reason);
_fail("Expect.isTrue($actual$msg) fails.");
@@ -138,7 +138,7 @@
/**
* Checks whether the actual value is a bool and its value is false.
*/
- static void isFalse(var actual, [String reason = null]) {
+ static void isFalse(var actual, [String reason = ""]) {
if (_identical(actual, false)) return;
String msg = _getMessage(reason);
_fail("Expect.isFalse($actual$msg) fails.");
@@ -147,7 +147,7 @@
/**
* Checks whether [actual] is null.
*/
- static void isNull(actual, [String reason = null]) {
+ static void isNull(actual, [String reason = ""]) {
if (null == actual) return;
String msg = _getMessage(reason);
_fail("Expect.isNull(actual: <$actual>$msg) fails.");
@@ -156,7 +156,7 @@
/**
* Checks whether [actual] is not null.
*/
- static void isNotNull(actual, [String reason = null]) {
+ static void isNotNull(actual, [String reason = ""]) {
if (null != actual) return;
String msg = _getMessage(reason);
_fail("Expect.isNotNull(actual: <$actual>$msg) fails.");
@@ -166,7 +166,7 @@
* Checks whether the expected and actual values are identical
* (using `identical`).
*/
- static void identical(var expected, var actual, [String reason = null]) {
+ static void identical(var expected, var actual, [String reason = ""]) {
if (_identical(expected, actual)) return;
String msg = _getMessage(reason);
if (expected is String && actual is String) {
@@ -187,17 +187,20 @@
* That is, `objects[i]` is identical to objects with indices in
* `_findEquivalences(objects)[i]`.
*
- * Uses `null` for objects that are only identical to themselves.
+ * Uses `[]` for objects that are only identical to themselves.
*/
static List<List<int>> _findEquivalences(List<Object> objects) {
- var equivalences = new List<List<int>>(objects.length);
+ var equivalences = new List<List<int>>.generate(objects.length, (_) => []);
for (int i = 0; i < objects.length; i++) {
- if (equivalences[i] != null) continue;
+ if (equivalences[i].isNotEmpty) continue;
var o = objects[i];
for (int j = i + 1; j < objects.length; j++) {
- if (equivalences[j] != null) continue;
+ if (equivalences[j].isNotEmpty) continue;
if (_identical(o, objects[j])) {
- equivalences[j] = (equivalences[i] ??= <int>[i])..add(j);
+ if (equivalences[i].isEmpty) {
+ equivalences[i].add(i);
+ }
+ equivalences[j] = equivalences[i]..add(j);
}
}
}
@@ -211,7 +214,7 @@
buffer.write(separator);
separator = ",";
var equivalence = equivalences[i];
- if (equivalence == null) {
+ if (equivalence.isEmpty) {
buffer.write('_');
} else {
int first = equivalence[0];
@@ -223,12 +226,12 @@
}
}
- static void allIdentical(Iterable<Object> objects, [String reason]) {
+ static void allIdentical(List<Object> objects, [String reason = ""]) {
if (objects.length <= 1) return;
String msg = _getMessage(reason);
var equivalences = _findEquivalences(objects);
var first = equivalences[0];
- if (first != null && first.length == objects.length) return;
+ if (first.isNotEmpty && first.length == objects.length) return;
var buffer = new StringBuffer("Expect.allIdentical([");
_writeEquivalences(objects, equivalences, buffer);
buffer..write("]")..write(msg)..write(")");
@@ -239,7 +242,7 @@
* Checks whether the expected and actual values are *not* identical
* (using `identical`).
*/
- static void notIdentical(var unexpected, var actual, [String reason = null]) {
+ static void notIdentical(var unexpected, var actual, [String reason = ""]) {
if (!_identical(unexpected, actual)) return;
String msg = _getMessage(reason);
_fail("Expect.notIdentical(expected and actual: <$actual>$msg) fails.");
@@ -248,13 +251,13 @@
/**
* Checks that no two [objects] are `identical`.
*/
- static void allDistinct(List<Object> objects, [String reason = null]) {
+ static void allDistinct(List<Object> objects, [String reason = ""]) {
String msg = _getMessage(reason);
var equivalences = _findEquivalences(objects);
bool hasEquivalence = false;
for (int i = 0; i < equivalences.length; i++) {
- if (equivalences[i] != null) {
+ if (equivalences[i].isNotEmpty) {
hasEquivalence = true;
break;
}
@@ -278,8 +281,8 @@
* value 4 significant digits smaller than the value given for expected.
*/
static void approxEquals(num expected, num actual,
- [num tolerance = null, String reason = null]) {
- if (tolerance == null) {
+ [num tolerance = -1, String reason = ""]) {
+ if (tolerance < 0) {
tolerance = (expected / 1e4).abs();
}
// Note: use !( <= ) rather than > so we fail on NaNs
@@ -290,7 +293,7 @@
'tolerance:<$tolerance>$msg) fails');
}
- static void notEquals(unexpected, actual, [String reason = null]) {
+ static void notEquals(unexpected, actual, [String reason = ""]) {
if (unexpected != actual) return;
String msg = _getMessage(reason);
_fail("Expect.notEquals(unexpected: <$unexpected>, actual:<$actual>$msg) "
@@ -303,7 +306,7 @@
* used by the standard list implementation. It should also produce nicer
* error messages than just calling `Expect.equals(expected, actual)`.
*/
- static void listEquals(List expected, List actual, [String reason = null]) {
+ static void listEquals(List expected, List actual, [String reason = ""]) {
String msg = _getMessage(reason);
int n = (expected.length < actual.length) ? expected.length : actual.length;
for (int i = 0; i < n; i++) {
@@ -327,7 +330,7 @@
* the semantics of [Map.containsKey] to determine what "same" means. For
* each key, checks that the values in both maps are equal using `==`.
*/
- static void mapEquals(Map expected, Map actual, [String reason = null]) {
+ static void mapEquals(Map expected, Map actual, [String reason = ""]) {
String msg = _getMessage(reason);
// Make sure all of the values are present in both, and they match.
@@ -352,7 +355,7 @@
* this method shows where the mismatch starts and ends.
*/
static void stringEquals(String expected, String actual,
- [String reason = null]) {
+ [String reason = ""]) {
if (expected == actual) return;
String msg = _getMessage(reason);
@@ -435,7 +438,7 @@
* every element of [actual] is also in [expected].
*/
static void setEquals(Iterable expected, Iterable actual,
- [String reason = null]) {
+ [String reason = ""]) {
final missingSet = new Set.from(expected);
missingSet.removeAll(actual);
final extraSet = new Set.from(actual);
@@ -517,6 +520,8 @@
}
}
+ static bool _defaultCheck([dynamic e]) => true;
+
/**
* Calls the function [f] and verifies that it throws a `T`.
* The optional [check] function can provide additional validation
@@ -533,8 +538,13 @@
* exception is not caught by [Expect.throws]. The test is still considered
* failing.
*/
- static void throws<T>(void f(), [bool check(T error), String reason]) {
- String msg = reason == null ? "" : "($reason)";
+ static void throws<T>(void f(),
+ [bool check(T error) = _defaultCheck, String reason = ""]) {
+ // TODO(vsm): Make check nullable. Existing tests pass null to set
+ // a reason.
+ check = check ?? _defaultCheck;
+ reason = reason ?? "";
+ String msg = reason.isEmpty ? "" : "($reason)";
if (f is! Function()) {
// Only throws from executing the function body should count as throwing.
// The failure to even call `f` should throw outside the try/catch.
@@ -545,7 +555,7 @@
} on Object catch (e, s) {
// A test failure doesn't count as throwing.
if (e is ExpectException) rethrow;
- if (e is T && (check == null || check(e))) return;
+ if (e is T && check(e as dynamic)) return;
// Throws something unexpected.
String type = "";
if (T != dynamic && T != Object) {
@@ -557,45 +567,44 @@
_fail('Expect.throws$msg fails: Did not throw');
}
- static void throwsArgumentError(void f(), [String reason]) {
- Expect.throws(
- f, (error) => error is ArgumentError, reason ?? "ArgumentError");
+ static void throwsArgumentError(void f(), [String reason = "ArgumentError"]) {
+ Expect.throws(f, (error) => error is ArgumentError, reason);
}
- static void throwsAssertionError(void f(), [String reason]) {
- Expect.throws(
- f, (error) => error is AssertionError, reason ?? "AssertionError");
+ static void throwsAssertionError(void f(),
+ [String reason = "AssertionError"]) {
+ Expect.throws(f, (error) => error is AssertionError, reason);
}
- static void throwsCastError(void f(), [String reason]) {
- Expect.throws(f, (error) => error is CastError, reason ?? "CastError");
+ static void throwsCastError(void f(), [String reason = "CastError"]) {
+ Expect.throws(f, (error) => error is CastError, reason);
}
- static void throwsFormatException(void f(), [String reason]) {
- Expect.throws(
- f, (error) => error is FormatException, reason ?? "FormatException");
+ static void throwsFormatException(void f(),
+ [String reason = "FormatException"]) {
+ Expect.throws(f, (error) => error is FormatException, reason);
}
- static void throwsNoSuchMethodError(void f(), [String reason]) {
- Expect.throws(f, (error) => error is NoSuchMethodError,
- reason ?? "NoSuchMethodError");
+ static void throwsNoSuchMethodError(void f(),
+ [String reason = "NoSuchMethodError"]) {
+ Expect.throws(f, (error) => error is NoSuchMethodError, reason);
}
- static void throwsRangeError(void f(), [String reason]) {
- Expect.throws(f, (error) => error is RangeError, reason ?? "RangeError");
+ static void throwsRangeError(void f(), [String reason = "RangeError"]) {
+ Expect.throws(f, (error) => error is RangeError, reason);
}
- static void throwsStateError(void f(), [String reason]) {
- Expect.throws(f, (error) => error is StateError, reason ?? "StateError");
+ static void throwsStateError(void f(), [String reason = "StateError"]) {
+ Expect.throws(f, (error) => error is StateError, reason);
}
- static void throwsTypeError(void f(), [String reason]) {
- Expect.throws(f, (error) => error is TypeError, reason ?? "TypeError");
+ static void throwsTypeError(void f(), [String reason = "TypeError"]) {
+ Expect.throws(f, (error) => error is TypeError, reason);
}
- static void throwsUnsupportedError(void f(), [String reason]) {
- Expect.throws(
- f, (error) => error is UnsupportedError, reason ?? "UnsupportedError");
+ static void throwsUnsupportedError(void f(),
+ [String reason = "UnsupportedError"]) {
+ Expect.throws(f, (error) => error is UnsupportedError, reason);
}
/// Reports that there is an error in the test itself and not the code under
@@ -608,7 +617,7 @@
}
/// Checks that [object] has type [T].
- static void type<T>(Object object, [String reason]) {
+ static void type<T>(dynamic object, [String reason = ""]) {
if (object is T) return;
String msg = _getMessage(reason);
_fail("Expect.type($object is $T$msg) fails "
@@ -616,7 +625,7 @@
}
/// Checks that [object] does not have type [T].
- static void notType<T>(Object object, [String reason]) {
+ static void notType<T>(dynamic object, [String reason = ""]) {
if (object is! T) return;
String msg = _getMessage(reason);
_fail("Expect.type($object is! $T$msg) fails"
@@ -648,7 +657,7 @@
}
static String _getMessage(String reason) =>
- (reason == null) ? "" : ", '$reason'";
+ (reason.isEmpty) ? "" : ", '$reason'";
@alwaysThrows
static void _fail(String message) {
diff --git a/pkg/expect/lib/matchers_lite.dart b/pkg/expect/lib/matchers_lite.dart
index 004e37e..5b8d11e 100644
--- a/pkg/expect/lib/matchers_lite.dart
+++ b/pkg/expect/lib/matchers_lite.dart
@@ -18,7 +18,7 @@
typedef Matcher = void Function(Object actual);
-void expect(Object actual, Object expected) {
+void expect(dynamic actual, dynamic expected) {
if (expected is Matcher) {
expected(actual);
} else {
@@ -27,7 +27,8 @@
}
Matcher unorderedEquals(Iterable<Object> expected) {
- return (Object actual) => Expect.setEquals(expected, actual);
+ return (Object actual) =>
+ Expect.setEquals(expected, actual as Iterable<Object>);
}
fail(String message) {
@@ -40,7 +41,7 @@
Matcher equals(Object expected) {
if (expected is String) {
- return (Object actual) => Expect.stringEquals(expected, actual);
+ return (Object actual) => Expect.stringEquals(expected, actual as String);
} else if (expected is Iterable<Object>) {
return (dynamic actual) =>
Expect.listEquals(expected.toList(), actual.toList());
diff --git a/pkg/expect/lib/minitest.dart b/pkg/expect/lib/minitest.dart
index 8082bd5..350b6aa 100644
--- a/pkg/expect/lib/minitest.dart
+++ b/pkg/expect/lib/minitest.dart
@@ -90,11 +90,9 @@
void test(String description, body()) {
// TODO(rnystrom): Do something useful with the description.
for (var group in _groups) {
- if (group.setUpFunction != null) {
- var result = group.setUpFunction();
- if (result is Future) {
- Expect.testError("setUp() does not support asynchronous functions.");
- }
+ var result = group.setUpFunction();
+ if (result is Future) {
+ Expect.testError("setUp() does not support asynchronous functions.");
}
}
@@ -106,12 +104,9 @@
} finally {
for (var i = _groups.length - 1; i >= 0; i--) {
var group = _groups[i];
- if (group.tearDownFunction != null) {
- var result = group.tearDownFunction();
- if (result is Future) {
- Expect
- .testError("tearDown() does not support asynchronous functions.");
- }
+ var result = group.tearDownFunction();
+ if (result is Future) {
+ Expect.testError("tearDown() does not support asynchronous functions.");
}
}
}
@@ -119,17 +114,17 @@
void setUp(body()) {
// Can't define multiple setUps at the same level.
- assert(_groups.last.setUpFunction == null);
+ assert(_groups.last.setUpFunction == _defaultAction);
_groups.last.setUpFunction = body;
}
void tearDown(body()) {
// Can't define multiple tearDowns at the same level.
- assert(_groups.last.tearDownFunction == null);
+ assert(_groups.last.tearDownFunction == _defaultAction);
_groups.last.tearDownFunction = body;
}
-void expect(Object actual, Object expected, {String reason}) {
+void expect(Object actual, Object expected, {String reason = ""}) {
// TODO(rnystrom): Do something useful with reason.
if (expected is! _Expectation) {
expected = equals(expected);
@@ -152,10 +147,10 @@
});
Object unorderedEquals(Object value) => new _Expectation((actual) {
- Expect.setEquals(value, actual);
+ Expect.setEquals(value as Iterable, actual as Iterable);
});
-Object predicate(bool fn(Object value), [String description]) =>
+Object predicate(bool fn(Object value), [String description = ""]) =>
new _Expectation((actual) {
Expect.isTrue(fn(actual), description);
});
@@ -179,7 +174,7 @@
});
Object closeTo(num value, num tolerance) => new _Expectation((actual) {
- Expect.approxEquals(value, actual, tolerance);
+ Expect.approxEquals(value, actual as num, tolerance);
});
/// Succeeds if the actual value is any of the given strings. Unlike matcher's
@@ -192,13 +187,15 @@
fail("Expected $actual to be one of $expected.");
});
+_defaultAction() {}
+
/// One level of group() nesting to track an optional [setUp()] and [tearDown()]
/// function for the group.
///
/// There is also an implicit top level group.
class _Group {
- _Action setUpFunction;
- _Action tearDownFunction;
+ _Action setUpFunction = _defaultAction;
+ _Action tearDownFunction = _defaultAction;
}
/// A wrapper around an expectation function.
diff --git a/pkg/front_end/lib/src/api_prototype/compiler_options.dart b/pkg/front_end/lib/src/api_prototype/compiler_options.dart
index bd628d8..c2c76e5 100644
--- a/pkg/front_end/lib/src/api_prototype/compiler_options.dart
+++ b/pkg/front_end/lib/src/api_prototype/compiler_options.dart
@@ -4,6 +4,8 @@
library front_end.compiler_options;
+import 'package:kernel/ast.dart' as kernel show Library;
+
import 'package:kernel/target/targets.dart' show Target;
import 'diagnostic_message.dart' show DiagnosticMessageHandler;
@@ -215,6 +217,13 @@
/// Whether to write a file (e.g. a dill file) when reporting a crash.
bool writeFileOnCrashReport = true;
+
+ /// The current sdk version string, e.g. "2.6.0-edge.sha1hash".
+ /// For instance used for language versioning (specifying the maximum
+ /// version).
+ String currentSdkVersion = "${kernel.Library.defaultLanguageVersionMajor}"
+ "."
+ "${kernel.Library.defaultLanguageVersionMinor}";
}
/// Parse experimental flag arguments of the form 'flag' or 'no-flag' into a map
diff --git a/pkg/front_end/lib/src/api_unstable/bazel_worker.dart b/pkg/front_end/lib/src/api_unstable/bazel_worker.dart
index 1473017..68939cd 100644
--- a/pkg/front_end/lib/src/api_unstable/bazel_worker.dart
+++ b/pkg/front_end/lib/src/api_unstable/bazel_worker.dart
@@ -48,7 +48,7 @@
export 'compiler_state.dart' show InitializedCompilerState;
-import 'util.dart' show equalMaps;
+import 'util.dart' show equalMaps, equalSets;
/// Initializes the compiler for a modular build.
///
@@ -56,6 +56,7 @@
/// as necessary based on [workerInputDigests].
Future<InitializedCompilerState> initializeIncrementalCompiler(
InitializedCompilerState oldState,
+ Set<String> tags,
Uri sdkSummary,
Uri packagesFile,
Uri librariesSpecificationUri,
@@ -84,7 +85,8 @@
if (oldState == null ||
oldState.incrementalCompiler == null ||
oldState.incrementalCompiler.outlineOnly != outlineOnly ||
- !equalMaps(oldState.options.experimentalFlags, experimentalFlags)) {
+ !equalMaps(oldState.options.experimentalFlags, experimentalFlags) ||
+ !equalSets(oldState.tags, tags)) {
// No - or immediately not correct - previous state.
startOver = true;
@@ -115,7 +117,7 @@
..experimentalFlags = experimentalFlags;
processedOpts = new ProcessedOptions(options: options);
- cachedSdkInput = WorkerInputComponent(
+ cachedSdkInput = new WorkerInputComponent(
sdkDigest, await processedOpts.loadSdkSummary(null));
workerInputCache[sdkSummary] = cachedSdkInput;
@@ -193,7 +195,7 @@
if (summaryDigest == null) {
throw new StateError("Expected to get digest for $summary");
}
- WorkerInputComponent cachedInput = WorkerInputComponent(
+ WorkerInputComponent cachedInput = new WorkerInputComponent(
summaryDigest,
await processedOpts.loadComponent(
await fileSystem.entityForUri(summary).readAsBytes(), nameRoot,
@@ -212,6 +214,7 @@
return new InitializedCompilerState(options, processedOpts,
workerInputCache: workerInputCache,
incrementalCompiler: incrementalCompiler,
+ tags: tags,
libraryToInputDill: libraryToInputDill);
}
diff --git a/pkg/front_end/lib/src/api_unstable/compiler_state.dart b/pkg/front_end/lib/src/api_unstable/compiler_state.dart
index 57fdac4..0852c60 100644
--- a/pkg/front_end/lib/src/api_unstable/compiler_state.dart
+++ b/pkg/front_end/lib/src/api_unstable/compiler_state.dart
@@ -16,11 +16,13 @@
final ProcessedOptions processedOpts;
final Map<Uri, WorkerInputComponent> workerInputCache;
final IncrementalCompiler incrementalCompiler;
+ final Set<String> tags;
final Map<Uri, Uri> libraryToInputDill;
InitializedCompilerState(this.options, this.processedOpts,
{this.workerInputCache,
this.incrementalCompiler,
+ this.tags,
this.libraryToInputDill});
}
diff --git a/pkg/front_end/lib/src/api_unstable/ddc.dart b/pkg/front_end/lib/src/api_unstable/ddc.dart
index 547f79a..585c738 100644
--- a/pkg/front_end/lib/src/api_unstable/ddc.dart
+++ b/pkg/front_end/lib/src/api_unstable/ddc.dart
@@ -33,7 +33,7 @@
import 'compiler_state.dart'
show InitializedCompilerState, WorkerInputComponent, digestsEqual;
-import 'util.dart' show equalLists, equalMaps;
+import 'util.dart' show equalLists, equalMaps, equalSets;
export '../api_prototype/compiler_options.dart'
show CompilerOptions, parseExperimentalFlags, parseExperimentalArguments;
@@ -134,6 +134,7 @@
Future<InitializedCompilerState> initializeIncrementalCompiler(
InitializedCompilerState oldState,
+ Set<String> tags,
List<Component> doneInputSummaries,
bool compileSdk,
Uri sdkRoot,
@@ -169,8 +170,9 @@
cachedSdkInput == null ||
!digestsEqual(cachedSdkInput.digest, sdkDigest) ||
!equalMaps(oldState.options.experimentalFlags, experiments) ||
- !equalMaps(oldState.options.environmentDefines, environmentDefines)) {
- // No previous state.
+ !equalMaps(oldState.options.environmentDefines, environmentDefines) ||
+ !equalSets(oldState.tags, tags)) {
+ // No - or immediately not correct - previous state.
options = new CompilerOptions()
..compileSdk = compileSdk
..sdkRoot = sdkRoot
@@ -265,7 +267,7 @@
throw new StateError("Expected to get digest for $summary");
}
List<int> bytes = await fileSystem.entityForUri(summary).readAsBytes();
- WorkerInputComponent cachedInput = WorkerInputComponent(
+ WorkerInputComponent cachedInput = new WorkerInputComponent(
digest,
await compilerState.processedOpts
.loadComponent(bytes, nameRoot, alwaysCreateNewNamedNodes: true));
@@ -283,6 +285,7 @@
return new InitializedCompilerState(options, processedOpts,
workerInputCache: workerInputCache,
incrementalCompiler: incrementalCompiler,
+ tags: tags,
libraryToInputDill: libraryToInputDill);
}
diff --git a/pkg/front_end/lib/src/api_unstable/util.dart b/pkg/front_end/lib/src/api_unstable/util.dart
index 146ddd0..cc5f7fc 100644
--- a/pkg/front_end/lib/src/api_unstable/util.dart
+++ b/pkg/front_end/lib/src/api_unstable/util.dart
@@ -12,6 +12,16 @@
return true;
}
+bool equalSets<K>(Set<K> a, Set<K> b) {
+ if (identical(a, b)) return true;
+ if (a == null || b == null) return false;
+ if (a.length != b.length) return false;
+ for (K entry in a) {
+ if (!b.contains(entry)) return false;
+ }
+ return true;
+}
+
bool equalMaps<K, V>(Map<K, V> a, Map<K, V> b) {
if (identical(a, b)) return true;
if (a == null || b == null) return false;
diff --git a/pkg/front_end/lib/src/api_unstable/vm.dart b/pkg/front_end/lib/src/api_unstable/vm.dart
index 47691d7..38dc042 100644
--- a/pkg/front_end/lib/src/api_unstable/vm.dart
+++ b/pkg/front_end/lib/src/api_unstable/vm.dart
@@ -40,19 +40,23 @@
show
LocatedMessage,
messageBytecodeLimitExceededTooManyArguments,
+ messageFfiExceptionalReturnNull,
+ messageFfiExpectedConstant,
noLength,
+ templateFfiDartTypeMismatch,
+ templateFfiExpectedExceptionalReturn,
+ templateFfiExpectedNoExceptionalReturn,
+ templateFfiExtendsOrImplementsSealedClass,
templateFfiFieldAnnotation,
+ templateFfiFieldInitializer,
templateFfiFieldNoAnnotation,
templateFfiNotStatic,
+ templateFfiStructGeneric,
templateFfiTypeInvalid,
templateFfiTypeMismatch,
templateFfiTypeUnsized,
- templateFfiFieldInitializer,
- templateIllegalRecursiveType,
- templateFfiDartTypeMismatch,
- templateFfiExtendsOrImplementsSealedClass,
- templateFfiStructGeneric,
- templateFfiWrongStructInheritance;
+ templateFfiWrongStructInheritance,
+ templateIllegalRecursiveType;
export '../fasta/hybrid_file_system.dart' show HybridFileSystem;
diff --git a/pkg/front_end/lib/src/base/instrumentation.dart b/pkg/front_end/lib/src/base/instrumentation.dart
index 5c16ee9..7846749 100644
--- a/pkg/front_end/lib/src/base/instrumentation.dart
+++ b/pkg/front_end/lib/src/base/instrumentation.dart
@@ -10,7 +10,8 @@
.replaceAll('→', '->')
.replaceAll('dart.core::', '')
.replaceAll('dart.async::', '')
- .replaceAll('test::', '');
+ .replaceAll('test::', '')
+ .replaceAll(new RegExp(r'\s*/\*.*?\*/\s*'), '');
/// Interface providing the ability to record property/value pairs associated
/// with source file locations. Intended to facilitate testing.
diff --git a/pkg/front_end/lib/src/base/processed_options.dart b/pkg/front_end/lib/src/base/processed_options.dart
index e1cb003..1f89337 100644
--- a/pkg/front_end/lib/src/base/processed_options.dart
+++ b/pkg/front_end/lib/src/base/processed_options.dart
@@ -306,6 +306,11 @@
/// Whether to write a file (e.g. a dill file) when reporting a crash.
bool get writeFileOnCrashReport => _raw.writeFileOnCrashReport;
+ /// The current sdk version string, e.g. "2.6.0-edge.sha1hash".
+ /// For instance used for language versioning (specifying the maximum
+ /// version).
+ String get currentSdkVersion => _raw.currentSdkVersion;
+
Target _target;
Target get target => _target ??=
_raw.target ?? new NoneTarget(new TargetFlags(legacyMode: legacyMode));
diff --git a/pkg/front_end/lib/src/fasta/builder/builder.dart b/pkg/front_end/lib/src/fasta/builder/builder.dart
index 285dc07..58fcf09 100644
--- a/pkg/front_end/lib/src/fasta/builder/builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/builder.dart
@@ -55,6 +55,8 @@
export 'named_type_builder.dart' show NamedTypeBuilder;
+export 'nullability_builder.dart' show NullabilityBuilder;
+
export 'prefix_builder.dart' show PrefixBuilder;
export 'type_alias_builder.dart' show TypeAliasBuilder;
diff --git a/pkg/front_end/lib/src/fasta/builder/builtin_type_builder.dart b/pkg/front_end/lib/src/fasta/builder/builtin_type_builder.dart
index 0e4d3a3..a673664 100644
--- a/pkg/front_end/lib/src/fasta/builder/builtin_type_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/builtin_type_builder.dart
@@ -4,7 +4,7 @@
library fasta.builtin_type_builder;
-import 'package:kernel/ast.dart' show DartType;
+import 'package:kernel/ast.dart' show DartType, Nullability;
import 'builder.dart' show LibraryBuilder, TypeBuilder, TypeDeclarationBuilder;
@@ -15,11 +15,15 @@
String name, this.type, LibraryBuilder compilationUnit, int charOffset)
: super(null, 0, name, compilationUnit, charOffset);
- DartType buildType(LibraryBuilder library, List<TypeBuilder> arguments) =>
- type;
+ DartType buildType(LibraryBuilder library, Nullability nullability,
+ List<TypeBuilder> arguments) {
+ // TODO(dmitryas): Use [nullability].
+ return type;
+ }
- DartType buildTypesWithBuiltArguments(
- LibraryBuilder library, List<DartType> arguments) {
+ DartType buildTypesWithBuiltArguments(LibraryBuilder library,
+ Nullability nullability, List<DartType> arguments) {
+ // TODO(dmitryas): Use [nullability].
return type;
}
diff --git a/pkg/front_end/lib/src/fasta/builder/class_builder.dart b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
index 6441675..481328b 100644
--- a/pkg/front_end/lib/src/fasta/builder/class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
@@ -21,6 +21,7 @@
Member,
MethodInvocation,
Name,
+ Nullability,
Procedure,
ProcedureKind,
RedirectingFactoryConstructor,
@@ -65,6 +66,8 @@
TypeBuilder,
TypeVariableBuilder;
+import 'declaration.dart';
+
import 'declaration_builder.dart';
import '../fasta_codes.dart'
@@ -80,8 +83,6 @@
noLength,
templateDuplicatedDeclarationUse,
templateGenericFunctionTypeInferredAsActualTypeArgument,
- templateIllegalMixinDueToConstructors,
- templateIllegalMixinDueToConstructorsCause,
templateImplementsRepeated,
templateImplementsSuperClass,
templateImplicitMixinOverrideContext,
@@ -100,6 +101,7 @@
templateOverrideMoreRequiredArguments,
templateOverrideTypeMismatchParameter,
templateOverrideTypeMismatchReturnType,
+ templateOverrideTypeMismatchSetter,
templateOverrideTypeVariablesMismatch,
templateRedirectingFactoryIncompatibleTypeArgument,
templateRedirectionTargetNotFound,
@@ -130,7 +132,7 @@
import '../names.dart' show noSuchMethodName;
import '../problems.dart'
- show internalProblem, unexpected, unhandled, unimplemented;
+ show internalProblem, unexpected, unhandled, unimplemented, unsupported;
import '../scope.dart' show AmbiguousBuilder;
@@ -201,7 +203,7 @@
}
MetadataBuilder.buildAnnotations(
- isPatch ? origin.target : cls, metadata, library, this, null);
+ isPatch ? origin.cls : cls, metadata, library, this, null);
constructors.forEach(build);
scope.forEach(build);
}
@@ -261,12 +263,12 @@
// be inferred. Currently, the inference is not performed.
// The code below is a workaround.
typeArguments = new List<DartType>.filled(
- targetBuilder.target.enclosingClass.typeParameters.length,
+ targetBuilder.member.enclosingClass.typeParameters.length,
const DynamicType(),
growable: true);
}
declaration.setRedirectingFactoryBody(
- targetBuilder.target, typeArguments);
+ targetBuilder.member, typeArguments);
} else if (targetBuilder is DillMemberBuilder) {
List<DartType> typeArguments = declaration.typeArguments;
if (typeArguments == null) {
@@ -274,7 +276,7 @@
// be inferred. Currently, the inference is not performed.
// The code below is a workaround.
typeArguments = new List<DartType>.filled(
- targetBuilder.target.enclosingClass.typeParameters.length,
+ targetBuilder.member.enclosingClass.typeParameters.length,
const DynamicType(),
growable: true);
}
@@ -351,10 +353,11 @@
}
@override
- Builder lookupLocalMember(String name, {bool required: false}) {
- Builder builder = scope.local[name];
+ Builder lookupLocalMember(String name,
+ {bool setter: false, bool required: false}) {
+ Builder builder = setter ? scope.setters[name] : scope.local[name];
if (builder == null && isPatch) {
- builder = origin.scope.local[name];
+ builder = setter ? origin.scope.setters[name] : origin.scope.local[name];
}
if (required && builder == null) {
internalProblem(
@@ -382,9 +385,18 @@
return declaration;
}
+ /// The [Class] built by this builder.
+ ///
+ /// For a patch class the origin class is returned.
Class get cls;
- Class get target => cls;
+ // Deliberately unrelated return type to statically detect more accidental
+ // use until Builder.target is fully retired.
+ UnrelatedTarget get target => unsupported(
+ "ClassBuilder.target is deprecated. "
+ "Use ClassBuilder.cls instead.",
+ charOffset,
+ fileUri);
Class get actualCls;
@@ -395,10 +407,12 @@
InterfaceType get thisType => cls.thisType;
/// [arguments] have already been built.
- InterfaceType buildTypesWithBuiltArguments(
- LibraryBuilder library, List<DartType> arguments) {
+ InterfaceType buildTypesWithBuiltArguments(LibraryBuilder library,
+ Nullability nullability, List<DartType> arguments) {
assert(arguments == null || cls.typeParameters.length == arguments.length);
- return arguments == null ? cls.rawType : new InterfaceType(cls, arguments);
+ return arguments == null
+ ? cls.rawType
+ : new InterfaceType(cls, arguments, nullability);
}
@override
@@ -443,20 +457,21 @@
}
/// If [arguments] are null, the default types for the variables are used.
- InterfaceType buildType(LibraryBuilder library, List<TypeBuilder> arguments) {
+ InterfaceType buildType(LibraryBuilder library, Nullability nullability,
+ List<TypeBuilder> arguments) {
return buildTypesWithBuiltArguments(
- library, buildTypeArguments(library, arguments));
+ library, nullability, buildTypeArguments(library, arguments));
}
Supertype buildSupertype(
LibraryBuilder library, List<TypeBuilder> arguments) {
- Class cls = isPatch ? origin.target : this.cls;
+ Class cls = isPatch ? origin.cls : this.cls;
return new Supertype(cls, buildTypeArguments(library, arguments));
}
Supertype buildMixedInType(
LibraryBuilder library, List<TypeBuilder> arguments) {
- Class cls = isPatch ? origin.target : this.cls;
+ Class cls = isPatch ? origin.cls : this.cls;
if (arguments != null) {
return new Supertype(cls, buildTypeArguments(library, arguments));
} else {
@@ -507,9 +522,9 @@
problemsOffsets ??= new Map<ClassBuilder, int>();
problemsOffsets[interface] ??= charOffset;
- } else if (interface.target == coreTypes.futureOrClass) {
+ } else if (interface.cls == coreTypes.futureOrClass) {
addProblem(messageImplementsFutureOr, charOffset,
- interface.target.name.length);
+ interface.cls.name.length);
} else {
implemented.add(interface);
}
@@ -651,7 +666,7 @@
}
void addRedirectingConstructor(
- ProcedureBuilder constructor, SourceLibraryBuilder library) {
+ ProcedureBuilder constructorBuilder, SourceLibraryBuilder library) {
// Add a new synthetic field to this class for representing factory
// constructors. This is used to support resolving such constructors in
// source code.
@@ -674,10 +689,10 @@
cls.addMember(field);
return new DillMemberBuilder(field, this);
});
- Field field = constructorsField.target;
+ Field field = constructorsField.member;
ListLiteral literal = field.initializer;
literal.expressions
- .add(new StaticGet(constructor.target)..parent = literal);
+ .add(new StaticGet(constructorBuilder.procedure)..parent = literal);
}
void handleSeenCovariant(
@@ -1124,11 +1139,20 @@
Message message;
int fileOffset;
if (declaredParameter == null) {
- message = templateOverrideTypeMismatchReturnType.withArguments(
- declaredMemberName,
- declaredType,
- interfaceType,
- interfaceMemberName);
+ if (asIfDeclaredParameter) {
+ // Setter overridden by field
+ message = templateOverrideTypeMismatchSetter.withArguments(
+ declaredMemberName,
+ declaredType,
+ interfaceType,
+ interfaceMemberName);
+ } else {
+ message = templateOverrideTypeMismatchReturnType.withArguments(
+ declaredMemberName,
+ declaredType,
+ interfaceType,
+ interfaceMemberName);
+ }
fileOffset = declaredMember.fileOffset;
} else {
message = templateOverrideTypeMismatchParameter.withArguments(
@@ -1418,26 +1442,6 @@
: name;
}
- void checkMixinDeclaration() {
- assert(cls.isMixinDeclaration);
- for (Builder constructor in constructors.local.values) {
- if (!constructor.isSynthetic &&
- (constructor.isFactory || constructor.isConstructor)) {
- addProblem(
- templateIllegalMixinDueToConstructors
- .withArguments(fullNameForErrors),
- charOffset,
- noLength,
- context: [
- templateIllegalMixinDueToConstructorsCause
- .withArguments(fullNameForErrors)
- .withLocation(
- constructor.fileUri, constructor.charOffset, noLength)
- ]);
- }
- }
- }
-
void checkMixinApplication(ClassHierarchy hierarchy) {
// A mixin declaration can only be applied to a class that implements all
// the declaration's superclass constraints.
@@ -1540,7 +1544,7 @@
}
List<DartType> typeArguments =
- getRedirectingFactoryBody(factory.target).typeArguments;
+ getRedirectingFactoryBody(factory.procedure).typeArguments;
FunctionType targetFunctionType = target.functionType;
if (typeArguments != null &&
targetFunctionType.typeParameters.length != typeArguments.length) {
@@ -1665,7 +1669,7 @@
///
/// It's an error if [superclass] isn't a superclass.
Map<TypeParameter, DartType> getSubstitutionMap(Class superclass) {
- Supertype supertype = target.supertype;
+ Supertype supertype = cls.supertype;
Map<TypeParameter, DartType> substitutionMap = <TypeParameter, DartType>{};
List<DartType> arguments;
List<TypeParameter> variables;
@@ -1785,8 +1789,8 @@
builder = getSuperclass(builder)?.origin;
}
if (builder != null) {
- Class target = builder.target;
- for (Constructor constructor in target.constructors) {
+ Class cls = builder.cls;
+ for (Constructor constructor in cls.constructors) {
if (constructor.name == name) return constructor;
}
}
diff --git a/pkg/front_end/lib/src/fasta/builder/declaration.dart b/pkg/front_end/lib/src/fasta/builder/declaration.dart
index 107d2a5..e2c75dc 100644
--- a/pkg/front_end/lib/src/fasta/builder/declaration.dart
+++ b/pkg/front_end/lib/src/fasta/builder/declaration.dart
@@ -6,6 +6,9 @@
import '../problems.dart' show unsupported;
+/// Dummy class to help deprecate [Builder.target].
+abstract class UnrelatedTarget {}
+
abstract class Builder {
/// Used when multiple things with the same name are declared within the same
/// parent. Only used for top-level and class-member declarations, not for
diff --git a/pkg/front_end/lib/src/fasta/builder/declaration_builder.dart b/pkg/front_end/lib/src/fasta/builder/declaration_builder.dart
index 6704c07..bc61309 100644
--- a/pkg/front_end/lib/src/fasta/builder/declaration_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/declaration_builder.dart
@@ -48,7 +48,9 @@
/// Lookups the member [name] declared in this declaration.
///
+ /// If [setter] is `true` the sought member is a setter or assignable field.
/// If [required] is `true` and no member is found an internal problem is
/// reported.
- Builder lookupLocalMember(String name, {bool required: false});
+ Builder lookupLocalMember(String name,
+ {bool setter: false, bool required: false});
}
diff --git a/pkg/front_end/lib/src/fasta/builder/enum_builder.dart b/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
index 093e2f0..dcb82cb 100644
--- a/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
@@ -4,7 +4,7 @@
library fasta.enum_builder;
-import 'builder.dart' show ClassBuilder, MetadataBuilder;
+import 'builder.dart' show ClassBuilder, MetadataBuilder, NullabilityBuilder;
import 'package:kernel/ast.dart'
show
@@ -19,6 +19,7 @@
IntLiteral,
InterfaceType,
ListLiteral,
+ Nullability,
ProcedureKind,
ReturnStatement,
StaticGet,
@@ -107,15 +108,19 @@
assert(enumConstantInfos == null || enumConstantInfos.isNotEmpty);
// TODO(ahe): These types shouldn't be looked up in scope, they come
// directly from dart:core.
- TypeBuilder intType = new NamedTypeBuilder("int", null);
- TypeBuilder stringType = new NamedTypeBuilder("String", null);
- NamedTypeBuilder objectType = new NamedTypeBuilder("Object", null);
+ TypeBuilder intType =
+ new NamedTypeBuilder("int", const NullabilityBuilder.omitted(), null);
+ TypeBuilder stringType = new NamedTypeBuilder(
+ "String", const NullabilityBuilder.omitted(), null);
+ NamedTypeBuilder objectType = new NamedTypeBuilder(
+ "Object", const NullabilityBuilder.omitted(), null);
Class cls = new Class(name: name);
Map<String, MemberBuilder> members = <String, MemberBuilder>{};
Map<String, MemberBuilder> constructors = <String, MemberBuilder>{};
- NamedTypeBuilder selfType = new NamedTypeBuilder(name, null);
- TypeBuilder listType =
- new NamedTypeBuilder("List", <TypeBuilder>[selfType]);
+ NamedTypeBuilder selfType =
+ new NamedTypeBuilder(name, const NullabilityBuilder.omitted(), null);
+ TypeBuilder listType = new NamedTypeBuilder(
+ "List", const NullabilityBuilder.omitted(), <TypeBuilder>[selfType]);
/// metadata class E {
/// final int index;
@@ -218,7 +223,7 @@
enumConstantInfo.charOffset,
enumConstantInfo.charOffset);
metadataCollector?.setDocumentationComment(
- fieldBuilder.target, documentationComment);
+ fieldBuilder.field, documentationComment);
members[name] = fieldBuilder..next = existing;
}
}
@@ -227,9 +232,12 @@
EnumBuilder enumBuilder = new EnumBuilder.internal(
metadata,
name,
- new Scope(members, null, parent.scope, "enum $name",
+ new Scope(
+ local: members,
+ parent: parent.scope,
+ debugName: "enum $name",
isModifiable: false),
- new Scope(constructors, null, null, name, isModifiable: false),
+ new Scope(local: constructors, debugName: name, isModifiable: false),
cls,
enumConstantInfos,
intType,
@@ -255,7 +263,9 @@
TypeBuilder get mixedInType => null;
- InterfaceType buildType(LibraryBuilder library, List<TypeBuilder> arguments) {
+ InterfaceType buildType(LibraryBuilder library, Nullability nullability,
+ List<TypeBuilder> arguments) {
+ // TODO(dmitryas): Use [nullability].
return cls.rawType;
}
@@ -316,7 +326,7 @@
objectClass.charOffset, objectClass.name.length, objectClass.fileUri);
} else {
constructor.initializers.add(
- new SuperInitializer(superConstructor.target, new Arguments.empty())
+ new SuperInitializer(superConstructor.member, new Arguments.empty())
..parent = constructor);
}
int index = 0;
diff --git a/pkg/front_end/lib/src/fasta/builder/extension_builder.dart b/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
index d31fa16..8984604 100644
--- a/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
@@ -6,15 +6,16 @@
import 'package:kernel/ast.dart';
+import '../fasta_codes.dart' show templateInternalProblemNotFoundIn;
+import '../scope.dart';
+import '../problems.dart';
import 'builder.dart';
+import 'declaration.dart';
import 'declaration_builder.dart';
import 'library_builder.dart';
import 'metadata_builder.dart';
import 'type_builder.dart';
import 'type_variable_builder.dart';
-import '../fasta_codes.dart' show templateInternalProblemNotFoundIn;
-import '../scope.dart';
-import '../problems.dart';
abstract class ExtensionBuilder extends DeclarationBuilder {
final List<TypeVariableBuilder> typeParameters;
@@ -31,6 +32,9 @@
this.onType)
: super(metadata, modifiers, name, parent, charOffset, scope);
+ /// Return the [Extension] built by this builder.
+ Extension get extension;
+
/// Lookup a static member of this declaration.
Builder findStaticBuilder(
String name, int charOffset, Uri fileUri, LibraryBuilder accessingLibrary,
@@ -45,14 +49,23 @@
return declaration;
}
+ // Deliberately unrelated return type to statically detect more accidental
+ // use until Builder.target is fully retired.
+ UnrelatedTarget get target => unsupported(
+ "ExtensionBuilder.target is deprecated. "
+ "Use ExtensionBuilder.extension instead.",
+ charOffset,
+ fileUri);
+
@override
- DartType buildType(LibraryBuilder library, List<TypeBuilder> arguments) {
+ DartType buildType(LibraryBuilder library, Nullability nullability,
+ List<TypeBuilder> arguments) {
throw new UnsupportedError("ExtensionBuilder.buildType is not supported.");
}
@override
- DartType buildTypesWithBuiltArguments(
- LibraryBuilder library, List<DartType> arguments) {
+ DartType buildTypesWithBuiltArguments(LibraryBuilder library,
+ Nullability nullability, List<DartType> arguments) {
throw new UnsupportedError("ExtensionBuilder.buildTypesWithBuiltArguments "
"is not supported.");
}
@@ -64,9 +77,10 @@
InterfaceType get thisType => null;
@override
- Builder lookupLocalMember(String name, {bool required: false}) {
+ Builder lookupLocalMember(String name,
+ {bool setter: false, bool required: false}) {
// TODO(johnniwinther): Support patching on extensions.
- Builder builder = scope.local[name];
+ Builder builder = setter ? scope.setters[name] : scope.local[name];
if (required && builder == null) {
internalProblem(
templateInternalProblemNotFoundIn.withArguments(
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 91a427f..44bba27 100644
--- a/pkg/front_end/lib/src/fasta/builder/field_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
@@ -9,7 +9,15 @@
import 'builder.dart' show LibraryBuilder, MemberBuilder;
import 'package:kernel/ast.dart'
- show Class, DartType, Expression, Field, InvalidType, Name, NullLiteral;
+ show
+ Class,
+ DartType,
+ Expression,
+ Field,
+ InvalidType,
+ Member,
+ Name,
+ NullLiteral;
import '../constant_context.dart' show ConstantContext;
@@ -42,7 +50,8 @@
import '../type_inference/type_inference_engine.dart'
show IncludesTypeParametersNonCovariantly, Variance;
-import '../type_inference/type_inferrer.dart' show TypeInferrerImpl;
+import '../type_inference/type_inferrer.dart'
+ show ExpressionInferenceResult, TypeInferrerImpl;
import '../type_inference/type_schema.dart' show UnknownType;
@@ -67,6 +76,8 @@
..fileEndOffset = charEndOffset,
super(compilationUnit, charOffset);
+ Member get member => field;
+
String get debugName => "FieldBuilder";
bool get isField => true;
@@ -85,7 +96,7 @@
(hasInitializer || isClassInstanceMember);
}
- Field build(SourceLibraryBuilder library) {
+ Field build(SourceLibraryBuilder libraryBuilder) {
field
..isCovariant = isCovariant
..isFinal = isFinal
@@ -93,7 +104,7 @@
..isLate = isLate;
if (isExtensionMember) {
ExtensionBuilder extension = parent;
- field.name = new Name('${extension.name}|$name', library.target);
+ field.name = new Name('${extension.name}|$name', libraryBuilder.library);
field
..hasImplicitGetter = false
..hasImplicitSetter = false
@@ -101,7 +112,7 @@
..isExtensionMember = true;
} else {
// TODO(johnniwinther): How can the name already have been computed.
- field.name ??= new Name(name, library.target);
+ field.name ??= new Name(name, libraryBuilder.library);
bool isInstanceMember = !isStatic && !isTopLevel;
field
..hasImplicitGetter = isInstanceMember
@@ -110,12 +121,13 @@
..isExtensionMember = false;
}
if (type != null) {
- field.type = type.build(library);
+ field.type = type.build(libraryBuilder);
if (!isFinal && !isConst) {
IncludesTypeParametersNonCovariantly needsCheckVisitor;
if (parent is ClassBuilder) {
- Class enclosingClass = parent.target;
+ ClassBuilder enclosingClassBuilder = parent;
+ Class enclosingClass = enclosingClassBuilder.cls;
if (enclosingClass.typeParameters.isNotEmpty) {
needsCheckVisitor = new IncludesTypeParametersNonCovariantly(
enclosingClass.typeParameters,
@@ -151,8 +163,9 @@
classBuilder.hasConstConstructor)) &&
constInitializerToken != null) {
Scope scope = classBuilder?.scope ?? library.scope;
- BodyBuilder bodyBuilder = new BodyBuilder.forOutlineExpression(
- library, classBuilder, this, scope, fileUri);
+ BodyBuilder bodyBuilder = library.loader
+ .createBodyBuilderForOutlineExpression(
+ library, classBuilder, this, scope, fileUri);
bodyBuilder.constantContext =
isConst ? ConstantContext.inferred : ConstantContext.none;
initializer = bodyBuilder.parseFieldInitializer(constInitializerToken)
@@ -169,8 +182,6 @@
constInitializerToken = null;
}
- Field get target => field;
-
@override
void inferType() {
SourceLibraryBuilder library = this.library;
@@ -197,16 +208,19 @@
type.isStarted = true;
TypeInferrerImpl typeInferrer = library.loader.typeInferenceEngine
.createTopLevelTypeInferrer(
- fileUri, field.enclosingClass?.thisType, null);
- BodyBuilder bodyBuilder = new BodyBuilder.forField(this, typeInferrer);
+ fileUri, field.enclosingClass?.thisType, library);
+ BodyBuilder bodyBuilder =
+ library.loader.createBodyBuilderForField(this, typeInferrer);
bodyBuilder.constantContext =
isConst ? ConstantContext.inferred : ConstantContext.none;
initializer = bodyBuilder.parseFieldInitializer(type.initializerToken);
type.initializerToken = null;
- DartType inferredType = typeInferrer.inferDeclarationType(typeInferrer
- .inferExpression(field.initializer, const UnknownType(), true,
- isVoidAllowed: true));
+ ExpressionInferenceResult result = typeInferrer.inferExpression(
+ field.initializer, const UnknownType(), true,
+ isVoidAllowed: true);
+ DartType inferredType =
+ typeInferrer.inferDeclarationType(result.inferredType);
if (field.type is ImplicitFieldType) {
// `field.type` may have changed if a circularity was detected when
@@ -215,7 +229,8 @@
IncludesTypeParametersNonCovariantly needsCheckVisitor;
if (parent is ClassBuilder) {
- Class enclosingClass = parent.target;
+ ClassBuilder enclosingClassBuilder = parent;
+ Class enclosingClass = enclosingClassBuilder.cls;
if (enclosingClass.typeParameters.isNotEmpty) {
needsCheckVisitor = new IncludesTypeParametersNonCovariantly(
enclosingClass.typeParameters,
diff --git a/pkg/front_end/lib/src/fasta/builder/formal_parameter_builder.dart b/pkg/front_end/lib/src/fasta/builder/formal_parameter_builder.dart
index 89fba82..4e7e8c3 100644
--- a/pkg/front_end/lib/src/fasta/builder/formal_parameter_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/formal_parameter_builder.dart
@@ -60,7 +60,7 @@
FormalParameterKind kind = FormalParameterKind.mandatory;
/// The variable declaration created for this formal parameter.
- VariableDeclaration declaration;
+ VariableDeclaration variable;
/// The first token of the default value, if any.
///
@@ -94,12 +94,12 @@
@override
String get fullNameForErrors => name;
- VariableDeclaration get target => declaration;
+ VariableDeclaration get target => variable;
VariableDeclaration build(
SourceLibraryBuilder library, int functionNestingLevel) {
- if (declaration == null) {
- declaration = new VariableDeclarationJudgment(name, functionNestingLevel,
+ if (variable == null) {
+ variable = new VariableDeclarationJudgment(name, functionNestingLevel,
type: type?.build(library),
isFinal: isFinal,
isConst: isConst,
@@ -108,7 +108,7 @@
isRequired: isNamedRequired)
..fileOffset = charOffset;
}
- return declaration;
+ return variable;
}
FormalParameterBuilder clone(List<TypeBuilder> newTypes) {
@@ -120,7 +120,7 @@
}
FormalParameterBuilder forFormalParameterInitializerScope() {
- assert(declaration != null);
+ assert(variable != null);
return !isInitializingFormal
? this
: (new FormalParameterBuilder(
@@ -131,15 +131,15 @@
null,
charOffset)
..parent = parent
- ..declaration = declaration);
+ ..variable = variable);
}
void finalizeInitializingFormal() {
Object cls = parent.parent;
if (cls is ClassBuilder) {
- Builder field = cls.scope.lookup(name, charOffset, fileUri);
- if (field is FieldBuilder) {
- target.type = field.target.type;
+ Builder fieldBuilder = cls.scope.lookup(name, charOffset, fileUri);
+ if (fieldBuilder is FieldBuilder) {
+ variable.type = fieldBuilder.field.type;
}
}
}
@@ -152,23 +152,27 @@
// constant evaluation. Similarly we need to include initializers for
// optional and named parameters of instance methods because these might be
// needed to generated noSuchMethod forwarders.
- final bool isConstConstructorParameter =
- (parent is ConstructorBuilder && parent.target.isConst);
+ bool isConstConstructorParameter = false;
+ if (parent is ConstructorBuilder) {
+ ConstructorBuilder constructorBuilder = parent;
+ isConstConstructorParameter = constructorBuilder.constructor.isConst;
+ }
if ((isConstConstructorParameter || parent.isClassInstanceMember) &&
initializerToken != null) {
final ClassBuilder classBuilder = parent.parent;
Scope scope = classBuilder.scope;
- BodyBuilder bodyBuilder = new BodyBuilder.forOutlineExpression(
- library, classBuilder, this, scope, fileUri);
+ BodyBuilder bodyBuilder = library.loader
+ .createBodyBuilderForOutlineExpression(
+ library, classBuilder, this, scope, fileUri);
bodyBuilder.constantContext = ConstantContext.required;
- target.initializer = bodyBuilder.parseFieldInitializer(initializerToken)
- ..parent = target;
+ variable.initializer = bodyBuilder.parseFieldInitializer(initializerToken)
+ ..parent = variable;
bodyBuilder.typeInferrer?.inferParameterInitializer(
- bodyBuilder, target.initializer, target.type);
+ bodyBuilder, variable.initializer, variable.type);
if (library.loader is SourceLoader) {
SourceLoader loader = library.loader;
- loader.transformPostInference(target, bodyBuilder.transformSetLiterals,
- bodyBuilder.transformCollections);
+ loader.transformPostInference(variable,
+ bodyBuilder.transformSetLiterals, bodyBuilder.transformCollections);
}
bodyBuilder.resolveRedirectingFactoryTargets();
}
diff --git a/pkg/front_end/lib/src/fasta/builder/invalid_type_builder.dart b/pkg/front_end/lib/src/fasta/builder/invalid_type_builder.dart
index 52355e7..4e71b742 100644
--- a/pkg/front_end/lib/src/fasta/builder/invalid_type_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/invalid_type_builder.dart
@@ -4,7 +4,7 @@
library fasta.invalid_type_builder;
-import 'package:kernel/ast.dart' show DartType, InvalidType;
+import 'package:kernel/ast.dart' show DartType, InvalidType, Nullability;
import '../fasta_codes.dart' show LocatedMessage;
@@ -28,13 +28,14 @@
@override
InvalidType get target => const InvalidType();
- DartType buildType(LibraryBuilder library, List<TypeBuilder> arguments) {
- return buildTypesWithBuiltArguments(library, null);
+ DartType buildType(LibraryBuilder library, Nullability nullability,
+ List<TypeBuilder> arguments) {
+ return buildTypesWithBuiltArguments(library, null, null);
}
/// [Arguments] have already been built.
- DartType buildTypesWithBuiltArguments(
- LibraryBuilder library, List<DartType> arguments) {
+ DartType buildTypesWithBuiltArguments(LibraryBuilder library,
+ Nullability nullability, List<DartType> arguments) {
if (!suppressMessage) {
library.addProblem(message.messageObject, message.charOffset,
message.length, message.uri,
diff --git a/pkg/front_end/lib/src/fasta/builder/library_builder.dart b/pkg/front_end/lib/src/fasta/builder/library_builder.dart
index d83d032..44d9beb 100644
--- a/pkg/front_end/lib/src/fasta/builder/library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/library_builder.dart
@@ -32,11 +32,14 @@
FieldBuilder,
ModifierBuilder,
NameIterator,
+ NullabilityBuilder,
PrefixBuilder,
Scope,
ScopeBuilder,
TypeBuilder;
+import 'declaration.dart';
+
abstract class LibraryBuilder extends ModifierBuilder {
final Scope scope;
@@ -61,6 +64,14 @@
bool get isSynthetic => false;
+ // Deliberately unrelated return type to statically detect more accidental
+ // use until Builder.target is fully retired.
+ UnrelatedTarget get target => unsupported(
+ "LibraryBuilder.target is deprecated. "
+ "Use LibraryBuilder.library instead.",
+ charOffset,
+ fileUri);
+
/// Set the langauge version to a specific non-null major and minor version.
///
/// If the language version has previously been explicitly set set (i.e. with
@@ -91,13 +102,13 @@
@override
int get modifiers => 0;
- @override
- Library get target;
+ /// Returns the [Library] built by this builder.
+ Library get library;
Uri get uri;
Iterator<Builder> get iterator {
- return LibraryLocalDeclarationIterator(this);
+ return new LibraryLocalDeclarationIterator(this);
}
NameIterator get nameIterator {
@@ -262,6 +273,19 @@
void buildOutlineExpressions() {}
List<FieldBuilder> takeImplicitlyTypedFields() => null;
+
+ // TODO(dmitryas): Compute the predicate using the library version instead.
+ bool get isNonNullableByDefault => loader.target.enableNonNullable;
+
+ NullabilityBuilder computeNullabilityFromToken(bool markedAsNullable) {
+ if (!isNonNullableByDefault) {
+ return const NullabilityBuilder.legacy();
+ }
+ if (markedAsNullable) {
+ return const NullabilityBuilder.nullable();
+ }
+ return const NullabilityBuilder.omitted();
+ }
}
class LibraryLocalDeclarationIterator implements Iterator<Builder> {
diff --git a/pkg/front_end/lib/src/fasta/builder/member_builder.dart b/pkg/front_end/lib/src/fasta/builder/member_builder.dart
index cc6877d..ddc7a64 100644
--- a/pkg/front_end/lib/src/fasta/builder/member_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/member_builder.dart
@@ -4,11 +4,16 @@
library fasta.member_builder;
+import 'dart:core' hide MapEntry;
+
+import 'package:kernel/ast.dart';
+
import '../problems.dart' show unsupported;
import 'builder.dart'
show ClassBuilder, Builder, LibraryBuilder, ModifierBuilder;
+import 'declaration.dart';
import 'declaration_builder.dart';
import 'extension_builder.dart';
@@ -53,12 +58,31 @@
if (parent is LibraryBuilder) {
LibraryBuilder library = parent;
return library.partOfLibrary ?? library;
+ } else if (parent is ExtensionBuilder) {
+ ExtensionBuilder extension = parent;
+ return extension.library;
} else {
ClassBuilder cls = parent;
return cls.library;
}
}
+ /// The [Member] built by this builder;
+ Member get member;
+
+ // TODO(johnniwinther): Deprecate this.
+ Member get target => member;
+
+ // TODO(johnniwinther): Remove this and create a [ProcedureBuilder] interface.
+ Member get extensionTearOff =>
+ unsupported("extensionTearOff", charOffset, fileUri);
+
+ // TODO(johnniwinther): Remove this and create a [ProcedureBuilder] interface.
+ Procedure get procedure => unsupported("procedure", charOffset, fileUri);
+
+ // TODO(johnniwinther): Remove this and create a [ProcedureBuilder] interface.
+ ProcedureKind get kind => unsupported("kind", charOffset, fileUri);
+
void buildOutlineExpressions(LibraryBuilder library) {}
@override
diff --git a/pkg/front_end/lib/src/fasta/builder/metadata_builder.dart b/pkg/front_end/lib/src/fasta/builder/metadata_builder.dart
index 5ac0dc0..cf5bbb6 100644
--- a/pkg/front_end/lib/src/fasta/builder/metadata_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/metadata_builder.dart
@@ -34,8 +34,9 @@
Scope scope = parent is Library || parent is Class || classBuilder == null
? library.scope
: classBuilder.scope;
- BodyBuilder bodyBuilder = new BodyBuilder.forOutlineExpression(
- library, classBuilder, member, scope, fileUri);
+ BodyBuilder bodyBuilder = library.loader
+ .createBodyBuilderForOutlineExpression(
+ library, classBuilder, member, scope, fileUri);
for (int i = 0; i < metadata.length; ++i) {
MetadataBuilder annotationBuilder = metadata[i];
parent.addAnnotation(
diff --git a/pkg/front_end/lib/src/fasta/builder/named_type_builder.dart b/pkg/front_end/lib/src/fasta/builder/named_type_builder.dart
index b12233e..458013a 100644
--- a/pkg/front_end/lib/src/fasta/builder/named_type_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/named_type_builder.dart
@@ -31,6 +31,7 @@
Builder,
Identifier,
LibraryBuilder,
+ NullabilityBuilder,
PrefixBuilder,
QualifiedName,
Scope,
@@ -54,12 +55,15 @@
List<TypeBuilder> arguments;
+ final NullabilityBuilder nullabilityBuilder;
+
@override
TypeDeclarationBuilder declaration;
- NamedTypeBuilder(this.name, this.arguments);
+ NamedTypeBuilder(this.name, this.nullabilityBuilder, this.arguments);
- NamedTypeBuilder.fromTypeDeclarationBuilder(this.declaration,
+ NamedTypeBuilder.fromTypeDeclarationBuilder(
+ this.declaration, this.nullabilityBuilder,
[this.arguments])
: this.name = declaration.name;
@@ -181,6 +185,7 @@
t.printOn(buffer);
}
buffer.write(">");
+ nullabilityBuilder.writeNullabilityOn(buffer);
return buffer;
}
@@ -209,7 +214,8 @@
DartType build(LibraryBuilder library) {
assert(declaration != null, "Declaration has not been resolved on $this.");
- return declaration.buildType(library, arguments);
+ return declaration.buildType(
+ library, nullabilityBuilder.build(library), arguments);
}
Supertype buildSupertype(
@@ -248,7 +254,8 @@
}
}
- TypeBuilder subst(Map<TypeVariableBuilder, TypeBuilder> substitution) {
+ TypeBuilder subst(Map<TypeVariableBuilder, TypeBuilder> substitution,
+ [List<NamedTypeBuilder> unboundTypes]) {
TypeBuilder result = substitution[declaration];
if (result != null) {
assert(declaration is TypeVariableBuilder);
@@ -257,7 +264,7 @@
List<TypeBuilder> arguments;
int i = 0;
for (TypeBuilder argument in this.arguments) {
- TypeBuilder type = argument.subst(substitution);
+ TypeBuilder type = argument.subst(substitution, unboundTypes);
if (type != argument) {
arguments ??= this.arguments.toList();
arguments[i] = type;
@@ -265,7 +272,16 @@
i++;
}
if (arguments != null) {
- return new NamedTypeBuilder(name, arguments)..bind(declaration);
+ NamedTypeBuilder result =
+ new NamedTypeBuilder(name, nullabilityBuilder, arguments);
+ if (declaration != null) {
+ result.bind(declaration);
+ } else if (unboundTypes != null) {
+ unboundTypes.add(result);
+ } else {
+ throw new UnsupportedError("Unbound type in substitution: $result.");
+ }
+ return result;
}
}
return this;
@@ -279,7 +295,8 @@
clonedArguments[i] = arguments[i].clone(newTypes);
}
}
- NamedTypeBuilder newType = new NamedTypeBuilder(name, clonedArguments);
+ NamedTypeBuilder newType =
+ new NamedTypeBuilder(name, nullabilityBuilder, clonedArguments);
newTypes.add(newType);
return newType;
}
diff --git a/pkg/front_end/lib/src/fasta/builder/nullability_builder.dart b/pkg/front_end/lib/src/fasta/builder/nullability_builder.dart
new file mode 100644
index 0000000..dbe2ed7
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/builder/nullability_builder.dart
@@ -0,0 +1,84 @@
+// Copyright (c) 2019, 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:core' hide MapEntry;
+import 'package:kernel/ast.dart';
+import '../kernel/body_builder.dart';
+import '../builder/builder.dart';
+import '../problems.dart';
+
+/// Represents the nullability modifiers encountered while parsing the types.
+///
+/// The syntactic nullability needs to be interpreted, that is, built, into the
+/// semantic nullability used on [DartType]s of Kernel.
+enum SyntacticNullability {
+ /// Used when the type is declared with '?' suffix after it.
+ nullable,
+
+ /// Used when the type is declared in an opted-out library.
+ legacy,
+
+ /// Used when the type is declared without any nullability suffixes.
+ omitted,
+}
+
+class NullabilityBuilder {
+ final SyntacticNullability _syntacticNullability;
+
+ const NullabilityBuilder.nullable()
+ : _syntacticNullability = SyntacticNullability.nullable;
+
+ const NullabilityBuilder.legacy()
+ : _syntacticNullability = SyntacticNullability.legacy;
+
+ const NullabilityBuilder.omitted()
+ : _syntacticNullability = SyntacticNullability.omitted;
+
+ /// Used temporarily in the places that need proper handling of NNBD features.
+ ///
+ /// Over time the uses of [NullabilityBuilder.pendingImplementation] should be
+ /// eliminated, and the constructor should be eventually removed. Currently,
+ /// it redirects to [NullabilityBuilder.legacy] as a conservative safety
+ /// measure for the pre-NNBD code and as a visible reminder of the feature
+ /// implementation being in progress in the NNBD code.
+ // TODO(dmitryas): Remove this constructor.
+ const NullabilityBuilder.pendingImplementation() : this.legacy();
+
+ Nullability build(LibraryBuilder libraryBuilder, {Nullability ifOmitted}) {
+ // TODO(dmitryas): Ensure that either ifOmitted is set or libraryBuilder is
+ // provided;
+ //assert(libraryBuilder != null || ifOmitted != null);
+ ifOmitted ??= (libraryBuilder == null ? Nullability.legacy : null);
+
+ ifOmitted ??= libraryBuilder.isNonNullableByDefault
+ ? Nullability.nonNullable
+ : Nullability.legacy;
+ switch (_syntacticNullability) {
+ case SyntacticNullability.legacy:
+ return Nullability.legacy;
+ case SyntacticNullability.nullable:
+ return Nullability.nullable;
+ case SyntacticNullability.omitted:
+ return ifOmitted;
+ }
+ return unhandled("$_syntacticNullability", "buildNullability",
+ TreeNode.noOffset, noLocation);
+ }
+
+ void writeNullabilityOn(StringBuffer sb) {
+ switch (_syntacticNullability) {
+ case SyntacticNullability.legacy:
+ sb.write("*");
+ return;
+ case SyntacticNullability.nullable:
+ sb.write("?");
+ return;
+ case SyntacticNullability.omitted:
+ // Do nothing.
+ return;
+ }
+ unhandled("$_syntacticNullability", "writeNullabilityOn", TreeNode.noOffset,
+ noLocation);
+ }
+}
diff --git a/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart b/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart
index 6f97cf0..e39c9c2 100644
--- a/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart
@@ -4,13 +4,10 @@
library fasta.procedure_builder;
-// Note: we're deliberately using AsyncMarker and ProcedureKind from kernel
-// outside the kernel-specific builders. This is simpler than creating
-// additional enums.
-import 'package:kernel/ast.dart'
- show AsyncMarker, ProcedureKind, VariableDeclaration;
+import 'dart:core' hide MapEntry;
-import 'package:kernel/type_algebra.dart' show containsTypeVariable, substitute;
+import 'package:kernel/ast.dart';
+
import 'package:kernel/type_algebra.dart';
import 'builder.dart'
@@ -25,35 +22,7 @@
TypeVariableBuilder;
import 'extension_builder.dart';
-
-import 'package:kernel/ast.dart'
- show
- Arguments,
- AsyncMarker,
- Class,
- Constructor,
- ConstructorInvocation,
- DartType,
- DynamicType,
- EmptyStatement,
- Expression,
- FunctionNode,
- Initializer,
- InterfaceType,
- Member,
- Name,
- Procedure,
- ProcedureKind,
- RedirectingInitializer,
- Statement,
- StaticInvocation,
- StringLiteral,
- SuperInitializer,
- TreeNode,
- TypeParameter,
- TypeParameterType,
- VariableDeclaration,
- setParents;
+import 'type_variable_builder.dart';
import '../../scanner/token.dart' show Token;
@@ -171,7 +140,10 @@
local[formal.name] = formal;
}
}
- return new Scope(local, null, parent, "formal parameter",
+ return new Scope(
+ local: local,
+ parent: parent,
+ debugName: "formal parameter",
isModifiable: false);
}
@@ -196,7 +168,10 @@
for (FormalParameterBuilder formal in formals) {
local[formal.name] = formal.forFormalParameterInitializerScope();
}
- return new Scope(local, null, parent, "formal parameter initializer",
+ return new Scope(
+ local: local,
+ parent: parent,
+ debugName: "formal parameter initializer",
isModifiable: false);
}
@@ -209,7 +184,10 @@
for (TypeVariableBuilder variable in typeVariables) {
local[variable.name] = variable;
}
- return new Scope(local, null, parent, "type parameter",
+ return new Scope(
+ local: local,
+ parent: parent,
+ debugName: "type parameter",
isModifiable: false);
}
@@ -226,7 +204,7 @@
FunctionNode function;
- Statement actualBody;
+ Statement _body;
FunctionBuilder get actualOrigin;
@@ -238,7 +216,7 @@
// newBody.fileOffset, fileUri);
// }
// }
- actualBody = newBody;
+ _body = newBody;
if (function != null) {
// A forwarding semi-stub is a method that is abstract in the source code,
// but which needs to have a forwarding stub body in order to ensure that
@@ -255,18 +233,18 @@
}
void setRedirectingFactoryBody(Member target, List<DartType> typeArguments) {
- if (actualBody != null) {
- unexpected("null", "${actualBody.runtimeType}", charOffset, fileUri);
+ if (_body != null) {
+ unexpected("null", "${_body.runtimeType}", charOffset, fileUri);
}
- actualBody = new RedirectingFactoryBody(target, typeArguments);
- function.body = actualBody;
- actualBody?.parent = function;
+ _body = new RedirectingFactoryBody(target, typeArguments);
+ function.body = _body;
+ _body?.parent = function;
if (isPatch) {
actualOrigin.setRedirectingFactoryBody(target, typeArguments);
}
}
- Statement get body => actualBody ??= new EmptyStatement();
+ Statement get body => _body ??= new EmptyStatement();
bool get isNative => nativeMethodName != null;
@@ -275,7 +253,8 @@
FunctionNode result = new FunctionNode(body, asyncMarker: asyncModifier);
IncludesTypeParametersNonCovariantly needsCheckVisitor;
if (!isConstructor && !isFactory && parent is ClassBuilder) {
- Class enclosingClass = parent.target;
+ ClassBuilder enclosingClassBuilder = parent;
+ Class enclosingClass = enclosingClassBuilder.cls;
if (enclosingClass.typeParameters.isNotEmpty) {
needsCheckVisitor = new IncludesTypeParametersNonCovariantly(
enclosingClass.typeParameters,
@@ -335,7 +314,9 @@
if (!isConstructor &&
!isDeclarationInstanceMember &&
parent is ClassBuilder) {
- List<TypeParameter> typeParameters = parent.target.typeParameters;
+ ClassBuilder enclosingClassBuilder = parent;
+ List<TypeParameter> typeParameters =
+ enclosingClassBuilder.cls.typeParameters;
if (typeParameters.isNotEmpty) {
Map<TypeParameter, DartType> substitution;
DartType removeTypeVariables(DartType type) {
@@ -403,7 +384,7 @@
@override
void buildOutlineExpressions(LibraryBuilder library) {
MetadataBuilder.buildAnnotations(
- target, metadata, library, isClassMember ? parent : null, this);
+ member, metadata, library, isClassMember ? parent : null, this);
if (formals != null) {
// For const constructors we need to include default parameter values
@@ -417,18 +398,18 @@
}
void becomeNative(Loader loader) {
- Builder constructor = loader.getNativeAnnotation();
+ MemberBuilder constructor = loader.getNativeAnnotation();
Arguments arguments =
new Arguments(<Expression>[new StringLiteral(nativeMethodName)]);
Expression annotation;
if (constructor.isConstructor) {
- annotation = new ConstructorInvocation(constructor.target, arguments)
+ annotation = new ConstructorInvocation(constructor.member, arguments)
..isConst = true;
} else {
- annotation = new StaticInvocation(constructor.target, arguments)
+ annotation = new StaticInvocation(constructor.member, arguments)
..isConst = true;
}
- target.addAnnotation(annotation);
+ member.addAnnotation(annotation);
}
bool checkPatch(FunctionBuilder patch) {
@@ -453,7 +434,7 @@
}
class ProcedureBuilder extends FunctionBuilder {
- final Procedure procedure;
+ final Procedure _procedure;
final int charOpenParenOffset;
final ProcedureKind kind;
@@ -462,8 +443,14 @@
@override
ProcedureBuilder actualOrigin;
+ Procedure get actualProcedure => _procedure;
+
bool hadTypesInferred = false;
+ /// If this is an extension instance method then [_extensionTearOff] holds
+ /// the synthetically created tear off function.
+ Procedure _extensionTearOff;
+
ProcedureBuilder(
List<MetadataBuilder> metadata,
int modifiers,
@@ -478,7 +465,7 @@
this.charOpenParenOffset,
int charEndOffset,
[String nativeMethodName])
- : procedure =
+ : _procedure =
new Procedure(null, kind, null, fileUri: compilationUnit?.fileUri)
..startFileOffset = startCharOffset
..fileOffset = charOffset
@@ -492,10 +479,64 @@
AsyncMarker get asyncModifier => actualAsyncModifier;
Statement get body {
- if (actualBody == null && !isAbstract && !isExternal) {
- actualBody = new EmptyStatement();
+ if (_body == null && !isAbstract && !isExternal) {
+ _body = new EmptyStatement();
}
- return actualBody;
+ return _body;
+ }
+
+ /// If this is an extension instance setter, wrap the setter body to return
+ /// the rhs value from the method.
+ ///
+ /// That is, this setter
+ ///
+ /// extension E on A {
+ /// void set property(B value) {
+ /// value++;
+ /// }
+ /// }
+ ///
+ /// is converted into this top level method
+ ///
+ /// B E|property(A #this, B value) {
+ /// final #t1 = value;
+ /// value++;
+ /// return #t1;
+ /// }
+ ///
+ void _updateExtensionSetterBody() {
+ if (isExtensionInstanceMember && isSetter) {
+ // TODO(johnniwinther): Avoid the synthetic variable if the parameter is
+ // never modified.
+ // TODO(johnniwinther): Handle setter bodies with return statements.
+ VariableDeclaration value = procedure.function.positionalParameters[1];
+ procedure.function.returnType = value.type;
+ Statement body = procedure.function.body;
+ List<Statement> statements = [];
+ Block block = new Block(statements);
+ VariableDeclaration variableDeclaration =
+ new VariableDeclarationJudgment.forValue(
+ new VariableGet(value)..fileOffset = procedure.fileOffset)
+ ..type = value.type;
+ statements.add(variableDeclaration);
+ if (body is Block) {
+ statements.addAll(body.statements);
+ } else {
+ statements.add(body);
+ }
+ ReturnStatement returnStatement = new ReturnStatement(
+ new VariableGet(variableDeclaration)
+ ..fileOffset = procedure.fileEndOffset);
+ statements.add(returnStatement);
+ setParents(block.statements, block);
+ procedure.function.body = block;
+ block.parent = procedure.function;
+ }
+ }
+
+ void set body(Statement newBody) {
+ super.body = newBody;
+ _updateExtensionSetterBody();
}
void set asyncModifier(AsyncMarker newModifier) {
@@ -525,18 +566,18 @@
return parent is ExtensionBuilder;
}
- Procedure build(SourceLibraryBuilder library) {
+ Procedure build(SourceLibraryBuilder libraryBuilder) {
// TODO(ahe): I think we may call this twice on parts. Investigate.
- if (procedure.name == null) {
- procedure.function = buildFunction(library);
- procedure.function.parent = procedure;
- procedure.function.fileOffset = charOpenParenOffset;
- procedure.function.fileEndOffset = procedure.fileEndOffset;
- procedure.isAbstract = isAbstract;
- procedure.isExternal = isExternal;
- procedure.isConst = isConst;
+ if (_procedure.name == null) {
+ _procedure.function = buildFunction(libraryBuilder);
+ _procedure.function.parent = _procedure;
+ _procedure.function.fileOffset = charOpenParenOffset;
+ _procedure.function.fileEndOffset = _procedure.fileEndOffset;
+ _procedure.isAbstract = isAbstract;
+ _procedure.isExternal = isExternal;
+ _procedure.isConst = isConst;
if (isExtensionMethod) {
- ExtensionBuilder extension = parent;
+ ExtensionBuilder extensionBuilder = parent;
procedure.isExtensionMember = true;
procedure.isStatic = true;
String kindInfix = '';
@@ -560,17 +601,171 @@
}
procedure.kind = ProcedureKind.Method;
}
- procedure.name =
- new Name('${extension.name}|${kindInfix}${name}', library.target);
+ procedure.name = new Name(
+ '${extensionBuilder.name}|${kindInfix}${name}',
+ libraryBuilder.library);
} else {
- procedure.isStatic = isStatic;
- procedure.name = new Name(name, library.target);
+ _procedure.isStatic = isStatic;
+ _procedure.name = new Name(name, libraryBuilder.library);
}
}
- return procedure;
+ if (extensionTearOff != null) {
+ _buildExtensionTearOff(libraryBuilder, parent);
+ }
+ return _procedure;
}
- Procedure get target => origin.procedure;
+ /// Creates a top level function that creates a tear off of an extension
+ /// instance method.
+ ///
+ /// For this declaration
+ ///
+ /// extension E<T> on A<T> {
+ /// X method<S>(S s, Y y) {}
+ /// }
+ ///
+ /// we create the top level function
+ ///
+ /// X E|method<T, S>(A<T> #this, S s, Y y) {}
+ ///
+ /// and the tear off function
+ ///
+ /// X Function<S>(S, Y) E|get#method<T>(A<T> #this) {
+ /// return (S s, Y y) => E|method<T, S>(#this, s, y);
+ /// }
+ ///
+ void _buildExtensionTearOff(
+ SourceLibraryBuilder libraryBuilder, ExtensionBuilder extensionBuilder) {
+ assert(
+ _extensionTearOff != null, "No extension tear off created for $this.");
+ if (_extensionTearOff.name != null) return;
+
+ int fileOffset = _procedure.fileOffset;
+
+ int extensionTypeParameterCount =
+ extensionBuilder.typeParameters?.length ?? 0;
+
+ List<TypeParameter> typeParameters = <TypeParameter>[];
+
+ List<DartType> typeArguments = <DartType>[];
+ for (TypeParameter typeParameter in function.typeParameters) {
+ TypeParameter newTypeParameter = new TypeParameter(typeParameter.name);
+ typeParameters.add(newTypeParameter);
+ typeArguments.add(new TypeParameterType(newTypeParameter));
+ }
+
+ List<TypeParameter> tearOffTypeParameters = <TypeParameter>[];
+ List<TypeParameter> closureTypeParameters = <TypeParameter>[];
+ Substitution substitution =
+ Substitution.fromPairs(function.typeParameters, typeArguments);
+ for (int index = 0; index < typeParameters.length; index++) {
+ TypeParameter newTypeParameter = typeParameters[index];
+ newTypeParameter.bound =
+ substitution.substituteType(function.typeParameters[index].bound);
+ newTypeParameter.defaultType = function.typeParameters[index].defaultType;
+ if (index < extensionTypeParameterCount) {
+ tearOffTypeParameters.add(newTypeParameter);
+ } else {
+ closureTypeParameters.add(newTypeParameter);
+ }
+ }
+
+ VariableDeclaration copyParameter(
+ VariableDeclaration parameter, DartType type,
+ {bool isOptional}) {
+ // TODO(johnniwinther): Handle default values.
+ return new VariableDeclaration(parameter.name,
+ type: type,
+ initializer: isOptional ? new NullLiteral() : null,
+ isFinal: parameter.isFinal)
+ ..fileOffset = parameter.fileOffset;
+ }
+
+ VariableDeclaration extensionThis = copyParameter(
+ function.positionalParameters.first,
+ substitution.substituteType(function.positionalParameters.first.type),
+ isOptional: false);
+
+ DartType closureReturnType =
+ substitution.substituteType(function.returnType);
+ List<VariableDeclaration> closurePositionalParameters = [];
+ List<Expression> closurePositionalArguments = [];
+
+ for (int position = 0;
+ position < function.positionalParameters.length;
+ position++) {
+ VariableDeclaration parameter = function.positionalParameters[position];
+ if (position == 0) {
+ /// Pass `this` as a captured variable.
+ closurePositionalArguments
+ .add(new VariableGet(extensionThis)..fileOffset = fileOffset);
+ } else {
+ DartType type = substitution.substituteType(parameter.type);
+ VariableDeclaration newParameter = copyParameter(parameter, type,
+ isOptional: position >= function.requiredParameterCount);
+ closurePositionalParameters.add(newParameter);
+ closurePositionalArguments
+ .add(new VariableGet(newParameter)..fileOffset = fileOffset);
+ }
+ }
+ List<VariableDeclaration> closureNamedParameters = [];
+ List<NamedExpression> closureNamedArguments = [];
+ for (VariableDeclaration parameter in function.namedParameters) {
+ DartType type = substitution.substituteType(parameter.type);
+ VariableDeclaration newParameter =
+ copyParameter(parameter, type, isOptional: true);
+ closureNamedParameters.add(newParameter);
+ closureNamedArguments.add(new NamedExpression(parameter.name,
+ new VariableGet(newParameter)..fileOffset = fileOffset));
+ }
+
+ Statement closureBody = new ReturnStatement(
+ new StaticInvocation(
+ procedure,
+ new Arguments(closurePositionalArguments,
+ types: typeArguments, named: closureNamedArguments))
+ ..fileOffset = fileOffset)
+ ..fileOffset = fileOffset;
+
+ FunctionExpression closure = new FunctionExpression(new FunctionNode(
+ closureBody,
+ typeParameters: closureTypeParameters,
+ positionalParameters: closurePositionalParameters,
+ namedParameters: closureNamedParameters,
+ requiredParameterCount: procedure.function.requiredParameterCount - 1,
+ returnType: closureReturnType,
+ asyncMarker: procedure.function.asyncMarker,
+ dartAsyncMarker: procedure.function.dartAsyncMarker))
+ ..fileOffset = fileOffset;
+
+ _extensionTearOff
+ ..name = new Name(
+ '${extensionBuilder.name}|get#${name}', libraryBuilder.library)
+ ..function = new FunctionNode(
+ new ReturnStatement(closure)..fileOffset = fileOffset,
+ typeParameters: tearOffTypeParameters,
+ positionalParameters: [extensionThis],
+ requiredParameterCount: 1,
+ returnType: closure.function.functionType)
+ ..fileUri = fileUri
+ ..fileOffset = fileOffset;
+ _extensionTearOff.function.parent = _extensionTearOff;
+ }
+
+ /// The [Procedure] built by this builder.
+ Procedure get procedure => isPatch ? origin.procedure : _procedure;
+
+ /// If this is an extension instance method then [_extensionTearOff] holds
+ /// the synthetically created tear off function.
+ Procedure get extensionTearOff {
+ if (isExtensionInstanceMember && kind == ProcedureKind.Method) {
+ _extensionTearOff ??= new Procedure(null, ProcedureKind.Method, null,
+ isStatic: true, isExtensionMember: true);
+ }
+ return _extensionTearOff;
+ }
+
+ Member get member => procedure;
@override
int finishPatch() {
@@ -579,22 +774,22 @@
// TODO(ahe): restore file-offset once we track both origin and patch file
// URIs. See https://github.com/dart-lang/sdk/issues/31579
origin.procedure.fileUri = fileUri;
- origin.procedure.startFileOffset = procedure.startFileOffset;
- origin.procedure.fileOffset = procedure.fileOffset;
- origin.procedure.fileEndOffset = procedure.fileEndOffset;
+ origin.procedure.startFileOffset = _procedure.startFileOffset;
+ origin.procedure.fileOffset = _procedure.fileOffset;
+ origin.procedure.fileEndOffset = _procedure.fileEndOffset;
origin.procedure.annotations
- .forEach((m) => m.fileOffset = procedure.fileOffset);
+ .forEach((m) => m.fileOffset = _procedure.fileOffset);
- origin.procedure.isAbstract = procedure.isAbstract;
- origin.procedure.isExternal = procedure.isExternal;
- origin.procedure.function = procedure.function;
+ origin.procedure.isAbstract = _procedure.isAbstract;
+ origin.procedure.isExternal = _procedure.isExternal;
+ origin.procedure.function = _procedure.function;
origin.procedure.function.parent = origin.procedure;
return 1;
}
@override
void becomeNative(Loader loader) {
- procedure.isExternal = true;
+ _procedure.isExternal = true;
super.becomeNative(loader);
}
@@ -612,7 +807,7 @@
// TODO(ahe): Move this to own file?
class ConstructorBuilder extends FunctionBuilder {
- final Constructor constructor;
+ final Constructor _constructor;
final int charOpenParenOffset;
@@ -627,6 +822,8 @@
@override
ConstructorBuilder actualOrigin;
+ Constructor get actualConstructor => _constructor;
+
ConstructorBuilder(
List<MetadataBuilder> metadata,
int modifiers,
@@ -640,7 +837,7 @@
this.charOpenParenOffset,
int charEndOffset,
[String nativeMethodName])
- : constructor = new Constructor(null, fileUri: compilationUnit?.fileUri)
+ : _constructor = new Constructor(null, fileUri: compilationUnit?.fileUri)
..startFileOffset = startCharOffset
..fileOffset = charOffset
..fileEndOffset = charEndOffset,
@@ -663,7 +860,7 @@
ProcedureKind get kind => null;
bool get isRedirectingGenerativeConstructor {
- return isRedirectingGenerativeConstructorImplementation(constructor);
+ return isRedirectingGenerativeConstructorImplementation(_constructor);
}
bool get isEligibleForTopLevelInference {
@@ -676,26 +873,27 @@
return false;
}
- Constructor build(SourceLibraryBuilder library) {
- if (constructor.name == null) {
- constructor.function = buildFunction(library);
- constructor.function.parent = constructor;
- constructor.function.fileOffset = charOpenParenOffset;
- constructor.function.fileEndOffset = constructor.fileEndOffset;
- constructor.function.typeParameters = const <TypeParameter>[];
- constructor.isConst = isConst;
- constructor.isExternal = isExternal;
- constructor.name = new Name(name, library.target);
+ Member build(SourceLibraryBuilder libraryBuilder) {
+ if (_constructor.name == null) {
+ _constructor.function = buildFunction(libraryBuilder);
+ _constructor.function.parent = _constructor;
+ _constructor.function.fileOffset = charOpenParenOffset;
+ _constructor.function.fileEndOffset = _constructor.fileEndOffset;
+ _constructor.function.typeParameters = const <TypeParameter>[];
+ _constructor.isConst = isConst;
+ _constructor.isExternal = isExternal;
+ _constructor.name = new Name(name, libraryBuilder.library);
}
if (isEligibleForTopLevelInference) {
for (FormalParameterBuilder formal in formals) {
if (formal.type == null && formal.isInitializingFormal) {
- formal.declaration.type = null;
+ formal.variable.type = null;
}
}
- library.loader.typeInferenceEngine.toBeInferred[constructor] = library;
+ libraryBuilder.loader.typeInferenceEngine.toBeInferred[_constructor] =
+ libraryBuilder;
}
- return constructor;
+ return _constructor;
}
@override
@@ -706,8 +904,9 @@
// for const constructors into the outline.
if (isConst && beginInitializers != null) {
ClassBuilder classBuilder = parent;
- BodyBuilder bodyBuilder = new BodyBuilder.forOutlineExpression(
- library, classBuilder, this, classBuilder.scope, fileUri);
+ BodyBuilder bodyBuilder = library.loader
+ .createBodyBuilderForOutlineExpression(
+ library, classBuilder, this, classBuilder.scope, fileUri);
bodyBuilder.constantContext = ConstantContext.inferred;
bodyBuilder.parseInitializers(beginInitializers);
bodyBuilder.resolveRedirectingFactoryTargets();
@@ -719,22 +918,26 @@
// According to the specification §9.3 the return type of a constructor
// function is its enclosing class.
FunctionNode functionNode = super.buildFunction(library);
- ClassBuilder enclosingClass = parent;
+ ClassBuilder enclosingClassBuilder = parent;
+ Class enclosingClass = enclosingClassBuilder.cls;
List<DartType> typeParameterTypes = new List<DartType>();
- for (int i = 0; i < enclosingClass.target.typeParameters.length; i++) {
- TypeParameter typeParameter = enclosingClass.target.typeParameters[i];
+ for (int i = 0; i < enclosingClass.typeParameters.length; i++) {
+ TypeParameter typeParameter = enclosingClass.typeParameters[i];
typeParameterTypes.add(new TypeParameterType(typeParameter));
}
functionNode.returnType =
- new InterfaceType(enclosingClass.target, typeParameterTypes);
+ new InterfaceType(enclosingClass, typeParameterTypes);
return functionNode;
}
- Constructor get target => origin.constructor;
+ /// The [Constructor] built by this builder.
+ Constructor get constructor => isPatch ? origin.constructor : _constructor;
+
+ Member get member => constructor;
void injectInvalidInitializer(
Message message, int charOffset, ExpressionGeneratorHelper helper) {
- List<Initializer> initializers = constructor.initializers;
+ List<Initializer> initializers = _constructor.initializers;
Initializer lastInitializer = initializers.removeLast();
assert(lastInitializer == superInitializer ||
lastInitializer == redirectingInitializer);
@@ -742,34 +945,34 @@
helper.desugarSyntheticExpression(
helper.buildProblem(message, charOffset, noLength)),
charOffset);
- initializers.add(error..parent = constructor);
+ initializers.add(error..parent = _constructor);
initializers.add(lastInitializer);
}
void addInitializer(
Initializer initializer, ExpressionGeneratorHelper helper) {
- List<Initializer> initializers = constructor.initializers;
+ List<Initializer> initializers = _constructor.initializers;
if (initializer is SuperInitializer) {
if (superInitializer != null || redirectingInitializer != null) {
injectInvalidInitializer(messageMoreThanOneSuperOrThisInitializer,
initializer.fileOffset, helper);
} else {
- initializers.add(initializer..parent = constructor);
+ initializers.add(initializer..parent = _constructor);
superInitializer = initializer;
}
} else if (initializer is RedirectingInitializer) {
if (superInitializer != null || redirectingInitializer != null) {
injectInvalidInitializer(messageMoreThanOneSuperOrThisInitializer,
initializer.fileOffset, helper);
- } else if (constructor.initializers.isNotEmpty) {
- Initializer first = constructor.initializers.first;
+ } else if (_constructor.initializers.isNotEmpty) {
+ Initializer first = _constructor.initializers.first;
Initializer error = helper.buildInvalidInitializer(
helper.desugarSyntheticExpression(helper.buildProblem(
messageThisInitializerNotAlone, first.fileOffset, noLength)),
first.fileOffset);
- initializers.add(error..parent = constructor);
+ initializers.add(error..parent = _constructor);
} else {
- initializers.add(initializer..parent = constructor);
+ initializers.add(initializer..parent = _constructor);
redirectingInitializer = initializer;
}
} else if (redirectingInitializer != null) {
@@ -779,7 +982,7 @@
injectInvalidInitializer(
messageSuperInitializerNotLast, superInitializer.fileOffset, helper);
} else {
- initializers.add(initializer..parent = constructor);
+ initializers.add(initializer..parent = _constructor);
}
}
@@ -790,23 +993,23 @@
// TODO(ahe): restore file-offset once we track both origin and patch file
// URIs. See https://github.com/dart-lang/sdk/issues/31579
origin.constructor.fileUri = fileUri;
- origin.constructor.startFileOffset = constructor.startFileOffset;
- origin.constructor.fileOffset = constructor.fileOffset;
- origin.constructor.fileEndOffset = constructor.fileEndOffset;
+ origin.constructor.startFileOffset = _constructor.startFileOffset;
+ origin.constructor.fileOffset = _constructor.fileOffset;
+ origin.constructor.fileEndOffset = _constructor.fileEndOffset;
origin.constructor.annotations
- .forEach((m) => m.fileOffset = constructor.fileOffset);
+ .forEach((m) => m.fileOffset = _constructor.fileOffset);
- origin.constructor.isExternal = constructor.isExternal;
- origin.constructor.function = constructor.function;
+ origin.constructor.isExternal = _constructor.isExternal;
+ origin.constructor.function = _constructor.function;
origin.constructor.function.parent = origin.constructor;
- origin.constructor.initializers = constructor.initializers;
+ origin.constructor.initializers = _constructor.initializers;
setParents(origin.constructor.initializers, origin.constructor);
return 1;
}
@override
void becomeNative(Loader loader) {
- constructor.isExternal = true;
+ _constructor.isExternal = true;
super.becomeNative(loader);
}
@@ -828,8 +1031,8 @@
// again.
// Note: this method clears both initializers from the target Kernel node
// and internal state associated with parsing initializers.
- if (target.isConst) {
- target.initializers.length = 0;
+ if (constructor.isConst) {
+ constructor.initializers.length = 0;
redirectingInitializer = null;
superInitializer = null;
hasMovedSuperInitializer = false;
@@ -871,12 +1074,12 @@
nativeMethodName);
@override
- Statement get body => actualBody;
+ Statement get body => _body;
@override
void setRedirectingFactoryBody(Member target, List<DartType> typeArguments) {
- if (actualBody != null) {
- unexpected("null", "${actualBody.runtimeType}", charOffset, fileUri);
+ if (_body != null) {
+ unexpected("null", "${_body.runtimeType}", charOffset, fileUri);
}
// Ensure that constant factories only have constant targets/bodies.
@@ -885,9 +1088,9 @@
noLength, fileUri);
}
- actualBody = new RedirectingFactoryBody(target, typeArguments);
- function.body = actualBody;
- actualBody?.parent = function;
+ _body = new RedirectingFactoryBody(target, typeArguments);
+ function.body = _body;
+ _body?.parent = function;
if (isPatch) {
if (function.typeParameters != null) {
Map<TypeParameter, DartType> substitution = <TypeParameter, DartType>{};
diff --git a/pkg/front_end/lib/src/fasta/builder/type_alias_builder.dart b/pkg/front_end/lib/src/fasta/builder/type_alias_builder.dart
index 3a151b4..35afd4b 100644
--- a/pkg/front_end/lib/src/fasta/builder/type_alias_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/type_alias_builder.dart
@@ -10,6 +10,7 @@
DynamicType,
FunctionType,
InvalidType,
+ Nullability,
TypeParameter,
Typedef,
VariableDeclaration;
@@ -29,7 +30,7 @@
TypeBuilder,
TypeVariableBuilder;
-import '../problems.dart' show unhandled;
+import '../problems.dart' show unhandled, unsupported;
import '../source/source_library_builder.dart' show SourceLibraryBuilder;
@@ -41,32 +42,43 @@
TypeDeclarationBuilder,
TypeVariableBuilder;
+import 'declaration.dart';
+
class TypeAliasBuilder extends TypeDeclarationBuilder {
final TypeBuilder type;
final List<TypeVariableBuilder> typeVariables;
- final Typedef target;
+ /// The [Typedef] built by this builder.
+ final Typedef typedef;
DartType thisType;
TypeAliasBuilder(List<MetadataBuilder> metadata, String name,
this.typeVariables, this.type, LibraryBuilder parent, int charOffset,
- [Typedef target])
- : target = target ??
+ [Typedef typedef])
+ : typedef = typedef ??
(new Typedef(name, null,
typeParameters: TypeVariableBuilder.typeParametersFromBuilders(
typeVariables),
- fileUri: parent.target.fileUri)
+ fileUri: parent.library.fileUri)
..fileOffset = charOffset),
super(metadata, 0, name, parent, charOffset);
+ // Deliberately unrelated return type to statically detect more accidental
+ // use until Builder.target is fully retired.
+ UnrelatedTarget get target => unsupported(
+ "TypeAliasBuilder.target is deprecated. "
+ "Use TypeAliasBuilder.typedef instead.",
+ charOffset,
+ fileUri);
+
String get debugName => "TypeAliasBuilder";
LibraryBuilder get parent => super.parent;
Typedef build(SourceLibraryBuilder libraryBuilder) {
- target..type ??= buildThisType(libraryBuilder);
+ typedef..type ??= buildThisType(libraryBuilder);
TypeBuilder type = this.type;
if (type is FunctionTypeBuilder) {
@@ -78,7 +90,7 @@
}
FreshTypeParameters freshTypeParameters =
getFreshTypeParameters(typeParameters);
- target.typeParametersOfFunctionType
+ typedef.typeParametersOfFunctionType
.addAll(freshTypeParameters.freshTypeParameters);
if (type.formals != null) {
@@ -86,9 +98,9 @@
VariableDeclaration parameter = formal.build(libraryBuilder, 0);
parameter.type = freshTypeParameters.substitute(parameter.type);
if (formal.isNamed) {
- target.namedParameters.add(parameter);
+ typedef.namedParameters.add(parameter);
} else {
- target.positionalParameters.add(parameter);
+ typedef.positionalParameters.add(parameter);
}
}
}
@@ -96,7 +108,7 @@
unhandled("${type.fullNameForErrors}", "build", charOffset, fileUri);
}
- return target;
+ return typedef;
}
DartType buildThisType(LibraryBuilder library) {
@@ -114,7 +126,7 @@
thisType = cyclicTypeAliasMarker;
TypeBuilder type = this.type;
if (type is FunctionTypeBuilder) {
- FunctionType builtType = type?.build(library, target.thisType);
+ FunctionType builtType = type?.build(library, typedef.thisType);
if (builtType != null) {
if (typeVariables != null) {
for (TypeVariableBuilder tv in typeVariables) {
@@ -135,15 +147,16 @@
}
/// [arguments] have already been built.
- DartType buildTypesWithBuiltArguments(
- LibraryBuilder library, List<DartType> arguments) {
+ DartType buildTypesWithBuiltArguments(LibraryBuilder library,
+ Nullability nullability, List<DartType> arguments) {
+ // TODO(dmitryas): Use [nullability].
DartType thisType = buildThisType(library);
if (const DynamicType() == thisType) return thisType;
FunctionType result = thisType;
- if (target.typeParameters.isEmpty && arguments == null) return result;
+ if (typedef.typeParameters.isEmpty && arguments == null) return result;
Map<TypeParameter, DartType> substitution = <TypeParameter, DartType>{};
- for (int i = 0; i < target.typeParameters.length; i++) {
- substitution[target.typeParameters[i]] = arguments[i];
+ for (int i = 0; i < typedef.typeParameters.length; i++) {
+ substitution[typedef.typeParameters[i]] = arguments[i];
}
return substitute(result, substitution);
}
@@ -191,14 +204,15 @@
int get typeVariablesCount => typeVariables?.length ?? 0;
@override
- DartType buildType(LibraryBuilder library, List<TypeBuilder> arguments) {
+ DartType buildType(LibraryBuilder library, Nullability nullability,
+ List<TypeBuilder> arguments) {
DartType thisType = buildThisType(library);
if (thisType is InvalidType) return thisType;
FunctionType result = thisType;
- if (target.typeParameters.isEmpty && arguments == null) return result;
+ if (typedef.typeParameters.isEmpty && arguments == null) return result;
// Otherwise, substitute.
return buildTypesWithBuiltArguments(
- library, buildTypeArguments(library, arguments));
+ library, nullability, buildTypeArguments(library, arguments));
}
}
diff --git a/pkg/front_end/lib/src/fasta/builder/type_builder.dart b/pkg/front_end/lib/src/fasta/builder/type_builder.dart
index 0c0b5f9..d3bf14f 100644
--- a/pkg/front_end/lib/src/fasta/builder/type_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/type_builder.dart
@@ -8,8 +8,11 @@
import '../fasta_codes.dart' show LocatedMessage;
-import 'builder.dart'
- show LibraryBuilder, Scope, TypeDeclarationBuilder, TypeVariableBuilder;
+import '../scope.dart';
+import 'library_builder.dart';
+import 'named_type_builder.dart';
+import 'type_declaration_builder.dart';
+import 'type_variable_builder.dart';
abstract class TypeBuilder {
const TypeBuilder();
@@ -36,7 +39,18 @@
String toString() => "$debugName(${printOn(new StringBuffer())})";
- TypeBuilder subst(Map<TypeVariableBuilder, TypeBuilder> substitution) => this;
+ /// Returns the [TypeBuilder] for this type in which [TypeVariableBuilder]s
+ /// in [substitution] have been replaced by the corresponding [TypeBuilder]s.
+ ///
+ /// If [unboundTypes] is provided, created type builders that are not bound
+ /// are added to [unboundTypes]. Otherwise, creating an unbound type builder
+ /// throws an error.
+ // TODO(johnniwinther): Change [NamedTypeBuilder] to hold the
+ // [TypeParameterScopeBuilder] should resolve it, so that we cannot create
+ // [NamedTypeBuilder]s that are orphaned.
+ TypeBuilder subst(Map<TypeVariableBuilder, TypeBuilder> substitution,
+ [List<NamedTypeBuilder> unboundTypes]) =>
+ this;
/// Clones the type builder recursively without binding the subterms to
/// existing declaration or type variable builders. All newly built types
diff --git a/pkg/front_end/lib/src/fasta/builder/type_declaration_builder.dart b/pkg/front_end/lib/src/fasta/builder/type_declaration_builder.dart
index fa2c7bd..e25faa6 100644
--- a/pkg/front_end/lib/src/fasta/builder/type_declaration_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/type_declaration_builder.dart
@@ -4,7 +4,7 @@
library fasta.type_declaration_builder;
-import 'package:kernel/ast.dart' show DartType;
+import 'package:kernel/ast.dart' show DartType, Nullability;
import 'builder.dart'
show Builder, LibraryBuilder, MetadataBuilder, ModifierBuilder, TypeBuilder;
@@ -31,9 +31,10 @@
int get typeVariablesCount => 0;
- DartType buildType(LibraryBuilder library, List<TypeBuilder> arguments);
+ DartType buildType(LibraryBuilder library, Nullability nullability,
+ List<TypeBuilder> arguments);
/// [arguments] have already been built.
- DartType buildTypesWithBuiltArguments(
- LibraryBuilder library, List<DartType> arguments);
+ DartType buildTypesWithBuiltArguments(LibraryBuilder library,
+ Nullability nullability, List<DartType> arguments);
}
diff --git a/pkg/front_end/lib/src/fasta/builder/type_variable_builder.dart b/pkg/front_end/lib/src/fasta/builder/type_variable_builder.dart
index 05f880f..bea9904 100644
--- a/pkg/front_end/lib/src/fasta/builder/type_variable_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/type_variable_builder.dart
@@ -4,18 +4,27 @@
library fasta.type_variable_builder;
-import 'builder.dart' show LibraryBuilder, TypeBuilder, TypeDeclarationBuilder;
+import 'builder.dart'
+ show
+ LibraryBuilder,
+ NullabilityBuilder,
+ TypeBuilder,
+ TypeDeclarationBuilder;
import 'package:kernel/ast.dart'
- show DartType, TypeParameter, TypeParameterType;
+ show DartType, Nullability, TypeParameter, TypeParameterType;
import '../fasta_codes.dart' show templateTypeArgumentsOnTypeVariable;
import '../kernel/kernel_builder.dart'
show ClassBuilder, NamedTypeBuilder, LibraryBuilder, TypeBuilder;
+import '../problems.dart' show unsupported;
+
import '../source/source_library_builder.dart' show SourceLibraryBuilder;
+import 'declaration.dart';
+
class TypeVariableBuilder extends TypeDeclarationBuilder {
TypeBuilder bound;
@@ -25,17 +34,21 @@
TypeVariableBuilder actualOrigin;
+ final bool isExtensionTypeParameter;
+
TypeVariableBuilder(
String name, SourceLibraryBuilder compilationUnit, int charOffset,
- {this.bound, bool synthesizeTypeParameterName: false})
- : actualParameter = new TypeParameter(
- synthesizeTypeParameterName ? '#$name' : name, null)
+ {this.bound, this.isExtensionTypeParameter: false})
+ : actualParameter = new TypeParameter(name, null)
..fileOffset = charOffset,
super(null, 0, name, compilationUnit, charOffset);
TypeVariableBuilder.fromKernel(
TypeParameter parameter, LibraryBuilder compilationUnit)
: actualParameter = parameter,
+ // TODO(johnniwinther): Do we need to support synthesized type
+ // parameters from kernel?
+ this.isExtensionTypeParameter = false,
super(null, 0, parameter.name, compilationUnit, parameter.fileOffset);
bool get isTypeVariable => true;
@@ -55,11 +68,20 @@
TypeVariableBuilder get origin => actualOrigin ?? this;
+ /// The [TypeParameter] built by this builder.
TypeParameter get parameter => origin.actualParameter;
- TypeParameter get target => parameter;
+ // Deliberately unrelated return type to statically detect more accidental
+ // uses until Builder.target is fully retired.
+ UnrelatedTarget get target => unsupported(
+ "TypeVariableBuilder.target is deprecated. "
+ "Use TypeVariableBuilder.parameter instead.",
+ charOffset,
+ fileUri);
- DartType buildType(LibraryBuilder library, List<TypeBuilder> arguments) {
+ DartType buildType(LibraryBuilder library, Nullability nullability,
+ List<TypeBuilder> arguments) {
+ // TODO(dmitryas): Use [nullability].
if (arguments != null) {
int charOffset = -1; // TODO(ahe): Provide these.
Uri fileUri = null; // TODO(ahe): Provide these.
@@ -72,8 +94,8 @@
return new TypeParameterType(parameter);
}
- DartType buildTypesWithBuiltArguments(
- LibraryBuilder library, List<DartType> arguments) {
+ DartType buildTypesWithBuiltArguments(LibraryBuilder library,
+ Nullability nullability, List<DartType> arguments) {
if (arguments != null) {
int charOffset = -1; // TODO(ahe): Provide these.
Uri fileUri = null; // TODO(ahe): Provide these.
@@ -83,17 +105,20 @@
name.length,
fileUri);
}
- return buildType(library, null);
+ return buildType(library, nullability, null);
}
TypeBuilder asTypeBuilder() {
- return new NamedTypeBuilder(name, null)..bind(this);
+ return new NamedTypeBuilder(
+ name, const NullabilityBuilder.pendingImplementation(), null)
+ ..bind(this);
}
void finish(
LibraryBuilder library, ClassBuilder object, TypeBuilder dynamicType) {
if (isPatch) return;
- DartType objectType = object.buildType(library, null);
+ // TODO(dmitryas): Set the nullability of objectType correctly.
+ DartType objectType = object.buildType(library, Nullability.legacy, null);
parameter.bound ??= bound?.build(library) ?? objectType;
// If defaultType is not set, initialize it to dynamic, unless the bound is
// explicitly specified as Object, in which case defaultType should also be
@@ -119,11 +144,11 @@
@override
bool operator ==(Object other) {
- return other is TypeVariableBuilder && target == other.target;
+ return other is TypeVariableBuilder && parameter == other.parameter;
}
@override
- int get hashCode => target.hashCode;
+ int get hashCode => parameter.hashCode;
static List<TypeParameter> typeParametersFromBuilders(
List<TypeVariableBuilder> builders) {
@@ -131,7 +156,7 @@
List<TypeParameter> result =
new List<TypeParameter>.filled(builders.length, null, growable: true);
for (int i = 0; i < builders.length; i++) {
- result[i] = builders[i].target;
+ result[i] = builders[i].parameter;
}
return result;
}
diff --git a/pkg/front_end/lib/src/fasta/compiler_context.dart b/pkg/front_end/lib/src/fasta/compiler_context.dart
index 4aabb61..98d4be9 100644
--- a/pkg/front_end/lib/src/fasta/compiler_context.dart
+++ b/pkg/front_end/lib/src/fasta/compiler_context.dart
@@ -56,6 +56,8 @@
Uri cachedSdkRoot = null;
+ bool compilingPlatform = false;
+
CompilerContext(this.options);
void disableColors() {
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_class_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_class_builder.dart
index c7e42fe..eec951a 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_class_builder.dart
@@ -18,7 +18,7 @@
Scope,
TypeVariableBuilder;
-import '../modifier.dart' show abstractMask;
+import '../modifier.dart' show abstractMask, namedMixinApplicationMask;
import 'dill_library_builder.dart' show DillLibraryBuilder;
@@ -37,9 +37,15 @@
null,
null,
null,
- new Scope(<String, MemberBuilder>{}, <String, MemberBuilder>{},
- parent.scope, "class ${cls.name}", isModifiable: false),
- new Scope(<String, MemberBuilder>{}, null, null, cls.name,
+ new Scope(
+ local: <String, MemberBuilder>{},
+ setters: <String, MemberBuilder>{},
+ parent: parent.scope,
+ debugName: "class ${cls.name}",
+ isModifiable: false),
+ new Scope(
+ local: <String, MemberBuilder>{},
+ debugName: cls.name,
isModifiable: false),
parent,
cls.fileOffset);
@@ -136,7 +142,14 @@
}
int computeModifiers(Class cls) {
- return cls.isAbstract ? abstractMask : 0;
+ int modifiers = 0;
+ if (cls.isAbstract) {
+ modifiers |= abstractMask;
+ }
+ if (cls.isMixinApplication && cls.name != null) {
+ modifiers |= namedMixinApplicationMask;
+ }
+ return modifiers;
}
TypeBuilder computeTypeBuilder(
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_extension_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_extension_builder.dart
new file mode 100644
index 0000000..f0b1108
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/dill/dill_extension_builder.dart
@@ -0,0 +1,89 @@
+// Copyright (c) 2019, 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:core' hide MapEntry;
+
+import 'package:kernel/ast.dart';
+
+import '../builder/extension_builder.dart';
+import '../builder/library_builder.dart';
+import '../builder/type_builder.dart';
+import '../builder/type_variable_builder.dart';
+import '../kernel/kernel_builder.dart';
+import '../scope.dart';
+
+import 'dill_class_builder.dart';
+import 'dill_extension_member_builder.dart';
+
+class DillExtensionBuilder extends ExtensionBuilder {
+ final Extension extension;
+ List<TypeVariableBuilder> _typeParameters;
+ TypeBuilder _onType;
+
+ DillExtensionBuilder(this.extension, LibraryBuilder parent)
+ : super(
+ null,
+ 0,
+ extension.name,
+ parent,
+ extension.fileOffset,
+ new Scope(
+ local: <String, MemberBuilder>{},
+ setters: <String, MemberBuilder>{},
+ parent: parent.scope,
+ debugName: "extension ${extension.name}",
+ isModifiable: false),
+ null,
+ null) {
+ Map<Name, ExtensionMemberDescriptor> _methods = {};
+ Map<Name, Member> _tearOffs = {};
+ for (ExtensionMemberDescriptor descriptor in extension.members) {
+ Name name = descriptor.name;
+ switch (descriptor.kind) {
+ case ExtensionMemberKind.Method:
+ _methods[name] = descriptor;
+ break;
+ case ExtensionMemberKind.TearOff:
+ _tearOffs[name] = descriptor.member.asMember;
+ break;
+ case ExtensionMemberKind.Getter:
+ case ExtensionMemberKind.Operator:
+ case ExtensionMemberKind.Field:
+ Member member = descriptor.member.asMember;
+ scopeBuilder.addMember(name.name,
+ new DillExtensionMemberBuilder(member, descriptor, this));
+ break;
+ case ExtensionMemberKind.Setter:
+ Member member = descriptor.member.asMember;
+ scopeBuilder.addSetter(name.name,
+ new DillExtensionMemberBuilder(member, descriptor, this));
+ break;
+ }
+ }
+ _methods.forEach((Name name, ExtensionMemberDescriptor descriptor) {
+ Member member = descriptor.member.asMember;
+ scopeBuilder.addMember(
+ name.name,
+ new DillExtensionMemberBuilder(
+ member, descriptor, this, _tearOffs[name]));
+ });
+ }
+
+ @override
+ List<TypeVariableBuilder> get typeParameters {
+ if (_typeParameters == null && extension.typeParameters.isNotEmpty) {
+ _typeParameters =
+ computeTypeVariableBuilders(library, extension.typeParameters);
+ }
+ return _typeParameters;
+ }
+
+ @override
+ TypeBuilder get onType {
+ if (_onType == null) {
+ _onType = library.loader.computeTypeBuilder(extension.onType);
+ }
+ return _onType;
+ }
+}
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_extension_member_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_extension_member_builder.dart
new file mode 100644
index 0000000..b46cd36
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/dill/dill_extension_member_builder.dart
@@ -0,0 +1,61 @@
+// Copyright (c) 2019, 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:core' hide MapEntry;
+
+import 'package:kernel/ast.dart';
+
+import '../builder/declaration.dart';
+
+import '../problems.dart';
+
+import 'dill_member_builder.dart';
+
+class DillExtensionMemberBuilder extends DillMemberBuilder {
+ final ExtensionMemberDescriptor _descriptor;
+
+ @override
+ final Member extensionTearOff;
+
+ DillExtensionMemberBuilder(Member member, this._descriptor, Builder parent,
+ [this.extensionTearOff])
+ : super(member, parent);
+
+ @override
+ bool get isStatic => _descriptor.isStatic;
+
+ @override
+ bool get isExternal => _descriptor.isExternal;
+
+ @override
+ Procedure get procedure {
+ switch (_descriptor.kind) {
+ case ExtensionMemberKind.Method:
+ case ExtensionMemberKind.Getter:
+ case ExtensionMemberKind.Operator:
+ case ExtensionMemberKind.Setter:
+ return member;
+ case ExtensionMemberKind.TearOff:
+ case ExtensionMemberKind.Field:
+ }
+ return unsupported("procedure", charOffset, fileUri);
+ }
+
+ @override
+ ProcedureKind get kind {
+ switch (_descriptor.kind) {
+ case ExtensionMemberKind.Method:
+ return ProcedureKind.Method;
+ case ExtensionMemberKind.Getter:
+ return ProcedureKind.Getter;
+ case ExtensionMemberKind.Operator:
+ return ProcedureKind.Operator;
+ case ExtensionMemberKind.Setter:
+ return ProcedureKind.Setter;
+ case ExtensionMemberKind.TearOff:
+ case ExtensionMemberKind.Field:
+ }
+ return null;
+ }
+}
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart
index f95d327..56c203ae 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart
@@ -11,6 +11,7 @@
Class,
DartType,
DynamicType,
+ Extension,
Field,
FunctionType,
Library,
@@ -33,6 +34,12 @@
import '../problems.dart' show internalProblem, unhandled, unimplemented;
+import '../builder/class_builder.dart';
+
+import '../builder/member_builder.dart';
+
+import '../builder/type_alias_builder.dart';
+
import '../kernel/kernel_builder.dart'
show Builder, DynamicTypeBuilder, InvalidTypeBuilder, LibraryBuilder, Scope;
@@ -40,6 +47,8 @@
import 'dill_class_builder.dart' show DillClassBuilder;
+import 'dill_extension_builder.dart';
+
import 'dill_member_builder.dart' show DillMemberBuilder;
import 'dill_loader.dart' show DillLoader;
@@ -50,9 +59,13 @@
DillLibraryBuilder libraryBuilder;
LazyLibraryScope(Map<String, Builder> local, Map<String, Builder> setters,
- Scope parent, String debugName,
- {bool isModifiable: true})
- : super(local, setters, parent, debugName, isModifiable: isModifiable);
+ Scope parent, String debugName, {bool isModifiable: true})
+ : super(
+ local: local,
+ setters: setters,
+ parent: parent,
+ debugName: debugName,
+ isModifiable: isModifiable);
LazyLibraryScope.top({bool isModifiable: false})
: this(<String, Builder>{}, <String, Builder>{}, null, "top",
@@ -72,6 +85,7 @@
}
class DillLibraryBuilder extends LibraryBuilder {
+ @override
final Library library;
DillLoader loader;
@@ -106,6 +120,7 @@
if (isBuilt) return;
isBuilt = true;
library.classes.forEach(addClass);
+ library.extensions.forEach(addExtension);
library.procedures.forEach(addMember);
library.typedefs.forEach(addTypedef);
library.fields.forEach(addMember);
@@ -131,9 +146,6 @@
@override
String get name => library.name;
- @override
- Library get target => library;
-
void addSyntheticDeclarationOfDynamic() {
addBuilder(
"dynamic", new DynamicTypeBuilder(const DynamicType(), this, -1), -1);
@@ -156,6 +168,12 @@
}
}
+ void addExtension(Extension extension) {
+ DillExtensionBuilder extensionBuilder =
+ new DillExtensionBuilder(extension, this);
+ addBuilder(extension.name, extensionBuilder, extension.fileOffset);
+ }
+
void addMember(Member member) {
String name = member.name.name;
if (name == "_exports#") {
@@ -298,7 +316,9 @@
-1,
fileUri);
}
- assert(node == declaration.target);
+ assert((declaration is ClassBuilder && node == declaration.cls) ||
+ (declaration is TypeAliasBuilder && node == declaration.typedef) ||
+ (declaration is MemberBuilder && node == declaration.member));
}
}
}
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart
index 1884cfc..4e04550 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart
@@ -30,8 +30,6 @@
String get debugName => "DillMemberBuilder";
- Member get target => member;
-
String get name => member.name.name;
bool get isConstructor => member is Constructor;
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_type_alias_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_type_alias_builder.dart
index dce2cac..42b6dd1 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_type_alias_builder.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_type_alias_builder.dart
@@ -28,7 +28,7 @@
}
@override
- int get typeVariablesCount => target.typeParameters.length;
+ int get typeVariablesCount => typedef.typeParameters.length;
@override
FunctionTypeBuilder get type {
@@ -37,7 +37,7 @@
@override
DartType buildThisType(LibraryBuilder library) {
- return thisType ??= target.type;
+ return thisType ??= typedef.type;
}
@override
@@ -48,10 +48,10 @@
// [cls.typeParameters].
if (arguments == null) {
List<DartType> result = new List<DartType>.filled(
- target.typeParameters.length, null,
+ typedef.typeParameters.length, null,
growable: true);
for (int i = 0; i < result.length; ++i) {
- result[i] = target.typeParameters[i].defaultType;
+ result[i] = typedef.typeParameters[i].defaultType;
}
return result;
}
diff --git a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
index cb27792..d5482bf 100644
--- a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
+++ b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
@@ -1719,6 +1719,14 @@
message: r"""Null value during constant evaluation.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeConstEvalStartingPoint = messageConstEvalStartingPoint;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageConstEvalStartingPoint = const MessageCode(
+ "ConstEvalStartingPoint",
+ message: r"""Constant evaluation error:""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeConstEvalUnevaluated = messageConstEvalUnevaluated;
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3300,6 +3308,47 @@
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeExplicitExtensionArgumentMismatch =
+ messageExplicitExtensionArgumentMismatch;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageExplicitExtensionArgumentMismatch = const MessageCode(
+ "ExplicitExtensionArgumentMismatch",
+ message:
+ r"""Explicit extension application requires exactly 1 positional argument.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+ Message Function(
+ String name,
+ int
+ count)> templateExplicitExtensionTypeArgumentMismatch = const Template<
+ Message Function(String name, int count)>(
+ messageTemplate:
+ r"""Explicit extension application of extension '#name' takes '#count' type argument(s).""",
+ withArguments: _withArgumentsExplicitExtensionTypeArgumentMismatch);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name, int count)>
+ codeExplicitExtensionTypeArgumentMismatch =
+ const Code<Message Function(String name, int count)>(
+ "ExplicitExtensionTypeArgumentMismatch",
+ templateExplicitExtensionTypeArgumentMismatch,
+);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsExplicitExtensionTypeArgumentMismatch(
+ String name, int count) {
+ if (name.isEmpty) throw 'No name provided';
+ name = demangleMixinApplicationName(name);
+ if (count == null) throw 'No count provided';
+ return new Message(codeExplicitExtensionTypeArgumentMismatch,
+ message:
+ """Explicit extension application of extension '${name}' takes '${count}' type argument(s).""",
+ arguments: {'name': name, 'count': count});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeExportAfterPart = messageExportAfterPart;
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3390,6 +3439,39 @@
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeExtensionDeclaresAbstractMember =
+ messageExtensionDeclaresAbstractMember;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageExtensionDeclaresAbstractMember = const MessageCode(
+ "ExtensionDeclaresAbstractMember",
+ index: 94,
+ message: r"""Extensions can't declare abstract members.""",
+ tip: r"""Try providing an implementation for the member.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeExtensionDeclaresConstructor =
+ messageExtensionDeclaresConstructor;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageExtensionDeclaresConstructor = const MessageCode(
+ "ExtensionDeclaresConstructor",
+ index: 92,
+ message: r"""Extensions can't declare constructors.""",
+ tip: r"""Try removing the constructor declaration.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeExtensionDeclaresInstanceField =
+ messageExtensionDeclaresInstanceField;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageExtensionDeclaresInstanceField = const MessageCode(
+ "ExtensionDeclaresInstanceField",
+ index: 93,
+ message: r"""Extensions can't declare instance fields""",
+ tip: r"""Try removing the field declaration or making it a static field""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeExternalClass = messageExternalClass;
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3673,6 +3755,81 @@
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeFfiExceptionalReturnNull = messageFfiExceptionalReturnNull;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageFfiExceptionalReturnNull = const MessageCode(
+ "FfiExceptionalReturnNull",
+ message: r"""Exceptional return value must not be null.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeFfiExpectedConstant = messageFfiExpectedConstant;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageFfiExpectedConstant = const MessageCode(
+ "FfiExpectedConstant",
+ message: r"""Exceptional return value must be a constant.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+ Message Function(
+ DartType
+ _type)> templateFfiExpectedExceptionalReturn = const Template<
+ Message Function(DartType _type)>(
+ messageTemplate:
+ r"""Expected an exceptional return value for a native callback returning '#type'.""",
+ withArguments: _withArgumentsFfiExpectedExceptionalReturn);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(DartType _type)> codeFfiExpectedExceptionalReturn =
+ const Code<Message Function(DartType _type)>(
+ "FfiExpectedExceptionalReturn",
+ templateFfiExpectedExceptionalReturn,
+);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsFfiExpectedExceptionalReturn(DartType _type) {
+ TypeLabeler labeler = new TypeLabeler();
+ List<Object> typeParts = labeler.labelType(_type);
+ String type = typeParts.join();
+ return new Message(codeFfiExpectedExceptionalReturn,
+ message:
+ """Expected an exceptional return value for a native callback returning '${type}'.""" +
+ labeler.originMessages,
+ arguments: {'type': _type});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+ Message Function(
+ DartType
+ _type)> templateFfiExpectedNoExceptionalReturn = const Template<
+ Message Function(DartType _type)>(
+ messageTemplate:
+ r"""Exceptional return value cannot be provided for a native callback returning '#type'.""",
+ withArguments: _withArgumentsFfiExpectedNoExceptionalReturn);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(DartType _type)>
+ codeFfiExpectedNoExceptionalReturn =
+ const Code<Message Function(DartType _type)>(
+ "FfiExpectedNoExceptionalReturn",
+ templateFfiExpectedNoExceptionalReturn,
+);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsFfiExpectedNoExceptionalReturn(DartType _type) {
+ TypeLabeler labeler = new TypeLabeler();
+ List<Object> typeParts = labeler.labelType(_type);
+ String type = typeParts.join();
+ return new Message(codeFfiExpectedNoExceptionalReturn,
+ message:
+ """Exceptional return value cannot be provided for a native callback returning '${type}'.""" +
+ labeler.originMessages,
+ arguments: {'type': _type});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<Message Function(String name)>
templateFfiExtendsOrImplementsSealedClass =
const Template<Message Function(String name)>(
@@ -3702,7 +3859,7 @@
Message Function(String name)> templateFfiFieldAnnotation = const Template<
Message Function(String name)>(
messageTemplate:
- r"""Field '#name' requires exactly one annotation to declare its C++ type, which cannot be Void. dart:ffi Structs cannot have regular Dart fields.""",
+ r"""Field '#name' requires exactly one annotation to declare its native type, which cannot be Void. dart:ffi Structs cannot have regular Dart fields.""",
withArguments: _withArgumentsFfiFieldAnnotation);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3718,7 +3875,7 @@
name = demangleMixinApplicationName(name);
return new Message(codeFfiFieldAnnotation,
message:
- """Field '${name}' requires exactly one annotation to declare its C++ type, which cannot be Void. dart:ffi Structs cannot have regular Dart fields.""",
+ """Field '${name}' requires exactly one annotation to declare its native type, which cannot be Void. dart:ffi Structs cannot have regular Dart fields.""",
arguments: {'name': name});
}
@@ -3754,7 +3911,7 @@
name)> templateFfiFieldNoAnnotation = const Template<
Message Function(String name)>(
messageTemplate:
- r"""Field '#name' requires no annotation to declare its C++ type, it is a Pointer which is represented by the same type in Dart and C++.""",
+ r"""Field '#name' requires no annotation to declare its native type, it is a Pointer which is represented by the same type in Dart and native code.""",
withArguments: _withArgumentsFfiFieldNoAnnotation);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3770,7 +3927,7 @@
name = demangleMixinApplicationName(name);
return new Message(codeFfiFieldNoAnnotation,
message:
- """Field '${name}' requires no annotation to declare its C++ type, it is a Pointer which is represented by the same type in Dart and C++.""",
+ """Field '${name}' requires no annotation to declare its native type, it is a Pointer which is represented by the same type in Dart and native code.""",
arguments: {'name': name});
}
@@ -3779,7 +3936,7 @@
Message Function(String name)> templateFfiNotStatic = const Template<
Message Function(String name)>(
messageTemplate:
- r"""#name expects a static function as parameter. dart:ffi only supports calling static Dart functions from c.""",
+ r"""#name expects a static function as parameter. dart:ffi only supports calling static Dart functions from native code.""",
withArguments: _withArgumentsFfiNotStatic);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3795,7 +3952,7 @@
name = demangleMixinApplicationName(name);
return new Message(codeFfiNotStatic,
message:
- """${name} expects a static function as parameter. dart:ffi only supports calling static Dart functions from c.""",
+ """${name} expects a static function as parameter. dart:ffi only supports calling static Dart functions from native code.""",
arguments: {'name': name});
}
@@ -7061,6 +7218,15 @@
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeMixinDeclaresConstructor = messageMixinDeclaresConstructor;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageMixinDeclaresConstructor = const MessageCode(
+ "MixinDeclaresConstructor",
+ index: 95,
+ message: r"""Mixins can't declare constructors.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<
Message Function(
String name,
@@ -7971,6 +8137,54 @@
const Template<
Message Function(
String name,
+ DartType _type,
+ DartType _type2,
+ String
+ name2)> templateOverrideTypeMismatchSetter = const Template<
+ Message Function(
+ String name, DartType _type, DartType _type2, String name2)>(
+ messageTemplate:
+ r"""The field '#name' has type '#type', which does not match the corresponding type, '#type2', in the overridden setter, '#name2'.""",
+ withArguments: _withArgumentsOverrideTypeMismatchSetter);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<
+ Message Function(
+ String name, DartType _type, DartType _type2, String name2)>
+ codeOverrideTypeMismatchSetter = const Code<
+ Message Function(
+ String name, DartType _type, DartType _type2, String name2)>(
+ "OverrideTypeMismatchSetter", templateOverrideTypeMismatchSetter,
+ analyzerCodes: <String>["INVALID_METHOD_OVERRIDE"]);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsOverrideTypeMismatchSetter(
+ String name, DartType _type, DartType _type2, String name2) {
+ if (name.isEmpty) throw 'No name provided';
+ name = demangleMixinApplicationName(name);
+ TypeLabeler labeler = new TypeLabeler();
+ List<Object> typeParts = labeler.labelType(_type);
+ List<Object> type2Parts = labeler.labelType(_type2);
+ if (name2.isEmpty) throw 'No name provided';
+ name2 = demangleMixinApplicationName(name2);
+ String type = typeParts.join();
+ String type2 = type2Parts.join();
+ return new Message(codeOverrideTypeMismatchSetter,
+ message:
+ """The field '${name}' has type '${type}', which does not match the corresponding type, '${type2}', in the overridden setter, '${name2}'.""" +
+ labeler.originMessages,
+ arguments: {
+ 'name': name,
+ 'type': _type,
+ 'type2': _type2,
+ 'name2': name2
+ });
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+ Message Function(
+ String name,
String
name2)> templateOverrideTypeVariablesMismatch = const Template<
Message Function(String name, String name2)>(
diff --git a/pkg/front_end/lib/src/fasta/flow_analysis/flow_analysis.dart b/pkg/front_end/lib/src/fasta/flow_analysis/flow_analysis.dart
index e90aab5..202fd66 100644
--- a/pkg/front_end/lib/src/fasta/flow_analysis/flow_analysis.dart
+++ b/pkg/front_end/lib/src/fasta/flow_analysis/flow_analysis.dart
@@ -4,39 +4,128 @@
import 'package:meta/meta.dart';
-/// Sets of local variables that are potentially assigned in a loop statement,
-/// switch statement, try statement, or loop collection element.
-class AssignedVariables<StatementOrElement, Variable> {
- final emptySet = Set<Variable>();
+/// [AssignedVariables] is a helper class capable of computing the set of
+/// variables that are potentially written to, and potentially captured by
+/// closures, at various locations inside the code being analyzed. This class
+/// should be used prior to running flow analysis, to compute the sets of
+/// variables to pass in to flow analysis.
+///
+/// This class is intended to be used in two phases. In the first phase, the
+/// client should traverse the source code recursively, making calls to
+/// [beginNode] and [endNode] to indicate the constructs in which writes should
+/// be tracked, and calls to [write] to indicate when a write is encountered.
+/// The order of visiting is not important provided that nesting is respected.
+/// This phase is called the "pre-traversal" because it should happen prior to
+/// flow analysis.
+///
+/// Then, in the second phase, the client may make queries using
+/// [capturedAnywhere], [writtenInNode], and [capturedInNode].
+///
+/// We use the term "node" to refer generally to a loop statement, switch
+/// statement, try statement, loop collection element, local function, or
+/// closure.
+class AssignedVariables<Node, Variable> {
+ /// Mapping from a node to the set of local variables that are potentially
+ /// written to within that node.
+ final Map<Node, Set<Variable>> _writtenInNode = {};
- /// Mapping from a statement or element to the set of local variables that
- /// are potentially assigned in that statement or element.
- final Map<StatementOrElement, Set<Variable>> _map = {};
+ /// Mapping from a node to the set of local variables for which a potential
+ /// write is captured by a local function or closure inside that node.
+ final Map<Node, Set<Variable>> _capturedInNode = {};
- /// The stack of nested statements or collection elements.
- final List<Set<Variable>> _stack = [];
+ /// Set of local variables for which a potential write is captured by a local
+ /// function or closure anywhere in the code being analyzed.
+ final Set<Variable> _capturedAnywhere = {};
+
+ /// Stack of sets accumulating variables that are potentially written to.
+ ///
+ /// A set is pushed onto the stack when a node is entered, and popped when
+ /// a node is left.
+ final List<Set<Variable>> _writtenStack = [];
+
+ /// Stack of sets accumulating variables for which a potential write is
+ /// captured by a local function or closure.
+ ///
+ /// A set is pushed onto the stack when a node is entered, and popped when
+ /// a node is left.
+ final List<Set<Variable>> _capturedStack = [];
+
+ /// Stack of integers counting the number of entries in [_capturedStack] that
+ /// should be updated when a variable write is seen.
+ ///
+ /// When a closure is entered, the length of [_capturedStack] is pushed onto
+ /// this stack; when a node is left, it is popped.
+ ///
+ /// Each time a write occurs, we consult the top of this stack to determine
+ /// how many elements of [capturedStack] should be updated.
+ final List<int> _closureIndexStack = [];
AssignedVariables();
- /// Return the set of variables that are potentially assigned in the
- /// [statementOrElement].
- Set<Variable> operator [](StatementOrElement statementOrElement) {
- return _map[statementOrElement] ?? emptySet;
- }
+ /// Queries the set of variables for which a potential write is captured by a
+ /// local function or closure anywhere in the code being analyzed.
+ Set<Variable> get capturedAnywhere => _capturedAnywhere;
- void beginStatementOrElement() {
- Set<Variable> set = Set<Variable>.identity();
- _stack.add(set);
- }
-
- void endStatementOrElement(StatementOrElement node) {
- _map[node] = _stack.removeLast();
- }
-
- void write(Variable variable) {
- for (int i = 0; i < _stack.length; ++i) {
- _stack[i].add(variable);
+ /// This method should be called during pre-traversal, to mark the start of a
+ /// loop statement, switch statement, try statement, loop collection element,
+ /// local function, or closure which might need to be queried later.
+ ///
+ /// [isClosure] should be true if the node is a local function or closure.
+ ///
+ /// The span between the call to [beginNode] and [endNode] should cover any
+ /// statements and expressions that might be crossed by a backwards jump. So
+ /// for instance, in a "for" loop, the condition, updaters, and body should be
+ /// covered, but the initializers should not. Similarly, in a switch
+ /// statement, the body of the switch statement should be covered, but the
+ /// switch expression should not.
+ void beginNode({bool isClosure: false}) {
+ _writtenStack.add(new Set<Variable>.identity());
+ if (isClosure) {
+ _closureIndexStack.add(_capturedStack.length);
}
+ _capturedStack.add(new Set<Variable>.identity());
+ }
+
+ /// Queries the set of variables for which a potential write is captured by a
+ /// local function or closure inside the [node].
+ Set<Variable> capturedInNode(Node node) {
+ return _capturedInNode[node] ?? const {};
+ }
+
+ /// This method should be called during pre-traversal, to mark the end of a
+ /// loop statement, switch statement, try statement, loop collection element,
+ /// local function, or closure which might need to be queried later.
+ ///
+ /// [isClosure] should be true if the node is a local function or closure.
+ ///
+ /// See [beginNode] for more details.
+ void endNode(Node node, {bool isClosure: false}) {
+ _writtenInNode[node] = _writtenStack.removeLast();
+ _capturedInNode[node] = _capturedStack.removeLast();
+ if (isClosure) {
+ _closureIndexStack.removeLast();
+ }
+ }
+
+ /// This method should be called during pre-traversal, to mark a write to a
+ /// variable.
+ void write(Variable variable) {
+ for (int i = 0; i < _writtenStack.length; ++i) {
+ _writtenStack[i].add(variable);
+ }
+ if (_closureIndexStack.isNotEmpty) {
+ _capturedAnywhere.add(variable);
+ int closureIndex = _closureIndexStack.last;
+ for (int i = 0; i < closureIndex; ++i) {
+ _capturedStack[i].add(variable);
+ }
+ }
+ }
+
+ /// Queries the set of variables that are potentially written to inside the
+ /// [node].
+ Set<Variable> writtenInNode(Node node) {
+ return _writtenInNode[node] ?? const {};
}
}
@@ -47,8 +136,6 @@
return result;
}
- final _VariableSet<Variable> _emptySet;
-
/// The [NodeOperations], used to manipulate expressions.
final NodeOperations<Expression> nodeOperations;
@@ -92,30 +179,18 @@
/// erroneous code, it's possible that a variable might be used before its
/// declaration.
final Set<Variable> _referencedVariables =
- _assertionsEnabled ? Set<Variable>() : null;
+ _assertionsEnabled ? new Set<Variable>() : null;
factory FlowAnalysis(
NodeOperations<Expression> nodeOperations,
TypeOperations<Variable, Type> typeOperations,
FunctionBodyAccess<Variable> functionBody,
) {
- _VariableSet<Variable> emptySet =
- FlowModel<Variable, Type>(false).notAssigned;
- return FlowAnalysis._(
- nodeOperations,
- typeOperations,
- functionBody,
- emptySet,
- );
+ return new FlowAnalysis._(nodeOperations, typeOperations, functionBody);
}
- FlowAnalysis._(
- this.nodeOperations,
- this.typeOperations,
- this.functionBody,
- this._emptySet,
- ) {
- _current = FlowModel<Variable, Type>(true);
+ FlowAnalysis._(this.nodeOperations, this.typeOperations, this.functionBody) {
+ _current = new FlowModel<Variable, Type>(true);
}
/// Return `true` if the current state is reachable.
@@ -191,21 +266,20 @@
}
_condition = binaryExpression;
- FlowModel<Variable, Type> currentPromoted =
+ FlowModel<Variable, Type> currentModel =
_current.markNonNullable(typeOperations, variable);
if (notEqual) {
- _conditionTrue = currentPromoted;
+ _conditionTrue = currentModel;
_conditionFalse = _current;
} else {
_conditionTrue = _current;
- _conditionFalse = currentPromoted;
+ _conditionFalse = currentModel;
}
}
void doStatement_bodyBegin(
- Statement doStatement, Set<Variable> loopAssigned) {
- _variablesReferenced(loopAssigned);
- _current = _current.removePromotedAll(loopAssigned);
+ Statement doStatement, Iterable<Variable> loopAssigned) {
+ _current = _current.removePromotedAll(loopAssigned, _referencedVariables);
_statementToStackIndex[doStatement] = _stack.length;
_stack.add(null); // break
@@ -235,8 +309,8 @@
void finish() {
assert(_stack.isEmpty);
assert(() {
- Set<Variable> variablesNotAdded =
- _referencedVariables.difference(Set<Variable>.from(_addedVariables));
+ Set<Variable> variablesNotAdded = _referencedVariables
+ .difference(new Set<Variable>.from(_addedVariables));
assert(variablesNotAdded.isEmpty,
'Variables not passed to add: $variablesNotAdded');
return true;
@@ -253,12 +327,21 @@
///
/// [condition] is an opaque representation of the loop condition; it is
/// matched against expressions passed to previous calls to determine whether
- /// the loop condition should cause any promotions to occur.
+ /// the loop condition should cause any promotions to occur. If [condition]
+ /// is null, the condition is understood to be empty (equivalent to a
+ /// condition of `true`).
void for_bodyBegin(Statement node, Expression condition) {
- _conditionalEnd(condition);
- // Tail of the stack: falseCondition, trueCondition
+ FlowModel<Variable, Type> trueCondition;
+ if (condition == null) {
+ trueCondition = _current;
+ _stack.add(_current.setReachable(false));
+ } else {
+ _conditionalEnd(condition);
+ // Tail of the stack: falseCondition, trueCondition
- FlowModel<Variable, Type> trueCondition = _stack.removeLast();
+ trueCondition = _stack.removeLast();
+ }
+ // Tail of the stack: falseCondition
if (node != null) {
_statementToStackIndex[node] = _stack.length;
@@ -290,8 +373,7 @@
/// [loopAssigned] should be the set of variables that are assigned anywhere
/// in the loop's condition, updaters, or body.
void for_conditionBegin(Set<Variable> loopAssigned) {
- _variablesReferenced(loopAssigned);
- _current = _current.removePromotedAll(loopAssigned);
+ _current = _current.removePromotedAll(loopAssigned, _referencedVariables);
}
/// Call this method just after visiting the updaters of a conventional "for"
@@ -327,9 +409,8 @@
/// [loopAssigned] should be the set of variables that are assigned anywhere
/// in the loop's body.
void forEach_bodyBegin(Set<Variable> loopAssigned) {
- _variablesReferenced(loopAssigned);
_stack.add(_current);
- _current = _current.removePromotedAll(loopAssigned);
+ _current = _current.removePromotedAll(loopAssigned, _referencedVariables);
}
/// Call this method just before visiting the body of a "for-in" statement or
@@ -342,19 +423,19 @@
void functionExpression_begin() {
_stack.add(_current);
- Set<Variable> notPromoted = null;
- for (MapEntry<Variable, Type> entry in _current.promoted.entries) {
+ List<Variable> notPromoted = [];
+ for (MapEntry<Variable, VariableModel<Type>> entry
+ in _current.variableInfo.entries) {
Variable variable = entry.key;
- Type promotedType = entry.value;
+ Type promotedType = entry.value.promotedType;
if (promotedType != null &&
functionBody.isPotentiallyMutatedInScope(variable)) {
- notPromoted ??= Set<Variable>.identity();
notPromoted.add(variable);
}
}
- if (notPromoted != null) {
- _current = _current.removePromotedAll(notPromoted);
+ if (notPromoted.isNotEmpty) {
+ _current = _current.removePromotedAll(notPromoted, null);
}
}
@@ -425,7 +506,16 @@
/// Return whether the [variable] is definitely assigned in the current state.
bool isAssigned(Variable variable) {
_variableReferenced(variable);
- return !_current.notAssigned.contains(variable);
+ VariableModel<Type> variableInfo = _current.variableInfo[variable];
+ if (variableInfo == null) {
+ // In error-free code, variables should always be registered with flow
+ // analysis before they're used. But this can't be relied on when the
+ // analyzer is doing error recovery. So if we encounter a variable that
+ // hasn't been registered with flow analysis yet, assume it's unassigned.
+ return false;
+ } else {
+ return variableInfo.assigned;
+ }
}
void isExpression_end(
@@ -503,34 +593,56 @@
/// is currently promoted. Otherwise returns `null`.
Type promotedType(Variable variable) {
_variableReferenced(variable);
- return _current.promoted[variable];
+ return _current.variableInfo[variable]?.promotedType;
}
- /// The [notPromoted] set contains all variables that are potentially
- /// assigned in other cases that might target this with `continue`, so
- /// these variables might have different types and are "un-promoted" from
- /// the "afterExpression" state.
- void switchStatement_beginCase(Set<Variable> notPromoted) {
- _variablesReferenced(notPromoted);
- _current = _stack.last.removePromotedAll(notPromoted);
- }
-
- void switchStatement_end(Statement switchStatement, bool hasDefault) {
- // Tail of the stack: break, continue, afterExpression
- FlowModel<Variable, Type> afterExpression = _current = _stack.removeLast();
- _stack.removeLast(); // continue
- FlowModel<Variable, Type> breakState = _stack.removeLast();
-
- if (hasDefault) {
- // breakState should not be null because we should have joined it with
- // something non-null when handling the default case.
- assert(breakState != null);
- _current = breakState;
+ /// Call this method just before visiting one of the cases in the body of a
+ /// switch statement. See [switchStatement_expressionEnd] for details.
+ ///
+ /// [hasLabel] indicates whether the case has any labels.
+ ///
+ /// The [notPromoted] set contains all variables that are potentially assigned
+ /// within the body of the switch statement.
+ void switchStatement_beginCase(
+ bool hasLabel, Iterable<Variable> notPromoted) {
+ if (hasLabel) {
+ _current =
+ _stack.last.removePromotedAll(notPromoted, _referencedVariables);
} else {
- _current = _join(breakState, afterExpression);
+ _current = _stack.last;
}
}
+ /// Call this method just after visiting the body of a switch statement. See
+ /// [switchStatement_expressionEnd] for details.
+ ///
+ /// [hasDefault] indicates whether the switch statement had a "default" case.
+ void switchStatement_end(bool hasDefault) {
+ // Tail of the stack: break, continue, afterExpression
+ FlowModel<Variable, Type> afterExpression = _stack.removeLast();
+ _stack.removeLast(); // continue
+ FlowModel<Variable, Type> breakState = _stack.removeLast();
+
+ // It is allowed to "fall off" the end of a switch statement, so join the
+ // current state to any breaks that were found previously.
+ breakState = _join(breakState, _current);
+
+ // And, if there is an implicit fall-through default, join it to any breaks.
+ if (!hasDefault) breakState = _join(breakState, afterExpression);
+
+ _current = breakState;
+ }
+
+ /// Call this method just after visiting the expression part of a switch
+ /// statement.
+ ///
+ /// The order of visiting a switch statement should be:
+ /// - Visit the switch expression.
+ /// - Call [switchStatement_expressionEnd].
+ /// - For each switch case (including the default case, if any):
+ /// - Call [switchStatement_beginCase].
+ /// - Visit the case.
+ /// - Call [switchStatement_end].
void switchStatement_expressionEnd(Statement switchStatement) {
_statementToStackIndex[switchStatement] = _stack.length;
_stack.add(null); // break
@@ -543,11 +655,10 @@
// Tail of the stack: beforeBody
}
- void tryCatchStatement_bodyEnd(Set<Variable> assignedInBody) {
- _variablesReferenced(assignedInBody);
+ void tryCatchStatement_bodyEnd(Iterable<Variable> assignedInBody) {
FlowModel<Variable, Type> beforeBody = _stack.removeLast();
FlowModel<Variable, Type> beforeCatch =
- beforeBody.removePromotedAll(assignedInBody);
+ beforeBody.removePromotedAll(assignedInBody, _referencedVariables);
_stack.add(beforeCatch);
_stack.add(_current); // afterBodyAndCatches
// Tail of the stack: beforeCatch, afterBodyAndCatches
@@ -576,20 +687,15 @@
void tryFinallyStatement_end(Set<Variable> assignedInFinally) {
_variablesReferenced(assignedInFinally);
FlowModel<Variable, Type> afterBody = _stack.removeLast();
- _current = _current.restrict(
- typeOperations,
- _emptySet,
- afterBody,
- assignedInFinally,
- );
+ _current = _current.restrict(typeOperations, afterBody, assignedInFinally);
}
- void tryFinallyStatement_finallyBegin(Set<Variable> assignedInBody) {
- _variablesReferenced(assignedInBody);
+ void tryFinallyStatement_finallyBegin(Iterable<Variable> assignedInBody) {
FlowModel<Variable, Type> beforeTry = _stack.removeLast();
FlowModel<Variable, Type> afterBody = _current;
_stack.add(afterBody);
- _current = _join(afterBody, beforeTry.removePromotedAll(assignedInBody));
+ _current = _join(afterBody,
+ beforeTry.removePromotedAll(assignedInBody, _referencedVariables));
}
void whileStatement_bodyBegin(
@@ -606,9 +712,8 @@
_current = trueCondition;
}
- void whileStatement_conditionBegin(Set<Variable> loopAssigned) {
- _variablesReferenced(loopAssigned);
- _current = _current.removePromotedAll(loopAssigned);
+ void whileStatement_conditionBegin(Iterable<Variable> loopAssigned) {
+ _current = _current.removePromotedAll(loopAssigned, _referencedVariables);
}
void whileStatement_end() {
@@ -622,7 +727,7 @@
/// Register write of the given [variable] in the current state.
void write(Variable variable) {
_variableReferenced(variable);
- _current = _current.write(typeOperations, _emptySet, variable);
+ _current = _current.write(typeOperations, variable);
}
void _conditionalEnd(Expression condition) {
@@ -672,23 +777,18 @@
/// Indicates whether this point in the control flow is reachable.
final bool reachable;
- /// The set of variables that are not yet definitely assigned at this point in
- /// the control flow.
- final _VariableSet<Variable> notAssigned;
-
- /// For each variable being tracked by flow analysis, the variable's promoted
- /// type, or `null` if the variable's type is not promoted.
+ /// For each variable being tracked by flow analysis, the variable's model.
///
/// Flow analysis has no awareness of scope, so variables that are out of
/// scope are retained in the map until such time as their declaration no
/// longer dominates the control flow. So, for example, if a variable is
- /// declared and then promoted inside the `then` branch of an `if` statement,
- /// and the `else` branch of the `if` statement ends in a `return` statement,
- /// then the variable remains in the map after the `if` statement ends, even
- /// though the variable is not in scope anymore. This should not have any
- /// effect on analysis results for error-free code, because it is an error to
- /// refer to a variable that is no longer in scope.
- final Map<Variable, Type> promoted;
+ /// declared inside the `then` branch of an `if` statement, and the `else`
+ /// branch of the `if` statement ends in a `return` statement, then the
+ /// variable remains in the map after the `if` statement ends, even though the
+ /// variable is not in scope anymore. This should not have any effect on
+ /// analysis results for error-free code, because it is an error to refer to a
+ /// variable that is no longer in scope.
+ final Map<Variable, VariableModel<Type> /*!*/ > variableInfo;
/// Creates a state object with the given [reachable] status. All variables
/// are assumed to be unpromoted and already assigned, so joining another
@@ -696,30 +796,27 @@
FlowModel(bool reachable)
: this._(
reachable,
- _VariableSet<Variable>._(const []),
const {},
);
- FlowModel._(
- this.reachable,
- this.notAssigned,
- this.promoted,
- );
+ FlowModel._(this.reachable, this.variableInfo) {
+ assert(() {
+ for (VariableModel<Type> value in variableInfo.values) {
+ assert(value != null);
+ }
+ return true;
+ }());
+ }
/// Updates the state to track a newly declared local [variable]. The
/// optional [assigned] boolean indicates whether the variable is assigned at
/// the point of declaration.
FlowModel<Variable, Type> add(Variable variable, {bool assigned: false}) {
- _VariableSet<Variable> newNotAssigned =
- assigned ? notAssigned : notAssigned.add(variable);
- Map<Variable, Type> newPromoted = Map<Variable, Type>.from(promoted);
- newPromoted[variable] = null;
+ Map<Variable, VariableModel<Type>> newVariableInfo =
+ new Map<Variable, VariableModel<Type>>.from(variableInfo);
+ newVariableInfo[variable] = new VariableModel<Type>(null, assigned);
- return FlowModel<Variable, Type>._(
- reachable,
- newNotAssigned,
- newPromoted,
- );
+ return new FlowModel<Variable, Type>._(reachable, newVariableInfo);
}
/// Updates the state to indicate that the given [variable] has been
@@ -729,21 +826,12 @@
/// assigned? Does it matter?
FlowModel<Variable, Type> markNonNullable(
TypeOperations<Variable, Type> typeOperations, Variable variable) {
- Type previousType = promoted[variable];
+ VariableModel<Type> info = variableInfo[variable];
+ Type previousType = info.promotedType;
previousType ??= typeOperations.variableType(variable);
Type type = typeOperations.promoteToNonNull(previousType);
-
- if (!typeOperations.isSameType(type, previousType)) {
- Map<Variable, Type> newPromoted = <Variable, Type>{}..addAll(promoted);
- newPromoted[variable] = type;
- return FlowModel<Variable, Type>._(
- reachable,
- notAssigned,
- newPromoted,
- );
- }
-
- return this;
+ if (typeOperations.isSameType(type, previousType)) return this;
+ return _updateVariableInfo(variable, info.withPromotedType(type));
}
/// Updates the state to indicate that the given [variable] has been
@@ -760,26 +848,24 @@
Variable variable,
Type type,
) {
- Type previousType = promoted[variable];
+ VariableModel<Type> info = variableInfo[variable];
+ Type previousType = info.promotedType;
previousType ??= typeOperations.variableType(variable);
- if (typeOperations.isSubtypeOf(type, previousType) &&
- !typeOperations.isSameType(type, previousType)) {
- Map<Variable, Type> newPromoted = <Variable, Type>{}..addAll(promoted);
- newPromoted[variable] = type;
- return FlowModel<Variable, Type>._(
- reachable,
- notAssigned,
- newPromoted,
- );
+ if (!typeOperations.isSubtypeOf(type, previousType) ||
+ typeOperations.isSameType(type, previousType)) {
+ return this;
}
-
- return this;
+ return _updateVariableInfo(variable, info.withPromotedType(type));
}
/// Updates the state to indicate that the given [variables] are no longer
/// promoted; they are presumed to have their declared types.
///
+ /// If assertions are enabled and [referencedVariables] is not `null`, all
+ /// variables in [variables] will be stored in [referencedVariables] as a side
+ /// effect of this call.
+ ///
/// This is used at the top of loops to conservatively cancel the promotion of
/// variables that are modified within the loop, so that we correctly analyze
/// code like the following:
@@ -796,16 +882,22 @@
/// and only remove promotions if it can be shown that they aren't restored
/// later in the loop body. If we switch to a fixed point analysis, we should
/// be able to remove this method.
- FlowModel<Variable, Type> removePromotedAll(Set<Variable> variables) {
- Map<Variable, Type> newPromoted = _removePromotedAll(promoted, variables);
-
- if (identical(newPromoted, promoted)) return this;
-
- return FlowModel<Variable, Type>._(
- reachable,
- notAssigned,
- newPromoted,
- );
+ FlowModel<Variable, Type> removePromotedAll(
+ Iterable<Variable> variables, Set<Variable> referencedVariables) {
+ Map<Variable, VariableModel<Type>> newVariableInfo;
+ for (Variable variable in variables) {
+ assert(() {
+ referencedVariables?.add(variable);
+ return true;
+ }());
+ VariableModel<Type> info = variableInfo[variable];
+ if (info?.promotedType != null) {
+ (newVariableInfo ??= new Map<Variable, VariableModel<Type>>.from(
+ variableInfo))[variable] = info.withPromotedType(null);
+ }
+ }
+ if (newVariableInfo == null) return this;
+ return new FlowModel<Variable, Type>._(reachable, newVariableInfo);
}
/// Updates the state to reflect a control path that is known to have
@@ -829,74 +921,37 @@
/// block are considered "unsafe" because the assignment might have cancelled
/// the effect of any promotion that occurred inside the `try` block.
FlowModel<Variable, Type> restrict(
- TypeOperations<Variable, Type> typeOperations,
- _VariableSet<Variable> emptySet,
- FlowModel<Variable, Type> other,
- Set<Variable> unsafe,
- ) {
+ TypeOperations<Variable, Type> typeOperations,
+ FlowModel<Variable, Type> other,
+ Set<Variable> unsafe) {
bool newReachable = reachable && other.reachable;
- _VariableSet<Variable> newNotAssigned = notAssigned.intersect(
- empty: emptySet,
- other: other.notAssigned,
- );
- if (newNotAssigned.variables.length == notAssigned.variables.length) {
- newNotAssigned = notAssigned;
- } else if (newNotAssigned.variables.length ==
- other.notAssigned.variables.length) {
- newNotAssigned = other.notAssigned;
- }
- Map<Variable, Type> newPromoted = <Variable, Type>{};
- bool promotedMatchesThis = true;
- bool promotedMatchesOther = other.promoted.length == promoted.length;
- for (MapEntry<Variable, Type> entry in promoted.entries) {
+ Map<Variable, VariableModel<Type>> newVariableInfo =
+ <Variable, VariableModel<Type>>{};
+ bool variableInfoMatchesThis = true;
+ bool variableInfoMatchesOther =
+ other.variableInfo.length == variableInfo.length;
+ for (MapEntry<Variable, VariableModel<Type>> entry
+ in variableInfo.entries) {
Variable variable = entry.key;
- Type thisType = entry.value;
- Type otherType = other.promoted[variable];
- if (!unsafe.contains(variable)) {
- if (otherType != null &&
- (thisType == null ||
- typeOperations.isSubtypeOf(otherType, thisType))) {
- newPromoted[variable] = otherType;
- if (promotedMatchesThis &&
- (thisType == null ||
- !typeOperations.isSameType(thisType, otherType))) {
- promotedMatchesThis = false;
- }
- continue;
- }
- }
- if (thisType != null) {
- newPromoted[variable] = thisType;
- if (promotedMatchesOther &&
- (otherType == null ||
- !typeOperations.isSameType(thisType, otherType))) {
- promotedMatchesOther = false;
- }
- } else {
- newPromoted[variable] = null;
- if (promotedMatchesOther && otherType != null) {
- promotedMatchesOther = false;
- }
- }
+ VariableModel<Type> otherModel = other.variableInfo[variable];
+ VariableModel<Type> restricted = entry.value
+ .restrict(typeOperations, otherModel, unsafe.contains(variable));
+ newVariableInfo[variable] = restricted;
+ if (!identical(restricted, entry.value)) variableInfoMatchesThis = false;
+ if (!identical(restricted, otherModel)) variableInfoMatchesOther = false;
}
- assert(promotedMatchesThis ==
- _promotionsEqual(typeOperations, newPromoted, promoted));
- assert(promotedMatchesOther ==
- _promotionsEqual(typeOperations, newPromoted, other.promoted));
- if (promotedMatchesThis) {
- newPromoted = promoted;
- } else if (promotedMatchesOther) {
- newPromoted = other.promoted;
+ assert(variableInfoMatchesThis ==
+ _variableInfosEqual(newVariableInfo, variableInfo));
+ assert(variableInfoMatchesOther ==
+ _variableInfosEqual(newVariableInfo, other.variableInfo));
+ if (variableInfoMatchesThis) {
+ newVariableInfo = variableInfo;
+ } else if (variableInfoMatchesOther) {
+ newVariableInfo = other.variableInfo;
}
- return _identicalOrNew(
- this,
- other,
- newReachable,
- newNotAssigned,
- newPromoted,
- );
+ return _identicalOrNew(this, other, newReachable, newVariableInfo);
}
/// Updates the state to indicate whether the control flow path is
@@ -904,78 +959,33 @@
FlowModel<Variable, Type> setReachable(bool reachable) {
if (this.reachable == reachable) return this;
- return FlowModel<Variable, Type>._(
- reachable,
- notAssigned,
- promoted,
- );
+ return new FlowModel<Variable, Type>._(reachable, variableInfo);
}
@override
- String toString() => '($reachable, $notAssigned, $promoted)';
+ String toString() => '($reachable, $variableInfo)';
/// Updates the state to indicate that an assignment was made to the given
/// [variable]. The variable is marked as definitely assigned, and any
/// previous type promotion is removed.
///
/// TODO(paulberry): allow for writes that preserve type promotions.
- FlowModel<Variable, Type> write(TypeOperations<Variable, Type> typeOperations,
- _VariableSet<Variable> emptySet, Variable variable) {
- _VariableSet<Variable> newNotAssigned =
- typeOperations.isLocalVariable(variable)
- ? notAssigned.remove(emptySet, variable)
- : notAssigned;
-
- Map<Variable, Type> newPromoted = _removePromoted(promoted, variable);
-
- if (identical(newNotAssigned, notAssigned) &&
- identical(newPromoted, promoted)) {
- return this;
- }
-
- return FlowModel<Variable, Type>._(
- reachable,
- newNotAssigned,
- newPromoted,
- );
+ FlowModel<Variable, Type> write(
+ TypeOperations<Variable, Type> typeOperations, Variable variable) {
+ VariableModel<Type> infoForVar = variableInfo[variable];
+ VariableModel<Type> newInfoForVar = infoForVar.write();
+ if (identical(newInfoForVar, infoForVar)) return this;
+ return _updateVariableInfo(variable, newInfoForVar);
}
- /// Removes a [variable] from a "promoted" [map], treating the map as
- /// immutable.
- Map<Variable, Type> _removePromoted(
- Map<Variable, Type> map, Variable variable) {
- if (map[variable] == null) return map;
-
- Map<Variable, Type> result = Map<Variable, Type>.from(map);
- result[variable] = null;
- return result;
- }
-
- /// Removes a set of [variable]s from a "promoted" [map], treating the map as
- /// immutable.
- Map<Variable, Type> _removePromotedAll(
- Map<Variable, Type> map,
- Set<Variable> variables,
- ) {
- if (map.isEmpty) return const {};
- if (variables.isEmpty) return map;
-
- Map<Variable, Type> result = <Variable, Type>{};
- bool noChanges = true;
- for (MapEntry<Variable, Type> entry in map.entries) {
- Variable variable = entry.key;
- Type promotedType = entry.value;
- if (variables.contains(variable) && promotedType != null) {
- result[variable] = null;
- noChanges = false;
- } else {
- result[variable] = promotedType;
- }
- }
-
- if (noChanges) return map;
- if (result.isEmpty) return const {};
- return result;
+ /// Returns a new [FlowModel] where the information for [variable] is replaced
+ /// with [model].
+ FlowModel<Variable, Type> _updateVariableInfo(
+ Variable variable, VariableModel<Type> model) {
+ Map<Variable, VariableModel<Type>> newVariableInfo =
+ new Map<Variable, VariableModel<Type>>.from(variableInfo);
+ newVariableInfo[variable] = model;
+ return new FlowModel<Variable, Type>._(reachable, newVariableInfo);
}
/// Forms a new state to reflect a control flow path that might have come from
@@ -999,59 +1009,39 @@
if (!first.reachable && second.reachable) return second;
bool newReachable = first.reachable || second.reachable;
- _VariableSet<Variable> newNotAssigned =
- first.notAssigned.union(second.notAssigned);
- Map<Variable, Type> newPromoted =
- FlowModel.joinPromoted(typeOperations, first.promoted, second.promoted);
+ Map<Variable, VariableModel<Type>> newVariableInfo =
+ FlowModel.joinVariableInfo(
+ typeOperations, first.variableInfo, second.variableInfo);
return FlowModel._identicalOrNew(
- first,
- second,
- newReachable,
- newNotAssigned,
- newPromoted,
- );
+ first, second, newReachable, newVariableInfo);
}
- /// Joins two "promoted" maps. See [join] for details.
+ /// Joins two "variable info" maps. See [join] for details.
@visibleForTesting
- static Map<Variable, Type> joinPromoted<Variable, Type>(
+ static Map<Variable, VariableModel<Type>> joinVariableInfo<Variable, Type>(
TypeOperations<Variable, Type> typeOperations,
- Map<Variable, Type> first,
- Map<Variable, Type> second,
+ Map<Variable, VariableModel<Type>> first,
+ Map<Variable, VariableModel<Type>> second,
) {
if (identical(first, second)) return first;
if (first.isEmpty || second.isEmpty) return const {};
- Map<Variable, Type> result = <Variable, Type>{};
+ Map<Variable, VariableModel<Type>> result =
+ <Variable, VariableModel<Type>>{};
bool alwaysFirst = true;
bool alwaysSecond = true;
- for (MapEntry<Variable, Type> entry in first.entries) {
+ for (MapEntry<Variable, VariableModel<Type>> entry in first.entries) {
Variable variable = entry.key;
- if (!second.containsKey(variable)) {
+ VariableModel<Type> secondModel = second[variable];
+ if (secondModel == null) {
alwaysFirst = false;
} else {
- Type firstType = entry.value;
- Type secondType = second[variable];
- if (identical(firstType, secondType)) {
- result[variable] = firstType;
- } else if (firstType == null) {
- result[variable] = null;
- alwaysSecond = false;
- } else if (secondType == null) {
- result[variable] = null;
- alwaysFirst = false;
- } else if (typeOperations.isSubtypeOf(firstType, secondType)) {
- result[variable] = secondType;
- alwaysFirst = false;
- } else if (typeOperations.isSubtypeOf(secondType, firstType)) {
- result[variable] = firstType;
- alwaysSecond = false;
- } else {
- result[variable] = null;
- alwaysFirst = false;
- alwaysSecond = false;
- }
+ VariableModel<Type> joined =
+ VariableModel.join<Type>(typeOperations, entry.value, secondModel);
+ result[variable] = joined;
+ if (!identical(joined, entry.value)) alwaysFirst = false;
+ if (!identical(joined, secondModel)) alwaysSecond = false;
}
}
@@ -1064,45 +1054,36 @@
/// Creates a new [FlowModel] object, unless it is equivalent to either
/// [first] or [second], in which case one of those objects is re-used.
static FlowModel<Variable, Type> _identicalOrNew<Variable, Type>(
- FlowModel<Variable, Type> first,
- FlowModel<Variable, Type> second,
- bool newReachable,
- _VariableSet<Variable> newNotAssigned,
- Map<Variable, Type> newPromoted,
- ) {
+ FlowModel<Variable, Type> first,
+ FlowModel<Variable, Type> second,
+ bool newReachable,
+ Map<Variable, VariableModel<Type>> newVariableInfo) {
if (first.reachable == newReachable &&
- identical(first.notAssigned, newNotAssigned) &&
- identical(first.promoted, newPromoted)) {
+ identical(first.variableInfo, newVariableInfo)) {
return first;
}
if (second.reachable == newReachable &&
- identical(second.notAssigned, newNotAssigned) &&
- identical(second.promoted, newPromoted)) {
+ identical(second.variableInfo, newVariableInfo)) {
return second;
}
- return FlowModel<Variable, Type>._(
- newReachable,
- newNotAssigned,
- newPromoted,
- );
+ return new FlowModel<Variable, Type>._(newReachable, newVariableInfo);
}
- /// Determines whether the given "promoted" maps are equivalent.
- static bool _promotionsEqual<Variable, Type>(
- TypeOperations<Variable, Type> typeOperations,
- Map<Variable, Type> p1,
- Map<Variable, Type> p2) {
+ /// Determines whether the given "variableInfo" maps are equivalent.
+ ///
+ /// The equivalence check is shallow; if two variables' models are not
+ /// identical, we return `false`.
+ static bool _variableInfosEqual<Variable, Type>(
+ Map<Variable, VariableModel<Type>> p1,
+ Map<Variable, VariableModel<Type>> p2) {
if (p1.length != p2.length) return false;
if (!p1.keys.toSet().containsAll(p2.keys)) return false;
- for (MapEntry<Variable, Type> entry in p1.entries) {
- Type p1Value = entry.value;
- Type p2Value = p2[entry.key];
- if (p1Value == null) {
- if (p2Value != null) return false;
- } else {
- if (p2Value == null) return false;
- if (!typeOperations.isSameType(p1Value, p2Value)) return false;
+ for (MapEntry<Variable, VariableModel<Type>> entry in p1.entries) {
+ VariableModel<Type> p1Value = entry.value;
+ VariableModel<Type> p2Value = p2[entry.key];
+ if (!identical(p1Value, p2Value)) {
+ return false;
}
}
return true;
@@ -1143,98 +1124,98 @@
Type variableType(Variable variable);
}
-/// List based immutable set of variables.
-class _VariableSet<Variable> {
- final List<Variable> variables;
+/// An instance of the [VariableModel] class represents the information gathered
+/// by flow analysis for a single variable at a single point in the control flow
+/// of the function or method being analyzed.
+///
+/// Instances of this class are immutable, so the methods below that "update"
+/// the state actually leave `this` unchanged and return a new state object.
+@visibleForTesting
+class VariableModel<Type> {
+ /// The type that the variable has been promoted to, or `null` if the variable
+ /// is not promoted.
+ final Type promotedType;
- _VariableSet._(this.variables);
+ /// Indicates whether the variable has definitely been assigned.
+ final bool assigned;
- _VariableSet<Variable> add(Variable addedVariable) {
- if (contains(addedVariable)) {
- return this;
- }
+ VariableModel(this.promotedType, this.assigned);
- int length = variables.length;
- List<Variable> newVariables = List<Variable>(length + 1);
- for (int i = 0; i < length; ++i) {
- newVariables[i] = variables[i];
- }
- newVariables[length] = addedVariable;
- return _VariableSet._(newVariables);
+ @override
+ bool operator ==(Object other) {
+ return other is VariableModel<Type> &&
+ this.promotedType == other.promotedType &&
+ this.assigned == other.assigned;
}
- _VariableSet<Variable> addAll(Iterable<Variable> variables) {
- _VariableSet<Variable> result = this;
- for (Variable variable in variables) {
- result = result.add(variable);
- }
- return result;
- }
-
- bool contains(Variable variable) {
- int length = variables.length;
- for (int i = 0; i < length; ++i) {
- if (identical(variables[i], variable)) {
- return true;
+ /// Returns an updated model reflect a control path that is known to have
+ /// previously passed through some [other] state. See [FlowModel.restrict]
+ /// for details.
+ VariableModel<Type> restrict(TypeOperations<Object, Type> typeOperations,
+ VariableModel<Type> otherModel, bool unsafe) {
+ Type thisType = promotedType;
+ Type otherType = otherModel?.promotedType;
+ bool newAssigned = assigned || otherModel.assigned;
+ if (!unsafe) {
+ if (otherType != null &&
+ (thisType == null ||
+ typeOperations.isSubtypeOf(otherType, thisType))) {
+ return _identicalOrNew(this, otherModel, otherType, newAssigned);
}
}
- return false;
- }
-
- _VariableSet<Variable> intersect({
- _VariableSet<Variable> empty,
- _VariableSet<Variable> other,
- }) {
- if (identical(other, empty)) return empty;
- if (identical(this, other)) return this;
-
- // TODO(scheglov) optimize
- List<Variable> newVariables =
- variables.toSet().intersection(other.variables.toSet()).toList();
-
- if (newVariables.isEmpty) return empty;
- return _VariableSet._(newVariables);
- }
-
- _VariableSet<Variable> remove(
- _VariableSet<Variable> empty,
- Variable removedVariable,
- ) {
- if (!contains(removedVariable)) {
- return this;
- }
-
- int length = variables.length;
- if (length == 1) {
- return empty;
- }
-
- List<Variable> newVariables = List<Variable>(length - 1);
- int newIndex = 0;
- for (int i = 0; i < length; ++i) {
- Variable variable = variables[i];
- if (!identical(variable, removedVariable)) {
- newVariables[newIndex++] = variable;
- }
- }
-
- return _VariableSet._(newVariables);
+ return _identicalOrNew(this, otherModel, thisType, newAssigned);
}
@override
- String toString() => variables.isEmpty ? '{}' : '{ ${variables.join(', ')} }';
+ String toString() => 'VariableModel($promotedType, $assigned)';
- _VariableSet<Variable> union(_VariableSet<Variable> other) {
- if (other.variables.isEmpty) {
- return this;
- }
+ /// Returns a new [VariableModel] where the promoted type is replaced with
+ /// [promotedType].
+ VariableModel<Type> withPromotedType(Type promotedType) =>
+ new VariableModel<Type>(promotedType, assigned);
- _VariableSet<Variable> result = this;
- List<Variable> otherVariables = other.variables;
- for (int i = 0; i < otherVariables.length; ++i) {
- Variable otherVariable = otherVariables[i];
- result = result.add(otherVariable);
+ /// Returns a new [VariableModel] reflecting the fact that the variable was
+ /// just written to.
+ VariableModel<Type> write() {
+ if (promotedType == null && assigned) return this;
+ return new VariableModel<Type>(null, true);
+ }
+
+ /// Joins two variable models. See [FlowModel.join] for details.
+ static VariableModel<Type> join<Type>(
+ TypeOperations<Object, Type> typeOperations,
+ VariableModel<Type> first,
+ VariableModel<Type> second) {
+ Type firstType = first.promotedType;
+ Type secondType = second.promotedType;
+ Type newPromotedType;
+ if (identical(firstType, secondType)) {
+ newPromotedType = firstType;
+ } else if (firstType == null || secondType == null) {
+ newPromotedType = null;
+ } else if (typeOperations.isSubtypeOf(firstType, secondType)) {
+ newPromotedType = secondType;
+ } else if (typeOperations.isSubtypeOf(secondType, firstType)) {
+ newPromotedType = firstType;
+ } else {
+ newPromotedType = null;
}
- return result;
+ bool newAssigned = first.assigned && second.assigned;
+ return _identicalOrNew(first, second, newPromotedType, newAssigned);
+ }
+
+ /// Creates a new [VariableModel] object, unless it is equivalent to either
+ /// [first] or [second], in which case one of those objects is re-used.
+ static VariableModel<Type> _identicalOrNew<Type>(VariableModel<Type> first,
+ VariableModel<Type> second, Type newPromotedType, bool newAssigned) {
+ if (identical(first.promotedType, newPromotedType) &&
+ first.assigned == newAssigned) {
+ return first;
+ } else if (identical(second.promotedType, newPromotedType) &&
+ second.assigned == newAssigned) {
+ return second;
+ } else {
+ return new VariableModel<Type>(newPromotedType, newAssigned);
+ }
}
}
diff --git a/pkg/front_end/lib/src/fasta/import.dart b/pkg/front_end/lib/src/fasta/import.dart
index af6a7fb..437ec72 100644
--- a/pkg/front_end/lib/src/fasta/import.dart
+++ b/pkg/front_end/lib/src/fasta/import.dart
@@ -100,7 +100,7 @@
if (prefix == null) return null;
LibraryDependency dependency = null;
if (deferred) {
- dependency = new LibraryDependency.deferredImport(imported.target, prefix,
+ dependency = new LibraryDependency.deferredImport(imported.library, prefix,
combinators: toKernelCombinators(combinators))
..fileOffset = charOffset;
}
diff --git a/pkg/front_end/lib/src/fasta/incremental_compiler.dart b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
index 14a8d00..1288b94 100644
--- a/pkg/front_end/lib/src/fasta/incremental_compiler.dart
+++ b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
@@ -48,7 +48,7 @@
import '../api_prototype/memory_file_system.dart' show MemoryFileSystem;
-import 'builder/builder.dart' show LibraryBuilder;
+import 'builder/builder.dart' show ClassBuilder, LibraryBuilder;
import 'builder_graph.dart' show BuilderGraph;
@@ -248,7 +248,7 @@
// Remove component problems for libraries we don't reuse.
if (remainingComponentProblems.isNotEmpty) {
- Library lib = builder.target;
+ Library lib = builder.library;
removeLibraryFromRemainingComponentProblems(lib, uriTranslator);
}
}
@@ -256,7 +256,7 @@
if (removedDillBuilders) {
dillLoadedData.loader.libraries.clear();
for (LibraryBuilder builder in dillLoadedData.loader.builders.values) {
- dillLoadedData.loader.libraries.add(builder.target);
+ dillLoadedData.loader.libraries.add(builder.library);
}
}
@@ -282,7 +282,7 @@
if (hierarchy != null) {
List<Library> removedLibraries = new List<Library>();
for (LibraryBuilder builder in notReusedLibraries) {
- Library lib = builder.target;
+ Library lib = builder.library;
removedLibraries.add(lib);
}
hierarchy.applyTreeChanges(removedLibraries, const []);
@@ -389,7 +389,7 @@
allLibraries = outputLibraries.toSet();
if (!c.options.omitPlatform) {
for (int i = 0; i < platformBuilders.length; i++) {
- Library lib = platformBuilders[i].target;
+ Library lib = platformBuilders[i].library;
outputLibraries.add(lib);
}
}
@@ -503,7 +503,7 @@
if (modulesToLoad != null && userBuilders != null) {
Set<Library> loadedNotKept = new Set<Library>();
for (LibraryBuilder builder in userBuilders.values) {
- loadedNotKept.add(builder.target);
+ loadedNotKept.add(builder.library);
}
for (Component module in modulesToLoad) {
loadedNotKept.removeAll(module.libraries);
@@ -651,13 +651,13 @@
List<Uri> worklist = new List<Uri>();
worklist.addAll(entries);
- for (LibraryBuilder library in reusedLibraries) {
- if (library.uri.scheme == "dart" && !library.isSynthetic) {
+ for (LibraryBuilder libraryBuilder in reusedLibraries) {
+ if (libraryBuilder.uri.scheme == "dart" && !libraryBuilder.isSynthetic) {
continue;
}
- Library lib = library.target;
- potentiallyReferencedLibraries[library.uri] = lib;
- libraryMap[library.uri] = lib;
+ Library lib = libraryBuilder.library;
+ potentiallyReferencedLibraries[libraryBuilder.uri] = lib;
+ libraryMap[libraryBuilder.uri] = lib;
}
LibraryGraph graph = new LibraryGraph(libraryMap);
@@ -683,7 +683,7 @@
if (uri.scheme == "package") continue;
LibraryBuilder builder = userCode.loader.builders.remove(uri);
if (builder != null) {
- Library lib = builder.target;
+ Library lib = builder.library;
removedLibraries.add(lib);
dillLoadedData.loader.builders.remove(uri);
CompilerContext.current.uriToSource.remove(uri);
@@ -834,13 +834,14 @@
assert(dillLoadedData != null && userCode != null);
return await context.runInContext((_) async {
- LibraryBuilder library =
+ LibraryBuilder libraryBuilder =
userCode.loader.read(libraryUri, -1, accessor: userCode.loader.first);
- Class kernelClass;
+ Class cls;
if (className != null) {
- kernelClass = library.scopeBuilder[className]?.target;
- if (kernelClass == null) return null;
+ ClassBuilder classBuilder = libraryBuilder.scopeBuilder[className];
+ cls = classBuilder?.cls;
+ if (cls == null) return null;
}
userCode.loader.seenMessages.clear();
@@ -857,12 +858,16 @@
debugExprUri,
userCode.loader,
null,
- scope: library.scope.createNestedScope("expression"),
- nameOrigin: library.target,
+ scope: libraryBuilder.scope.createNestedScope("expression"),
+ nameOrigin: libraryBuilder.library,
);
+ debugLibrary.setLanguageVersion(
+ libraryBuilder.library.languageVersionMajor,
+ libraryBuilder.library.languageVersionMinor);
- if (library is DillLibraryBuilder) {
- for (LibraryDependency dependency in library.target.dependencies) {
+ if (libraryBuilder is DillLibraryBuilder) {
+ for (LibraryDependency dependency
+ in libraryBuilder.library.dependencies) {
if (!dependency.isImport) continue;
List<Combinator> combinators;
@@ -871,10 +876,10 @@
combinators ??= <Combinator>[];
combinators.add(combinator.isShow
- ? new Combinator.show(
- combinator.names, combinator.fileOffset, library.fileUri)
- : new Combinator.hide(
- combinator.names, combinator.fileOffset, library.fileUri));
+ ? new Combinator.show(combinator.names, combinator.fileOffset,
+ libraryBuilder.fileUri)
+ : new Combinator.hide(combinator.names, combinator.fileOffset,
+ libraryBuilder.fileUri));
}
debugLibrary.addImport(
@@ -915,13 +920,13 @@
..parent = parameters;
procedure.fileUri = debugLibrary.fileUri;
- procedure.parent = className != null ? kernelClass : library.target;
+ procedure.parent = className != null ? cls : libraryBuilder.library;
userCode.uriToSource.remove(debugExprUri);
userCode.loader.sourceBytes.remove(debugExprUri);
// Make sure the library has a canonical name.
- Component c = new Component(libraries: [debugLibrary.target]);
+ Component c = new Component(libraries: [debugLibrary.library]);
c.computeCanonicalNames();
userCode.runProcedureTransformations(procedure);
@@ -972,31 +977,31 @@
return false;
}
- addBuilderAndInvalidateUris(Uri uri, LibraryBuilder library) {
- if (uri.scheme == "dart" && !library.isSynthetic) {
- result.add(library);
+ addBuilderAndInvalidateUris(Uri uri, LibraryBuilder libraryBuilder) {
+ if (uri.scheme == "dart" && !libraryBuilder.isSynthetic) {
+ result.add(libraryBuilder);
return;
}
- builders[uri] = library;
- if (isInvalidated(uri, library.target.fileUri)) {
+ builders[uri] = libraryBuilder;
+ if (isInvalidated(uri, libraryBuilder.library.fileUri)) {
invalidatedImportUris.add(uri);
}
- if (library is SourceLibraryBuilder) {
- for (LibraryBuilder part in library.parts) {
+ if (libraryBuilder is SourceLibraryBuilder) {
+ for (LibraryBuilder part in libraryBuilder.parts) {
if (isInvalidated(part.uri, part.fileUri)) {
invalidatedImportUris.add(part.uri);
builders[part.uri] = part;
}
}
- } else if (library is DillLibraryBuilder) {
- for (LibraryPart part in library.target.parts) {
- Uri partUri = library.uri.resolve(part.partUri);
- Uri fileUri =
- getPartFileUri(library.library.fileUri, part, uriTranslator);
+ } else if (libraryBuilder is DillLibraryBuilder) {
+ for (LibraryPart part in libraryBuilder.library.parts) {
+ Uri partUri = libraryBuilder.uri.resolve(part.partUri);
+ Uri fileUri = getPartFileUri(
+ libraryBuilder.library.fileUri, part, uriTranslator);
if (isInvalidated(partUri, fileUri)) {
invalidatedImportUris.add(partUri);
- builders[partUri] = library;
+ builders[partUri] = libraryBuilder;
}
}
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index 2b72f56..bf7c912 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -112,7 +112,7 @@
import 'kernel_builder.dart';
// TODO(ahe): Remove this and ensure all nodes have a location.
-const Token noLocation = null;
+const Null noLocation = null;
// TODO(danrubel): Remove this once control flow and spread collection support
// has been enabled by default.
@@ -124,7 +124,7 @@
// TODO(ahe): Rename [library] to 'part'.
@override
- final SourceLibraryBuilder library;
+ final SourceLibraryBuilder libraryBuilder;
final ModifierBuilder member;
@@ -265,7 +265,7 @@
final List<TypeParameter> extensionTypeParameters;
BodyBuilder(
- {this.library,
+ {this.libraryBuilder,
this.member,
this.enclosingScope,
this.formalParameterScope,
@@ -280,22 +280,23 @@
: forest = const Forest(),
classBuilder =
declarationBuilder is ClassBuilder ? declarationBuilder : null,
- enableNative =
- library.loader.target.backendTarget.enableNative(library.uri),
- stringExpectedAfterNative =
- library.loader.target.backendTarget.nativeExtensionExpectsString,
- ignoreMainInGetMainClosure = library.uri.scheme == 'dart' &&
- (library.uri.path == "_builtin" || library.uri.path == "ui"),
+ enableNative = libraryBuilder.loader.target.backendTarget
+ .enableNative(libraryBuilder.uri),
+ stringExpectedAfterNative = libraryBuilder
+ .loader.target.backendTarget.nativeExtensionExpectsString,
+ ignoreMainInGetMainClosure = libraryBuilder.uri.scheme == 'dart' &&
+ (libraryBuilder.uri.path == "_builtin" ||
+ libraryBuilder.uri.path == "ui"),
needsImplicitSuperInitializer = declarationBuilder is ClassBuilder &&
coreTypes?.objectClass != declarationBuilder.cls,
typePromoter = typeInferrer?.typePromoter,
- legacyMode = library.legacyMode,
+ legacyMode = libraryBuilder.legacyMode,
super(enclosingScope);
BodyBuilder.withParents(FieldBuilder field, SourceLibraryBuilder part,
DeclarationBuilder declarationBuilder, TypeInferrer typeInferrer)
: this(
- library: part,
+ libraryBuilder: part,
member: field,
enclosingScope: declarationBuilder?.scope ?? field.library.scope,
formalParameterScope: null,
@@ -323,7 +324,7 @@
Scope scope,
Uri fileUri)
: this(
- library: library,
+ libraryBuilder: library,
member: member,
enclosingScope: scope,
formalParameterScope: null,
@@ -481,7 +482,8 @@
}
LocatedMessage context = scope.declare(
variable.name,
- new VariableBuilder(variable, member ?? classBuilder ?? library, uri),
+ new VariableBuilder(
+ variable, member ?? classBuilder ?? libraryBuilder, uri),
uri);
if (context != null) {
// This case is different from the above error. In this case, the problem
@@ -503,7 +505,7 @@
void inferAnnotations(List<Expression> annotations) {
if (annotations != null) {
typeInferrer?.inferMetadata(this, annotations);
- library.loader.transformListPostInference(
+ libraryBuilder.loader.transformListPostInference(
annotations, transformSetLiterals, transformCollections);
}
}
@@ -535,14 +537,14 @@
expression = new UnresolvedNameGenerator(
this,
deprecated_extractToken(identifier),
- new Name(identifier.name, library.nameOrigin));
+ new Name(identifier.name, libraryBuilder.nameOrigin));
}
if (name?.isNotEmpty ?? false) {
Token period = periodBeforeName ?? beginToken.next.next;
Generator generator = expression;
expression = generator.buildPropertyAccess(
new IncompletePropertyAccessGenerator(
- this, period.next, new Name(name, library.nameOrigin)),
+ this, period.next, new Name(name, libraryBuilder.nameOrigin)),
period.next.offset,
false);
}
@@ -580,17 +582,17 @@
Token beginToken,
Token endToken) {
debugEvent("TopLevelFields");
- if (!library.loader.target.enableNonNullable) {
+ if (!libraryBuilder.loader.target.enableNonNullable) {
reportNonNullableModifierError(lateToken);
}
push(count);
}
@override
- void endFields(Token staticToken, Token covariantToken, Token lateToken,
+ void endClassFields(Token staticToken, Token covariantToken, Token lateToken,
Token varFinalOrConst, int count, Token beginToken, Token endToken) {
debugEvent("Fields");
- if (!library.loader.target.enableNonNullable) {
+ if (!libraryBuilder.loader.target.enableNonNullable) {
reportNonNullableModifierError(lateToken);
}
push(count);
@@ -610,30 +612,30 @@
declaration =
declarationBuilder.lookupLocalMember(name, required: true);
} else {
- declaration = library.lookupLocalMember(name, required: true);
+ declaration = libraryBuilder.lookupLocalMember(name, required: true);
}
- FieldBuilder field;
+ FieldBuilder fieldBuilder;
if (declaration.isField && declaration.next == null) {
- field = declaration;
+ fieldBuilder = declaration;
} else {
continue;
}
- fields.add(field);
+ fields.add(fieldBuilder);
if (initializer != null) {
- if (field.next != null) {
+ if (fieldBuilder.next != null) {
// Duplicate definition. The field might not be the correct one,
// so we skip inference of the initializer.
// Error reporting and recovery is handled elsewhere.
- } else if (field.target.initializer != null) {
+ } else if (fieldBuilder.field.initializer != null) {
// The initializer was already compiled (e.g., if it appear in the
// outline, like constant field initializers) so we do not need to
// perform type inference or transformations.
} else {
- field.initializer = initializer;
+ fieldBuilder.initializer = initializer;
typeInferrer?.inferFieldInitializer(
- this, field.builtType, initializer);
- library.loader.transformPostInference(
- field.target, transformSetLiterals, transformCollections);
+ this, fieldBuilder.builtType, initializer);
+ libraryBuilder.loader.transformPostInference(
+ fieldBuilder.field, transformSetLiterals, transformCollections);
}
}
}
@@ -693,8 +695,8 @@
formal.name,
formal.charOffset,
formal.charOffset,
- new VariableGet(formal.declaration),
- formalType: formal.declaration.type);
+ new VariableGet(formal.variable),
+ formalType: formal.variable.type);
}
member.addInitializer(initializer, this);
}
@@ -772,7 +774,7 @@
DartType _computeReturnTypeContext(MemberBuilder member) {
if (member is ProcedureBuilder) {
- return member.procedure.function.returnType;
+ return member.actualProcedure.function.returnType;
} else {
assert(member is ConstructorBuilder);
return const DynamicType();
@@ -801,7 +803,7 @@
realParameter.initializer = initializer..parent = realParameter;
typeInferrer?.inferParameterInitializer(
this, initializer, realParameter.type);
- library.loader.transformPostInference(
+ libraryBuilder.loader.transformPostInference(
realParameter, transformSetLiterals, transformCollections);
}
}
@@ -810,7 +812,7 @@
typeInferrer?.inferFunctionBody(
this, _computeReturnTypeContext(member), asyncModifier, body);
if (body != null) {
- library.loader.transformPostInference(
+ libraryBuilder.loader.transformPostInference(
body, transformSetLiterals, transformCollections);
}
@@ -835,14 +837,14 @@
Message problem;
switch (asyncModifier) {
case AsyncMarker.Async:
- DartType futureBottomType = library.loader.futureOfBottom;
+ DartType futureBottomType = libraryBuilder.loader.futureOfBottom;
if (!typeEnvironment.isSubtypeOf(futureBottomType, returnType)) {
problem = fasta.messageIllegalAsyncReturnType;
}
break;
case AsyncMarker.AsyncStar:
- DartType streamBottomType = library.loader.streamOfBottom;
+ DartType streamBottomType = libraryBuilder.loader.streamOfBottom;
if (returnType is VoidType) {
problem = fasta.messageIllegalAsyncGeneratorVoidReturnType;
} else if (!typeEnvironment.isSubtypeOf(
@@ -852,7 +854,7 @@
break;
case AsyncMarker.SyncStar:
- DartType iterableBottomType = library.loader.iterableOfBottom;
+ DartType iterableBottomType = libraryBuilder.loader.iterableOfBottom;
if (returnType is VoidType) {
problem = fasta.messageIllegalSyncGeneratorVoidReturnType;
} else if (!typeEnvironment.isSubtypeOf(
@@ -883,7 +885,7 @@
formals.parameters.single.isOptional) {
int charOffset = formals?.charOffset ??
body?.fileOffset ??
- builder.target.fileOffset;
+ builder.member.fileOffset;
if (body == null) {
body = new EmptyStatement()..fileOffset = charOffset;
}
@@ -958,8 +960,8 @@
if (member == null) return;
Library ensureLibraryLoaded = member.enclosingLibrary;
LibraryBuilder builder =
- library.loader.builders[ensureLibraryLoaded.importUri] ??
- library.loader.target.dillTarget.loader
+ libraryBuilder.loader.builders[ensureLibraryLoaded.importUri] ??
+ libraryBuilder.loader.target.dillTarget.loader
.builders[ensureLibraryLoaded.importUri];
if (builder is DillLibraryBuilder) {
builder.ensureLoaded();
@@ -975,8 +977,8 @@
if (member == null) return true;
Library ensureLibraryLoaded = member.enclosingLibrary;
LibraryBuilder builder =
- library.loader.builders[ensureLibraryLoaded.importUri] ??
- library.loader.target.dillTarget.loader
+ libraryBuilder.loader.builders[ensureLibraryLoaded.importUri] ??
+ libraryBuilder.loader.target.dillTarget.loader
.builders[ensureLibraryLoaded.importUri];
if (builder is DillLibraryBuilder) {
return builder.isBuiltAndMarked;
@@ -1025,7 +1027,7 @@
} else if (resolvedTarget is Constructor &&
resolvedTarget.enclosingClass.isAbstract) {
replacementNode = evaluateArgumentsBefore(
- forest.createArguments(invocation.arguments.positional, null,
+ forest.createArguments(noLocation, invocation.arguments.positional,
types: invocation.arguments.types,
named: invocation.arguments.named),
buildAbstractClassInstantiationError(
@@ -1046,7 +1048,8 @@
forest.createNullLiteral(null)
..fileOffset = invocation.fileOffset,
errorName,
- forest.createArguments(invocation.arguments.positional, null,
+ forest.createArguments(
+ noLocation, invocation.arguments.positional,
types: invocation.arguments.types,
named: invocation.arguments.named),
initialTarget.fileOffset);
@@ -1064,7 +1067,8 @@
replacementNode = buildStaticInvocation(
resolvedTarget,
- forest.createArguments(invocation.arguments.positional, null,
+ forest.createArguments(
+ noLocation, invocation.arguments.positional,
types: invocation.arguments.types,
named: invocation.arguments.named),
constness: invocation.isConst
@@ -1172,8 +1176,8 @@
List<TypeVariableBuilder> typeParameterBuilders;
for (TypeParameter typeParameter in parameters.typeParameters) {
typeParameterBuilders ??= <TypeVariableBuilder>[];
- typeParameterBuilders
- .add(new TypeVariableBuilder.fromKernel(typeParameter, library));
+ typeParameterBuilders.add(
+ new TypeVariableBuilder.fromKernel(typeParameter, libraryBuilder));
}
enterFunctionTypeScope(typeParameterBuilders);
@@ -1185,8 +1189,8 @@
for (int i = 0; i < parameters.positionalParameters.length; i++) {
VariableDeclaration formal = parameters.positionalParameters[i];
formals[i] = new FormalParameterBuilder(
- null, 0, null, formal.name, library, formal.fileOffset)
- ..declaration = formal;
+ null, 0, null, formal.name, libraryBuilder, formal.fileOffset)
+ ..variable = formal;
}
enterLocalScope(
null,
@@ -1205,7 +1209,7 @@
.withLocation(uri, eof.charOffset, eof.length));
}
- ReturnJudgment fakeReturn = new ReturnJudgment(null, expression);
+ ReturnJudgment fakeReturn = new ReturnJudgment(true, expression);
typeInferrer?.inferFunctionBody(
this, const DynamicType(), AsyncMarker.Sync, fakeReturn);
@@ -1248,7 +1252,7 @@
/// Edition](
/// https://ecma-international.org/publications/files/ECMA-ST/ECMA-408.pdf).
assert(builder == member);
- Constructor constructor = builder.constructor;
+ Constructor constructor = builder.actualConstructor;
if (asyncModifier != AsyncMarker.Sync) {
// TODO(ahe): Change this to a null check.
int offset = builder.body?.fileOffset ?? builder.charOffset;
@@ -1287,7 +1291,7 @@
constructor.initializers.add(initializer);
}
setParents(constructor.initializers, constructor);
- library.loader.transformListPostInference(
+ libraryBuilder.loader.transformListPostInference(
constructor.initializers, transformSetLiterals, transformCollections);
if (constructor.function.body == null) {
/// >If a generative constructor c is not a redirecting constructor
@@ -1337,12 +1341,12 @@
arguments.getRange(0, firstNamedArgumentIndex));
List<NamedExpression> named = new List<NamedExpression>.from(
arguments.getRange(firstNamedArgumentIndex, arguments.length));
- push(forest.createArguments(positional, beginToken, named: named));
+ push(forest.createArguments(beginToken.offset, positional, named: named));
} else {
// TODO(kmillikin): Find a way to avoid allocating a second list in the
// case where there were no named arguments, which is a common one.
push(forest.createArguments(
- new List<Expression>.from(arguments), beginToken));
+ beginToken.offset, new List<Expression>.from(arguments)));
}
}
@@ -1397,7 +1401,7 @@
assert(typeArguments == null);
}
if (receiver is Identifier) {
- Name name = new Name(receiver.name, library.nameOrigin);
+ Name name = new Name(receiver.name, libraryBuilder.nameOrigin);
if (arguments == null) {
push(new IncompletePropertyAccessGenerator(this, beginToken, name));
} else {
@@ -1432,9 +1436,8 @@
push(new VariableUseGenerator(this, token, expression.variable));
expression.extend();
} else {
- VariableDeclaration variable = new VariableDeclarationJudgment.forValue(
- expression, functionNestingLevel)
- ..fileOffset = expression.fileOffset;
+ VariableDeclaration variable = forest.createVariableDeclarationForValue(
+ expression.fileOffset, expression);
push(new CascadeJudgment(variable)..fileOffset = expression.fileOffset);
push(new VariableUseGenerator(this, token, variable));
}
@@ -1515,7 +1518,7 @@
}
} else {
Expression result = buildMethodInvocation(a, new Name(operator),
- forest.createArguments(<Expression>[b], noLocation), token.charOffset,
+ forest.createArguments(noLocation, <Expression>[b]), token.charOffset,
// This *could* be a constant expression, we can't know without
// evaluating [a] and [b].
isConstantExpression: !isSuper,
@@ -1594,7 +1597,7 @@
if (periodIndex != -1) {
length -= periodIndex + 1;
}
- Name kernelName = new Name(name, library.nameOrigin);
+ Name kernelName = new Name(name, libraryBuilder.nameOrigin);
List<LocatedMessage> context;
if (candidate != null && candidate.location != null) {
Uri uri = candidate.location.file;
@@ -1631,7 +1634,7 @@
wasHandled: true, context: context);
return forest.createThrow(
null,
- library.loader.instantiateNoSuchMethodError(
+ libraryBuilder.loader.instantiateNoSuchMethodError(
receiver, name, arguments, charOffset,
isMethod: !isGetter && !isSetter,
isGetter: isGetter,
@@ -1782,107 +1785,6 @@
this, token, createVariableGet(variable, charOffset), name);
}
- @override
- Expression createExtensionTearOff(
- Procedure procedure,
- VariableDeclaration extensionThis,
- List<TypeParameter> extensionTypeParameters,
- Token token) {
- int charOffset = offsetForToken(token);
-
- FunctionNode function = procedure.function;
- List<TypeParameter> typeParameters = [];
- List<DartType> typeArguments = [];
- int extensionTypeParameterCount = extensionTypeParameters?.length ?? 0;
- for (int index = 0; index < extensionTypeParameterCount; index++) {
- typeArguments
- .add(forest.createTypeParameterType(extensionTypeParameters[index]));
- }
- for (int index = extensionTypeParameterCount;
- index < function.typeParameters.length;
- index++) {
- TypeParameter typeParameter = function.typeParameters[index];
- TypeParameter newTypeParameter =
- forest.createTypeParameter(typeParameter.name);
- typeParameters.add(newTypeParameter);
- typeArguments.add(forest.createTypeParameterType(newTypeParameter));
- }
- Substitution substitution =
- Substitution.fromPairs(function.typeParameters, typeArguments);
- for (int index = extensionTypeParameterCount;
- index < function.typeParameters.length;
- index++) {
- TypeParameter oldTypeParameter = function.typeParameters[index];
- TypeParameter newTypeParameter =
- typeParameters[index - extensionTypeParameterCount];
- newTypeParameter.bound =
- substitution.substituteType(oldTypeParameter.bound);
- newTypeParameter.defaultType = oldTypeParameter.defaultType;
- }
-
- DartType returnType = substitution.substituteType(function.returnType);
-
- List<VariableDeclaration> positionalParameters = [];
- List<Expression> positionalArguments = [];
- functionNestingLevel++;
-
- VariableDeclaration copyParameter(VariableDeclaration parameter,
- {bool isOptional}) {
- // TODO(johnniwinther): Handle default values.
- return forest.createVariableDeclaration(
- parameter.name, functionNestingLevel,
- type: substitution.substituteType(parameter.type),
- initializer: isOptional ? forest.createNullLiteral(token) : null);
- }
-
- for (int position = 0;
- position < function.positionalParameters.length;
- position++) {
- VariableDeclaration parameter = function.positionalParameters[position];
- if (position == 0) {
- /// Pass `this` as a captured variable.
- positionalArguments.add(createVariableGet(extensionThis, charOffset));
- } else {
- VariableDeclaration newParameter = copyParameter(parameter,
- isOptional: position >= function.requiredParameterCount);
- positionalParameters.add(newParameter);
- positionalArguments.add(createVariableGet(newParameter, charOffset));
- }
- }
- List<VariableDeclaration> namedParameters = [];
- List<NamedExpression> namedArguments = [];
- for (VariableDeclaration parameter in function.namedParameters) {
- VariableDeclaration newParameter =
- copyParameter(parameter, isOptional: true);
- namedParameters.add(newParameter);
- namedArguments.add(forest.createNamedExpression(
- parameter.name, createVariableGet(newParameter, charOffset)));
- }
-
- Statement body = forest.createReturnStatement(
- null,
- buildStaticInvocation(
- procedure,
- forest.createArguments(positionalArguments, token,
- types: typeArguments, named: namedArguments),
- charOffset: charOffset),
- charOffset);
-
- FunctionExpression expression = forest.createFunctionExpression(
- forest.createFunctionNode(body,
- typeParameters: typeParameters,
- positionalParameters: positionalParameters,
- namedParameters: namedParameters,
- requiredParameterCount:
- procedure.function.requiredParameterCount - 1,
- returnType: returnType,
- asyncMarker: procedure.function.asyncMarker,
- dartAsyncMarker: procedure.function.dartAsyncMarker),
- charOffset);
- functionNestingLevel--;
- return expression;
- }
-
/// Look up [name] in [scope] using [token] as location information (both to
/// report problems and as the file offset in the generated kernel code).
/// [isQualified] should be true if [name] is a qualified access (which
@@ -1903,8 +1805,8 @@
prefix == null &&
(classBuilder?.isPatch ?? false)) {
// The scope of a patched method includes the origin class.
- declaration =
- classBuilder.origin.findStaticBuilder(name, charOffset, uri, library);
+ declaration = classBuilder.origin
+ .findStaticBuilder(name, charOffset, uri, libraryBuilder);
}
if (declaration != null &&
declaration.isDeclarationInstanceMember &&
@@ -1928,7 +1830,7 @@
declaration.isDeclarationInstanceMember)) {
// We either didn't find a declaration or found an instance member from
// a non-instance context.
- Name n = new Name(name, library.nameOrigin);
+ Name n = new Name(name, libraryBuilder.nameOrigin);
if (!isQualified && isDeclarationInstanceContext) {
assert(declaration == null);
if (constantContext != ConstantContext.none || member.isField) {
@@ -1987,7 +1889,7 @@
addProblem(
fasta.messageNotAConstantExpression, charOffset, token.length);
}
- Name n = new Name(name, library.nameOrigin);
+ Name n = new Name(name, libraryBuilder.nameOrigin);
Member getter;
Member setter;
if (declaration is AccessErrorBuilder) {
@@ -2207,8 +2109,8 @@
push(buildProblemStatement(
fasta.messageConstructorWithReturnType, beginToken.charOffset));
} else {
- push(forest.createReturnStatement(
- beginToken, expression, offsetForToken(beginToken)));
+ push(forest.createReturnStatement(offsetForToken(beginToken), expression,
+ isArrow: !identical(beginToken.lexeme, "return")));
}
}
@@ -2292,7 +2194,8 @@
isLate: isLate)
..fileOffset = identifier.charOffset
..fileEqualsOffset = offsetForToken(equalsToken);
- library.checkBoundsInVariableDeclaration(variable, typeEnvironment, uri);
+ libraryBuilder.checkBoundsInVariableDeclaration(
+ variable, typeEnvironment, uri);
push(variable);
}
@@ -2314,7 +2217,7 @@
debugEvent("NoFieldInitializer");
if (constantContext == ConstantContext.inferred) {
// Creating a null value to prevent the Dart VM from crashing.
- push(forest.createNullLiteral(token));
+ push(forest.createNullLiteral(offsetForToken(token)));
} else {
push(NullValue.FieldInitializer);
}
@@ -2339,7 +2242,7 @@
void beginVariablesDeclaration(
Token token, Token lateToken, Token varFinalOrConst) {
debugEvent("beginVariablesDeclaration");
- if (!library.loader.target.enableNonNullable) {
+ if (!libraryBuilder.loader.target.enableNonNullable) {
reportNonNullableModifierError(lateToken);
}
UnresolvedType type = pop();
@@ -2517,17 +2420,6 @@
Object variableOrExpression = pop();
exitLocalScope();
- if (!library.loader.target.enableControlFlowCollections) {
- // TODO(danrubel): Report a more user friendly error message
- // when an experiment is not enabled
- handleRecoverableError(
- fasta.templateUnexpectedToken.withArguments(forToken),
- forToken,
- forToken);
- push(invalidCollectionElement);
- return;
- }
-
if (constantContext != ConstantContext.none) {
handleRecoverableError(
fasta.templateCantUseControlFlowOrSpreadAsConstant
@@ -2675,7 +2567,7 @@
leftBracket,
expressions,
rightBracket);
- library.checkBoundsInListLiteral(node, typeEnvironment, uri);
+ libraryBuilder.checkBoundsInListLiteral(node, typeEnvironment, uri);
push(node);
}
@@ -2684,7 +2576,7 @@
DartType typeArgument;
if (typeArguments != null) {
typeArgument = buildDartType(typeArguments.single);
- if (!library.loader.target.legacyMode) {
+ if (!libraryBuilder.loader.target.legacyMode) {
typeArgument = instantiateToBounds(typeArgument, coreTypes.objectClass);
}
} else {
@@ -2714,7 +2606,7 @@
leftBrace,
expressions,
leftBrace.endGroup);
- library.checkBoundsInSetLiteral(node, typeEnvironment, uri);
+ libraryBuilder.checkBoundsInSetLiteral(node, typeEnvironment, uri);
push(node);
}
@@ -2800,7 +2692,7 @@
@override
void handleLiteralNull(Token token) {
debugEvent("LiteralNull");
- push(forest.createNullLiteral(token));
+ push(forest.createNullLiteral(offsetForToken(token)));
}
void buildLiteralMap(List<UnresolvedType> typeArguments, Token constKeyword,
@@ -2834,7 +2726,7 @@
leftBrace,
entries,
leftBrace.endGroup);
- library.checkBoundsInMapLiteral(node, typeEnvironment, uri);
+ libraryBuilder.checkBoundsInMapLiteral(node, typeEnvironment, uri);
push(node);
}
@@ -2885,7 +2777,7 @@
@override
void handleNonNullAssertExpression(Token bang) {
- if (!library.loader.target.enableNonNullable) {
+ if (!libraryBuilder.loader.target.enableNonNullable) {
reportNonNullAssertExpressionNotEnabled(bang);
}
}
@@ -2894,9 +2786,10 @@
void handleType(Token beginToken, Token questionMark) {
// TODO(ahe): The scope is wrong for return types of generic functions.
debugEvent("Type");
- if (!library.loader.target.enableNonNullable) {
+ if (!libraryBuilder.loader.target.enableNonNullable) {
reportErrorIfNullableType(questionMark);
}
+ bool isMarkedAsNullable = questionMark != null;
List<UnresolvedType> arguments = pop();
Object name = pop();
if (name is QualifiedName) {
@@ -2910,10 +2803,13 @@
String displayName = debugName(name, suffix.lexeme);
int offset = offsetForToken(beginToken);
Message message = fasta.templateNotAType.withArguments(displayName);
- library.addProblem(
+ libraryBuilder.addProblem(
message, offset, lengthOfSpan(beginToken, suffix), uri);
push(new UnresolvedType(
- new NamedTypeBuilder(name, null)
+ new NamedTypeBuilder(
+ name,
+ libraryBuilder.computeNullabilityFromToken(isMarkedAsNullable),
+ null)
..bind(new InvalidTypeBuilder(
name,
message.withLocation(
@@ -2925,15 +2821,18 @@
}
TypeBuilder result;
if (name is Generator) {
- result = name.buildTypeWithResolvedArguments(arguments);
+ result = name.buildTypeWithResolvedArguments(
+ libraryBuilder.computeNullabilityFromToken(isMarkedAsNullable),
+ arguments);
if (result == null) {
unhandled("null", "result", beginToken.charOffset, uri);
}
} else if (name is ProblemBuilder) {
// TODO(ahe): Arguments could be passed here.
- library.addProblem(
+ libraryBuilder.addProblem(
name.message, name.charOffset, name.name.length, name.fileUri);
- result = new NamedTypeBuilder(name.name, null)
+ result = new NamedTypeBuilder(name.name,
+ libraryBuilder.computeNullabilityFromToken(isMarkedAsNullable), null)
..bind(new InvalidTypeBuilder(
name.name,
name.message.withLocation(
@@ -2971,7 +2870,7 @@
@override
void endFunctionType(Token functionToken, Token questionMark) {
debugEvent("FunctionType");
- if (!library.loader.target.enableNonNullable) {
+ if (!libraryBuilder.loader.target.enableNonNullable) {
reportErrorIfNullableType(questionMark);
}
FormalParameters formals = pop();
@@ -2986,9 +2885,10 @@
void handleVoidKeyword(Token token) {
debugEvent("VoidKeyword");
int offset = offsetForToken(token);
+ // "void" is always nullable.
push(new UnresolvedType(
- new NamedTypeBuilder("void", null)
- ..bind(new VoidTypeBuilder(const VoidType(), library, offset)),
+ new NamedTypeBuilder("void", const NullabilityBuilder.nullable(), null)
+ ..bind(new VoidTypeBuilder(const VoidType(), libraryBuilder, offset)),
offset,
uri));
}
@@ -2997,18 +2897,12 @@
void handleAsOperator(Token operator) {
debugEvent("AsOperator");
DartType type = buildDartType(pop());
- library.checkBoundsInType(type, typeEnvironment, uri, operator.charOffset);
+ libraryBuilder.checkBoundsInType(
+ type, typeEnvironment, uri, operator.charOffset);
Expression expression = popForValue();
- if (!library.loader.target.enableConstantUpdate2018 &&
- constantContext != ConstantContext.none) {
- push(desugarSyntheticExpression(buildProblem(
- fasta.templateNotConstantExpression.withArguments('As expression'),
- operator.charOffset,
- operator.length)));
- } else {
- Expression node = forest.createAsExpression(expression, type, operator);
- push(node);
- }
+ Expression asExpression =
+ forest.createAsExpression(expression, type, operator);
+ push(asExpression);
}
@override
@@ -3019,21 +2913,13 @@
bool isInverted = not != null;
Expression isExpression =
forest.createIsExpression(operand, isOperator, not, type);
- library.checkBoundsInType(
+ libraryBuilder.checkBoundsInType(
type, typeEnvironment, uri, isOperator.charOffset);
if (operand is VariableGet) {
typePromoter?.handleIsCheck(isExpression, isInverted, operand.variable,
type, functionNestingLevel);
}
- if (!library.loader.target.enableConstantUpdate2018 &&
- constantContext != ConstantContext.none) {
- push(desugarSyntheticExpression(buildProblem(
- fasta.templateNotConstantExpression.withArguments('Is expression'),
- isOperator.charOffset,
- isOperator.length)));
- } else {
- push(isExpression);
- }
+ push(isExpression);
}
@override
@@ -3081,7 +2967,7 @@
void beginFormalParameter(Token token, MemberKind kind, Token requiredToken,
Token covariantToken, Token varFinalOrConst) {
// TODO(danrubel): handle required token
- if (!library.loader.target.enableNonNullable) {
+ if (!libraryBuilder.loader.target.enableNonNullable) {
reportNonNullableModifierError(requiredToken);
}
push((covariantToken != null ? covariantMask : 0) |
@@ -3139,10 +3025,10 @@
}
} else {
parameter = new FormalParameterBuilder(null, modifiers, type?.builder,
- name?.name, library, offsetForToken(nameToken));
+ name?.name, libraryBuilder, offsetForToken(nameToken));
}
VariableDeclaration variable =
- parameter.build(library, functionNestingLevel);
+ parameter.build(libraryBuilder, functionNestingLevel);
Expression initializer = name?.initializer;
if (initializer != null) {
if (member is RedirectingFactoryBuilder) {
@@ -3208,7 +3094,7 @@
FormalParameters formals = pop();
UnresolvedType returnType = pop();
List<TypeVariableBuilder> typeVariables = pop();
- if (!library.loader.target.enableNonNullable) {
+ if (!libraryBuilder.loader.target.enableNonNullable) {
reportErrorIfNullableType(question);
}
UnresolvedType type = formals.toFunctionType(returnType, typeVariables);
@@ -3281,7 +3167,7 @@
enterLocalScope(
null,
formals.computeFormalParameterScope(
- scope, member ?? classBuilder ?? library, this));
+ scope, member ?? classBuilder ?? libraryBuilder, this));
}
}
@@ -3317,10 +3203,11 @@
int parameterCount = catchParameters.parameters.length;
if (parameterCount > 0) {
exception = catchParameters.parameters[0];
- exception.build(library, functionNestingLevel).type = exceptionType;
+ exception.build(libraryBuilder, functionNestingLevel).type =
+ exceptionType;
if (parameterCount > 1) {
stackTrace = catchParameters.parameters[1];
- stackTrace.build(library, functionNestingLevel).type =
+ stackTrace.build(libraryBuilder, functionNestingLevel).type =
coreTypes.stackTraceClass.rawType;
}
}
@@ -3611,7 +3498,8 @@
ConstructorInvocation node =
new ConstructorInvocation(target, arguments, isConst: isConst)
..fileOffset = charOffset;
- library.checkBoundsInConstructorInvocation(node, typeEnvironment, uri);
+ libraryBuilder.checkBoundsInConstructorInvocation(
+ node, typeEnvironment, uri);
return node;
} else {
Procedure procedure = target;
@@ -3627,22 +3515,49 @@
arguments,
charOffset);
}
- StaticInvocation node = FactoryConstructorInvocationJudgment(
+ StaticInvocation node = new FactoryConstructorInvocationJudgment(
target, arguments,
isConst: isConst)
..fileOffset = charOffset;
- library.checkBoundsInFactoryInvocation(node, typeEnvironment, uri);
+ libraryBuilder.checkBoundsInFactoryInvocation(
+ node, typeEnvironment, uri);
return node;
} else {
StaticInvocation node =
new StaticInvocation(target, arguments, isConst: isConst)
..fileOffset = charOffset;
- library.checkBoundsInStaticInvocation(node, typeEnvironment, uri);
+ libraryBuilder.checkBoundsInStaticInvocation(
+ node, typeEnvironment, uri);
return node;
}
}
}
+ Expression buildExtensionMethodInvocation(
+ int fileOffset, Procedure target, Arguments arguments) {
+ // TODO(johnniwinther): Check type argument count.
+ List<TypeParameter> typeParameters = target.function.typeParameters;
+ LocatedMessage argMessage = checkArgumentsForFunction(
+ target.function, arguments, fileOffset, typeParameters);
+ if (argMessage != null) {
+ return wrapSyntheticExpression(
+ throwNoSuchMethodError(
+ forest.createNullLiteral(null)..fileOffset = fileOffset,
+ target.name.name,
+ arguments,
+ fileOffset,
+ candidate: target,
+ message: argMessage),
+ fileOffset);
+ }
+
+ StaticInvocation node = new StaticInvocation(target, arguments)
+ ..fileOffset = fileOffset;
+ // TODO(johnniwinther): Check type argument bounds.
+ //libraryBuilder.checkBoundsInStaticInvocation(node, typeEnvironment, uri);
+ return node;
+ }
+
@override
LocatedMessage checkArgumentsForFunction(FunctionNode function,
Arguments arguments, int offset, List<TypeParameter> typeParameters) {
@@ -3870,7 +3785,8 @@
return buildProblem(fasta.messageEnumInstantiation,
nameToken.charOffset, nameToken.length);
}
- Builder b = type.findConstructorOrFactory(name, charOffset, uri, library);
+ Builder b =
+ type.findConstructorOrFactory(name, charOffset, uri, libraryBuilder);
Member target = b?.target;
if (b == null) {
// Not found. Reported below.
@@ -3904,7 +3820,7 @@
target.function.typeParameters.length !=
forest.argumentsTypeArguments(arguments).length) {
arguments = forest.createArguments(
- forest.argumentsPositional(arguments), null,
+ noLocation, forest.argumentsPositional(arguments),
named: forest.argumentsNamed(arguments),
types: new List<DartType>.filled(
target.function.typeParameters.length, const DynamicType(),
@@ -3987,27 +3903,6 @@
Token ifToken = pop();
typePromoter?.enterElse();
typePromoter?.exitConditional();
- if (!library.loader.target.enableControlFlowCollections) {
- // TODO(danrubel): Report a more user friendly error message
- // when an experiment is not enabled
- handleRecoverableError(
- fasta.templateUnexpectedToken.withArguments(ifToken),
- ifToken,
- ifToken);
- push(invalidCollectionElement);
- return;
- }
-
- if (constantContext != ConstantContext.none &&
- !library.loader.target.enableConstantUpdate2018) {
- handleRecoverableError(
- fasta.templateCantUseControlFlowOrSpreadAsConstant
- .withArguments(ifToken),
- ifToken,
- ifToken);
- push(invalidCollectionElement);
- return;
- }
transformCollections = true;
if (entry is MapEntry) {
@@ -4026,27 +3921,6 @@
Object condition = pop(); // parenthesized expression
Token ifToken = pop();
typePromoter?.exitConditional();
- if (!library.loader.target.enableControlFlowCollections) {
- // TODO(danrubel): Report a more user friendly error message
- // when an experiment is not enabled
- handleRecoverableError(
- fasta.templateUnexpectedToken.withArguments(ifToken),
- ifToken,
- ifToken);
- push(invalidCollectionElement);
- return;
- }
-
- if (constantContext != ConstantContext.none &&
- !library.loader.target.enableConstantUpdate2018) {
- handleRecoverableError(
- fasta.templateCantUseControlFlowOrSpreadAsConstant
- .withArguments(ifToken),
- ifToken,
- ifToken);
- push(invalidCollectionElement);
- return;
- }
transformCollections = true;
if (thenEntry is MapEntry) {
@@ -4100,26 +3974,6 @@
void handleSpreadExpression(Token spreadToken) {
debugEvent("SpreadExpression");
Object expression = pop();
- if (!library.loader.target.enableSpreadCollections) {
- handleRecoverableError(
- fasta.templateUnexpectedToken.withArguments(spreadToken),
- spreadToken,
- spreadToken);
- push(invalidCollectionElement);
- return;
- }
-
- if (constantContext != ConstantContext.none &&
- !library.loader.target.enableConstantUpdate2018) {
- handleRecoverableError(
- fasta.templateCantUseControlFlowOrSpreadAsConstant
- .withArguments(spreadToken),
- spreadToken,
- spreadToken);
- push(invalidCollectionElement);
- return;
- }
-
transformCollections = true;
push(forest.createSpreadElement(toValue(expression), spreadToken));
}
@@ -4261,8 +4115,8 @@
if (!isFunctionExpression) {
annotations = pop(); // Metadata.
}
- FunctionNode function = formals.buildFunctionNode(library, returnType,
- typeParameters, asyncModifier, body, token.charOffset);
+ FunctionNode function = formals.buildFunctionNode(libraryBuilder,
+ returnType, typeParameters, asyncModifier, body, token.charOffset);
if (declaration is FunctionDeclaration) {
VariableDeclaration variable = declaration.variable;
@@ -4343,11 +4197,11 @@
FormalParameters formals = pop();
exitFunction();
List<TypeVariableBuilder> typeParameters = pop();
- FunctionNode function = formals.buildFunctionNode(
- library, null, typeParameters, asyncModifier, body, token.charOffset)
+ FunctionNode function = formals.buildFunctionNode(libraryBuilder, null,
+ typeParameters, asyncModifier, body, token.charOffset)
..fileOffset = beginToken.charOffset;
- if (library.legacyMode && asyncModifier != AsyncMarker.Sync) {
+ if (libraryBuilder.legacyMode && asyncModifier != AsyncMarker.Sync) {
DartType returnType;
switch (asyncModifier) {
case AsyncMarker.Async:
@@ -4427,17 +4281,6 @@
Object lvalue = pop(); // lvalue
exitLocalScope();
- if (!library.loader.target.enableControlFlowCollections) {
- // TODO(danrubel): Report a more user friendly error message
- // when an experiment is not enabled
- handleRecoverableError(
- fasta.templateUnexpectedToken.withArguments(forToken),
- forToken,
- forToken);
- push(invalidCollectionElement);
- return;
- }
-
if (constantContext != ConstantContext.none) {
handleRecoverableError(
fasta.templateCantUseControlFlowOrSpreadAsConstant
@@ -4465,7 +4308,7 @@
VariableDeclaration buildForInVariable(Object lvalue) {
if (lvalue is VariableDeclaration) return lvalue;
- return new VariableDeclarationJudgment.forValue(null, functionNestingLevel);
+ return forest.createVariableDeclarationForValue(noLocation, null);
}
Expression checkForInVariable(
@@ -4987,7 +4830,7 @@
Identifier name = pop();
List<Expression> annotations = pop();
TypeVariableBuilder variable =
- new TypeVariableBuilder(name.name, library, name.charOffset);
+ new TypeVariableBuilder(name.name, libraryBuilder, name.charOffset);
if (annotations != null) {
inferAnnotations(annotations);
for (Expression annotation in annotations) {
@@ -5027,25 +4870,28 @@
if (!legacyMode) {
List<TypeBuilder> calculatedBounds = calculateBounds(
typeVariables,
- library.loader.target.dynamicType,
- library.loader.target.bottomType,
- library.loader.target.objectClassBuilder);
+ libraryBuilder.loader.target.dynamicType,
+ libraryBuilder.loader.target.bottomType,
+ libraryBuilder.loader.target.objectClassBuilder);
for (int i = 0; i < typeVariables.length; ++i) {
typeVariables[i].defaultType = calculatedBounds[i];
- typeVariables[i].defaultType.resolveIn(scope,
- typeVariables[i].charOffset, typeVariables[i].fileUri, library);
+ typeVariables[i].defaultType.resolveIn(
+ scope,
+ typeVariables[i].charOffset,
+ typeVariables[i].fileUri,
+ libraryBuilder);
typeVariables[i].finish(
- library,
- library.loader.target.objectClassBuilder,
- library.loader.target.dynamicType);
+ libraryBuilder,
+ libraryBuilder.loader.target.objectClassBuilder,
+ libraryBuilder.loader.target.dynamicType);
}
} else {
for (int i = 0; i < typeVariables.length; ++i) {
- typeVariables[i].defaultType = library.loader.target.dynamicType;
+ typeVariables[i].defaultType = libraryBuilder.loader.target.dynamicType;
typeVariables[i].finish(
- library,
- library.loader.target.objectClassBuilder,
- library.loader.target.dynamicType);
+ libraryBuilder,
+ libraryBuilder.loader.target.objectClassBuilder,
+ libraryBuilder.loader.target.dynamicType);
}
}
}
@@ -5065,7 +4911,7 @@
growable: true);
int i = 0;
for (TypeVariableBuilder builder in typeVariableBuilders) {
- typeParameters[i++] = builder.target;
+ typeParameters[i++] = builder.parameter;
}
return typeParameters;
}
@@ -5084,7 +4930,7 @@
addProblem(message, charOffset, length,
wasHandled: true, context: context);
}
- String text = library.loader.target.context
+ String text = libraryBuilder.loader.target.context
.format(message.withLocation(uri, charOffset, length), Severity.error);
return wrapSyntheticExpression(
new InvalidExpression(text)..fileOffset = charOffset, charOffset);
@@ -5137,13 +4983,14 @@
return forest.createThrow(
null,
buildStaticInvocation(
- library.loader.coreTypes.fallThroughErrorUrlAndLineConstructor,
- forest.createArguments(<Expression>[
+ libraryBuilder
+ .loader.coreTypes.fallThroughErrorUrlAndLineConstructor,
+ forest.createArguments(noLocation, <Expression>[
forest.createStringLiteral("${location?.file ?? uri}", null)
..fileOffset = charOffset,
forest.createIntLiteral(location?.line ?? 0, null)
..fileOffset = charOffset,
- ], noLocation),
+ ]),
charOffset: charOffset))
..fileOffset = charOffset;
}
@@ -5153,13 +5000,13 @@
[int charOffset = -1]) {
addProblemErrorIfConst(message, charOffset, className.length);
// TODO(ahe): The following doesn't make sense to Analyzer AST.
- Builder constructor = library.loader.getAbstractClassInstantiationError();
+ Builder constructor =
+ libraryBuilder.loader.getAbstractClassInstantiationError();
Expression invocation = buildStaticInvocation(
constructor.target,
- forest.createArguments(<Expression>[
+ forest.createArguments(charOffset, <Expression>[
forest.createStringLiteral(className, null)..fileOffset = charOffset
- ], noLocation)
- ..fileOffset = charOffset,
+ ]),
charOffset: charOffset);
if (invocation is shadow.SyntheticExpressionJudgment) {
invocation = desugarSyntheticExpression(invocation);
@@ -5257,14 +5104,13 @@
.withLocation(uri, builder.charOffset, name.length)
]);
Builder constructor =
- library.loader.getDuplicatedFieldInitializerError();
+ libraryBuilder.loader.getDuplicatedFieldInitializerError();
Expression invocation = buildStaticInvocation(
constructor.target,
- forest.createArguments(<Expression>[
+ forest.createArguments(assignmentOffset, <Expression>[
forest.createStringLiteral(name, null)
..fileOffset = assignmentOffset
- ], noLocation)
- ..fileOffset = assignmentOffset,
+ ]),
charOffset: assignmentOffset);
if (invocation is shadow.SyntheticExpressionJudgment) {
invocation = desugarSyntheticExpression(invocation);
@@ -5280,7 +5126,7 @@
if (!legacyMode &&
formalType != null &&
!typeEnvironment.isSubtypeOf(formalType, builder.field.type)) {
- library.addProblem(
+ libraryBuilder.addProblem(
fasta.templateInitializingFormalTypeMismatch
.withArguments(name, formalType, builder.field.type),
assignmentOffset,
@@ -5375,7 +5221,8 @@
UnresolvedType unresolved, bool nonInstanceAccessIsError) {
TypeBuilder builder = unresolved.builder;
if (builder is NamedTypeBuilder && builder.declaration.isTypeVariable) {
- TypeParameter typeParameter = builder.declaration.target;
+ TypeVariableBuilder typeParameterBuilder = builder.declaration;
+ TypeParameter typeParameter = typeParameterBuilder.parameter;
LocatedMessage message;
if (!isDeclarationInstanceContext && typeParameter.parent is Class) {
message = fasta.messageTypeVariableInStaticContext.withLocation(
@@ -5392,7 +5239,8 @@
}
addProblem(message.messageObject, message.charOffset, message.length);
return new UnresolvedType(
- new NamedTypeBuilder(typeParameter.name, null)
+ new NamedTypeBuilder(
+ typeParameter.name, builder.nullabilityBuilder, null)
..bind(new InvalidTypeBuilder(typeParameter.name, message)),
unresolved.charOffset,
unresolved.fileUri);
@@ -5494,7 +5342,7 @@
{bool wasHandled: false,
List<LocatedMessage> context,
Severity severity}) {
- library.addProblem(message, charOffset, length, uri,
+ libraryBuilder.addProblem(message, charOffset, length, uri,
wasHandled: wasHandled, context: context, severity: severity);
}
@@ -5554,7 +5402,7 @@
}
bool isErroneousNode(TreeNode node) {
- return library.loader.handledErrors.isNotEmpty &&
+ return libraryBuilder.loader.handledErrors.isNotEmpty &&
forest.isErroneousNode(node);
}
@@ -5564,7 +5412,7 @@
if (unresolvedType == null) return null;
return validateTypeUse(unresolvedType, nonInstanceAccessIsError)
.builder
- ?.build(library);
+ ?.build(libraryBuilder);
}
@override
@@ -5862,7 +5710,11 @@
local[parameter.name] = parameter;
}
}
- return new Scope(local, null, parent, "formals", isModifiable: false);
+ return new Scope(
+ local: local,
+ parent: parent,
+ debugName: "formals",
+ isModifiable: false);
}
String toString() {
diff --git a/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart b/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
index 131372b..075dc56 100644
--- a/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
@@ -85,6 +85,7 @@
ProcedureBuilder,
LibraryBuilder,
MemberBuilder,
+ NullabilityBuilder,
TypeBuilder,
TypeVariableBuilder;
@@ -106,8 +107,8 @@
return member is Procedure ? member.kind : null;
}
-bool isNameVisibleIn(Name name, LibraryBuilder library) {
- return !name.isPrivate || name.library == library.target;
+bool isNameVisibleIn(Name name, LibraryBuilder libraryBuilder) {
+ return !name.isPrivate || name.library == libraryBuilder.library;
}
/// Returns true if [a] is a class member conflict with [b]. [a] is assumed to
@@ -196,19 +197,19 @@
class ClassHierarchyBuilder {
final Map<Class, ClassHierarchyNode> nodes = <Class, ClassHierarchyNode>{};
- final ClassBuilder objectClass;
+ final ClassBuilder objectClassBuilder;
final Loader loader;
- final Class objectKernelClass;
+ final Class objectClass;
- final Class futureKernelClass;
+ final Class futureClass;
- final Class futureOrKernelClass;
+ final Class futureOrClass;
- final Class functionKernelClass;
+ final Class functionClass;
- final Class nullKernelClass;
+ final Class nullClass;
final List<DelayedOverrideCheck> overrideChecks = <DelayedOverrideCheck>[];
@@ -219,18 +220,18 @@
Types types;
- ClassHierarchyBuilder(this.objectClass, this.loader, this.coreTypes)
- : objectKernelClass = objectClass.target,
- futureKernelClass = coreTypes.futureClass,
- futureOrKernelClass = coreTypes.futureOrClass,
- functionKernelClass = coreTypes.functionClass,
- nullKernelClass = coreTypes.nullClass {
+ ClassHierarchyBuilder(this.objectClassBuilder, this.loader, this.coreTypes)
+ : objectClass = objectClassBuilder.cls,
+ futureClass = coreTypes.futureClass,
+ futureOrClass = coreTypes.futureOrClass,
+ functionClass = coreTypes.functionClass,
+ nullClass = coreTypes.nullClass {
types = new Types(this);
}
- ClassHierarchyNode getNodeFromClass(ClassBuilder cls) {
- return nodes[cls.target] ??=
- new ClassHierarchyNodeBuilder(this, cls).build();
+ ClassHierarchyNode getNodeFromClass(ClassBuilder classBuilder) {
+ return nodes[classBuilder.cls] ??=
+ new ClassHierarchyNodeBuilder(this, classBuilder).build();
}
ClassHierarchyNode getNodeFromType(TypeBuilder type) {
@@ -246,12 +247,14 @@
TypeBuilder asSupertypeOf(Class cls, Class supertype) {
ClassHierarchyNode clsNode = getNodeFromKernelClass(cls);
if (cls == supertype) {
- return new NamedTypeBuilder(clsNode.cls.name, null)..bind(clsNode.cls);
+ return new NamedTypeBuilder(clsNode.classBuilder.name,
+ const NullabilityBuilder.pendingImplementation(), null)
+ ..bind(clsNode.classBuilder);
}
ClassHierarchyNode supertypeNode = getNodeFromKernelClass(supertype);
List<TypeBuilder> supertypes = clsNode.superclasses;
int depth = supertypeNode.depth;
- Builder supertypeDeclaration = supertypeNode.cls;
+ Builder supertypeDeclaration = supertypeNode.classBuilder;
if (depth < supertypes.length) {
TypeBuilder asSupertypeOf = supertypes[depth];
if (asSupertypeOf.declaration == supertypeDeclaration) {
@@ -270,7 +273,7 @@
InterfaceType type, Class superclass) {
Class kernelClass = type.classNode;
if (kernelClass == superclass) return type;
- if (kernelClass == nullKernelClass) {
+ if (kernelClass == nullClass) {
if (superclass.typeParameters.isEmpty) {
return superclass.rawType;
} else {
@@ -279,7 +282,7 @@
return new InterfaceType(
superclass,
new List<DartType>.filled(
- superclass.typeParameters.length, nullKernelClass.rawType));
+ superclass.typeParameters.length, nullClass.rawType));
}
}
NamedTypeBuilder supertype = asSupertypeOf(kernelClass, superclass);
@@ -304,28 +307,30 @@
ClassHierarchyNode node = nodes2[i];
if (node == null) continue;
if (nodes1.contains(node)) {
- DartType candidate1 = getKernelTypeAsInstanceOf(type1, node.cls.target);
- DartType candidate2 = getKernelTypeAsInstanceOf(type2, node.cls.target);
+ DartType candidate1 =
+ getKernelTypeAsInstanceOf(type1, node.classBuilder.cls);
+ DartType candidate2 =
+ getKernelTypeAsInstanceOf(type2, node.classBuilder.cls);
if (candidate1 == candidate2) {
common.add(node);
}
}
}
- if (common.length == 1) return objectKernelClass.rawType;
+ if (common.length == 1) return objectClass.rawType;
common.sort(ClassHierarchyNode.compareMaxInheritancePath);
for (int i = 0; i < common.length - 1; i++) {
ClassHierarchyNode node = common[i];
if (node.maxInheritancePath != common[i + 1].maxInheritancePath) {
- return getKernelTypeAsInstanceOf(type1, node.cls.target);
+ return getKernelTypeAsInstanceOf(type1, node.classBuilder.cls);
} else {
do {
i++;
} while (node.maxInheritancePath == common[i + 1].maxInheritancePath);
}
}
- return objectKernelClass.rawType;
+ return objectClass.rawType;
}
Member getInterfaceMemberKernel(Class cls, Name name, bool isSetter) {
@@ -365,10 +370,10 @@
ClassHierarchyBuilder hierarchy =
new ClassHierarchyBuilder(objectClass, loader, coreTypes);
for (int i = 0; i < classes.length; i++) {
- ClassBuilder cls = classes[i];
- if (!cls.isPatch) {
- hierarchy.nodes[cls.target] =
- new ClassHierarchyNodeBuilder(hierarchy, cls).build();
+ ClassBuilder classBuilder = classes[i];
+ if (!classBuilder.isPatch) {
+ hierarchy.nodes[classBuilder.cls] =
+ new ClassHierarchyNodeBuilder(hierarchy, classBuilder).build();
} else {
// TODO(ahe): Merge the injected members of patch into the hierarchy
// node of `cls.origin`.
@@ -381,15 +386,15 @@
class ClassHierarchyNodeBuilder {
final ClassHierarchyBuilder hierarchy;
- final ClassBuilder cls;
+ final ClassBuilder classBuilder;
bool hasNoSuchMethod = false;
List<Builder> abstractMembers = null;
- ClassHierarchyNodeBuilder(this.hierarchy, this.cls);
+ ClassHierarchyNodeBuilder(this.hierarchy, this.classBuilder);
- ClassBuilder get objectClass => hierarchy.objectClass;
+ ClassBuilder get objectClass => hierarchy.objectClassBuilder;
final Map<Class, Substitution> substitutions = <Class, Substitution>{};
@@ -422,7 +427,8 @@
case MergeKind.superclassSetters:
// [a] is a method declared in [cls]. This means it defines the
// interface of this class regardless if its abstract.
- debug?.log("superclass: checkValidOverride(${cls.fullNameForErrors}, "
+ debug?.log("superclass: checkValidOverride("
+ "${classBuilder.fullNameForErrors}, "
"${fullName(a)}, ${fullName(b)})");
checkValidOverride(
a, AbstractMemberOverridingImplementation.selectAbstract(b));
@@ -431,26 +437,27 @@
if (isAbstract(b)) {
recordAbstractMember(a);
} else {
- if (!cls.isAbstract) {
+ if (!classBuilder.isAbstract) {
// The interface of this class is [a]. But the implementation is
// [b]. So [b] must implement [a], unless [cls] is abstract.
checkValidOverride(b, a);
}
result = new AbstractMemberOverridingImplementation(
- cls,
+ classBuilder,
a,
AbstractMemberOverridingImplementation.selectConcrete(b),
mergeKind == MergeKind.superclassSetters,
- cls.library.loader == hierarchy.loader);
+ classBuilder.library.loader == hierarchy.loader);
hierarchy.delayedMemberChecks.add(result);
}
- } else if (cls.isMixinApplication && a.parent != cls) {
+ } else if (classBuilder.isMixinApplication &&
+ a.parent != classBuilder) {
result = InheritedImplementationInterfaceConflict.combined(
- cls,
+ classBuilder,
a,
b,
mergeKind == MergeKind.superclassSetters,
- cls.library.loader == hierarchy.loader,
+ classBuilder.library.loader == hierarchy.loader,
isInheritableConflict: false);
if (result is DelayedMember) {
hierarchy.delayedMemberChecks.add(result);
@@ -466,32 +473,34 @@
case MergeKind.membersWithSetters:
case MergeKind.settersWithMembers:
- if (a.parent == cls && b.parent != cls) {
+ if (a.parent == classBuilder && b.parent != classBuilder) {
if (a is FieldBuilder) {
if (a.isFinal && b.isSetter) {
- hierarchy.overrideChecks.add(new DelayedOverrideCheck(cls, a, b));
+ hierarchy.overrideChecks
+ .add(new DelayedOverrideCheck(classBuilder, a, b));
} else {
if (!inferFieldTypes(a, b)) {
hierarchy.overrideChecks
- .add(new DelayedOverrideCheck(cls, a, b));
+ .add(new DelayedOverrideCheck(classBuilder, a, b));
}
}
} else if (a is ProcedureBuilder) {
if (!inferMethodTypes(a, b)) {
- hierarchy.overrideChecks.add(new DelayedOverrideCheck(cls, a, b));
+ hierarchy.overrideChecks
+ .add(new DelayedOverrideCheck(classBuilder, a, b));
}
}
}
break;
case MergeKind.interfacesMembers:
- result = InterfaceConflict.combined(
- cls, a, b, false, cls.library.loader == hierarchy.loader);
+ result = InterfaceConflict.combined(classBuilder, a, b, false,
+ classBuilder.library.loader == hierarchy.loader);
break;
case MergeKind.interfacesSetters:
- result = InterfaceConflict.combined(
- cls, a, b, true, cls.library.loader == hierarchy.loader);
+ result = InterfaceConflict.combined(classBuilder, a, b, true,
+ classBuilder.library.loader == hierarchy.loader);
break;
case MergeKind.supertypesMembers:
@@ -502,8 +511,9 @@
b = AbstractMemberOverridingImplementation.selectAbstract(b);
// If [a] is declared in this class, it defines the interface.
- if (a.parent == cls) {
- debug?.log("supertypes: checkValidOverride(${cls.fullNameForErrors}, "
+ if (a.parent == classBuilder) {
+ debug?.log("supertypes: checkValidOverride("
+ "${classBuilder.fullNameForErrors}, "
"${fullName(a)}, ${fullName(b)})");
checkValidOverride(a, b);
if (a is DelayedMember && !a.isInheritableConflict) {
@@ -516,18 +526,18 @@
} else {
if (isAbstract(a)) {
result = InterfaceConflict.combined(
- cls,
+ classBuilder,
a,
b,
mergeKind == MergeKind.supertypesSetters,
- cls.library.loader == hierarchy.loader);
+ classBuilder.library.loader == hierarchy.loader);
} else {
result = InheritedImplementationInterfaceConflict.combined(
- cls,
+ classBuilder,
a,
b,
mergeKind == MergeKind.supertypesSetters,
- cls.library.loader == hierarchy.loader);
+ classBuilder.library.loader == hierarchy.loader);
}
debug?.log("supertypes: ${result}");
if (result is DelayedMember) {
@@ -583,25 +593,29 @@
return inferSetterType(a, b);
}
bool hadTypesInferred = a.hadTypesInferred;
- ClassBuilder aCls = a.parent;
+ ClassBuilder aClassBuilder = a.parent;
Substitution aSubstitution;
- if (cls != aCls) {
- assert(substitutions.containsKey(aCls.target),
- "${cls.fullNameForErrors} ${aCls.fullNameForErrors}");
- aSubstitution = substitutions[aCls.target];
- debug?.log("${cls.fullNameForErrors} -> ${aCls.fullNameForErrors} "
- "$aSubstitution");
+ if (classBuilder != aClassBuilder) {
+ assert(
+ substitutions.containsKey(aClassBuilder.cls),
+ "${classBuilder.fullNameForErrors} "
+ "${aClassBuilder.fullNameForErrors}");
+ aSubstitution = substitutions[aClassBuilder.cls];
+ debug?.log("${classBuilder.fullNameForErrors} -> "
+ "${aClassBuilder.fullNameForErrors} $aSubstitution");
}
- ClassBuilder bCls = b.parent;
+ ClassBuilder bClassBuilder = b.parent;
Substitution bSubstitution;
- if (cls != bCls) {
- assert(substitutions.containsKey(bCls.target),
- "${cls.fullNameForErrors} ${bCls.fullNameForErrors}");
- bSubstitution = substitutions[bCls.target];
- debug?.log("${cls.fullNameForErrors} -> ${bCls.fullNameForErrors} "
- "$bSubstitution");
+ if (classBuilder != bClassBuilder) {
+ assert(
+ substitutions.containsKey(bClassBuilder.cls),
+ "${classBuilder.fullNameForErrors} "
+ "${bClassBuilder.fullNameForErrors}");
+ bSubstitution = substitutions[bClassBuilder.cls];
+ debug?.log("${classBuilder.fullNameForErrors} -> "
+ "${bClassBuilder.fullNameForErrors} $bSubstitution");
}
- Procedure aProcedure = a.target;
+ Procedure aProcedure = a.procedure;
if (b.target is! Procedure) {
debug?.log("Giving up 1");
return false;
@@ -662,9 +676,9 @@
}
if (aReturnType != bReturnType) {
- if (a.parent == cls && a.returnType == null) {
- result =
- inferReturnType(cls, a, bReturnType, hadTypesInferred, hierarchy);
+ if (a.parent == classBuilder && a.returnType == null) {
+ result = inferReturnType(
+ classBuilder, a, bReturnType, hadTypesInferred, hierarchy);
} else {
debug?.log("Giving up 6");
result = false;
@@ -687,9 +701,9 @@
bType = substitution.substituteType(bType);
}
if (aType != bType) {
- if (a.parent == cls && a.formals[i].type == null) {
- result = inferParameterType(
- cls, a, a.formals[i], bType, hadTypesInferred, hierarchy);
+ if (a.parent == classBuilder && a.formals[i].type == null) {
+ result = inferParameterType(classBuilder, a, a.formals[i], bType,
+ hadTypesInferred, hierarchy);
} else {
debug?.log("Giving up 8");
result = false;
@@ -748,9 +762,9 @@
break;
}
}
- if (a.parent == cls && parameter.type == null) {
+ if (a.parent == classBuilder && parameter.type == null) {
result = inferParameterType(
- cls, a, parameter, bType, hadTypesInferred, hierarchy);
+ classBuilder, a, parameter, bType, hadTypesInferred, hierarchy);
} else {
debug?.log("Giving up 12");
result = false;
@@ -793,14 +807,14 @@
debug?.log("Giving up (not field/procedure: ${bTarget.runtimeType})");
return false;
}
- return a.target.function.returnType == bType;
+ return a.procedure.function.returnType == bType;
}
bool inferSetterType(ProcedureBuilder a, Builder b) {
debug?.log(
"Inferring setter types for ${fullName(a)} based on ${fullName(b)}");
Member bTarget = b.target;
- Procedure aProcedure = a.target;
+ Procedure aProcedure = a.procedure;
VariableDeclaration aParameter =
aProcedure.function.positionalParameters.single;
DartType bType;
@@ -853,10 +867,11 @@
if (b is DelayedMember) {
for (int i = 0; i < b.declarations.length; i++) {
hierarchy.overrideChecks
- .add(new DelayedOverrideCheck(cls, a, b.declarations[i]));
+ .add(new DelayedOverrideCheck(classBuilder, a, b.declarations[i]));
}
} else {
- hierarchy.overrideChecks.add(new DelayedOverrideCheck(cls, a, b));
+ hierarchy.overrideChecks
+ .add(new DelayedOverrideCheck(classBuilder, a, b));
}
}
@@ -880,7 +895,7 @@
VariableDeclaration parameter =
bTarget.function.positionalParameters.single;
// inheritedType = parameter.type;
- copyFieldCovarianceFromParameter(a.parent, a.target, parameter);
+ copyFieldCovarianceFromParameter(a.parent, a.member, parameter);
if (!hasExplicitlyTypedFormalParameter(b, 0)) {
debug?.log("Giving up (type may be inferred)");
return false;
@@ -890,36 +905,41 @@
inheritedType = bTarget.function.returnType;
}
} else if (bTarget is Field) {
- copyFieldCovariance(a.parent, a.target, bTarget);
+ copyFieldCovariance(a.parent, a.member, bTarget);
inheritedType = bTarget.type;
}
if (inheritedType == null) {
debug?.log("Giving up (inheritedType == null)\n${StackTrace.current}");
return false;
}
- ClassBuilder aCls = a.parent;
+ ClassBuilder aClassBuilder = a.parent;
Substitution aSubstitution;
- if (cls != aCls) {
- assert(substitutions.containsKey(aCls.target),
- "${cls.fullNameForErrors} ${aCls.fullNameForErrors}");
- aSubstitution = substitutions[aCls.target];
- debug?.log("${cls.fullNameForErrors} -> ${aCls.fullNameForErrors} "
- "$aSubstitution");
+ if (classBuilder != aClassBuilder) {
+ assert(
+ substitutions.containsKey(aClassBuilder.cls),
+ "${classBuilder.fullNameForErrors} "
+ "${aClassBuilder.fullNameForErrors}");
+ aSubstitution = substitutions[aClassBuilder.cls];
+ debug?.log("${classBuilder.fullNameForErrors} -> "
+ "${aClassBuilder.fullNameForErrors} $aSubstitution");
}
- ClassBuilder bCls = b.parent;
+ ClassBuilder bClassBuilder = b.parent;
Substitution bSubstitution;
- if (cls != bCls) {
- assert(substitutions.containsKey(bCls.target),
- "${cls.fullNameForErrors} ${bCls.fullNameForErrors}");
- bSubstitution = substitutions[bCls.target];
- debug?.log("${cls.fullNameForErrors} -> ${bCls.fullNameForErrors} "
- "$bSubstitution");
+ if (classBuilder != bClassBuilder) {
+ assert(
+ substitutions.containsKey(bClassBuilder.cls),
+ "${classBuilder.fullNameForErrors} "
+ "${bClassBuilder.fullNameForErrors}");
+ bSubstitution = substitutions[bClassBuilder.cls];
+ debug?.log("${classBuilder.fullNameForErrors} -> "
+ "${bClassBuilder.fullNameForErrors} $bSubstitution");
}
if (bSubstitution != null && inheritedType is! ImplicitFieldType) {
inheritedType = bSubstitution.substituteType(inheritedType);
}
- DartType declaredType = a.target.type;
+ Field aField = a.member;
+ DartType declaredType = aField.type;
if (aSubstitution != null) {
declaredType = aSubstitution.substituteType(declaredType);
}
@@ -927,19 +947,19 @@
bool result = false;
if (a is FieldBuilder) {
- if (a.parent == cls && a.type == null) {
+ if (a.parent == classBuilder && a.type == null) {
if (a.hadTypesInferred) {
- reportCantInferFieldType(cls, a);
+ reportCantInferFieldType(classBuilder, a);
inheritedType = const InvalidType();
} else {
result = true;
a.hadTypesInferred = true;
}
if (inheritedType is ImplicitFieldType) {
- SourceLibraryBuilder library = cls.library;
+ SourceLibraryBuilder library = classBuilder.library;
(library.implicitlyTypedFields ??= <FieldBuilder>[]).add(a);
}
- a.target.type = inheritedType;
+ a.field.type = inheritedType;
}
}
return result;
@@ -947,7 +967,7 @@
void copyParameterCovariance(Builder parent, VariableDeclaration aParameter,
VariableDeclaration bParameter) {
- if (parent == cls) {
+ if (parent == classBuilder) {
if (bParameter.isCovariant) {
aParameter.isCovariant = true;
}
@@ -959,7 +979,7 @@
void copyParameterCovarianceFromField(
Builder parent, VariableDeclaration aParameter, Field bField) {
- if (parent == cls) {
+ if (parent == classBuilder) {
if (bField.isCovariant) {
aParameter.isCovariant = true;
}
@@ -970,7 +990,7 @@
}
void copyFieldCovariance(Builder parent, Field aField, Field bField) {
- if (parent == cls) {
+ if (parent == classBuilder) {
if (bField.isCovariant) {
aField.isCovariant = true;
}
@@ -982,7 +1002,7 @@
void copyFieldCovarianceFromParameter(
Builder parent, Field aField, VariableDeclaration bParameter) {
- if (parent == cls) {
+ if (parent == classBuilder) {
if (bParameter.isCovariant) {
aField.isCovariant = true;
}
@@ -994,7 +1014,7 @@
void copyTypeParameterCovariance(
Builder parent, TypeParameter aParameter, TypeParameter bParameter) {
- if (parent == cls) {
+ if (parent == classBuilder) {
if (bParameter.isGenericCovariantImpl) {
aParameter.isGenericCovariantImpl = true;
}
@@ -1004,16 +1024,18 @@
void reportInheritanceConflict(Builder a, Builder b) {
String name = a.fullNameForErrors;
if (a.parent != b.parent) {
- if (a.parent == cls) {
- cls.addProblem(messageDeclaredMemberConflictsWithInheritedMember,
- a.charOffset, name.length,
+ if (a.parent == classBuilder) {
+ classBuilder.addProblem(
+ messageDeclaredMemberConflictsWithInheritedMember,
+ a.charOffset,
+ name.length,
context: <LocatedMessage>[
messageDeclaredMemberConflictsWithInheritedMemberCause
.withLocation(b.fileUri, b.charOffset, name.length)
]);
} else {
- cls.addProblem(messageInheritedMembersConflict, cls.charOffset,
- cls.fullNameForErrors.length,
+ classBuilder.addProblem(messageInheritedMembersConflict,
+ classBuilder.charOffset, classBuilder.fullNameForErrors.length,
context: inheritedConflictContext(a, b));
}
} else if (a.isStatic != b.isStatic) {
@@ -1026,7 +1048,7 @@
staticMember = b;
instanceMember = a;
}
- cls.library.addProblem(messageStaticAndInstanceConflict,
+ classBuilder.library.addProblem(messageStaticAndInstanceConflict,
staticMember.charOffset, name.length, staticMember.fileUri,
context: <LocatedMessage>[
messageStaticAndInstanceConflictCause.withLocation(
@@ -1048,8 +1070,11 @@
existing = b;
duplicate = a;
}
- cls.library.addProblem(templateDuplicatedDeclaration.withArguments(name),
- duplicate.charOffset, name.length, duplicate.fileUri,
+ classBuilder.library.addProblem(
+ templateDuplicatedDeclaration.withArguments(name),
+ duplicate.charOffset,
+ name.length,
+ duplicate.fileUri,
context: <LocatedMessage>[
templateDuplicatedDeclarationCause.withArguments(name).withLocation(
existing.fileUri, existing.charOffset, name.length)
@@ -1104,7 +1129,7 @@
((mergeKind == MergeKind.superclassMembers ||
mergeKind == MergeKind.superclassSetters) &&
target.isAbstract)) {
- if (isNameVisibleIn(target.name, cls.library)) {
+ if (isNameVisibleIn(target.name, classBuilder.library)) {
recordAbstractMember(member);
}
}
@@ -1117,7 +1142,7 @@
mergeKind != MergeKind.settersWithMembers &&
member is DelayedMember &&
member.isInheritableConflict) {
- hierarchy.delayedMemberChecks.add(member.withParent(cls));
+ hierarchy.delayedMemberChecks.add(member.withParent(classBuilder));
}
return member;
}
@@ -1132,19 +1157,19 @@
}
ClassHierarchyNode build() {
- assert(!cls.isPatch);
+ assert(!classBuilder.isPatch);
ClassHierarchyNode supernode;
- if (objectClass != cls.origin) {
- supernode = hierarchy.getNodeFromType(cls.supertype);
+ if (objectClass != classBuilder.origin) {
+ supernode = hierarchy.getNodeFromType(classBuilder.supertype);
if (supernode == null) {
supernode = hierarchy.getNodeFromClass(objectClass);
}
assert(supernode != null);
}
- Scope scope = cls.scope;
- if (cls.isMixinApplication) {
- Builder mixin = cls.mixedInType.declaration;
+ Scope scope = classBuilder.scope;
+ if (classBuilder.isMixinApplication) {
+ Builder mixin = classBuilder.mixedInType.declaration;
inferMixinApplication();
// recordSupertype(cls.mixedInType);
while (mixin.isNamedMixinApplication) {
@@ -1203,15 +1228,17 @@
maxInheritancePath = supernode.maxInheritancePath + 1;
superclasses = new List<TypeBuilder>(supernode.superclasses.length + 1);
superclasses.setRange(0, superclasses.length - 1,
- substSupertypes(cls.supertype, supernode.superclasses));
- superclasses[superclasses.length - 1] = recordSupertype(cls.supertype);
+ substSupertypes(classBuilder.supertype, supernode.superclasses));
+ superclasses[superclasses.length - 1] =
+ recordSupertype(classBuilder.supertype);
- List<TypeBuilder> directInterfaces = ignoreFunction(cls.interfaces);
- if (cls.isMixinApplication) {
+ List<TypeBuilder> directInterfaces =
+ ignoreFunction(classBuilder.interfaces);
+ if (classBuilder.isMixinApplication) {
if (directInterfaces == null) {
- directInterfaces = <TypeBuilder>[cls.mixedInType];
+ directInterfaces = <TypeBuilder>[classBuilder.mixedInType];
} else {
- directInterfaces = <TypeBuilder>[cls.mixedInType]
+ directInterfaces = <TypeBuilder>[classBuilder.mixedInType]
..addAll(directInterfaces);
}
}
@@ -1223,7 +1250,7 @@
List<TypeBuilder> superclassInterfaces = supernode.interfaces;
if (superclassInterfaces != null) {
superclassInterfaces =
- substSupertypes(cls.supertype, superclassInterfaces);
+ substSupertypes(classBuilder.supertype, superclassInterfaces);
}
classMembers = merge(
@@ -1298,7 +1325,7 @@
merge(classMembers, interfaceSetters, MergeKind.membersWithSetters);
}
}
- if (abstractMembers != null && !cls.isAbstract) {
+ if (abstractMembers != null && !classBuilder.isAbstract) {
if (!hasNoSuchMethod) {
reportMissingMembers();
} else {
@@ -1306,7 +1333,7 @@
}
}
return new ClassHierarchyNode(
- cls,
+ classBuilder,
classMembers,
classSetters,
interfaceMembers,
@@ -1320,33 +1347,34 @@
TypeBuilder recordSupertype(TypeBuilder supertype) {
if (supertype is NamedTypeBuilder) {
- debug?.log("In ${this.cls.fullNameForErrors} "
+ debug?.log("In ${this.classBuilder.fullNameForErrors} "
"recordSupertype(${supertype.fullNameForErrors})");
Builder declaration = supertype.declaration;
if (declaration is! ClassBuilder) return supertype;
- ClassBuilder cls = declaration;
- if (cls.isMixinApplication) {
- recordSupertype(cls.mixedInType);
+ ClassBuilder classBuilder = declaration;
+ if (classBuilder.isMixinApplication) {
+ recordSupertype(classBuilder.mixedInType);
}
- List<TypeVariableBuilder> typeVariables = cls.typeVariables;
- if (typeVariables == null) {
- substitutions[cls.target] = Substitution.empty;
- assert(cls.target.typeParameters.isEmpty);
+ List<TypeVariableBuilder> typeVariableBuilders =
+ classBuilder.typeVariables;
+ if (typeVariableBuilders == null) {
+ substitutions[classBuilder.cls] = Substitution.empty;
+ assert(classBuilder.cls.typeParameters.isEmpty);
} else {
List<TypeBuilder> arguments =
supertype.arguments ?? computeDefaultTypeArguments(supertype);
- if (arguments.length != typeVariables.length) {
+ if (arguments.length != typeVariableBuilders.length) {
arguments = computeDefaultTypeArguments(supertype);
}
- List<DartType> kernelArguments = new List<DartType>(arguments.length);
- List<TypeParameter> kernelParameters =
+ List<DartType> typeArguments = new List<DartType>(arguments.length);
+ List<TypeParameter> typeParameters =
new List<TypeParameter>(arguments.length);
for (int i = 0; i < arguments.length; i++) {
- kernelParameters[i] = typeVariables[i].target;
- kernelArguments[i] = arguments[i].build(this.cls.parent);
+ typeParameters[i] = typeVariableBuilders[i].parameter;
+ typeArguments[i] = arguments[i].build(this.classBuilder.parent);
}
- substitutions[cls.target] =
- Substitution.fromPairs(kernelParameters, kernelArguments);
+ substitutions[classBuilder.cls] =
+ Substitution.fromPairs(typeParameters, typeArguments);
}
}
return supertype;
@@ -1359,7 +1387,8 @@
ClassBuilder cls = declaration;
List<TypeVariableBuilder> typeVariables = cls.typeVariables;
if (typeVariables == null) {
- debug?.log("In ${this.cls.fullNameForErrors} $supertypes aren't substed");
+ debug?.log("In ${this.classBuilder.fullNameForErrors} "
+ "$supertypes aren't substed");
for (int i = 0; i < supertypes.length; i++) {
recordSupertype(supertypes[i]);
}
@@ -1377,11 +1406,13 @@
TypeBuilder supertype = supertypes[i];
TypeBuilder substed = recordSupertype(supertype.subst(substitution));
if (supertype != substed) {
- debug?.log("In ${this.cls.fullNameForErrors} $supertype -> $substed");
+ debug?.log(
+ "In ${this.classBuilder.fullNameForErrors} $supertype -> $substed");
result ??= supertypes.toList();
result[i] = substed;
} else {
- debug?.log("In ${this.cls.fullNameForErrors} $supertype isn't substed");
+ debug?.log("In ${this.classBuilder.fullNameForErrors} "
+ "$supertype isn't substed");
}
}
return result ?? supertypes;
@@ -1393,7 +1424,7 @@
for (int i = 0; i < result.length; ++i) {
TypeVariableBuilder tv = cls.typeVariables[i];
result[i] = tv.defaultType ??
- cls.library.loader.computeTypeBuilder(tv.target.defaultType);
+ cls.library.loader.computeTypeBuilder(tv.parameter.defaultType);
}
return result;
}
@@ -1404,7 +1435,8 @@
if (node == null) return null;
int depth = node.depth;
int myDepth = superclasses.length;
- if (depth < myDepth && superclasses[depth].declaration == node.cls) {
+ if (depth < myDepth &&
+ superclasses[depth].declaration == node.classBuilder) {
// This is a potential conflict.
return superclasses[depth];
} else {
@@ -1423,7 +1455,7 @@
MergeResult mergeInterfaces(
ClassHierarchyNode supernode, List<TypeBuilder> interfaces) {
- debug?.log("mergeInterfaces($cls (${this.cls}) "
+ debug?.log("mergeInterfaces($classBuilder (${this.classBuilder}) "
"${supernode.interfaces} ${interfaces}");
List<List<Builder>> memberLists =
new List<List<Builder>>(interfaces.length + 1);
@@ -1525,7 +1557,7 @@
for (int i = 0; i < abstractMembers.length; i++) {
Builder declaration = abstractMembers[i];
Member target = declaration.target;
- if (isNameVisibleIn(target.name, cls.library)) {
+ if (isNameVisibleIn(target.name, classBuilder.library)) {
String name = declaration.fullNameForErrors;
String parentName = declaration.parent.fullNameForErrors;
String displayName =
@@ -1542,11 +1574,11 @@
for (int i = 0; i < names.length; i++) {
context.add(contextMap[names[i]]);
}
- cls.addProblem(
+ classBuilder.addProblem(
templateMissingImplementationNotAbstract.withArguments(
- cls.fullNameForErrors, names),
- cls.charOffset,
- cls.fullNameForErrors.length,
+ classBuilder.fullNameForErrors, names),
+ classBuilder.charOffset,
+ classBuilder.fullNameForErrors.length,
context: context);
}
@@ -1612,25 +1644,25 @@
}
void inferMixinApplication() {
- Class kernelClass = cls.target;
- Supertype kernelMixedInType = kernelClass.mixedInType;
- if (kernelMixedInType == null) return;
- List<DartType> typeArguments = kernelMixedInType.typeArguments;
+ Class cls = classBuilder.cls;
+ Supertype mixedInType = cls.mixedInType;
+ if (mixedInType == null) return;
+ List<DartType> typeArguments = mixedInType.typeArguments;
if (typeArguments.isEmpty || typeArguments.first is! UnknownType) return;
new BuilderMixinInferrer(
- cls,
+ classBuilder,
hierarchy.coreTypes,
new TypeBuilderConstraintGatherer(
- hierarchy, kernelMixedInType.classNode.typeParameters))
- .infer(kernelClass);
+ hierarchy, mixedInType.classNode.typeParameters))
+ .infer(cls);
List<TypeBuilder> inferredArguments =
new List<TypeBuilder>(typeArguments.length);
for (int i = 0; i < typeArguments.length; i++) {
inferredArguments[i] =
hierarchy.loader.computeTypeBuilder(typeArguments[i]);
}
- NamedTypeBuilder mixedInType = cls.mixedInType;
- mixedInType.arguments = inferredArguments;
+ NamedTypeBuilder mixedInTypeBuilder = classBuilder.mixedInType;
+ mixedInTypeBuilder.arguments = inferredArguments;
}
/// The class Function from dart:core is supposed to be ignored when used as
@@ -1638,8 +1670,8 @@
List<TypeBuilder> ignoreFunction(List<TypeBuilder> interfaces) {
if (interfaces == null) return null;
for (int i = 0; i < interfaces.length; i++) {
- ClassBuilder cls = getClass(interfaces[i]);
- if (cls != null && cls.target == hierarchy.functionKernelClass) {
+ ClassBuilder classBuilder = getClass(interfaces[i]);
+ if (classBuilder != null && classBuilder.cls == hierarchy.functionClass) {
if (interfaces.length == 1) {
return null;
} else {
@@ -1655,7 +1687,7 @@
class ClassHierarchyNode {
/// The class corresponding to this hierarchy node.
- final ClassBuilder cls;
+ final ClassBuilder classBuilder;
/// All the members of this class including [classMembers] of its
/// superclasses. The members are sorted by [compareDeclarations].
@@ -1678,15 +1710,15 @@
/// This may be null, in which case [classSetters] is the interface setters.
final List<Builder> interfaceSetters;
- /// All superclasses of [cls] excluding itself. The classes are sorted by
- /// depth from the root (Object) in ascending order.
+ /// All superclasses of [classBuilder] excluding itself. The classes are
+ /// sorted by depth from the root (Object) in ascending order.
final List<TypeBuilder> superclasses;
- /// The list of all classes implemented by [cls] and its supertypes excluding
- /// any classes from [superclasses].
+ /// The list of all classes implemented by [classBuilder] and its supertypes
+ /// excluding any classes from [superclasses].
final List<TypeBuilder> interfaces;
- /// The longest inheritance path from [cls] to `Object`.
+ /// The longest inheritance path from [classBuilder] to `Object`.
final int maxInheritancePath;
int get depth => superclasses.length;
@@ -1694,7 +1726,7 @@
final bool hasNoSuchMethod;
ClassHierarchyNode(
- this.cls,
+ this.classBuilder,
this.classMembers,
this.classSetters,
this.interfaceMembers,
@@ -1704,7 +1736,7 @@
this.maxInheritancePath,
this.hasNoSuchMethod);
- /// Returns a list of all supertypes of [cls], including this node.
+ /// Returns a list of all supertypes of [classBuilder], including this node.
List<ClassHierarchyNode> computeAllSuperNodes(
ClassHierarchyBuilder hierarchy) {
List<ClassHierarchyNode> result = new List<ClassHierarchyNode>(
@@ -1728,7 +1760,7 @@
String toString([StringBuffer sb]) {
sb ??= new StringBuffer();
sb
- ..write(cls.fullNameForErrors)
+ ..write(classBuilder.fullNameForErrors)
..writeln(":");
if (maxInheritancePath != this.depth) {
sb
@@ -1914,19 +1946,19 @@
: super.subclassing(typeParameters);
@override
- Class get objectClass => hierarchy.objectKernelClass;
+ Class get objectClass => hierarchy.objectClass;
@override
- Class get functionClass => hierarchy.functionKernelClass;
+ Class get functionClass => hierarchy.functionClass;
@override
- Class get futureClass => hierarchy.futureKernelClass;
+ Class get futureClass => hierarchy.futureClass;
@override
- Class get futureOrClass => hierarchy.futureOrKernelClass;
+ Class get futureOrClass => hierarchy.futureOrClass;
@override
- Class get nullClass => hierarchy.nullKernelClass;
+ Class get nullClass => hierarchy.nullClass;
@override
InterfaceType get nullType => nullClass.rawType;
@@ -1959,7 +1991,7 @@
@override
InterfaceType futureType(DartType type) {
- return new InterfaceType(hierarchy.futureKernelClass, <DartType>[type]);
+ return new InterfaceType(hierarchy.futureClass, <DartType>[type]);
}
@override
@@ -1975,24 +2007,24 @@
}
class DelayedOverrideCheck {
- final ClassBuilder cls;
+ final ClassBuilder classBuilder;
final Builder a;
final Builder b;
- const DelayedOverrideCheck(this.cls, this.a, this.b);
+ const DelayedOverrideCheck(this.classBuilder, this.a, this.b);
void check(ClassHierarchyBuilder hierarchy) {
void callback(
Member declaredMember, Member interfaceMember, bool isSetter) {
- cls.checkOverride(
+ classBuilder.checkOverride(
hierarchy.types, declaredMember, interfaceMember, isSetter, callback,
- isInterfaceCheck: !cls.isMixinApplication);
+ isInterfaceCheck: !classBuilder.isMixinApplication);
}
Builder a = this.a;
debug?.log("Delayed override check of ${fullName(a)} "
- "${fullName(b)} wrt. ${cls.fullNameForErrors}");
- if (cls == a.parent) {
+ "${fullName(b)} wrt. ${classBuilder.fullNameForErrors}");
+ if (classBuilder == a.parent) {
if (a is ProcedureBuilder) {
if (a.isGetter && !hasExplicitReturnType(a)) {
DartType type;
@@ -2009,10 +2041,11 @@
if (type != null) {
type = Substitution.fromInterfaceType(
hierarchy.getKernelTypeAsInstanceOf(
- cls.cls.thisType, b.target.enclosingClass))
+ classBuilder.cls.thisType, b.target.enclosingClass))
.substituteType(type);
if (!a.hadTypesInferred || !b.isSetter) {
- inferReturnType(cls, a, type, a.hadTypesInferred, hierarchy);
+ inferReturnType(
+ classBuilder, a, type, a.hadTypesInferred, hierarchy);
}
}
} else if (a.isSetter && !hasExplicitlyTypedFormalParameter(a, 0)) {
@@ -2030,10 +2063,10 @@
if (type != null) {
type = Substitution.fromInterfaceType(
hierarchy.getKernelTypeAsInstanceOf(
- cls.cls.thisType, b.target.enclosingClass))
+ classBuilder.cls.thisType, b.target.enclosingClass))
.substituteType(type);
if (!a.hadTypesInferred || !b.isGetter) {
- inferParameterType(cls, a, a.formals.single, type,
+ inferParameterType(classBuilder, a, a.formals.single, type,
a.hadTypesInferred, hierarchy);
}
}
@@ -2054,21 +2087,21 @@
if (type != null) {
type = Substitution.fromInterfaceType(
hierarchy.getKernelTypeAsInstanceOf(
- cls.cls.thisType, b.target.enclosingClass))
+ classBuilder.cls.thisType, b.target.enclosingClass))
.substituteType(type);
- if (type != a.target.type) {
+ if (type != a.field.type) {
if (a.hadTypesInferred) {
if (b.isSetter &&
(!impliesSetter(a) ||
- hierarchy.types.isSubtypeOfKernel(type, a.target.type))) {
- type = a.target.type;
+ hierarchy.types.isSubtypeOfKernel(type, a.field.type))) {
+ type = a.field.type;
} else {
- reportCantInferFieldType(cls, a);
+ reportCantInferFieldType(classBuilder, a);
type = const InvalidType();
}
}
debug?.log("Inferred type ${type} for ${fullName(a)}");
- a.target.type = type;
+ a.field.type = type;
}
}
a.hadTypesInferred = true;
@@ -2498,18 +2531,18 @@
wasHandled: true);
}
-bool inferReturnType(ClassBuilder cls, ProcedureBuilder member, DartType type,
- bool hadTypesInferred, ClassHierarchyBuilder hierarchy) {
- if (type == member.target.function.returnType) return true;
+bool inferReturnType(ClassBuilder cls, ProcedureBuilder procedureBuilder,
+ DartType type, bool hadTypesInferred, ClassHierarchyBuilder hierarchy) {
+ if (type == procedureBuilder.procedure.function.returnType) return true;
bool result = true;
if (hadTypesInferred) {
- reportCantInferReturnType(cls, member, hierarchy);
+ reportCantInferReturnType(cls, procedureBuilder, hierarchy);
type = const InvalidType();
result = false;
} else {
- member.hadTypesInferred = true;
+ procedureBuilder.hadTypesInferred = true;
}
- member.target.function.returnType = type;
+ procedureBuilder.procedure.function.returnType = type;
return result;
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/collections.dart b/pkg/front_end/lib/src/fasta/kernel/collections.dart
index 84e251f..21ba143 100644
--- a/pkg/front_end/lib/src/fasta/kernel/collections.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/collections.dart
@@ -50,10 +50,10 @@
}
@override
- accept(ExpressionVisitor<Object> v) => v.defaultExpression(this);
+ R accept<R>(ExpressionVisitor<R> v) => v.defaultExpression(this);
@override
- accept1(ExpressionVisitor1<Object, Object> v, arg) =>
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
v.defaultExpression(this, arg);
}
@@ -80,7 +80,7 @@
@override
transformChildren(Transformer v) {
if (expression != null) {
- expression = expression.accept(v);
+ expression = expression.accept<TreeNode>(v);
expression?.parent = this;
}
}
@@ -108,15 +108,15 @@
@override
transformChildren(Transformer v) {
if (condition != null) {
- condition = condition.accept(v);
+ condition = condition.accept<TreeNode>(v);
condition?.parent = this;
}
if (then != null) {
- then = then.accept(v);
+ then = then.accept<TreeNode>(v);
then?.parent = this;
}
if (otherwise != null) {
- otherwise = otherwise.accept(v);
+ otherwise = otherwise.accept<TreeNode>(v);
otherwise?.parent = this;
}
}
@@ -148,12 +148,12 @@
transformChildren(Transformer v) {
transformList(variables, v, this);
if (condition != null) {
- condition = condition.accept(v);
+ condition = condition.accept<TreeNode>(v);
condition?.parent = this;
}
transformList(updates, v, this);
if (body != null) {
- body = body.accept(v);
+ body = body.accept<TreeNode>(v);
body?.parent = this;
}
}
@@ -188,23 +188,23 @@
transformChildren(Transformer v) {
if (variable != null) {
- variable = variable.accept(v);
+ variable = variable.accept<TreeNode>(v);
variable?.parent = this;
}
if (iterable != null) {
- iterable = iterable.accept(v);
+ iterable = iterable.accept<TreeNode>(v);
iterable?.parent = this;
}
if (prologue != null) {
- prologue = prologue.accept(v);
+ prologue = prologue.accept<TreeNode>(v);
prologue?.parent = this;
}
if (body != null) {
- body = body.accept(v);
+ body = body.accept<TreeNode>(v);
body?.parent = this;
}
if (problem != null) {
- problem = problem.accept(v);
+ problem = problem.accept<TreeNode>(v);
problem?.parent = this;
}
}
@@ -213,26 +213,26 @@
mixin ControlFlowMapEntry implements MapEntry {
@override
Expression get key {
- throw UnsupportedError('ControlFlowMapEntry.key getter');
+ throw new UnsupportedError('ControlFlowMapEntry.key getter');
}
@override
void set key(Expression expr) {
- throw UnsupportedError('ControlFlowMapEntry.key setter');
+ throw new UnsupportedError('ControlFlowMapEntry.key setter');
}
@override
Expression get value {
- throw UnsupportedError('ControlFlowMapEntry.value getter');
+ throw new UnsupportedError('ControlFlowMapEntry.value getter');
}
@override
void set value(Expression expr) {
- throw UnsupportedError('ControlFlowMapEntry.value setter');
+ throw new UnsupportedError('ControlFlowMapEntry.value setter');
}
@override
- accept(TreeVisitor<Object> v) => v.defaultTreeNode(this);
+ R accept<R>(TreeVisitor<R> v) => v.defaultTreeNode(this);
}
/// A spread element in a map literal.
@@ -258,7 +258,7 @@
@override
transformChildren(Transformer v) {
if (expression != null) {
- expression = expression.accept(v);
+ expression = expression.accept<TreeNode>(v);
expression?.parent = this;
}
}
@@ -286,15 +286,15 @@
@override
transformChildren(Transformer v) {
if (condition != null) {
- condition = condition.accept(v);
+ condition = condition.accept<TreeNode>(v);
condition?.parent = this;
}
if (then != null) {
- then = then.accept(v);
+ then = then.accept<TreeNode>(v);
then?.parent = this;
}
if (otherwise != null) {
- otherwise = otherwise.accept(v);
+ otherwise = otherwise.accept<TreeNode>(v);
otherwise?.parent = this;
}
}
@@ -326,12 +326,12 @@
transformChildren(Transformer v) {
transformList(variables, v, this);
if (condition != null) {
- condition = condition.accept(v);
+ condition = condition.accept<TreeNode>(v);
condition?.parent = this;
}
transformList(updates, v, this);
if (body != null) {
- body = body.accept(v);
+ body = body.accept<TreeNode>(v);
body?.parent = this;
}
}
@@ -366,23 +366,23 @@
transformChildren(Transformer v) {
if (variable != null) {
- variable = variable.accept(v);
+ variable = variable.accept<TreeNode>(v);
variable?.parent = this;
}
if (iterable != null) {
- iterable = iterable.accept(v);
+ iterable = iterable.accept<TreeNode>(v);
iterable?.parent = this;
}
if (prologue != null) {
- prologue = prologue.accept(v);
+ prologue = prologue.accept<TreeNode>(v);
prologue?.parent = this;
}
if (body != null) {
- body = body.accept(v);
+ body = body.accept<TreeNode>(v);
body?.parent = this;
}
if (problem != null) {
- problem = problem.accept(v);
+ problem = problem.accept<TreeNode>(v);
problem?.parent = this;
}
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
index b6c81d7..73b8e87 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
@@ -42,6 +42,7 @@
messageConstEvalNotListOrSetInSpread,
messageConstEvalNotMapInSpread,
messageConstEvalNullValue,
+ messageConstEvalStartingPoint,
messageConstEvalUnevaluated,
noLength,
templateConstEvalDeferredLibrary,
@@ -117,14 +118,14 @@
class JavaScriptIntConstant extends DoubleConstant {
final BigInt bigIntValue;
- JavaScriptIntConstant(int value) : this.fromBigInt(BigInt.from(value));
+ JavaScriptIntConstant(int value) : this.fromBigInt(new BigInt.from(value));
JavaScriptIntConstant.fromDouble(double value)
- : bigIntValue = BigInt.from(value),
+ : bigIntValue = new BigInt.from(value),
super(value);
JavaScriptIntConstant.fromBigInt(this.bigIntValue)
: super(bigIntValue.toDouble());
JavaScriptIntConstant.fromUInt64(int value)
- : this.fromBigInt(BigInt.from(value).toUnsigned(64));
+ : this.fromBigInt(new BigInt.from(value).toUnsigned(64));
DartType getType(TypeEnvironment types) => types.intType;
@@ -212,7 +213,7 @@
Procedure visitProcedure(Procedure node) {
constantEvaluator.withNewEnvironment(() {
transformAnnotations(node.annotations, node);
- node.function = node.function.accept(this)..parent = node;
+ node.function = node.function.accept<TreeNode>(this)..parent = node;
});
return node;
}
@@ -222,7 +223,7 @@
constantEvaluator.withNewEnvironment(() {
transformAnnotations(node.annotations, node);
transformList(node.initializers, this, node);
- node.function = node.function.accept(this)..parent = node;
+ node.function = node.function.accept<TreeNode>(this)..parent = node;
});
return node;
}
@@ -295,7 +296,7 @@
}
}
if (node.body != null) {
- node.body = node.body.accept(this)..parent = node;
+ node.body = node.body.accept<TreeNode>(this)..parent = node;
}
return node;
}
@@ -321,7 +322,8 @@
}
}
} else {
- node.initializer = node.initializer.accept(this)..parent = node;
+ node.initializer = node.initializer.accept<TreeNode>(this)
+ ..parent = node;
}
}
return node;
@@ -343,7 +345,8 @@
} else {
transformAnnotations(node.annotations, node);
if (node.initializer != null) {
- node.initializer = node.initializer.accept(this)..parent = node;
+ node.initializer = node.initializer.accept<TreeNode>(this)
+ ..parent = node;
}
}
return node;
@@ -589,34 +592,43 @@
lazyDepth = 0;
try {
Constant result = _evaluateSubexpression(node);
- if (errorOnUnevaluatedConstant && result is UnevaluatedConstant) {
- return report(node, messageConstEvalUnevaluated);
+ if (result is UnevaluatedConstant) {
+ if (errorOnUnevaluatedConstant) {
+ return report(node, messageConstEvalUnevaluated);
+ }
+ return new UnevaluatedConstant(
+ removeRedundantFileUriExpressions(result.expression));
}
return result;
} on _AbortDueToError catch (e) {
final Uri uri = getFileUri(e.node);
final int fileOffset = getFileOffset(uri, e.node);
- final LocatedMessage locatedMessage =
+ final LocatedMessage locatedMessageActualError =
e.message.withLocation(uri, fileOffset, noLength);
- final List<LocatedMessage> contextMessages = <LocatedMessage>[];
+ final List<LocatedMessage> contextMessages = <LocatedMessage>[
+ locatedMessageActualError
+ ];
if (e.context != null) contextMessages.addAll(e.context);
for (final TreeNode node in contextChain) {
+ if (node == e.node) continue;
final Uri uri = getFileUri(node);
final int fileOffset = getFileOffset(uri, node);
contextMessages.add(
messageConstEvalContext.withLocation(uri, fileOffset, noLength));
}
- errorReporter.report(locatedMessage, contextMessages);
+
+ {
+ final Uri uri = getFileUri(node);
+ final int fileOffset = getFileOffset(uri, node);
+ final LocatedMessage locatedMessage = messageConstEvalStartingPoint
+ .withLocation(uri, fileOffset, noLength);
+ errorReporter.report(locatedMessage, contextMessages);
+ }
return new UnevaluatedConstant(new InvalidExpression(e.message.message));
} on _AbortDueToInvalidExpression catch (e) {
- // TODO(askesc): Copy position from erroneous node.
- // Currently not possible, as it might be in a different file.
- // Can be done if we add an explicit URI to InvalidExpression.
- InvalidExpression invalid = new InvalidExpression(e.message);
- if (invalid.fileOffset == TreeNode.noOffset) {
- invalid.fileOffset = node.fileOffset;
- }
+ InvalidExpression invalid = new InvalidExpression(e.message)
+ ..fileOffset = node.fileOffset;
errorReporter.reportInvalidExpression(invalid);
return new UnevaluatedConstant(invalid);
}
@@ -636,8 +648,13 @@
/// Produce an unevaluated constant node for an expression.
Constant unevaluated(Expression original, Expression replacement) {
replacement.fileOffset = original.fileOffset;
- // TODO(askesc,johnniwinther): Preserve fileUri on [replacement].
- return new UnevaluatedConstant(replacement);
+ return new UnevaluatedConstant(
+ new FileUriExpression(replacement, getFileUri(original))
+ ..fileOffset = original.fileOffset);
+ }
+
+ Expression removeRedundantFileUriExpressions(Expression node) {
+ return node.accept(new RedundantFileUriExpressionRemover()) as Expression;
}
/// Extract an expression from a (possibly unevaluated) constant to become
@@ -762,6 +779,11 @@
}
@override
+ Constant visitFileUriExpression(FileUriExpression node) {
+ return _evaluateSubexpression(node.expression);
+ }
+
+ @override
Constant visitNullLiteral(NullLiteral node) => nullConstant;
@override
@@ -2299,6 +2321,23 @@
}
}
+class RedundantFileUriExpressionRemover extends Transformer {
+ Uri currentFileUri = null;
+
+ TreeNode visitFileUriExpression(FileUriExpression node) {
+ if (node.fileUri == currentFileUri) {
+ return node.expression.accept(this);
+ } else {
+ Uri oldFileUri = currentFileUri;
+ currentFileUri = node.fileUri;
+ node.expression = node.expression.accept(this) as Expression
+ ..parent = node;
+ currentFileUri = oldFileUri;
+ return node;
+ }
+ }
+}
+
// Used as control-flow to abort the current evaluation.
class _AbortDueToError {
final TreeNode node;
diff --git a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
index d9ba7e9..69994cc 100644
--- a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
@@ -29,36 +29,13 @@
import '../constant_context.dart' show ConstantContext;
-import '../builder/builder.dart' show PrefixBuilder, TypeDeclarationBuilder;
+import '../builder/builder.dart'
+ show NullabilityBuilder, PrefixBuilder, TypeDeclarationBuilder;
import '../builder/declaration_builder.dart';
+import '../builder/extension_builder.dart';
+import '../builder/member_builder.dart';
-import '../fasta_codes.dart'
- show
- LocatedMessage,
- Message,
- Template,
- messageCannotAssignToSuper,
- messageCannotAssignToParenthesizedExpression,
- messageCantUsePrefixAsExpression,
- messageCantUsePrefixWithNullAware,
- messageIllegalAssignmentToNonAssignable,
- messageInvalidInitializer,
- messageInvalidUseOfNullAwareAccess,
- messageLoadLibraryTakesNoArguments,
- messageNotAConstantExpression,
- messageNotAnLvalue,
- messageSuperAsExpression,
- noLength,
- templateCantUseDeferredPrefixAsConstant,
- templateConstructorNotFound,
- templateDeferredTypeAnnotation,
- templateMissingExplicitTypeArguments,
- templateNotConstantExpression,
- templateNotAPrefixInTypeAnnotation,
- templateNotAType,
- templateSuperclassHasNoConstructor,
- templateThisOrSuperAccessInFieldInitializer,
- templateUnresolvedPrefixInTypeAnnotation;
+import '../fasta_codes.dart';
import '../names.dart'
show
@@ -82,7 +59,7 @@
import '../parser.dart' show lengthForToken, lengthOfSpan, offsetForToken;
-import '../problems.dart' show unhandled, unsupported;
+import '../problems.dart';
import '../scope.dart';
@@ -133,7 +110,8 @@
SuperPropertyGetJudgment,
SyntheticWrapper,
VariableDeclarationJudgment,
- VariableGetJudgment;
+ VariableGetJudgment,
+ getExplicitTypeArguments;
/// A generator represents a subexpression for which we can't yet build an
/// expression because we don't yet know the context in which it's used.
@@ -153,7 +131,9 @@
/// A token that defines a position subexpression that being built.
final Token token;
- Generator(this._helper, this.token);
+ final int fileOffset;
+
+ Generator(this._helper, this.token) : fileOffset = offsetForToken(token);
/// Easy access to the [Forest] factory object.
Forest get _forest => _helper.forest;
@@ -303,8 +283,7 @@
complexAssignment?.isPostIncDec = true;
VariableDeclarationJudgment dummy =
new VariableDeclarationJudgment.forValue(
- _makeWrite(combiner, true, complexAssignment),
- _helper.functionNestingLevel);
+ _makeWrite(combiner, true, complexAssignment));
return _finish(
makeLet(value, makeLet(dummy, valueAccess())), complexAssignment);
}
@@ -315,12 +294,12 @@
Expression _makeInvalidRead() {
return _helper.wrapSyntheticExpression(
_helper.throwNoSuchMethodError(
- _forest.createNullLiteral(token),
+ _forest.createNullLiteral(fileOffset),
_plainNameForRead,
_forest.createArgumentsEmpty(noLocation),
- offsetForToken(token),
+ fileOffset,
isGetter: true),
- offsetForToken(token));
+ fileOffset);
}
/// Returns a [Expression] representing a compile-time error wrapping
@@ -330,12 +309,12 @@
Expression _makeInvalidWrite(Expression value) {
return _helper.wrapSyntheticExpression(
_helper.throwNoSuchMethodError(
- _forest.createNullLiteral(token),
+ _forest.createNullLiteral(fileOffset),
_plainNameForRead,
- _forest.createArguments(<Expression>[value], noLocation),
- offsetForToken(token),
+ _forest.createArguments(noLocation, <Expression>[value]),
+ fileOffset,
isSetter: true),
- offsetForToken(token));
+ fileOffset);
}
/// Returns an [Expression] the reads this subexpression.
@@ -409,11 +388,10 @@
Expression buildForEffect() => buildSimpleRead();
Initializer buildFieldInitializer(Map<String, int> initializedFields) {
- int offset = offsetForToken(token);
return _helper.buildInvalidInitializer(
_helper.desugarSyntheticExpression(_helper.buildProblem(
- messageInvalidInitializer, offset, lengthForToken(token))),
- offset);
+ messageInvalidInitializer, fileOffset, lengthForToken(token))),
+ fileOffset);
}
/// Returns an expression, generator or initializer for an invocation of this
@@ -442,7 +420,7 @@
if (_helper.constantContext != ConstantContext.none &&
send.name != lengthName) {
_helper.addProblem(
- messageNotAConstantExpression, offsetForToken(token), token.length);
+ messageNotAConstantExpression, fileOffset, token.length);
}
return PropertyAccessGenerator.make(_helper, send.token,
buildSimpleRead(), send.name, null, null, isNullAware);
@@ -454,13 +432,15 @@
///
/// The type arguments have not been resolved and should be resolved to
/// create a [TypeBuilder] for a valid type.
- TypeBuilder buildTypeWithResolvedArguments(List<UnresolvedType> arguments) {
- NamedTypeBuilder result = new NamedTypeBuilder(token.lexeme, null);
+ TypeBuilder buildTypeWithResolvedArguments(
+ NullabilityBuilder nullabilityBuilder, List<UnresolvedType> arguments) {
+ NamedTypeBuilder result =
+ new NamedTypeBuilder(token.lexeme, nullabilityBuilder, null);
Message message = templateNotAType.withArguments(token.lexeme);
- _helper.library.addProblem(
- message, offsetForToken(token), lengthForToken(token), _uri);
- result.bind(result.buildInvalidType(message.withLocation(
- _uri, offsetForToken(token), lengthForToken(token))));
+ _helper.libraryBuilder
+ .addProblem(message, fileOffset, lengthForToken(token), _uri);
+ result.bind(result.buildInvalidType(
+ message.withLocation(_uri, fileOffset, lengthForToken(token))));
return result;
}
@@ -482,14 +462,14 @@
}
return _helper.wrapInvalidConstructorInvocation(
_helper.throwNoSuchMethodError(
- _forest.createNullLiteral(token),
+ _forest.createNullLiteral(fileOffset),
_helper.constructorNameForDiagnostics(name,
className: _plainNameForRead),
arguments,
nameToken.charOffset),
null,
arguments,
- offsetForToken(token));
+ fileOffset);
}
void printOn(StringSink sink);
@@ -498,7 +478,7 @@
StringBuffer buffer = new StringBuffer();
buffer.write(_debugName);
buffer.write("(offset: ");
- buffer.write("${offsetForToken(token)}");
+ buffer.write("${fileOffset}");
printOn(buffer);
buffer.write(")");
return "$buffer";
@@ -542,7 +522,7 @@
?.getFactForAccess(variable, _helper.functionNestingLevel);
TypePromotionScope scope = _helper.typePromoter?.currentScope;
VariableGetJudgment read = new VariableGetJudgment(variable, fact, scope)
- ..fileOffset = offsetForToken(token);
+ ..fileOffset = fileOffset;
complexAssignment?.read = read;
return read;
}
@@ -560,8 +540,7 @@
complexAssignment.write = write;
}
} else {
- write = new VariableSet(variable, value)
- ..fileOffset = offsetForToken(token);
+ write = new VariableSet(variable, value)..fileOffset = fileOffset;
complexAssignment?.write = write;
}
return write;
@@ -577,7 +556,7 @@
@override
ComplexAssignmentJudgment startComplexAssignment(Expression rhs) {
return SyntheticWrapper.wrapVariableAssignment(rhs)
- ..fileOffset = offsetForToken(token);
+ ..fileOffset = fileOffset;
}
@override
@@ -634,8 +613,7 @@
receiverAccess() {
_receiverVariable ??= new VariableDeclaration.forValue(receiver);
- return new VariableGet(_receiverVariable)
- ..fileOffset = offsetForToken(token);
+ return new VariableGet(_receiverVariable)..fileOffset = fileOffset;
}
@override
@@ -664,15 +642,14 @@
@override
Expression _makeSimpleRead() {
- return new PropertyGet(receiver, name, getter)
- ..fileOffset = offsetForToken(token);
+ return new PropertyGet(receiver, name, getter)..fileOffset = fileOffset;
}
@override
Expression _makeSimpleWrite(Expression value, bool voidContext,
ComplexAssignmentJudgment complexAssignment) {
PropertySet write = new PropertySet(receiver, name, value, setter)
- ..fileOffset = offsetForToken(token);
+ ..fileOffset = fileOffset;
complexAssignment?.write = write;
return write;
}
@@ -680,7 +657,7 @@
@override
Expression _makeRead(ComplexAssignmentJudgment complexAssignment) {
PropertyGet read = new PropertyGet(receiverAccess(), name, getter)
- ..fileOffset = offsetForToken(token);
+ ..fileOffset = fileOffset;
complexAssignment?.read = read;
return read;
}
@@ -689,7 +666,7 @@
Expression _makeWrite(Expression value, bool voidContext,
ComplexAssignmentJudgment complexAssignment) {
PropertySet write = new PropertySet(receiverAccess(), name, value, setter)
- ..fileOffset = offsetForToken(token);
+ ..fileOffset = fileOffset;
complexAssignment?.write = write;
return write;
}
@@ -785,11 +762,11 @@
@override
Expression _makeRead(ComplexAssignmentJudgment complexAssignment) {
if (getter == null) {
- _helper.warnUnresolvedGet(name, offsetForToken(token));
+ _helper.warnUnresolvedGet(name, fileOffset);
}
PropertyGet read =
new PropertyGet(_forest.createThisExpression(token), name, getter)
- ..fileOffset = offsetForToken(token);
+ ..fileOffset = fileOffset;
complexAssignment?.read = read;
return read;
}
@@ -798,11 +775,11 @@
Expression _makeWrite(Expression value, bool voidContext,
ComplexAssignmentJudgment complexAssignment) {
if (setter == null) {
- _helper.warnUnresolvedSet(name, offsetForToken(token));
+ _helper.warnUnresolvedSet(name, fileOffset);
}
PropertySet write = new PropertySet(
_forest.createThisExpression(token), name, value, setter)
- ..fileOffset = offsetForToken(token);
+ ..fileOffset = fileOffset;
complexAssignment?.write = write;
return write;
}
@@ -874,7 +851,7 @@
@override
Expression _makeRead(ComplexAssignmentJudgment complexAssignment) {
PropertyGet read = new PropertyGet(receiverAccess(), name, getter)
- ..fileOffset = offsetForToken(token);
+ ..fileOffset = fileOffset;
complexAssignment?.read = read;
return read;
}
@@ -883,7 +860,7 @@
Expression _makeWrite(Expression value, bool voidContext,
ComplexAssignmentJudgment complexAssignment) {
PropertySet write = new PropertySet(receiverAccess(), name, value, setter)
- ..fileOffset = offsetForToken(token);
+ ..fileOffset = fileOffset;
complexAssignment?.write = write;
return write;
}
@@ -891,14 +868,13 @@
@override
Expression _finish(
Expression body, ComplexAssignmentJudgment complexAssignment) {
- int offset = offsetForToken(token);
Expression nullAwareGuard = _forest.createConditionalExpression(
- buildIsNull(receiverAccess(), offset, _helper),
+ buildIsNull(receiverAccess(), fileOffset, _helper),
null,
- _forest.createNullLiteral(null)..fileOffset = offset,
+ _forest.createNullLiteral(null)..fileOffset = fileOffset,
null,
body)
- ..fileOffset = offset;
+ ..fileOffset = fileOffset;
if (complexAssignment != null) {
body = makeLet(receiver, nullAwareGuard);
if (_helper.legacyMode) return body;
@@ -908,7 +884,7 @@
return kernelPropertyAssign;
} else {
return new NullAwarePropertyGetJudgment(receiver, nullAwareGuard)
- ..fileOffset = offset;
+ ..fileOffset = fileOffset;
}
}
@@ -959,12 +935,12 @@
@override
Expression _makeRead(ComplexAssignmentJudgment complexAssignment) {
if (getter == null) {
- _helper.warnUnresolvedGet(name, offsetForToken(token), isSuper: true);
+ _helper.warnUnresolvedGet(name, fileOffset, isSuper: true);
}
// TODO(ahe): Use [DirectPropertyGet] when possible.
SuperPropertyGetJudgment read =
new SuperPropertyGetJudgment(name, interfaceTarget: getter)
- ..fileOffset = offsetForToken(token);
+ ..fileOffset = fileOffset;
complexAssignment?.read = read;
return read;
}
@@ -973,11 +949,11 @@
Expression _makeWrite(Expression value, bool voidContext,
ComplexAssignmentJudgment complexAssignment) {
if (setter == null) {
- _helper.warnUnresolvedSet(name, offsetForToken(token), isSuper: true);
+ _helper.warnUnresolvedSet(name, fileOffset, isSuper: true);
}
// TODO(ahe): Use [DirectPropertySet] when possible.
SuperPropertySet write = new SuperPropertySet(name, value, setter)
- ..fileOffset = offsetForToken(token);
+ ..fileOffset = fileOffset;
complexAssignment?.write = write;
return write;
}
@@ -1043,23 +1019,22 @@
Expression indexAccess() {
indexVariable ??= new VariableDeclaration.forValue(index);
- return new VariableGet(indexVariable)..fileOffset = offsetForToken(token);
+ return new VariableGet(indexVariable)..fileOffset = fileOffset;
}
Expression receiverAccess() {
// We cannot reuse the receiver if it is a variable since it might be
// reassigned in the index expression.
receiverVariable ??= new VariableDeclaration.forValue(receiver);
- return new VariableGet(receiverVariable)
- ..fileOffset = offsetForToken(token);
+ return new VariableGet(receiverVariable)..fileOffset = fileOffset;
}
@override
Expression _makeSimpleRead() {
MethodInvocationJudgment read = new MethodInvocationJudgment(receiver,
- indexGetName, _forest.createArguments(<Expression>[index], token),
+ indexGetName, _forest.createArguments(fileOffset, <Expression>[index]),
interfaceTarget: getter)
- ..fileOffset = offsetForToken(token);
+ ..fileOffset = fileOffset;
return read;
}
@@ -1070,9 +1045,9 @@
MethodInvocationJudgment write = new MethodInvocationJudgment(
receiver,
indexSetName,
- _forest.createArguments(<Expression>[index, value], token),
+ _forest.createArguments(fileOffset, <Expression>[index, value]),
interfaceTarget: setter)
- ..fileOffset = offsetForToken(token);
+ ..fileOffset = fileOffset;
complexAssignment?.write = write;
return write;
}
@@ -1082,9 +1057,9 @@
MethodInvocationJudgment read = new MethodInvocationJudgment(
receiverAccess(),
indexGetName,
- _forest.createArguments(<Expression>[indexAccess()], token),
+ _forest.createArguments(fileOffset, <Expression>[indexAccess()]),
interfaceTarget: getter)
- ..fileOffset = offsetForToken(token);
+ ..fileOffset = fileOffset;
complexAssignment?.read = read;
return read;
}
@@ -1096,9 +1071,9 @@
MethodInvocationJudgment write = new MethodInvocationJudgment(
receiverAccess(),
indexSetName,
- _forest.createArguments(<Expression>[indexAccess(), value], token),
+ _forest.createArguments(fileOffset, <Expression>[indexAccess(), value]),
interfaceTarget: setter)
- ..fileOffset = offsetForToken(token);
+ ..fileOffset = fileOffset;
complexAssignment?.write = write;
return write;
}
@@ -1113,14 +1088,13 @@
MethodInvocationJudgment write = new MethodInvocationJudgment(
receiverAccess(),
indexSetName,
- _forest.createArguments(
- <Expression>[indexAccess(), new VariableGet(valueVariable)], token),
+ _forest.createArguments(fileOffset,
+ <Expression>[indexAccess(), new VariableGet(valueVariable)]),
interfaceTarget: setter)
- ..fileOffset = offsetForToken(token);
+ ..fileOffset = fileOffset;
complexAssignment?.write = write;
VariableDeclarationJudgment dummy =
- new VariableDeclarationJudgment.forValue(
- write, _helper.functionNestingLevel);
+ new VariableDeclarationJudgment.forValue(write);
return makeLet(
valueVariable, makeLet(dummy, new VariableGet(valueVariable)));
}
@@ -1128,11 +1102,10 @@
@override
Expression _finish(
Expression body, ComplexAssignmentJudgment complexAssignment) {
- int offset = offsetForToken(token);
return super._finish(
- makeLet(
- receiverVariable, makeLet(indexVariable, body)..fileOffset = offset)
- ..fileOffset = offset,
+ makeLet(receiverVariable,
+ makeLet(indexVariable, body)..fileOffset = fileOffset)
+ ..fileOffset = fileOffset,
complexAssignment);
}
@@ -1213,10 +1186,10 @@
MethodInvocationJudgment write = new MethodInvocationJudgment(
_forest.createThisExpression(token),
indexSetName,
- _forest.createArguments(
- <Expression>[indexAccess(), new VariableGet(valueVariable)], token),
+ _forest.createArguments(fileOffset,
+ <Expression>[indexAccess(), new VariableGet(valueVariable)]),
interfaceTarget: setter)
- ..fileOffset = offsetForToken(token);
+ ..fileOffset = fileOffset;
complexAssignment?.write = write;
VariableDeclaration dummy = new VariableDeclaration.forValue(write);
return makeLet(
@@ -1226,9 +1199,9 @@
@override
Expression _makeSimpleRead() {
return new MethodInvocationJudgment(_forest.createThisExpression(token),
- indexGetName, _forest.createArguments(<Expression>[index], token),
+ indexGetName, _forest.createArguments(fileOffset, <Expression>[index]),
interfaceTarget: getter)
- ..fileOffset = offsetForToken(token);
+ ..fileOffset = fileOffset;
}
@override
@@ -1238,9 +1211,9 @@
MethodInvocationJudgment write = new MethodInvocationJudgment(
_forest.createThisExpression(token),
indexSetName,
- _forest.createArguments(<Expression>[index, value], token),
+ _forest.createArguments(fileOffset, <Expression>[index, value]),
interfaceTarget: setter)
- ..fileOffset = offsetForToken(token);
+ ..fileOffset = fileOffset;
complexAssignment?.write = write;
return write;
}
@@ -1250,9 +1223,9 @@
MethodInvocationJudgment read = new MethodInvocationJudgment(
_forest.createThisExpression(token),
indexGetName,
- _forest.createArguments(<Expression>[indexAccess()], token),
+ _forest.createArguments(fileOffset, <Expression>[indexAccess()]),
interfaceTarget: getter)
- ..fileOffset = offsetForToken(token);
+ ..fileOffset = fileOffset;
complexAssignment?.read = read;
return read;
}
@@ -1264,9 +1237,9 @@
MethodInvocationJudgment write = new MethodInvocationJudgment(
_forest.createThisExpression(token),
indexSetName,
- _forest.createArguments(<Expression>[indexAccess(), value], token),
+ _forest.createArguments(fileOffset, <Expression>[indexAccess(), value]),
interfaceTarget: setter)
- ..fileOffset = offsetForToken(token);
+ ..fileOffset = fileOffset;
complexAssignment?.write = write;
return write;
}
@@ -1328,15 +1301,14 @@
Expression value, ComplexAssignmentJudgment complexAssignment) {
VariableDeclaration valueVariable = new VariableDeclaration.forValue(value);
if (setter == null) {
- _helper.warnUnresolvedMethod(indexSetName, offsetForToken(token),
- isSuper: true);
+ _helper.warnUnresolvedMethod(indexSetName, fileOffset, isSuper: true);
}
SuperMethodInvocation write = new SuperMethodInvocation(
indexSetName,
- _forest.createArguments(
- <Expression>[indexAccess(), new VariableGet(valueVariable)], token),
+ _forest.createArguments(fileOffset,
+ <Expression>[indexAccess(), new VariableGet(valueVariable)]),
setter)
- ..fileOffset = offsetForToken(token);
+ ..fileOffset = fileOffset;
complexAssignment?.write = write;
VariableDeclaration dummy = new VariableDeclaration.forValue(write);
return makeLet(
@@ -1346,14 +1318,13 @@
@override
Expression _makeSimpleRead() {
if (getter == null) {
- _helper.warnUnresolvedMethod(indexGetName, offsetForToken(token),
- isSuper: true);
+ _helper.warnUnresolvedMethod(indexGetName, fileOffset, isSuper: true);
}
// TODO(ahe): Use [DirectMethodInvocation] when possible.
return new SuperMethodInvocationJudgment(
- indexGetName, _forest.createArguments(<Expression>[index], token),
+ indexGetName, _forest.createArguments(fileOffset, <Expression>[index]),
interfaceTarget: getter)
- ..fileOffset = offsetForToken(token);
+ ..fileOffset = fileOffset;
}
@override
@@ -1361,12 +1332,11 @@
ComplexAssignmentJudgment complexAssignment) {
if (!voidContext) return _makeWriteAndReturn(value, complexAssignment);
if (setter == null) {
- _helper.warnUnresolvedMethod(indexSetName, offsetForToken(token),
- isSuper: true);
+ _helper.warnUnresolvedMethod(indexSetName, fileOffset, isSuper: true);
}
SuperMethodInvocation write = new SuperMethodInvocation(indexSetName,
- _forest.createArguments(<Expression>[index, value], token), setter)
- ..fileOffset = offsetForToken(token);
+ _forest.createArguments(fileOffset, <Expression>[index, value]), setter)
+ ..fileOffset = fileOffset;
complexAssignment?.write = write;
return write;
}
@@ -1374,12 +1344,13 @@
@override
Expression _makeRead(ComplexAssignmentJudgment complexAssignment) {
if (getter == null) {
- _helper.warnUnresolvedMethod(indexGetName, offsetForToken(token),
- isSuper: true);
+ _helper.warnUnresolvedMethod(indexGetName, fileOffset, isSuper: true);
}
- SuperMethodInvocation read = new SuperMethodInvocation(indexGetName,
- _forest.createArguments(<Expression>[indexAccess()], token), getter)
- ..fileOffset = offsetForToken(token);
+ SuperMethodInvocation read = new SuperMethodInvocation(
+ indexGetName,
+ _forest.createArguments(fileOffset, <Expression>[indexAccess()]),
+ getter)
+ ..fileOffset = fileOffset;
complexAssignment?.read = read;
return read;
}
@@ -1389,14 +1360,13 @@
ComplexAssignmentJudgment complexAssignment) {
if (!voidContext) return _makeWriteAndReturn(value, complexAssignment);
if (setter == null) {
- _helper.warnUnresolvedMethod(indexSetName, offsetForToken(token),
- isSuper: true);
+ _helper.warnUnresolvedMethod(indexSetName, fileOffset, isSuper: true);
}
SuperMethodInvocation write = new SuperMethodInvocation(
indexSetName,
- _forest.createArguments(<Expression>[indexAccess(), value], token),
+ _forest.createArguments(fileOffset, <Expression>[indexAccess(), value]),
setter)
- ..fileOffset = offsetForToken(token);
+ ..fileOffset = fileOffset;
complexAssignment?.write = write;
return write;
}
@@ -1404,8 +1374,7 @@
@override
Expression _finish(
Expression body, ComplexAssignmentJudgment complexAssignment) {
- return super._finish(
- makeLet(indexVariable, body)..fileOffset = offsetForToken(token),
+ return super._finish(makeLet(indexVariable, body)..fileOffset = fileOffset,
complexAssignment);
}
@@ -1546,7 +1515,7 @@
write = new StaticSet(writeTarget, value);
}
complexAssignment?.write = write;
- write.fileOffset = offsetForToken(token);
+ write.fileOffset = fileOffset;
return write;
}
@@ -1595,33 +1564,30 @@
/// extension B on A {
/// get property => 0;
/// set property(_) {}
-/// var field;
/// method() {
/// property; // this generator is created for `property`.
/// property = 0; // this generator is created for `property`.
-/// field = 0; // this generator is created for `field`.
/// method; // this generator is created for `method`.
/// method(); // this generator is created for `method`.
/// }
/// }
///
+/// These can only occur within an extension instance member.
class ExtensionInstanceAccessGenerator extends Generator {
/// The static [Member] generated for an instance extension member which is
- /// used for performing a read or invocation on this subexpression.
+ /// used for performing a read on this subexpression.
///
/// This can be `null` if the subexpression doesn't have a readable target.
/// For instance if the subexpression is a setter without a corresponding
/// getter.
final Procedure readTarget;
- /// `true` if the [readTarget] is declared as a regular method in the
- /// extension.
+ /// The static [Member] generated for an instance extension member which is
+ /// used for performing an invocation on this subexpression.
///
- /// All extension instance members are converted into to top level methods so
- /// this field is needed to know whether a read should be a tear off, which
- /// is the case for regular methods, or an invocation should be a read follow
- /// by a call, which is the case for getters.
- final bool readTargetIsRegularMethod;
+ /// This can be `null` if the subexpression doesn't have an invokable target.
+ /// For instance if the subexpression is a getter or setter.
+ final Procedure invokeTarget;
/// The static [Member] generated for an instance extension member which is
/// used for performing a write on this subexpression.
@@ -1645,7 +1611,7 @@
ExpressionGeneratorHelper helper,
Token token,
this.readTarget,
- this.readTargetIsRegularMethod,
+ this.invokeTarget,
this.writeTarget,
this.extensionThis,
this.extensionTypeParameters)
@@ -1673,23 +1639,21 @@
offsetForToken(token),
helper.uri);
}
- bool readTargetIsRegularMethod = declaration.isRegularMethod;
- Procedure getter;
- if (declaration.isGetter || declaration.isRegularMethod) {
- getter = declaration.target;
+ Procedure readTarget;
+ Procedure invokeTarget;
+ if (declaration.isGetter) {
+ readTarget = declaration.target;
+ } else if (declaration.isRegularMethod) {
+ MemberBuilder procedureBuilder = declaration;
+ readTarget = procedureBuilder.extensionTearOff;
+ invokeTarget = procedureBuilder.procedure;
}
- Procedure setter;
+ Procedure writeTarget;
if (builderSetter != null && builderSetter.isSetter) {
- setter = builderSetter.target;
+ writeTarget = builderSetter.target;
}
- return new ExtensionInstanceAccessGenerator(
- helper,
- token,
- getter,
- readTargetIsRegularMethod,
- setter,
- extensionThis,
- extensionTypeParameters);
+ return new ExtensionInstanceAccessGenerator(helper, token, readTarget,
+ invokeTarget, writeTarget, extensionThis, extensionTypeParameters);
}
@override
@@ -1698,6 +1662,20 @@
@override
String get _plainNameForRead => (readTarget ?? writeTarget).name.name;
+ int get _extensionTypeParameterCount => extensionTypeParameters?.length ?? 0;
+
+ List<DartType> _createExtensionTypeArguments() {
+ List<DartType> extensionTypeArguments = const <DartType>[];
+ if (extensionTypeParameters != null) {
+ extensionTypeArguments = [];
+ for (TypeParameter typeParameter in extensionTypeParameters) {
+ extensionTypeArguments
+ .add(_forest.createTypeParameterType(typeParameter));
+ }
+ }
+ return extensionTypeArguments;
+ }
+
@override
Expression _makeRead(ComplexAssignmentJudgment complexAssignment) {
Expression read;
@@ -1706,23 +1684,16 @@
if (complexAssignment != null) {
read = _helper.desugarSyntheticExpression(read);
}
- } else if (readTargetIsRegularMethod) {
- read = _helper.createExtensionTearOff(
- readTarget, extensionThis, extensionTypeParameters, token);
} else {
- List<DartType> typeArguments;
- if (extensionTypeParameters != null) {
- typeArguments = [];
- for (TypeParameter typeParameter in extensionTypeParameters) {
- typeArguments.add(_forest.createTypeParameterType(typeParameter));
- }
- }
- read = _helper.buildStaticInvocation(
+ read = _helper.buildExtensionMethodInvocation(
+ fileOffset,
readTarget,
- _helper.forest.createArguments([
- _helper.createVariableGet(extensionThis, offsetForToken(token))
- ], token, types: typeArguments),
- charOffset: token.charOffset);
+ _helper.forest.createArgumentsForExtensionMethod(
+ fileOffset,
+ _extensionTypeParameterCount,
+ 0,
+ _helper.createVariableGet(extensionThis, fileOffset),
+ extensionTypeArguments: _createExtensionTypeArguments()));
}
complexAssignment?.read = read;
return read;
@@ -1738,49 +1709,38 @@
write = _helper.desugarSyntheticExpression(write);
}
} else {
- List<DartType> typeArguments;
- if (extensionTypeParameters != null) {
- typeArguments = [];
- for (TypeParameter typeParameter in extensionTypeParameters) {
- typeArguments.add(_forest.createTypeParameterType(typeParameter));
- }
- }
- write = _helper.buildStaticInvocation(
+ write = _helper.buildExtensionMethodInvocation(
+ fileOffset,
writeTarget,
- _helper.forest.createArguments([
- _helper.createVariableGet(extensionThis, offsetForToken(token)),
- value
- ], token, types: typeArguments),
- charOffset: token.charOffset);
+ _helper.forest.createArgumentsForExtensionMethod(
+ fileOffset,
+ _extensionTypeParameterCount,
+ 0,
+ _helper.createVariableGet(extensionThis, fileOffset),
+ extensionTypeArguments: _createExtensionTypeArguments(),
+ positionalArguments: [value]));
}
complexAssignment?.write = write;
- write.fileOffset = offsetForToken(token);
+ write.fileOffset = fileOffset;
return write;
}
@override
Expression doInvocation(int offset, Arguments arguments) {
- if (readTargetIsRegularMethod) {
- List<Expression> positionalArguments = [
- _helper.createVariableGet(extensionThis, offset)
- ]..addAll(arguments.positional);
- List<DartType> typeArguments;
- if (extensionTypeParameters != null) {
- typeArguments = [];
- for (TypeParameter typeParameter in extensionTypeParameters) {
- typeArguments.add(_forest.createTypeParameterType(typeParameter));
- }
- if (arguments.types.isNotEmpty) {
- typeArguments.addAll(arguments.types);
- }
- } else if (arguments.types.isNotEmpty) {
- typeArguments = arguments.types;
- }
- return _helper.buildStaticInvocation(
- readTarget,
- _forest.createArguments(positionalArguments, token,
- named: arguments.named, types: typeArguments),
- charOffset: offset);
+ if (invokeTarget != null) {
+ return _helper.buildExtensionMethodInvocation(
+ offset,
+ invokeTarget,
+ _forest.createArgumentsForExtensionMethod(
+ fileOffset,
+ _extensionTypeParameterCount,
+ invokeTarget.function.typeParameters.length -
+ _extensionTypeParameterCount,
+ _helper.createVariableGet(extensionThis, offset),
+ extensionTypeArguments: _createExtensionTypeArguments(),
+ typeArguments: arguments.types,
+ positionalArguments: arguments.positional,
+ namedArguments: arguments.named));
} else {
return _helper.buildMethodInvocation(buildSimpleRead(), callName,
arguments, adjustForImplicitCall(_plainNameForRead, offset),
@@ -1802,6 +1762,298 @@
}
}
+/// A [ExplicitExtensionInstanceAccessGenerator] represents a subexpression
+/// whose prefix is a forced extension instance member access.
+///
+/// For instance
+///
+/// class A<T> {}
+/// extension B on A<int> {
+/// method() {}
+/// }
+/// extension C<T> {
+/// T get field => 0;
+/// set field(T _) {}
+/// }
+///
+/// method(A a) {
+/// B(a).method; // this generator is created for `B(a).method`.
+/// B(a).method(); // this generator is created for `B(a).method`.
+/// C<int>(a).field; // this generator is created for `C<int>(a).field`.
+/// C(a).field = 0; // this generator is created for `C(a).field`.
+/// }
+///
+class ExplicitExtensionInstanceAccessGenerator extends Generator {
+ /// The static [Member] generated for an instance extension member which is
+ /// used for performing a read on this subexpression.
+ ///
+ /// This can be `null` if the subexpression doesn't have a readable target.
+ /// For instance if the subexpression is a setter without a corresponding
+ /// getter.
+ final Procedure readTarget;
+
+ /// The static [Member] generated for an instance extension member which is
+ /// used for performing an invocation on this subexpression.
+ ///
+ /// This can be `null` if the subexpression doesn't have an invokable target.
+ /// For instance if the subexpression is a getter or setter.
+ final Procedure invokeTarget;
+
+ /// The static [Member] generated for an instance extension member which is
+ /// used for performing a write on this subexpression.
+ ///
+ /// This can be `null` if the subexpression doesn't have a writable target.
+ /// For instance if the subexpression is a final field, a method, or a getter
+ /// without a corresponding setter.
+ final Procedure writeTarget;
+
+ /// The expression holding the receiver value for the explicit extension
+ /// access, that is, `a` in `Extension<int>(a).method<String>()`.
+ final Expression receiver;
+
+ /// The type arguments explicitly passed to the explicit extension access,
+ /// like `<int>` in `Extension<int>(a).method<String>()`.
+ final List<DartType> explicitTypeArguments;
+
+ final int extensionTypeParameterCount;
+
+ ExplicitExtensionInstanceAccessGenerator(
+ ExpressionGeneratorHelper helper,
+ Token token,
+ this.readTarget,
+ this.invokeTarget,
+ this.writeTarget,
+ this.receiver,
+ this.explicitTypeArguments,
+ this.extensionTypeParameterCount)
+ : assert(readTarget != null || writeTarget != null),
+ assert(receiver != null),
+ super(helper, token);
+
+ factory ExplicitExtensionInstanceAccessGenerator.fromBuilder(
+ ExpressionGeneratorHelper helper,
+ Token token,
+ Builder getterBuilder,
+ Builder setterBuilder,
+ Expression receiver,
+ List<DartType> explicitTypeArguments,
+ int extensionTypeParameterCount) {
+ Procedure readTarget;
+ Procedure invokeTarget;
+ if (getterBuilder != null) {
+ if (getterBuilder is AccessErrorBuilder) {
+ AccessErrorBuilder error = getterBuilder;
+ getterBuilder = error.builder;
+ // We should only see an access error here if we've looked up a setter
+ // when not explicitly looking for a setter.
+ assert(getterBuilder.isSetter);
+ } else if (getterBuilder.isGetter) {
+ readTarget = getterBuilder.target;
+ } else if (getterBuilder.isRegularMethod) {
+ MemberBuilder procedureBuilder = getterBuilder;
+ readTarget = procedureBuilder.extensionTearOff;
+ invokeTarget = procedureBuilder.procedure;
+ } else {
+ return unhandled(
+ "${getterBuilder.runtimeType}",
+ "InstanceExtensionAccessGenerator.fromBuilder",
+ offsetForToken(token),
+ helper.uri);
+ }
+ }
+ Procedure writeTarget;
+ if (setterBuilder != null && setterBuilder.isSetter) {
+ writeTarget = setterBuilder.target;
+ }
+ return new ExplicitExtensionInstanceAccessGenerator(
+ helper,
+ token,
+ readTarget,
+ invokeTarget,
+ writeTarget,
+ receiver,
+ explicitTypeArguments,
+ extensionTypeParameterCount);
+ }
+
+ @override
+ String get _debugName => "InstanceExtensionAccessGenerator";
+
+ @override
+ String get _plainNameForRead => (readTarget ?? writeTarget).name.name;
+
+ List<DartType> _createExtensionTypeArguments() {
+ return explicitTypeArguments ?? const <DartType>[];
+ }
+
+ @override
+ Expression _makeRead(ComplexAssignmentJudgment complexAssignment) {
+ Expression read;
+ if (readTarget == null) {
+ read = _makeInvalidRead();
+ if (complexAssignment != null) {
+ read = _helper.desugarSyntheticExpression(read);
+ }
+ } else {
+ read = _helper.buildExtensionMethodInvocation(
+ fileOffset,
+ readTarget,
+ _helper.forest.createArgumentsForExtensionMethod(
+ fileOffset, extensionTypeParameterCount, 0, receiver,
+ extensionTypeArguments: _createExtensionTypeArguments()));
+ }
+ complexAssignment?.read = read;
+ return read;
+ }
+
+ @override
+ Expression _makeWrite(Expression value, bool voidContext,
+ ComplexAssignmentJudgment complexAssignment) {
+ Expression write;
+ if (writeTarget == null) {
+ write = _makeInvalidWrite(value);
+ if (complexAssignment != null) {
+ write = _helper.desugarSyntheticExpression(write);
+ }
+ } else {
+ write = _helper.buildExtensionMethodInvocation(
+ fileOffset,
+ writeTarget,
+ _helper.forest.createArgumentsForExtensionMethod(
+ fileOffset, extensionTypeParameterCount, 0, receiver,
+ extensionTypeArguments: _createExtensionTypeArguments(),
+ positionalArguments: [value]));
+ }
+ complexAssignment?.write = write;
+ write.fileOffset = fileOffset;
+ return write;
+ }
+
+ @override
+ Expression doInvocation(int offset, Arguments arguments) {
+ if (invokeTarget != null) {
+ return _helper.buildExtensionMethodInvocation(
+ fileOffset,
+ invokeTarget,
+ _forest.createArgumentsForExtensionMethod(
+ fileOffset,
+ extensionTypeParameterCount,
+ invokeTarget.function.typeParameters.length -
+ extensionTypeParameterCount,
+ receiver,
+ extensionTypeArguments: _createExtensionTypeArguments(),
+ typeArguments: arguments.types,
+ positionalArguments: arguments.positional,
+ namedArguments: arguments.named));
+ } else {
+ return _helper.buildMethodInvocation(buildSimpleRead(), callName,
+ arguments, adjustForImplicitCall(_plainNameForRead, offset),
+ isImplicitCall: true);
+ }
+ }
+
+ @override
+ ComplexAssignmentJudgment startComplexAssignment(Expression rhs) =>
+ SyntheticWrapper.wrapStaticAssignment(rhs);
+
+ @override
+ void printOn(StringSink sink) {
+ NameSystem syntheticNames = new NameSystem();
+ sink.write(", readTarget: ");
+ printQualifiedNameOn(readTarget, sink, syntheticNames: syntheticNames);
+ sink.write(", writeTarget: ");
+ printQualifiedNameOn(writeTarget, sink, syntheticNames: syntheticNames);
+ }
+}
+
+/// A [ExplicitExtensionAccessGenerator] represents a subexpression whose
+/// prefix is a forced extension resolution.
+///
+/// For instance
+///
+/// class A<T> {}
+/// extension B on A<int> {
+/// method() {}
+/// }
+/// extension C<T> on A<T> {
+/// T get field => 0;
+/// set field(T _) {}
+/// }
+///
+/// method(A a) {
+/// B(a).method; // this generator is created for `B(a)`.
+/// B(a).method(); // this generator is created for `B(a)`.
+/// C<int>(a).field; // this generator is created for `C<int>(a)`.
+/// C(a).field = 0; // this generator is created for `C(a)`.
+/// }
+///
+/// When an access is performed on this generator a
+/// [ExplicitExtensionInstanceAccessGenerator] is created.
+class ExplicitExtensionAccessGenerator extends Generator {
+ final ExtensionBuilder extensionBuilder;
+ final Expression receiver;
+ final List<DartType> explicitTypeArguments;
+
+ ExplicitExtensionAccessGenerator(
+ ExpressionGeneratorHelper helper,
+ Token token,
+ this.extensionBuilder,
+ this.receiver,
+ this.explicitTypeArguments)
+ : super(helper, token);
+
+ @override
+ String get _plainNameForRead {
+ return unsupported(
+ "ExplicitExtensionAccessGenerator.plainNameForRead", fileOffset, _uri);
+ }
+
+ @override
+ String get _debugName => "ExplicitExtensionAccessGenerator";
+
+ /* Expression | Generator */ buildPropertyAccess(
+ IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
+ if (_helper.constantContext != ConstantContext.none) {
+ _helper.addProblem(
+ messageNotAConstantExpression, fileOffset, token.length);
+ }
+ Builder getter = extensionBuilder.lookupLocalMember(send.name.name);
+ Builder setter =
+ extensionBuilder.lookupLocalMember(send.name.name, setter: true);
+ if (getter == null && setter == null) {
+ return new UnresolvedNameGenerator(_helper, token, send.name);
+ }
+ Generator generator =
+ new ExplicitExtensionInstanceAccessGenerator.fromBuilder(
+ _helper,
+ token,
+ getter,
+ setter,
+ receiver,
+ explicitTypeArguments,
+ extensionBuilder.typeParameters?.length ?? 0);
+ if (send.arguments != null) {
+ return generator.doInvocation(offsetForToken(send.token), send.arguments);
+ } else {
+ return generator;
+ }
+ }
+
+ @override
+ doInvocation(int offset, Arguments arguments) {
+ return unimplemented(
+ "ExplicitExtensionAccessGenerator.doInvocation", fileOffset, _uri);
+ }
+
+ @override
+ void printOn(StringSink sink) {
+ sink.write(", extensionBuilder: ");
+ sink.write(extensionBuilder);
+ sink.write(", receiver: ");
+ sink.write(receiver);
+ }
+}
+
class LoadLibraryGenerator extends Generator {
final LoadLibraryBuilder builder;
@@ -1814,12 +2066,13 @@
@override
String get _debugName => "LoadLibraryGenerator";
+
@override
Expression _makeRead(ComplexAssignmentJudgment complexAssignment) {
builder.importDependency.targetLibrary;
LoadLibraryTearOffJudgment read = new LoadLibraryTearOffJudgment(
builder.importDependency, builder.createTearoffMethod(_helper.forest))
- ..fileOffset = offsetForToken(token);
+ ..fileOffset = fileOffset;
complexAssignment?.read = read;
return read;
}
@@ -1894,19 +2147,19 @@
@override
String get _plainNameForRead {
- return unsupported(
- "deferredAccessor.plainNameForRead", offsetForToken(token), _uri);
+ return unsupported("deferredAccessor.plainNameForRead", fileOffset, _uri);
}
@override
String get _debugName => "DeferredAccessGenerator";
@override
- TypeBuilder buildTypeWithResolvedArguments(List<UnresolvedType> arguments) {
+ TypeBuilder buildTypeWithResolvedArguments(
+ NullabilityBuilder nullabilityBuilder, List<UnresolvedType> arguments) {
String name = "${prefixGenerator._plainNameForRead}."
"${suffixGenerator._plainNameForRead}";
- TypeBuilder type =
- suffixGenerator.buildTypeWithResolvedArguments(arguments);
+ TypeBuilder type = suffixGenerator.buildTypeWithResolvedArguments(
+ nullabilityBuilder, arguments);
LocatedMessage message;
if (type is NamedTypeBuilder && type.declaration is InvalidTypeBuilder) {
InvalidTypeBuilder declaration = type.declaration;
@@ -1920,8 +2173,9 @@
.withLocation(
_uri, charOffset, lengthOfSpan(prefixGenerator.token, token));
}
- NamedTypeBuilder result = new NamedTypeBuilder(name, null);
- _helper.library.addProblem(
+ NamedTypeBuilder result =
+ new NamedTypeBuilder(name, nullabilityBuilder, null);
+ _helper.libraryBuilder.addProblem(
message.messageObject, message.charOffset, message.length, message.uri);
result.bind(result.buildInvalidType(message));
return result;
@@ -1989,10 +2243,12 @@
String get _debugName => "TypeUseGenerator";
@override
- TypeBuilder buildTypeWithResolvedArguments(List<UnresolvedType> arguments) {
+ TypeBuilder buildTypeWithResolvedArguments(
+ NullabilityBuilder nullabilityBuilder, List<UnresolvedType> arguments) {
if (declaration.isExtension) {
// Extension declarations cannot be used as types.
- return super.buildTypeWithResolvedArguments(arguments);
+ return super
+ .buildTypeWithResolvedArguments(nullabilityBuilder, arguments);
}
if (arguments != null) {
int expected = declaration.typeVariablesCount;
@@ -2000,7 +2256,7 @@
// Build the type arguments to report any errors they may have.
_helper.buildDartTypeArguments(arguments);
_helper.warnTypeArgumentsMismatch(
- declaration.name, expected, offsetForToken(token));
+ declaration.name, expected, fileOffset);
// We ignore the provided arguments, which will in turn return the
// raw type below.
// TODO(sigmund): change to use an InvalidType and include the raw type
@@ -2011,7 +2267,7 @@
_helper.addProblem(
templateMissingExplicitTypeArguments
.withArguments(declaration.typeVariablesCount),
- offsetForToken(token),
+ fileOffset,
lengthForToken(token));
}
@@ -2023,7 +2279,8 @@
_helper.validateTypeUse(arguments[i], false).builder;
}
}
- return new NamedTypeBuilder(_plainNameForRead, argumentBuilders)
+ return new NamedTypeBuilder(
+ _plainNameForRead, nullabilityBuilder, argumentBuilders)
..bind(declaration);
}
@@ -2057,21 +2314,23 @@
@override
Expression get expression {
if (super.expression == null) {
- int offset = offsetForToken(token);
if (declaration is InvalidTypeBuilder) {
InvalidTypeBuilder declaration = this.declaration;
_helper.addProblemErrorIfConst(
- declaration.message.messageObject, offset, token.length);
+ declaration.message.messageObject, fileOffset, token.length);
super.expression = _helper.wrapSyntheticExpression(
_forest.createThrow(null,
_forest.createStringLiteral(declaration.message.message, token))
- ..fileOffset = offset,
- offset);
+ ..fileOffset = fileOffset,
+ fileOffset);
} else {
super.expression = _forest.createTypeLiteral(
_helper.buildDartType(
new UnresolvedType(
- buildTypeWithResolvedArguments(null), offset, _uri),
+ buildTypeWithResolvedArguments(
+ const NullabilityBuilder.legacy(), null),
+ fileOffset,
+ _uri),
nonInstanceAccessIsError: true),
token);
}
@@ -2083,13 +2342,12 @@
Expression _makeInvalidWrite(Expression value) {
return _helper.wrapSyntheticExpression(
_helper.throwNoSuchMethodError(
- _forest.createNullLiteral(token),
+ _forest.createNullLiteral(fileOffset),
_plainNameForRead,
- _forest.createArguments(<Expression>[value], null)
- ..fileOffset = value.fileOffset,
- offsetForToken(token),
+ _forest.createArguments(fileOffset, <Expression>[value]),
+ fileOffset,
isSetter: true),
- offsetForToken(token));
+ fileOffset);
}
@override
@@ -2105,7 +2363,7 @@
if (declaration is DeclarationBuilder) {
DeclarationBuilder declaration = this.declaration;
Builder member = declaration.findStaticBuilder(
- name.name, offsetForToken(send.token), _uri, _helper.library);
+ name.name, offsetForToken(send.token), _uri, _helper.libraryBuilder);
Generator generator;
if (member == null) {
@@ -2132,12 +2390,12 @@
setter = member;
} else if (member.isGetter) {
setter = declaration.findStaticBuilder(
- name.name, offsetForToken(token), _uri, _helper.library,
+ name.name, fileOffset, _uri, _helper.libraryBuilder,
isSetter: true);
} else if (member.isField) {
if (member.isFinal || member.isConst) {
setter = declaration.findStaticBuilder(
- name.name, offsetForToken(token), _uri, _helper.library,
+ name.name, fileOffset, _uri, _helper.libraryBuilder,
isSetter: true);
} else {
setter = member;
@@ -2156,9 +2414,32 @@
}
@override
- Expression doInvocation(int offset, Arguments arguments) {
- return _helper.buildConstructorInvocation(declaration, token, token,
- arguments, "", null, token.charOffset, Constness.implicit);
+ doInvocation(int offset, Arguments arguments) {
+ if (declaration.isExtension) {
+ ExtensionBuilder extensionBuilder = declaration;
+ if (arguments.positional.length != 1 || arguments.named.isNotEmpty) {
+ return _helper.buildProblem(messageExplicitExtensionArgumentMismatch,
+ fileOffset, lengthForToken(token));
+ }
+ List<DartType> explicitTypeArguments =
+ getExplicitTypeArguments(arguments);
+ if (explicitTypeArguments != null) {
+ int typeParameterCount = extensionBuilder.typeParameters?.length ?? 0;
+ if (explicitTypeArguments.length != typeParameterCount) {
+ return _helper.buildProblem(
+ templateExplicitExtensionTypeArgumentMismatch.withArguments(
+ extensionBuilder.name, typeParameterCount),
+ fileOffset,
+ lengthForToken(token));
+ }
+ }
+ // TODO(johnniwinther): Check argument and type argument count.
+ return new ExplicitExtensionAccessGenerator(_helper, token, declaration,
+ arguments.positional.single, explicitTypeArguments);
+ } else {
+ return _helper.buildConstructorInvocation(declaration, token, token,
+ arguments, "", null, token.charOffset, Constness.implicit);
+ }
}
}
@@ -2219,7 +2500,7 @@
super._finish(makeLet(value, body), complexAssignment);
@override
- Expression doInvocation(int offset, Arguments arguments) {
+ doInvocation(int offset, Arguments arguments) {
return _helper.buildMethodInvocation(buildSimpleRead(), callName, arguments,
adjustForImplicitCall(_plainNameForRead, offset),
isImplicitCall: true);
@@ -2247,7 +2528,7 @@
Expression buildError(Arguments arguments,
{bool isGetter: false, bool isSetter: false, int offset});
- Name get name => unsupported("name", offsetForToken(token), _uri);
+ Name get name => unsupported("name", fileOffset, _uri);
@override
String get _plainNameForRead => name.name;
@@ -2257,7 +2538,7 @@
@override
Initializer buildFieldInitializer(Map<String, int> initializedFields) {
return _helper.buildInvalidInitializer(_helper.desugarSyntheticExpression(
- buildError(_forest.createArgumentsEmpty(token), isSetter: true)));
+ buildError(_forest.createArgumentsEmpty(fileOffset), isSetter: true)));
}
@override
@@ -2274,7 +2555,7 @@
@override
Expression buildAssignment(Expression value, {bool voidContext: false}) {
- return buildError(_forest.createArguments(<Expression>[value], token),
+ return buildError(_forest.createArguments(fileOffset, <Expression>[value]),
isSetter: true);
}
@@ -2285,7 +2566,7 @@
Procedure interfaceTarget,
bool isPreIncDec: false,
bool isPostIncDec: false}) {
- return buildError(_forest.createArguments(<Expression>[value], token),
+ return buildError(_forest.createArguments(fileOffset, <Expression>[value]),
isGetter: true);
}
@@ -2293,9 +2574,9 @@
Expression buildPrefixIncrement(Name binaryOperator,
{int offset: -1, bool voidContext: false, Procedure interfaceTarget}) {
return buildError(
- _forest.createArguments(<Expression>[
+ _forest.createArguments(fileOffset, <Expression>[
_forest.createIntLiteral(1, null)..fileOffset = offset
- ], token),
+ ]),
isGetter: true)
..fileOffset = offset;
}
@@ -2304,9 +2585,9 @@
Expression buildPostfixIncrement(Name binaryOperator,
{int offset: -1, bool voidContext: false, Procedure interfaceTarget}) {
return buildError(
- _forest.createArguments(<Expression>[
+ _forest.createArguments(fileOffset, <Expression>[
_forest.createIntLiteral(1, null)..fileOffset = offset
- ], token),
+ ]),
isGetter: true)
..fileOffset = offset;
}
@@ -2315,23 +2596,23 @@
Expression buildNullAwareAssignment(
Expression value, DartType type, int offset,
{bool voidContext: false}) {
- return buildError(_forest.createArguments(<Expression>[value], token),
+ return buildError(_forest.createArguments(fileOffset, <Expression>[value]),
isSetter: true);
}
@override
Expression buildSimpleRead() {
- return buildError(_forest.createArgumentsEmpty(token), isGetter: true);
+ return buildError(_forest.createArgumentsEmpty(fileOffset), isGetter: true);
}
@override
Expression _makeInvalidRead() {
- return buildError(_forest.createArgumentsEmpty(token), isGetter: true);
+ return buildError(_forest.createArgumentsEmpty(fileOffset), isGetter: true);
}
@override
Expression _makeInvalidWrite(Expression value) {
- return buildError(_forest.createArguments(<Expression>[value], token),
+ return buildError(_forest.createArguments(fileOffset, <Expression>[value]),
isSetter: true);
}
@@ -2352,7 +2633,7 @@
_helper.desugarSyntheticExpression(buildError(arguments)),
null,
arguments,
- offsetForToken(token));
+ fileOffset);
}
}
@@ -2387,7 +2668,7 @@
@override
Expression buildError(Arguments arguments,
{bool isGetter: false, bool isSetter: false, int offset}) {
- offset ??= offsetForToken(this.token);
+ offset ??= fileOffset;
return _helper.wrapSyntheticExpression(
_helper.throwNoSuchMethodError(
_forest.createNullLiteral(null)..fileOffset = offset,
@@ -2421,8 +2702,8 @@
@override
Expression buildSimpleRead() {
- return buildError(_forest.createArgumentsEmpty(token), isGetter: true)
- ..fileOffset = token.charOffset;
+ return buildError(_forest.createArgumentsEmpty(fileOffset), isGetter: true)
+ ..fileOffset = fileOffset;
}
@override
@@ -2435,7 +2716,7 @@
bool isCompound, Expression value) {
return _helper.wrapUnresolvedVariableAssignment(
_helper.desugarSyntheticExpression(buildError(
- _forest.createArguments(<Expression>[value], token),
+ _forest.createArguments(fileOffset, <Expression>[value]),
isSetter: true)),
isCompound,
value,
@@ -2452,7 +2733,7 @@
UnlinkedGenerator(
ExpressionGeneratorHelper helper, Token token, this.declaration)
- : name = new Name(declaration.name, helper.library.target),
+ : name = new Name(declaration.name, helper.libraryBuilder.library),
receiver = new InvalidExpression(declaration.name)
..fileOffset = offsetForToken(token),
super(helper, token);
@@ -2471,13 +2752,12 @@
@override
Expression buildAssignment(Expression value, {bool voidContext: false}) {
- return new PropertySet(receiver, name, value)
- ..fileOffset = offsetForToken(token);
+ return new PropertySet(receiver, name, value)..fileOffset = fileOffset;
}
@override
Expression buildSimpleRead() {
- return new PropertyGet(receiver, name)..fileOffset = offsetForToken(token);
+ return new PropertyGet(receiver, name)..fileOffset = fileOffset;
}
@override
@@ -2545,7 +2825,7 @@
@override
Expression _makeInvalidWrite(Expression value) {
return _helper.buildProblem(messageIllegalAssignmentToNonAssignable,
- offsetForToken(token), lengthForToken(token));
+ fileOffset, lengthForToken(token));
}
}
@@ -2574,50 +2854,50 @@
Expression handleAssignment(bool voidContext) {
if (_helper.constantContext != ConstantContext.none) {
return _helper.buildProblem(
- messageNotAConstantExpression, offsetForToken(token), token.length);
+ messageNotAConstantExpression, fileOffset, token.length);
}
if (identical("=", assignmentOperator)) {
return generator.buildAssignment(value, voidContext: voidContext);
} else if (identical("+=", assignmentOperator)) {
return generator.buildCompoundAssignment(plusName, value,
- offset: offsetForToken(token), voidContext: voidContext);
+ offset: fileOffset, voidContext: voidContext);
} else if (identical("-=", assignmentOperator)) {
return generator.buildCompoundAssignment(minusName, value,
- offset: offsetForToken(token), voidContext: voidContext);
+ offset: fileOffset, voidContext: voidContext);
} else if (identical("*=", assignmentOperator)) {
return generator.buildCompoundAssignment(multiplyName, value,
- offset: offsetForToken(token), voidContext: voidContext);
+ offset: fileOffset, voidContext: voidContext);
} else if (identical("%=", assignmentOperator)) {
return generator.buildCompoundAssignment(percentName, value,
- offset: offsetForToken(token), voidContext: voidContext);
+ offset: fileOffset, voidContext: voidContext);
} else if (identical("&=", assignmentOperator)) {
return generator.buildCompoundAssignment(ampersandName, value,
- offset: offsetForToken(token), voidContext: voidContext);
+ offset: fileOffset, voidContext: voidContext);
} else if (identical("/=", assignmentOperator)) {
return generator.buildCompoundAssignment(divisionName, value,
- offset: offsetForToken(token), voidContext: voidContext);
+ offset: fileOffset, voidContext: voidContext);
} else if (identical("<<=", assignmentOperator)) {
return generator.buildCompoundAssignment(leftShiftName, value,
- offset: offsetForToken(token), voidContext: voidContext);
+ offset: fileOffset, voidContext: voidContext);
} else if (identical(">>=", assignmentOperator)) {
return generator.buildCompoundAssignment(rightShiftName, value,
- offset: offsetForToken(token), voidContext: voidContext);
+ offset: fileOffset, voidContext: voidContext);
} else if (identical(">>>=", assignmentOperator)) {
return generator.buildCompoundAssignment(tripleShiftName, value,
- offset: offsetForToken(token), voidContext: voidContext);
+ offset: fileOffset, voidContext: voidContext);
} else if (identical("??=", assignmentOperator)) {
return generator.buildNullAwareAssignment(
- value, const DynamicType(), offsetForToken(token),
+ value, const DynamicType(), fileOffset,
voidContext: voidContext);
} else if (identical("^=", assignmentOperator)) {
return generator.buildCompoundAssignment(caretName, value,
- offset: offsetForToken(token), voidContext: voidContext);
+ offset: fileOffset, voidContext: voidContext);
} else if (identical("|=", assignmentOperator)) {
return generator.buildCompoundAssignment(barName, value,
- offset: offsetForToken(token), voidContext: voidContext);
+ offset: fileOffset, voidContext: voidContext);
} else if (identical("~/=", assignmentOperator)) {
return generator.buildCompoundAssignment(mustacheName, value,
- offset: offsetForToken(token), voidContext: voidContext);
+ offset: fileOffset, voidContext: voidContext);
} else {
return unhandled(assignmentOperator, "handleAssignment", token.charOffset,
_helper.uri);
@@ -2631,7 +2911,7 @@
return generator.buildFieldInitializer(initializedFields);
}
return _helper.buildFieldInitializer(false, generator._plainNameForRead,
- offsetForToken(generator.token), offsetForToken(token), value);
+ offsetForToken(generator.token), fileOffset, value);
}
@override
@@ -2658,7 +2938,7 @@
@override
Expression buildSimpleRead() {
return generator.buildPostfixIncrement(binaryOperator,
- offset: offsetForToken(token),
+ offset: fileOffset,
voidContext: false,
interfaceTarget: interfaceTarget);
}
@@ -2666,7 +2946,7 @@
@override
Expression buildForEffect() {
return generator.buildPostfixIncrement(binaryOperator,
- offset: offsetForToken(token),
+ offset: fileOffset,
voidContext: true,
interfaceTarget: interfaceTarget);
}
@@ -2700,7 +2980,7 @@
if (_helper.constantContext != ConstantContext.none && prefix.deferred) {
_helper.addProblem(
templateCantUseDeferredPrefixAsConstant.withArguments(token),
- offsetForToken(token),
+ fileOffset,
lengthForToken(token));
}
Object result = _helper.scopeLookup(prefix.exportScope, name.lexeme, name,
@@ -2711,7 +2991,7 @@
result = new DeferredAccessGenerator(_helper, name, this, result);
}
} else {
- _helper.wrapInDeferredCheck(result, prefix, offsetForToken(token));
+ _helper.wrapInDeferredCheck(result, prefix, fileOffset);
}
}
return result;
@@ -2722,9 +3002,9 @@
int offset, Arguments arguments) {
return _helper.wrapInLocatedProblem(
_helper.evaluateArgumentsBefore(
- arguments, _forest.createNullLiteral(token)),
+ arguments, _forest.createNullLiteral(fileOffset)),
messageCantUsePrefixAsExpression.withLocation(
- _helper.uri, offsetForToken(token), lengthForToken(token)));
+ _helper.uri, fileOffset, lengthForToken(token)));
}
@override
@@ -2735,14 +3015,13 @@
"'${send.name.name}' != ${send.token.lexeme}");
Object result = qualifiedLookup(send.token);
if (send is SendAccessGenerator) {
- result =
- _helper.finishSend(result, send.arguments, offsetForToken(token));
+ result = _helper.finishSend(result, send.arguments, fileOffset);
}
if (isNullAware) {
result = _helper.wrapInLocatedProblem(
_helper.toValue(result),
messageCantUsePrefixWithNullAware.withLocation(
- _helper.uri, offsetForToken(token), lengthForToken(token)));
+ _helper.uri, fileOffset, lengthForToken(token)));
}
return result;
} else {
@@ -2752,8 +3031,8 @@
@override
Expression _makeInvalidRead() {
- return _helper.buildProblem(messageCantUsePrefixAsExpression,
- offsetForToken(token), lengthForToken(token));
+ return _helper.buildProblem(
+ messageCantUsePrefixAsExpression, fileOffset, lengthForToken(token));
}
@override
@@ -2795,20 +3074,25 @@
_forest.createNullLiteral(null)..fileOffset = offset,
_plainNameForRead,
arguments,
- offsetForToken(token)),
- offsetForToken(token));
+ fileOffset),
+ fileOffset);
}
@override
- TypeBuilder buildTypeWithResolvedArguments(List<UnresolvedType> arguments) {
+ TypeBuilder buildTypeWithResolvedArguments(
+ NullabilityBuilder nullabilityBuilder, List<UnresolvedType> arguments) {
Template<Message Function(String, String)> template = isUnresolved
? templateUnresolvedPrefixInTypeAnnotation
: templateNotAPrefixInTypeAnnotation;
- NamedTypeBuilder result = new NamedTypeBuilder(_plainNameForRead, null);
+ NamedTypeBuilder result =
+ new NamedTypeBuilder(_plainNameForRead, nullabilityBuilder, null);
Message message =
template.withArguments(prefixGenerator.token.lexeme, token.lexeme);
- _helper.library.addProblem(message, offsetForToken(prefixGenerator.token),
- lengthOfSpan(prefixGenerator.token, token), _uri);
+ _helper.libraryBuilder.addProblem(
+ message,
+ offsetForToken(prefixGenerator.token),
+ lengthOfSpan(prefixGenerator.token, token),
+ _uri);
result.bind(result.buildInvalidType(message.withLocation(
_uri,
offsetForToken(prefixGenerator.token),
@@ -2840,7 +3124,7 @@
void printOn(StringSink sink) {}
Expression buildProblem() {
- return _helper.buildProblem(message, offsetForToken(token), noLength,
+ return _helper.buildProblem(message, fileOffset, noLength,
suppressMessage: true);
}
@@ -2897,11 +3181,13 @@
return buildProblem();
}
- TypeBuilder buildTypeWithResolvedArguments(List<UnresolvedType> arguments) {
- NamedTypeBuilder result = new NamedTypeBuilder(token.lexeme, null);
- _helper.library.addProblem(message, offsetForToken(token), noLength, _uri);
- result.bind(result.buildInvalidType(
- message.withLocation(_uri, offsetForToken(token), noLength)));
+ TypeBuilder buildTypeWithResolvedArguments(
+ NullabilityBuilder nullabilityBuilder, List<UnresolvedType> arguments) {
+ NamedTypeBuilder result =
+ new NamedTypeBuilder(token.lexeme, nullabilityBuilder, null);
+ _helper.libraryBuilder.addProblem(message, fileOffset, noLength, _uri);
+ result.bind(result
+ .buildInvalidType(message.withLocation(_uri, fileOffset, noLength)));
return result;
}
@@ -2974,8 +3260,8 @@
: super(helper, token);
String get _plainNameForRead {
- return unsupported("${isSuper ? 'super' : 'this'}.plainNameForRead",
- offsetForToken(token), _uri);
+ return unsupported(
+ "${isSuper ? 'super' : 'this'}.plainNameForRead", fileOffset, _uri);
}
String get _debugName => "ThisAccessGenerator";
@@ -2988,8 +3274,8 @@
return _forest.createThisExpression(token);
}
} else {
- return _helper.buildProblem(messageSuperAsExpression,
- offsetForToken(token), lengthForToken(token));
+ return _helper.buildProblem(
+ messageSuperAsExpression, fileOffset, lengthForToken(token));
}
}
@@ -2997,7 +3283,7 @@
String keyword = isSuper ? "super" : "this";
return _helper.buildProblem(
templateThisOrSuperAccessInFieldInitializer.withArguments(keyword),
- offsetForToken(token),
+ fileOffset,
keyword.length);
}
@@ -3083,7 +3369,7 @@
? templateSuperclassHasNoConstructor
: templateConstructorNotFound)
.withArguments(fullName)
- .withLocation(_uri, offsetForToken(token), lengthForToken(token));
+ .withLocation(_uri, fileOffset, lengthForToken(token));
}
if (message != null) {
return _helper.buildInvalidInitializer(_helper.wrapSyntheticExpression(
@@ -3141,7 +3427,7 @@
Expression buildAssignmentError() {
return _helper.desugarSyntheticExpression(_helper.buildProblem(
isSuper ? messageCannotAssignToSuper : messageNotAnLvalue,
- offsetForToken(token),
+ fileOffset,
token.length));
}
@@ -3183,7 +3469,7 @@
{bool isGetter: false, bool isSetter: false, int offset}) {
int length = noLength;
if (offset == null) {
- offset = offsetForToken(token);
+ offset = fileOffset;
length = lengthForToken(token);
}
return _helper.buildProblem(message, offset, length);
@@ -3194,8 +3480,8 @@
@override
Expression buildSimpleRead() {
- return buildError(_forest.createArgumentsEmpty(token), isGetter: true)
- ..fileOffset = offsetForToken(token);
+ return buildError(_forest.createArgumentsEmpty(fileOffset), isGetter: true)
+ ..fileOffset = fileOffset;
}
@override
@@ -3224,11 +3510,11 @@
String get _debugName => "SendAccessGenerator";
Expression buildSimpleRead() {
- return unsupported("buildSimpleRead", offsetForToken(token), _uri);
+ return unsupported("buildSimpleRead", fileOffset, _uri);
}
Expression buildAssignment(Expression value, {bool voidContext: false}) {
- return unsupported("buildAssignment", offsetForToken(token), _uri);
+ return unsupported("buildAssignment", fileOffset, _uri);
}
withReceiver(Object receiver, int operatorOffset, {bool isNullAware: false}) {
@@ -3236,7 +3522,7 @@
return receiver.buildPropertyAccess(this, operatorOffset, isNullAware);
}
return _helper.buildMethodInvocation(
- _helper.toValue(receiver), name, arguments, offsetForToken(token),
+ _helper.toValue(receiver), name, arguments, fileOffset,
isNullAware: isNullAware);
}
@@ -3252,24 +3538,21 @@
Procedure interfaceTarget,
bool isPreIncDec: false,
bool isPostIncDec: false}) {
- return unsupported(
- "buildCompoundAssignment", offset ?? offsetForToken(token), _uri);
+ return unsupported("buildCompoundAssignment", offset ?? fileOffset, _uri);
}
Expression buildPrefixIncrement(Name binaryOperator,
{int offset: TreeNode.noOffset,
bool voidContext: false,
Procedure interfaceTarget}) {
- return unsupported(
- "buildPrefixIncrement", offset ?? offsetForToken(token), _uri);
+ return unsupported("buildPrefixIncrement", offset ?? fileOffset, _uri);
}
Expression buildPostfixIncrement(Name binaryOperator,
{int offset: TreeNode.noOffset,
bool voidContext: false,
Procedure interfaceTarget}) {
- return unsupported(
- "buildPostfixIncrement", offset ?? offsetForToken(token), _uri);
+ return unsupported("buildPostfixIncrement", offset ?? fileOffset, _uri);
}
Expression doInvocation(int offset, Arguments arguments) {
@@ -3303,11 +3586,11 @@
String get _debugName => "IncompletePropertyAccessGenerator";
Expression buildSimpleRead() {
- return unsupported("buildSimpleRead", offsetForToken(token), _uri);
+ return unsupported("buildSimpleRead", fileOffset, _uri);
}
Expression buildAssignment(Expression value, {bool voidContext: false}) {
- return unsupported("buildAssignment", offsetForToken(token), _uri);
+ return unsupported("buildAssignment", fileOffset, _uri);
}
withReceiver(Object receiver, int operatorOffset, {bool isNullAware: false}) {
@@ -3330,24 +3613,21 @@
Procedure interfaceTarget,
bool isPreIncDec: false,
bool isPostIncDec: false}) {
- return unsupported(
- "buildCompoundAssignment", offset ?? offsetForToken(token), _uri);
+ return unsupported("buildCompoundAssignment", offset ?? fileOffset, _uri);
}
Expression buildPrefixIncrement(Name binaryOperator,
{int offset: TreeNode.noOffset,
bool voidContext: false,
Procedure interfaceTarget}) {
- return unsupported(
- "buildPrefixIncrement", offset ?? offsetForToken(token), _uri);
+ return unsupported("buildPrefixIncrement", offset ?? fileOffset, _uri);
}
Expression buildPostfixIncrement(Name binaryOperator,
{int offset: TreeNode.noOffset,
bool voidContext: false,
Procedure interfaceTarget}) {
- return unsupported(
- "buildPostfixIncrement", offset ?? offsetForToken(token), _uri);
+ return unsupported("buildPostfixIncrement", offset ?? fileOffset, _uri);
}
Expression doInvocation(int offset, Arguments arguments) {
@@ -3371,17 +3651,17 @@
@override
ComplexAssignmentJudgment startComplexAssignment(Expression rhs) {
return SyntheticWrapper.wrapIllegalAssignment(rhs,
- assignmentOffset: offsetForToken(token));
+ assignmentOffset: fileOffset);
}
Expression _makeInvalidWrite(Expression value) {
return _helper.wrapInvalidWrite(
_helper.desugarSyntheticExpression(_helper.buildProblem(
messageCannotAssignToParenthesizedExpression,
- offsetForToken(token),
+ fileOffset,
lengthForToken(token))),
expression,
- offsetForToken(token));
+ fileOffset);
}
}
@@ -3393,11 +3673,8 @@
Expression makeBinary(Expression left, Name operator, Procedure interfaceTarget,
Expression right, ExpressionGeneratorHelper helper,
{int offset: TreeNode.noOffset}) {
- return new MethodInvocationJudgment(
- left,
- operator,
- helper.forest.createArguments(<Expression>[right], null)
- ..fileOffset = offset,
+ return new MethodInvocationJudgment(left, operator,
+ helper.forest.createArguments(offset, <Expression>[right]),
interfaceTarget: interfaceTarget)
..fileOffset = offset;
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart b/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart
index 3beeb4f..c847440 100644
--- a/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart
@@ -43,7 +43,7 @@
show PrefixBuilder, LibraryBuilder, TypeDeclarationBuilder;
abstract class ExpressionGeneratorHelper implements InferenceHelper {
- LibraryBuilder get library;
+ LibraryBuilder get libraryBuilder;
TypePromoter get typePromoter;
@@ -83,6 +83,9 @@
Expression buildStaticInvocation(Procedure target, Arguments arguments,
{Constness constness, int charOffset});
+ Expression buildExtensionMethodInvocation(
+ int fileOffset, Procedure target, Arguments arguments);
+
Expression throwNoSuchMethodError(
Expression receiver, String name, Arguments arguments, int offset,
{Member candidate,
@@ -164,37 +167,4 @@
/// Creates a [VariableGet] of the [variable] using [charOffset] as the file
/// offset of the created node.
Expression createVariableGet(VariableDeclaration variable, int charOffset);
-
- /// Creates a tear off of the extension instance method [procedure].
- ///
- /// The tear off is created as a function expression that captures the
- /// current `this` value from [extensionThis] and [extensionTypeParameters]
- /// synthetically copied to the extension instance method.
- ///
- /// For instance the declaration of `B.m`:
- ///
- /// class A<X, Y> {}
- /// class B<S, T> on A<S, T> {
- /// void m<U>(U u) {}
- /// }
- ///
- /// is converted into this top level method:
- ///
- /// void B<S,T>|m<U>(A<S, T> #this, U u) {}
- ///
- /// and a tear off
- ///
- /// A<X, Y> a = ...;
- /// var f = a.m;
- ///
- /// is converted into:
- ///
- /// A<int, String> a = ...;
- /// var f = <#U>(#U u) => B<S,T>|m<int,String,#U>(a, u);
- ///
- Expression createExtensionTearOff(
- Procedure procedure,
- VariableDeclaration extensionThis,
- List<TypeParameter> extensionTypeParameters,
- Token token);
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/forest.dart b/pkg/front_end/lib/src/fasta/kernel/forest.dart
index 34cbd35..f63bfbc 100644
--- a/pkg/front_end/lib/src/fasta/kernel/forest.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/forest.dart
@@ -8,6 +8,8 @@
import 'package:kernel/ast.dart';
+import '../names.dart';
+
import '../parser.dart' show offsetForToken, optional;
import '../problems.dart' show unsupported;
@@ -42,6 +44,7 @@
ListLiteralJudgment,
LoadLibraryJudgment,
MapLiteralJudgment,
+ MethodInvocationJudgment,
ReturnJudgment,
SetLiteralJudgment,
ShadowLargeIntLiteral,
@@ -58,14 +61,32 @@
class Forest {
const Forest();
- Arguments createArguments(List<Expression> positional, Token token,
+ Arguments createArguments(int fileOffset, List<Expression> positional,
{List<DartType> types, List<NamedExpression> named}) {
return new ArgumentsJudgment(positional, types: types, named: named)
- ..fileOffset = offsetForToken(token);
+ ..fileOffset = fileOffset ?? TreeNode.noOffset;
}
- Arguments createArgumentsEmpty(Token token) {
- return createArguments(<Expression>[], token);
+ Arguments createArgumentsForExtensionMethod(
+ int fileOffset,
+ int extensionTypeParameterCount,
+ int typeParameterCount,
+ Expression receiver,
+ {List<DartType> extensionTypeArguments = const <DartType>[],
+ List<DartType> typeArguments = const <DartType>[],
+ List<Expression> positionalArguments = const <Expression>[],
+ List<NamedExpression> namedArguments = const <NamedExpression>[]}) {
+ return new ArgumentsJudgment.forExtensionMethod(
+ extensionTypeParameterCount, typeParameterCount, receiver,
+ extensionTypeArguments: extensionTypeArguments,
+ typeArguments: typeArguments,
+ positionalArguments: positionalArguments,
+ namedArguments: namedArguments)
+ ..fileOffset = fileOffset ?? TreeNode.noOffset;
+ }
+
+ Arguments createArgumentsEmpty(int fileOffset) {
+ return createArguments(fileOffset, <Expression>[]);
}
List<NamedExpression> argumentsNamed(Arguments arguments) {
@@ -190,9 +211,9 @@
..fileOffset = offsetForToken(constKeyword ?? leftBrace);
}
- /// Return a representation of a null literal at the given [location].
- NullLiteral createNullLiteral(Token token) {
- return new NullLiteral()..fileOffset = offsetForToken(token);
+ /// Return a representation of a null literal at the given [fileOffset].
+ NullLiteral createNullLiteral(int fileOffset) {
+ return new NullLiteral()..fileOffset = fileOffset ?? TreeNode.noOffset;
}
/// Return a representation of a simple string literal at the given
@@ -495,10 +516,10 @@
}
/// Return a representation of a return statement.
- Statement createReturnStatement(
- Token returnKeyword, Expression expression, int charOffset) {
- return new ReturnJudgment(returnKeyword?.lexeme, expression)
- ..fileOffset = charOffset;
+ Statement createReturnStatement(int fileOffset, Expression expression,
+ {bool isArrow: true}) {
+ return new ReturnJudgment(isArrow, expression)
+ ..fileOffset = fileOffset ?? TreeNode.noOffset;
}
Expression createStringConcatenation(
@@ -637,7 +658,7 @@
bool isFieldFormal: false,
bool isCovariant: false,
bool isLocalFunction: false}) {
- return VariableDeclarationJudgment(name, functionNestingLevel,
+ return new VariableDeclarationJudgment(name, functionNestingLevel,
type: type,
initializer: initializer,
isFinal: isFinal,
@@ -647,6 +668,18 @@
isLocalFunction: isLocalFunction);
}
+ VariableDeclaration createVariableDeclarationForValue(
+ int fileOffset, Expression initializer,
+ {DartType type = const DynamicType()}) {
+ return new VariableDeclarationJudgment.forValue(initializer)
+ ..type = type
+ ..fileOffset = fileOffset ?? TreeNode.noOffset;
+ }
+
+ Let createLet(VariableDeclaration variable, Expression body) {
+ return new Let(variable, body);
+ }
+
FunctionNode createFunctionNode(Statement body,
{List<TypeParameter> typeParameters,
List<VariableDeclaration> positionalParameters,
@@ -674,13 +707,26 @@
}
FunctionExpression createFunctionExpression(
- FunctionNode function, int fileOffset) {
- return new FunctionExpression(function)..fileOffset = fileOffset;
+ int fileOffset, FunctionNode function) {
+ return new FunctionExpression(function)
+ ..fileOffset = fileOffset ?? TreeNode.noOffset;
+ }
+
+ MethodInvocation createFunctionInvocation(
+ int fileOffset, Expression expression, Arguments arguments) {
+ return new MethodInvocationJudgment(expression, callName, arguments)
+ ..fileOffset = fileOffset ?? TreeNode.noOffset;
}
NamedExpression createNamedExpression(String name, Expression expression) {
return new NamedExpression(name, expression);
}
+
+ StaticInvocation createStaticInvocation(
+ int fileOffset, Procedure procedure, Arguments arguments) {
+ return new StaticInvocation(procedure, arguments)
+ ..fileOffset = fileOffset ?? TreeNode.noOffset;
+ }
}
class _VariablesDeclaration extends Statement {
@@ -691,19 +737,19 @@
setParents(declarations, this);
}
- accept(v) {
- unsupported("accept", fileOffset, uri);
+ R accept<R>(v) {
+ throw unsupported("accept", fileOffset, uri);
}
- accept1(v, arg) {
- unsupported("accept1", fileOffset, uri);
+ R accept1<R, A>(v, arg) {
+ throw unsupported("accept1", fileOffset, uri);
}
visitChildren(v) {
- unsupported("visitChildren", fileOffset, uri);
+ throw unsupported("visitChildren", fileOffset, uri);
}
transformChildren(v) {
- unsupported("transformChildren", fileOffset, uri);
+ throw unsupported("transformChildren", fileOffset, uri);
}
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart b/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart
index 1074242..3c7ea2e 100644
--- a/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart
@@ -23,12 +23,12 @@
ImplicitFieldType(this.member, this.initializerToken);
- accept(DartTypeVisitor<Object> v) {
- unsupported("accept", member.charOffset, member.fileUri);
+ R accept<R>(DartTypeVisitor<R> v) {
+ throw unsupported("accept", member.charOffset, member.fileUri);
}
- accept1(DartTypeVisitor1<Object, Object> v, arg) {
- unsupported("accept1", member.charOffset, member.fileUri);
+ R accept1<R, A>(DartTypeVisitor1<R, A> v, arg) {
+ throw unsupported("accept1", member.charOffset, member.fileUri);
}
visitChildren(Visitor<Object> v) {
diff --git a/pkg/front_end/lib/src/fasta/kernel/implicit_type_argument.dart b/pkg/front_end/lib/src/fasta/kernel/implicit_type_argument.dart
index 2a35783..6cb9d18 100644
--- a/pkg/front_end/lib/src/fasta/kernel/implicit_type_argument.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/implicit_type_argument.dart
@@ -21,13 +21,13 @@
get nullability => unsupported("nullability", -1, null);
@override
- accept(DartTypeVisitor<Object> v) {
- unhandled("$runtimeType", "${v.runtimeType}", -1, null);
+ R accept<R>(DartTypeVisitor<R> v) {
+ throw unhandled("$runtimeType", "${v.runtimeType}", -1, null);
}
@override
- accept1(DartTypeVisitor1<Object, Object> v, arg) {
- unhandled("$runtimeType", "${v.runtimeType}", -1, null);
+ R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) {
+ throw unhandled("$runtimeType", "${v.runtimeType}", -1, null);
}
@override
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 dcfc73d..0f0236a 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -4,7 +4,8 @@
part of "kernel_shadow_ast.dart";
-class InferenceVisitor extends BodyVisitor1<void, DartType> {
+class InferenceVisitor
+ extends BodyVisitor1<ExpressionInferenceResult, DartType> {
final ShadowTypeInferrer inferrer;
Class mapEntryClass;
@@ -24,31 +25,42 @@
InferenceVisitor(this.inferrer);
@override
- void defaultExpression(Expression node, DartType typeContext) {
+ ExpressionInferenceResult defaultExpression(
+ Expression node, DartType typeContext) {
unhandled("${node.runtimeType}", "InferenceVisitor", node.fileOffset,
inferrer.helper.uri);
+ return const ExpressionInferenceResult(const InvalidType());
}
@override
- void defaultStatement(Statement node, _) {
+ ExpressionInferenceResult defaultStatement(Statement node, _) {
unhandled("${node.runtimeType}", "InferenceVisitor", node.fileOffset,
inferrer.helper.uri);
+ return const ExpressionInferenceResult(const InvalidType());
}
@override
- void visitInvalidExpression(InvalidExpression node, DartType typeContext) {}
+ ExpressionInferenceResult visitInvalidExpression(
+ InvalidExpression node, DartType typeContext) =>
+ const ExpressionInferenceResult(const BottomType());
@override
- void visitIntLiteral(IntLiteral node, DartType typeContext) {}
+ ExpressionInferenceResult visitIntLiteral(
+ IntLiteral node, DartType typeContext) =>
+ new ExpressionInferenceResult(inferrer.coreTypes.intClass.rawType);
@override
- void visitDoubleLiteral(DoubleLiteral node, DartType typeContext) {}
+ ExpressionInferenceResult visitDoubleLiteral(
+ DoubleLiteral node, DartType typeContext) =>
+ new ExpressionInferenceResult(inferrer.coreTypes.doubleClass.rawType);
@override
- void visitAsExpression(AsExpression node, DartType typeContext) {
+ ExpressionInferenceResult visitAsExpression(
+ AsExpression node, DartType typeContext) {
inferrer.inferExpression(
node.operand, const UnknownType(), !inferrer.isTopLevel,
isVoidAllowed: true);
+ return new ExpressionInferenceResult(node.type);
}
void visitAssertInitializerJudgment(AssertInitializerJudgment node) {
@@ -73,16 +85,17 @@
}
@override
- void visitAwaitExpression(AwaitExpression node, DartType typeContext) {
+ ExpressionInferenceResult visitAwaitExpression(
+ AwaitExpression node, DartType typeContext) {
if (!inferrer.typeSchemaEnvironment.isEmptyContext(typeContext)) {
typeContext = inferrer.wrapFutureOrType(typeContext);
}
Expression operand = node.operand;
inferrer.inferExpression(operand, typeContext, true, isVoidAllowed: true);
- inferrer.storeInferredType(
- node,
- inferrer.typeSchemaEnvironment
- .unfutureType(getInferredType(operand, inferrer)));
+ DartType inferredType = inferrer.typeSchemaEnvironment
+ .unfutureType(getInferredType(operand, inferrer));
+ inferrer.storeInferredType(node, inferredType);
+ return new ExpressionInferenceResult(inferredType);
}
void visitBlockJudgment(BlockJudgment node) {
@@ -92,27 +105,31 @@
}
@override
- void visitBoolLiteral(BoolLiteral node, DartType typeContext) {}
+ ExpressionInferenceResult visitBoolLiteral(
+ BoolLiteral node, DartType typeContext) =>
+ new ExpressionInferenceResult(inferrer.coreTypes.boolClass.rawType);
@override
- void visitBreakStatement(BreakStatement node, _) {
+ Null visitBreakStatement(BreakStatement node, _) {
// No inference needs to be done.
}
- void visitCascadeJudgment(CascadeJudgment node, DartType typeContext) {
- node.inferredType =
+ ExpressionInferenceResult visitCascadeJudgment(
+ CascadeJudgment node, DartType typeContext) {
+ ExpressionInferenceResult result =
inferrer.inferExpression(node.targetJudgment, typeContext, true);
+ node.inferredType = result.inferredType;
node.variable.type = getInferredType(node, inferrer);
for (Expression judgment in node.cascadeJudgments) {
inferrer.inferExpression(
judgment, const UnknownType(), !inferrer.isTopLevel,
isVoidAllowed: true);
}
- return null;
+ return new ExpressionInferenceResult(node.inferredType);
}
@override
- void visitConditionalExpression(
+ ExpressionInferenceResult visitConditionalExpression(
ConditionalExpression node, DartType typeContext) {
Expression condition = node.condition;
Expression then = node.then;
@@ -130,10 +147,11 @@
.getStandardUpperBound(getInferredType(then, inferrer),
getInferredType(otherwise, inferrer));
node.staticType = inferredType;
+ return new ExpressionInferenceResult(inferredType);
}
@override
- void visitConstructorInvocation(
+ ExpressionInferenceResult visitConstructorInvocation(
ConstructorInvocation node, DartType typeContext) {
LibraryBuilder library = inferrer.engine.beingInferred[node.target];
if (library != null) {
@@ -175,14 +193,14 @@
}
bool hasExplicitTypeArguments =
getExplicitTypeArguments(node.arguments) != null;
- ExpressionInferenceResult inferenceResult = inferrer.inferInvocation(
+ DartType inferredType = inferrer.inferInvocation(
typeContext,
node.fileOffset,
node.target.function.functionType,
computeConstructorReturnType(node.target),
node.arguments,
isConst: node.isConst);
- inferrer.storeInferredType(node, inferenceResult.type);
+ inferrer.storeInferredType(node, inferredType);
if (!inferrer.isTopLevel) {
SourceLibraryBuilder library = inferrer.library;
if (!hasExplicitTypeArguments) {
@@ -191,19 +209,22 @@
inferred: true);
}
}
+ return new ExpressionInferenceResult(inferredType);
}
void visitContinueSwitchJudgment(ContinueSwitchJudgment node) {
// No inference needs to be done.
}
- void visitDeferredCheckJudgment(
+
+ ExpressionInferenceResult visitDeferredCheckJudgment(
DeferredCheckJudgment node, DartType typeContext) {
// Since the variable is not used in the body we don't need to type infer
// it. We can just type infer the body.
- Expression judgment = node.judgment;
- inferrer.inferExpression(judgment, typeContext, true, isVoidAllowed: true);
- node.inferredType = getInferredType(judgment, inferrer);
- return null;
+ ExpressionInferenceResult result = inferrer.inferExpression(
+ node.expression, typeContext, true,
+ isVoidAllowed: true);
+ node.inferredType = result.inferredType;
+ return new ExpressionInferenceResult(result.inferredType);
}
void visitDoJudgment(DoJudgment node) {
@@ -218,32 +239,34 @@
node.condition.fileOffset);
}
- void visitDoubleJudgment(DoubleJudgment node, DartType typeContext) {
- node.inferredType = inferrer.coreTypes.doubleClass.rawType;
- return null;
+ ExpressionInferenceResult visitDoubleJudgment(
+ DoubleJudgment node, DartType typeContext) {
+ return new ExpressionInferenceResult(
+ node.inferredType = inferrer.coreTypes.doubleClass.rawType);
}
void visitEmptyStatementJudgment(EmptyStatementJudgment node) {
// No inference needs to be done.
}
+
void visitExpressionStatementJudgment(ExpressionStatementJudgment node) {
inferrer.inferExpression(
node.judgment, const UnknownType(), !inferrer.isTopLevel,
isVoidAllowed: true);
}
- void visitFactoryConstructorInvocationJudgment(
+ ExpressionInferenceResult visitFactoryConstructorInvocationJudgment(
FactoryConstructorInvocationJudgment node, DartType typeContext) {
bool hadExplicitTypeArguments =
getExplicitTypeArguments(node.arguments) != null;
- ExpressionInferenceResult inferenceResult = inferrer.inferInvocation(
+ DartType inferredType = inferrer.inferInvocation(
typeContext,
node.fileOffset,
node.target.function.functionType,
computeConstructorReturnType(node.target),
node.argumentJudgments,
isConst: node.isConst);
- node.inferredType = inferenceResult.type;
+ node.inferredType = inferredType;
if (!inferrer.isTopLevel) {
SourceLibraryBuilder library = inferrer.library;
if (!hadExplicitTypeArguments) {
@@ -252,12 +275,13 @@
inferred: true);
}
}
- return null;
+ return new ExpressionInferenceResult(inferredType);
}
void visitShadowFieldInitializer(ShadowFieldInitializer node) {
- DartType initializerType =
+ ExpressionInferenceResult initializerResult =
inferrer.inferExpression(node.value, node.field.type, true);
+ DartType initializerType = initializerResult.inferredType;
inferrer.ensureAssignable(
node.field.type, initializerType, node.value, node.fileOffset);
}
@@ -360,10 +384,10 @@
} else if (syntheticAssignment is PropertySet ||
syntheticAssignment is SuperPropertySet) {
DartType receiverType = inferrer.thisType;
- Object writeMember =
+ ObjectAccessTarget writeTarget =
inferrer.findPropertySetMember(receiverType, syntheticAssignment);
syntheticWriteType =
- elementType = inferrer.getSetterType(writeMember, receiverType);
+ elementType = inferrer.getSetterType(writeTarget, receiverType);
if (syntheticAssignment is PropertySet) {
rhs = syntheticAssignment.value;
} else if (syntheticAssignment is SuperPropertySet) {
@@ -403,7 +427,7 @@
}
@override
- void visitForInStatement(ForInStatement node, _) {
+ Null visitForInStatement(ForInStatement node, _) {
if (node.variable.name == null) {
handleForInWithoutVariable(node.variable, node.iterable, node.body,
isAsync: node.isAsync);
@@ -419,9 +443,10 @@
if (variable.name == null) {
Expression initializer = variable.initializer;
if (initializer != null) {
- variable.type = inferrer.inferExpression(
+ ExpressionInferenceResult result = inferrer.inferExpression(
initializer, const UnknownType(), true,
isVoidAllowed: true);
+ variable.type = result.inferredType;
}
} else {
inferrer.inferStatement(variable);
@@ -445,7 +470,7 @@
inferrer.inferStatement(node.body);
}
- ExpressionInferenceResult visitFunctionNodeJudgment(
+ DartType visitFunctionNodeJudgment(
FunctionNodeJudgment node,
DartType typeContext,
DartType returnContext,
@@ -458,16 +483,18 @@
inferrer.inferMetadataKeepingHelper(node.variable.annotations);
DartType returnContext =
node._hasImplicitReturnType ? null : node.function.returnType;
- ExpressionInferenceResult inferenceResult = visitFunctionNodeJudgment(
+ DartType inferredType = visitFunctionNodeJudgment(
node.functionJudgment, null, returnContext, node.fileOffset);
- node.variable.type = inferenceResult.type;
+ node.variable.type = inferredType;
}
@override
- void visitFunctionExpression(FunctionExpression node, DartType typeContext) {
- ExpressionInferenceResult inferenceResult = visitFunctionNodeJudgment(
+ ExpressionInferenceResult visitFunctionExpression(
+ FunctionExpression node, DartType typeContext) {
+ DartType inferredType = visitFunctionNodeJudgment(
node.function, typeContext, null, node.fileOffset);
- inferrer.storeInferredType(node, inferenceResult.type);
+ inferrer.storeInferredType(node, inferredType);
+ return new ExpressionInferenceResult(inferredType);
}
void visitInvalidSuperInitializerJudgment(
@@ -485,7 +512,8 @@
skipTypeArgumentInference: true);
}
- void visitIfNullJudgment(IfNullJudgment node, DartType typeContext) {
+ ExpressionInferenceResult visitIfNullJudgment(
+ IfNullJudgment node, DartType typeContext) {
Expression leftJudgment = node.leftJudgment;
Expression rightJudgment = node.rightJudgment;
// To infer `e0 ?? e1` in context K:
@@ -509,7 +537,7 @@
node.inferredType =
inferrer.typeSchemaEnvironment.getStandardUpperBound(lhsType, rhsType);
node.body.staticType = getInferredType(node, inferrer);
- return null;
+ return new ExpressionInferenceResult(node.inferredType);
}
void visitIfJudgment(IfJudgment node) {
@@ -528,7 +556,7 @@
}
}
- void visitIllegalAssignmentJudgment(
+ ExpressionInferenceResult visitIllegalAssignmentJudgment(
IllegalAssignmentJudgment node, DartType typeContext) {
if (node.write != null) {
inferrer.inferExpression(
@@ -538,46 +566,49 @@
node.rhs, const UnknownType(), !inferrer.isTopLevel);
node._replaceWithDesugared();
node.inferredType = const DynamicType();
- return null;
+ return const ExpressionInferenceResult(const DynamicType());
}
- void visitIndexAssignmentJudgment(
+ ExpressionInferenceResult visitIndexAssignmentJudgment(
IndexAssignmentJudgment node, DartType typeContext) {
DartType receiverType = node._inferReceiver(inferrer);
- Object writeMember =
+ ObjectAccessTarget writeTarget =
inferrer.findMethodInvocationMember(receiverType, node.write);
// To replicate analyzer behavior, we base type inference on the write
// member. TODO(paulberry): would it be better to use the read member
// when doing compound assignment?
- FunctionType calleeType = inferrer.getCalleeFunctionType(
- inferrer.getCalleeType(writeMember, receiverType), false);
- DartType expectedIndexTypeForWrite;
DartType indexContext = const UnknownType();
- DartType writeContext = const UnknownType();
- if (calleeType.positionalParameters.length >= 2) {
- // TODO(paulberry): we ought to get a context for the index expression
- // from the index formal parameter, but analyzer doesn't so for now we
- // replicate its behavior.
- expectedIndexTypeForWrite = calleeType.positionalParameters[0];
- writeContext = calleeType.positionalParameters[1];
- }
- inferrer.inferExpression(node.index, indexContext, true);
- DartType indexType = getInferredType(node.index, inferrer);
+ DartType expectedIndexTypeForWrite =
+ inferrer.getIndexSetKeyType(writeTarget, receiverType);
+ DartType writeContext =
+ inferrer.getIndexSetValueType(writeTarget, receiverType);
+ ExpressionInferenceResult indexResult =
+ inferrer.inferExpression(node.index, indexContext, true);
+ DartType indexType = indexResult.inferredType;
node._storeLetType(inferrer, node.index, indexType);
- if (writeContext is! UnknownType) {
- inferrer.ensureAssignable(
- expectedIndexTypeForWrite,
- indexType,
- node._getInvocationArguments(inferrer, node.write).positional[0],
- node.write.fileOffset);
+ if (indexResult.replacement != null) {
+ node.index = indexResult.replacement;
}
+ Expression writeIndexExpression =
+ node._getInvocationArguments(inferrer, node.write).positional[0];
+ if (writeTarget.isExtensionMember) {
+ MethodInvocation write = node.write;
+ Expression replacement = inferrer.transformExtensionMethodInvocation(
+ writeTarget, write, write.receiver, write.arguments);
+ node.write = replacement;
+ }
+ if (writeContext is! UnknownType) {
+ inferrer.ensureAssignable(expectedIndexTypeForWrite, indexType,
+ writeIndexExpression, node.write.fileOffset);
+ }
+
InvocationExpression read = node.read;
DartType readType;
if (read != null) {
- Object readMember = inferrer
+ ObjectAccessTarget readMember = inferrer
.findMethodInvocationMember(receiverType, read, instrumented: false);
- FunctionType calleeFunctionType = inferrer.getCalleeFunctionType(
- inferrer.getCalleeType(readMember, receiverType), false);
+ FunctionType calleeFunctionType =
+ inferrer.getFunctionType(readMember, receiverType, false);
inferrer.ensureAssignable(
getPositionalParameterType(calleeFunctionType, 0),
indexType,
@@ -599,19 +630,21 @@
read.fileOffset);
node._storeLetType(inferrer, replacedRead, readType);
}
- node._inferRhs(inferrer, readType, writeContext);
+ DartType inferredType =
+ node._inferRhs(inferrer, readType, writeContext).inferredType;
node._replaceWithDesugared();
- return null;
+ return new ExpressionInferenceResult(inferredType);
}
- void visitIntJudgment(IntJudgment node, DartType typeContext) {
+ ExpressionInferenceResult visitIntJudgment(
+ IntJudgment node, DartType typeContext) {
if (inferrer.isDoubleContext(typeContext)) {
double doubleValue = node.asDouble();
if (doubleValue != null) {
node.parent.replaceChild(
- node, DoubleLiteral(doubleValue)..fileOffset = node.fileOffset);
+ node, new DoubleLiteral(doubleValue)..fileOffset = node.fileOffset);
node.inferredType = inferrer.coreTypes.doubleClass.rawType;
- return null;
+ return new ExpressionInferenceResult(node.inferredType);
}
}
Expression error = checkWebIntLiteralsErrorIfUnexact(
@@ -619,21 +652,21 @@
if (error != null) {
node.parent.replaceChild(node, error);
node.inferredType = const BottomType();
- return null;
+ return const ExpressionInferenceResult(const BottomType());
}
node.inferredType = inferrer.coreTypes.intClass.rawType;
- return null;
+ return new ExpressionInferenceResult(node.inferredType);
}
- void visitShadowLargeIntLiteral(
+ ExpressionInferenceResult visitShadowLargeIntLiteral(
ShadowLargeIntLiteral node, DartType typeContext) {
if (inferrer.isDoubleContext(typeContext)) {
double doubleValue = node.asDouble();
if (doubleValue != null) {
node.parent.replaceChild(
- node, DoubleLiteral(doubleValue)..fileOffset = node.fileOffset);
+ node, new DoubleLiteral(doubleValue)..fileOffset = node.fileOffset);
node.inferredType = inferrer.coreTypes.doubleClass.rawType;
- return null;
+ return new ExpressionInferenceResult(node.inferredType);
}
}
@@ -646,19 +679,19 @@
node.literal.length));
node.parent.replaceChild(node, replacement);
node.inferredType = const BottomType();
- return null;
+ return const ExpressionInferenceResult(const BottomType());
}
Expression error = checkWebIntLiteralsErrorIfUnexact(
inferrer, intValue, node.literal, node.fileOffset);
if (error != null) {
node.parent.replaceChild(node, error);
node.inferredType = const BottomType();
- return null;
+ return const ExpressionInferenceResult(const BottomType());
}
- node.parent
- .replaceChild(node, IntLiteral(intValue)..fileOffset = node.fileOffset);
+ node.parent.replaceChild(
+ node, new IntLiteral(intValue)..fileOffset = node.fileOffset);
node.inferredType = inferrer.coreTypes.intClass.rawType;
- return null;
+ return new ExpressionInferenceResult(node.inferredType);
}
void visitShadowInvalidInitializer(ShadowInvalidInitializer node) {
@@ -671,13 +704,15 @@
}
@override
- void visitIsExpression(IsExpression node, DartType typeContext) {
+ ExpressionInferenceResult visitIsExpression(
+ IsExpression node, DartType typeContext) {
inferrer.inferExpression(
node.operand, const UnknownType(), !inferrer.isTopLevel);
+ return new ExpressionInferenceResult(inferrer.coreTypes.boolClass.rawType);
}
@override
- void visitLabeledStatement(LabeledStatement node, _) {
+ Null visitLabeledStatement(LabeledStatement node, _) {
inferrer.inferStatement(node.body);
}
@@ -703,12 +738,13 @@
bool inferenceNeeded,
bool typeChecksNeeded) {
if (element is SpreadElement) {
- DartType spreadType = inferrer.inferExpression(
+ ExpressionInferenceResult spreadResult = inferrer.inferExpression(
element.expression,
new InterfaceType(inferrer.coreTypes.iterableClass,
<DartType>[inferredTypeArgument]),
inferenceNeeded || typeChecksNeeded,
isVoidAllowed: true);
+ DartType spreadType = spreadResult.inferredType;
inferredSpreadTypes[element.expression] = spreadType;
if (typeChecksNeeded) {
DartType spreadElementType =
@@ -750,9 +786,10 @@
const DynamicType();
} else if (element is IfElement) {
DartType boolType = inferrer.coreTypes.boolClass.rawType;
- DartType conditionType = inferrer.inferExpression(
+ ExpressionInferenceResult conditionResult = inferrer.inferExpression(
element.condition, boolType, typeChecksNeeded,
isVoidAllowed: false);
+ DartType conditionType = conditionResult.inferredType;
inferrer.ensureAssignable(boolType, conditionType, element.condition,
element.condition.fileOffset);
DartType thenType = inferElement(
@@ -780,9 +817,11 @@
for (VariableDeclaration declaration in element.variables) {
if (declaration.name == null) {
if (declaration.initializer != null) {
- declaration.type = inferrer.inferExpression(declaration.initializer,
- declaration.type, inferenceNeeded || typeChecksNeeded,
- isVoidAllowed: true);
+ ExpressionInferenceResult initializerResult =
+ inferrer.inferExpression(declaration.initializer,
+ declaration.type, inferenceNeeded || typeChecksNeeded,
+ isVoidAllowed: true);
+ declaration.type = initializerResult.inferredType;
}
} else {
inferrer.inferStatement(declaration);
@@ -820,9 +859,10 @@
return inferElement(element.body, element, inferredTypeArgument,
inferredSpreadTypes, inferenceNeeded, typeChecksNeeded);
} else {
- DartType inferredType = inferrer.inferExpression(
+ ExpressionInferenceResult result = inferrer.inferExpression(
element, inferredTypeArgument, inferenceNeeded || typeChecksNeeded,
isVoidAllowed: true);
+ DartType inferredType = result.inferredType;
if (inferredTypeArgument is! UnknownType) {
inferrer.ensureAssignable(
inferredTypeArgument, inferredType, element, element.fileOffset,
@@ -859,7 +899,7 @@
}
}
- void visitListLiteralJudgment(
+ ExpressionInferenceResult visitListLiteralJudgment(
ListLiteralJudgment node, DartType typeContext) {
Class listClass = inferrer.coreTypes.listClass;
InterfaceType listType = listClass.thisType;
@@ -931,11 +971,12 @@
}
}
- return null;
+ return new ExpressionInferenceResult(node.inferredType);
}
@override
- void visitLogicalExpression(LogicalExpression node, DartType typeContext) {
+ ExpressionInferenceResult visitLogicalExpression(
+ LogicalExpression node, DartType typeContext) {
InterfaceType boolType = inferrer.coreTypes.boolClass.rawType;
Expression left = node.left;
Expression right = node.right;
@@ -945,7 +986,7 @@
node.left, node.left.fileOffset);
inferrer.ensureAssignable(boolType, getInferredType(right, inferrer),
node.right, node.right.fileOffset);
- return null;
+ return new ExpressionInferenceResult(boolType);
}
// Calculates the key and the value type of a spread map entry of type
@@ -987,9 +1028,10 @@
bool inferenceNeeded,
bool typeChecksNeeded) {
if (entry is SpreadMapEntry) {
- DartType spreadType = inferrer.inferExpression(
+ ExpressionInferenceResult spreadResult = inferrer.inferExpression(
entry.expression, spreadContext, inferenceNeeded || typeChecksNeeded,
isVoidAllowed: true);
+ DartType spreadType = spreadResult.inferredType;
inferredSpreadTypes[entry.expression] = spreadType;
int length = actualTypes.length;
actualTypes.add(null);
@@ -1090,9 +1132,10 @@
return;
} else if (entry is IfMapEntry) {
DartType boolType = inferrer.coreTypes.boolClass.rawType;
- DartType conditionType = inferrer.inferExpression(
+ ExpressionInferenceResult conditionResult = inferrer.inferExpression(
entry.condition, boolType, typeChecksNeeded,
isVoidAllowed: false);
+ DartType conditionType = conditionResult.inferredType;
inferrer.ensureAssignable(
boolType, conditionType, entry.condition, entry.condition.fileOffset);
// Note that this recursive invocation of inferMapEntry will add two types
@@ -1141,9 +1184,12 @@
for (VariableDeclaration declaration in entry.variables) {
if (declaration.name == null) {
if (declaration.initializer != null) {
- declaration.type = inferrer.inferExpression(declaration.initializer,
- declaration.type, inferenceNeeded || typeChecksNeeded,
+ ExpressionInferenceResult result = inferrer.inferExpression(
+ declaration.initializer,
+ declaration.type,
+ inferenceNeeded || typeChecksNeeded,
isVoidAllowed: true);
+ declaration.type = result.inferredType;
}
} else {
inferrer.inferStatement(declaration);
@@ -1201,12 +1247,14 @@
inferenceNeeded,
typeChecksNeeded);
} else {
- DartType keyType = inferrer.inferExpression(
+ ExpressionInferenceResult keyResult = inferrer.inferExpression(
entry.key, inferredKeyType, true,
isVoidAllowed: true);
- DartType valueType = inferrer.inferExpression(
+ DartType keyType = keyResult.inferredType;
+ ExpressionInferenceResult valueResult = inferrer.inferExpression(
entry.value, inferredValueType, true,
isVoidAllowed: true);
+ DartType valueType = valueResult.inferredType;
inferrer.ensureAssignable(
inferredKeyType, keyType, entry.key, entry.key.fileOffset,
isVoidAllowed: inferredKeyType is VoidType);
@@ -1272,7 +1320,8 @@
}
}
- void visitMapLiteralJudgment(MapLiteralJudgment node, DartType typeContext) {
+ ExpressionInferenceResult visitMapLiteralJudgment(
+ MapLiteralJudgment node, DartType typeContext) {
Class mapClass = inferrer.coreTypes.mapClass;
InterfaceType mapType = mapClass.thisType;
List<DartType> inferredTypes;
@@ -1307,7 +1356,7 @@
node.parent.replaceChild(node, setLiteral);
visitSetLiteralJudgment(setLiteral, typeContext);
node.inferredType = setLiteral.inferredType;
- return;
+ return new ExpressionInferenceResult(node.inferredType);
}
}
}
@@ -1425,7 +1474,7 @@
node.inferredType = setLiteral.inferredType =
new InterfaceType(inferrer.coreTypes.setClass, inferredTypesForSet);
- return;
+ return new ExpressionInferenceResult(node.inferredType);
}
if (canBeSet && canBeMap && node.entries.isNotEmpty) {
node.parent.replaceChild(
@@ -1434,7 +1483,7 @@
.buildProblem(messageCantDisambiguateNotEnoughInformation,
node.fileOffset, 1)));
node.inferredType = const BottomType();
- return;
+ return const ExpressionInferenceResult(const BottomType());
}
if (!canBeSet && !canBeMap) {
if (!inferrer.isTopLevel) {
@@ -1445,7 +1494,7 @@
node.fileOffset, 1)));
}
node.inferredType = const BottomType();
- return;
+ return const ExpressionInferenceResult(const BottomType());
}
inferrer.typeSchemaEnvironment.inferGenericFunctionOrType(
mapType,
@@ -1483,9 +1532,10 @@
inferred: true);
}
}
+ return new ExpressionInferenceResult(node.inferredType);
}
- void visitMethodInvocationJudgment(
+ ExpressionInferenceResult visitMethodInvocationJudgment(
MethodInvocationJudgment node, DartType typeContext) {
if (node.name.name == 'unary-' &&
node.arguments.types.isEmpty &&
@@ -1505,10 +1555,10 @@
if (inferrer.isDoubleContext(typeContext)) {
double doubleValue = receiver.asDouble(negated: true);
if (doubleValue != null) {
- node.parent.replaceChild(
- node, DoubleLiteral(doubleValue)..fileOffset = node.fileOffset);
+ node.parent.replaceChild(node,
+ new DoubleLiteral(doubleValue)..fileOffset = node.fileOffset);
node.inferredType = inferrer.coreTypes.doubleClass.rawType;
- return null;
+ return new ExpressionInferenceResult(node.inferredType);
}
}
Expression error = checkWebIntLiteralsErrorIfUnexact(
@@ -1516,7 +1566,7 @@
if (error != null) {
node.parent.replaceChild(node, error);
node.inferredType = const BottomType();
- return null;
+ return const ExpressionInferenceResult(const BottomType());
}
} else if (node.receiver is ShadowLargeIntLiteral) {
ShadowLargeIntLiteral receiver = node.receiver;
@@ -1525,9 +1575,9 @@
double doubleValue = receiver.asDouble(negated: true);
if (doubleValue != null) {
node.parent.replaceChild(node,
- DoubleLiteral(doubleValue)..fileOffset = node.fileOffset);
+ new DoubleLiteral(doubleValue)..fileOffset = node.fileOffset);
node.inferredType = inferrer.coreTypes.doubleClass.rawType;
- return null;
+ return new ExpressionInferenceResult(node.inferredType);
}
}
int intValue = receiver.asInt64(negated: true);
@@ -1540,7 +1590,7 @@
receiver.literal.length));
node.parent.replaceChild(node, error);
node.inferredType = const BottomType();
- return null;
+ return const ExpressionInferenceResult(const BottomType());
}
if (intValue != null) {
Expression error = checkWebIntLiteralsErrorIfUnexact(
@@ -1548,64 +1598,69 @@
if (error != null) {
node.parent.replaceChild(node, error);
node.inferredType = const BottomType();
- return null;
+ return const ExpressionInferenceResult(const BottomType());
}
- node.receiver = IntLiteral(-intValue)
+ node.receiver = new IntLiteral(-intValue)
..fileOffset = node.receiver.fileOffset
..parent = node;
}
}
}
}
- ExpressionInferenceResult inferenceResult = inferrer.inferMethodInvocation(
+ ExpressionInferenceResult result = inferrer.inferMethodInvocation(
node, node.receiver, node.fileOffset, node._isImplicitCall, typeContext,
desugaredInvocation: node);
- node.inferredType = inferenceResult.type;
+ node.inferredType = result.inferredType;
+ return new ExpressionInferenceResult(
+ result.inferredType, result.replacement);
}
- void visitNamedFunctionExpressionJudgment(
+ ExpressionInferenceResult visitNamedFunctionExpressionJudgment(
NamedFunctionExpressionJudgment node, DartType typeContext) {
Expression initializer = node.variableJudgment.initializer;
inferrer.inferExpression(initializer, typeContext, true);
node.inferredType = getInferredType(initializer, inferrer);
node.variable.type = node.inferredType;
- return null;
+ return new ExpressionInferenceResult(node.inferredType);
}
@override
- void visitNot(Not node, DartType typeContext) {
+ ExpressionInferenceResult visitNot(Not node, DartType typeContext) {
Expression operand = node.operand;
InterfaceType boolType = inferrer.coreTypes.boolClass.rawType;
inferrer.inferExpression(operand, boolType, !inferrer.isTopLevel);
inferrer.ensureAssignable(boolType, getInferredType(operand, inferrer),
node.operand, node.fileOffset);
+ return new ExpressionInferenceResult(boolType);
}
- void visitNullAwareMethodInvocationJudgment(
+ ExpressionInferenceResult visitNullAwareMethodInvocationJudgment(
NullAwareMethodInvocationJudgment node, DartType typeContext) {
- ExpressionInferenceResult inferenceResult = inferrer.inferMethodInvocation(
+ ExpressionInferenceResult result = inferrer.inferMethodInvocation(
node, node.variable.initializer, node.fileOffset, false, typeContext,
receiverVariable: node.variable,
desugaredInvocation: node._desugaredInvocation);
- node.inferredType = inferenceResult.type;
+ node.inferredType = result.inferredType;
node.body.staticType = node.inferredType;
- return null;
+ return new ExpressionInferenceResult(result.inferredType);
}
- void visitNullAwarePropertyGetJudgment(
+ ExpressionInferenceResult visitNullAwarePropertyGetJudgment(
NullAwarePropertyGetJudgment node, DartType typeContext) {
- inferrer.inferPropertyGet(
+ ExpressionInferenceResult result = inferrer.inferPropertyGet(
node, node.receiverJudgment, node.fileOffset, typeContext,
receiverVariable: node.variable, desugaredGet: node._desugaredGet);
- node.body.staticType = node.inferredType;
- return null;
+ node.body.staticType = result.inferredType;
+ return new ExpressionInferenceResult(result.inferredType);
}
@override
- void visitNullLiteral(NullLiteral node, DartType typeContext) {}
+ ExpressionInferenceResult visitNullLiteral(
+ NullLiteral node, DartType typeContext) =>
+ new ExpressionInferenceResult(inferrer.coreTypes.nullClass.rawType);
@override
- void visitLet(Let node, DartType typeContext) {
+ ExpressionInferenceResult visitLet(Let node, DartType typeContext) {
DartType variableType = node.variable.type;
if (variableType == const DynamicType()) {
return defaultExpression(node, typeContext);
@@ -1614,47 +1669,72 @@
inferrer.inferExpression(initializer, variableType, true,
isVoidAllowed: true);
Expression body = node.body;
- inferrer.inferExpression(body, typeContext, true, isVoidAllowed: true);
+ ExpressionInferenceResult result =
+ inferrer.inferExpression(body, typeContext, true, isVoidAllowed: true);
+ DartType inferredType = result.inferredType;
// TODO(ahe): This shouldn't be needed. See InferredTypeVisitor.visitLet.
- inferrer.storeInferredType(node, getInferredType(body, inferrer));
+ inferrer.storeInferredType(node, inferredType);
+ return new ExpressionInferenceResult(inferredType);
}
- void visitPropertyAssignmentJudgment(
+ ExpressionInferenceResult visitPropertyAssignmentJudgment(
PropertyAssignmentJudgment node, DartType typeContext) {
DartType receiverType = node._inferReceiver(inferrer);
DartType readType;
if (node.read != null) {
- Object readMember = inferrer
+ ObjectAccessTarget readTarget = inferrer
.findPropertyGetMember(receiverType, node.read, instrumented: false);
- readType = inferrer.getCalleeType(readMember, receiverType);
+ readType = inferrer.getGetterType(readTarget, receiverType);
inferrer.handlePropertyGetContravariance(
node.receiver,
- readMember,
+ readTarget,
node.read is PropertyGet ? node.read : null,
node.read,
readType,
node.read.fileOffset);
node._storeLetType(inferrer, node.read, readType);
}
- Member writeMember;
+ ObjectAccessTarget writeTarget;
if (node.write != null) {
- writeMember = node._handleWriteContravariance(inferrer, receiverType);
+ writeTarget = node._handleWriteContravariance(inferrer, receiverType);
}
// To replicate analyzer behavior, we base type inference on the write
// member. TODO(paulberry): would it be better to use the read member when
// doing compound assignment?
- DartType writeContext = inferrer.getSetterType(writeMember, receiverType);
- node._inferRhs(inferrer, readType, writeContext);
+ DartType writeContext = inferrer.getSetterType(writeTarget, receiverType);
+ DartType inferredType =
+ node._inferRhs(inferrer, readType, writeContext).inferredType;
node.nullAwareGuard?.staticType = node.inferredType;
- node._replaceWithDesugared();
- return null;
+ Expression replacement;
+ if (writeTarget.isExtensionMember) {
+ node.parent.replaceChild(
+ node,
+ replacement = inferrer.helper.forest.createStaticInvocation(
+ node.fileOffset,
+ writeTarget.member,
+ inferrer.helper.forest.createArgumentsForExtensionMethod(
+ node.fileOffset,
+ writeTarget.inferredExtensionTypeArguments.length,
+ 0,
+ node.receiver,
+ extensionTypeArguments:
+ writeTarget.inferredExtensionTypeArguments,
+ positionalArguments: [node.rhs])));
+ inferrer.storeInferredType(replacement, inferredType);
+ } else {
+ node._replaceWithDesugared();
+ }
+
+ return new ExpressionInferenceResult(inferredType, replacement);
}
@override
- void visitPropertyGet(PropertyGet node, DartType typeContext) {
- inferrer.inferPropertyGet(node, node.receiver, node.fileOffset, typeContext,
- desugaredGet: node);
+ ExpressionInferenceResult visitPropertyGet(
+ PropertyGet node, DartType typeContext) {
+ return inferrer.inferPropertyGet(
+ node, node.receiver, node.fileOffset, typeContext,
+ desugaredGet: node, allowExtensionMethods: true);
}
void visitRedirectingInitializerJudgment(
@@ -1679,7 +1759,8 @@
}
@override
- void visitRethrow(Rethrow node, DartType typeContext) {}
+ ExpressionInferenceResult visitRethrow(Rethrow node, DartType typeContext) =>
+ const ExpressionInferenceResult(const BottomType());
void visitReturnJudgment(ReturnJudgment node) {
Expression judgment = node.judgment;
@@ -1695,11 +1776,11 @@
} else {
inferredType = inferrer.coreTypes.nullClass.rawType;
}
- closureContext.handleReturn(inferrer, node, inferredType,
- !identical(node.returnKeywordLexeme, "return"));
+ closureContext.handleReturn(inferrer, node, inferredType, node.isArrow);
}
- void visitSetLiteralJudgment(SetLiteralJudgment node, DartType typeContext) {
+ ExpressionInferenceResult visitSetLiteralJudgment(
+ SetLiteralJudgment node, DartType typeContext) {
Class setClass = inferrer.coreTypes.setClass;
InterfaceType setType = setClass.thisType;
List<DartType> inferredTypes;
@@ -1773,9 +1854,10 @@
inferrer.helper.transformSetLiterals = true;
}
}
+ return new ExpressionInferenceResult(node.inferredType);
}
- void visitStaticAssignmentJudgment(
+ ExpressionInferenceResult visitStaticAssignmentJudgment(
StaticAssignmentJudgment node, DartType typeContext) {
DartType readType = const DynamicType(); // Only used in error recovery
Expression read = node.read;
@@ -1791,13 +1873,15 @@
writeMember = write.target;
TypeInferenceEngine.resolveInferenceNode(writeMember);
}
- node._inferRhs(inferrer, readType, writeContext);
+ DartType inferredType =
+ node._inferRhs(inferrer, readType, writeContext).inferredType;
node._replaceWithDesugared();
- return null;
+ return new ExpressionInferenceResult(inferredType);
}
@override
- void visitStaticGet(StaticGet node, DartType typeContext) {
+ ExpressionInferenceResult visitStaticGet(
+ StaticGet node, DartType typeContext) {
Member target = node.target;
TypeInferenceEngine.resolveInferenceNode(target);
DartType type = target.getterType;
@@ -1805,31 +1889,32 @@
type = inferrer.instantiateTearOff(type, typeContext, node);
}
inferrer.storeInferredType(node, type);
+ return new ExpressionInferenceResult(type);
}
@override
- void visitStaticInvocation(StaticInvocation node, DartType typeContext) {
+ ExpressionInferenceResult visitStaticInvocation(
+ StaticInvocation node, DartType typeContext) {
FunctionType calleeType = node.target != null
? node.target.function.functionType
: new FunctionType([], const DynamicType());
bool hadExplicitTypeArguments =
getExplicitTypeArguments(node.arguments) != null;
- ExpressionInferenceResult inferenceResult = inferrer.inferInvocation(
- typeContext,
- node.fileOffset,
- calleeType,
- calleeType.returnType,
- node.arguments);
- inferrer.storeInferredType(node, inferenceResult.type);
- if (!hadExplicitTypeArguments && node.target != null) {
- inferrer.library?.checkBoundsInStaticInvocation(
+ DartType inferredType = inferrer.inferInvocation(typeContext,
+ node.fileOffset, calleeType, calleeType.returnType, node.arguments);
+ inferrer.storeInferredType(node, inferredType);
+ if (!inferrer.isTopLevel &&
+ !hadExplicitTypeArguments &&
+ node.target != null) {
+ inferrer.library.checkBoundsInStaticInvocation(
node, inferrer.typeSchemaEnvironment, inferrer.helper.uri,
inferred: true);
}
+ return new ExpressionInferenceResult(inferredType);
}
@override
- void visitStringConcatenation(
+ ExpressionInferenceResult visitStringConcatenation(
StringConcatenation node, DartType typeContext) {
if (!inferrer.isTopLevel) {
for (Expression expression in node.expressions) {
@@ -1837,10 +1922,14 @@
expression, const UnknownType(), !inferrer.isTopLevel);
}
}
+ return new ExpressionInferenceResult(
+ inferrer.coreTypes.stringClass.rawType);
}
@override
- void visitStringLiteral(StringLiteral node, DartType typeContext) {}
+ ExpressionInferenceResult visitStringLiteral(
+ StringLiteral node, DartType typeContext) =>
+ new ExpressionInferenceResult(inferrer.coreTypes.stringClass.rawType);
void visitSuperInitializerJudgment(SuperInitializerJudgment node) {
Substitution substitution = Substitution.fromSupertype(
@@ -1856,28 +1945,34 @@
skipTypeArgumentInference: true);
}
- void visitSuperMethodInvocationJudgment(
+ ExpressionInferenceResult visitSuperMethodInvocationJudgment(
SuperMethodInvocationJudgment node, DartType typeContext) {
if (node.interfaceTarget != null) {
inferrer.instrumentation?.record(inferrer.uri, node.fileOffset, 'target',
new InstrumentationValueForMember(node.interfaceTarget));
}
- ExpressionInferenceResult inferenceResult = inferrer.inferMethodInvocation(
+ ExpressionInferenceResult result = inferrer.inferMethodInvocation(
node, null, node.fileOffset, false, typeContext,
- interfaceMember: node.interfaceTarget,
+ target: node.interfaceTarget != null
+ ? new ObjectAccessTarget.interfaceMember(node.interfaceTarget)
+ : const ObjectAccessTarget.unresolved(),
methodName: node.name,
arguments: node.arguments);
- node.inferredType = inferenceResult.type;
+ node.inferredType = result.inferredType;
+ return new ExpressionInferenceResult(result.inferredType);
}
- void visitSuperPropertyGetJudgment(
+ ExpressionInferenceResult visitSuperPropertyGetJudgment(
SuperPropertyGetJudgment node, DartType typeContext) {
if (node.interfaceTarget != null) {
inferrer.instrumentation?.record(inferrer.uri, node.fileOffset, 'target',
new InstrumentationValueForMember(node.interfaceTarget));
}
- inferrer.inferPropertyGet(node, null, node.fileOffset, typeContext,
- interfaceMember: node.interfaceTarget, propertyName: node.name);
+ return inferrer.inferPropertyGet(node, null, node.fileOffset, typeContext,
+ readTarget: node.interfaceTarget != null
+ ? new ObjectAccessTarget.interfaceMember(node.interfaceTarget)
+ : const ObjectAccessTarget.unresolved(),
+ propertyName: node.name);
}
void visitSwitchStatementJudgment(SwitchStatementJudgment node) {
@@ -1887,8 +1982,9 @@
for (SwitchCaseJudgment switchCase in node.caseJudgments) {
for (Expression caseExpression in switchCase.expressionJudgments) {
- DartType caseExpressionType =
+ ExpressionInferenceResult caseExpressionResult =
inferrer.inferExpression(caseExpression, expressionType, true);
+ DartType caseExpressionType = caseExpressionResult.inferredType;
// Check whether the expression type is assignable to the case
// expression type.
@@ -1908,13 +2004,13 @@
}
}
- void visitSymbolLiteralJudgment(
+ ExpressionInferenceResult visitSymbolLiteralJudgment(
SymbolLiteralJudgment node, DartType typeContext) {
node.inferredType = inferrer.coreTypes.symbolClass.rawType;
- return null;
+ return new ExpressionInferenceResult(node.inferredType);
}
- void visitInvalidConstructorInvocationJudgment(
+ ExpressionInferenceResult visitInvalidConstructorInvocationJudgment(
InvalidConstructorInvocationJudgment node, DartType typeContext) {
FunctionType calleeType;
DartType returnType;
@@ -1925,17 +2021,13 @@
calleeType = new FunctionType([], const DynamicType());
returnType = const DynamicType();
}
- ExpressionInferenceResult inferenceResult = inferrer.inferInvocation(
- typeContext,
- node.fileOffset,
- calleeType,
- returnType,
- node.argumentJudgments);
- node.inferredType = inferenceResult.type;
+ DartType inferredType = inferrer.inferInvocation(typeContext,
+ node.fileOffset, calleeType, returnType, node.argumentJudgments);
+ node.inferredType = inferredType;
return visitSyntheticExpressionJudgment(node, typeContext);
}
- void visitInvalidWriteJudgment(
+ ExpressionInferenceResult visitInvalidWriteJudgment(
InvalidWriteJudgment node, DartType typeContext) {
// When a compound assignment, the expression is already wrapping in
// VariableDeclaration in _makeRead(). Otherwise, temporary associate
@@ -1947,19 +2039,22 @@
return visitSyntheticExpressionJudgment(node, typeContext);
}
- void visitSyntheticExpressionJudgment(
+ ExpressionInferenceResult visitSyntheticExpressionJudgment(
SyntheticExpressionJudgment node, DartType typeContext) {
node._replaceWithDesugared();
node.inferredType = const DynamicType();
- return null;
+ return const ExpressionInferenceResult(const DynamicType());
}
- void visitThisExpression(ThisExpression node, DartType typeContext) {}
+ ExpressionInferenceResult visitThisExpression(
+ ThisExpression node, DartType typeContext) =>
+ new ExpressionInferenceResult(inferrer.thisType);
@override
- void visitThrow(Throw node, DartType typeContext) {
+ ExpressionInferenceResult visitThrow(Throw node, DartType typeContext) {
inferrer.inferExpression(
node.expression, const UnknownType(), !inferrer.isTopLevel);
+ return const ExpressionInferenceResult(const BottomType());
}
void visitCatchJudgment(CatchJudgment node) {
@@ -1978,13 +2073,13 @@
inferrer.inferStatement(node.finalizer);
}
- void visitTypeLiteralJudgment(
+ ExpressionInferenceResult visitTypeLiteralJudgment(
TypeLiteralJudgment node, DartType typeContext) {
node.inferredType = inferrer.coreTypes.typeClass.rawType;
- return null;
+ return new ExpressionInferenceResult(node.inferredType);
}
- void visitVariableAssignmentJudgment(
+ ExpressionInferenceResult visitVariableAssignmentJudgment(
VariableAssignmentJudgment node, DartType typeContext) {
DartType readType;
Expression read = node.read;
@@ -1999,9 +2094,10 @@
node._storeLetType(inferrer, read, writeContext);
}
}
- node._inferRhs(inferrer, readType, writeContext);
+ DartType inferredType =
+ node._inferRhs(inferrer, readType, writeContext).inferredType;
node._replaceWithDesugared();
- return null;
+ return new ExpressionInferenceResult(inferredType);
}
void visitVariableDeclarationJudgment(VariableDeclarationJudgment node) {
@@ -2011,10 +2107,12 @@
DartType inferredType;
DartType initializerType;
if (initializerJudgment != null) {
- inferrer.inferExpression(initializerJudgment, declaredType,
+ ExpressionInferenceResult initializerResult = inferrer.inferExpression(
+ initializerJudgment,
+ declaredType,
!inferrer.isTopLevel || node._implicitlyTyped,
isVoidAllowed: true);
- initializerType = getInferredType(initializerJudgment, inferrer);
+ initializerType = initializerResult.inferredType;
inferredType = inferrer.inferDeclarationType(initializerType);
} else {
inferredType = const DynamicType();
@@ -2042,9 +2140,10 @@
}
}
- void visitUnresolvedTargetInvocationJudgment(
+ ExpressionInferenceResult visitUnresolvedTargetInvocationJudgment(
UnresolvedTargetInvocationJudgment node, DartType typeContext) {
- void result = visitSyntheticExpressionJudgment(node, typeContext);
+ ExpressionInferenceResult result =
+ visitSyntheticExpressionJudgment(node, typeContext);
inferrer.inferInvocation(
typeContext,
node.fileOffset,
@@ -2054,7 +2153,7 @@
return result;
}
- void visitUnresolvedVariableAssignmentJudgment(
+ ExpressionInferenceResult visitUnresolvedVariableAssignmentJudgment(
UnresolvedVariableAssignmentJudgment node, DartType typeContext) {
inferrer.inferExpression(node.rhs, const UnknownType(), true);
node.inferredType = node.isCompound
@@ -2063,7 +2162,7 @@
return visitSyntheticExpressionJudgment(node, typeContext);
}
- void visitVariableGetJudgment(
+ ExpressionInferenceResult visitVariableGetJudgment(
VariableGetJudgment node, DartType typeContext) {
VariableDeclarationJudgment variable = node.variable;
bool mutatedInClosure = variable._mutatedInClosure;
@@ -2081,7 +2180,7 @@
type = inferrer.instantiateTearOff(type, typeContext, node);
}
node.inferredType = type;
- return null;
+ return new ExpressionInferenceResult(type);
}
void visitWhileJudgment(WhileJudgment node) {
@@ -2117,7 +2216,7 @@
getInferredType(judgment, inferrer), node.expression, node.fileOffset);
}
- void visitLoadLibraryJudgment(
+ ExpressionInferenceResult visitLoadLibraryJudgment(
LoadLibraryJudgment node, DartType typeContext) {
node.inferredType =
inferrer.typeSchemaEnvironment.futureType(const DynamicType());
@@ -2126,17 +2225,18 @@
inferrer.inferInvocation(typeContext, node.fileOffset, calleeType,
calleeType.returnType, node.argumentJudgments);
}
- return null;
+ return new ExpressionInferenceResult(node.inferredType);
}
- void visitLoadLibraryTearOffJudgment(
+ ExpressionInferenceResult visitLoadLibraryTearOffJudgment(
LoadLibraryTearOffJudgment node, DartType typeContext) {
node.inferredType = new FunctionType(
[], inferrer.typeSchemaEnvironment.futureType(const DynamicType()));
- return null;
+ return new ExpressionInferenceResult(node.inferredType);
}
@override
- void visitCheckLibraryIsLoaded(
- CheckLibraryIsLoaded node, DartType typeContext) {}
+ ExpressionInferenceResult visitCheckLibraryIsLoaded(
+ CheckLibraryIsLoaded node, DartType typeContext) =>
+ new ExpressionInferenceResult(inferrer.coreTypes.objectClass.rawType);
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
index 2ffbade..36e77d4 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
@@ -66,13 +66,7 @@
import '../type_inference/type_inference_engine.dart'
show IncludesTypeParametersNonCovariantly, TypeInferenceEngine;
-import '../type_inference/type_inferrer.dart'
- show
- ClosureContext,
- ExpressionInferenceResult,
- MethodContravarianceCheckKind,
- TypeInferrer,
- TypeInferrerImpl;
+import '../type_inference/type_inferrer.dart';
import '../type_inference/type_promotion.dart'
show TypePromoter, TypePromoterImpl, TypePromotionFact, TypePromotionScope;
@@ -115,9 +109,50 @@
}
}
+int getExtensionTypeParameterCount(Arguments arguments) {
+ if (arguments is ArgumentsJudgment) {
+ return arguments._extensionTypeParameterCount;
+ } else {
+ // TODO(johnniwinther): Remove this path or assert why it is accepted.
+ return 0;
+ }
+}
+
+int getExtensionTypeArgumentCount(Arguments arguments) {
+ if (arguments is ArgumentsJudgment) {
+ return arguments._extensionTypeArgumentCount;
+ } else {
+ // TODO(johnniwinther): Remove this path or assert why it is accepted.
+ return 0;
+ }
+}
+
+List<DartType> getExplicitExtensionTypeArguments(Arguments arguments) {
+ if (arguments is ArgumentsJudgment) {
+ if (arguments._extensionTypeArgumentCount == 0) {
+ return null;
+ } else {
+ return arguments.types
+ .take(arguments._extensionTypeArgumentCount)
+ .toList();
+ }
+ } else {
+ // TODO(johnniwinther): Remove this path or assert why it is accepted.
+ return null;
+ }
+}
+
List<DartType> getExplicitTypeArguments(Arguments arguments) {
if (arguments is ArgumentsJudgment) {
- return arguments._hasExplicitTypeArguments ? arguments.types : null;
+ if (arguments._explicitTypeArgumentCount == 0) {
+ return null;
+ } else if (arguments._extensionTypeParameterCount == 0) {
+ return arguments.types;
+ } else {
+ return arguments.types
+ .skip(arguments._extensionTypeParameterCount)
+ .toList();
+ }
} else {
// This code path should only be taken in situations where there are no
// type arguments at all, e.g. calling a user-definable operator.
@@ -146,25 +181,61 @@
/// Concrete shadow object representing a set of invocation arguments.
class ArgumentsJudgment extends Arguments {
- bool _hasExplicitTypeArguments;
+ // TODO(johnniwinther): Move this to the static invocation instead.
+ final int _extensionTypeParameterCount;
+
+ final int _extensionTypeArgumentCount;
+
+ int _explicitTypeArgumentCount;
List<Expression> get positionalJudgments => positional.cast();
ArgumentsJudgment(List<Expression> positional,
{List<DartType> types, List<NamedExpression> named})
- : _hasExplicitTypeArguments = types != null && types.isNotEmpty,
+ : _explicitTypeArgumentCount = types?.length ?? 0,
+ _extensionTypeParameterCount = 0,
+ _extensionTypeArgumentCount = 0,
super(positional, types: types, named: named);
+ ArgumentsJudgment.forExtensionMethod(int extensionTypeParameterCount,
+ int typeParameterCount, Expression receiver,
+ {List<DartType> extensionTypeArguments = const <DartType>[],
+ List<DartType> typeArguments = const <DartType>[],
+ List<Expression> positionalArguments = const <Expression>[],
+ List<NamedExpression> namedArguments = const <NamedExpression>[]})
+ : _extensionTypeParameterCount = extensionTypeParameterCount,
+ _extensionTypeArgumentCount = extensionTypeArguments.length,
+ _explicitTypeArgumentCount = typeArguments.length,
+ assert(
+ extensionTypeArguments.isEmpty ||
+ extensionTypeArguments.length == extensionTypeParameterCount,
+ "Extension type arguments must be empty or complete."),
+ super(<Expression>[receiver]..addAll(positionalArguments),
+ named: namedArguments,
+ types: <DartType>[]
+ ..addAll(_normalizeTypeArguments(
+ extensionTypeParameterCount, extensionTypeArguments))
+ ..addAll(
+ _normalizeTypeArguments(typeParameterCount, typeArguments)));
+
+ static List<DartType> _normalizeTypeArguments(
+ int length, List<DartType> arguments) {
+ if (arguments.isEmpty && length > 0) {
+ return new List<DartType>.filled(length, const UnknownType());
+ }
+ return arguments;
+ }
+
static void setNonInferrableArgumentTypes(
ArgumentsJudgment arguments, List<DartType> types) {
arguments.types.clear();
arguments.types.addAll(types);
- arguments._hasExplicitTypeArguments = true;
+ arguments._explicitTypeArgumentCount = types.length;
}
static void removeNonInferrableArgumentTypes(ArgumentsJudgment arguments) {
arguments.types.clear();
- arguments._hasExplicitTypeArguments = false;
+ arguments._explicitTypeArgumentCount = 0;
}
}
@@ -280,7 +351,8 @@
}
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitCascadeJudgment(this, typeContext);
}
}
@@ -298,7 +370,7 @@
Expression read;
/// The expression appearing on the RHS of the assignment.
- final Expression rhs;
+ Expression rhs;
/// The expression that performs the write (e.g. `a.[]=(b, a.[](b) + 1)` in
/// `++a[b]`).
@@ -358,19 +430,22 @@
?.addProblem(messageVoidExpression, read.fileOffset, noLength);
}
int writeOffset = write == null ? -1 : write.fileOffset;
- Procedure combinerMember;
+ ObjectAccessTarget combinerTarget = const ObjectAccessTarget.unresolved();
DartType combinedType;
if (combiner != null) {
bool isOverloadedArithmeticOperator = false;
- combinerMember = inferrer.findMethodInvocationMember(readType, combiner,
+ combinerTarget = inferrer.findMethodInvocationMember(readType, combiner,
instrumented: false);
- if (combinerMember is Procedure) {
+ assert(!combinerTarget.isCallFunction);
+ if (combinerTarget.isInstanceMember &&
+ combinerTarget.member is Procedure) {
isOverloadedArithmeticOperator = inferrer.typeSchemaEnvironment
- .isOverloadedArithmeticOperatorAndType(combinerMember, readType);
+ .isOverloadedArithmeticOperatorAndType(
+ combinerTarget.member, readType);
}
DartType rhsType;
- FunctionType combinerType = inferrer.getCalleeFunctionType(
- inferrer.getCalleeType(combinerMember, readType), false);
+ FunctionType combinerType =
+ inferrer.getFunctionType(combinerTarget, readType, false);
if (isPreIncDec || isPostIncDec) {
rhsType = inferrer.coreTypes.intClass.rawType;
} else {
@@ -380,8 +455,12 @@
assert(identical(combiner.arguments.positional.first, rhs));
// Analyzer uses a null context for the RHS here.
// TODO(paulberry): improve on this.
- inferrer.inferExpression(rhs, const UnknownType(), true);
- rhsType = getInferredType(rhs, inferrer);
+ ExpressionInferenceResult rhsResult =
+ inferrer.inferExpression(rhs, const UnknownType(), true);
+ if (rhsResult.replacement != null) {
+ rhs = rhsResult.replacement;
+ }
+ rhsType = rhsResult.inferredType;
// Do not use rhs after this point because it may be a Shadow node
// that has been replaced in the tree with its desugaring.
DartType expectedType = getPositionalParameterType(combinerType, 0);
@@ -396,7 +475,7 @@
}
MethodContravarianceCheckKind checkKind =
inferrer.preCheckInvocationContravariance(read, readType,
- combinerMember, combiner, combiner.arguments, combiner);
+ combinerTarget, combiner, combiner.arguments, combiner);
Expression replacedCombiner = inferrer.handleInvocationContravariance(
checkKind,
combiner,
@@ -412,9 +491,13 @@
}
_storeLetType(inferrer, replacedCombiner, combinedType);
} else {
- inferrer.inferExpression(rhs, writeContext ?? const UnknownType(), true,
+ ExpressionInferenceResult rhsResult = inferrer.inferExpression(
+ rhs, writeContext ?? const UnknownType(), true,
isVoidAllowed: true);
- DartType rhsType = getInferredType(rhs, inferrer);
+ if (rhsResult.replacement != null) {
+ rhs = rhsResult.replacement;
+ }
+ DartType rhsType = rhsResult.inferredType;
Expression replacedRhs = inferrer.ensureAssignable(
writeContext, rhsType, rhs, writeOffset,
isVoidAllowed: writeContext is VoidType);
@@ -441,7 +524,8 @@
}
inferredType =
isPostIncDec ? (readType ?? const DynamicType()) : combinedType;
- return new _ComplexAssignmentInferenceResult(combinerMember);
+ return new _ComplexAssignmentInferenceResult(
+ combinerTarget.member, inferredType);
}
}
@@ -503,10 +587,11 @@
DeferredCheckJudgment(VariableDeclaration variable, Expression body)
: super(variable, body);
- Expression get judgment => body;
+ Expression get expression => body;
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitDeferredCheckJudgment(this, typeContext);
}
}
@@ -530,7 +615,8 @@
DoubleJudgment(double value) : super(value);
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitDoubleJudgment(this, typeContext);
}
}
@@ -542,7 +628,8 @@
/// Calls back to [inferrer] to perform type inference for whatever concrete
/// type of [Expression] this is.
- void acceptInference(InferenceVisitor visitor, DartType typeContext);
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext);
}
/// Concrete shadow object representing an empty statement in kernel form.
@@ -583,7 +670,8 @@
ArgumentsJudgment get argumentJudgments => arguments;
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitFactoryConstructorInvocationJudgment(this, typeContext);
}
}
@@ -698,7 +786,8 @@
Expression get rightJudgment => body.then;
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitIfNullJudgment(this, typeContext);
}
}
@@ -729,7 +818,8 @@
}
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitIllegalAssignmentJudgment(this, typeContext);
}
}
@@ -738,7 +828,7 @@
/// `a[b]`.
class IndexAssignmentJudgment extends ComplexAssignmentJudgmentWithReceiver {
/// In an assignment to an index expression, the index expression.
- final Expression index;
+ Expression index;
IndexAssignmentJudgment._(Expression receiver, this.index, Expression rhs,
{bool isSuper: false})
@@ -764,7 +854,8 @@
}
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitIndexAssignmentJudgment(this, typeContext);
}
}
@@ -780,11 +871,11 @@
Expression checkWebIntLiteralsErrorIfUnexact(
ShadowTypeInferrer inferrer, int value, String literal, int charOffset) {
if (value >= 0 && value <= (1 << 53)) return null;
- if (inferrer.library == null) return null;
+ if (inferrer.isTopLevel) return null;
if (!inferrer.library.loader.target.backendTarget
.errorOnUnexactWebIntLiterals) return null;
- BigInt asInt = BigInt.from(value).toUnsigned(64);
- BigInt asDouble = BigInt.from(asInt.toDouble());
+ BigInt asInt = new BigInt.from(value).toUnsigned(64);
+ BigInt asDouble = new BigInt.from(asInt.toDouble());
if (asInt == asDouble) return null;
String text = literal ?? value.toString();
String nearest = text.startsWith('0x') || text.startsWith('0X')
@@ -808,13 +899,14 @@
double asDouble({bool negated: false}) {
if (value == 0 && negated) return -0.0;
- BigInt intValue = BigInt.from(negated ? -value : value);
+ BigInt intValue = new BigInt.from(negated ? -value : value);
double doubleValue = intValue.toDouble();
- return intValue == BigInt.from(doubleValue) ? doubleValue : null;
+ return intValue == new BigInt.from(doubleValue) ? doubleValue : null;
}
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitIntJudgment(this, typeContext);
}
}
@@ -834,7 +926,7 @@
double doubleValue = intValue.toDouble();
return !doubleValue.isNaN &&
!doubleValue.isInfinite &&
- intValue == BigInt.from(doubleValue)
+ intValue == new BigInt.from(doubleValue)
? doubleValue
: null;
}
@@ -844,7 +936,8 @@
}
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitShadowLargeIntLiteral(this, typeContext);
}
}
@@ -890,7 +983,8 @@
super(expressions, typeArgument: typeArgument, isConst: isConst);
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitListLiteralJudgment(this, typeContext);
}
}
@@ -905,7 +999,8 @@
super(expressions, typeArgument: typeArgument, isConst: isConst);
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitSetLiteralJudgment(this, typeContext);
}
}
@@ -922,7 +1017,8 @@
keyType: keyType, valueType: valueType, isConst: isConst);
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitMapLiteralJudgment(this, typeContext);
}
}
@@ -945,7 +1041,8 @@
ArgumentsJudgment get argumentJudgments => arguments;
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitMethodInvocationJudgment(this, typeContext);
}
}
@@ -969,7 +1066,8 @@
VariableDeclarationJudgment get variableJudgment => variable;
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitNamedFunctionExpressionJudgment(this, typeContext);
}
}
@@ -994,7 +1092,8 @@
MethodInvocation get _desugaredInvocation => body.otherwise;
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitNullAwareMethodInvocationJudgment(this, typeContext);
}
}
@@ -1020,7 +1119,8 @@
Expression get receiverJudgment => variable.initializer;
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitNullAwarePropertyGetJudgment(this, typeContext);
}
}
@@ -1042,13 +1142,14 @@
return parts;
}
- Object _handleWriteContravariance(
+ ObjectAccessTarget _handleWriteContravariance(
ShadowTypeInferrer inferrer, DartType receiverType) {
return inferrer.findPropertySetMember(receiverType, write);
}
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitPropertyAssignmentJudgment(this, typeContext);
}
}
@@ -1071,10 +1172,9 @@
/// Concrete shadow object representing a return statement in kernel form.
class ReturnJudgment extends ReturnStatement implements StatementJudgment {
- final String returnKeywordLexeme;
+ final bool isArrow;
- ReturnJudgment(this.returnKeywordLexeme, [Expression expression])
- : super(expression);
+ ReturnJudgment(this.isArrow, [Expression expression]) : super(expression);
Expression get judgment => expression;
@@ -1097,7 +1197,8 @@
StaticAssignmentJudgment._(Expression rhs) : super._(rhs);
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitStaticAssignmentJudgment(this, typeContext);
}
}
@@ -1128,7 +1229,8 @@
ArgumentsJudgment get argumentJudgments => arguments;
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitSuperMethodInvocationJudgment(this, typeContext);
}
}
@@ -1142,7 +1244,8 @@
: super(name, interfaceTarget);
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitSuperPropertyGetJudgment(this, typeContext);
}
}
@@ -1185,7 +1288,8 @@
SymbolLiteralJudgment(String value) : super(value);
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitSymbolLiteralJudgment(this, typeContext);
}
}
@@ -1205,7 +1309,8 @@
ArgumentsJudgment get argumentJudgments => arguments;
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitInvalidConstructorInvocationJudgment(this, typeContext);
}
}
@@ -1219,7 +1324,8 @@
: super._(desugared);
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitInvalidWriteJudgment(this, typeContext);
}
}
@@ -1245,15 +1351,17 @@
}
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitSyntheticExpressionJudgment(this, typeContext);
}
/// Removes this expression from the expression tree, replacing it with
/// [desugared].
- void _replaceWithDesugared() {
+ Expression _replaceWithDesugared() {
parent.replaceChild(this, desugared);
parent = null;
+ return desugared;
}
/// Updates any [Let] nodes in the desugared expression to account for the
@@ -1287,17 +1395,17 @@
}
@override
- accept(ExpressionVisitor<dynamic> v) {
+ R accept<R>(ExpressionVisitor<R> v) {
// This is designed to throw an exception during serialization. It can also
// lead to exceptions during transformations, but we have to accept a
// [Transformer] as this is used to implement `replaceChild`.
if (v is Transformer) return super.accept(v);
- unsupported("accept", fileOffset, getFileUri(this));
+ throw unsupported("accept", fileOffset, getFileUri(this));
}
@override
- accept1(ExpressionVisitor1<dynamic, dynamic> v, arg) {
- unsupported("accept1", fileOffset, getFileUri(this));
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) {
+ throw unsupported("accept1", fileOffset, getFileUri(this));
}
@override
@@ -1376,7 +1484,7 @@
}
@override
- DartType inferExpression(
+ ExpressionInferenceResult inferExpression(
kernel.Expression expression, DartType typeContext, bool typeNeeded,
{bool isVoidAllowed: false}) {
// `null` should never be used as the type context. An instance of
@@ -1395,22 +1503,24 @@
// When doing top level inference, we skip subexpressions whose type isn't
// needed so that we don't induce bogus dependencies on fields mentioned in
// those subexpressions.
- if (!typeNeeded) return null;
+ if (!typeNeeded) return const ExpressionInferenceResult(null);
InferenceVisitor visitor = new InferenceVisitor(this);
+ ExpressionInferenceResult result;
if (expression is ExpressionJudgment) {
- expression.acceptInference(visitor, typeContext);
+ result = expression.acceptInference(visitor, typeContext);
} else {
- expression.accept1(visitor, typeContext);
+ result = expression.accept1(visitor, typeContext);
}
- DartType inferredType = getInferredType(expression, this);
+ DartType inferredType = result.inferredType;
+ assert(inferredType != null, "No type inferred for $expression.");
if (inferredType is VoidType && !isVoidAllowed) {
if (expression.parent is! ArgumentsJudgment) {
helper?.addProblem(
messageVoidExpression, expression.fileOffset, noLength);
}
}
- return inferredType;
+ return result;
}
@override
@@ -1462,7 +1572,8 @@
TypeLiteralJudgment(DartType type) : super(type);
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitTypeLiteralJudgment(this, typeContext);
}
}
@@ -1540,7 +1651,8 @@
VariableAssignmentJudgment._(Expression rhs) : super._(rhs);
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitVariableAssignmentJudgment(this, typeContext);
}
}
@@ -1598,9 +1710,9 @@
_isLocalFunction = false,
super.forValue(initializer);
- VariableDeclarationJudgment.forValue(
- Expression initializer, this._functionNestingLevel)
+ VariableDeclarationJudgment.forValue(Expression initializer)
: forSyntheticToken = false,
+ _functionNestingLevel = 0,
_implicitlyTyped = true,
_isLocalFunction = false,
super.forValue(initializer);
@@ -1639,7 +1751,8 @@
: super._(desugared);
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitUnresolvedTargetInvocationJudgment(this, typeContext);
}
}
@@ -1655,7 +1768,8 @@
: super._(desugared);
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitUnresolvedVariableAssignmentJudgment(this, typeContext);
}
}
@@ -1672,7 +1786,8 @@
: super(variable);
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitVariableGetJudgment(this, typeContext);
}
}
@@ -1713,7 +1828,8 @@
ArgumentsJudgment get argumentJudgments => arguments;
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitLoadLibraryJudgment(this, typeContext);
}
}
@@ -1728,7 +1844,8 @@
LoadLibraryTearOffJudgment(this.import, Procedure target) : super(target);
@override
- void acceptInference(InferenceVisitor visitor, DartType typeContext) {
+ ExpressionInferenceResult acceptInference(
+ InferenceVisitor visitor, DartType typeContext) {
return visitor.visitLoadLibraryTearOffJudgment(this, typeContext);
}
}
@@ -1739,13 +1856,16 @@
/// `null` if the assignment is not compound.
final Procedure combiner;
- _ComplexAssignmentInferenceResult(this.combiner);
+ /// The inferred type of the RHS.
+ final DartType inferredType;
+
+ _ComplexAssignmentInferenceResult(this.combiner, this.inferredType);
}
class _UnfinishedCascade extends Expression {
- accept(v) => unsupported("accept", -1, null);
+ R accept<R>(v) => unsupported("accept", -1, null);
- accept1(v, arg) => unsupported("accept1", -1, null);
+ R accept1<R, A>(v, arg) => unsupported("accept1", -1, null);
getStaticType(types) => unsupported("getStaticType", -1, null);
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 ab78a04..8755030 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -95,6 +95,7 @@
NamedTypeBuilder,
ProcedureBuilder,
LibraryBuilder,
+ NullabilityBuilder,
TypeBuilder,
TypeDeclarationBuilder;
@@ -120,11 +121,16 @@
Component component;
- final TypeBuilder dynamicType = new NamedTypeBuilder("dynamic", null);
+ // 'dynamic' is always nullable.
+ final TypeBuilder dynamicType = new NamedTypeBuilder(
+ "dynamic", const NullabilityBuilder.nullable(), null);
- final NamedTypeBuilder objectType = new NamedTypeBuilder("Object", null);
+ final NamedTypeBuilder objectType =
+ new NamedTypeBuilder("Object", const NullabilityBuilder.omitted(), null);
- final TypeBuilder bottomType = new NamedTypeBuilder("Null", null);
+ // Null is always nullable.
+ final TypeBuilder bottomType =
+ new NamedTypeBuilder("Null", const NullabilityBuilder.nullable(), null);
bool get legacyMode => backendTarget.legacyMode;
@@ -230,12 +236,13 @@
}
void breakCycle(ClassBuilder builder) {
- Class cls = builder.target;
+ Class cls = builder.cls;
cls.implementedTypes.clear();
cls.supertype = null;
cls.mixedInType = null;
- builder.supertype = new NamedTypeBuilder("Object", null)
- ..bind(objectClassBuilder);
+ builder.supertype =
+ new NamedTypeBuilder("Object", const NullabilityBuilder.omitted(), null)
+ ..bind(objectClassBuilder);
builder.interfaces = null;
builder.mixedInType = null;
}
@@ -350,7 +357,7 @@
declaration = problem.getFirstDeclaration();
}
if (declaration is ProcedureBuilder) {
- component.mainMethod = declaration.procedure;
+ component.mainMethod = declaration.actualProcedure;
} else if (declaration is DillMemberBuilder) {
if (declaration.member is Procedure) {
component.mainMethod = declaration.member;
@@ -374,10 +381,11 @@
while (iterator.moveNext()) {
Builder declaration = iterator.current;
if (declaration is SourceClassBuilder) {
- Class cls = declaration.target;
+ Class cls = declaration.cls;
if (cls != objectClass) {
cls.supertype ??= objectClass.asRawSupertype;
- declaration.supertype ??= new NamedTypeBuilder("Object", null)
+ declaration.supertype ??= new NamedTypeBuilder(
+ "Object", const NullabilityBuilder.omitted(), null)
..bind(objectClassBuilder);
}
if (declaration.isMixinApplication) {
@@ -394,7 +402,7 @@
void installSyntheticConstructors(List<SourceClassBuilder> builders) {
Class objectClass = this.objectClass;
for (SourceClassBuilder builder in builders) {
- if (builder.target != objectClass && !builder.isPatch) {
+ if (builder.cls != objectClass && !builder.isPatch) {
if (builder.isPatch ||
builder.isMixinDeclaration ||
builder.isExtension) {
@@ -419,9 +427,9 @@
assert(!builder.isMixinApplication);
assert(!builder.isExtension);
// TODO(askesc): Make this check light-weight in the absence of patches.
- if (builder.target.constructors.isNotEmpty) return;
- if (builder.target.redirectingFactoryConstructors.isNotEmpty) return;
- for (Procedure proc in builder.target.procedures) {
+ if (builder.cls.constructors.isNotEmpty) return;
+ if (builder.cls.redirectingFactoryConstructors.isNotEmpty) return;
+ for (Procedure proc in builder.cls.procedures) {
if (proc.isFactory) return;
}
@@ -430,13 +438,13 @@
/// >Iff no constructor is specified for a class C, it implicitly has a
/// >default constructor C() : super() {}, unless C is class Object.
// The superinitializer is installed below in [finishConstructors].
- builder.addSyntheticConstructor(makeDefaultConstructor(builder.target));
+ builder.addSyntheticConstructor(makeDefaultConstructor(builder.cls));
}
void installForwardingConstructors(SourceClassBuilder builder) {
assert(builder.isMixinApplication);
if (builder.library.loader != loader) return;
- if (builder.target.constructors.isNotEmpty) {
+ if (builder.cls.constructors.isNotEmpty) {
// These were installed by a subclass in the recursive call below.
return;
}
@@ -465,17 +473,17 @@
}
if (supertype is ClassBuilder) {
if (supertype.cls.constructors.isEmpty) {
- builder.addSyntheticConstructor(makeDefaultConstructor(builder.target));
+ builder.addSyntheticConstructor(makeDefaultConstructor(builder.cls));
} else {
Map<TypeParameter, DartType> substitutionMap =
- builder.getSubstitutionMap(supertype.target);
+ builder.getSubstitutionMap(supertype.cls);
for (Constructor constructor in supertype.cls.constructors) {
builder.addSyntheticConstructor(makeMixinApplicationConstructor(
- builder.target, builder.cls.mixin, constructor, substitutionMap));
+ builder.cls, builder.cls.mixin, constructor, substitutionMap));
}
}
} else if (supertype is InvalidTypeBuilder) {
- builder.addSyntheticConstructor(makeDefaultConstructor(builder.target));
+ builder.addSyntheticConstructor(makeDefaultConstructor(builder.cls));
} else {
unhandled("${supertype.runtimeType}", "installForwardingConstructors",
builder.charOffset, builder.fileUri);
@@ -564,19 +572,16 @@
void computeCoreTypes() {
List<Library> libraries = <Library>[];
- for (String platformLibrary in const [
+ for (String platformLibrary in [
"dart:_internal",
"dart:async",
- // TODO(askesc): When all backends support set literals, we no longer
- // need to index dart:collection, as it is only needed for desugaring of
- // const sets. We can remove it from this list at that time.
- "dart:collection",
"dart:core",
- "dart:mirrors"
+ "dart:mirrors",
+ ...backendTarget.extraIndexedLibraries
]) {
Uri uri = Uri.parse(platformLibrary);
- LibraryBuilder library = loader.builders[uri];
- if (library == null) {
+ LibraryBuilder libraryBuilder = loader.builders[uri];
+ if (libraryBuilder == null) {
// TODO(ahe): This is working around a bug in kernel_driver_test or
// kernel_driver.
bool found = false;
@@ -592,7 +597,7 @@
throw "Can't find $uri";
}
} else {
- libraries.add(library.target);
+ libraries.add(libraryBuilder.library);
}
}
Component platformLibraries =
@@ -605,7 +610,7 @@
void finishAllConstructors(List<SourceClassBuilder> builders) {
Class objectClass = this.objectClass;
for (SourceClassBuilder builder in builders) {
- Class cls = builder.target;
+ Class cls = builder.cls;
if (cls != objectClass) {
finishConstructors(builder);
}
@@ -613,11 +618,11 @@
ticker.logMs("Finished constructors");
}
- /// Ensure constructors of [cls] have the correct initializers and other
+ /// Ensure constructors of [builder] have the correct initializers and other
/// requirements.
void finishConstructors(SourceClassBuilder builder) {
if (builder.isPatch) return;
- Class cls = builder.target;
+ Class cls = builder.cls;
/// Quotes below are from [Dart Programming Language Specification, 4th
/// Edition](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-408.pdf):
@@ -783,19 +788,19 @@
loader.libraries,
new KernelDiagnosticReporter(loader),
logger: (String msg) => ticker.logMs(msg));
- if (loader.target.enableConstantUpdate2018) {
- TypeEnvironment environment =
- new TypeEnvironment(loader.coreTypes, loader.hierarchy);
- constants.transformLibraries(
- loader.libraries,
- backendTarget.constantsBackend(loader.coreTypes),
- environmentDefines,
- environment,
- new KernelConstantErrorReporter(loader),
- desugarSets: !backendTarget.supportsSetLiterals,
- errorOnUnevaluatedConstant: errorOnUnevaluatedConstant);
- ticker.logMs("Evaluated constants");
- }
+
+ TypeEnvironment environment =
+ new TypeEnvironment(loader.coreTypes, loader.hierarchy);
+ constants.transformLibraries(
+ loader.libraries,
+ backendTarget.constantsBackend(loader.coreTypes),
+ environmentDefines,
+ environment,
+ new KernelConstantErrorReporter(loader),
+ desugarSets: !backendTarget.supportsSetLiterals,
+ errorOnUnevaluatedConstant: errorOnUnevaluatedConstant);
+ ticker.logMs("Evaluated constants");
+
backendTarget.performModularTransformationsOnLibraries(
component,
loader.coreTypes,
diff --git a/pkg/front_end/lib/src/fasta/kernel/load_library_builder.dart b/pkg/front_end/lib/src/fasta/kernel/load_library_builder.dart
index c4e8e9998..c22f4d5 100644
--- a/pkg/front_end/lib/src/fasta/kernel/load_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/load_library_builder.dart
@@ -51,12 +51,12 @@
LoadLibrary expression = createLoadLibrary(charOffset, forest, null);
String prefix = expression.import.name;
tearoff = new Procedure(
- new Name('__loadLibrary_$prefix', parent.target),
+ new Name('__loadLibrary_$prefix', parent.library),
ProcedureKind.Method,
new FunctionNode(new ReturnStatement(expression),
returnType: new InterfaceType(parent.loader.coreTypes.futureClass,
<DartType>[const DynamicType()])),
- fileUri: parent.target.fileUri,
+ fileUri: parent.library.fileUri,
isStatic: true)
..startFileOffset = charOffset
..fileOffset = charOffset;
diff --git a/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart b/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart
index 6cab740..e7d57d6 100644
--- a/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart
@@ -113,7 +113,7 @@
int i = 0;
for (; i < elements.length; ++i) {
if (elements[i] is ControlFlowElement) break;
- elements[i] = elements[i].accept(this)..parent = node;
+ elements[i] = elements[i].accept<TreeNode>(this)..parent = node;
}
// If there were only expressions, we are done.
@@ -159,7 +159,8 @@
} else if (element is ForInElement) {
_translateForInElement(element, elementType, isSet, result, body);
} else {
- _addExpressionElement(element.accept(this), isSet, result, body);
+ _addExpressionElement(
+ element.accept<TreeNode>(this), isSet, result, body);
}
}
@@ -190,7 +191,8 @@
? elseStatements.first
: new Block(elseStatements);
}
- body.add(new IfStatement(element.condition.accept(this), thenBody, elseBody)
+ body.add(new IfStatement(
+ element.condition.accept<TreeNode>(this), thenBody, elseBody)
..fileOffset = element.fileOffset);
}
@@ -201,7 +203,7 @@
Statement loopBody =
statements.length == 1 ? statements.first : new Block(statements);
ForStatement loop = new ForStatement(element.variables,
- element.condition?.accept(this), element.updates, loopBody)
+ element.condition?.accept<TreeNode>(this), element.updates, loopBody)
..fileOffset = element.fileOffset;
transformList(loop.variables, this, loop);
transformList(loop.updates, this, loop);
@@ -215,7 +217,7 @@
if (prologue == null) {
statements = <Statement>[];
} else {
- prologue = prologue.accept(this);
+ prologue = prologue.accept<TreeNode>(this);
statements =
prologue is Block ? prologue.statements : <Statement>[prologue];
}
@@ -223,17 +225,17 @@
Statement loopBody =
statements.length == 1 ? statements.first : new Block(statements);
if (element.problem != null) {
- body.add(new ExpressionStatement(element.problem.accept(this)));
+ body.add(new ExpressionStatement(element.problem.accept<TreeNode>(this)));
}
body.add(new ForInStatement(
- element.variable, element.iterable.accept(this), loopBody,
+ element.variable, element.iterable.accept<TreeNode>(this), loopBody,
isAsync: element.isAsync)
..fileOffset = element.fileOffset);
}
void _translateSpreadElement(SpreadElement element, DartType elementType,
bool isSet, VariableDeclaration result, List<Statement> body) {
- Expression value = element.expression.accept(this);
+ Expression value = element.expression.accept<TreeNode>(this);
// Null-aware spreads require testing the subexpression's value.
VariableDeclaration temp;
if (element.isNullAware) {
@@ -314,7 +316,7 @@
int i = 0;
for (; i < node.entries.length; ++i) {
if (node.entries[i] is ControlFlowMapEntry) break;
- node.entries[i] = node.entries[i].accept(this)..parent = node;
+ node.entries[i] = node.entries[i].accept<TreeNode>(this)..parent = node;
}
// If there were no control-flow entries we are done.
@@ -350,7 +352,7 @@
} else if (entry is ForInMapEntry) {
_translateForInEntry(entry, keyType, valueType, result, body);
} else {
- _addNormalEntry(entry.accept(this), result, body);
+ _addNormalEntry(entry.accept<TreeNode>(this), result, body);
}
}
@@ -380,7 +382,7 @@
elseBody.length == 1 ? elseBody.first : new Block(elseBody);
}
body.add(new IfStatement(
- entry.condition.accept(this), thenStatement, elseStatement));
+ entry.condition.accept<TreeNode>(this), thenStatement, elseStatement));
}
void _translateForEntry(ForMapEntry entry, DartType keyType,
@@ -389,8 +391,8 @@
_translateEntry(entry.body, keyType, valueType, result, statements);
Statement loopBody =
statements.length == 1 ? statements.first : new Block(statements);
- ForStatement loop = new ForStatement(
- entry.variables, entry.condition?.accept(this), entry.updates, loopBody)
+ ForStatement loop = new ForStatement(entry.variables,
+ entry.condition?.accept<TreeNode>(this), entry.updates, loopBody)
..fileOffset = entry.fileOffset;
transformList(loop.variables, this, loop);
transformList(loop.updates, this, loop);
@@ -404,7 +406,7 @@
if (prologue == null) {
statements = <Statement>[];
} else {
- prologue = prologue.accept(this);
+ prologue = prologue.accept<TreeNode>(this);
statements =
prologue is Block ? prologue.statements : <Statement>[prologue];
}
@@ -412,17 +414,17 @@
Statement loopBody =
statements.length == 1 ? statements.first : new Block(statements);
if (entry.problem != null) {
- body.add(new ExpressionStatement(entry.problem.accept(this)));
+ body.add(new ExpressionStatement(entry.problem.accept<TreeNode>(this)));
}
body.add(new ForInStatement(
- entry.variable, entry.iterable.accept(this), loopBody,
+ entry.variable, entry.iterable.accept<TreeNode>(this), loopBody,
isAsync: entry.isAsync)
..fileOffset = entry.fileOffset);
}
void _translateSpreadEntry(SpreadMapEntry entry, DartType keyType,
DartType valueType, VariableDeclaration result, List<Statement> body) {
- Expression value = entry.expression.accept(this);
+ Expression value = entry.expression.accept<TreeNode>(this);
// Null-aware spreads require testing the subexpression's value.
VariableDeclaration temp;
if (entry.isNullAware) {
@@ -499,7 +501,7 @@
int i = 0;
for (; i < elements.length; ++i) {
if (elements[i] is ControlFlowElement) break;
- elements[i] = elements[i].accept(this)..parent = node;
+ elements[i] = elements[i].accept<TreeNode>(this)..parent = node;
}
// If there were only expressions, we are done.
@@ -524,7 +526,7 @@
parts.add(makeLiteral(currentPart));
currentPart = null;
}
- Expression spreadExpression = element.expression.accept(this);
+ Expression spreadExpression = element.expression.accept<TreeNode>(this);
if (element.isNullAware) {
VariableDeclaration temp =
new VariableDeclaration(null, initializer: spreadExpression);
@@ -544,10 +546,10 @@
parts.add(makeLiteral(currentPart));
currentPart = null;
}
- Expression condition = element.condition.accept(this);
- Expression then = makeLiteral([element.then]).accept(this);
+ Expression condition = element.condition.accept<TreeNode>(this);
+ Expression then = makeLiteral([element.then]).accept<TreeNode>(this);
Expression otherwise = element.otherwise != null
- ? makeLiteral([element.otherwise]).accept(this)
+ ? makeLiteral([element.otherwise]).accept<TreeNode>(this)
: makeLiteral([]);
parts.add(new ConditionalExpression(
condition, then, otherwise, const DynamicType()));
@@ -557,7 +559,7 @@
element.fileOffset, getFileUri(element));
} else {
currentPart ??= <Expression>[];
- currentPart.add(element.accept(this));
+ currentPart.add(element.accept<TreeNode>(this));
}
}
if (currentPart != null) {
@@ -573,7 +575,7 @@
int i = 0;
for (; i < node.entries.length; ++i) {
if (node.entries[i] is ControlFlowMapEntry) break;
- node.entries[i] = node.entries[i].accept(this)..parent = node;
+ node.entries[i] = node.entries[i].accept<TreeNode>(this)..parent = node;
}
// If there were no control-flow entries we are done.
@@ -595,7 +597,7 @@
parts.add(makeLiteral(currentPart));
currentPart = null;
}
- Expression spreadExpression = entry.expression.accept(this);
+ Expression spreadExpression = entry.expression.accept<TreeNode>(this);
if (entry.isNullAware) {
VariableDeclaration temp =
new VariableDeclaration(null, initializer: spreadExpression);
@@ -615,10 +617,10 @@
parts.add(makeLiteral(currentPart));
currentPart = null;
}
- Expression condition = entry.condition.accept(this);
- Expression then = makeLiteral([entry.then]).accept(this);
+ Expression condition = entry.condition.accept<TreeNode>(this);
+ Expression then = makeLiteral([entry.then]).accept<TreeNode>(this);
Expression otherwise = entry.otherwise != null
- ? makeLiteral([entry.otherwise]).accept(this)
+ ? makeLiteral([entry.otherwise]).accept<TreeNode>(this)
: makeLiteral([]);
parts.add(new ConditionalExpression(
condition, then, otherwise, const DynamicType()));
@@ -628,7 +630,7 @@
entry.fileOffset, getFileUri(entry));
} else {
currentPart ??= <MapEntry>[];
- currentPart.add(entry.accept(this));
+ currentPart.add(entry.accept<TreeNode>(this));
}
}
if (currentPart != null) {
diff --git a/pkg/front_end/lib/src/fasta/kernel/transform_set_literals.dart b/pkg/front_end/lib/src/fasta/kernel/transform_set_literals.dart
index 3480b2b..ab150cf 100644
--- a/pkg/front_end/lib/src/fasta/kernel/transform_set_literals.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/transform_set_literals.dart
@@ -9,19 +9,11 @@
import 'package:kernel/ast.dart'
show
Arguments,
- Class,
- Constructor,
- ConstructorInvocation,
- DartType,
Expression,
InterfaceType,
Let,
- Library,
- MapEntry,
- MapLiteral,
MethodInvocation,
Name,
- NullLiteral,
Procedure,
SetLiteral,
StaticInvocation,
@@ -40,11 +32,8 @@
// TODO(askesc): Delete this class when all backends support set literals.
class SetLiteralTransformer extends Transformer {
final CoreTypes coreTypes;
- final DartType nullType;
final Procedure setFactory;
final Procedure addMethod;
- final Constructor unmodifiableSetConstructor;
- final bool transformConst;
static Procedure _findSetFactory(CoreTypes coreTypes) {
Procedure factory = coreTypes.index.getMember('dart:core', 'Set', '');
@@ -56,68 +45,32 @@
return coreTypes.index.getMember('dart:core', 'Set', 'add');
}
- static Constructor _findUnmodifiableSetConstructor(SourceLoader loader) {
- // We should not generally dig into libraries like this, and we should
- // avoid dependencies on libraries other than the ones indexed by
- // CoreTypes. This is a temporary solution until all backends have
- // implemented support for set literals.
- Uri collectionUri = Uri.parse("dart:collection");
- Library collectionLibrary = loader.builders[collectionUri].target;
- for (int i = 0; i < collectionLibrary.classes.length; i++) {
- Class classNode = collectionLibrary.classes[i];
- if (classNode.name == "_UnmodifiableSet") {
- for (int j = 0; j < collectionLibrary.classes.length; j++) {
- Constructor constructor = classNode.constructors[j];
- if (constructor.name.name.isEmpty) {
- return constructor;
- }
- }
- }
- }
- return null;
- }
-
- SetLiteralTransformer(SourceLoader loader, {this.transformConst: true})
+ SetLiteralTransformer(SourceLoader loader)
: coreTypes = loader.coreTypes,
- nullType = new InterfaceType(loader.coreTypes.nullClass, []),
setFactory = _findSetFactory(loader.coreTypes),
- addMethod = _findAddMethod(loader.coreTypes),
- unmodifiableSetConstructor = _findUnmodifiableSetConstructor(loader);
+ addMethod = _findAddMethod(loader.coreTypes);
TreeNode visitSetLiteral(SetLiteral node) {
- if (node.isConst) {
- if (!transformConst) return node;
- List<MapEntry> entries = new List<MapEntry>(node.expressions.length);
- for (int i = 0; i < node.expressions.length; i++) {
- // expression_i: null
- Expression entry = node.expressions[i].accept(this);
- entries[i] = new MapEntry(entry, new NullLiteral());
- }
- Expression mapExp = new MapLiteral(entries,
- keyType: node.typeArgument, valueType: nullType, isConst: true);
- return new ConstructorInvocation(unmodifiableSetConstructor,
- new Arguments([mapExp], types: [node.typeArgument]),
- isConst: true);
- } else {
- // Outermost declaration of let chain: Set<E> setVar = new Set<E>();
- VariableDeclaration setVar = new VariableDeclaration.forValue(
- new StaticInvocation(
- setFactory, new Arguments([], types: [node.typeArgument])),
- type: new InterfaceType(coreTypes.setClass, [node.typeArgument]));
- // Innermost body of let chain: setVar
- Expression setExp = new VariableGet(setVar);
- for (int i = node.expressions.length - 1; i >= 0; i--) {
- // let _ = setVar.add(expression) in rest
- Expression entry = node.expressions[i].accept(this);
- setExp = new Let(
- new VariableDeclaration.forValue(new MethodInvocation(
- new VariableGet(setVar),
- new Name("add"),
- new Arguments([entry]),
- addMethod)),
- setExp);
- }
- return new Let(setVar, setExp);
+ if (node.isConst) return node;
+
+ // Outermost declaration of let chain: Set<E> setVar = new Set<E>();
+ VariableDeclaration setVar = new VariableDeclaration.forValue(
+ new StaticInvocation(
+ setFactory, new Arguments([], types: [node.typeArgument])),
+ type: new InterfaceType(coreTypes.setClass, [node.typeArgument]));
+ // Innermost body of let chain: setVar
+ Expression setExp = new VariableGet(setVar);
+ for (int i = node.expressions.length - 1; i >= 0; i--) {
+ // let _ = setVar.add(expression) in rest
+ Expression entry = node.expressions[i].accept<TreeNode>(this);
+ setExp = new Let(
+ new VariableDeclaration.forValue(new MethodInvocation(
+ new VariableGet(setVar),
+ new Name("add"),
+ new Arguments([entry]),
+ addMethod)),
+ setExp);
}
+ return new Let(setVar, setExp);
}
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart b/pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart
index 58bd5a7..e176829 100644
--- a/pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart
@@ -145,7 +145,8 @@
}
}
if (arguments != null) {
- return new NamedTypeBuilder(type.name, arguments)..bind(type.declaration);
+ return new NamedTypeBuilder(type.name, type.nullabilityBuilder, arguments)
+ ..bind(type.declaration);
}
return type;
}
@@ -411,7 +412,7 @@
TypeDeclarationBuilder declaration = type.declaration;
if (declaration is DillClassBuilder) {
bool hasInbound = false;
- List<TypeParameter> typeParameters = declaration.target.typeParameters;
+ List<TypeParameter> typeParameters = declaration.cls.typeParameters;
for (int i = 0; i < typeParameters.length && !hasInbound; ++i) {
if (containsTypeVariable(
typeParameters[i].bound, typeParameters.toSet())) {
@@ -424,7 +425,7 @@
}
} else if (declaration is DillTypeAliasBuilder) {
bool hasInbound = false;
- List<TypeParameter> typeParameters = declaration.target.typeParameters;
+ List<TypeParameter> typeParameters = declaration.typedef.typeParameters;
for (int i = 0; i < typeParameters.length && !hasInbound; ++i) {
if (containsTypeVariable(
typeParameters[i].bound, typeParameters.toSet())) {
diff --git a/pkg/front_end/lib/src/fasta/kernel/type_builder_computer.dart b/pkg/front_end/lib/src/fasta/kernel/type_builder_computer.dart
index ba72be2..5f6dfb0 100644
--- a/pkg/front_end/lib/src/fasta/kernel/type_builder_computer.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/type_builder_computer.dart
@@ -30,6 +30,7 @@
NamedTypeBuilder,
TypeVariableBuilder,
LibraryBuilder,
+ NullabilityBuilder,
TypeBuilder,
VoidTypeBuilder;
@@ -51,13 +52,17 @@
}
TypeBuilder visitDynamicType(DynamicType node) {
- return new NamedTypeBuilder("dynamic", null)
+ // 'dynamic' is always nullable.
+ return new NamedTypeBuilder(
+ "dynamic", const NullabilityBuilder.nullable(), null)
..bind(
new DynamicTypeBuilder(const DynamicType(), loader.coreLibrary, -1));
}
TypeBuilder visitVoidType(VoidType node) {
- return new NamedTypeBuilder("void", null)
+ // 'void' is always nullable.
+ return new NamedTypeBuilder(
+ "void", const NullabilityBuilder.nullable(), null)
..bind(new VoidTypeBuilder(const VoidType(), loader.coreLibrary, -1));
}
@@ -76,7 +81,11 @@
arguments[i] = kernelArguments[i].accept(this);
}
}
- return new NamedTypeBuilder(cls.name, arguments)..bind(cls);
+ // TODO(dmitryas): Compute the nullabilityBuilder field for the result from
+ // the nullability field of 'node'.
+ return new NamedTypeBuilder(
+ cls.name, const NullabilityBuilder.pendingImplementation(), arguments)
+ ..bind(cls);
}
@override
@@ -114,7 +123,10 @@
Class kernelClass = parameter.parent;
Library kernelLibrary = kernelClass.enclosingLibrary;
LibraryBuilder library = loader.builders[kernelLibrary.importUri];
- return new NamedTypeBuilder(parameter.name, null)
+ // TODO(dmitryas): Compute the nullabilityBuilder field for the result from
+ // the nullability field of 'node'.
+ return new NamedTypeBuilder(
+ parameter.name, const NullabilityBuilder.pendingImplementation(), null)
..bind(new TypeVariableBuilder.fromKernel(parameter, library));
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/types.dart b/pkg/front_end/lib/src/fasta/kernel/types.dart
index de2ee77..a70d416 100644
--- a/pkg/front_end/lib/src/fasta/kernel/types.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/types.dart
@@ -57,10 +57,10 @@
}
if (t is InterfaceType) {
Class cls = t.classNode;
- if (cls == hierarchy.objectKernelClass) {
+ if (cls == hierarchy.objectClass) {
return true; // Rule 2.
}
- if (cls == hierarchy.futureOrKernelClass) {
+ if (cls == hierarchy.futureOrClass) {
const IsFutureOrSubtypeOf relation = const IsFutureOrSubtypeOf();
if (s is DynamicType) {
return relation.isDynamicRelated(
@@ -68,7 +68,7 @@
} else if (s is VoidType) {
return relation.isVoidRelated(s, sNullability, t, tNullability, this);
} else if (s is InterfaceType) {
- return s.classNode == hierarchy.futureOrKernelClass
+ return s.classNode == hierarchy.futureOrClass
? relation.isFutureOrRelated(
s, sNullability, t, tNullability, this)
: relation.isInterfaceRelated(
@@ -94,7 +94,7 @@
} else if (s is VoidType) {
return relation.isVoidRelated(s, sNullability, t, tNullability, this);
} else if (s is InterfaceType) {
- return s.classNode == hierarchy.futureOrKernelClass
+ return s.classNode == hierarchy.futureOrClass
? relation.isFutureOrRelated(
s, sNullability, t, tNullability, this)
: relation.isInterfaceRelated(
@@ -121,7 +121,7 @@
} else if (s is VoidType) {
return relation.isVoidRelated(s, sNullability, t, tNullability, this);
} else if (s is InterfaceType) {
- return s.classNode == hierarchy.futureOrKernelClass
+ return s.classNode == hierarchy.futureOrClass
? relation.isFutureOrRelated(s, sNullability, t, tNullability, this)
: relation.isInterfaceRelated(
s, sNullability, t, tNullability, this);
@@ -148,7 +148,7 @@
} else if (s is VoidType) {
return relation.isVoidRelated(s, sNullability, t, tNullability, this);
} else if (s is InterfaceType) {
- return s.classNode == hierarchy.futureOrKernelClass
+ return s.classNode == hierarchy.futureOrClass
? relation.isFutureOrRelated(
s, sNullability, t, tNullability, this)
: relation.isInterfaceRelated(
@@ -175,7 +175,7 @@
} else if (s is VoidType) {
return relation.isVoidRelated(s, sNullability, t, tNullability, this);
} else if (s is InterfaceType) {
- return s.classNode == hierarchy.futureOrKernelClass
+ return s.classNode == hierarchy.futureOrClass
? relation.isFutureOrRelated(
s, sNullability, t, tNullability, this)
: relation.isInterfaceRelated(
@@ -202,7 +202,7 @@
} else if (s is VoidType) {
return relation.isVoidRelated(s, sNullability, t, tNullability, this);
} else if (s is InterfaceType) {
- return s.classNode == hierarchy.futureOrKernelClass
+ return s.classNode == hierarchy.futureOrClass
? relation.isFutureOrRelated(s, sNullability, t, tNullability, this)
: relation.isInterfaceRelated(
s, sNullability, t, tNullability, this);
@@ -283,7 +283,7 @@
@override
bool isInterfaceRelated(InterfaceType s, Nullability sNullability,
InterfaceType t, Nullability tNullability, Types types) {
- if (s.classNode == types.hierarchy.nullKernelClass) {
+ if (s.classNode == types.hierarchy.nullClass) {
// This is an optimization, to avoid instantiating unnecessary type
// arguments in getKernelTypeAsInstanceOf.
return true;
@@ -316,7 +316,7 @@
return false; // Rule 7.1
}
if (!types.isSubtypeOfKernel(
- new InterfaceType(types.hierarchy.futureKernelClass, arguments), t)) {
+ new InterfaceType(types.hierarchy.futureClass, arguments), t)) {
return false; // Rule 7.2
}
return true;
@@ -341,7 +341,7 @@
@override
bool isFunctionRelated(FunctionType s, Nullability sNullability,
InterfaceType t, Nullability tNullability, Types types) {
- return t.classNode == types.hierarchy.functionKernelClass; // Rule 14.
+ return t.classNode == types.hierarchy.functionClass; // Rule 14.
}
@override
@@ -443,7 +443,7 @@
@override
bool isInterfaceRelated(InterfaceType s, Nullability sNullability,
FunctionType t, Nullability tNullability, Types types) {
- return s.classNode == types.hierarchy.nullKernelClass; // Rule 4.
+ return s.classNode == types.hierarchy.nullClass; // Rule 4.
}
@override
@@ -518,7 +518,7 @@
@override
bool isInterfaceRelated(InterfaceType s, Nullability sNullability,
TypeParameterType t, Nullability tNullability, Types types) {
- return s.classNode == types.hierarchy.nullKernelClass; // Rule 4.
+ return s.classNode == types.hierarchy.nullClass; // Rule 4.
}
@override
@@ -628,7 +628,7 @@
}
// Rule 10.
return types.isSubtypeOfKernel(
- s, new InterfaceType(types.hierarchy.futureKernelClass, arguments));
+ s, new InterfaceType(types.hierarchy.futureClass, arguments));
}
@override
@@ -673,7 +673,7 @@
// Rule 10.
return types.isSubtypeOfKernel(
- s, new InterfaceType(types.hierarchy.futureKernelClass, arguments));
+ s, new InterfaceType(types.hierarchy.futureClass, arguments));
}
@override
@@ -746,7 +746,7 @@
TypeParameterType intersection,
Nullability intersectionNullability,
Types types) {
- return s.classNode == types.hierarchy.nullKernelClass; // Rule 4.
+ return s.classNode == types.hierarchy.nullClass; // Rule 4.
}
@override
diff --git a/pkg/front_end/lib/src/fasta/kernel/utils.dart b/pkg/front_end/lib/src/fasta/kernel/utils.dart
index 7f9f97d..8262018 100644
--- a/pkg/front_end/lib/src/fasta/kernel/utils.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/utils.dart
@@ -12,14 +12,15 @@
import 'package:kernel/ast.dart'
show
+ Class,
+ Component,
DartType,
Library,
- Component,
Procedure,
- Class,
+ Supertype,
+ TreeNode,
TypeParameter,
- TypeParameterType,
- Supertype;
+ TypeParameterType;
import 'package:kernel/binary/ast_to_binary.dart' show BinaryPrinter;
@@ -78,8 +79,11 @@
const String kDebugClassName = "#DebugClass";
Component createExpressionEvaluationComponent(Procedure procedure) {
- Library fakeLibrary =
- new Library(new Uri(scheme: 'evaluate', path: 'source'));
+ Library realLibrary = procedure.enclosingLibrary;
+
+ Library fakeLibrary = new Library(new Uri(scheme: 'evaluate', path: 'source'))
+ ..setLanguageVersion(
+ realLibrary.languageVersionMajor, realLibrary.languageVersionMinor);
if (procedure.parent is Class) {
Class realClass = procedure.parent;
@@ -98,7 +102,7 @@
typeSubstitution: typeSubstitution, typeParams: typeParams);
for (TypeParameter typeParam in realClass.typeParameters) {
- fakeClass.typeParameters.add(typeParam.accept(cloner));
+ fakeClass.typeParameters.add(typeParam.accept<TreeNode>(cloner));
}
if (realClass.supertype != null) {
@@ -109,7 +113,7 @@
}
// Rebind the type parameters in the procedure.
- procedure = procedure.accept(cloner);
+ procedure = procedure.accept<TreeNode>(cloner);
procedure.parent = fakeClass;
fakeClass.procedures.add(procedure);
fakeLibrary.classes.add(fakeClass);
diff --git a/pkg/front_end/lib/src/fasta/kernel/verifier.dart b/pkg/front_end/lib/src/fasta/kernel/verifier.dart
index f24a1ce..ac24a09 100644
--- a/pkg/front_end/lib/src/fasta/kernel/verifier.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/verifier.dart
@@ -9,6 +9,7 @@
AsExpression,
Class,
Component,
+ DartType,
ExpressionStatement,
Field,
Let,
@@ -32,7 +33,7 @@
import '../severity.dart' show Severity;
-import '../type_inference/type_schema.dart' show TypeSchemaVisitor, UnknownType;
+import '../type_inference/type_schema.dart' show UnknownType;
import 'kernel_shadow_ast.dart' show SyntheticExpressionJudgment;
@@ -47,8 +48,7 @@
return verifier.errors;
}
-class FastaVerifyingVisitor extends VerifyingVisitor
- implements TypeSchemaVisitor<void> {
+class FastaVerifyingVisitor extends VerifyingVisitor {
final List<LocatedMessage> errors = <LocatedMessage>[];
Uri fileUri;
@@ -174,9 +174,12 @@
}
@override
- visitUnknownType(UnknownType node) {
- // Note: we can't pass [node] to [problem] because it's not a [TreeNode].
- problem(null, "Unexpected appearance of the unknown type.");
+ defaultDartType(DartType node) {
+ if (node is UnknownType) {
+ // Note: we can't pass [node] to [problem] because it's not a [TreeNode].
+ problem(null, "Unexpected appearance of the unknown type.");
+ }
+ super.defaultDartType(node);
}
@override
diff --git a/pkg/front_end/lib/src/fasta/loader.dart b/pkg/front_end/lib/src/fasta/loader.dart
index b1ff995..7177fc3 100644
--- a/pkg/front_end/lib/src/fasta/loader.dart
+++ b/pkg/front_end/lib/src/fasta/loader.dart
@@ -11,10 +11,16 @@
import 'package:kernel/ast.dart' show Class, DartType, Library;
import 'builder/builder.dart'
- show ClassBuilder, Builder, LibraryBuilder, TypeBuilder;
+ show Builder, ClassBuilder, LibraryBuilder, Scope, TypeBuilder;
+
+import 'builder/declaration_builder.dart' show DeclarationBuilder;
+
+import 'builder/modifier_builder.dart' show ModifierBuilder;
import 'crash.dart' show firstSourceUri;
+import 'kernel/body_builder.dart' show BodyBuilder;
+
import 'messages.dart'
show
FormattedMessage,
@@ -158,6 +164,11 @@
}
LibraryBuilder library =
target.createLibraryBuilder(uri, fileUri, origin);
+ if (library == null) {
+ throw new StateError("createLibraryBuilder for uri $uri, "
+ "fileUri $fileUri returned null.");
+ }
+
if (hasPackageSpecifiedLanguageVersion) {
library.setLanguageVersion(packageSpecifiedLanguageVersionMajor,
packageSpecifiedLanguageVersionMinor,
@@ -350,4 +361,14 @@
ClassBuilder computeClassBuilderFromTargetClass(Class cls);
TypeBuilder computeTypeBuilder(DartType type);
+
+ BodyBuilder createBodyBuilderForOutlineExpression(
+ LibraryBuilder library,
+ DeclarationBuilder declarationBuilder,
+ ModifierBuilder member,
+ Scope scope,
+ Uri fileUri) {
+ return new BodyBuilder.forOutlineExpression(
+ library, declarationBuilder, member, scope, fileUri);
+ }
}
diff --git a/pkg/front_end/lib/src/fasta/parser.dart b/pkg/front_end/lib/src/fasta/parser.dart
index 0561820..950a70c 100644
--- a/pkg/front_end/lib/src/fasta/parser.dart
+++ b/pkg/front_end/lib/src/fasta/parser.dart
@@ -24,7 +24,7 @@
export 'parser/listener.dart' show Listener;
-export 'parser/class_kind.dart' show ClassKind;
+export 'parser/declaration_kind.dart' show DeclarationKind;
export 'parser/member_kind.dart' show MemberKind;
diff --git a/pkg/front_end/lib/src/fasta/parser/class_kind.dart b/pkg/front_end/lib/src/fasta/parser/declaration_kind.dart
similarity index 70%
rename from pkg/front_end/lib/src/fasta/parser/class_kind.dart
rename to pkg/front_end/lib/src/fasta/parser/declaration_kind.dart
index e5873ad..7037020 100644
--- a/pkg/front_end/lib/src/fasta/parser/class_kind.dart
+++ b/pkg/front_end/lib/src/fasta/parser/declaration_kind.dart
@@ -1,10 +1,11 @@
-// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// Copyright (c) 2019, 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.
-library fasta.parser.class_kind;
+enum DeclarationKind {
+ /// A top level declaration.
+ TopLevel,
-enum ClassKind {
/// A class declaration. Not including a named mixin declaration.
Class,
diff --git a/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart b/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart
index ed2ea4e..e569a14 100644
--- a/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart
+++ b/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart
@@ -71,13 +71,13 @@
}
@override
- void beginClassOrMixinBody(ClassKind kind, Token token) {
+ void beginClassOrMixinBody(DeclarationKind kind, Token token) {
listener?.beginClassOrMixinBody(kind, token);
}
@override
- void beginClassOrNamedMixinApplication(Token token) {
- listener?.beginClassOrNamedMixinApplication(token);
+ void beginClassOrNamedMixinApplicationPrelude(Token token) {
+ listener?.beginClassOrNamedMixinApplicationPrelude(token);
}
@override
@@ -146,6 +146,11 @@
}
@override
+ void beginExtensionDeclarationPrelude(Token extensionKeyword) {
+ listener?.beginExtensionDeclarationPrelude(extensionKeyword);
+ }
+
+ @override
void beginExtensionDeclaration(Token extensionKeyword, Token name) {
listener?.beginExtensionDeclaration(extensionKeyword, name);
}
@@ -480,12 +485,6 @@
}
@override
- void endInvalidAwaitExpression(
- Token beginToken, Token endToken, MessageCode errorCode) {
- listener?.endInvalidAwaitExpression(beginToken, endToken, errorCode);
- }
-
- @override
void endBinaryExpression(Token token) {
listener?.endBinaryExpression(token);
}
@@ -516,13 +515,40 @@
}
@override
+ void endClassConstructor(Token getOrSet, Token beginToken, Token beginParam,
+ Token beginInitializers, Token endToken) {
+ listener?.endClassConstructor(
+ getOrSet, beginToken, beginParam, beginInitializers, endToken);
+ }
+
+ @override
void endClassDeclaration(Token beginToken, Token endToken) {
listener?.endClassDeclaration(beginToken, endToken);
}
@override
+ void endClassFactoryMethod(
+ Token beginToken, Token factoryKeyword, Token endToken) {
+ listener?.endClassFactoryMethod(beginToken, factoryKeyword, endToken);
+ }
+
+ @override
+ void endClassFields(Token staticToken, Token covariantToken, Token lateToken,
+ Token varFinalOrConst, int count, Token beginToken, Token endToken) {
+ listener?.endClassFields(staticToken, covariantToken, lateToken,
+ varFinalOrConst, count, beginToken, endToken);
+ }
+
+ @override
+ void endClassMethod(Token getOrSet, Token beginToken, Token beginParam,
+ Token beginInitializers, Token endToken) {
+ listener?.endClassMethod(
+ getOrSet, beginToken, beginParam, beginInitializers, endToken);
+ }
+
+ @override
void endClassOrMixinBody(
- ClassKind kind, int memberCount, Token beginToken, Token endToken) {
+ DeclarationKind kind, int memberCount, Token beginToken, Token endToken) {
listener?.endClassOrMixinBody(kind, memberCount, beginToken, endToken);
}
@@ -594,15 +620,42 @@
}
@override
+ void endExtensionConstructor(Token getOrSet, Token beginToken,
+ Token beginParam, Token beginInitializers, Token endToken) {
+ listener?.endExtensionConstructor(
+ getOrSet, beginToken, beginParam, beginInitializers, endToken);
+ }
+
+ @override
void endExtensionDeclaration(
Token extensionKeyword, Token onKeyword, Token token) {
listener?.endExtensionDeclaration(extensionKeyword, onKeyword, token);
}
@override
- void endFactoryMethod(
+ void endExtensionFactoryMethod(
Token beginToken, Token factoryKeyword, Token endToken) {
- listener?.endFactoryMethod(beginToken, factoryKeyword, endToken);
+ listener?.endExtensionFactoryMethod(beginToken, factoryKeyword, endToken);
+ }
+
+ @override
+ void endExtensionFields(
+ Token staticToken,
+ Token covariantToken,
+ Token lateToken,
+ Token varFinalOrConst,
+ int count,
+ Token beginToken,
+ Token endToken) {
+ listener?.endExtensionFields(staticToken, covariantToken, lateToken,
+ varFinalOrConst, count, beginToken, endToken);
+ }
+
+ @override
+ void endExtensionMethod(Token getOrSet, Token beginToken, Token beginParam,
+ Token beginInitializers, Token endToken) {
+ listener?.endExtensionMethod(
+ getOrSet, beginToken, beginParam, beginInitializers, endToken);
}
@override
@@ -611,13 +664,6 @@
}
@override
- void endFields(Token staticToken, Token covariantToken, Token lateToken,
- Token varFinalOrConst, int count, Token beginToken, Token endToken) {
- listener?.endFields(staticToken, covariantToken, lateToken, varFinalOrConst,
- count, beginToken, endToken);
- }
-
- @override
void endForControlFlow(Token token) {
listener?.endForControlFlow(token);
}
@@ -748,6 +794,12 @@
}
@override
+ void endInvalidAwaitExpression(
+ Token beginToken, Token endToken, MessageCode errorCode) {
+ listener?.endInvalidAwaitExpression(beginToken, endToken, errorCode);
+ }
+
+ @override
void endLabeledStatement(int labelCount) {
listener?.endLabeledStatement(labelCount);
}
@@ -788,9 +840,9 @@
}
@override
- void endMethod(Token getOrSet, Token beginToken, Token beginParam,
+ void endMixinConstructor(Token getOrSet, Token beginToken, Token beginParam,
Token beginInitializers, Token endToken) {
- listener?.endMethod(
+ listener?.endMixinConstructor(
getOrSet, beginToken, beginParam, beginInitializers, endToken);
}
@@ -800,6 +852,26 @@
}
@override
+ void endMixinFactoryMethod(
+ Token beginToken, Token factoryKeyword, Token endToken) {
+ listener?.endMixinFactoryMethod(beginToken, factoryKeyword, endToken);
+ }
+
+ @override
+ void endMixinFields(Token staticToken, Token covariantToken, Token lateToken,
+ Token varFinalOrConst, int count, Token beginToken, Token endToken) {
+ listener?.endMixinFields(staticToken, covariantToken, lateToken,
+ varFinalOrConst, count, beginToken, endToken);
+ }
+
+ @override
+ void endMixinMethod(Token getOrSet, Token beginToken, Token beginParam,
+ Token beginInitializers, Token endToken) {
+ listener?.endMixinMethod(
+ getOrSet, beginToken, beginParam, beginInitializers, endToken);
+ }
+
+ @override
void endNamedFunctionExpression(Token endToken) {
listener?.endNamedFunctionExpression(endToken);
}
diff --git a/pkg/front_end/lib/src/fasta/parser/listener.dart b/pkg/front_end/lib/src/fasta/parser/listener.dart
index 6312ccd..7d24308 100644
--- a/pkg/front_end/lib/src/fasta/parser/listener.dart
+++ b/pkg/front_end/lib/src/fasta/parser/listener.dart
@@ -19,7 +19,7 @@
import 'identifier_context.dart' show IdentifierContext;
-import 'class_kind.dart' show ClassKind;
+import 'declaration_kind.dart' show DeclarationKind;
import 'member_kind.dart' show MemberKind;
@@ -91,23 +91,28 @@
/// Handle the start of the body of a class, mixin or extension declaration
/// beginning at [token]. The actual kind of declaration is indicated by
/// [kind].
- void beginClassOrMixinBody(ClassKind kind, Token token) {}
+ void beginClassOrMixinBody(DeclarationKind kind, Token token) {}
/// Handle the end of the body of a class, mixin or extension declaration.
/// The only substructures are the class, mixin or extension members.
///
/// The actual kind of declaration is indicated by [kind].
void endClassOrMixinBody(
- ClassKind kind, int memberCount, Token beginToken, Token endToken) {
+ DeclarationKind kind, int memberCount, Token beginToken, Token endToken) {
logEvent("ClassOrMixinBody");
}
/// Called before parsing a class or named mixin application.
- void beginClassOrNamedMixinApplication(Token token) {}
+ ///
+ /// At this point only the `class` keyword have been seen, so we know a
+ /// declaration is coming but not its name or type parameter declarations.
+ void beginClassOrNamedMixinApplicationPrelude(Token token) {}
/// Handle the beginning of a class declaration.
/// [begin] may be the same as [name], or may point to modifiers
/// (or extraneous modifiers in the case of recovery) preceding [name].
+ ///
+ /// At this point we have parsed the name and type parameter declarations.
void beginClassDeclaration(Token begin, Token abstractToken, Token name) {}
/// Handle an extends clause in a class declaration. Substructures:
@@ -195,7 +200,15 @@
/// Handle the beginning of an extension methods declaration. Substructures:
/// - metadata
+ ///
+ /// At this point only the `extension` keyword have been seen, so we know a
+ /// declaration is coming but not its name or type parameter declarations.
+ void beginExtensionDeclarationPrelude(Token extensionKeyword) {}
+
+ /// Handle the beginning of an extension methods declaration. Substructures:
/// - type variables
+ ///
+ /// At this point we have parsed the name and type parameter declarations.
void beginExtensionDeclaration(Token extensionKeyword, Token name) {}
/// Handle the end of an extension methods declaration. Substructures:
@@ -295,9 +308,21 @@
void beginFactoryMethod(
Token lastConsumed, Token externalToken, Token constToken) {}
- void endFactoryMethod(
+ void endClassFactoryMethod(
Token beginToken, Token factoryKeyword, Token endToken) {
- logEvent("FactoryMethod");
+ logEvent("ClassFactoryMethod");
+ }
+
+ void endMixinFactoryMethod(
+ Token beginToken, Token factoryKeyword, Token endToken) {
+ // TODO(danrubel): push implementation into subclasses
+ endClassFactoryMethod(beginToken, factoryKeyword, endToken);
+ }
+
+ void endExtensionFactoryMethod(
+ Token beginToken, Token factoryKeyword, Token endToken) {
+ // TODO(danrubel): push implementation into subclasses
+ endClassFactoryMethod(beginToken, factoryKeyword, endToken);
}
void beginFormalParameter(Token token, MemberKind kind, Token requiredToken,
@@ -325,18 +350,52 @@
logEvent("FormalParameters");
}
- /// Handle the end of a field declaration. Substructures:
+ /// Handle the end of a class field declaration. Substructures:
/// - Metadata
/// - Modifiers
/// - Type
/// - Variable declarations (count times)
///
/// Doesn't have a corresponding begin event, use [beginMember] instead.
- void endFields(Token staticToken, Token covariantToken, Token lateToken,
+ void endClassFields(Token staticToken, Token covariantToken, Token lateToken,
Token varFinalOrConst, int count, Token beginToken, Token endToken) {
logEvent("Fields");
}
+ /// Handle the end of a mixin field declaration. Substructures:
+ /// - Metadata
+ /// - Modifiers
+ /// - Type
+ /// - Variable declarations (count times)
+ ///
+ /// Doesn't have a corresponding begin event, use [beginMember] instead.
+ void endMixinFields(Token staticToken, Token covariantToken, Token lateToken,
+ Token varFinalOrConst, int count, Token beginToken, Token endToken) {
+ // TODO(danrubel): push implementation into subclasses
+ endClassFields(staticToken, covariantToken, lateToken, varFinalOrConst,
+ count, beginToken, endToken);
+ }
+
+ /// Handle the end of a extension field declaration. Substructures:
+ /// - Metadata
+ /// - Modifiers
+ /// - Type
+ /// - Variable declarations (count times)
+ ///
+ /// Doesn't have a corresponding begin event, use [beginMember] instead.
+ void endExtensionFields(
+ Token staticToken,
+ Token covariantToken,
+ Token lateToken,
+ Token varFinalOrConst,
+ int count,
+ Token beginToken,
+ Token endToken) {
+ // TODO(danrubel): push implementation into subclasses
+ endClassFields(staticToken, covariantToken, lateToken, varFinalOrConst,
+ count, beginToken, endToken);
+ }
+
/// Marks that the grammar term `forInitializerStatement` has been parsed and
/// it was an empty statement.
void handleForInitializerEmptyStatement(Token token) {
@@ -514,6 +573,8 @@
/// Handle the beginning of a named mixin application.
/// [beginToken] may be the same as [name], or may point to modifiers
/// (or extraneous modifiers in the case of recovery) preceding [name].
+ ///
+ /// At this point we have parsed the name and type parameter declarations.
void beginNamedMixinApplication(
Token begin, Token abstractToken, Token name) {}
@@ -749,7 +810,10 @@
}
/// This event is added for convenience. Normally, one should override
- /// [endMethod] or [endFields] instead.
+ /// [endClassFields], [endMixinFields], [endExtensionFields],
+ /// [endClassMethod], [endMixinMethod], [endExtensionMethod],
+ /// [endClassConstructor], [endMixinConstructor],
+ /// or [endExtensionConstructor] instead.
void endMember() {
logEvent("Member");
}
@@ -759,7 +823,7 @@
void beginMethod(Token externalToken, Token staticToken, Token covariantToken,
Token varFinalOrConst, Token getOrSet, Token name) {}
- /// Handle the end of a method declaration. Substructures:
+ /// Handle the end of a class method declaration. Substructures:
/// - metadata
/// - return type
/// - method name (identifier, possibly qualified)
@@ -768,9 +832,89 @@
/// - initializers
/// - async marker
/// - body
- void endMethod(Token getOrSet, Token beginToken, Token beginParam,
+ void endClassMethod(Token getOrSet, Token beginToken, Token beginParam,
Token beginInitializers, Token endToken) {
- logEvent("Method");
+ logEvent("ClassMethod");
+ }
+
+ /// Handle the end of a mixin method declaration. Substructures:
+ /// - metadata
+ /// - return type
+ /// - method name (identifier, possibly qualified)
+ /// - type variables
+ /// - formal parameters
+ /// - initializers
+ /// - async marker
+ /// - body
+ void endMixinMethod(Token getOrSet, Token beginToken, Token beginParam,
+ Token beginInitializers, Token endToken) {
+ // TODO(danrubel): push implementation into subclasses
+ endClassMethod(
+ getOrSet, beginToken, beginParam, beginInitializers, endToken);
+ }
+
+ /// Handle the end of a extension method declaration. Substructures:
+ /// - metadata
+ /// - return type
+ /// - method name (identifier, possibly qualified)
+ /// - type variables
+ /// - formal parameters
+ /// - initializers
+ /// - async marker
+ /// - body
+ void endExtensionMethod(Token getOrSet, Token beginToken, Token beginParam,
+ Token beginInitializers, Token endToken) {
+ // TODO(danrubel): push implementation into subclasses
+ endClassMethod(
+ getOrSet, beginToken, beginParam, beginInitializers, endToken);
+ }
+
+ /// Handle the end of a class constructor declaration. Substructures:
+ /// - metadata
+ /// - return type
+ /// - method name (identifier, possibly qualified)
+ /// - type variables
+ /// - formal parameters
+ /// - initializers
+ /// - async marker
+ /// - body
+ void endClassConstructor(Token getOrSet, Token beginToken, Token beginParam,
+ Token beginInitializers, Token endToken) {
+ // TODO(danrubel): push implementation into subclasses
+ endClassMethod(
+ getOrSet, beginToken, beginParam, beginInitializers, endToken);
+ }
+
+ /// Handle the end of a mixin constructor declaration. Substructures:
+ /// - metadata
+ /// - return type
+ /// - method name (identifier, possibly qualified)
+ /// - type variables
+ /// - formal parameters
+ /// - initializers
+ /// - async marker
+ /// - body
+ void endMixinConstructor(Token getOrSet, Token beginToken, Token beginParam,
+ Token beginInitializers, Token endToken) {
+ // TODO(danrubel): push implementation into subclasses
+ endClassMethod(
+ getOrSet, beginToken, beginParam, beginInitializers, endToken);
+ }
+
+ /// Handle the end of a extension constructor declaration. Substructures:
+ /// - metadata
+ /// - return type
+ /// - method name (identifier, possibly qualified)
+ /// - type variables
+ /// - formal parameters
+ /// - initializers
+ /// - async marker
+ /// - body
+ void endExtensionConstructor(Token getOrSet, Token beginToken,
+ Token beginParam, Token beginInitializers, Token endToken) {
+ // TODO(danrubel): push implementation into subclasses
+ endClassMethod(
+ getOrSet, beginToken, beginParam, beginInitializers, endToken);
}
void beginMetadataStar(Token token) {}
diff --git a/pkg/front_end/lib/src/fasta/parser/modifier_context.dart b/pkg/front_end/lib/src/fasta/parser/modifier_context.dart
index 5807629..2c11862 100644
--- a/pkg/front_end/lib/src/fasta/parser/modifier_context.dart
+++ b/pkg/front_end/lib/src/fasta/parser/modifier_context.dart
@@ -355,7 +355,7 @@
if (constToken != null) {
reportConflictingModifiers(next, constToken);
} else if (varToken != null) {
- reportConflictingModifiers(next, varToken);
+ reportModifierOutOfOrder(next, varToken.lexeme);
} else if (finalToken != null) {
reportModifierOutOfOrder(next, finalToken.lexeme);
}
@@ -429,10 +429,6 @@
assert(optional('var', next));
if (varFinalOrConst == null && !afterFactory) {
varToken = next;
-
- if (lateToken != null) {
- reportConflictingModifiers(next, lateToken);
- }
return next;
}
diff --git a/pkg/front_end/lib/src/fasta/parser/parser.dart b/pkg/front_end/lib/src/fasta/parser/parser.dart
index affb84563..a296c652 100644
--- a/pkg/front_end/lib/src/fasta/parser/parser.dart
+++ b/pkg/front_end/lib/src/fasta/parser/parser.dart
@@ -53,7 +53,7 @@
import 'async_modifier.dart' show AsyncModifier;
-import 'class_kind.dart' show ClassKind;
+import 'declaration_kind.dart' show DeclarationKind;
import 'directive_context.dart';
@@ -127,7 +127,7 @@
/// Parse methods all have the prefix `parse`, generate events
/// (by calling methods on [listener]), and return the next token to parse.
/// Some exceptions to this last point are methods such as [parseFunctionBody]
-/// and [parseClassOrMixinBody] which return the last token parsed
+/// and [parseClassOrMixinOrExtensionBody] which return the last token parsed
/// rather than the next token to be parsed.
/// Parse methods are generally named `parseGrammarProductionSuffix`.
/// The suffix can be one of `opt`, or `star`.
@@ -1749,7 +1749,7 @@
Token abstractToken, Token classKeyword) {
assert(optional('class', classKeyword));
Token begin = abstractToken ?? classKeyword;
- listener.beginClassOrNamedMixinApplication(begin);
+ listener.beginClassOrNamedMixinApplicationPrelude(begin);
Token name = ensureIdentifier(
classKeyword, IdentifierContext.classOrMixinOrExtensionDeclaration);
Token token = computeTypeParamOrArg(name, true).parseVariables(name, this);
@@ -1758,7 +1758,7 @@
return parseNamedMixinApplication(token, begin, classKeyword);
} else {
listener.beginClassDeclaration(begin, abstractToken, name);
- return parseClass(token, begin, classKeyword);
+ return parseClass(token, begin, classKeyword, name.lexeme);
}
}
@@ -1790,7 +1790,8 @@
/// metadata abstract? 'class' mixinApplicationClass
/// ;
/// ```
- Token parseClass(Token token, Token begin, Token classKeyword) {
+ Token parseClass(
+ Token token, Token begin, Token classKeyword, String className) {
Token start = token;
token = parseClassHeaderOpt(token, begin, classKeyword);
if (!optional('{', token.next)) {
@@ -1798,7 +1799,8 @@
token = parseClassHeaderRecovery(start, begin, classKeyword);
ensureBlock(token, null, 'class declaration');
}
- token = parseClassOrMixinBody(ClassKind.Class, token);
+ token = parseClassOrMixinOrExtensionBody(
+ token, DeclarationKind.Class, className);
listener.endClassDeclaration(begin, token);
return token;
}
@@ -1953,7 +1955,7 @@
/// ```
Token parseMixin(Token mixinKeyword) {
assert(optional('mixin', mixinKeyword));
- listener.beginClassOrNamedMixinApplication(mixinKeyword);
+ listener.beginClassOrNamedMixinApplicationPrelude(mixinKeyword);
Token name = ensureIdentifier(
mixinKeyword, IdentifierContext.classOrMixinOrExtensionDeclaration);
Token headerStart =
@@ -1965,7 +1967,8 @@
token = parseMixinHeaderRecovery(token, mixinKeyword, headerStart);
ensureBlock(token, null, 'mixin declaration');
}
- token = parseClassOrMixinBody(ClassKind.Mixin, token);
+ token = parseClassOrMixinOrExtensionBody(
+ token, DeclarationKind.Mixin, name.lexeme);
listener.endMixinDeclaration(mixinKeyword, token);
return token;
}
@@ -2086,6 +2089,7 @@
Token parseExtension(Token extensionKeyword) {
assert(optional('extension', extensionKeyword));
Token token = extensionKeyword;
+ listener.beginExtensionDeclarationPrelude(extensionKeyword);
Token name = token.next;
if (name.isIdentifier && !optional('on', name)) {
token = name;
@@ -2134,8 +2138,8 @@
}
ensureBlock(token, null, 'extension declaration');
}
- // TODO(danrubel): Do not allow fields or constructors
- token = parseClassOrMixinBody(ClassKind.Extension, token);
+ token = parseClassOrMixinOrExtensionBody(
+ token, DeclarationKind.Extension, name?.lexeme);
listener.endExtensionDeclaration(extensionKeyword, onKeyword, token);
return token;
}
@@ -2351,8 +2355,17 @@
reportRecoverableErrorWithToken(
getOrSet, fasta.templateExtraneousModifier);
}
- return parseFields(beforeStart, externalToken, null, null, lateToken,
- varFinalOrConst, beforeType, typeInfo, token.next, true);
+ return parseFields(
+ beforeStart,
+ externalToken,
+ null,
+ null,
+ lateToken,
+ varFinalOrConst,
+ beforeType,
+ typeInfo,
+ token.next,
+ DeclarationKind.TopLevel);
}
Token parseFields(
@@ -2365,7 +2378,7 @@
Token beforeType,
TypeInfo typeInfo,
Token name,
- bool isTopLevel) {
+ DeclarationKind kind) {
if (externalToken != null) {
reportRecoverableError(externalToken, fasta.messageExternalField);
}
@@ -2388,18 +2401,18 @@
Token token = typeInfo.parseType(beforeType, this);
assert(token.next == name);
- IdentifierContext context = isTopLevel
+ IdentifierContext context = kind == DeclarationKind.TopLevel
? IdentifierContext.topLevelVariableDeclaration
: IdentifierContext.fieldDeclaration;
- name = ensureIdentifier(token, context);
+ Token firstName = name = ensureIdentifier(token, context);
int fieldCount = 1;
- token = parseFieldInitializerOpt(
- name, name, lateToken, varFinalOrConst, isTopLevel);
+ token =
+ parseFieldInitializerOpt(name, name, lateToken, varFinalOrConst, kind);
while (optional(',', token.next)) {
name = ensureIdentifier(token.next, context);
token = parseFieldInitializerOpt(
- name, name, lateToken, varFinalOrConst, isTopLevel);
+ name, name, lateToken, varFinalOrConst, kind);
++fieldCount;
}
Token semicolon = token.next;
@@ -2407,7 +2420,7 @@
token = semicolon;
} else {
// Recovery
- if (isTopLevel &&
+ if (kind == DeclarationKind.TopLevel &&
beforeType.next.isIdentifier &&
beforeType.next.lexeme == 'extension') {
// Looks like an extension method
@@ -2423,12 +2436,27 @@
token = ensureSemicolon(token);
}
}
- if (isTopLevel) {
- listener.endTopLevelFields(staticToken, covariantToken, lateToken,
- varFinalOrConst, fieldCount, beforeStart.next, token);
- } else {
- listener.endFields(staticToken, covariantToken, lateToken,
- varFinalOrConst, fieldCount, beforeStart.next, token);
+ switch (kind) {
+ case DeclarationKind.TopLevel:
+ listener.endTopLevelFields(staticToken, covariantToken, lateToken,
+ varFinalOrConst, fieldCount, beforeStart.next, token);
+ break;
+ case DeclarationKind.Class:
+ listener.endClassFields(staticToken, covariantToken, lateToken,
+ varFinalOrConst, fieldCount, beforeStart.next, token);
+ break;
+ case DeclarationKind.Mixin:
+ listener.endMixinFields(staticToken, covariantToken, lateToken,
+ varFinalOrConst, fieldCount, beforeStart.next, token);
+ break;
+ case DeclarationKind.Extension:
+ if (staticToken == null) {
+ reportRecoverableError(
+ firstName, fasta.messageExtensionDeclaresInstanceField);
+ }
+ listener.endExtensionFields(staticToken, covariantToken, lateToken,
+ varFinalOrConst, fieldCount, beforeStart.next, token);
+ break;
}
return token;
}
@@ -2484,7 +2512,7 @@
}
Token parseFieldInitializerOpt(Token token, Token name, Token lateToken,
- Token varFinalOrConst, bool isTopLevel) {
+ Token varFinalOrConst, DeclarationKind kind) {
Token next = token.next;
if (optional('=', next)) {
Token assignment = next;
@@ -2498,7 +2526,7 @@
name,
fasta.templateConstFieldWithoutInitializer
.withArguments(name.lexeme));
- } else if (isTopLevel &&
+ } else if (kind == DeclarationKind.TopLevel &&
optional("final", varFinalOrConst) &&
lateToken == null) {
reportRecoverableError(
@@ -2893,7 +2921,7 @@
return token;
}
- Token skipClassOrMixinBody(Token token) {
+ Token skipClassOrMixinOrExtensionBody(Token token) {
// The scanner ensures that `{` always has a closing `}`.
return ensureBlock(token, null, null);
}
@@ -2903,13 +2931,15 @@
/// '{' classMember* '}'
/// ;
/// ```
- Token parseClassOrMixinBody(ClassKind kind, Token token) {
+ Token parseClassOrMixinOrExtensionBody(
+ Token token, DeclarationKind kind, String enclosingDeclarationName) {
Token begin = token = token.next;
assert(optional('{', token));
listener.beginClassOrMixinBody(kind, token);
int count = 0;
while (notEofOrValue('}', token.next)) {
- token = parseClassOrMixinMemberImpl(token);
+ token = parseClassOrMixinOrExtensionMemberImpl(
+ token, kind, enclosingDeclarationName);
++count;
}
token = token.next;
@@ -2923,14 +2953,40 @@
token.lexeme == 'unary' &&
optional('-', token.next);
- /// Parse a class or mixin member.
+ /// Parse a class member.
///
/// This method is only invoked from outside the parser. As a result, this
/// method takes the next token to be consumed rather than the last consumed
/// token and returns the token after the last consumed token rather than the
/// last consumed token.
- Token parseClassOrMixinMember(Token token) {
- return parseClassOrMixinMemberImpl(syntheticPreviousToken(token)).next;
+ Token parseClassMember(Token token, String className) {
+ return parseClassOrMixinOrExtensionMemberImpl(
+ syntheticPreviousToken(token), DeclarationKind.Class, className)
+ .next;
+ }
+
+ /// Parse a mixin member.
+ ///
+ /// This method is only invoked from outside the parser. As a result, this
+ /// method takes the next token to be consumed rather than the last consumed
+ /// token and returns the token after the last consumed token rather than the
+ /// last consumed token.
+ Token parseMixinMember(Token token, String mixinName) {
+ return parseClassOrMixinOrExtensionMemberImpl(
+ syntheticPreviousToken(token), DeclarationKind.Mixin, mixinName)
+ .next;
+ }
+
+ /// Parse an extension member.
+ ///
+ /// This method is only invoked from outside the parser. As a result, this
+ /// method takes the next token to be consumed rather than the last consumed
+ /// token and returns the token after the last consumed token rather than the
+ /// last consumed token.
+ Token parseExtensionMember(Token token, String extensionName) {
+ return parseClassOrMixinOrExtensionMemberImpl(syntheticPreviousToken(token),
+ DeclarationKind.Extension, extensionName)
+ .next;
}
/// ```
@@ -2944,8 +3000,14 @@
/// fieldDeclaration |
/// methodDeclaration
/// ;
+ ///
+ /// extensionMember:
+ /// staticFieldDeclaration |
+ /// methodDeclaration
+ /// ;
/// ```
- Token parseClassOrMixinMemberImpl(Token token) {
+ Token parseClassOrMixinOrExtensionMemberImpl(
+ Token token, DeclarationKind kind, String enclosingDeclarationName) {
Token beforeStart = token = parseMetadataStar(token);
Token covariantToken;
@@ -3031,7 +3093,7 @@
if (beforeType != token) {
reportRecoverableError(token, fasta.messageTypeBeforeFactory);
}
- token = parseFactoryMethod(token, beforeStart, externalToken,
+ token = parseFactoryMethod(token, kind, beforeStart, externalToken,
staticToken ?? covariantToken, varFinalOrConst);
listener.endMember();
return token;
@@ -3053,7 +3115,9 @@
beforeType,
typeInfo,
getOrSet,
- token.next);
+ token.next,
+ kind,
+ enclosingDeclarationName);
listener.endMember();
return token;
} else if (optional('===', next2) ||
@@ -3069,7 +3133,8 @@
covariantToken,
lateToken,
varFinalOrConst,
- beforeType);
+ beforeType,
+ kind);
} else if (isUnaryMinus(next2)) {
// Recovery
token = parseMethod(
@@ -3082,7 +3147,9 @@
beforeType,
typeInfo,
getOrSet,
- token.next);
+ token.next,
+ kind,
+ enclosingDeclarationName);
listener.endMember();
return token;
}
@@ -3092,7 +3159,7 @@
token == beforeStart &&
next.next.isIdentifier)) {
// Recovery
- return recoverFromInvalidClassMember(
+ return recoverFromInvalidMember(
token,
beforeStart,
externalToken,
@@ -3102,7 +3169,9 @@
varFinalOrConst,
beforeType,
typeInfo,
- getOrSet);
+ getOrSet,
+ kind,
+ enclosingDeclarationName);
}
} else if (typeInfo == noType && varFinalOrConst == null) {
Token next2 = next.next;
@@ -3119,7 +3188,8 @@
covariantToken,
lateToken,
varFinalOrConst,
- beforeType);
+ beforeType,
+ kind);
}
}
}
@@ -3143,7 +3213,9 @@
beforeType,
typeInfo,
getOrSet,
- token.next);
+ token.next,
+ kind,
+ enclosingDeclarationName);
} else {
if (getOrSet != null) {
reportRecoverableErrorWithToken(
@@ -3159,7 +3231,7 @@
beforeType,
typeInfo,
token.next,
- false);
+ kind);
}
listener.endMember();
return token;
@@ -3175,7 +3247,9 @@
Token beforeType,
TypeInfo typeInfo,
Token getOrSet,
- Token name) {
+ Token name,
+ DeclarationKind kind,
+ String enclosingDeclarationName) {
if (lateToken != null) {
reportRecoverableErrorWithToken(
lateToken, fasta.templateExtraneousModifier);
@@ -3247,12 +3321,14 @@
listener.handleNoTypeVariables(token.next);
}
- MemberKind kind = staticToken != null
- ? MemberKind.StaticMethod
- : MemberKind.NonStaticMethod;
Token beforeParam = token;
- Token beforeInitializers =
- parseGetterOrFormalParameters(token, name, isGetter, kind);
+ Token beforeInitializers = parseGetterOrFormalParameters(
+ token,
+ name,
+ isGetter,
+ staticToken != null
+ ? MemberKind.StaticMethod
+ : MemberKind.NonStaticMethod);
token = parseInitializersOpt(beforeInitializers);
if (token == beforeInitializers) beforeInitializers = null;
@@ -3262,27 +3338,124 @@
if (getOrSet != null && !inPlainSync && optional("set", getOrSet)) {
reportRecoverableError(asyncToken, fasta.messageSetterNotSync);
}
- Token next = token.next;
+ final Token bodyStart = token.next;
if (externalToken != null) {
- if (!optional(';', next)) {
- reportRecoverableError(next, fasta.messageExternalMethodWithBody);
+ if (!optional(';', bodyStart)) {
+ reportRecoverableError(bodyStart, fasta.messageExternalMethodWithBody);
}
}
- if (optional('=', next)) {
- reportRecoverableError(next, fasta.messageRedirectionInNonFactory);
+ if (optional('=', bodyStart)) {
+ reportRecoverableError(bodyStart, fasta.messageRedirectionInNonFactory);
token = parseRedirectingFactoryBody(token);
} else {
token = parseFunctionBody(token, false,
(staticToken == null || externalToken != null) && inPlainSync);
}
asyncState = savedAsyncModifier;
- listener.endMethod(getOrSet, beforeStart.next, beforeParam.next,
- beforeInitializers?.next, token);
+
+ bool isConstructor = false;
+ if (optional('.', name.next) || beforeInitializers != null) {
+ isConstructor = true;
+ if (name.lexeme != enclosingDeclarationName) {
+ // Recovery: The name does not match,
+ // but the name is prefixed or the declaration contains initializers.
+ // Report an error and continue with invalid name.
+ // TODO(danrubel): report invalid constructor name
+ // Currently multiple listeners report this error, but that logic should
+ // be removed and the error reported here instead.
+ }
+ if (getOrSet != null) {
+ // Recovery
+ if (optional('.', name.next)) {
+ // Unexpected get/set before constructor.
+ // Report an error and skip over the token.
+ // TODO(danrubel): report an error on get/set token
+ // This is currently reported by listeners other than AstBuilder.
+ // It should be reported here rather than in the listeners.
+ } else {
+ isConstructor = false;
+ if (beforeInitializers != null) {
+ // Unexpected initializers after get/set declaration.
+ // Report an error on the initializers
+ // and continue with the get/set declaration.
+ // TODO(danrubel): report invalid initializers error
+ // Currently multiple listeners report this error, but that logic
+ // should be removed and the error reported here instead.
+ }
+ }
+ }
+ } else if (name.lexeme == enclosingDeclarationName) {
+ if (getOrSet != null) {
+ // Recovery: The get/set member name is invalid.
+ // Report an error and continue with invalid name.
+ // TODO(danrubel): report invalid get/set member name
+ // Currently multiple listeners report this error, but that logic should
+ // be removed and the error reported here instead.
+ } else {
+ isConstructor = true;
+ }
+ }
+
+ if (isConstructor) {
+ //
+ // constructor
+ //
+ if (staticToken != null) {
+ reportRecoverableError(staticToken, fasta.messageStaticConstructor);
+ }
+ switch (kind) {
+ case DeclarationKind.Class:
+ // TODO(danrubel): Remove getOrSet from constructor events
+ listener.endClassConstructor(getOrSet, beforeStart.next,
+ beforeParam.next, beforeInitializers?.next, token);
+ break;
+ case DeclarationKind.Mixin:
+ reportRecoverableError(name, fasta.messageMixinDeclaresConstructor);
+ listener.endMixinConstructor(getOrSet, beforeStart.next,
+ beforeParam.next, beforeInitializers?.next, token);
+ break;
+ case DeclarationKind.Extension:
+ reportRecoverableError(
+ name, fasta.messageExtensionDeclaresConstructor);
+ listener.endExtensionConstructor(getOrSet, beforeStart.next,
+ beforeParam.next, beforeInitializers?.next, token);
+ break;
+ case DeclarationKind.TopLevel:
+ throw "Internal error: TopLevel constructor.";
+ break;
+ }
+ } else {
+ //
+ // method
+ //
+ switch (kind) {
+ case DeclarationKind.Class:
+ // TODO(danrubel): Remove beginInitializers token from method events
+ listener.endClassMethod(getOrSet, beforeStart.next, beforeParam.next,
+ beforeInitializers?.next, token);
+ break;
+ case DeclarationKind.Mixin:
+ listener.endMixinMethod(getOrSet, beforeStart.next, beforeParam.next,
+ beforeInitializers?.next, token);
+ break;
+ case DeclarationKind.Extension:
+ if (optional(';', bodyStart)) {
+ reportRecoverableError(isOperator ? name.next : name,
+ fasta.messageExtensionDeclaresAbstractMember);
+ }
+ listener.endExtensionMethod(getOrSet, beforeStart.next,
+ beforeParam.next, beforeInitializers?.next, token);
+ break;
+ case DeclarationKind.TopLevel:
+ throw "Internal error: TopLevel method.";
+ break;
+ }
+ }
return token;
}
- Token parseFactoryMethod(Token token, Token beforeStart, Token externalToken,
- Token staticOrCovariant, Token varFinalOrConst) {
+ Token parseFactoryMethod(Token token, DeclarationKind kind, Token beforeStart,
+ Token externalToken, Token staticOrCovariant, Token varFinalOrConst) {
Token factoryKeyword = token = token.next;
assert(optional('factory', factoryKeyword));
@@ -3342,7 +3515,25 @@
}
token = parseFunctionBody(token, false, false);
}
- listener.endFactoryMethod(beforeStart.next, factoryKeyword, token);
+ switch (kind) {
+ case DeclarationKind.Class:
+ listener.endClassFactoryMethod(beforeStart.next, factoryKeyword, token);
+ break;
+ case DeclarationKind.Mixin:
+ reportRecoverableError(
+ factoryKeyword, fasta.messageMixinDeclaresConstructor);
+ listener.endMixinFactoryMethod(beforeStart.next, factoryKeyword, token);
+ break;
+ case DeclarationKind.Extension:
+ reportRecoverableError(
+ factoryKeyword, fasta.messageExtensionDeclaresConstructor);
+ listener.endExtensionFactoryMethod(
+ beforeStart.next, factoryKeyword, token);
+ break;
+ case DeclarationKind.TopLevel:
+ throw "Internal error: TopLevel factory.";
+ break;
+ }
return token;
}
@@ -4008,7 +4199,7 @@
listener.handleUnaryPostfixAssignmentExpression(token.next);
token = next;
} else if (identical(type, TokenType.BANG)) {
- listener.handleNonNullAssertExpression(token.next);
+ listener.handleNonNullAssertExpression(next);
token = next;
}
} else if (identical(tokenLevel, SELECTOR_PRECEDENCE)) {
@@ -4081,7 +4272,10 @@
if (identical(type, TokenType.BANG)) {
// The '!' has prefix precedence but here it's being used as a
// postfix operator to assert the expression has a non-null value.
- if (identical(token.next.type, TokenType.PERIOD)) {
+ TokenType nextType = token.next.type;
+ if (identical(nextType, TokenType.PERIOD) ||
+ identical(nextType, TokenType.OPEN_PAREN) ||
+ identical(nextType, TokenType.OPEN_SQUARE_BRACKET)) {
return SELECTOR_PRECEDENCE;
}
return POSTFIX_PRECEDENCE;
@@ -5208,7 +5402,8 @@
} else if (optional('late', next)) {
lateToken = token = next;
next = token.next;
- if (isModifier(next) && optional('final', next)) {
+ if (isModifier(next) &&
+ (optional('var', next) || optional('final', next))) {
varFinalOrConst = token = next;
next = token.next;
}
@@ -5278,7 +5473,12 @@
typeInfo.isNullable &&
typeInfo.couldBeExpression) {
assert(optional('?', token));
- assert(next.isIdentifier);
+ assert(next.isKeywordOrIdentifier);
+ if (!next.isIdentifier) {
+ reportRecoverableError(
+ next, fasta.templateExpectedIdentifier.withArguments(next));
+ next = rewriter.insertSyntheticIdentifier(next);
+ }
Token afterIdentifier = next.next;
//
// found <typeref> `?` <identifier>
@@ -6255,7 +6455,8 @@
Token covariantToken,
Token lateToken,
Token varFinalOrConst,
- Token beforeType) {
+ Token beforeType,
+ DeclarationKind kind) {
TypeInfo typeInfo = computeType(beforeType, true, true);
Token beforeName = typeInfo.skipType(beforeType);
@@ -6282,7 +6483,9 @@
beforeType,
typeInfo,
null,
- beforeName.next);
+ beforeName.next,
+ kind,
+ null);
listener.endMember();
return token;
}
@@ -6290,7 +6493,7 @@
/// Recover from finding an invalid class member. The metadata for the member,
/// if any, has already been parsed (and events have already been generated).
/// The member was expected to start with the token after [token].
- Token recoverFromInvalidClassMember(
+ Token recoverFromInvalidMember(
Token token,
Token beforeStart,
Token externalToken,
@@ -6300,7 +6503,9 @@
Token varFinalOrConst,
Token beforeType,
TypeInfo typeInfo,
- Token getOrSet) {
+ Token getOrSet,
+ DeclarationKind kind,
+ String enclosingDeclarationName) {
Token next = token.next;
String value = next.stringValue;
@@ -6311,8 +6516,15 @@
} else if (identical(value, 'typedef')) {
return reportAndSkipTypedefInClass(next);
} else if (next.isOperator && next.endGroup == null) {
- return parseInvalidOperatorDeclaration(beforeStart, externalToken,
- staticToken, covariantToken, lateToken, varFinalOrConst, beforeType);
+ return parseInvalidOperatorDeclaration(
+ beforeStart,
+ externalToken,
+ staticToken,
+ covariantToken,
+ lateToken,
+ varFinalOrConst,
+ beforeType,
+ kind);
}
if (getOrSet != null ||
@@ -6329,7 +6541,9 @@
beforeType,
typeInfo,
getOrSet,
- token.next);
+ token.next,
+ kind,
+ enclosingDeclarationName);
} else if (token == beforeStart) {
// TODO(danrubel): Provide a more specific error message for extra ';'.
reportRecoverableErrorWithToken(next, fasta.templateExpectedClassMember);
@@ -6349,7 +6563,7 @@
beforeType,
typeInfo,
token.next,
- false);
+ kind);
}
listener.endMember();
diff --git a/pkg/front_end/lib/src/fasta/parser/top_level_parser.dart b/pkg/front_end/lib/src/fasta/parser/top_level_parser.dart
index e75ccc9..802f28e 100644
--- a/pkg/front_end/lib/src/fasta/parser/top_level_parser.dart
+++ b/pkg/front_end/lib/src/fasta/parser/top_level_parser.dart
@@ -6,7 +6,7 @@
import '../../scanner/token.dart' show Token;
-import 'class_kind.dart' show ClassKind;
+import 'declaration_kind.dart' show DeclarationKind;
import 'class_member_parser.dart' show ClassMemberParser;
@@ -17,6 +17,8 @@
class TopLevelParser extends ClassMemberParser {
TopLevelParser(Listener listener) : super(listener);
- Token parseClassOrMixinBody(ClassKind kind, Token token) =>
- skipClassOrMixinBody(token);
+ @override
+ Token parseClassOrMixinOrExtensionBody(
+ Token token, DeclarationKind kind, String enclosingDeclarationName) =>
+ skipClassOrMixinOrExtensionBody(token);
}
diff --git a/pkg/front_end/lib/src/fasta/scanner/abstract_scanner.dart b/pkg/front_end/lib/src/fasta/scanner/abstract_scanner.dart
index 2103911..50fedf3 100644
--- a/pkg/front_end/lib/src/fasta/scanner/abstract_scanner.dart
+++ b/pkg/front_end/lib/src/fasta/scanner/abstract_scanner.dart
@@ -1350,7 +1350,7 @@
while (true) {
if (identical($EOF, next)) {
if (!asciiOnlyLines) handleUnicode(unicodeStart);
- prependErrorToken(UnterminatedToken(
+ prependErrorToken(new UnterminatedToken(
messageUnterminatedComment, tokenStart, stringOffset));
advanceAfterError(true);
break;
@@ -1618,7 +1618,7 @@
} else {
beginToken(); // The synthetic identifier starts here.
appendSyntheticSubstringToken(TokenType.IDENTIFIER, scanOffset, true, '');
- prependErrorToken(UnterminatedToken(
+ prependErrorToken(new UnterminatedToken(
messageUnexpectedDollarInString, tokenStart, stringOffset));
}
beginToken(); // The string interpolation suffix starts here.
@@ -1763,7 +1763,7 @@
codeUnits.add(next);
next = advance();
}
- appendToken(StringToken.fromString(TokenType.IDENTIFIER,
+ appendToken(new StringToken.fromString(TokenType.IDENTIFIER,
new String.fromCharCodes(codeUnits), charOffset));
return next;
} else {
@@ -1885,9 +1885,9 @@
/// [ScannerConfiguration] contains information for configuring which tokens
/// the scanner produces based upon the Dart language level.
class ScannerConfiguration {
- static const ScannerConfiguration classic = ScannerConfiguration();
+ static const ScannerConfiguration classic = const ScannerConfiguration();
static const ScannerConfiguration nonNullable =
- ScannerConfiguration(enableNonNullable: true);
+ const ScannerConfiguration(enableNonNullable: true);
/// Experimental flag for enabling scanning of the `extension` keyword.
final bool enableExtensionMethods;
diff --git a/pkg/front_end/lib/src/fasta/scanner/error_token.dart b/pkg/front_end/lib/src/fasta/scanner/error_token.dart
index 7c4ba8a..57a5e0f 100644
--- a/pkg/front_end/lib/src/fasta/scanner/error_token.dart
+++ b/pkg/front_end/lib/src/fasta/scanner/error_token.dart
@@ -77,7 +77,7 @@
// Attempt to include the location which is calling the parser
// in an effort to debug https://github.com/dart-lang/sdk/issues/37528
- RegExp pattern = RegExp('^#[0-9]* *Parser');
+ RegExp pattern = new RegExp('^#[0-9]* *Parser');
List<String> traceLines = StackTrace.current.toString().split('\n');
for (int index = traceLines.length - 2; index >= 0; --index) {
String line = traceLines[index];
diff --git a/pkg/front_end/lib/src/fasta/scope.dart b/pkg/front_end/lib/src/fasta/scope.dart
index 40ca796..404a00e 100644
--- a/pkg/front_end/lib/src/fasta/scope.dart
+++ b/pkg/front_end/lib/src/fasta/scope.dart
@@ -6,6 +6,8 @@
import 'builder/builder.dart' show Builder, NameIterator, TypeVariableBuilder;
+import 'builder/extension_builder.dart';
+
import 'fasta_codes.dart'
show
LocatedMessage,
@@ -24,14 +26,45 @@
/// Setters declared in this scope.
Map<String, Builder> setters;
+ /// The extensions declared in this scope.
+ ///
+ /// This includes all available extensions even if the extensions are not
+ /// accessible by name because of duplicate imports.
+ ///
+ /// For instance:
+ ///
+ /// lib1.dart:
+ /// extension Extension on String {
+ /// method1() {}
+ /// staticMethod1() {}
+ /// }
+ /// lib2.dart:
+ /// extension Extension on String {
+ /// method2() {}
+ /// staticMethod2() {}
+ /// }
+ /// main.dart:
+ /// import 'lib1.dart';
+ /// import 'lib2.dart';
+ ///
+ /// main() {
+ /// 'foo'.method1(); // This method is available.
+ /// 'foo'.method2(); // This method is available.
+ /// // These methods are not available because Extension is ambiguous:
+ /// Extension.staticMethod1();
+ /// Extension.staticMethod2();
+ /// }
+ ///
+ List<ExtensionBuilder> _extensions;
+
/// The scope that this scope is nested within, or `null` if this is the top
/// level scope.
Scope parent;
final String classNameOrDebugName;
- MutableScope(
- this.local, this.setters, this.parent, this.classNameOrDebugName) {
+ MutableScope(this.local, this.setters, this._extensions, this.parent,
+ this.classNameOrDebugName) {
assert(classNameOrDebugName != null);
}
@@ -49,22 +82,36 @@
Map<String, int> usedNames;
- Scope(Map<String, Builder> local, Map<String, Builder> setters, Scope parent,
- String debugName, {this.isModifiable: true})
- : super(local, setters = setters ?? const <String, Builder>{}, parent,
- debugName);
+ Scope(
+ {Map<String, Builder> local,
+ Map<String, Builder> setters,
+ List<ExtensionBuilder> extensions,
+ Scope parent,
+ String debugName,
+ this.isModifiable: true})
+ : super(local, setters = setters ?? const <String, Builder>{}, extensions,
+ parent, debugName);
Scope.top({bool isModifiable: false})
- : this(<String, Builder>{}, <String, Builder>{}, null, "top",
+ : this(
+ local: <String, Builder>{},
+ setters: <String, Builder>{},
+ debugName: "top",
isModifiable: isModifiable);
Scope.immutable()
- : this(const <String, Builder>{}, const <String, Builder>{}, null,
- "immutable",
+ : this(
+ local: const <String, Builder>{},
+ setters: const <String, Builder>{},
+ debugName: "immutable",
isModifiable: false);
Scope.nested(Scope parent, String debugName, {bool isModifiable: true})
- : this(<String, Builder>{}, <String, Builder>{}, parent, debugName,
+ : this(
+ local: <String, Builder>{},
+ setters: <String, Builder>{},
+ parent: parent,
+ debugName: debugName,
isModifiable: isModifiable);
Iterator<Builder> get iterator {
@@ -76,7 +123,12 @@
}
Scope copyWithParent(Scope parent, String debugName) {
- return new Scope(super.local, super.setters, parent, debugName,
+ return new Scope(
+ local: super.local,
+ setters: super.setters,
+ extensions: _extensions,
+ parent: parent,
+ debugName: debugName,
isModifiable: isModifiable);
}
@@ -97,6 +149,7 @@
super.local = scope.local;
super.setters = scope.setters;
super.parent = scope.parent;
+ super._extensions = scope._extensions;
}
Scope createNestedScope(String debugName, {bool isModifiable: true}) {
@@ -121,7 +174,13 @@
/// x = 42;
/// print("The answer is $x.");
Scope createNestedLabelScope() {
- return new Scope(local, setters, parent, "label", isModifiable: true);
+ return new Scope(
+ local: local,
+ setters: setters,
+ extensions: _extensions,
+ parent: parent,
+ debugName: "label",
+ isModifiable: true);
}
void recordUse(String name, int charOffset, Uri fileUri) {
@@ -235,6 +294,18 @@
return null;
}
+ /// Adds [builder] to the extensions in this scope.
+ void addExtension(ExtensionBuilder builder) {
+ _extensions ??= [];
+ _extensions.add(builder);
+ }
+
+ /// Calls [f] for each extension in this scope and parent scopes.
+ void forEachExtension(void Function(ExtensionBuilder) f) {
+ _extensions?.forEach(f);
+ parent?.forEachExtension(f);
+ }
+
void merge(
Scope scope,
Builder computeAmbiguousDeclaration(
@@ -308,7 +379,12 @@
}
}
return needsCopy
- ? new Scope(local, setters, parent, classNameOrDebugName,
+ ? new Scope(
+ local: local,
+ setters: setters,
+ extensions: _extensions,
+ parent: parent,
+ debugName: classNameOrDebugName,
isModifiable: isModifiable)
: this;
}
@@ -327,6 +403,10 @@
scope.setters[name] = builder;
}
+ void addExtension(ExtensionBuilder builder) {
+ scope.addExtension(builder);
+ }
+
Builder operator [](String name) => scope.local[name];
}
diff --git a/pkg/front_end/lib/src/fasta/source/diet_listener.dart b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
index 69f967d..b855f5b 100644
--- a/pkg/front_end/lib/src/fasta/source/diet_listener.dart
+++ b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
@@ -45,7 +45,8 @@
import '../kernel/kernel_builder.dart'
show FormalParameterBuilder, TypeAliasBuilder, TypeBuilder;
-import '../parser.dart' show Assert, ClassKind, MemberKind, Parser, optional;
+import '../parser.dart'
+ show Assert, DeclarationKind, MemberKind, Parser, optional;
import '../problems.dart'
show DebugAbort, internalProblem, unexpected, unhandled;
@@ -64,7 +65,7 @@
import '../quote.dart' show unescapeString;
class DietListener extends StackListener {
- final SourceLibraryBuilder library;
+ final SourceLibraryBuilder libraryBuilder;
final ClassHierarchy hierarchy;
@@ -96,7 +97,7 @@
DietListener(SourceLibraryBuilder library, this.hierarchy, this.coreTypes,
this.typeInferenceEngine)
- : library = library,
+ : libraryBuilder = library,
uri = library.fileUri,
memberScope = library.scope,
enableNative =
@@ -262,8 +263,8 @@
checkEmpty(typedefKeyword.charOffset);
if (name is ParserRecovery) return;
- Builder typedefBuilder = lookupBuilder(typedefKeyword, null, name);
- parseMetadata(typedefBuilder, metadata, typedefBuilder.target);
+ TypeAliasBuilder typedefBuilder = lookupBuilder(typedefKeyword, null, name);
+ parseMetadata(typedefBuilder, metadata, typedefBuilder.typedef);
if (typedefBuilder is TypeAliasBuilder) {
TypeBuilder type = typedefBuilder.type;
if (type is FunctionTypeBuilder) {
@@ -281,13 +282,13 @@
parseMetadata(typedefBuilder, metadataToken, null);
if (formal.isPositional) {
VariableDeclaration parameter =
- typedefBuilder.target.positionalParameters[i];
+ typedefBuilder.typedef.positionalParameters[i];
for (Expression annotation in annotations) {
parameter.addAnnotation(annotation);
}
} else {
for (VariableDeclaration named
- in typedefBuilder.target.namedParameters) {
+ in typedefBuilder.typedef.namedParameters) {
if (named.name == formal.name) {
for (Expression annotation in annotations) {
named.addAnnotation(annotation);
@@ -308,7 +309,7 @@
}
@override
- void endFields(Token staticToken, Token covariantToken, Token lateToken,
+ void endClassFields(Token staticToken, Token covariantToken, Token lateToken,
Token varFinalOrConst, int count, Token beginToken, Token endToken) {
debugEvent("Fields");
buildFields(count, beginToken, false);
@@ -498,10 +499,10 @@
unescapeString(importUriToken.lexeme, importUriToken, this);
if (importUri.startsWith("dart-ext:")) return;
- Library libraryNode = library.target;
+ Library libraryNode = libraryBuilder.library;
LibraryDependency dependency =
libraryNode.dependencies[importExportDirectiveIndex++];
- parseMetadata(library, metadata, dependency);
+ parseMetadata(libraryBuilder, metadata, dependency);
}
@override
@@ -514,10 +515,10 @@
debugEvent("Export");
Token metadata = pop();
- Library libraryNode = library.target;
+ Library libraryNode = libraryBuilder.library;
LibraryDependency dependency =
libraryNode.dependencies[importExportDirectiveIndex++];
- parseMetadata(library, metadata, dependency);
+ parseMetadata(libraryBuilder, metadata, dependency);
}
@override
@@ -525,14 +526,14 @@
debugEvent("Part");
Token metadata = pop();
- Library libraryNode = library.target;
+ Library libraryNode = libraryBuilder.library;
if (libraryNode.parts.length > partDirectiveIndex) {
// If partDirectiveIndex >= libraryNode.parts.length we are in a case of
// on part having other parts. An error has already been issued.
// Don't try to parse metadata into other parts that have nothing to do
// with the one this keyword is talking about.
LibraryPart part = libraryNode.parts[partDirectiveIndex++];
- parseMetadata(library, metadata, part);
+ parseMetadata(libraryBuilder, metadata, part);
}
}
@@ -560,9 +561,9 @@
}
@override
- void endFactoryMethod(
+ void endClassFactoryMethod(
Token beginToken, Token factoryKeyword, Token endToken) {
- debugEvent("FactoryMethod");
+ debugEvent("ClassFactoryMethod");
Token bodyToken = pop();
Object name = pop();
Token metadata = pop();
@@ -605,7 +606,7 @@
}
@override
- void endMethod(Token getOrSet, Token beginToken, Token beginParam,
+ void endClassMethod(Token getOrSet, Token beginToken, Token beginParam,
Token beginInitializers, Token endToken) {
debugEvent("Method");
// TODO(danrubel): Consider removing the beginParam parameter
@@ -643,13 +644,33 @@
// for better error recovery?
InterfaceType thisType =
extensionThis == null ? currentDeclaration?.thisType : null;
- TypeInferrer typeInferrer =
- typeInferenceEngine?.createLocalTypeInferrer(uri, thisType, library);
+ TypeInferrer typeInferrer = typeInferenceEngine?.createLocalTypeInferrer(
+ uri, thisType, libraryBuilder);
ConstantContext constantContext = builder.isConstructor && builder.isConst
? ConstantContext.inferred
: ConstantContext.none;
+ return createListenerInternal(
+ builder,
+ memberScope,
+ formalParameterScope,
+ isDeclarationInstanceMember,
+ extensionThis,
+ extensionTypeParameters,
+ typeInferrer,
+ constantContext);
+ }
+
+ StackListener createListenerInternal(
+ ModifierBuilder builder,
+ Scope memberScope,
+ Scope formalParameterScope,
+ bool isDeclarationInstanceMember,
+ VariableDeclaration extensionThis,
+ List<TypeParameter> extensionTypeParameters,
+ TypeInferrer typeInferrer,
+ ConstantContext constantContext) {
return new BodyBuilder(
- library: library,
+ libraryBuilder: libraryBuilder,
member: builder,
enclosingScope: memberScope,
formalParameterScope: formalParameterScope,
@@ -738,7 +759,7 @@
}
@override
- void beginClassOrMixinBody(ClassKind kind, Token token) {
+ void beginClassOrMixinBody(DeclarationKind kind, Token token) {
assert(checkState(token, [
ValueKind.Token,
ValueKind.NameOrParserRecovery,
@@ -749,7 +770,7 @@
Object name = pop();
pop(); // Annotation begin token.
assert(currentDeclaration == null);
- assert(memberScope == library.scope);
+ assert(memberScope == libraryBuilder.scope);
if (name is ParserRecovery) {
currentClassIsParserRecovery = true;
return;
@@ -760,11 +781,11 @@
@override
void endClassOrMixinBody(
- ClassKind kind, int memberCount, Token beginToken, Token endToken) {
+ DeclarationKind kind, int memberCount, Token beginToken, Token endToken) {
debugEvent("ClassOrMixinBody");
currentDeclaration = null;
currentClassIsParserRecovery = false;
- memberScope = library.scope;
+ memberScope = libraryBuilder.scope;
}
@override
@@ -796,7 +817,7 @@
debugEvent("beginExtensionDeclaration");
String name = nameToken?.lexeme ??
// Synthesized name used internally.
- 'extension#${unnamedExtensionCounter++}';
+ '_extension#${unnamedExtensionCounter++}';
push(name);
push(extensionKeyword);
}
@@ -889,7 +910,8 @@
if (isTopLevel) {
token = parser.parseTopLevelMember(metadata ?? token);
} else {
- token = parser.parseClassOrMixinMember(metadata ?? token).next;
+ // TODO(danrubel): disambiguate between class/mixin/extension members
+ token = parser.parseClassMember(metadata ?? token, null).next;
}
listenerFinishFields(listener, startToken, metadata, isTopLevel);
listener.checkEmpty(token.charOffset);
@@ -910,9 +932,9 @@
declaration = currentDeclaration.scope.local[name];
}
} else if (getOrSet != null && optional("set", getOrSet)) {
- declaration = library.scope.setters[name];
+ declaration = libraryBuilder.scope.setters[name];
} else {
- declaration = library.scopeBuilder[name];
+ declaration = libraryBuilder.scopeBuilder[name];
}
declaration = handleDuplicatedName(declaration, token);
checkBuilder(token, declaration, name);
@@ -977,7 +999,7 @@
@override
void addProblem(Message message, int charOffset, int length,
{bool wasHandled: false, List<LocatedMessage> context}) {
- library.addProblem(message, charOffset, length, uri,
+ libraryBuilder.addProblem(message, charOffset, length, uri,
wasHandled: wasHandled, context: context);
}
diff --git a/pkg/front_end/lib/src/fasta/source/outline_builder.dart b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
index 65d70e6..13ee5bc 100644
--- a/pkg/front_end/lib/src/fasta/source/outline_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
@@ -25,7 +25,6 @@
messageExpectedBlockToSkip,
messageInterpolationInUri,
messageOperatorWithOptionalFormals,
- messageStaticConstructor,
messageTypedefNotFunction,
Template,
templateCycleInTypeVariables,
@@ -76,7 +75,7 @@
import '../parser.dart'
show
Assert,
- ClassKind,
+ DeclarationKind,
FormalParameterKind,
IdentifierContext,
lengthOfSpan,
@@ -454,7 +453,7 @@
}
@override
- void beginClassOrNamedMixinApplication(Token token) {
+ void beginClassOrNamedMixinApplicationPrelude(Token token) {
debugEvent("beginClassOrNamedMixinApplication");
library.beginNestedDeclaration(
TypeParameterScopeKind.classOrNamedMixinApplication,
@@ -481,12 +480,16 @@
}
@override
- void beginClassOrMixinBody(ClassKind kind, Token token) {
- if (kind == ClassKind.Extension) {
- assert(checkState(token, [ValueKind.TypeBuilder]));
- TypeBuilder extensionThisType = peek();
- library.currentTypeParameterScopeBuilder
- .registerExtensionThisType(extensionThisType);
+ void beginClassOrMixinBody(DeclarationKind kind, Token token) {
+ if (kind == DeclarationKind.Extension) {
+ assert(checkState(token, [
+ unionOfKinds([ValueKind.ParserRecovery, ValueKind.TypeBuilder])
+ ]));
+ Object extensionThisType = peek();
+ if (extensionThisType is TypeBuilder) {
+ library.currentTypeParameterScopeBuilder
+ .registerExtensionThisType(extensionThisType);
+ }
}
debugEvent("beginClassOrMixinBody");
// Resolve unresolved types from the class header (i.e., superclass, mixins,
@@ -629,17 +632,23 @@
}
@override
+ void beginExtensionDeclarationPrelude(Token extensionKeyword) {
+ assert(checkState(extensionKeyword, [ValueKind.MetadataListOrNull]));
+ debugEvent("beginExtensionDeclaration");
+ library.beginNestedDeclaration(
+ TypeParameterScopeKind.extensionDeclaration, "extension");
+ }
+
+ @override
void beginExtensionDeclaration(Token extensionKeyword, Token nameToken) {
assert(checkState(extensionKeyword,
[ValueKind.TypeVariableListOrNull, ValueKind.MetadataListOrNull]));
debugEvent("beginExtensionDeclaration");
- library.beginNestedDeclaration(
- TypeParameterScopeKind.extensionDeclaration, "extension");
List<TypeVariableBuilder> typeVariables = pop();
int offset = nameToken?.charOffset ?? extensionKeyword.charOffset;
String name = nameToken?.lexeme ??
// Synthesized name used internally.
- 'extension#${unnamedExtensionCounter++}';
+ '_extension#${unnamedExtensionCounter++}';
push(name);
push(offset);
push(typeVariables ?? NullValue.TypeVariables);
@@ -651,7 +660,7 @@
void endExtensionDeclaration(
Token extensionKeyword, Token onKeyword, Token endToken) {
assert(checkState(extensionKeyword, [
- ValueKind.TypeBuilder,
+ unionOfKinds([ValueKind.ParserRecovery, ValueKind.TypeBuilder]),
ValueKind.TypeVariableListOrNull,
ValueKind.Integer,
ValueKind.NameOrNull,
@@ -805,10 +814,7 @@
modifiers.add(External);
}
if (staticToken != null) {
- if (inConstructor) {
- handleRecoverableError(
- messageStaticConstructor, staticToken, staticToken);
- } else {
+ if (!inConstructor) {
modifiers ??= <Modifier>[];
modifiers.add(Static);
}
@@ -838,7 +844,7 @@
}
@override
- void endMethod(Token getOrSet, Token beginToken, Token beginParam,
+ void endClassMethod(Token getOrSet, Token beginToken, Token beginParam,
Token beginInitializers, Token endToken) {
assert(checkState(beginToken, [ValueKind.MethodBody]));
debugEvent("Method");
@@ -961,17 +967,15 @@
// We synthesize the names of the generated [TypeParameter]s, i.e.
// rename 'T' to '#T'. We cannot do it on the builders because their
// names are used to create the scope.
- // TODO(johnniwinther): Handle shadowing of extension type variables.
List<TypeVariableBuilder> synthesizedTypeVariables = library
.copyTypeVariables(extension.typeVariables, declarationBuilder,
- // TODO(johnniwinther): The synthesized names show up in
- // messages. Move synthesizing of names later to avoid this.
- synthesizeTypeParameterNames: true);
+ isExtensionTypeParameter: true);
substitution = {};
for (int i = 0; i < synthesizedTypeVariables.length; i++) {
substitution[extension.typeVariables[i]] =
new NamedTypeBuilder.fromTypeDeclarationBuilder(
- synthesizedTypeVariables[i]);
+ synthesizedTypeVariables[i],
+ const NullabilityBuilder.pendingImplementation());
}
if (typeVariables != null) {
typeVariables = synthesizedTypeVariables..addAll(typeVariables);
@@ -982,8 +986,11 @@
List<FormalParameterBuilder> synthesizedFormals = [];
TypeBuilder thisType = extension.extensionThisType;
if (substitution != null) {
- thisType = thisType.subst(substitution);
- declarationBuilder.addType(new UnresolvedType(thisType, -1, null));
+ List<NamedTypeBuilder> unboundTypes = [];
+ thisType = thisType.subst(substitution, unboundTypes);
+ for (NamedTypeBuilder unboundType in unboundTypes) {
+ extension.addType(new UnresolvedType(unboundType, -1, null));
+ }
}
synthesizedFormals.add(new FormalParameterBuilder(
null, finalMask, thisType, "#this", null, charOffset));
@@ -1129,13 +1136,18 @@
if (!library.loader.target.enableNonNullable) {
reportErrorIfNullableType(questionMark);
}
+ bool isMarkedAsNullable = questionMark != null;
List<TypeBuilder> arguments = pop();
int charOffset = pop();
Object name = pop();
if (name is ParserRecovery) {
push(name);
} else {
- push(library.addNamedType(name, arguments, charOffset));
+ push(library.addNamedType(
+ name,
+ library.computeNullabilityFromToken(isMarkedAsNullable),
+ arguments,
+ charOffset));
}
}
@@ -1479,7 +1491,7 @@
}
@override
- void endFields(Token staticToken, Token covariantToken, Token lateToken,
+ void endClassFields(Token staticToken, Token covariantToken, Token lateToken,
Token varFinalOrConst, int count, Token beginToken, Token endToken) {
debugEvent("Fields");
if (!library.loader.target.enableNonNullable) {
@@ -1606,6 +1618,12 @@
: templateCycleInTypeVariables.withArguments(
builder.name, via.join("', '"));
addProblem(message, builder.charOffset, builder.name.length);
+ builder.bound = new NamedTypeBuilder(builder.name,
+ const NullabilityBuilder.pendingImplementation(), null)
+ ..bind(new InvalidTypeBuilder(
+ builder.name,
+ message.withLocation(
+ uri, builder.charOffset, builder.name.length)));
}
}
}
@@ -1662,9 +1680,9 @@
}
@override
- void endFactoryMethod(
+ void endClassFactoryMethod(
Token beginToken, Token factoryKeyword, Token endToken) {
- debugEvent("FactoryMethod");
+ debugEvent("ClassFactoryMethod");
MethodBody kind = pop();
ConstructorReferenceBuilder redirectionTarget;
if (kind == MethodBody.RedirectingFactoryBody) {
@@ -1797,7 +1815,7 @@
@override
void endClassOrMixinBody(
- ClassKind kind, int memberCount, Token beginToken, Token endToken) {
+ DeclarationKind kind, int memberCount, Token beginToken, Token endToken) {
debugEvent("ClassOrMixinBody");
}
diff --git a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
index 7edee90..a55b41d 100644
--- a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
@@ -33,6 +33,7 @@
NamedTypeBuilder,
LibraryBuilder,
MetadataBuilder,
+ NullabilityBuilder,
Scope,
TypeBuilder,
TypeVariableBuilder,
@@ -129,10 +130,10 @@
cls.addMember(field);
}
} else if (declaration is FunctionBuilder) {
- Member function = declaration.build(library);
- function.parent = cls;
+ Member member = declaration.build(library);
+ member.parent = cls;
if (!declaration.isPatch && declaration.next == null) {
- cls.addMember(function);
+ cls.addMember(member);
}
} else {
unhandled("${declaration.runtimeType}", "buildBuilders",
@@ -257,7 +258,8 @@
}
}
if (message != null) {
- return new NamedTypeBuilder(supertype.name, null)
+ return new NamedTypeBuilder(supertype.name,
+ const NullabilityBuilder.pendingImplementation(), null)
..bind(new InvalidTypeBuilder(supertype.name,
message.withLocation(fileUri, charOffset, noLength)));
}
diff --git a/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart b/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart
index fd87fa7..1961514 100644
--- a/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart
@@ -15,7 +15,7 @@
import 'source_library_builder.dart';
import '../kernel/kernel_builder.dart';
-import '../problems.dart' show unexpected, unhandled;
+import '../problems.dart';
import '../fasta_codes.dart'
show
@@ -48,7 +48,10 @@
super(metadata, modifiers, name, parent, nameOffset, scope,
typeParameters, onType);
- Extension build(SourceLibraryBuilder library, LibraryBuilder coreLibrary) {
+ Extension get extension => _extension;
+
+ Extension build(
+ SourceLibraryBuilder libraryBuilder, LibraryBuilder coreLibrary) {
void buildBuilders(String name, Builder declaration) {
do {
if (declaration.parent != this) {
@@ -60,21 +63,50 @@
charOffset, fileUri);
}
} else if (declaration is FieldBuilder) {
- Field field = declaration.build(library);
- library.target.addMember(field);
+ Field field = declaration.build(libraryBuilder);
+ libraryBuilder.library.addMember(field);
_extension.members.add(new ExtensionMemberDescriptor(
- name: new Name(declaration.name, library.target),
+ name: new Name(declaration.name, libraryBuilder.library),
member: field.reference,
- isStatic: declaration.isStatic));
- } else if (declaration is FunctionBuilder) {
- Member function = declaration.build(library);
- library.target.addMember(function);
+ isStatic: declaration.isStatic,
+ kind: ExtensionMemberKind.Field));
+ } else if (declaration is ProcedureBuilder) {
+ Member function = declaration.build(libraryBuilder);
+ libraryBuilder.library.addMember(function);
+ ExtensionMemberKind kind;
+ switch (declaration.kind) {
+ case ProcedureKind.Method:
+ kind = ExtensionMemberKind.Method;
+ break;
+ case ProcedureKind.Getter:
+ kind = ExtensionMemberKind.Getter;
+ break;
+ case ProcedureKind.Setter:
+ kind = ExtensionMemberKind.Setter;
+ break;
+ case ProcedureKind.Operator:
+ kind = ExtensionMemberKind.Operator;
+ break;
+ case ProcedureKind.Factory:
+ unsupported("Extension method kind: ${declaration.kind}",
+ declaration.charOffset, declaration.fileUri);
+ }
_extension.members.add(new ExtensionMemberDescriptor(
- name: new Name(declaration.name, library.target),
+ name: new Name(declaration.name, libraryBuilder.library),
member: function.reference,
isStatic: declaration.isStatic,
isExternal: declaration.isExternal,
- kind: declaration.kind));
+ kind: kind));
+ Procedure tearOff = declaration.extensionTearOff;
+ if (tearOff != null) {
+ libraryBuilder.library.addMember(tearOff);
+ _extension.members.add(new ExtensionMemberDescriptor(
+ name: new Name(declaration.name, libraryBuilder.library),
+ member: tearOff.reference,
+ isStatic: false,
+ isExternal: false,
+ kind: ExtensionMemberKind.TearOff));
+ }
} else {
unhandled("${declaration.runtimeType}", "buildBuilders",
declaration.charOffset, declaration.fileUri);
@@ -108,7 +140,7 @@
}
});
- _extension.onType = onType?.build(library);
+ _extension.onType = onType?.build(libraryBuilder);
return _extension;
}
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 5747b08..308acca 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
@@ -72,6 +72,7 @@
NameIterator,
PrefixBuilder,
FunctionBuilder,
+ NullabilityBuilder,
QualifiedName,
Scope,
TypeBuilder,
@@ -278,6 +279,7 @@
/// an error reading its source.
Message accessProblem;
+ @override
final Library library;
final SourceLibraryBuilder actualOrigin;
@@ -357,7 +359,9 @@
scope,
actualOrigin,
target ??
- (actualOrigin?.library ?? new Library(uri, fileUri: fileUri)),
+ (actualOrigin?.library ?? new Library(uri, fileUri: fileUri)
+ ..setLanguageVersion(loader.target.currentSdkVersionMajor,
+ loader.target.currentSdkVersionMinor)),
nameOrigin);
@override
@@ -376,7 +380,7 @@
@override
void setLanguageVersion(int major, int minor,
- {int offset: 0, int length: noLength, bool explicit}) {
+ {int offset: 0, int length: noLength, bool explicit: false}) {
if (languageVersionExplicitlySet) return;
if (explicit) languageVersionExplicitlySet = true;
@@ -386,15 +390,15 @@
return;
}
- // If no language version has been set, the default is used.
- // If trying to set a langauge version that is higher than the "already-set"
+ // If trying to set a langauge version that is higher than the current sdk
// version it's an error.
- if (major > library.languageVersionMajor ||
- (major == library.languageVersionMajor &&
- minor > library.languageVersionMinor)) {
+ if (major > loader.target.currentSdkVersionMajor ||
+ (major == loader.target.currentSdkVersionMajor &&
+ minor > loader.target.currentSdkVersionMinor)) {
addPostponedProblem(
templateLanguageVersionTooHigh.withArguments(
- library.languageVersionMajor, library.languageVersionMinor),
+ loader.target.currentSdkVersionMajor,
+ loader.target.currentSdkVersionMinor),
offset,
length,
fileUri);
@@ -723,6 +727,9 @@
existing.fileUri, existing.charOffset, fullName.length)
]);
}
+ if (declaration.isExtension) {
+ currentTypeParameterScopeBuilder.extensions.add(declaration);
+ }
return members[name] = declaration;
}
@@ -983,9 +990,9 @@
boundlessTypeVariables.addAll(part.boundlessTypeVariables);
// Check that the targets are different. This is not normally a problem
// but is for patch files.
- if (target != part.target && part.target.problemsAsJson != null) {
- target.problemsAsJson ??= <String>[];
- target.problemsAsJson.addAll(part.target.problemsAsJson);
+ if (library != part.library && part.library.problemsAsJson != null) {
+ library.problemsAsJson ??= <String>[];
+ library.problemsAsJson.addAll(part.library.problemsAsJson);
}
List<FieldBuilder> partImplicitlyTypedFields =
part.takeImplicitlyTypedFields();
@@ -1049,7 +1056,15 @@
while (memberLast.next != null) {
memberLast = memberLast.next;
}
- library.additionalExports.add(memberLast.target.reference);
+ if (memberLast is ClassBuilder) {
+ library.additionalExports.add(memberLast.cls.reference);
+ } else if (memberLast is TypeAliasBuilder) {
+ library.additionalExports.add(memberLast.typedef.reference);
+ } else if (memberLast is ExtensionBuilder) {
+ library.additionalExports.add(memberLast.extension.reference);
+ } else {
+ library.additionalExports.add(memberLast.target.reference);
+ }
}
}
}
@@ -1070,6 +1085,9 @@
} else {
map[name] = member;
}
+ if (member.isExtension) {
+ importScope.addExtension(member);
+ }
}
/// Resolves all unresolved types in [types]. The list of types is cleared
@@ -1138,9 +1156,6 @@
@override
SourceLibraryBuilder get origin => actualOrigin ?? this;
- @override
- Library get target => library;
-
Uri get uri => library.importUri;
void addSyntheticDeclarationOfDynamic() {
@@ -1148,9 +1163,10 @@
"dynamic", new DynamicTypeBuilder(const DynamicType(), this, -1), -1);
}
- TypeBuilder addNamedType(
- Object name, List<TypeBuilder> arguments, int charOffset) {
- return addType(new NamedTypeBuilder(name, arguments), charOffset);
+ TypeBuilder addNamedType(Object name, NullabilityBuilder nullabilityBuilder,
+ List<TypeBuilder> arguments, int charOffset) {
+ return addType(
+ new NamedTypeBuilder(name, nullabilityBuilder, arguments), charOffset);
}
TypeBuilder addMixinApplication(
@@ -1159,7 +1175,9 @@
}
TypeBuilder addVoidType(int charOffset) {
- return addNamedType("void", null, charOffset)
+ // 'void' is always nullable.
+ return addNamedType(
+ "void", const NullabilityBuilder.nullable(), null, charOffset)
..bind(new VoidTypeBuilder(const VoidType(), this, charOffset));
}
@@ -1204,8 +1222,8 @@
severity: severity,
problemOnLibrary: true);
if (formattedMessage != null) {
- target.problemsAsJson ??= <String>[];
- target.problemsAsJson.add(formattedMessage.toJsonString());
+ library.problemsAsJson ??= <String>[];
+ library.problemsAsJson.add(formattedMessage.toJsonString());
}
return formattedMessage;
}
@@ -1286,14 +1304,17 @@
Map<String, MemberBuilder> constructors = declaration.constructors;
Map<String, MemberBuilder> setters = declaration.setters;
- Scope classScope = new Scope(members, setters,
- scope.withTypeVariables(typeVariables), "class $className",
+ Scope classScope = new Scope(
+ local: members,
+ setters: setters,
+ parent: scope.withTypeVariables(typeVariables),
+ debugName: "class $className",
isModifiable: false);
// When looking up a constructor, we don't consider type variables or the
// library scope.
- Scope constructorScope =
- new Scope(constructors, null, null, className, isModifiable: false);
+ Scope constructorScope = new Scope(
+ local: constructors, debugName: className, isModifiable: false);
bool isMixinDeclaration = false;
if (modifiers & mixinDeclarationMask != 0) {
isMixinDeclaration = true;
@@ -1302,7 +1323,7 @@
if (declaration.hasConstConstructor) {
modifiers |= hasConstConstructorMask;
}
- ClassBuilder cls = new SourceClassBuilder(
+ ClassBuilder classBuilder = new SourceClassBuilder(
metadata,
modifiers,
className,
@@ -1323,14 +1344,14 @@
endOffset,
isMixinDeclaration: isMixinDeclaration);
loader.target.metadataCollector
- ?.setDocumentationComment(cls.target, documentationComment);
+ ?.setDocumentationComment(classBuilder.cls, documentationComment);
constructorReferences.clear();
Map<String, TypeVariableBuilder> typeVariablesByName =
- checkTypeVariables(typeVariables, cls);
+ checkTypeVariables(typeVariables, classBuilder);
void setParent(String name, MemberBuilder member) {
while (member != null) {
- member.parent = cls;
+ member.parent = classBuilder;
member = member.next;
}
}
@@ -1339,8 +1360,10 @@
if (typeVariablesByName != null) {
TypeVariableBuilder tv = typeVariablesByName[name];
if (tv != null) {
- cls.addProblem(templateConflictsWithTypeVariable.withArguments(name),
- member.charOffset, name.length,
+ classBuilder.addProblem(
+ templateConflictsWithTypeVariable.withArguments(name),
+ member.charOffset,
+ name.length,
context: [
messageConflictsWithTypeVariableCause.withLocation(
tv.fileUri, tv.charOffset, name.length)
@@ -1353,7 +1376,7 @@
members.forEach(setParentAndCheckConflicts);
constructors.forEach(setParentAndCheckConflicts);
setters.forEach(setParentAndCheckConflicts);
- addBuilder(className, cls, nameOffset);
+ addBuilder(className, classBuilder, nameOffset);
}
Map<String, TypeVariableBuilder> checkTypeVariables(
@@ -1364,14 +1387,21 @@
for (TypeVariableBuilder tv in typeVariables) {
TypeVariableBuilder existing = typeVariablesByName[tv.name];
if (existing != null) {
- addProblem(messageTypeVariableDuplicatedName, tv.charOffset,
- tv.name.length, fileUri,
- context: [
- templateTypeVariableDuplicatedNameCause
- .withArguments(tv.name)
- .withLocation(
- fileUri, existing.charOffset, existing.name.length)
- ]);
+ if (existing.isExtensionTypeParameter) {
+ // The type parameter from the extension is shadowed by the type
+ // parameter from the member. Rename the shadowed type parameter.
+ existing.parameter.name = '#${existing.name}';
+ typeVariablesByName[tv.name] = tv;
+ } else {
+ addProblem(messageTypeVariableDuplicatedName, tv.charOffset,
+ tv.name.length, fileUri,
+ context: [
+ templateTypeVariableDuplicatedNameCause
+ .withArguments(tv.name)
+ .withLocation(
+ fileUri, existing.charOffset, existing.name.length)
+ ]);
+ }
} else {
typeVariablesByName[tv.name] = tv;
if (owner is ClassBuilder) {
@@ -1406,11 +1436,14 @@
Map<String, MemberBuilder> constructors = declaration.constructors;
Map<String, MemberBuilder> setters = declaration.setters;
- Scope classScope = new Scope(members, setters,
- scope.withTypeVariables(typeVariables), "extension $extensionName",
+ Scope classScope = new Scope(
+ local: members,
+ setters: setters,
+ parent: scope.withTypeVariables(typeVariables),
+ debugName: "extension $extensionName",
isModifiable: false);
- ExtensionBuilder extension = new SourceExtensionBuilder(
+ ExtensionBuilder extensionBuilder = new SourceExtensionBuilder(
metadata,
modifiers,
extensionName,
@@ -1421,15 +1454,15 @@
startOffset,
nameOffset,
endOffset);
- loader.target.metadataCollector
- ?.setDocumentationComment(extension.target, documentationComment);
+ loader.target.metadataCollector?.setDocumentationComment(
+ extensionBuilder.extension, documentationComment);
constructorReferences.clear();
Map<String, TypeVariableBuilder> typeVariablesByName =
- checkTypeVariables(typeVariables, extension);
+ checkTypeVariables(typeVariables, extensionBuilder);
void setParent(String name, MemberBuilder member) {
while (member != null) {
- member.parent = extension;
+ member.parent = extensionBuilder;
member = member.next;
}
}
@@ -1438,7 +1471,7 @@
if (typeVariablesByName != null) {
TypeVariableBuilder tv = typeVariablesByName[name];
if (tv != null) {
- extension.addProblem(
+ extensionBuilder.addProblem(
templateConflictsWithTypeVariable.withArguments(name),
member.charOffset,
name.length,
@@ -1454,7 +1487,7 @@
members.forEach(setParentAndCheckConflicts);
constructors.forEach(setParentAndCheckConflicts);
setters.forEach(setParentAndCheckConflicts);
- addBuilder(extensionName, extension, nameOffset);
+ addBuilder(extensionName, extensionBuilder, nameOffset);
}
TypeBuilder applyMixins(TypeBuilder type, int startCharOffset, int charOffset,
@@ -1624,13 +1657,17 @@
applicationTypeArguments = <TypeBuilder>[];
for (TypeVariableBuilder typeVariable in typeVariables) {
- applicationTypeArguments
- .add(addNamedType(typeVariable.name, null, charOffset)..bind(
- // The type variable types passed as arguments to the
- // generic class representing the anonymous mixin
- // application should refer back to the type variables of
- // the class that extend the anonymous mixin application.
- typeVariable));
+ applicationTypeArguments.add(addNamedType(
+ typeVariable.name,
+ const NullabilityBuilder.pendingImplementation(),
+ null,
+ charOffset)
+ ..bind(
+ // The type variable types passed as arguments to the
+ // generic class representing the anonymous mixin
+ // application should refer back to the type variables of
+ // the class that extend the anonymous mixin application.
+ typeVariable));
}
}
}
@@ -1650,10 +1687,15 @@
? interfaces
: isMixinDeclaration ? [supertype, mixin] : null,
null, // No `on` clause types.
- new Scope(<String, MemberBuilder>{}, <String, MemberBuilder>{},
- scope.withTypeVariables(typeVariables),
- "mixin $fullname ", isModifiable: false),
- new Scope(<String, MemberBuilder>{}, null, null, fullname,
+ new Scope(
+ local: <String, MemberBuilder>{},
+ setters: <String, MemberBuilder>{},
+ parent: scope.withTypeVariables(typeVariables),
+ debugName: "mixin $fullname ",
+ isModifiable: false),
+ new Scope(
+ local: <String, MemberBuilder>{},
+ debugName: fullname,
isModifiable: false),
this,
<ConstructorReferenceBuilder>[],
@@ -1662,16 +1704,19 @@
charEndOffset,
mixedInType: isMixinDeclaration ? null : mixin);
if (isNamedMixinApplication) {
- loader.target.metadataCollector?.setDocumentationComment(
- application.target, documentationComment);
+ loader.target.metadataCollector
+ ?.setDocumentationComment(application.cls, documentationComment);
}
// TODO(ahe, kmillikin): Should always be true?
// pkg/analyzer/test/src/summary/resynthesize_kernel_test.dart can't
// handle that :(
application.cls.isAnonymousMixin = !isNamedMixinApplication;
addBuilder(fullname, application, charOffset);
- supertype =
- addNamedType(fullname, applicationTypeArguments, charOffset);
+ supertype = addNamedType(
+ fullname,
+ const NullabilityBuilder.pendingImplementation(),
+ applicationTypeArguments,
+ charOffset);
}
return supertype;
} else {
@@ -1718,16 +1763,17 @@
if (hasInitializer) {
modifiers |= hasInitializerMask;
}
- FieldBuilder field = new FieldBuilder(
+ FieldBuilder fieldBuilder = new FieldBuilder(
metadata, type, name, modifiers, this, charOffset, charEndOffset);
- field.constInitializerToken = constInitializerToken;
- addBuilder(name, field, charOffset);
+ fieldBuilder.constInitializerToken = constInitializerToken;
+ addBuilder(name, fieldBuilder, charOffset);
if (!legacyMode && type == null && initializerToken != null) {
- field.target.type = new ImplicitFieldType(field, initializerToken);
- (implicitlyTypedFields ??= <FieldBuilder>[]).add(field);
+ fieldBuilder.field.type =
+ new ImplicitFieldType(fieldBuilder, initializerToken);
+ (implicitlyTypedFields ??= <FieldBuilder>[]).add(fieldBuilder);
}
loader.target.metadataCollector
- ?.setDocumentationComment(field.target, documentationComment);
+ ?.setDocumentationComment(fieldBuilder.field, documentationComment);
}
void addConstructor(
@@ -1746,7 +1792,7 @@
String nativeMethodName,
{Token beginInitializers}) {
MetadataCollector metadataCollector = loader.target.metadataCollector;
- ConstructorBuilder procedure = new ConstructorBuilder(
+ ConstructorBuilder constructorBuilder = new ConstructorBuilder(
metadata,
modifiers & ~abstractMask,
returnType,
@@ -1760,18 +1806,20 @@
charEndOffset,
nativeMethodName);
metadataCollector?.setDocumentationComment(
- procedure.target, documentationComment);
- metadataCollector?.setConstructorNameOffset(procedure.target, name);
- checkTypeVariables(typeVariables, procedure);
- addBuilder(constructorName, procedure, charOffset);
+ constructorBuilder.constructor, documentationComment);
+ metadataCollector?.setConstructorNameOffset(
+ constructorBuilder.constructor, name);
+ checkTypeVariables(typeVariables, constructorBuilder);
+ addBuilder(constructorName, constructorBuilder, charOffset);
if (nativeMethodName != null) {
- addNativeMethod(procedure);
+ addNativeMethod(constructorBuilder);
}
- if (procedure.isConst) {
+ if (constructorBuilder.isConst) {
currentTypeParameterScopeBuilder?.hasConstConstructor = true;
// const constructors will have their initializers compiled and written
// into the outline.
- procedure.beginInitializers = beginInitializers ?? Token.eof(-1);
+ constructorBuilder.beginInitializers =
+ beginInitializers ?? new Token.eof(-1);
}
}
@@ -1799,7 +1847,7 @@
returnType = addVoidType(charOffset);
}
}
- FunctionBuilder procedure = new ProcedureBuilder(
+ ProcedureBuilder procedureBuilder = new ProcedureBuilder(
metadata,
modifiers,
returnType,
@@ -1814,11 +1862,11 @@
charEndOffset,
nativeMethodName);
metadataCollector?.setDocumentationComment(
- procedure.target, documentationComment);
- checkTypeVariables(typeVariables, procedure);
- addBuilder(name, procedure, charOffset);
+ procedureBuilder.procedure, documentationComment);
+ checkTypeVariables(typeVariables, procedureBuilder);
+ addBuilder(name, procedureBuilder, charOffset);
if (nativeMethodName != null) {
- addNativeMethod(procedure);
+ addNativeMethod(procedureBuilder);
}
}
@@ -1836,6 +1884,7 @@
String nativeMethodName) {
TypeBuilder returnType = addNamedType(
currentTypeParameterScopeBuilder.parent.name,
+ const NullabilityBuilder.omitted(),
<TypeBuilder>[],
charOffset);
// Nested declaration began in `OutlineBuilder.beginFactoryMethod`.
@@ -1852,9 +1901,9 @@
procedureName = name;
}
- ProcedureBuilder procedure;
+ ProcedureBuilder procedureBuilder;
if (redirectionTarget != null) {
- procedure = new RedirectingFactoryBuilder(
+ procedureBuilder = new RedirectingFactoryBuilder(
metadata,
staticMask | modifiers,
returnType,
@@ -1872,7 +1921,7 @@
nativeMethodName,
redirectionTarget);
} else {
- procedure = new ProcedureBuilder(
+ procedureBuilder = new ProcedureBuilder(
metadata,
staticMask | modifiers,
returnType,
@@ -1893,22 +1942,24 @@
MetadataCollector metadataCollector = loader.target.metadataCollector;
metadataCollector?.setDocumentationComment(
- procedure.target, documentationComment);
- metadataCollector?.setConstructorNameOffset(procedure.target, name);
+ procedureBuilder.procedure, documentationComment);
+ metadataCollector?.setConstructorNameOffset(
+ procedureBuilder.procedure, name);
TypeParameterScopeBuilder savedDeclaration =
currentTypeParameterScopeBuilder;
currentTypeParameterScopeBuilder = factoryDeclaration;
- for (TypeVariableBuilder tv in procedure.typeVariables) {
- NamedTypeBuilder t = procedure.returnType;
- t.arguments.add(addNamedType(tv.name, null, procedure.charOffset));
+ for (TypeVariableBuilder tv in procedureBuilder.typeVariables) {
+ NamedTypeBuilder t = procedureBuilder.returnType;
+ t.arguments.add(addNamedType(tv.name, const NullabilityBuilder.omitted(),
+ null, procedureBuilder.charOffset));
}
currentTypeParameterScopeBuilder = savedDeclaration;
- factoryDeclaration.resolveTypes(procedure.typeVariables, this);
- addBuilder(procedureName, procedure, charOffset);
+ factoryDeclaration.resolveTypes(procedureBuilder.typeVariables, this);
+ addBuilder(procedureName, procedureBuilder, charOffset);
if (nativeMethodName != null) {
- addNativeMethod(procedure);
+ addNativeMethod(procedureBuilder);
}
}
@@ -1925,7 +1976,7 @@
enumConstantInfos, this, startCharOffset, charOffset, charEndOffset);
addBuilder(name, builder, charOffset);
metadataCollector?.setDocumentationComment(
- builder.target, documentationComment);
+ builder.cls, documentationComment);
}
void addFunctionTypeAlias(
@@ -1935,15 +1986,15 @@
List<TypeVariableBuilder> typeVariables,
FunctionTypeBuilder type,
int charOffset) {
- TypeAliasBuilder typedef = new TypeAliasBuilder(
+ TypeAliasBuilder typedefBuilder = new TypeAliasBuilder(
metadata, name, typeVariables, type, this, charOffset);
loader.target.metadataCollector
- ?.setDocumentationComment(typedef.target, documentationComment);
- checkTypeVariables(typeVariables, typedef);
+ ?.setDocumentationComment(typedefBuilder.typedef, documentationComment);
+ checkTypeVariables(typeVariables, typedefBuilder);
// Nested declaration began in `OutlineBuilder.beginFunctionTypeAlias`.
endNestedDeclaration(TypeParameterScopeKind.typedef, "#typedef")
.resolveTypes(typeVariables, this);
- addBuilder(name, typedef, charOffset);
+ addBuilder(name, typedefBuilder, charOffset);
}
FunctionTypeBuilder addFunctionType(
@@ -2098,7 +2149,7 @@
library.addDependency(import.prefixBuilder.dependency);
} else {
library.addDependency(new LibraryDependency.import(
- import.imported.target,
+ import.imported.library,
name: import.prefix,
combinators: toKernelCombinators(import.combinators))
..fileOffset = import.charOffset);
@@ -2107,7 +2158,7 @@
// Add export
Export export = exports[exportIndex++];
library.addDependency(new LibraryDependency.export(
- export.exported.target,
+ export.exported.library,
combinators: toKernelCombinators(export.combinators))
..fileOffset = export.charOffset);
}
@@ -2302,14 +2353,14 @@
/// [TypeParameter] are prefix with '#' to indicate that their synthesized.
List<TypeVariableBuilder> copyTypeVariables(
List<TypeVariableBuilder> original, TypeParameterScopeBuilder declaration,
- {bool synthesizeTypeParameterNames: false}) {
+ {bool isExtensionTypeParameter: false}) {
List<TypeBuilder> newTypes = <TypeBuilder>[];
List<TypeVariableBuilder> copy = <TypeVariableBuilder>[];
for (TypeVariableBuilder variable in original) {
TypeVariableBuilder newVariable = new TypeVariableBuilder(
variable.name, this, variable.charOffset,
bound: variable.bound?.clone(newTypes),
- synthesizeTypeParameterName: synthesizeTypeParameterNames);
+ isExtensionTypeParameter: isExtensionTypeParameter);
copy.add(newVariable);
boundlessTypeVariables.add(newVariable);
}
@@ -2830,10 +2881,10 @@
while (iterator.moveNext()) {
Builder declaration = iterator.current;
if (declaration is FieldBuilder) {
- checkBoundsInField(declaration.target, typeEnvironment);
+ checkBoundsInField(declaration.field, typeEnvironment);
} else if (declaration is ProcedureBuilder) {
- checkBoundsInFunctionNode(
- declaration.target.function, typeEnvironment, declaration.fileUri);
+ checkBoundsInFunctionNode(declaration.procedure.function,
+ typeEnvironment, declaration.fileUri);
} else if (declaration is ClassBuilder) {
declaration.checkBoundsInOutline(typeEnvironment);
}
@@ -2892,6 +2943,8 @@
final Map<String, Builder> setters;
+ final List<ExtensionBuilder> extensions;
+
final List<UnresolvedType> types = <UnresolvedType>[];
// TODO(johnniwinther): Stop using [_name] for determining the declaration
@@ -2912,14 +2965,28 @@
bool hasConstConstructor = false;
- TypeParameterScopeBuilder(this._kind, this.members, this.setters,
- this.constructors, this._name, this._charOffset, this.parent) {
+ TypeParameterScopeBuilder(
+ this._kind,
+ this.members,
+ this.setters,
+ this.constructors,
+ this.extensions,
+ this._name,
+ this._charOffset,
+ this.parent) {
assert(_name != null);
}
TypeParameterScopeBuilder.library()
- : this(TypeParameterScopeKind.library, <String, Builder>{},
- <String, Builder>{}, null, "<library>", -1, null);
+ : this(
+ TypeParameterScopeKind.library,
+ <String, Builder>{},
+ <String, Builder>{},
+ null, // No support for constructors in library scopes.
+ <ExtensionBuilder>[],
+ "<library>",
+ -1,
+ null);
TypeParameterScopeBuilder createNested(
TypeParameterScopeKind kind, String name, bool hasMembers) {
@@ -2928,6 +2995,7 @@
hasMembers ? <String, MemberBuilder>{} : null,
hasMembers ? <String, MemberBuilder>{} : null,
hasMembers ? <String, MemberBuilder>{} : null,
+ null, // No support for extensions in nested scopes.
name,
-1,
this);
@@ -3092,7 +3160,13 @@
}
Scope toScope(Scope parent) {
- return new Scope(members, setters, parent, name, isModifiable: false);
+ return new Scope(
+ local: members,
+ setters: setters,
+ extensions: extensions,
+ parent: parent,
+ debugName: name,
+ isModifiable: false);
}
@override
diff --git a/pkg/front_end/lib/src/fasta/source/source_loader.dart b/pkg/front_end/lib/src/fasta/source/source_loader.dart
index c954495..f9a2a91 100644
--- a/pkg/front_end/lib/src/fasta/source/source_loader.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart
@@ -113,6 +113,8 @@
Token,
scan;
+import '../type_inference/type_inferrer.dart';
+
import 'diet_listener.dart' show DietListener;
import 'diet_parser.dart' show DietParser;
@@ -212,9 +214,6 @@
enableExtensionMethods: target.enableExtensionMethods,
enableNonNullable: target.enableNonNullable),
languageVersionChanged: (_, LanguageVersionToken version) {
- // TODO(jensj): What if we have several? What if it is unsupported?
- // What if the language version was already set via packages and this is
- // higher? Etc
library.setLanguageVersion(version.major, version.minor,
offset: version.offset, length: version.length, explicit: true);
});
@@ -264,6 +263,9 @@
case "dart:_internal":
return utf8.encode(defaultDartInternalSource);
+ case "dart:typed_data":
+ return utf8.encode(defaultDartTypedDataSource);
+
default:
return utf8.encode(message == null ? "" : "/* ${message.message} */");
}
@@ -809,13 +811,13 @@
Component computeFullComponent() {
Set<Library> libraries = new Set<Library>();
List<Library> workList = <Library>[];
- builders.forEach((Uri uri, LibraryBuilder library) {
- if (!library.isPatch &&
- (library.loader == this ||
- library.uri.scheme == "dart" ||
- library == this.first)) {
- if (libraries.add(library.target)) {
- workList.add(library.target);
+ builders.forEach((Uri uri, LibraryBuilder libraryBuilder) {
+ if (!libraryBuilder.isPatch &&
+ (libraryBuilder.loader == this ||
+ libraryBuilder.uri.scheme == "dart" ||
+ libraryBuilder == this.first)) {
+ if (libraries.add(libraryBuilder.library)) {
+ workList.add(libraryBuilder.library);
}
}
});
@@ -951,7 +953,7 @@
for (SourceClassBuilder builder in sourceClasses) {
if (builder.library.loader == this && !builder.isPatch) {
if (builder.addNoSuchMethodForwarders(target, hierarchy)) {
- changedClasses.add(builder.target);
+ changedClasses.add(builder.cls);
}
}
}
@@ -962,10 +964,6 @@
void checkMixins(List<SourceClassBuilder> sourceClasses) {
for (SourceClassBuilder builder in sourceClasses) {
if (builder.library.loader == this && !builder.isPatch) {
- if (builder.isMixinDeclaration) {
- builder.checkMixinDeclaration();
- }
-
Class mixedInClass = builder.cls.mixedInClass;
if (mixedInClass != null && mixedInClass.isMixinDeclaration) {
builder.checkMixinApplication(hierarchy);
@@ -1046,8 +1044,7 @@
node.accept(collectionTransformer ??= new CollectionTransformer(this));
}
if (transformSetLiterals) {
- node.accept(setLiteralTransformer ??= new SetLiteralTransformer(this,
- transformConst: !target.enableConstantUpdate2018));
+ node.accept(setLiteralTransformer ??= new SetLiteralTransformer(this));
}
}
@@ -1061,9 +1058,8 @@
}
}
if (transformSetLiterals) {
- SetLiteralTransformer transformer = setLiteralTransformer ??=
- new SetLiteralTransformer(this,
- transformConst: !target.enableConstantUpdate2018);
+ SetLiteralTransformer transformer =
+ setLiteralTransformer ??= new SetLiteralTransformer(this);
for (int i = 0; i < list.length; ++i) {
list[i] = list[i].accept(transformer);
}
@@ -1121,6 +1117,11 @@
TypeBuilder computeTypeBuilder(DartType type) {
return type.accept(new TypeBuilderComputer(this));
}
+
+ BodyBuilder createBodyBuilderForField(
+ FieldBuilder field, TypeInferrer typeInferrer) {
+ return new BodyBuilder.forField(field, typeInferrer);
+ }
}
/// A minimal implementation of dart:core that is sufficient to create an
@@ -1264,6 +1265,16 @@
}
""";
+/// A minimal implementation of dart:typed_data that is sufficient to create an
+/// instance of [CoreTypes] and compile program.
+const String defaultDartTypedDataSource = """
+class Endian {
+ static const Endian little = null;
+ static const Endian big = null;
+ static final Endian host = null;
+}
+""";
+
class AmbiguousTypesRecord {
final Class cls;
final Supertype a;
diff --git a/pkg/front_end/lib/src/fasta/source/type_promotion_look_ahead_listener.dart b/pkg/front_end/lib/src/fasta/source/type_promotion_look_ahead_listener.dart
index c4de27c..ebf430a 100644
--- a/pkg/front_end/lib/src/fasta/source/type_promotion_look_ahead_listener.dart
+++ b/pkg/front_end/lib/src/fasta/source/type_promotion_look_ahead_listener.dart
@@ -11,7 +11,7 @@
import '../parser.dart'
show
Assert,
- ClassKind,
+ DeclarationKind,
FormalParameterKind,
IdentifierContext,
Listener,
@@ -314,7 +314,7 @@
@override
void endClassOrMixinBody(
- ClassKind kind, int memberCount, Token beginToken, Token endToken) {
+ DeclarationKind kind, int memberCount, Token beginToken, Token endToken) {
debugEvent("ClassOrMixinBody", beginToken);
state.checkEmpty(endToken);
}
@@ -545,9 +545,9 @@
}
@override
- void endFactoryMethod(
+ void endClassFactoryMethod(
Token beginToken, Token factoryKeyword, Token endToken) {
- debugEvent("FactoryMethod", beginToken);
+ debugEvent("ClassFactoryMethod", beginToken);
state.pop(); // Name.
state.checkEmpty(endToken);
}
@@ -564,7 +564,7 @@
}
@override
- void endFields(Token staticToken, Token covariantToken, Token lateToken,
+ void endClassFields(Token staticToken, Token covariantToken, Token lateToken,
Token varFinalOrConst, int count, Token beginToken, Token endToken) {
debugEvent("Fields", staticToken);
state.discard(count); // Field names.
@@ -982,7 +982,7 @@
}
@override
- void endMethod(Token getOrSet, Token beginToken, Token beginParam,
+ void endClassMethod(Token getOrSet, Token beginToken, Token beginParam,
Token beginInitializers, Token endToken) {
debugEvent("endMethod", endToken);
state.pop(); // Method name.
diff --git a/pkg/front_end/lib/src/fasta/source/value_kinds.dart b/pkg/front_end/lib/src/fasta/source/value_kinds.dart
index 9186a6d..08ecbf0 100644
--- a/pkg/front_end/lib/src/fasta/source/value_kinds.dart
+++ b/pkg/front_end/lib/src/fasta/source/value_kinds.dart
@@ -33,9 +33,9 @@
/// Checks the [value] an returns `true` if the value is of the expected kind.
bool check(Object value);
- static const ValueKind Arguments = _SingleValueKind<type.Arguments>();
+ static const ValueKind Arguments = const _SingleValueKind<type.Arguments>();
static const ValueKind ArgumentsOrNull =
- _SingleValueKind<type.Arguments>(NullValue.Arguments);
+ const _SingleValueKind<type.Arguments>(NullValue.Arguments);
static const ValueKind Expression = const _SingleValueKind<type.Expression>();
static const ValueKind Identifier = const _SingleValueKind<type.Identifier>();
static const ValueKind IdentifierOrNull =
@@ -55,7 +55,8 @@
static const ValueKind Name = const _SingleValueKind<String>();
static const ValueKind NameOrNull =
const _SingleValueKind<String>(NullValue.Name);
- static const ValueKind NameOrOperator = _UnionValueKind([Name, Operator]);
+ static const ValueKind NameOrOperator =
+ const _UnionValueKind([Name, Operator]);
static const ValueKind NameOrQualifiedNameOrOperator =
const _UnionValueKind([Name, QualifiedName, Operator]);
static const ValueKind NameOrParserRecovery =
@@ -64,9 +65,9 @@
const _SingleValueKind<List<type.MetadataBuilder>>(NullValue.Metadata);
static const ValueKind Operator = const _SingleValueKind<type.Operator>();
static const ValueKind ParserRecovery =
- _SingleValueKind<type.ParserRecovery>();
+ const _SingleValueKind<type.ParserRecovery>();
static const ValueKind ProblemBuilder =
- _SingleValueKind<type.ProblemBuilder>();
+ const _SingleValueKind<type.ProblemBuilder>();
static const ValueKind QualifiedName =
const _SingleValueKind<type.QualifiedName>();
static const ValueKind Token = const _SingleValueKind<type.Token>();
@@ -143,5 +144,5 @@
/// Helper method for creating a union of a list of [ValueKind]s.
ValueKind unionOfKinds(List<ValueKind> kinds) {
- return _UnionValueKind(kinds);
+ return new _UnionValueKind(kinds);
}
diff --git a/pkg/front_end/lib/src/fasta/target_implementation.dart b/pkg/front_end/lib/src/fasta/target_implementation.dart
index dd80c6f..e6ada23 100644
--- a/pkg/front_end/lib/src/fasta/target_implementation.dart
+++ b/pkg/front_end/lib/src/fasta/target_implementation.dart
@@ -48,24 +48,15 @@
Builder cachedNativeAnnotation;
Builder cachedNativeExtensionAnnotation;
- bool enableConstantUpdate2018;
- bool enableControlFlowCollections;
bool enableExtensionMethods;
bool enableNonNullable;
- bool enableSpreadCollections;
bool enableTripleShift;
TargetImplementation(Ticker ticker, this.uriTranslator, this.backendTarget)
- : enableConstantUpdate2018 = CompilerContext.current.options
- .isExperimentEnabled(ExperimentalFlag.constantUpdate2018),
- enableControlFlowCollections = CompilerContext.current.options
- .isExperimentEnabled(ExperimentalFlag.controlFlowCollections),
- enableExtensionMethods = CompilerContext.current.options
+ : enableExtensionMethods = CompilerContext.current.options
.isExperimentEnabled(ExperimentalFlag.extensionMethods),
enableNonNullable = CompilerContext.current.options
.isExperimentEnabled(ExperimentalFlag.nonNullable),
- enableSpreadCollections = CompilerContext.current.options
- .isExperimentEnabled(ExperimentalFlag.spreadCollections),
enableTripleShift = CompilerContext.current.options
.isExperimentEnabled(ExperimentalFlag.tripleShift),
super(ticker);
@@ -134,6 +125,11 @@
for (String uri in backendTarget.extraRequiredLibraries) {
loader.read(Uri.parse(uri), 0, accessor: loader.coreLibrary);
}
+ if (context.compilingPlatform) {
+ for (String uri in backendTarget.extraRequiredLibrariesPlatform) {
+ loader.read(Uri.parse(uri), 0, accessor: loader.coreLibrary);
+ }
+ }
}
void addSourceInformation(
@@ -162,4 +158,37 @@
}
return rewriteSeverity(severity, message.code, fileUri);
}
+
+ String get currentSdkVersion {
+ return CompilerContext.current.options.currentSdkVersion;
+ }
+
+ int _currentSdkVersionMajor;
+ int _currentSdkVersionMinor;
+ int get currentSdkVersionMajor {
+ if (_currentSdkVersionMajor != null) return _currentSdkVersionMajor;
+ _parseCurrentSdkVersion();
+ return _currentSdkVersionMajor;
+ }
+
+ int get currentSdkVersionMinor {
+ if (_currentSdkVersionMinor != null) return _currentSdkVersionMinor;
+ _parseCurrentSdkVersion();
+ return _currentSdkVersionMinor;
+ }
+
+ void _parseCurrentSdkVersion() {
+ bool good = false;
+ if (currentSdkVersion != null) {
+ List<String> dotSeparatedParts = currentSdkVersion.split(".");
+ if (dotSeparatedParts.length >= 2) {
+ _currentSdkVersionMajor = int.tryParse(dotSeparatedParts[0]);
+ _currentSdkVersionMinor = int.tryParse(dotSeparatedParts[1]);
+ good = true;
+ }
+ }
+ if (!good) {
+ throw new StateError("Unparsable sdk version given: $currentSdkVersion");
+ }
+ }
}
diff --git a/pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart b/pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart
index c690103..d08f492 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart
@@ -2,17 +2,23 @@
// 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' show Arguments, Expression, FunctionType;
+import 'dart:core' hide MapEntry;
+
+import 'package:kernel/ast.dart';
import 'package:kernel/core_types.dart' show CoreTypes;
import '../fasta_codes.dart' show LocatedMessage, Message;
+import '../kernel/forest.dart';
+
abstract class InferenceHelper {
CoreTypes get coreTypes;
Uri get uri;
+ Forest get forest;
+
set transformSetLiterals(bool value);
Expression buildProblem(Message message, int charOffset, int length,
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index 7c8edce..f01431a 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE.md file.
+import 'package:front_end/src/fasta/kernel/kernel_shadow_ast.dart';
import 'package:kernel/ast.dart' as kernel;
import 'package:kernel/ast.dart'
@@ -16,6 +17,7 @@
DartType,
DynamicType,
Expression,
+ Extension,
Field,
FunctionExpression,
FunctionNode,
@@ -39,6 +41,7 @@
SetLiteral,
Statement,
StaticGet,
+ StaticInvocation,
SuperMethodInvocation,
SuperPropertyGet,
SuperPropertySet,
@@ -49,7 +52,8 @@
TypeParameterType,
VariableDeclaration,
VariableGet,
- VoidType;
+ VoidType,
+ setParents;
import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
@@ -67,6 +71,9 @@
InstrumentationValueForType,
InstrumentationValueForTypeArgs;
+import '../builder/extension_builder.dart';
+import '../builder/member_builder.dart';
+
import '../fasta_codes.dart'
show
LocatedMessage,
@@ -105,7 +112,7 @@
ShadowTypeInferrer,
VariableDeclarationJudgment,
getExplicitTypeArguments,
- getInferredType;
+ getExtensionTypeParameterCount;
import '../kernel/type_algorithms.dart' show hasAnyTypeVariables;
@@ -542,7 +549,7 @@
TypeInferrerImpl.private(
this.engine, this.uri, bool topLevel, this.thisType, this.library)
- : assert((topLevel && library == null) || (!topLevel && library != null)),
+ : assert(library != null),
classHierarchy = engine.classHierarchy,
instrumentation = topLevel ? null : engine.instrumentation,
typeSchemaEnvironment = engine.typeSchemaEnvironment,
@@ -650,7 +657,7 @@
PropertyGet tearOff =
new PropertyGet(new VariableGet(t), callName, callMember)
..fileOffset = fileOffset;
- actualType = getCalleeType(callMember, actualType);
+ actualType = getGetterTypeForMemberTarget(callMember, actualType);
ConditionalExpression conditional = new ConditionalExpression(
nullCheck,
new NullLiteral()..fileOffset = fileOffset,
@@ -727,6 +734,17 @@
return type is InterfaceType && type.classNode == coreTypes.nullClass;
}
+ List<DartType> _inferExtensionTypeArguments(
+ List<TypeParameter> typeParameters,
+ DartType onType,
+ DartType receiverType) {
+ List<DartType> inferredTypes =
+ new List<DartType>.filled(typeParameters.length, const UnknownType());
+ typeSchemaEnvironment.inferGenericFunctionOrType(
+ null, typeParameters, [onType], [receiverType], null, inferredTypes);
+ return inferredTypes;
+ }
+
/// Finds a member of [receiverType] called [name], and if it is found,
/// reports it through instrumentation using [fileOffset].
///
@@ -738,18 +756,20 @@
/// up targeting it if the arguments do not match (the basic principle is that
/// the Object member is used for inferring types only if noSuchMethod cannot
/// be targeted due to, e.g., an incorrect argument count).
- Object findInterfaceMember(DartType receiverType, Name name, int fileOffset,
+ ObjectAccessTarget findInterfaceMember(
+ DartType receiverType, Name name, int fileOffset,
{Template<Message Function(String, DartType)> errorTemplate,
Expression expression,
Expression receiver,
bool setter: false,
- bool instrumented: true}) {
+ bool instrumented: true,
+ bool includeExtensionMethods: false}) {
assert(receiverType != null && isKnown(receiverType));
receiverType = resolveTypeParameter(receiverType);
if (receiverType is FunctionType && name.name == 'call') {
- return 'call';
+ return const ObjectAccessTarget.callFunction();
}
Class classNode = receiverType is InterfaceType
@@ -757,15 +777,113 @@
: coreTypes.objectClass;
Member interfaceMember =
_getInterfaceMember(classNode, name, setter, fileOffset);
+ ObjectAccessTarget target = interfaceMember != null
+ ? new ObjectAccessTarget.interfaceMember(interfaceMember)
+ : const ObjectAccessTarget.unresolved();
if (instrumented &&
receiverType != const DynamicType() &&
- interfaceMember != null) {
+ target.isInstanceMember) {
instrumentation?.record(uri, fileOffset, 'target',
- new InstrumentationValueForMember(interfaceMember));
+ new InstrumentationValueForMember(target.member));
+ }
+
+ if (target.isUnresolved && includeExtensionMethods) {
+ ExtensionAccessCandidate bestSoFar;
+ List<ExtensionAccessCandidate> noneMoreSpecific = [];
+ library.scope.forEachExtension((ExtensionBuilder extensionBuilder) {
+ MemberBuilder memberBuilder =
+ extensionBuilder.lookupLocalMember(name.name, setter: setter);
+ if (memberBuilder != null && !memberBuilder.isStatic) {
+ Extension extension = extensionBuilder.extension;
+ DartType onType;
+ DartType onTypeInstantiateToBounds;
+ List<DartType> inferredTypeArguments;
+ if (extensionBuilder.extension.typeParameters.isEmpty) {
+ onTypeInstantiateToBounds =
+ onType = extensionBuilder.extension.onType;
+ inferredTypeArguments = const <DartType>[];
+ } else {
+ List<TypeParameter> typeParameters =
+ extensionBuilder.extension.typeParameters;
+ inferredTypeArguments = _inferExtensionTypeArguments(
+ extensionBuilder.extension.typeParameters,
+ extensionBuilder.extension.onType,
+ receiverType);
+ Substitution inferredSubstitution =
+ Substitution.fromPairs(typeParameters, inferredTypeArguments);
+
+ for (int index = 0; index < typeParameters.length; index++) {
+ TypeParameter typeParameter = typeParameters[index];
+ DartType typeArgument = inferredTypeArguments[index];
+ DartType bound =
+ inferredSubstitution.substituteType(typeParameter.bound);
+ if (!typeSchemaEnvironment.isSubtypeOf(typeArgument, bound)) {
+ return;
+ }
+ }
+ onType = inferredSubstitution
+ .substituteType(extensionBuilder.extension.onType);
+ List<DartType> instantiateToBoundTypeArguments =
+ calculateBounds(typeParameters, coreTypes.objectClass);
+ Substitution instantiateToBoundsSubstitution =
+ Substitution.fromPairs(
+ typeParameters, instantiateToBoundTypeArguments);
+ onTypeInstantiateToBounds = instantiateToBoundsSubstitution
+ .substituteType(extensionBuilder.extension.onType);
+ }
+
+ if (typeSchemaEnvironment.isSubtypeOf(receiverType, onType)) {
+ ExtensionAccessCandidate candidate = new ExtensionAccessCandidate(
+ extension,
+ onType,
+ onTypeInstantiateToBounds,
+ new ObjectAccessTarget.extensionMember(
+ memberBuilder.procedure,
+ memberBuilder.extensionTearOff,
+ memberBuilder.kind,
+ inferredTypeArguments));
+ if (noneMoreSpecific.isNotEmpty) {
+ bool isMostSpecific = true;
+ for (ExtensionAccessCandidate other in noneMoreSpecific) {
+ bool isMoreSpecific =
+ candidate.isMoreSpecificThan(typeSchemaEnvironment, other);
+ if (isMoreSpecific != true) {
+ isMostSpecific = false;
+ break;
+ }
+ }
+ if (isMostSpecific) {
+ bestSoFar = candidate;
+ noneMoreSpecific.clear();
+ } else {
+ noneMoreSpecific.add(candidate);
+ }
+ } else if (bestSoFar == null) {
+ bestSoFar = candidate;
+ } else {
+ bool isMoreSpecific = candidate.isMoreSpecificThan(
+ typeSchemaEnvironment, bestSoFar);
+ if (isMoreSpecific == true) {
+ bestSoFar = candidate;
+ } else if (isMoreSpecific == null) {
+ noneMoreSpecific.add(bestSoFar);
+ noneMoreSpecific.add(candidate);
+ bestSoFar = null;
+ }
+ }
+ }
+ }
+ });
+ if (bestSoFar != null) {
+ target = bestSoFar.target;
+ } else {
+ // TODO(johnniwinther): Report a better error message when more than
+ // one potential targets were found.
+ }
}
if (!isTopLevel &&
- interfaceMember == null &&
+ target.isUnresolved &&
receiverType is! DynamicType &&
receiverType is! InvalidType &&
!(receiverType == coreTypes.functionClass.rawType &&
@@ -783,55 +901,58 @@
fileOffset,
length)));
}
- return interfaceMember;
+ return target;
}
/// Finds a member of [receiverType] called [name] and records it in
/// [methodInvocation].
- Object findMethodInvocationMember(
+ ObjectAccessTarget findMethodInvocationMember(
DartType receiverType, InvocationExpression methodInvocation,
{bool instrumented: true}) {
// TODO(paulberry): could we add getters to InvocationExpression to make
// these is-checks unnecessary?
if (methodInvocation is MethodInvocation) {
- Object interfaceMember = findInterfaceMember(
+ ObjectAccessTarget interfaceTarget = findInterfaceMember(
receiverType, methodInvocation.name, methodInvocation.fileOffset,
errorTemplate: templateUndefinedMethod,
expression: methodInvocation,
receiver: methodInvocation.receiver,
- instrumented: instrumented);
- if (receiverType == const DynamicType() && interfaceMember is Procedure) {
- Arguments arguments = methodInvocation.arguments;
- FunctionNode signature = interfaceMember.function;
- if (arguments.positional.length < signature.requiredParameterCount ||
- arguments.positional.length >
- signature.positionalParameters.length) {
- return null;
- }
- for (kernel.NamedExpression argument in arguments.named) {
- if (!signature.namedParameters
- .any((declaration) => declaration.name == argument.name)) {
- return null;
+ instrumented: instrumented,
+ includeExtensionMethods: true);
+ if (interfaceTarget.isInstanceMember) {
+ Member interfaceMember = interfaceTarget.member;
+ if (receiverType == const DynamicType() &&
+ interfaceMember is Procedure) {
+ Arguments arguments = methodInvocation.arguments;
+ FunctionNode signature = interfaceMember.function;
+ if (arguments.positional.length < signature.requiredParameterCount ||
+ arguments.positional.length >
+ signature.positionalParameters.length) {
+ return const ObjectAccessTarget.unresolved();
+ }
+ for (kernel.NamedExpression argument in arguments.named) {
+ if (!signature.namedParameters
+ .any((declaration) => declaration.name == argument.name)) {
+ return const ObjectAccessTarget.unresolved();
+ }
+ }
+ if (instrumented && instrumentation != null) {
+ instrumentation.record(uri, methodInvocation.fileOffset, 'target',
+ new InstrumentationValueForMember(interfaceMember));
}
}
- if (instrumented && instrumentation != null) {
- instrumentation.record(uri, methodInvocation.fileOffset, 'target',
- new InstrumentationValueForMember(interfaceMember));
- }
- methodInvocation.interfaceTarget = interfaceMember;
- } else if (interfaceMember is Member) {
methodInvocation.interfaceTarget = interfaceMember;
}
- return interfaceMember;
+ return interfaceTarget;
} else if (methodInvocation is SuperMethodInvocation) {
assert(receiverType != const DynamicType());
- Object interfaceMember = findInterfaceMember(
+ ObjectAccessTarget interfaceTarget = findInterfaceMember(
receiverType, methodInvocation.name, methodInvocation.fileOffset,
instrumented: instrumented);
- if (interfaceMember is Member) {
- methodInvocation.interfaceTarget = interfaceMember;
+ if (interfaceTarget.isInstanceMember) {
+ methodInvocation.interfaceTarget = interfaceTarget.member;
}
- return interfaceMember;
+ return interfaceTarget;
} else {
throw unhandled("${methodInvocation.runtimeType}",
"findMethodInvocationMember", methodInvocation.fileOffset, uri);
@@ -840,34 +961,35 @@
/// Finds a member of [receiverType] called [name], and if it is found,
/// reports it through instrumentation and records it in [propertyGet].
- Object findPropertyGetMember(DartType receiverType, Expression propertyGet,
+ ObjectAccessTarget findPropertyGetMember(
+ DartType receiverType, Expression propertyGet,
{bool instrumented: true}) {
// TODO(paulberry): could we add a common base class to PropertyGet and
// SuperPropertyGet to make these is-checks unnecessary?
if (propertyGet is PropertyGet) {
- Object interfaceMember = findInterfaceMember(
+ ObjectAccessTarget readTarget = findInterfaceMember(
receiverType, propertyGet.name, propertyGet.fileOffset,
errorTemplate: templateUndefinedGetter,
expression: propertyGet,
receiver: propertyGet.receiver,
instrumented: instrumented);
- if (interfaceMember is Member) {
+ if (readTarget.isInstanceMember) {
if (instrumented &&
instrumentation != null &&
receiverType == const DynamicType()) {
instrumentation.record(uri, propertyGet.fileOffset, 'target',
- new InstrumentationValueForMember(interfaceMember));
+ new InstrumentationValueForMember(readTarget.member));
}
- propertyGet.interfaceTarget = interfaceMember;
+ propertyGet.interfaceTarget = readTarget.member;
}
- return interfaceMember;
+ return readTarget;
} else if (propertyGet is SuperPropertyGet) {
assert(receiverType != const DynamicType());
- Object interfaceMember = findInterfaceMember(
+ ObjectAccessTarget interfaceMember = findInterfaceMember(
receiverType, propertyGet.name, propertyGet.fileOffset,
instrumented: instrumented);
- if (interfaceMember is Member) {
- propertyGet.interfaceTarget = interfaceMember;
+ if (interfaceMember.isInstanceMember) {
+ propertyGet.interfaceTarget = interfaceMember.member;
}
return interfaceMember;
} else {
@@ -878,33 +1000,35 @@
/// Finds a member of [receiverType] called [name], and if it is found,
/// reports it through instrumentation and records it in [propertySet].
- Object findPropertySetMember(DartType receiverType, Expression propertySet,
+ ObjectAccessTarget findPropertySetMember(
+ DartType receiverType, Expression propertySet,
{bool instrumented: true}) {
if (propertySet is PropertySet) {
- Object interfaceMember = findInterfaceMember(
+ ObjectAccessTarget writeTarget = findInterfaceMember(
receiverType, propertySet.name, propertySet.fileOffset,
errorTemplate: templateUndefinedSetter,
expression: propertySet,
receiver: propertySet.receiver,
setter: true,
- instrumented: instrumented);
- if (interfaceMember is Member) {
+ instrumented: instrumented,
+ includeExtensionMethods: true);
+ if (writeTarget.isInstanceMember) {
if (instrumented &&
instrumentation != null &&
receiverType == const DynamicType()) {
instrumentation.record(uri, propertySet.fileOffset, 'target',
- new InstrumentationValueForMember(interfaceMember));
+ new InstrumentationValueForMember(writeTarget.member));
}
- propertySet.interfaceTarget = interfaceMember;
+ propertySet.interfaceTarget = writeTarget.member;
}
- return interfaceMember;
+ return writeTarget;
} else if (propertySet is SuperPropertySet) {
assert(receiverType != const DynamicType());
- Object interfaceMember = findInterfaceMember(
+ ObjectAccessTarget interfaceMember = findInterfaceMember(
receiverType, propertySet.name, propertySet.fileOffset,
setter: true, instrumented: instrumented);
- if (interfaceMember is Member) {
- propertySet.interfaceTarget = interfaceMember;
+ if (interfaceMember.isInstanceMember) {
+ propertySet.interfaceTarget = interfaceMember.member;
}
return interfaceMember;
} else {
@@ -913,56 +1037,259 @@
}
}
- FunctionType getCalleeFunctionType(DartType calleeType, bool followCall) {
+ /// Returns the type of [target] when accessed as a getter on [receiverType].
+ ///
+ /// For instance
+ ///
+ /// class Class<T> {
+ /// T method() {}
+ /// T getter => null;
+ /// }
+ ///
+ /// Class<int> c = ...
+ /// c.method; // The getter type is `int Function()`.
+ /// c.getter; // The getter type is `int`.
+ ///
+ DartType getGetterType(ObjectAccessTarget target, DartType receiverType) {
+ switch (target.kind) {
+ case ObjectAccessTargetKind.callFunction:
+ return receiverType;
+ case ObjectAccessTargetKind.unresolved:
+ return const DynamicType();
+ case ObjectAccessTargetKind.instanceMember:
+ return getGetterTypeForMemberTarget(target.member, receiverType);
+ case ObjectAccessTargetKind.extensionMember:
+ switch (target.extensionMethodKind) {
+ case ProcedureKind.Method:
+ case ProcedureKind.Operator:
+ FunctionType functionType = target.member.function.functionType;
+ List<TypeParameter> extensionTypeParameters = functionType
+ .typeParameters
+ .take(target.inferredExtensionTypeArguments.length)
+ .toList();
+ Substitution substitution = Substitution.fromPairs(
+ extensionTypeParameters, target.inferredExtensionTypeArguments);
+ return substitution.substituteType(new FunctionType(
+ functionType.positionalParameters.skip(1).toList(),
+ functionType.returnType,
+ namedParameters: functionType.namedParameters,
+ typeParameters: functionType.typeParameters
+ .skip(target.inferredExtensionTypeArguments.length)
+ .toList(),
+ requiredParameterCount:
+ functionType.requiredParameterCount - 1));
+ case ProcedureKind.Getter:
+ FunctionType functionType = target.member.function.functionType;
+ List<TypeParameter> extensionTypeParameters = functionType
+ .typeParameters
+ .take(target.inferredExtensionTypeArguments.length)
+ .toList();
+ Substitution substitution = Substitution.fromPairs(
+ extensionTypeParameters, target.inferredExtensionTypeArguments);
+ return substitution.substituteType(functionType.returnType);
+ case ProcedureKind.Setter:
+ case ProcedureKind.Factory:
+ break;
+ }
+ }
+ throw unhandled('$target', 'getGetterType', null, null);
+ }
+
+ /// Returns the getter type of [member] on a receiver of type [receiverType].
+ ///
+ /// For instance
+ ///
+ /// class Class<T> {
+ /// T method() {}
+ /// T getter => null;
+ /// }
+ ///
+ /// Class<int> c = ...
+ /// c.method; // The getter type is `int Function()`.
+ /// c.getter; // The getter type is `int`.
+ ///
+ DartType getGetterTypeForMemberTarget(
+ Member interfaceMember, DartType receiverType) {
+ Class memberClass = interfaceMember.enclosingClass;
+ assert(
+ interfaceMember is kernel.Field || interfaceMember is kernel.Procedure,
+ "Unexpected interface member $interfaceMember.");
+ DartType calleeType = interfaceMember.getterType;
+ if (memberClass.typeParameters.isNotEmpty) {
+ receiverType = resolveTypeParameter(receiverType);
+ if (receiverType is InterfaceType) {
+ InterfaceType castedType =
+ classHierarchy.getTypeAsInstanceOf(receiverType, memberClass);
+ calleeType = Substitution.fromInterfaceType(castedType)
+ .substituteType(calleeType);
+ }
+ }
+ return calleeType;
+ }
+
+ /// Returns the type of [target] when accessed as an invocation on
+ /// [receiverType].
+ ///
+ /// If the target is known not to be invokable [unknownFunction] is returned.
+ ///
+ /// For instance
+ ///
+ /// class Class<T> {
+ /// T method() {}
+ /// T Function() getter1 => null;
+ /// T getter2 => null;
+ /// }
+ ///
+ /// Class<int> c = ...
+ /// c.method; // The getter type is `int Function()`.
+ /// c.getter1; // The getter type is `int Function()`.
+ /// c.getter2; // The getter type is [unknownFunction].
+ ///
+ FunctionType getFunctionType(
+ ObjectAccessTarget target, DartType receiverType, bool followCall) {
+ switch (target.kind) {
+ case ObjectAccessTargetKind.callFunction:
+ return _getFunctionType(receiverType, followCall);
+ case ObjectAccessTargetKind.unresolved:
+ return unknownFunction;
+ case ObjectAccessTargetKind.instanceMember:
+ return _getFunctionType(
+ getGetterTypeForMemberTarget(target.member, receiverType),
+ followCall);
+ case ObjectAccessTargetKind.extensionMember:
+ switch (target.extensionMethodKind) {
+ case ProcedureKind.Method:
+ case ProcedureKind.Operator:
+ return target.member.function.functionType;
+ case ProcedureKind.Getter:
+ // TODO(johnniwinther): Handle implicit .call on extension getter.
+ return _getFunctionType(target.member.function.returnType, false);
+ case ProcedureKind.Setter:
+ case ProcedureKind.Factory:
+ break;
+ }
+ }
+ throw unhandled('$target', 'getFunctionType', null, null);
+ }
+
+ /// Returns the type of the 'key' parameter in an []= implementation.
+ ///
+ /// For instance
+ ///
+ /// class Class<K, V> {
+ /// void operator []=(K key, V value) {}
+ /// }
+ ///
+ /// extension Extension<K, V> on Class<K, V> {
+ /// void operator []=(K key, V value) {}
+ /// }
+ ///
+ /// new Class<int, String>()[0] = 'foo'; // The key type is `int`.
+ /// Extension<int, String>(null)[0] = 'foo'; // The key type is `int`.
+ ///
+ DartType getIndexSetKeyType(
+ ObjectAccessTarget target, DartType receiverType) {
+ switch (target.kind) {
+ case ObjectAccessTargetKind.instanceMember:
+ FunctionType functionType = _getFunctionType(
+ getGetterTypeForMemberTarget(target.member, receiverType), false);
+ if (functionType.positionalParameters.length >= 1) {
+ return functionType.positionalParameters[0];
+ }
+ break;
+ case ObjectAccessTargetKind.extensionMember:
+ switch (target.extensionMethodKind) {
+ case ProcedureKind.Operator:
+ FunctionType functionType = target.member.function.functionType;
+ if (functionType.positionalParameters.length >= 2) {
+ DartType indexType = functionType.positionalParameters[1];
+ if (functionType.typeParameters.isNotEmpty) {
+ Substitution substitution = Substitution.fromPairs(
+ functionType.typeParameters,
+ target.inferredExtensionTypeArguments);
+ return substitution.substituteType(indexType);
+ }
+ return indexType;
+ }
+ break;
+ default:
+ throw unhandled('$target', 'getFunctionType', null, null);
+ }
+ break;
+ case ObjectAccessTargetKind.callFunction:
+ case ObjectAccessTargetKind.unresolved:
+ break;
+ }
+ return const UnknownType();
+ }
+
+ /// Returns the type of the 'value' parameter in an []= implementation.
+ ///
+ /// For instance
+ ///
+ /// class Class<K, V> {
+ /// void operator []=(K key, V value) {}
+ /// }
+ ///
+ /// extension Extension<K, V> on Class<K, V> {
+ /// void operator []=(K key, V value) {}
+ /// }
+ ///
+ /// new Class<int, String>()[0] = 'foo'; // The value type is `String`.
+ /// Extension<int, String>(null)[0] = 'foo'; // The value type is `String`.
+ ///
+ DartType getIndexSetValueType(
+ ObjectAccessTarget target, DartType receiverType) {
+ switch (target.kind) {
+ case ObjectAccessTargetKind.instanceMember:
+ FunctionType functionType = _getFunctionType(
+ getGetterTypeForMemberTarget(target.member, receiverType), false);
+ if (functionType.positionalParameters.length >= 2) {
+ return functionType.positionalParameters[1];
+ }
+ break;
+ case ObjectAccessTargetKind.extensionMember:
+ switch (target.extensionMethodKind) {
+ case ProcedureKind.Operator:
+ FunctionType functionType = target.member.function.functionType;
+ if (functionType.positionalParameters.length >= 3) {
+ DartType indexType = functionType.positionalParameters[2];
+ if (functionType.typeParameters.isNotEmpty) {
+ Substitution substitution = Substitution.fromPairs(
+ functionType.typeParameters,
+ target.inferredExtensionTypeArguments);
+ return substitution.substituteType(indexType);
+ }
+ return indexType;
+ }
+ break;
+ default:
+ throw unhandled('$target', 'getFunctionType', null, null);
+ }
+ break;
+ case ObjectAccessTargetKind.callFunction:
+ case ObjectAccessTargetKind.unresolved:
+ break;
+ }
+ return const UnknownType();
+ }
+
+ FunctionType _getFunctionType(DartType calleeType, bool followCall) {
if (calleeType is FunctionType) {
return calleeType;
} else if (followCall && calleeType is InterfaceType) {
Member member =
_getInterfaceMember(calleeType.classNode, callName, false, -1);
- DartType callType = getCalleeType(member, calleeType);
- if (callType is FunctionType) {
- return callType;
+ if (member != null) {
+ DartType callType = getGetterTypeForMemberTarget(member, calleeType);
+ if (callType is FunctionType) {
+ return callType;
+ }
}
}
return unknownFunction;
}
- DartType getCalleeType(Object interfaceMember, DartType receiverType) {
- if (identical(interfaceMember, 'call')) {
- return receiverType;
- } else if (interfaceMember == null) {
- return const DynamicType();
- } else if (interfaceMember is Member) {
- Class memberClass = interfaceMember.enclosingClass;
- DartType calleeType;
- if (interfaceMember is Procedure) {
- if (interfaceMember.kind == ProcedureKind.Getter) {
- calleeType = interfaceMember.function.returnType;
- } else {
- calleeType = interfaceMember.function.functionType;
- }
- } else if (interfaceMember is Field) {
- calleeType = interfaceMember.type;
- } else {
- throw unhandled(interfaceMember.runtimeType.toString(), 'getCalleeType',
- null, null);
- }
- if (memberClass.typeParameters.isNotEmpty) {
- receiverType = resolveTypeParameter(receiverType);
- if (receiverType is InterfaceType) {
- InterfaceType castedType =
- classHierarchy.getTypeAsInstanceOf(receiverType, memberClass);
- calleeType = Substitution.fromInterfaceType(castedType)
- .substituteType(calleeType);
- }
- }
- return calleeType;
- } else {
- throw unhandled(
- interfaceMember.runtimeType.toString(), 'getCalleeType', null, null);
- }
- }
-
DartType getDerivedTypeArgumentOf(DartType type, Class class_) {
if (type is InterfaceType) {
InterfaceType typeAsInstanceOfClass =
@@ -987,41 +1314,60 @@
return member;
}
- DartType getSetterType(Object interfaceMember, DartType receiverType) {
- if (interfaceMember is FunctionType) {
- return interfaceMember;
- } else if (interfaceMember == null) {
- return const DynamicType();
- } else if (interfaceMember is Member) {
- Class memberClass = interfaceMember.enclosingClass;
- DartType setterType;
- if (interfaceMember is Procedure) {
- assert(interfaceMember.kind == ProcedureKind.Setter);
- List<VariableDeclaration> setterParameters =
- interfaceMember.function.positionalParameters;
- setterType = setterParameters.length > 0
- ? setterParameters[0].type
- : const DynamicType();
- } else if (interfaceMember is Field) {
- setterType = interfaceMember.type;
- } else {
- throw unhandled(interfaceMember.runtimeType.toString(), 'getSetterType',
- null, null);
- }
- if (memberClass.typeParameters.isNotEmpty) {
- receiverType = resolveTypeParameter(receiverType);
- if (receiverType is InterfaceType) {
- InterfaceType castedType =
- classHierarchy.getTypeAsInstanceOf(receiverType, memberClass);
- setterType = Substitution.fromInterfaceType(castedType)
- .substituteType(setterType);
+ DartType getSetterType(ObjectAccessTarget target, DartType receiverType) {
+ switch (target.kind) {
+ case ObjectAccessTargetKind.unresolved:
+ return const DynamicType();
+ case ObjectAccessTargetKind.instanceMember:
+ Member interfaceMember = target.member;
+ Class memberClass = interfaceMember.enclosingClass;
+ DartType setterType;
+ if (interfaceMember is Procedure) {
+ assert(interfaceMember.kind == ProcedureKind.Setter);
+ List<VariableDeclaration> setterParameters =
+ interfaceMember.function.positionalParameters;
+ setterType = setterParameters.length > 0
+ ? setterParameters[0].type
+ : const DynamicType();
+ } else if (interfaceMember is Field) {
+ setterType = interfaceMember.type;
+ } else {
+ throw unhandled(interfaceMember.runtimeType.toString(),
+ 'getSetterType', null, null);
}
- }
- return setterType;
- } else {
- throw unhandled(
- interfaceMember.runtimeType.toString(), 'getSetterType', null, null);
+ if (memberClass.typeParameters.isNotEmpty) {
+ receiverType = resolveTypeParameter(receiverType);
+ if (receiverType is InterfaceType) {
+ InterfaceType castedType =
+ classHierarchy.getTypeAsInstanceOf(receiverType, memberClass);
+ setterType = Substitution.fromInterfaceType(castedType)
+ .substituteType(setterType);
+ }
+ }
+ return setterType;
+ case ObjectAccessTargetKind.extensionMember:
+ switch (target.extensionMethodKind) {
+ case ProcedureKind.Setter:
+ FunctionType functionType = target.member.function.functionType;
+ List<TypeParameter> extensionTypeParameters = functionType
+ .typeParameters
+ .take(target.inferredExtensionTypeArguments.length)
+ .toList();
+ Substitution substitution = Substitution.fromPairs(
+ extensionTypeParameters, target.inferredExtensionTypeArguments);
+ return substitution
+ .substituteType(functionType.positionalParameters[1]);
+ case ProcedureKind.Method:
+ case ProcedureKind.Getter:
+ case ProcedureKind.Factory:
+ case ProcedureKind.Operator:
+ break;
+ }
+ // TODO(johnniwinther): Compute the right setter type.
+ return const DynamicType();
+ case ObjectAccessTargetKind.callFunction:
}
+ throw unhandled(target.runtimeType.toString(), 'getSetterType', null, null);
}
DartType getTypeArgumentOf(DartType type, Class class_) {
@@ -1092,15 +1438,16 @@
/// expression.
Expression handlePropertyGetContravariance(
Expression receiver,
- Object interfaceMember,
+ ObjectAccessTarget readTarget,
PropertyGet desugaredGet,
Expression expression,
DartType inferredType,
int fileOffset) {
bool checkReturn = false;
if (receiver != null &&
- interfaceMember != null &&
+ readTarget.isInstanceMember &&
receiver is! ThisExpression) {
+ Member interfaceMember = readTarget.member;
if (interfaceMember is Procedure) {
checkReturn = returnedTypeParametersOccurNonCovariantly(
interfaceMember.enclosingClass,
@@ -1144,12 +1491,13 @@
///
/// [typeContext] is the expected type of the expression, based on surrounding
/// code. [typeNeeded] indicates whether it is necessary to compute the
- /// actual type of the expression. If [typeNeeded] is `true`, the actual type
- /// of the expression is returned; otherwise `null` is returned.
+ /// actual type of the expression. If [typeNeeded] is `true`,
+ /// [ExpressionInferenceResult.inferredType] is the actual type of the
+ /// expression; otherwise `null`.
///
/// Derived classes should override this method with logic that dispatches on
/// the expression type and calls the appropriate specialized "infer" method.
- DartType inferExpression(
+ ExpressionInferenceResult inferExpression(
kernel.Expression expression, DartType typeContext, bool typeNeeded,
{bool isVoidAllowed});
@@ -1162,9 +1510,10 @@
assert(closureContext == null);
assert(!isTopLevel);
this.helper = helper;
- DartType actualType =
+ ExpressionInferenceResult result =
inferExpression(initializer, context, true, isVoidAllowed: true);
- ensureAssignable(context, actualType, initializer, initializer.fileOffset,
+ ensureAssignable(
+ context, result.inferredType, initializer, initializer.fileOffset,
isVoidAllowed: context is VoidType);
this.helper = null;
}
@@ -1180,14 +1529,105 @@
this.helper = null;
}
- /// Performs the type inference steps that are shared by all kinds of
- /// invocations (constructors, instance methods, and static methods).
- ExpressionInferenceResult inferInvocation(DartType typeContext, int offset,
+ DartType inferInvocation(DartType typeContext, int offset,
FunctionType calleeType, DartType returnType, Arguments arguments,
{bool isOverloadedArithmeticOperator: false,
DartType receiverType,
bool skipTypeArgumentInference: false,
- bool isConst: false}) {
+ bool isConst: false,
+ bool isImplicitExtensionMember: false}) {
+ int extensionTypeParameterCount = getExtensionTypeParameterCount(arguments);
+ if (extensionTypeParameterCount != 0) {
+ return _inferGenericExtensionMethodInvocation(extensionTypeParameterCount,
+ typeContext, offset, calleeType, returnType, arguments,
+ isOverloadedArithmeticOperator: isOverloadedArithmeticOperator,
+ receiverType: receiverType,
+ skipTypeArgumentInference: skipTypeArgumentInference,
+ isConst: isConst,
+ isImplicitExtensionMember: isImplicitExtensionMember);
+ }
+ return _inferInvocation(
+ typeContext, offset, calleeType, returnType, arguments,
+ isOverloadedArithmeticOperator: isOverloadedArithmeticOperator,
+ receiverType: receiverType,
+ skipTypeArgumentInference: skipTypeArgumentInference,
+ isConst: isConst,
+ isImplicitExtensionMember: isImplicitExtensionMember);
+ }
+
+ DartType _inferGenericExtensionMethodInvocation(
+ int extensionTypeParameterCount,
+ DartType typeContext,
+ int offset,
+ FunctionType calleeType,
+ DartType returnType,
+ Arguments arguments,
+ {bool isOverloadedArithmeticOperator: false,
+ DartType receiverType,
+ bool skipTypeArgumentInference: false,
+ bool isConst: false,
+ bool isImplicitExtensionMember: false}) {
+ FunctionType extensionFunctionType = new FunctionType(
+ [calleeType.positionalParameters.first], const DynamicType(),
+ requiredParameterCount: 1,
+ typeParameters: calleeType.typeParameters
+ .take(extensionTypeParameterCount)
+ .toList());
+ Arguments extensionArguments = helper.forest.createArguments(
+ arguments.fileOffset, [arguments.positional.first],
+ types: getExplicitExtensionTypeArguments(arguments));
+ _inferInvocation(const UnknownType(), offset, extensionFunctionType,
+ extensionFunctionType.returnType, extensionArguments,
+ skipTypeArgumentInference: skipTypeArgumentInference,
+ receiverType: receiverType,
+ isImplicitExtensionMember: isImplicitExtensionMember);
+ Substitution extensionSubstitution = Substitution.fromPairs(
+ extensionFunctionType.typeParameters, extensionArguments.types);
+
+ List<TypeParameter> targetTypeParameters = const <TypeParameter>[];
+ if (calleeType.typeParameters.length > extensionTypeParameterCount) {
+ targetTypeParameters =
+ calleeType.typeParameters.skip(extensionTypeParameterCount).toList();
+ }
+ FunctionType targetFunctionType = new FunctionType(
+ calleeType.positionalParameters.skip(1).toList(), calleeType.returnType,
+ requiredParameterCount: calleeType.requiredParameterCount - 1,
+ namedParameters: calleeType.namedParameters,
+ typeParameters: targetTypeParameters);
+ targetFunctionType =
+ extensionSubstitution.substituteType(targetFunctionType);
+ DartType targetReturnType =
+ extensionSubstitution.substituteType(returnType);
+ Arguments targetArguments = helper.forest.createArguments(
+ arguments.fileOffset, arguments.positional.skip(1).toList(),
+ named: arguments.named, types: getExplicitTypeArguments(arguments));
+ DartType inferredType = _inferInvocation(typeContext, offset,
+ targetFunctionType, targetReturnType, targetArguments,
+ isOverloadedArithmeticOperator: isOverloadedArithmeticOperator,
+ skipTypeArgumentInference: skipTypeArgumentInference,
+ isConst: isConst);
+ arguments.positional.clear();
+ arguments.positional.addAll(extensionArguments.positional);
+ arguments.positional.addAll(targetArguments.positional);
+ setParents(arguments.positional, arguments);
+ // The `targetArguments.named` is the same list as `arguments.named` so
+ // we just need to ensure that parent relations are realigned.
+ setParents(arguments.named, arguments);
+ arguments.types.clear();
+ arguments.types.addAll(extensionArguments.types);
+ arguments.types.addAll(targetArguments.types);
+ return inferredType;
+ }
+
+ /// Performs the type inference steps that are shared by all kinds of
+ /// invocations (constructors, instance methods, and static methods).
+ DartType _inferInvocation(DartType typeContext, int offset,
+ FunctionType calleeType, DartType returnType, Arguments arguments,
+ {bool isOverloadedArithmeticOperator: false,
+ DartType receiverType,
+ bool skipTypeArgumentInference: false,
+ bool isConst: false,
+ bool isImplicitExtensionMember: false}) {
lastInferredSubstitution = null;
lastCalleeType = null;
List<TypeParameter> calleeTypeParameters = calleeType.typeParameters;
@@ -1250,19 +1690,29 @@
DartType inferredFormalType = substitution != null
? substitution.substituteType(formalType)
: formalType;
- DartType expressionType = inferExpression(
- expression,
- inferredFormalType,
- inferenceNeeded ||
- isOverloadedArithmeticOperator ||
- typeChecksNeeded);
+ DartType inferredType;
+ if (isImplicitExtensionMember && i == 1) {
+ assert(
+ receiverType != null,
+ "No receiver type provided for implicit extension member "
+ "invocation.");
+ inferredType = receiverType;
+ } else {
+ ExpressionInferenceResult result = inferExpression(
+ expression,
+ inferredFormalType,
+ inferenceNeeded ||
+ isOverloadedArithmeticOperator ||
+ typeChecksNeeded);
+ inferredType = result.inferredType;
+ }
if (inferenceNeeded || typeChecksNeeded) {
formalTypes.add(formalType);
- actualTypes.add(expressionType);
+ actualTypes.add(inferredType);
}
if (isOverloadedArithmeticOperator) {
returnType = typeSchemaEnvironment.getTypeOfOverloadedArithmetic(
- receiverType, expressionType);
+ receiverType, inferredType);
}
});
@@ -1356,11 +1806,11 @@
inferredType = substitution == null
? returnType
: substitution.substituteType(returnType);
- return new ExpressionInferenceResult(null, inferredType);
+ return inferredType;
}
- ExpressionInferenceResult inferLocalFunction(FunctionNode function,
- DartType typeContext, int fileOffset, DartType returnContext) {
+ DartType inferLocalFunction(FunctionNode function, DartType typeContext,
+ int fileOffset, DartType returnContext) {
bool hasImplicitReturnType = false;
if (returnContext == null) {
hasImplicitReturnType = true;
@@ -1493,7 +1943,7 @@
function.returnType = inferredReturnType;
}
this.closureContext = oldClosureContext;
- return new ExpressionInferenceResult(null, function.functionType);
+ return function.functionType;
}
@override
@@ -1523,6 +1973,29 @@
}
}
+ StaticInvocation transformExtensionMethodInvocation(ObjectAccessTarget target,
+ Expression expression, Expression receiver, Arguments arguments) {
+ assert(target.isExtensionMember);
+ Procedure procedure = target.member;
+ Expression replacement;
+ expression.parent.replaceChild(
+ expression,
+ replacement = helper.forest.createStaticInvocation(
+ expression.fileOffset,
+ target.member,
+ arguments = helper.forest.createArgumentsForExtensionMethod(
+ arguments.fileOffset,
+ target.inferredExtensionTypeArguments.length,
+ procedure.function.typeParameters.length -
+ target.inferredExtensionTypeArguments.length,
+ receiver,
+ extensionTypeArguments: target.inferredExtensionTypeArguments,
+ positionalArguments: arguments.positional,
+ namedArguments: arguments.named,
+ typeArguments: arguments.types)));
+ return replacement;
+ }
+
/// Performs the core type inference algorithm for method invocations (this
/// handles both null-aware and non-null-aware method invocations).
ExpressionInferenceResult inferMethodInvocation(
@@ -1533,28 +2006,39 @@
DartType typeContext,
{VariableDeclaration receiverVariable,
MethodInvocation desugaredInvocation,
- Object interfaceMember,
+ ObjectAccessTarget target,
Name methodName,
Arguments arguments}) {
+ assert(desugaredInvocation == null || target == null);
+ assert(desugaredInvocation != null || target != null);
// First infer the receiver so we can look up the method that was invoked.
- DartType receiverType = receiver == null
- ? thisType
- : inferExpression(receiver, const UnknownType(), true);
+ DartType receiverType;
+ if (receiver == null) {
+ receiverType = thisType;
+ } else {
+ ExpressionInferenceResult result =
+ inferExpression(receiver, const UnknownType(), true);
+ receiverType = result.inferredType;
+ }
receiverVariable?.type = receiverType;
if (desugaredInvocation != null) {
- interfaceMember =
- findMethodInvocationMember(receiverType, desugaredInvocation);
+ target = findMethodInvocationMember(receiverType, desugaredInvocation);
methodName = desugaredInvocation.name;
arguments = desugaredInvocation.arguments;
}
- bool isOverloadedArithmeticOperator = interfaceMember is Procedure &&
+ assert(
+ target != null,
+ "No target for ${expression} with desugared "
+ "invocation ${desugaredInvocation}.");
+ bool isOverloadedArithmeticOperator = target.isInstanceMember &&
+ target.member is Procedure &&
typeSchemaEnvironment.isOverloadedArithmeticOperatorAndType(
- interfaceMember, receiverType);
- DartType calleeType = getCalleeType(interfaceMember, receiverType);
+ target.member, receiverType);
+ DartType calleeType = getGetterType(target, receiverType);
FunctionType functionType =
- getCalleeFunctionType(calleeType, !isImplicitCall);
+ getFunctionType(target, receiverType, !isImplicitCall);
- if (interfaceMember != null &&
+ if (!target.isUnresolved &&
calleeType is! DynamicType &&
calleeType != coreTypes.functionClass.rawType &&
identical(functionType, unknownFunction)) {
@@ -1562,32 +2046,34 @@
kernel.Expression error = helper.wrapInProblem(expression,
templateInvokeNonFunction.withArguments(methodName.name), noLength);
parent?.replaceChild(expression, error);
- return new ExpressionInferenceResult(null, const DynamicType());
+ return const ExpressionInferenceResult(const DynamicType());
}
MethodContravarianceCheckKind checkKind = preCheckInvocationContravariance(
receiver,
receiverType,
- interfaceMember,
+ target,
desugaredInvocation,
arguments,
expression);
- ExpressionInferenceResult inferenceResult = inferInvocation(typeContext,
- fileOffset, functionType, functionType.returnType, arguments,
+ StaticInvocation replacement;
+ if (target.isExtensionMember) {
+ replacement = transformExtensionMethodInvocation(
+ target, expression, receiver, arguments);
+ arguments = replacement.arguments;
+ }
+ DartType inferredType = inferInvocation(typeContext, fileOffset,
+ functionType, functionType.returnType, arguments,
isOverloadedArithmeticOperator: isOverloadedArithmeticOperator,
- receiverType: receiverType);
- DartType inferredType = inferenceResult.type;
+ receiverType: receiverType,
+ isImplicitExtensionMember: target.isExtensionMember);
if (methodName.name == '==') {
inferredType = coreTypes.boolClass.rawType;
}
handleInvocationContravariance(checkKind, desugaredInvocation, arguments,
expression, inferredType, functionType, fileOffset);
- if (!identical(interfaceMember, 'call')) {
- if (isImplicitCall &&
- interfaceMember != null &&
- !(interfaceMember is Procedure &&
- interfaceMember.kind == ProcedureKind.Method) &&
- receiverType is! DynamicType &&
- receiverType != typeSchemaEnvironment.rawFunctionType) {
+ if (isImplicitCall && target.isInstanceMember) {
+ Member member = target.member;
+ if (!(member is Procedure && member.kind == ProcedureKind.Method)) {
TreeNode parent = expression.parent;
Expression errorNode = helper.wrapInProblem(
expression,
@@ -1598,8 +2084,11 @@
}
// If [arguments] were inferred, check them.
- // TODO(dmitryas): Figure out why [library] is sometimes null.
- if (library != null) {
+ // TODO(dmitryas): Figure out why [library] is sometimes null? Answer:
+ // because top level inference never got a library. This has changed so
+ // we always have a library. Should we still skip this for top level
+ // inference?
+ if (!isTopLevel) {
// [actualReceiverType], [interfaceTarget], and [actualMethodName] below
// are for a workaround for the cases like the following:
//
@@ -1615,7 +2104,7 @@
actualMethodName = callName;
} else {
actualReceiverType = receiverType;
- interfaceTarget = interfaceMember is Member ? interfaceMember : null;
+ interfaceTarget = target.isInstanceMember ? target.member : null;
actualMethodName = methodName;
}
library.checkBoundsInMethodInvocation(
@@ -1631,7 +2120,7 @@
inferred: getExplicitTypeArguments(arguments) == null);
}
- return new ExpressionInferenceResult(null, inferredType);
+ return new ExpressionInferenceResult(inferredType, replacement);
}
@override
@@ -1640,53 +2129,97 @@
assert(closureContext == null);
this.helper = helper;
assert(declaredType != null);
- DartType actualType = inferExpression(initializer, declaredType, true);
+ ExpressionInferenceResult result =
+ inferExpression(initializer, declaredType, true);
ensureAssignable(
- declaredType, actualType, initializer, initializer.fileOffset);
+ declaredType, result.inferredType, initializer, initializer.fileOffset);
this.helper = null;
}
/// Performs the core type inference algorithm for property gets (this handles
/// both null-aware and non-null-aware property gets).
- void inferPropertyGet(Expression expression, Expression receiver,
- int fileOffset, DartType typeContext,
+ ExpressionInferenceResult inferPropertyGet(Expression expression,
+ Expression receiver, int fileOffset, DartType typeContext,
{VariableDeclaration receiverVariable,
PropertyGet desugaredGet,
- Object interfaceMember,
- Name propertyName}) {
+ ObjectAccessTarget readTarget,
+ Name propertyName,
+ bool allowExtensionMethods: false}) {
// First infer the receiver so we can look up the getter that was invoked.
DartType receiverType;
if (receiver == null) {
receiverType = thisType;
} else {
- inferExpression(receiver, const UnknownType(), true);
- receiverType = getInferredType(receiver, this);
+ ExpressionInferenceResult result =
+ inferExpression(receiver, const UnknownType(), true);
+ receiverType = result.inferredType;
}
receiverVariable?.type = receiverType;
propertyName ??= desugaredGet.name;
if (desugaredGet != null) {
- interfaceMember = findInterfaceMember(
- receiverType, propertyName, fileOffset,
+ readTarget = findInterfaceMember(receiverType, propertyName, fileOffset,
errorTemplate: templateUndefinedGetter,
expression: expression,
- receiver: receiver);
- if (interfaceMember is Member) {
+ receiver: receiver,
+ includeExtensionMethods: allowExtensionMethods);
+ if (readTarget.isInstanceMember) {
if (instrumentation != null && receiverType == const DynamicType()) {
instrumentation.record(uri, desugaredGet.fileOffset, 'target',
- new InstrumentationValueForMember(interfaceMember));
+ new InstrumentationValueForMember(readTarget.member));
}
- desugaredGet.interfaceTarget = interfaceMember;
+ desugaredGet.interfaceTarget = readTarget.member;
}
}
- DartType inferredType = getCalleeType(interfaceMember, receiverType);
+ DartType inferredType = getGetterType(readTarget, receiverType);
Expression replacedExpression = handlePropertyGetContravariance(receiver,
- interfaceMember, desugaredGet, expression, inferredType, fileOffset);
- if ((interfaceMember is Procedure &&
- interfaceMember.kind == ProcedureKind.Method)) {
- inferredType =
- instantiateTearOff(inferredType, typeContext, replacedExpression);
+ readTarget, desugaredGet, expression, inferredType, fileOffset);
+ Expression replacement;
+ if (readTarget.isInstanceMember) {
+ Member member = readTarget.member;
+ if (member is Procedure && member.kind == ProcedureKind.Method) {
+ inferredType =
+ instantiateTearOff(inferredType, typeContext, replacedExpression);
+ }
+ } else if (readTarget.isExtensionMember) {
+ int fileOffset = expression.fileOffset;
+ switch (readTarget.extensionMethodKind) {
+ case kernel.ProcedureKind.Getter:
+ expression.parent.replaceChild(
+ expression,
+ replacement = expression = helper.forest.createStaticInvocation(
+ fileOffset,
+ readTarget.member,
+ helper.forest.createArgumentsForExtensionMethod(
+ fileOffset,
+ readTarget.inferredExtensionTypeArguments.length,
+ 0,
+ receiver,
+ extensionTypeArguments:
+ readTarget.inferredExtensionTypeArguments)));
+ break;
+ case kernel.ProcedureKind.Method:
+ expression.parent.replaceChild(
+ expression,
+ replacement = expression = helper.forest.createStaticInvocation(
+ fileOffset,
+ readTarget.tearoffTarget,
+ helper.forest.createArgumentsForExtensionMethod(
+ fileOffset,
+ readTarget.inferredExtensionTypeArguments.length,
+ 0,
+ receiver,
+ extensionTypeArguments:
+ readTarget.inferredExtensionTypeArguments)));
+ break;
+ case kernel.ProcedureKind.Setter:
+ case kernel.ProcedureKind.Factory:
+ case kernel.ProcedureKind.Operator:
+ unhandled('$readTarget', "inferPropertyGet", fileOffset, uri);
+ break;
+ }
}
storeInferredType(expression, inferredType);
+ return new ExpressionInferenceResult(inferredType, replacement);
}
/// Modifies a type as appropriate when inferring a closure return type.
@@ -1759,35 +2292,38 @@
MethodContravarianceCheckKind preCheckInvocationContravariance(
Expression receiver,
DartType receiverType,
- Object interfaceMember,
+ ObjectAccessTarget target,
MethodInvocation desugaredInvocation,
Arguments arguments,
Expression expression) {
- if (interfaceMember is Field ||
- interfaceMember is Procedure &&
- interfaceMember.kind == ProcedureKind.Getter) {
- DartType getType = getCalleeType(interfaceMember, receiverType);
- if (getType is DynamicType) {
- return MethodContravarianceCheckKind.none;
- }
- if (receiver != null && receiver is! ThisExpression) {
- if ((interfaceMember is Field &&
- returnedTypeParametersOccurNonCovariantly(
- interfaceMember.enclosingClass, interfaceMember.type)) ||
- (interfaceMember is Procedure &&
- returnedTypeParametersOccurNonCovariantly(
- interfaceMember.enclosingClass,
- interfaceMember.function.returnType))) {
- return MethodContravarianceCheckKind.checkGetterReturn;
+ if (target.isInstanceMember) {
+ Member interfaceMember = target.member;
+ if (interfaceMember is Field ||
+ interfaceMember is Procedure &&
+ interfaceMember.kind == ProcedureKind.Getter) {
+ DartType getType = getGetterType(target, receiverType);
+ if (getType is DynamicType) {
+ return MethodContravarianceCheckKind.none;
}
+ if (receiver != null && receiver is! ThisExpression) {
+ if ((interfaceMember is Field &&
+ returnedTypeParametersOccurNonCovariantly(
+ interfaceMember.enclosingClass, interfaceMember.type)) ||
+ (interfaceMember is Procedure &&
+ returnedTypeParametersOccurNonCovariantly(
+ interfaceMember.enclosingClass,
+ interfaceMember.function.returnType))) {
+ return MethodContravarianceCheckKind.checkGetterReturn;
+ }
+ }
+ } else if (receiver != null &&
+ receiver is! ThisExpression &&
+ interfaceMember is Procedure &&
+ returnedTypeParametersOccurNonCovariantly(
+ interfaceMember.enclosingClass,
+ interfaceMember.function.returnType)) {
+ return MethodContravarianceCheckKind.checkMethodReturn;
}
- } else if (receiver != null &&
- receiver is! ThisExpression &&
- interfaceMember is Procedure &&
- returnedTypeParametersOccurNonCovariantly(
- interfaceMember.enclosingClass,
- interfaceMember.function.returnType)) {
- return MethodContravarianceCheckKind.checkMethodReturn;
}
return MethodContravarianceCheckKind.none;
}
@@ -1862,7 +2398,7 @@
Class class_, Name name, bool setter, int charOffset) {
Member member = engine.hierarchyBuilder.getCombinedMemberSignatureKernel(
class_, name, setter, charOffset, library);
- if (member == null && (library?.isPatch ?? false)) {
+ if (member == null && library.isPatch) {
// TODO(dmitryas): Hack for parts.
member ??=
classHierarchy.getInterfaceMember(class_, name, setter: setter);
@@ -2073,8 +2609,154 @@
/// The result of an expression inference.
class ExpressionInferenceResult {
- final Expression expression;
- final DartType type;
+ /// The inferred type of the expression.
+ final DartType inferredType;
- ExpressionInferenceResult(this.expression, this.type);
+ /// If not-null, the [replacement] that replaced the inferred expression.
+ final Expression replacement;
+
+ const ExpressionInferenceResult(this.inferredType, [this.replacement]);
+}
+
+enum ObjectAccessTargetKind {
+ instanceMember,
+ callFunction,
+ unresolved,
+ extensionMember,
+}
+
+/// Result for performing an access on an object, like `o.foo`, `o.foo()` and
+/// `o.foo = ...`.
+class ObjectAccessTarget {
+ final ObjectAccessTargetKind kind;
+ final Member member;
+
+ const ObjectAccessTarget.internal(this.kind, this.member);
+
+ /// Creates an access to the instance [member].
+ factory ObjectAccessTarget.interfaceMember(Member member) {
+ assert(member != null);
+ return new ObjectAccessTarget.internal(
+ ObjectAccessTargetKind.instanceMember, member);
+ }
+
+ /// Creates an access to the extension [member].
+ factory ObjectAccessTarget.extensionMember(
+ Member member,
+ Member tearoffTarget,
+ ProcedureKind kind,
+ List<DartType> inferredTypeArguments) = ExtensionAccessTarget;
+
+ /// Creates an access to a 'call' method on a function, i.e. a function
+ /// invocation.
+ const ObjectAccessTarget.callFunction()
+ : this.internal(ObjectAccessTargetKind.callFunction, null);
+
+ /// Creates an access with no target.
+ ///
+ /// Done depending on context this may or may not be an error. For instance
+ /// if the receiver has type `dynamic` this is not an error.
+ const ObjectAccessTarget.unresolved()
+ : this.internal(ObjectAccessTargetKind.unresolved, null);
+
+ /// Returns `true` if this is an access to an instance member.
+ bool get isInstanceMember => kind == ObjectAccessTargetKind.instanceMember;
+
+ /// Returns `true` if this is an access to an extension member.
+ bool get isExtensionMember => kind == ObjectAccessTargetKind.extensionMember;
+
+ /// Returns `true` if this is an access to the 'call' method on a function.
+ bool get isCallFunction => kind == ObjectAccessTargetKind.callFunction;
+
+ /// Returns `true` if this is an access without a known target.
+ bool get isUnresolved => kind == ObjectAccessTargetKind.unresolved;
+
+ /// Returns the original procedure kind, if this is an extension method
+ /// target.
+ ///
+ /// This is need because getters, setters, and methods are converted into
+ /// top level methods, but access and invocation should still be treated as
+ /// if they are the original procedure kind.
+ ProcedureKind get extensionMethodKind =>
+ throw new UnsupportedError('ObjectAccessTarget.extensionMethodKind');
+
+ /// Returns inferred type arguments for the type parameters of an extension
+ /// method that comes from the extension declaration.
+ List<DartType> get inferredExtensionTypeArguments =>
+ throw new UnsupportedError(
+ 'ObjectAccessTarget.inferredExtensionTypeArguments');
+
+ /// Returns the member to use for a tearoff.
+ ///
+ /// This is currently used for extension methods.
+ // TODO(johnniwinther): Normalize use by having `readTarget` and
+ // `invokeTarget`?
+ Member get tearoffTarget =>
+ throw new UnsupportedError('ObjectAccessTarget.tearoffTarget');
+
+ @override
+ String toString() => 'ObjectAccessTarget($kind,$member)';
+}
+
+class ExtensionAccessTarget extends ObjectAccessTarget {
+ final Member tearoffTarget;
+ final ProcedureKind extensionMethodKind;
+ final List<DartType> inferredExtensionTypeArguments;
+
+ ExtensionAccessTarget(Member member, this.tearoffTarget,
+ this.extensionMethodKind, this.inferredExtensionTypeArguments)
+ : super.internal(ObjectAccessTargetKind.extensionMember, member);
+
+ @override
+ String toString() =>
+ 'ExtensionAccessTarget($kind,$member,$extensionMethodKind)';
+}
+
+class ExtensionAccessCandidate {
+ final bool isPlatform;
+ final DartType onType;
+ final DartType onTypeInstantiateToBounds;
+ final ExtensionAccessTarget target;
+
+ ExtensionAccessCandidate(Extension extension, this.onType,
+ this.onTypeInstantiateToBounds, this.target)
+ : isPlatform = extension.enclosingLibrary.importUri.scheme == 'dart';
+
+ bool isMoreSpecificThan(TypeSchemaEnvironment typeSchemaEnvironment,
+ ExtensionAccessCandidate other) {
+ if (this.isPlatform == other.isPlatform) {
+ // Both are platform or not platform.
+ bool thisIsSubtype =
+ typeSchemaEnvironment.isSubtypeOf(this.onType, other.onType);
+ bool thisIsSupertype =
+ typeSchemaEnvironment.isSubtypeOf(other.onType, this.onType);
+ if (thisIsSubtype && !thisIsSupertype) {
+ // This is subtype of other and not vice-versa.
+ return true;
+ } else if (thisIsSupertype && !thisIsSubtype) {
+ // [other] is subtype of this and not vice-versa.
+ return false;
+ } else if (thisIsSubtype || thisIsSupertype) {
+ thisIsSubtype = typeSchemaEnvironment.isSubtypeOf(
+ this.onTypeInstantiateToBounds, other.onTypeInstantiateToBounds);
+ thisIsSupertype = typeSchemaEnvironment.isSubtypeOf(
+ other.onTypeInstantiateToBounds, this.onTypeInstantiateToBounds);
+ if (thisIsSubtype && !thisIsSupertype) {
+ // This is subtype of other and not vice-versa.
+ return true;
+ } else if (thisIsSupertype && !thisIsSubtype) {
+ // [other] is subtype of this and not vice-versa.
+ return false;
+ }
+ }
+ } else if (other.isPlatform) {
+ // This is not platform, [other] is: this is more specific.
+ return true;
+ } else {
+ // This is platform, [other] is not: other is more specific.
+ return false;
+ }
+ // Neither is more specific than the other.
+ return null;
+ }
}
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_schema.dart b/pkg/front_end/lib/src/fasta/type_inference/type_schema.dart
index e5ba185..1634efb 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_schema.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_schema.dart
@@ -32,7 +32,7 @@
}
/// Extension of [Printer] that represents the unknown type as `?`.
-class TypeSchemaPrinter extends Printer implements TypeSchemaVisitor<Null> {
+class TypeSchemaPrinter extends Printer {
TypeSchemaPrinter(StringSink sink,
{NameSystem syntheticNames,
bool showExternal,
@@ -47,17 +47,11 @@
annotator: annotator);
@override
- visitUnknownType(UnknownType node) {
+ defaultDartType(covariant UnknownType node) {
writeWord('?');
}
}
-/// Extension of [DartTypeVisitor] which can visit [UnknownType].
-class TypeSchemaVisitor<R> extends DartTypeVisitor<R> {
- /// Called when [UnknownType] is visited.
- R visitUnknownType(UnknownType node) => defaultDartType(node);
-}
-
/// The unknown type (denoted `?`) is an object which can appear anywhere that
/// a type is expected. It represents a component of a type which has not yet
/// been fixed by inference.
@@ -77,21 +71,12 @@
}
@override
- accept(DartTypeVisitor<dynamic> v) {
- if (v is TypeSchemaVisitor<dynamic>) {
- return v.visitUnknownType(this);
- } else {
- // Note: in principle it seems like this should throw, since any visitor
- // that operates on a type schema ought to inherit from TypeSchemaVisitor.
- // However, that would make it impossible to use toString() on any type
- // schema, since toString() uses the kernel's Printer visitor, which can't
- // possibly inherit from TypeSchemaVisitor since it's inside kernel.
- return v.defaultDartType(this);
- }
+ R accept<R>(DartTypeVisitor<R> v) {
+ return v.defaultDartType(this);
}
@override
- accept1(DartTypeVisitor1<dynamic, dynamic> v, arg) =>
+ R accept1<R, A>(DartTypeVisitor1<R, A> v, arg) =>
v.defaultDartType(this, arg);
@override
@@ -99,9 +84,9 @@
}
/// Visitor that computes [isKnown].
-class _IsKnownVisitor extends TypeSchemaVisitor<bool> {
+class _IsKnownVisitor extends DartTypeVisitor<bool> {
@override
- bool defaultDartType(DartType node) => true;
+ bool defaultDartType(DartType node) => node is! UnknownType;
@override
bool visitFunctionType(FunctionType node) {
@@ -130,7 +115,4 @@
}
return true;
}
-
- @override
- bool visitUnknownType(UnknownType node) => false;
}
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_schema_elimination.dart b/pkg/front_end/lib/src/fasta/type_inference/type_schema_elimination.dart
index 5c0233d..1b8cd24 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_schema_elimination.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_schema_elimination.dart
@@ -3,11 +3,17 @@
// BSD-style license that can be found in the LICENSE.md file.
import 'package:kernel/ast.dart'
- show DartType, DynamicType, FunctionType, InterfaceType, NamedType;
+ show
+ DartType,
+ DartTypeVisitor,
+ DynamicType,
+ FunctionType,
+ InterfaceType,
+ NamedType;
import 'package:kernel/core_types.dart' show CoreTypes;
-import 'type_schema.dart' show TypeSchemaVisitor, UnknownType;
+import 'type_schema.dart' show UnknownType;
/// Returns the greatest closure of the given type [schema] with respect to `?`.
///
@@ -46,7 +52,7 @@
/// Each visitor method returns `null` if there are no `?`s contained in the
/// type, otherwise it returns the result of substituting `?` with `Null` or
/// `Object`, as appropriate.
-class _TypeSchemaEliminationVisitor extends TypeSchemaVisitor<DartType> {
+class _TypeSchemaEliminationVisitor extends DartTypeVisitor<DartType> {
final DartType nullType;
bool isLeastClosure;
@@ -115,8 +121,12 @@
}
@override
- DartType visitUnknownType(UnknownType node) =>
- isLeastClosure ? nullType : const DynamicType();
+ DartType defaultDartType(DartType node) {
+ if (node is UnknownType) {
+ return isLeastClosure ? nullType : const DynamicType();
+ }
+ return null;
+ }
/// Runs an instance of the visitor on the given [schema] and returns the
/// resulting type. If the schema contains no instances of `?`, the original
diff --git a/pkg/front_end/lib/src/testing/id_testing_helper.dart b/pkg/front_end/lib/src/testing/id_testing_helper.dart
index c6f7538..ec92375 100644
--- a/pkg/front_end/lib/src/testing/id_testing_helper.dart
+++ b/pkg/front_end/lib/src/testing/id_testing_helper.dart
@@ -33,14 +33,9 @@
/// Test configuration used for testing CFE in its default state.
const TestConfig defaultCfeConfig = const TestConfig(cfeMarker, 'cfe');
-/// Test configuration used for testing CFE with constant evaluation.
-const TestConfig cfeConstantUpdate2018Config = const TestConfig(
- cfeMarker, 'cfe with constant-update-2018',
- experimentalFlags: const {ExperimentalFlag.constantUpdate2018: true});
-
/// Test configuration used for testing CFE with extension methods.
const TestConfig cfeExtensionMethodsConfig = const TestConfig(
- cfeMarker, 'cfe with constant-update-2018',
+ cfeMarker, 'cfe with extension methods',
experimentalFlags: const {ExperimentalFlag.extensionMethods: true});
class TestConfig {
@@ -49,6 +44,8 @@
final Map<ExperimentalFlag, bool> experimentalFlags;
const TestConfig(this.marker, this.name, {this.experimentalFlags = const {}});
+
+ void customizeCompilerOptions(CompilerOptions options) {}
}
// TODO(johnniwinther): Support annotations for compile-time errors.
@@ -245,6 +242,7 @@
};
options.debugDump = printCode;
options.experimentalFlags.addAll(config.experimentalFlags);
+ config.customizeCompilerOptions(options);
InternalCompilerResult compilerResult = await compileScript(
testData.memorySourceFiles,
options: options,
@@ -285,7 +283,9 @@
}
Map<Id, ActualData<T>> actualMapFor(TreeNode node) {
- Uri uri = node is Library ? node.fileUri : node.location.file;
+ Uri uri = node is Library
+ ? node.fileUri
+ : (node is Member ? node.fileUri : node.location.file);
return actualMaps.putIfAbsent(uri, () => <Id, ActualData<T>>{});
}
diff --git a/pkg/front_end/lib/src/testing/id_testing_utils.dart b/pkg/front_end/lib/src/testing/id_testing_utils.dart
index 83179c8..d32d8f5 100644
--- a/pkg/front_end/lib/src/testing/id_testing_utils.dart
+++ b/pkg/front_end/lib/src/testing/id_testing_utils.dart
@@ -97,7 +97,7 @@
});
}
-TypeParameterScopeBuilder lookupLibraryDeclarationBuilder(
+LibraryBuilder lookupLibraryBuilder(
InternalCompilerResult compilerResult, Library library,
{bool required: true}) {
SourceLoader loader = compilerResult.kernelTargetForTesting.loader;
@@ -105,6 +105,14 @@
if (builder == null && required) {
throw new ArgumentError("DeclarationBuilder for $library not found.");
}
+ return builder;
+}
+
+TypeParameterScopeBuilder lookupLibraryDeclarationBuilder(
+ InternalCompilerResult compilerResult, Library library,
+ {bool required: true}) {
+ SourceLibraryBuilder builder =
+ lookupLibraryBuilder(compilerResult, library, required: required);
return builder.libraryDeclaration;
}
@@ -196,8 +204,8 @@
return memberBuilder;
}
-/// Look up the [MemberBuilder] for [member] through the [ClassBuilder] for
-/// [cls] using [memberName] as its name.
+/// Look up the [MemberBuilder] for [member] through the [ExtensionBuilder] for
+/// [extension] using [memberName] as its name.
MemberBuilder lookupExtensionMemberBuilder(
InternalCompilerResult compilerResult,
Extension extension,
@@ -254,7 +262,7 @@
}
}
- void defaultConstant(Constant node) => throw UnimplementedError(
+ void defaultConstant(Constant node) => throw new UnimplementedError(
'Unexpected constant $node (${node.runtimeType})');
void visitNullConstant(NullConstant node) {
@@ -378,8 +386,8 @@
}
}
- void defaultDartType(DartType node) =>
- throw UnimplementedError('Unexpected type $node (${node.runtimeType})');
+ void defaultDartType(DartType node) => throw new UnimplementedError(
+ 'Unexpected type $node (${node.runtimeType})');
void visitInvalidType(InvalidType node) {
sb.write('<invalid>');
@@ -525,25 +533,24 @@
if (descriptor.isStatic) {
sb.write('static ');
}
- if (descriptor.kind == null) {
- sb.write('field ');
- } else {
- switch (descriptor.kind) {
- case ProcedureKind.Method:
- break;
- case ProcedureKind.Getter:
- sb.write('getter ');
- break;
- case ProcedureKind.Setter:
- sb.write('setter ');
- break;
- case ProcedureKind.Operator:
- sb.write('operator ');
- break;
- case ProcedureKind.Factory:
- throw new UnsupportedError(
- "Unexpected procedure kind ${descriptor.kind}.");
- }
+ switch (descriptor.kind) {
+ case ExtensionMemberKind.Method:
+ break;
+ case ExtensionMemberKind.Getter:
+ sb.write('getter ');
+ break;
+ case ExtensionMemberKind.Setter:
+ sb.write('setter ');
+ break;
+ case ExtensionMemberKind.Operator:
+ sb.write('operator ');
+ break;
+ case ExtensionMemberKind.Field:
+ sb.write('field ');
+ break;
+ case ExtensionMemberKind.TearOff:
+ sb.write('tearoff ');
+ break;
}
sb.write(descriptor.name.name);
sb.write('=');
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index 56dfe2e..8d11e08 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -103,6 +103,8 @@
ConstEvalNotListOrSetInSpread/example: Fail
ConstEvalNotMapInSpread/example: Fail
ConstEvalNullValue/example: Fail
+ConstEvalStartingPoint/analyzerCode: Fail # This is just used for displaying the starting point.
+ConstEvalStartingPoint/example: Fail # This is just used for displaying the starting point.
ConstEvalUnevaluated/analyzerCode: Fail
ConstEvalUnevaluated/example: Fail
ConstEvalZeroDivisor/example: Fail
@@ -124,8 +126,6 @@
CovariantMember/part_wrapped_script2: Fail
CovariantMember/script1: Fail
CovariantMember/script2: Fail
-CycleInTypeVariables/part_wrapped_script1: Fail
-CycleInTypeVariables/script1: Fail # We report an error for each type variable involved in the cycle.
CyclicClassHierarchy/part_wrapped_script1: Fail
CyclicClassHierarchy/part_wrapped_script2: Fail
CyclicClassHierarchy/script1: Fail # We report an error for each class involved in the cycle.
@@ -193,6 +193,10 @@
ExpectedUri/analyzerCode: Fail
ExpectedUri/example: Fail
ExperimentNotEnabled/example: Fail
+ExplicitExtensionArgumentMismatch/analyzerCode: Fail
+ExplicitExtensionArgumentMismatch/example: Fail
+ExplicitExtensionTypeArgumentMismatch/analyzerCode: Fail
+ExplicitExtensionTypeArgumentMismatch/example: Fail
ExportAfterPart/part_wrapped_script1: Fail
ExportAfterPart/script1: Fail
ExpressionNotMetadata/analyzerCode: Fail
@@ -205,6 +209,9 @@
ExternalFactoryRedirection/example: Fail
ExternalFactoryWithBody/part_wrapped_script1: Fail
ExternalFactoryWithBody/script1: Fail
+ExtensionDeclaresAbstractMember/example: Fail
+ExtensionDeclaresConstructor/example: Fail
+ExtensionDeclaresInstanceField/example: Fail
ExtraneousModifier/part_wrapped_script1: Fail
ExtraneousModifier/part_wrapped_script2: Fail
ExtraneousModifier/part_wrapped_script3: Fail
@@ -258,6 +265,10 @@
FfiExtendsOrImplementsSealedClass/analyzerCode: Fail
FfiStructGeneric/analyzerCode: Fail
FfiWrongStructInheritance/analyzerCode: Fail
+FfiExpectedExceptionalReturn/analyzerCode: Fail
+FfiExpectedNoExceptionalReturn/analyzerCode: Fail
+FfiExpectedConstant/analyzerCode: Fail
+FfiExceptionalReturnNull/analyzerCode: Fail
FieldInitializedOutsideDeclaringClass/part_wrapped_script1: Fail
FieldInitializedOutsideDeclaringClass/script1: Fail
FieldInitializerOutsideConstructor/part_wrapped_script1: Fail
@@ -363,6 +374,7 @@
MissingMain/example: Fail
MissingPartOf/part_wrapped_script: Fail # Using 'part' in the (now) part.
MissingPrefixInDeferredImport/example: Fail
+MixinDeclaresConstructor/example: Fail
MixinInferenceNoMatchingClass/example: Fail
ModifierOutOfOrder/part_wrapped_script1: Fail
ModifierOutOfOrder/script1: Fail
@@ -407,6 +419,7 @@
OverrideMoreRequiredArguments/example: Fail
OverrideTypeMismatchParameter/example: Fail
OverrideTypeMismatchReturnType/example: Fail
+OverrideTypeMismatchSetter/example: Fail
OverrideTypeVariablesMismatch/example: Fail
PackageNotFound/analyzerCode: Fail
PackageNotFound/example: Fail
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 4ba9581..a1b889c 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -82,6 +82,9 @@
analyzerCode: ILLEGAL_CHARACTER
expression: "\x1b 1"
+ConstEvalStartingPoint:
+ template: "Constant evaluation error:"
+
ConstEvalContext:
template: "While analyzing:"
@@ -1858,13 +1861,38 @@
}
IllegalMixinDueToConstructors:
+ # a class with a constructor is used as a mixin
template: "Can't use '#name' as a mixin because it has constructors."
- analyzerCode: MIXIN_DECLARES_CONSTRUCTOR
+ analyzerCode: MIXIN_DECLARES_CONSTRUCTOR # CompileTimeErrorCode
+
+MixinDeclaresConstructor:
+ # a mixin declaration contains a constructor declaration
+ index: 95
+ template: "Mixins can't declare constructors."
+ analyzerCode: ParserErrorCode.MIXIN_DECLARES_CONSTRUCTOR
IllegalMixinDueToConstructorsCause:
template: "This constructor prevents using '#name' as a mixin."
severity: CONTEXT
+ExtensionDeclaresAbstractMember:
+ index: 94
+ template: "Extensions can't declare abstract members."
+ tip: "Try providing an implementation for the member."
+ analyzerCode: ParserErrorCode.EXTENSION_DECLARES_ABSTRACT_MEMBER
+
+ExtensionDeclaresConstructor:
+ index: 92
+ template: "Extensions can't declare constructors."
+ tip: "Try removing the constructor declaration."
+ analyzerCode: ParserErrorCode.EXTENSION_DECLARES_CONSTRUCTOR
+
+ExtensionDeclaresInstanceField:
+ index: 93
+ template: "Extensions can't declare instance fields"
+ tip: "Try removing the field declaration or making it a static field"
+ analyzerCode: ParserErrorCode.EXTENSION_DECLARES_INSTANCE_FIELD
+
ConflictsWithConstructor:
template: "Conflicts with constructor '#name'."
analyzerCode: CONFLICTS_WITH_CONSTRUCTOR
@@ -2015,6 +2043,10 @@
tip: "Change to a subtype of '#type2'."
analyzerCode: INVALID_METHOD_OVERRIDE
+OverrideTypeMismatchSetter:
+ template: "The field '#name' has type '#type', which does not match the corresponding type, '#type2', in the overridden setter, '#name2'."
+ analyzerCode: INVALID_METHOD_OVERRIDE
+
PartOfSelf:
template: "A file can't be a part of itself."
analyzerCode: PART_OF_NON_PART
@@ -3463,17 +3495,17 @@
FfiFieldAnnotation:
# Used by dart:ffi
- template: "Field '#name' requires exactly one annotation to declare its C++ type, which cannot be Void. dart:ffi Structs cannot have regular Dart fields."
+ template: "Field '#name' requires exactly one annotation to declare its native type, which cannot be Void. dart:ffi Structs cannot have regular Dart fields."
external: test/ffi_test.dart
FfiFieldNoAnnotation:
# Used by dart:ffi
- template: "Field '#name' requires no annotation to declare its C++ type, it is a Pointer which is represented by the same type in Dart and C++."
+ template: "Field '#name' requires no annotation to declare its native type, it is a Pointer which is represented by the same type in Dart and native code."
external: test/ffi_test.dart
FfiNotStatic:
# Used by dart:ffi
- template: "#name expects a static function as parameter. dart:ffi only supports calling static Dart functions from c."
+ template: "#name expects a static function as parameter. dart:ffi only supports calling static Dart functions from native code."
external: test/ffi_test.dart
FfiFieldInitializer:
@@ -3501,6 +3533,26 @@
template: "Expected '#type' to be a subtype of '#type2'."
external: test/ffi_test.dart
+FfiExpectedExceptionalReturn:
+ # Used by dart:ffi
+ template: "Expected an exceptional return value for a native callback returning '#type'."
+ external: test/ffi_test.dart
+
+FfiExpectedNoExceptionalReturn:
+ # Used by dart:ffi
+ template: "Exceptional return value cannot be provided for a native callback returning '#type'."
+ external: test/ffi_test.dart
+
+FfiExpectedConstant:
+ # Used by dart:ffi
+ template: "Exceptional return value must be a constant."
+ external: test/ffi_test.dart
+
+FfiExceptionalReturnNull:
+ # Used by dart:ffi
+ template: "Exceptional return value must not be null."
+ external: test/ffi_test.dart
+
SpreadTypeMismatch:
template: "Unexpected type '#type' of a spread. Expected 'dynamic' or an Iterable."
script:
@@ -3640,3 +3692,9 @@
// @dart = 2.3
part of 'main.dart';
+
+ExplicitExtensionArgumentMismatch:
+ template: "Explicit extension application requires exactly 1 positional argument."
+
+ExplicitExtensionTypeArgumentMismatch:
+ template: "Explicit extension application of extension '#name' takes '#count' type argument(s)."
diff --git a/pkg/front_end/pubspec.yaml b/pkg/front_end/pubspec.yaml
index 876a203..ea3f3bf 100644
--- a/pkg/front_end/pubspec.yaml
+++ b/pkg/front_end/pubspec.yaml
@@ -1,24 +1,24 @@
name: front_end
# Currently, front_end API is not stable and users should not
# depend on semver semantics when depending on this package.
-version: 0.1.23
+version: 0.1.24
author: Dart Team <misc@dartlang.org>
description: Front end for compilation of Dart code.
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/front_end
environment:
sdk: '>=2.2.2 <3.0.0'
dependencies:
- kernel: 0.3.23
+ kernel: 0.3.24
package_config: '^1.1.0'
- path: '^1.3.9'
- yaml: '^2.1.12'
dev_dependencies:
- analyzer: 0.38.1
+ analyzer: 0.38.2
args: '>=0.13.0 <2.0.0'
build_integration:
path: ../build_integration
dart_style: '^1.0.7'
json_rpc_2: ^2.0.9
+ path: '^1.3.9'
test: ^1.3.4
test_reflective_loader: ^0.1.0
web_socket_channel: ^1.0.4
+ yaml: '^2.1.12'
diff --git a/pkg/front_end/test/binary_md_dill_reader.dart b/pkg/front_end/test/binary_md_dill_reader.dart
new file mode 100644
index 0000000..44e75c8
--- /dev/null
+++ b/pkg/front_end/test/binary_md_dill_reader.dart
@@ -0,0 +1,826 @@
+// Copyright (c) 2019, 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:math" as math;
+
+class BinaryMdDillReader {
+ final String _binaryMdContent;
+
+ /// The actual binary content.
+ final List<int> _dillContent;
+
+ String _currentlyUnparsed = "";
+ Map<String, List<String>> _readingInstructions;
+ Map<String, List<String>> _generics;
+ Map<int, String> tagToName;
+ Map<int, String> constantTagToName;
+ int version;
+ Map<String, String> _extends;
+ int _binaryMdNestingDepth;
+ String _binaryMdCurrentClass;
+
+ /// The offset in the binary where we're supposed to read next.
+ int _binaryOffset;
+
+ int _depth;
+ Map _dillStringsPointer;
+ int verboseLevel = 0;
+ bool _ranSetup = false;
+
+ BinaryMdDillReader(this._binaryMdContent, this._dillContent);
+
+ void setup() {
+ if (!_ranSetup) {
+ _setupFields();
+ _readBinaryMd();
+ _ranSetup = true;
+ }
+ }
+
+ Map attemptRead() {
+ setup();
+ return _readDill();
+ }
+
+ /// Initialize the bare essentials, e.g. that a double is 8 bytes.
+ void _setupFields() {
+ _readingInstructions = {
+ "Byte": ["byte"],
+ "UInt32": ["byte", "byte", "byte", "byte"],
+ "Double": ["byte", "byte", "byte", "byte", "byte", "byte", "byte", "byte"]
+ };
+ _generics = {};
+ tagToName = {};
+ constantTagToName = {};
+ _extends = {};
+ _binaryMdNestingDepth = 0;
+ _binaryMdCurrentClass = "";
+ }
+
+ /// Read the binary.md text and put the data into the various tables.
+ void _readBinaryMd() {
+ List<String> lines = _binaryMdContent.split("\n");
+ bool inComment = false;
+ for (String s in lines) {
+ if (s.trim().startsWith("//") || s.trim() == "") {
+ continue;
+ } else if (s.trim().startsWith("/*")) {
+ inComment = true;
+ continue;
+ } else if (s.trim().startsWith("*/")) {
+ inComment = false;
+ continue;
+ } else if (inComment) {
+ continue;
+ } else if (s.trim().startsWith("type ") ||
+ s.trim().startsWith("abstract type ") ||
+ s.trim().startsWith("enum ")) {
+ _binaryMdHandlePossibleClassStart(s);
+ } else if (s.trim() == "if name begins with '_' {" &&
+ _binaryMdCurrentClass == "Name") {
+ // Special-case if sentence in Name.
+ _binaryMdNestingDepth++;
+ } else if (s.trim().endsWith("{")) {
+ throw "Unhandled case: $s";
+ } else if (s.trim() == "}") {
+ _binaryMdNestingDepth--;
+ _binaryMdCurrentClass = "";
+ } else if (_binaryMdNestingDepth > 0 && _binaryMdCurrentClass != "") {
+ _binaryMdHandleContent(s);
+ }
+ }
+
+ _binaryMdCheckHasAllTypes();
+ if (verboseLevel > 0) {
+ print("Seems to find all types.");
+ }
+ }
+
+ int numLibs;
+ int binaryOffsetForSourceTable;
+ int binaryOffsetForCanonicalNames;
+ int binaryOffsetForMetadataPayloads;
+ int binaryOffsetForMetadataMappings;
+ int binaryOffsetForStringTable;
+ int binaryOffsetForConstantTable;
+ int mainMethodReference;
+
+ /// Read the dill file data, parsing it into a Map.
+ Map _readDill() {
+ _binaryOffset = 0;
+ _depth = 0;
+
+ // Hack start: Read ComponentIndex first.
+ _binaryOffset = _dillContent.length - (4 * 2);
+ numLibs = _peekUint32();
+
+ // Skip to the start of the index.
+ _binaryOffset = _dillContent.length -
+ ((numLibs + 1) + 9 /* number of fixed fields */) * 4;
+
+ // Read index.
+ binaryOffsetForSourceTable = _peekUint32();
+ _binaryOffset += 4;
+ binaryOffsetForCanonicalNames = _peekUint32();
+ _binaryOffset += 4;
+ binaryOffsetForMetadataPayloads = _peekUint32();
+ _binaryOffset += 4;
+ binaryOffsetForMetadataMappings = _peekUint32();
+ _binaryOffset += 4;
+ binaryOffsetForStringTable = _peekUint32();
+ _binaryOffset += 4;
+ binaryOffsetForConstantTable = _peekUint32();
+ _binaryOffset += 4;
+ mainMethodReference = _peekUint32();
+
+ _binaryOffset = binaryOffsetForStringTable;
+ var saved = _readingInstructions["ComponentFile"];
+ _readingInstructions["ComponentFile"] = ["StringTable strings;"];
+ _readBinary("ComponentFile");
+ _readingInstructions["ComponentFile"] = saved;
+ _binaryOffset = 0;
+ _depth = 0;
+ // Hack end.
+
+ Map componentFile = _readBinary("ComponentFile");
+ if (_binaryOffset != _dillContent.length) {
+ throw "Didn't read the entire binary: "
+ "Only read $_binaryOffset of ${_dillContent.length} bytes. "
+ "($componentFile)";
+ }
+ if (verboseLevel > 0) {
+ print("Successfully read the dill file.");
+ }
+ return componentFile;
+ }
+
+ /// Initial setup of a "class definition" in the binary.md file.
+ /// This includes parsing the name, setting up any "extends"-relationship,
+ /// generics etc.
+ _binaryMdHandlePossibleClassStart(String s) {
+ if (s.startsWith("type Byte =")) return;
+ if (s.startsWith("type UInt32 =")) return;
+
+ if (_binaryMdNestingDepth != 0 || _binaryMdCurrentClass != "") {
+ throw "Cannot handle nesting: "
+ "'$s', $_binaryMdNestingDepth, $_binaryMdCurrentClass";
+ }
+
+ if (s.contains("{")) _binaryMdNestingDepth++;
+ if (s.contains("}")) _binaryMdNestingDepth--;
+
+ String name = s.trim();
+ if (name.startsWith("abstract ")) name = name.substring("abstract ".length);
+ if (name.startsWith("type ")) name = name.substring("type ".length);
+ bool isEnum = false;
+ if (name.startsWith("enum ")) {
+ name = name.substring("enum ".length);
+ isEnum = true;
+ }
+ String nameExtends = null;
+ Match extendsMatch = (new RegExp("extends (.+)[ \{]")).firstMatch(name);
+ if (extendsMatch != null) {
+ nameExtends = extendsMatch.group(1);
+ }
+ name = _getType(name);
+ if (name.contains("<")) {
+ List<String> types = _getGenerics(name);
+ name = name.substring(0, name.indexOf("<")) + "<${types.length}>";
+ _generics[name] ??= types;
+ }
+ if (_binaryMdNestingDepth != 0) _binaryMdCurrentClass = name;
+ if (nameExtends != null) {
+ _extends[name] = nameExtends.trim();
+ }
+
+ if (isEnum) {
+ _readingInstructions[name] ??= ["byte"];
+ } else {
+ _readingInstructions[name] ??= [];
+ }
+ }
+
+ Map<String, String> _typeCache = {};
+
+ /// Extract the type/name of an input string, e.g. turns
+ ///
+ /// * "ClassLevel { Type = 0, [...], }" into "ClassLevel"
+ /// * "Class extends Node {" into "Class"
+ /// * "Byte tag = 97;" into "Byte"
+ /// * "List<T> {" into "List<T>"
+ String _getType(final String inputString) {
+ String cached = _typeCache[inputString];
+ if (cached != null) return cached;
+ int end = math.max(
+ math.max(inputString.indexOf(" "), inputString.lastIndexOf(">") + 1),
+ inputString.lastIndexOf("]") + 1);
+ if (end <= 0) end = inputString.length;
+ String result = inputString.substring(0, end);
+ if (result.contains(" extends")) {
+ result = result.substring(0, result.indexOf(" extends "));
+ }
+ _typeCache[inputString] = result;
+
+ return result;
+ }
+
+ /// Extract the generics used in an input type, e.g. turns
+ ///
+ /// * "Pair<A, B>" into ["A", "B"]
+ /// * "List<Expression>" into ["Expression"]
+ ///
+ /// Note that the input string *has* to use generics, i.e. have '<' and '>'
+ /// in it.
+ /// Also note that nested generics isn't really supported
+ /// (e.g. Foo<Bar<Baz>>).
+ List<String> _getGenerics(String s) {
+ s = s.substring(s.indexOf("<") + 1, s.lastIndexOf(">"));
+ if (s.contains("<")) {
+ if (s == "Pair<FileOffset, Expression>") {
+ return ["Pair<FileOffset, Expression>"];
+ } else if (s == "Pair<UInt32, UInt32>") {
+ return ["Pair<UInt32, UInt32>"];
+ } else if (s == "Pair<FieldReference, Expression>") {
+ return ["Pair<FieldReference, Expression>"];
+ } else if (s == "Pair<ConstantReference, ConstantReference>") {
+ return ["Pair<ConstantReference, ConstantReference>"];
+ } else if (s == "Pair<FieldReference, ConstantReference>") {
+ return ["Pair<FieldReference, ConstantReference>"];
+ }
+ throw "Doesn't supported nested generics (input: $s).";
+ }
+
+ return s.split(",").map((untrimmed) => untrimmed.trim()).toList();
+ }
+
+ /// Parses a line of binary.md content for a "current class" into the
+ /// reading-instructions for that class.
+ /// There is special handling around tags, and around lines that are split,
+ /// i.e. not yet finished (not ending in a semi-colon).
+ void _binaryMdHandleContent(String s) {
+ if (s.trim().startsWith("UInt32 formatVersion = ")) {
+ String versionString =
+ s.trim().substring("UInt32 formatVersion = ".length);
+ if (versionString.endsWith(";")) {
+ versionString = versionString.substring(0, versionString.length - 1);
+ }
+ if (version != null) {
+ throw "Already have a version set ($version), "
+ "now trying to set $versionString";
+ }
+ version = int.parse(versionString);
+ }
+ if (s.trim().startsWith("Byte tag = ")) {
+ String tag = s.trim().substring("Byte tag = ".length);
+ if (tag.endsWith(";")) tag = tag.substring(0, tag.length - 1);
+ if (tag == "128 + N; // Where 0 <= N < 8.") {
+ for (int n = 0; n < 8; ++n) {
+ tagToName[128 + n] = _binaryMdCurrentClass;
+ }
+ } else if (tag == "136 + N; // Where 0 <= N < 8.") {
+ for (int n = 0; n < 8; ++n) {
+ tagToName[136 + n] = _binaryMdCurrentClass;
+ }
+ } else if (tag == "144 + N; // Where 0 <= N < 8.") {
+ for (int n = 0; n < 8; ++n) {
+ tagToName[144 + n] = _binaryMdCurrentClass;
+ }
+ } else {
+ if (tag.contains("; // Note: tag is out of order")) {
+ tag = tag.substring(0, tag.indexOf("; // Note: tag is out of order"));
+ }
+ Map<int, String> tagMap;
+ if (_isA(_binaryMdCurrentClass, "Constant")) {
+ tagMap = constantTagToName;
+ } else {
+ tagMap = tagToName;
+ }
+ if (tagMap[int.parse(tag)] != null) {
+ throw "Two tags with same name!: "
+ "$tag (${tagMap[int.parse(tag)]} and ${_binaryMdCurrentClass})";
+ }
+ tagMap[int.parse(tag)] = _binaryMdCurrentClass;
+ }
+ }
+
+ {
+ var line = _currentlyUnparsed + s.trim();
+ if (line.contains("//")) line = line.substring(0, line.indexOf("//"));
+ if (!line.trim().endsWith(";")) {
+ _currentlyUnparsed = line;
+ return;
+ }
+ s = line;
+ _currentlyUnparsed = "";
+ }
+
+ _readingInstructions[_binaryMdCurrentClass].add(s.trim());
+ }
+
+ /// Check the all types referenced by reading instructions are types we know
+ /// about.
+ void _binaryMdCheckHasAllTypes() {
+ for (String key in _readingInstructions.keys) {
+ for (String s in _readingInstructions[key]) {
+ String type = _getType(s);
+ if (!_isKnownType(type, key)) {
+ throw "Unknown type: $type (used in $key)";
+ }
+ }
+ }
+ }
+
+ /// Check that we know about the specific type, i.e. know something about how
+ /// to read it.
+ bool _isKnownType(String type, String parent) {
+ if (type == "byte") return true;
+ if (_readingInstructions[type] != null) return true;
+ if (type.contains("[") &&
+ _readingInstructions[type.substring(0, type.indexOf("["))] != null) {
+ return true;
+ }
+
+ if (parent.contains("<")) {
+ Set<String> types = _generics[parent].toSet();
+ if (types.contains(type)) return true;
+ if (type.contains("[") &&
+ types.contains(type.substring(0, type.indexOf("[")))) return true;
+ }
+ if (type.contains("<")) {
+ List<String> types = _getGenerics(type);
+ String renamedType =
+ type.substring(0, type.indexOf("<")) + "<${types.length}>";
+ if (_readingInstructions[renamedType] != null) {
+ bool ok = true;
+ for (String type in types) {
+ if (!_isKnownType(type, renamedType)) {
+ ok = false;
+ break;
+ }
+ }
+ if (ok) return true;
+ }
+ }
+
+ return false;
+ }
+
+ /// Get a string from the string table after the string table has been read
+ /// from the dill file.
+ String getDillString(int num) {
+ List<int> endOffsets =
+ (_dillStringsPointer["endOffsets"]["items"] as List<dynamic>).cast();
+ List<int> utf8 = (_dillStringsPointer["utf8Bytes"] as List<dynamic>).cast();
+ return new String.fromCharCodes(
+ utf8.sublist(num == 0 ? 0 : endOffsets[num - 1], endOffsets[num]));
+ }
+
+ RegExp regExpSplit = new RegExp(r"[\. ]");
+
+ /// Actually read the binary dill file. Read type [what] at the current
+ /// binary position as specified by field [_binaryOffset].
+ dynamic _readBinary(String what) {
+ ++_depth;
+ what = _remapWhat(what);
+
+ // Read any 'base types'.
+ if (what == "UInt") {
+ return _readUint();
+ }
+ if (what == "UInt32") {
+ return _readUint32();
+ }
+ if (what == "byte" || what == "Byte") {
+ int value = _dillContent[_binaryOffset];
+ ++_binaryOffset;
+ --_depth;
+ return value;
+ }
+
+ // Not a 'base type'. Read according to [_readingInstructions] field.
+ List<String> types = [];
+ List<String> typeNames = [];
+ String orgWhat = what;
+ int orgPosition = _binaryOffset;
+ if (what.contains("<")) {
+ types = _getGenerics(what);
+ what = what.substring(0, what.indexOf("<")) + "<${types.length}>";
+ typeNames = _generics[what];
+ }
+
+ if (_readingInstructions[what] == null) {
+ throw "Didn't find instructions for '$what'";
+ }
+
+ Map<String, dynamic> vars = {};
+ if (verboseLevel > 1) {
+ print("".padLeft(_depth * 2) + " -> $what ($orgWhat @ $orgPosition)");
+ }
+
+ for (String instruction in _readingInstructions[what]) {
+ // Special-case a few things that aren't (easily) described in the
+ // binary.md file.
+ if (what == "Name" && instruction == "LibraryReference library;") {
+ // Special-case if sentence in Name.
+ String name = getDillString(vars["name"]["index"]);
+ if (!name.startsWith("_")) continue;
+ } else if (what == "ComponentFile" &&
+ instruction == "MetadataPayload[] metadataPayloads;") {
+ // Special-case skipping metadata payloads.
+ _binaryOffset = binaryOffsetForMetadataMappings;
+ continue;
+ } else if (what == "ComponentFile" &&
+ instruction == "RList<MetadataMapping> metadataMappings;") {
+ // Special-case skipping metadata mappings.
+ _binaryOffset = binaryOffsetForStringTable;
+ continue;
+ } else if (what == "ComponentIndex" &&
+ instruction == "Byte[] 8bitAlignment;") {
+ // Special-case 8-byte alignment.
+ int sizeWithoutPadding = _binaryOffset +
+ ((numLibs + 1) + 9 /* number of fixed fields */) * 4;
+ int padding = 8 - sizeWithoutPadding % 8;
+ if (padding == 8) padding = 0;
+ _binaryOffset += padding;
+ continue;
+ }
+
+ String type = _getType(instruction);
+ String name = instruction.substring(type.length).trim();
+ if (name.contains("//")) {
+ name = name.substring(0, name.indexOf("//")).trim();
+ }
+ if (name.contains("=")) {
+ name = name.substring(0, name.indexOf("=")).trim();
+ }
+ if (name.endsWith(";")) name = name.substring(0, name.length - 1);
+ int oldOffset = _binaryOffset;
+
+ if (verboseLevel > 1) {
+ print("".padLeft(_depth * 2 + 1) +
+ " -> $instruction ($type) (@ $_binaryOffset) "
+ "($orgWhat @ $orgPosition)");
+ }
+
+ bool readNothingIsOk = false;
+ if (type.contains("[")) {
+ // The type is an array. Read into a List.
+ // Note that we need to know the length of that list.
+ String count = type.substring(type.indexOf("[") + 1, type.indexOf("]"));
+ type = type.substring(0, type.indexOf("["));
+ type = _lookupGenericType(typeNames, type, types);
+
+ int intCount = -1;
+ if (vars[count] != null && vars[count] is int) {
+ intCount = vars[count];
+ } else if (count.contains(".")) {
+ List<String> countData =
+ count.split(regExpSplit).map((s) => s.trim()).toList();
+ if (vars[countData[0]] != null) {
+ dynamic v = vars[countData[0]];
+ if (v is Map &&
+ countData[1] == "last" &&
+ v["items"] is List &&
+ v["items"].last is int) {
+ intCount = v["items"].last;
+ } else if (v is Map && v[countData[1]] != null) {
+ v = v[countData[1]];
+ if (v is Map && v[countData[2]] != null) {
+ v = v[countData[2]];
+ if (v is int) intCount = v;
+ } else if (v is int &&
+ countData.length == 4 &&
+ countData[2] == "+") {
+ intCount = v + int.parse(countData[3]);
+ }
+ } else {
+ throw "Unknown dot to int ($count)";
+ }
+ }
+ }
+
+ // Special-case that we know how many libraries we have.
+ if (intCount < 0 && type == "Library" && _depth == 1) {
+ intCount = numLibs;
+ }
+ if (intCount < 0 &&
+ type == "UInt32" &&
+ _depth == 2 &&
+ count == "libraryCount + 1") {
+ intCount = numLibs + 1;
+ }
+
+ if (intCount >= 0) {
+ readNothingIsOk = intCount == 0;
+ List<dynamic> value = new List(intCount);
+ for (int i = 0; i < intCount; ++i) {
+ int oldOffset2 = _binaryOffset;
+ value[i] = _readBinary(type);
+ if (_binaryOffset <= oldOffset2) {
+ throw "Didn't read anything for $type @ $_binaryOffset";
+ }
+ }
+ vars[name] = value;
+ } else {
+ throw "Array of unknown size ($count)";
+ }
+ } else {
+ // Not an array, read the single field recursively.
+ type = _lookupGenericType(typeNames, type, types);
+ dynamic value = _readBinary(type);
+ vars[name] = value;
+ _checkTag(instruction, value);
+ }
+ if (_binaryOffset <= oldOffset && !readNothingIsOk) {
+ throw "Didn't read anything for $type @ $_binaryOffset";
+ }
+
+ // Special case that when we read the string table we need to remember it
+ // to be able to lookup strings to read names properly later
+ // (private names has a library, public names does not).
+ if (what == "ComponentFile") {
+ if (name == "strings") _dillStringsPointer = vars[name];
+ }
+ }
+
+ --_depth;
+ return vars;
+ }
+
+ /// Verify, that if the instruction was a tag with a value
+ /// (e.g. "Byte tag = 5;"), then the value read was indeed the expected value
+ /// (5 in this example).
+ void _checkTag(String instruction, dynamic value) {
+ if (instruction.trim().startsWith("Byte tag = ")) {
+ String tag = instruction.trim().substring("Byte tag = ".length);
+ if (tag.contains("//")) {
+ tag = tag.substring(0, tag.indexOf("//")).trim();
+ }
+ if (tag.endsWith(";")) tag = tag.substring(0, tag.length - 1).trim();
+ int tagAsInt = int.tryParse(tag) ?? -1;
+ if (tagAsInt >= 0) {
+ if (tagAsInt != value) {
+ throw "Unexpected tag. "
+ "Expected $tagAsInt but got $value (around $_binaryOffset).";
+ }
+ }
+ }
+ }
+
+ /// Looks up any generics used, replacing the generic-name (if any) with the
+ /// actual type, e.g.
+ /// * ([], "UInt", []) into "UInt"
+ /// * (["T"], "T", ["Expression"]) into "Expression"
+ /// * (["T0", "T1"], "T0", ["FileOffset", "Expression"]) into "FileOffset"
+ String _lookupGenericType(
+ List<String> typeNames, String type, List<String> types) {
+ for (int i = 0; i < typeNames.length; ++i) {
+ if (typeNames[i] == type) {
+ type = types[i];
+ break;
+ }
+ }
+ return type;
+ }
+
+ /// Check if [what] is an [a], i.e. if [what] extends [a].
+ /// This method uses the [_extends] map and it is thus risky to use it before
+ /// the binary.md file has been read in entirety (because the field isn't
+ /// completely filled out yet).
+ bool _isA(String what, String a) {
+ String parent = what;
+ while (parent != null) {
+ if (parent == a) return true;
+ parent = _extends[parent];
+ }
+ return false;
+ }
+
+ /// Remaps the type by looking at tags, e.g. if asked to read an "Expression"
+ /// and the tag actually says "Block", return "Block" after checking that a
+ /// "Block" is actually an "Expression".
+ String _remapWhat(String what) {
+ Map<int, String> tagMap;
+ if (_isA(what, "Constant")) {
+ tagMap = constantTagToName;
+ } else {
+ tagMap = tagToName;
+ }
+
+ if (what == "Expression") {
+ if (tagMap[_dillContent[_binaryOffset]] != null) {
+ what = tagMap[_dillContent[_binaryOffset]];
+ if (!_isA(what, "Expression")) {
+ throw "Expected Expression but found $what";
+ }
+ } else {
+ throw "Unknown expression";
+ }
+ }
+ if (what == "IntegerLiteral") {
+ if (tagMap[_dillContent[_binaryOffset]] != null) {
+ what = tagMap[_dillContent[_binaryOffset]];
+ if (!_isA(what, "IntegerLiteral")) {
+ throw "Expected IntegerLiteral but found $what";
+ }
+ } else {
+ throw "Unknown IntegerLiteral";
+ }
+ }
+ if (what == "Statement") {
+ if (tagMap[_dillContent[_binaryOffset]] != null) {
+ what = tagMap[_dillContent[_binaryOffset]];
+ if (!_isA(what, "Statement")) {
+ throw "Expected Statement but found $what";
+ }
+ } else {
+ throw "Unknown Statement";
+ }
+ }
+ if (what == "Initializer") {
+ if (tagMap[_dillContent[_binaryOffset]] != null) {
+ what = tagMap[_dillContent[_binaryOffset]];
+ if (!_isA(what, "Initializer")) {
+ throw "Expected Initializer but found $what";
+ }
+ } else {
+ throw "Unknown Initializer";
+ }
+ }
+ if (what == "DartType") {
+ if (tagMap[_dillContent[_binaryOffset]] != null) {
+ what = tagMap[_dillContent[_binaryOffset]];
+ if (!_isA(what, "DartType")) {
+ throw "Expected DartType but found $what";
+ }
+ } else {
+ throw "Unknown DartType at $_binaryOffset "
+ "(${_dillContent[_binaryOffset]})";
+ }
+ }
+ if (what.startsWith("Option<")) {
+ if (tagMap[_dillContent[_binaryOffset]] != null &&
+ tagMap[_dillContent[_binaryOffset]].startsWith("Something<")) {
+ what = what.replaceFirst("Option<", "Something<");
+ }
+ }
+ if (what == "Constant") {
+ if (tagMap[_dillContent[_binaryOffset]] != null) {
+ what = tagMap[_dillContent[_binaryOffset]];
+ if (!_isA(what, "Constant")) {
+ throw "Expected Constant but found $what";
+ }
+ } else {
+ throw "Unknown Constant";
+ }
+ }
+
+ return what;
+ }
+
+ /// Read the "UInt" type as used in kernel. This is hard-coded.
+ /// Note that this decrements the [_depth] and increments the
+ /// [_binaryOffset] correctly.
+ int _readUint() {
+ int b = _dillContent[_binaryOffset];
+ if (b & 128 == 0) {
+ ++_binaryOffset;
+ --_depth;
+ return b;
+ }
+ if (b & 192 == 128) {
+ int value = (_dillContent[_binaryOffset] & 63) << 8 |
+ _dillContent[_binaryOffset + 1];
+ _binaryOffset += 2;
+ --_depth;
+ return value;
+ }
+ if (b & 192 == 192) {
+ int value = (_dillContent[_binaryOffset] & 63) << 24 |
+ _dillContent[_binaryOffset + 1] << 16 |
+ _dillContent[_binaryOffset + 2] << 8 |
+ _dillContent[_binaryOffset + 3];
+ _binaryOffset += 4;
+ --_depth;
+ return value;
+ }
+ throw "Unexpected UInt";
+ }
+
+ /// Read the "UInt43" type as used in kernel. This is hard-coded.
+ /// Note that this decrements the [_depth] and increments the
+ /// [_binaryOffset] correctly.
+ int _readUint32() {
+ int value = (_dillContent[_binaryOffset] & 63) << 24 |
+ _dillContent[_binaryOffset + 1] << 16 |
+ _dillContent[_binaryOffset + 2] << 8 |
+ _dillContent[_binaryOffset + 3];
+ _binaryOffset += 4;
+ --_depth;
+ return value;
+ }
+
+ /// Read the "UInt32" type as used in kernel. This is hard-coded.
+ /// This does not change any state.
+ int _peekUint32() {
+ return (_dillContent[_binaryOffset] & 63) << 24 |
+ _dillContent[_binaryOffset + 1] << 16 |
+ _dillContent[_binaryOffset + 2] << 8 |
+ _dillContent[_binaryOffset + 3];
+ }
+}
+
+class DillComparer {
+ Map<int, String> tagToName;
+ StringBuffer outputTo;
+
+ bool compare(List<int> a, List<int> b, String binaryMd,
+ [StringBuffer outputTo]) {
+ this.outputTo = outputTo;
+ bool printOnExit = false;
+ if (this.outputTo == null) {
+ this.outputTo = new StringBuffer();
+ printOnExit = true;
+ }
+ BinaryMdDillReader readerA = new BinaryMdDillReader(binaryMd, a);
+ dynamic aResult = readerA.attemptRead();
+ tagToName = readerA.tagToName;
+
+ BinaryMdDillReader readerB = new BinaryMdDillReader(binaryMd, b);
+ dynamic bResult = readerB.attemptRead();
+
+ bool result = _compareInternal(aResult, bResult);
+ if (printOnExit) print(outputTo);
+ return result;
+ }
+
+ bool _compareInternal(dynamic a, dynamic b) {
+ if (a.runtimeType != b.runtimeType) {
+ outputTo.writeln(
+ "Different runtime types (${a.runtimeType} and ${b.runtimeType})");
+ return false;
+ }
+ if (a is List) {
+ List listA = a;
+ List listB = b;
+ if (listA.length != listB.length) {
+ outputTo.writeln(
+ "Lists have different length (${listA.length} vs ${listB.length} "
+ "${_getTag(a)}");
+ return false;
+ }
+ for (int i = 0; i < listA.length; i++) {
+ if (!_compareInternal(listA[i], listB[i])) {
+ outputTo
+ .writeln("Lists have different values at index $i ${_getTag(a)}");
+ return false;
+ }
+ }
+ return true;
+ }
+
+ if (a is Map<String, dynamic>) {
+ Map<String, dynamic> mapA = a;
+ Map<String, dynamic> mapB = b;
+ for (String key in mapA.keys) {
+ dynamic valueA = mapA[key];
+ dynamic valueB = mapB[key];
+ if (!_compareInternal(valueA, valueB)) {
+ outputTo.writeln(
+ "Map with key '$key' has different values ${_getTag(a)}");
+ return false;
+ }
+ }
+ if (mapA.length != mapB.length) {
+ outputTo.writeln("Maps have different number of entries "
+ "(${mapA.length} vs ${mapB.length}). ${_getTag(a)}");
+ return false;
+ }
+ return true;
+ }
+
+ if (a is int) {
+ if (a != b) {
+ outputTo.writeln("Integers differ: $a vs $b");
+ return false;
+ }
+ return true;
+ }
+
+ throw "Unsupported: ${a.runtimeType}";
+ }
+
+ String _getTag(dynamic input) {
+ if (input is Map) {
+ dynamic tag = input["tag"];
+ if (tag != null) {
+ if (tagToName[tag] != null) {
+ return "(tag $tag, likely '${tagToName[tag]}')";
+ }
+ return "(tag $tag)";
+ }
+ }
+ return "";
+ }
+}
diff --git a/pkg/front_end/test/binary_md_vm_tags_and_version_test.dart b/pkg/front_end/test/binary_md_vm_tags_and_version_test.dart
new file mode 100644
index 0000000..5f30b25
--- /dev/null
+++ b/pkg/front_end/test/binary_md_vm_tags_and_version_test.dart
@@ -0,0 +1,204 @@
+// Copyright (c) 2019, 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' show File, Platform;
+
+import 'package:front_end/src/api_prototype/compiler_options.dart'
+ show DiagnosticMessage;
+
+import 'package:front_end/src/fasta/severity.dart' show Severity;
+
+import 'package:kernel/kernel.dart'
+ show Class, Component, ConstantExpression, Field, IntConstant, Library;
+
+import 'package:kernel/target/targets.dart' show NoneTarget, TargetFlags;
+
+import 'binary_md_dill_reader.dart' show BinaryMdDillReader;
+
+import 'incremental_load_from_dill_test.dart'
+ show getOptions, normalCompileToComponent;
+
+import 'utils/io_utils.dart' show computeRepoDir;
+
+const String maxSupported =
+ "static const uint32_t kMaxSupportedKernelFormatVersion = ";
+
+// Match stuff like "V(Nothing, 0)"
+final RegExp tagParser = new RegExp(r"V\((\w*),\s*(\d+)\)");
+
+// Match stuff like "kNullConstant = 0,"
+final RegExp constantTagParser = new RegExp(r"k(\w*)\s*=\s*(\d+)");
+
+main() async {
+ File binaryMd = new File("$repoDir/pkg/kernel/binary.md");
+ String binaryMdContent = binaryMd.readAsStringSync();
+
+ BinaryMdDillReader binaryMdReader =
+ new BinaryMdDillReader(binaryMdContent, []);
+ binaryMdReader.setup();
+
+ File vmTagFile = new File("$repoDir/runtime/vm/kernel_binary.h");
+ String vmTagContent = vmTagFile.readAsStringSync();
+ List<String> vmTagLines = vmTagContent.split("\n");
+ int vmVersion;
+ Map<int, String> vmTagToName = {};
+ Map<int, String> vmConstantTagToName = {};
+ for (int i = 0; i < vmTagLines.length; i++) {
+ String line = vmTagLines[i];
+ if (line.startsWith(maxSupported)) {
+ vmVersion = int.parse(line
+ .substring(line.indexOf(maxSupported) + maxSupported.length)
+ .substring(0, 2) // Assume version < 100 for now.
+ .trim());
+ } else if (line.startsWith("#define KERNEL_TAG_LIST(V)")) {
+ while (true) {
+ RegExpMatch match = tagParser.firstMatch(line);
+ if (match != null) {
+ int value = int.parse(match.group(2));
+ int end = value + 1;
+ if (uses8Tags(match.group(1))) {
+ end = value + 8;
+ }
+ for (int j = value; j < end; j++) {
+ vmTagToName[j] = match.group(1);
+ }
+ }
+ if (!vmTagLines[i].trim().endsWith(r"\")) {
+ break;
+ }
+ i++;
+ line = vmTagLines[i];
+ }
+ } else if (line.startsWith("enum ConstantTag {")) {
+ while (true) {
+ RegExpMatch match = constantTagParser.firstMatch(line);
+ if (match != null) {
+ vmConstantTagToName[int.parse(match.group(2))] = match.group(1);
+ }
+ if (vmTagLines[i].trim().startsWith("}")) {
+ break;
+ }
+ i++;
+ line = vmTagLines[i];
+ }
+ }
+ }
+
+ final Uri kernelTagUri = Uri.base.resolve("pkg/kernel/lib/binary/tag.dart");
+ Component c = await normalCompileToComponent(kernelTagUri,
+ options: getOptions()
+ ..target = new NoneTarget(new TargetFlags())
+ ..onDiagnostic = (DiagnosticMessage message) {
+ if (message.severity == Severity.error) {
+ print(message.plainTextFormatted.join('\n'));
+ }
+ });
+
+ Library tagLibrary =
+ c.libraries.firstWhere((l) => l.fileUri.pathSegments.last == "tag.dart");
+ Class tagClass = tagLibrary.classes.firstWhere((c) => c.name == "Tag");
+ Class constantTagClass =
+ tagLibrary.classes.firstWhere((c) => c.name == "ConstantTag");
+
+ int tagVersion;
+ for (TagCompare compareMe in [
+ new TagCompare(binaryMdReader.tagToName, binaryMdReader.version,
+ vmTagToName, vmVersion, tagClass),
+ new TagCompare(binaryMdReader.constantTagToName, binaryMdReader.version,
+ vmConstantTagToName, vmVersion, constantTagClass)
+ ]) {
+ Map<int, String> tagToName = {};
+ for (Field f in compareMe.tagClass.fields) {
+ // Class doesn't only contain tag stuff.
+ if (f.name.name.endsWith("Mask")) continue;
+ if (f.name.name.endsWith("HighBit")) continue;
+ if (f.name.name.endsWith("Bias")) continue;
+ if (f.name.name == "ComponentFile") continue;
+ ConstantExpression value = f.initializer;
+ IntConstant intConstant = value.constant;
+ int intValue = intConstant.value;
+ if (f.name.name == "BinaryFormatVersion") {
+ tagVersion = intValue;
+ continue;
+ }
+
+ int end = intValue + 1;
+ // There are a few special cases that takes up a total of 8 tags.
+ if (uses8Tags(f.name.name)) {
+ end = intValue + 8;
+ }
+ for (; intValue < end; intValue++) {
+ if (tagToName[intValue] != null) {
+ throw "Double entry for ${intValue}: "
+ "${f.name.name} and ${tagToName[intValue]}";
+ }
+ tagToName[intValue] = f.name.name;
+ }
+ }
+
+ Map<int, String> tagToNameMd = {};
+ for (MapEntry<int, String> entry in compareMe.mdTagToName.entries) {
+ if (entry.value.contains("<")) {
+ tagToNameMd[entry.key] =
+ entry.value.substring(0, entry.value.indexOf("<")).trim();
+ } else {
+ tagToNameMd[entry.key] = entry.value;
+ }
+ }
+
+ // Kernels tag.dart vs binary.mds tags.
+ for (int key in tagToNameMd.keys) {
+ String nameMd = tagToNameMd[key];
+ String name = tagToName[key];
+ if (nameMd == name) continue;
+ throw "$key: $nameMd vs $name";
+ }
+ for (int key in tagToName.keys) {
+ String nameMd = tagToNameMd[key];
+ String name = tagToName[key];
+ if (nameMd == name) continue;
+ throw "$key: $nameMd vs $name";
+ }
+ if (tagVersion != compareMe.mdVersion) {
+ throw "Version in tag.dart: $tagVersion; "
+ "version in binary.md: ${compareMe.mdVersion}";
+ }
+
+ // Kernels tag.dart vs the VMs tags.
+ // Here we only compare one way because the VM can have more (old) tags.
+ for (int key in tagToName.keys) {
+ String nameVm = compareMe.vmTagToName[key];
+ String name = tagToName[key];
+ if (nameVm == name) continue;
+ throw "$key: $nameVm vs $name";
+ }
+ if (tagVersion != compareMe.vmVersion) {
+ throw "Version in tag.dart: $tagVersion; "
+ "version in VM: ${compareMe.vmVersion}";
+ }
+ }
+
+ print("OK");
+}
+
+bool uses8Tags(String name) {
+ return name == "SpecializedVariableGet" ||
+ name == "SpecializedVariableSet" ||
+ name == "SpecializedIntLiteral";
+}
+
+final String repoDir = computeRepoDir();
+
+String get dartVm => Platform.executable;
+
+class TagCompare {
+ final Map<int, String> mdTagToName;
+ final int mdVersion;
+ final Map<int, String> vmTagToName;
+ final int vmVersion;
+ final Class tagClass;
+
+ TagCompare(this.mdTagToName, this.mdVersion, this.vmTagToName, this.vmVersion,
+ this.tagClass);
+}
diff --git a/pkg/front_end/test/constants/constant_test.dart b/pkg/front_end/test/constants/constant_test.dart
index 7fbee80..6bba0a7 100644
--- a/pkg/front_end/test/constants/constant_test.dart
+++ b/pkg/front_end/test/constants/constant_test.dart
@@ -13,8 +13,8 @@
InternalCompilerResult,
DataComputer,
FormattedMessage,
- cfeConstantUpdate2018Config,
createUriForFileName,
+ defaultCfeConfig,
onFailure,
runTestFor;
import 'package:front_end/src/testing/id_testing_utils.dart';
@@ -28,8 +28,7 @@
supportedMarkers: sharedMarkers,
createUriForFileName: createUriForFileName,
onFailure: onFailure,
- runTest: runTestFor(
- const ConstantsDataComputer(), [cfeConstantUpdate2018Config]));
+ runTest: runTestFor(const ConstantsDataComputer(), [defaultCfeConfig]));
}
class ConstantsDataComputer extends DataComputer<String> {
diff --git a/pkg/front_end/test/deps_test.dart b/pkg/front_end/test/deps_test.dart
new file mode 100644
index 0000000..4d9bf2f
--- /dev/null
+++ b/pkg/front_end/test/deps_test.dart
@@ -0,0 +1,144 @@
+import 'dart:io';
+
+import 'package:expect/expect.dart' show Expect;
+import 'package:front_end/src/api_prototype/compiler_options.dart';
+import 'package:front_end/src/base/processed_options.dart';
+import 'package:front_end/src/fasta/compiler_context.dart';
+import 'package:front_end/src/fasta/dill/dill_target.dart';
+import 'package:front_end/src/fasta/kernel/kernel_target.dart';
+import 'package:front_end/src/fasta/severity.dart';
+import 'package:front_end/src/fasta/ticker.dart';
+import 'package:front_end/src/fasta/uri_translator.dart';
+import 'package:kernel/kernel.dart';
+import 'package:kernel/target/targets.dart';
+import 'package:front_end/src/compute_platform_binaries_location.dart'
+ show computePlatformBinariesLocation;
+import "package:vm/target/vm.dart" show VmTarget;
+import 'utils/io_utils.dart' show computeRepoDirUri;
+
+final Uri repoDir = computeRepoDirUri();
+
+Set<String> whitelistedExternalDartFiles = {
+ "third_party/pkg/charcode/lib/ascii.dart",
+ "third_party/pkg_tested/package_config/lib/packages.dart",
+ "third_party/pkg_tested/package_config/lib/packages_file.dart",
+ "third_party/pkg_tested/package_config/lib/src/packages_impl.dart",
+ "third_party/pkg_tested/package_config/lib/src/util.dart",
+ // TODO(CFE-team): This file should not be included.
+ // The package isn't even in pubspec.yaml.
+ "pkg/meta/lib/meta.dart",
+};
+
+Future<void> main() async {
+ Ticker ticker = new Ticker(isVerbose: false);
+ CompilerOptions compilerOptions = getOptions();
+
+ Uri dotPackagesUri = repoDir.resolve(".packages");
+ if (!new File.fromUri(dotPackagesUri).existsSync()) {
+ throw "Couldn't find .packages";
+ }
+ compilerOptions.packagesFileUri = dotPackagesUri;
+
+ ProcessedOptions options = new ProcessedOptions(options: compilerOptions);
+
+ Uri frontendLibUri = repoDir.resolve("pkg/front_end/lib/");
+ List<FileSystemEntity> entities =
+ new Directory.fromUri(frontendLibUri).listSync(recursive: true);
+ for (FileSystemEntity entity in entities) {
+ if (entity is File && entity.path.endsWith(".dart")) {
+ options.inputs.add(entity.uri);
+ }
+ }
+
+ List<Uri> result = await CompilerContext.runWithOptions<List<Uri>>(options,
+ (CompilerContext c) async {
+ UriTranslator uriTranslator = await c.options.getUriTranslator();
+ DillTarget dillTarget =
+ new DillTarget(ticker, uriTranslator, c.options.target);
+ KernelTarget kernelTarget =
+ new KernelTarget(c.fileSystem, false, dillTarget, uriTranslator);
+ Uri platform = c.options.sdkSummary;
+ if (platform != null) {
+ var bytes = new File.fromUri(platform).readAsBytesSync();
+ var platformComponent = loadComponentFromBytes(bytes);
+ dillTarget.loader
+ .appendLibraries(platformComponent, byteCount: bytes.length);
+ }
+
+ kernelTarget.setEntryPoints(c.options.inputs);
+ await dillTarget.buildOutlines();
+ await kernelTarget.loader.buildOutlines();
+ return new List<Uri>.from(c.dependencies);
+ });
+
+ Set<Uri> otherDartUris = new Set<Uri>();
+ Set<Uri> otherNonDartUris = new Set<Uri>();
+ Set<Uri> frontEndUris = new Set<Uri>();
+ Set<Uri> kernelUris = new Set<Uri>();
+ Set<Uri> dartPlatformUris = new Set<Uri>();
+ Uri kernelUri = repoDir.resolve("pkg/kernel/");
+ Uri platformUri1 = repoDir.resolve("sdk/lib/");
+ Uri platformUri2 = repoDir.resolve("runtime/lib/");
+ Uri platformUri3 = repoDir.resolve("runtime/bin/");
+ for (Uri uri in result) {
+ if (uri.toString().startsWith(frontendLibUri.toString())) {
+ frontEndUris.add(uri);
+ } else if (uri.toString().startsWith(kernelUri.toString())) {
+ kernelUris.add(uri);
+ } else if (uri.toString().startsWith(platformUri1.toString()) ||
+ uri.toString().startsWith(platformUri2.toString()) ||
+ uri.toString().startsWith(platformUri3.toString())) {
+ dartPlatformUris.add(uri);
+ } else if (uri.toString().endsWith(".dart")) {
+ otherDartUris.add(uri);
+ } else {
+ otherNonDartUris.add(uri);
+ }
+ }
+
+ // * Everything in frontEndUris is okay --- the frontend can import itself.
+ // * Everything in kernel is okay --- the frontend is allowed to
+ // import package:kernel.
+ // * For other entries, remove whitelisted entries.
+ // * Everything else is an error.
+
+ // Remove white-listed non-dart files.
+ otherNonDartUris.remove(dotPackagesUri);
+ otherNonDartUris.remove(repoDir.resolve("sdk/lib/libraries.json"));
+
+ // Remove white-listed dart files.
+ for (String s in whitelistedExternalDartFiles) {
+ otherDartUris.remove(repoDir.resolve(s));
+ }
+
+ if (otherNonDartUris.isNotEmpty || otherDartUris.isNotEmpty) {
+ print("The following files was imported without being whitelisted:");
+ for (Uri uri in otherNonDartUris) {
+ print(" - $uri");
+ }
+ for (Uri uri in otherDartUris) {
+ print(" - $uri");
+ }
+ exitCode = 1;
+ }
+}
+
+CompilerOptions getOptions() {
+ // Compile sdk because when this is run from a lint it uses the checked-in sdk
+ // and we might not have a suitable compiled platform.dill file.
+ Uri sdkRoot = computePlatformBinariesLocation(forceBuildDir: true);
+ CompilerOptions options = new CompilerOptions()
+ ..sdkRoot = sdkRoot
+ ..compileSdk = true
+ ..target = new VmTarget(new TargetFlags())
+ ..librariesSpecificationUri = repoDir.resolve("sdk/lib/libraries.json")
+ ..omitPlatform = true
+ ..onDiagnostic = (DiagnosticMessage message) {
+ if (message.severity == Severity.error) {
+ Expect.fail(
+ "Unexpected error: ${message.plainTextFormatted.join('\n')}");
+ }
+ }
+ ..environmentDefines = const {};
+ return options;
+}
diff --git a/pkg/front_end/test/explicit_creation_test.dart b/pkg/front_end/test/explicit_creation_test.dart
new file mode 100644
index 0000000..d655ac1
--- /dev/null
+++ b/pkg/front_end/test/explicit_creation_test.dart
@@ -0,0 +1,270 @@
+// Copyright (c) 2019, 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:front_end/src/api_prototype/compiler_options.dart' as api;
+import 'package:front_end/src/api_prototype/file_system.dart' as api;
+import 'package:front_end/src/base/processed_options.dart';
+import 'package:front_end/src/compute_platform_binaries_location.dart'
+ show computePlatformBinariesLocation;
+import 'package:front_end/src/fasta/builder/builder.dart';
+import 'package:front_end/src/fasta/builder/declaration_builder.dart';
+import 'package:front_end/src/fasta/compiler_context.dart';
+import 'package:front_end/src/fasta/constant_context.dart';
+import 'package:front_end/src/fasta/dill/dill_target.dart';
+import 'package:front_end/src/fasta/fasta_codes.dart' as fasta;
+import 'package:front_end/src/fasta/kernel/body_builder.dart';
+import 'package:front_end/src/fasta/kernel/constness.dart';
+import 'package:front_end/src/fasta/kernel/kernel_target.dart';
+import 'package:front_end/src/fasta/severity.dart';
+import 'package:front_end/src/fasta/source/diet_listener.dart';
+import 'package:front_end/src/fasta/source/source_library_builder.dart';
+import 'package:front_end/src/fasta/source/source_loader.dart';
+import 'package:front_end/src/fasta/source/stack_listener.dart';
+import 'package:front_end/src/fasta/ticker.dart';
+import 'package:front_end/src/fasta/type_inference/type_inference_engine.dart';
+import 'package:front_end/src/fasta/type_inference/type_inferrer.dart';
+import 'package:front_end/src/fasta/uri_translator.dart';
+import 'package:front_end/src/scanner/token.dart';
+import 'package:kernel/class_hierarchy.dart';
+import 'package:kernel/core_types.dart';
+import 'package:kernel/kernel.dart';
+import 'package:kernel/target/targets.dart';
+import "package:vm/target/vm.dart" show VmTarget;
+
+final Uri repoDir = _computeRepoDir();
+
+Uri _computeRepoDir() {
+ ProcessResult result = Process.runSync(
+ 'git', ['rev-parse', '--show-toplevel'],
+ runInShell: true,
+ workingDirectory: new File.fromUri(Platform.script).parent.path);
+ String dirPath = (result.stdout as String).trim();
+ return new Directory(dirPath).uri;
+}
+
+Uri frontendLibUri;
+
+Future<void> main() async {
+ Ticker ticker = new Ticker(isVerbose: false);
+ api.CompilerOptions compilerOptions = getOptions();
+
+ Uri dotPackagesUri = repoDir.resolve(".packages");
+ if (!new File.fromUri(dotPackagesUri).existsSync()) {
+ throw "Couldn't find .packages";
+ }
+ compilerOptions.packagesFileUri = dotPackagesUri;
+
+ ProcessedOptions options = new ProcessedOptions(options: compilerOptions);
+
+ frontendLibUri = repoDir.resolve("pkg/front_end/lib/");
+ List<FileSystemEntity> entities =
+ new Directory.fromUri(frontendLibUri).listSync(recursive: true);
+ for (FileSystemEntity entity in entities) {
+ if (entity is File && entity.path.endsWith(".dart")) {
+ options.inputs.add(entity.uri);
+ }
+ }
+
+ Stopwatch stopwatch = new Stopwatch()..start();
+
+ await CompilerContext.runWithOptions<List<Uri>>(options,
+ (CompilerContext c) async {
+ UriTranslator uriTranslator = await c.options.getUriTranslator();
+ DillTarget dillTarget =
+ new DillTarget(ticker, uriTranslator, c.options.target);
+ KernelTarget kernelTarget =
+ new KernelTargetTest(c.fileSystem, false, dillTarget, uriTranslator);
+
+ Uri platform = c.options.sdkSummary;
+ if (platform != null) {
+ var bytes = new File.fromUri(platform).readAsBytesSync();
+ var platformComponent = loadComponentFromBytes(bytes);
+ dillTarget.loader
+ .appendLibraries(platformComponent, byteCount: bytes.length);
+ }
+
+ kernelTarget.setEntryPoints(c.options.inputs);
+ await dillTarget.buildOutlines();
+ await kernelTarget.buildOutlines();
+ await kernelTarget.buildComponent();
+ return null;
+ });
+
+ print("Done in ${stopwatch.elapsedMilliseconds} ms. "
+ "Found $errorCount errors.");
+}
+
+class KernelTargetTest extends KernelTarget {
+ KernelTargetTest(api.FileSystem fileSystem, bool includeComments,
+ DillTarget dillTarget, UriTranslator uriTranslator)
+ : super(fileSystem, includeComments, dillTarget, uriTranslator);
+
+ @override
+ SourceLoader createLoader() {
+ return new SourceLoaderTest(fileSystem, includeComments, this);
+ }
+}
+
+class SourceLoaderTest extends SourceLoader {
+ SourceLoaderTest(
+ api.FileSystem fileSystem, bool includeComments, KernelTarget target)
+ : super(fileSystem, includeComments, target);
+
+ @override
+ DietListener createDietListener(SourceLibraryBuilder library) {
+ return new DietListenerTest(
+ library, hierarchy, coreTypes, typeInferenceEngine);
+ }
+
+ BodyBuilder createBodyBuilderForOutlineExpression(
+ LibraryBuilder library,
+ DeclarationBuilder declarationBuilder,
+ ModifierBuilder member,
+ Scope scope,
+ Uri fileUri) {
+ return new BodyBuilderTest.forOutlineExpression(
+ library, declarationBuilder, member, scope, fileUri);
+ }
+
+ BodyBuilder createBodyBuilderForField(
+ FieldBuilder field, TypeInferrer typeInferrer) {
+ return new BodyBuilderTest.forField(field, typeInferrer);
+ }
+}
+
+class DietListenerTest extends DietListener {
+ DietListenerTest(SourceLibraryBuilder library, ClassHierarchy hierarchy,
+ CoreTypes coreTypes, TypeInferenceEngine typeInferenceEngine)
+ : super(library, hierarchy, coreTypes, typeInferenceEngine);
+
+ @override
+ StackListener createListenerInternal(
+ ModifierBuilder builder,
+ Scope memberScope,
+ Scope formalParameterScope,
+ bool isDeclarationInstanceMember,
+ VariableDeclaration extensionThis,
+ List<TypeParameter> extensionTypeParameters,
+ TypeInferrer typeInferrer,
+ ConstantContext constantContext) {
+ return new BodyBuilderTest(
+ libraryBuilder: libraryBuilder,
+ member: builder,
+ enclosingScope: memberScope,
+ formalParameterScope: formalParameterScope,
+ hierarchy: hierarchy,
+ coreTypes: coreTypes,
+ declarationBuilder: currentDeclaration,
+ isDeclarationInstanceMember: isDeclarationInstanceMember,
+ extensionThis: extensionThis,
+ extensionTypeParameters: extensionTypeParameters,
+ uri: uri,
+ typeInferrer: typeInferrer)
+ ..constantContext = constantContext;
+ }
+}
+
+class BodyBuilderTest extends BodyBuilder {
+ @override
+ BodyBuilderTest(
+ {libraryBuilder,
+ member,
+ enclosingScope,
+ formalParameterScope,
+ hierarchy,
+ coreTypes,
+ declarationBuilder,
+ isDeclarationInstanceMember,
+ extensionThis,
+ extensionTypeParameters,
+ uri,
+ typeInferrer})
+ : super(
+ libraryBuilder: libraryBuilder,
+ member: member,
+ enclosingScope: enclosingScope,
+ formalParameterScope: formalParameterScope,
+ hierarchy: hierarchy,
+ coreTypes: coreTypes,
+ declarationBuilder: declarationBuilder,
+ isDeclarationInstanceMember: isDeclarationInstanceMember,
+ extensionThis: extensionThis,
+ extensionTypeParameters: extensionTypeParameters,
+ uri: uri,
+ typeInferrer: typeInferrer);
+
+ @override
+ BodyBuilderTest.forField(FieldBuilder field, TypeInferrer typeInferrer)
+ : super.forField(field, typeInferrer);
+
+ @override
+ BodyBuilderTest.forOutlineExpression(
+ SourceLibraryBuilder library,
+ DeclarationBuilder declarationBuilder,
+ ModifierBuilder member,
+ Scope scope,
+ Uri fileUri)
+ : super.forOutlineExpression(
+ library, declarationBuilder, member, scope, fileUri);
+
+ @override
+ Expression buildConstructorInvocation(
+ TypeDeclarationBuilder type,
+ Token nameToken,
+ Token nameLastToken,
+ Arguments arguments,
+ String name,
+ List<UnresolvedType> typeArguments,
+ int charOffset,
+ Constness constness) {
+ Token maybeNewOrConst = nameToken.previous;
+ bool doReport = true;
+ if (maybeNewOrConst is KeywordToken) {
+ if (maybeNewOrConst.lexeme == "new" ||
+ maybeNewOrConst.lexeme == "const") {
+ doReport = false;
+ }
+ } else if (maybeNewOrConst is SimpleToken) {
+ if (maybeNewOrConst.lexeme == "@") {
+ doReport = false;
+ }
+ }
+ if (doReport && !uri.toString().startsWith(frontendLibUri.toString())) {
+ doReport = false;
+ }
+ if (doReport) {
+ addProblem(
+ fasta.templateUnspecified.withArguments("Should use new or const"),
+ nameToken.charOffset,
+ nameToken.length);
+ }
+ return super.buildConstructorInvocation(type, nameToken, nameLastToken,
+ arguments, name, typeArguments, charOffset, constness);
+ }
+}
+
+int errorCount = 0;
+
+api.CompilerOptions getOptions() {
+ // Compile sdk because when this is run from a lint it uses the checked-in sdk
+ // and we might not have a suitable compiled platform.dill file.
+ Uri sdkRoot = computePlatformBinariesLocation(forceBuildDir: true);
+ api.CompilerOptions options = new api.CompilerOptions()
+ ..sdkRoot = sdkRoot
+ ..compileSdk = true
+ ..target = new VmTarget(new TargetFlags())
+ ..librariesSpecificationUri = repoDir.resolve("sdk/lib/libraries.json")
+ ..omitPlatform = true
+ ..onDiagnostic = (api.DiagnosticMessage message) {
+ if (message.severity == Severity.error) {
+ print(message.plainTextFormatted.join('\n'));
+ errorCount++;
+ exitCode = 1;
+ }
+ }
+ ..environmentDefines = const {};
+ return options;
+}
diff --git a/pkg/front_end/test/extensions/data/ambiguous/lib1.dart b/pkg/front_end/test/extensions/data/ambiguous/lib1.dart
new file mode 100644
index 0000000..ae7f7b6
--- /dev/null
+++ b/pkg/front_end/test/extensions/data/ambiguous/lib1.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2019, 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.
+
+/*library: scope=[AmbiguousExtension1,AmbiguousExtension2,UnambiguousExtension1]*/
+
+/*class: AmbiguousExtension1:
+ builder-name=AmbiguousExtension1,
+ builder-onType=String,
+ extension-members=[
+ static ambiguousStaticMethod1=AmbiguousExtension1|ambiguousStaticMethod1],
+ extension-name=AmbiguousExtension1,
+ extension-onType=String
+*/
+extension AmbiguousExtension1 on String {
+ /*member: AmbiguousExtension1|ambiguousStaticMethod1:
+ builder-name=ambiguousStaticMethod1,
+ member-name=AmbiguousExtension1|ambiguousStaticMethod1
+ */
+ static void ambiguousStaticMethod1() {}
+}
+
+/*class: AmbiguousExtension2:
+ builder-name=AmbiguousExtension2,
+ builder-onType=String,
+ extension-members=[
+ static unambiguousStaticMethod1=AmbiguousExtension2|unambiguousStaticMethod1],
+ extension-name=AmbiguousExtension2,
+ extension-onType=String
+*/
+extension AmbiguousExtension2 on String {
+ /*member: AmbiguousExtension2|unambiguousStaticMethod1:
+ builder-name=unambiguousStaticMethod1,
+ member-name=AmbiguousExtension2|unambiguousStaticMethod1
+ */
+ static void unambiguousStaticMethod1() {}
+}
+
+/*class: UnambiguousExtension1:
+ builder-name=UnambiguousExtension1,
+ builder-onType=String,
+ extension-members=[
+ static ambiguousStaticMethod2=UnambiguousExtension1|ambiguousStaticMethod2],
+ extension-name=UnambiguousExtension1,
+ extension-onType=String
+*/
+extension UnambiguousExtension1 on String {
+ /*member: UnambiguousExtension1|ambiguousStaticMethod2:
+ builder-name=ambiguousStaticMethod2,
+ member-name=UnambiguousExtension1|ambiguousStaticMethod2
+ */
+ static void ambiguousStaticMethod2() {}
+}
\ No newline at end of file
diff --git a/pkg/front_end/test/extensions/data/ambiguous/lib2.dart b/pkg/front_end/test/extensions/data/ambiguous/lib2.dart
new file mode 100644
index 0000000..5958aa2
--- /dev/null
+++ b/pkg/front_end/test/extensions/data/ambiguous/lib2.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2019, 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.
+
+/*library: scope=[AmbiguousExtension1,AmbiguousExtension2,UnambiguousExtension2]*/
+
+/*class: AmbiguousExtension1:
+ builder-name=AmbiguousExtension1,
+ builder-onType=String,
+ extension-members=[
+ static ambiguousStaticMethod1=AmbiguousExtension1|ambiguousStaticMethod1],
+ extension-name=AmbiguousExtension1,
+ extension-onType=String
+*/
+extension AmbiguousExtension1 on String {
+ /*member: AmbiguousExtension1|ambiguousStaticMethod1:
+ builder-name=ambiguousStaticMethod1,
+ member-name=AmbiguousExtension1|ambiguousStaticMethod1
+ */
+ static void ambiguousStaticMethod1() {}
+}
+
+/*class: AmbiguousExtension2:
+ builder-name=AmbiguousExtension2,
+ builder-onType=String,
+ extension-members=[
+ static unambiguousStaticMethod2=AmbiguousExtension2|unambiguousStaticMethod2],
+ extension-name=AmbiguousExtension2,
+ extension-onType=String
+*/
+extension AmbiguousExtension2 on String {
+ /*member: AmbiguousExtension2|unambiguousStaticMethod2:
+ builder-name=unambiguousStaticMethod2,
+ member-name=AmbiguousExtension2|unambiguousStaticMethod2
+ */
+ static void unambiguousStaticMethod2() {}
+}
+
+/*class: UnambiguousExtension2:
+ builder-name=UnambiguousExtension2,
+ builder-onType=String,
+ extension-members=[
+ static ambiguousStaticMethod2=UnambiguousExtension2|ambiguousStaticMethod2],
+ extension-name=UnambiguousExtension2,
+ extension-onType=String
+*/
+extension UnambiguousExtension2 on String {
+ /*member: UnambiguousExtension2|ambiguousStaticMethod2:
+ builder-name=ambiguousStaticMethod2,
+ member-name=UnambiguousExtension2|ambiguousStaticMethod2
+ */
+ static void ambiguousStaticMethod2() {}
+}
\ No newline at end of file
diff --git a/pkg/front_end/test/extensions/data/ambiguous/main.dart b/pkg/front_end/test/extensions/data/ambiguous/main.dart
new file mode 100644
index 0000000..f4cef0c
--- /dev/null
+++ b/pkg/front_end/test/extensions/data/ambiguous/main.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2019, 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.
+
+/*library: scope=[
+ lib1.dart.AmbiguousExtension1,
+ lib1.dart.AmbiguousExtension2,
+ lib1.dart.UnambiguousExtension1,
+ lib2.dart.AmbiguousExtension1,
+ lib2.dart.AmbiguousExtension2,
+ lib2.dart.UnambiguousExtension2]
+*/
+
+import 'lib1.dart';
+import 'lib2.dart';
+
+main() {
+ /*error: errors=['AmbiguousExtension1' is imported from both 'org-dartlang-test:///a/b/c/lib1.dart' and 'org-dartlang-test:///a/b/c/lib2.dart'.]*/
+ AmbiguousExtension1.ambiguousStaticMethod1();
+ /*error: errors=['AmbiguousExtension2' is imported from both 'org-dartlang-test:///a/b/c/lib1.dart' and 'org-dartlang-test:///a/b/c/lib2.dart'.]*/
+ AmbiguousExtension2.unambiguousStaticMethod1();
+ UnambiguousExtension1.ambiguousStaticMethod2();
+ UnambiguousExtension2.ambiguousStaticMethod2();
+}
diff --git a/pkg/front_end/test/extensions/data/explicit_this.dart b/pkg/front_end/test/extensions/data/explicit_this.dart
index b684007..735e7d6 100644
--- a/pkg/front_end/test/extensions/data/explicit_this.dart
+++ b/pkg/front_end/test/extensions/data/explicit_this.dart
@@ -2,6 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+/*library: scope=[A2]*/
+
class A1 {
Object field;
void method1() {}
@@ -13,7 +15,10 @@
extension-members=[
method2=A2|method2,
method3=A2|method3,
- method4=A2|method4],
+ method4=A2|method4,
+ tearoff method2=A2|get#method2,
+ tearoff method3=A2|get#method3,
+ tearoff method4=A2|get#method4],
extension-name=A2,
extension-onType=A1
*/
@@ -26,23 +31,44 @@
*/
void method2() => this.method1();
+ /*member: A2|get#method2:
+ builder-name=method2,
+ builder-params=[#this],
+ member-name=A2|get#method2,
+ member-params=[#this]
+ */
+
/*member: A2|method3:
builder-name=method3,
builder-params=[#this],
member-name=A2|method3,
member-params=[#this]
- */
+ */
Object method3() => this.field;
+ /*member: A2|get#method3:
+ builder-name=method3,
+ builder-params=[#this],
+ member-name=A2|get#method3,
+ member-params=[#this]
+ */
+
/*member: A2|method4:
- builder-name=method4,
- builder-params=[#this,o],
- member-name=A2|method4,
- member-params=[#this,o]
- */
+ builder-name=method4,
+ builder-params=[#this,o],
+ member-name=A2|method4,
+ member-params=[#this,o]
+ */
void method4(Object o) {
this.field = o;
}
+
+ /*member: A2|get#method4:
+ builder-name=method4,
+ builder-params=[#this,o],
+ member-name=A2|get#method4,
+ member-params=[#this]
+ */
}
main() {
diff --git a/pkg/front_end/test/extensions/data/export_unnamed/lib.dart b/pkg/front_end/test/extensions/data/export_unnamed/lib.dart
new file mode 100644
index 0000000..04d4c90
--- /dev/null
+++ b/pkg/front_end/test/extensions/data/export_unnamed/lib.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2019, 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.
+
+/*library: scope=[NamedExtension,_extension#0]*/
+
+/*class: _extension#0:
+ builder-name=_extension#0,
+ builder-onType=String,
+ extension-members=[static staticMethod=_extension#0|staticMethod],
+ extension-name=_extension#0,
+ extension-onType=String
+*/
+extension on String {
+ /*member: _extension#0|staticMethod:
+ builder-name=staticMethod,
+ member-name=_extension#0|staticMethod
+ */
+ static void staticMethod() {}
+}
+
+/*class: NamedExtension:
+ builder-name=NamedExtension,
+ builder-onType=String,
+ extension-members=[static staticMethod=NamedExtension|staticMethod],
+ extension-name=NamedExtension,
+ extension-onType=String
+*/
+extension NamedExtension on String {
+ /*member: NamedExtension|staticMethod:
+ builder-name=staticMethod,
+ member-name=NamedExtension|staticMethod
+ */
+ static void staticMethod() {}
+}
diff --git a/pkg/front_end/test/extensions/data/export_unnamed/main.dart b/pkg/front_end/test/extensions/data/export_unnamed/main.dart
new file mode 100644
index 0000000..01ddd37
--- /dev/null
+++ b/pkg/front_end/test/extensions/data/export_unnamed/main.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2019, 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.
+
+/*library: scope=[lib.dart.NamedExtension]*/
+
+import 'lib.dart';
+
+main() {
+ NamedExtension.staticMethod();
+}
diff --git a/pkg/front_end/test/extensions/data/extension_on_type_variable.dart b/pkg/front_end/test/extensions/data/extension_on_type_variable.dart
index 44f9af1..0c8613f 100644
--- a/pkg/front_end/test/extensions/data/extension_on_type_variable.dart
+++ b/pkg/front_end/test/extensions/data/extension_on_type_variable.dart
@@ -2,11 +2,15 @@
// 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.
+/*library: scope=[GeneralGeneric]*/
+
/*class: GeneralGeneric:
builder-name=GeneralGeneric,
builder-onType=T,
builder-type-params=[T],
- extension-members=[method=GeneralGeneric|method],
+ extension-members=[
+ method=GeneralGeneric|method,
+ tearoff method=GeneralGeneric|get#method],
extension-name=GeneralGeneric,
extension-onType=T,
extension-type-params=[T]
@@ -18,9 +22,18 @@
builder-type-params=[T],
member-name=GeneralGeneric|method,
member-params=[#this],
- member-type-params=[#T]
+ member-type-params=[T]
*/
T method() => this;
+
+ /*member: GeneralGeneric|get#method:
+ builder-name=method,
+ builder-params=[#this],
+ builder-type-params=[T],
+ member-name=GeneralGeneric|get#method,
+ member-params=[#this],
+ member-type-params=[T]
+ */
}
main() {
diff --git a/pkg/front_end/test/extensions/data/implicit_this.dart b/pkg/front_end/test/extensions/data/implicit_this.dart
index 9a9e7de..95e1fb3 100644
--- a/pkg/front_end/test/extensions/data/implicit_this.dart
+++ b/pkg/front_end/test/extensions/data/implicit_this.dart
@@ -2,6 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+/*library: scope=[A2]*/
+
class A1 {
Object field;
void method1() {}
@@ -13,7 +15,10 @@
extension-members=[
method2=A2|method2,
method3=A2|method3,
- method4=A2|method4],
+ method4=A2|method4,
+ tearoff method2=A2|get#method2,
+ tearoff method3=A2|get#method3,
+ tearoff method4=A2|get#method4],
extension-name=A2,
extension-onType=A1
*/
@@ -26,6 +31,12 @@
*/
void method2() => method1();
+ /*member: A2|get#method2:
+ builder-name=method2,
+ builder-params=[#this],
+ member-name=A2|get#method2,member-params=[#this]
+ */
+
/*member: A2|method3:
builder-name=method3,
builder-params=[#this],
@@ -34,6 +45,13 @@
*/
Object method3() => field;
+ /*member: A2|get#method3:
+ builder-name=method3,
+ builder-params=[#this],
+ member-name=A2|get#method3,
+ member-params=[#this]
+ */
+
/*member: A2|method4:
builder-name=method4,
builder-params=[#this,o],
@@ -43,6 +61,13 @@
void method4(Object o) {
field = o;
}
+
+ /*member: A2|get#method4:
+ builder-name=method4,
+ builder-params=[#this,o],
+ member-name=A2|get#method4,
+ member-params=[#this]
+ */
}
main() {
diff --git a/pkg/front_end/test/extensions/data/instance_members.dart b/pkg/front_end/test/extensions/data/instance_members.dart
index 35463d5..1c02c85 100644
--- a/pkg/front_end/test/extensions/data/instance_members.dart
+++ b/pkg/front_end/test/extensions/data/instance_members.dart
@@ -2,6 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+/*library: scope=[A2,B2]*/
+
class A1 {}
/*class: A2:
@@ -11,7 +13,11 @@
method1=A2|method1,
method2=A2|method2,
method3=A2|method3,
- method4=A2|method4],
+ method4=A2|method4,
+ tearoff method1=A2|get#method1,
+ tearoff method2=A2|get#method2,
+ tearoff method3=A2|get#method3,
+ tearoff method4=A2|get#method4],
extension-name=A2,
extension-onType=A1
*/
@@ -26,6 +32,13 @@
return this;
}
+ /*member: A2|get#method1:
+ builder-name=method1,
+ builder-params=[#this],
+ member-name=A2|get#method1,
+ member-params=[#this]
+ */
+
/*member: A2|method2:
builder-name=method2,
builder-params=[#this,o],
@@ -39,6 +52,14 @@
return this;
}
+ /*member: A2|get#method2:
+ builder-name=method2,
+ builder-params=[#this,o],
+ builder-type-params=[T],
+ member-name=A2|get#method2,
+ member-params=[#this]
+ */
+
/*member: A2|method3:
builder-name=method3,
builder-params=[#this],
@@ -54,6 +75,15 @@
return this;
}
+ /*member: A2|get#method3:
+ builder-name=method3,
+ builder-params=[#this],
+ builder-pos-params=[o],
+ builder-type-params=[T],
+ member-name=A2|get#method3,
+ member-params=[#this]
+ */
+
/*member: A2|method4:
builder-name=method4,
builder-params=[#this],
@@ -68,6 +98,15 @@
print(o);
return this;
}
+
+ /*member: A2|get#method4:
+ builder-name=method4,
+ builder-named-params=[o],
+ builder-params=[#this],
+ builder-type-params=[T],
+ member-name=A2|get#method4,
+ member-params=[#this]
+ */
}
class B1<T> {}
@@ -78,7 +117,9 @@
builder-type-params=[T],
extension-members=[
method1=B2|method1,
- method2=B2|method2],
+ method2=B2|method2,
+ tearoff method1=B2|get#method1,
+ tearoff method2=B2|get#method2],
extension-name=B2,
extension-onType=B1<T>,
extension-type-params=[T]
@@ -90,24 +131,42 @@
builder-type-params=[T],
member-name=B2|method1,
member-params=[#this],
- member-type-params=[#T]
+ member-type-params=[T]
*/
B1<T> method1() {
return this;
}
+ /*member: B2|get#method1:
+ builder-name=method1,
+ builder-params=[#this],
+ builder-type-params=[T],
+ member-name=B2|get#method1,
+ member-params=[#this],
+ member-type-params=[T]
+ */
+
/*member: B2|method2:
builder-name=method2,
builder-params=[#this,o],
builder-type-params=[T,S],
member-name=B2|method2,
member-params=[#this,o],
- member-type-params=[#T,S]
+ member-type-params=[T,S]
*/
B1<T> method2<S>(S o) {
print(o);
return this;
}
+
+ /*member: B2|get#method2:
+ builder-name=method2,
+ builder-params=[#this,o],
+ builder-type-params=[T,S],
+ member-name=B2|get#method2,
+ member-params=[#this],
+ member-type-params=[T]
+ */
}
main() {}
\ No newline at end of file
diff --git a/pkg/front_end/test/extensions/data/named_declarations.dart b/pkg/front_end/test/extensions/data/named_declarations.dart
index c9e7c08..fa16eec 100644
--- a/pkg/front_end/test/extensions/data/named_declarations.dart
+++ b/pkg/front_end/test/extensions/data/named_declarations.dart
@@ -2,6 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+/*library: scope=[A2,B2,B3,B4]*/
+
class A1 {}
/*class: A2:
diff --git a/pkg/front_end/test/extensions/data/other_kinds.dart b/pkg/front_end/test/extensions/data/other_kinds.dart
index 72f4547..cab0879 100644
--- a/pkg/front_end/test/extensions/data/other_kinds.dart
+++ b/pkg/front_end/test/extensions/data/other_kinds.dart
@@ -2,6 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+/*library: scope=[A2]*/
+
class A1 {
int _instanceField;
int getInstanceField() => _instanceField;
diff --git a/pkg/front_end/test/extensions/data/reexport/lib.dart b/pkg/front_end/test/extensions/data/reexport/lib.dart
new file mode 100644
index 0000000..f38ec65
--- /dev/null
+++ b/pkg/front_end/test/extensions/data/reexport/lib.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2019, 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.
+
+export 'lib1.dart';
+/*error: errors=['ClashingExtension' is exported from both 'org-dartlang-test:///a/b/c/lib1.dart' and 'org-dartlang-test:///a/b/c/lib2.dart'.]*/
+export 'lib2.dart';
diff --git a/pkg/front_end/test/extensions/data/reexport/lib1.dart b/pkg/front_end/test/extensions/data/reexport/lib1.dart
new file mode 100644
index 0000000..d3529cb
--- /dev/null
+++ b/pkg/front_end/test/extensions/data/reexport/lib1.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2019, 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.
+
+/*library: scope=[ClashingExtension,UniqueExtension1]*/
+
+/*class: ClashingExtension:
+ builder-name=ClashingExtension,
+ builder-onType=String,
+ extension-members=[static staticMethod=ClashingExtension|staticMethod],
+ extension-name=ClashingExtension,
+ extension-onType=String
+*/
+extension ClashingExtension on String {
+ /*member: ClashingExtension|staticMethod:
+ builder-name=staticMethod,
+ member-name=ClashingExtension|staticMethod
+ */
+ static staticMethod() {}
+}
+
+
+/*class: UniqueExtension1:
+ builder-name=UniqueExtension1,
+ builder-onType=String,
+ extension-members=[static staticMethod=UniqueExtension1|staticMethod],
+ extension-name=UniqueExtension1,
+ extension-onType=String
+*/
+extension UniqueExtension1 on String {
+ /*member: UniqueExtension1|staticMethod:
+ builder-name=staticMethod,
+ member-name=UniqueExtension1|staticMethod
+ */
+ static staticMethod() {}
+}
\ No newline at end of file
diff --git a/pkg/front_end/test/extensions/data/reexport/lib2.dart b/pkg/front_end/test/extensions/data/reexport/lib2.dart
new file mode 100644
index 0000000..b0d9665
--- /dev/null
+++ b/pkg/front_end/test/extensions/data/reexport/lib2.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2019, 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.
+
+/*library: scope=[ClashingExtension,UniqueExtension2]*/
+
+/*class: ClashingExtension:
+ builder-name=ClashingExtension,
+ builder-onType=String,
+ extension-members=[static staticMethod=ClashingExtension|staticMethod],
+ extension-name=ClashingExtension,
+ extension-onType=String
+*/
+extension ClashingExtension on String {
+ /*member: ClashingExtension|staticMethod:
+ builder-name=staticMethod,
+ member-name=ClashingExtension|staticMethod
+ */
+ static staticMethod() {}
+}
+
+/*class: UniqueExtension2:
+ builder-name=UniqueExtension2,
+ builder-onType=String,
+ extension-members=[static staticMethod=UniqueExtension2|staticMethod],
+ extension-name=UniqueExtension2,
+ extension-onType=String
+*/
+extension UniqueExtension2 on String {
+ /*member: UniqueExtension2|staticMethod:
+ builder-name=staticMethod,
+ member-name=UniqueExtension2|staticMethod
+ */
+ static staticMethod() {}
+}
\ No newline at end of file
diff --git a/pkg/front_end/test/extensions/data/reexport/main.dart b/pkg/front_end/test/extensions/data/reexport/main.dart
new file mode 100644
index 0000000..b5c8603
--- /dev/null
+++ b/pkg/front_end/test/extensions/data/reexport/main.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2019, 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.
+
+/*library: scope=[lib1.dart.UniqueExtension1,lib2.dart.UniqueExtension2]*/
+
+import 'lib.dart';
+
+main() {
+ /*error: errors=['ClashingExtension' is exported from both 'org-dartlang-test:///a/b/c/lib1.dart' and 'org-dartlang-test:///a/b/c/lib2.dart'.]*/
+ ClashingExtension.staticMethod();
+ UniqueExtension1.staticMethod();
+ UniqueExtension2.staticMethod();
+}
diff --git a/pkg/front_end/test/extensions/data/show_hide/lib1.dart b/pkg/front_end/test/extensions/data/show_hide/lib1.dart
new file mode 100644
index 0000000..7790aeb
--- /dev/null
+++ b/pkg/front_end/test/extensions/data/show_hide/lib1.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2019, 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.
+
+/*library: scope=[HiddenExtension1,ShownExtension1]*/
+
+/*class: ShownExtension1:
+ builder-name=ShownExtension1,
+ builder-onType=String,
+ extension-members=[static staticMethod=ShownExtension1|staticMethod],
+ extension-name=ShownExtension1,
+ extension-onType=String
+*/
+extension ShownExtension1 on String {
+ /*member: ShownExtension1|staticMethod:
+ builder-name=staticMethod,
+ member-name=ShownExtension1|staticMethod
+ */
+ static void staticMethod() {}
+}
+
+/*class: HiddenExtension1:
+ builder-name=HiddenExtension1,
+ builder-onType=String,
+ extension-members=[static staticMethod=HiddenExtension1|staticMethod],
+ extension-name=HiddenExtension1,
+ extension-onType=String
+*/
+extension HiddenExtension1 on String {
+ /*member: HiddenExtension1|staticMethod:
+ builder-name=staticMethod,
+ member-name=HiddenExtension1|staticMethod
+ */
+ static void staticMethod() {}
+}
\ No newline at end of file
diff --git a/pkg/front_end/test/extensions/data/show_hide/lib2.dart b/pkg/front_end/test/extensions/data/show_hide/lib2.dart
new file mode 100644
index 0000000..5c9d793
--- /dev/null
+++ b/pkg/front_end/test/extensions/data/show_hide/lib2.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2019, 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.
+
+/*library: scope=[HiddenExtension2,ShownExtension2]*/
+
+/*class: HiddenExtension2:
+ builder-name=HiddenExtension2,
+ builder-onType=String,
+ extension-members=[static staticMethod=HiddenExtension2|staticMethod],
+ extension-name=HiddenExtension2,
+ extension-onType=String
+*/
+extension HiddenExtension2 on String {
+ /*member: HiddenExtension2|staticMethod:
+ builder-name=staticMethod,
+ member-name=HiddenExtension2|staticMethod
+ */
+ static void staticMethod() {}
+}
+
+/*class: ShownExtension2:
+ builder-name=ShownExtension2,
+ builder-onType=String,
+ extension-members=[static staticMethod=ShownExtension2|staticMethod],
+ extension-name=ShownExtension2,
+ extension-onType=String
+*/
+extension ShownExtension2 on String {
+ /*member: ShownExtension2|staticMethod:
+ builder-name=staticMethod,
+ member-name=ShownExtension2|staticMethod
+ */
+ static void staticMethod() {}
+}
\ No newline at end of file
diff --git a/pkg/front_end/test/extensions/data/show_hide/main.dart b/pkg/front_end/test/extensions/data/show_hide/main.dart
new file mode 100644
index 0000000..2e2e978
--- /dev/null
+++ b/pkg/front_end/test/extensions/data/show_hide/main.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2019, 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.
+
+/*library: scope=[lib1.dart.ShownExtension1,lib2.dart.ShownExtension2]*/
+
+import 'lib1.dart' show ShownExtension1;
+import 'lib2.dart' hide HiddenExtension2;
+
+main() {
+ ShownExtension1.staticMethod();
+ /*error: errors=[Getter not found: 'HiddenExtension1'.]*/
+ HiddenExtension1.staticMethod();
+ ShownExtension2.staticMethod();
+ /*error: errors=[Getter not found: 'HiddenExtension2'.]*/
+ HiddenExtension2.staticMethod();
+}
diff --git a/pkg/front_end/test/extensions/data/static_members.dart b/pkg/front_end/test/extensions/data/static_members.dart
index aeda9d9..cd426fa 100644
--- a/pkg/front_end/test/extensions/data/static_members.dart
+++ b/pkg/front_end/test/extensions/data/static_members.dart
@@ -2,6 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+/*library: scope=[A2,B2]*/
+
class A1 {}
/*class: A2:
diff --git a/pkg/front_end/test/extensions/data/super.dart b/pkg/front_end/test/extensions/data/super.dart
index 21bd03a..a4d838d 100644
--- a/pkg/front_end/test/extensions/data/super.dart
+++ b/pkg/front_end/test/extensions/data/super.dart
@@ -2,6 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+/*library: scope=[A2]*/
+
class A1 {
method1() {}
}
@@ -9,7 +11,9 @@
/*class: A2:
builder-name=A2,
builder-onType=A1,
- extension-members=[method2=A2|method2],
+ extension-members=[
+ method2=A2|method2,
+ tearoff method2=A2|get#method2],
extension-name=A2,
extension-onType=A1
*/
@@ -23,6 +27,13 @@
method2() {
/*error: errors=[SuperAsIdentifier]*/ super.method1();
}
+
+ /*member: A2|get#method2:
+ builder-name=method2,
+ builder-params=[#this],
+ member-name=A2|get#method2,
+ member-params=[#this]
+ */
}
main() {
diff --git a/pkg/front_end/test/extensions/data/type_variables.dart b/pkg/front_end/test/extensions/data/type_variables.dart
index 9283d71..5a421a1 100644
--- a/pkg/front_end/test/extensions/data/type_variables.dart
+++ b/pkg/front_end/test/extensions/data/type_variables.dart
@@ -2,6 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+/*library: scope=[A2,A3,A4]*/
+
class A1<T> {}
/*class: A2:
@@ -10,7 +12,9 @@
builder-type-params=[T],
extension-members=[
method1=A2|method1,
- method2=A2|method2],
+ method2=A2|method2,
+ tearoff method1=A2|get#method1,
+ tearoff method2=A2|get#method2],
extension-name=A2,
extension-onType=A1<T>,
extension-type-params=[T]
@@ -22,27 +26,84 @@
builder-type-params=[T,S extends T],
member-name=A2|method1,
member-params=[#this],
- member-type-params=[#T,S extends #T]
+ member-type-params=[T,S extends T]
*/
A1<T> method1<S extends T>() {
return this;
}
+ /*member: A2|get#method1:
+ builder-name=method1,
+ builder-params=[#this],
+ builder-type-params=[T,S extends T],
+ member-name=A2|get#method1,
+ member-params=[#this],
+ member-type-params=[T]
+ */
+
/*member: A2|method2:
builder-name=method2,
builder-params=[#this,o],
builder-type-params=[T,S extends A1<T>],
member-name=A2|method2,
member-params=[#this,o],
- member-type-params=[#T,S extends A1<#T>]
+ member-type-params=[T,S extends A1<T>]
*/
A1<T> method2<S extends A1<T>>(S o) {
print(o);
return this;
}
+
+ /*member: A2|get#method2:
+ builder-name=method2,
+ builder-params=[#this,o],
+ builder-type-params=[T,S extends A1<T>],
+ member-name=A2|get#method2,
+ member-params=[#this],
+ member-type-params=[T]
+ */
}
-// TODO(johnniwinther): Support F-bounded extensions. Currently the type
-// variable is not recognized as a type within the bound.
+/*class: A3:
+ builder-name=A3,
+ builder-onType=A1<T>,
+ builder-type-params=[T extends A1<T>],
+ extension-name=A3,
+ extension-onType=A1<T>,
+ extension-type-params=[T extends A1<T>]
+*/
+extension A3<T extends A1<T>> on A1<T> {
+}
+
+/*class: A4:
+ builder-name=A4,
+ builder-onType=A1<T>,
+ builder-type-params=[T],
+ extension-members=[
+ method=A4|method,
+ tearoff method=A4|get#method],
+ extension-name=A4,
+ extension-onType=A1<T>,
+ extension-type-params=[T]
+*/
+extension A4<T> on A1<T> {
+ /*member: A4|method:
+ builder-name=method,
+ builder-params=[#this],
+ builder-type-params=[T,T],
+ member-name=A4|method,
+ member-params=[#this],
+ member-type-params=[#T,T]*/
+ method<T>() {}
+
+ /*member: A4|get#method:
+ builder-name=method,
+ builder-params=[#this],
+ builder-type-params=[T,T],
+ member-name=A4|get#method,
+ member-params=[#this],
+ member-type-params=[#T]
+ */
+}
main() {}
\ No newline at end of file
diff --git a/pkg/front_end/test/extensions/data/unnamed_declarations.dart b/pkg/front_end/test/extensions/data/unnamed_declarations.dart
index d36cf3d..eab0143 100644
--- a/pkg/front_end/test/extensions/data/unnamed_declarations.dart
+++ b/pkg/front_end/test/extensions/data/unnamed_declarations.dart
@@ -2,101 +2,152 @@
// 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.
+/*library: scope=[_extension#0,_extension#1,_extension#2,_extension#3,_extension#4]*/
+
class A1 {}
-/*class: extension#0:
- builder-name=extension#0,
+/*class: _extension#0:
+ builder-name=_extension#0,
builder-onType=A1,
- extension-members=[method=extension#0|method],
- extension-name=extension#0,
+ extension-members=[
+ method=_extension#0|method,
+ tearoff method=_extension#0|get#method],
+ extension-name=_extension#0,
extension-onType=A1
*/
extension on A1 {
- /*member: extension#0|method:
+ /*member: _extension#0|method:
builder-name=method,
builder-params=[#this],
- member-name=extension#0|method,
+ member-name=_extension#0|method,
member-params=[#this]
*/
method() {}
+
+ /*member: _extension#0|get#method:
+ builder-name=method,
+ builder-params=[#this],
+ member-name=_extension#0|get#method,
+ member-params=[#this]
+ */
}
-/*class: extension#1:
- builder-name=extension#1,
+/*class: _extension#1:
+ builder-name=_extension#1,
builder-onType=A1,
- extension-members=[method=extension#1|method],
- extension-name=extension#1,
+ extension-members=[
+ method=_extension#1|method,
+ tearoff method=_extension#1|get#method],
+ extension-name=_extension#1,
extension-onType=A1
*/
extension on A1 {
- /*member: extension#1|method:
+ /*member: _extension#1|method:
builder-name=method,
builder-params=[#this],
- member-name=extension#1|method,
+ member-name=_extension#1|method,
member-params=[#this]
*/
method() {}
+
+ /*member: _extension#1|get#method:
+ builder-name=method,
+ builder-params=[#this],
+ member-name=_extension#1|get#method,
+ member-params=[#this]
+ */
}
class B1<T> {}
-/*class: extension#2:
- builder-name=extension#2,
+/*class: _extension#2:
+ builder-name=_extension#2,
builder-onType=B1<T>,
builder-type-params=[T],
- extension-members=[method=extension#2|method],
- extension-name=extension#2,
+ extension-members=[
+ method=_extension#2|method,
+ tearoff method=_extension#2|get#method],
+ extension-name=_extension#2,
extension-onType=B1<T>,
extension-type-params=[T]
*/
extension <T> on B1<T> {
- /*member: extension#2|method:
+ /*member: _extension#2|method:
builder-name=method,
builder-params=[#this],
builder-type-params=[T],
- member-name=extension#2|method,
+ member-name=_extension#2|method,
member-params=[#this],
- member-type-params=[#T]
+ member-type-params=[T]
*/
method() {}
+
+ /*member: _extension#2|get#method:
+ builder-name=method,
+ builder-params=[#this],
+ builder-type-params=[T],
+ member-name=_extension#2|get#method,
+ member-params=[#this],
+ member-type-params=[T]
+ */
}
-/*class: extension#3:
- builder-name=extension#3,
+/*class: _extension#3:
+ builder-name=_extension#3,
builder-onType=B1<A1>,
- extension-members=[method=extension#3|method],
- extension-name=extension#3,
+ extension-members=[
+ method=_extension#3|method,
+ tearoff method=_extension#3|get#method],
+ extension-name=_extension#3,
extension-onType=B1<A1>
*/
extension on B1<A1> {
- /*member: extension#3|method:
+ /*member: _extension#3|method:
builder-name=method,
builder-params=[#this],
- member-name=extension#3|method,
+ member-name=_extension#3|method,
member-params=[#this]
*/
method() {}
+
+ /*member: _extension#3|get#method:
+ builder-name=method,
+ builder-params=[#this],
+ member-name=_extension#3|get#method,
+ member-params=[#this]
+ */
}
-/*class: extension#4:
- builder-name=extension#4,
+/*class: _extension#4:
+ builder-name=_extension#4,
builder-onType=B1<T>,
builder-type-params=[T extends A1],
- extension-members=[method=extension#4|method],
- extension-name=extension#4,
+ extension-members=[
+ method=_extension#4|method,
+ tearoff method=_extension#4|get#method],
+ extension-name=_extension#4,
extension-onType=B1<T>,
extension-type-params=[T extends A1]
*/
extension <T extends A1> on B1<T> {
- /*member: extension#4|method:
+ /*member: _extension#4|method:
builder-name=method,
builder-params=[#this],
builder-type-params=[T extends A1],
- member-name=extension#4|method,
+ member-name=_extension#4|method,
member-params=[#this],
- member-type-params=[#T extends A1]
+ member-type-params=[T extends A1]
*/
method() {}
+
+ /*member: _extension#4|get#method:
+ builder-name=method,
+ builder-params=[#this],
+ builder-type-params=[T extends A1],
+ member-name=_extension#4|get#method,
+ member-params=[#this],
+ member-type-params=[T extends A1]
+ */
}
main() {}
diff --git a/pkg/front_end/test/extensions/data/use_as_type.dart b/pkg/front_end/test/extensions/data/use_as_type.dart
index f9e9b1d..6f411ab 100644
--- a/pkg/front_end/test/extensions/data/use_as_type.dart
+++ b/pkg/front_end/test/extensions/data/use_as_type.dart
@@ -2,6 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+/*library: scope=[A2,B2]*/
+
class A1 {}
/*class: A2:
diff --git a/pkg/front_end/test/extensions/extensions_test.dart b/pkg/front_end/test/extensions/extensions_test.dart
index 298ec22..33e8fb4 100644
--- a/pkg/front_end/test/extensions/extensions_test.dart
+++ b/pkg/front_end/test/extensions/extensions_test.dart
@@ -43,6 +43,13 @@
new ExtensionsDataExtractor(compilerResult, actualMap).computeForClass(cls);
}
+ void computeLibraryData(InternalCompilerResult compilerResult,
+ Library library, Map<Id, ActualData<Features>> actualMap,
+ {bool verbose}) {
+ new ExtensionsDataExtractor(compilerResult, actualMap)
+ .computeForLibrary(library);
+ }
+
@override
void computeExtensionData(InternalCompilerResult compilerResult,
Extension extension, Map<Id, ActualData<Features>> actualMap,
@@ -84,6 +91,7 @@
static const String builderRequiredParameters = 'builder-params';
static const String builderPositionalParameters = 'builder-pos-params';
static const String builderNamedParameters = 'builder-named-params';
+ static const String builderScope = 'scope';
static const String clsName = 'cls-name';
static const String clsTypeParameters = 'cls-type-params';
@@ -112,6 +120,22 @@
: super(compilerResult, actualMap);
@override
+ Features computeLibraryValue(Id id, Library library) {
+ Features features = new Features();
+ LibraryBuilder libraryBuilder =
+ lookupLibraryBuilder(compilerResult, library);
+ libraryBuilder.scope.forEachExtension((ExtensionBuilder extension) {
+ LibraryBuilder library = extension.parent;
+ String libraryPrefix = '';
+ if (library != libraryBuilder) {
+ libraryPrefix = '${library.fileUri.pathSegments.last}.';
+ }
+ features.addElement(Tags.builderScope, '$libraryPrefix${extension.name}');
+ });
+ return features;
+ }
+
+ @override
Features computeClassValue(Id id, Class cls) {
ClassBuilder clsBuilder = lookupClassBuilder(compilerResult, cls);
if (!clsBuilder.isExtension) {
diff --git a/pkg/front_end/test/fasta/expression_test.dart b/pkg/front_end/test/fasta/expression_test.dart
index 40ccfb4..8366fcb 100644
--- a/pkg/front_end/test/fasta/expression_test.dart
+++ b/pkg/front_end/test/fasta/expression_test.dart
@@ -10,16 +10,6 @@
import "dart:io" show File, IOSink;
-import "package:kernel/ast.dart"
- show Procedure, Component, DynamicType, DartType, TypeParameter;
-
-import "package:testing/testing.dart"
- show Chain, ChainContext, Result, Step, TestDescription, runMe;
-
-import "package:testing/src/log.dart" show splitLines;
-
-import "package:yaml/yaml.dart" show YamlMap, YamlList, loadYamlNode;
-
import "package:front_end/src/api_prototype/compiler_options.dart"
show CompilerOptions, DiagnosticMessage;
@@ -29,31 +19,41 @@
import "package:front_end/src/api_prototype/terminal_color_support.dart"
show printDiagnosticMessage;
+import 'package:front_end/src/base/processed_options.dart'
+ show ProcessedOptions;
+
import 'package:front_end/src/compute_platform_binaries_location.dart'
show computePlatformBinariesLocation;
import 'package:front_end/src/external_state_snapshot.dart'
show ExternalStateSnapshot;
-import 'package:front_end/src/base/processed_options.dart'
- show ProcessedOptions;
-
import 'package:front_end/src/fasta/compiler_context.dart' show CompilerContext;
import 'package:front_end/src/fasta/incremental_compiler.dart'
show IncrementalCompiler;
+import "package:kernel/ast.dart"
+ show Procedure, Component, DynamicType, DartType, TypeParameter;
+
import 'package:kernel/target/targets.dart' show TargetFlags;
import 'package:kernel/text/ast_to_text.dart' show Printer;
+import "package:testing/src/log.dart" show splitLines;
+
+import "package:testing/testing.dart"
+ show Chain, ChainContext, Result, Step, TestDescription, runMe;
+
import 'package:vm/target/vm.dart' show VmTarget;
-import '../../lib/src/fasta/testing/kernel_chain.dart' show runDiff, openWrite;
+import "package:yaml/yaml.dart" show YamlMap, YamlList, loadYamlNode;
import '../../lib/src/fasta/kernel/utils.dart'
show writeComponentToFile, serializeProcedure;
+import '../utils/kernel_chain.dart' show runDiff, openWrite;
+
const JsonEncoder json = const JsonEncoder.withIndent(" ");
class Context extends ChainContext {
@@ -388,12 +388,12 @@
final Uri entryPoint = base.resolve("nothing.dart");
/// The custom URI used to locate the dill file in the MemoryFileSystem.
- final Uri sdkSummary = base.resolve("vm_platform.dill");
+ final Uri sdkSummary = base.resolve("vm_platform_strong.dill");
/// The actual location of the dill file.
final Uri sdkSummaryFile =
computePlatformBinariesLocation(forceBuildDir: true)
- .resolve("vm_platform.dill");
+ .resolve("vm_platform_strong.dill");
final MemoryFileSystem fs = new MemoryFileSystem(base);
@@ -433,4 +433,4 @@
}
main([List<String> arguments = const []]) =>
- runMe(arguments, createContext, "../../testing.json");
+ runMe(arguments, createContext, configurationPath: "../../testing.json");
diff --git a/pkg/front_end/test/fasta/fast_strong_test.dart b/pkg/front_end/test/fasta/fast_strong_test.dart
index 6c1464c..26c0875 100644
--- a/pkg/front_end/test/fasta/fast_strong_test.dart
+++ b/pkg/front_end/test/fasta/fast_strong_test.dart
@@ -18,4 +18,5 @@
}
main([List<String> arguments = const []]) => runMe(arguments, createContext,
- "../../testing.json", Platform.script.resolve("strong_test.dart"));
+ configurationPath: "../../testing.json",
+ me: Platform.script.resolve("strong_tester.dart"));
diff --git a/pkg/front_end/test/fasta/flow_analysis/assigned_variables_test.dart b/pkg/front_end/test/fasta/flow_analysis/assigned_variables_test.dart
new file mode 100644
index 0000000..887559e
--- /dev/null
+++ b/pkg/front_end/test/fasta/flow_analysis/assigned_variables_test.dart
@@ -0,0 +1,104 @@
+// Copyright (c) 2019, 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:front_end/src/fasta/flow_analysis/flow_analysis.dart';
+import 'package:test/test.dart';
+
+main() {
+ test('capturedAnywhere records assignments in closures', () {
+ var assignedVariables = AssignedVariables<_Node, _Variable>();
+ var v1 = _Variable('v1');
+ var v2 = _Variable('v2');
+ var v3 = _Variable('v3');
+ assignedVariables.write(v1);
+ assignedVariables.beginNode(isClosure: true);
+ assignedVariables.write(v2);
+ assignedVariables.endNode(_Node(), isClosure: true);
+ assignedVariables.write(v3);
+ expect(assignedVariables.capturedAnywhere, {v2});
+ });
+
+ test('writtenInNode ignores assignments outside the node', () {
+ var assignedVariables = AssignedVariables<_Node, _Variable>();
+ var v1 = _Variable('v1');
+ var v2 = _Variable('v2');
+ assignedVariables.write(v1);
+ assignedVariables.beginNode();
+ var node = _Node();
+ assignedVariables.endNode(node);
+ assignedVariables.write(v2);
+ expect(assignedVariables.writtenInNode(node), isEmpty);
+ });
+
+ test('writtenInNode records assignments inside the node', () {
+ var assignedVariables = AssignedVariables<_Node, _Variable>();
+ var v1 = _Variable('v1');
+ assignedVariables.beginNode();
+ assignedVariables.write(v1);
+ var node = _Node();
+ assignedVariables.endNode(node);
+ expect(assignedVariables.writtenInNode(node), {v1});
+ });
+
+ test('writtenInNode records assignments in a nested node', () {
+ var assignedVariables = AssignedVariables<_Node, _Variable>();
+ var v1 = _Variable('v1');
+ assignedVariables.beginNode();
+ assignedVariables.beginNode();
+ assignedVariables.write(v1);
+ assignedVariables.endNode(_Node());
+ var node = _Node();
+ assignedVariables.endNode(node);
+ expect(assignedVariables.writtenInNode(node), {v1});
+ });
+
+ test('writtenInNode records assignments in a closure', () {
+ var assignedVariables = AssignedVariables<_Node, _Variable>();
+ var v1 = _Variable('v1');
+ assignedVariables.beginNode(isClosure: true);
+ assignedVariables.write(v1);
+ var node = _Node();
+ assignedVariables.endNode(node, isClosure: true);
+ expect(assignedVariables.writtenInNode(node), {v1});
+ });
+
+ test('capturedInNode ignores assignments in non-nested closures', () {
+ var assignedVariables = AssignedVariables<_Node, _Variable>();
+ var v1 = _Variable('v1');
+ var v2 = _Variable('v2');
+ assignedVariables.beginNode(isClosure: true);
+ assignedVariables.write(v1);
+ assignedVariables.endNode(_Node(), isClosure: true);
+ assignedVariables.beginNode();
+ var node = _Node();
+ assignedVariables.endNode(node);
+ assignedVariables.beginNode(isClosure: true);
+ assignedVariables.write(v2);
+ assignedVariables.endNode(_Node(), isClosure: true);
+ expect(assignedVariables.capturedInNode(node), isEmpty);
+ });
+
+ test('capturedInNode records assignments in nested closures', () {
+ var assignedVariables = AssignedVariables<_Node, _Variable>();
+ var v1 = _Variable('v1');
+ assignedVariables.beginNode();
+ assignedVariables.beginNode(isClosure: true);
+ assignedVariables.write(v1);
+ assignedVariables.endNode(_Node(), isClosure: true);
+ var node = _Node();
+ assignedVariables.endNode(node);
+ expect(assignedVariables.capturedInNode(node), {v1});
+ });
+}
+
+class _Node {}
+
+class _Variable {
+ final String name;
+
+ _Variable(this.name);
+
+ @override
+ String toString() => name;
+}
diff --git a/pkg/front_end/test/fasta/flow_analysis/flow_analysis_test.dart b/pkg/front_end/test/fasta/flow_analysis/flow_analysis_test.dart
index ba4bae0..26fa4ca 100644
--- a/pkg/front_end/test/fasta/flow_analysis/flow_analysis_test.dart
+++ b/pkg/front_end/test/fasta/flow_analysis/flow_analysis_test.dart
@@ -3,51 +3,60 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:front_end/src/fasta/flow_analysis/flow_analysis.dart';
+import 'package:meta/meta.dart';
import 'package:test/test.dart';
main() {
group('API', () {
test('conditional_thenBegin promotes true branch', () {
var h = _Harness();
- var x = h.addAssignedVar('x', 'int?');
- h.flow.conditional_thenBegin(h.notNull(x)());
- expect(h.flow.promotedType(x).type, 'int');
- h.flow.conditional_elseBegin(_Expression());
- expect(h.flow.promotedType(x), isNull);
- h.flow.conditional_end(_Expression(), _Expression());
- expect(h.flow.promotedType(x), isNull);
- h.flow.finish();
+ var x = h.addVar('x', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ flow.conditional_thenBegin(h.notNull(x)());
+ expect(flow.promotedType(x).type, 'int');
+ flow.conditional_elseBegin(_Expression());
+ expect(flow.promotedType(x), isNull);
+ flow.conditional_end(_Expression(), _Expression());
+ expect(flow.promotedType(x), isNull);
+ });
});
test('conditional_elseBegin promotes false branch', () {
var h = _Harness();
- var x = h.addAssignedVar('x', 'int?');
- h.flow.conditional_thenBegin(h.eqNull(x)());
- expect(h.flow.promotedType(x), isNull);
- h.flow.conditional_elseBegin(_Expression());
- expect(h.flow.promotedType(x).type, 'int');
- h.flow.conditional_end(_Expression(), _Expression());
- expect(h.flow.promotedType(x), isNull);
- h.flow.finish();
+ var x = h.addVar('x', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ flow.conditional_thenBegin(h.eqNull(x)());
+ expect(flow.promotedType(x), isNull);
+ flow.conditional_elseBegin(_Expression());
+ expect(flow.promotedType(x).type, 'int');
+ flow.conditional_end(_Expression(), _Expression());
+ expect(flow.promotedType(x), isNull);
+ });
});
test('conditional_end keeps promotions common to true and false branches',
() {
var h = _Harness();
- var x = h.addAssignedVar('x', 'int?');
- var y = h.addAssignedVar('x', 'int?');
- var z = h.addAssignedVar('x', 'int?');
- h.flow.conditional_thenBegin(_Expression());
- h.promote(x, 'int');
- h.promote(y, 'int');
- h.flow.conditional_elseBegin(_Expression());
- h.promote(x, 'int');
- h.promote(z, 'int');
- h.flow.conditional_end(_Expression(), _Expression());
- expect(h.flow.promotedType(x).type, 'int');
- expect(h.flow.promotedType(y), isNull);
- expect(h.flow.promotedType(z), isNull);
- h.flow.finish();
+ var x = h.addVar('x', 'int?');
+ var y = h.addVar('y', 'int?');
+ var z = h.addVar('z', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ h.declare(y, initialized: true);
+ h.declare(z, initialized: true);
+ flow.conditional_thenBegin(_Expression());
+ h.promote(x, 'int');
+ h.promote(y, 'int');
+ flow.conditional_elseBegin(_Expression());
+ h.promote(x, 'int');
+ h.promote(z, 'int');
+ flow.conditional_end(_Expression(), _Expression());
+ expect(flow.promotedType(x).type, 'int');
+ expect(flow.promotedType(y), isNull);
+ expect(flow.promotedType(z), isNull);
+ });
});
test('conditional joins true states', () {
@@ -55,17 +64,21 @@
// promotes x, but not y or z
// }
var h = _Harness();
- var x = h.addAssignedVar('x', 'int?');
- var y = h.addAssignedVar('y', 'int?');
- var z = h.addAssignedVar('z', 'int?');
- h.if_(
- h.conditional(h.expr, h.and(h.notNull(x), h.notNull(y)),
- h.and(h.notNull(x), h.notNull(z))), () {
- expect(h.flow.promotedType(x).type, 'int');
- expect(h.flow.promotedType(y), isNull);
- expect(h.flow.promotedType(z), isNull);
+ var x = h.addVar('x', 'int?');
+ var y = h.addVar('y', 'int?');
+ var z = h.addVar('z', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ h.declare(y, initialized: true);
+ h.declare(z, initialized: true);
+ h.if_(
+ h.conditional(h.expr, h.and(h.notNull(x), h.notNull(y)),
+ h.and(h.notNull(x), h.notNull(z))), () {
+ expect(flow.promotedType(x).type, 'int');
+ expect(flow.promotedType(y), isNull);
+ expect(flow.promotedType(z), isNull);
+ });
});
- h.flow.finish();
});
test('conditional joins false states', () {
@@ -74,134 +87,183 @@
// promotes x, but not y or z
// }
var h = _Harness();
- var x = h.addAssignedVar('x', 'int?');
- var y = h.addAssignedVar('y', 'int?');
- var z = h.addAssignedVar('z', 'int?');
- h.ifElse(
- h.conditional(h.expr, h.or(h.eqNull(x), h.eqNull(y)),
- h.or(h.eqNull(x), h.eqNull(z))),
- () {}, () {
- expect(h.flow.promotedType(x).type, 'int');
- expect(h.flow.promotedType(y), isNull);
- expect(h.flow.promotedType(z), isNull);
+ var x = h.addVar('x', 'int?');
+ var y = h.addVar('y', 'int?');
+ var z = h.addVar('z', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ h.declare(y, initialized: true);
+ h.declare(z, initialized: true);
+ h.ifElse(
+ h.conditional(h.expr, h.or(h.eqNull(x), h.eqNull(y)),
+ h.or(h.eqNull(x), h.eqNull(z))),
+ () {}, () {
+ expect(flow.promotedType(x).type, 'int');
+ expect(flow.promotedType(y), isNull);
+ expect(flow.promotedType(z), isNull);
+ });
});
- h.flow.finish();
});
test('conditionEqNull(notEqual: true) promotes true branch', () {
var h = _Harness();
- var x = h.addAssignedVar('x', 'int?');
- var expr = _Expression();
- h.flow.conditionEqNull(expr, x, notEqual: true);
- h.flow.ifStatement_thenBegin(expr);
- expect(h.flow.promotedType(x).type, 'int');
- h.flow.ifStatement_elseBegin();
- expect(h.flow.promotedType(x), isNull);
- h.flow.ifStatement_end(true);
- h.flow.finish();
+ var x = h.addVar('x', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ var expr = _Expression();
+ flow.conditionEqNull(expr, x, notEqual: true);
+ flow.ifStatement_thenBegin(expr);
+ expect(flow.promotedType(x).type, 'int');
+ flow.ifStatement_elseBegin();
+ expect(flow.promotedType(x), isNull);
+ flow.ifStatement_end(true);
+ });
});
test('conditionEqNull(notEqual: false) promotes false branch', () {
var h = _Harness();
- var x = h.addAssignedVar('x', 'int?');
- var expr = _Expression();
- h.flow.conditionEqNull(expr, x, notEqual: false);
- h.flow.ifStatement_thenBegin(expr);
- expect(h.flow.promotedType(x), isNull);
- h.flow.ifStatement_elseBegin();
- expect(h.flow.promotedType(x).type, 'int');
- h.flow.ifStatement_end(true);
- h.flow.finish();
+ var x = h.addVar('x', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ var expr = _Expression();
+ flow.conditionEqNull(expr, x, notEqual: false);
+ flow.ifStatement_thenBegin(expr);
+ expect(flow.promotedType(x), isNull);
+ flow.ifStatement_elseBegin();
+ expect(flow.promotedType(x).type, 'int');
+ flow.ifStatement_end(true);
+ });
});
test('doStatement_bodyBegin() un-promotes', () {
var h = _Harness();
- var x = h.addAssignedVar('x', 'int?');
- h.promote(x, 'int');
- expect(h.flow.promotedType(x).type, 'int');
- h.flow.doStatement_bodyBegin(_Statement(), {x});
- expect(h.flow.promotedType(x), isNull);
- h.flow.doStatement_conditionBegin();
- h.flow.doStatement_end(_Expression());
- h.flow.finish();
+ var x = h.addVar('x', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ h.promote(x, 'int');
+ expect(flow.promotedType(x).type, 'int');
+ flow.doStatement_bodyBegin(_Statement(), {x});
+ expect(flow.promotedType(x), isNull);
+ flow.doStatement_conditionBegin();
+ flow.doStatement_end(_Expression());
+ });
});
test('doStatement_conditionBegin() joins continue state', () {
var h = _Harness();
- var x = h.addAssignedVar('x', 'int?');
- var stmt = _Statement();
- h.flow.doStatement_bodyBegin(stmt, {});
- h.if_(h.notNull(x), () {
- h.flow.handleContinue(stmt);
+ var x = h.addVar('x', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ var stmt = _Statement();
+ flow.doStatement_bodyBegin(stmt, {});
+ h.if_(h.notNull(x), () {
+ flow.handleContinue(stmt);
+ });
+ flow.handleExit();
+ expect(flow.isReachable, false);
+ expect(flow.promotedType(x), isNull);
+ flow.doStatement_conditionBegin();
+ expect(flow.isReachable, true);
+ expect(flow.promotedType(x).type, 'int');
+ flow.doStatement_end(_Expression());
});
- h.flow.handleExit();
- expect(h.flow.isReachable, false);
- expect(h.flow.promotedType(x), isNull);
- h.flow.doStatement_conditionBegin();
- expect(h.flow.isReachable, true);
- expect(h.flow.promotedType(x).type, 'int');
- h.flow.doStatement_end(_Expression());
- h.flow.finish();
});
test('doStatement_end() promotes', () {
var h = _Harness();
- var x = h.addAssignedVar('x', 'int?');
- h.flow.doStatement_bodyBegin(_Statement(), {});
- h.flow.doStatement_conditionBegin();
- expect(h.flow.promotedType(x), isNull);
- h.flow.doStatement_end(h.eqNull(x)());
- expect(h.flow.promotedType(x).type, 'int');
- h.flow.finish();
+ var x = h.addVar('x', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ flow.doStatement_bodyBegin(_Statement(), {});
+ flow.doStatement_conditionBegin();
+ expect(flow.promotedType(x), isNull);
+ flow.doStatement_end(h.eqNull(x)());
+ expect(flow.promotedType(x).type, 'int');
+ });
});
test('finish checks proper nesting', () {
var h = _Harness();
var expr = _Expression();
- h.flow.ifStatement_thenBegin(expr);
- expect(() => h.flow.finish(), _asserts);
+ var flow = h.createFlow();
+ flow.ifStatement_thenBegin(expr);
+ expect(() => flow.finish(), _asserts);
});
test('finish checks for un-added variables', () {
var h = _Harness();
var x = _Var('x', _Type('int'));
- h.flow.isAssigned(x);
- expect(() => h.flow.finish(), _asserts);
+ var flow = h.createFlow();
+ flow.isAssigned(x);
+ expect(() => flow.finish(), _asserts);
});
test('for_conditionBegin() un-promotes', () {
var h = _Harness();
- var x = h.addAssignedVar('x', 'int?');
- h.promote(x, 'int');
- expect(h.flow.promotedType(x).type, 'int');
- h.flow.for_conditionBegin({x});
- expect(h.flow.promotedType(x), isNull);
- h.flow.for_bodyBegin(_Statement(), _Expression());
- h.flow.for_updaterBegin();
- h.flow.for_end();
- h.flow.finish();
+ var x = h.addVar('x', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ h.promote(x, 'int');
+ expect(flow.promotedType(x).type, 'int');
+ flow.for_conditionBegin({x});
+ expect(flow.promotedType(x), isNull);
+ flow.for_bodyBegin(_Statement(), _Expression());
+ flow.for_updaterBegin();
+ flow.for_end();
+ });
+ });
+
+ test('for_conditionBegin() handles not-yet-seen variables', () {
+ var h = _Harness();
+ var x = h.addVar('x', 'int?');
+ var y = h.addVar('y', 'int?');
+ h.run((flow) {
+ h.declare(y, initialized: true);
+ h.promote(y, 'int');
+ flow.for_conditionBegin({x});
+ flow.add(x, assigned: true);
+ flow.for_bodyBegin(_Statement(), _Expression());
+ flow.for_updaterBegin();
+ flow.for_end();
+ });
+ });
+
+ test('for_bodyBegin() handles empty condition', () {
+ var h = _Harness();
+ h.run((flow) {
+ flow.for_conditionBegin({});
+ flow.for_bodyBegin(_Statement(), null);
+ flow.for_updaterBegin();
+ expect(flow.isReachable, isTrue);
+ flow.for_end();
+ expect(flow.isReachable, isFalse);
+ });
});
test('for_bodyBegin() promotes', () {
var h = _Harness();
- var x = h.addAssignedVar('x', 'int?');
- h.flow.for_conditionBegin({});
- h.flow.for_bodyBegin(_Statement(), h.notNull(x)());
- expect(h.flow.promotedType(x).type, 'int');
- h.flow.for_updaterBegin();
- h.flow.for_end();
- h.flow.finish();
+ var x = h.addVar('x', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ flow.for_conditionBegin({});
+ flow.for_bodyBegin(_Statement(), h.notNull(x)());
+ expect(flow.promotedType(x).type, 'int');
+ flow.for_updaterBegin();
+ flow.for_end();
+ });
});
test('for_bodyBegin() can be used with a null statement', () {
// This is needed for collection elements that are for-loops.
var h = _Harness();
- var x = h.addAssignedVar('x', 'int?');
- h.flow.for_conditionBegin({});
- h.flow.for_bodyBegin(null, h.notNull(x)());
- h.flow.for_updaterBegin();
- h.flow.for_end();
- h.flow.finish();
+ var x = h.addVar('x', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ flow.for_conditionBegin({});
+ flow.for_bodyBegin(null, h.notNull(x)());
+ flow.for_updaterBegin();
+ flow.for_end();
+ });
});
test('for_updaterBegin() joins current and continue states', () {
@@ -209,25 +271,29 @@
// x, y, and z. We promote x and y in the continue path, and x and z in
// the current path. Inside the updater, only x should be promoted.
var h = _Harness();
- var x = h.addAssignedVar('x', 'int?');
- var y = h.addAssignedVar('y', 'int?');
- var z = h.addAssignedVar('z', 'int?');
- var stmt = _Statement();
- h.flow.for_conditionBegin({});
- h.flow.for_bodyBegin(stmt, h.expr());
- h.if_(h.expr, () {
+ var x = h.addVar('x', 'int?');
+ var y = h.addVar('y', 'int?');
+ var z = h.addVar('z', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ h.declare(y, initialized: true);
+ h.declare(z, initialized: true);
+ var stmt = _Statement();
+ flow.for_conditionBegin({});
+ flow.for_bodyBegin(stmt, h.expr());
+ h.if_(h.expr, () {
+ h.promote(x, 'int');
+ h.promote(y, 'int');
+ flow.handleContinue(stmt);
+ });
h.promote(x, 'int');
- h.promote(y, 'int');
- h.flow.handleContinue(stmt);
+ h.promote(z, 'int');
+ flow.for_updaterBegin();
+ expect(flow.promotedType(x).type, 'int');
+ expect(flow.promotedType(y), isNull);
+ expect(flow.promotedType(z), isNull);
+ flow.for_end();
});
- h.promote(x, 'int');
- h.promote(z, 'int');
- h.flow.for_updaterBegin();
- expect(h.flow.promotedType(x).type, 'int');
- expect(h.flow.promotedType(y), isNull);
- expect(h.flow.promotedType(z), isNull);
- h.flow.for_end();
- h.flow.finish();
});
test('for_end() joins break and condition-false states', () {
@@ -235,169 +301,85 @@
// x, y, and z. We promote x and y in the break path, and x and z in the
// condition-false path. After the loop, only x should be promoted.
var h = _Harness();
- var x = h.addAssignedVar('x', 'int?');
- var y = h.addAssignedVar('y', 'int?');
- var z = h.addAssignedVar('z', 'int?');
- var stmt = _Statement();
- h.flow.for_conditionBegin({});
- h.flow.for_bodyBegin(stmt, h.or(h.eqNull(x), h.eqNull(z))());
- h.if_(h.expr, () {
- h.promote(x, 'int');
- h.promote(y, 'int');
- h.flow.handleBreak(stmt);
+ var x = h.addVar('x', 'int?');
+ var y = h.addVar('y', 'int?');
+ var z = h.addVar('z', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ h.declare(y, initialized: true);
+ h.declare(z, initialized: true);
+ var stmt = _Statement();
+ flow.for_conditionBegin({});
+ flow.for_bodyBegin(stmt, h.or(h.eqNull(x), h.eqNull(z))());
+ h.if_(h.expr, () {
+ h.promote(x, 'int');
+ h.promote(y, 'int');
+ flow.handleBreak(stmt);
+ });
+ flow.for_updaterBegin();
+ flow.for_end();
+ expect(flow.promotedType(x).type, 'int');
+ expect(flow.promotedType(y), isNull);
+ expect(flow.promotedType(z), isNull);
});
- h.flow.for_updaterBegin();
- h.flow.for_end();
- expect(h.flow.promotedType(x).type, 'int');
- expect(h.flow.promotedType(y), isNull);
- expect(h.flow.promotedType(z), isNull);
- h.flow.finish();
});
test('forEach_bodyBegin() un-promotes', () {
var h = _Harness();
- var x = h.addAssignedVar('x', 'int?');
- h.promote(x, 'int');
- expect(h.flow.promotedType(x).type, 'int');
- h.flow.forEach_bodyBegin({x});
- expect(h.flow.promotedType(x), isNull);
- h.flow.forEach_end();
- h.flow.finish();
+ var x = h.addVar('x', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ h.promote(x, 'int');
+ expect(flow.promotedType(x).type, 'int');
+ flow.forEach_bodyBegin({x});
+ expect(flow.promotedType(x), isNull);
+ flow.forEach_end();
+ });
});
test('forEach_end() restores state before loop', () {
var h = _Harness();
- var x = h.addAssignedVar('x', 'int?');
- h.flow.forEach_bodyBegin({});
- h.promote(x, 'int');
- expect(h.flow.promotedType(x).type, 'int');
- h.flow.forEach_end();
- expect(h.flow.promotedType(x), isNull);
- h.flow.finish();
+ var x = h.addVar('x', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ flow.forEach_bodyBegin({});
+ h.promote(x, 'int');
+ expect(flow.promotedType(x).type, 'int');
+ flow.forEach_end();
+ expect(flow.promotedType(x), isNull);
+ });
});
test('ifStatement_end(false) keeps else branch if then branch exits', () {
var h = _Harness();
- var x = h.addAssignedVar('x', 'int?');
- h.flow.ifStatement_thenBegin(h.eqNull(x)());
- h.flow.handleExit();
- h.flow.ifStatement_end(false);
- expect(h.flow.promotedType(x).type, 'int');
- h.flow.finish();
- });
-
- test('logicalBinaryOp_rightBegin(isAnd: true) promotes in RHS', () {
- var h = _Harness();
- var x = h.addAssignedVar('x', 'int?');
- h.flow.logicalBinaryOp_rightBegin(h.notNull(x)(), isAnd: true);
- expect(h.flow.promotedType(x).type, 'int');
- h.flow.logicalBinaryOp_end(_Expression(), _Expression(), isAnd: true);
- h.flow.finish();
- });
-
- test('logicalBinaryOp_rightEnd(isAnd: true) keeps promotions from RHS', () {
- var h = _Harness();
- var x = h.addAssignedVar('x', 'int?');
- h.flow.logicalBinaryOp_rightBegin(_Expression(), isAnd: true);
- var wholeExpr = _Expression();
- h.flow.logicalBinaryOp_end(wholeExpr, h.notNull(x)(), isAnd: true);
- h.flow.ifStatement_thenBegin(wholeExpr);
- expect(h.flow.promotedType(x).type, 'int');
- h.flow.ifStatement_end(false);
- h.flow.finish();
- });
-
- test('logicalBinaryOp_rightEnd(isAnd: false) keeps promotions from RHS',
- () {
- var h = _Harness();
- var x = h.addAssignedVar('x', 'int?');
- h.flow.logicalBinaryOp_rightBegin(_Expression(), isAnd: false);
- var wholeExpr = _Expression();
- h.flow.logicalBinaryOp_end(wholeExpr, h.eqNull(x)(), isAnd: false);
- h.flow.ifStatement_thenBegin(wholeExpr);
- h.flow.ifStatement_elseBegin();
- expect(h.flow.promotedType(x).type, 'int');
- h.flow.ifStatement_end(true);
- h.flow.finish();
- });
-
- test('logicalBinaryOp_rightBegin(isAnd: false) promotes in RHS', () {
- var h = _Harness();
- var x = h.addAssignedVar('x', 'int?');
- h.flow.logicalBinaryOp_rightBegin(h.eqNull(x)(), isAnd: false);
- expect(h.flow.promotedType(x).type, 'int');
- h.flow.logicalBinaryOp_end(_Expression(), _Expression(), isAnd: false);
- h.flow.finish();
- });
-
- test('logicalBinaryOp(isAnd: true) joins promotions', () {
- // if (x != null && y != null) {
- // promotes x and y
- // }
- var h = _Harness();
- var x = h.addAssignedVar('x', 'int?');
- var y = h.addAssignedVar('y', 'int?');
- h.if_(h.and(h.notNull(x), h.notNull(y)), () {
- expect(h.flow.promotedType(x).type, 'int');
- expect(h.flow.promotedType(y).type, 'int');
+ var x = h.addVar('x', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ flow.ifStatement_thenBegin(h.eqNull(x)());
+ flow.handleExit();
+ flow.ifStatement_end(false);
+ expect(flow.promotedType(x).type, 'int');
});
- h.flow.finish();
- });
-
- test('logicalBinaryOp(isAnd: false) joins promotions', () {
- // if (x == null || y == null) {} else {
- // promotes x and y
- // }
- var h = _Harness();
- var x = h.addAssignedVar('x', 'int?');
- var y = h.addAssignedVar('y', 'int?');
- h.ifElse(h.or(h.eqNull(x), h.eqNull(y)), () {}, () {
- expect(h.flow.promotedType(x).type, 'int');
- expect(h.flow.promotedType(y).type, 'int');
- });
- h.flow.finish();
- });
-
- test('Infinite loop does not implicitly assign variables', () {
- var h = _Harness();
- var x = h.addUnassignedVar('x', 'int');
- var trueCondition = _Expression();
- h.flow.whileStatement_conditionBegin({x});
- h.flow.booleanLiteral(trueCondition, true);
- h.flow.whileStatement_bodyBegin(_Statement(), trueCondition);
- h.flow.whileStatement_end();
- expect(h.flow.isAssigned(x), false);
- });
-
- test('If(false) does not discard promotions', () {
- var h = _Harness();
- var x = h.addAssignedVar('x', 'Object');
- h.promote(x, 'int');
- expect(h.flow.promotedType(x).type, 'int');
- // if (false) {
- var falseExpression = _Expression();
- h.flow.booleanLiteral(falseExpression, false);
- h.flow.ifStatement_thenBegin(falseExpression);
- expect(h.flow.promotedType(x).type, 'int');
- h.flow.ifStatement_end(false);
});
void _checkIs(String declaredType, String tryPromoteType,
String expectedPromotedType) {
var h = _Harness();
- var x = h.addAssignedVar('x', 'int?');
- var expr = _Expression();
- h.flow.isExpression_end(expr, x, false, _Type(tryPromoteType));
- h.flow.ifStatement_thenBegin(expr);
- if (expectedPromotedType == null) {
- expect(h.flow.promotedType(x), isNull);
- } else {
- expect(h.flow.promotedType(x).type, expectedPromotedType);
- }
- h.flow.ifStatement_elseBegin();
- expect(h.flow.promotedType(x), isNull);
- h.flow.ifStatement_end(true);
- h.flow.finish();
+ var x = h.addVar('x', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ var expr = _Expression();
+ flow.isExpression_end(expr, x, false, _Type(tryPromoteType));
+ flow.ifStatement_thenBegin(expr);
+ if (expectedPromotedType == null) {
+ expect(flow.promotedType(x), isNull);
+ } else {
+ expect(flow.promotedType(x).type, expectedPromotedType);
+ }
+ flow.ifStatement_elseBegin();
+ expect(flow.promotedType(x), isNull);
+ flow.ifStatement_end(true);
+ });
}
test('isExpression_end promotes to a subtype', () {
@@ -411,10 +393,527 @@
test('isExpression_end does not promote to an unrelated type', () {
_checkIs('int', 'String', null);
});
+
+ test('logicalBinaryOp_rightBegin(isAnd: true) promotes in RHS', () {
+ var h = _Harness();
+ var x = h.addVar('x', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ flow.logicalBinaryOp_rightBegin(h.notNull(x)(), isAnd: true);
+ expect(flow.promotedType(x).type, 'int');
+ flow.logicalBinaryOp_end(_Expression(), _Expression(), isAnd: true);
+ });
+ });
+
+ test('logicalBinaryOp_rightEnd(isAnd: true) keeps promotions from RHS', () {
+ var h = _Harness();
+ var x = h.addVar('x', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ flow.logicalBinaryOp_rightBegin(_Expression(), isAnd: true);
+ var wholeExpr = _Expression();
+ flow.logicalBinaryOp_end(wholeExpr, h.notNull(x)(), isAnd: true);
+ flow.ifStatement_thenBegin(wholeExpr);
+ expect(flow.promotedType(x).type, 'int');
+ flow.ifStatement_end(false);
+ });
+ });
+
+ test('logicalBinaryOp_rightEnd(isAnd: false) keeps promotions from RHS',
+ () {
+ var h = _Harness();
+ var x = h.addVar('x', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ flow.logicalBinaryOp_rightBegin(_Expression(), isAnd: false);
+ var wholeExpr = _Expression();
+ flow.logicalBinaryOp_end(wholeExpr, h.eqNull(x)(), isAnd: false);
+ flow.ifStatement_thenBegin(wholeExpr);
+ flow.ifStatement_elseBegin();
+ expect(flow.promotedType(x).type, 'int');
+ flow.ifStatement_end(true);
+ });
+ });
+
+ test('logicalBinaryOp_rightBegin(isAnd: false) promotes in RHS', () {
+ var h = _Harness();
+ var x = h.addVar('x', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ flow.logicalBinaryOp_rightBegin(h.eqNull(x)(), isAnd: false);
+ expect(flow.promotedType(x).type, 'int');
+ flow.logicalBinaryOp_end(_Expression(), _Expression(), isAnd: false);
+ });
+ });
+
+ test('logicalBinaryOp(isAnd: true) joins promotions', () {
+ // if (x != null && y != null) {
+ // promotes x and y
+ // }
+ var h = _Harness();
+ var x = h.addVar('x', 'int?');
+ var y = h.addVar('y', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ h.declare(y, initialized: true);
+ h.if_(h.and(h.notNull(x), h.notNull(y)), () {
+ expect(flow.promotedType(x).type, 'int');
+ expect(flow.promotedType(y).type, 'int');
+ });
+ });
+ });
+
+ test('logicalBinaryOp(isAnd: false) joins promotions', () {
+ // if (x == null || y == null) {} else {
+ // promotes x and y
+ // }
+ var h = _Harness();
+ var x = h.addVar('x', 'int?');
+ var y = h.addVar('y', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ h.declare(y, initialized: true);
+ h.ifElse(h.or(h.eqNull(x), h.eqNull(y)), () {}, () {
+ expect(flow.promotedType(x).type, 'int');
+ expect(flow.promotedType(y).type, 'int');
+ });
+ });
+ });
+
+ test('promotedType handles not-yet-seen variables', () {
+ // Note: this is needed for error recovery in the analyzer.
+ var h = _Harness();
+ var x = h.addVar('x', 'int');
+ h.run((flow) {
+ expect(flow.promotedType(x), isNull);
+ h.declare(x, initialized: true);
+ });
+ });
+
+ test('switchStatement_beginCase(false) restores previous promotions', () {
+ var h = _Harness();
+ var x = h.addVar('x', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ h.promote(x, 'int');
+ flow.switchStatement_expressionEnd(_Statement());
+ flow.switchStatement_beginCase(false, {x});
+ expect(flow.promotedType(x).type, 'int');
+ flow.write(x);
+ expect(flow.promotedType(x), isNull);
+ flow.switchStatement_beginCase(false, {x});
+ expect(flow.promotedType(x).type, 'int');
+ flow.write(x);
+ expect(flow.promotedType(x), isNull);
+ flow.switchStatement_end(false);
+ });
+ });
+
+ test('switchStatement_beginCase(false) does not un-promote', () {
+ var h = _Harness();
+ var x = h.addVar('x', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ h.promote(x, 'int');
+ flow.switchStatement_expressionEnd(_Statement());
+ flow.switchStatement_beginCase(false, {x});
+ expect(flow.promotedType(x).type, 'int');
+ flow.write(x);
+ expect(flow.promotedType(x), isNull);
+ flow.switchStatement_end(false);
+ });
+ });
+
+ test('switchStatement_beginCase(true) un-promotes', () {
+ var h = _Harness();
+ var x = h.addVar('x', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ h.promote(x, 'int');
+ flow.switchStatement_expressionEnd(_Statement());
+ flow.switchStatement_beginCase(true, {x});
+ expect(flow.promotedType(x), isNull);
+ flow.write(x);
+ expect(flow.promotedType(x), isNull);
+ flow.switchStatement_end(false);
+ });
+ });
+
+ test('switchStatement_end(false) joins break and default', () {
+ var h = _Harness();
+ var x = h.addVar('x', 'int?');
+ var y = h.addVar('y', 'int?');
+ var z = h.addVar('z', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ h.declare(y, initialized: true);
+ h.declare(z, initialized: true);
+ h.promote(y, 'int');
+ h.promote(z, 'int');
+ var stmt = _Statement();
+ flow.switchStatement_expressionEnd(stmt);
+ flow.switchStatement_beginCase(false, {y});
+ h.promote(x, 'int');
+ flow.write(y);
+ flow.handleBreak(stmt);
+ flow.switchStatement_end(false);
+ expect(flow.promotedType(x), isNull);
+ expect(flow.promotedType(y), isNull);
+ expect(flow.promotedType(z).type, 'int');
+ });
+ });
+
+ test('switchStatement_end(true) joins breaks', () {
+ var h = _Harness();
+ var w = h.addVar('w', 'int?');
+ var x = h.addVar('x', 'int?');
+ var y = h.addVar('y', 'int?');
+ var z = h.addVar('z', 'int?');
+ h.run((flow) {
+ h.declare(w, initialized: true);
+ h.declare(x, initialized: true);
+ h.declare(y, initialized: true);
+ h.declare(z, initialized: true);
+ h.promote(x, 'int');
+ h.promote(y, 'int');
+ h.promote(z, 'int');
+ var stmt = _Statement();
+ flow.switchStatement_expressionEnd(stmt);
+ flow.switchStatement_beginCase(false, {x, y});
+ h.promote(w, 'int');
+ h.promote(y, 'int');
+ flow.write(x);
+ flow.handleBreak(stmt);
+ flow.switchStatement_beginCase(false, {x, y});
+ h.promote(w, 'int');
+ h.promote(x, 'int');
+ flow.write(y);
+ flow.handleBreak(stmt);
+ flow.switchStatement_end(true);
+ expect(flow.promotedType(w).type, 'int');
+ expect(flow.promotedType(x), isNull);
+ expect(flow.promotedType(y), isNull);
+ expect(flow.promotedType(z).type, 'int');
+ });
+ });
+
+ test('switchStatement_end(true) allows fall-through of last case', () {
+ var h = _Harness();
+ var x = h.addVar('x', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ var stmt = _Statement();
+ flow.switchStatement_expressionEnd(stmt);
+ flow.switchStatement_beginCase(false, {});
+ h.promote(x, 'int');
+ flow.handleBreak(stmt);
+ flow.switchStatement_beginCase(false, {});
+ flow.switchStatement_end(true);
+ expect(flow.promotedType(x), isNull);
+ });
+ });
+
+ test('tryCatchStatement_bodyEnd() restores pre-try state', () {
+ var h = _Harness();
+ var x = h.addVar('x', 'int?');
+ var y = h.addVar('y', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ h.declare(y, initialized: true);
+ h.promote(y, 'int');
+ flow.tryCatchStatement_bodyBegin();
+ h.promote(x, 'int');
+ expect(flow.promotedType(x).type, 'int');
+ expect(flow.promotedType(y).type, 'int');
+ flow.tryCatchStatement_bodyEnd({});
+ flow.tryCatchStatement_catchBegin();
+ expect(flow.promotedType(x), isNull);
+ expect(flow.promotedType(y).type, 'int');
+ flow.tryCatchStatement_catchEnd();
+ flow.tryCatchStatement_end();
+ });
+ });
+
+ test('tryCatchStatement_bodyEnd() un-promotes variables assigned in body',
+ () {
+ var h = _Harness();
+ var x = h.addVar('x', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ h.promote(x, 'int');
+ expect(flow.promotedType(x).type, 'int');
+ flow.tryCatchStatement_bodyBegin();
+ flow.write(x);
+ h.promote(x, 'int');
+ expect(flow.promotedType(x).type, 'int');
+ flow.tryCatchStatement_bodyEnd({x});
+ flow.tryCatchStatement_catchBegin();
+ expect(flow.promotedType(x), isNull);
+ flow.tryCatchStatement_catchEnd();
+ flow.tryCatchStatement_end();
+ });
+ });
+
+ test('tryCatchStatement_catchBegin() restores previous post-body state',
+ () {
+ var h = _Harness();
+ var x = h.addVar('x', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ flow.tryCatchStatement_bodyBegin();
+ flow.tryCatchStatement_bodyEnd({});
+ flow.tryCatchStatement_catchBegin();
+ h.promote(x, 'int');
+ expect(flow.promotedType(x).type, 'int');
+ flow.tryCatchStatement_catchEnd();
+ flow.tryCatchStatement_catchBegin();
+ expect(flow.promotedType(x), isNull);
+ flow.tryCatchStatement_catchEnd();
+ flow.tryCatchStatement_end();
+ });
+ });
+
+ test('tryCatchStatement_catchEnd() joins catch state with after-try state',
+ () {
+ var h = _Harness();
+ var x = h.addVar('x', 'int?');
+ var y = h.addVar('y', 'int?');
+ var z = h.addVar('z', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ h.declare(y, initialized: true);
+ h.declare(z, initialized: true);
+ flow.tryCatchStatement_bodyBegin();
+ h.promote(x, 'int');
+ h.promote(y, 'int');
+ flow.tryCatchStatement_bodyEnd({});
+ flow.tryCatchStatement_catchBegin();
+ h.promote(x, 'int');
+ h.promote(z, 'int');
+ flow.tryCatchStatement_catchEnd();
+ flow.tryCatchStatement_end();
+ // Only x should be promoted, because it's the only variable promoted
+ // in both the try body and the catch handler.
+ expect(flow.promotedType(x).type, 'int');
+ expect(flow.promotedType(y), isNull);
+ expect(flow.promotedType(z), isNull);
+ });
+ });
+
+ test('tryCatchStatement_catchEnd() joins catch states', () {
+ var h = _Harness();
+ var x = h.addVar('x', 'int?');
+ var y = h.addVar('y', 'int?');
+ var z = h.addVar('z', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ h.declare(y, initialized: true);
+ h.declare(z, initialized: true);
+ flow.tryCatchStatement_bodyBegin();
+ flow.handleExit();
+ flow.tryCatchStatement_bodyEnd({});
+ flow.tryCatchStatement_catchBegin();
+ h.promote(x, 'int');
+ h.promote(y, 'int');
+ flow.tryCatchStatement_catchEnd();
+ flow.tryCatchStatement_catchBegin();
+ h.promote(x, 'int');
+ h.promote(z, 'int');
+ flow.tryCatchStatement_catchEnd();
+ flow.tryCatchStatement_end();
+ // Only x should be promoted, because it's the only variable promoted
+ // in both catch handlers.
+ expect(flow.promotedType(x).type, 'int');
+ expect(flow.promotedType(y), isNull);
+ expect(flow.promotedType(z), isNull);
+ });
+ });
+
+ test('tryFinallyStatement_finallyBegin() restores pre-try state', () {
+ var h = _Harness();
+ var x = h.addVar('x', 'int?');
+ var y = h.addVar('y', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ h.declare(y, initialized: true);
+ h.promote(y, 'int');
+ flow.tryFinallyStatement_bodyBegin();
+ h.promote(x, 'int');
+ expect(flow.promotedType(x).type, 'int');
+ expect(flow.promotedType(y).type, 'int');
+ flow.tryFinallyStatement_finallyBegin({});
+ expect(flow.promotedType(x), isNull);
+ expect(flow.promotedType(y).type, 'int');
+ flow.tryFinallyStatement_end({});
+ });
+ });
+
+ test(
+ 'tryFinallyStatement_finallyBegin() un-promotes variables assigned in '
+ 'body', () {
+ var h = _Harness();
+ var x = h.addVar('x', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ h.promote(x, 'int');
+ expect(flow.promotedType(x).type, 'int');
+ flow.tryFinallyStatement_bodyBegin();
+ flow.write(x);
+ h.promote(x, 'int');
+ expect(flow.promotedType(x).type, 'int');
+ flow.tryFinallyStatement_finallyBegin({x});
+ expect(flow.promotedType(x), isNull);
+ flow.tryFinallyStatement_end({});
+ });
+ });
+
+ test('tryFinallyStatement_end() restores promotions from try body', () {
+ var h = _Harness();
+ var x = h.addVar('x', 'int?');
+ var y = h.addVar('y', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ h.declare(y, initialized: true);
+ flow.tryFinallyStatement_bodyBegin();
+ h.promote(x, 'int');
+ expect(flow.promotedType(x).type, 'int');
+ flow.tryFinallyStatement_finallyBegin({});
+ expect(flow.promotedType(x), isNull);
+ h.promote(y, 'int');
+ expect(flow.promotedType(y).type, 'int');
+ flow.tryFinallyStatement_end({});
+ // Both x and y should now be promoted.
+ expect(flow.promotedType(x).type, 'int');
+ expect(flow.promotedType(y).type, 'int');
+ });
+ });
+
+ test(
+ 'tryFinallyStatement_end() does not restore try body promotions for '
+ 'variables assigned in finally', () {
+ var h = _Harness();
+ var x = h.addVar('x', 'int?');
+ var y = h.addVar('y', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ h.declare(y, initialized: true);
+ flow.tryFinallyStatement_bodyBegin();
+ h.promote(x, 'int');
+ expect(flow.promotedType(x).type, 'int');
+ flow.tryFinallyStatement_finallyBegin({});
+ expect(flow.promotedType(x), isNull);
+ flow.write(x);
+ flow.write(y);
+ h.promote(y, 'int');
+ expect(flow.promotedType(y).type, 'int');
+ flow.tryFinallyStatement_end({x, y});
+ // x should not be re-promoted, because it might have been assigned a
+ // non-promoted value in the "finally" block. But y's promotion still
+ // stands, because y was promoted in the finally block.
+ expect(flow.promotedType(x), isNull);
+ expect(flow.promotedType(y).type, 'int');
+ });
+ });
+
+ test('whileStatement_conditionBegin() un-promotes', () {
+ var h = _Harness();
+ var x = h.addVar('x', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ h.promote(x, 'int');
+ expect(flow.promotedType(x).type, 'int');
+ flow.whileStatement_conditionBegin({x});
+ expect(flow.promotedType(x), isNull);
+ flow.whileStatement_bodyBegin(_Statement(), _Expression());
+ flow.whileStatement_end();
+ });
+ });
+
+ test('whileStatement_conditionBegin() handles not-yet-seen variables', () {
+ var h = _Harness();
+ var x = h.addVar('x', 'int?');
+ var y = h.addVar('y', 'int?');
+ h.run((flow) {
+ h.declare(y, initialized: true);
+ h.promote(y, 'int');
+ flow.whileStatement_conditionBegin({x});
+ flow.add(x, assigned: true);
+ flow.whileStatement_bodyBegin(_Statement(), _Expression());
+ flow.whileStatement_end();
+ });
+ });
+
+ test('whileStatement_bodyBegin() promotes', () {
+ var h = _Harness();
+ var x = h.addVar('x', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ flow.whileStatement_conditionBegin({});
+ flow.whileStatement_bodyBegin(_Statement(), h.notNull(x)());
+ expect(flow.promotedType(x).type, 'int');
+ flow.whileStatement_end();
+ });
+ });
+
+ test('whileStatement_end() joins break and condition-false states', () {
+ // To test that the states are properly joined, we have three variables:
+ // x, y, and z. We promote x and y in the break path, and x and z in the
+ // condition-false path. After the loop, only x should be promoted.
+ var h = _Harness();
+ var x = h.addVar('x', 'int?');
+ var y = h.addVar('y', 'int?');
+ var z = h.addVar('z', 'int?');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ h.declare(y, initialized: true);
+ h.declare(z, initialized: true);
+ var stmt = _Statement();
+ flow.whileStatement_conditionBegin({});
+ flow.whileStatement_bodyBegin(stmt, h.or(h.eqNull(x), h.eqNull(z))());
+ h.if_(h.expr, () {
+ h.promote(x, 'int');
+ h.promote(y, 'int');
+ flow.handleBreak(stmt);
+ });
+ flow.whileStatement_end();
+ expect(flow.promotedType(x).type, 'int');
+ expect(flow.promotedType(y), isNull);
+ expect(flow.promotedType(z), isNull);
+ });
+ });
+
+ test('Infinite loop does not implicitly assign variables', () {
+ var h = _Harness();
+ var x = h.addVar('x', 'int');
+ h.run((flow) {
+ h.declare(x, initialized: false);
+ var trueCondition = _Expression();
+ flow.whileStatement_conditionBegin({x});
+ flow.booleanLiteral(trueCondition, true);
+ flow.whileStatement_bodyBegin(_Statement(), trueCondition);
+ flow.whileStatement_end();
+ expect(flow.isAssigned(x), false);
+ });
+ });
+
+ test('If(false) does not discard promotions', () {
+ var h = _Harness();
+ var x = h.addVar('x', 'Object');
+ h.run((flow) {
+ h.declare(x, initialized: true);
+ h.promote(x, 'int');
+ expect(flow.promotedType(x).type, 'int');
+ // if (false) {
+ var falseExpression = _Expression();
+ flow.booleanLiteral(falseExpression, false);
+ flow.ifStatement_thenBegin(falseExpression);
+ expect(flow.promotedType(x).type, 'int');
+ flow.ifStatement_end(false);
+ });
+ });
});
group('State', () {
- var emptySet = FlowModel<_Var, _Type>(true).notAssigned;
var intVar = _Var('x', _Type('int'));
var intQVar = _Var('x', _Type('int?'));
var objectQVar = _Var('x', _Type('Object?'));
@@ -431,8 +930,7 @@
var s = initial.setReachable(newReachability);
expect(s, isNot(same(initial)));
expect(s.reachable, newReachability);
- expect(s.notAssigned, same(initial.notAssigned));
- expect(s.promoted, same(initial.promoted));
+ expect(s.variableInfo, same(initial.variableInfo));
}
_check(unreachable, true);
@@ -445,24 +943,21 @@
// By default, added variables are considered unassigned.
var s1 = FlowModel<_Var, _Type>(true);
var s2 = s1.add(intVar);
- expect(s2.notAssigned.contains(intVar), true);
expect(s2.reachable, true);
- expect(s2.promoted, {intVar: null});
+ expect(s2.variableInfo, {intVar: VariableModel<_Type>(null, false)});
});
test('unassigned', () {
var s1 = FlowModel<_Var, _Type>(true);
var s2 = s1.add(intVar, assigned: false);
- expect(s2.notAssigned.contains(intVar), true);
expect(s2.reachable, true);
- expect(s2.promoted, {intVar: null});
+ expect(s2.variableInfo, {intVar: VariableModel<_Type>(null, false)});
});
test('assigned', () {
var s1 = FlowModel<_Var, _Type>(true);
var s2 = s1.add(intVar, assigned: true);
- expect(s2.notAssigned.contains(intVar), false);
- expect(s2.promoted, {intVar: null});
+ expect(s2.variableInfo, {intVar: VariableModel<_Type>(null, true)});
});
});
@@ -493,9 +988,9 @@
var s1 = FlowModel<_Var, _Type>(true).add(intQVar);
var s2 = s1.promote(h, intQVar, _Type('int'));
expect(s2.reachable, true);
- expect(s2.notAssigned, same(s1.notAssigned));
_Type.allowComparisons(() {
- expect(s2.promoted, {intQVar: _Type('int')});
+ expect(s2.variableInfo,
+ {intQVar: VariableModel<_Type>(_Type('int'), false)});
});
});
@@ -533,9 +1028,9 @@
.promote(h, objectQVar, _Type('int?'));
var s2 = s1.promote(h, objectQVar, _Type('int'));
expect(s2.reachable, true);
- expect(s2.notAssigned, same(s1.notAssigned));
_Type.allowComparisons(() {
- expect(s2.promoted, {objectQVar: _Type('int')});
+ expect(s2.variableInfo,
+ {objectQVar: VariableModel<_Type>(_Type('int'), false)});
});
});
});
@@ -545,17 +1040,16 @@
test('unchanged', () {
var h = _Harness();
var s1 = FlowModel<_Var, _Type>(true).add(objectQVar, assigned: true);
- var s2 = s1.write(h, emptySet, objectQVar);
+ var s2 = s1.write(h, objectQVar);
expect(s2, same(s1));
});
test('marks as assigned', () {
var h = _Harness();
var s1 = FlowModel<_Var, _Type>(true).add(objectQVar, assigned: false);
- var s2 = s1.write(h, emptySet, objectQVar);
+ var s2 = s1.write(h, objectQVar);
expect(s2.reachable, true);
- expect(s2.notAssigned.contains(objectQVar), false);
- expect(s2.promoted, same(s1.promoted));
+ expect(s2.variableInfo[objectQVar], VariableModel<_Type>(null, true));
});
test('un-promotes', () {
@@ -563,11 +1057,10 @@
var s1 = FlowModel<_Var, _Type>(true)
.add(objectQVar, assigned: true)
.promote(h, objectQVar, _Type('int'));
- expect(s1.promoted, contains(objectQVar));
- var s2 = s1.write(h, emptySet, objectQVar);
+ expect(s1.variableInfo, contains(objectQVar));
+ var s2 = s1.write(h, objectQVar);
expect(s2.reachable, true);
- expect(s2.notAssigned, same(s1.notAssigned));
- expect(s2.promoted, {objectQVar: null});
+ expect(s2.variableInfo, {objectQVar: VariableModel<_Type>(null, true)});
});
});
@@ -584,8 +1077,9 @@
var s1 = FlowModel<_Var, _Type>(true).add(intQVar);
var s2 = s1.markNonNullable(h, intQVar);
expect(s2.reachable, true);
- expect(s2.notAssigned, same(s1.notAssigned));
- expect(s2.promoted[intQVar].type, 'int');
+ _Type.allowComparisons(() {
+ expect(s2.variableInfo[intQVar], VariableModel(_Type('int'), false));
+ });
});
test('promoted -> unchanged', () {
@@ -604,9 +1098,9 @@
.promote(h, objectQVar, _Type('int?'));
var s2 = s1.markNonNullable(h, objectQVar);
expect(s2.reachable, true);
- expect(s2.notAssigned, same(s1.notAssigned));
_Type.allowComparisons(() {
- expect(s2.promoted, {objectQVar: _Type('int')});
+ expect(s2.variableInfo,
+ {objectQVar: VariableModel<_Type>(_Type('int'), false)});
});
});
});
@@ -618,7 +1112,7 @@
.add(objectQVar)
.add(intQVar)
.promote(h, objectQVar, _Type('int'));
- var s2 = s1.removePromotedAll([intQVar].toSet());
+ var s2 = s1.removePromotedAll([intQVar], null);
expect(s2, same(s1));
});
@@ -629,11 +1123,13 @@
.add(intQVar)
.promote(h, objectQVar, _Type('int'))
.promote(h, intQVar, _Type('int'));
- var s2 = s1.removePromotedAll([intQVar].toSet());
+ var s2 = s1.removePromotedAll([intQVar], null);
expect(s2.reachable, true);
- expect(s2.notAssigned, same(s1.notAssigned));
_Type.allowComparisons(() {
- expect(s2.promoted, {objectQVar: _Type('int'), intQVar: null});
+ expect(s2.variableInfo, {
+ objectQVar: VariableModel<_Type>(_Type('int'), false),
+ intQVar: VariableModel<_Type>(null, false)
+ });
});
});
});
@@ -643,14 +1139,10 @@
var h = _Harness();
var reachable = FlowModel<_Var, _Type>(true);
var unreachable = reachable.setReachable(false);
- expect(
- reachable.restrict(h, emptySet, reachable, Set()), same(reachable));
- expect(reachable.restrict(h, emptySet, unreachable, Set()),
- same(unreachable));
- expect(unreachable.restrict(h, emptySet, unreachable, Set()),
- same(unreachable));
- expect(unreachable.restrict(h, emptySet, unreachable, Set()),
- same(unreachable));
+ expect(reachable.restrict(h, reachable, Set()), same(reachable));
+ expect(reachable.restrict(h, unreachable, Set()), same(unreachable));
+ expect(unreachable.restrict(h, unreachable, Set()), same(unreachable));
+ expect(unreachable.restrict(h, unreachable, Set()), same(unreachable));
});
test('assignments', () {
@@ -660,13 +1152,13 @@
var c = _Var('c', _Type('int'));
var d = _Var('d', _Type('int'));
var s0 = FlowModel<_Var, _Type>(true).add(a).add(b).add(c).add(d);
- var s1 = s0.write(h, emptySet, a).write(h, emptySet, b);
- var s2 = s0.write(h, emptySet, a).write(h, emptySet, c);
- var result = s1.restrict(h, emptySet, s2, Set());
- expect(result.notAssigned.contains(a), false);
- expect(result.notAssigned.contains(b), false);
- expect(result.notAssigned.contains(c), false);
- expect(result.notAssigned.contains(d), true);
+ var s1 = s0.write(h, a).write(h, b);
+ var s2 = s0.write(h, a).write(h, c);
+ var result = s1.restrict(h, s2, Set());
+ expect(result.variableInfo[a].assigned, true);
+ expect(result.variableInfo[b].assigned, true);
+ expect(result.variableInfo[c].assigned, true);
+ expect(result.variableInfo[d].assigned, false);
});
test('promotion', () {
@@ -677,13 +1169,12 @@
var s0 = FlowModel<_Var, _Type>(true).add(x, assigned: true);
var s1 = thisType == null ? s0 : s0.promote(h, x, _Type(thisType));
var s2 = otherType == null ? s0 : s0.promote(h, x, _Type(otherType));
- var result =
- s1.restrict(h, emptySet, s2, unsafe ? [x].toSet() : Set());
+ var result = s1.restrict(h, s2, unsafe ? [x].toSet() : Set());
if (expectedType == null) {
- expect(result.promoted, contains(x));
- expect(result.promoted[x], isNull);
+ expect(result.variableInfo, contains(x));
+ expect(result.variableInfo[x].promotedType, isNull);
} else {
- expect(result.promoted[x].type, expectedType);
+ expect(result.variableInfo[x].promotedType.type, expectedType);
}
}
@@ -706,77 +1197,97 @@
var x = _Var('x', _Type('Object?'));
var s0 = FlowModel<_Var, _Type>(true);
var s1 = s0.add(x, assigned: true);
- expect(s0.restrict(h, emptySet, s1, {}), same(s0));
- expect(s0.restrict(h, emptySet, s1, {x}), same(s0));
- expect(s1.restrict(h, emptySet, s0, {}), same(s1));
- expect(s1.restrict(h, emptySet, s0, {x}), same(s1));
+ expect(s0.restrict(h, s1, {}), same(s0));
+ expect(s0.restrict(h, s1, {x}), same(s0));
+ expect(s1.restrict(h, s0, {}), same(s1));
+ expect(s1.restrict(h, s0, {x}), same(s1));
});
});
});
group('join', () {
- group('should re-use an input if possible', () {
- var x = _Var('x', null);
- var y = _Var('y', null);
- var intType = _Type('int');
- var intQType = _Type('int?');
- var stringType = _Type('String');
- const emptyMap = <Null, Null>{};
+ var x = _Var('x', null);
+ var y = _Var('y', null);
+ var intType = _Type('int');
+ var intQType = _Type('int?');
+ var stringType = _Type('String');
+ const emptyMap = <Null, VariableModel<Null>>{};
+ VariableModel<_Type> model(_Type type) => VariableModel<_Type>(type, true);
+
+ group('without input reuse', () {
+ test('promoted with unpromoted', () {
+ var h = _Harness();
+ var p1 = {x: model(intType), y: model(null)};
+ var p2 = {x: model(null), y: model(intType)};
+ expect(FlowModel.joinVariableInfo(h, p1, p2),
+ {x: model(null), y: model(null)});
+ });
+ });
+ group('should re-use an input if possible', () {
test('identical inputs', () {
var h = _Harness();
- var p = {x: intType, y: stringType};
- expect(FlowModel.joinPromoted(h, p, p), same(p));
+ var p = {x: model(intType), y: model(stringType)};
+ expect(FlowModel.joinVariableInfo(h, p, p), same(p));
});
test('one input empty', () {
var h = _Harness();
- var p1 = {x: intType, y: stringType};
- var p2 = <_Var, _Type>{};
- expect(FlowModel.joinPromoted(h, p1, p2), same(emptyMap));
- expect(FlowModel.joinPromoted(h, p2, p1), same(emptyMap));
+ var p1 = {x: model(intType), y: model(stringType)};
+ var p2 = <_Var, VariableModel<_Type>>{};
+ expect(FlowModel.joinVariableInfo(h, p1, p2), same(emptyMap));
+ expect(FlowModel.joinVariableInfo(h, p2, p1), same(emptyMap));
+ });
+
+ test('promoted with unpromoted', () {
+ var h = _Harness();
+ var p1 = {x: model(intType)};
+ var p2 = {x: model(null)};
+ expect(FlowModel.joinVariableInfo(h, p1, p2), same(p2));
+ expect(FlowModel.joinVariableInfo(h, p2, p1), same(p2));
});
test('related types', () {
var h = _Harness();
- var p1 = {x: intType};
- var p2 = {x: intQType};
- expect(FlowModel.joinPromoted(h, p1, p2), same(p2));
- expect(FlowModel.joinPromoted(h, p2, p1), same(p2));
+ var p1 = {x: model(intType)};
+ var p2 = {x: model(intQType)};
+ expect(FlowModel.joinVariableInfo(h, p1, p2), same(p2));
+ expect(FlowModel.joinVariableInfo(h, p2, p1), same(p2));
});
test('unrelated types', () {
var h = _Harness();
- var p1 = {x: intType};
- var p2 = {x: stringType};
- expect(FlowModel.joinPromoted(h, p1, p2), {x: null});
- expect(FlowModel.joinPromoted(h, p2, p1), {x: null});
+ var p1 = {x: model(intType)};
+ var p2 = {x: model(stringType)};
+ expect(FlowModel.joinVariableInfo(h, p1, p2), {x: model(null)});
+ expect(FlowModel.joinVariableInfo(h, p2, p1), {x: model(null)});
});
test('sub-map', () {
var h = _Harness();
- var p1 = {x: intType, y: stringType};
- var p2 = {x: intType};
- expect(FlowModel.joinPromoted(h, p1, p2), same(p2));
- expect(FlowModel.joinPromoted(h, p2, p1), same(p2));
+ var xModel = model(intType);
+ var p1 = {x: xModel, y: model(stringType)};
+ var p2 = {x: xModel};
+ expect(FlowModel.joinVariableInfo(h, p1, p2), same(p2));
+ expect(FlowModel.joinVariableInfo(h, p2, p1), same(p2));
});
test('sub-map with matched subtype', () {
var h = _Harness();
- var p1 = {x: intType, y: stringType};
- var p2 = {x: intQType};
- expect(FlowModel.joinPromoted(h, p1, p2), same(p2));
- expect(FlowModel.joinPromoted(h, p2, p1), same(p2));
+ var p1 = {x: model(intType), y: model(stringType)};
+ var p2 = {x: model(intQType)};
+ expect(FlowModel.joinVariableInfo(h, p1, p2), same(p2));
+ expect(FlowModel.joinVariableInfo(h, p2, p1), same(p2));
});
test('sub-map with mismatched subtype', () {
var h = _Harness();
- var p1 = {x: intQType, y: stringType};
- var p2 = {x: intType};
- var join12 = FlowModel.joinPromoted(h, p1, p2);
- _Type.allowComparisons(() => expect(join12, {x: intQType}));
- var join21 = FlowModel.joinPromoted(h, p2, p1);
- _Type.allowComparisons(() => expect(join21, {x: intQType}));
+ var p1 = {x: model(intQType), y: model(stringType)};
+ var p2 = {x: model(intType)};
+ var join12 = FlowModel.joinVariableInfo(h, p1, p2);
+ _Type.allowComparisons(() => expect(join12, {x: model(intQType)}));
+ var join21 = FlowModel.joinVariableInfo(h, p2, p1);
+ _Type.allowComparisons(() => expect(join21, {x: model(intQType)}));
});
});
});
@@ -811,26 +1322,15 @@
NodeOperations<_Expression>,
TypeOperations<_Var, _Type>,
FunctionBodyAccess<_Var> {
- FlowAnalysis<_Statement, _Expression, _Var, _Type> flow;
-
- _Harness() {
- flow = FlowAnalysis<_Statement, _Expression, _Var, _Type>(this, this, this);
- }
+ FlowAnalysis<_Statement, _Expression, _Var, _Type> _flow;
/// Returns a [LazyExpression] representing an expression with now special
/// flow analysis semantics.
LazyExpression get expr => () => _Expression();
- _Var addAssignedVar(String name, String type) {
- var v = _Var(name, _Type(type));
- flow.add(v, assigned: true);
- return v;
- }
-
- _Var addUnassignedVar(String name, String type) {
- var v = _Var(name, _Type(type));
- flow.add(v, assigned: false);
- return v;
+ _Var addVar(String name, String type) {
+ assert(_flow == null);
+ return _Var(name, _Type(type));
}
/// Given two [LazyExpression]s, produces a new [LazyExpression] representing
@@ -838,8 +1338,8 @@
LazyExpression and(LazyExpression lhs, LazyExpression rhs) {
return () {
var expr = _Expression();
- flow.logicalBinaryOp_rightBegin(lhs(), isAnd: true);
- flow.logicalBinaryOp_end(expr, rhs(), isAnd: true);
+ _flow.logicalBinaryOp_rightBegin(lhs(), isAnd: true);
+ _flow.logicalBinaryOp_end(expr, rhs(), isAnd: true);
return expr;
};
}
@@ -850,37 +1350,44 @@
LazyExpression cond, LazyExpression ifTrue, LazyExpression ifFalse) {
return () {
var expr = _Expression();
- flow.conditional_thenBegin(cond());
- flow.conditional_elseBegin(ifTrue());
- flow.conditional_end(expr, ifFalse());
+ _flow.conditional_thenBegin(cond());
+ _flow.conditional_elseBegin(ifTrue());
+ _flow.conditional_end(expr, ifFalse());
return expr;
};
}
+ FlowAnalysis<_Statement, _Expression, _Var, _Type> createFlow() =>
+ FlowAnalysis<_Statement, _Expression, _Var, _Type>(this, this, this);
+
+ void declare(_Var v, {@required bool initialized}) {
+ _flow.add(v, assigned: initialized);
+ }
+
/// Creates a [LazyExpression] representing an `== null` check performed on
/// [variable].
LazyExpression eqNull(_Var variable) {
return () {
var expr = _Expression();
- flow.conditionEqNull(expr, variable, notEqual: false);
+ _flow.conditionEqNull(expr, variable, notEqual: false);
return expr;
};
}
/// Invokes flow analysis of an `if` statement with no `else` part.
void if_(LazyExpression cond, void ifTrue()) {
- flow.ifStatement_thenBegin(cond());
+ _flow.ifStatement_thenBegin(cond());
ifTrue();
- flow.ifStatement_end(false);
+ _flow.ifStatement_end(false);
}
/// Invokes flow analysis of an `if` statement with an `else` part.
void ifElse(LazyExpression cond, void ifTrue(), void ifFalse()) {
- flow.ifStatement_thenBegin(cond());
+ _flow.ifStatement_thenBegin(cond());
ifTrue();
- flow.ifStatement_elseBegin();
+ _flow.ifStatement_elseBegin();
ifFalse();
- flow.ifStatement_end(false);
+ _flow.ifStatement_end(false);
}
@override
@@ -894,7 +1401,7 @@
LazyExpression isNotType(_Var variable, String type) {
return () {
var expr = _Expression();
- flow.isExpression_end(expr, variable, true, _Type(type));
+ _flow.isExpression_end(expr, variable, true, _Type(type));
return expr;
};
}
@@ -940,7 +1447,7 @@
LazyExpression notNull(_Var variable) {
return () {
var expr = _Expression();
- flow.conditionEqNull(expr, variable, notEqual: true);
+ _flow.conditionEqNull(expr, variable, notEqual: true);
return expr;
};
}
@@ -950,15 +1457,15 @@
LazyExpression or(LazyExpression lhs, LazyExpression rhs) {
return () {
var expr = _Expression();
- flow.logicalBinaryOp_rightBegin(lhs(), isAnd: false);
- flow.logicalBinaryOp_end(expr, rhs(), isAnd: false);
+ _flow.logicalBinaryOp_rightBegin(lhs(), isAnd: false);
+ _flow.logicalBinaryOp_end(expr, rhs(), isAnd: false);
return expr;
};
}
/// Causes [variable] to be promoted to [type].
void promote(_Var variable, String type) {
- if_(isNotType(variable, type), flow.handleExit);
+ if_(isNotType(variable, type), _flow.handleExit);
}
@override
@@ -970,6 +1477,14 @@
}
}
+ void run(
+ void callback(FlowAnalysis<_Statement, _Expression, _Var, _Type> flow)) {
+ assert(_flow == null);
+ _flow = createFlow();
+ callback(_flow);
+ _flow.finish();
+ }
+
@override
_Expression unwrapParenthesized(_Expression node) {
// TODO(paulberry): test cases where this matters
diff --git a/pkg/front_end/test/fasta/generator_to_string_test.dart b/pkg/front_end/test/fasta/generator_to_string_test.dart
index f130cba..30206f6 100644
--- a/pkg/front_end/test/fasta/generator_to_string_test.dart
+++ b/pkg/front_end/test/fasta/generator_to_string_test.dart
@@ -97,7 +97,9 @@
VariableDeclaration variable = new VariableDeclaration(null);
BodyBuilder helper = new BodyBuilder(
- library: libraryBuilder, isDeclarationInstanceMember: false, uri: uri);
+ libraryBuilder: libraryBuilder,
+ isDeclarationInstanceMember: false,
+ uri: uri);
Generator generator = new ThisAccessGenerator(helper, token, false, false);
diff --git a/pkg/front_end/test/fasta/incremental_hello_test.dart b/pkg/front_end/test/fasta/incremental_hello_test.dart
index 06004bc..ccafee3 100644
--- a/pkg/front_end/test/fasta/incremental_hello_test.dart
+++ b/pkg/front_end/test/fasta/incremental_hello_test.dart
@@ -47,7 +47,7 @@
} else {
optionBuilder.sdkSummary =
computePlatformBinariesLocation(forceBuildDir: true)
- .resolve("vm_platform.dill");
+ .resolve("vm_platform_strong.dill");
}
final Uri helloDart =
diff --git a/pkg/front_end/test/fasta/incremental_test.dart b/pkg/front_end/test/fasta/incremental_test.dart
index 4208d17..59c2e1d 100644
--- a/pkg/front_end/test/fasta/incremental_test.dart
+++ b/pkg/front_end/test/fasta/incremental_test.dart
@@ -209,12 +209,12 @@
Future<Context> createContext(
Chain suite, Map<String, String> environment) async {
/// The custom URI used to locate the dill file in the MemoryFileSystem.
- final Uri sdkSummary = base.resolve("vm_platform.dill");
+ final Uri sdkSummary = base.resolve("vm_platform_strong.dill");
/// The actual location of the dill file.
final Uri sdkSummaryFile =
computePlatformBinariesLocation(forceBuildDir: true)
- .resolve("vm_platform.dill");
+ .resolve("vm_platform_strong.dill");
final MemoryFileSystem fs = new MemoryFileSystem(base);
@@ -246,4 +246,4 @@
}
main([List<String> arguments = const []]) =>
- runMe(arguments, createContext, "../../testing.json");
+ runMe(arguments, createContext, configurationPath: "../../testing.json");
diff --git a/pkg/front_end/test/fasta/messages_test.dart b/pkg/front_end/test/fasta/messages_test.dart
index e2f30c9..08e960e 100644
--- a/pkg/front_end/test/fasta/messages_test.dart
+++ b/pkg/front_end/test/fasta/messages_test.dart
@@ -663,4 +663,4 @@
}
main([List<String> arguments = const []]) =>
- runMe(arguments, createContext, "../../testing.json");
+ runMe(arguments, createContext, configurationPath: "../../testing.json");
diff --git a/pkg/front_end/test/fasta/outline_test.dart b/pkg/front_end/test/fasta/outline_test.dart
index 43e9cc9..cc5ec1d 100644
--- a/pkg/front_end/test/fasta/outline_test.dart
+++ b/pkg/front_end/test/fasta/outline_test.dart
@@ -14,4 +14,4 @@
}
main([List<String> arguments = const []]) =>
- runMe(arguments, createContext, "../../testing.json");
+ runMe(arguments, createContext, configurationPath: "../../testing.json");
diff --git a/pkg/front_end/test/fasta/parser/parser_suite.dart b/pkg/front_end/test/fasta/parser/parser_suite.dart
index ad15a8f..e2321af 100644
--- a/pkg/front_end/test/fasta/parser/parser_suite.dart
+++ b/pkg/front_end/test/fasta/parser/parser_suite.dart
@@ -2,11 +2,12 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE.md file.
-import 'package:testing/testing.dart';
+import 'package:front_end/src/fasta/parser.dart' show ParserError, parse;
-import 'package:front_end/src/fasta/testing/scanner_chain.dart';
+import 'package:testing/testing.dart'
+ show Chain, ChainContext, Future, Result, Step, runMe;
-import 'package:front_end/src/fasta/parser.dart';
+import '../../utils/scanner_chain.dart' show Read, Scan, ScannedFile;
Future<ChainContext> createContext(
Chain suite, Map<String, String> environment) async {
@@ -40,4 +41,4 @@
}
main(List<String> arguments) =>
- runMe(arguments, createContext, "../../../testing.json");
+ runMe(arguments, createContext, configurationPath: "../../../testing.json");
diff --git a/pkg/front_end/test/fasta/scanner/scanner_suite.dart b/pkg/front_end/test/fasta/scanner/scanner_suite.dart
index 8ca4f7a..1fb6f442 100644
--- a/pkg/front_end/test/fasta/scanner/scanner_suite.dart
+++ b/pkg/front_end/test/fasta/scanner/scanner_suite.dart
@@ -2,9 +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.md file.
-import 'package:testing/testing.dart';
+import 'package:testing/testing.dart'
+ show Chain, ChainContext, Future, Step, runMe;
-import 'package:front_end/src/fasta/testing/scanner_chain.dart';
+import '../../utils/scanner_chain.dart' show Read, Scan;
Future<ChainContext> createContext(
Chain suite, Map<String, String> environment) async {
@@ -19,4 +20,4 @@
}
main(List<String> arguments) =>
- runMe(arguments, createContext, "../../../testing.json");
+ runMe(arguments, createContext, configurationPath: "../../../testing.json");
diff --git a/pkg/front_end/test/fasta/strong1_test.dart b/pkg/front_end/test/fasta/strong1_test.dart
new file mode 100644
index 0000000..cb30b7e
--- /dev/null
+++ b/pkg/front_end/test/fasta/strong1_test.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2019, 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.md file.
+
+import 'strong_tester.dart';
+
+main(List<String> arguments) {
+ internalMain(arguments: arguments, shards: shardCount, shard: 0);
+}
diff --git a/pkg/front_end/test/fasta/strong2_test.dart b/pkg/front_end/test/fasta/strong2_test.dart
new file mode 100644
index 0000000..10fafaf
--- /dev/null
+++ b/pkg/front_end/test/fasta/strong2_test.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2019, 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.md file.
+
+import 'strong_tester.dart';
+
+main(List<String> arguments) {
+ internalMain(arguments: arguments, shards: shardCount, shard: 1);
+}
diff --git a/pkg/front_end/test/fasta/strong3_test.dart b/pkg/front_end/test/fasta/strong3_test.dart
new file mode 100644
index 0000000..044c7e8
--- /dev/null
+++ b/pkg/front_end/test/fasta/strong3_test.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2019, 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.md file.
+
+import 'strong_tester.dart';
+
+main(List<String> arguments) {
+ internalMain(arguments: arguments, shards: shardCount, shard: 2);
+}
diff --git a/pkg/front_end/test/fasta/strong4_test.dart b/pkg/front_end/test/fasta/strong4_test.dart
new file mode 100644
index 0000000..9e459e3
--- /dev/null
+++ b/pkg/front_end/test/fasta/strong4_test.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2019, 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.md file.
+
+import 'strong_tester.dart';
+
+main(List<String> arguments) {
+ internalMain(arguments: arguments, shards: shardCount, shard: 3);
+}
diff --git a/pkg/front_end/test/fasta/strong_test.dart b/pkg/front_end/test/fasta/strong_test.dart
deleted file mode 100644
index e8e430d..0000000
--- a/pkg/front_end/test/fasta/strong_test.dart
+++ /dev/null
@@ -1,18 +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.md file.
-
-library fasta.test.strong_test;
-
-import 'dart:async' show Future;
-
-import 'testing/suite.dart';
-
-Future<FastaContext> createContext(
- Chain suite, Map<String, String> environment) {
- environment[ENABLE_FULL_COMPILE] = "";
- return FastaContext.create(suite, environment);
-}
-
-main([List<String> arguments = const []]) =>
- runMe(arguments, createContext, "../../testing.json");
diff --git a/pkg/front_end/test/fasta/strong_tester.dart b/pkg/front_end/test/fasta/strong_tester.dart
new file mode 100644
index 0000000..402ff57
--- /dev/null
+++ b/pkg/front_end/test/fasta/strong_tester.dart
@@ -0,0 +1,31 @@
+// 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.md file.
+
+library fasta.test.strong_test;
+
+import 'dart:async' show Future;
+import 'dart:io' show Platform;
+
+import 'testing/suite.dart';
+
+const int shardCount = 4;
+
+Future<FastaContext> createContext(
+ Chain suite, Map<String, String> environment) {
+ environment[ENABLE_FULL_COMPILE] = "";
+ return FastaContext.create(suite, environment);
+}
+
+main(List<String> arguments) {
+ internalMain(arguments: arguments);
+}
+
+internalMain(
+ {List<String> arguments = const [], int shards = 1, int shard = 0}) {
+ runMe(arguments, createContext,
+ configurationPath: "../../testing.json",
+ me: Platform.script.resolve('strong_tester.dart'),
+ shards: shards,
+ shard: shard);
+}
diff --git a/pkg/front_end/test/fasta/testing/suite.dart b/pkg/front_end/test/fasta/testing/suite.dart
index 420ed92..4170490 100644
--- a/pkg/front_end/test/fasta/testing/suite.dart
+++ b/pkg/front_end/test/fasta/testing/suite.dart
@@ -10,31 +10,12 @@
import 'dart:io' show Directory, File, Platform;
-import 'package:front_end/src/api_prototype/compiler_options.dart';
-import 'package:kernel/ast.dart'
- show AwaitExpression, Component, Library, Node, Visitor;
-
-import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
-
-import 'package:kernel/core_types.dart' show CoreTypes;
-
-import 'package:kernel/kernel.dart' show loadComponentFromBytes;
-
-import 'package:kernel/target/targets.dart'
- show TargetFlags, DiagnosticReporter;
-
-import 'package:testing/testing.dart'
+import 'package:front_end/src/api_prototype/compiler_options.dart'
show
- Chain,
- ChainContext,
- Expectation,
- ExpectationSet,
- Result,
- Step,
- TestDescription,
- StdioProcess;
-
-import 'package:vm/target/vm.dart' show VmTarget;
+ CompilerOptions,
+ DiagnosticMessage,
+ parseExperimentalArguments,
+ parseExperimentalFlags;
import 'package:front_end/src/api_prototype/compiler_options.dart'
show CompilerOptions, DiagnosticMessage;
@@ -67,7 +48,36 @@
import 'package:front_end/src/fasta/kernel/kernel_target.dart'
show KernelTarget;
-import 'package:front_end/src/fasta/testing/kernel_chain.dart'
+import 'package:front_end/src/fasta/ticker.dart' show Ticker;
+
+import 'package:front_end/src/fasta/uri_translator.dart' show UriTranslator;
+
+import 'package:kernel/ast.dart'
+ show AwaitExpression, Component, Library, Node, Visitor;
+
+import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
+
+import 'package:kernel/core_types.dart' show CoreTypes;
+
+import 'package:kernel/kernel.dart' show loadComponentFromBytes;
+
+import 'package:kernel/target/targets.dart'
+ show TargetFlags, DiagnosticReporter;
+
+import 'package:testing/testing.dart'
+ show
+ Chain,
+ ChainContext,
+ Expectation,
+ ExpectationSet,
+ Result,
+ Step,
+ TestDescription,
+ StdioProcess;
+
+import 'package:vm/target/vm.dart' show VmTarget;
+
+import '../../utils/kernel_chain.dart'
show
KernelTextSerialization,
MatchContext,
@@ -77,13 +87,9 @@
Verify,
WriteDill;
-import 'package:front_end/src/fasta/testing/validating_instrumentation.dart'
+import '../../utils/validating_instrumentation.dart'
show ValidatingInstrumentation;
-import 'package:front_end/src/fasta/ticker.dart' show Ticker;
-
-import 'package:front_end/src/fasta/uri_translator.dart' show UriTranslator;
-
export 'package:testing/testing.dart' show Chain, runMe;
const String ENABLE_FULL_COMPILE = " full compile ";
diff --git a/pkg/front_end/test/fasta/text_serialization_test.dart b/pkg/front_end/test/fasta/text_serialization_test.dart
index 07ecb85..fa51b54 100644
--- a/pkg/front_end/test/fasta/text_serialization_test.dart
+++ b/pkg/front_end/test/fasta/text_serialization_test.dart
@@ -16,4 +16,4 @@
}
main([List<String> arguments = const []]) =>
- runMe(arguments, createContext, "../../testing.json");
+ runMe(arguments, createContext, configurationPath: "../../testing.json");
diff --git a/pkg/front_end/test/fasta/type_inference/type_schema_test.dart b/pkg/front_end/test/fasta/type_inference/type_schema_test.dart
index 8bc8c5c..471b69d 100644
--- a/pkg/front_end/test/fasta/type_inference/type_schema_test.dart
+++ b/pkg/front_end/test/fasta/type_inference/type_schema_test.dart
@@ -117,7 +117,7 @@
}
}
-class _TypeSchemaVisitor<R> extends Visitor<R> implements TypeSchemaVisitor<R> {
+class _TypeSchemaVisitor<R> extends Visitor<R> {
final _UnaryFunction<DartType, R> _defaultDartType;
final _UnaryFunction<UnknownType, R> _visitUnknownType;
@@ -129,19 +129,12 @@
@override
R defaultDartType(DartType node) {
- if (_defaultDartType != null) {
+ if (node is UnknownType && _visitUnknownType != null) {
+ return _visitUnknownType(node);
+ } else if (_defaultDartType != null) {
return _defaultDartType(node);
} else {
return super.defaultDartType(node);
}
}
-
- @override
- R visitUnknownType(UnknownType node) {
- if (_visitUnknownType != null) {
- return _visitUnknownType(node);
- } else {
- return defaultDartType(node);
- }
- }
}
diff --git a/pkg/front_end/test/fasta/type_promotion_look_ahead_test.dart b/pkg/front_end/test/fasta/type_promotion_look_ahead_test.dart
index ebc39e7..398f5a1 100644
--- a/pkg/front_end/test/fasta/type_promotion_look_ahead_test.dart
+++ b/pkg/front_end/test/fasta/type_promotion_look_ahead_test.dart
@@ -26,15 +26,14 @@
TypePromotionState,
UnspecifiedDeclaration;
-import 'package:front_end/src/fasta/testing/kernel_chain.dart'
- show MatchContext;
-
-import 'package:front_end/src/fasta/testing/scanner_chain.dart'
- show Read, Scan, ScannedFile;
-
import 'package:kernel/ast.dart' show Source;
-import 'package:testing/testing.dart';
+import 'package:testing/testing.dart'
+ show Chain, ChainContext, ExpectationSet, Future, Result, Step, runMe;
+
+import '../utils/kernel_chain.dart' show MatchContext;
+
+import '../utils/scanner_chain.dart' show Read, Scan, ScannedFile;
const String EXPECTATIONS = '''
[
@@ -228,4 +227,4 @@
}
main([List<String> arguments = const []]) =>
- runMe(arguments, createContext, "../../testing.json");
+ runMe(arguments, createContext, configurationPath: "../../testing.json");
diff --git a/pkg/front_end/test/fasta/types/dill_hierachy_test.dart b/pkg/front_end/test/fasta/types/dill_hierachy_test.dart
index 56053fa..80393e4 100644
--- a/pkg/front_end/test/fasta/types/dill_hierachy_test.dart
+++ b/pkg/front_end/test/fasta/types/dill_hierachy_test.dart
@@ -69,7 +69,7 @@
Longest path to Object: 3
superclasses:
Object
- interfaces: B<T>, A, C<U>
+ interfaces: B<T>*, A, C<U>*
classMembers:
classSetters:
interfaceMembers:
@@ -79,7 +79,7 @@
Longest path to Object: 4
superclasses:
Object
- interfaces: D<int, double>, B<int>, A, C<double>
+ interfaces: D<int, double>*, B<int>*, A, C<double>*
classMembers:
classSetters:
interfaceMembers:
@@ -89,7 +89,7 @@
Longest path to Object: 4
superclasses:
Object
- interfaces: D<int, bool>, B<int>, A, C<bool>
+ interfaces: D<int, bool>*, B<int>*, A, C<bool>*
classMembers:
classSetters:
interfaceMembers:
diff --git a/pkg/front_end/test/fasta/types/kernel_type_parser.dart b/pkg/front_end/test/fasta/types/kernel_type_parser.dart
index 128559f..4d47cf6 100644
--- a/pkg/front_end/test/fasta/types/kernel_type_parser.dart
+++ b/pkg/front_end/test/fasta/types/kernel_type_parser.dart
@@ -14,6 +14,7 @@
Library,
NamedType,
Node,
+ Nullability,
Supertype,
TreeNode,
TypeParameter,
@@ -40,6 +41,7 @@
ParsedTypedef,
ParsedVoidType,
Visitor;
+import 'type_parser.dart';
Component parseComponent(String source, Uri uri) {
Uri coreUri = Uri.parse("dart:core");
@@ -90,6 +92,18 @@
final KernelEnvironment parent;
+ /// Collects types to set their nullabilities after type parameters are ready.
+ ///
+ /// [TypeParameterType]s may receive their nullability at the declaration or
+ /// from the bound of the [TypeParameter]s they refer to. If a
+ /// [TypeParameterType] is allocated at the time when the bound of the
+ /// [TypeParameter] is not set yet, that is, if it's encountered in that
+ /// bound or the bound of other [TypeParameter] from the same scope, and the
+ /// nullability of that [TypeParameterType] is not set at declaration, the
+ /// [TypeParameterType] is added to [pendingNullabilities], so that it can be
+ /// updated when the bound of the [TypeParameter] is ready.
+ final List<TypeParameterType> pendingNullabilities = <TypeParameterType>[];
+
KernelEnvironment(this.uri, this.fileUri, [this.parent]);
Node kernelFromParsedType(ParsedType type) {
@@ -161,14 +175,31 @@
} else if (kernelArguments.length != typeVariables.length) {
throw "Expected ${typeVariables.length} type arguments: $node";
}
- return new InterfaceType(declaration, kernelArguments, node.nullability);
+ return new InterfaceType(declaration, kernelArguments,
+ interpretParsedNullability(node.parsedNullability));
} else if (declaration is TypeParameter) {
if (arguments.isNotEmpty) {
throw "Type variable can't have arguments (${node.name})";
}
- return new TypeParameterType(declaration, null, node.nullability);
+ Nullability nullability = declaration.bound == null
+ ? null
+ : TypeParameterType.computeNullabilityFromBound(declaration);
+ TypeParameterType type = new TypeParameterType(
+ declaration,
+ null,
+ interpretParsedNullability(node.parsedNullability,
+ ifOmitted: nullability));
+ // If the nullability was omitted on the type and can't be computed from
+ // the bound because it's not yet available, it will be set to null. In
+ // that case, put it to the list to be updated later, when the bound is
+ // available.
+ if (type.declaredNullability == null) {
+ environment.pendingNullabilities.add(type);
+ }
+ return type;
} else if (declaration is Typedef) {
- return new TypedefType(declaration, kernelArguments, node.nullability);
+ return new TypedefType(declaration, kernelArguments,
+ interpretParsedNullability(node.parsedNullability));
} else {
throw "Unhandled ${declaration.runtimeType}";
}
@@ -264,7 +295,7 @@
namedParameters: namedParameters,
requiredParameterCount: node.arguments.required.length,
typeParameters: parameterEnvironment.parameters,
- nullability: node.nullability);
+ nullability: interpretParsedNullability(node.parsedNullability));
}
VoidType visitVoidType(ParsedVoidType node, KernelEnvironment environment) {
@@ -322,6 +353,12 @@
for (int i = 0; i < typeParameters.length; i++) {
typeParameters[i].defaultType = defaultTypes[i];
}
+
+ for (TypeParameterType type in nestedEnvironment.pendingNullabilities) {
+ type.declaredNullability =
+ TypeParameterType.computeNullabilityFromBound(type.parameter);
+ }
+ nestedEnvironment.pendingNullabilities.clear();
return new ParameterEnvironment(typeParameters, nestedEnvironment);
}
}
diff --git a/pkg/front_end/test/fasta/types/type_parser.dart b/pkg/front_end/test/fasta/types/type_parser.dart
index a40bbdf..c9e0592 100644
--- a/pkg/front_end/test/fasta/types/type_parser.dart
+++ b/pkg/front_end/test/fasta/types/type_parser.dart
@@ -2,25 +2,53 @@
// 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" show Nullability;
+import 'package:kernel/ast.dart' show Nullability;
import "package:front_end/src/fasta/scanner.dart" show scanString, Token;
import "package:front_end/src/fasta/parser/type_info_impl.dart"
show splitCloser;
+import "package:front_end/src/fasta/problems.dart";
+import 'package:kernel/text/text_serialization_verifier.dart';
+
abstract class ParsedType {
R accept<R, A>(Visitor<R, A> visitor, [A a]);
}
+enum ParsedNullability {
+ // Used when the type is declared with the '?' suffix.
+ nullable,
+
+ // Used when the type is declared with the '*' suffix.
+ legacy,
+
+ // Used when the nullability suffix is omitted after the type declaration.
+ omitted,
+}
+
+Nullability interpretParsedNullability(ParsedNullability parsedNullability,
+ {Nullability ifOmitted = Nullability.nonNullable}) {
+ switch (parsedNullability) {
+ case ParsedNullability.nullable:
+ return Nullability.nullable;
+ case ParsedNullability.legacy:
+ return Nullability.legacy;
+ case ParsedNullability.omitted:
+ return ifOmitted;
+ }
+ return unhandled(
+ "$parsedNullability", "interpretParsedNullability", noOffset, noUri);
+}
+
class ParsedInterfaceType extends ParsedType {
final String name;
final List<ParsedType> arguments;
- final Nullability nullability;
+ final ParsedNullability parsedNullability;
- ParsedInterfaceType(this.name, this.arguments, this.nullability);
+ ParsedInterfaceType(this.name, this.arguments, this.parsedNullability);
String toString() {
StringBuffer sb = new StringBuffer();
@@ -120,10 +148,10 @@
final ParsedArguments arguments;
- final Nullability nullability;
+ final ParsedNullability parsedNullability;
- ParsedFunctionType(
- this.typeVariables, this.returnType, this.arguments, this.nullability);
+ ParsedFunctionType(this.typeVariables, this.returnType, this.arguments,
+ this.parsedNullability);
String toString() {
StringBuffer sb = new StringBuffer();
@@ -268,12 +296,12 @@
}
}
- Nullability parseNullability() {
- Nullability result = Nullability.nonNullable;
+ ParsedNullability parseNullability() {
+ ParsedNullability result = ParsedNullability.omitted;
if (optionalAdvance("?")) {
- result = Nullability.nullable;
+ result = ParsedNullability.nullable;
} else if (optionalAdvance("*")) {
- result = Nullability.legacy;
+ result = ParsedNullability.legacy;
}
return result;
}
@@ -288,7 +316,7 @@
type = parseFunctionType();
} else if (optionalAdvance("void")) {
type = new ParsedInterfaceType(
- "void", <ParsedType>[], Nullability.nullable);
+ "void", <ParsedType>[], ParsedNullability.nullable);
optionalAdvance("?");
} else {
String name = parseName();
@@ -303,8 +331,8 @@
peek = splitCloser(peek) ?? peek;
expect(">");
}
- Nullability nullability = parseNullability();
- type = new ParsedInterfaceType(name, arguments, nullability);
+ ParsedNullability parsedNullability = parseNullability();
+ type = new ParsedInterfaceType(name, arguments, parsedNullability);
}
if (result == null) {
result = type;
@@ -325,10 +353,10 @@
ParsedArguments arguments = parseArguments();
expect("-");
expect(">");
- Nullability nullability = parseNullability();
+ ParsedNullability parsedNullability = parseNullability();
ParsedType returnType = parseReturnType();
return new ParsedFunctionType(
- typeVariables, returnType, arguments, nullability);
+ typeVariables, returnType, arguments, parsedNullability);
}
String parseName() {
diff --git a/pkg/front_end/test/fasta/unlinked_scope_test.dart b/pkg/front_end/test/fasta/unlinked_scope_test.dart
index 69e04e0..05a25dc 100644
--- a/pkg/front_end/test/fasta/unlinked_scope_test.dart
+++ b/pkg/front_end/test/fasta/unlinked_scope_test.dart
@@ -67,7 +67,7 @@
MockBodyBuilder.internal(
MockLibraryBuilder libraryBuilder, String name, Scope scope)
: super(
- library: libraryBuilder,
+ libraryBuilder: libraryBuilder,
member: libraryBuilder.mockProcedure(name),
enclosingScope: scope,
formalParameterScope: scope,
diff --git a/pkg/front_end/test/flow_analysis/reachability/data/switch.dart b/pkg/front_end/test/flow_analysis/reachability/data/switch.dart
index 82e0b50..a257adb 100644
--- a/pkg/front_end/test/flow_analysis/reachability/data/switch.dart
+++ b/pkg/front_end/test/flow_analysis/reachability/data/switch.dart
@@ -15,3 +15,22 @@
}
3;
}
+
+void case_falls_through_end(int i) {
+ switch (i) {
+ case 1:
+ 1;
+ }
+ 2;
+}
+
+/*member: all_cases_exit:doesNotComplete*/
+void all_cases_exit(int i) {
+ switch (i) {
+ case 1:
+ return;
+ default:
+ return;
+ }
+ /*stmt: unreachable*/ 1;
+}
diff --git a/pkg/front_end/test/flow_analysis/type_promotion/data/for.dart b/pkg/front_end/test/flow_analysis/type_promotion/data/for.dart
index 19c4b8f..81e631f 100644
--- a/pkg/front_end/test/flow_analysis/type_promotion/data/for.dart
+++ b/pkg/front_end/test/flow_analysis/type_promotion/data/for.dart
@@ -29,6 +29,17 @@
}
}
+void for_outerIsType_loopAssigned_body_emptyCondition(bool b, Object x) {
+ if (x is String) {
+ for (;;) {
+ if (!b) break;
+ x;
+ x = 42;
+ }
+ x;
+ }
+}
+
void for_outerIsType_loopAssigned_condition(Object x) {
if (x is String) {
for (; (x = 42) > 0;) {
@@ -47,6 +58,16 @@
}
}
+void for_outerIsType_loopAssigned_updaters_emptyCondition(bool b, Object x) {
+ if (x is String) {
+ for (;; x = 42) {
+ if (!b) break;
+ x;
+ }
+ x;
+ }
+}
+
void forEach_outerIsType_loopAssigned(Object x) {
if (x is String) {
for (var _ in [0, 1, 2]) {
@@ -77,6 +98,15 @@
}
}
+void collection_for_outerIsType_loopAssigned_body_emptyCondition(Object x) {
+ if (x is String) {
+ [
+ for (;;) [x, (x = 42)]
+ ];
+ x;
+ }
+}
+
void collection_for_outerIsType_loopAssigned_condition(Object x) {
if (x is String) {
[for (; (x = 42) > 0;) x];
@@ -91,6 +121,13 @@
}
}
+void collection_for_outerIsType_loopAssigned_updaters_emptyCondition(Object x) {
+ if (x is String) {
+ [for (;; x = 42) x];
+ x;
+ }
+}
+
void collection_forEach_outerIsType_loopAssigned(Object x) {
if (x is String) {
[
@@ -99,3 +136,10 @@
x;
}
}
+
+void assign_var_declared_in_loop() {
+ for (int x = 0; x < 10; x++) {
+ bool b = true;
+ b = false;
+ }
+}
diff --git a/pkg/front_end/test/flow_analysis/type_promotion/data/switch.dart b/pkg/front_end/test/flow_analysis/type_promotion/data/switch.dart
index 9939bb7..ecaaa0a 100644
--- a/pkg/front_end/test/flow_analysis/type_promotion/data/switch.dart
+++ b/pkg/front_end/test/flow_analysis/type_promotion/data/switch.dart
@@ -19,3 +19,15 @@
x;
}
}
+
+void case_falls_through_end(int i, Object o) {
+ switch (i) {
+ case 1:
+ if (o is! int) return;
+ /*int*/ o;
+ break;
+ case 2:
+ o;
+ }
+ o;
+}
diff --git a/pkg/front_end/test/incremental_bulk_compiler_full.dart b/pkg/front_end/test/incremental_bulk_compiler_full.dart
index cc73543..ad1a7f3 100644
--- a/pkg/front_end/test/incremental_bulk_compiler_full.dart
+++ b/pkg/front_end/test/incremental_bulk_compiler_full.dart
@@ -29,7 +29,7 @@
import 'incremental_utils.dart' as util;
main([List<String> arguments = const []]) =>
- runMe(arguments, createContext, "../testing.json");
+ runMe(arguments, createContext, configurationPath: "../testing.json");
Future<Context> createContext(
Chain suite, Map<String, String> environment) async {
diff --git a/pkg/front_end/test/incremental_bulk_compiler_smoke_test.dart b/pkg/front_end/test/incremental_bulk_compiler_smoke_test.dart
index 5399635..866104c 100644
--- a/pkg/front_end/test/incremental_bulk_compiler_smoke_test.dart
+++ b/pkg/front_end/test/incremental_bulk_compiler_smoke_test.dart
@@ -9,7 +9,7 @@
import 'incremental_bulk_compiler_full.dart' show Context;
main([List<String> arguments = const []]) =>
- runMe(arguments, createContext, "../testing.json");
+ runMe(arguments, createContext, configurationPath: "../testing.json");
Future<Context> createContext(
Chain suite, Map<String, String> environment) async {
diff --git a/pkg/front_end/test/incremental_load_from_dill_test.dart b/pkg/front_end/test/incremental_load_from_dill_test.dart
index b88f426..d258364 100644
--- a/pkg/front_end/test/incremental_load_from_dill_test.dart
+++ b/pkg/front_end/test/incremental_load_from_dill_test.dart
@@ -54,13 +54,17 @@
import "package:yaml/yaml.dart" show YamlList, YamlMap, loadYamlNode;
+import 'binary_md_dill_reader.dart' show DillComparer;
+
import "incremental_utils.dart" as util;
import 'package:front_end/src/fasta/fasta_codes.dart'
show DiagnosticMessageFromJson, FormattedMessage;
+import 'utils/io_utils.dart' show computeRepoDir;
+
main([List<String> arguments = const []]) =>
- runMe(arguments, createContext, "../testing.json");
+ runMe(arguments, createContext, configurationPath: "../testing.json");
Future<Context> createContext(
Chain suite, Map<String, String> environment) async {
@@ -196,7 +200,7 @@
Future<Map<String, List<int>>> createModules(
Map module, final List<int> sdkSummaryData) async {
final Uri base = Uri.parse("org-dartlang-test:///");
- final Uri sdkSummary = base.resolve("vm_platform.dill");
+ final Uri sdkSummary = base.resolve("vm_platform_strong.dill");
MemoryFileSystem fs = new MemoryFileSystem(base);
fs.entityForUri(sdkSummary).writeAsBytesSync(sdkSummaryData);
@@ -263,7 +267,7 @@
Future<Null> newWorldTest(List worlds, Map modules, bool omitPlatform) async {
final Uri sdkRoot = computePlatformBinariesLocation(forceBuildDir: true);
final Uri base = Uri.parse("org-dartlang-test:///");
- final Uri sdkSummary = base.resolve("vm_platform.dill");
+ final Uri sdkSummary = base.resolve("vm_platform_strong.dill");
final Uri initializeFrom = base.resolve("initializeFrom.dill");
Uri platformUri = sdkRoot.resolve("vm_platform_strong.dill");
final List<int> sdkSummaryData =
@@ -286,7 +290,12 @@
.readComponent(newestWholeComponent);
}
+ int worldNum = 0;
for (YamlMap world in worlds) {
+ worldNum++;
+ print("----------------");
+ print("World #$worldNum");
+ print("----------------");
List<Component> modulesToUse;
if (world["modules"] != null) {
moduleComponents ??= new Map<String, Component>();
@@ -768,7 +777,24 @@
}
for (int i = 0; i < length; ++i) {
if (a[i] != b[i]) {
- Expect.fail("Data differs at byte ${i + 1}.");
+ print("Data differs at byte ${i + 1}.");
+
+ StringBuffer message = new StringBuffer();
+ message.writeln("Data differs at byte ${i + 1}.");
+ message.writeln("");
+ message.writeln("Will try to find more useful information:");
+
+ final String repoDir = computeRepoDir();
+ File binaryMd = new File("$repoDir/pkg/kernel/binary.md");
+ String binaryMdContent = binaryMd.readAsStringSync();
+
+ DillComparer dillComparer = new DillComparer();
+ if (dillComparer.compare(a, b, binaryMdContent, message)) {
+ message.writeln(
+ "Somehow the two different byte-lists compared to the same.");
+ }
+
+ Expect.fail(message.toString());
}
}
Expect.equals(a.length, b.length);
@@ -798,11 +824,27 @@
options ??= getOptions();
TestIncrementalCompiler compiler =
new TestIncrementalCompiler(options, input);
+ List<int> bytes =
+ await normalCompileToBytes(input, options: options, compiler: compiler);
+ new File.fromUri(output).writeAsBytesSync(bytes);
+ return compiler.initializedFromDill;
+}
+
+Future<List<int>> normalCompileToBytes(Uri input,
+ {CompilerOptions options, IncrementalCompiler compiler}) async {
+ Component component = await normalCompileToComponent(input,
+ options: options, compiler: compiler);
+ return util.postProcess(component);
+}
+
+Future<Component> normalCompileToComponent(Uri input,
+ {CompilerOptions options, IncrementalCompiler compiler}) async {
+ options ??= getOptions();
+ compiler ??= new TestIncrementalCompiler(options, input);
Component component = await compiler.computeDelta();
util.throwOnEmptyMixinBodies(component);
util.throwOnInsufficientUriToSource(component);
- new File.fromUri(output).writeAsBytesSync(util.postProcess(component));
- return compiler.initializedFromDill;
+ return component;
}
Future<bool> initializedCompile(
diff --git a/pkg/front_end/test/language_versioning/data/package_default_version/lib/foo.dart b/pkg/front_end/test/language_versioning/data/package_default_version/lib/foo.dart
index 1c14ade..f175cd0 100644
--- a/pkg/front_end/test/language_versioning/data/package_default_version/lib/foo.dart
+++ b/pkg/front_end/test/language_versioning/data/package_default_version/lib/foo.dart
@@ -6,9 +6,11 @@
import 'foo2.dart';
import 'foo3.dart';
+import 'foo4.dart';
foo() {
print("Hello from foo!");
foo2();
foo3();
+ foo4();
}
diff --git a/pkg/front_end/test/language_versioning/data/package_default_version/lib/foo3.dart b/pkg/front_end/test/language_versioning/data/package_default_version/lib/foo3.dart
index 8ff3e3c4..6ffcfd9 100644
--- a/pkg/front_end/test/language_versioning/data/package_default_version/lib/foo3.dart
+++ b/pkg/front_end/test/language_versioning/data/package_default_version/lib/foo3.dart
@@ -2,14 +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.
-// .packages specifies 2.5, this library tries to go above that, which is an
-// error. The library stays on the .packages specified one (2.5) and an error is
-// issued.
+// .packages specifies 2.5, this library tries to go above that, which is fine.
-/*error: LanguageVersionTooHigh*/
// @dart = 2.6
-/*library: languageVersion=2.5*/
+/*library: languageVersion=2.6*/
foo3() {
print("Hello from foo3!");
diff --git a/pkg/front_end/test/language_versioning/data/package_default_version/lib/foo4.dart b/pkg/front_end/test/language_versioning/data/package_default_version/lib/foo4.dart
new file mode 100644
index 0000000..9591a55
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/data/package_default_version/lib/foo4.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2019, 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.
+
+// .packages specifies 2.5, this library tries to go above that, which is fine,
+// except it still has to be within the range of the sdk. The library stays on
+// the .packages specified one (2.5) and an error is issued.
+
+/*error: LanguageVersionTooHigh*/
+// @dart = 2.9
+
+/*library: languageVersion=2.5*/
+
+foo4() {
+ print("Hello from foo4!");
+}
diff --git a/pkg/front_end/test/language_versioning/language_versioning_test.dart b/pkg/front_end/test/language_versioning/language_versioning_test.dart
index 510bba0..691df94 100644
--- a/pkg/front_end/test/language_versioning/language_versioning_test.dart
+++ b/pkg/front_end/test/language_versioning/language_versioning_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'dart:io' show Directory, Platform;
+import 'package:front_end/src/api_prototype/compiler_options.dart';
import 'package:front_end/src/fasta/messages.dart' show FormattedMessage;
import 'package:front_end/src/testing/id.dart' show ActualData, Id;
import 'package:front_end/src/testing/id_testing.dart'
@@ -11,9 +12,9 @@
import 'package:front_end/src/testing/id_testing_helper.dart'
show
CfeDataExtractor,
- InternalCompilerResult,
DataComputer,
- defaultCfeConfig,
+ InternalCompilerResult,
+ TestConfig,
createUriForFileName,
onFailure,
runTestFor;
@@ -21,8 +22,9 @@
main(List<String> args) async {
// Fix default/max major and minor version so we can test it.
- Library.defaultLangaugeVersionMajor = 2;
- Library.defaultLangaugeVersionMinor = 8;
+ // This config sets it to 2.8.
+ TestConfigWithLanguageVersion cfeConfig =
+ new TestConfigWithLanguageVersion(cfeMarker, "cfe");
Directory dataDir = new Directory.fromUri(Platform.script.resolve('data'));
await runTests(dataDir,
@@ -30,8 +32,17 @@
supportedMarkers: [cfeMarker],
createUriForFileName: createUriForFileName,
onFailure: onFailure,
- runTest: runTestFor(
- const LanguageVersioningDataComputer(), [defaultCfeConfig]));
+ runTest: runTestFor(const LanguageVersioningDataComputer(), [cfeConfig]));
+}
+
+class TestConfigWithLanguageVersion extends TestConfig {
+ TestConfigWithLanguageVersion(String marker, String name)
+ : super(marker, name);
+
+ @override
+ void customizeCompilerOptions(CompilerOptions options) {
+ options.currentSdkVersion = "2.8";
+ }
}
class LanguageVersioningDataComputer extends DataComputer<String> {
diff --git a/pkg/front_end/test/language_versioning/language_versioning_up_to_date_test.dart b/pkg/front_end/test/language_versioning/language_versioning_up_to_date_test.dart
new file mode 100644
index 0000000..36d0799
--- /dev/null
+++ b/pkg/front_end/test/language_versioning/language_versioning_up_to_date_test.dart
@@ -0,0 +1,61 @@
+// Copyright (c) 2019, 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' show Platform, Process, ProcessResult;
+import 'package:front_end/src/api_prototype/compiler_options.dart';
+import 'package:kernel/ast.dart' as kernel show Library;
+
+import '../utils/io_utils.dart';
+
+final String repoDir = computeRepoDir();
+
+String get dartVm => Platform.executable;
+
+main(List<String> args) async {
+ ProcessResult result = await Process.run(
+ "python", ["tools/make_version.py", "--no_git", "-q"],
+ workingDirectory: repoDir);
+
+ String stdout = result.stdout.toString();
+ String stderr = result.stderr.toString();
+ int exitCode = result.exitCode;
+
+ print("--- stdout ---");
+ print(stdout);
+ print("--- stderr ---");
+ print(stderr);
+ print("---exit code ---");
+ print(exitCode);
+
+ // E.g. "2.6.0-edge" (without the quotes).
+ String versionString = stdout.split("\n")[0];
+ List<String> dotSeparatedParts = versionString.split(".");
+ int major = int.tryParse(dotSeparatedParts[0]);
+ int minor = int.tryParse(dotSeparatedParts[1]);
+
+ if (kernel.Library.defaultLanguageVersionMajor != major ||
+ kernel.Library.defaultLanguageVersionMinor != minor) {
+ throw "Kernel defaults "
+ "${kernel.Library.defaultLanguageVersionMajor}"
+ "."
+ "${kernel.Library.defaultLanguageVersionMinor}"
+ " does not match output from make_version.py ($major.$minor)";
+ } else {
+ print("Kernel version matches.");
+ }
+
+ CompilerOptions compilerOptions = new CompilerOptions();
+
+ List<String> dotSeparatedPartsFromOptions =
+ compilerOptions.currentSdkVersion.split(".");
+ int majorFromOptions = int.tryParse(dotSeparatedPartsFromOptions[0]);
+ int minorFromOptions = int.tryParse(dotSeparatedPartsFromOptions[1]);
+ if (majorFromOptions != major || minorFromOptions != minor) {
+ throw "CompilerOptions defaults "
+ "${majorFromOptions}.${minorFromOptions}"
+ " does not match output from make_version.py ($major.$minor)";
+ } else {
+ print("CompilerOptions default version matches.");
+ }
+}
diff --git a/pkg/front_end/test/lint_test.dart b/pkg/front_end/test/lint_test.dart
index f39f95c7..f674e25 100644
--- a/pkg/front_end/test/lint_test.dart
+++ b/pkg/front_end/test/lint_test.dart
@@ -32,7 +32,7 @@
show Chain, ChainContext, Result, Step, TestDescription, runMe;
main([List<String> arguments = const []]) =>
- runMe(arguments, createContext, "../testing.json");
+ runMe(arguments, createContext, configurationPath: "../testing.json");
Future<Context> createContext(
Chain suite, Map<String, String> environment) async {
@@ -227,7 +227,7 @@
}
}
- void endFields(Token staticToken, Token covariantToken, Token lateToken,
+ void endClassFields(Token staticToken, Token covariantToken, Token lateToken,
Token varFinalOrConst, int count, Token beginToken, Token endToken) {
if (!_latestType.type) {
onProblem(
diff --git a/pkg/front_end/test/lint_test.status b/pkg/front_end/test/lint_test.status
index 7d72c5b..f7c20bf 100644
--- a/pkg/front_end/test/lint_test.status
+++ b/pkg/front_end/test/lint_test.status
@@ -6,7 +6,6 @@
src/fasta/builder/class_builder/ImportsTwice: Fail
src/fasta/builder/field_builder/ImportsTwice: Fail
src/fasta/builder/prefix_builder/ImportsTwice: Fail
-src/fasta/builder/procedure_builder/ImportsTwice: Fail
src/fasta/incremental_compiler/ImportsTwice: Fail
src/fasta/kernel/body_builder/ImportsTwice: Fail
src/fasta/kernel/expression_generator_helper/ImportsTwice: Fail
diff --git a/pkg/front_end/test/old_dill_test.dart b/pkg/front_end/test/old_dill_test.dart
index df757c40..f8b22f8 100644
--- a/pkg/front_end/test/old_dill_test.dart
+++ b/pkg/front_end/test/old_dill_test.dart
@@ -20,7 +20,7 @@
await checkDill();
return null;
}
- await runMe(arguments, createContext, "../testing.json");
+ await runMe(arguments, createContext, configurationPath: "../testing.json");
await checkDill();
}
diff --git a/pkg/front_end/test/read_dill_from_binary_md_test.dart b/pkg/front_end/test/read_dill_from_binary_md_test.dart
new file mode 100644
index 0000000..cc738f1
--- /dev/null
+++ b/pkg/front_end/test/read_dill_from_binary_md_test.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2019, 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' show Future;
+
+import 'dart:io' show File, Platform;
+
+import 'package:kernel/target/targets.dart' show NoneTarget, TargetFlags;
+
+import 'binary_md_dill_reader.dart' show BinaryMdDillReader;
+
+import 'incremental_load_from_dill_test.dart'
+ show getOptions, normalCompileToBytes;
+
+import 'utils/io_utils.dart' show computeRepoDir;
+
+main() async {
+ await testDart2jsCompile();
+}
+
+Future<void> testDart2jsCompile() async {
+ final Uri dart2jsUrl = Uri.base.resolve("pkg/compiler/bin/dart2js.dart");
+ Stopwatch stopwatch = new Stopwatch()..start();
+ List<int> bytes = await normalCompileToBytes(dart2jsUrl,
+ options: getOptions()..target = new NoneTarget(new TargetFlags()));
+ print("Compiled dart2js in ${stopwatch.elapsedMilliseconds} ms");
+
+ stopwatch.reset();
+ File binaryMd = new File("$repoDir/pkg/kernel/binary.md");
+ String binaryMdContent = binaryMd.readAsStringSync();
+ print("Read binary.md in ${stopwatch.elapsedMilliseconds} ms");
+
+ stopwatch.reset();
+ BinaryMdDillReader binaryMdDillReader =
+ new BinaryMdDillReader(binaryMdContent, bytes);
+ binaryMdDillReader.attemptRead();
+ print("Parsed dart2js compiled bytes via binary.md "
+ "in ${stopwatch.elapsedMilliseconds} ms");
+}
+
+final String repoDir = computeRepoDir();
+
+String get dartVm => Platform.executable;
diff --git a/pkg/front_end/test/scanner_fasta_test.dart b/pkg/front_end/test/scanner_fasta_test.dart
index 02cd12f..c9ae5b2 100644
--- a/pkg/front_end/test/scanner_fasta_test.dart
+++ b/pkg/front_end/test/scanner_fasta_test.dart
@@ -97,6 +97,8 @@
}
for (int byte0 = 1; byte0 <= 0xFF; ++byte0) {
+ List<int> bytes = [byte0, 0];
+ scanBytes(bytes);
for (int byte1 = 1; byte1 <= 0xFF; ++byte1) {
List<int> bytes = [byte0, byte1, 0];
scanBytes(bytes);
diff --git a/pkg/front_end/test/spell_checking_list_blacklist.txt b/pkg/front_end/test/spell_checking_list_blacklist.txt
new file mode 100644
index 0000000..9649873
--- /dev/null
+++ b/pkg/front_end/test/spell_checking_list_blacklist.txt
@@ -0,0 +1,79 @@
+# Copyright (c) 2019, 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.
+
+# Blank lines and comments are ignored.
+# Comments can also be inline like 'correct # this is ok'.
+# Note that at least one space before the hash is required.
+
+
+alread
+chnage
+clonable
+comile
+complation
+conditoinal
+conected
+constructer
+constructers
+contaning
+contol
+covarint
+depencencies
+detemination
+diagnotics
+down't
+effeciency
+erronious
+errornious
+evaluted
+explaination
+expresison
+expressoin
+gurantees
+hiearchy
+hierachy
+independendent
+infered
+instantaite
+instantating
+instantition
+instesection
+internel
+keybord
+libarary
+librares
+neame
+neccessary
+normaly
+nullabiliity
+obect
+occured
+occurence
+ocurred
+opreations
+Orignially
+outtermost
+phisical
+plaform
+poluted
+preceeded
+previosly
+priotity
+proram
+recomile
+resently
+satifying
+seach
+singluar
+Specifiction
+staments
+statment
+stubstitution
+subsitutions
+subtring
+suffient
+terminted
+tood
+unlinke
+valiation
\ No newline at end of file
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 1475e26..7a131c6 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -6,52 +6,110 @@
# Comments can also be inline like 'correct # this is ok'.
# Note that at least one space before the hash is required.
+a+b
+abbreviate
+abcdef
+abs
+accounting
+accounts
+accumulated
+accumulating
+across
+affecting
+afterwards
+agree
ahe
ai
aiki
aka
+alexmarkov
+aligned
+alive
+allocate
+altered
+analogous
+annotate
ansi
+answering
+anyone
ap
api
+app
arg
args
argument1
+arise
+arises
+arising
+arity
+artifact
+artificial
+asgerf
askesc
+assigning
+assigns
ast
asy
atm
+atom
+atoms
+attributes
automagically
+awaiting
b
b23d3b125e9d246e07a2b43b61740759a0dace
backping
bang
bar
+basically
+batch
baz
bazel
bb
+beforehand
+behave
+bellow
+belonging
benchmarks
bf
bi
+bias
+biased
bin
+binder
+binders
+binds
bj
-blah
blob
+blocking
bn
+bo
bodied
+body's
bof
bom
+bother
+breadcrumbs
brianwilkerson
bs
bsd
+bslash
+buffered
builder`s
bulder
+bulk
+bump
+bypassing
c
+caches
callee
caller's
callers
+callsite
came
canonicalizer
cant
+cardinality
caret
carets
carriage
@@ -67,54 +125,127 @@
ck
cl
claim
+clarification
+clashes
class's
+clazz
cls
cn
+co
codebase
codec
codes
+collision
com
+combinations
combinator
+combine2
combiner
+compared
+compares
+completes
+complicating
component's
+compressed
+compression
+concat
+concatenate
+concerned
cond
+condensed
config
configs
+configured
constness
+consult
+consumers
+container
+containers
+continuations
contra
+convention
core
core's
+corrected
+cosmetic
+counters
cr
+creator
+criterion
+cross
+cruft
+cryptic
+ctx
cut
cwd
+cyclically
d
d11e
dag
+dangling
danrubel
daringfireball
dartbug
dartdoc
dartlang
+dc
ddc
ddk
+dea112b090073317d
+debuggable
dec
decl
+decoupled
+decreases
+deemed
+deepest
+deeply
+degrades
+degree
del
+delimit
+demands
demangle
demangled
deps
-desc
+dereferenced
+dereferencing
+descent
+deserializer
+deserializers
+deserializes
+deserializing
+design
+despite
+destination
+destinations
+destroy
+deterministic
dev
diff
diffs
digest
digests
+dijkstra's
+directed
+directions
+dirty
+disallow
+disambiguator
+disjoint
+dispatched
+divided
dmitryas
doc
docs
dom
-dpkg
+doubles
+downcasts
+downloaded
+downloading
dq
+dquote
+dst
dummy
e
easy
@@ -123,77 +254,179 @@
ed
eek
ef
+effects
+efficient
+efficiently
elem
+eliminating
elt
em
emit
+emits
emitted
+emitting
en
+enforce
+enforced
+enumerates
env
eof
eq
+equation
+erasure
+estimate
eval
+excludes
+exhausted
+existentially
exp
+expense
exportee
exportees
expr
+expression's
ext
+extenders
+extracted
+extracts
f
+faced
+factor
fangorn
fasta
+favoring
+fc
fe
feff
ff
+fff
ffff
+fffff
ffi
+file's
+filenames
+firsts
+fishy
fishythefish
+fleshed
+float64
floitsch
+flowed
+flushed
+flutter's
fn
fo
foo
foobar
formed
former
+fortunately
+fourth
+framework
+freely
frontend
+frontends
fs
+function's
+fuse
futured
g
+generation
gets
+getting
gft
-git
github
glb
+globally
gn
googlesource
goto
gotos
+gradually
+graphs
gt
+guarantee
+guarded
gypi
gz
gzip
gzipped
h
+hashes
+hashing
+heap
+height
+hello
+helpful
hfs
+highlight
+highlighting
+highlights
hillerstrom
+histogram
+hit
hoc
+hoisted
href
html
https
+human
i
+i'll
id
+identifies
+identifying
ideographic
idn
ids
iff
+il
+immutability
impl
+implementers
+imply
+implying
+importantly
inc
+incomparable
+incremented
+independently
+indexer
+indexing
+indirection
+individual
+informative
infos
init
+initializations
+initializer's
+insertion
+inspector
+inspired
+instanceof
+instantiator
+intentionally
+interior
+interleaved
+intermediate
+interpolations
+intersects
+interval
+intervals
ints
+invariants
io
+is64
issuecomment
+iterables
+iterating
+iterations
+iterators
j
+jacobr
+jakemac
java
+jenkins
jensj
johnniwinther
js
@@ -207,27 +440,45 @@
klass
kmillikin
kustermann
+kv
l
+lacks
lang
+largest
+lattice
+layer
leafp
len
+lets
+letting
lex
lexemes
lf
lhs
lib
libs
+lifted
+lifter
+linearized
+lives
lm
+locationd
+lots
+lparen
lry
ls
lt
+lub
lvalue
m
+maintaining
+mangled
+manipulation
markdown
mb
md
me
-met
+merely
meta
method1a
method1b
@@ -237,131 +488,288 @@
method3b
mi
min
+mixers
mk
mm
mn
monomorphic
+moves
msg
+murmur
n
na
+nameless
+namer
+natively
nbsp
ncs
ncurses
nd
+near
+neighboring
nextnext
ni
+nine
nj
nk
nnbd
+node's
+nonimplementation
+notion
nr
ns
nsm
+nth
+nullabilities
nullability
nullable
+nullary
+nulls
o
obj
+observe
+obstruct
+occasionally
+occupied
+occurences
offs
ogham
+oked
op
opt
+optimizations
opts
+ordered
+orders
ordinal
org
+orphans
os
+overlap
+overloader
overshadowed
+overwrite
+overwriting
+ownership
p
p1
p2
+par
+parallel
param
+parameter's
+parametrized
params
paren
parens
+parenteses
+particularly
path
-pathos
paulberry
pay
payload
+payloads
pdf
per
perf
+permit
pi
+picking
pkg
pm
pn
pointwise
+polluted
+popped
pos
+possibility
postfix
+pow
+pragma
pre
prebuilt
+preorder
prev
+prime
printer
printf
println
proc
+producers
+product
+progresses
+proof
+prop
+propose
+proposed
proto
ps
+pulled
+pure
+puts
q
q'i
qi
qm
quad
+quantified
+queries
+quick
+quoted
r
+r'\f
+r'\r
r'\s
+r'\t
+r'\u
+r'\v
+r'$creation
radix
+raises
ran
+randomly
+ranges
+ranked
+ratio
re
reach
+react
+realign
reassigned
rebind
rebuild
+recall
+received
recompiled
recompiling
recompute
recomputed
+recreate
+recursion
red
+redeclared
redirectee
+redirector
reexports
ref
reflect
reg
+regis
rehash
+reindexed
+reissued
rejoin
+relatively
relativize
+relax
+relaxes
+remapped
+remedy
+removal
+remover
reparse
+replacer
+replaces
+repo
+repositories
+requirement
res
+residue
+respond
+restriction
+resumed
+rewrites
+rewrote
rhs
ri
+rightmost
rn
rnystrom
+role
+room
+rooted
+roughly
+rounding
+rparen
+runnable
s
sb
scheglov
+scoped
+scoping
sdk's
+seconds
+sections
+selectors
+semantically
+separators
+sequencing
+serializables
+serializer
+serializers
+serve
server
service
setaf
sh
+sha1hash
+shadowed
+shallow
shas
+shrinking
+shru
si
+sibling
+siblings
+sides
sigmund
+significant
+simplify
+singleton
+sinker
+site
six
size
+sizes
sj
slash
slb
+slots
+slowing
smi
sn
socket
+sole
+solely
+somewhat
+spaced
+sparse
spec
spec'ed
+specially
+specifics
+speeding
+spend
+spuriously
sq
+sra
src
st
+stability
+stacktrace
+stacktraces
+stale
+statics
stderr
stdin
-stdio
stdout
stmt
+str
+streaming
+strict
+stringified
+stringify
+structures
stub
stubs
stx
@@ -369,16 +777,36 @@
subexpression
subexpression's
subexpressions
+subnode
+subnodes
+subscription
+subsection
+subsections
subst
substed
+substitutes
+substitutor
+sum
+summarizing
superclasses
superinitializer
+superinterfaces
supernode
supers
+suppose
+suspended
svg
sw
+swapped
+sweep
+synchronously
synth
t
+tagged
+tagger
+tags
+taking
+team
tear
tearing
tearoff
@@ -386,17 +814,23 @@
tell
tells
temp
+temporaries
+temps
term
termcap
+terminator
+tester
tex
th
ti
tick
ticker
tid
+ties
tiki
tilde
till
+tiny
tj
tm
tmp
@@ -405,34 +839,81 @@
token's
tokenize
tokenized
+tolerate
+tolerated
+toplevel
+topological
+tops
tput
+tracker
+transformers
+transforming
+translation
+traversal
+traverse
+trees
+tricky
+trips
ts
tty
+tuple
+tuple2
+tuple3
+tuple4
typeref
u
+u001b
+ufeff
ui
uint
uint16
uint32
uint8
+umbrella
un
+unaffected
unalias
+unaligned
+unaltered
+unassigned
+unbound
uncomment
+uncommon
+unconditionally
unconstrained
+undeclare
unequal
unescape
unexact
unfinalized
+unfolds
unfuture
unfutured
+unguarded
+unifiable
+unification
+unifier
+unify
+unions
+uniqueness
+universally
unlinked
unlower
+unordered
+unpaired
unparsed
-update2018
+unpleasant
+unreachable
+unshadowed
+unwraps
+unzip
+upcast
ur
uri's
url
urls
+usr
+usually
utf16
utf8
util
@@ -441,39 +922,71 @@
variable's
variance
variances
+variant
+variants
+vary
vegorov
+versa
+vice
+violated
+visit*
+visitors
+visits
+vm's
+vs
vtab
w
+wanted
+waste
+watch
wc
+weird
weren't
werror
+whatnot
+whichever
+widget
+widgets
wiki
wikipedia
with1
+worthwhile
writeln
wrt
www
x
x0
x00
+x00003fff
+x0007ffff
+x03ffffff
x10
x10ffff
x180
x1b
x1f
x1ff
+x1fffffff
x2
x200
x202
x205
x3
+x3f
+x3fffffff
x5
x7
+x7fff
+x90
+x9ddfea08eb
+xbb
+xbf
xcodebuild
xd
xdbff
xdc
xdfff
+xef
xi
xm
xn
@@ -481,6 +994,8 @@
xterm
xx
xxxx
+xxxxxx
+xxxxxxx
y
yaml
yet
@@ -489,6 +1004,7 @@
z
zi
zip
+zipped
zn
zone
zoned
diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt
index 0b43a76..056b0f5 100644
--- a/pkg/front_end/test/spell_checking_list_common.txt
+++ b/pkg/front_end/test/spell_checking_list_common.txt
@@ -32,6 +32,7 @@
accessing
accessor
accessors
+accidental
accidentally
accordance
according
@@ -79,6 +80,7 @@
algorithm
algorithms
alias
+alignment
all
allocated
allocating
@@ -218,6 +220,7 @@
backwards
bad
balanced
+bare
base
based
basic
@@ -334,6 +337,7 @@
canonicalized
capabilities
capability
+capable
capital
capture
captured
@@ -386,6 +390,7 @@
circularities
circularity
circumstances
+clashing
class
classes
classic
@@ -512,6 +517,7 @@
connection
consequence
consequently
+conservative
conservatively
consider
considered
@@ -593,6 +599,7 @@
couldn't
count
counter
+counting
counts
couple
covariance
@@ -603,16 +610,19 @@
covers
crash
crashed
+crashes
crashing
create
created
creates
creating
creation
+crossed
curly
current
currently
custom
+customize
cyan
cycle
cycles
@@ -819,6 +829,7 @@
early
easier
easiest
+easily
edge
edges
edit
@@ -855,10 +866,12 @@
encoder
encodes
encoding
+encounter
encountered
encounters
end
ended
+endian
ending
endings
ends
@@ -877,6 +890,7 @@
entering
entire
entirely
+entirety
entities
entity
entity's
@@ -889,6 +903,7 @@
equal
equality
equals
+equivalence
equivalent
equivalents
erroneous
@@ -899,6 +914,7 @@
escapes
escaping
essence
+essentials
etc
evaluate
evaluated
@@ -924,6 +940,7 @@
exceeded
except
exception
+exceptional
exceptions
exclamation
exclude
@@ -1237,6 +1254,7 @@
ignores
ignoring
illegal
+imaginary
imitation
immediate
immediately
@@ -1352,6 +1370,8 @@
instantiation
instantiations
instead
+instruction
+instructions
instrumentation
instrumented
int
@@ -1402,6 +1422,7 @@
invocation
invocation's
invocations
+invokable
invoke
invoked
invokes
@@ -1608,6 +1629,7 @@
matter
maturity
max
+maximum
may
maybe
mean
@@ -1662,6 +1684,7 @@
mock
mode
model
+models
modes
modifiable
modification
@@ -1812,6 +1835,7 @@
operator
operators
opposed
+opted
optimistically
optimization
optimize
@@ -1830,6 +1854,7 @@
originally
originate
originated
+originates
originating
origins
orphan
@@ -1906,6 +1931,7 @@
paths
pattern
peek
+pending
percent
perform
performance
@@ -1925,8 +1951,10 @@
pick
picked
pipeline
+piping
pivot
place
+places
placed
placeholder
placeholders
@@ -1976,6 +2004,7 @@
precision
preclude
precondition
+predefined
predicate
preemptively
prefer
@@ -1985,6 +2014,7 @@
prefix
prefixed
prefixes
+prelude
prepare
prepared
preparing
@@ -2084,6 +2114,7 @@
qualifier
qualifiers
quality
+queried
query
question
queue
@@ -2109,6 +2140,7 @@
reads
ready
real
+realigned
realized
really
reason
@@ -2156,6 +2188,7 @@
refers
refine
refinement
+reflecting
regardless
region
regions
@@ -2173,11 +2206,13 @@
related
relation
relational
+relations
relationship
relationships
relative
release
relevant
+relied
relies
reloads
rely
@@ -2189,12 +2224,14 @@
remember
remembered
remembers
+reminder
remote
remove
removed
removes
removing
rename
+renamed
renaming
repeated
repeatedly
@@ -2237,6 +2274,7 @@
resolving
resources
respect
+respected
respective
respectively
respects
@@ -2256,6 +2294,7 @@
retain
retained
rethrow
+retired
retrieve
retrieved
retrieves
@@ -2298,6 +2337,7 @@
runtime
safe
safely
+safety
said
sake
same
@@ -2350,6 +2390,7 @@
sends
sense
sent
+sentence
sentinel
separate
separated
@@ -2392,6 +2433,7 @@
shouldn't
show
shown
+shows
shrink
side
sign
@@ -2401,6 +2443,7 @@
signatures
signed
silent
+silently
silly
similar
similarly
@@ -2452,6 +2495,7 @@
sorted
sorting
sorts
+sought
source
sources
space
@@ -2483,6 +2527,7 @@
stamps
standalone
standard
+stands
star
start
started
@@ -2560,6 +2605,7 @@
sufficient
sufficiently
suffix
+suffixes
suggested
suitable
summaries
@@ -2608,6 +2654,7 @@
systems
tab
table
+tables
tabs
tag
tail
@@ -2749,6 +2796,7 @@
turn
turned
turning
+turns
tv
twice
two
@@ -2760,9 +2808,11 @@
typically
typing
unable
+unambiguous
unary
unbalanced
unbind
+uncertain
unchanged
unclaimed
unclear
@@ -2771,6 +2821,7 @@
underlying
underscore
understand
+understood
unevaluated
unexpected
unfinished
@@ -2799,6 +2850,7 @@
unnamed
unnecessarily
unnecessary
+unparsable
unpromoted
unread
unrecognized
@@ -2872,6 +2924,7 @@
verify
verifying
version
+versioning
versions
vertex
vertical
diff --git a/pkg/front_end/test/spell_checking_list_messages.txt b/pkg/front_end/test/spell_checking_list_messages.txt
index 0ed2f9a..cbc5036 100644
--- a/pkg/front_end/test/spell_checking_list_messages.txt
+++ b/pkg/front_end/test/spell_checking_list_messages.txt
@@ -6,6 +6,7 @@
# Comments can also be inline like 'correct # this is ok'.
# Note that at least one space before the hash is required.
+argument(s)
b
c
compilercontext.runincontext
@@ -48,4 +49,4 @@
type3.#name
u
v
-x
\ No newline at end of file
+x
diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt
index 18a1ce4..6786412 100644
--- a/pkg/front_end/test/spell_checking_list_tests.txt
+++ b/pkg/front_end/test/spell_checking_list_tests.txt
@@ -13,17 +13,13 @@
aaa
abc
abcompile
-across
actions
affected
albeit
-alive
allocations
anon
-app
approval
approximation
-arity
asserter
auth
autobianchi
@@ -35,7 +31,6 @@
bailout
bash
bat
-batch
bbb
bc
bench
@@ -43,6 +38,8 @@
besides
beta
bigger
+blacklist
+blah
blindly
blocked
blorp
@@ -52,7 +49,6 @@
brave
brown
builddir
-bulk
bulk2
bulkcompile
c's
@@ -76,12 +72,12 @@
collisions
commit
companion
+comparer
comparisons
compilations
compiler's
complement
completers
-completes
confirm
consecutive
considering
@@ -94,15 +90,16 @@
cumulative
dacoharkes
daemon
-dangling
dartanalyzer
dartfile
dashes
day
db
+decrements
def
depended
depfile
+desc
deviation
dfast
dictionaries
@@ -119,7 +116,6 @@
doctype
doesnt
dog
-downcasts
downstream
dumping
dupe
@@ -130,7 +126,6 @@
ease
ec
edits
-efficient
elapse
ell
entrypoint
@@ -139,7 +134,6 @@
err
everytime
evicting
-excludes
exe
execute
exercised
@@ -157,7 +151,6 @@
falling
favors
fibonacci
-filenames
filesystem
finder
fisk
@@ -167,23 +160,20 @@
forces
foreign
fox
-framework
fulfill
func
futures
gallery
gamma
gen
-generation
generators
-glb
+git
greeting
gtgt
gulp
gunk
hackish
harness
-hello
hest
heuristics
hi
@@ -202,8 +192,7 @@
inclosure
increased
incrementally
-individual
-insertion
+increments
inspect
insufficient
intact
@@ -211,20 +200,16 @@
interpolate
inv
invalidating
-invariants
isolate
isolates
iter
-iterations
jumped
+kernels
ko
la
-lacks
-largest
lc
ld
le
-lets
lightly
likewise
linebreaks
@@ -235,13 +220,13 @@
logd
logs
loopback
-lots
-lub
mac
maker
matters
mc
+mds
measured
+met
metric
metrics
mf
@@ -257,8 +242,6 @@
negatable
ninja
nonexisting
-notion
-nullary
numerator
observable
observatory
@@ -266,7 +249,6 @@
okay
oracle
overlay
-parametrized
party
pause
periodic
@@ -284,17 +266,18 @@
producer
profiler
promotes
-prop
propagated
protected
provider
-pure
+pubspec
pv
px
py
-quick
+python
quot
+r"
r"\s
+r"k
rd
reachability
reality
@@ -308,14 +291,16 @@
regenerate
regressions
reload
+remap
+remaps
repeating
-repo
repro
resource
respected
response
retains
rev
+risky
say
scans
screen
@@ -323,48 +308,34 @@
sdkroot
sdks
secondary
-seconds
segment
-shadowed
shipped
shot
signalled
-simplify
-site
-somewhat
spans
spell
spellcheck
-spelled
spelling
spent
splitting
sqrt
-statics
std
-str
+stdio
strip
strongest
-structures
stub's
stupid
subcommand
-subscription
+subdir
subtool
subtools
suite
-sum
summarization
summarized
superinterface
supermixin
supplement
-swapped
-tags
-team
templates
-terminator
-tester
thereof
thing
threw
@@ -373,11 +344,8 @@
timing
timings
title
-toplevel
tpt
-transforming
transitively
-translation
triangle
trigger
triggers
@@ -389,31 +357,22 @@
typeargs
typeparam
typeparambounds
-unassigned
unawaited
unbreak
-unification
-unordered
-unreachable
unregistered
untransformed
+untrimmed
uppercase
upward
-usr
+uses8
usual
val
-variants
+vars
verbatim
-versa
versioning
-vice
-vm's
-vs
waiting
walt
-wanted
warmup
-weird
whitelist
whitelisting
wins
diff --git a/pkg/front_end/test/spell_checking_utils.dart b/pkg/front_end/test/spell_checking_utils.dart
index 7c3c21774..479effa 100644
--- a/pkg/front_end/test/spell_checking_utils.dart
+++ b/pkg/front_end/test/spell_checking_utils.dart
@@ -9,6 +9,8 @@
cfeMessages,
cfeCode,
cfeTests,
+ // The blacklist is special and is always loaded!
+ blacklist,
}
Map<Dictionaries, Set<String>> loadedDictionaries;
@@ -20,6 +22,7 @@
List<String> wrongWords;
List<int> wrongWordsOffset;
+ List<bool> wrongWordBlacklisted;
List<int> wordOffsets = new List<int>();
List<String> words =
splitStringIntoWords(s, wordOffsets, splitAsCode: splitAsCode);
@@ -29,6 +32,7 @@
bool found = false;
for (int j = 0; j < dictionaries.length; j++) {
Dictionaries dictionaryType = dictionaries[j];
+ if (dictionaryType == Dictionaries.blacklist) continue;
Set<String> dictionary = loadedDictionaries[dictionaryType];
if (dictionary.contains(word)) {
found = true;
@@ -40,16 +44,22 @@
wrongWords.add(word);
wrongWordsOffset ??= new List<int>();
wrongWordsOffset.add(offset);
+ wrongWordBlacklisted ??= new List<bool>();
+ wrongWordBlacklisted
+ .add(loadedDictionaries[Dictionaries.blacklist].contains(word));
}
}
- return new SpellingResult(wrongWords, wrongWordsOffset);
+
+ return new SpellingResult(wrongWords, wrongWordsOffset, wrongWordBlacklisted);
}
class SpellingResult {
final List<String> misspelledWords;
final List<int> misspelledWordsOffset;
+ final List<bool> misspelledWordsBlacklisted;
- SpellingResult(this.misspelledWords, this.misspelledWordsOffset);
+ SpellingResult(this.misspelledWords, this.misspelledWordsOffset,
+ this.misspelledWordsBlacklisted);
}
void ensureDictionariesLoaded(List<Dictionaries> dictionaries) {
@@ -71,6 +81,14 @@
}
loadedDictionaries ??= new Map<Dictionaries, Set<String>>();
+ // Ensure the blacklist is loaded.
+ Set<String> blacklistDictionary = loadedDictionaries[Dictionaries.blacklist];
+ if (blacklistDictionary == null) {
+ blacklistDictionary = new Set<String>();
+ loadedDictionaries[Dictionaries.blacklist] = blacklistDictionary;
+ addWords(dictionaryToUri(Dictionaries.blacklist), blacklistDictionary);
+ }
+
for (int j = 0; j < dictionaries.length; j++) {
Dictionaries dictionaryType = dictionaries[j];
Set<String> dictionary = loadedDictionaries[dictionaryType];
@@ -78,6 +96,13 @@
dictionary = new Set<String>();
loadedDictionaries[dictionaryType] = dictionary;
addWords(dictionaryToUri(dictionaryType), dictionary);
+ // Check that no good words occur in the blacklist.
+ for (String s in dictionary) {
+ if (blacklistDictionary.contains(s)) {
+ throw "Word '$s' in dictionary $dictionaryType "
+ "is also in the blacklist.";
+ }
+ }
}
}
}
@@ -96,6 +121,9 @@
case Dictionaries.cfeTests:
return Uri.base
.resolve("pkg/front_end/test/spell_checking_list_tests.txt");
+ case Dictionaries.blacklist:
+ return Uri.base
+ .resolve("pkg/front_end/test/spell_checking_list_blacklist.txt");
}
throw "Unknown Dictionary";
}
@@ -107,9 +135,9 @@
String regExpStringInner = r"\s-=\|\/,";
if (splitAsCode) {
// If splitting as code also split by "_", ":", ".", "(", ")", "<", ">",
- // "[", "]", "{", "}", "@", "&", "#", "?". (As well as doing stuff to camel
- // casing further below).
- regExpStringInner = "${regExpStringInner}_:\\.\\(\\)<>\\[\\]\{\}@&#\\?";
+ // "[", "]", "{", "}", "@", "&", "#", "?", "%".
+ // (As well as doing stuff to camel casing further below).
+ regExpStringInner = "${regExpStringInner}_:\\.\\(\\)<>\\[\\]\{\}@&#\\?%";
}
// Match one or more of the characters specified above.
String regExp = "[$regExpStringInner]+";
diff --git a/pkg/front_end/test/spell_checking_utils_test.dart b/pkg/front_end/test/spell_checking_utils_test.dart
index 202dc65..ed6bb7c 100644
--- a/pkg/front_end/test/spell_checking_utils_test.dart
+++ b/pkg/front_end/test/spell_checking_utils_test.dart
@@ -77,6 +77,9 @@
expectSplit("foo?bar", false, ["foo?bar"], [0]);
expectSplit("foo?bar", true, ["foo", "bar"], [0, 4]);
+ expectSplit("foo%bar", false, ["foo%bar"], [0]);
+ expectSplit("foo%bar", true, ["foo", "bar"], [0, 4]);
+
print("OK");
}
diff --git a/pkg/front_end/test/spelling_test_base.dart b/pkg/front_end/test/spelling_test_base.dart
index 274ac0e..ac96efe 100644
--- a/pkg/front_end/test/spelling_test_base.dart
+++ b/pkg/front_end/test/spelling_test_base.dart
@@ -28,7 +28,7 @@
import 'spell_checking_utils.dart' as spell;
-abstract class Context extends ChainContext {
+abstract class SpellContext extends ChainContext {
final List<Step> steps = const <Step>[
const SpellTest(),
];
@@ -41,15 +41,17 @@
}
List<spell.Dictionaries> get dictionaries;
+
+ bool get onlyBlacklisted;
}
-class SpellTest extends Step<TestDescription, TestDescription, Context> {
+class SpellTest extends Step<TestDescription, TestDescription, SpellContext> {
const SpellTest();
String get name => "spell test";
Future<Result<TestDescription>> run(
- TestDescription description, Context context) async {
+ TestDescription description, SpellContext context) async {
File f = new File.fromUri(description.uri);
List<int> rawBytes = f.readAsBytesSync();
@@ -90,6 +92,8 @@
dictionaries: context.dictionaries);
if (spellingResult.misspelledWords != null) {
for (int i = 0; i < spellingResult.misspelledWords.length; i++) {
+ bool blacklisted = spellingResult.misspelledWordsBlacklisted[i];
+ if (context.onlyBlacklisted && !blacklisted) continue;
int offset =
comment.offset + spellingResult.misspelledWordsOffset[i];
String word = spellingResult.misspelledWords[i];
@@ -106,6 +110,8 @@
dictionaries: context.dictionaries);
if (spellingResult.misspelledWords != null) {
for (int i = 0; i < spellingResult.misspelledWords.length; i++) {
+ bool blacklisted = spellingResult.misspelledWordsBlacklisted[i];
+ if (context.onlyBlacklisted && !blacklisted) continue;
int offset = token.offset + spellingResult.misspelledWordsOffset[i];
String word = spellingResult.misspelledWords[i];
addErrorMessage(offset, word.length, "Misspelled word '$word'.");
diff --git a/pkg/front_end/test/spelling_test_external_targets.dart b/pkg/front_end/test/spelling_test_external_targets.dart
new file mode 100644
index 0000000..4f532a2
--- /dev/null
+++ b/pkg/front_end/test/spelling_test_external_targets.dart
@@ -0,0 +1,50 @@
+// Copyright (c) 2019, 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' show Future;
+
+import 'dart:io' show Directory, File, FileSystemEntity;
+
+import 'package:testing/testing.dart'
+ show Chain, FileBasedTestDescription, TestDescription, runMe;
+
+import 'spelling_test_base.dart' show SpellContext;
+
+import 'spell_checking_utils.dart' as spell;
+
+main([List<String> arguments = const []]) =>
+ runMe(arguments, createContext, configurationPath: "../testing.json");
+
+Future<SpellContext> createContext(
+ Chain suite, Map<String, String> environment) async {
+ return new SpellContextExternal();
+}
+
+class SpellContextExternal extends SpellContext {
+ @override
+ List<spell.Dictionaries> get dictionaries => const <spell.Dictionaries>[];
+
+ @override
+ bool get onlyBlacklisted => true;
+
+ Stream<TestDescription> list(Chain suite) async* {
+ for (String subdir in const ["pkg/", "sdk/"]) {
+ Directory testRoot = new Directory.fromUri(suite.uri.resolve(subdir));
+ if (await testRoot.exists()) {
+ Stream<FileSystemEntity> files =
+ testRoot.list(recursive: true, followLinks: false);
+ await for (FileSystemEntity entity in files) {
+ if (entity is! File) continue;
+ String path = entity.uri.path;
+ if (suite.exclude.any((RegExp r) => path.contains(r))) continue;
+ if (suite.pattern.any((RegExp r) => path.contains(r))) {
+ yield new FileBasedTestDescription(suite.uri, entity);
+ }
+ }
+ } else {
+ throw "${suite.uri} isn't a directory";
+ }
+ }
+ }
+}
diff --git a/pkg/front_end/test/spelling_test_not_src_test.dart b/pkg/front_end/test/spelling_test_not_src_test.dart
index e1f675a..f281d14 100644
--- a/pkg/front_end/test/spelling_test_not_src_test.dart
+++ b/pkg/front_end/test/spelling_test_not_src_test.dart
@@ -11,18 +11,21 @@
import 'spell_checking_utils.dart' as spell;
main([List<String> arguments = const []]) =>
- runMe(arguments, createContext, "../testing.json");
+ runMe(arguments, createContext, configurationPath: "../testing.json");
-Future<Context> createContext(
+Future<SpellContext> createContext(
Chain suite, Map<String, String> environment) async {
- return new ContextTest();
+ return new SpellContextTest();
}
-class ContextTest extends Context {
+class SpellContextTest extends SpellContext {
@override
List<spell.Dictionaries> get dictionaries => const <spell.Dictionaries>[
spell.Dictionaries.common,
spell.Dictionaries.cfeCode,
spell.Dictionaries.cfeTests
];
+
+ @override
+ bool get onlyBlacklisted => false;
}
diff --git a/pkg/front_end/test/spelling_test_src_test.dart b/pkg/front_end/test/spelling_test_src_test.dart
index 73cdc8d..12f5dcb 100644
--- a/pkg/front_end/test/spelling_test_src_test.dart
+++ b/pkg/front_end/test/spelling_test_src_test.dart
@@ -11,17 +11,20 @@
import 'spell_checking_utils.dart' as spell;
main([List<String> arguments = const []]) =>
- runMe(arguments, createContext, "../testing.json");
+ runMe(arguments, createContext, configurationPath: "../testing.json");
-Future<Context> createContext(
+Future<SpellContext> createContext(
Chain suite, Map<String, String> environment) async {
- return new ContextSrc();
+ return new SpellContextSource();
}
-class ContextSrc extends Context {
+class SpellContextSource extends SpellContext {
@override
List<spell.Dictionaries> get dictionaries => const <spell.Dictionaries>[
spell.Dictionaries.common,
spell.Dictionaries.cfeCode
];
+
+ @override
+ bool get onlyBlacklisted => false;
}
diff --git a/pkg/front_end/test/static_types/data/prefix_postfix.dart b/pkg/front_end/test/static_types/data/prefix_postfix.dart
new file mode 100644
index 0000000..a6b9d6e
--- /dev/null
+++ b/pkg/front_end/test/static_types/data/prefix_postfix.dart
@@ -0,0 +1,131 @@
+// Copyright (c) 2019, 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.
+
+num numTopLevel = /*int*/ 0;
+int intTopLevel = /*int*/ 0;
+dynamic dynamicTopLevel = /*int*/ 0;
+
+testTopLevel() {
+ /*update: num*/ /*num*/ numTopLevel /*invoke: num*/ /*int*/ ++;
+ /*update: num*/ /*num*/ numTopLevel /*invoke: num*/ /*int*/ --;
+ /*invoke: num*/ /*int*/ ++ /*update: num*/ /*num*/ numTopLevel;
+ /*invoke: num*/ /*int*/ -- /*update: num*/ /*num*/ numTopLevel;
+
+ /*update: int*/ /*int*/ intTopLevel /*invoke: int*/ /*int*/ ++;
+ /*update: int*/ /*int*/ intTopLevel /*invoke: int*/ /*int*/ --;
+ /*invoke: int*/ /*int*/ ++ /*update: int*/ /*int*/ intTopLevel;
+ /*invoke: int*/ /*int*/ -- /*update: int*/ /*int*/ intTopLevel;
+
+ /*update: dynamic*/ /*dynamic*/ dynamicTopLevel
+ /*invoke: dynamic*/ /*int*/ ++;
+ /*update: dynamic*/ /*dynamic*/ dynamicTopLevel
+ /*invoke: dynamic*/ /*int*/ --;
+ /*invoke: dynamic*/ /*int*/ ++
+ /*update: dynamic*/ /*dynamic*/ dynamicTopLevel;
+ /*invoke: dynamic*/ /*int*/ --
+ /*update: dynamic*/ /*dynamic*/ dynamicTopLevel;
+}
+
+class Class {
+ num numInstance = /*int*/ 0;
+ int intInstance = /*int*/ 0;
+ dynamic dynamicInstance = /*int*/ 0;
+
+ testInstance() {
+ /*update: num*/ /*num*/ numInstance /*invoke: num*/ /*int*/ ++;
+ /*update: num*/ /*num*/ numInstance /*invoke: num*/ /*int*/ --;
+ /*invoke: num*/ /*int*/ ++ /*update: num*/ /*num*/ numInstance;
+ /*invoke: num*/ /*int*/ -- /*update: num*/ /*num*/ numInstance;
+
+ /*update: int*/ /*int*/ intInstance /*invoke: int*/ /*int*/ ++;
+ /*update: int*/ /*int*/ intInstance /*invoke: int*/ /*int*/ --;
+ /*invoke: int*/ /*int*/ ++ /*update: int*/ /*int*/ intInstance;
+ /*invoke: int*/ /*int*/ -- /*update: int*/ /*int*/ intInstance;
+
+ /*update: dynamic*/ /*dynamic*/ dynamicInstance
+ /*invoke: dynamic*/ /*int*/ ++;
+ /*update: dynamic*/ /*dynamic*/ dynamicInstance
+ /*invoke: dynamic*/ /*int*/ --;
+ /*invoke: dynamic*/ /*int*/ ++
+ /*update: dynamic*/ /*dynamic*/ dynamicInstance;
+ /*invoke: dynamic*/ /*int*/ --
+ /*update: dynamic*/ /*dynamic*/ dynamicInstance;
+ }
+}
+
+testInstanceOnClass(Class c) {
+ /*Class*/ c. /*update: num*/ /*num*/ numInstance /*invoke: num*/ /*int*/ ++;
+ /*Class*/ c. /*update: num*/ /*num*/ numInstance /*invoke: num*/ /*int*/ --;
+ /*invoke: num*/ /*int*/ ++ /*Class*/ c. /*update: num*/ /*num*/ numInstance;
+ /*invoke: num*/ /*int*/ -- /*Class*/ c. /*update: num*/ /*num*/ numInstance;
+
+ /*Class*/ c. /*update: int*/ /*int*/ intInstance /*invoke: int*/ /*int*/ ++;
+ /*Class*/ c. /*update: int*/ /*int*/ intInstance /*invoke: int*/ /*int*/ --;
+ /*invoke: int*/ /*int*/ ++ /*Class*/ c. /*update: int*/ /*int*/ intInstance;
+ /*invoke: int*/ /*int*/ -- /*Class*/ c. /*update: int*/ /*int*/ intInstance;
+
+ /*Class*/ c. /*update: dynamic*/ /*dynamic*/ dynamicInstance
+ /*invoke: dynamic*/ /*int*/ ++;
+ /*Class*/ c. /*update: dynamic*/ /*dynamic*/ dynamicInstance
+ /*invoke: dynamic*/ /*int*/ --;
+ /*invoke: dynamic*/ /*int*/ ++ /*Class*/ c
+ . /*update: dynamic*/ /*dynamic*/ dynamicInstance;
+ /*invoke: dynamic*/ /*int*/ -- /*Class*/ c
+ . /*update: dynamic*/ /*dynamic*/ dynamicInstance;
+}
+
+testInstanceOnDynamic(dynamic c) {
+ /*dynamic*/ c. /*update: dynamic*/ /*dynamic*/ numInstance
+ /*invoke: dynamic*/ /*int*/ ++;
+ /*dynamic*/ c. /*update: dynamic*/ /*dynamic*/ numInstance
+ /*invoke: dynamic*/ /*int*/ --;
+ /*invoke: dynamic*/ /*int*/ ++ /*dynamic*/ c
+ . /*update: dynamic*/ /*dynamic*/ numInstance;
+ /*invoke: dynamic*/ /*int*/ -- /*dynamic*/ c
+ . /*update: dynamic*/ /*dynamic*/ numInstance;
+
+ /*dynamic*/ c. /*update: dynamic*/ /*dynamic*/ intInstance
+ /*invoke: dynamic*/ /*int*/ ++;
+ /*dynamic*/ c. /*update: dynamic*/ /*dynamic*/ intInstance
+ /*invoke: dynamic*/ /*int*/ --;
+ /*invoke: dynamic*/ /*int*/ ++ /*dynamic*/ c
+ . /*update: dynamic*/ /*dynamic*/ intInstance;
+ /*invoke: dynamic*/ /*int*/ -- /*dynamic*/ c
+ . /*update: dynamic*/ /*dynamic*/ intInstance;
+
+ /*dynamic*/ c. /*update: dynamic*/ /*dynamic*/ dynamicInstance
+ /*invoke: dynamic*/ /*int*/ ++;
+ /*dynamic*/ c. /*update: dynamic*/ /*dynamic*/ dynamicInstance
+ /*invoke: dynamic*/ /*int*/ --;
+ /*invoke: dynamic*/ /*int*/ ++ /*dynamic*/ c
+ . /*update: dynamic*/ /*dynamic*/ dynamicInstance;
+ /*invoke: dynamic*/ /*int*/ -- /*dynamic*/ c
+ . /*update: dynamic*/ /*dynamic*/ dynamicInstance;
+}
+
+main() {
+ /// ignore: unused_local_variable
+ num numLocal = /*int*/ 0;
+
+ /// ignore: unused_local_variable
+ int intLocal = /*int*/ 0;
+
+ /// ignore: unused_local_variable
+ dynamic dynamicLocal = /*int*/ 0;
+
+ /*update: num*/ /*num*/ numLocal /*invoke: num*/ /*int*/ ++;
+ /*update: num*/ /*num*/ numLocal /*invoke: num*/ /*int*/ --;
+ /*invoke: num*/ /*int*/ ++ /*update: num*/ /*num*/ numLocal;
+ /*invoke: num*/ /*int*/ -- /*update: num*/ /*num*/ numLocal;
+
+ /*update: int*/ /*int*/ intLocal /*invoke: int*/ /*int*/ ++;
+ /*update: int*/ /*int*/ intLocal /*invoke: int*/ /*int*/ --;
+ /*invoke: int*/ /*int*/ ++ /*update: int*/ /*int*/ intLocal;
+ /*invoke: int*/ /*int*/ -- /*update: int*/ /*int*/ intLocal;
+
+ /*update: dynamic*/ /*dynamic*/ dynamicLocal /*invoke: dynamic*/ /*int*/ ++;
+ /*update: dynamic*/ /*dynamic*/ dynamicLocal /*invoke: dynamic*/ /*int*/ --;
+ /*invoke: dynamic*/ /*int*/ ++ /*update: dynamic*/ /*dynamic*/ dynamicLocal;
+ /*invoke: dynamic*/ /*int*/ -- /*update: dynamic*/ /*dynamic*/ dynamicLocal;
+}
diff --git a/pkg/front_end/test/utils/io_utils.dart b/pkg/front_end/test/utils/io_utils.dart
new file mode 100644
index 0000000..7fdd197
--- /dev/null
+++ b/pkg/front_end/test/utils/io_utils.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2019, 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.md file.
+
+import 'dart:io' show Directory, File, Platform, Process, ProcessResult;
+
+String computeRepoDir() {
+ ProcessResult result = Process.runSync(
+ 'git', ['rev-parse', '--show-toplevel'],
+ runInShell: true,
+ workingDirectory: new File.fromUri(Platform.script).parent.path);
+ return (result.stdout as String).trim();
+}
+
+Uri computeRepoDirUri() {
+ String dirPath = computeRepoDir();
+ return new Directory(dirPath).uri;
+}
diff --git a/pkg/front_end/lib/src/fasta/testing/kernel_chain.dart b/pkg/front_end/test/utils/kernel_chain.dart
similarity index 88%
rename from pkg/front_end/lib/src/fasta/testing/kernel_chain.dart
rename to pkg/front_end/test/utils/kernel_chain.dart
index 62bc602..fca8792 100644
--- a/pkg/front_end/lib/src/fasta/testing/kernel_chain.dart
+++ b/pkg/front_end/test/utils/kernel_chain.dart
@@ -7,15 +7,38 @@
import 'dart:async' show Future;
import 'dart:io' show Directory, File, IOSink;
+import 'dart:io';
import 'dart:typed_data' show Uint8List;
+import 'package:front_end/src/api_prototype/compiler_options.dart'
+ show CompilerOptions, DiagnosticMessage;
+
+import 'package:front_end/src/base/processed_options.dart'
+ show ProcessedOptions;
+
+import 'package:front_end/src/compute_platform_binaries_location.dart'
+ show computePlatformBinariesLocation;
+
+import 'package:front_end/src/fasta/compiler_context.dart' show CompilerContext;
+
+import 'package:front_end/src/fasta/fasta_codes.dart'
+ show templateInternalProblemUnhandled, templateUnspecified;
+
+import 'package:front_end/src/fasta/kernel/verifier.dart' show verifyComponent;
+
+import 'package:front_end/src/fasta/messages.dart' show LocatedMessage;
+
+import 'package:front_end/src/fasta/resolve_input_uri.dart' show isWindows;
+
+import 'package:front_end/src/fasta/util/relativize.dart' show relativizeUri;
+
import 'package:kernel/ast.dart' show Component, Library;
-import 'package:kernel/binary/ast_to_binary.dart' show BinaryPrinter;
-
import 'package:kernel/binary/ast_from_binary.dart' show BinaryBuilder;
+import 'package:kernel/binary/ast_to_binary.dart' show BinaryPrinter;
+
import 'package:kernel/error_formatter.dart' show ErrorFormatter;
import 'package:kernel/kernel.dart' show loadComponentFromBinary;
@@ -35,27 +58,6 @@
import 'package:testing/testing.dart'
show ChainContext, Expectation, ExpectationSet, Result, StdioProcess, Step;
-import '../../api_prototype/compiler_options.dart'
- show CompilerOptions, DiagnosticMessage;
-
-import '../../base/processed_options.dart' show ProcessedOptions;
-
-import '../../compute_platform_binaries_location.dart'
- show computePlatformBinariesLocation;
-
-import '../compiler_context.dart' show CompilerContext;
-
-import '../kernel/verifier.dart' show verifyComponent;
-
-import '../messages.dart' show LocatedMessage;
-
-import '../fasta_codes.dart'
- show templateInternalProblemUnhandled, templateUnspecified;
-
-import '../resolve_input_uri.dart' show isWindows;
-
-import '../util/relativize.dart' show relativizeUri;
-
final Uri platformBinariesLocation = computePlatformBinariesLocation();
abstract class MatchContext implements ChainContext {
@@ -401,10 +403,32 @@
}
Future<String> runDiff(Uri expected, String actual) async {
- StdioProcess process = await StdioProcess.run(
- "git", <String>["diff", "--no-index", "-u", expected.toFilePath(), "-"],
- input: actual, runInShell: true);
- return process.output;
+ if (Platform.isWindows) {
+ // TODO(johnniwinther): Work-around for Windows. For some reason piping
+ // the actual result through stdin doesn't work; it shows a diff as if the
+ // actual result is the empty string.
+ Directory tempDirectory = Directory.systemTemp.createTempSync();
+ Uri uri = tempDirectory.uri.resolve('actual');
+ File file = new File.fromUri(uri)..writeAsStringSync(actual);
+ StdioProcess process = await StdioProcess.run(
+ "git",
+ <String>[
+ "diff",
+ "--no-index",
+ "-u",
+ expected.toFilePath(),
+ uri.toFilePath()
+ ],
+ runInShell: true);
+ file.deleteSync();
+ tempDirectory.deleteSync();
+ return process.output;
+ } else {
+ StdioProcess process = await StdioProcess.run(
+ "git", <String>["diff", "--no-index", "-u", expected.toFilePath(), "-"],
+ input: actual, runInShell: true);
+ return process.output;
+ }
}
Future<void> openWrite(Uri uri, f(IOSink sink)) async {
diff --git a/pkg/front_end/lib/src/fasta/testing/scanner_chain.dart b/pkg/front_end/test/utils/scanner_chain.dart
similarity index 80%
rename from pkg/front_end/lib/src/fasta/testing/scanner_chain.dart
rename to pkg/front_end/test/utils/scanner_chain.dart
index 151291f..3dbdd99 100644
--- a/pkg/front_end/lib/src/fasta/testing/scanner_chain.dart
+++ b/pkg/front_end/test/utils/scanner_chain.dart
@@ -4,11 +4,12 @@
library fasta.testing.scanner_chain;
-import 'package:testing/testing.dart';
+import 'package:front_end/src/fasta/scanner.dart' show ScannerResult, scan;
-import '../scanner.dart';
+import 'package:front_end/src/fasta/scanner/io.dart' show readBytesFromFile;
-import '../scanner/io.dart';
+import 'package:testing/testing.dart'
+ show ChainContext, Future, Result, Step, TestDescription;
class ReadFile {
final Uri uri;
diff --git a/pkg/front_end/lib/src/fasta/testing/validating_instrumentation.dart b/pkg/front_end/test/utils/validating_instrumentation.dart
similarity index 94%
rename from pkg/front_end/lib/src/fasta/testing/validating_instrumentation.dart
rename to pkg/front_end/test/utils/validating_instrumentation.dart
index 8c96c60..afdda22 100644
--- a/pkg/front_end/lib/src/fasta/testing/validating_instrumentation.dart
+++ b/pkg/front_end/test/utils/validating_instrumentation.dart
@@ -8,19 +8,22 @@
import 'dart:io' show File;
-import '../../base/instrumentation.dart';
+import 'package:front_end/src/base/instrumentation.dart'
+ show Instrumentation, InstrumentationValue;
-import '../../scanner/token.dart' as analyzer;
+import 'package:front_end/src/fasta/compiler_context.dart' show CompilerContext;
-import '../compiler_context.dart' show CompilerContext;
+import 'package:front_end/src/fasta/messages.dart'
+ show noLength, templateUnspecified;
-import '../messages.dart' show noLength, templateUnspecified;
+import 'package:front_end/src/fasta/scanner.dart'
+ show ScannerResult, Token, scan;
-import '../scanner.dart' show ScannerResult, Token, scan;
+import 'package:front_end/src/fasta/scanner/io.dart' show readBytesFromFile;
-import '../scanner/io.dart' show readBytesFromFile;
+import 'package:front_end/src/fasta/severity.dart' show Severity;
-import '../severity.dart' show Severity;
+import 'package:front_end/src/scanner/token.dart' as analyzer show Token;
/// Implementation of [Instrumentation] which checks property/value pairs
/// against expectations encoded in source files using "/*@...*/" comments.
diff --git a/pkg/front_end/test/whole_program_test.dart b/pkg/front_end/test/whole_program_test.dart
index 717e20c..f9c2d2f 100644
--- a/pkg/front_end/test/whole_program_test.dart
+++ b/pkg/front_end/test/whole_program_test.dart
@@ -52,7 +52,7 @@
Future runCompiler(Uri input, Uri output) async {
final Uri platformDill = computePlatformBinariesLocation(forceBuildDir: true)
- .resolve("vm_platform.dill");
+ .resolve("vm_platform_strong.dill");
final List<String> arguments = <String>[
'--packages=${packagesFile.toFilePath()}',
diff --git a/pkg/front_end/testcases/expression/type_param_bound.expression.yaml.expect b/pkg/front_end/testcases/expression/type_param_bound.expression.yaml.expect
index 4d0bbb7..a38c415 100644
--- a/pkg/front_end/testcases/expression/type_param_bound.expression.yaml.expect
+++ b/pkg/front_end/testcases/expression/type_param_bound.expression.yaml.expect
@@ -6,4 +6,4 @@
^
}
method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr<T extends dynamic>() → dynamic
- return main::hasBound<#lib1::debugExpr::T>();
+ return main::hasBound<#lib1::debugExpr::T*>();
diff --git a/pkg/front_end/testcases/expression/type_param_bound_2.expression.yaml.expect b/pkg/front_end/testcases/expression/type_param_bound_2.expression.yaml.expect
index 4d0bbb7..a38c415 100644
--- a/pkg/front_end/testcases/expression/type_param_bound_2.expression.yaml.expect
+++ b/pkg/front_end/testcases/expression/type_param_bound_2.expression.yaml.expect
@@ -6,4 +6,4 @@
^
}
method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr<T extends dynamic>() → dynamic
- return main::hasBound<#lib1::debugExpr::T>();
+ return main::hasBound<#lib1::debugExpr::T*>();
diff --git a/pkg/front_end/testcases/expression/type_param_shadow.expression.yaml.expect b/pkg/front_end/testcases/expression/type_param_shadow.expression.yaml.expect
index dfc583e..6cb5b78 100644
--- a/pkg/front_end/testcases/expression/type_param_shadow.expression.yaml.expect
+++ b/pkg/front_end/testcases/expression/type_param_shadow.expression.yaml.expect
@@ -1,4 +1,4 @@
Errors: {
}
method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr<T extends dynamic>(dynamic x) → dynamic
- return x is main::A::debugExpr::T;
+ return x is main::A::debugExpr::T*;
diff --git a/pkg/front_end/testcases/expression/type_param_shadow_arg.expression.yaml.expect b/pkg/front_end/testcases/expression/type_param_shadow_arg.expression.yaml.expect
index 1a951e3..5b54940 100644
--- a/pkg/front_end/testcases/expression/type_param_shadow_arg.expression.yaml.expect
+++ b/pkg/front_end/testcases/expression/type_param_shadow_arg.expression.yaml.expect
@@ -1,4 +1,4 @@
Errors: {
}
method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr<T extends dynamic>(dynamic x) → dynamic
- return main::id<main::A::debugExpr::T>(x as{TypeError} main::A::debugExpr::T);
+ return main::id<main::A::debugExpr::T*>(x as{TypeError} main::A::debugExpr::T*);
diff --git a/pkg/front_end/testcases/expression/type_param_shadow_arg_ctor_inferred.expression.yaml.expect b/pkg/front_end/testcases/expression/type_param_shadow_arg_ctor_inferred.expression.yaml.expect
index 9a35069..82ea2ad 100644
--- a/pkg/front_end/testcases/expression/type_param_shadow_arg_ctor_inferred.expression.yaml.expect
+++ b/pkg/front_end/testcases/expression/type_param_shadow_arg_ctor_inferred.expression.yaml.expect
@@ -7,5 +7,5 @@
}
method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr<T extends dynamic>() → dynamic
return () → dart.core::Null* {
- main::A::debugExpr::T k = let final<BottomType> #t1 = invalid-expression "org-dartlang-debug:synthetic_debug_expression:2:13: Error: A value of type 'A<dynamic>' can't be assigned to a variable of type 'T'.\n - 'A' is from 'pkg/front_end/testcases/expression/main.dart'.\nTry changing the type of the left hand side, or casting the right hand side to 'T'.\n T k = new A();\n ^" in new main::A::•<dynamic>() as{TypeError} <BottomType>;
+ main::A::debugExpr::T* k = let final<BottomType> #t1 = invalid-expression "org-dartlang-debug:synthetic_debug_expression:2:13: Error: A value of type 'A<dynamic>' can't be assigned to a variable of type 'T'.\n - 'A' is from 'pkg/front_end/testcases/expression/main.dart'.\nTry changing the type of the left hand side, or casting the right hand side to 'T'.\n T k = new A();\n ^" in new main::A::•<dynamic>() as{TypeError} <BottomType>;
};
diff --git a/pkg/front_end/testcases/expression/type_param_shadow_arg_inferred.expression.yaml.expect b/pkg/front_end/testcases/expression/type_param_shadow_arg_inferred.expression.yaml.expect
index 8c299a7..140cb36 100644
--- a/pkg/front_end/testcases/expression/type_param_shadow_arg_inferred.expression.yaml.expect
+++ b/pkg/front_end/testcases/expression/type_param_shadow_arg_inferred.expression.yaml.expect
@@ -2,6 +2,6 @@
}
method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr<T extends dynamic>() → dynamic
return () → dart.core::Null* {
- main::A::debugExpr::T k = null;
- k = main::id<main::A::debugExpr::T>(k);
+ main::A::debugExpr::T* k = null;
+ k = main::id<main::A::debugExpr::T*>(k);
};
diff --git a/pkg/front_end/testcases/expression/type_param_shadow_ctor.expression.yaml.expect b/pkg/front_end/testcases/expression/type_param_shadow_ctor.expression.yaml.expect
index 87f7a81..6ae7542 100644
--- a/pkg/front_end/testcases/expression/type_param_shadow_ctor.expression.yaml.expect
+++ b/pkg/front_end/testcases/expression/type_param_shadow_ctor.expression.yaml.expect
@@ -1,4 +1,4 @@
Errors: {
}
method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr<T extends dynamic>() → dynamic
- return new main::A::•<main::A::debugExpr::T>();
+ return new main::A::•<main::A::debugExpr::T*>();
diff --git a/pkg/front_end/testcases/expression/type_param_shadow_var.expression.yaml.expect b/pkg/front_end/testcases/expression/type_param_shadow_var.expression.yaml.expect
index 4a2c0ec..ad817cd 100644
--- a/pkg/front_end/testcases/expression/type_param_shadow_var.expression.yaml.expect
+++ b/pkg/front_end/testcases/expression/type_param_shadow_var.expression.yaml.expect
@@ -2,5 +2,5 @@
}
method /* from org-dartlang-debug:synthetic_debug_expression */ debugExpr<T extends dynamic>(dynamic x) → dynamic
return () → dart.core::Null* {
- main::A::debugExpr::T x = null;
+ main::A::debugExpr::T* x = null;
};
diff --git a/pkg/front_end/testcases/extensions/direct_instance_access.dart.outline.expect b/pkg/front_end/testcases/extensions/direct_instance_access.dart.outline.expect
index dfcdbe8..86ff6e6 100644
--- a/pkg/front_end/testcases/extensions/direct_instance_access.dart.outline.expect
+++ b/pkg/front_end/testcases/extensions/direct_instance_access.dart.outline.expect
@@ -14,27 +14,41 @@
}
extension Extension on self::Class* {
method readGetter = self::Extension|readGetter;
+ tearoff readGetter = self::Extension|get#readGetter;
method writeSetterRequired = self::Extension|writeSetterRequired;
+ tearoff writeSetterRequired = self::Extension|get#writeSetterRequired;
method writeSetterOptional = self::Extension|writeSetterOptional;
+ tearoff writeSetterOptional = self::Extension|get#writeSetterOptional;
method writeSetterNamed = self::Extension|writeSetterNamed;
+ tearoff writeSetterNamed = self::Extension|get#writeSetterNamed;
get tearOffGetterNoArgs = self::Extension|get#tearOffGetterNoArgs;
get tearOffGetterRequired = self::Extension|get#tearOffGetterRequired;
get tearOffGetterOptional = self::Extension|get#tearOffGetterOptional;
get tearOffGetterNamed = self::Extension|get#tearOffGetterNamed;
get property = self::Extension|get#property;
method invocations = self::Extension|invocations;
+ tearoff invocations = self::Extension|get#invocations;
method tearOffs = self::Extension|tearOffs;
+ tearoff tearOffs = self::Extension|get#tearOffs;
method getterCalls = self::Extension|getterCalls;
+ tearoff getterCalls = self::Extension|get#getterCalls;
set property = self::Extension|set#property;
}
extension GenericExtension<T extends core::Object* = dynamic> on self::GenericClass<T*>* {
method readGetter = self::GenericExtension|readGetter;
+ tearoff readGetter = self::GenericExtension|get#readGetter;
method writeSetterRequired = self::GenericExtension|writeSetterRequired;
+ tearoff writeSetterRequired = self::GenericExtension|get#writeSetterRequired;
method writeSetterOptional = self::GenericExtension|writeSetterOptional;
+ tearoff writeSetterOptional = self::GenericExtension|get#writeSetterOptional;
method writeSetterNamed = self::GenericExtension|writeSetterNamed;
+ tearoff writeSetterNamed = self::GenericExtension|get#writeSetterNamed;
method genericWriteSetterRequired = self::GenericExtension|genericWriteSetterRequired;
+ tearoff genericWriteSetterRequired = self::GenericExtension|get#genericWriteSetterRequired;
method genericWriteSetterOptional = self::GenericExtension|genericWriteSetterOptional;
+ tearoff genericWriteSetterOptional = self::GenericExtension|get#genericWriteSetterOptional;
method genericWriteSetterNamed = self::GenericExtension|genericWriteSetterNamed;
+ tearoff genericWriteSetterNamed = self::GenericExtension|get#genericWriteSetterNamed;
get property = self::GenericExtension|get#property;
get tearOffGetterNoArgs = self::GenericExtension|get#tearOffGetterNoArgs;
get tearOffGetterRequired = self::GenericExtension|get#tearOffGetterRequired;
@@ -44,18 +58,29 @@
get tearOffGetterGenericOptional = self::GenericExtension|get#tearOffGetterGenericOptional;
get tearOffGetterGenericNamed = self::GenericExtension|get#tearOffGetterGenericNamed;
method invocations = self::GenericExtension|invocations;
+ tearoff invocations = self::GenericExtension|get#invocations;
method tearOffs = self::GenericExtension|tearOffs;
+ tearoff tearOffs = self::GenericExtension|get#tearOffs;
method getterCalls = self::GenericExtension|getterCalls;
+ tearoff getterCalls = self::GenericExtension|get#getterCalls;
set property = self::GenericExtension|set#property;
}
+static method Extension|get#readGetter(final self::Class* #this) → () →* dynamic
+ return () → dynamic => self::Extension|readGetter(#this);
static method Extension|readGetter(final self::Class* #this) → dynamic
;
static method Extension|writeSetterRequired(final self::Class* #this, dynamic value) → dynamic
;
+static method Extension|get#writeSetterRequired(final self::Class* #this) → (dynamic) →* dynamic
+ return (dynamic value) → dynamic => self::Extension|writeSetterRequired(#this, value);
static method Extension|writeSetterOptional(final self::Class* #this, [dynamic value]) → dynamic
;
+static method Extension|get#writeSetterOptional(final self::Class* #this) → ([dynamic]) →* dynamic
+ return ([dynamic value = null]) → dynamic => self::Extension|writeSetterOptional(#this, value);
static method Extension|writeSetterNamed(final self::Class* #this, {dynamic value}) → dynamic
;
+static method Extension|get#writeSetterNamed(final self::Class* #this) → ({value: dynamic}) →* dynamic
+ return ({dynamic value = null}) → dynamic => self::Extension|writeSetterNamed(#this, value: value);
static method Extension|get#tearOffGetterNoArgs(final self::Class* #this) → dynamic
;
static method Extension|get#tearOffGetterRequired(final self::Class* #this) → dynamic
@@ -70,47 +95,73 @@
;
static method Extension|invocations(final self::Class* #this, dynamic value) → dynamic
;
+static method Extension|get#invocations(final self::Class* #this) → (dynamic) →* dynamic
+ return (dynamic value) → dynamic => self::Extension|invocations(#this, value);
+static method Extension|get#tearOffs(final self::Class* #this) → (dynamic) →* dynamic
+ return (dynamic value) → dynamic => self::Extension|tearOffs(#this, value);
static method Extension|tearOffs(final self::Class* #this, dynamic value) → dynamic
;
static method Extension|getterCalls(final self::Class* #this, dynamic value) → dynamic
;
-static method GenericExtension|readGetter<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|readGetter::#T*>* #this) → self::GenericExtension|readGetter::#T*
+static method Extension|get#getterCalls(final self::Class* #this) → (dynamic) →* dynamic
+ return (dynamic value) → dynamic => self::Extension|getterCalls(#this, value);
+static method GenericExtension|readGetter<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|readGetter::T*>* #this) → self::GenericExtension|readGetter::T*
;
-static method GenericExtension|writeSetterRequired<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterRequired::#T*>* #this, self::GenericExtension|writeSetterRequired::#T* value) → dynamic
+static method GenericExtension|get#readGetter<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#readGetter::T*>* #this) → () →* self::GenericExtension|get#readGetter::T*
+ return () → self::GenericExtension|get#readGetter::T* => self::GenericExtension|readGetter<self::GenericExtension|get#readGetter::T*>(#this);
+static method GenericExtension|writeSetterRequired<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterRequired::T*>* #this, self::GenericExtension|writeSetterRequired::T* value) → dynamic
;
-static method GenericExtension|writeSetterOptional<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterOptional::#T*>* #this, [self::GenericExtension|writeSetterOptional::#T* value]) → dynamic
+static method GenericExtension|get#writeSetterRequired<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#writeSetterRequired::T*>* #this) → (self::GenericExtension|get#writeSetterRequired::T*) →* dynamic
+ return (self::GenericExtension|get#writeSetterRequired::T* value) → dynamic => self::GenericExtension|writeSetterRequired<self::GenericExtension|get#writeSetterRequired::T*>(#this, value);
+static method GenericExtension|writeSetterOptional<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterOptional::T*>* #this, [self::GenericExtension|writeSetterOptional::T* value]) → dynamic
;
-static method GenericExtension|writeSetterNamed<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterNamed::#T*>* #this, {self::GenericExtension|writeSetterNamed::#T* value}) → dynamic
+static method GenericExtension|get#writeSetterOptional<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#writeSetterOptional::T*>* #this) → ([self::GenericExtension|get#writeSetterOptional::T*]) →* dynamic
+ return ([self::GenericExtension|get#writeSetterOptional::T* value = null]) → dynamic => self::GenericExtension|writeSetterOptional<self::GenericExtension|get#writeSetterOptional::T*>(#this, value);
+static method GenericExtension|writeSetterNamed<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterNamed::T*>* #this, {self::GenericExtension|writeSetterNamed::T* value}) → dynamic
;
-static method GenericExtension|genericWriteSetterRequired<#T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterRequired::#T = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterRequired::#T*>* #this, self::GenericExtension|genericWriteSetterRequired::S value) → dynamic
+static method GenericExtension|get#writeSetterNamed<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#writeSetterNamed::T*>* #this) → ({value: self::GenericExtension|get#writeSetterNamed::T*}) →* dynamic
+ return ({self::GenericExtension|get#writeSetterNamed::T* value = null}) → dynamic => self::GenericExtension|writeSetterNamed<self::GenericExtension|get#writeSetterNamed::T*>(#this, value: value);
+static method GenericExtension|genericWriteSetterRequired<T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterRequired::T* = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterRequired::T*>* #this, self::GenericExtension|genericWriteSetterRequired::S* value) → dynamic
;
-static method GenericExtension|genericWriteSetterOptional<#T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterOptional::#T = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterOptional::#T*>* #this, [self::GenericExtension|genericWriteSetterOptional::S value]) → dynamic
+static method GenericExtension|get#genericWriteSetterRequired<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#genericWriteSetterRequired::T*>* #this) → <S extends self::GenericExtension|get#genericWriteSetterRequired::T* = dynamic>(S*) →* dynamic
+ return <S extends self::GenericExtension|get#genericWriteSetterRequired::T* = dynamic>(S* value) → dynamic => self::GenericExtension|genericWriteSetterRequired<self::GenericExtension|get#genericWriteSetterRequired::T*, S*>(#this, value);
+static method GenericExtension|genericWriteSetterOptional<T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterOptional::T* = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterOptional::T*>* #this, [self::GenericExtension|genericWriteSetterOptional::S* value]) → dynamic
;
-static method GenericExtension|genericWriteSetterNamed<#T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterNamed::#T = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterNamed::#T*>* #this, {self::GenericExtension|genericWriteSetterNamed::S value}) → dynamic
+static method GenericExtension|get#genericWriteSetterOptional<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#genericWriteSetterOptional::T*>* #this) → <S extends self::GenericExtension|get#genericWriteSetterOptional::T* = dynamic>([S*]) →* dynamic
+ return <S extends self::GenericExtension|get#genericWriteSetterOptional::T* = dynamic>([S* value = null]) → dynamic => self::GenericExtension|genericWriteSetterOptional<self::GenericExtension|get#genericWriteSetterOptional::T*, S*>(#this, value);
+static method GenericExtension|get#genericWriteSetterNamed<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#genericWriteSetterNamed::T*>* #this) → <S extends self::GenericExtension|get#genericWriteSetterNamed::T* = dynamic>({value: S*}) →* dynamic
+ return <S extends self::GenericExtension|get#genericWriteSetterNamed::T* = dynamic>({S* value = null}) → dynamic => self::GenericExtension|genericWriteSetterNamed<self::GenericExtension|get#genericWriteSetterNamed::T*, S*>(#this, value: value);
+static method GenericExtension|genericWriteSetterNamed<T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterNamed::T* = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterNamed::T*>* #this, {self::GenericExtension|genericWriteSetterNamed::S* value}) → dynamic
;
-static method GenericExtension|get#property<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#property::#T*>* #this) → self::GenericExtension|get#property::#T*
+static method GenericExtension|get#property<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#property::T*>* #this) → self::GenericExtension|get#property::T*
;
-static method GenericExtension|set#property<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|set#property::#T*>* #this, self::GenericExtension|set#property::#T* value) → void
+static method GenericExtension|set#property<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|set#property::T*>* #this, self::GenericExtension|set#property::T* value) → void
;
-static method GenericExtension|get#tearOffGetterNoArgs<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterNoArgs::#T*>* #this) → dynamic
+static method GenericExtension|get#tearOffGetterNoArgs<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterNoArgs::T*>* #this) → dynamic
;
-static method GenericExtension|get#tearOffGetterRequired<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterRequired::#T*>* #this) → dynamic
+static method GenericExtension|get#tearOffGetterRequired<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterRequired::T*>* #this) → dynamic
;
-static method GenericExtension|get#tearOffGetterOptional<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterOptional::#T*>* #this) → dynamic
+static method GenericExtension|get#tearOffGetterOptional<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterOptional::T*>* #this) → dynamic
;
-static method GenericExtension|get#tearOffGetterNamed<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterNamed::#T*>* #this) → dynamic
+static method GenericExtension|get#tearOffGetterNamed<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterNamed::T*>* #this) → dynamic
;
-static method GenericExtension|get#tearOffGetterGenericRequired<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericRequired::#T*>* #this) → dynamic
+static method GenericExtension|get#tearOffGetterGenericRequired<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericRequired::T*>* #this) → dynamic
;
-static method GenericExtension|get#tearOffGetterGenericOptional<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericOptional::#T*>* #this) → dynamic
+static method GenericExtension|get#tearOffGetterGenericOptional<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericOptional::T*>* #this) → dynamic
;
-static method GenericExtension|get#tearOffGetterGenericNamed<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericNamed::#T*>* #this) → dynamic
+static method GenericExtension|get#tearOffGetterGenericNamed<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericNamed::T*>* #this) → dynamic
;
-static method GenericExtension|invocations<#T extends core::Object* = dynamic, S extends self::GenericExtension|invocations::#T = dynamic>(final self::GenericClass<self::GenericExtension|invocations::#T*>* #this, self::GenericExtension|invocations::S value) → dynamic
+static method GenericExtension|invocations<T extends core::Object* = dynamic, S extends self::GenericExtension|invocations::T* = dynamic>(final self::GenericClass<self::GenericExtension|invocations::T*>* #this, self::GenericExtension|invocations::S* value) → dynamic
;
-static method GenericExtension|tearOffs<#T extends core::Object* = dynamic, S extends self::GenericExtension|tearOffs::#T = dynamic>(final self::GenericClass<self::GenericExtension|tearOffs::#T*>* #this, self::GenericExtension|tearOffs::S value) → dynamic
+static method GenericExtension|get#invocations<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#invocations::T*>* #this) → <S extends self::GenericExtension|get#invocations::T* = dynamic>(S*) →* dynamic
+ return <S extends self::GenericExtension|get#invocations::T* = dynamic>(S* value) → dynamic => self::GenericExtension|invocations<self::GenericExtension|get#invocations::T*, S*>(#this, value);
+static method GenericExtension|tearOffs<T extends core::Object* = dynamic, S extends self::GenericExtension|tearOffs::T* = dynamic>(final self::GenericClass<self::GenericExtension|tearOffs::T*>* #this, self::GenericExtension|tearOffs::S* value) → dynamic
;
-static method GenericExtension|getterCalls<#T extends core::Object* = dynamic, S extends self::GenericExtension|getterCalls::#T = dynamic>(final self::GenericClass<self::GenericExtension|getterCalls::#T*>* #this, self::GenericExtension|getterCalls::S value) → dynamic
+static method GenericExtension|get#tearOffs<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffs::T*>* #this) → <S extends self::GenericExtension|get#tearOffs::T* = dynamic>(S*) →* dynamic
+ return <S extends self::GenericExtension|get#tearOffs::T* = dynamic>(S* value) → dynamic => self::GenericExtension|tearOffs<self::GenericExtension|get#tearOffs::T*, S*>(#this, value);
+static method GenericExtension|getterCalls<T extends core::Object* = dynamic, S extends self::GenericExtension|getterCalls::T* = dynamic>(final self::GenericClass<self::GenericExtension|getterCalls::T*>* #this, self::GenericExtension|getterCalls::S* value) → dynamic
;
+static method GenericExtension|get#getterCalls<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#getterCalls::T*>* #this) → <S extends self::GenericExtension|get#getterCalls::T* = dynamic>(S*) →* dynamic
+ return <S extends self::GenericExtension|get#getterCalls::T* = dynamic>(S* value) → dynamic => self::GenericExtension|getterCalls<self::GenericExtension|get#getterCalls::T*, S*>(#this, value);
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/extensions/direct_instance_access.dart.strong.expect b/pkg/front_end/testcases/extensions/direct_instance_access.dart.strong.expect
index eff6825..a652a17 100644
--- a/pkg/front_end/testcases/extensions/direct_instance_access.dart.strong.expect
+++ b/pkg/front_end/testcases/extensions/direct_instance_access.dart.strong.expect
@@ -16,27 +16,41 @@
}
extension Extension on self::Class* {
method readGetter = self::Extension|readGetter;
+ tearoff readGetter = self::Extension|get#readGetter;
method writeSetterRequired = self::Extension|writeSetterRequired;
+ tearoff writeSetterRequired = self::Extension|get#writeSetterRequired;
method writeSetterOptional = self::Extension|writeSetterOptional;
+ tearoff writeSetterOptional = self::Extension|get#writeSetterOptional;
method writeSetterNamed = self::Extension|writeSetterNamed;
+ tearoff writeSetterNamed = self::Extension|get#writeSetterNamed;
get tearOffGetterNoArgs = self::Extension|get#tearOffGetterNoArgs;
get tearOffGetterRequired = self::Extension|get#tearOffGetterRequired;
get tearOffGetterOptional = self::Extension|get#tearOffGetterOptional;
get tearOffGetterNamed = self::Extension|get#tearOffGetterNamed;
get property = self::Extension|get#property;
method invocations = self::Extension|invocations;
+ tearoff invocations = self::Extension|get#invocations;
method tearOffs = self::Extension|tearOffs;
+ tearoff tearOffs = self::Extension|get#tearOffs;
method getterCalls = self::Extension|getterCalls;
+ tearoff getterCalls = self::Extension|get#getterCalls;
set property = self::Extension|set#property;
}
extension GenericExtension<T extends core::Object* = dynamic> on self::GenericClass<T*>* {
method readGetter = self::GenericExtension|readGetter;
+ tearoff readGetter = self::GenericExtension|get#readGetter;
method writeSetterRequired = self::GenericExtension|writeSetterRequired;
+ tearoff writeSetterRequired = self::GenericExtension|get#writeSetterRequired;
method writeSetterOptional = self::GenericExtension|writeSetterOptional;
+ tearoff writeSetterOptional = self::GenericExtension|get#writeSetterOptional;
method writeSetterNamed = self::GenericExtension|writeSetterNamed;
+ tearoff writeSetterNamed = self::GenericExtension|get#writeSetterNamed;
method genericWriteSetterRequired = self::GenericExtension|genericWriteSetterRequired;
+ tearoff genericWriteSetterRequired = self::GenericExtension|get#genericWriteSetterRequired;
method genericWriteSetterOptional = self::GenericExtension|genericWriteSetterOptional;
+ tearoff genericWriteSetterOptional = self::GenericExtension|get#genericWriteSetterOptional;
method genericWriteSetterNamed = self::GenericExtension|genericWriteSetterNamed;
+ tearoff genericWriteSetterNamed = self::GenericExtension|get#genericWriteSetterNamed;
get property = self::GenericExtension|get#property;
get tearOffGetterNoArgs = self::GenericExtension|get#tearOffGetterNoArgs;
get tearOffGetterRequired = self::GenericExtension|get#tearOffGetterRequired;
@@ -46,34 +60,47 @@
get tearOffGetterGenericOptional = self::GenericExtension|get#tearOffGetterGenericOptional;
get tearOffGetterGenericNamed = self::GenericExtension|get#tearOffGetterGenericNamed;
method invocations = self::GenericExtension|invocations;
+ tearoff invocations = self::GenericExtension|get#invocations;
method tearOffs = self::GenericExtension|tearOffs;
+ tearoff tearOffs = self::GenericExtension|get#tearOffs;
method getterCalls = self::GenericExtension|getterCalls;
+ tearoff getterCalls = self::GenericExtension|get#getterCalls;
set property = self::GenericExtension|set#property;
}
+static method Extension|get#readGetter(final self::Class* #this) → () →* dynamic
+ return () → dynamic => self::Extension|readGetter(#this);
static method Extension|readGetter(final self::Class* #this) → dynamic {
return self::Extension|get#property(#this);
}
static method Extension|writeSetterRequired(final self::Class* #this, dynamic value) → dynamic {
self::Extension|set#property(#this, value);
}
+static method Extension|get#writeSetterRequired(final self::Class* #this) → (dynamic) →* dynamic
+ return (dynamic value) → dynamic => self::Extension|writeSetterRequired(#this, value);
static method Extension|writeSetterOptional(final self::Class* #this = #C1, [dynamic value = #C1]) → dynamic {
self::Extension|set#property(#this, value);
}
+static method Extension|get#writeSetterOptional(final self::Class* #this) → ([dynamic]) →* dynamic
+ return ([dynamic value = #C1]) → dynamic => self::Extension|writeSetterOptional(#this, value);
static method Extension|writeSetterNamed(final self::Class* #this = #C1, {dynamic value = #C1}) → dynamic {
self::Extension|set#property(#this, value);
}
-static method Extension|get#tearOffGetterNoArgs(final self::Class* #this) → dynamic
- return () → dynamic => self::Extension|readGetter(#this);
-static method Extension|get#tearOffGetterRequired(final self::Class* #this) → dynamic
- return (dynamic value) → dynamic => self::Extension|writeSetterRequired(#this, value);
-static method Extension|get#tearOffGetterOptional(final self::Class* #this) → dynamic
- return ([dynamic value = #C1]) → dynamic => self::Extension|writeSetterOptional(#this, value);
-static method Extension|get#tearOffGetterNamed(final self::Class* #this) → dynamic
+static method Extension|get#writeSetterNamed(final self::Class* #this) → ({value: dynamic}) →* dynamic
return ({dynamic value = #C1}) → dynamic => self::Extension|writeSetterNamed(#this, value: value);
+static method Extension|get#tearOffGetterNoArgs(final self::Class* #this) → dynamic
+ return self::Extension|get#readGetter(#this);
+static method Extension|get#tearOffGetterRequired(final self::Class* #this) → dynamic
+ return self::Extension|get#writeSetterRequired(#this);
+static method Extension|get#tearOffGetterOptional(final self::Class* #this) → dynamic
+ return self::Extension|get#writeSetterOptional(#this);
+static method Extension|get#tearOffGetterNamed(final self::Class* #this) → dynamic
+ return self::Extension|get#writeSetterNamed(#this);
static method Extension|get#property(final self::Class* #this) → dynamic
return #this.{self::Class::field};
-static method Extension|set#property(final self::Class* #this, dynamic value) → void {
+static method Extension|set#property(final self::Class* #this, dynamic value) → dynamic {
+ final dynamic #t1 = value;
#this.{self::Class::field} = value;
+ return #t1;
}
static method Extension|invocations(final self::Class* #this, dynamic value) → dynamic {
self::Extension|readGetter(#this);
@@ -83,15 +110,19 @@
self::Extension|writeSetterNamed(#this);
self::Extension|writeSetterNamed(#this, value: value);
}
+static method Extension|get#invocations(final self::Class* #this) → (dynamic) →* dynamic
+ return (dynamic value) → dynamic => self::Extension|invocations(#this, value);
+static method Extension|get#tearOffs(final self::Class* #this) → (dynamic) →* dynamic
+ return (dynamic value) → dynamic => self::Extension|tearOffs(#this, value);
static method Extension|tearOffs(final self::Class* #this, dynamic value) → dynamic {
- () →* dynamic tearOffNoArgs = () → dynamic => self::Extension|readGetter(#this);
+ () →* dynamic tearOffNoArgs = self::Extension|get#readGetter(#this);
tearOffNoArgs.call();
- (dynamic) →* dynamic tearOffRequired = (dynamic value) → dynamic => self::Extension|writeSetterRequired(#this, value);
+ (dynamic) →* dynamic tearOffRequired = self::Extension|get#writeSetterRequired(#this);
tearOffRequired.call(value);
- ([dynamic]) →* dynamic tearOffOptional = ([dynamic value = #C1]) → dynamic => self::Extension|writeSetterOptional(#this, value);
+ ([dynamic]) →* dynamic tearOffOptional = self::Extension|get#writeSetterOptional(#this);
tearOffOptional.call();
tearOffOptional.call(value);
- ({value: dynamic}) →* dynamic tearOffNamed = ({dynamic value = #C1}) → dynamic => self::Extension|writeSetterNamed(#this, value: value);
+ ({value: dynamic}) →* dynamic tearOffNamed = self::Extension|get#writeSetterNamed(#this);
tearOffNamed.call();
tearOffNamed.call(value: value);
}
@@ -103,107 +134,131 @@
self::Extension|get#tearOffGetterNamed(#this).call();
self::Extension|get#tearOffGetterNamed(#this).call(value: value);
}
-static method GenericExtension|readGetter<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|readGetter::#T*>* #this) → self::GenericExtension|readGetter::#T* {
- return self::GenericExtension|get#property<self::GenericExtension|readGetter::#T*>(#this);
+static method Extension|get#getterCalls(final self::Class* #this) → (dynamic) →* dynamic
+ return (dynamic value) → dynamic => self::Extension|getterCalls(#this, value);
+static method GenericExtension|readGetter<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|readGetter::T*>* #this) → self::GenericExtension|readGetter::T* {
+ return self::GenericExtension|get#property<self::GenericExtension|readGetter::T*>(#this);
}
-static method GenericExtension|writeSetterRequired<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterRequired::#T*>* #this, self::GenericExtension|writeSetterRequired::#T* value) → dynamic {
- self::GenericExtension|set#property<self::GenericExtension|writeSetterRequired::#T*>(#this, value);
+static method GenericExtension|get#readGetter<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#readGetter::T*>* #this) → () →* self::GenericExtension|get#readGetter::T*
+ return () → self::GenericExtension|get#readGetter::T* => self::GenericExtension|readGetter<self::GenericExtension|get#readGetter::T*>(#this);
+static method GenericExtension|writeSetterRequired<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterRequired::T*>* #this, self::GenericExtension|writeSetterRequired::T* value) → dynamic {
+ self::GenericExtension|set#property<self::GenericExtension|writeSetterRequired::T*>(#this, value);
}
-static method GenericExtension|writeSetterOptional<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterOptional::#T*>* #this = #C1, [self::GenericExtension|writeSetterOptional::#T* value = #C1]) → dynamic {
- self::GenericExtension|set#property<self::GenericExtension|writeSetterOptional::#T*>(#this, value);
+static method GenericExtension|get#writeSetterRequired<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#writeSetterRequired::T*>* #this) → (self::GenericExtension|get#writeSetterRequired::T*) →* dynamic
+ return (self::GenericExtension|get#writeSetterRequired::T* value) → dynamic => self::GenericExtension|writeSetterRequired<self::GenericExtension|get#writeSetterRequired::T*>(#this, value);
+static method GenericExtension|writeSetterOptional<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterOptional::T*>* #this = #C1, [self::GenericExtension|writeSetterOptional::T* value = #C1]) → dynamic {
+ self::GenericExtension|set#property<self::GenericExtension|writeSetterOptional::T*>(#this, value);
}
-static method GenericExtension|writeSetterNamed<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterNamed::#T*>* #this = #C1, {self::GenericExtension|writeSetterNamed::#T* value = #C1}) → dynamic {
- self::GenericExtension|set#property<self::GenericExtension|writeSetterNamed::#T*>(#this, value);
+static method GenericExtension|get#writeSetterOptional<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#writeSetterOptional::T*>* #this) → ([self::GenericExtension|get#writeSetterOptional::T*]) →* dynamic
+ return ([self::GenericExtension|get#writeSetterOptional::T* value = #C1]) → dynamic => self::GenericExtension|writeSetterOptional<self::GenericExtension|get#writeSetterOptional::T*>(#this, value);
+static method GenericExtension|writeSetterNamed<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterNamed::T*>* #this = #C1, {self::GenericExtension|writeSetterNamed::T* value = #C1}) → dynamic {
+ self::GenericExtension|set#property<self::GenericExtension|writeSetterNamed::T*>(#this, value);
}
-static method GenericExtension|genericWriteSetterRequired<#T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterRequired::#T = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterRequired::#T*>* #this, self::GenericExtension|genericWriteSetterRequired::S value) → dynamic {
- self::GenericExtension|set#property<self::GenericExtension|genericWriteSetterRequired::#T*>(#this, value);
+static method GenericExtension|get#writeSetterNamed<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#writeSetterNamed::T*>* #this) → ({value: self::GenericExtension|get#writeSetterNamed::T*}) →* dynamic
+ return ({self::GenericExtension|get#writeSetterNamed::T* value = #C1}) → dynamic => self::GenericExtension|writeSetterNamed<self::GenericExtension|get#writeSetterNamed::T*>(#this, value: value);
+static method GenericExtension|genericWriteSetterRequired<T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterRequired::T* = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterRequired::T*>* #this, self::GenericExtension|genericWriteSetterRequired::S* value) → dynamic {
+ self::GenericExtension|set#property<self::GenericExtension|genericWriteSetterRequired::T*>(#this, value);
}
-static method GenericExtension|genericWriteSetterOptional<#T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterOptional::#T = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterOptional::#T*>* #this = #C1, [self::GenericExtension|genericWriteSetterOptional::S value = #C1]) → dynamic {
- self::GenericExtension|set#property<self::GenericExtension|genericWriteSetterOptional::#T*>(#this, value);
+static method GenericExtension|get#genericWriteSetterRequired<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#genericWriteSetterRequired::T*>* #this) → <S extends self::GenericExtension|get#genericWriteSetterRequired::T* = dynamic>(S*) →* dynamic
+ return <S extends self::GenericExtension|get#genericWriteSetterRequired::T* = dynamic>(S* value) → dynamic => self::GenericExtension|genericWriteSetterRequired<self::GenericExtension|get#genericWriteSetterRequired::T*, S*>(#this, value);
+static method GenericExtension|genericWriteSetterOptional<T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterOptional::T* = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterOptional::T*>* #this = #C1, [self::GenericExtension|genericWriteSetterOptional::S* value = #C1]) → dynamic {
+ self::GenericExtension|set#property<self::GenericExtension|genericWriteSetterOptional::T*>(#this, value);
}
-static method GenericExtension|genericWriteSetterNamed<#T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterNamed::#T = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterNamed::#T*>* #this = #C1, {self::GenericExtension|genericWriteSetterNamed::S value = #C1}) → dynamic {
- self::GenericExtension|set#property<self::GenericExtension|genericWriteSetterNamed::#T*>(#this, value);
+static method GenericExtension|get#genericWriteSetterOptional<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#genericWriteSetterOptional::T*>* #this) → <S extends self::GenericExtension|get#genericWriteSetterOptional::T* = dynamic>([S*]) →* dynamic
+ return <S extends self::GenericExtension|get#genericWriteSetterOptional::T* = dynamic>([S* value = #C1]) → dynamic => self::GenericExtension|genericWriteSetterOptional<self::GenericExtension|get#genericWriteSetterOptional::T*, S*>(#this, value);
+static method GenericExtension|get#genericWriteSetterNamed<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#genericWriteSetterNamed::T*>* #this) → <S extends self::GenericExtension|get#genericWriteSetterNamed::T* = dynamic>({value: S*}) →* dynamic
+ return <S extends self::GenericExtension|get#genericWriteSetterNamed::T* = dynamic>({S* value = #C1}) → dynamic => self::GenericExtension|genericWriteSetterNamed<self::GenericExtension|get#genericWriteSetterNamed::T*, S*>(#this, value: value);
+static method GenericExtension|genericWriteSetterNamed<T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterNamed::T* = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterNamed::T*>* #this = #C1, {self::GenericExtension|genericWriteSetterNamed::S* value = #C1}) → dynamic {
+ self::GenericExtension|set#property<self::GenericExtension|genericWriteSetterNamed::T*>(#this, value);
}
-static method GenericExtension|get#property<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#property::#T*>* #this) → self::GenericExtension|get#property::#T*
+static method GenericExtension|get#property<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#property::T*>* #this) → self::GenericExtension|get#property::T*
return #this.{self::GenericClass::field};
-static method GenericExtension|set#property<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|set#property::#T*>* #this, self::GenericExtension|set#property::#T* value) → void {
+static method GenericExtension|set#property<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|set#property::T*>* #this, self::GenericExtension|set#property::T* value) → self::GenericExtension|set#property::T* {
+ final self::GenericExtension|set#property::T* #t2 = value;
#this.{self::GenericClass::field} = value;
+ return #t2;
}
-static method GenericExtension|get#tearOffGetterNoArgs<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterNoArgs::#T*>* #this) → dynamic
- return () → self::GenericExtension|get#tearOffGetterNoArgs::#T* => self::GenericExtension|readGetter<self::GenericExtension|get#tearOffGetterNoArgs::#T*>(#this);
-static method GenericExtension|get#tearOffGetterRequired<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterRequired::#T*>* #this) → dynamic
- return (self::GenericExtension|get#tearOffGetterRequired::#T* value) → dynamic => self::GenericExtension|writeSetterRequired<self::GenericExtension|get#tearOffGetterRequired::#T*>(#this, value);
-static method GenericExtension|get#tearOffGetterOptional<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterOptional::#T*>* #this) → dynamic
- return ([self::GenericExtension|get#tearOffGetterOptional::#T* value = #C1]) → dynamic => self::GenericExtension|writeSetterOptional<self::GenericExtension|get#tearOffGetterOptional::#T*>(#this, value);
-static method GenericExtension|get#tearOffGetterNamed<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterNamed::#T*>* #this) → dynamic
- return ({self::GenericExtension|get#tearOffGetterNamed::#T* value = #C1}) → dynamic => self::GenericExtension|writeSetterNamed<self::GenericExtension|get#tearOffGetterNamed::#T*>(#this, value: value);
-static method GenericExtension|get#tearOffGetterGenericRequired<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericRequired::#T*>* #this) → dynamic
- return <S extends self::GenericExtension|get#tearOffGetterGenericRequired::#T* = dynamic>(S value) → dynamic => self::GenericExtension|genericWriteSetterRequired<self::GenericExtension|get#tearOffGetterGenericRequired::#T*, S>(#this, value);
-static method GenericExtension|get#tearOffGetterGenericOptional<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericOptional::#T*>* #this) → dynamic
- return <S extends self::GenericExtension|get#tearOffGetterGenericOptional::#T* = dynamic>([S value = #C1]) → dynamic => self::GenericExtension|genericWriteSetterOptional<self::GenericExtension|get#tearOffGetterGenericOptional::#T*, S>(#this, value);
-static method GenericExtension|get#tearOffGetterGenericNamed<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericNamed::#T*>* #this) → dynamic
- return <S extends self::GenericExtension|get#tearOffGetterGenericNamed::#T* = dynamic>({S value = #C1}) → dynamic => self::GenericExtension|genericWriteSetterNamed<self::GenericExtension|get#tearOffGetterGenericNamed::#T*, S>(#this, value: value);
-static method GenericExtension|invocations<#T extends core::Object* = dynamic, S extends self::GenericExtension|invocations::#T = dynamic>(final self::GenericClass<self::GenericExtension|invocations::#T*>* #this, self::GenericExtension|invocations::S value) → dynamic {
- self::GenericExtension|readGetter<self::GenericExtension|invocations::#T*>(#this);
- self::GenericExtension|writeSetterRequired<self::GenericExtension|invocations::#T*>(#this, value);
- self::GenericExtension|writeSetterOptional<self::GenericExtension|invocations::#T*>(#this);
- self::GenericExtension|writeSetterOptional<self::GenericExtension|invocations::#T*>(#this, value);
- self::GenericExtension|writeSetterNamed<self::GenericExtension|invocations::#T*>(#this);
- self::GenericExtension|writeSetterNamed<self::GenericExtension|invocations::#T*>(#this, value: value);
+static method GenericExtension|get#tearOffGetterNoArgs<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterNoArgs::T*>* #this) → dynamic
+ return self::GenericExtension|get#readGetter<self::GenericExtension|get#tearOffGetterNoArgs::T*>(#this);
+static method GenericExtension|get#tearOffGetterRequired<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterRequired::T*>* #this) → dynamic
+ return self::GenericExtension|get#writeSetterRequired<self::GenericExtension|get#tearOffGetterRequired::T*>(#this);
+static method GenericExtension|get#tearOffGetterOptional<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterOptional::T*>* #this) → dynamic
+ return self::GenericExtension|get#writeSetterOptional<self::GenericExtension|get#tearOffGetterOptional::T*>(#this);
+static method GenericExtension|get#tearOffGetterNamed<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterNamed::T*>* #this) → dynamic
+ return self::GenericExtension|get#writeSetterNamed<self::GenericExtension|get#tearOffGetterNamed::T*>(#this);
+static method GenericExtension|get#tearOffGetterGenericRequired<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericRequired::T*>* #this) → dynamic
+ return self::GenericExtension|get#genericWriteSetterRequired<self::GenericExtension|get#tearOffGetterGenericRequired::T*>(#this);
+static method GenericExtension|get#tearOffGetterGenericOptional<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericOptional::T*>* #this) → dynamic
+ return self::GenericExtension|get#genericWriteSetterOptional<self::GenericExtension|get#tearOffGetterGenericOptional::T*>(#this);
+static method GenericExtension|get#tearOffGetterGenericNamed<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericNamed::T*>* #this) → dynamic
+ return self::GenericExtension|get#genericWriteSetterNamed<self::GenericExtension|get#tearOffGetterGenericNamed::T*>(#this);
+static method GenericExtension|invocations<T extends core::Object* = dynamic, S extends self::GenericExtension|invocations::T* = dynamic>(final self::GenericClass<self::GenericExtension|invocations::T*>* #this, self::GenericExtension|invocations::S* value) → dynamic {
+ self::GenericExtension|readGetter<self::GenericExtension|invocations::T*>(#this);
+ self::GenericExtension|writeSetterRequired<self::GenericExtension|invocations::T*>(#this, value);
+ self::GenericExtension|writeSetterOptional<self::GenericExtension|invocations::T*>(#this);
+ self::GenericExtension|writeSetterOptional<self::GenericExtension|invocations::T*>(#this, value);
+ self::GenericExtension|writeSetterNamed<self::GenericExtension|invocations::T*>(#this);
+ self::GenericExtension|writeSetterNamed<self::GenericExtension|invocations::T*>(#this, value: value);
}
-static method GenericExtension|tearOffs<#T extends core::Object* = dynamic, S extends self::GenericExtension|tearOffs::#T = dynamic>(final self::GenericClass<self::GenericExtension|tearOffs::#T*>* #this, self::GenericExtension|tearOffs::S value) → dynamic {
- () →* self::GenericExtension|tearOffs::#T* tearOffNoArgs = () → self::GenericExtension|tearOffs::#T* => self::GenericExtension|readGetter<self::GenericExtension|tearOffs::#T*>(#this);
+static method GenericExtension|get#invocations<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#invocations::T*>* #this) → <S extends self::GenericExtension|get#invocations::T* = dynamic>(S*) →* dynamic
+ return <S extends self::GenericExtension|get#invocations::T* = dynamic>(S* value) → dynamic => self::GenericExtension|invocations<self::GenericExtension|get#invocations::T*, S*>(#this, value);
+static method GenericExtension|tearOffs<T extends core::Object* = dynamic, S extends self::GenericExtension|tearOffs::T* = dynamic>(final self::GenericClass<self::GenericExtension|tearOffs::T*>* #this, self::GenericExtension|tearOffs::S* value) → dynamic {
+ () →* self::GenericExtension|tearOffs::T* tearOffNoArgs = self::GenericExtension|get#readGetter<self::GenericExtension|tearOffs::T*>(#this);
tearOffNoArgs.call();
- (self::GenericExtension|tearOffs::#T*) →* dynamic tearOffRequired = (self::GenericExtension|tearOffs::#T* value) → dynamic => self::GenericExtension|writeSetterRequired<self::GenericExtension|tearOffs::#T*>(#this, value);
+ (self::GenericExtension|tearOffs::T*) →* dynamic tearOffRequired = self::GenericExtension|get#writeSetterRequired<self::GenericExtension|tearOffs::T*>(#this);
tearOffRequired.call(value);
- ([self::GenericExtension|tearOffs::#T*]) →* dynamic tearOffOptional = ([self::GenericExtension|tearOffs::#T* value = #C1]) → dynamic => self::GenericExtension|writeSetterOptional<self::GenericExtension|tearOffs::#T*>(#this, value);
+ ([self::GenericExtension|tearOffs::T*]) →* dynamic tearOffOptional = self::GenericExtension|get#writeSetterOptional<self::GenericExtension|tearOffs::T*>(#this);
tearOffOptional.call();
tearOffOptional.call(value);
- ({value: self::GenericExtension|tearOffs::#T*}) →* dynamic tearOffNamed = ({self::GenericExtension|tearOffs::#T* value = #C1}) → dynamic => self::GenericExtension|writeSetterNamed<self::GenericExtension|tearOffs::#T*>(#this, value: value);
+ ({value: self::GenericExtension|tearOffs::T*}) →* dynamic tearOffNamed = self::GenericExtension|get#writeSetterNamed<self::GenericExtension|tearOffs::T*>(#this);
tearOffNamed.call();
tearOffNamed.call(value: value);
- <S extends self::GenericExtension|tearOffs::#T* = dynamic>(S) →* dynamic genericTearOffRequired = <S extends self::GenericExtension|tearOffs::#T* = dynamic>(S value) → dynamic => self::GenericExtension|genericWriteSetterRequired<self::GenericExtension|tearOffs::#T*, S>(#this, value);
- genericTearOffRequired.call<self::GenericExtension|tearOffs::S>(value);
- genericTearOffRequired.call<self::GenericExtension|tearOffs::#T*>(value);
- genericTearOffRequired.call<self::GenericExtension|tearOffs::S>(value);
- <S extends self::GenericExtension|tearOffs::#T* = dynamic>([S]) →* dynamic genericTearOffOptional = <S extends self::GenericExtension|tearOffs::#T* = dynamic>([S value = #C1]) → dynamic => self::GenericExtension|genericWriteSetterOptional<self::GenericExtension|tearOffs::#T*, S>(#this, value);
- genericTearOffOptional.call<self::GenericExtension|tearOffs::#T*>();
- genericTearOffOptional.call<self::GenericExtension|tearOffs::#T*>();
- genericTearOffOptional.call<self::GenericExtension|tearOffs::S>();
- genericTearOffOptional.call<self::GenericExtension|tearOffs::S>(value);
- genericTearOffOptional.call<self::GenericExtension|tearOffs::#T*>(value);
- genericTearOffOptional.call<self::GenericExtension|tearOffs::S>(value);
- <S extends self::GenericExtension|tearOffs::#T* = dynamic>({value: S}) →* dynamic genericTearOffNamed = <S extends self::GenericExtension|tearOffs::#T* = dynamic>({S value = #C1}) → dynamic => self::GenericExtension|genericWriteSetterNamed<self::GenericExtension|tearOffs::#T*, S>(#this, value: value);
- genericTearOffNamed.call<self::GenericExtension|tearOffs::#T*>();
- genericTearOffNamed.call<self::GenericExtension|tearOffs::#T*>();
- genericTearOffNamed.call<self::GenericExtension|tearOffs::S>();
- genericTearOffNamed.call<self::GenericExtension|tearOffs::S>(value: value);
- genericTearOffNamed.call<self::GenericExtension|tearOffs::#T*>(value: value);
- genericTearOffNamed.call<self::GenericExtension|tearOffs::S>(value: value);
+ <S extends self::GenericExtension|tearOffs::T* = dynamic>(S*) →* dynamic genericTearOffRequired = self::GenericExtension|get#genericWriteSetterRequired<self::GenericExtension|tearOffs::T*>(#this);
+ genericTearOffRequired.call<self::GenericExtension|tearOffs::S*>(value);
+ genericTearOffRequired.call<self::GenericExtension|tearOffs::T*>(value);
+ genericTearOffRequired.call<self::GenericExtension|tearOffs::S*>(value);
+ <S extends self::GenericExtension|tearOffs::T* = dynamic>([S*]) →* dynamic genericTearOffOptional = self::GenericExtension|get#genericWriteSetterOptional<self::GenericExtension|tearOffs::T*>(#this);
+ genericTearOffOptional.call<self::GenericExtension|tearOffs::T*>();
+ genericTearOffOptional.call<self::GenericExtension|tearOffs::T*>();
+ genericTearOffOptional.call<self::GenericExtension|tearOffs::S*>();
+ genericTearOffOptional.call<self::GenericExtension|tearOffs::S*>(value);
+ genericTearOffOptional.call<self::GenericExtension|tearOffs::T*>(value);
+ genericTearOffOptional.call<self::GenericExtension|tearOffs::S*>(value);
+ <S extends self::GenericExtension|tearOffs::T* = dynamic>({value: S*}) →* dynamic genericTearOffNamed = self::GenericExtension|get#genericWriteSetterNamed<self::GenericExtension|tearOffs::T*>(#this);
+ genericTearOffNamed.call<self::GenericExtension|tearOffs::T*>();
+ genericTearOffNamed.call<self::GenericExtension|tearOffs::T*>();
+ genericTearOffNamed.call<self::GenericExtension|tearOffs::S*>();
+ genericTearOffNamed.call<self::GenericExtension|tearOffs::S*>(value: value);
+ genericTearOffNamed.call<self::GenericExtension|tearOffs::T*>(value: value);
+ genericTearOffNamed.call<self::GenericExtension|tearOffs::S*>(value: value);
}
-static method GenericExtension|getterCalls<#T extends core::Object* = dynamic, S extends self::GenericExtension|getterCalls::#T = dynamic>(final self::GenericClass<self::GenericExtension|getterCalls::#T*>* #this, self::GenericExtension|getterCalls::S value) → dynamic {
- self::GenericExtension|get#tearOffGetterNoArgs<self::GenericExtension|getterCalls::#T*>(#this).call();
- self::GenericExtension|get#tearOffGetterRequired<self::GenericExtension|getterCalls::#T*>(#this).call(value);
- self::GenericExtension|get#tearOffGetterOptional<self::GenericExtension|getterCalls::#T*>(#this).call();
- self::GenericExtension|get#tearOffGetterOptional<self::GenericExtension|getterCalls::#T*>(#this).call(value);
- self::GenericExtension|get#tearOffGetterNamed<self::GenericExtension|getterCalls::#T*>(#this).call();
- self::GenericExtension|get#tearOffGetterNamed<self::GenericExtension|getterCalls::#T*>(#this).call(value: value);
- self::GenericExtension|get#tearOffGetterGenericRequired<self::GenericExtension|getterCalls::#T*>(#this).call(value);
- self::GenericExtension|get#tearOffGetterGenericRequired<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::#T*>(value);
- self::GenericExtension|get#tearOffGetterGenericRequired<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::S>(value);
- self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::#T*>(#this).call();
- self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::#T*>();
- self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::S>();
- self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::#T*>(#this).call(value);
- self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::#T*>(value);
- self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::S>(value);
- self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::#T*>(#this).call();
- self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::#T*>();
- self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::S>();
- self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::#T*>(#this).call(value: value);
- self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::#T*>(value: value);
- self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::S>(value: value);
+static method GenericExtension|get#tearOffs<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffs::T*>* #this) → <S extends self::GenericExtension|get#tearOffs::T* = dynamic>(S*) →* dynamic
+ return <S extends self::GenericExtension|get#tearOffs::T* = dynamic>(S* value) → dynamic => self::GenericExtension|tearOffs<self::GenericExtension|get#tearOffs::T*, S*>(#this, value);
+static method GenericExtension|getterCalls<T extends core::Object* = dynamic, S extends self::GenericExtension|getterCalls::T* = dynamic>(final self::GenericClass<self::GenericExtension|getterCalls::T*>* #this, self::GenericExtension|getterCalls::S* value) → dynamic {
+ self::GenericExtension|get#tearOffGetterNoArgs<self::GenericExtension|getterCalls::T*>(#this).call();
+ self::GenericExtension|get#tearOffGetterRequired<self::GenericExtension|getterCalls::T*>(#this).call(value);
+ self::GenericExtension|get#tearOffGetterOptional<self::GenericExtension|getterCalls::T*>(#this).call();
+ self::GenericExtension|get#tearOffGetterOptional<self::GenericExtension|getterCalls::T*>(#this).call(value);
+ self::GenericExtension|get#tearOffGetterNamed<self::GenericExtension|getterCalls::T*>(#this).call();
+ self::GenericExtension|get#tearOffGetterNamed<self::GenericExtension|getterCalls::T*>(#this).call(value: value);
+ self::GenericExtension|get#tearOffGetterGenericRequired<self::GenericExtension|getterCalls::T*>(#this).call(value);
+ self::GenericExtension|get#tearOffGetterGenericRequired<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::T*>(value);
+ self::GenericExtension|get#tearOffGetterGenericRequired<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::S*>(value);
+ self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::T*>(#this).call();
+ self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::T*>();
+ self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::S*>();
+ self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::T*>(#this).call(value);
+ self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::T*>(value);
+ self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::S*>(value);
+ self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::T*>(#this).call();
+ self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::T*>();
+ self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::S*>();
+ self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::T*>(#this).call(value: value);
+ self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::T*>(value: value);
+ self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::S*>(value: value);
}
+static method GenericExtension|get#getterCalls<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#getterCalls::T*>* #this) → <S extends self::GenericExtension|get#getterCalls::T* = dynamic>(S*) →* dynamic
+ return <S extends self::GenericExtension|get#getterCalls::T* = dynamic>(S* value) → dynamic => self::GenericExtension|getterCalls<self::GenericExtension|get#getterCalls::T*, S*>(#this, value);
static method main() → dynamic {}
constants {
diff --git a/pkg/front_end/testcases/extensions/direct_instance_access.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/direct_instance_access.dart.strong.transformed.expect
index eff6825..a652a17 100644
--- a/pkg/front_end/testcases/extensions/direct_instance_access.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/extensions/direct_instance_access.dart.strong.transformed.expect
@@ -16,27 +16,41 @@
}
extension Extension on self::Class* {
method readGetter = self::Extension|readGetter;
+ tearoff readGetter = self::Extension|get#readGetter;
method writeSetterRequired = self::Extension|writeSetterRequired;
+ tearoff writeSetterRequired = self::Extension|get#writeSetterRequired;
method writeSetterOptional = self::Extension|writeSetterOptional;
+ tearoff writeSetterOptional = self::Extension|get#writeSetterOptional;
method writeSetterNamed = self::Extension|writeSetterNamed;
+ tearoff writeSetterNamed = self::Extension|get#writeSetterNamed;
get tearOffGetterNoArgs = self::Extension|get#tearOffGetterNoArgs;
get tearOffGetterRequired = self::Extension|get#tearOffGetterRequired;
get tearOffGetterOptional = self::Extension|get#tearOffGetterOptional;
get tearOffGetterNamed = self::Extension|get#tearOffGetterNamed;
get property = self::Extension|get#property;
method invocations = self::Extension|invocations;
+ tearoff invocations = self::Extension|get#invocations;
method tearOffs = self::Extension|tearOffs;
+ tearoff tearOffs = self::Extension|get#tearOffs;
method getterCalls = self::Extension|getterCalls;
+ tearoff getterCalls = self::Extension|get#getterCalls;
set property = self::Extension|set#property;
}
extension GenericExtension<T extends core::Object* = dynamic> on self::GenericClass<T*>* {
method readGetter = self::GenericExtension|readGetter;
+ tearoff readGetter = self::GenericExtension|get#readGetter;
method writeSetterRequired = self::GenericExtension|writeSetterRequired;
+ tearoff writeSetterRequired = self::GenericExtension|get#writeSetterRequired;
method writeSetterOptional = self::GenericExtension|writeSetterOptional;
+ tearoff writeSetterOptional = self::GenericExtension|get#writeSetterOptional;
method writeSetterNamed = self::GenericExtension|writeSetterNamed;
+ tearoff writeSetterNamed = self::GenericExtension|get#writeSetterNamed;
method genericWriteSetterRequired = self::GenericExtension|genericWriteSetterRequired;
+ tearoff genericWriteSetterRequired = self::GenericExtension|get#genericWriteSetterRequired;
method genericWriteSetterOptional = self::GenericExtension|genericWriteSetterOptional;
+ tearoff genericWriteSetterOptional = self::GenericExtension|get#genericWriteSetterOptional;
method genericWriteSetterNamed = self::GenericExtension|genericWriteSetterNamed;
+ tearoff genericWriteSetterNamed = self::GenericExtension|get#genericWriteSetterNamed;
get property = self::GenericExtension|get#property;
get tearOffGetterNoArgs = self::GenericExtension|get#tearOffGetterNoArgs;
get tearOffGetterRequired = self::GenericExtension|get#tearOffGetterRequired;
@@ -46,34 +60,47 @@
get tearOffGetterGenericOptional = self::GenericExtension|get#tearOffGetterGenericOptional;
get tearOffGetterGenericNamed = self::GenericExtension|get#tearOffGetterGenericNamed;
method invocations = self::GenericExtension|invocations;
+ tearoff invocations = self::GenericExtension|get#invocations;
method tearOffs = self::GenericExtension|tearOffs;
+ tearoff tearOffs = self::GenericExtension|get#tearOffs;
method getterCalls = self::GenericExtension|getterCalls;
+ tearoff getterCalls = self::GenericExtension|get#getterCalls;
set property = self::GenericExtension|set#property;
}
+static method Extension|get#readGetter(final self::Class* #this) → () →* dynamic
+ return () → dynamic => self::Extension|readGetter(#this);
static method Extension|readGetter(final self::Class* #this) → dynamic {
return self::Extension|get#property(#this);
}
static method Extension|writeSetterRequired(final self::Class* #this, dynamic value) → dynamic {
self::Extension|set#property(#this, value);
}
+static method Extension|get#writeSetterRequired(final self::Class* #this) → (dynamic) →* dynamic
+ return (dynamic value) → dynamic => self::Extension|writeSetterRequired(#this, value);
static method Extension|writeSetterOptional(final self::Class* #this = #C1, [dynamic value = #C1]) → dynamic {
self::Extension|set#property(#this, value);
}
+static method Extension|get#writeSetterOptional(final self::Class* #this) → ([dynamic]) →* dynamic
+ return ([dynamic value = #C1]) → dynamic => self::Extension|writeSetterOptional(#this, value);
static method Extension|writeSetterNamed(final self::Class* #this = #C1, {dynamic value = #C1}) → dynamic {
self::Extension|set#property(#this, value);
}
-static method Extension|get#tearOffGetterNoArgs(final self::Class* #this) → dynamic
- return () → dynamic => self::Extension|readGetter(#this);
-static method Extension|get#tearOffGetterRequired(final self::Class* #this) → dynamic
- return (dynamic value) → dynamic => self::Extension|writeSetterRequired(#this, value);
-static method Extension|get#tearOffGetterOptional(final self::Class* #this) → dynamic
- return ([dynamic value = #C1]) → dynamic => self::Extension|writeSetterOptional(#this, value);
-static method Extension|get#tearOffGetterNamed(final self::Class* #this) → dynamic
+static method Extension|get#writeSetterNamed(final self::Class* #this) → ({value: dynamic}) →* dynamic
return ({dynamic value = #C1}) → dynamic => self::Extension|writeSetterNamed(#this, value: value);
+static method Extension|get#tearOffGetterNoArgs(final self::Class* #this) → dynamic
+ return self::Extension|get#readGetter(#this);
+static method Extension|get#tearOffGetterRequired(final self::Class* #this) → dynamic
+ return self::Extension|get#writeSetterRequired(#this);
+static method Extension|get#tearOffGetterOptional(final self::Class* #this) → dynamic
+ return self::Extension|get#writeSetterOptional(#this);
+static method Extension|get#tearOffGetterNamed(final self::Class* #this) → dynamic
+ return self::Extension|get#writeSetterNamed(#this);
static method Extension|get#property(final self::Class* #this) → dynamic
return #this.{self::Class::field};
-static method Extension|set#property(final self::Class* #this, dynamic value) → void {
+static method Extension|set#property(final self::Class* #this, dynamic value) → dynamic {
+ final dynamic #t1 = value;
#this.{self::Class::field} = value;
+ return #t1;
}
static method Extension|invocations(final self::Class* #this, dynamic value) → dynamic {
self::Extension|readGetter(#this);
@@ -83,15 +110,19 @@
self::Extension|writeSetterNamed(#this);
self::Extension|writeSetterNamed(#this, value: value);
}
+static method Extension|get#invocations(final self::Class* #this) → (dynamic) →* dynamic
+ return (dynamic value) → dynamic => self::Extension|invocations(#this, value);
+static method Extension|get#tearOffs(final self::Class* #this) → (dynamic) →* dynamic
+ return (dynamic value) → dynamic => self::Extension|tearOffs(#this, value);
static method Extension|tearOffs(final self::Class* #this, dynamic value) → dynamic {
- () →* dynamic tearOffNoArgs = () → dynamic => self::Extension|readGetter(#this);
+ () →* dynamic tearOffNoArgs = self::Extension|get#readGetter(#this);
tearOffNoArgs.call();
- (dynamic) →* dynamic tearOffRequired = (dynamic value) → dynamic => self::Extension|writeSetterRequired(#this, value);
+ (dynamic) →* dynamic tearOffRequired = self::Extension|get#writeSetterRequired(#this);
tearOffRequired.call(value);
- ([dynamic]) →* dynamic tearOffOptional = ([dynamic value = #C1]) → dynamic => self::Extension|writeSetterOptional(#this, value);
+ ([dynamic]) →* dynamic tearOffOptional = self::Extension|get#writeSetterOptional(#this);
tearOffOptional.call();
tearOffOptional.call(value);
- ({value: dynamic}) →* dynamic tearOffNamed = ({dynamic value = #C1}) → dynamic => self::Extension|writeSetterNamed(#this, value: value);
+ ({value: dynamic}) →* dynamic tearOffNamed = self::Extension|get#writeSetterNamed(#this);
tearOffNamed.call();
tearOffNamed.call(value: value);
}
@@ -103,107 +134,131 @@
self::Extension|get#tearOffGetterNamed(#this).call();
self::Extension|get#tearOffGetterNamed(#this).call(value: value);
}
-static method GenericExtension|readGetter<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|readGetter::#T*>* #this) → self::GenericExtension|readGetter::#T* {
- return self::GenericExtension|get#property<self::GenericExtension|readGetter::#T*>(#this);
+static method Extension|get#getterCalls(final self::Class* #this) → (dynamic) →* dynamic
+ return (dynamic value) → dynamic => self::Extension|getterCalls(#this, value);
+static method GenericExtension|readGetter<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|readGetter::T*>* #this) → self::GenericExtension|readGetter::T* {
+ return self::GenericExtension|get#property<self::GenericExtension|readGetter::T*>(#this);
}
-static method GenericExtension|writeSetterRequired<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterRequired::#T*>* #this, self::GenericExtension|writeSetterRequired::#T* value) → dynamic {
- self::GenericExtension|set#property<self::GenericExtension|writeSetterRequired::#T*>(#this, value);
+static method GenericExtension|get#readGetter<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#readGetter::T*>* #this) → () →* self::GenericExtension|get#readGetter::T*
+ return () → self::GenericExtension|get#readGetter::T* => self::GenericExtension|readGetter<self::GenericExtension|get#readGetter::T*>(#this);
+static method GenericExtension|writeSetterRequired<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterRequired::T*>* #this, self::GenericExtension|writeSetterRequired::T* value) → dynamic {
+ self::GenericExtension|set#property<self::GenericExtension|writeSetterRequired::T*>(#this, value);
}
-static method GenericExtension|writeSetterOptional<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterOptional::#T*>* #this = #C1, [self::GenericExtension|writeSetterOptional::#T* value = #C1]) → dynamic {
- self::GenericExtension|set#property<self::GenericExtension|writeSetterOptional::#T*>(#this, value);
+static method GenericExtension|get#writeSetterRequired<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#writeSetterRequired::T*>* #this) → (self::GenericExtension|get#writeSetterRequired::T*) →* dynamic
+ return (self::GenericExtension|get#writeSetterRequired::T* value) → dynamic => self::GenericExtension|writeSetterRequired<self::GenericExtension|get#writeSetterRequired::T*>(#this, value);
+static method GenericExtension|writeSetterOptional<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterOptional::T*>* #this = #C1, [self::GenericExtension|writeSetterOptional::T* value = #C1]) → dynamic {
+ self::GenericExtension|set#property<self::GenericExtension|writeSetterOptional::T*>(#this, value);
}
-static method GenericExtension|writeSetterNamed<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterNamed::#T*>* #this = #C1, {self::GenericExtension|writeSetterNamed::#T* value = #C1}) → dynamic {
- self::GenericExtension|set#property<self::GenericExtension|writeSetterNamed::#T*>(#this, value);
+static method GenericExtension|get#writeSetterOptional<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#writeSetterOptional::T*>* #this) → ([self::GenericExtension|get#writeSetterOptional::T*]) →* dynamic
+ return ([self::GenericExtension|get#writeSetterOptional::T* value = #C1]) → dynamic => self::GenericExtension|writeSetterOptional<self::GenericExtension|get#writeSetterOptional::T*>(#this, value);
+static method GenericExtension|writeSetterNamed<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|writeSetterNamed::T*>* #this = #C1, {self::GenericExtension|writeSetterNamed::T* value = #C1}) → dynamic {
+ self::GenericExtension|set#property<self::GenericExtension|writeSetterNamed::T*>(#this, value);
}
-static method GenericExtension|genericWriteSetterRequired<#T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterRequired::#T = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterRequired::#T*>* #this, self::GenericExtension|genericWriteSetterRequired::S value) → dynamic {
- self::GenericExtension|set#property<self::GenericExtension|genericWriteSetterRequired::#T*>(#this, value);
+static method GenericExtension|get#writeSetterNamed<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#writeSetterNamed::T*>* #this) → ({value: self::GenericExtension|get#writeSetterNamed::T*}) →* dynamic
+ return ({self::GenericExtension|get#writeSetterNamed::T* value = #C1}) → dynamic => self::GenericExtension|writeSetterNamed<self::GenericExtension|get#writeSetterNamed::T*>(#this, value: value);
+static method GenericExtension|genericWriteSetterRequired<T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterRequired::T* = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterRequired::T*>* #this, self::GenericExtension|genericWriteSetterRequired::S* value) → dynamic {
+ self::GenericExtension|set#property<self::GenericExtension|genericWriteSetterRequired::T*>(#this, value);
}
-static method GenericExtension|genericWriteSetterOptional<#T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterOptional::#T = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterOptional::#T*>* #this = #C1, [self::GenericExtension|genericWriteSetterOptional::S value = #C1]) → dynamic {
- self::GenericExtension|set#property<self::GenericExtension|genericWriteSetterOptional::#T*>(#this, value);
+static method GenericExtension|get#genericWriteSetterRequired<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#genericWriteSetterRequired::T*>* #this) → <S extends self::GenericExtension|get#genericWriteSetterRequired::T* = dynamic>(S*) →* dynamic
+ return <S extends self::GenericExtension|get#genericWriteSetterRequired::T* = dynamic>(S* value) → dynamic => self::GenericExtension|genericWriteSetterRequired<self::GenericExtension|get#genericWriteSetterRequired::T*, S*>(#this, value);
+static method GenericExtension|genericWriteSetterOptional<T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterOptional::T* = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterOptional::T*>* #this = #C1, [self::GenericExtension|genericWriteSetterOptional::S* value = #C1]) → dynamic {
+ self::GenericExtension|set#property<self::GenericExtension|genericWriteSetterOptional::T*>(#this, value);
}
-static method GenericExtension|genericWriteSetterNamed<#T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterNamed::#T = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterNamed::#T*>* #this = #C1, {self::GenericExtension|genericWriteSetterNamed::S value = #C1}) → dynamic {
- self::GenericExtension|set#property<self::GenericExtension|genericWriteSetterNamed::#T*>(#this, value);
+static method GenericExtension|get#genericWriteSetterOptional<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#genericWriteSetterOptional::T*>* #this) → <S extends self::GenericExtension|get#genericWriteSetterOptional::T* = dynamic>([S*]) →* dynamic
+ return <S extends self::GenericExtension|get#genericWriteSetterOptional::T* = dynamic>([S* value = #C1]) → dynamic => self::GenericExtension|genericWriteSetterOptional<self::GenericExtension|get#genericWriteSetterOptional::T*, S*>(#this, value);
+static method GenericExtension|get#genericWriteSetterNamed<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#genericWriteSetterNamed::T*>* #this) → <S extends self::GenericExtension|get#genericWriteSetterNamed::T* = dynamic>({value: S*}) →* dynamic
+ return <S extends self::GenericExtension|get#genericWriteSetterNamed::T* = dynamic>({S* value = #C1}) → dynamic => self::GenericExtension|genericWriteSetterNamed<self::GenericExtension|get#genericWriteSetterNamed::T*, S*>(#this, value: value);
+static method GenericExtension|genericWriteSetterNamed<T extends core::Object* = dynamic, S extends self::GenericExtension|genericWriteSetterNamed::T* = dynamic>(final self::GenericClass<self::GenericExtension|genericWriteSetterNamed::T*>* #this = #C1, {self::GenericExtension|genericWriteSetterNamed::S* value = #C1}) → dynamic {
+ self::GenericExtension|set#property<self::GenericExtension|genericWriteSetterNamed::T*>(#this, value);
}
-static method GenericExtension|get#property<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#property::#T*>* #this) → self::GenericExtension|get#property::#T*
+static method GenericExtension|get#property<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#property::T*>* #this) → self::GenericExtension|get#property::T*
return #this.{self::GenericClass::field};
-static method GenericExtension|set#property<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|set#property::#T*>* #this, self::GenericExtension|set#property::#T* value) → void {
+static method GenericExtension|set#property<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|set#property::T*>* #this, self::GenericExtension|set#property::T* value) → self::GenericExtension|set#property::T* {
+ final self::GenericExtension|set#property::T* #t2 = value;
#this.{self::GenericClass::field} = value;
+ return #t2;
}
-static method GenericExtension|get#tearOffGetterNoArgs<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterNoArgs::#T*>* #this) → dynamic
- return () → self::GenericExtension|get#tearOffGetterNoArgs::#T* => self::GenericExtension|readGetter<self::GenericExtension|get#tearOffGetterNoArgs::#T*>(#this);
-static method GenericExtension|get#tearOffGetterRequired<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterRequired::#T*>* #this) → dynamic
- return (self::GenericExtension|get#tearOffGetterRequired::#T* value) → dynamic => self::GenericExtension|writeSetterRequired<self::GenericExtension|get#tearOffGetterRequired::#T*>(#this, value);
-static method GenericExtension|get#tearOffGetterOptional<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterOptional::#T*>* #this) → dynamic
- return ([self::GenericExtension|get#tearOffGetterOptional::#T* value = #C1]) → dynamic => self::GenericExtension|writeSetterOptional<self::GenericExtension|get#tearOffGetterOptional::#T*>(#this, value);
-static method GenericExtension|get#tearOffGetterNamed<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterNamed::#T*>* #this) → dynamic
- return ({self::GenericExtension|get#tearOffGetterNamed::#T* value = #C1}) → dynamic => self::GenericExtension|writeSetterNamed<self::GenericExtension|get#tearOffGetterNamed::#T*>(#this, value: value);
-static method GenericExtension|get#tearOffGetterGenericRequired<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericRequired::#T*>* #this) → dynamic
- return <S extends self::GenericExtension|get#tearOffGetterGenericRequired::#T* = dynamic>(S value) → dynamic => self::GenericExtension|genericWriteSetterRequired<self::GenericExtension|get#tearOffGetterGenericRequired::#T*, S>(#this, value);
-static method GenericExtension|get#tearOffGetterGenericOptional<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericOptional::#T*>* #this) → dynamic
- return <S extends self::GenericExtension|get#tearOffGetterGenericOptional::#T* = dynamic>([S value = #C1]) → dynamic => self::GenericExtension|genericWriteSetterOptional<self::GenericExtension|get#tearOffGetterGenericOptional::#T*, S>(#this, value);
-static method GenericExtension|get#tearOffGetterGenericNamed<#T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericNamed::#T*>* #this) → dynamic
- return <S extends self::GenericExtension|get#tearOffGetterGenericNamed::#T* = dynamic>({S value = #C1}) → dynamic => self::GenericExtension|genericWriteSetterNamed<self::GenericExtension|get#tearOffGetterGenericNamed::#T*, S>(#this, value: value);
-static method GenericExtension|invocations<#T extends core::Object* = dynamic, S extends self::GenericExtension|invocations::#T = dynamic>(final self::GenericClass<self::GenericExtension|invocations::#T*>* #this, self::GenericExtension|invocations::S value) → dynamic {
- self::GenericExtension|readGetter<self::GenericExtension|invocations::#T*>(#this);
- self::GenericExtension|writeSetterRequired<self::GenericExtension|invocations::#T*>(#this, value);
- self::GenericExtension|writeSetterOptional<self::GenericExtension|invocations::#T*>(#this);
- self::GenericExtension|writeSetterOptional<self::GenericExtension|invocations::#T*>(#this, value);
- self::GenericExtension|writeSetterNamed<self::GenericExtension|invocations::#T*>(#this);
- self::GenericExtension|writeSetterNamed<self::GenericExtension|invocations::#T*>(#this, value: value);
+static method GenericExtension|get#tearOffGetterNoArgs<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterNoArgs::T*>* #this) → dynamic
+ return self::GenericExtension|get#readGetter<self::GenericExtension|get#tearOffGetterNoArgs::T*>(#this);
+static method GenericExtension|get#tearOffGetterRequired<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterRequired::T*>* #this) → dynamic
+ return self::GenericExtension|get#writeSetterRequired<self::GenericExtension|get#tearOffGetterRequired::T*>(#this);
+static method GenericExtension|get#tearOffGetterOptional<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterOptional::T*>* #this) → dynamic
+ return self::GenericExtension|get#writeSetterOptional<self::GenericExtension|get#tearOffGetterOptional::T*>(#this);
+static method GenericExtension|get#tearOffGetterNamed<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterNamed::T*>* #this) → dynamic
+ return self::GenericExtension|get#writeSetterNamed<self::GenericExtension|get#tearOffGetterNamed::T*>(#this);
+static method GenericExtension|get#tearOffGetterGenericRequired<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericRequired::T*>* #this) → dynamic
+ return self::GenericExtension|get#genericWriteSetterRequired<self::GenericExtension|get#tearOffGetterGenericRequired::T*>(#this);
+static method GenericExtension|get#tearOffGetterGenericOptional<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericOptional::T*>* #this) → dynamic
+ return self::GenericExtension|get#genericWriteSetterOptional<self::GenericExtension|get#tearOffGetterGenericOptional::T*>(#this);
+static method GenericExtension|get#tearOffGetterGenericNamed<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffGetterGenericNamed::T*>* #this) → dynamic
+ return self::GenericExtension|get#genericWriteSetterNamed<self::GenericExtension|get#tearOffGetterGenericNamed::T*>(#this);
+static method GenericExtension|invocations<T extends core::Object* = dynamic, S extends self::GenericExtension|invocations::T* = dynamic>(final self::GenericClass<self::GenericExtension|invocations::T*>* #this, self::GenericExtension|invocations::S* value) → dynamic {
+ self::GenericExtension|readGetter<self::GenericExtension|invocations::T*>(#this);
+ self::GenericExtension|writeSetterRequired<self::GenericExtension|invocations::T*>(#this, value);
+ self::GenericExtension|writeSetterOptional<self::GenericExtension|invocations::T*>(#this);
+ self::GenericExtension|writeSetterOptional<self::GenericExtension|invocations::T*>(#this, value);
+ self::GenericExtension|writeSetterNamed<self::GenericExtension|invocations::T*>(#this);
+ self::GenericExtension|writeSetterNamed<self::GenericExtension|invocations::T*>(#this, value: value);
}
-static method GenericExtension|tearOffs<#T extends core::Object* = dynamic, S extends self::GenericExtension|tearOffs::#T = dynamic>(final self::GenericClass<self::GenericExtension|tearOffs::#T*>* #this, self::GenericExtension|tearOffs::S value) → dynamic {
- () →* self::GenericExtension|tearOffs::#T* tearOffNoArgs = () → self::GenericExtension|tearOffs::#T* => self::GenericExtension|readGetter<self::GenericExtension|tearOffs::#T*>(#this);
+static method GenericExtension|get#invocations<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#invocations::T*>* #this) → <S extends self::GenericExtension|get#invocations::T* = dynamic>(S*) →* dynamic
+ return <S extends self::GenericExtension|get#invocations::T* = dynamic>(S* value) → dynamic => self::GenericExtension|invocations<self::GenericExtension|get#invocations::T*, S*>(#this, value);
+static method GenericExtension|tearOffs<T extends core::Object* = dynamic, S extends self::GenericExtension|tearOffs::T* = dynamic>(final self::GenericClass<self::GenericExtension|tearOffs::T*>* #this, self::GenericExtension|tearOffs::S* value) → dynamic {
+ () →* self::GenericExtension|tearOffs::T* tearOffNoArgs = self::GenericExtension|get#readGetter<self::GenericExtension|tearOffs::T*>(#this);
tearOffNoArgs.call();
- (self::GenericExtension|tearOffs::#T*) →* dynamic tearOffRequired = (self::GenericExtension|tearOffs::#T* value) → dynamic => self::GenericExtension|writeSetterRequired<self::GenericExtension|tearOffs::#T*>(#this, value);
+ (self::GenericExtension|tearOffs::T*) →* dynamic tearOffRequired = self::GenericExtension|get#writeSetterRequired<self::GenericExtension|tearOffs::T*>(#this);
tearOffRequired.call(value);
- ([self::GenericExtension|tearOffs::#T*]) →* dynamic tearOffOptional = ([self::GenericExtension|tearOffs::#T* value = #C1]) → dynamic => self::GenericExtension|writeSetterOptional<self::GenericExtension|tearOffs::#T*>(#this, value);
+ ([self::GenericExtension|tearOffs::T*]) →* dynamic tearOffOptional = self::GenericExtension|get#writeSetterOptional<self::GenericExtension|tearOffs::T*>(#this);
tearOffOptional.call();
tearOffOptional.call(value);
- ({value: self::GenericExtension|tearOffs::#T*}) →* dynamic tearOffNamed = ({self::GenericExtension|tearOffs::#T* value = #C1}) → dynamic => self::GenericExtension|writeSetterNamed<self::GenericExtension|tearOffs::#T*>(#this, value: value);
+ ({value: self::GenericExtension|tearOffs::T*}) →* dynamic tearOffNamed = self::GenericExtension|get#writeSetterNamed<self::GenericExtension|tearOffs::T*>(#this);
tearOffNamed.call();
tearOffNamed.call(value: value);
- <S extends self::GenericExtension|tearOffs::#T* = dynamic>(S) →* dynamic genericTearOffRequired = <S extends self::GenericExtension|tearOffs::#T* = dynamic>(S value) → dynamic => self::GenericExtension|genericWriteSetterRequired<self::GenericExtension|tearOffs::#T*, S>(#this, value);
- genericTearOffRequired.call<self::GenericExtension|tearOffs::S>(value);
- genericTearOffRequired.call<self::GenericExtension|tearOffs::#T*>(value);
- genericTearOffRequired.call<self::GenericExtension|tearOffs::S>(value);
- <S extends self::GenericExtension|tearOffs::#T* = dynamic>([S]) →* dynamic genericTearOffOptional = <S extends self::GenericExtension|tearOffs::#T* = dynamic>([S value = #C1]) → dynamic => self::GenericExtension|genericWriteSetterOptional<self::GenericExtension|tearOffs::#T*, S>(#this, value);
- genericTearOffOptional.call<self::GenericExtension|tearOffs::#T*>();
- genericTearOffOptional.call<self::GenericExtension|tearOffs::#T*>();
- genericTearOffOptional.call<self::GenericExtension|tearOffs::S>();
- genericTearOffOptional.call<self::GenericExtension|tearOffs::S>(value);
- genericTearOffOptional.call<self::GenericExtension|tearOffs::#T*>(value);
- genericTearOffOptional.call<self::GenericExtension|tearOffs::S>(value);
- <S extends self::GenericExtension|tearOffs::#T* = dynamic>({value: S}) →* dynamic genericTearOffNamed = <S extends self::GenericExtension|tearOffs::#T* = dynamic>({S value = #C1}) → dynamic => self::GenericExtension|genericWriteSetterNamed<self::GenericExtension|tearOffs::#T*, S>(#this, value: value);
- genericTearOffNamed.call<self::GenericExtension|tearOffs::#T*>();
- genericTearOffNamed.call<self::GenericExtension|tearOffs::#T*>();
- genericTearOffNamed.call<self::GenericExtension|tearOffs::S>();
- genericTearOffNamed.call<self::GenericExtension|tearOffs::S>(value: value);
- genericTearOffNamed.call<self::GenericExtension|tearOffs::#T*>(value: value);
- genericTearOffNamed.call<self::GenericExtension|tearOffs::S>(value: value);
+ <S extends self::GenericExtension|tearOffs::T* = dynamic>(S*) →* dynamic genericTearOffRequired = self::GenericExtension|get#genericWriteSetterRequired<self::GenericExtension|tearOffs::T*>(#this);
+ genericTearOffRequired.call<self::GenericExtension|tearOffs::S*>(value);
+ genericTearOffRequired.call<self::GenericExtension|tearOffs::T*>(value);
+ genericTearOffRequired.call<self::GenericExtension|tearOffs::S*>(value);
+ <S extends self::GenericExtension|tearOffs::T* = dynamic>([S*]) →* dynamic genericTearOffOptional = self::GenericExtension|get#genericWriteSetterOptional<self::GenericExtension|tearOffs::T*>(#this);
+ genericTearOffOptional.call<self::GenericExtension|tearOffs::T*>();
+ genericTearOffOptional.call<self::GenericExtension|tearOffs::T*>();
+ genericTearOffOptional.call<self::GenericExtension|tearOffs::S*>();
+ genericTearOffOptional.call<self::GenericExtension|tearOffs::S*>(value);
+ genericTearOffOptional.call<self::GenericExtension|tearOffs::T*>(value);
+ genericTearOffOptional.call<self::GenericExtension|tearOffs::S*>(value);
+ <S extends self::GenericExtension|tearOffs::T* = dynamic>({value: S*}) →* dynamic genericTearOffNamed = self::GenericExtension|get#genericWriteSetterNamed<self::GenericExtension|tearOffs::T*>(#this);
+ genericTearOffNamed.call<self::GenericExtension|tearOffs::T*>();
+ genericTearOffNamed.call<self::GenericExtension|tearOffs::T*>();
+ genericTearOffNamed.call<self::GenericExtension|tearOffs::S*>();
+ genericTearOffNamed.call<self::GenericExtension|tearOffs::S*>(value: value);
+ genericTearOffNamed.call<self::GenericExtension|tearOffs::T*>(value: value);
+ genericTearOffNamed.call<self::GenericExtension|tearOffs::S*>(value: value);
}
-static method GenericExtension|getterCalls<#T extends core::Object* = dynamic, S extends self::GenericExtension|getterCalls::#T = dynamic>(final self::GenericClass<self::GenericExtension|getterCalls::#T*>* #this, self::GenericExtension|getterCalls::S value) → dynamic {
- self::GenericExtension|get#tearOffGetterNoArgs<self::GenericExtension|getterCalls::#T*>(#this).call();
- self::GenericExtension|get#tearOffGetterRequired<self::GenericExtension|getterCalls::#T*>(#this).call(value);
- self::GenericExtension|get#tearOffGetterOptional<self::GenericExtension|getterCalls::#T*>(#this).call();
- self::GenericExtension|get#tearOffGetterOptional<self::GenericExtension|getterCalls::#T*>(#this).call(value);
- self::GenericExtension|get#tearOffGetterNamed<self::GenericExtension|getterCalls::#T*>(#this).call();
- self::GenericExtension|get#tearOffGetterNamed<self::GenericExtension|getterCalls::#T*>(#this).call(value: value);
- self::GenericExtension|get#tearOffGetterGenericRequired<self::GenericExtension|getterCalls::#T*>(#this).call(value);
- self::GenericExtension|get#tearOffGetterGenericRequired<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::#T*>(value);
- self::GenericExtension|get#tearOffGetterGenericRequired<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::S>(value);
- self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::#T*>(#this).call();
- self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::#T*>();
- self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::S>();
- self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::#T*>(#this).call(value);
- self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::#T*>(value);
- self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::S>(value);
- self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::#T*>(#this).call();
- self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::#T*>();
- self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::S>();
- self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::#T*>(#this).call(value: value);
- self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::#T*>(value: value);
- self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::#T*>(#this).call<self::GenericExtension|getterCalls::S>(value: value);
+static method GenericExtension|get#tearOffs<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#tearOffs::T*>* #this) → <S extends self::GenericExtension|get#tearOffs::T* = dynamic>(S*) →* dynamic
+ return <S extends self::GenericExtension|get#tearOffs::T* = dynamic>(S* value) → dynamic => self::GenericExtension|tearOffs<self::GenericExtension|get#tearOffs::T*, S*>(#this, value);
+static method GenericExtension|getterCalls<T extends core::Object* = dynamic, S extends self::GenericExtension|getterCalls::T* = dynamic>(final self::GenericClass<self::GenericExtension|getterCalls::T*>* #this, self::GenericExtension|getterCalls::S* value) → dynamic {
+ self::GenericExtension|get#tearOffGetterNoArgs<self::GenericExtension|getterCalls::T*>(#this).call();
+ self::GenericExtension|get#tearOffGetterRequired<self::GenericExtension|getterCalls::T*>(#this).call(value);
+ self::GenericExtension|get#tearOffGetterOptional<self::GenericExtension|getterCalls::T*>(#this).call();
+ self::GenericExtension|get#tearOffGetterOptional<self::GenericExtension|getterCalls::T*>(#this).call(value);
+ self::GenericExtension|get#tearOffGetterNamed<self::GenericExtension|getterCalls::T*>(#this).call();
+ self::GenericExtension|get#tearOffGetterNamed<self::GenericExtension|getterCalls::T*>(#this).call(value: value);
+ self::GenericExtension|get#tearOffGetterGenericRequired<self::GenericExtension|getterCalls::T*>(#this).call(value);
+ self::GenericExtension|get#tearOffGetterGenericRequired<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::T*>(value);
+ self::GenericExtension|get#tearOffGetterGenericRequired<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::S*>(value);
+ self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::T*>(#this).call();
+ self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::T*>();
+ self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::S*>();
+ self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::T*>(#this).call(value);
+ self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::T*>(value);
+ self::GenericExtension|get#tearOffGetterGenericOptional<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::S*>(value);
+ self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::T*>(#this).call();
+ self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::T*>();
+ self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::S*>();
+ self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::T*>(#this).call(value: value);
+ self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::T*>(value: value);
+ self::GenericExtension|get#tearOffGetterGenericNamed<self::GenericExtension|getterCalls::T*>(#this).call<self::GenericExtension|getterCalls::S*>(value: value);
}
+static method GenericExtension|get#getterCalls<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#getterCalls::T*>* #this) → <S extends self::GenericExtension|get#getterCalls::T* = dynamic>(S*) →* dynamic
+ return <S extends self::GenericExtension|get#getterCalls::T* = dynamic>(S* value) → dynamic => self::GenericExtension|getterCalls<self::GenericExtension|get#getterCalls::T*, S*>(#this, value);
static method main() → dynamic {}
constants {
diff --git a/pkg/front_end/testcases/extensions/direct_static_access.dart.outline.expect b/pkg/front_end/testcases/extensions/direct_static_access.dart.outline.expect
index 5a1e9ab..f704ade 100644
--- a/pkg/front_end/testcases/extensions/direct_static_access.dart.outline.expect
+++ b/pkg/front_end/testcases/extensions/direct_static_access.dart.outline.expect
@@ -29,9 +29,13 @@
static method fieldAccessFromStaticContext = self::Extension|fieldAccessFromStaticContext;
static method getterCallsFromStaticContext = self::Extension|getterCallsFromStaticContext;
method invocationsFromInstanceContext = self::Extension|invocationsFromInstanceContext;
+ tearoff invocationsFromInstanceContext = self::Extension|get#invocationsFromInstanceContext;
method tearOffsFromInstanceContext = self::Extension|tearOffsFromInstanceContext;
+ tearoff tearOffsFromInstanceContext = self::Extension|get#tearOffsFromInstanceContext;
method fieldAccessFromInstanceContext = self::Extension|fieldAccessFromInstanceContext;
+ tearoff fieldAccessFromInstanceContext = self::Extension|get#fieldAccessFromInstanceContext;
method getterCallsFromInstanceContext = self::Extension|getterCallsFromInstanceContext;
+ tearoff getterCallsFromInstanceContext = self::Extension|get#getterCallsFromInstanceContext;
static set property = set self::Extension|property;
}
static field dynamic Extension|field;
@@ -75,13 +79,21 @@
;
static method Extension|getterCallsFromStaticContext(core::int* value) → dynamic
;
-static method Extension|invocationsFromInstanceContext<#T extends core::Object* = dynamic>(final self::Class<self::Extension|invocationsFromInstanceContext::#T*>* #this, self::Extension|invocationsFromInstanceContext::#T* value) → dynamic
+static method Extension|invocationsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|invocationsFromInstanceContext::T*>* #this, self::Extension|invocationsFromInstanceContext::T* value) → dynamic
;
-static method Extension|tearOffsFromInstanceContext<#T extends core::Object* = dynamic>(final self::Class<self::Extension|tearOffsFromInstanceContext::#T*>* #this, self::Extension|tearOffsFromInstanceContext::#T* value) → dynamic
+static method Extension|get#invocationsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|get#invocationsFromInstanceContext::T*>* #this) → (self::Extension|get#invocationsFromInstanceContext::T*) →* dynamic
+ return (self::Extension|get#invocationsFromInstanceContext::T* value) → dynamic => self::Extension|invocationsFromInstanceContext<self::Extension|get#invocationsFromInstanceContext::T*>(#this, value);
+static method Extension|tearOffsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|tearOffsFromInstanceContext::T*>* #this, self::Extension|tearOffsFromInstanceContext::T* value) → dynamic
;
-static method Extension|fieldAccessFromInstanceContext<#T extends core::Object* = dynamic>(final self::Class<self::Extension|fieldAccessFromInstanceContext::#T*>* #this) → dynamic
+static method Extension|get#tearOffsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|get#tearOffsFromInstanceContext::T*>* #this) → (self::Extension|get#tearOffsFromInstanceContext::T*) →* dynamic
+ return (self::Extension|get#tearOffsFromInstanceContext::T* value) → dynamic => self::Extension|tearOffsFromInstanceContext<self::Extension|get#tearOffsFromInstanceContext::T*>(#this, value);
+static method Extension|fieldAccessFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|fieldAccessFromInstanceContext::T*>* #this) → dynamic
;
-static method Extension|getterCallsFromInstanceContext<#T extends core::Object* = dynamic>(final self::Class<self::Extension|getterCallsFromInstanceContext::#T*>* #this, self::Extension|getterCallsFromInstanceContext::#T* value) → dynamic
+static method Extension|get#fieldAccessFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|get#fieldAccessFromInstanceContext::T*>* #this) → () →* dynamic
+ return () → dynamic => self::Extension|fieldAccessFromInstanceContext<self::Extension|get#fieldAccessFromInstanceContext::T*>(#this);
+static method Extension|getterCallsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|getterCallsFromInstanceContext::T*>* #this, self::Extension|getterCallsFromInstanceContext::T* value) → dynamic
;
+static method Extension|get#getterCallsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|get#getterCallsFromInstanceContext::T*>* #this) → (self::Extension|get#getterCallsFromInstanceContext::T*) →* dynamic
+ return (self::Extension|get#getterCallsFromInstanceContext::T* value) → dynamic => self::Extension|getterCallsFromInstanceContext<self::Extension|get#getterCallsFromInstanceContext::T*>(#this, value);
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/extensions/direct_static_access.dart.strong.expect b/pkg/front_end/testcases/extensions/direct_static_access.dart.strong.expect
index 1d70dc7..a7051b9 100644
--- a/pkg/front_end/testcases/extensions/direct_static_access.dart.strong.expect
+++ b/pkg/front_end/testcases/extensions/direct_static_access.dart.strong.expect
@@ -30,9 +30,13 @@
static method fieldAccessFromStaticContext = self::Extension|fieldAccessFromStaticContext;
static method getterCallsFromStaticContext = self::Extension|getterCallsFromStaticContext;
method invocationsFromInstanceContext = self::Extension|invocationsFromInstanceContext;
+ tearoff invocationsFromInstanceContext = self::Extension|get#invocationsFromInstanceContext;
method tearOffsFromInstanceContext = self::Extension|tearOffsFromInstanceContext;
+ tearoff tearOffsFromInstanceContext = self::Extension|get#tearOffsFromInstanceContext;
method fieldAccessFromInstanceContext = self::Extension|fieldAccessFromInstanceContext;
+ tearoff fieldAccessFromInstanceContext = self::Extension|get#fieldAccessFromInstanceContext;
method getterCallsFromInstanceContext = self::Extension|getterCallsFromInstanceContext;
+ tearoff getterCallsFromInstanceContext = self::Extension|get#getterCallsFromInstanceContext;
static set property = set self::Extension|property;
}
static field dynamic Extension|field;
@@ -141,25 +145,27 @@
self::Extension|tearOffGetterGenericNamed.call(value: value);
self::Extension|tearOffGetterGenericNamed.call<core::int*>(value: value);
}
-static method Extension|invocationsFromInstanceContext<#T extends core::Object* = dynamic>(final self::Class<self::Extension|invocationsFromInstanceContext::#T*>* #this, self::Extension|invocationsFromInstanceContext::#T* value) → dynamic {
+static method Extension|invocationsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|invocationsFromInstanceContext::T*>* #this, self::Extension|invocationsFromInstanceContext::T* value) → dynamic {
self::Extension|readGetter();
self::Extension|writeSetterRequired(value);
self::Extension|writeSetterOptional();
self::Extension|writeSetterOptional(value);
self::Extension|writeSetterNamed();
self::Extension|writeSetterNamed(value: value);
- self::Extension|genericWriteSetterRequired<self::Extension|invocationsFromInstanceContext::#T*>(value);
- self::Extension|genericWriteSetterRequired<self::Extension|invocationsFromInstanceContext::#T*>(value);
+ self::Extension|genericWriteSetterRequired<self::Extension|invocationsFromInstanceContext::T*>(value);
+ self::Extension|genericWriteSetterRequired<self::Extension|invocationsFromInstanceContext::T*>(value);
self::Extension|genericWriteSetterOptional<dynamic>();
- self::Extension|genericWriteSetterOptional<self::Extension|invocationsFromInstanceContext::#T*>();
- self::Extension|genericWriteSetterOptional<self::Extension|invocationsFromInstanceContext::#T*>(value);
- self::Extension|genericWriteSetterOptional<self::Extension|invocationsFromInstanceContext::#T*>(value);
+ self::Extension|genericWriteSetterOptional<self::Extension|invocationsFromInstanceContext::T*>();
+ self::Extension|genericWriteSetterOptional<self::Extension|invocationsFromInstanceContext::T*>(value);
+ self::Extension|genericWriteSetterOptional<self::Extension|invocationsFromInstanceContext::T*>(value);
self::Extension|genericWriteSetterNamed<dynamic>();
- self::Extension|genericWriteSetterNamed<self::Extension|invocationsFromInstanceContext::#T*>();
- self::Extension|genericWriteSetterNamed<self::Extension|invocationsFromInstanceContext::#T*>(value: value);
- self::Extension|genericWriteSetterNamed<self::Extension|invocationsFromInstanceContext::#T*>(value: value);
+ self::Extension|genericWriteSetterNamed<self::Extension|invocationsFromInstanceContext::T*>();
+ self::Extension|genericWriteSetterNamed<self::Extension|invocationsFromInstanceContext::T*>(value: value);
+ self::Extension|genericWriteSetterNamed<self::Extension|invocationsFromInstanceContext::T*>(value: value);
}
-static method Extension|tearOffsFromInstanceContext<#T extends core::Object* = dynamic>(final self::Class<self::Extension|tearOffsFromInstanceContext::#T*>* #this, self::Extension|tearOffsFromInstanceContext::#T* value) → dynamic {
+static method Extension|get#invocationsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|get#invocationsFromInstanceContext::T*>* #this) → (self::Extension|get#invocationsFromInstanceContext::T*) →* dynamic
+ return (self::Extension|get#invocationsFromInstanceContext::T* value) → dynamic => self::Extension|invocationsFromInstanceContext<self::Extension|get#invocationsFromInstanceContext::T*>(#this, value);
+static method Extension|tearOffsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|tearOffsFromInstanceContext::T*>* #this, self::Extension|tearOffsFromInstanceContext::T* value) → dynamic {
() →* dynamic tearOffNoArgs = #C2;
tearOffNoArgs.call();
(dynamic) →* dynamic tearOffRequired = #C3;
@@ -171,24 +177,28 @@
tearOffNamed.call();
tearOffNamed.call(value: value);
<S extends core::Object* = dynamic>(self::Extension|genericWriteSetterRequired::S*) →* dynamic tearOffGenericRequired = #C6;
- tearOffGenericRequired.call<self::Extension|tearOffsFromInstanceContext::#T*>(value);
- tearOffGenericRequired.call<self::Extension|tearOffsFromInstanceContext::#T*>(value);
+ tearOffGenericRequired.call<self::Extension|tearOffsFromInstanceContext::T*>(value);
+ tearOffGenericRequired.call<self::Extension|tearOffsFromInstanceContext::T*>(value);
<S extends core::Object* = dynamic>([self::Extension|genericWriteSetterOptional::S*]) →* dynamic tearOffGenericOptional = #C7;
tearOffGenericOptional.call<dynamic>();
- tearOffGenericOptional.call<self::Extension|tearOffsFromInstanceContext::#T*>();
- tearOffGenericOptional.call<self::Extension|tearOffsFromInstanceContext::#T*>(value);
- tearOffGenericOptional.call<self::Extension|tearOffsFromInstanceContext::#T*>(value);
+ tearOffGenericOptional.call<self::Extension|tearOffsFromInstanceContext::T*>();
+ tearOffGenericOptional.call<self::Extension|tearOffsFromInstanceContext::T*>(value);
+ tearOffGenericOptional.call<self::Extension|tearOffsFromInstanceContext::T*>(value);
<S extends core::Object* = dynamic>({value: self::Extension|genericWriteSetterNamed::S*}) →* dynamic tearOffGenericNamed = #C8;
tearOffGenericNamed.call<dynamic>();
- tearOffGenericNamed.call<self::Extension|tearOffsFromInstanceContext::#T*>();
- tearOffGenericNamed.call<self::Extension|tearOffsFromInstanceContext::#T*>(value: value);
- tearOffGenericNamed.call<self::Extension|tearOffsFromInstanceContext::#T*>(value: value);
+ tearOffGenericNamed.call<self::Extension|tearOffsFromInstanceContext::T*>();
+ tearOffGenericNamed.call<self::Extension|tearOffsFromInstanceContext::T*>(value: value);
+ tearOffGenericNamed.call<self::Extension|tearOffsFromInstanceContext::T*>(value: value);
}
-static method Extension|fieldAccessFromInstanceContext<#T extends core::Object* = dynamic>(final self::Class<self::Extension|fieldAccessFromInstanceContext::#T*>* #this) → dynamic {
+static method Extension|get#tearOffsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|get#tearOffsFromInstanceContext::T*>* #this) → (self::Extension|get#tearOffsFromInstanceContext::T*) →* dynamic
+ return (self::Extension|get#tearOffsFromInstanceContext::T* value) → dynamic => self::Extension|tearOffsFromInstanceContext<self::Extension|get#tearOffsFromInstanceContext::T*>(#this, value);
+static method Extension|fieldAccessFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|fieldAccessFromInstanceContext::T*>* #this) → dynamic {
self::Extension|field = self::Extension|property;
self::Extension|property = self::Extension|field;
}
-static method Extension|getterCallsFromInstanceContext<#T extends core::Object* = dynamic>(final self::Class<self::Extension|getterCallsFromInstanceContext::#T*>* #this, self::Extension|getterCallsFromInstanceContext::#T* value) → dynamic {
+static method Extension|get#fieldAccessFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|get#fieldAccessFromInstanceContext::T*>* #this) → () →* dynamic
+ return () → dynamic => self::Extension|fieldAccessFromInstanceContext<self::Extension|get#fieldAccessFromInstanceContext::T*>(#this);
+static method Extension|getterCallsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|getterCallsFromInstanceContext::T*>* #this, self::Extension|getterCallsFromInstanceContext::T* value) → dynamic {
self::Extension|tearOffGetterNoArgs.call();
self::Extension|tearOffGetterRequired.call(value);
self::Extension|tearOffGetterOptional.call();
@@ -196,16 +206,18 @@
self::Extension|tearOffGetterNamed.call();
self::Extension|tearOffGetterNamed.call(value: value);
self::Extension|tearOffGetterGenericRequired.call(value);
- self::Extension|tearOffGetterGenericRequired.call<self::Extension|getterCallsFromInstanceContext::#T*>(value);
+ self::Extension|tearOffGetterGenericRequired.call<self::Extension|getterCallsFromInstanceContext::T*>(value);
self::Extension|tearOffGetterGenericOptional.call();
- self::Extension|tearOffGetterGenericOptional.call<self::Extension|getterCallsFromInstanceContext::#T*>();
+ self::Extension|tearOffGetterGenericOptional.call<self::Extension|getterCallsFromInstanceContext::T*>();
self::Extension|tearOffGetterGenericOptional.call(value);
- self::Extension|tearOffGetterGenericOptional.call<self::Extension|getterCallsFromInstanceContext::#T*>(value);
+ self::Extension|tearOffGetterGenericOptional.call<self::Extension|getterCallsFromInstanceContext::T*>(value);
self::Extension|tearOffGetterGenericNamed.call();
- self::Extension|tearOffGetterGenericNamed.call<self::Extension|getterCallsFromInstanceContext::#T*>();
+ self::Extension|tearOffGetterGenericNamed.call<self::Extension|getterCallsFromInstanceContext::T*>();
self::Extension|tearOffGetterGenericNamed.call(value: value);
- self::Extension|tearOffGetterGenericNamed.call<self::Extension|getterCallsFromInstanceContext::#T*>(value: value);
+ self::Extension|tearOffGetterGenericNamed.call<self::Extension|getterCallsFromInstanceContext::T*>(value: value);
}
+static method Extension|get#getterCallsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|get#getterCallsFromInstanceContext::T*>* #this) → (self::Extension|get#getterCallsFromInstanceContext::T*) →* dynamic
+ return (self::Extension|get#getterCallsFromInstanceContext::T* value) → dynamic => self::Extension|getterCallsFromInstanceContext<self::Extension|get#getterCallsFromInstanceContext::T*>(#this, value);
static method main() → dynamic {}
constants {
diff --git a/pkg/front_end/testcases/extensions/direct_static_access.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/direct_static_access.dart.strong.transformed.expect
index 1d70dc7..a7051b9 100644
--- a/pkg/front_end/testcases/extensions/direct_static_access.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/extensions/direct_static_access.dart.strong.transformed.expect
@@ -30,9 +30,13 @@
static method fieldAccessFromStaticContext = self::Extension|fieldAccessFromStaticContext;
static method getterCallsFromStaticContext = self::Extension|getterCallsFromStaticContext;
method invocationsFromInstanceContext = self::Extension|invocationsFromInstanceContext;
+ tearoff invocationsFromInstanceContext = self::Extension|get#invocationsFromInstanceContext;
method tearOffsFromInstanceContext = self::Extension|tearOffsFromInstanceContext;
+ tearoff tearOffsFromInstanceContext = self::Extension|get#tearOffsFromInstanceContext;
method fieldAccessFromInstanceContext = self::Extension|fieldAccessFromInstanceContext;
+ tearoff fieldAccessFromInstanceContext = self::Extension|get#fieldAccessFromInstanceContext;
method getterCallsFromInstanceContext = self::Extension|getterCallsFromInstanceContext;
+ tearoff getterCallsFromInstanceContext = self::Extension|get#getterCallsFromInstanceContext;
static set property = set self::Extension|property;
}
static field dynamic Extension|field;
@@ -141,25 +145,27 @@
self::Extension|tearOffGetterGenericNamed.call(value: value);
self::Extension|tearOffGetterGenericNamed.call<core::int*>(value: value);
}
-static method Extension|invocationsFromInstanceContext<#T extends core::Object* = dynamic>(final self::Class<self::Extension|invocationsFromInstanceContext::#T*>* #this, self::Extension|invocationsFromInstanceContext::#T* value) → dynamic {
+static method Extension|invocationsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|invocationsFromInstanceContext::T*>* #this, self::Extension|invocationsFromInstanceContext::T* value) → dynamic {
self::Extension|readGetter();
self::Extension|writeSetterRequired(value);
self::Extension|writeSetterOptional();
self::Extension|writeSetterOptional(value);
self::Extension|writeSetterNamed();
self::Extension|writeSetterNamed(value: value);
- self::Extension|genericWriteSetterRequired<self::Extension|invocationsFromInstanceContext::#T*>(value);
- self::Extension|genericWriteSetterRequired<self::Extension|invocationsFromInstanceContext::#T*>(value);
+ self::Extension|genericWriteSetterRequired<self::Extension|invocationsFromInstanceContext::T*>(value);
+ self::Extension|genericWriteSetterRequired<self::Extension|invocationsFromInstanceContext::T*>(value);
self::Extension|genericWriteSetterOptional<dynamic>();
- self::Extension|genericWriteSetterOptional<self::Extension|invocationsFromInstanceContext::#T*>();
- self::Extension|genericWriteSetterOptional<self::Extension|invocationsFromInstanceContext::#T*>(value);
- self::Extension|genericWriteSetterOptional<self::Extension|invocationsFromInstanceContext::#T*>(value);
+ self::Extension|genericWriteSetterOptional<self::Extension|invocationsFromInstanceContext::T*>();
+ self::Extension|genericWriteSetterOptional<self::Extension|invocationsFromInstanceContext::T*>(value);
+ self::Extension|genericWriteSetterOptional<self::Extension|invocationsFromInstanceContext::T*>(value);
self::Extension|genericWriteSetterNamed<dynamic>();
- self::Extension|genericWriteSetterNamed<self::Extension|invocationsFromInstanceContext::#T*>();
- self::Extension|genericWriteSetterNamed<self::Extension|invocationsFromInstanceContext::#T*>(value: value);
- self::Extension|genericWriteSetterNamed<self::Extension|invocationsFromInstanceContext::#T*>(value: value);
+ self::Extension|genericWriteSetterNamed<self::Extension|invocationsFromInstanceContext::T*>();
+ self::Extension|genericWriteSetterNamed<self::Extension|invocationsFromInstanceContext::T*>(value: value);
+ self::Extension|genericWriteSetterNamed<self::Extension|invocationsFromInstanceContext::T*>(value: value);
}
-static method Extension|tearOffsFromInstanceContext<#T extends core::Object* = dynamic>(final self::Class<self::Extension|tearOffsFromInstanceContext::#T*>* #this, self::Extension|tearOffsFromInstanceContext::#T* value) → dynamic {
+static method Extension|get#invocationsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|get#invocationsFromInstanceContext::T*>* #this) → (self::Extension|get#invocationsFromInstanceContext::T*) →* dynamic
+ return (self::Extension|get#invocationsFromInstanceContext::T* value) → dynamic => self::Extension|invocationsFromInstanceContext<self::Extension|get#invocationsFromInstanceContext::T*>(#this, value);
+static method Extension|tearOffsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|tearOffsFromInstanceContext::T*>* #this, self::Extension|tearOffsFromInstanceContext::T* value) → dynamic {
() →* dynamic tearOffNoArgs = #C2;
tearOffNoArgs.call();
(dynamic) →* dynamic tearOffRequired = #C3;
@@ -171,24 +177,28 @@
tearOffNamed.call();
tearOffNamed.call(value: value);
<S extends core::Object* = dynamic>(self::Extension|genericWriteSetterRequired::S*) →* dynamic tearOffGenericRequired = #C6;
- tearOffGenericRequired.call<self::Extension|tearOffsFromInstanceContext::#T*>(value);
- tearOffGenericRequired.call<self::Extension|tearOffsFromInstanceContext::#T*>(value);
+ tearOffGenericRequired.call<self::Extension|tearOffsFromInstanceContext::T*>(value);
+ tearOffGenericRequired.call<self::Extension|tearOffsFromInstanceContext::T*>(value);
<S extends core::Object* = dynamic>([self::Extension|genericWriteSetterOptional::S*]) →* dynamic tearOffGenericOptional = #C7;
tearOffGenericOptional.call<dynamic>();
- tearOffGenericOptional.call<self::Extension|tearOffsFromInstanceContext::#T*>();
- tearOffGenericOptional.call<self::Extension|tearOffsFromInstanceContext::#T*>(value);
- tearOffGenericOptional.call<self::Extension|tearOffsFromInstanceContext::#T*>(value);
+ tearOffGenericOptional.call<self::Extension|tearOffsFromInstanceContext::T*>();
+ tearOffGenericOptional.call<self::Extension|tearOffsFromInstanceContext::T*>(value);
+ tearOffGenericOptional.call<self::Extension|tearOffsFromInstanceContext::T*>(value);
<S extends core::Object* = dynamic>({value: self::Extension|genericWriteSetterNamed::S*}) →* dynamic tearOffGenericNamed = #C8;
tearOffGenericNamed.call<dynamic>();
- tearOffGenericNamed.call<self::Extension|tearOffsFromInstanceContext::#T*>();
- tearOffGenericNamed.call<self::Extension|tearOffsFromInstanceContext::#T*>(value: value);
- tearOffGenericNamed.call<self::Extension|tearOffsFromInstanceContext::#T*>(value: value);
+ tearOffGenericNamed.call<self::Extension|tearOffsFromInstanceContext::T*>();
+ tearOffGenericNamed.call<self::Extension|tearOffsFromInstanceContext::T*>(value: value);
+ tearOffGenericNamed.call<self::Extension|tearOffsFromInstanceContext::T*>(value: value);
}
-static method Extension|fieldAccessFromInstanceContext<#T extends core::Object* = dynamic>(final self::Class<self::Extension|fieldAccessFromInstanceContext::#T*>* #this) → dynamic {
+static method Extension|get#tearOffsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|get#tearOffsFromInstanceContext::T*>* #this) → (self::Extension|get#tearOffsFromInstanceContext::T*) →* dynamic
+ return (self::Extension|get#tearOffsFromInstanceContext::T* value) → dynamic => self::Extension|tearOffsFromInstanceContext<self::Extension|get#tearOffsFromInstanceContext::T*>(#this, value);
+static method Extension|fieldAccessFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|fieldAccessFromInstanceContext::T*>* #this) → dynamic {
self::Extension|field = self::Extension|property;
self::Extension|property = self::Extension|field;
}
-static method Extension|getterCallsFromInstanceContext<#T extends core::Object* = dynamic>(final self::Class<self::Extension|getterCallsFromInstanceContext::#T*>* #this, self::Extension|getterCallsFromInstanceContext::#T* value) → dynamic {
+static method Extension|get#fieldAccessFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|get#fieldAccessFromInstanceContext::T*>* #this) → () →* dynamic
+ return () → dynamic => self::Extension|fieldAccessFromInstanceContext<self::Extension|get#fieldAccessFromInstanceContext::T*>(#this);
+static method Extension|getterCallsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|getterCallsFromInstanceContext::T*>* #this, self::Extension|getterCallsFromInstanceContext::T* value) → dynamic {
self::Extension|tearOffGetterNoArgs.call();
self::Extension|tearOffGetterRequired.call(value);
self::Extension|tearOffGetterOptional.call();
@@ -196,16 +206,18 @@
self::Extension|tearOffGetterNamed.call();
self::Extension|tearOffGetterNamed.call(value: value);
self::Extension|tearOffGetterGenericRequired.call(value);
- self::Extension|tearOffGetterGenericRequired.call<self::Extension|getterCallsFromInstanceContext::#T*>(value);
+ self::Extension|tearOffGetterGenericRequired.call<self::Extension|getterCallsFromInstanceContext::T*>(value);
self::Extension|tearOffGetterGenericOptional.call();
- self::Extension|tearOffGetterGenericOptional.call<self::Extension|getterCallsFromInstanceContext::#T*>();
+ self::Extension|tearOffGetterGenericOptional.call<self::Extension|getterCallsFromInstanceContext::T*>();
self::Extension|tearOffGetterGenericOptional.call(value);
- self::Extension|tearOffGetterGenericOptional.call<self::Extension|getterCallsFromInstanceContext::#T*>(value);
+ self::Extension|tearOffGetterGenericOptional.call<self::Extension|getterCallsFromInstanceContext::T*>(value);
self::Extension|tearOffGetterGenericNamed.call();
- self::Extension|tearOffGetterGenericNamed.call<self::Extension|getterCallsFromInstanceContext::#T*>();
+ self::Extension|tearOffGetterGenericNamed.call<self::Extension|getterCallsFromInstanceContext::T*>();
self::Extension|tearOffGetterGenericNamed.call(value: value);
- self::Extension|tearOffGetterGenericNamed.call<self::Extension|getterCallsFromInstanceContext::#T*>(value: value);
+ self::Extension|tearOffGetterGenericNamed.call<self::Extension|getterCallsFromInstanceContext::T*>(value: value);
}
+static method Extension|get#getterCallsFromInstanceContext<T extends core::Object* = dynamic>(final self::Class<self::Extension|get#getterCallsFromInstanceContext::T*>* #this) → (self::Extension|get#getterCallsFromInstanceContext::T*) →* dynamic
+ return (self::Extension|get#getterCallsFromInstanceContext::T* value) → dynamic => self::Extension|getterCallsFromInstanceContext<self::Extension|get#getterCallsFromInstanceContext::T*>(#this, value);
static method main() → dynamic {}
constants {
diff --git a/pkg/front_end/testcases/extensions/explicit_extension_access.dart b/pkg/front_end/testcases/extensions/explicit_extension_access.dart
new file mode 100644
index 0000000..d030faf
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/explicit_extension_access.dart
@@ -0,0 +1,58 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Class {
+ int field1 = 42;
+ int field2 = 87;
+}
+
+extension Extension1 on Class {
+ int get field => field1;
+ void set field(int value) {
+ field1 = value;
+ }
+ int method() => field1;
+ int genericMethod<T extends num>(T t) => field1 + t;
+}
+
+extension Extension2 on Class {
+ int get field => field2;
+ void set field(int value) {
+ field2 = value;
+ }
+ int method() => field2;
+ int genericMethod<T extends num>(T t) => field2 + t;
+}
+
+main() {
+ Class c = new Class();
+ expect(42, Extension1(c).field);
+ expect(87, Extension2(c).field);
+ expect(42, Extension1(c).method());
+ expect(87, Extension2(c).method());
+ var tearOff1 = Extension1(c).method;
+ var tearOff2 = Extension2(c).method;
+ expect(42, tearOff1());
+ expect(87, tearOff2());
+ expect(52, Extension1(c).genericMethod(10));
+ expect(97, Extension2(c).genericMethod(10));
+ expect(52, Extension1(c).genericMethod<num>(10));
+ expect(97, Extension2(c).genericMethod<num>(10));
+ var genericTearOff1 = Extension1(c).genericMethod;
+ var genericTearOff2 = Extension2(c).genericMethod;
+ expect(52, genericTearOff1(10));
+ expect(97, genericTearOff2(10));
+ expect(52, genericTearOff1<num>(10));
+ expect(97, genericTearOff2<num>(10));
+ expect(23, Extension1(c).field = 23);
+ expect(67, Extension2(c).field = 67);
+ expect(23, Extension1(c).field);
+ expect(67, Extension2(c).field);
+}
+
+expect(expected, actual) {
+ if (expected != actual) {
+ throw 'Mismatch: expected=$expected, actual=$actual';
+ }
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/explicit_extension_access.dart.outline.expect b/pkg/front_end/testcases/extensions/explicit_extension_access.dart.outline.expect
new file mode 100644
index 0000000..cf66bc6
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/explicit_extension_access.dart.outline.expect
@@ -0,0 +1,54 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+ field core::int* field1;
+ field core::int* field2;
+ synthetic constructor •() → self::Class*
+ ;
+}
+extension Extension1 on self::Class* {
+ get field = self::Extension1|get#field;
+ method method = self::Extension1|method;
+ tearoff method = self::Extension1|get#method;
+ method genericMethod = self::Extension1|genericMethod;
+ tearoff genericMethod = self::Extension1|get#genericMethod;
+ set field = self::Extension1|set#field;
+}
+extension Extension2 on self::Class* {
+ get field = self::Extension2|get#field;
+ method method = self::Extension2|method;
+ tearoff method = self::Extension2|get#method;
+ method genericMethod = self::Extension2|genericMethod;
+ tearoff genericMethod = self::Extension2|get#genericMethod;
+ set field = self::Extension2|set#field;
+}
+static method Extension1|get#field(final self::Class* #this) → core::int*
+ ;
+static method Extension1|set#field(final self::Class* #this, core::int* value) → void
+ ;
+static method Extension1|method(final self::Class* #this) → core::int*
+ ;
+static method Extension1|get#method(final self::Class* #this) → () →* core::int*
+ return () → core::int* => self::Extension1|method(#this);
+static method Extension1|genericMethod<T extends core::num* = dynamic>(final self::Class* #this, self::Extension1|genericMethod::T* t) → core::int*
+ ;
+static method Extension1|get#genericMethod(final self::Class* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+ return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension1|genericMethod<T*>(#this, t);
+static method Extension2|get#field(final self::Class* #this) → core::int*
+ ;
+static method Extension2|set#field(final self::Class* #this, core::int* value) → void
+ ;
+static method Extension2|method(final self::Class* #this) → core::int*
+ ;
+static method Extension2|get#method(final self::Class* #this) → () →* core::int*
+ return () → core::int* => self::Extension2|method(#this);
+static method Extension2|genericMethod<T extends core::num* = dynamic>(final self::Class* #this, self::Extension2|genericMethod::T* t) → core::int*
+ ;
+static method Extension2|get#genericMethod(final self::Class* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+ return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension2|genericMethod<T*>(#this, t);
+static method main() → dynamic
+ ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+ ;
diff --git a/pkg/front_end/testcases/extensions/explicit_extension_access.dart.strong.expect b/pkg/front_end/testcases/extensions/explicit_extension_access.dart.strong.expect
new file mode 100644
index 0000000..70f01be
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/explicit_extension_access.dart.strong.expect
@@ -0,0 +1,87 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+ field core::int* field1 = 42;
+ field core::int* field2 = 87;
+ synthetic constructor •() → self::Class*
+ : super core::Object::•()
+ ;
+}
+extension Extension1 on self::Class* {
+ get field = self::Extension1|get#field;
+ method method = self::Extension1|method;
+ tearoff method = self::Extension1|get#method;
+ method genericMethod = self::Extension1|genericMethod;
+ tearoff genericMethod = self::Extension1|get#genericMethod;
+ set field = self::Extension1|set#field;
+}
+extension Extension2 on self::Class* {
+ get field = self::Extension2|get#field;
+ method method = self::Extension2|method;
+ tearoff method = self::Extension2|get#method;
+ method genericMethod = self::Extension2|genericMethod;
+ tearoff genericMethod = self::Extension2|get#genericMethod;
+ set field = self::Extension2|set#field;
+}
+static method Extension1|get#field(final self::Class* #this) → core::int*
+ return #this.{self::Class::field1};
+static method Extension1|set#field(final self::Class* #this, core::int* value) → core::int* {
+ final core::int* #t1 = value;
+ #this.{self::Class::field1} = value;
+ return #t1;
+}
+static method Extension1|method(final self::Class* #this) → core::int*
+ return #this.{self::Class::field1};
+static method Extension1|get#method(final self::Class* #this) → () →* core::int*
+ return () → core::int* => self::Extension1|method(#this);
+static method Extension1|genericMethod<T extends core::num* = dynamic>(final self::Class* #this, self::Extension1|genericMethod::T* t) → core::int*
+ return #this.{self::Class::field1}.{core::num::+}(t) as{TypeError} core::int*;
+static method Extension1|get#genericMethod(final self::Class* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+ return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension1|genericMethod<T*>(#this, t);
+static method Extension2|get#field(final self::Class* #this) → core::int*
+ return #this.{self::Class::field2};
+static method Extension2|set#field(final self::Class* #this, core::int* value) → core::int* {
+ final core::int* #t2 = value;
+ #this.{self::Class::field2} = value;
+ return #t2;
+}
+static method Extension2|method(final self::Class* #this) → core::int*
+ return #this.{self::Class::field2};
+static method Extension2|get#method(final self::Class* #this) → () →* core::int*
+ return () → core::int* => self::Extension2|method(#this);
+static method Extension2|genericMethod<T extends core::num* = dynamic>(final self::Class* #this, self::Extension2|genericMethod::T* t) → core::int*
+ return #this.{self::Class::field2}.{core::num::+}(t) as{TypeError} core::int*;
+static method Extension2|get#genericMethod(final self::Class* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+ return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension2|genericMethod<T*>(#this, t);
+static method main() → dynamic {
+ self::Class* c = new self::Class::•();
+ self::expect(42, self::Extension1|get#field(c));
+ self::expect(87, self::Extension2|get#field(c));
+ self::expect(42, self::Extension1|method(c));
+ self::expect(87, self::Extension2|method(c));
+ () →* core::int* tearOff1 = self::Extension1|get#method(c);
+ () →* core::int* tearOff2 = self::Extension2|get#method(c);
+ self::expect(42, tearOff1.call());
+ self::expect(87, tearOff2.call());
+ self::expect(52, self::Extension1|genericMethod<core::int*>(c, 10));
+ self::expect(97, self::Extension2|genericMethod<core::int*>(c, 10));
+ self::expect(52, self::Extension1|genericMethod<core::num*>(c, 10));
+ self::expect(97, self::Extension2|genericMethod<core::num*>(c, 10));
+ <T extends core::num* = dynamic>(T*) →* core::int* genericTearOff1 = self::Extension1|get#genericMethod(c);
+ <T extends core::num* = dynamic>(T*) →* core::int* genericTearOff2 = self::Extension2|get#genericMethod(c);
+ self::expect(52, genericTearOff1.call<core::int*>(10));
+ self::expect(97, genericTearOff2.call<core::int*>(10));
+ self::expect(52, genericTearOff1.call<core::num*>(10));
+ self::expect(97, genericTearOff2.call<core::num*>(10));
+ self::expect(23, self::Extension1|set#field(c, 23));
+ self::expect(67, self::Extension2|set#field(c, 67));
+ self::expect(23, self::Extension1|get#field(c));
+ self::expect(67, self::Extension2|get#field(c));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!expected.{core::Object::==}(actual)) {
+ throw "Mismatch: expected=${expected}, actual=${actual}";
+ }
+}
diff --git a/pkg/front_end/testcases/extensions/explicit_extension_access.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/explicit_extension_access.dart.strong.transformed.expect
new file mode 100644
index 0000000..70f01be
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/explicit_extension_access.dart.strong.transformed.expect
@@ -0,0 +1,87 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+ field core::int* field1 = 42;
+ field core::int* field2 = 87;
+ synthetic constructor •() → self::Class*
+ : super core::Object::•()
+ ;
+}
+extension Extension1 on self::Class* {
+ get field = self::Extension1|get#field;
+ method method = self::Extension1|method;
+ tearoff method = self::Extension1|get#method;
+ method genericMethod = self::Extension1|genericMethod;
+ tearoff genericMethod = self::Extension1|get#genericMethod;
+ set field = self::Extension1|set#field;
+}
+extension Extension2 on self::Class* {
+ get field = self::Extension2|get#field;
+ method method = self::Extension2|method;
+ tearoff method = self::Extension2|get#method;
+ method genericMethod = self::Extension2|genericMethod;
+ tearoff genericMethod = self::Extension2|get#genericMethod;
+ set field = self::Extension2|set#field;
+}
+static method Extension1|get#field(final self::Class* #this) → core::int*
+ return #this.{self::Class::field1};
+static method Extension1|set#field(final self::Class* #this, core::int* value) → core::int* {
+ final core::int* #t1 = value;
+ #this.{self::Class::field1} = value;
+ return #t1;
+}
+static method Extension1|method(final self::Class* #this) → core::int*
+ return #this.{self::Class::field1};
+static method Extension1|get#method(final self::Class* #this) → () →* core::int*
+ return () → core::int* => self::Extension1|method(#this);
+static method Extension1|genericMethod<T extends core::num* = dynamic>(final self::Class* #this, self::Extension1|genericMethod::T* t) → core::int*
+ return #this.{self::Class::field1}.{core::num::+}(t) as{TypeError} core::int*;
+static method Extension1|get#genericMethod(final self::Class* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+ return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension1|genericMethod<T*>(#this, t);
+static method Extension2|get#field(final self::Class* #this) → core::int*
+ return #this.{self::Class::field2};
+static method Extension2|set#field(final self::Class* #this, core::int* value) → core::int* {
+ final core::int* #t2 = value;
+ #this.{self::Class::field2} = value;
+ return #t2;
+}
+static method Extension2|method(final self::Class* #this) → core::int*
+ return #this.{self::Class::field2};
+static method Extension2|get#method(final self::Class* #this) → () →* core::int*
+ return () → core::int* => self::Extension2|method(#this);
+static method Extension2|genericMethod<T extends core::num* = dynamic>(final self::Class* #this, self::Extension2|genericMethod::T* t) → core::int*
+ return #this.{self::Class::field2}.{core::num::+}(t) as{TypeError} core::int*;
+static method Extension2|get#genericMethod(final self::Class* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+ return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension2|genericMethod<T*>(#this, t);
+static method main() → dynamic {
+ self::Class* c = new self::Class::•();
+ self::expect(42, self::Extension1|get#field(c));
+ self::expect(87, self::Extension2|get#field(c));
+ self::expect(42, self::Extension1|method(c));
+ self::expect(87, self::Extension2|method(c));
+ () →* core::int* tearOff1 = self::Extension1|get#method(c);
+ () →* core::int* tearOff2 = self::Extension2|get#method(c);
+ self::expect(42, tearOff1.call());
+ self::expect(87, tearOff2.call());
+ self::expect(52, self::Extension1|genericMethod<core::int*>(c, 10));
+ self::expect(97, self::Extension2|genericMethod<core::int*>(c, 10));
+ self::expect(52, self::Extension1|genericMethod<core::num*>(c, 10));
+ self::expect(97, self::Extension2|genericMethod<core::num*>(c, 10));
+ <T extends core::num* = dynamic>(T*) →* core::int* genericTearOff1 = self::Extension1|get#genericMethod(c);
+ <T extends core::num* = dynamic>(T*) →* core::int* genericTearOff2 = self::Extension2|get#genericMethod(c);
+ self::expect(52, genericTearOff1.call<core::int*>(10));
+ self::expect(97, genericTearOff2.call<core::int*>(10));
+ self::expect(52, genericTearOff1.call<core::num*>(10));
+ self::expect(97, genericTearOff2.call<core::num*>(10));
+ self::expect(23, self::Extension1|set#field(c, 23));
+ self::expect(67, self::Extension2|set#field(c, 67));
+ self::expect(23, self::Extension1|get#field(c));
+ self::expect(67, self::Extension2|get#field(c));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!expected.{core::Object::==}(actual)) {
+ throw "Mismatch: expected=${expected}, actual=${actual}";
+ }
+}
diff --git a/pkg/front_end/testcases/extensions/explicit_extension_inference.dart b/pkg/front_end/testcases/extensions/explicit_extension_inference.dart
new file mode 100644
index 0000000..d2a63b9
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/explicit_extension_inference.dart
@@ -0,0 +1,107 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class A {}
+class B extends A {}
+class C extends B {}
+
+class GenericClass<T> {}
+
+extension GenericExtension<T> on GenericClass<T> {
+ T get property => null;
+
+ T method(T t) => null;
+
+ S genericMethod1<S>(S s) => null;
+}
+
+main() {
+ A aVariable;
+ C cVariable;
+
+ GenericClass<A> aClass;
+ GenericClass<B> bClass;
+ GenericClass<C> cClass;
+
+ cVariable = GenericExtension(aClass).property;
+ cVariable = GenericExtension<A>(aClass).property;
+ cVariable = GenericExtension<B>(aClass).property;
+ cVariable = GenericExtension<C>(aClass).property;
+
+ cVariable = GenericExtension(bClass).property;
+ cVariable = GenericExtension<A>(bClass).property;
+ cVariable = GenericExtension<B>(bClass).property;
+ cVariable = GenericExtension<C>(bClass).property;
+
+ aVariable = GenericExtension(cClass).property;
+ aVariable = GenericExtension<A>(cClass).property;
+ aVariable = GenericExtension<B>(cClass).property;
+ aVariable = GenericExtension<C>(cClass).property;
+
+ cVariable = GenericExtension(aClass).method(aVariable);
+ cVariable = GenericExtension<A>(aClass).method(aVariable);
+ cVariable = GenericExtension<B>(aClass).method(aVariable);
+ cVariable = GenericExtension<C>(aClass).method(aVariable);
+
+ cVariable = GenericExtension(bClass).method(aVariable);
+ cVariable = GenericExtension<A>(bClass).method(aVariable);
+ cVariable = GenericExtension<B>(bClass).method(aVariable);
+ cVariable = GenericExtension<C>(bClass).method(aVariable);
+
+ aVariable = GenericExtension(cClass).method(aVariable);
+ aVariable = GenericExtension<A>(cClass).method(aVariable);
+ aVariable = GenericExtension<B>(cClass).method(aVariable);
+ aVariable = GenericExtension<C>(cClass).method(aVariable);
+
+ cVariable = GenericExtension(aClass).genericMethod1(aVariable);
+ cVariable = GenericExtension(aClass).genericMethod1<A>(aVariable);
+ cVariable = GenericExtension(aClass).genericMethod1<B>(aVariable);
+ cVariable = GenericExtension(aClass).genericMethod1<C>(aVariable);
+ cVariable = GenericExtension<A>(aClass).genericMethod1(aVariable);
+ cVariable = GenericExtension<A>(aClass).genericMethod1<A>(aVariable);
+ cVariable = GenericExtension<A>(aClass).genericMethod1<B>(aVariable);
+ cVariable = GenericExtension<A>(aClass).genericMethod1<C>(aVariable);
+ cVariable = GenericExtension<B>(aClass).genericMethod1(aVariable);
+ cVariable = GenericExtension<B>(aClass).genericMethod1<A>(aVariable);
+ cVariable = GenericExtension<B>(aClass).genericMethod1<B>(aVariable);
+ cVariable = GenericExtension<B>(aClass).genericMethod1<C>(aVariable);
+ cVariable = GenericExtension<C>(aClass).genericMethod1(aVariable);
+ cVariable = GenericExtension<C>(aClass).genericMethod1<A>(aVariable);
+ cVariable = GenericExtension<C>(aClass).genericMethod1<B>(aVariable);
+ cVariable = GenericExtension<C>(aClass).genericMethod1<C>(aVariable);
+
+ cVariable = GenericExtension(bClass).genericMethod1(aVariable);
+ cVariable = GenericExtension(bClass).genericMethod1<A>(aVariable);
+ cVariable = GenericExtension(bClass).genericMethod1<B>(aVariable);
+ cVariable = GenericExtension(bClass).genericMethod1<C>(aVariable);
+ cVariable = GenericExtension<A>(bClass).genericMethod1(aVariable);
+ cVariable = GenericExtension<A>(bClass).genericMethod1<A>(aVariable);
+ cVariable = GenericExtension<A>(bClass).genericMethod1<B>(aVariable);
+ cVariable = GenericExtension<A>(bClass).genericMethod1<C>(aVariable);
+ cVariable = GenericExtension<B>(bClass).genericMethod1(aVariable);
+ cVariable = GenericExtension<B>(bClass).genericMethod1<A>(aVariable);
+ cVariable = GenericExtension<B>(bClass).genericMethod1<B>(aVariable);
+ cVariable = GenericExtension<B>(bClass).genericMethod1<C>(aVariable);
+ cVariable = GenericExtension<C>(bClass).genericMethod1(aVariable);
+ cVariable = GenericExtension<C>(bClass).genericMethod1<A>(aVariable);
+ cVariable = GenericExtension<C>(bClass).genericMethod1<B>(aVariable);
+ cVariable = GenericExtension<C>(bClass).genericMethod1<C>(aVariable);
+
+ cVariable = GenericExtension(cClass).genericMethod1(aVariable);
+ cVariable = GenericExtension(cClass).genericMethod1<A>(aVariable);
+ cVariable = GenericExtension(cClass).genericMethod1<B>(aVariable);
+ cVariable = GenericExtension(cClass).genericMethod1<C>(aVariable);
+ cVariable = GenericExtension<A>(cClass).genericMethod1(aVariable);
+ cVariable = GenericExtension<A>(cClass).genericMethod1<A>(aVariable);
+ cVariable = GenericExtension<A>(cClass).genericMethod1<B>(aVariable);
+ cVariable = GenericExtension<A>(cClass).genericMethod1<C>(aVariable);
+ cVariable = GenericExtension<B>(cClass).genericMethod1(aVariable);
+ cVariable = GenericExtension<B>(cClass).genericMethod1<A>(aVariable);
+ cVariable = GenericExtension<B>(cClass).genericMethod1<B>(aVariable);
+ cVariable = GenericExtension<B>(cClass).genericMethod1<C>(aVariable);
+ cVariable = GenericExtension<C>(cClass).genericMethod1(aVariable);
+ cVariable = GenericExtension<C>(cClass).genericMethod1<A>(aVariable);
+ cVariable = GenericExtension<C>(cClass).genericMethod1<B>(aVariable);
+ cVariable = GenericExtension<C>(cClass).genericMethod1<C>(aVariable);
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/explicit_extension_inference.dart.outline.expect b/pkg/front_end/testcases/extensions/explicit_extension_inference.dart.outline.expect
new file mode 100644
index 0000000..b09bea2
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/explicit_extension_inference.dart.outline.expect
@@ -0,0 +1,39 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ synthetic constructor •() → self::A*
+ ;
+}
+class B extends self::A {
+ synthetic constructor •() → self::B*
+ ;
+}
+class C extends self::B {
+ synthetic constructor •() → self::C*
+ ;
+}
+class GenericClass<T extends core::Object* = dynamic> extends core::Object {
+ synthetic constructor •() → self::GenericClass<self::GenericClass::T*>*
+ ;
+}
+extension GenericExtension<T extends core::Object* = dynamic> on self::GenericClass<T*>* {
+ get property = self::GenericExtension|get#property;
+ method method = self::GenericExtension|method;
+ tearoff method = self::GenericExtension|get#method;
+ method genericMethod1 = self::GenericExtension|genericMethod1;
+ tearoff genericMethod1 = self::GenericExtension|get#genericMethod1;
+}
+static method GenericExtension|get#property<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#property::T*>* #this) → self::GenericExtension|get#property::T*
+ ;
+static method GenericExtension|method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|method::T*>* #this, self::GenericExtension|method::T* t) → self::GenericExtension|method::T*
+ ;
+static method GenericExtension|get#method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#method::T*>* #this) → (self::GenericExtension|get#method::T*) →* self::GenericExtension|get#method::T*
+ return (self::GenericExtension|get#method::T* t) → self::GenericExtension|get#method::T* => self::GenericExtension|method<self::GenericExtension|get#method::T*>(#this, t);
+static method GenericExtension|genericMethod1<T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|genericMethod1::T*>* #this, self::GenericExtension|genericMethod1::S* s) → self::GenericExtension|genericMethod1::S*
+ ;
+static method GenericExtension|get#genericMethod1<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#genericMethod1::T*>* #this) → <S extends core::Object* = dynamic>(S*) →* S*
+ return <S extends core::Object* = dynamic>(S* s) → S* => self::GenericExtension|genericMethod1<self::GenericExtension|get#genericMethod1::T*, S*>(#this, s);
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/extensions/explicit_extension_inference.dart.strong.expect b/pkg/front_end/testcases/extensions/explicit_extension_inference.dart.strong.expect
new file mode 100644
index 0000000..b3a12f5
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/explicit_extension_inference.dart.strong.expect
@@ -0,0 +1,120 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ synthetic constructor •() → self::A*
+ : super core::Object::•()
+ ;
+}
+class B extends self::A {
+ synthetic constructor •() → self::B*
+ : super self::A::•()
+ ;
+}
+class C extends self::B {
+ synthetic constructor •() → self::C*
+ : super self::B::•()
+ ;
+}
+class GenericClass<T extends core::Object* = dynamic> extends core::Object {
+ synthetic constructor •() → self::GenericClass<self::GenericClass::T*>*
+ : super core::Object::•()
+ ;
+}
+extension GenericExtension<T extends core::Object* = dynamic> on self::GenericClass<T*>* {
+ get property = self::GenericExtension|get#property;
+ method method = self::GenericExtension|method;
+ tearoff method = self::GenericExtension|get#method;
+ method genericMethod1 = self::GenericExtension|genericMethod1;
+ tearoff genericMethod1 = self::GenericExtension|get#genericMethod1;
+}
+static method GenericExtension|get#property<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#property::T*>* #this) → self::GenericExtension|get#property::T*
+ return null;
+static method GenericExtension|method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|method::T*>* #this, self::GenericExtension|method::T* t) → self::GenericExtension|method::T*
+ return null;
+static method GenericExtension|get#method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#method::T*>* #this) → (self::GenericExtension|get#method::T*) →* self::GenericExtension|get#method::T*
+ return (self::GenericExtension|get#method::T* t) → self::GenericExtension|get#method::T* => self::GenericExtension|method<self::GenericExtension|get#method::T*>(#this, t);
+static method GenericExtension|genericMethod1<T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|genericMethod1::T*>* #this, self::GenericExtension|genericMethod1::S* s) → self::GenericExtension|genericMethod1::S*
+ return null;
+static method GenericExtension|get#genericMethod1<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#genericMethod1::T*>* #this) → <S extends core::Object* = dynamic>(S*) →* S*
+ return <S extends core::Object* = dynamic>(S* s) → S* => self::GenericExtension|genericMethod1<self::GenericExtension|get#genericMethod1::T*, S*>(#this, s);
+static method main() → dynamic {
+ self::A* aVariable;
+ self::C* cVariable;
+ self::GenericClass<self::A*>* aClass;
+ self::GenericClass<self::B*>* bClass;
+ self::GenericClass<self::C*>* cClass;
+ cVariable = self::GenericExtension|get#property<self::A*>(aClass) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|get#property<self::A*>(aClass) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|get#property<self::B*>(aClass as{TypeError} self::GenericClass<self::B*>*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|get#property<self::C*>(aClass as{TypeError} self::GenericClass<self::C*>*);
+ cVariable = self::GenericExtension|get#property<self::B*>(bClass) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|get#property<self::A*>(bClass) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|get#property<self::B*>(bClass) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|get#property<self::C*>(bClass as{TypeError} self::GenericClass<self::C*>*);
+ aVariable = self::GenericExtension|get#property<self::C*>(cClass);
+ aVariable = self::GenericExtension|get#property<self::A*>(cClass);
+ aVariable = self::GenericExtension|get#property<self::B*>(cClass);
+ aVariable = self::GenericExtension|get#property<self::C*>(cClass);
+ cVariable = self::GenericExtension|method<self::A*>(aClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|method<self::A*>(aClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|method<self::B*>(aClass as{TypeError} self::GenericClass<self::B*>*, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|method<self::C*>(aClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|method<self::B*>(bClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|method<self::A*>(bClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|method<self::B*>(bClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|method<self::C*>(bClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::C*);
+ aVariable = self::GenericExtension|method<self::C*>(cClass, aVariable as{TypeError} self::C*);
+ aVariable = self::GenericExtension|method<self::A*>(cClass, aVariable);
+ aVariable = self::GenericExtension|method<self::B*>(cClass, aVariable as{TypeError} self::B*);
+ aVariable = self::GenericExtension|method<self::C*>(cClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(aClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::A*>(aClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::B*>(aClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(aClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(aClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::A*>(aClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::B*>(aClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(aClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(aClass as{TypeError} self::GenericClass<self::B*>*, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::A*>(aClass as{TypeError} self::GenericClass<self::B*>*, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::B*>(aClass as{TypeError} self::GenericClass<self::B*>*, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(aClass as{TypeError} self::GenericClass<self::B*>*, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(aClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::A*>(aClass as{TypeError} self::GenericClass<self::C*>*, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::B*>(aClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(aClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::A*>(bClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::B*>(bClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::A*>(bClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::B*>(bClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::A*>(bClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::B*>(bClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(bClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::A*>(bClass as{TypeError} self::GenericClass<self::C*>*, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::B*>(bClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(bClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::A*>(cClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::B*>(cClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::A*>(cClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::B*>(cClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::A*>(cClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::B*>(cClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::A*>(cClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::B*>(cClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+}
diff --git a/pkg/front_end/testcases/extensions/explicit_extension_inference.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/explicit_extension_inference.dart.strong.transformed.expect
new file mode 100644
index 0000000..b3a12f5
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/explicit_extension_inference.dart.strong.transformed.expect
@@ -0,0 +1,120 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ synthetic constructor •() → self::A*
+ : super core::Object::•()
+ ;
+}
+class B extends self::A {
+ synthetic constructor •() → self::B*
+ : super self::A::•()
+ ;
+}
+class C extends self::B {
+ synthetic constructor •() → self::C*
+ : super self::B::•()
+ ;
+}
+class GenericClass<T extends core::Object* = dynamic> extends core::Object {
+ synthetic constructor •() → self::GenericClass<self::GenericClass::T*>*
+ : super core::Object::•()
+ ;
+}
+extension GenericExtension<T extends core::Object* = dynamic> on self::GenericClass<T*>* {
+ get property = self::GenericExtension|get#property;
+ method method = self::GenericExtension|method;
+ tearoff method = self::GenericExtension|get#method;
+ method genericMethod1 = self::GenericExtension|genericMethod1;
+ tearoff genericMethod1 = self::GenericExtension|get#genericMethod1;
+}
+static method GenericExtension|get#property<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#property::T*>* #this) → self::GenericExtension|get#property::T*
+ return null;
+static method GenericExtension|method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|method::T*>* #this, self::GenericExtension|method::T* t) → self::GenericExtension|method::T*
+ return null;
+static method GenericExtension|get#method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#method::T*>* #this) → (self::GenericExtension|get#method::T*) →* self::GenericExtension|get#method::T*
+ return (self::GenericExtension|get#method::T* t) → self::GenericExtension|get#method::T* => self::GenericExtension|method<self::GenericExtension|get#method::T*>(#this, t);
+static method GenericExtension|genericMethod1<T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|genericMethod1::T*>* #this, self::GenericExtension|genericMethod1::S* s) → self::GenericExtension|genericMethod1::S*
+ return null;
+static method GenericExtension|get#genericMethod1<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#genericMethod1::T*>* #this) → <S extends core::Object* = dynamic>(S*) →* S*
+ return <S extends core::Object* = dynamic>(S* s) → S* => self::GenericExtension|genericMethod1<self::GenericExtension|get#genericMethod1::T*, S*>(#this, s);
+static method main() → dynamic {
+ self::A* aVariable;
+ self::C* cVariable;
+ self::GenericClass<self::A*>* aClass;
+ self::GenericClass<self::B*>* bClass;
+ self::GenericClass<self::C*>* cClass;
+ cVariable = self::GenericExtension|get#property<self::A*>(aClass) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|get#property<self::A*>(aClass) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|get#property<self::B*>(aClass as{TypeError} self::GenericClass<self::B*>*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|get#property<self::C*>(aClass as{TypeError} self::GenericClass<self::C*>*);
+ cVariable = self::GenericExtension|get#property<self::B*>(bClass) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|get#property<self::A*>(bClass) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|get#property<self::B*>(bClass) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|get#property<self::C*>(bClass as{TypeError} self::GenericClass<self::C*>*);
+ aVariable = self::GenericExtension|get#property<self::C*>(cClass);
+ aVariable = self::GenericExtension|get#property<self::A*>(cClass);
+ aVariable = self::GenericExtension|get#property<self::B*>(cClass);
+ aVariable = self::GenericExtension|get#property<self::C*>(cClass);
+ cVariable = self::GenericExtension|method<self::A*>(aClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|method<self::A*>(aClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|method<self::B*>(aClass as{TypeError} self::GenericClass<self::B*>*, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|method<self::C*>(aClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|method<self::B*>(bClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|method<self::A*>(bClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|method<self::B*>(bClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|method<self::C*>(bClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::C*);
+ aVariable = self::GenericExtension|method<self::C*>(cClass, aVariable as{TypeError} self::C*);
+ aVariable = self::GenericExtension|method<self::A*>(cClass, aVariable);
+ aVariable = self::GenericExtension|method<self::B*>(cClass, aVariable as{TypeError} self::B*);
+ aVariable = self::GenericExtension|method<self::C*>(cClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(aClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::A*>(aClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::B*>(aClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(aClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(aClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::A*>(aClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::B*>(aClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(aClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(aClass as{TypeError} self::GenericClass<self::B*>*, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::A*>(aClass as{TypeError} self::GenericClass<self::B*>*, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::B*>(aClass as{TypeError} self::GenericClass<self::B*>*, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(aClass as{TypeError} self::GenericClass<self::B*>*, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(aClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::A*>(aClass as{TypeError} self::GenericClass<self::C*>*, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::B*>(aClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(aClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::A*>(bClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::B*>(bClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::A*>(bClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::B*>(bClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::A*>(bClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::B*>(bClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(bClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::A*>(bClass as{TypeError} self::GenericClass<self::C*>*, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::B*>(bClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(bClass as{TypeError} self::GenericClass<self::C*>*, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::A*>(cClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::B*>(cClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::A*>(cClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::B*>(cClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::A*>(cClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::B*>(cClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::A*>(cClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::B*>(cClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+}
diff --git a/pkg/front_end/testcases/extensions/explicit_extension_inference.dart.type_promotion.expect b/pkg/front_end/testcases/extensions/explicit_extension_inference.dart.type_promotion.expect
new file mode 100644
index 0000000..48040a1
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/explicit_extension_inference.dart.type_promotion.expect
@@ -0,0 +1,216 @@
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:27:13: Context: Write to cVariable@468
+ cVariable = GenericExtension(aClass).property;
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:28:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<A>(aClass).property;
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:29:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<B>(aClass).property;
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:30:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<C>(aClass).property;
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:32:13: Context: Write to cVariable@468
+ cVariable = GenericExtension(bClass).property;
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:33:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<A>(bClass).property;
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:34:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<B>(bClass).property;
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:35:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<C>(bClass).property;
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:37:13: Context: Write to aVariable@453
+ aVariable = GenericExtension(cClass).property;
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:38:13: Context: Write to aVariable@453
+ aVariable = GenericExtension<A>(cClass).property;
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:39:13: Context: Write to aVariable@453
+ aVariable = GenericExtension<B>(cClass).property;
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:40:13: Context: Write to aVariable@453
+ aVariable = GenericExtension<C>(cClass).property;
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:42:13: Context: Write to cVariable@468
+ cVariable = GenericExtension(aClass).method(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:43:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<A>(aClass).method(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:44:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<B>(aClass).method(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:45:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<C>(aClass).method(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:47:13: Context: Write to cVariable@468
+ cVariable = GenericExtension(bClass).method(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:48:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<A>(bClass).method(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:49:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<B>(bClass).method(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:50:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<C>(bClass).method(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:52:13: Context: Write to aVariable@453
+ aVariable = GenericExtension(cClass).method(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:53:13: Context: Write to aVariable@453
+ aVariable = GenericExtension<A>(cClass).method(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:54:13: Context: Write to aVariable@453
+ aVariable = GenericExtension<B>(cClass).method(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:55:13: Context: Write to aVariable@453
+ aVariable = GenericExtension<C>(cClass).method(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:57:13: Context: Write to cVariable@468
+ cVariable = GenericExtension(aClass).genericMethod1(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:58:13: Context: Write to cVariable@468
+ cVariable = GenericExtension(aClass).genericMethod1<A>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:59:13: Context: Write to cVariable@468
+ cVariable = GenericExtension(aClass).genericMethod1<B>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:60:13: Context: Write to cVariable@468
+ cVariable = GenericExtension(aClass).genericMethod1<C>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:61:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<A>(aClass).genericMethod1(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:62:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<A>(aClass).genericMethod1<A>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:63:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<A>(aClass).genericMethod1<B>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:64:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<A>(aClass).genericMethod1<C>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:65:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<B>(aClass).genericMethod1(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:66:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<B>(aClass).genericMethod1<A>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:67:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<B>(aClass).genericMethod1<B>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:68:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<B>(aClass).genericMethod1<C>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:69:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<C>(aClass).genericMethod1(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:70:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<C>(aClass).genericMethod1<A>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:71:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<C>(aClass).genericMethod1<B>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:72:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<C>(aClass).genericMethod1<C>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:74:13: Context: Write to cVariable@468
+ cVariable = GenericExtension(bClass).genericMethod1(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:75:13: Context: Write to cVariable@468
+ cVariable = GenericExtension(bClass).genericMethod1<A>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:76:13: Context: Write to cVariable@468
+ cVariable = GenericExtension(bClass).genericMethod1<B>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:77:13: Context: Write to cVariable@468
+ cVariable = GenericExtension(bClass).genericMethod1<C>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:78:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<A>(bClass).genericMethod1(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:79:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<A>(bClass).genericMethod1<A>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:80:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<A>(bClass).genericMethod1<B>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:81:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<A>(bClass).genericMethod1<C>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:82:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<B>(bClass).genericMethod1(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:83:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<B>(bClass).genericMethod1<A>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:84:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<B>(bClass).genericMethod1<B>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:85:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<B>(bClass).genericMethod1<C>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:86:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<C>(bClass).genericMethod1(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:87:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<C>(bClass).genericMethod1<A>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:88:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<C>(bClass).genericMethod1<B>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:89:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<C>(bClass).genericMethod1<C>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:91:13: Context: Write to cVariable@468
+ cVariable = GenericExtension(cClass).genericMethod1(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:92:13: Context: Write to cVariable@468
+ cVariable = GenericExtension(cClass).genericMethod1<A>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:93:13: Context: Write to cVariable@468
+ cVariable = GenericExtension(cClass).genericMethod1<B>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:94:13: Context: Write to cVariable@468
+ cVariable = GenericExtension(cClass).genericMethod1<C>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:95:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<A>(cClass).genericMethod1(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:96:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<A>(cClass).genericMethod1<A>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:97:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<A>(cClass).genericMethod1<B>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:98:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<A>(cClass).genericMethod1<C>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:99:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<B>(cClass).genericMethod1(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:100:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<B>(cClass).genericMethod1<A>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:101:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<B>(cClass).genericMethod1<B>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:102:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<B>(cClass).genericMethod1<C>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:103:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<C>(cClass).genericMethod1(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:104:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<C>(cClass).genericMethod1<A>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:105:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<C>(cClass).genericMethod1<B>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/explicit_extension_inference.dart:106:13: Context: Write to cVariable@468
+ cVariable = GenericExtension<C>(cClass).genericMethod1<C>(aVariable);
+ ^
diff --git a/pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart b/pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart
new file mode 100644
index 0000000..d8a4598
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart
@@ -0,0 +1,104 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Class<T extends num> {
+ T field1;
+ T field2;
+
+ Class(this.field1, this.field2);
+}
+
+extension Extension1<T extends num> on Class<T> {
+ static String latestType;
+ T get field {
+ latestType = '$T';
+ return field1;
+ }
+ void set field(T value) {
+ latestType = '$T';
+ field1 = value;
+ }
+ T method() {
+ latestType = '$T';
+ return field1;
+ }
+ T genericMethod<S extends num>(S t) {
+ latestType = '$T:$S';
+ return field1 + t;
+ }
+}
+
+extension Extension2<T extends num> on Class<T> {
+ T get field => field2;
+ void set field(T value) {
+ field2 = value;
+ }
+ T method() => field2;
+ T genericMethod<S extends num>(S t) => field2 + t;
+}
+
+main() {
+ Class<int> c = new Class<int>(42, 87);
+ expect(42, Extension1<num>(c).field);
+ expect('num', Extension1.latestType);
+ expect(42, Extension1<int>(c).field);
+ expect('int', Extension1.latestType);
+ expect(87, Extension2<num>(c).field);
+
+ expect(42, Extension1<num>(c).method());
+ expect('num', Extension1.latestType);
+ expect(42, Extension1<int>(c).method());
+ expect('int', Extension1.latestType);
+ expect(87, Extension2<num>(c).method());
+ var tearOffNumber1 = Extension1<num>(c).method;
+ var tearOffInteger1 = Extension1<int>(c).method;
+ var tearOff2 = Extension2<num>(c).method;
+ expect(42, tearOffNumber1());
+ expect('num', Extension1.latestType);
+ expect(42, tearOffInteger1());
+ expect('int', Extension1.latestType);
+ expect(87, tearOff2());
+ expect(52, Extension1<num>(c).genericMethod(10));
+ expect('num:int', Extension1.latestType);
+ expect(52, Extension1<int>(c).genericMethod(10));
+ expect('int:int', Extension1.latestType);
+ expect(97, Extension2<num>(c).genericMethod(10));
+ expect(52, Extension1<num>(c).genericMethod<num>(10));
+ expect('num:num', Extension1.latestType);
+ expect(52, Extension1<int>(c).genericMethod<num>(10));
+ expect('int:num', Extension1.latestType);
+ expect(97, Extension2<num>(c).genericMethod<num>(10));
+ expect(52, Extension1(c).genericMethod(10));
+ expect('int:int', Extension1.latestType);
+ expect(52, Extension1(c).genericMethod<num>(10));
+ expect('int:num', Extension1.latestType);
+ expect(52, Extension1(c).genericMethod<int>(10));
+ expect('int:int', Extension1.latestType);
+ var genericTearOffNumber1 = Extension1<num>(c).genericMethod;
+ var genericTearOffInteger1 = Extension1<int>(c).genericMethod;
+ var genericTearOff2 = Extension2<num>(c).genericMethod;
+ expect(52, genericTearOffNumber1(10));
+ expect('num:int', Extension1.latestType);
+ expect(52, genericTearOffInteger1(10));
+ expect('int:int', Extension1.latestType);
+ expect(97, genericTearOff2(10));
+ expect(52, genericTearOffNumber1<num>(10));
+ expect('num:num', Extension1.latestType);
+ expect(52, genericTearOffInteger1<num>(10));
+ expect('int:num', Extension1.latestType);
+ expect(97, genericTearOff2<num>(10));
+ expect(23, Extension1<num>(c).field = 23);
+ expect('num', Extension1.latestType);
+ expect(23, Extension1<int>(c).field = 23);
+ expect('int', Extension1.latestType);
+ expect(67, Extension2<num>(c).field = 67);
+ expect(23, Extension1<num>(c).field);
+ expect(67, Extension2<num>(c).field);
+}
+
+expect(expected, actual) {
+ if (expected != actual) {
+ throw 'Mismatch: expected=$expected, actual=$actual';
+ }
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart.outline.expect b/pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart.outline.expect
new file mode 100644
index 0000000..731ecb8
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart.outline.expect
@@ -0,0 +1,56 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class<T extends core::num* = core::num*> extends core::Object {
+ generic-covariant-impl field self::Class::T* field1;
+ generic-covariant-impl field self::Class::T* field2;
+ constructor •(self::Class::T* field1, self::Class::T* field2) → self::Class<self::Class::T*>*
+ ;
+}
+extension Extension1<T extends core::num* = dynamic> on self::Class<T*>* {
+ static field latestType = self::Extension1|latestType;
+ get field = self::Extension1|get#field;
+ method method = self::Extension1|method;
+ tearoff method = self::Extension1|get#method;
+ method genericMethod = self::Extension1|genericMethod;
+ tearoff genericMethod = self::Extension1|get#genericMethod;
+ set field = self::Extension1|set#field;
+}
+extension Extension2<T extends core::num* = dynamic> on self::Class<T*>* {
+ get field = self::Extension2|get#field;
+ method method = self::Extension2|method;
+ tearoff method = self::Extension2|get#method;
+ method genericMethod = self::Extension2|genericMethod;
+ tearoff genericMethod = self::Extension2|get#genericMethod;
+ set field = self::Extension2|set#field;
+}
+static field core::String* Extension1|latestType;
+static method Extension1|get#field<T extends core::num* = dynamic>(final self::Class<self::Extension1|get#field::T*>* #this) → self::Extension1|get#field::T*
+ ;
+static method Extension1|set#field<T extends core::num* = dynamic>(final self::Class<self::Extension1|set#field::T*>* #this, self::Extension1|set#field::T* value) → void
+ ;
+static method Extension1|method<T extends core::num* = dynamic>(final self::Class<self::Extension1|method::T*>* #this) → self::Extension1|method::T*
+ ;
+static method Extension1|get#method<T extends core::num* = dynamic>(final self::Class<self::Extension1|get#method::T*>* #this) → () →* self::Extension1|get#method::T*
+ return () → self::Extension1|get#method::T* => self::Extension1|method<self::Extension1|get#method::T*>(#this);
+static method Extension1|genericMethod<T extends core::num* = dynamic, S extends core::num* = dynamic>(final self::Class<self::Extension1|genericMethod::T*>* #this, self::Extension1|genericMethod::S* t) → self::Extension1|genericMethod::T*
+ ;
+static method Extension1|get#genericMethod<T extends core::num* = dynamic>(final self::Class<self::Extension1|get#genericMethod::T*>* #this) → <S extends core::num* = dynamic>(S*) →* self::Extension1|get#genericMethod::T*
+ return <S extends core::num* = dynamic>(S* t) → self::Extension1|get#genericMethod::T* => self::Extension1|genericMethod<self::Extension1|get#genericMethod::T*, S*>(#this, t);
+static method Extension2|get#field<T extends core::num* = dynamic>(final self::Class<self::Extension2|get#field::T*>* #this) → self::Extension2|get#field::T*
+ ;
+static method Extension2|set#field<T extends core::num* = dynamic>(final self::Class<self::Extension2|set#field::T*>* #this, self::Extension2|set#field::T* value) → void
+ ;
+static method Extension2|method<T extends core::num* = dynamic>(final self::Class<self::Extension2|method::T*>* #this) → self::Extension2|method::T*
+ ;
+static method Extension2|get#method<T extends core::num* = dynamic>(final self::Class<self::Extension2|get#method::T*>* #this) → () →* self::Extension2|get#method::T*
+ return () → self::Extension2|get#method::T* => self::Extension2|method<self::Extension2|get#method::T*>(#this);
+static method Extension2|genericMethod<T extends core::num* = dynamic, S extends core::num* = dynamic>(final self::Class<self::Extension2|genericMethod::T*>* #this, self::Extension2|genericMethod::S* t) → self::Extension2|genericMethod::T*
+ ;
+static method Extension2|get#genericMethod<T extends core::num* = dynamic>(final self::Class<self::Extension2|get#genericMethod::T*>* #this) → <S extends core::num* = dynamic>(S*) →* self::Extension2|get#genericMethod::T*
+ return <S extends core::num* = dynamic>(S* t) → self::Extension2|get#genericMethod::T* => self::Extension2|genericMethod<self::Extension2|get#genericMethod::T*, S*>(#this, t);
+static method main() → dynamic
+ ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+ ;
diff --git a/pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart.strong.expect b/pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart.strong.expect
new file mode 100644
index 0000000..e203cfb
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart.strong.expect
@@ -0,0 +1,128 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class<T extends core::num* = core::num*> extends core::Object {
+ generic-covariant-impl field self::Class::T* field1;
+ generic-covariant-impl field self::Class::T* field2;
+ constructor •(self::Class::T* field1, self::Class::T* field2) → self::Class<self::Class::T*>*
+ : self::Class::field1 = field1, self::Class::field2 = field2, super core::Object::•()
+ ;
+}
+extension Extension1<T extends core::num* = dynamic> on self::Class<T*>* {
+ static field latestType = self::Extension1|latestType;
+ get field = self::Extension1|get#field;
+ method method = self::Extension1|method;
+ tearoff method = self::Extension1|get#method;
+ method genericMethod = self::Extension1|genericMethod;
+ tearoff genericMethod = self::Extension1|get#genericMethod;
+ set field = self::Extension1|set#field;
+}
+extension Extension2<T extends core::num* = dynamic> on self::Class<T*>* {
+ get field = self::Extension2|get#field;
+ method method = self::Extension2|method;
+ tearoff method = self::Extension2|get#method;
+ method genericMethod = self::Extension2|genericMethod;
+ tearoff genericMethod = self::Extension2|get#genericMethod;
+ set field = self::Extension2|set#field;
+}
+static field core::String* Extension1|latestType;
+static method Extension1|get#field<T extends core::num* = dynamic>(final self::Class<self::Extension1|get#field::T*>* #this) → self::Extension1|get#field::T* {
+ self::Extension1|latestType = "${self::Extension1|get#field::T*}";
+ return #this.{self::Class::field1};
+}
+static method Extension1|set#field<T extends core::num* = dynamic>(final self::Class<self::Extension1|set#field::T*>* #this, self::Extension1|set#field::T* value) → self::Extension1|set#field::T* {
+ final self::Extension1|set#field::T* #t1 = value;
+ self::Extension1|latestType = "${self::Extension1|set#field::T*}";
+ #this.{self::Class::field1} = value;
+ return #t1;
+}
+static method Extension1|method<T extends core::num* = dynamic>(final self::Class<self::Extension1|method::T*>* #this) → self::Extension1|method::T* {
+ self::Extension1|latestType = "${self::Extension1|method::T*}";
+ return #this.{self::Class::field1};
+}
+static method Extension1|get#method<T extends core::num* = dynamic>(final self::Class<self::Extension1|get#method::T*>* #this) → () →* self::Extension1|get#method::T*
+ return () → self::Extension1|get#method::T* => self::Extension1|method<self::Extension1|get#method::T*>(#this);
+static method Extension1|genericMethod<T extends core::num* = dynamic, S extends core::num* = dynamic>(final self::Class<self::Extension1|genericMethod::T*>* #this, self::Extension1|genericMethod::S* t) → self::Extension1|genericMethod::T* {
+ self::Extension1|latestType = "${self::Extension1|genericMethod::T*}:${self::Extension1|genericMethod::S*}";
+ return #this.{self::Class::field1}.{core::num::+}(t) as{TypeError} self::Extension1|genericMethod::T*;
+}
+static method Extension1|get#genericMethod<T extends core::num* = dynamic>(final self::Class<self::Extension1|get#genericMethod::T*>* #this) → <S extends core::num* = dynamic>(S*) →* self::Extension1|get#genericMethod::T*
+ return <S extends core::num* = dynamic>(S* t) → self::Extension1|get#genericMethod::T* => self::Extension1|genericMethod<self::Extension1|get#genericMethod::T*, S*>(#this, t);
+static method Extension2|get#field<T extends core::num* = dynamic>(final self::Class<self::Extension2|get#field::T*>* #this) → self::Extension2|get#field::T*
+ return #this.{self::Class::field2};
+static method Extension2|set#field<T extends core::num* = dynamic>(final self::Class<self::Extension2|set#field::T*>* #this, self::Extension2|set#field::T* value) → self::Extension2|set#field::T* {
+ final self::Extension2|set#field::T* #t2 = value;
+ #this.{self::Class::field2} = value;
+ return #t2;
+}
+static method Extension2|method<T extends core::num* = dynamic>(final self::Class<self::Extension2|method::T*>* #this) → self::Extension2|method::T*
+ return #this.{self::Class::field2};
+static method Extension2|get#method<T extends core::num* = dynamic>(final self::Class<self::Extension2|get#method::T*>* #this) → () →* self::Extension2|get#method::T*
+ return () → self::Extension2|get#method::T* => self::Extension2|method<self::Extension2|get#method::T*>(#this);
+static method Extension2|genericMethod<T extends core::num* = dynamic, S extends core::num* = dynamic>(final self::Class<self::Extension2|genericMethod::T*>* #this, self::Extension2|genericMethod::S* t) → self::Extension2|genericMethod::T*
+ return #this.{self::Class::field2}.{core::num::+}(t) as{TypeError} self::Extension2|genericMethod::T*;
+static method Extension2|get#genericMethod<T extends core::num* = dynamic>(final self::Class<self::Extension2|get#genericMethod::T*>* #this) → <S extends core::num* = dynamic>(S*) →* self::Extension2|get#genericMethod::T*
+ return <S extends core::num* = dynamic>(S* t) → self::Extension2|get#genericMethod::T* => self::Extension2|genericMethod<self::Extension2|get#genericMethod::T*, S*>(#this, t);
+static method main() → dynamic {
+ self::Class<core::int*>* c = new self::Class::•<core::int*>(42, 87);
+ self::expect(42, self::Extension1|get#field<core::num*>(c));
+ self::expect("num", self::Extension1|latestType);
+ self::expect(42, self::Extension1|get#field<core::int*>(c));
+ self::expect("int", self::Extension1|latestType);
+ self::expect(87, self::Extension2|get#field<core::num*>(c));
+ self::expect(42, self::Extension1|method<core::num*>(c));
+ self::expect("num", self::Extension1|latestType);
+ self::expect(42, self::Extension1|method<core::int*>(c));
+ self::expect("int", self::Extension1|latestType);
+ self::expect(87, self::Extension2|method<core::num*>(c));
+ () →* core::num* tearOffNumber1 = self::Extension1|get#method<core::num*>(c);
+ () →* core::int* tearOffInteger1 = self::Extension1|get#method<core::int*>(c);
+ () →* core::num* tearOff2 = self::Extension2|get#method<core::num*>(c);
+ self::expect(42, tearOffNumber1.call());
+ self::expect("num", self::Extension1|latestType);
+ self::expect(42, tearOffInteger1.call());
+ self::expect("int", self::Extension1|latestType);
+ self::expect(87, tearOff2.call());
+ self::expect(52, self::Extension1|genericMethod<core::num*, core::int*>(c, 10));
+ self::expect("num:int", self::Extension1|latestType);
+ self::expect(52, self::Extension1|genericMethod<core::int*, core::int*>(c, 10));
+ self::expect("int:int", self::Extension1|latestType);
+ self::expect(97, self::Extension2|genericMethod<core::num*, core::int*>(c, 10));
+ self::expect(52, self::Extension1|genericMethod<core::num*, core::num*>(c, 10));
+ self::expect("num:num", self::Extension1|latestType);
+ self::expect(52, self::Extension1|genericMethod<core::int*, core::num*>(c, 10));
+ self::expect("int:num", self::Extension1|latestType);
+ self::expect(97, self::Extension2|genericMethod<core::num*, core::num*>(c, 10));
+ self::expect(52, self::Extension1|genericMethod<core::int*, core::int*>(c, 10));
+ self::expect("int:int", self::Extension1|latestType);
+ self::expect(52, self::Extension1|genericMethod<core::int*, core::num*>(c, 10));
+ self::expect("int:num", self::Extension1|latestType);
+ self::expect(52, self::Extension1|genericMethod<core::int*, core::int*>(c, 10));
+ self::expect("int:int", self::Extension1|latestType);
+ <S extends core::num* = dynamic>(S*) →* core::num* genericTearOffNumber1 = self::Extension1|get#genericMethod<core::num*>(c);
+ <S extends core::num* = dynamic>(S*) →* core::int* genericTearOffInteger1 = self::Extension1|get#genericMethod<core::int*>(c);
+ <S extends core::num* = dynamic>(S*) →* core::num* genericTearOff2 = self::Extension2|get#genericMethod<core::num*>(c);
+ self::expect(52, genericTearOffNumber1.call<core::int*>(10));
+ self::expect("num:int", self::Extension1|latestType);
+ self::expect(52, genericTearOffInteger1.call<core::int*>(10));
+ self::expect("int:int", self::Extension1|latestType);
+ self::expect(97, genericTearOff2.call<core::int*>(10));
+ self::expect(52, genericTearOffNumber1.call<core::num*>(10));
+ self::expect("num:num", self::Extension1|latestType);
+ self::expect(52, genericTearOffInteger1.call<core::num*>(10));
+ self::expect("int:num", self::Extension1|latestType);
+ self::expect(97, genericTearOff2.call<core::num*>(10));
+ self::expect(23, self::Extension1|set#field<core::num*>(c, 23));
+ self::expect("num", self::Extension1|latestType);
+ self::expect(23, self::Extension1|set#field<core::int*>(c, 23));
+ self::expect("int", self::Extension1|latestType);
+ self::expect(67, self::Extension2|set#field<core::num*>(c, 67));
+ self::expect(23, self::Extension1|get#field<core::num*>(c));
+ self::expect(67, self::Extension2|get#field<core::num*>(c));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!expected.{core::Object::==}(actual)) {
+ throw "Mismatch: expected=${expected}, actual=${actual}";
+ }
+}
diff --git a/pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart.strong.transformed.expect
new file mode 100644
index 0000000..e203cfb
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart.strong.transformed.expect
@@ -0,0 +1,128 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class<T extends core::num* = core::num*> extends core::Object {
+ generic-covariant-impl field self::Class::T* field1;
+ generic-covariant-impl field self::Class::T* field2;
+ constructor •(self::Class::T* field1, self::Class::T* field2) → self::Class<self::Class::T*>*
+ : self::Class::field1 = field1, self::Class::field2 = field2, super core::Object::•()
+ ;
+}
+extension Extension1<T extends core::num* = dynamic> on self::Class<T*>* {
+ static field latestType = self::Extension1|latestType;
+ get field = self::Extension1|get#field;
+ method method = self::Extension1|method;
+ tearoff method = self::Extension1|get#method;
+ method genericMethod = self::Extension1|genericMethod;
+ tearoff genericMethod = self::Extension1|get#genericMethod;
+ set field = self::Extension1|set#field;
+}
+extension Extension2<T extends core::num* = dynamic> on self::Class<T*>* {
+ get field = self::Extension2|get#field;
+ method method = self::Extension2|method;
+ tearoff method = self::Extension2|get#method;
+ method genericMethod = self::Extension2|genericMethod;
+ tearoff genericMethod = self::Extension2|get#genericMethod;
+ set field = self::Extension2|set#field;
+}
+static field core::String* Extension1|latestType;
+static method Extension1|get#field<T extends core::num* = dynamic>(final self::Class<self::Extension1|get#field::T*>* #this) → self::Extension1|get#field::T* {
+ self::Extension1|latestType = "${self::Extension1|get#field::T*}";
+ return #this.{self::Class::field1};
+}
+static method Extension1|set#field<T extends core::num* = dynamic>(final self::Class<self::Extension1|set#field::T*>* #this, self::Extension1|set#field::T* value) → self::Extension1|set#field::T* {
+ final self::Extension1|set#field::T* #t1 = value;
+ self::Extension1|latestType = "${self::Extension1|set#field::T*}";
+ #this.{self::Class::field1} = value;
+ return #t1;
+}
+static method Extension1|method<T extends core::num* = dynamic>(final self::Class<self::Extension1|method::T*>* #this) → self::Extension1|method::T* {
+ self::Extension1|latestType = "${self::Extension1|method::T*}";
+ return #this.{self::Class::field1};
+}
+static method Extension1|get#method<T extends core::num* = dynamic>(final self::Class<self::Extension1|get#method::T*>* #this) → () →* self::Extension1|get#method::T*
+ return () → self::Extension1|get#method::T* => self::Extension1|method<self::Extension1|get#method::T*>(#this);
+static method Extension1|genericMethod<T extends core::num* = dynamic, S extends core::num* = dynamic>(final self::Class<self::Extension1|genericMethod::T*>* #this, self::Extension1|genericMethod::S* t) → self::Extension1|genericMethod::T* {
+ self::Extension1|latestType = "${self::Extension1|genericMethod::T*}:${self::Extension1|genericMethod::S*}";
+ return #this.{self::Class::field1}.{core::num::+}(t) as{TypeError} self::Extension1|genericMethod::T*;
+}
+static method Extension1|get#genericMethod<T extends core::num* = dynamic>(final self::Class<self::Extension1|get#genericMethod::T*>* #this) → <S extends core::num* = dynamic>(S*) →* self::Extension1|get#genericMethod::T*
+ return <S extends core::num* = dynamic>(S* t) → self::Extension1|get#genericMethod::T* => self::Extension1|genericMethod<self::Extension1|get#genericMethod::T*, S*>(#this, t);
+static method Extension2|get#field<T extends core::num* = dynamic>(final self::Class<self::Extension2|get#field::T*>* #this) → self::Extension2|get#field::T*
+ return #this.{self::Class::field2};
+static method Extension2|set#field<T extends core::num* = dynamic>(final self::Class<self::Extension2|set#field::T*>* #this, self::Extension2|set#field::T* value) → self::Extension2|set#field::T* {
+ final self::Extension2|set#field::T* #t2 = value;
+ #this.{self::Class::field2} = value;
+ return #t2;
+}
+static method Extension2|method<T extends core::num* = dynamic>(final self::Class<self::Extension2|method::T*>* #this) → self::Extension2|method::T*
+ return #this.{self::Class::field2};
+static method Extension2|get#method<T extends core::num* = dynamic>(final self::Class<self::Extension2|get#method::T*>* #this) → () →* self::Extension2|get#method::T*
+ return () → self::Extension2|get#method::T* => self::Extension2|method<self::Extension2|get#method::T*>(#this);
+static method Extension2|genericMethod<T extends core::num* = dynamic, S extends core::num* = dynamic>(final self::Class<self::Extension2|genericMethod::T*>* #this, self::Extension2|genericMethod::S* t) → self::Extension2|genericMethod::T*
+ return #this.{self::Class::field2}.{core::num::+}(t) as{TypeError} self::Extension2|genericMethod::T*;
+static method Extension2|get#genericMethod<T extends core::num* = dynamic>(final self::Class<self::Extension2|get#genericMethod::T*>* #this) → <S extends core::num* = dynamic>(S*) →* self::Extension2|get#genericMethod::T*
+ return <S extends core::num* = dynamic>(S* t) → self::Extension2|get#genericMethod::T* => self::Extension2|genericMethod<self::Extension2|get#genericMethod::T*, S*>(#this, t);
+static method main() → dynamic {
+ self::Class<core::int*>* c = new self::Class::•<core::int*>(42, 87);
+ self::expect(42, self::Extension1|get#field<core::num*>(c));
+ self::expect("num", self::Extension1|latestType);
+ self::expect(42, self::Extension1|get#field<core::int*>(c));
+ self::expect("int", self::Extension1|latestType);
+ self::expect(87, self::Extension2|get#field<core::num*>(c));
+ self::expect(42, self::Extension1|method<core::num*>(c));
+ self::expect("num", self::Extension1|latestType);
+ self::expect(42, self::Extension1|method<core::int*>(c));
+ self::expect("int", self::Extension1|latestType);
+ self::expect(87, self::Extension2|method<core::num*>(c));
+ () →* core::num* tearOffNumber1 = self::Extension1|get#method<core::num*>(c);
+ () →* core::int* tearOffInteger1 = self::Extension1|get#method<core::int*>(c);
+ () →* core::num* tearOff2 = self::Extension2|get#method<core::num*>(c);
+ self::expect(42, tearOffNumber1.call());
+ self::expect("num", self::Extension1|latestType);
+ self::expect(42, tearOffInteger1.call());
+ self::expect("int", self::Extension1|latestType);
+ self::expect(87, tearOff2.call());
+ self::expect(52, self::Extension1|genericMethod<core::num*, core::int*>(c, 10));
+ self::expect("num:int", self::Extension1|latestType);
+ self::expect(52, self::Extension1|genericMethod<core::int*, core::int*>(c, 10));
+ self::expect("int:int", self::Extension1|latestType);
+ self::expect(97, self::Extension2|genericMethod<core::num*, core::int*>(c, 10));
+ self::expect(52, self::Extension1|genericMethod<core::num*, core::num*>(c, 10));
+ self::expect("num:num", self::Extension1|latestType);
+ self::expect(52, self::Extension1|genericMethod<core::int*, core::num*>(c, 10));
+ self::expect("int:num", self::Extension1|latestType);
+ self::expect(97, self::Extension2|genericMethod<core::num*, core::num*>(c, 10));
+ self::expect(52, self::Extension1|genericMethod<core::int*, core::int*>(c, 10));
+ self::expect("int:int", self::Extension1|latestType);
+ self::expect(52, self::Extension1|genericMethod<core::int*, core::num*>(c, 10));
+ self::expect("int:num", self::Extension1|latestType);
+ self::expect(52, self::Extension1|genericMethod<core::int*, core::int*>(c, 10));
+ self::expect("int:int", self::Extension1|latestType);
+ <S extends core::num* = dynamic>(S*) →* core::num* genericTearOffNumber1 = self::Extension1|get#genericMethod<core::num*>(c);
+ <S extends core::num* = dynamic>(S*) →* core::int* genericTearOffInteger1 = self::Extension1|get#genericMethod<core::int*>(c);
+ <S extends core::num* = dynamic>(S*) →* core::num* genericTearOff2 = self::Extension2|get#genericMethod<core::num*>(c);
+ self::expect(52, genericTearOffNumber1.call<core::int*>(10));
+ self::expect("num:int", self::Extension1|latestType);
+ self::expect(52, genericTearOffInteger1.call<core::int*>(10));
+ self::expect("int:int", self::Extension1|latestType);
+ self::expect(97, genericTearOff2.call<core::int*>(10));
+ self::expect(52, genericTearOffNumber1.call<core::num*>(10));
+ self::expect("num:num", self::Extension1|latestType);
+ self::expect(52, genericTearOffInteger1.call<core::num*>(10));
+ self::expect("int:num", self::Extension1|latestType);
+ self::expect(97, genericTearOff2.call<core::num*>(10));
+ self::expect(23, self::Extension1|set#field<core::num*>(c, 23));
+ self::expect("num", self::Extension1|latestType);
+ self::expect(23, self::Extension1|set#field<core::int*>(c, 23));
+ self::expect("int", self::Extension1|latestType);
+ self::expect(67, self::Extension2|set#field<core::num*>(c, 67));
+ self::expect(23, self::Extension1|get#field<core::num*>(c));
+ self::expect(67, self::Extension2|get#field<core::num*>(c));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!expected.{core::Object::==}(actual)) {
+ throw "Mismatch: expected=${expected}, actual=${actual}";
+ }
+}
diff --git a/pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart.type_promotion.expect b/pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart.type_promotion.expect
new file mode 100644
index 0000000..b4cc663
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart.type_promotion.expect
@@ -0,0 +1,12 @@
+pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart:15:16: Context: Write to latestType@375
+ latestType = '$T';
+ ^
+pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart:19:16: Context: Write to latestType@375
+ latestType = '$T';
+ ^
+pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart:23:16: Context: Write to latestType@375
+ latestType = '$T';
+ ^
+pkg/front_end/testcases/extensions/explicit_generic_extension_access.dart:27:16: Context: Write to latestType@375
+ latestType = '$T:$S';
+ ^
diff --git a/pkg/front_end/testcases/extensions/explicit_this.dart.outline.expect b/pkg/front_end/testcases/extensions/explicit_this.dart.outline.expect
index 0819186..ccf3c26 100644
--- a/pkg/front_end/testcases/extensions/explicit_this.dart.outline.expect
+++ b/pkg/front_end/testcases/extensions/explicit_this.dart.outline.expect
@@ -11,14 +11,23 @@
}
extension A2 on self::A1* {
method method2 = self::A2|method2;
+ tearoff method2 = self::A2|get#method2;
method method3 = self::A2|method3;
+ tearoff method3 = self::A2|get#method3;
method method4 = self::A2|method4;
+ tearoff method4 = self::A2|get#method4;
}
static method A2|method2(final self::A1* #this) → void
;
+static method A2|get#method2(final self::A1* #this) → () →* void
+ return () → void => self::A2|method2(#this);
static method A2|method3(final self::A1* #this) → core::Object*
;
+static method A2|get#method3(final self::A1* #this) → () →* core::Object*
+ return () → core::Object* => self::A2|method3(#this);
static method A2|method4(final self::A1* #this, core::Object* o) → void
;
+static method A2|get#method4(final self::A1* #this) → (core::Object*) →* void
+ return (core::Object* o) → void => self::A2|method4(#this, o);
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/extensions/explicit_this.dart.strong.expect b/pkg/front_end/testcases/extensions/explicit_this.dart.strong.expect
index 0ea07bf..b1249bd 100644
--- a/pkg/front_end/testcases/extensions/explicit_this.dart.strong.expect
+++ b/pkg/front_end/testcases/extensions/explicit_this.dart.strong.expect
@@ -11,14 +11,23 @@
}
extension A2 on self::A1* {
method method2 = self::A2|method2;
+ tearoff method2 = self::A2|get#method2;
method method3 = self::A2|method3;
+ tearoff method3 = self::A2|get#method3;
method method4 = self::A2|method4;
+ tearoff method4 = self::A2|get#method4;
}
static method A2|method2(final self::A1* #this) → void
return #this.{self::A1::method1}();
+static method A2|get#method2(final self::A1* #this) → () →* void
+ return () → void => self::A2|method2(#this);
static method A2|method3(final self::A1* #this) → core::Object*
return #this.{self::A1::field};
+static method A2|get#method3(final self::A1* #this) → () →* core::Object*
+ return () → core::Object* => self::A2|method3(#this);
static method A2|method4(final self::A1* #this, core::Object* o) → void {
#this.{self::A1::field} = o;
}
+static method A2|get#method4(final self::A1* #this) → (core::Object*) →* void
+ return (core::Object* o) → void => self::A2|method4(#this, o);
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extensions/explicit_this.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/explicit_this.dart.strong.transformed.expect
index 0ea07bf..b1249bd 100644
--- a/pkg/front_end/testcases/extensions/explicit_this.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/extensions/explicit_this.dart.strong.transformed.expect
@@ -11,14 +11,23 @@
}
extension A2 on self::A1* {
method method2 = self::A2|method2;
+ tearoff method2 = self::A2|get#method2;
method method3 = self::A2|method3;
+ tearoff method3 = self::A2|get#method3;
method method4 = self::A2|method4;
+ tearoff method4 = self::A2|get#method4;
}
static method A2|method2(final self::A1* #this) → void
return #this.{self::A1::method1}();
+static method A2|get#method2(final self::A1* #this) → () →* void
+ return () → void => self::A2|method2(#this);
static method A2|method3(final self::A1* #this) → core::Object*
return #this.{self::A1::field};
+static method A2|get#method3(final self::A1* #this) → () →* core::Object*
+ return () → core::Object* => self::A2|method3(#this);
static method A2|method4(final self::A1* #this, core::Object* o) → void {
#this.{self::A1::field} = o;
}
+static method A2|get#method4(final self::A1* #this) → (core::Object*) →* void
+ return (core::Object* o) → void => self::A2|method4(#this, o);
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extensions/extension_methods.dart.strong.expect b/pkg/front_end/testcases/extensions/extension_methods.dart.strong.expect
index ebd3f24..b1e71de 100644
--- a/pkg/front_end/testcases/extensions/extension_methods.dart.strong.expect
+++ b/pkg/front_end/testcases/extensions/extension_methods.dart.strong.expect
@@ -1,13 +1,4 @@
library;
-//
-// Problems in library:
-//
-// pkg/front_end/testcases/extensions/extension_methods.dart:19:26: Error: The getter 'two' isn't defined for the class 'C'.
-// - 'C' is from 'pkg/front_end/testcases/extensions/extension_methods.dart'.
-// Try correcting the name to the name of an existing getter, or defining a getter or field named 'two'.
-// var result = c.one + c.two;
-// ^^^
-//
import self as self;
import "dart:core" as core;
import "package:expect/expect.dart" as exp;
@@ -28,10 +19,6 @@
return 2;
static method main() → dynamic {
self::C* c = new self::C::•();
- core::num* result = c.{self::C::one}.{core::num::+}(invalid-expression "pkg/front_end/testcases/extensions/extension_methods.dart:19:26: Error: The getter 'two' isn't defined for the class 'C'.
- - 'C' is from 'pkg/front_end/testcases/extensions/extension_methods.dart'.
-Try correcting the name to the name of an existing getter, or defining a getter or field named 'two'.
- var result = c.one + c.two;
- ^^^" as{TypeError} core::num*);
+ core::int* result = c.{self::C::one}.{core::num::+}(self::E|get#two(c));
exp::Expect::equals(result, 3);
}
diff --git a/pkg/front_end/testcases/extensions/extension_methods.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/extension_methods.dart.strong.transformed.expect
index ebd3f24..b1e71de 100644
--- a/pkg/front_end/testcases/extensions/extension_methods.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/extensions/extension_methods.dart.strong.transformed.expect
@@ -1,13 +1,4 @@
library;
-//
-// Problems in library:
-//
-// pkg/front_end/testcases/extensions/extension_methods.dart:19:26: Error: The getter 'two' isn't defined for the class 'C'.
-// - 'C' is from 'pkg/front_end/testcases/extensions/extension_methods.dart'.
-// Try correcting the name to the name of an existing getter, or defining a getter or field named 'two'.
-// var result = c.one + c.two;
-// ^^^
-//
import self as self;
import "dart:core" as core;
import "package:expect/expect.dart" as exp;
@@ -28,10 +19,6 @@
return 2;
static method main() → dynamic {
self::C* c = new self::C::•();
- core::num* result = c.{self::C::one}.{core::num::+}(invalid-expression "pkg/front_end/testcases/extensions/extension_methods.dart:19:26: Error: The getter 'two' isn't defined for the class 'C'.
- - 'C' is from 'pkg/front_end/testcases/extensions/extension_methods.dart'.
-Try correcting the name to the name of an existing getter, or defining a getter or field named 'two'.
- var result = c.one + c.two;
- ^^^" as{TypeError} core::num*);
+ core::int* result = c.{self::C::one}.{core::num::+}(self::E|get#two(c));
exp::Expect::equals(result, 3);
}
diff --git a/pkg/front_end/testcases/extensions/implicit_extension_inference.dart b/pkg/front_end/testcases/extensions/implicit_extension_inference.dart
new file mode 100644
index 0000000..fe69fc8
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/implicit_extension_inference.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class A {}
+class B extends A {}
+class C extends B {}
+
+class GenericClass<T> {}
+
+extension GenericExtension<T> on GenericClass<T> {
+ T get property => null;
+
+ T method(T t) => null;
+
+ S genericMethod1<S>(S s) => null;
+}
+
+main() {
+ A aVariable;
+ C cVariable;
+
+ GenericClass<A> aClass;
+ GenericClass<B> bClass;
+ GenericClass<C> cClass;
+
+ cVariable = aClass.property;
+ cVariable = bClass.property;
+ aVariable = cClass.property;
+
+ cVariable = aClass.method(aVariable);
+ cVariable = bClass.method(aVariable);
+ aVariable = cClass.method(aVariable);
+
+ cVariable = aClass.genericMethod1(aVariable);
+ cVariable = aClass.genericMethod1<A>(aVariable);
+ cVariable = aClass.genericMethod1<B>(aVariable);
+ cVariable = aClass.genericMethod1<C>(aVariable);
+
+ cVariable = bClass.genericMethod1(aVariable);
+ cVariable = bClass.genericMethod1<A>(aVariable);
+ cVariable = bClass.genericMethod1<B>(aVariable);
+ cVariable = bClass.genericMethod1<C>(aVariable);
+
+ cVariable = cClass.genericMethod1(aVariable);
+ cVariable = cClass.genericMethod1<A>(aVariable);
+ cVariable = cClass.genericMethod1<B>(aVariable);
+ cVariable = cClass.genericMethod1<C>(aVariable);
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/implicit_extension_inference.dart.outline.expect b/pkg/front_end/testcases/extensions/implicit_extension_inference.dart.outline.expect
new file mode 100644
index 0000000..b09bea2
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/implicit_extension_inference.dart.outline.expect
@@ -0,0 +1,39 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ synthetic constructor •() → self::A*
+ ;
+}
+class B extends self::A {
+ synthetic constructor •() → self::B*
+ ;
+}
+class C extends self::B {
+ synthetic constructor •() → self::C*
+ ;
+}
+class GenericClass<T extends core::Object* = dynamic> extends core::Object {
+ synthetic constructor •() → self::GenericClass<self::GenericClass::T*>*
+ ;
+}
+extension GenericExtension<T extends core::Object* = dynamic> on self::GenericClass<T*>* {
+ get property = self::GenericExtension|get#property;
+ method method = self::GenericExtension|method;
+ tearoff method = self::GenericExtension|get#method;
+ method genericMethod1 = self::GenericExtension|genericMethod1;
+ tearoff genericMethod1 = self::GenericExtension|get#genericMethod1;
+}
+static method GenericExtension|get#property<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#property::T*>* #this) → self::GenericExtension|get#property::T*
+ ;
+static method GenericExtension|method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|method::T*>* #this, self::GenericExtension|method::T* t) → self::GenericExtension|method::T*
+ ;
+static method GenericExtension|get#method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#method::T*>* #this) → (self::GenericExtension|get#method::T*) →* self::GenericExtension|get#method::T*
+ return (self::GenericExtension|get#method::T* t) → self::GenericExtension|get#method::T* => self::GenericExtension|method<self::GenericExtension|get#method::T*>(#this, t);
+static method GenericExtension|genericMethod1<T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|genericMethod1::T*>* #this, self::GenericExtension|genericMethod1::S* s) → self::GenericExtension|genericMethod1::S*
+ ;
+static method GenericExtension|get#genericMethod1<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#genericMethod1::T*>* #this) → <S extends core::Object* = dynamic>(S*) →* S*
+ return <S extends core::Object* = dynamic>(S* s) → S* => self::GenericExtension|genericMethod1<self::GenericExtension|get#genericMethod1::T*, S*>(#this, s);
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/extensions/implicit_extension_inference.dart.strong.expect b/pkg/front_end/testcases/extensions/implicit_extension_inference.dart.strong.expect
new file mode 100644
index 0000000..1bf8085
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/implicit_extension_inference.dart.strong.expect
@@ -0,0 +1,66 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ synthetic constructor •() → self::A*
+ : super core::Object::•()
+ ;
+}
+class B extends self::A {
+ synthetic constructor •() → self::B*
+ : super self::A::•()
+ ;
+}
+class C extends self::B {
+ synthetic constructor •() → self::C*
+ : super self::B::•()
+ ;
+}
+class GenericClass<T extends core::Object* = dynamic> extends core::Object {
+ synthetic constructor •() → self::GenericClass<self::GenericClass::T*>*
+ : super core::Object::•()
+ ;
+}
+extension GenericExtension<T extends core::Object* = dynamic> on self::GenericClass<T*>* {
+ get property = self::GenericExtension|get#property;
+ method method = self::GenericExtension|method;
+ tearoff method = self::GenericExtension|get#method;
+ method genericMethod1 = self::GenericExtension|genericMethod1;
+ tearoff genericMethod1 = self::GenericExtension|get#genericMethod1;
+}
+static method GenericExtension|get#property<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#property::T*>* #this) → self::GenericExtension|get#property::T*
+ return null;
+static method GenericExtension|method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|method::T*>* #this, self::GenericExtension|method::T* t) → self::GenericExtension|method::T*
+ return null;
+static method GenericExtension|get#method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#method::T*>* #this) → (self::GenericExtension|get#method::T*) →* self::GenericExtension|get#method::T*
+ return (self::GenericExtension|get#method::T* t) → self::GenericExtension|get#method::T* => self::GenericExtension|method<self::GenericExtension|get#method::T*>(#this, t);
+static method GenericExtension|genericMethod1<T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|genericMethod1::T*>* #this, self::GenericExtension|genericMethod1::S* s) → self::GenericExtension|genericMethod1::S*
+ return null;
+static method GenericExtension|get#genericMethod1<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#genericMethod1::T*>* #this) → <S extends core::Object* = dynamic>(S*) →* S*
+ return <S extends core::Object* = dynamic>(S* s) → S* => self::GenericExtension|genericMethod1<self::GenericExtension|get#genericMethod1::T*, S*>(#this, s);
+static method main() → dynamic {
+ self::A* aVariable;
+ self::C* cVariable;
+ self::GenericClass<self::A*>* aClass;
+ self::GenericClass<self::B*>* bClass;
+ self::GenericClass<self::C*>* cClass;
+ cVariable = self::GenericExtension|get#property<self::A*>(aClass) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|get#property<self::B*>(bClass) as{TypeError} self::C*;
+ aVariable = self::GenericExtension|get#property<self::C*>(cClass);
+ cVariable = self::GenericExtension|method<self::A*>(aClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|method<self::B*>(bClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ aVariable = self::GenericExtension|method<self::C*>(cClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(aClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::A*>(aClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::B*>(aClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(aClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::A*>(bClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::B*>(bClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::A*>(cClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::B*>(cClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+}
diff --git a/pkg/front_end/testcases/extensions/implicit_extension_inference.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/implicit_extension_inference.dart.strong.transformed.expect
new file mode 100644
index 0000000..1bf8085
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/implicit_extension_inference.dart.strong.transformed.expect
@@ -0,0 +1,66 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ synthetic constructor •() → self::A*
+ : super core::Object::•()
+ ;
+}
+class B extends self::A {
+ synthetic constructor •() → self::B*
+ : super self::A::•()
+ ;
+}
+class C extends self::B {
+ synthetic constructor •() → self::C*
+ : super self::B::•()
+ ;
+}
+class GenericClass<T extends core::Object* = dynamic> extends core::Object {
+ synthetic constructor •() → self::GenericClass<self::GenericClass::T*>*
+ : super core::Object::•()
+ ;
+}
+extension GenericExtension<T extends core::Object* = dynamic> on self::GenericClass<T*>* {
+ get property = self::GenericExtension|get#property;
+ method method = self::GenericExtension|method;
+ tearoff method = self::GenericExtension|get#method;
+ method genericMethod1 = self::GenericExtension|genericMethod1;
+ tearoff genericMethod1 = self::GenericExtension|get#genericMethod1;
+}
+static method GenericExtension|get#property<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#property::T*>* #this) → self::GenericExtension|get#property::T*
+ return null;
+static method GenericExtension|method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|method::T*>* #this, self::GenericExtension|method::T* t) → self::GenericExtension|method::T*
+ return null;
+static method GenericExtension|get#method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#method::T*>* #this) → (self::GenericExtension|get#method::T*) →* self::GenericExtension|get#method::T*
+ return (self::GenericExtension|get#method::T* t) → self::GenericExtension|get#method::T* => self::GenericExtension|method<self::GenericExtension|get#method::T*>(#this, t);
+static method GenericExtension|genericMethod1<T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|genericMethod1::T*>* #this, self::GenericExtension|genericMethod1::S* s) → self::GenericExtension|genericMethod1::S*
+ return null;
+static method GenericExtension|get#genericMethod1<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#genericMethod1::T*>* #this) → <S extends core::Object* = dynamic>(S*) →* S*
+ return <S extends core::Object* = dynamic>(S* s) → S* => self::GenericExtension|genericMethod1<self::GenericExtension|get#genericMethod1::T*, S*>(#this, s);
+static method main() → dynamic {
+ self::A* aVariable;
+ self::C* cVariable;
+ self::GenericClass<self::A*>* aClass;
+ self::GenericClass<self::B*>* bClass;
+ self::GenericClass<self::C*>* cClass;
+ cVariable = self::GenericExtension|get#property<self::A*>(aClass) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|get#property<self::B*>(bClass) as{TypeError} self::C*;
+ aVariable = self::GenericExtension|get#property<self::C*>(cClass);
+ cVariable = self::GenericExtension|method<self::A*>(aClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|method<self::B*>(bClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ aVariable = self::GenericExtension|method<self::C*>(cClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(aClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::A*>(aClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::B*>(aClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::A*, self::C*>(aClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::A*>(bClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::B*>(bClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::B*, self::C*>(bClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::A*>(cClass, aVariable) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::B*>(cClass, aVariable as{TypeError} self::B*) as{TypeError} self::C*;
+ cVariable = self::GenericExtension|genericMethod1<self::C*, self::C*>(cClass, aVariable as{TypeError} self::C*);
+}
diff --git a/pkg/front_end/testcases/extensions/implicit_extension_inference.dart.type_promotion.expect b/pkg/front_end/testcases/extensions/implicit_extension_inference.dart.type_promotion.expect
new file mode 100644
index 0000000..c086585
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/implicit_extension_inference.dart.type_promotion.expect
@@ -0,0 +1,54 @@
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:27:13: Context: Write to cVariable@468
+ cVariable = aClass.property;
+ ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:28:13: Context: Write to cVariable@468
+ cVariable = bClass.property;
+ ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:29:13: Context: Write to aVariable@453
+ aVariable = cClass.property;
+ ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:31:13: Context: Write to cVariable@468
+ cVariable = aClass.method(aVariable);
+ ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:32:13: Context: Write to cVariable@468
+ cVariable = bClass.method(aVariable);
+ ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:33:13: Context: Write to aVariable@453
+ aVariable = cClass.method(aVariable);
+ ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:35:13: Context: Write to cVariable@468
+ cVariable = aClass.genericMethod1(aVariable);
+ ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:36:13: Context: Write to cVariable@468
+ cVariable = aClass.genericMethod1<A>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:37:13: Context: Write to cVariable@468
+ cVariable = aClass.genericMethod1<B>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:38:13: Context: Write to cVariable@468
+ cVariable = aClass.genericMethod1<C>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:40:13: Context: Write to cVariable@468
+ cVariable = bClass.genericMethod1(aVariable);
+ ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:41:13: Context: Write to cVariable@468
+ cVariable = bClass.genericMethod1<A>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:42:13: Context: Write to cVariable@468
+ cVariable = bClass.genericMethod1<B>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:43:13: Context: Write to cVariable@468
+ cVariable = bClass.genericMethod1<C>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:45:13: Context: Write to cVariable@468
+ cVariable = cClass.genericMethod1(aVariable);
+ ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:46:13: Context: Write to cVariable@468
+ cVariable = cClass.genericMethod1<A>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:47:13: Context: Write to cVariable@468
+ cVariable = cClass.genericMethod1<B>(aVariable);
+ ^
+pkg/front_end/testcases/extensions/implicit_extension_inference.dart:48:13: Context: Write to cVariable@468
+ cVariable = cClass.genericMethod1<C>(aVariable);
+ ^
diff --git a/pkg/front_end/testcases/extensions/implicit_this.dart.outline.expect b/pkg/front_end/testcases/extensions/implicit_this.dart.outline.expect
index 0819186..ccf3c26 100644
--- a/pkg/front_end/testcases/extensions/implicit_this.dart.outline.expect
+++ b/pkg/front_end/testcases/extensions/implicit_this.dart.outline.expect
@@ -11,14 +11,23 @@
}
extension A2 on self::A1* {
method method2 = self::A2|method2;
+ tearoff method2 = self::A2|get#method2;
method method3 = self::A2|method3;
+ tearoff method3 = self::A2|get#method3;
method method4 = self::A2|method4;
+ tearoff method4 = self::A2|get#method4;
}
static method A2|method2(final self::A1* #this) → void
;
+static method A2|get#method2(final self::A1* #this) → () →* void
+ return () → void => self::A2|method2(#this);
static method A2|method3(final self::A1* #this) → core::Object*
;
+static method A2|get#method3(final self::A1* #this) → () →* core::Object*
+ return () → core::Object* => self::A2|method3(#this);
static method A2|method4(final self::A1* #this, core::Object* o) → void
;
+static method A2|get#method4(final self::A1* #this) → (core::Object*) →* void
+ return (core::Object* o) → void => self::A2|method4(#this, o);
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/extensions/implicit_this.dart.strong.expect b/pkg/front_end/testcases/extensions/implicit_this.dart.strong.expect
index 0ea07bf..b1249bd 100644
--- a/pkg/front_end/testcases/extensions/implicit_this.dart.strong.expect
+++ b/pkg/front_end/testcases/extensions/implicit_this.dart.strong.expect
@@ -11,14 +11,23 @@
}
extension A2 on self::A1* {
method method2 = self::A2|method2;
+ tearoff method2 = self::A2|get#method2;
method method3 = self::A2|method3;
+ tearoff method3 = self::A2|get#method3;
method method4 = self::A2|method4;
+ tearoff method4 = self::A2|get#method4;
}
static method A2|method2(final self::A1* #this) → void
return #this.{self::A1::method1}();
+static method A2|get#method2(final self::A1* #this) → () →* void
+ return () → void => self::A2|method2(#this);
static method A2|method3(final self::A1* #this) → core::Object*
return #this.{self::A1::field};
+static method A2|get#method3(final self::A1* #this) → () →* core::Object*
+ return () → core::Object* => self::A2|method3(#this);
static method A2|method4(final self::A1* #this, core::Object* o) → void {
#this.{self::A1::field} = o;
}
+static method A2|get#method4(final self::A1* #this) → (core::Object*) →* void
+ return (core::Object* o) → void => self::A2|method4(#this, o);
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extensions/implicit_this.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/implicit_this.dart.strong.transformed.expect
index 0ea07bf..b1249bd 100644
--- a/pkg/front_end/testcases/extensions/implicit_this.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/extensions/implicit_this.dart.strong.transformed.expect
@@ -11,14 +11,23 @@
}
extension A2 on self::A1* {
method method2 = self::A2|method2;
+ tearoff method2 = self::A2|get#method2;
method method3 = self::A2|method3;
+ tearoff method3 = self::A2|get#method3;
method method4 = self::A2|method4;
+ tearoff method4 = self::A2|get#method4;
}
static method A2|method2(final self::A1* #this) → void
return #this.{self::A1::method1}();
+static method A2|get#method2(final self::A1* #this) → () →* void
+ return () → void => self::A2|method2(#this);
static method A2|method3(final self::A1* #this) → core::Object*
return #this.{self::A1::field};
+static method A2|get#method3(final self::A1* #this) → () →* core::Object*
+ return () → core::Object* => self::A2|method3(#this);
static method A2|method4(final self::A1* #this, core::Object* o) → void {
#this.{self::A1::field} = o;
}
+static method A2|get#method4(final self::A1* #this) → (core::Object*) →* void
+ return (core::Object* o) → void => self::A2|method4(#this, o);
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extensions/index.dart b/pkg/front_end/testcases/extensions/index.dart
new file mode 100644
index 0000000..f34eac8
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/index.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class MapLike<K, V> {
+ final Map<K, V> _map = {};
+
+ V get(Object key) => _map[key];
+ V put(K key, V value) => _map[key] = value;
+}
+
+extension Extension<K, V> on MapLike<K, V> {
+ V operator [](Object key) => get(key);
+ void operator []=(K key, V value) => put(key, value);
+}
+
+main() {
+ MapLike<int, String> map1 = new MapLike();
+ expect(null, map1[0]);
+ map1.put(0, '0');
+ expect('0', map1[0]);
+ expect(null, map1[1]);
+ expect('1', map1[1] = '1');
+ expect('1', map1[1]);
+}
+
+expect(expected, actual) {
+ if (expected != actual) {
+ throw 'Mismatch: expected=$expected, actual=$actual';
+ }
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/index.dart.outline.expect b/pkg/front_end/testcases/extensions/index.dart.outline.expect
new file mode 100644
index 0000000..c9b2e9d
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/index.dart.outline.expect
@@ -0,0 +1,25 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class MapLike<K extends core::Object* = dynamic, V extends core::Object* = dynamic> extends core::Object {
+ final field core::Map<self::MapLike::K*, self::MapLike::V*>* _map;
+ synthetic constructor •() → self::MapLike<self::MapLike::K*, self::MapLike::V*>*
+ ;
+ method get(core::Object* key) → self::MapLike::V*
+ ;
+ method put(generic-covariant-impl self::MapLike::K* key, generic-covariant-impl self::MapLike::V* value) → self::MapLike::V*
+ ;
+}
+extension Extension<K extends core::Object* = dynamic, V extends core::Object* = dynamic> on self::MapLike<K*, V*>* {
+ operator [] = self::Extension|[];
+ operator []= = self::Extension|[]=;
+}
+static method Extension|[]<K extends core::Object* = dynamic, V extends core::Object* = dynamic>(final self::MapLike<self::Extension|[]::K*, self::Extension|[]::V*>* #this, core::Object* key) → self::Extension|[]::V*
+ ;
+static method Extension|[]=<K extends core::Object* = dynamic, V extends core::Object* = dynamic>(final self::MapLike<self::Extension|[]=::K*, self::Extension|[]=::V*>* #this, self::Extension|[]=::K* key, self::Extension|[]=::V* value) → void
+ ;
+static method main() → dynamic
+ ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+ ;
diff --git a/pkg/front_end/testcases/extensions/index.dart.strong.expect b/pkg/front_end/testcases/extensions/index.dart.strong.expect
new file mode 100644
index 0000000..70bdb38
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/index.dart.strong.expect
@@ -0,0 +1,36 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class MapLike<K extends core::Object* = dynamic, V extends core::Object* = dynamic> extends core::Object {
+ final field core::Map<self::MapLike::K*, self::MapLike::V*>* _map = <self::MapLike::K*, self::MapLike::V*>{};
+ synthetic constructor •() → self::MapLike<self::MapLike::K*, self::MapLike::V*>*
+ : super core::Object::•()
+ ;
+ method get(core::Object* key) → self::MapLike::V*
+ return this.{self::MapLike::_map}.{core::Map::[]}(key);
+ method put(generic-covariant-impl self::MapLike::K* key, generic-covariant-impl self::MapLike::V* value) → self::MapLike::V*
+ return let final core::Map<self::MapLike::K*, self::MapLike::V*>* #t1 = this.{self::MapLike::_map} in let final self::MapLike::K* #t2 = key in let final self::MapLike::V* #t3 = value in let final void #t4 = #t1.{core::Map::[]=}(#t2, #t3) in #t3;
+}
+extension Extension<K extends core::Object* = dynamic, V extends core::Object* = dynamic> on self::MapLike<K*, V*>* {
+ operator [] = self::Extension|[];
+ operator []= = self::Extension|[]=;
+}
+static method Extension|[]<K extends core::Object* = dynamic, V extends core::Object* = dynamic>(final self::MapLike<self::Extension|[]::K*, self::Extension|[]::V*>* #this, core::Object* key) → self::Extension|[]::V*
+ return #this.{self::MapLike::get}(key);
+static method Extension|[]=<K extends core::Object* = dynamic, V extends core::Object* = dynamic>(final self::MapLike<self::Extension|[]=::K*, self::Extension|[]=::V*>* #this, self::Extension|[]=::K* key, self::Extension|[]=::V* value) → void
+ return #this.{self::MapLike::put}(key, value);
+static method main() → dynamic {
+ self::MapLike<core::int*, core::String*>* map1 = new self::MapLike::•<core::int*, core::String*>();
+ self::expect(null, self::Extension|[]<core::int*, core::String*>(map1, 0));
+ map1.{self::MapLike::put}(0, "0");
+ self::expect("0", self::Extension|[]<core::int*, core::String*>(map1, 0));
+ self::expect(null, self::Extension|[]<core::int*, core::String*>(map1, 1));
+ self::expect("1", let final self::MapLike<core::int*, core::String*>* #t5 = map1 in let final core::int* #t6 = 1 in let final core::String* #t7 = "1" in let final void #t8 = self::Extension|[]=<core::int*, core::String*>(#t5, #t6, #t7) in #t7);
+ self::expect("1", self::Extension|[]<core::int*, core::String*>(map1, 1));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!expected.{core::Object::==}(actual)) {
+ throw "Mismatch: expected=${expected}, actual=${actual}";
+ }
+}
diff --git a/pkg/front_end/testcases/extensions/index.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/index.dart.strong.transformed.expect
new file mode 100644
index 0000000..70bdb38
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/index.dart.strong.transformed.expect
@@ -0,0 +1,36 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class MapLike<K extends core::Object* = dynamic, V extends core::Object* = dynamic> extends core::Object {
+ final field core::Map<self::MapLike::K*, self::MapLike::V*>* _map = <self::MapLike::K*, self::MapLike::V*>{};
+ synthetic constructor •() → self::MapLike<self::MapLike::K*, self::MapLike::V*>*
+ : super core::Object::•()
+ ;
+ method get(core::Object* key) → self::MapLike::V*
+ return this.{self::MapLike::_map}.{core::Map::[]}(key);
+ method put(generic-covariant-impl self::MapLike::K* key, generic-covariant-impl self::MapLike::V* value) → self::MapLike::V*
+ return let final core::Map<self::MapLike::K*, self::MapLike::V*>* #t1 = this.{self::MapLike::_map} in let final self::MapLike::K* #t2 = key in let final self::MapLike::V* #t3 = value in let final void #t4 = #t1.{core::Map::[]=}(#t2, #t3) in #t3;
+}
+extension Extension<K extends core::Object* = dynamic, V extends core::Object* = dynamic> on self::MapLike<K*, V*>* {
+ operator [] = self::Extension|[];
+ operator []= = self::Extension|[]=;
+}
+static method Extension|[]<K extends core::Object* = dynamic, V extends core::Object* = dynamic>(final self::MapLike<self::Extension|[]::K*, self::Extension|[]::V*>* #this, core::Object* key) → self::Extension|[]::V*
+ return #this.{self::MapLike::get}(key);
+static method Extension|[]=<K extends core::Object* = dynamic, V extends core::Object* = dynamic>(final self::MapLike<self::Extension|[]=::K*, self::Extension|[]=::V*>* #this, self::Extension|[]=::K* key, self::Extension|[]=::V* value) → void
+ return #this.{self::MapLike::put}(key, value);
+static method main() → dynamic {
+ self::MapLike<core::int*, core::String*>* map1 = new self::MapLike::•<core::int*, core::String*>();
+ self::expect(null, self::Extension|[]<core::int*, core::String*>(map1, 0));
+ map1.{self::MapLike::put}(0, "0");
+ self::expect("0", self::Extension|[]<core::int*, core::String*>(map1, 0));
+ self::expect(null, self::Extension|[]<core::int*, core::String*>(map1, 1));
+ self::expect("1", let final self::MapLike<core::int*, core::String*>* #t5 = map1 in let final core::int* #t6 = 1 in let final core::String* #t7 = "1" in let final void #t8 = self::Extension|[]=<core::int*, core::String*>(#t5, #t6, #t7) in #t7);
+ self::expect("1", self::Extension|[]<core::int*, core::String*>(map1, 1));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!expected.{core::Object::==}(actual)) {
+ throw "Mismatch: expected=${expected}, actual=${actual}";
+ }
+}
diff --git a/pkg/front_end/testcases/extensions/instance_access.dart b/pkg/front_end/testcases/extensions/instance_access.dart
new file mode 100644
index 0000000..249f712
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/instance_access.dart
@@ -0,0 +1,111 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Class1 {
+ int field;
+
+ Class1(this.field);
+
+ String toString() => 'Class1($field)';
+}
+
+class Class2 {
+ int field;
+
+ Class2(this.field);
+
+ String toString() => 'Class2($field)';
+}
+
+extension Extension1 on Class1 {
+ int method() {
+ print('Extension1.method on $this');
+ return field;
+ }
+ int genericMethod<T extends num>(T t) {
+ print('Extension1.genericMethod<$T>($t) on $this');
+ return field + t;
+ }
+ int get property {
+ print('Extension1.property get on $this');
+ return field;
+ }
+ set property(int value) {
+ field = value;
+ print('Extension1.property set($value) on $this');
+ value++;
+ }
+}
+
+
+extension Extension2 on Class2 {
+ int method() {
+ print('Extension2.method on $this');
+ return field + 3;
+ }
+ int genericMethod<T extends num>(T t) {
+ print('Extension2.genericMethod<$T>($t) on $this');
+ return field + t + 4;
+ }
+ int get property {
+ print('Extension2.property get on $this');
+ return field + 5;
+ }
+ set property(int value) {
+ print('Extension2.property set($value) on $this');
+ value++;
+ field = value;
+ }
+}
+
+main() {
+ testExtension1();
+ testExtension2();
+}
+
+testExtension1() {
+ Class1 c0 = new Class1(0);
+ Class1 c1 = new Class1(1);
+ expect(0, c0.method());
+ expect(1, c1.method());
+ expect(42, c0.genericMethod(42));
+ expect(43, c0.genericMethod<num>(43));
+ expect(88, c1.genericMethod(87));
+ expect(89, c1.genericMethod<num>(88));
+ expect(0, c0.property);
+ expect(42, c0.property = 42);
+ expect(1, c1.property);
+ expect(87, c0.property = 87);
+ expect(27, c0.property = c1.property = 27);
+ expect(37, c1.property = c0.property = 37);
+ expect(77, c1.property = c0.property = c1.property = 77);
+ expect(67, c0.property = c1.property = c0.property = 67);
+}
+
+testExtension2() {
+ Class2 c0 = new Class2(0);
+ Class2 c1 = new Class2(1);
+ expect(3, c0.method());
+ expect(4, c1.method());
+ expect(46, c0.genericMethod(42));
+ expect(47, c0.genericMethod<num>(43));
+ expect(92, c1.genericMethod(87));
+ expect(93, c1.genericMethod<num>(88));
+ expect(5, c0.property);
+ expect(42, c0.property = 42);
+ expect(48, c0.property);
+ expect(6, c1.property);
+ expect(43, c1.property = 43);
+ expect(49, c1.property);
+ expect(49, c0.property = c1.property);
+ expect(55, c1.property = c0.property);
+ expect(61, c1.property = c0.property = c1.property);
+ expect(67, c0.property = c1.property = c0.property);
+}
+
+expect(expected, actual) {
+ if (expected != actual) {
+ throw 'Mismatch: expected=$expected, actual=$actual';
+ }
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/instance_access.dart.outline.expect b/pkg/front_end/testcases/extensions/instance_access.dart.outline.expect
new file mode 100644
index 0000000..c0d9552
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/instance_access.dart.outline.expect
@@ -0,0 +1,66 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ field core::int* field;
+ constructor •(core::int* field) → self::Class1*
+ ;
+ method toString() → core::String*
+ ;
+}
+class Class2 extends core::Object {
+ field core::int* field;
+ constructor •(core::int* field) → self::Class2*
+ ;
+ method toString() → core::String*
+ ;
+}
+extension Extension1 on self::Class1* {
+ method method = self::Extension1|method;
+ tearoff method = self::Extension1|get#method;
+ method genericMethod = self::Extension1|genericMethod;
+ tearoff genericMethod = self::Extension1|get#genericMethod;
+ get property = self::Extension1|get#property;
+ set property = self::Extension1|set#property;
+}
+extension Extension2 on self::Class2* {
+ method method = self::Extension2|method;
+ tearoff method = self::Extension2|get#method;
+ method genericMethod = self::Extension2|genericMethod;
+ tearoff genericMethod = self::Extension2|get#genericMethod;
+ get property = self::Extension2|get#property;
+ set property = self::Extension2|set#property;
+}
+static method Extension1|method(final self::Class1* #this) → core::int*
+ ;
+static method Extension1|get#method(final self::Class1* #this) → () →* core::int*
+ return () → core::int* => self::Extension1|method(#this);
+static method Extension1|genericMethod<T extends core::num* = dynamic>(final self::Class1* #this, self::Extension1|genericMethod::T* t) → core::int*
+ ;
+static method Extension1|get#genericMethod(final self::Class1* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+ return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension1|genericMethod<T*>(#this, t);
+static method Extension1|get#property(final self::Class1* #this) → core::int*
+ ;
+static method Extension1|set#property(final self::Class1* #this, core::int* value) → void
+ ;
+static method Extension2|method(final self::Class2* #this) → core::int*
+ ;
+static method Extension2|get#method(final self::Class2* #this) → () →* core::int*
+ return () → core::int* => self::Extension2|method(#this);
+static method Extension2|genericMethod<T extends core::num* = dynamic>(final self::Class2* #this, self::Extension2|genericMethod::T* t) → core::int*
+ ;
+static method Extension2|get#genericMethod(final self::Class2* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+ return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension2|genericMethod<T*>(#this, t);
+static method Extension2|get#property(final self::Class2* #this) → core::int*
+ ;
+static method Extension2|set#property(final self::Class2* #this, core::int* value) → void
+ ;
+static method main() → dynamic
+ ;
+static method testExtension1() → dynamic
+ ;
+static method testExtension2() → dynamic
+ ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+ ;
diff --git a/pkg/front_end/testcases/extensions/instance_access.dart.strong.expect b/pkg/front_end/testcases/extensions/instance_access.dart.strong.expect
new file mode 100644
index 0000000..1417dd4
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/instance_access.dart.strong.expect
@@ -0,0 +1,129 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ field core::int* field;
+ constructor •(core::int* field) → self::Class1*
+ : self::Class1::field = field, super core::Object::•()
+ ;
+ method toString() → core::String*
+ return "Class1(${this.{self::Class1::field}})";
+}
+class Class2 extends core::Object {
+ field core::int* field;
+ constructor •(core::int* field) → self::Class2*
+ : self::Class2::field = field, super core::Object::•()
+ ;
+ method toString() → core::String*
+ return "Class2(${this.{self::Class2::field}})";
+}
+extension Extension1 on self::Class1* {
+ method method = self::Extension1|method;
+ tearoff method = self::Extension1|get#method;
+ method genericMethod = self::Extension1|genericMethod;
+ tearoff genericMethod = self::Extension1|get#genericMethod;
+ get property = self::Extension1|get#property;
+ set property = self::Extension1|set#property;
+}
+extension Extension2 on self::Class2* {
+ method method = self::Extension2|method;
+ tearoff method = self::Extension2|get#method;
+ method genericMethod = self::Extension2|genericMethod;
+ tearoff genericMethod = self::Extension2|get#genericMethod;
+ get property = self::Extension2|get#property;
+ set property = self::Extension2|set#property;
+}
+static method Extension1|method(final self::Class1* #this) → core::int* {
+ core::print("Extension1.method on ${#this}");
+ return #this.{self::Class1::field};
+}
+static method Extension1|get#method(final self::Class1* #this) → () →* core::int*
+ return () → core::int* => self::Extension1|method(#this);
+static method Extension1|genericMethod<T extends core::num* = dynamic>(final self::Class1* #this, self::Extension1|genericMethod::T* t) → core::int* {
+ core::print("Extension1.genericMethod<${self::Extension1|genericMethod::T*}>(${t}) on ${#this}");
+ return #this.{self::Class1::field}.{core::num::+}(t) as{TypeError} core::int*;
+}
+static method Extension1|get#genericMethod(final self::Class1* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+ return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension1|genericMethod<T*>(#this, t);
+static method Extension1|get#property(final self::Class1* #this) → core::int* {
+ core::print("Extension1.property get on ${#this}");
+ return #this.{self::Class1::field};
+}
+static method Extension1|set#property(final self::Class1* #this, core::int* value) → core::int* {
+ final core::int* #t1 = value;
+ #this.{self::Class1::field} = value;
+ core::print("Extension1.property set(${value}) on ${#this}");
+ value = value.{core::num::+}(1);
+ return #t1;
+}
+static method Extension2|method(final self::Class2* #this) → core::int* {
+ core::print("Extension2.method on ${#this}");
+ return #this.{self::Class2::field}.{core::num::+}(3);
+}
+static method Extension2|get#method(final self::Class2* #this) → () →* core::int*
+ return () → core::int* => self::Extension2|method(#this);
+static method Extension2|genericMethod<T extends core::num* = dynamic>(final self::Class2* #this, self::Extension2|genericMethod::T* t) → core::int* {
+ core::print("Extension2.genericMethod<${self::Extension2|genericMethod::T*}>(${t}) on ${#this}");
+ return #this.{self::Class2::field}.{core::num::+}(t).{core::num::+}(4) as{TypeError} core::int*;
+}
+static method Extension2|get#genericMethod(final self::Class2* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+ return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension2|genericMethod<T*>(#this, t);
+static method Extension2|get#property(final self::Class2* #this) → core::int* {
+ core::print("Extension2.property get on ${#this}");
+ return #this.{self::Class2::field}.{core::num::+}(5);
+}
+static method Extension2|set#property(final self::Class2* #this, core::int* value) → core::int* {
+ final core::int* #t2 = value;
+ core::print("Extension2.property set(${value}) on ${#this}");
+ value = value.{core::num::+}(1);
+ #this.{self::Class2::field} = value;
+ return #t2;
+}
+static method main() → dynamic {
+ self::testExtension1();
+ self::testExtension2();
+}
+static method testExtension1() → dynamic {
+ self::Class1* c0 = new self::Class1::•(0);
+ self::Class1* c1 = new self::Class1::•(1);
+ self::expect(0, self::Extension1|method(c0));
+ self::expect(1, self::Extension1|method(c1));
+ self::expect(42, self::Extension1|genericMethod<core::int*>(c0, 42));
+ self::expect(43, self::Extension1|genericMethod<core::num*>(c0, 43));
+ self::expect(88, self::Extension1|genericMethod<core::int*>(c1, 87));
+ self::expect(89, self::Extension1|genericMethod<core::num*>(c1, 88));
+ self::expect(0, self::Extension1|get#property(c0));
+ self::expect(42, self::Extension1|set#property(c0, 42));
+ self::expect(1, self::Extension1|get#property(c1));
+ self::expect(87, self::Extension1|set#property(c0, 87));
+ self::expect(27, self::Extension1|set#property(c0, self::Extension1|set#property(c1, 27)));
+ self::expect(37, self::Extension1|set#property(c1, self::Extension1|set#property(c0, 37)));
+ self::expect(77, self::Extension1|set#property(c1, self::Extension1|set#property(c0, self::Extension1|set#property(c1, 77))));
+ self::expect(67, self::Extension1|set#property(c0, self::Extension1|set#property(c1, self::Extension1|set#property(c0, 67))));
+}
+static method testExtension2() → dynamic {
+ self::Class2* c0 = new self::Class2::•(0);
+ self::Class2* c1 = new self::Class2::•(1);
+ self::expect(3, self::Extension2|method(c0));
+ self::expect(4, self::Extension2|method(c1));
+ self::expect(46, self::Extension2|genericMethod<core::int*>(c0, 42));
+ self::expect(47, self::Extension2|genericMethod<core::num*>(c0, 43));
+ self::expect(92, self::Extension2|genericMethod<core::int*>(c1, 87));
+ self::expect(93, self::Extension2|genericMethod<core::num*>(c1, 88));
+ self::expect(5, self::Extension2|get#property(c0));
+ self::expect(42, self::Extension2|set#property(c0, 42));
+ self::expect(48, self::Extension2|get#property(c0));
+ self::expect(6, self::Extension2|get#property(c1));
+ self::expect(43, self::Extension2|set#property(c1, 43));
+ self::expect(49, self::Extension2|get#property(c1));
+ self::expect(49, self::Extension2|set#property(c0, self::Extension2|get#property(c1)));
+ self::expect(55, self::Extension2|set#property(c1, self::Extension2|get#property(c0)));
+ self::expect(61, self::Extension2|set#property(c1, self::Extension2|set#property(c0, self::Extension2|get#property(c1))));
+ self::expect(67, self::Extension2|set#property(c0, self::Extension2|set#property(c1, self::Extension2|get#property(c0))));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!expected.{core::Object::==}(actual)) {
+ throw "Mismatch: expected=${expected}, actual=${actual}";
+ }
+}
diff --git a/pkg/front_end/testcases/extensions/instance_access.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/instance_access.dart.strong.transformed.expect
new file mode 100644
index 0000000..1417dd4
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/instance_access.dart.strong.transformed.expect
@@ -0,0 +1,129 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ field core::int* field;
+ constructor •(core::int* field) → self::Class1*
+ : self::Class1::field = field, super core::Object::•()
+ ;
+ method toString() → core::String*
+ return "Class1(${this.{self::Class1::field}})";
+}
+class Class2 extends core::Object {
+ field core::int* field;
+ constructor •(core::int* field) → self::Class2*
+ : self::Class2::field = field, super core::Object::•()
+ ;
+ method toString() → core::String*
+ return "Class2(${this.{self::Class2::field}})";
+}
+extension Extension1 on self::Class1* {
+ method method = self::Extension1|method;
+ tearoff method = self::Extension1|get#method;
+ method genericMethod = self::Extension1|genericMethod;
+ tearoff genericMethod = self::Extension1|get#genericMethod;
+ get property = self::Extension1|get#property;
+ set property = self::Extension1|set#property;
+}
+extension Extension2 on self::Class2* {
+ method method = self::Extension2|method;
+ tearoff method = self::Extension2|get#method;
+ method genericMethod = self::Extension2|genericMethod;
+ tearoff genericMethod = self::Extension2|get#genericMethod;
+ get property = self::Extension2|get#property;
+ set property = self::Extension2|set#property;
+}
+static method Extension1|method(final self::Class1* #this) → core::int* {
+ core::print("Extension1.method on ${#this}");
+ return #this.{self::Class1::field};
+}
+static method Extension1|get#method(final self::Class1* #this) → () →* core::int*
+ return () → core::int* => self::Extension1|method(#this);
+static method Extension1|genericMethod<T extends core::num* = dynamic>(final self::Class1* #this, self::Extension1|genericMethod::T* t) → core::int* {
+ core::print("Extension1.genericMethod<${self::Extension1|genericMethod::T*}>(${t}) on ${#this}");
+ return #this.{self::Class1::field}.{core::num::+}(t) as{TypeError} core::int*;
+}
+static method Extension1|get#genericMethod(final self::Class1* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+ return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension1|genericMethod<T*>(#this, t);
+static method Extension1|get#property(final self::Class1* #this) → core::int* {
+ core::print("Extension1.property get on ${#this}");
+ return #this.{self::Class1::field};
+}
+static method Extension1|set#property(final self::Class1* #this, core::int* value) → core::int* {
+ final core::int* #t1 = value;
+ #this.{self::Class1::field} = value;
+ core::print("Extension1.property set(${value}) on ${#this}");
+ value = value.{core::num::+}(1);
+ return #t1;
+}
+static method Extension2|method(final self::Class2* #this) → core::int* {
+ core::print("Extension2.method on ${#this}");
+ return #this.{self::Class2::field}.{core::num::+}(3);
+}
+static method Extension2|get#method(final self::Class2* #this) → () →* core::int*
+ return () → core::int* => self::Extension2|method(#this);
+static method Extension2|genericMethod<T extends core::num* = dynamic>(final self::Class2* #this, self::Extension2|genericMethod::T* t) → core::int* {
+ core::print("Extension2.genericMethod<${self::Extension2|genericMethod::T*}>(${t}) on ${#this}");
+ return #this.{self::Class2::field}.{core::num::+}(t).{core::num::+}(4) as{TypeError} core::int*;
+}
+static method Extension2|get#genericMethod(final self::Class2* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+ return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension2|genericMethod<T*>(#this, t);
+static method Extension2|get#property(final self::Class2* #this) → core::int* {
+ core::print("Extension2.property get on ${#this}");
+ return #this.{self::Class2::field}.{core::num::+}(5);
+}
+static method Extension2|set#property(final self::Class2* #this, core::int* value) → core::int* {
+ final core::int* #t2 = value;
+ core::print("Extension2.property set(${value}) on ${#this}");
+ value = value.{core::num::+}(1);
+ #this.{self::Class2::field} = value;
+ return #t2;
+}
+static method main() → dynamic {
+ self::testExtension1();
+ self::testExtension2();
+}
+static method testExtension1() → dynamic {
+ self::Class1* c0 = new self::Class1::•(0);
+ self::Class1* c1 = new self::Class1::•(1);
+ self::expect(0, self::Extension1|method(c0));
+ self::expect(1, self::Extension1|method(c1));
+ self::expect(42, self::Extension1|genericMethod<core::int*>(c0, 42));
+ self::expect(43, self::Extension1|genericMethod<core::num*>(c0, 43));
+ self::expect(88, self::Extension1|genericMethod<core::int*>(c1, 87));
+ self::expect(89, self::Extension1|genericMethod<core::num*>(c1, 88));
+ self::expect(0, self::Extension1|get#property(c0));
+ self::expect(42, self::Extension1|set#property(c0, 42));
+ self::expect(1, self::Extension1|get#property(c1));
+ self::expect(87, self::Extension1|set#property(c0, 87));
+ self::expect(27, self::Extension1|set#property(c0, self::Extension1|set#property(c1, 27)));
+ self::expect(37, self::Extension1|set#property(c1, self::Extension1|set#property(c0, 37)));
+ self::expect(77, self::Extension1|set#property(c1, self::Extension1|set#property(c0, self::Extension1|set#property(c1, 77))));
+ self::expect(67, self::Extension1|set#property(c0, self::Extension1|set#property(c1, self::Extension1|set#property(c0, 67))));
+}
+static method testExtension2() → dynamic {
+ self::Class2* c0 = new self::Class2::•(0);
+ self::Class2* c1 = new self::Class2::•(1);
+ self::expect(3, self::Extension2|method(c0));
+ self::expect(4, self::Extension2|method(c1));
+ self::expect(46, self::Extension2|genericMethod<core::int*>(c0, 42));
+ self::expect(47, self::Extension2|genericMethod<core::num*>(c0, 43));
+ self::expect(92, self::Extension2|genericMethod<core::int*>(c1, 87));
+ self::expect(93, self::Extension2|genericMethod<core::num*>(c1, 88));
+ self::expect(5, self::Extension2|get#property(c0));
+ self::expect(42, self::Extension2|set#property(c0, 42));
+ self::expect(48, self::Extension2|get#property(c0));
+ self::expect(6, self::Extension2|get#property(c1));
+ self::expect(43, self::Extension2|set#property(c1, 43));
+ self::expect(49, self::Extension2|get#property(c1));
+ self::expect(49, self::Extension2|set#property(c0, self::Extension2|get#property(c1)));
+ self::expect(55, self::Extension2|set#property(c1, self::Extension2|get#property(c0)));
+ self::expect(61, self::Extension2|set#property(c1, self::Extension2|set#property(c0, self::Extension2|get#property(c1))));
+ self::expect(67, self::Extension2|set#property(c0, self::Extension2|set#property(c1, self::Extension2|get#property(c0))));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!expected.{core::Object::==}(actual)) {
+ throw "Mismatch: expected=${expected}, actual=${actual}";
+ }
+}
diff --git a/pkg/front_end/testcases/extensions/instance_access.dart.type_promotion.expect b/pkg/front_end/testcases/extensions/instance_access.dart.type_promotion.expect
new file mode 100644
index 0000000..052b274
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/instance_access.dart.type_promotion.expect
@@ -0,0 +1,6 @@
+pkg/front_end/testcases/extensions/instance_access.dart:37:10: Context: Write to value@755
+ value++;
+ ^^
+pkg/front_end/testcases/extensions/instance_access.dart:57:10: Context: Write to value@1217
+ value++;
+ ^^
diff --git a/pkg/front_end/testcases/extensions/instance_access_of_static.dart b/pkg/front_end/testcases/extensions/instance_access_of_static.dart
new file mode 100644
index 0000000..a8b0b2d
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/instance_access_of_static.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Class1 {
+}
+
+extension Extension1 on Class1 {
+ static staticMethod() {
+ print('Extension1.staticMethod()');
+ }
+
+ static get staticProperty {
+ print('Extension1.staticProperty()');
+ }
+ static set staticProperty(int value) {
+ print('Extension1.staticProperty($value)');
+ value++;
+ }
+
+ static var staticField = 42;
+}
+
+main() {
+ Class1 c = new Class1();
+ c.staticMethod();
+ c.staticMethod;
+ c.staticProperty;
+ c.staticProperty = 42;
+ c.staticField;
+ c.staticField = 42;
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/instance_access_of_static.dart.outline.expect b/pkg/front_end/testcases/extensions/instance_access_of_static.dart.outline.expect
new file mode 100644
index 0000000..731aa09
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/instance_access_of_static.dart.outline.expect
@@ -0,0 +1,23 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ synthetic constructor •() → self::Class1*
+ ;
+}
+extension Extension1 on self::Class1* {
+ static method staticMethod = self::Extension1|staticMethod;
+ static get staticProperty = get self::Extension1|staticProperty;
+ static field staticField = self::Extension1|staticField;
+ static set staticProperty = set self::Extension1|staticProperty;
+}
+static field core::int* Extension1|staticField;
+static method Extension1|staticMethod() → dynamic
+ ;
+static get Extension1|staticProperty() → dynamic
+ ;
+static set Extension1|staticProperty(core::int* value) → void
+ ;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/extensions/instance_access_of_static.dart.strong.expect b/pkg/front_end/testcases/extensions/instance_access_of_static.dart.strong.expect
new file mode 100644
index 0000000..75191b4
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/instance_access_of_static.dart.strong.expect
@@ -0,0 +1,98 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/instance_access_of_static.dart:26:5: Error: The method 'staticMethod' isn't defined for the class 'Class1'.
+// - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+// Try correcting the name to the name of an existing method, or defining a method named 'staticMethod'.
+// c.staticMethod();
+// ^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/instance_access_of_static.dart:27:5: Error: The getter 'staticMethod' isn't defined for the class 'Class1'.
+// - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'staticMethod'.
+// c.staticMethod;
+// ^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/instance_access_of_static.dart:28:5: Error: The getter 'staticProperty' isn't defined for the class 'Class1'.
+// - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'staticProperty'.
+// c.staticProperty;
+// ^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/instance_access_of_static.dart:29:5: Error: The setter 'staticProperty' isn't defined for the class 'Class1'.
+// - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'staticProperty'.
+// c.staticProperty = 42;
+// ^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/instance_access_of_static.dart:30:5: Error: The getter 'staticField' isn't defined for the class 'Class1'.
+// - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'staticField'.
+// c.staticField;
+// ^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/instance_access_of_static.dart:31:5: Error: The setter 'staticField' isn't defined for the class 'Class1'.
+// - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'staticField'.
+// c.staticField = 42;
+// ^^^^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ synthetic constructor •() → self::Class1*
+ : super core::Object::•()
+ ;
+}
+extension Extension1 on self::Class1* {
+ static method staticMethod = self::Extension1|staticMethod;
+ static get staticProperty = get self::Extension1|staticProperty;
+ static field staticField = self::Extension1|staticField;
+ static set staticProperty = set self::Extension1|staticProperty;
+}
+static field core::int* Extension1|staticField = 42;
+static method Extension1|staticMethod() → dynamic {
+ core::print("Extension1.staticMethod()");
+}
+static get Extension1|staticProperty() → dynamic {
+ core::print("Extension1.staticProperty()");
+}
+static set Extension1|staticProperty(core::int* value) → void {
+ core::print("Extension1.staticProperty(${value})");
+ value = value.{core::num::+}(1);
+}
+static method main() → dynamic {
+ self::Class1* c = new self::Class1::•();
+ invalid-expression "pkg/front_end/testcases/extensions/instance_access_of_static.dart:26:5: Error: The method 'staticMethod' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+Try correcting the name to the name of an existing method, or defining a method named 'staticMethod'.
+ c.staticMethod();
+ ^^^^^^^^^^^^";
+ invalid-expression "pkg/front_end/testcases/extensions/instance_access_of_static.dart:27:5: Error: The getter 'staticMethod' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'staticMethod'.
+ c.staticMethod;
+ ^^^^^^^^^^^^";
+ invalid-expression "pkg/front_end/testcases/extensions/instance_access_of_static.dart:28:5: Error: The getter 'staticProperty' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'staticProperty'.
+ c.staticProperty;
+ ^^^^^^^^^^^^^^";
+ invalid-expression "pkg/front_end/testcases/extensions/instance_access_of_static.dart:29:5: Error: The setter 'staticProperty' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'staticProperty'.
+ c.staticProperty = 42;
+ ^^^^^^^^^^^^^^";
+ invalid-expression "pkg/front_end/testcases/extensions/instance_access_of_static.dart:30:5: Error: The getter 'staticField' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'staticField'.
+ c.staticField;
+ ^^^^^^^^^^^";
+ invalid-expression "pkg/front_end/testcases/extensions/instance_access_of_static.dart:31:5: Error: The setter 'staticField' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'staticField'.
+ c.staticField = 42;
+ ^^^^^^^^^^^";
+}
diff --git a/pkg/front_end/testcases/extensions/instance_access_of_static.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/instance_access_of_static.dart.strong.transformed.expect
new file mode 100644
index 0000000..75191b4
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/instance_access_of_static.dart.strong.transformed.expect
@@ -0,0 +1,98 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/instance_access_of_static.dart:26:5: Error: The method 'staticMethod' isn't defined for the class 'Class1'.
+// - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+// Try correcting the name to the name of an existing method, or defining a method named 'staticMethod'.
+// c.staticMethod();
+// ^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/instance_access_of_static.dart:27:5: Error: The getter 'staticMethod' isn't defined for the class 'Class1'.
+// - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'staticMethod'.
+// c.staticMethod;
+// ^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/instance_access_of_static.dart:28:5: Error: The getter 'staticProperty' isn't defined for the class 'Class1'.
+// - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'staticProperty'.
+// c.staticProperty;
+// ^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/instance_access_of_static.dart:29:5: Error: The setter 'staticProperty' isn't defined for the class 'Class1'.
+// - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'staticProperty'.
+// c.staticProperty = 42;
+// ^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/instance_access_of_static.dart:30:5: Error: The getter 'staticField' isn't defined for the class 'Class1'.
+// - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'staticField'.
+// c.staticField;
+// ^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/instance_access_of_static.dart:31:5: Error: The setter 'staticField' isn't defined for the class 'Class1'.
+// - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'staticField'.
+// c.staticField = 42;
+// ^^^^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ synthetic constructor •() → self::Class1*
+ : super core::Object::•()
+ ;
+}
+extension Extension1 on self::Class1* {
+ static method staticMethod = self::Extension1|staticMethod;
+ static get staticProperty = get self::Extension1|staticProperty;
+ static field staticField = self::Extension1|staticField;
+ static set staticProperty = set self::Extension1|staticProperty;
+}
+static field core::int* Extension1|staticField = 42;
+static method Extension1|staticMethod() → dynamic {
+ core::print("Extension1.staticMethod()");
+}
+static get Extension1|staticProperty() → dynamic {
+ core::print("Extension1.staticProperty()");
+}
+static set Extension1|staticProperty(core::int* value) → void {
+ core::print("Extension1.staticProperty(${value})");
+ value = value.{core::num::+}(1);
+}
+static method main() → dynamic {
+ self::Class1* c = new self::Class1::•();
+ invalid-expression "pkg/front_end/testcases/extensions/instance_access_of_static.dart:26:5: Error: The method 'staticMethod' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+Try correcting the name to the name of an existing method, or defining a method named 'staticMethod'.
+ c.staticMethod();
+ ^^^^^^^^^^^^";
+ invalid-expression "pkg/front_end/testcases/extensions/instance_access_of_static.dart:27:5: Error: The getter 'staticMethod' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'staticMethod'.
+ c.staticMethod;
+ ^^^^^^^^^^^^";
+ invalid-expression "pkg/front_end/testcases/extensions/instance_access_of_static.dart:28:5: Error: The getter 'staticProperty' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'staticProperty'.
+ c.staticProperty;
+ ^^^^^^^^^^^^^^";
+ invalid-expression "pkg/front_end/testcases/extensions/instance_access_of_static.dart:29:5: Error: The setter 'staticProperty' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'staticProperty'.
+ c.staticProperty = 42;
+ ^^^^^^^^^^^^^^";
+ invalid-expression "pkg/front_end/testcases/extensions/instance_access_of_static.dart:30:5: Error: The getter 'staticField' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'staticField'.
+ c.staticField;
+ ^^^^^^^^^^^";
+ invalid-expression "pkg/front_end/testcases/extensions/instance_access_of_static.dart:31:5: Error: The setter 'staticField' isn't defined for the class 'Class1'.
+ - 'Class1' is from 'pkg/front_end/testcases/extensions/instance_access_of_static.dart'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'staticField'.
+ c.staticField = 42;
+ ^^^^^^^^^^^";
+}
diff --git a/pkg/front_end/testcases/extensions/instance_access_of_static.dart.type_promotion.expect b/pkg/front_end/testcases/extensions/instance_access_of_static.dart.type_promotion.expect
new file mode 100644
index 0000000..2967660
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/instance_access_of_static.dart.type_promotion.expect
@@ -0,0 +1,3 @@
+pkg/front_end/testcases/extensions/instance_access_of_static.dart:18:10: Context: Write to value@447
+ value++;
+ ^^
diff --git a/pkg/front_end/testcases/extensions/instance_members.dart.outline.expect b/pkg/front_end/testcases/extensions/instance_members.dart.outline.expect
index c2ae0c9..36c0330 100644
--- a/pkg/front_end/testcases/extensions/instance_members.dart.outline.expect
+++ b/pkg/front_end/testcases/extensions/instance_members.dart.outline.expect
@@ -12,25 +12,43 @@
}
extension A2 on self::A1* {
method method1 = self::A2|method1;
+ tearoff method1 = self::A2|get#method1;
method method2 = self::A2|method2;
+ tearoff method2 = self::A2|get#method2;
method method3 = self::A2|method3;
+ tearoff method3 = self::A2|get#method3;
method method4 = self::A2|method4;
+ tearoff method4 = self::A2|get#method4;
}
extension B2<T extends core::Object* = dynamic> on self::B1<T*>* {
method method1 = self::B2|method1;
+ tearoff method1 = self::B2|get#method1;
method method2 = self::B2|method2;
+ tearoff method2 = self::B2|get#method2;
}
static method A2|method1(final self::A1* #this) → self::A1*
;
+static method A2|get#method1(final self::A1* #this) → () →* self::A1*
+ return () → self::A1* => self::A2|method1(#this);
static method A2|method2<T extends core::Object* = dynamic>(final self::A1* #this, self::A2|method2::T* o) → self::A1*
;
+static method A2|get#method2(final self::A1* #this) → <T extends core::Object* = dynamic>(T*) →* self::A1*
+ return <T extends core::Object* = dynamic>(T* o) → self::A1* => self::A2|method2<T*>(#this, o);
static method A2|method3<T extends core::Object* = dynamic>(final self::A1* #this, [self::A2|method3::T* o]) → self::A1*
;
+static method A2|get#method3(final self::A1* #this) → <T extends core::Object* = dynamic>([T*]) →* self::A1*
+ return <T extends core::Object* = dynamic>([T* o = null]) → self::A1* => self::A2|method3<T*>(#this, o);
static method A2|method4<T extends core::Object* = dynamic>(final self::A1* #this, {self::A2|method4::T* o}) → self::A1*
;
-static method B2|method1<#T extends core::Object* = dynamic>(final self::B1<self::B2|method1::#T*>* #this) → self::B1<self::B2|method1::#T*>*
+static method A2|get#method4(final self::A1* #this) → <T extends core::Object* = dynamic>({o: T*}) →* self::A1*
+ return <T extends core::Object* = dynamic>({T* o = null}) → self::A1* => self::A2|method4<T*>(#this, o: o);
+static method B2|method1<T extends core::Object* = dynamic>(final self::B1<self::B2|method1::T*>* #this) → self::B1<self::B2|method1::T*>*
;
-static method B2|method2<#T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::B1<self::B2|method2::#T*>* #this, self::B2|method2::S* o) → self::B1<self::B2|method2::#T*>*
+static method B2|get#method1<T extends core::Object* = dynamic>(final self::B1<self::B2|get#method1::T*>* #this) → () →* self::B1<self::B2|get#method1::T*>*
+ return () → self::B1<self::B2|get#method1::T*>* => self::B2|method1<self::B2|get#method1::T*>(#this);
+static method B2|method2<T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::B1<self::B2|method2::T*>* #this, self::B2|method2::S* o) → self::B1<self::B2|method2::T*>*
;
+static method B2|get#method2<T extends core::Object* = dynamic>(final self::B1<self::B2|get#method2::T*>* #this) → <S extends core::Object* = dynamic>(S*) →* self::B1<self::B2|get#method2::T*>*
+ return <S extends core::Object* = dynamic>(S* o) → self::B1<self::B2|get#method2::T*>* => self::B2|method2<self::B2|get#method2::T*, S*>(#this, o);
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/extensions/instance_members.dart.strong.expect b/pkg/front_end/testcases/extensions/instance_members.dart.strong.expect
index 598e9a6..dfed3fb 100644
--- a/pkg/front_end/testcases/extensions/instance_members.dart.strong.expect
+++ b/pkg/front_end/testcases/extensions/instance_members.dart.strong.expect
@@ -14,36 +14,54 @@
}
extension A2 on self::A1* {
method method1 = self::A2|method1;
+ tearoff method1 = self::A2|get#method1;
method method2 = self::A2|method2;
+ tearoff method2 = self::A2|get#method2;
method method3 = self::A2|method3;
+ tearoff method3 = self::A2|get#method3;
method method4 = self::A2|method4;
+ tearoff method4 = self::A2|get#method4;
}
extension B2<T extends core::Object* = dynamic> on self::B1<T*>* {
method method1 = self::B2|method1;
+ tearoff method1 = self::B2|get#method1;
method method2 = self::B2|method2;
+ tearoff method2 = self::B2|get#method2;
}
static method A2|method1(final self::A1* #this) → self::A1* {
return #this;
}
+static method A2|get#method1(final self::A1* #this) → () →* self::A1*
+ return () → self::A1* => self::A2|method1(#this);
static method A2|method2<T extends core::Object* = dynamic>(final self::A1* #this, self::A2|method2::T* o) → self::A1* {
core::print(o);
return #this;
}
+static method A2|get#method2(final self::A1* #this) → <T extends core::Object* = dynamic>(T*) →* self::A1*
+ return <T extends core::Object* = dynamic>(T* o) → self::A1* => self::A2|method2<T*>(#this, o);
static method A2|method3<T extends core::Object* = dynamic>(final self::A1* #this = #C1, [self::A2|method3::T* o = #C1]) → self::A1* {
core::print(o);
return #this;
}
+static method A2|get#method3(final self::A1* #this) → <T extends core::Object* = dynamic>([T*]) →* self::A1*
+ return <T extends core::Object* = dynamic>([T* o = #C1]) → self::A1* => self::A2|method3<T*>(#this, o);
static method A2|method4<T extends core::Object* = dynamic>(final self::A1* #this = #C1, {self::A2|method4::T* o = #C1}) → self::A1* {
core::print(o);
return #this;
}
-static method B2|method1<#T extends core::Object* = dynamic>(final self::B1<self::B2|method1::#T*>* #this) → self::B1<self::B2|method1::#T*>* {
+static method A2|get#method4(final self::A1* #this) → <T extends core::Object* = dynamic>({o: T*}) →* self::A1*
+ return <T extends core::Object* = dynamic>({T* o = #C1}) → self::A1* => self::A2|method4<T*>(#this, o: o);
+static method B2|method1<T extends core::Object* = dynamic>(final self::B1<self::B2|method1::T*>* #this) → self::B1<self::B2|method1::T*>* {
return #this;
}
-static method B2|method2<#T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::B1<self::B2|method2::#T*>* #this, self::B2|method2::S* o) → self::B1<self::B2|method2::#T*>* {
+static method B2|get#method1<T extends core::Object* = dynamic>(final self::B1<self::B2|get#method1::T*>* #this) → () →* self::B1<self::B2|get#method1::T*>*
+ return () → self::B1<self::B2|get#method1::T*>* => self::B2|method1<self::B2|get#method1::T*>(#this);
+static method B2|method2<T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::B1<self::B2|method2::T*>* #this, self::B2|method2::S* o) → self::B1<self::B2|method2::T*>* {
core::print(o);
return #this;
}
+static method B2|get#method2<T extends core::Object* = dynamic>(final self::B1<self::B2|get#method2::T*>* #this) → <S extends core::Object* = dynamic>(S*) →* self::B1<self::B2|get#method2::T*>*
+ return <S extends core::Object* = dynamic>(S* o) → self::B1<self::B2|get#method2::T*>* => self::B2|method2<self::B2|get#method2::T*, S*>(#this, o);
static method main() → dynamic {}
constants {
diff --git a/pkg/front_end/testcases/extensions/instance_members.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/instance_members.dart.strong.transformed.expect
index 598e9a6..dfed3fb 100644
--- a/pkg/front_end/testcases/extensions/instance_members.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/extensions/instance_members.dart.strong.transformed.expect
@@ -14,36 +14,54 @@
}
extension A2 on self::A1* {
method method1 = self::A2|method1;
+ tearoff method1 = self::A2|get#method1;
method method2 = self::A2|method2;
+ tearoff method2 = self::A2|get#method2;
method method3 = self::A2|method3;
+ tearoff method3 = self::A2|get#method3;
method method4 = self::A2|method4;
+ tearoff method4 = self::A2|get#method4;
}
extension B2<T extends core::Object* = dynamic> on self::B1<T*>* {
method method1 = self::B2|method1;
+ tearoff method1 = self::B2|get#method1;
method method2 = self::B2|method2;
+ tearoff method2 = self::B2|get#method2;
}
static method A2|method1(final self::A1* #this) → self::A1* {
return #this;
}
+static method A2|get#method1(final self::A1* #this) → () →* self::A1*
+ return () → self::A1* => self::A2|method1(#this);
static method A2|method2<T extends core::Object* = dynamic>(final self::A1* #this, self::A2|method2::T* o) → self::A1* {
core::print(o);
return #this;
}
+static method A2|get#method2(final self::A1* #this) → <T extends core::Object* = dynamic>(T*) →* self::A1*
+ return <T extends core::Object* = dynamic>(T* o) → self::A1* => self::A2|method2<T*>(#this, o);
static method A2|method3<T extends core::Object* = dynamic>(final self::A1* #this = #C1, [self::A2|method3::T* o = #C1]) → self::A1* {
core::print(o);
return #this;
}
+static method A2|get#method3(final self::A1* #this) → <T extends core::Object* = dynamic>([T*]) →* self::A1*
+ return <T extends core::Object* = dynamic>([T* o = #C1]) → self::A1* => self::A2|method3<T*>(#this, o);
static method A2|method4<T extends core::Object* = dynamic>(final self::A1* #this = #C1, {self::A2|method4::T* o = #C1}) → self::A1* {
core::print(o);
return #this;
}
-static method B2|method1<#T extends core::Object* = dynamic>(final self::B1<self::B2|method1::#T*>* #this) → self::B1<self::B2|method1::#T*>* {
+static method A2|get#method4(final self::A1* #this) → <T extends core::Object* = dynamic>({o: T*}) →* self::A1*
+ return <T extends core::Object* = dynamic>({T* o = #C1}) → self::A1* => self::A2|method4<T*>(#this, o: o);
+static method B2|method1<T extends core::Object* = dynamic>(final self::B1<self::B2|method1::T*>* #this) → self::B1<self::B2|method1::T*>* {
return #this;
}
-static method B2|method2<#T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::B1<self::B2|method2::#T*>* #this, self::B2|method2::S* o) → self::B1<self::B2|method2::#T*>* {
+static method B2|get#method1<T extends core::Object* = dynamic>(final self::B1<self::B2|get#method1::T*>* #this) → () →* self::B1<self::B2|get#method1::T*>*
+ return () → self::B1<self::B2|get#method1::T*>* => self::B2|method1<self::B2|get#method1::T*>(#this);
+static method B2|method2<T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::B1<self::B2|method2::T*>* #this, self::B2|method2::S* o) → self::B1<self::B2|method2::T*>* {
core::print(o);
return #this;
}
+static method B2|get#method2<T extends core::Object* = dynamic>(final self::B1<self::B2|get#method2::T*>* #this) → <S extends core::Object* = dynamic>(S*) →* self::B1<self::B2|get#method2::T*>*
+ return <S extends core::Object* = dynamic>(S* o) → self::B1<self::B2|get#method2::T*>* => self::B2|method2<self::B2|get#method2::T*, S*>(#this, o);
static method main() → dynamic {}
constants {
diff --git a/pkg/front_end/testcases/extensions/instance_tearoff.dart b/pkg/front_end/testcases/extensions/instance_tearoff.dart
new file mode 100644
index 0000000..9689df3
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/instance_tearoff.dart
@@ -0,0 +1,91 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Class1 {
+ int field;
+
+ Class1(this.field);
+
+ String toString() => 'Class1($field)';
+}
+
+class Class2 {
+ int field;
+
+ Class2(this.field);
+
+ String toString() => 'Class2($field)';
+}
+
+extension Extension1 on Class1 {
+ int method() {
+ print('Extension1.method on $this');
+ return field;
+ }
+ int genericMethod<T extends num>(T t) {
+ print('Extension1.genericMethod<$T>($t) on $this');
+ return field + t;
+ }
+}
+
+
+extension Extension2 on Class2 {
+ int method() {
+ print('Extension2.method on $this');
+ return field + 2;
+ }
+ int genericMethod<T extends num>(T t) {
+ print('Extension2.genericMethod<$T>($t) on $this');
+ return field + t + 3;
+ }
+}
+
+main() {
+ testExtension1();
+ testExtension2();
+}
+
+testExtension1() {
+ Class1 c0 = new Class1(0);
+ Class1 c1 = new Class1(1);
+ var tearOff0 = c0.method;
+ expect(0, tearOff0());
+ c0 = new Class1(-4);
+ expect(0, tearOff0());
+ var tearOff1 = c1.method;
+ expect(1, tearOff1());
+ c1 = new Class1(-7);
+ expect(1, tearOff1());
+ var genericTearOff0 = c0.genericMethod;
+ expect(38, genericTearOff0(42));
+ expect(38, genericTearOff0<num>(42));
+ var genericTearOff1 = c1.genericMethod;
+ expect(35, genericTearOff1(42));
+ expect(35, genericTearOff1<num>(42));
+}
+
+testExtension2() {
+ Class2 c0 = new Class2(0);
+ Class2 c1 = new Class2(1);
+ var tearOff0 = c0.method;
+ expect(2, tearOff0());
+ c0 = new Class2(-4);
+ expect(2, tearOff0());
+ var tearOff1 = c1.method;
+ expect(3, tearOff1());
+ c1 = new Class2(-7);
+ expect(3, tearOff1());
+ var genericTearOff0 = c0.genericMethod;
+ expect(41, genericTearOff0(42));
+ expect(41, genericTearOff0<num>(42));
+ var genericTearOff1 = c1.genericMethod;
+ expect(38, genericTearOff1(42));
+ expect(38, genericTearOff1<num>(42));
+}
+
+expect(expected, actual) {
+ if (expected != actual) {
+ throw 'Mismatch: expected=$expected, actual=$actual';
+ }
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/instance_tearoff.dart.outline.expect b/pkg/front_end/testcases/extensions/instance_tearoff.dart.outline.expect
new file mode 100644
index 0000000..d50804e
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/instance_tearoff.dart.outline.expect
@@ -0,0 +1,54 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ field core::int* field;
+ constructor •(core::int* field) → self::Class1*
+ ;
+ method toString() → core::String*
+ ;
+}
+class Class2 extends core::Object {
+ field core::int* field;
+ constructor •(core::int* field) → self::Class2*
+ ;
+ method toString() → core::String*
+ ;
+}
+extension Extension1 on self::Class1* {
+ method method = self::Extension1|method;
+ tearoff method = self::Extension1|get#method;
+ method genericMethod = self::Extension1|genericMethod;
+ tearoff genericMethod = self::Extension1|get#genericMethod;
+}
+extension Extension2 on self::Class2* {
+ method method = self::Extension2|method;
+ tearoff method = self::Extension2|get#method;
+ method genericMethod = self::Extension2|genericMethod;
+ tearoff genericMethod = self::Extension2|get#genericMethod;
+}
+static method Extension1|method(final self::Class1* #this) → core::int*
+ ;
+static method Extension1|get#method(final self::Class1* #this) → () →* core::int*
+ return () → core::int* => self::Extension1|method(#this);
+static method Extension1|genericMethod<T extends core::num* = dynamic>(final self::Class1* #this, self::Extension1|genericMethod::T* t) → core::int*
+ ;
+static method Extension1|get#genericMethod(final self::Class1* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+ return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension1|genericMethod<T*>(#this, t);
+static method Extension2|method(final self::Class2* #this) → core::int*
+ ;
+static method Extension2|get#method(final self::Class2* #this) → () →* core::int*
+ return () → core::int* => self::Extension2|method(#this);
+static method Extension2|genericMethod<T extends core::num* = dynamic>(final self::Class2* #this, self::Extension2|genericMethod::T* t) → core::int*
+ ;
+static method Extension2|get#genericMethod(final self::Class2* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+ return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension2|genericMethod<T*>(#this, t);
+static method main() → dynamic
+ ;
+static method testExtension1() → dynamic
+ ;
+static method testExtension2() → dynamic
+ ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+ ;
diff --git a/pkg/front_end/testcases/extensions/instance_tearoff.dart.strong.expect b/pkg/front_end/testcases/extensions/instance_tearoff.dart.strong.expect
new file mode 100644
index 0000000..be0799d
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/instance_tearoff.dart.strong.expect
@@ -0,0 +1,101 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ field core::int* field;
+ constructor •(core::int* field) → self::Class1*
+ : self::Class1::field = field, super core::Object::•()
+ ;
+ method toString() → core::String*
+ return "Class1(${this.{self::Class1::field}})";
+}
+class Class2 extends core::Object {
+ field core::int* field;
+ constructor •(core::int* field) → self::Class2*
+ : self::Class2::field = field, super core::Object::•()
+ ;
+ method toString() → core::String*
+ return "Class2(${this.{self::Class2::field}})";
+}
+extension Extension1 on self::Class1* {
+ method method = self::Extension1|method;
+ tearoff method = self::Extension1|get#method;
+ method genericMethod = self::Extension1|genericMethod;
+ tearoff genericMethod = self::Extension1|get#genericMethod;
+}
+extension Extension2 on self::Class2* {
+ method method = self::Extension2|method;
+ tearoff method = self::Extension2|get#method;
+ method genericMethod = self::Extension2|genericMethod;
+ tearoff genericMethod = self::Extension2|get#genericMethod;
+}
+static method Extension1|method(final self::Class1* #this) → core::int* {
+ core::print("Extension1.method on ${#this}");
+ return #this.{self::Class1::field};
+}
+static method Extension1|get#method(final self::Class1* #this) → () →* core::int*
+ return () → core::int* => self::Extension1|method(#this);
+static method Extension1|genericMethod<T extends core::num* = dynamic>(final self::Class1* #this, self::Extension1|genericMethod::T* t) → core::int* {
+ core::print("Extension1.genericMethod<${self::Extension1|genericMethod::T*}>(${t}) on ${#this}");
+ return #this.{self::Class1::field}.{core::num::+}(t) as{TypeError} core::int*;
+}
+static method Extension1|get#genericMethod(final self::Class1* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+ return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension1|genericMethod<T*>(#this, t);
+static method Extension2|method(final self::Class2* #this) → core::int* {
+ core::print("Extension2.method on ${#this}");
+ return #this.{self::Class2::field}.{core::num::+}(2);
+}
+static method Extension2|get#method(final self::Class2* #this) → () →* core::int*
+ return () → core::int* => self::Extension2|method(#this);
+static method Extension2|genericMethod<T extends core::num* = dynamic>(final self::Class2* #this, self::Extension2|genericMethod::T* t) → core::int* {
+ core::print("Extension2.genericMethod<${self::Extension2|genericMethod::T*}>(${t}) on ${#this}");
+ return #this.{self::Class2::field}.{core::num::+}(t).{core::num::+}(3) as{TypeError} core::int*;
+}
+static method Extension2|get#genericMethod(final self::Class2* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+ return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension2|genericMethod<T*>(#this, t);
+static method main() → dynamic {
+ self::testExtension1();
+ self::testExtension2();
+}
+static method testExtension1() → dynamic {
+ self::Class1* c0 = new self::Class1::•(0);
+ self::Class1* c1 = new self::Class1::•(1);
+ () →* core::int* tearOff0 = self::Extension1|get#method(c0);
+ self::expect(0, tearOff0.call());
+ c0 = new self::Class1::•(4.{core::int::unary-}());
+ self::expect(0, tearOff0.call());
+ () →* core::int* tearOff1 = self::Extension1|get#method(c1);
+ self::expect(1, tearOff1.call());
+ c1 = new self::Class1::•(7.{core::int::unary-}());
+ self::expect(1, tearOff1.call());
+ <T extends core::num* = dynamic>(self::Extension1|genericMethod::T*) →* core::int* genericTearOff0 = self::Extension1|get#genericMethod(c0);
+ self::expect(38, genericTearOff0.call<core::int*>(42));
+ self::expect(38, genericTearOff0.call<core::num*>(42));
+ <T extends core::num* = dynamic>(self::Extension1|genericMethod::T*) →* core::int* genericTearOff1 = self::Extension1|get#genericMethod(c1);
+ self::expect(35, genericTearOff1.call<core::int*>(42));
+ self::expect(35, genericTearOff1.call<core::num*>(42));
+}
+static method testExtension2() → dynamic {
+ self::Class2* c0 = new self::Class2::•(0);
+ self::Class2* c1 = new self::Class2::•(1);
+ () →* core::int* tearOff0 = self::Extension2|get#method(c0);
+ self::expect(2, tearOff0.call());
+ c0 = new self::Class2::•(4.{core::int::unary-}());
+ self::expect(2, tearOff0.call());
+ () →* core::int* tearOff1 = self::Extension2|get#method(c1);
+ self::expect(3, tearOff1.call());
+ c1 = new self::Class2::•(7.{core::int::unary-}());
+ self::expect(3, tearOff1.call());
+ <T extends core::num* = dynamic>(self::Extension2|genericMethod::T*) →* core::int* genericTearOff0 = self::Extension2|get#genericMethod(c0);
+ self::expect(41, genericTearOff0.call<core::int*>(42));
+ self::expect(41, genericTearOff0.call<core::num*>(42));
+ <T extends core::num* = dynamic>(self::Extension2|genericMethod::T*) →* core::int* genericTearOff1 = self::Extension2|get#genericMethod(c1);
+ self::expect(38, genericTearOff1.call<core::int*>(42));
+ self::expect(38, genericTearOff1.call<core::num*>(42));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!expected.{core::Object::==}(actual)) {
+ throw "Mismatch: expected=${expected}, actual=${actual}";
+ }
+}
diff --git a/pkg/front_end/testcases/extensions/instance_tearoff.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/instance_tearoff.dart.strong.transformed.expect
new file mode 100644
index 0000000..be0799d
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/instance_tearoff.dart.strong.transformed.expect
@@ -0,0 +1,101 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ field core::int* field;
+ constructor •(core::int* field) → self::Class1*
+ : self::Class1::field = field, super core::Object::•()
+ ;
+ method toString() → core::String*
+ return "Class1(${this.{self::Class1::field}})";
+}
+class Class2 extends core::Object {
+ field core::int* field;
+ constructor •(core::int* field) → self::Class2*
+ : self::Class2::field = field, super core::Object::•()
+ ;
+ method toString() → core::String*
+ return "Class2(${this.{self::Class2::field}})";
+}
+extension Extension1 on self::Class1* {
+ method method = self::Extension1|method;
+ tearoff method = self::Extension1|get#method;
+ method genericMethod = self::Extension1|genericMethod;
+ tearoff genericMethod = self::Extension1|get#genericMethod;
+}
+extension Extension2 on self::Class2* {
+ method method = self::Extension2|method;
+ tearoff method = self::Extension2|get#method;
+ method genericMethod = self::Extension2|genericMethod;
+ tearoff genericMethod = self::Extension2|get#genericMethod;
+}
+static method Extension1|method(final self::Class1* #this) → core::int* {
+ core::print("Extension1.method on ${#this}");
+ return #this.{self::Class1::field};
+}
+static method Extension1|get#method(final self::Class1* #this) → () →* core::int*
+ return () → core::int* => self::Extension1|method(#this);
+static method Extension1|genericMethod<T extends core::num* = dynamic>(final self::Class1* #this, self::Extension1|genericMethod::T* t) → core::int* {
+ core::print("Extension1.genericMethod<${self::Extension1|genericMethod::T*}>(${t}) on ${#this}");
+ return #this.{self::Class1::field}.{core::num::+}(t) as{TypeError} core::int*;
+}
+static method Extension1|get#genericMethod(final self::Class1* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+ return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension1|genericMethod<T*>(#this, t);
+static method Extension2|method(final self::Class2* #this) → core::int* {
+ core::print("Extension2.method on ${#this}");
+ return #this.{self::Class2::field}.{core::num::+}(2);
+}
+static method Extension2|get#method(final self::Class2* #this) → () →* core::int*
+ return () → core::int* => self::Extension2|method(#this);
+static method Extension2|genericMethod<T extends core::num* = dynamic>(final self::Class2* #this, self::Extension2|genericMethod::T* t) → core::int* {
+ core::print("Extension2.genericMethod<${self::Extension2|genericMethod::T*}>(${t}) on ${#this}");
+ return #this.{self::Class2::field}.{core::num::+}(t).{core::num::+}(3) as{TypeError} core::int*;
+}
+static method Extension2|get#genericMethod(final self::Class2* #this) → <T extends core::num* = dynamic>(T*) →* core::int*
+ return <T extends core::num* = dynamic>(T* t) → core::int* => self::Extension2|genericMethod<T*>(#this, t);
+static method main() → dynamic {
+ self::testExtension1();
+ self::testExtension2();
+}
+static method testExtension1() → dynamic {
+ self::Class1* c0 = new self::Class1::•(0);
+ self::Class1* c1 = new self::Class1::•(1);
+ () →* core::int* tearOff0 = self::Extension1|get#method(c0);
+ self::expect(0, tearOff0.call());
+ c0 = new self::Class1::•(4.{core::int::unary-}());
+ self::expect(0, tearOff0.call());
+ () →* core::int* tearOff1 = self::Extension1|get#method(c1);
+ self::expect(1, tearOff1.call());
+ c1 = new self::Class1::•(7.{core::int::unary-}());
+ self::expect(1, tearOff1.call());
+ <T extends core::num* = dynamic>(self::Extension1|genericMethod::T*) →* core::int* genericTearOff0 = self::Extension1|get#genericMethod(c0);
+ self::expect(38, genericTearOff0.call<core::int*>(42));
+ self::expect(38, genericTearOff0.call<core::num*>(42));
+ <T extends core::num* = dynamic>(self::Extension1|genericMethod::T*) →* core::int* genericTearOff1 = self::Extension1|get#genericMethod(c1);
+ self::expect(35, genericTearOff1.call<core::int*>(42));
+ self::expect(35, genericTearOff1.call<core::num*>(42));
+}
+static method testExtension2() → dynamic {
+ self::Class2* c0 = new self::Class2::•(0);
+ self::Class2* c1 = new self::Class2::•(1);
+ () →* core::int* tearOff0 = self::Extension2|get#method(c0);
+ self::expect(2, tearOff0.call());
+ c0 = new self::Class2::•(4.{core::int::unary-}());
+ self::expect(2, tearOff0.call());
+ () →* core::int* tearOff1 = self::Extension2|get#method(c1);
+ self::expect(3, tearOff1.call());
+ c1 = new self::Class2::•(7.{core::int::unary-}());
+ self::expect(3, tearOff1.call());
+ <T extends core::num* = dynamic>(self::Extension2|genericMethod::T*) →* core::int* genericTearOff0 = self::Extension2|get#genericMethod(c0);
+ self::expect(41, genericTearOff0.call<core::int*>(42));
+ self::expect(41, genericTearOff0.call<core::num*>(42));
+ <T extends core::num* = dynamic>(self::Extension2|genericMethod::T*) →* core::int* genericTearOff1 = self::Extension2|get#genericMethod(c1);
+ self::expect(38, genericTearOff1.call<core::int*>(42));
+ self::expect(38, genericTearOff1.call<core::num*>(42));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!expected.{core::Object::==}(actual)) {
+ throw "Mismatch: expected=${expected}, actual=${actual}";
+ }
+}
diff --git a/pkg/front_end/testcases/extensions/instance_tearoff.dart.type_promotion.expect b/pkg/front_end/testcases/extensions/instance_tearoff.dart.type_promotion.expect
new file mode 100644
index 0000000..675c36c
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/instance_tearoff.dart.type_promotion.expect
@@ -0,0 +1,12 @@
+pkg/front_end/testcases/extensions/instance_tearoff.dart:54:6: Context: Write to c0@978
+ c0 = new Class1(-4);
+ ^
+pkg/front_end/testcases/extensions/instance_tearoff.dart:58:6: Context: Write to c1@1007
+ c1 = new Class1(-7);
+ ^
+pkg/front_end/testcases/extensions/instance_tearoff.dart:73:6: Context: Write to c0@1494
+ c0 = new Class2(-4);
+ ^
+pkg/front_end/testcases/extensions/instance_tearoff.dart:77:6: Context: Write to c1@1523
+ c1 = new Class2(-7);
+ ^
diff --git a/pkg/front_end/testcases/extensions/invalid_explicit_access.dart b/pkg/front_end/testcases/extensions/invalid_explicit_access.dart
new file mode 100644
index 0000000..5210e3a
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/invalid_explicit_access.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Class {}
+
+extension Extension on Class {
+ method(a) {}
+}
+
+class GenericClass<T> {}
+
+extension GenericExtension<T> on GenericClass<T> {
+ method() {}
+}
+
+
+
+main() {
+ String s = '';
+
+ Class c1 = new Class();
+ Extension().method(null);
+ Extension(c1, null).method(null);
+ Extension(receiver: c1).method(null);
+ Extension(c1, receiver: null).method(null);
+ Extension<int>(c1).method(null);
+ Extension(s).method(null);
+ Extension(c1).foo;
+ Extension(c1).foo = null;
+ Extension(c1).foo();
+ Extension(c1).method();
+ // TODO(johnniwinther): Report argument/parameter count corresponding to
+ // the source code/declaration, not the converted invocation.
+ // TODO(johnniwinther): Use the declaration name length for the squiggly.
+ Extension(c1).method(1, 2);
+ Extension(c1).method(a: 1);
+ Extension(c1).method(1, a: 2);
+ Extension(c1).method<int>(null);
+
+ GenericClass<int> c2 = new GenericClass<int>();
+ GenericExtension().method();
+ GenericExtension<int>().method();
+ GenericExtension(c2, null).method();
+ GenericExtension<int>(c2, null).method();
+ GenericExtension(receiver: c2).method();
+ GenericExtension<int>(receiver: c2).method();
+ GenericExtension(c2, receiver: null).method();
+ GenericExtension<int>(c2, receiver: null).method();
+ GenericExtension<int, String>(c2).method();
+ GenericExtension(s).method();
+ GenericExtension<int>(s).method();
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/invalid_explicit_access.dart.outline.expect b/pkg/front_end/testcases/extensions/invalid_explicit_access.dart.outline.expect
new file mode 100644
index 0000000..ff612da
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/invalid_explicit_access.dart.outline.expect
@@ -0,0 +1,30 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+ synthetic constructor •() → self::Class*
+ ;
+}
+class GenericClass<T extends core::Object* = dynamic> extends core::Object {
+ synthetic constructor •() → self::GenericClass<self::GenericClass::T*>*
+ ;
+}
+extension Extension on self::Class* {
+ method method = self::Extension|method;
+ tearoff method = self::Extension|get#method;
+}
+extension GenericExtension<T extends core::Object* = dynamic> on self::GenericClass<T*>* {
+ method method = self::GenericExtension|method;
+ tearoff method = self::GenericExtension|get#method;
+}
+static method Extension|method(final self::Class* #this, dynamic a) → dynamic
+ ;
+static method Extension|get#method(final self::Class* #this) → (dynamic) →* dynamic
+ return (dynamic a) → dynamic => self::Extension|method(#this, a);
+static method GenericExtension|method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|method::T*>* #this) → dynamic
+ ;
+static method GenericExtension|get#method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#method::T*>* #this) → () →* dynamic
+ return () → dynamic => self::GenericExtension|method<self::GenericExtension|get#method::T*>(#this);
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/extensions/invalid_explicit_access.dart.strong.expect b/pkg/front_end/testcases/extensions/invalid_explicit_access.dart.strong.expect
new file mode 100644
index 0000000..b24b206
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/invalid_explicit_access.dart.strong.expect
@@ -0,0 +1,240 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:23:3: Error: Explicit extension application requires exactly 1 positional argument.
+// Extension().method(null);
+// ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:24:3: Error: Explicit extension application requires exactly 1 positional argument.
+// Extension(c1, null).method(null);
+// ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:25:3: Error: Explicit extension application requires exactly 1 positional argument.
+// Extension(receiver: c1).method(null);
+// ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:26:3: Error: Explicit extension application requires exactly 1 positional argument.
+// Extension(c1, receiver: null).method(null);
+// ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:27:3: Error: Explicit extension application of extension 'Extension' takes '0' type argument(s).
+// Extension<int>(c1).method(null);
+// ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:29:3: Error: Getter not found: 'foo'.
+// Extension(c1).foo;
+// ^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:30:3: Error: Setter not found: 'foo'.
+// Extension(c1).foo = null;
+// ^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:31:3: Error: Getter not found: 'foo'.
+// Extension(c1).foo();
+// ^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:32:3: Error: Too few positional arguments: 2 required, 1 given.
+// Extension(c1).method();
+// ^
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:8:3: Context: Found this candidate, but the arguments don't match.
+// method(a) {}
+// ^^^^^^^^^^^^^...
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:36:3: Error: Too many positional arguments: 2 allowed, but 3 found.
+// Try removing the extra positional arguments.
+// Extension(c1).method(1, 2);
+// ^
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:8:3: Context: Found this candidate, but the arguments don't match.
+// method(a) {}
+// ^^^^^^^^^^^^^...
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:37:3: Error: Too few positional arguments: 2 required, 1 given.
+// Extension(c1).method(a: 1);
+// ^
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:8:3: Context: Found this candidate, but the arguments don't match.
+// method(a) {}
+// ^^^^^^^^^^^^^...
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:38:27: Error: No named parameter with the name 'a'.
+// Extension(c1).method(1, a: 2);
+// ^
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:8:3: Context: Found this candidate, but the arguments don't match.
+// method(a) {}
+// ^^^^^^^^^^^^^...
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:39:3: Error: Expected 0 type arguments.
+// Extension(c1).method<int>(null);
+// ^
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:8:3: Context: Found this candidate, but the arguments don't match.
+// method(a) {}
+// ^^^^^^^^^^^^^...
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:42:3: Error: Explicit extension application requires exactly 1 positional argument.
+// GenericExtension().method();
+// ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:43:3: Error: Explicit extension application requires exactly 1 positional argument.
+// GenericExtension<int>().method();
+// ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:44:3: Error: Explicit extension application requires exactly 1 positional argument.
+// GenericExtension(c2, null).method();
+// ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:45:3: Error: Explicit extension application requires exactly 1 positional argument.
+// GenericExtension<int>(c2, null).method();
+// ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:46:3: Error: Explicit extension application requires exactly 1 positional argument.
+// GenericExtension(receiver: c2).method();
+// ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:47:3: Error: Explicit extension application requires exactly 1 positional argument.
+// GenericExtension<int>(receiver: c2).method();
+// ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:48:3: Error: Explicit extension application requires exactly 1 positional argument.
+// GenericExtension(c2, receiver: null).method();
+// ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:49:3: Error: Explicit extension application requires exactly 1 positional argument.
+// GenericExtension<int>(c2, receiver: null).method();
+// ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:50:3: Error: Explicit extension application of extension 'GenericExtension' takes '1' type argument(s).
+// GenericExtension<int, String>(c2).method();
+// ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:28:13: Error: The argument type 'String' can't be assigned to the parameter type 'Class'.
+// - 'Class' is from 'pkg/front_end/testcases/extensions/invalid_explicit_access.dart'.
+// Try changing the type of the parameter, or casting the argument to 'Class'.
+// Extension(s).method(null);
+// ^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:51:20: Error: The argument type 'String' can't be assigned to the parameter type 'GenericClass<dynamic>'.
+// - 'GenericClass' is from 'pkg/front_end/testcases/extensions/invalid_explicit_access.dart'.
+// Try changing the type of the parameter, or casting the argument to 'GenericClass<dynamic>'.
+// GenericExtension(s).method();
+// ^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:52:25: Error: The argument type 'String' can't be assigned to the parameter type 'GenericClass<int>'.
+// - 'GenericClass' is from 'pkg/front_end/testcases/extensions/invalid_explicit_access.dart'.
+// Try changing the type of the parameter, or casting the argument to 'GenericClass<int>'.
+// GenericExtension<int>(s).method();
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+ synthetic constructor •() → self::Class*
+ : super core::Object::•()
+ ;
+}
+class GenericClass<T extends core::Object* = dynamic> extends core::Object {
+ synthetic constructor •() → self::GenericClass<self::GenericClass::T*>*
+ : super core::Object::•()
+ ;
+}
+extension Extension on self::Class* {
+ method method = self::Extension|method;
+ tearoff method = self::Extension|get#method;
+}
+extension GenericExtension<T extends core::Object* = dynamic> on self::GenericClass<T*>* {
+ method method = self::GenericExtension|method;
+ tearoff method = self::GenericExtension|get#method;
+}
+static method Extension|method(final self::Class* #this, dynamic a) → dynamic {}
+static method Extension|get#method(final self::Class* #this) → (dynamic) →* dynamic
+ return (dynamic a) → dynamic => self::Extension|method(#this, a);
+static method GenericExtension|method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|method::T*>* #this) → dynamic {}
+static method GenericExtension|get#method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#method::T*>* #this) → () →* dynamic
+ return () → dynamic => self::GenericExtension|method<self::GenericExtension|get#method::T*>(#this);
+static method main() → dynamic {
+ core::String* s = "";
+ self::Class* c1 = new self::Class::•();
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:23:3: Error: Explicit extension application requires exactly 1 positional argument.
+ Extension().method(null);
+ ^^^^^^^^^".method(null);
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:24:3: Error: Explicit extension application requires exactly 1 positional argument.
+ Extension(c1, null).method(null);
+ ^^^^^^^^^".method(null);
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:25:3: Error: Explicit extension application requires exactly 1 positional argument.
+ Extension(receiver: c1).method(null);
+ ^^^^^^^^^".method(null);
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:26:3: Error: Explicit extension application requires exactly 1 positional argument.
+ Extension(c1, receiver: null).method(null);
+ ^^^^^^^^^".method(null);
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:27:3: Error: Explicit extension application of extension 'Extension' takes '0' type argument(s).
+ Extension<int>(c1).method(null);
+ ^^^^^^^^^".method(null);
+ self::Extension|method(let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:28:13: Error: The argument type 'String' can't be assigned to the parameter type 'Class'.
+ - 'Class' is from 'pkg/front_end/testcases/extensions/invalid_explicit_access.dart'.
+Try changing the type of the parameter, or casting the argument to 'Class'.
+ Extension(s).method(null);
+ ^" in s as{TypeError} self::Class*, null);
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:29:3: Error: Getter not found: 'foo'.
+ Extension(c1).foo;
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:30:3: Error: Setter not found: 'foo'.
+ Extension(c1).foo = null;
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:31:3: Error: Getter not found: 'foo'.
+ Extension(c1).foo();
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:32:3: Error: Too few positional arguments: 2 required, 1 given.
+ Extension(c1).method();
+ ^";
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:36:3: Error: Too many positional arguments: 2 allowed, but 3 found.
+Try removing the extra positional arguments.
+ Extension(c1).method(1, 2);
+ ^";
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:37:3: Error: Too few positional arguments: 2 required, 1 given.
+ Extension(c1).method(a: 1);
+ ^";
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:38:27: Error: No named parameter with the name 'a'.
+ Extension(c1).method(1, a: 2);
+ ^";
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:39:3: Error: Expected 0 type arguments.
+ Extension(c1).method<int>(null);
+ ^";
+ self::GenericClass<core::int*>* c2 = new self::GenericClass::•<core::int*>();
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:42:3: Error: Explicit extension application requires exactly 1 positional argument.
+ GenericExtension().method();
+ ^^^^^^^^^^^^^^^^".method();
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:43:3: Error: Explicit extension application requires exactly 1 positional argument.
+ GenericExtension<int>().method();
+ ^^^^^^^^^^^^^^^^".method();
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:44:3: Error: Explicit extension application requires exactly 1 positional argument.
+ GenericExtension(c2, null).method();
+ ^^^^^^^^^^^^^^^^".method();
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:45:3: Error: Explicit extension application requires exactly 1 positional argument.
+ GenericExtension<int>(c2, null).method();
+ ^^^^^^^^^^^^^^^^".method();
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:46:3: Error: Explicit extension application requires exactly 1 positional argument.
+ GenericExtension(receiver: c2).method();
+ ^^^^^^^^^^^^^^^^".method();
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:47:3: Error: Explicit extension application requires exactly 1 positional argument.
+ GenericExtension<int>(receiver: c2).method();
+ ^^^^^^^^^^^^^^^^".method();
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:48:3: Error: Explicit extension application requires exactly 1 positional argument.
+ GenericExtension(c2, receiver: null).method();
+ ^^^^^^^^^^^^^^^^".method();
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:49:3: Error: Explicit extension application requires exactly 1 positional argument.
+ GenericExtension<int>(c2, receiver: null).method();
+ ^^^^^^^^^^^^^^^^".method();
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:50:3: Error: Explicit extension application of extension 'GenericExtension' takes '1' type argument(s).
+ GenericExtension<int, String>(c2).method();
+ ^^^^^^^^^^^^^^^^".method();
+ self::GenericExtension|method<dynamic>(let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:51:20: Error: The argument type 'String' can't be assigned to the parameter type 'GenericClass<dynamic>'.
+ - 'GenericClass' is from 'pkg/front_end/testcases/extensions/invalid_explicit_access.dart'.
+Try changing the type of the parameter, or casting the argument to 'GenericClass<dynamic>'.
+ GenericExtension(s).method();
+ ^" in s as{TypeError} self::GenericClass<dynamic>*);
+ self::GenericExtension|method<core::int*>(let final<BottomType> #t3 = invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:52:25: Error: The argument type 'String' can't be assigned to the parameter type 'GenericClass<int>'.
+ - 'GenericClass' is from 'pkg/front_end/testcases/extensions/invalid_explicit_access.dart'.
+Try changing the type of the parameter, or casting the argument to 'GenericClass<int>'.
+ GenericExtension<int>(s).method();
+ ^" in s as{TypeError} self::GenericClass<core::int*>*);
+}
diff --git a/pkg/front_end/testcases/extensions/invalid_explicit_access.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/invalid_explicit_access.dart.strong.transformed.expect
new file mode 100644
index 0000000..b24b206
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/invalid_explicit_access.dart.strong.transformed.expect
@@ -0,0 +1,240 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:23:3: Error: Explicit extension application requires exactly 1 positional argument.
+// Extension().method(null);
+// ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:24:3: Error: Explicit extension application requires exactly 1 positional argument.
+// Extension(c1, null).method(null);
+// ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:25:3: Error: Explicit extension application requires exactly 1 positional argument.
+// Extension(receiver: c1).method(null);
+// ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:26:3: Error: Explicit extension application requires exactly 1 positional argument.
+// Extension(c1, receiver: null).method(null);
+// ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:27:3: Error: Explicit extension application of extension 'Extension' takes '0' type argument(s).
+// Extension<int>(c1).method(null);
+// ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:29:3: Error: Getter not found: 'foo'.
+// Extension(c1).foo;
+// ^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:30:3: Error: Setter not found: 'foo'.
+// Extension(c1).foo = null;
+// ^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:31:3: Error: Getter not found: 'foo'.
+// Extension(c1).foo();
+// ^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:32:3: Error: Too few positional arguments: 2 required, 1 given.
+// Extension(c1).method();
+// ^
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:8:3: Context: Found this candidate, but the arguments don't match.
+// method(a) {}
+// ^^^^^^^^^^^^^...
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:36:3: Error: Too many positional arguments: 2 allowed, but 3 found.
+// Try removing the extra positional arguments.
+// Extension(c1).method(1, 2);
+// ^
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:8:3: Context: Found this candidate, but the arguments don't match.
+// method(a) {}
+// ^^^^^^^^^^^^^...
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:37:3: Error: Too few positional arguments: 2 required, 1 given.
+// Extension(c1).method(a: 1);
+// ^
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:8:3: Context: Found this candidate, but the arguments don't match.
+// method(a) {}
+// ^^^^^^^^^^^^^...
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:38:27: Error: No named parameter with the name 'a'.
+// Extension(c1).method(1, a: 2);
+// ^
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:8:3: Context: Found this candidate, but the arguments don't match.
+// method(a) {}
+// ^^^^^^^^^^^^^...
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:39:3: Error: Expected 0 type arguments.
+// Extension(c1).method<int>(null);
+// ^
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:8:3: Context: Found this candidate, but the arguments don't match.
+// method(a) {}
+// ^^^^^^^^^^^^^...
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:42:3: Error: Explicit extension application requires exactly 1 positional argument.
+// GenericExtension().method();
+// ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:43:3: Error: Explicit extension application requires exactly 1 positional argument.
+// GenericExtension<int>().method();
+// ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:44:3: Error: Explicit extension application requires exactly 1 positional argument.
+// GenericExtension(c2, null).method();
+// ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:45:3: Error: Explicit extension application requires exactly 1 positional argument.
+// GenericExtension<int>(c2, null).method();
+// ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:46:3: Error: Explicit extension application requires exactly 1 positional argument.
+// GenericExtension(receiver: c2).method();
+// ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:47:3: Error: Explicit extension application requires exactly 1 positional argument.
+// GenericExtension<int>(receiver: c2).method();
+// ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:48:3: Error: Explicit extension application requires exactly 1 positional argument.
+// GenericExtension(c2, receiver: null).method();
+// ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:49:3: Error: Explicit extension application requires exactly 1 positional argument.
+// GenericExtension<int>(c2, receiver: null).method();
+// ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:50:3: Error: Explicit extension application of extension 'GenericExtension' takes '1' type argument(s).
+// GenericExtension<int, String>(c2).method();
+// ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:28:13: Error: The argument type 'String' can't be assigned to the parameter type 'Class'.
+// - 'Class' is from 'pkg/front_end/testcases/extensions/invalid_explicit_access.dart'.
+// Try changing the type of the parameter, or casting the argument to 'Class'.
+// Extension(s).method(null);
+// ^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:51:20: Error: The argument type 'String' can't be assigned to the parameter type 'GenericClass<dynamic>'.
+// - 'GenericClass' is from 'pkg/front_end/testcases/extensions/invalid_explicit_access.dart'.
+// Try changing the type of the parameter, or casting the argument to 'GenericClass<dynamic>'.
+// GenericExtension(s).method();
+// ^
+//
+// pkg/front_end/testcases/extensions/invalid_explicit_access.dart:52:25: Error: The argument type 'String' can't be assigned to the parameter type 'GenericClass<int>'.
+// - 'GenericClass' is from 'pkg/front_end/testcases/extensions/invalid_explicit_access.dart'.
+// Try changing the type of the parameter, or casting the argument to 'GenericClass<int>'.
+// GenericExtension<int>(s).method();
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+ synthetic constructor •() → self::Class*
+ : super core::Object::•()
+ ;
+}
+class GenericClass<T extends core::Object* = dynamic> extends core::Object {
+ synthetic constructor •() → self::GenericClass<self::GenericClass::T*>*
+ : super core::Object::•()
+ ;
+}
+extension Extension on self::Class* {
+ method method = self::Extension|method;
+ tearoff method = self::Extension|get#method;
+}
+extension GenericExtension<T extends core::Object* = dynamic> on self::GenericClass<T*>* {
+ method method = self::GenericExtension|method;
+ tearoff method = self::GenericExtension|get#method;
+}
+static method Extension|method(final self::Class* #this, dynamic a) → dynamic {}
+static method Extension|get#method(final self::Class* #this) → (dynamic) →* dynamic
+ return (dynamic a) → dynamic => self::Extension|method(#this, a);
+static method GenericExtension|method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|method::T*>* #this) → dynamic {}
+static method GenericExtension|get#method<T extends core::Object* = dynamic>(final self::GenericClass<self::GenericExtension|get#method::T*>* #this) → () →* dynamic
+ return () → dynamic => self::GenericExtension|method<self::GenericExtension|get#method::T*>(#this);
+static method main() → dynamic {
+ core::String* s = "";
+ self::Class* c1 = new self::Class::•();
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:23:3: Error: Explicit extension application requires exactly 1 positional argument.
+ Extension().method(null);
+ ^^^^^^^^^".method(null);
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:24:3: Error: Explicit extension application requires exactly 1 positional argument.
+ Extension(c1, null).method(null);
+ ^^^^^^^^^".method(null);
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:25:3: Error: Explicit extension application requires exactly 1 positional argument.
+ Extension(receiver: c1).method(null);
+ ^^^^^^^^^".method(null);
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:26:3: Error: Explicit extension application requires exactly 1 positional argument.
+ Extension(c1, receiver: null).method(null);
+ ^^^^^^^^^".method(null);
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:27:3: Error: Explicit extension application of extension 'Extension' takes '0' type argument(s).
+ Extension<int>(c1).method(null);
+ ^^^^^^^^^".method(null);
+ self::Extension|method(let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:28:13: Error: The argument type 'String' can't be assigned to the parameter type 'Class'.
+ - 'Class' is from 'pkg/front_end/testcases/extensions/invalid_explicit_access.dart'.
+Try changing the type of the parameter, or casting the argument to 'Class'.
+ Extension(s).method(null);
+ ^" in s as{TypeError} self::Class*, null);
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:29:3: Error: Getter not found: 'foo'.
+ Extension(c1).foo;
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:30:3: Error: Setter not found: 'foo'.
+ Extension(c1).foo = null;
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:31:3: Error: Getter not found: 'foo'.
+ Extension(c1).foo();
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:32:3: Error: Too few positional arguments: 2 required, 1 given.
+ Extension(c1).method();
+ ^";
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:36:3: Error: Too many positional arguments: 2 allowed, but 3 found.
+Try removing the extra positional arguments.
+ Extension(c1).method(1, 2);
+ ^";
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:37:3: Error: Too few positional arguments: 2 required, 1 given.
+ Extension(c1).method(a: 1);
+ ^";
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:38:27: Error: No named parameter with the name 'a'.
+ Extension(c1).method(1, a: 2);
+ ^";
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:39:3: Error: Expected 0 type arguments.
+ Extension(c1).method<int>(null);
+ ^";
+ self::GenericClass<core::int*>* c2 = new self::GenericClass::•<core::int*>();
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:42:3: Error: Explicit extension application requires exactly 1 positional argument.
+ GenericExtension().method();
+ ^^^^^^^^^^^^^^^^".method();
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:43:3: Error: Explicit extension application requires exactly 1 positional argument.
+ GenericExtension<int>().method();
+ ^^^^^^^^^^^^^^^^".method();
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:44:3: Error: Explicit extension application requires exactly 1 positional argument.
+ GenericExtension(c2, null).method();
+ ^^^^^^^^^^^^^^^^".method();
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:45:3: Error: Explicit extension application requires exactly 1 positional argument.
+ GenericExtension<int>(c2, null).method();
+ ^^^^^^^^^^^^^^^^".method();
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:46:3: Error: Explicit extension application requires exactly 1 positional argument.
+ GenericExtension(receiver: c2).method();
+ ^^^^^^^^^^^^^^^^".method();
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:47:3: Error: Explicit extension application requires exactly 1 positional argument.
+ GenericExtension<int>(receiver: c2).method();
+ ^^^^^^^^^^^^^^^^".method();
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:48:3: Error: Explicit extension application requires exactly 1 positional argument.
+ GenericExtension(c2, receiver: null).method();
+ ^^^^^^^^^^^^^^^^".method();
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:49:3: Error: Explicit extension application requires exactly 1 positional argument.
+ GenericExtension<int>(c2, receiver: null).method();
+ ^^^^^^^^^^^^^^^^".method();
+ invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:50:3: Error: Explicit extension application of extension 'GenericExtension' takes '1' type argument(s).
+ GenericExtension<int, String>(c2).method();
+ ^^^^^^^^^^^^^^^^".method();
+ self::GenericExtension|method<dynamic>(let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:51:20: Error: The argument type 'String' can't be assigned to the parameter type 'GenericClass<dynamic>'.
+ - 'GenericClass' is from 'pkg/front_end/testcases/extensions/invalid_explicit_access.dart'.
+Try changing the type of the parameter, or casting the argument to 'GenericClass<dynamic>'.
+ GenericExtension(s).method();
+ ^" in s as{TypeError} self::GenericClass<dynamic>*);
+ self::GenericExtension|method<core::int*>(let final<BottomType> #t3 = invalid-expression "pkg/front_end/testcases/extensions/invalid_explicit_access.dart:52:25: Error: The argument type 'String' can't be assigned to the parameter type 'GenericClass<int>'.
+ - 'GenericClass' is from 'pkg/front_end/testcases/extensions/invalid_explicit_access.dart'.
+Try changing the type of the parameter, or casting the argument to 'GenericClass<int>'.
+ GenericExtension<int>(s).method();
+ ^" in s as{TypeError} self::GenericClass<core::int*>*);
+}
diff --git a/pkg/front_end/testcases/extensions/nested_on_types.dart b/pkg/front_end/testcases/extensions/nested_on_types.dart
new file mode 100644
index 0000000..f0cbdc1
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/nested_on_types.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class A<T> {}
+
+extension Extension<T> on A<A<T>> {
+ method1() {}
+
+ method2<A>(A a) {}
+}
+
+main() {
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/nested_on_types.dart.outline.expect b/pkg/front_end/testcases/extensions/nested_on_types.dart.outline.expect
new file mode 100644
index 0000000..dae6f4a
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/nested_on_types.dart.outline.expect
@@ -0,0 +1,24 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A<T extends core::Object* = dynamic> extends core::Object {
+ synthetic constructor •() → self::A<self::A::T*>*
+ ;
+}
+extension Extension<T extends core::Object* = dynamic> on self::A<self::A<T*>*>* {
+ method method1 = self::Extension|method1;
+ tearoff method1 = self::Extension|get#method1;
+ method method2 = self::Extension|method2;
+ tearoff method2 = self::Extension|get#method2;
+}
+static method Extension|method1<T extends core::Object* = dynamic>(final self::A<self::A<self::Extension|method1::T*>*>* #this) → dynamic
+ ;
+static method Extension|get#method1<T extends core::Object* = dynamic>(final self::A<self::A<self::Extension|get#method1::T*>*>* #this) → () →* dynamic
+ return () → dynamic => self::Extension|method1<self::Extension|get#method1::T*>(#this);
+static method Extension|method2<T extends core::Object* = dynamic, A extends core::Object* = dynamic>(final self::A<self::A<self::Extension|method2::T*>*>* #this, self::Extension|method2::A* a) → dynamic
+ ;
+static method Extension|get#method2<T extends core::Object* = dynamic>(final self::A<self::A<self::Extension|get#method2::T*>*>* #this) → <A extends core::Object* = dynamic>(A*) →* dynamic
+ return <A extends core::Object* = dynamic>(A* a) → dynamic => self::Extension|method2<self::Extension|get#method2::T*, A*>(#this, a);
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/extensions/nested_on_types.dart.strong.expect b/pkg/front_end/testcases/extensions/nested_on_types.dart.strong.expect
new file mode 100644
index 0000000..6a8c1f4
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/nested_on_types.dart.strong.expect
@@ -0,0 +1,22 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A<T extends core::Object* = dynamic> extends core::Object {
+ synthetic constructor •() → self::A<self::A::T*>*
+ : super core::Object::•()
+ ;
+}
+extension Extension<T extends core::Object* = dynamic> on self::A<self::A<T*>*>* {
+ method method1 = self::Extension|method1;
+ tearoff method1 = self::Extension|get#method1;
+ method method2 = self::Extension|method2;
+ tearoff method2 = self::Extension|get#method2;
+}
+static method Extension|method1<T extends core::Object* = dynamic>(final self::A<self::A<self::Extension|method1::T*>*>* #this) → dynamic {}
+static method Extension|get#method1<T extends core::Object* = dynamic>(final self::A<self::A<self::Extension|get#method1::T*>*>* #this) → () →* dynamic
+ return () → dynamic => self::Extension|method1<self::Extension|get#method1::T*>(#this);
+static method Extension|method2<T extends core::Object* = dynamic, A extends core::Object* = dynamic>(final self::A<self::A<self::Extension|method2::T*>*>* #this, self::Extension|method2::A* a) → dynamic {}
+static method Extension|get#method2<T extends core::Object* = dynamic>(final self::A<self::A<self::Extension|get#method2::T*>*>* #this) → <A extends core::Object* = dynamic>(A*) →* dynamic
+ return <A extends core::Object* = dynamic>(A* a) → dynamic => self::Extension|method2<self::Extension|get#method2::T*, A*>(#this, a);
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extensions/nested_on_types.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/nested_on_types.dart.strong.transformed.expect
new file mode 100644
index 0000000..6a8c1f4
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/nested_on_types.dart.strong.transformed.expect
@@ -0,0 +1,22 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A<T extends core::Object* = dynamic> extends core::Object {
+ synthetic constructor •() → self::A<self::A::T*>*
+ : super core::Object::•()
+ ;
+}
+extension Extension<T extends core::Object* = dynamic> on self::A<self::A<T*>*>* {
+ method method1 = self::Extension|method1;
+ tearoff method1 = self::Extension|get#method1;
+ method method2 = self::Extension|method2;
+ tearoff method2 = self::Extension|get#method2;
+}
+static method Extension|method1<T extends core::Object* = dynamic>(final self::A<self::A<self::Extension|method1::T*>*>* #this) → dynamic {}
+static method Extension|get#method1<T extends core::Object* = dynamic>(final self::A<self::A<self::Extension|get#method1::T*>*>* #this) → () →* dynamic
+ return () → dynamic => self::Extension|method1<self::Extension|get#method1::T*>(#this);
+static method Extension|method2<T extends core::Object* = dynamic, A extends core::Object* = dynamic>(final self::A<self::A<self::Extension|method2::T*>*>* #this, self::Extension|method2::A* a) → dynamic {}
+static method Extension|get#method2<T extends core::Object* = dynamic>(final self::A<self::A<self::Extension|get#method2::T*>*>* #this) → <A extends core::Object* = dynamic>(A*) →* dynamic
+ return <A extends core::Object* = dynamic>(A* a) → dynamic => self::Extension|method2<self::Extension|get#method2::T*, A*>(#this, a);
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extensions/on_type_inference.dart b/pkg/front_end/testcases/extensions/on_type_inference.dart
new file mode 100644
index 0000000..2cce0dc
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/on_type_inference.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2019, 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.
+
+extension BestCom<T extends num> on Iterable<T> {
+ T best() => null;
+}
+extension BestList<T> on List<T> {
+ T best() => null;
+}
+extension BestSpec on List<num> {
+ num best() => null;
+}
+
+main() {
+ List<int> x;
+ var v = x.best();
+ List<num> y;
+ var w = y.best();
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/on_type_inference.dart.outline.expect b/pkg/front_end/testcases/extensions/on_type_inference.dart.outline.expect
new file mode 100644
index 0000000..a4e1d3c
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/on_type_inference.dart.outline.expect
@@ -0,0 +1,30 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+extension BestCom<T extends core::num* = dynamic> on core::Iterable<T*>* {
+ method best = self::BestCom|best;
+ tearoff best = self::BestCom|get#best;
+}
+extension BestList<T extends core::Object* = dynamic> on core::List<T*>* {
+ method best = self::BestList|best;
+ tearoff best = self::BestList|get#best;
+}
+extension BestSpec on core::List<core::num*>* {
+ method best = self::BestSpec|best;
+ tearoff best = self::BestSpec|get#best;
+}
+static method BestCom|best<T extends core::num* = dynamic>(final core::Iterable<self::BestCom|best::T*>* #this) → self::BestCom|best::T*
+ ;
+static method BestCom|get#best<T extends core::num* = dynamic>(final core::Iterable<self::BestCom|get#best::T*>* #this) → () →* self::BestCom|get#best::T*
+ return () → self::BestCom|get#best::T* => self::BestCom|best<self::BestCom|get#best::T*>(#this);
+static method BestList|best<T extends core::Object* = dynamic>(final core::List<self::BestList|best::T*>* #this) → self::BestList|best::T*
+ ;
+static method BestList|get#best<T extends core::Object* = dynamic>(final core::List<self::BestList|get#best::T*>* #this) → () →* self::BestList|get#best::T*
+ return () → self::BestList|get#best::T* => self::BestList|best<self::BestList|get#best::T*>(#this);
+static method BestSpec|best(final core::List<core::num*>* #this) → core::num*
+ ;
+static method BestSpec|get#best(final core::List<core::num*>* #this) → () →* core::num*
+ return () → core::num* => self::BestSpec|best(#this);
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/extensions/on_type_inference.dart.strong.expect b/pkg/front_end/testcases/extensions/on_type_inference.dart.strong.expect
new file mode 100644
index 0000000..25a3e4a
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/on_type_inference.dart.strong.expect
@@ -0,0 +1,34 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+extension BestCom<T extends core::num* = dynamic> on core::Iterable<T*>* {
+ method best = self::BestCom|best;
+ tearoff best = self::BestCom|get#best;
+}
+extension BestList<T extends core::Object* = dynamic> on core::List<T*>* {
+ method best = self::BestList|best;
+ tearoff best = self::BestList|get#best;
+}
+extension BestSpec on core::List<core::num*>* {
+ method best = self::BestSpec|best;
+ tearoff best = self::BestSpec|get#best;
+}
+static method BestCom|best<T extends core::num* = dynamic>(final core::Iterable<self::BestCom|best::T*>* #this) → self::BestCom|best::T*
+ return null;
+static method BestCom|get#best<T extends core::num* = dynamic>(final core::Iterable<self::BestCom|get#best::T*>* #this) → () →* self::BestCom|get#best::T*
+ return () → self::BestCom|get#best::T* => self::BestCom|best<self::BestCom|get#best::T*>(#this);
+static method BestList|best<T extends core::Object* = dynamic>(final core::List<self::BestList|best::T*>* #this) → self::BestList|best::T*
+ return null;
+static method BestList|get#best<T extends core::Object* = dynamic>(final core::List<self::BestList|get#best::T*>* #this) → () →* self::BestList|get#best::T*
+ return () → self::BestList|get#best::T* => self::BestList|best<self::BestList|get#best::T*>(#this);
+static method BestSpec|best(final core::List<core::num*>* #this) → core::num*
+ return null;
+static method BestSpec|get#best(final core::List<core::num*>* #this) → () →* core::num*
+ return () → core::num* => self::BestSpec|best(#this);
+static method main() → dynamic {
+ core::List<core::int*>* x;
+ core::int* v = self::BestList|best<core::int*>(x);
+ core::List<core::num*>* y;
+ core::num* w = self::BestSpec|best(y);
+}
diff --git a/pkg/front_end/testcases/extensions/on_type_inference.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/on_type_inference.dart.strong.transformed.expect
new file mode 100644
index 0000000..25a3e4a
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/on_type_inference.dart.strong.transformed.expect
@@ -0,0 +1,34 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+extension BestCom<T extends core::num* = dynamic> on core::Iterable<T*>* {
+ method best = self::BestCom|best;
+ tearoff best = self::BestCom|get#best;
+}
+extension BestList<T extends core::Object* = dynamic> on core::List<T*>* {
+ method best = self::BestList|best;
+ tearoff best = self::BestList|get#best;
+}
+extension BestSpec on core::List<core::num*>* {
+ method best = self::BestSpec|best;
+ tearoff best = self::BestSpec|get#best;
+}
+static method BestCom|best<T extends core::num* = dynamic>(final core::Iterable<self::BestCom|best::T*>* #this) → self::BestCom|best::T*
+ return null;
+static method BestCom|get#best<T extends core::num* = dynamic>(final core::Iterable<self::BestCom|get#best::T*>* #this) → () →* self::BestCom|get#best::T*
+ return () → self::BestCom|get#best::T* => self::BestCom|best<self::BestCom|get#best::T*>(#this);
+static method BestList|best<T extends core::Object* = dynamic>(final core::List<self::BestList|best::T*>* #this) → self::BestList|best::T*
+ return null;
+static method BestList|get#best<T extends core::Object* = dynamic>(final core::List<self::BestList|get#best::T*>* #this) → () →* self::BestList|get#best::T*
+ return () → self::BestList|get#best::T* => self::BestList|best<self::BestList|get#best::T*>(#this);
+static method BestSpec|best(final core::List<core::num*>* #this) → core::num*
+ return null;
+static method BestSpec|get#best(final core::List<core::num*>* #this) → () →* core::num*
+ return () → core::num* => self::BestSpec|best(#this);
+static method main() → dynamic {
+ core::List<core::int*>* x;
+ core::int* v = self::BestList|best<core::int*>(x);
+ core::List<core::num*>* y;
+ core::num* w = self::BestSpec|best(y);
+}
diff --git a/pkg/front_end/testcases/extensions/on_type_variable_inference.dart b/pkg/front_end/testcases/extensions/on_type_variable_inference.dart
new file mode 100644
index 0000000..a56cd04
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/on_type_variable_inference.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Struct {}
+
+class StructA extends Struct {}
+
+class StructB extends Struct {}
+
+class NonStruct {}
+
+extension Extension<T extends Struct> on T {
+ T method() => this;
+ T get property => this;
+ void set property(T value) {}
+}
+
+main() {
+ Struct struct;
+ StructA structA;
+ StructB structB;
+
+ struct.method();
+ struct.property = structA.property;
+ structA.method();
+ structA.property = struct.property;
+ structB.method();
+ structB.property = structB.property;
+
+ new Struct().method();
+ new Struct().property;
+ new Struct().property = null;
+ new StructA().method();
+ new StructA().property;
+ new StructA().property = null;
+ new StructB().method();
+ new StructB().property;
+ new StructB().property = null;
+}
+
+testNonStruct() {
+ NonStruct nonStruct;
+ nonStruct.method();
+ nonStruct.property = nonStruct.property;
+ new NonStruct().method();
+ new NonStruct().property;
+ new NonStruct().property = null;
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/on_type_variable_inference.dart.outline.expect b/pkg/front_end/testcases/extensions/on_type_variable_inference.dart.outline.expect
new file mode 100644
index 0000000..2cb9786
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/on_type_variable_inference.dart.outline.expect
@@ -0,0 +1,38 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Struct extends core::Object {
+ synthetic constructor •() → self::Struct*
+ ;
+}
+class StructA extends self::Struct {
+ synthetic constructor •() → self::StructA*
+ ;
+}
+class StructB extends self::Struct {
+ synthetic constructor •() → self::StructB*
+ ;
+}
+class NonStruct extends core::Object {
+ synthetic constructor •() → self::NonStruct*
+ ;
+}
+extension Extension<T extends self::Struct* = dynamic> on T* {
+ method method = self::Extension|method;
+ tearoff method = self::Extension|get#method;
+ get property = self::Extension|get#property;
+ set property = self::Extension|set#property;
+}
+static method Extension|method<T extends self::Struct* = dynamic>(final self::Extension|method::T* #this) → self::Extension|method::T*
+ ;
+static method Extension|get#method<T extends self::Struct* = dynamic>(final self::Extension|get#method::T* #this) → () →* self::Extension|get#method::T*
+ return () → self::Extension|get#method::T* => self::Extension|method<self::Extension|get#method::T*>(#this);
+static method Extension|get#property<T extends self::Struct* = dynamic>(final self::Extension|get#property::T* #this) → self::Extension|get#property::T*
+ ;
+static method Extension|set#property<T extends self::Struct* = dynamic>(final self::Extension|set#property::T* #this, self::Extension|set#property::T* value) → void
+ ;
+static method main() → dynamic
+ ;
+static method testNonStruct() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/extensions/on_type_variable_inference.dart.strong.expect b/pkg/front_end/testcases/extensions/on_type_variable_inference.dart.strong.expect
new file mode 100644
index 0000000..7860276
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/on_type_variable_inference.dart.strong.expect
@@ -0,0 +1,127 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/on_type_variable_inference.dart:44:13: Error: The method 'method' isn't defined for the class 'NonStruct'.
+// - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+// Try correcting the name to the name of an existing method, or defining a method named 'method'.
+// nonStruct.method();
+// ^^^^^^
+//
+// pkg/front_end/testcases/extensions/on_type_variable_inference.dart:45:13: Error: The setter 'property' isn't defined for the class 'NonStruct'.
+// - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'property'.
+// nonStruct.property = nonStruct.property;
+// ^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/on_type_variable_inference.dart:45:34: Error: The getter 'property' isn't defined for the class 'NonStruct'.
+// - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'property'.
+// nonStruct.property = nonStruct.property;
+// ^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/on_type_variable_inference.dart:46:19: Error: The method 'method' isn't defined for the class 'NonStruct'.
+// - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+// Try correcting the name to the name of an existing method, or defining a method named 'method'.
+// new NonStruct().method();
+// ^^^^^^
+//
+// pkg/front_end/testcases/extensions/on_type_variable_inference.dart:47:19: Error: The getter 'property' isn't defined for the class 'NonStruct'.
+// - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'property'.
+// new NonStruct().property;
+// ^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/on_type_variable_inference.dart:48:19: Error: The setter 'property' isn't defined for the class 'NonStruct'.
+// - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'property'.
+// new NonStruct().property = null;
+// ^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class Struct extends core::Object {
+ synthetic constructor •() → self::Struct*
+ : super core::Object::•()
+ ;
+}
+class StructA extends self::Struct {
+ synthetic constructor •() → self::StructA*
+ : super self::Struct::•()
+ ;
+}
+class StructB extends self::Struct {
+ synthetic constructor •() → self::StructB*
+ : super self::Struct::•()
+ ;
+}
+class NonStruct extends core::Object {
+ synthetic constructor •() → self::NonStruct*
+ : super core::Object::•()
+ ;
+}
+extension Extension<T extends self::Struct* = dynamic> on T* {
+ method method = self::Extension|method;
+ tearoff method = self::Extension|get#method;
+ get property = self::Extension|get#property;
+ set property = self::Extension|set#property;
+}
+static method Extension|method<T extends self::Struct* = dynamic>(final self::Extension|method::T* #this) → self::Extension|method::T*
+ return #this;
+static method Extension|get#method<T extends self::Struct* = dynamic>(final self::Extension|get#method::T* #this) → () →* self::Extension|get#method::T*
+ return () → self::Extension|get#method::T* => self::Extension|method<self::Extension|get#method::T*>(#this);
+static method Extension|get#property<T extends self::Struct* = dynamic>(final self::Extension|get#property::T* #this) → self::Extension|get#property::T*
+ return #this;
+static method Extension|set#property<T extends self::Struct* = dynamic>(final self::Extension|set#property::T* #this, self::Extension|set#property::T* value) → self::Extension|set#property::T* {
+ final self::Extension|set#property::T* #t1 = value;
+ return #t1;
+}
+static method main() → dynamic {
+ self::Struct* struct;
+ self::StructA* structA;
+ self::StructB* structB;
+ self::Extension|method<self::Struct*>(struct);
+ self::Extension|set#property<self::Struct*>(struct, self::Extension|get#property<self::StructA*>(structA));
+ self::Extension|method<self::StructA*>(structA);
+ self::Extension|set#property<self::StructA*>(structA, self::Extension|get#property<self::Struct*>(struct));
+ self::Extension|method<self::StructB*>(structB);
+ self::Extension|set#property<self::StructB*>(structB, self::Extension|get#property<self::StructB*>(structB));
+ self::Extension|method<self::Struct*>(new self::Struct::•());
+ self::Extension|get#property<self::Struct*>(new self::Struct::•());
+ self::Extension|set#property<self::Struct*>(new self::Struct::•(), null);
+ self::Extension|method<self::StructA*>(new self::StructA::•());
+ self::Extension|get#property<self::StructA*>(new self::StructA::•());
+ self::Extension|set#property<self::StructA*>(new self::StructA::•(), null);
+ self::Extension|method<self::StructB*>(new self::StructB::•());
+ self::Extension|get#property<self::StructB*>(new self::StructB::•());
+ self::Extension|set#property<self::StructB*>(new self::StructB::•(), null);
+}
+static method testNonStruct() → dynamic {
+ self::NonStruct* nonStruct;
+ invalid-expression "pkg/front_end/testcases/extensions/on_type_variable_inference.dart:44:13: Error: The method 'method' isn't defined for the class 'NonStruct'.
+ - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+Try correcting the name to the name of an existing method, or defining a method named 'method'.
+ nonStruct.method();
+ ^^^^^^";
+ invalid-expression "pkg/front_end/testcases/extensions/on_type_variable_inference.dart:45:13: Error: The setter 'property' isn't defined for the class 'NonStruct'.
+ - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'property'.
+ nonStruct.property = nonStruct.property;
+ ^^^^^^^^";
+ invalid-expression "pkg/front_end/testcases/extensions/on_type_variable_inference.dart:46:19: Error: The method 'method' isn't defined for the class 'NonStruct'.
+ - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+Try correcting the name to the name of an existing method, or defining a method named 'method'.
+ new NonStruct().method();
+ ^^^^^^";
+ invalid-expression "pkg/front_end/testcases/extensions/on_type_variable_inference.dart:47:19: Error: The getter 'property' isn't defined for the class 'NonStruct'.
+ - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'property'.
+ new NonStruct().property;
+ ^^^^^^^^";
+ invalid-expression "pkg/front_end/testcases/extensions/on_type_variable_inference.dart:48:19: Error: The setter 'property' isn't defined for the class 'NonStruct'.
+ - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'property'.
+ new NonStruct().property = null;
+ ^^^^^^^^";
+}
diff --git a/pkg/front_end/testcases/extensions/on_type_variable_inference.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/on_type_variable_inference.dart.strong.transformed.expect
new file mode 100644
index 0000000..7860276
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/on_type_variable_inference.dart.strong.transformed.expect
@@ -0,0 +1,127 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/on_type_variable_inference.dart:44:13: Error: The method 'method' isn't defined for the class 'NonStruct'.
+// - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+// Try correcting the name to the name of an existing method, or defining a method named 'method'.
+// nonStruct.method();
+// ^^^^^^
+//
+// pkg/front_end/testcases/extensions/on_type_variable_inference.dart:45:13: Error: The setter 'property' isn't defined for the class 'NonStruct'.
+// - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'property'.
+// nonStruct.property = nonStruct.property;
+// ^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/on_type_variable_inference.dart:45:34: Error: The getter 'property' isn't defined for the class 'NonStruct'.
+// - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'property'.
+// nonStruct.property = nonStruct.property;
+// ^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/on_type_variable_inference.dart:46:19: Error: The method 'method' isn't defined for the class 'NonStruct'.
+// - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+// Try correcting the name to the name of an existing method, or defining a method named 'method'.
+// new NonStruct().method();
+// ^^^^^^
+//
+// pkg/front_end/testcases/extensions/on_type_variable_inference.dart:47:19: Error: The getter 'property' isn't defined for the class 'NonStruct'.
+// - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'property'.
+// new NonStruct().property;
+// ^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/on_type_variable_inference.dart:48:19: Error: The setter 'property' isn't defined for the class 'NonStruct'.
+// - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'property'.
+// new NonStruct().property = null;
+// ^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class Struct extends core::Object {
+ synthetic constructor •() → self::Struct*
+ : super core::Object::•()
+ ;
+}
+class StructA extends self::Struct {
+ synthetic constructor •() → self::StructA*
+ : super self::Struct::•()
+ ;
+}
+class StructB extends self::Struct {
+ synthetic constructor •() → self::StructB*
+ : super self::Struct::•()
+ ;
+}
+class NonStruct extends core::Object {
+ synthetic constructor •() → self::NonStruct*
+ : super core::Object::•()
+ ;
+}
+extension Extension<T extends self::Struct* = dynamic> on T* {
+ method method = self::Extension|method;
+ tearoff method = self::Extension|get#method;
+ get property = self::Extension|get#property;
+ set property = self::Extension|set#property;
+}
+static method Extension|method<T extends self::Struct* = dynamic>(final self::Extension|method::T* #this) → self::Extension|method::T*
+ return #this;
+static method Extension|get#method<T extends self::Struct* = dynamic>(final self::Extension|get#method::T* #this) → () →* self::Extension|get#method::T*
+ return () → self::Extension|get#method::T* => self::Extension|method<self::Extension|get#method::T*>(#this);
+static method Extension|get#property<T extends self::Struct* = dynamic>(final self::Extension|get#property::T* #this) → self::Extension|get#property::T*
+ return #this;
+static method Extension|set#property<T extends self::Struct* = dynamic>(final self::Extension|set#property::T* #this, self::Extension|set#property::T* value) → self::Extension|set#property::T* {
+ final self::Extension|set#property::T* #t1 = value;
+ return #t1;
+}
+static method main() → dynamic {
+ self::Struct* struct;
+ self::StructA* structA;
+ self::StructB* structB;
+ self::Extension|method<self::Struct*>(struct);
+ self::Extension|set#property<self::Struct*>(struct, self::Extension|get#property<self::StructA*>(structA));
+ self::Extension|method<self::StructA*>(structA);
+ self::Extension|set#property<self::StructA*>(structA, self::Extension|get#property<self::Struct*>(struct));
+ self::Extension|method<self::StructB*>(structB);
+ self::Extension|set#property<self::StructB*>(structB, self::Extension|get#property<self::StructB*>(structB));
+ self::Extension|method<self::Struct*>(new self::Struct::•());
+ self::Extension|get#property<self::Struct*>(new self::Struct::•());
+ self::Extension|set#property<self::Struct*>(new self::Struct::•(), null);
+ self::Extension|method<self::StructA*>(new self::StructA::•());
+ self::Extension|get#property<self::StructA*>(new self::StructA::•());
+ self::Extension|set#property<self::StructA*>(new self::StructA::•(), null);
+ self::Extension|method<self::StructB*>(new self::StructB::•());
+ self::Extension|get#property<self::StructB*>(new self::StructB::•());
+ self::Extension|set#property<self::StructB*>(new self::StructB::•(), null);
+}
+static method testNonStruct() → dynamic {
+ self::NonStruct* nonStruct;
+ invalid-expression "pkg/front_end/testcases/extensions/on_type_variable_inference.dart:44:13: Error: The method 'method' isn't defined for the class 'NonStruct'.
+ - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+Try correcting the name to the name of an existing method, or defining a method named 'method'.
+ nonStruct.method();
+ ^^^^^^";
+ invalid-expression "pkg/front_end/testcases/extensions/on_type_variable_inference.dart:45:13: Error: The setter 'property' isn't defined for the class 'NonStruct'.
+ - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'property'.
+ nonStruct.property = nonStruct.property;
+ ^^^^^^^^";
+ invalid-expression "pkg/front_end/testcases/extensions/on_type_variable_inference.dart:46:19: Error: The method 'method' isn't defined for the class 'NonStruct'.
+ - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+Try correcting the name to the name of an existing method, or defining a method named 'method'.
+ new NonStruct().method();
+ ^^^^^^";
+ invalid-expression "pkg/front_end/testcases/extensions/on_type_variable_inference.dart:47:19: Error: The getter 'property' isn't defined for the class 'NonStruct'.
+ - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'property'.
+ new NonStruct().property;
+ ^^^^^^^^";
+ invalid-expression "pkg/front_end/testcases/extensions/on_type_variable_inference.dart:48:19: Error: The setter 'property' isn't defined for the class 'NonStruct'.
+ - 'NonStruct' is from 'pkg/front_end/testcases/extensions/on_type_variable_inference.dart'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'property'.
+ new NonStruct().property = null;
+ ^^^^^^^^";
+}
diff --git a/pkg/front_end/testcases/extensions/operators.dart b/pkg/front_end/testcases/extensions/operators.dart
new file mode 100644
index 0000000..cbb3b41
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/operators.dart
@@ -0,0 +1,84 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Complex {
+ final double real;
+ final double imaginary;
+
+ const Complex(this.real, this.imaginary);
+
+ Complex add(Complex other) {
+ return new Complex(real + other.real, imaginary + other.imaginary);
+ }
+
+ Complex sub(Complex other) {
+ return new Complex(real - other.real, imaginary - other.imaginary);
+ }
+
+ Complex negate() {
+ return new Complex(-real, -imaginary);
+ }
+
+ int get hashCode => real.hashCode * 13 + imaginary.hashCode * 19;
+
+ bool operator ==(Object other) {
+ if (identical(this, other)) return true;
+ return other is Complex &&
+ real == other.real &&
+ imaginary == other.imaginary;
+ }
+
+ String toString() => 'Complex($real,$imaginary)';
+}
+
+extension Operators on Complex {
+ Complex operator +(Complex other) => add(other);
+ Complex operator -(Complex other) => sub(other);
+ Complex operator -() => negate();
+}
+
+main() {
+ Complex c_m2 = new Complex(-2, 2);
+ Complex c_m1 = new Complex(-1, 1);
+ Complex c0 = new Complex(0, 0);
+ Complex c1 = new Complex(1, -1);
+ Complex c2 = new Complex(2, -2);
+
+ expect(c_m2, c0 + c_m2);
+ expect(c_m2, c_m2 + c0);
+ expect(c_m2, c_m1 + c_m1);
+ expect(c_m1, c0 + c_m1);
+ expect(c_m1, c_m1 + c0);
+ expect(c0, c_m2 + c2);
+ expect(c0, c2 + c_m2);
+ expect(c0, c_m1 + c1);
+ expect(c0, c1 + c_m1);
+ expect(c0, c0 + c0);
+ expect(c1, c0 + c1);
+ expect(c1, c1 + c0);
+ expect(c2, c0 + c2);
+ expect(c2, c2 + c0);
+ expect(c2, c1 + c1);
+
+ expect(c_m2, c0 - c2);
+ expect(c2, c2 - c0);
+ expect(c_m2, -c2);
+ expect(c_m1, c1 - c2);
+ expect(c1, c2 - c1);
+ expect(c_m1, c0 - c1);
+ expect(c1, c1 - c0);
+ expect(c_m1, -c1);
+ expect(c0, c2 - c2);
+ expect(c0, c1 - c1);
+ expect(c0, c0 - c0);
+ expect(c0, c_m1 - c_m1);
+ expect(c0, c_m2 - c_m2);
+ expect(c0, -c0);
+}
+
+expect(expected, actual) {
+ if (expected != actual) {
+ throw 'Mismatch: expected=$expected, actual=$actual';
+ }
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/operators.dart.outline.expect b/pkg/front_end/testcases/extensions/operators.dart.outline.expect
new file mode 100644
index 0000000..bfa897a
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/operators.dart.outline.expect
@@ -0,0 +1,38 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Complex extends core::Object {
+ final field core::double* real;
+ final field core::double* imaginary;
+ const constructor •(core::double* real, core::double* imaginary) → self::Complex*
+ : self::Complex::real = real, self::Complex::imaginary = imaginary, super core::Object::•()
+ ;
+ method add(self::Complex* other) → self::Complex*
+ ;
+ method sub(self::Complex* other) → self::Complex*
+ ;
+ method negate() → self::Complex*
+ ;
+ get hashCode() → core::int*
+ ;
+ operator ==(core::Object* other) → core::bool*
+ ;
+ method toString() → core::String*
+ ;
+}
+extension Operators on self::Complex* {
+ operator + = self::Operators|+;
+ operator - = self::Operators|-;
+ operator unary- = self::Operators|unary-;
+}
+static method Operators|+(final self::Complex* #this, self::Complex* other) → self::Complex*
+ ;
+static method Operators|-(final self::Complex* #this, self::Complex* other) → self::Complex*
+ ;
+static method Operators|unary-(final self::Complex* #this) → self::Complex*
+ ;
+static method main() → dynamic
+ ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+ ;
diff --git a/pkg/front_end/testcases/extensions/operators.dart.strong.expect b/pkg/front_end/testcases/extensions/operators.dart.strong.expect
new file mode 100644
index 0000000..936cc18
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/operators.dart.strong.expect
@@ -0,0 +1,81 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Complex extends core::Object {
+ final field core::double* real;
+ final field core::double* imaginary;
+ const constructor •(core::double* real, core::double* imaginary) → self::Complex*
+ : self::Complex::real = real, self::Complex::imaginary = imaginary, super core::Object::•()
+ ;
+ method add(self::Complex* other) → self::Complex* {
+ return new self::Complex::•(this.{self::Complex::real}.{core::double::+}(other.{self::Complex::real}), this.{self::Complex::imaginary}.{core::double::+}(other.{self::Complex::imaginary}));
+ }
+ method sub(self::Complex* other) → self::Complex* {
+ return new self::Complex::•(this.{self::Complex::real}.{core::double::-}(other.{self::Complex::real}), this.{self::Complex::imaginary}.{core::double::-}(other.{self::Complex::imaginary}));
+ }
+ method negate() → self::Complex* {
+ return new self::Complex::•(this.{self::Complex::real}.{core::double::unary-}(), this.{self::Complex::imaginary}.{core::double::unary-}());
+ }
+ get hashCode() → core::int*
+ return this.{self::Complex::real}.{core::num::hashCode}.{core::num::*}(13).{core::num::+}(this.{self::Complex::imaginary}.{core::num::hashCode}.{core::num::*}(19));
+ operator ==(core::Object* other) → core::bool* {
+ if(core::identical(this, other))
+ return true;
+ return other is self::Complex* && this.{self::Complex::real}.{core::num::==}(other{self::Complex*}.{self::Complex::real}) && this.{self::Complex::imaginary}.{core::num::==}(other{self::Complex*}.{self::Complex::imaginary});
+ }
+ method toString() → core::String*
+ return "Complex(${this.{self::Complex::real}},${this.{self::Complex::imaginary}})";
+}
+extension Operators on self::Complex* {
+ operator + = self::Operators|+;
+ operator - = self::Operators|-;
+ operator unary- = self::Operators|unary-;
+}
+static method Operators|+(final self::Complex* #this, self::Complex* other) → self::Complex*
+ return #this.{self::Complex::add}(other);
+static method Operators|-(final self::Complex* #this, self::Complex* other) → self::Complex*
+ return #this.{self::Complex::sub}(other);
+static method Operators|unary-(final self::Complex* #this) → self::Complex*
+ return #this.{self::Complex::negate}();
+static method main() → dynamic {
+ self::Complex* c_m2 = new self::Complex::•(-2.0, 2.0);
+ self::Complex* c_m1 = new self::Complex::•(-1.0, 1.0);
+ self::Complex* c0 = new self::Complex::•(0.0, 0.0);
+ self::Complex* c1 = new self::Complex::•(1.0, -1.0);
+ self::Complex* c2 = new self::Complex::•(2.0, -2.0);
+ self::expect(c_m2, self::Operators|+(c0, c_m2));
+ self::expect(c_m2, self::Operators|+(c_m2, c0));
+ self::expect(c_m2, self::Operators|+(c_m1, c_m1));
+ self::expect(c_m1, self::Operators|+(c0, c_m1));
+ self::expect(c_m1, self::Operators|+(c_m1, c0));
+ self::expect(c0, self::Operators|+(c_m2, c2));
+ self::expect(c0, self::Operators|+(c2, c_m2));
+ self::expect(c0, self::Operators|+(c_m1, c1));
+ self::expect(c0, self::Operators|+(c1, c_m1));
+ self::expect(c0, self::Operators|+(c0, c0));
+ self::expect(c1, self::Operators|+(c0, c1));
+ self::expect(c1, self::Operators|+(c1, c0));
+ self::expect(c2, self::Operators|+(c0, c2));
+ self::expect(c2, self::Operators|+(c2, c0));
+ self::expect(c2, self::Operators|+(c1, c1));
+ self::expect(c_m2, self::Operators|-(c0, c2));
+ self::expect(c2, self::Operators|-(c2, c0));
+ self::expect(c_m2, self::Operators|unary-(c2));
+ self::expect(c_m1, self::Operators|-(c1, c2));
+ self::expect(c1, self::Operators|-(c2, c1));
+ self::expect(c_m1, self::Operators|-(c0, c1));
+ self::expect(c1, self::Operators|-(c1, c0));
+ self::expect(c_m1, self::Operators|unary-(c1));
+ self::expect(c0, self::Operators|-(c2, c2));
+ self::expect(c0, self::Operators|-(c1, c1));
+ self::expect(c0, self::Operators|-(c0, c0));
+ self::expect(c0, self::Operators|-(c_m1, c_m1));
+ self::expect(c0, self::Operators|-(c_m2, c_m2));
+ self::expect(c0, self::Operators|unary-(c0));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!expected.{core::Object::==}(actual)) {
+ throw "Mismatch: expected=${expected}, actual=${actual}";
+ }
+}
diff --git a/pkg/front_end/testcases/extensions/operators.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/operators.dart.strong.transformed.expect
new file mode 100644
index 0000000..936cc18
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/operators.dart.strong.transformed.expect
@@ -0,0 +1,81 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Complex extends core::Object {
+ final field core::double* real;
+ final field core::double* imaginary;
+ const constructor •(core::double* real, core::double* imaginary) → self::Complex*
+ : self::Complex::real = real, self::Complex::imaginary = imaginary, super core::Object::•()
+ ;
+ method add(self::Complex* other) → self::Complex* {
+ return new self::Complex::•(this.{self::Complex::real}.{core::double::+}(other.{self::Complex::real}), this.{self::Complex::imaginary}.{core::double::+}(other.{self::Complex::imaginary}));
+ }
+ method sub(self::Complex* other) → self::Complex* {
+ return new self::Complex::•(this.{self::Complex::real}.{core::double::-}(other.{self::Complex::real}), this.{self::Complex::imaginary}.{core::double::-}(other.{self::Complex::imaginary}));
+ }
+ method negate() → self::Complex* {
+ return new self::Complex::•(this.{self::Complex::real}.{core::double::unary-}(), this.{self::Complex::imaginary}.{core::double::unary-}());
+ }
+ get hashCode() → core::int*
+ return this.{self::Complex::real}.{core::num::hashCode}.{core::num::*}(13).{core::num::+}(this.{self::Complex::imaginary}.{core::num::hashCode}.{core::num::*}(19));
+ operator ==(core::Object* other) → core::bool* {
+ if(core::identical(this, other))
+ return true;
+ return other is self::Complex* && this.{self::Complex::real}.{core::num::==}(other{self::Complex*}.{self::Complex::real}) && this.{self::Complex::imaginary}.{core::num::==}(other{self::Complex*}.{self::Complex::imaginary});
+ }
+ method toString() → core::String*
+ return "Complex(${this.{self::Complex::real}},${this.{self::Complex::imaginary}})";
+}
+extension Operators on self::Complex* {
+ operator + = self::Operators|+;
+ operator - = self::Operators|-;
+ operator unary- = self::Operators|unary-;
+}
+static method Operators|+(final self::Complex* #this, self::Complex* other) → self::Complex*
+ return #this.{self::Complex::add}(other);
+static method Operators|-(final self::Complex* #this, self::Complex* other) → self::Complex*
+ return #this.{self::Complex::sub}(other);
+static method Operators|unary-(final self::Complex* #this) → self::Complex*
+ return #this.{self::Complex::negate}();
+static method main() → dynamic {
+ self::Complex* c_m2 = new self::Complex::•(-2.0, 2.0);
+ self::Complex* c_m1 = new self::Complex::•(-1.0, 1.0);
+ self::Complex* c0 = new self::Complex::•(0.0, 0.0);
+ self::Complex* c1 = new self::Complex::•(1.0, -1.0);
+ self::Complex* c2 = new self::Complex::•(2.0, -2.0);
+ self::expect(c_m2, self::Operators|+(c0, c_m2));
+ self::expect(c_m2, self::Operators|+(c_m2, c0));
+ self::expect(c_m2, self::Operators|+(c_m1, c_m1));
+ self::expect(c_m1, self::Operators|+(c0, c_m1));
+ self::expect(c_m1, self::Operators|+(c_m1, c0));
+ self::expect(c0, self::Operators|+(c_m2, c2));
+ self::expect(c0, self::Operators|+(c2, c_m2));
+ self::expect(c0, self::Operators|+(c_m1, c1));
+ self::expect(c0, self::Operators|+(c1, c_m1));
+ self::expect(c0, self::Operators|+(c0, c0));
+ self::expect(c1, self::Operators|+(c0, c1));
+ self::expect(c1, self::Operators|+(c1, c0));
+ self::expect(c2, self::Operators|+(c0, c2));
+ self::expect(c2, self::Operators|+(c2, c0));
+ self::expect(c2, self::Operators|+(c1, c1));
+ self::expect(c_m2, self::Operators|-(c0, c2));
+ self::expect(c2, self::Operators|-(c2, c0));
+ self::expect(c_m2, self::Operators|unary-(c2));
+ self::expect(c_m1, self::Operators|-(c1, c2));
+ self::expect(c1, self::Operators|-(c2, c1));
+ self::expect(c_m1, self::Operators|-(c0, c1));
+ self::expect(c1, self::Operators|-(c1, c0));
+ self::expect(c_m1, self::Operators|unary-(c1));
+ self::expect(c0, self::Operators|-(c2, c2));
+ self::expect(c0, self::Operators|-(c1, c1));
+ self::expect(c0, self::Operators|-(c0, c0));
+ self::expect(c0, self::Operators|-(c_m1, c_m1));
+ self::expect(c0, self::Operators|-(c_m2, c_m2));
+ self::expect(c0, self::Operators|unary-(c0));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!expected.{core::Object::==}(actual)) {
+ throw "Mismatch: expected=${expected}, actual=${actual}";
+ }
+}
diff --git a/pkg/front_end/testcases/extensions/operators.dart.type_promotion.expect b/pkg/front_end/testcases/extensions/operators.dart.type_promotion.expect
new file mode 100644
index 0000000..0cf24a9
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/operators.dart.type_promotion.expect
@@ -0,0 +1,3 @@
+pkg/front_end/testcases/extensions/operators.dart:27:18: Context: Possible promotion of other@348
+ return other is Complex &&
+ ^^
diff --git a/pkg/front_end/testcases/extensions/other_kinds.dart.strong.expect b/pkg/front_end/testcases/extensions/other_kinds.dart.strong.expect
index 6b24546..4c4e60c 100644
--- a/pkg/front_end/testcases/extensions/other_kinds.dart.strong.expect
+++ b/pkg/front_end/testcases/extensions/other_kinds.dart.strong.expect
@@ -30,8 +30,10 @@
static field core::int* A2|staticField = self::A1::getStaticField();
static method A2|get#instanceProperty(final self::A1* #this) → core::int*
return #this.{self::A1::getInstanceField}();
-static method A2|set#instanceProperty(final self::A1* #this, core::int* value) → void {
+static method A2|set#instanceProperty(final self::A1* #this, core::int* value) → core::int* {
+ final core::int* #t1 = value;
#this.{self::A1::setInstanceField}(value);
+ return #t1;
}
static method A2|+(final self::A1* #this, core::int* value) → core::int* {
return #this.{self::A1::getInstanceField}().{core::num::+}(value);
diff --git a/pkg/front_end/testcases/extensions/other_kinds.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/other_kinds.dart.strong.transformed.expect
index 6b24546..4c4e60c 100644
--- a/pkg/front_end/testcases/extensions/other_kinds.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/extensions/other_kinds.dart.strong.transformed.expect
@@ -30,8 +30,10 @@
static field core::int* A2|staticField = self::A1::getStaticField();
static method A2|get#instanceProperty(final self::A1* #this) → core::int*
return #this.{self::A1::getInstanceField}();
-static method A2|set#instanceProperty(final self::A1* #this, core::int* value) → void {
+static method A2|set#instanceProperty(final self::A1* #this, core::int* value) → core::int* {
+ final core::int* #t1 = value;
#this.{self::A1::setInstanceField}(value);
+ return #t1;
}
static method A2|+(final self::A1* #this, core::int* value) → core::int* {
return #this.{self::A1::getInstanceField}().{core::num::+}(value);
diff --git a/pkg/front_end/testcases/extensions/static_access.dart b/pkg/front_end/testcases/extensions/static_access.dart
index c31ac01..170f77e 100644
--- a/pkg/front_end/testcases/extensions/static_access.dart
+++ b/pkg/front_end/testcases/extensions/static_access.dart
@@ -10,6 +10,10 @@
static get property => 42;
static set property(value) {}
static var field;
+
+ instanceMethod() {}
+ get instanceProperty => 42;
+ set instanceProperty(value) {}
}
main() {
@@ -22,4 +26,4 @@
Extension.property = 42;
Extension.field;
Extension.field = 42;
-}
\ No newline at end of file
+}
diff --git a/pkg/front_end/testcases/extensions/static_access.dart.outline.expect b/pkg/front_end/testcases/extensions/static_access.dart.outline.expect
index 4e9dc86..840ecf2 100644
--- a/pkg/front_end/testcases/extensions/static_access.dart.outline.expect
+++ b/pkg/front_end/testcases/extensions/static_access.dart.outline.expect
@@ -11,7 +11,11 @@
static method genericMethod = self::Extension|genericMethod;
static get property = get self::Extension|property;
static field field = self::Extension|field;
+ method instanceMethod = self::Extension|instanceMethod;
+ tearoff instanceMethod = self::Extension|get#instanceMethod;
+ get instanceProperty = self::Extension|get#instanceProperty;
static set property = set self::Extension|property;
+ set instanceProperty = self::Extension|set#instanceProperty;
}
static field dynamic Extension|field;
static method Extension|method() → dynamic
@@ -22,5 +26,13 @@
;
static set Extension|property(dynamic value) → void
;
+static method Extension|instanceMethod(final self::Class* #this) → dynamic
+ ;
+static method Extension|get#instanceMethod(final self::Class* #this) → () →* dynamic
+ return () → dynamic => self::Extension|instanceMethod(#this);
+static method Extension|get#instanceProperty(final self::Class* #this) → dynamic
+ ;
+static method Extension|set#instanceProperty(final self::Class* #this, dynamic value) → void
+ ;
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/extensions/static_access.dart.strong.expect b/pkg/front_end/testcases/extensions/static_access.dart.strong.expect
index 9056365..9c616d4 100644
--- a/pkg/front_end/testcases/extensions/static_access.dart.strong.expect
+++ b/pkg/front_end/testcases/extensions/static_access.dart.strong.expect
@@ -12,7 +12,11 @@
static method genericMethod = self::Extension|genericMethod;
static get property = get self::Extension|property;
static field field = self::Extension|field;
+ method instanceMethod = self::Extension|instanceMethod;
+ tearoff instanceMethod = self::Extension|get#instanceMethod;
+ get instanceProperty = self::Extension|get#instanceProperty;
static set property = set self::Extension|property;
+ set instanceProperty = self::Extension|set#instanceProperty;
}
static field dynamic Extension|field;
static method Extension|method() → dynamic {}
@@ -20,6 +24,15 @@
static get Extension|property() → dynamic
return 42;
static set Extension|property(dynamic value) → void {}
+static method Extension|instanceMethod(final self::Class* #this) → dynamic {}
+static method Extension|get#instanceMethod(final self::Class* #this) → () →* dynamic
+ return () → dynamic => self::Extension|instanceMethod(#this);
+static method Extension|get#instanceProperty(final self::Class* #this) → dynamic
+ return 42;
+static method Extension|set#instanceProperty(final self::Class* #this, dynamic value) → dynamic {
+ final dynamic #t1 = value;
+ return #t1;
+}
static method main() → dynamic {
self::Extension|method();
self::Extension|genericMethod<core::int*>(42);
diff --git a/pkg/front_end/testcases/extensions/static_access.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/static_access.dart.strong.transformed.expect
index 9056365..9c616d4 100644
--- a/pkg/front_end/testcases/extensions/static_access.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/extensions/static_access.dart.strong.transformed.expect
@@ -12,7 +12,11 @@
static method genericMethod = self::Extension|genericMethod;
static get property = get self::Extension|property;
static field field = self::Extension|field;
+ method instanceMethod = self::Extension|instanceMethod;
+ tearoff instanceMethod = self::Extension|get#instanceMethod;
+ get instanceProperty = self::Extension|get#instanceProperty;
static set property = set self::Extension|property;
+ set instanceProperty = self::Extension|set#instanceProperty;
}
static field dynamic Extension|field;
static method Extension|method() → dynamic {}
@@ -20,6 +24,15 @@
static get Extension|property() → dynamic
return 42;
static set Extension|property(dynamic value) → void {}
+static method Extension|instanceMethod(final self::Class* #this) → dynamic {}
+static method Extension|get#instanceMethod(final self::Class* #this) → () →* dynamic
+ return () → dynamic => self::Extension|instanceMethod(#this);
+static method Extension|get#instanceProperty(final self::Class* #this) → dynamic
+ return 42;
+static method Extension|set#instanceProperty(final self::Class* #this, dynamic value) → dynamic {
+ final dynamic #t1 = value;
+ return #t1;
+}
static method main() → dynamic {
self::Extension|method();
self::Extension|genericMethod<core::int*>(42);
diff --git a/pkg/front_end/testcases/extensions/static_access_of_instance.dart b/pkg/front_end/testcases/extensions/static_access_of_instance.dart
new file mode 100644
index 0000000..606a735
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/static_access_of_instance.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Class {}
+
+extension Extension on Class {
+ instanceMethod() {}
+ get instanceProperty => 42;
+ set instanceProperty(value) {}
+}
+
+main() {
+ Extension.instanceMethod();
+ Extension.instanceMethod;
+ Extension.instanceProperty;
+ Extension.instanceProperty = 42;
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/static_access_of_instance.dart.outline.expect b/pkg/front_end/testcases/extensions/static_access_of_instance.dart.outline.expect
new file mode 100644
index 0000000..0578511
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/static_access_of_instance.dart.outline.expect
@@ -0,0 +1,24 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+ synthetic constructor •() → self::Class*
+ ;
+}
+extension Extension on self::Class* {
+ method instanceMethod = self::Extension|instanceMethod;
+ tearoff instanceMethod = self::Extension|get#instanceMethod;
+ get instanceProperty = self::Extension|get#instanceProperty;
+ set instanceProperty = self::Extension|set#instanceProperty;
+}
+static method Extension|instanceMethod(final self::Class* #this) → dynamic
+ ;
+static method Extension|get#instanceMethod(final self::Class* #this) → () →* dynamic
+ return () → dynamic => self::Extension|instanceMethod(#this);
+static method Extension|get#instanceProperty(final self::Class* #this) → dynamic
+ ;
+static method Extension|set#instanceProperty(final self::Class* #this, dynamic value) → void
+ ;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/extensions/static_access_of_instance.dart.strong.expect b/pkg/front_end/testcases/extensions/static_access_of_instance.dart.strong.expect
new file mode 100644
index 0000000..10c2dbb
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/static_access_of_instance.dart.strong.expect
@@ -0,0 +1,57 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/static_access_of_instance.dart:14:13: Error: Method not found: 'Extension.instanceMethod'.
+// Extension.instanceMethod();
+// ^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/static_access_of_instance.dart:15:13: Error: Getter not found: 'instanceMethod'.
+// Extension.instanceMethod;
+// ^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/static_access_of_instance.dart:16:13: Error: Getter not found: 'instanceProperty'.
+// Extension.instanceProperty;
+// ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/static_access_of_instance.dart:17:13: Error: Setter not found: 'instanceProperty'.
+// Extension.instanceProperty = 42;
+// ^^^^^^^^^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+ synthetic constructor •() → self::Class*
+ : super core::Object::•()
+ ;
+}
+extension Extension on self::Class* {
+ method instanceMethod = self::Extension|instanceMethod;
+ tearoff instanceMethod = self::Extension|get#instanceMethod;
+ get instanceProperty = self::Extension|get#instanceProperty;
+ set instanceProperty = self::Extension|set#instanceProperty;
+}
+static method Extension|instanceMethod(final self::Class* #this) → dynamic {}
+static method Extension|get#instanceMethod(final self::Class* #this) → () →* dynamic
+ return () → dynamic => self::Extension|instanceMethod(#this);
+static method Extension|get#instanceProperty(final self::Class* #this) → dynamic
+ return 42;
+static method Extension|set#instanceProperty(final self::Class* #this, dynamic value) → dynamic {
+ final dynamic #t1 = value;
+ return #t1;
+}
+static method main() → dynamic {
+ invalid-expression "pkg/front_end/testcases/extensions/static_access_of_instance.dart:14:13: Error: Method not found: 'Extension.instanceMethod'.
+ Extension.instanceMethod();
+ ^^^^^^^^^^^^^^";
+ invalid-expression "pkg/front_end/testcases/extensions/static_access_of_instance.dart:15:13: Error: Getter not found: 'instanceMethod'.
+ Extension.instanceMethod;
+ ^^^^^^^^^^^^^^";
+ invalid-expression "pkg/front_end/testcases/extensions/static_access_of_instance.dart:16:13: Error: Getter not found: 'instanceProperty'.
+ Extension.instanceProperty;
+ ^^^^^^^^^^^^^^^^";
+ invalid-expression "pkg/front_end/testcases/extensions/static_access_of_instance.dart:17:13: Error: Setter not found: 'instanceProperty'.
+ Extension.instanceProperty = 42;
+ ^^^^^^^^^^^^^^^^";
+}
diff --git a/pkg/front_end/testcases/extensions/static_access_of_instance.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/static_access_of_instance.dart.strong.transformed.expect
new file mode 100644
index 0000000..10c2dbb
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/static_access_of_instance.dart.strong.transformed.expect
@@ -0,0 +1,57 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/static_access_of_instance.dart:14:13: Error: Method not found: 'Extension.instanceMethod'.
+// Extension.instanceMethod();
+// ^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/static_access_of_instance.dart:15:13: Error: Getter not found: 'instanceMethod'.
+// Extension.instanceMethod;
+// ^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/static_access_of_instance.dart:16:13: Error: Getter not found: 'instanceProperty'.
+// Extension.instanceProperty;
+// ^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/static_access_of_instance.dart:17:13: Error: Setter not found: 'instanceProperty'.
+// Extension.instanceProperty = 42;
+// ^^^^^^^^^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+ synthetic constructor •() → self::Class*
+ : super core::Object::•()
+ ;
+}
+extension Extension on self::Class* {
+ method instanceMethod = self::Extension|instanceMethod;
+ tearoff instanceMethod = self::Extension|get#instanceMethod;
+ get instanceProperty = self::Extension|get#instanceProperty;
+ set instanceProperty = self::Extension|set#instanceProperty;
+}
+static method Extension|instanceMethod(final self::Class* #this) → dynamic {}
+static method Extension|get#instanceMethod(final self::Class* #this) → () →* dynamic
+ return () → dynamic => self::Extension|instanceMethod(#this);
+static method Extension|get#instanceProperty(final self::Class* #this) → dynamic
+ return 42;
+static method Extension|set#instanceProperty(final self::Class* #this, dynamic value) → dynamic {
+ final dynamic #t1 = value;
+ return #t1;
+}
+static method main() → dynamic {
+ invalid-expression "pkg/front_end/testcases/extensions/static_access_of_instance.dart:14:13: Error: Method not found: 'Extension.instanceMethod'.
+ Extension.instanceMethod();
+ ^^^^^^^^^^^^^^";
+ invalid-expression "pkg/front_end/testcases/extensions/static_access_of_instance.dart:15:13: Error: Getter not found: 'instanceMethod'.
+ Extension.instanceMethod;
+ ^^^^^^^^^^^^^^";
+ invalid-expression "pkg/front_end/testcases/extensions/static_access_of_instance.dart:16:13: Error: Getter not found: 'instanceProperty'.
+ Extension.instanceProperty;
+ ^^^^^^^^^^^^^^^^";
+ invalid-expression "pkg/front_end/testcases/extensions/static_access_of_instance.dart:17:13: Error: Setter not found: 'instanceProperty'.
+ Extension.instanceProperty = 42;
+ ^^^^^^^^^^^^^^^^";
+}
diff --git a/pkg/front_end/testcases/extensions/type_variables.dart b/pkg/front_end/testcases/extensions/type_variables.dart
index 0f784b7..bea2ded 100644
--- a/pkg/front_end/testcases/extensions/type_variables.dart
+++ b/pkg/front_end/testcases/extensions/type_variables.dart
@@ -9,8 +9,6 @@
return this;
}
- // TODO(johnniwinther): Resolve type variable uses correctly. Currently use
- // `T` here resolve to `A2.T` and the synthetically inserted type variable.
A1<T> method2<S extends A1<T>>(S o) {
print(o);
print(T);
@@ -19,7 +17,11 @@
}
}
-// TODO(johnniwinther): Support F-bounded extensions. Currently the type
-// variable is not recognized as a type within the bound.
+extension A3<T extends A1<T>> on A1<T> {
+}
+
+extension A4<T> on A1<T> {
+ method<T>() {}
+}
main() {}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/type_variables.dart.outline.expect b/pkg/front_end/testcases/extensions/type_variables.dart.outline.expect
index 3689d95..862daf8 100644
--- a/pkg/front_end/testcases/extensions/type_variables.dart.outline.expect
+++ b/pkg/front_end/testcases/extensions/type_variables.dart.outline.expect
@@ -8,11 +8,27 @@
}
extension A2<T extends core::Object* = dynamic> on self::A1<T*>* {
method method1 = self::A2|method1;
+ tearoff method1 = self::A2|get#method1;
method method2 = self::A2|method2;
+ tearoff method2 = self::A2|get#method2;
}
-static method A2|method1<#T extends core::Object* = dynamic, S extends self::A2|method1::#T = dynamic>(final self::A1<self::A2|method1::#T*>* #this) → self::A1<self::A2|method1::#T*>*
+extension A3<T extends self::A1<T*>* = dynamic> on self::A1<T*>* {
+}
+extension A4<T extends core::Object* = dynamic> on self::A1<T*>* {
+ method method = self::A4|method;
+ tearoff method = self::A4|get#method;
+}
+static method A2|method1<T extends core::Object* = dynamic, S extends self::A2|method1::T* = dynamic>(final self::A1<self::A2|method1::T*>* #this) → self::A1<self::A2|method1::T*>*
;
-static method A2|method2<#T extends core::Object* = dynamic, S extends self::A1<self::A2|method2::#T>* = dynamic>(final self::A1<self::A2|method2::#T*>* #this, self::A2|method2::S* o) → self::A1<self::A2|method2::#T*>*
+static method A2|get#method1<T extends core::Object* = dynamic>(final self::A1<self::A2|get#method1::T*>* #this) → <S extends self::A2|get#method1::T* = dynamic>() →* self::A1<self::A2|get#method1::T*>*
+ return <S extends self::A2|get#method1::T* = dynamic>() → self::A1<self::A2|get#method1::T*>* => self::A2|method1<self::A2|get#method1::T*, S*>(#this);
+static method A2|method2<T extends core::Object* = dynamic, S extends self::A1<self::A2|method2::T*>* = dynamic>(final self::A1<self::A2|method2::T*>* #this, self::A2|method2::S* o) → self::A1<self::A2|method2::T*>*
;
+static method A2|get#method2<T extends core::Object* = dynamic>(final self::A1<self::A2|get#method2::T*>* #this) → <S extends self::A1<self::A2|get#method2::T*>* = dynamic>(S*) →* self::A1<self::A2|get#method2::T*>*
+ return <S extends self::A1<self::A2|get#method2::T*>* = dynamic>(S* o) → self::A1<self::A2|get#method2::T*>* => self::A2|method2<self::A2|get#method2::T*, S*>(#this, o);
+static method A4|method<#T extends core::Object* = dynamic, T extends core::Object* = dynamic>(final self::A1<self::A4|method::#T*>* #this) → dynamic
+ ;
+static method A4|get#method<#T extends core::Object* = dynamic>(final self::A1<self::A4|get#method::#T*>* #this) → <T extends core::Object* = dynamic>() →* dynamic
+ return <T extends core::Object* = dynamic>() → dynamic => self::A4|method<self::A4|get#method::#T*, T*>(#this);
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/extensions/type_variables.dart.strong.expect b/pkg/front_end/testcases/extensions/type_variables.dart.strong.expect
index 4f6a8d5..27f3e58 100644
--- a/pkg/front_end/testcases/extensions/type_variables.dart.strong.expect
+++ b/pkg/front_end/testcases/extensions/type_variables.dart.strong.expect
@@ -9,15 +9,30 @@
}
extension A2<T extends core::Object* = dynamic> on self::A1<T*>* {
method method1 = self::A2|method1;
+ tearoff method1 = self::A2|get#method1;
method method2 = self::A2|method2;
+ tearoff method2 = self::A2|get#method2;
}
-static method A2|method1<#T extends core::Object* = dynamic, S extends self::A2|method1::#T = dynamic>(final self::A1<self::A2|method1::#T*>* #this) → self::A1<self::A2|method1::#T*>* {
+extension A3<T extends self::A1<T*>* = dynamic> on self::A1<T*>* {
+}
+extension A4<T extends core::Object* = dynamic> on self::A1<T*>* {
+ method method = self::A4|method;
+ tearoff method = self::A4|get#method;
+}
+static method A2|method1<T extends core::Object* = dynamic, S extends self::A2|method1::T* = dynamic>(final self::A1<self::A2|method1::T*>* #this) → self::A1<self::A2|method1::T*>* {
return #this;
}
-static method A2|method2<#T extends core::Object* = dynamic, S extends self::A1<self::A2|method2::#T>* = dynamic>(final self::A1<self::A2|method2::#T*>* #this, self::A2|method2::S* o) → self::A1<self::A2|method2::#T*>* {
+static method A2|get#method1<T extends core::Object* = dynamic>(final self::A1<self::A2|get#method1::T*>* #this) → <S extends self::A2|get#method1::T* = dynamic>() →* self::A1<self::A2|get#method1::T*>*
+ return <S extends self::A2|get#method1::T* = dynamic>() → self::A1<self::A2|get#method1::T*>* => self::A2|method1<self::A2|get#method1::T*, S*>(#this);
+static method A2|method2<T extends core::Object* = dynamic, S extends self::A1<self::A2|method2::T*>* = dynamic>(final self::A1<self::A2|method2::T*>* #this, self::A2|method2::S* o) → self::A1<self::A2|method2::T*>* {
core::print(o);
- core::print(self::A2|method2::#T*);
+ core::print(self::A2|method2::T*);
core::print(self::A2|method2::S*);
return #this;
}
+static method A2|get#method2<T extends core::Object* = dynamic>(final self::A1<self::A2|get#method2::T*>* #this) → <S extends self::A1<self::A2|get#method2::T*>* = dynamic>(S*) →* self::A1<self::A2|get#method2::T*>*
+ return <S extends self::A1<self::A2|get#method2::T*>* = dynamic>(S* o) → self::A1<self::A2|get#method2::T*>* => self::A2|method2<self::A2|get#method2::T*, S*>(#this, o);
+static method A4|method<#T extends core::Object* = dynamic, T extends core::Object* = dynamic>(final self::A1<self::A4|method::#T*>* #this) → dynamic {}
+static method A4|get#method<#T extends core::Object* = dynamic>(final self::A1<self::A4|get#method::#T*>* #this) → <T extends core::Object* = dynamic>() →* dynamic
+ return <T extends core::Object* = dynamic>() → dynamic => self::A4|method<self::A4|get#method::#T*, T*>(#this);
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extensions/type_variables.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/type_variables.dart.strong.transformed.expect
index 4f6a8d5..27f3e58 100644
--- a/pkg/front_end/testcases/extensions/type_variables.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/extensions/type_variables.dart.strong.transformed.expect
@@ -9,15 +9,30 @@
}
extension A2<T extends core::Object* = dynamic> on self::A1<T*>* {
method method1 = self::A2|method1;
+ tearoff method1 = self::A2|get#method1;
method method2 = self::A2|method2;
+ tearoff method2 = self::A2|get#method2;
}
-static method A2|method1<#T extends core::Object* = dynamic, S extends self::A2|method1::#T = dynamic>(final self::A1<self::A2|method1::#T*>* #this) → self::A1<self::A2|method1::#T*>* {
+extension A3<T extends self::A1<T*>* = dynamic> on self::A1<T*>* {
+}
+extension A4<T extends core::Object* = dynamic> on self::A1<T*>* {
+ method method = self::A4|method;
+ tearoff method = self::A4|get#method;
+}
+static method A2|method1<T extends core::Object* = dynamic, S extends self::A2|method1::T* = dynamic>(final self::A1<self::A2|method1::T*>* #this) → self::A1<self::A2|method1::T*>* {
return #this;
}
-static method A2|method2<#T extends core::Object* = dynamic, S extends self::A1<self::A2|method2::#T>* = dynamic>(final self::A1<self::A2|method2::#T*>* #this, self::A2|method2::S* o) → self::A1<self::A2|method2::#T*>* {
+static method A2|get#method1<T extends core::Object* = dynamic>(final self::A1<self::A2|get#method1::T*>* #this) → <S extends self::A2|get#method1::T* = dynamic>() →* self::A1<self::A2|get#method1::T*>*
+ return <S extends self::A2|get#method1::T* = dynamic>() → self::A1<self::A2|get#method1::T*>* => self::A2|method1<self::A2|get#method1::T*, S*>(#this);
+static method A2|method2<T extends core::Object* = dynamic, S extends self::A1<self::A2|method2::T*>* = dynamic>(final self::A1<self::A2|method2::T*>* #this, self::A2|method2::S* o) → self::A1<self::A2|method2::T*>* {
core::print(o);
- core::print(self::A2|method2::#T*);
+ core::print(self::A2|method2::T*);
core::print(self::A2|method2::S*);
return #this;
}
+static method A2|get#method2<T extends core::Object* = dynamic>(final self::A1<self::A2|get#method2::T*>* #this) → <S extends self::A1<self::A2|get#method2::T*>* = dynamic>(S*) →* self::A1<self::A2|get#method2::T*>*
+ return <S extends self::A1<self::A2|get#method2::T*>* = dynamic>(S* o) → self::A1<self::A2|get#method2::T*>* => self::A2|method2<self::A2|get#method2::T*, S*>(#this, o);
+static method A4|method<#T extends core::Object* = dynamic, T extends core::Object* = dynamic>(final self::A1<self::A4|method::#T*>* #this) → dynamic {}
+static method A4|get#method<#T extends core::Object* = dynamic>(final self::A1<self::A4|get#method::#T*>* #this) → <T extends core::Object* = dynamic>() →* dynamic
+ return <T extends core::Object* = dynamic>() → dynamic => self::A4|method<self::A4|get#method::#T*, T*>(#this);
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extensions/use_this.dart.outline.expect b/pkg/front_end/testcases/extensions/use_this.dart.outline.expect
index dbd8b2e..76a98246 100644
--- a/pkg/front_end/testcases/extensions/use_this.dart.outline.expect
+++ b/pkg/front_end/testcases/extensions/use_this.dart.outline.expect
@@ -12,19 +12,31 @@
}
extension A2 on self::A1* {
method method1 = self::A2|method1;
+ tearoff method1 = self::A2|get#method1;
method method2 = self::A2|method2;
+ tearoff method2 = self::A2|get#method2;
}
extension B2<T extends core::Object* = dynamic> on self::B1<T*>* {
method method1 = self::B2|method1;
+ tearoff method1 = self::B2|get#method1;
method method2 = self::B2|method2;
+ tearoff method2 = self::B2|get#method2;
}
static method A2|method1(final self::A1* #this) → self::A1*
;
+static method A2|get#method1(final self::A1* #this) → () →* self::A1*
+ return () → self::A1* => self::A2|method1(#this);
static method A2|method2<T extends core::Object* = dynamic>(final self::A1* #this, self::A2|method2::T* o) → self::A1*
;
-static method B2|method1<#T extends core::Object* = dynamic>(final self::B1<self::B2|method1::#T*>* #this) → self::B1<self::B2|method1::#T*>*
+static method A2|get#method2(final self::A1* #this) → <T extends core::Object* = dynamic>(T*) →* self::A1*
+ return <T extends core::Object* = dynamic>(T* o) → self::A1* => self::A2|method2<T*>(#this, o);
+static method B2|method1<T extends core::Object* = dynamic>(final self::B1<self::B2|method1::T*>* #this) → self::B1<self::B2|method1::T*>*
;
-static method B2|method2<#T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::B1<self::B2|method2::#T*>* #this, self::B2|method2::S* o) → self::B1<self::B2|method2::#T*>*
+static method B2|get#method1<T extends core::Object* = dynamic>(final self::B1<self::B2|get#method1::T*>* #this) → () →* self::B1<self::B2|get#method1::T*>*
+ return () → self::B1<self::B2|get#method1::T*>* => self::B2|method1<self::B2|get#method1::T*>(#this);
+static method B2|method2<T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::B1<self::B2|method2::T*>* #this, self::B2|method2::S* o) → self::B1<self::B2|method2::T*>*
;
+static method B2|get#method2<T extends core::Object* = dynamic>(final self::B1<self::B2|get#method2::T*>* #this) → <S extends core::Object* = dynamic>(S*) →* self::B1<self::B2|get#method2::T*>*
+ return <S extends core::Object* = dynamic>(S* o) → self::B1<self::B2|get#method2::T*>* => self::B2|method2<self::B2|get#method2::T*, S*>(#this, o);
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/extensions/use_this.dart.strong.expect b/pkg/front_end/testcases/extensions/use_this.dart.strong.expect
index 442c519..31c3f25 100644
--- a/pkg/front_end/testcases/extensions/use_this.dart.strong.expect
+++ b/pkg/front_end/testcases/extensions/use_this.dart.strong.expect
@@ -14,24 +14,36 @@
}
extension A2 on self::A1* {
method method1 = self::A2|method1;
+ tearoff method1 = self::A2|get#method1;
method method2 = self::A2|method2;
+ tearoff method2 = self::A2|get#method2;
}
extension B2<T extends core::Object* = dynamic> on self::B1<T*>* {
method method1 = self::B2|method1;
+ tearoff method1 = self::B2|get#method1;
method method2 = self::B2|method2;
+ tearoff method2 = self::B2|get#method2;
}
static method A2|method1(final self::A1* #this) → self::A1* {
return #this;
}
+static method A2|get#method1(final self::A1* #this) → () →* self::A1*
+ return () → self::A1* => self::A2|method1(#this);
static method A2|method2<T extends core::Object* = dynamic>(final self::A1* #this, self::A2|method2::T* o) → self::A1* {
core::print(o);
return #this;
}
-static method B2|method1<#T extends core::Object* = dynamic>(final self::B1<self::B2|method1::#T*>* #this) → self::B1<self::B2|method1::#T*>* {
+static method A2|get#method2(final self::A1* #this) → <T extends core::Object* = dynamic>(T*) →* self::A1*
+ return <T extends core::Object* = dynamic>(T* o) → self::A1* => self::A2|method2<T*>(#this, o);
+static method B2|method1<T extends core::Object* = dynamic>(final self::B1<self::B2|method1::T*>* #this) → self::B1<self::B2|method1::T*>* {
return #this;
}
-static method B2|method2<#T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::B1<self::B2|method2::#T*>* #this, self::B2|method2::S* o) → self::B1<self::B2|method2::#T*>* {
+static method B2|get#method1<T extends core::Object* = dynamic>(final self::B1<self::B2|get#method1::T*>* #this) → () →* self::B1<self::B2|get#method1::T*>*
+ return () → self::B1<self::B2|get#method1::T*>* => self::B2|method1<self::B2|get#method1::T*>(#this);
+static method B2|method2<T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::B1<self::B2|method2::T*>* #this, self::B2|method2::S* o) → self::B1<self::B2|method2::T*>* {
core::print(o);
return #this;
}
+static method B2|get#method2<T extends core::Object* = dynamic>(final self::B1<self::B2|get#method2::T*>* #this) → <S extends core::Object* = dynamic>(S*) →* self::B1<self::B2|get#method2::T*>*
+ return <S extends core::Object* = dynamic>(S* o) → self::B1<self::B2|get#method2::T*>* => self::B2|method2<self::B2|get#method2::T*, S*>(#this, o);
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extensions/use_this.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/use_this.dart.strong.transformed.expect
index 442c519..31c3f25 100644
--- a/pkg/front_end/testcases/extensions/use_this.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/extensions/use_this.dart.strong.transformed.expect
@@ -14,24 +14,36 @@
}
extension A2 on self::A1* {
method method1 = self::A2|method1;
+ tearoff method1 = self::A2|get#method1;
method method2 = self::A2|method2;
+ tearoff method2 = self::A2|get#method2;
}
extension B2<T extends core::Object* = dynamic> on self::B1<T*>* {
method method1 = self::B2|method1;
+ tearoff method1 = self::B2|get#method1;
method method2 = self::B2|method2;
+ tearoff method2 = self::B2|get#method2;
}
static method A2|method1(final self::A1* #this) → self::A1* {
return #this;
}
+static method A2|get#method1(final self::A1* #this) → () →* self::A1*
+ return () → self::A1* => self::A2|method1(#this);
static method A2|method2<T extends core::Object* = dynamic>(final self::A1* #this, self::A2|method2::T* o) → self::A1* {
core::print(o);
return #this;
}
-static method B2|method1<#T extends core::Object* = dynamic>(final self::B1<self::B2|method1::#T*>* #this) → self::B1<self::B2|method1::#T*>* {
+static method A2|get#method2(final self::A1* #this) → <T extends core::Object* = dynamic>(T*) →* self::A1*
+ return <T extends core::Object* = dynamic>(T* o) → self::A1* => self::A2|method2<T*>(#this, o);
+static method B2|method1<T extends core::Object* = dynamic>(final self::B1<self::B2|method1::T*>* #this) → self::B1<self::B2|method1::T*>* {
return #this;
}
-static method B2|method2<#T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::B1<self::B2|method2::#T*>* #this, self::B2|method2::S* o) → self::B1<self::B2|method2::#T*>* {
+static method B2|get#method1<T extends core::Object* = dynamic>(final self::B1<self::B2|get#method1::T*>* #this) → () →* self::B1<self::B2|get#method1::T*>*
+ return () → self::B1<self::B2|get#method1::T*>* => self::B2|method1<self::B2|get#method1::T*>(#this);
+static method B2|method2<T extends core::Object* = dynamic, S extends core::Object* = dynamic>(final self::B1<self::B2|method2::T*>* #this, self::B2|method2::S* o) → self::B1<self::B2|method2::T*>* {
core::print(o);
return #this;
}
+static method B2|get#method2<T extends core::Object* = dynamic>(final self::B1<self::B2|get#method2::T*>* #this) → <S extends core::Object* = dynamic>(S*) →* self::B1<self::B2|get#method2::T*>*
+ return <S extends core::Object* = dynamic>(S* o) → self::B1<self::B2|get#method2::T*>* => self::B2|method2<self::B2|get#method2::T*, S*>(#this, o);
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/general/bug37476.dart b/pkg/front_end/testcases/general/bug37476.dart
index 4483ee2..53a6f0d 100644
--- a/pkg/front_end/testcases/general/bug37476.dart
+++ b/pkg/front_end/testcases/general/bug37476.dart
@@ -23,7 +23,7 @@
main() {
try {
- a.foo /*@ checkReturn=<S extends num* = dynamic>(S) ->* void */ ();
+ a.foo /*@ checkReturn=<S extends num* = dynamic>(S*) ->* void */ ();
throw 'Expected TypeError';
} on TypeError catch (e) {
print(e);
diff --git a/pkg/front_end/testcases/general/bug37476.dart.strong.expect b/pkg/front_end/testcases/general/bug37476.dart.strong.expect
index 85d07b8..49098e1 100644
--- a/pkg/front_end/testcases/general/bug37476.dart.strong.expect
+++ b/pkg/front_end/testcases/general/bug37476.dart.strong.expect
@@ -24,7 +24,7 @@
static field self::B<core::num*>* b = new self::B::•<core::int*>();
static method main() → dynamic {
try {
- self::a.{self::A::foo}() as{TypeError} <S extends core::num* = dynamic>(S) →* void;
+ self::a.{self::A::foo}() as{TypeError} <S extends core::num* = dynamic>(S*) →* void;
throw "Expected TypeError";
}
on core::TypeError* catch(final core::TypeError* e) {
diff --git a/pkg/front_end/testcases/general/bug37476.dart.strong.transformed.expect b/pkg/front_end/testcases/general/bug37476.dart.strong.transformed.expect
index 85d07b8..49098e1 100644
--- a/pkg/front_end/testcases/general/bug37476.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/bug37476.dart.strong.transformed.expect
@@ -24,7 +24,7 @@
static field self::B<core::num*>* b = new self::B::•<core::int*>();
static method main() → dynamic {
try {
- self::a.{self::A::foo}() as{TypeError} <S extends core::num* = dynamic>(S) →* void;
+ self::a.{self::A::foo}() as{TypeError} <S extends core::num* = dynamic>(S*) →* void;
throw "Expected TypeError";
}
on core::TypeError* catch(final core::TypeError* e) {
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_01.dart b/pkg/front_end/testcases/general/error_locations/error_location_01.dart
new file mode 100644
index 0000000..84034a1
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_01.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2019, 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 'error_location_01_lib1.dart';
+import 'error_location_01_lib2.dart';
+
+main() {
+ foo();
+ bar();
+}
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_01.dart.outline.expect b/pkg/front_end/testcases/general/error_locations/error_location_01.dart.outline.expect
new file mode 100644
index 0000000..14fe62f
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_01.dart.outline.expect
@@ -0,0 +1,28 @@
+library;
+import self as self;
+
+import "org-dartlang-testcase:///error_location_01_lib1.dart";
+import "org-dartlang-testcase:///error_location_01_lib2.dart";
+
+static method main() → dynamic
+ ;
+
+library;
+import self as self2;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+ const constructor •(core::int* i) → self2::Foo*
+ : assert(i.{core::num::>}(0)), super core::Object::•()
+ ;
+}
+static method foo() → dynamic
+ ;
+
+library;
+import self as self3;
+
+import "org-dartlang-testcase:///error_location_01_lib1.dart";
+
+static method bar() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_01.dart.strong.expect b/pkg/front_end/testcases/general/error_locations/error_location_01.dart.strong.expect
new file mode 100644
index 0000000..3df9b64
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_01.dart.strong.expect
@@ -0,0 +1,44 @@
+//
+// Problems in component:
+//
+// pkg/front_end/testcases/general/error_locations/error_location_01_lib2.dart:8:9: Error: Constant evaluation error:
+// const Foo(0);
+// ^
+// pkg/front_end/testcases/general/error_locations/error_location_01_lib1.dart:6:31: Context: This assertion failed.
+// const Foo(int i) : assert(i > 0);
+// ^
+//
+library;
+import self as self;
+import "error_location_01_lib1.dart" as err;
+import "error_location_01_lib2.dart" as err2;
+
+import "org-dartlang-testcase:///error_location_01_lib1.dart";
+import "org-dartlang-testcase:///error_location_01_lib2.dart";
+
+static method main() → dynamic {
+ err::foo();
+ err2::bar();
+}
+
+library;
+import self as err;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+ const constructor •(core::int* i) → err::Foo*
+ : assert(i.{core::num::>}(0)), super core::Object::•()
+ ;
+}
+static method foo() → dynamic {
+ new err::Foo::•(0);
+}
+
+library;
+import self as err2;
+
+import "org-dartlang-testcase:///error_location_01_lib1.dart";
+
+static method bar() → dynamic {
+ invalid-expression "This assertion failed.";
+}
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_01.dart.strong.transformed.expect b/pkg/front_end/testcases/general/error_locations/error_location_01.dart.strong.transformed.expect
new file mode 100644
index 0000000..3df9b64
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_01.dart.strong.transformed.expect
@@ -0,0 +1,44 @@
+//
+// Problems in component:
+//
+// pkg/front_end/testcases/general/error_locations/error_location_01_lib2.dart:8:9: Error: Constant evaluation error:
+// const Foo(0);
+// ^
+// pkg/front_end/testcases/general/error_locations/error_location_01_lib1.dart:6:31: Context: This assertion failed.
+// const Foo(int i) : assert(i > 0);
+// ^
+//
+library;
+import self as self;
+import "error_location_01_lib1.dart" as err;
+import "error_location_01_lib2.dart" as err2;
+
+import "org-dartlang-testcase:///error_location_01_lib1.dart";
+import "org-dartlang-testcase:///error_location_01_lib2.dart";
+
+static method main() → dynamic {
+ err::foo();
+ err2::bar();
+}
+
+library;
+import self as err;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+ const constructor •(core::int* i) → err::Foo*
+ : assert(i.{core::num::>}(0)), super core::Object::•()
+ ;
+}
+static method foo() → dynamic {
+ new err::Foo::•(0);
+}
+
+library;
+import self as err2;
+
+import "org-dartlang-testcase:///error_location_01_lib1.dart";
+
+static method bar() → dynamic {
+ invalid-expression "This assertion failed.";
+}
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_01_lib1.dart b/pkg/front_end/testcases/general/error_locations/error_location_01_lib1.dart
new file mode 100644
index 0000000..5ebb8ff
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_01_lib1.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Foo {
+ const Foo(int i) : assert(i > 0);
+}
+
+foo() {
+ new Foo(0);
+}
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_01_lib2.dart b/pkg/front_end/testcases/general/error_locations/error_location_01_lib2.dart
new file mode 100644
index 0000000..e35bf9e
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_01_lib2.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2019, 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 'error_location_01_lib1.dart';
+
+bar() {
+ const Foo(0);
+}
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_02.dart b/pkg/front_end/testcases/general/error_locations/error_location_02.dart
new file mode 100644
index 0000000..938b958
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_02.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2019, 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 'error_location_02_lib1.dart';
+import 'error_location_02_lib2.dart';
+import 'error_location_02_lib3.dart';
+
+main() {
+ foo();
+ print(fooField2);
+}
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_02.dart.outline.expect b/pkg/front_end/testcases/general/error_locations/error_location_02.dart.outline.expect
new file mode 100644
index 0000000..25620a0
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_02.dart.outline.expect
@@ -0,0 +1,38 @@
+library;
+import self as self;
+
+import "org-dartlang-testcase:///error_location_02_lib1.dart";
+import "org-dartlang-testcase:///error_location_02_lib2.dart";
+import "org-dartlang-testcase:///error_location_02_lib3.dart";
+
+static method main() → dynamic
+ ;
+
+library;
+import self as self2;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+ const constructor •(core::int* i) → self2::Foo*
+ : assert(i.{core::num::>}(0)), super core::Object::•()
+ ;
+}
+static method foo() → dynamic
+ ;
+
+library;
+import self as self3;
+import "error_location_02_lib1.dart" as self2;
+
+import "org-dartlang-testcase:///error_location_02_lib1.dart";
+
+static const field self2::Foo* fooField = const self2::Foo::•(0);
+
+library;
+import self as self4;
+import "error_location_02_lib1.dart" as self2;
+import "error_location_02_lib2.dart" as self3;
+
+import "org-dartlang-testcase:///error_location_02_lib2.dart";
+
+static const field self2::Foo* fooField2 = self3::fooField;
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_02.dart.strong.expect b/pkg/front_end/testcases/general/error_locations/error_location_02.dart.strong.expect
new file mode 100644
index 0000000..efddc10
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_02.dart.strong.expect
@@ -0,0 +1,65 @@
+//
+// Problems in component:
+//
+// pkg/front_end/testcases/general/error_locations/error_location_02_lib3.dart:7:19: Error: Constant evaluation error:
+// const fooField2 = fooField;
+// ^
+// pkg/front_end/testcases/general/error_locations/error_location_02_lib1.dart:6:31: Context: This assertion failed.
+// const Foo(int i) : assert(i > 0);
+// ^
+// pkg/front_end/testcases/general/error_locations/error_location_02_lib3.dart:7:7: Context: While analyzing:
+// const fooField2 = fooField;
+// ^
+//
+// pkg/front_end/testcases/general/error_locations/error_location_02_lib2.dart:7:24: Error: Constant evaluation error:
+// const fooField = const Foo(0);
+// ^
+// pkg/front_end/testcases/general/error_locations/error_location_02_lib1.dart:6:31: Context: This assertion failed.
+// const Foo(int i) : assert(i > 0);
+// ^
+// pkg/front_end/testcases/general/error_locations/error_location_02_lib2.dart:7:7: Context: While analyzing:
+// const fooField = const Foo(0);
+// ^
+//
+library;
+import self as self;
+import "error_location_02_lib1.dart" as err;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///error_location_02_lib1.dart";
+import "org-dartlang-testcase:///error_location_02_lib2.dart";
+import "org-dartlang-testcase:///error_location_02_lib3.dart";
+
+static method main() → dynamic {
+ err::foo();
+ core::print(invalid-expression "This assertion failed.");
+}
+
+library;
+import self as err;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+ const constructor •(core::int* i) → err::Foo*
+ : assert(i.{core::num::>}(0)), super core::Object::•()
+ ;
+}
+static method foo() → dynamic {
+ new err::Foo::•(0);
+}
+
+library;
+import self as self2;
+import "error_location_02_lib1.dart" as err;
+
+import "org-dartlang-testcase:///error_location_02_lib1.dart";
+
+static const field err::Foo* fooField = invalid-expression "This assertion failed.";
+
+library;
+import self as self3;
+import "error_location_02_lib1.dart" as err;
+
+import "org-dartlang-testcase:///error_location_02_lib2.dart";
+
+static const field err::Foo* fooField2 = invalid-expression "This assertion failed.";
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_02.dart.strong.transformed.expect b/pkg/front_end/testcases/general/error_locations/error_location_02.dart.strong.transformed.expect
new file mode 100644
index 0000000..efddc10
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_02.dart.strong.transformed.expect
@@ -0,0 +1,65 @@
+//
+// Problems in component:
+//
+// pkg/front_end/testcases/general/error_locations/error_location_02_lib3.dart:7:19: Error: Constant evaluation error:
+// const fooField2 = fooField;
+// ^
+// pkg/front_end/testcases/general/error_locations/error_location_02_lib1.dart:6:31: Context: This assertion failed.
+// const Foo(int i) : assert(i > 0);
+// ^
+// pkg/front_end/testcases/general/error_locations/error_location_02_lib3.dart:7:7: Context: While analyzing:
+// const fooField2 = fooField;
+// ^
+//
+// pkg/front_end/testcases/general/error_locations/error_location_02_lib2.dart:7:24: Error: Constant evaluation error:
+// const fooField = const Foo(0);
+// ^
+// pkg/front_end/testcases/general/error_locations/error_location_02_lib1.dart:6:31: Context: This assertion failed.
+// const Foo(int i) : assert(i > 0);
+// ^
+// pkg/front_end/testcases/general/error_locations/error_location_02_lib2.dart:7:7: Context: While analyzing:
+// const fooField = const Foo(0);
+// ^
+//
+library;
+import self as self;
+import "error_location_02_lib1.dart" as err;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///error_location_02_lib1.dart";
+import "org-dartlang-testcase:///error_location_02_lib2.dart";
+import "org-dartlang-testcase:///error_location_02_lib3.dart";
+
+static method main() → dynamic {
+ err::foo();
+ core::print(invalid-expression "This assertion failed.");
+}
+
+library;
+import self as err;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+ const constructor •(core::int* i) → err::Foo*
+ : assert(i.{core::num::>}(0)), super core::Object::•()
+ ;
+}
+static method foo() → dynamic {
+ new err::Foo::•(0);
+}
+
+library;
+import self as self2;
+import "error_location_02_lib1.dart" as err;
+
+import "org-dartlang-testcase:///error_location_02_lib1.dart";
+
+static const field err::Foo* fooField = invalid-expression "This assertion failed.";
+
+library;
+import self as self3;
+import "error_location_02_lib1.dart" as err;
+
+import "org-dartlang-testcase:///error_location_02_lib2.dart";
+
+static const field err::Foo* fooField2 = invalid-expression "This assertion failed.";
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_02_lib1.dart b/pkg/front_end/testcases/general/error_locations/error_location_02_lib1.dart
new file mode 100644
index 0000000..5ebb8ff
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_02_lib1.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Foo {
+ const Foo(int i) : assert(i > 0);
+}
+
+foo() {
+ new Foo(0);
+}
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_02_lib2.dart b/pkg/front_end/testcases/general/error_locations/error_location_02_lib2.dart
new file mode 100644
index 0000000..d526e38
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_02_lib2.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2019, 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 'error_location_02_lib1.dart';
+
+const fooField = const Foo(0);
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_02_lib3.dart b/pkg/front_end/testcases/general/error_locations/error_location_02_lib3.dart
new file mode 100644
index 0000000..7123ffc
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_02_lib3.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2019, 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 'error_location_02_lib2.dart';
+
+const fooField2 = fooField;
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_03.dart b/pkg/front_end/testcases/general/error_locations/error_location_03.dart
new file mode 100644
index 0000000..47bffaf
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_03.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2019, 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 'error_location_03_lib1.dart';
+import 'error_location_03_lib2.dart';
+import 'error_location_03_lib3.dart';
+
+main() {
+ foo();
+ print(fooField);
+ print(fooField2);
+}
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_03.dart.outline.expect b/pkg/front_end/testcases/general/error_locations/error_location_03.dart.outline.expect
new file mode 100644
index 0000000..e2689c9
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_03.dart.outline.expect
@@ -0,0 +1,37 @@
+library;
+import self as self;
+
+import "org-dartlang-testcase:///error_location_03_lib1.dart";
+import "org-dartlang-testcase:///error_location_03_lib2.dart";
+import "org-dartlang-testcase:///error_location_03_lib3.dart";
+
+static method main() → dynamic
+ ;
+
+library;
+import self as self2;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+ const constructor •(core::int* i) → self2::Foo*
+ : assert(i.{core::num::>}(0)), super core::Object::•()
+ ;
+}
+static method foo() → dynamic
+ ;
+
+library;
+import self as self3;
+import "error_location_03_lib1.dart" as self2;
+
+import "org-dartlang-testcase:///error_location_03_lib1.dart";
+
+static const field self2::Foo* fooField = const self2::Foo::•(0);
+
+library;
+import self as self4;
+import "error_location_03_lib1.dart" as self2;
+
+import "org-dartlang-testcase:///error_location_03_lib1.dart";
+
+static const field self2::Foo* fooField2 = const self2::Foo::•(0);
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_03.dart.strong.expect b/pkg/front_end/testcases/general/error_locations/error_location_03.dart.strong.expect
new file mode 100644
index 0000000..4028b04
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_03.dart.strong.expect
@@ -0,0 +1,66 @@
+//
+// Problems in component:
+//
+// pkg/front_end/testcases/general/error_locations/error_location_03_lib2.dart:7:24: Error: Constant evaluation error:
+// const fooField = const Foo(0);
+// ^
+// pkg/front_end/testcases/general/error_locations/error_location_03_lib1.dart:6:31: Context: This assertion failed.
+// const Foo(int i) : assert(i > 0);
+// ^
+// pkg/front_end/testcases/general/error_locations/error_location_03_lib2.dart:7:7: Context: While analyzing:
+// const fooField = const Foo(0);
+// ^
+//
+// pkg/front_end/testcases/general/error_locations/error_location_03_lib3.dart:7:25: Error: Constant evaluation error:
+// const fooField2 = const Foo(0);
+// ^
+// pkg/front_end/testcases/general/error_locations/error_location_03_lib1.dart:6:31: Context: This assertion failed.
+// const Foo(int i) : assert(i > 0);
+// ^
+// pkg/front_end/testcases/general/error_locations/error_location_03_lib3.dart:7:7: Context: While analyzing:
+// const fooField2 = const Foo(0);
+// ^
+//
+library;
+import self as self;
+import "error_location_03_lib1.dart" as err;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///error_location_03_lib1.dart";
+import "org-dartlang-testcase:///error_location_03_lib2.dart";
+import "org-dartlang-testcase:///error_location_03_lib3.dart";
+
+static method main() → dynamic {
+ err::foo();
+ core::print(invalid-expression "This assertion failed.");
+ core::print(invalid-expression "This assertion failed.");
+}
+
+library;
+import self as err;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+ const constructor •(core::int* i) → err::Foo*
+ : assert(i.{core::num::>}(0)), super core::Object::•()
+ ;
+}
+static method foo() → dynamic {
+ new err::Foo::•(0);
+}
+
+library;
+import self as self2;
+import "error_location_03_lib1.dart" as err;
+
+import "org-dartlang-testcase:///error_location_03_lib1.dart";
+
+static const field err::Foo* fooField = invalid-expression "This assertion failed.";
+
+library;
+import self as self3;
+import "error_location_03_lib1.dart" as err;
+
+import "org-dartlang-testcase:///error_location_03_lib1.dart";
+
+static const field err::Foo* fooField2 = invalid-expression "This assertion failed.";
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_03.dart.strong.transformed.expect b/pkg/front_end/testcases/general/error_locations/error_location_03.dart.strong.transformed.expect
new file mode 100644
index 0000000..4028b04
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_03.dart.strong.transformed.expect
@@ -0,0 +1,66 @@
+//
+// Problems in component:
+//
+// pkg/front_end/testcases/general/error_locations/error_location_03_lib2.dart:7:24: Error: Constant evaluation error:
+// const fooField = const Foo(0);
+// ^
+// pkg/front_end/testcases/general/error_locations/error_location_03_lib1.dart:6:31: Context: This assertion failed.
+// const Foo(int i) : assert(i > 0);
+// ^
+// pkg/front_end/testcases/general/error_locations/error_location_03_lib2.dart:7:7: Context: While analyzing:
+// const fooField = const Foo(0);
+// ^
+//
+// pkg/front_end/testcases/general/error_locations/error_location_03_lib3.dart:7:25: Error: Constant evaluation error:
+// const fooField2 = const Foo(0);
+// ^
+// pkg/front_end/testcases/general/error_locations/error_location_03_lib1.dart:6:31: Context: This assertion failed.
+// const Foo(int i) : assert(i > 0);
+// ^
+// pkg/front_end/testcases/general/error_locations/error_location_03_lib3.dart:7:7: Context: While analyzing:
+// const fooField2 = const Foo(0);
+// ^
+//
+library;
+import self as self;
+import "error_location_03_lib1.dart" as err;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///error_location_03_lib1.dart";
+import "org-dartlang-testcase:///error_location_03_lib2.dart";
+import "org-dartlang-testcase:///error_location_03_lib3.dart";
+
+static method main() → dynamic {
+ err::foo();
+ core::print(invalid-expression "This assertion failed.");
+ core::print(invalid-expression "This assertion failed.");
+}
+
+library;
+import self as err;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+ const constructor •(core::int* i) → err::Foo*
+ : assert(i.{core::num::>}(0)), super core::Object::•()
+ ;
+}
+static method foo() → dynamic {
+ new err::Foo::•(0);
+}
+
+library;
+import self as self2;
+import "error_location_03_lib1.dart" as err;
+
+import "org-dartlang-testcase:///error_location_03_lib1.dart";
+
+static const field err::Foo* fooField = invalid-expression "This assertion failed.";
+
+library;
+import self as self3;
+import "error_location_03_lib1.dart" as err;
+
+import "org-dartlang-testcase:///error_location_03_lib1.dart";
+
+static const field err::Foo* fooField2 = invalid-expression "This assertion failed.";
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_03_lib1.dart b/pkg/front_end/testcases/general/error_locations/error_location_03_lib1.dart
new file mode 100644
index 0000000..5ebb8ff
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_03_lib1.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Foo {
+ const Foo(int i) : assert(i > 0);
+}
+
+foo() {
+ new Foo(0);
+}
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_03_lib2.dart b/pkg/front_end/testcases/general/error_locations/error_location_03_lib2.dart
new file mode 100644
index 0000000..a889a34
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_03_lib2.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2019, 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 'error_location_03_lib1.dart';
+
+const fooField = const Foo(0);
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_03_lib3.dart b/pkg/front_end/testcases/general/error_locations/error_location_03_lib3.dart
new file mode 100644
index 0000000..09a8a3b
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_03_lib3.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2019, 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 'error_location_03_lib1.dart';
+
+const fooField2 = const Foo(0);
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_04.dart b/pkg/front_end/testcases/general/error_locations/error_location_04.dart
new file mode 100644
index 0000000..353cc90
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_04.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2019, 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 'error_location_04_lib1.dart';
+import 'error_location_04_lib2.dart';
+
+main() {
+ foo();
+ bar();
+}
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_04.dart.outline.expect b/pkg/front_end/testcases/general/error_locations/error_location_04.dart.outline.expect
new file mode 100644
index 0000000..4034b8b
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_04.dart.outline.expect
@@ -0,0 +1,36 @@
+library;
+import self as self;
+
+import "org-dartlang-testcase:///error_location_04_lib1.dart";
+import "org-dartlang-testcase:///error_location_04_lib2.dart";
+
+static method main() → dynamic
+ ;
+
+library;
+import self as self2;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+ const constructor •(core::int* i) → self2::Foo*
+ : assert(i.{core::num::>}(0)), super core::Object::•()
+ ;
+}
+static method foo() → dynamic
+ ;
+
+library;
+import self as self3;
+import "dart:core" as core;
+import "error_location_04_lib1.dart" as self2;
+
+import "org-dartlang-testcase:///error_location_04_lib1.dart";
+
+class Bar extends core::Object {
+ final field self2::Foo* x;
+ const constructor •() → self3::Bar*
+ : self3::Bar::x = const self2::Foo::•(0), super core::Object::•()
+ ;
+}
+static method bar() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_04.dart.strong.expect b/pkg/front_end/testcases/general/error_locations/error_location_04.dart.strong.expect
new file mode 100644
index 0000000..ac754c7
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_04.dart.strong.expect
@@ -0,0 +1,50 @@
+//
+// Problems in component:
+//
+// pkg/front_end/testcases/general/error_locations/error_location_04_lib2.dart:9:27: Error: Constant evaluation error:
+// const Bar() : x = const Foo(0);
+// ^
+// pkg/front_end/testcases/general/error_locations/error_location_04_lib1.dart:6:31: Context: This assertion failed.
+// const Foo(int i) : assert(i > 0);
+// ^
+//
+library;
+import self as self;
+import "error_location_04_lib1.dart" as err;
+import "error_location_04_lib2.dart" as err2;
+
+import "org-dartlang-testcase:///error_location_04_lib1.dart";
+import "org-dartlang-testcase:///error_location_04_lib2.dart";
+
+static method main() → dynamic {
+ err::foo();
+ err2::bar();
+}
+
+library;
+import self as err;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+ const constructor •(core::int* i) → err::Foo*
+ : assert(i.{core::num::>}(0)), super core::Object::•()
+ ;
+}
+static method foo() → dynamic {
+ new err::Foo::•(0);
+}
+
+library;
+import self as err2;
+import "dart:core" as core;
+import "error_location_04_lib1.dart" as err;
+
+import "org-dartlang-testcase:///error_location_04_lib1.dart";
+
+class Bar extends core::Object {
+ final field err::Foo* x;
+ const constructor •() → err2::Bar*
+ : err2::Bar::x = invalid-expression "This assertion failed.", super core::Object::•()
+ ;
+}
+static method bar() → dynamic {}
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_04.dart.strong.transformed.expect b/pkg/front_end/testcases/general/error_locations/error_location_04.dart.strong.transformed.expect
new file mode 100644
index 0000000..ac754c7
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_04.dart.strong.transformed.expect
@@ -0,0 +1,50 @@
+//
+// Problems in component:
+//
+// pkg/front_end/testcases/general/error_locations/error_location_04_lib2.dart:9:27: Error: Constant evaluation error:
+// const Bar() : x = const Foo(0);
+// ^
+// pkg/front_end/testcases/general/error_locations/error_location_04_lib1.dart:6:31: Context: This assertion failed.
+// const Foo(int i) : assert(i > 0);
+// ^
+//
+library;
+import self as self;
+import "error_location_04_lib1.dart" as err;
+import "error_location_04_lib2.dart" as err2;
+
+import "org-dartlang-testcase:///error_location_04_lib1.dart";
+import "org-dartlang-testcase:///error_location_04_lib2.dart";
+
+static method main() → dynamic {
+ err::foo();
+ err2::bar();
+}
+
+library;
+import self as err;
+import "dart:core" as core;
+
+class Foo extends core::Object {
+ const constructor •(core::int* i) → err::Foo*
+ : assert(i.{core::num::>}(0)), super core::Object::•()
+ ;
+}
+static method foo() → dynamic {
+ new err::Foo::•(0);
+}
+
+library;
+import self as err2;
+import "dart:core" as core;
+import "error_location_04_lib1.dart" as err;
+
+import "org-dartlang-testcase:///error_location_04_lib1.dart";
+
+class Bar extends core::Object {
+ final field err::Foo* x;
+ const constructor •() → err2::Bar*
+ : err2::Bar::x = invalid-expression "This assertion failed.", super core::Object::•()
+ ;
+}
+static method bar() → dynamic {}
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_04_lib1.dart b/pkg/front_end/testcases/general/error_locations/error_location_04_lib1.dart
new file mode 100644
index 0000000..5ebb8ff
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_04_lib1.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Foo {
+ const Foo(int i) : assert(i > 0);
+}
+
+foo() {
+ new Foo(0);
+}
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_04_lib2.dart b/pkg/front_end/testcases/general/error_locations/error_location_04_lib2.dart
new file mode 100644
index 0000000..24de171
--- /dev/null
+++ b/pkg/front_end/testcases/general/error_locations/error_location_04_lib2.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2019, 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 'error_location_04_lib1.dart';
+
+class Bar {
+ final Foo x;
+ const Bar() : x = const Foo(0);
+}
+
+bar() {}
diff --git a/pkg/front_end/testcases/general/function_type_assignments.dart.outline.expect b/pkg/front_end/testcases/general/function_type_assignments.dart.outline.expect
index 3edc43d..1e430dd 100644
--- a/pkg/front_end/testcases/general/function_type_assignments.dart.outline.expect
+++ b/pkg/front_end/testcases/general/function_type_assignments.dart.outline.expect
@@ -9,7 +9,7 @@
;
static method identityObject<T extends core::Object* = core::Object*>(self::identityObject::T* t) → self::identityObject::T*
;
-static method identityList<T extends core::List<self::identityList::T>* = core::List<dynamic>*>(self::identityList::T* t) → self::identityList::T*
+static method identityList<T extends core::List<self::identityList::T*>* = core::List<dynamic>*>(self::identityList::T* t) → self::identityList::T*
;
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/general/function_type_assignments.dart.strong.expect b/pkg/front_end/testcases/general/function_type_assignments.dart.strong.expect
index 2323d85..4c4931a 100644
--- a/pkg/front_end/testcases/general/function_type_assignments.dart.strong.expect
+++ b/pkg/front_end/testcases/general/function_type_assignments.dart.strong.expect
@@ -40,7 +40,7 @@
return t;
static method identityObject<T extends core::Object* = core::Object*>(self::identityObject::T* t) → self::identityObject::T*
return t;
-static method identityList<T extends core::List<self::identityList::T>* = core::List<dynamic>*>(self::identityList::T* t) → self::identityList::T*
+static method identityList<T extends core::List<self::identityList::T*>* = core::List<dynamic>*>(self::identityList::T* t) → self::identityList::T*
return t;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/general/function_type_assignments.dart.strong.transformed.expect b/pkg/front_end/testcases/general/function_type_assignments.dart.strong.transformed.expect
index 2323d85..4c4931a 100644
--- a/pkg/front_end/testcases/general/function_type_assignments.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/function_type_assignments.dart.strong.transformed.expect
@@ -40,7 +40,7 @@
return t;
static method identityObject<T extends core::Object* = core::Object*>(self::identityObject::T* t) → self::identityObject::T*
return t;
-static method identityList<T extends core::List<self::identityList::T>* = core::List<dynamic>*>(self::identityList::T* t) → self::identityList::T*
+static method identityList<T extends core::List<self::identityList::T*>* = core::List<dynamic>*>(self::identityList::T* t) → self::identityList::T*
return t;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/general/magic_const.dart.strong.expect b/pkg/front_end/testcases/general/magic_const.dart.strong.expect
index baa2e58..6d9ece4 100644
--- a/pkg/front_end/testcases/general/magic_const.dart.strong.expect
+++ b/pkg/front_end/testcases/general/magic_const.dart.strong.expect
@@ -1,7 +1,10 @@
//
// Problems in component:
//
-// pkg/front_end/testcases/general/magic_const.dart:15:39: Error: Can't have a non-constant List literal within a const context.
+// pkg/front_end/testcases/general/magic_const.dart:15:39: Error: Constant evaluation error:
+// foo({a: Constant(), b: Constant(), c: []}) {}
+// ^
+// pkg/front_end/testcases/general/magic_const.dart:15:39: Context: Can't have a non-constant List literal within a const context.
// foo({a: Constant(), b: Constant(), c: []}) {}
// ^
// pkg/front_end/testcases/general/magic_const.dart:15:36: Context: While analyzing:
diff --git a/pkg/front_end/testcases/general/magic_const.dart.strong.transformed.expect b/pkg/front_end/testcases/general/magic_const.dart.strong.transformed.expect
index baa2e58..6d9ece4 100644
--- a/pkg/front_end/testcases/general/magic_const.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/magic_const.dart.strong.transformed.expect
@@ -1,7 +1,10 @@
//
// Problems in component:
//
-// pkg/front_end/testcases/general/magic_const.dart:15:39: Error: Can't have a non-constant List literal within a const context.
+// pkg/front_end/testcases/general/magic_const.dart:15:39: Error: Constant evaluation error:
+// foo({a: Constant(), b: Constant(), c: []}) {}
+// ^
+// pkg/front_end/testcases/general/magic_const.dart:15:39: Context: Can't have a non-constant List literal within a const context.
// foo({a: Constant(), b: Constant(), c: []}) {}
// ^
// pkg/front_end/testcases/general/magic_const.dart:15:36: Context: While analyzing:
diff --git a/pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart.strong.expect b/pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart.strong.expect
index 9e85373..7998fd7 100644
--- a/pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart.strong.expect
+++ b/pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart.strong.expect
@@ -1,7 +1,10 @@
//
// Problems in component:
//
-// pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart:9:15: Error: The type 'T' is not a constant because it depends on a type parameter, only instantiated types are allowed.
+// pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart:9:15: Error: Constant evaluation error:
+// C({a: 0, b: T}) : trace = "a: $a, b: $b";
+// ^
+// pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart:9:15: Context: The type 'T' is not a constant because it depends on a type parameter, only instantiated types are allowed.
// C({a: 0, b: T}) : trace = "a: $a, b: $b";
// ^
// pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart:9:12: Context: While analyzing:
diff --git a/pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart.strong.transformed.expect b/pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart.strong.transformed.expect
index 91cecbd..05cc2ce 100644
--- a/pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart.strong.transformed.expect
@@ -1,7 +1,10 @@
//
// Problems in component:
//
-// pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart:9:15: Error: The type 'T' is not a constant because it depends on a type parameter, only instantiated types are allowed.
+// pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart:9:15: Error: Constant evaluation error:
+// C({a: 0, b: T}) : trace = "a: $a, b: $b";
+// ^
+// pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart:9:15: Context: The type 'T' is not a constant because it depends on a type parameter, only instantiated types are allowed.
// C({a: 0, b: T}) : trace = "a: $a, b: $b";
// ^
// pkg/front_end/testcases/general/mixin_constructors_with_default_values.dart:9:12: Context: While analyzing:
diff --git a/pkg/front_end/testcases/general/non_covariant_checks.dart b/pkg/front_end/testcases/general/non_covariant_checks.dart
index bf2dac8..679753c 100644
--- a/pkg/front_end/testcases/general/non_covariant_checks.dart
+++ b/pkg/front_end/testcases/general/non_covariant_checks.dart
@@ -224,25 +224,25 @@
print(e);
}
try {
- c. /*@ checkReturn=<S extends num* = dynamic>() ->* S */ field12;
+ c. /*@ checkReturn=<S extends num* = dynamic>() ->* S* */ field12;
throw 'TypeError expected';
} on TypeError catch (e) {
print(e);
}
try {
- c. /*@ checkReturn=<S extends num* = dynamic>(S) ->* void */ field13;
+ c. /*@ checkReturn=<S extends num* = dynamic>(S*) ->* void */ field13;
throw 'TypeError expected';
} on TypeError catch (e) {
print(e);
}
try {
- c. /*@ checkReturn=<S extends num* = dynamic>(S) ->* S */ field14;
+ c. /*@ checkReturn=<S extends num* = dynamic>(S*) ->* S* */ field14;
throw 'TypeError expected';
} on TypeError catch (e) {
print(e);
}
try {
- c. /*@ checkReturn=(<S extends num* = dynamic>() ->* S) ->* void */ field15;
+ c. /*@ checkReturn=(<S extends num* = dynamic>() ->* S*) ->* void */ field15;
throw 'TypeError expected';
} on TypeError catch (e) {
print(e);
@@ -290,25 +290,25 @@
print(e);
}
try {
- c. /*@ checkReturn=<S extends num* = dynamic>() ->* S */ getter12;
+ c. /*@ checkReturn=<S extends num* = dynamic>() ->* S* */ getter12;
throw 'TypeError expected';
} on TypeError catch (e) {
print(e);
}
try {
- c. /*@ checkReturn=<S extends num* = dynamic>(S) ->* void */ getter13;
+ c. /*@ checkReturn=<S extends num* = dynamic>(S*) ->* void */ getter13;
throw 'TypeError expected';
} on TypeError catch (e) {
print(e);
}
try {
- c. /*@ checkReturn=<S extends num* = dynamic>(S) ->* S */ getter14;
+ c. /*@ checkReturn=<S extends num* = dynamic>(S*) ->* S* */ getter14;
throw 'TypeError expected';
} on TypeError catch (e) {
print(e);
}
try {
- c. /*@ checkReturn=(<S extends num* = dynamic>() ->* S) ->* void */ getter15;
+ c. /*@ checkReturn=(<S extends num* = dynamic>() ->* S*) ->* void */ getter15;
throw 'TypeError expected';
} on TypeError catch (e) {
print(e);
diff --git a/pkg/front_end/testcases/general/non_covariant_checks.dart.strong.expect b/pkg/front_end/testcases/general/non_covariant_checks.dart.strong.expect
index 30be3b1..0b3bcfc 100644
--- a/pkg/front_end/testcases/general/non_covariant_checks.dart.strong.expect
+++ b/pkg/front_end/testcases/general/non_covariant_checks.dart.strong.expect
@@ -192,28 +192,28 @@
core::print(e);
}
try {
- c.{self::C::field12} as{TypeError} <S extends core::num* = dynamic>() →* S;
+ c.{self::C::field12} as{TypeError} <S extends core::num* = dynamic>() →* S*;
throw "TypeError expected";
}
on core::TypeError* catch(final core::TypeError* e) {
core::print(e);
}
try {
- c.{self::C::field13} as{TypeError} <S extends core::num* = dynamic>(S) →* void;
+ c.{self::C::field13} as{TypeError} <S extends core::num* = dynamic>(S*) →* void;
throw "TypeError expected";
}
on core::TypeError* catch(final core::TypeError* e) {
core::print(e);
}
try {
- c.{self::C::field14} as{TypeError} <S extends core::num* = dynamic>(S) →* S;
+ c.{self::C::field14} as{TypeError} <S extends core::num* = dynamic>(S*) →* S*;
throw "TypeError expected";
}
on core::TypeError* catch(final core::TypeError* e) {
core::print(e);
}
try {
- c.{self::C::field15} as{TypeError} (<S extends core::num* = dynamic>() →* S) →* void;
+ c.{self::C::field15} as{TypeError} (<S extends core::num* = dynamic>() →* S*) →* void;
throw "TypeError expected";
}
on core::TypeError* catch(final core::TypeError* e) {
@@ -267,28 +267,28 @@
core::print(e);
}
try {
- c.{self::C::getter12} as{TypeError} <S extends core::num* = dynamic>() →* S;
+ c.{self::C::getter12} as{TypeError} <S extends core::num* = dynamic>() →* S*;
throw "TypeError expected";
}
on core::TypeError* catch(final core::TypeError* e) {
core::print(e);
}
try {
- c.{self::C::getter13} as{TypeError} <S extends core::num* = dynamic>(S) →* void;
+ c.{self::C::getter13} as{TypeError} <S extends core::num* = dynamic>(S*) →* void;
throw "TypeError expected";
}
on core::TypeError* catch(final core::TypeError* e) {
core::print(e);
}
try {
- c.{self::C::getter14} as{TypeError} <S extends core::num* = dynamic>(S) →* S;
+ c.{self::C::getter14} as{TypeError} <S extends core::num* = dynamic>(S*) →* S*;
throw "TypeError expected";
}
on core::TypeError* catch(final core::TypeError* e) {
core::print(e);
}
try {
- c.{self::C::getter15} as{TypeError} (<S extends core::num* = dynamic>() →* S) →* void;
+ c.{self::C::getter15} as{TypeError} (<S extends core::num* = dynamic>() →* S*) →* void;
throw "TypeError expected";
}
on core::TypeError* catch(final core::TypeError* e) {
diff --git a/pkg/front_end/testcases/general/non_covariant_checks.dart.strong.transformed.expect b/pkg/front_end/testcases/general/non_covariant_checks.dart.strong.transformed.expect
index 30be3b1..0b3bcfc 100644
--- a/pkg/front_end/testcases/general/non_covariant_checks.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/non_covariant_checks.dart.strong.transformed.expect
@@ -192,28 +192,28 @@
core::print(e);
}
try {
- c.{self::C::field12} as{TypeError} <S extends core::num* = dynamic>() →* S;
+ c.{self::C::field12} as{TypeError} <S extends core::num* = dynamic>() →* S*;
throw "TypeError expected";
}
on core::TypeError* catch(final core::TypeError* e) {
core::print(e);
}
try {
- c.{self::C::field13} as{TypeError} <S extends core::num* = dynamic>(S) →* void;
+ c.{self::C::field13} as{TypeError} <S extends core::num* = dynamic>(S*) →* void;
throw "TypeError expected";
}
on core::TypeError* catch(final core::TypeError* e) {
core::print(e);
}
try {
- c.{self::C::field14} as{TypeError} <S extends core::num* = dynamic>(S) →* S;
+ c.{self::C::field14} as{TypeError} <S extends core::num* = dynamic>(S*) →* S*;
throw "TypeError expected";
}
on core::TypeError* catch(final core::TypeError* e) {
core::print(e);
}
try {
- c.{self::C::field15} as{TypeError} (<S extends core::num* = dynamic>() →* S) →* void;
+ c.{self::C::field15} as{TypeError} (<S extends core::num* = dynamic>() →* S*) →* void;
throw "TypeError expected";
}
on core::TypeError* catch(final core::TypeError* e) {
@@ -267,28 +267,28 @@
core::print(e);
}
try {
- c.{self::C::getter12} as{TypeError} <S extends core::num* = dynamic>() →* S;
+ c.{self::C::getter12} as{TypeError} <S extends core::num* = dynamic>() →* S*;
throw "TypeError expected";
}
on core::TypeError* catch(final core::TypeError* e) {
core::print(e);
}
try {
- c.{self::C::getter13} as{TypeError} <S extends core::num* = dynamic>(S) →* void;
+ c.{self::C::getter13} as{TypeError} <S extends core::num* = dynamic>(S*) →* void;
throw "TypeError expected";
}
on core::TypeError* catch(final core::TypeError* e) {
core::print(e);
}
try {
- c.{self::C::getter14} as{TypeError} <S extends core::num* = dynamic>(S) →* S;
+ c.{self::C::getter14} as{TypeError} <S extends core::num* = dynamic>(S*) →* S*;
throw "TypeError expected";
}
on core::TypeError* catch(final core::TypeError* e) {
core::print(e);
}
try {
- c.{self::C::getter15} as{TypeError} (<S extends core::num* = dynamic>() →* S) →* void;
+ c.{self::C::getter15} as{TypeError} (<S extends core::num* = dynamic>() →* S*) →* void;
throw "TypeError expected";
}
on core::TypeError* catch(final core::TypeError* e) {
diff --git a/pkg/front_end/testcases/general/override_check_generic_method_f_bounded.dart.outline.expect b/pkg/front_end/testcases/general/override_check_generic_method_f_bounded.dart.outline.expect
index 193f75c..09d8a3c 100644
--- a/pkg/front_end/testcases/general/override_check_generic_method_f_bounded.dart.outline.expect
+++ b/pkg/front_end/testcases/general/override_check_generic_method_f_bounded.dart.outline.expect
@@ -2,20 +2,20 @@
import self as self;
import "dart:core" as core;
-class Foo<T extends self::Foo<self::Foo::T>* = self::Foo<dynamic>*> extends core::Object {
+class Foo<T extends self::Foo<self::Foo::T*>* = self::Foo<dynamic>*> extends core::Object {
synthetic constructor •() → self::Foo<self::Foo::T*>*
;
}
abstract class Bar extends core::Object {
synthetic constructor •() → self::Bar*
;
- abstract method fisk<S extends self::Foo<self::Bar::fisk::S>* = self::Foo<dynamic>*>() → void;
+ abstract method fisk<S extends self::Foo<self::Bar::fisk::S*>* = self::Foo<dynamic>*>() → void;
}
class Hest extends core::Object implements self::Bar {
synthetic constructor •() → self::Hest*
;
@core::override
- method fisk<U extends self::Foo<self::Hest::fisk::U>* = self::Foo<dynamic>*>() → void
+ method fisk<U extends self::Foo<self::Hest::fisk::U*>* = self::Foo<dynamic>*>() → void
;
}
static method main() → void
diff --git a/pkg/front_end/testcases/general/override_check_generic_method_f_bounded.dart.strong.expect b/pkg/front_end/testcases/general/override_check_generic_method_f_bounded.dart.strong.expect
index b606dd1..5b088fe 100644
--- a/pkg/front_end/testcases/general/override_check_generic_method_f_bounded.dart.strong.expect
+++ b/pkg/front_end/testcases/general/override_check_generic_method_f_bounded.dart.strong.expect
@@ -2,7 +2,7 @@
import self as self;
import "dart:core" as core;
-class Foo<T extends self::Foo<self::Foo::T>* = self::Foo<dynamic>*> extends core::Object {
+class Foo<T extends self::Foo<self::Foo::T*>* = self::Foo<dynamic>*> extends core::Object {
synthetic constructor •() → self::Foo<self::Foo::T*>*
: super core::Object::•()
;
@@ -11,14 +11,14 @@
synthetic constructor •() → self::Bar*
: super core::Object::•()
;
- abstract method fisk<S extends self::Foo<self::Bar::fisk::S>* = self::Foo<dynamic>*>() → void;
+ abstract method fisk<S extends self::Foo<self::Bar::fisk::S*>* = self::Foo<dynamic>*>() → void;
}
class Hest extends core::Object implements self::Bar {
synthetic constructor •() → self::Hest*
: super core::Object::•()
;
@#C1
- method fisk<U extends self::Foo<self::Hest::fisk::U>* = self::Foo<dynamic>*>() → void {}
+ method fisk<U extends self::Foo<self::Hest::fisk::U*>* = self::Foo<dynamic>*>() → void {}
}
static method main() → void {}
diff --git a/pkg/front_end/testcases/general/override_check_generic_method_f_bounded.dart.strong.transformed.expect b/pkg/front_end/testcases/general/override_check_generic_method_f_bounded.dart.strong.transformed.expect
index b606dd1..5b088fe 100644
--- a/pkg/front_end/testcases/general/override_check_generic_method_f_bounded.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/override_check_generic_method_f_bounded.dart.strong.transformed.expect
@@ -2,7 +2,7 @@
import self as self;
import "dart:core" as core;
-class Foo<T extends self::Foo<self::Foo::T>* = self::Foo<dynamic>*> extends core::Object {
+class Foo<T extends self::Foo<self::Foo::T*>* = self::Foo<dynamic>*> extends core::Object {
synthetic constructor •() → self::Foo<self::Foo::T*>*
: super core::Object::•()
;
@@ -11,14 +11,14 @@
synthetic constructor •() → self::Bar*
: super core::Object::•()
;
- abstract method fisk<S extends self::Foo<self::Bar::fisk::S>* = self::Foo<dynamic>*>() → void;
+ abstract method fisk<S extends self::Foo<self::Bar::fisk::S*>* = self::Foo<dynamic>*>() → void;
}
class Hest extends core::Object implements self::Bar {
synthetic constructor •() → self::Hest*
: super core::Object::•()
;
@#C1
- method fisk<U extends self::Foo<self::Hest::fisk::U>* = self::Foo<dynamic>*>() → void {}
+ method fisk<U extends self::Foo<self::Hest::fisk::U*>* = self::Foo<dynamic>*>() → void {}
}
static method main() → void {}
diff --git a/pkg/front_end/testcases/general/override_setter_with_field.dart b/pkg/front_end/testcases/general/override_setter_with_field.dart
new file mode 100644
index 0000000..687d9a5
--- /dev/null
+++ b/pkg/front_end/testcases/general/override_setter_with_field.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2019, 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.
+
+abstract class A {
+ void set x(Object y);
+}
+
+class B implements A {
+ int x;
+}
+
+main() {
+ new B().x = 5;
+}
diff --git a/pkg/front_end/testcases/general/override_setter_with_field.dart.outline.expect b/pkg/front_end/testcases/general/override_setter_with_field.dart.outline.expect
new file mode 100644
index 0000000..f54d02a
--- /dev/null
+++ b/pkg/front_end/testcases/general/override_setter_with_field.dart.outline.expect
@@ -0,0 +1,27 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/override_setter_with_field.dart:10:7: Error: The field 'B.x' has type 'int', which does not match the corresponding type, 'Object', in the overridden setter, 'A.x'.
+// - 'Object' is from 'dart:core'.
+// int x;
+// ^
+// pkg/front_end/testcases/general/override_setter_with_field.dart:6:12: Context: This is the overridden method ('x').
+// void set x(Object y);
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+abstract class A extends core::Object {
+ synthetic constructor •() → self::A*
+ ;
+ abstract set x(core::Object* y) → void;
+}
+class B extends core::Object implements self::A {
+ field core::int* x;
+ synthetic constructor •() → self::B*
+ ;
+}
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/general/override_setter_with_field.dart.strong.expect b/pkg/front_end/testcases/general/override_setter_with_field.dart.strong.expect
new file mode 100644
index 0000000..58904b1
--- /dev/null
+++ b/pkg/front_end/testcases/general/override_setter_with_field.dart.strong.expect
@@ -0,0 +1,30 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/override_setter_with_field.dart:10:7: Error: The field 'B.x' has type 'int', which does not match the corresponding type, 'Object', in the overridden setter, 'A.x'.
+// - 'Object' is from 'dart:core'.
+// int x;
+// ^
+// pkg/front_end/testcases/general/override_setter_with_field.dart:6:12: Context: This is the overridden method ('x').
+// void set x(Object y);
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+abstract class A extends core::Object {
+ synthetic constructor •() → self::A*
+ : super core::Object::•()
+ ;
+ abstract set x(core::Object* y) → void;
+}
+class B extends core::Object implements self::A {
+ field core::int* x = null;
+ synthetic constructor •() → self::B*
+ : super core::Object::•()
+ ;
+}
+static method main() → dynamic {
+ new self::B::•().{self::B::x} = 5;
+}
diff --git a/pkg/front_end/testcases/general/reject_generic_function_types_in_bounds.dart.outline.expect b/pkg/front_end/testcases/general/reject_generic_function_types_in_bounds.dart.outline.expect
index 2160bc2..fa3f49e 100644
--- a/pkg/front_end/testcases/general/reject_generic_function_types_in_bounds.dart.outline.expect
+++ b/pkg/front_end/testcases/general/reject_generic_function_types_in_bounds.dart.outline.expect
@@ -9,7 +9,7 @@
import self as self;
import "dart:core" as core;
-class Hest<TypeX extends <TypeY extends core::Object* = dynamic>(TypeY) →* TypeY = dynamic> extends core::Object {
+class Hest<TypeX extends <TypeY extends core::Object* = dynamic>(TypeY*) →* TypeY* = dynamic> extends core::Object {
synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
;
}
diff --git a/pkg/front_end/testcases/general/reject_generic_function_types_in_bounds.dart.strong.expect b/pkg/front_end/testcases/general/reject_generic_function_types_in_bounds.dart.strong.expect
index 8da8025..f5eae0d 100644
--- a/pkg/front_end/testcases/general/reject_generic_function_types_in_bounds.dart.strong.expect
+++ b/pkg/front_end/testcases/general/reject_generic_function_types_in_bounds.dart.strong.expect
@@ -9,7 +9,7 @@
import self as self;
import "dart:core" as core;
-class Hest<TypeX extends <TypeY extends core::Object* = dynamic>(TypeY) →* TypeY = dynamic> extends core::Object {
+class Hest<TypeX extends <TypeY extends core::Object* = dynamic>(TypeY*) →* TypeY* = dynamic> extends core::Object {
synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
: super core::Object::•()
;
diff --git a/pkg/front_end/testcases/general/reject_generic_function_types_in_bounds.dart.strong.transformed.expect b/pkg/front_end/testcases/general/reject_generic_function_types_in_bounds.dart.strong.transformed.expect
index 8da8025..f5eae0d 100644
--- a/pkg/front_end/testcases/general/reject_generic_function_types_in_bounds.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/reject_generic_function_types_in_bounds.dart.strong.transformed.expect
@@ -9,7 +9,7 @@
import self as self;
import "dart:core" as core;
-class Hest<TypeX extends <TypeY extends core::Object* = dynamic>(TypeY) →* TypeY = dynamic> extends core::Object {
+class Hest<TypeX extends <TypeY extends core::Object* = dynamic>(TypeY*) →* TypeY* = dynamic> extends core::Object {
synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
: super core::Object::•()
;
diff --git a/pkg/front_end/testcases/general/unsound_promotion.dart.strong.expect b/pkg/front_end/testcases/general/unsound_promotion.dart.strong.expect
index d4ea589..7251f88 100644
--- a/pkg/front_end/testcases/general/unsound_promotion.dart.strong.expect
+++ b/pkg/front_end/testcases/general/unsound_promotion.dart.strong.expect
@@ -34,7 +34,7 @@
}
static method f<S extends core::Object* = dynamic>(self::f::S* s) → core::List<self::f::S*>* {
if(s is self::A*) {
- core::List<self::f::S* extends self::A*>* list = self::g<self::f::S* extends self::A*>(s{self::f::S* extends self::A*});
+ core::List<self::f::S* & self::A* /* '*' & '*' = '*' */>* list = self::g<self::f::S* & self::A* /* '*' & '*' = '*' */>(s{self::f::S* & self::A* /* '*' & '*' = '*' */});
return list;
}
return null;
diff --git a/pkg/front_end/testcases/general/unsound_promotion.dart.strong.transformed.expect b/pkg/front_end/testcases/general/unsound_promotion.dart.strong.transformed.expect
index d4ea589..7251f88 100644
--- a/pkg/front_end/testcases/general/unsound_promotion.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/unsound_promotion.dart.strong.transformed.expect
@@ -34,7 +34,7 @@
}
static method f<S extends core::Object* = dynamic>(self::f::S* s) → core::List<self::f::S*>* {
if(s is self::A*) {
- core::List<self::f::S* extends self::A*>* list = self::g<self::f::S* extends self::A*>(s{self::f::S* extends self::A*});
+ core::List<self::f::S* & self::A* /* '*' & '*' = '*' */>* list = self::g<self::f::S* & self::A* /* '*' & '*' = '*' */>(s{self::f::S* & self::A* /* '*' & '*' = '*' */});
return list;
}
return null;
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_10.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_10.yaml
new file mode 100644
index 0000000..0ecda031
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_10.yaml
@@ -0,0 +1,93 @@
+# Copyright (c) 2019, 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.md file.
+
+# Compile an application with a const class with a initializer assert that would
+# fail once evaluated. Everything should be fine as there is no usage.
+# Add a two new files each with usage of it. An error should occur each place.
+# Fix one and the error should still occur in the other.
+# Fix the other but re-introduce the first and the error should still occur.
+# Fix both and the error should go away.
+
+type: newworld
+strong: true
+worlds:
+ - entry: main.dart
+ sources:
+ main.dart: |
+ import 'lib.dart';
+ main() {
+ foo();
+ }
+ lib.dart: |
+ class Foo {
+ const Foo(int i) : assert(i > 0);
+ }
+ foo() {
+ new Foo(0);
+ }
+ expectedLibraryCount: 2
+ errors: false
+ - entry: main.dart
+ errors: true
+ worldType: updated
+ invalidate:
+ - main.dart
+ sources:
+ main.dart: |
+ import 'lib.dart';
+ import 'lib2.dart';
+ import 'lib3.dart';
+ main() {
+ foo();
+ print(fooField2);
+ }
+ lib2.dart: |
+ import 'lib.dart';
+ const fooField = const Foo(0);
+ lib3.dart: |
+ import 'lib.dart';
+ const fooField2 = const Foo(0);
+ expectInitializeFromDill: false
+ expectedLibraryCount: 4
+ - entry: main.dart
+ errors: true
+ worldType: updated
+ invalidate:
+ - lib2.dart
+ sources:
+ lib2.dart: |
+ import 'lib.dart';
+ const fooField = const Foo(1);
+ expectInitializeFromDill: false
+ expectedLibraryCount: 4
+ - entry: main.dart
+ errors: true
+ worldType: updated
+ invalidate:
+ - lib2.dart
+ - lib3.dart
+ sources:
+ lib2.dart: |
+ import 'lib.dart';
+ const fooField = const Foo(0);
+ lib3.dart: |
+ import 'lib.dart';
+ const fooField2 = const Foo(1);
+ expectInitializeFromDill: false
+ expectedLibraryCount: 4
+ - entry: main.dart
+ errors: false
+ worldType: updated
+ invalidate:
+ - lib2.dart
+ - lib3.dart
+ sources:
+ lib2.dart: |
+ import 'lib.dart';
+ const fooField = const Foo(1);
+ lib3.dart: |
+ import 'lib.dart';
+ const fooField2 = const Foo(1);
+ expectInitializeFromDill: false
+ expectedLibraryCount: 4
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_11.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_11.yaml
new file mode 100644
index 0000000..4c8455b
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_11.yaml
@@ -0,0 +1,65 @@
+# Copyright (c) 2019, 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.md file.
+
+# Compile an application with a const class with a initializer assert that would
+# fail once evaluated. Everything should be fine as there is no usage.
+# Add another const class that references it. Error.
+# Fixing that should fix everything.
+
+type: newworld
+strong: true
+worlds:
+ - entry: main.dart
+ sources:
+ main.dart: |
+ import 'lib.dart';
+ main() {
+ foo();
+ }
+ lib.dart: |
+ class Foo {
+ const Foo(int i) : assert(i > 0);
+ }
+ foo() {
+ new Foo(0);
+ }
+ expectedLibraryCount: 2
+ errors: false
+ - entry: main.dart
+ errors: true
+ worldType: updated
+ invalidate:
+ - main.dart
+ sources:
+ main.dart: |
+ import 'lib.dart';
+ import 'lib2.dart';
+ main() {
+ foo();
+ bar();
+ }
+ lib2.dart: |
+ import 'lib.dart';
+ class Bar {
+ final Foo x;
+ const Bar() : x = const Foo(0);
+ }
+ bar() {}
+ expectInitializeFromDill: false
+ expectedLibraryCount: 3
+ - entry: main.dart
+ errors: false
+ worldType: updated
+ invalidate:
+ - lib2.dart
+ sources:
+ lib2.dart: |
+ import 'lib.dart';
+ class Bar {
+ final Foo x;
+ const Bar() : x = const Foo(1);
+ }
+ bar() {}
+ expectInitializeFromDill: false
+ expectedLibraryCount: 3
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_6.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_6.yaml
new file mode 100644
index 0000000..79727eb
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_6.yaml
@@ -0,0 +1,49 @@
+# Copyright (c) 2019, 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.md file.
+
+# Compile an application with errors in it, then - without fixing the errors -
+# recompile. Make sure we still get errors. As long as we don't fix the error,
+# we keep getting errors. Once we fix it, we no longer get errors.
+
+type: newworld
+strong: true
+worlds:
+ - entry: main.dart
+ sources:
+ main.dart: |
+ import 'lib.dart';
+ class Foo<X extends Bar> {}
+ lib.dart: |
+ // The error is here: Foo is unknown
+ // (although it might give some other error instead)
+ class Bar<X extends Foo<Null>> {}
+ expectedLibraryCount: 2
+ errors: true
+ - entry: main.dart
+ errors: true
+ worldType: updated
+ invalidate:
+ - main.dart
+ sources:
+ main.dart: |
+ import 'lib.dart';
+ class Foo {}
+ expectInitializeFromDill: false
+ expectedLibraryCount: 2
+ - entry: main.dart
+ errors: false
+ worldType: updated
+ invalidate:
+ - main.dart
+ - lib.dart
+ sources:
+ main.dart: |
+ import 'lib.dart';
+ class Foo<X extends Bar> {}
+ lib.dart: |
+ import 'main.dart';
+ class Bar<X extends Foo<Null>> {}
+ expectInitializeFromDill: false
+ expectedLibraryCount: 2
+
\ No newline at end of file
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_7.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_7.yaml
new file mode 100644
index 0000000..1b18f5c
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_7.yaml
@@ -0,0 +1,79 @@
+# Copyright (c) 2019, 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.md file.
+
+# Compile an application with errors in it, then - without fixing the errors -
+# recompile. Make sure we still get errors. As long as we don't fix the error,
+# we keep getting errors. Once we fix it, we no longer get errors.
+
+type: newworld
+strong: true
+worlds:
+ - entry: main.dart
+ sources:
+ main.dart: |
+ import 'lib.dart';
+ main() {
+ foo();
+ }
+ lib.dart: |
+ import 'nonexisting.dart';
+ foo() {}
+ expectedLibraryCount: 2
+ errors: true
+ - entry: main.dart
+ errors: true
+ worldType: updated
+ invalidate:
+ - main.dart
+ sources:
+ main.dart: |
+ import 'lib.dart';
+ main() {
+ foo();
+ foo();
+ }
+ expectInitializeFromDill: false
+ expectedLibraryCount: 2
+ - entry: main.dart
+ errors: true
+ worldType: updated
+ invalidate:
+ - main.dart
+ sources:
+ main.dart: |
+ import 'lib.dart';
+ import 'lib2.dart';
+ main() {
+ foo();
+ bar();
+ }
+ lib2.dart: |
+ bar() {
+ print("hello");
+ }
+ expectInitializeFromDill: false
+ expectedLibraryCount: 3
+ - entry: main.dart
+ errors: true
+ worldType: updated
+ invalidate:
+ - lib2.dart
+ sources:
+ lib2.dart: |
+ bar() {
+ print("hello2");
+ }
+ expectInitializeFromDill: false
+ expectedLibraryCount: 3
+
+ - entry: main.dart
+ errors: false
+ worldType: updated
+ invalidate:
+ - lib.dart
+ sources:
+ lib.dart: |
+ foo() {}
+ expectInitializeFromDill: false
+ expectedLibraryCount: 3
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_8.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_8.yaml
new file mode 100644
index 0000000..9e1b824
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_8.yaml
@@ -0,0 +1,60 @@
+# Copyright (c) 2019, 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.md file.
+
+# Compile an application with a const class with a initializer assert that would
+# fail once evaluated. Everything should be fine as there is no usage.
+# Add a new file with usage of it. An error should occur.
+# Remove said file again and the error should go away.
+
+type: newworld
+strong: true
+worlds:
+ - entry: main.dart
+ sources:
+ main.dart: |
+ import 'lib.dart';
+ main() {
+ foo();
+ }
+ lib.dart: |
+ class Foo {
+ const Foo(int i) : assert(i > 0);
+ }
+ foo() {
+ new Foo(0);
+ }
+ expectedLibraryCount: 2
+ errors: false
+ - entry: main.dart
+ errors: true
+ worldType: updated
+ invalidate:
+ - main.dart
+ sources:
+ main.dart: |
+ import 'lib.dart';
+ import 'lib2.dart';
+ main() {
+ foo();
+ }
+ lib2.dart: |
+ import 'lib.dart';
+ bar() {
+ const Foo(0);
+ }
+ expectInitializeFromDill: false
+ expectedLibraryCount: 3
+ - entry: main.dart
+ errors: false
+ worldType: updated
+ invalidate:
+ - main.dart
+ sources:
+ main.dart: |
+ import 'lib.dart';
+ main() {
+ foo();
+ }
+ expectInitializeFromDill: false
+ expectedLibraryCount: 2
\ No newline at end of file
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_9.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_9.yaml
new file mode 100644
index 0000000..c8ec3fa
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/reissue_errors_9.yaml
@@ -0,0 +1,62 @@
+# Copyright (c) 2019, 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.md file.
+
+# Compile an application with a const class with a initializer assert that would
+# fail once evaluated. Everything should be fine as there is no usage.
+# Add a new file with usage of it. An error should occur.
+# Fix said file again and the error should go away.
+# Any references to the constant shouldn't matter in this regard.
+
+type: newworld
+strong: true
+worlds:
+ - entry: main.dart
+ sources:
+ main.dart: |
+ import 'lib.dart';
+ main() {
+ foo();
+ }
+ lib.dart: |
+ class Foo {
+ const Foo(int i) : assert(i > 0);
+ }
+ foo() {
+ new Foo(0);
+ }
+ expectedLibraryCount: 2
+ errors: false
+ - entry: main.dart
+ errors: true
+ worldType: updated
+ invalidate:
+ - main.dart
+ sources:
+ main.dart: |
+ import 'lib.dart';
+ import 'lib2.dart';
+ import 'lib3.dart';
+ main() {
+ foo();
+ print(fooField2);
+ }
+ lib2.dart: |
+ import 'lib.dart';
+ const fooField = const Foo(0);
+ lib3.dart: |
+ import 'lib2.dart';
+ const fooField2 = fooField;
+ expectInitializeFromDill: false
+ expectedLibraryCount: 4
+ - entry: main.dart
+ errors: false
+ worldType: updated
+ invalidate:
+ - lib2.dart
+ sources:
+ lib2.dart: |
+ import 'lib.dart';
+ const fooField = const Foo(1);
+ expectInitializeFromDill: false
+ expectedLibraryCount: 4
\ No newline at end of file
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/status.status b/pkg/front_end/testcases/incremental_initialize_from_dill/status.status
index f3d01d2..3cae5cc 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/status.status
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/status.status
@@ -2,4 +2,4 @@
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE.md file.
-# Status file for the test suite ../test/incremental_load_from_dill_yaml_test.dart.
+# Status file for the test suite ../test/incremental_load_from_dill_test.dart.
diff --git a/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.outline.expect b/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.outline.expect
index 4d266f4..408d7df 100644
--- a/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.outline.expect
+++ b/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.outline.expect
@@ -6,7 +6,7 @@
synthetic constructor •() → self::Cloneable<self::Cloneable::T*>*
;
}
-class Pair<T extends self::Cloneable<self::Pair::T>* = self::Cloneable<dynamic>*, U extends self::Cloneable<self::Pair::U>* = self::Cloneable<dynamic>*> extends core::Object {
+class Pair<T extends self::Cloneable<self::Pair::T*>* = self::Cloneable<dynamic>*, U extends self::Cloneable<self::Pair::U*>* = self::Cloneable<dynamic>*> extends core::Object {
generic-covariant-impl field self::Pair::T* t;
generic-covariant-impl field self::Pair::U* u;
constructor •(self::Pair::T* t, self::Pair::U* u) → self::Pair<self::Pair::T*, self::Pair::U*>*
diff --git a/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.expect b/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.expect
index 2359c4d..c7e9952 100644
--- a/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.expect
@@ -28,7 +28,7 @@
: super core::Object::•()
;
}
-class Pair<T extends self::Cloneable<self::Pair::T>* = self::Cloneable<dynamic>*, U extends self::Cloneable<self::Pair::U>* = self::Cloneable<dynamic>*> extends core::Object {
+class Pair<T extends self::Cloneable<self::Pair::T*>* = self::Cloneable<dynamic>*, U extends self::Cloneable<self::Pair::U*>* = self::Cloneable<dynamic>*> extends core::Object {
generic-covariant-impl field self::Pair::T* t;
generic-covariant-impl field self::Pair::U* u;
constructor •(self::Pair::T* t, self::Pair::U* u) → self::Pair<self::Pair::T*, self::Pair::U*>*
diff --git a/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.transformed.expect
index 2359c4d..c7e9952 100644
--- a/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.transformed.expect
@@ -28,7 +28,7 @@
: super core::Object::•()
;
}
-class Pair<T extends self::Cloneable<self::Pair::T>* = self::Cloneable<dynamic>*, U extends self::Cloneable<self::Pair::U>* = self::Cloneable<dynamic>*> extends core::Object {
+class Pair<T extends self::Cloneable<self::Pair::T*>* = self::Cloneable<dynamic>*, U extends self::Cloneable<self::Pair::U*>* = self::Cloneable<dynamic>*> extends core::Object {
generic-covariant-impl field self::Pair::T* t;
generic-covariant-impl field self::Pair::U* u;
constructor •(self::Pair::T* t, self::Pair::U* u) → self::Pair<self::Pair::T*, self::Pair::U*>*
diff --git a/pkg/front_end/testcases/inference/instantiate_tearoff_after_contravariance_check.dart.strong.expect b/pkg/front_end/testcases/inference/instantiate_tearoff_after_contravariance_check.dart.strong.expect
index cc6f9e2..d7f5411 100644
--- a/pkg/front_end/testcases/inference/instantiate_tearoff_after_contravariance_check.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/instantiate_tearoff_after_contravariance_check.dart.strong.expect
@@ -10,6 +10,6 @@
return (self::C::T* y) → core::Null* {};
}
static method test(self::C<core::String*>* c) → void {
- (core::int*) →* (core::String*) →* void tearoff = c.{self::C::f} as{TypeError} <U extends core::Object* = dynamic>(U) →* (core::String*) →* void<core::int*>;
+ (core::int*) →* (core::String*) →* void tearoff = c.{self::C::f} as{TypeError} <U extends core::Object* = dynamic>(U*) →* (core::String*) →* void<core::int*>;
}
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/inference/instantiate_tearoff_after_contravariance_check.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/instantiate_tearoff_after_contravariance_check.dart.strong.transformed.expect
index cc6f9e2..d7f5411 100644
--- a/pkg/front_end/testcases/inference/instantiate_tearoff_after_contravariance_check.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/instantiate_tearoff_after_contravariance_check.dart.strong.transformed.expect
@@ -10,6 +10,6 @@
return (self::C::T* y) → core::Null* {};
}
static method test(self::C<core::String*>* c) → void {
- (core::int*) →* (core::String*) →* void tearoff = c.{self::C::f} as{TypeError} <U extends core::Object* = dynamic>(U) →* (core::String*) →* void<core::int*>;
+ (core::int*) →* (core::String*) →* void tearoff = c.{self::C::f} as{TypeError} <U extends core::Object* = dynamic>(U*) →* (core::String*) →* void<core::int*>;
}
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.outline.expect b/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.outline.expect
index f952fac..e769695 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.outline.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.outline.expect
@@ -18,7 +18,7 @@
synthetic constructor •() → self::I<self::I::X*>*
;
}
-class M0<X extends core::Object* = dynamic, Y extends core::Comparable<self::M0::Y>* = core::Comparable<dynamic>*> extends self::I<self::M0::X*> {
+class M0<X extends core::Object* = dynamic, Y extends core::Comparable<self::M0::Y*>* = core::Comparable<dynamic>*> extends self::I<self::M0::X*> {
synthetic constructor •() → self::M0<self::M0::X*, self::M0::Y*>*
;
}
diff --git a/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.strong.expect b/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.strong.expect
index e8afc30..e44fcb9 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.strong.expect
@@ -19,7 +19,7 @@
: super core::Object::•()
;
}
-class M0<X extends core::Object* = dynamic, Y extends core::Comparable<self::M0::Y>* = core::Comparable<dynamic>*> extends self::I<self::M0::X*> {
+class M0<X extends core::Object* = dynamic, Y extends core::Comparable<self::M0::Y*>* = core::Comparable<dynamic>*> extends self::I<self::M0::X*> {
synthetic constructor •() → self::M0<self::M0::X*, self::M0::Y*>*
: super self::I::•()
;
diff --git a/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.strong.transformed.expect
index 5ca76b8..d17f94c 100644
--- a/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/mixin_inference_instantiate_to_bounds_3.dart.strong.transformed.expect
@@ -19,7 +19,7 @@
: super core::Object::•()
;
}
-class M0<X extends core::Object* = dynamic, Y extends core::Comparable<self::M0::Y>* = core::Comparable<dynamic>*> extends self::I<self::M0::X*> {
+class M0<X extends core::Object* = dynamic, Y extends core::Comparable<self::M0::Y*>* = core::Comparable<dynamic>*> extends self::I<self::M0::X*> {
synthetic constructor •() → self::M0<self::M0::X*, self::M0::Y*>*
: super self::I::•()
;
diff --git a/pkg/front_end/testcases/inference/promote_bounds.dart b/pkg/front_end/testcases/inference/promote_bounds.dart
index 37cc023..7a631cb 100644
--- a/pkg/front_end/testcases/inference/promote_bounds.dart
+++ b/pkg/front_end/testcases/inference/promote_bounds.dart
@@ -20,7 +20,7 @@
}
if (a is C) {
// Promoted; we can now call bar.
- /*@ promotedType=f::T* extends C* */ a. /*@target=C::bar*/ bar();
+ /*@ promotedType=f::T* & C* */ a. /*@target=C::bar*/ bar();
}
}
diff --git a/pkg/front_end/testcases/inference/promote_bounds.dart.strong.expect b/pkg/front_end/testcases/inference/promote_bounds.dart.strong.expect
index a10d272..3e0e207 100644
--- a/pkg/front_end/testcases/inference/promote_bounds.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/promote_bounds.dart.strong.expect
@@ -19,7 +19,7 @@
a.{self::B::foo}();
}
if(a is self::C*) {
- a{self::f::T* extends self::C*}.{self::C::bar}();
+ a{self::f::T* & self::C* /* '*' & '*' = '*' */}.{self::C::bar}();
}
}
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/inference/promote_bounds.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/promote_bounds.dart.strong.transformed.expect
index a10d272..3e0e207 100644
--- a/pkg/front_end/testcases/inference/promote_bounds.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/promote_bounds.dart.strong.transformed.expect
@@ -19,7 +19,7 @@
a.{self::B::foo}();
}
if(a is self::C*) {
- a{self::f::T* extends self::C*}.{self::C::bar}();
+ a{self::f::T* & self::C* /* '*' & '*' = '*' */}.{self::C::bar}();
}
}
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/all_steps.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/all_steps.dart.outline.expect
index b3d2329..814e963 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/all_steps.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/all_steps.dart.outline.expect
@@ -10,7 +10,7 @@
synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
;
}
-class D<X extends self::B<self::D::X, self::D::Y>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y>* = self::C<dynamic, dynamic>*, Z extends (self::D::Y*) →* self::D::X* = (core::Null*) →* self::B<dynamic, dynamic>*, W extends core::num* = core::num*> extends core::Object {
+class D<X extends self::B<self::D::X*, self::D::Y*>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y*>* = self::C<dynamic, dynamic>*, Z extends (self::D::Y*) →* self::D::X* = (core::Null?) →* self::B<dynamic, dynamic>*, W extends core::num* = core::num*> extends core::Object {
synthetic constructor •() → self::D<self::D::X*, self::D::Y*, self::D::Z*, self::D::W*>*
;
}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/all_steps.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/all_steps.dart.strong.expect
index 9f78ee2..6202c0e 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/all_steps.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/all_steps.dart.strong.expect
@@ -12,11 +12,11 @@
: super core::Object::•()
;
}
-class D<X extends self::B<self::D::X, self::D::Y>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y>* = self::C<dynamic, dynamic>*, Z extends (self::D::Y*) →* self::D::X* = (core::Null*) →* self::B<dynamic, dynamic>*, W extends core::num* = core::num*> extends core::Object {
+class D<X extends self::B<self::D::X*, self::D::Y*>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y*>* = self::C<dynamic, dynamic>*, Z extends (self::D::Y*) →* self::D::X* = (core::Null?) →* self::B<dynamic, dynamic>*, W extends core::num* = core::num*> extends core::Object {
synthetic constructor •() → self::D<self::D::X*, self::D::Y*, self::D::Z*, self::D::W*>*
: super core::Object::•()
;
}
static method main() → dynamic {
- self::D<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*, (core::Null*) →* self::B<dynamic, dynamic>*, core::num*>* d;
+ self::D<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*, (core::Null?) →* self::B<dynamic, dynamic>*, core::num*>* d;
}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/all_steps.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/all_steps.dart.strong.transformed.expect
index 9f78ee2..6202c0e 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/all_steps.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/all_steps.dart.strong.transformed.expect
@@ -12,11 +12,11 @@
: super core::Object::•()
;
}
-class D<X extends self::B<self::D::X, self::D::Y>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y>* = self::C<dynamic, dynamic>*, Z extends (self::D::Y*) →* self::D::X* = (core::Null*) →* self::B<dynamic, dynamic>*, W extends core::num* = core::num*> extends core::Object {
+class D<X extends self::B<self::D::X*, self::D::Y*>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y*>* = self::C<dynamic, dynamic>*, Z extends (self::D::Y*) →* self::D::X* = (core::Null?) →* self::B<dynamic, dynamic>*, W extends core::num* = core::num*> extends core::Object {
synthetic constructor •() → self::D<self::D::X*, self::D::Y*, self::D::Z*, self::D::W*>*
: super core::Object::•()
;
}
static method main() → dynamic {
- self::D<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*, (core::Null*) →* self::B<dynamic, dynamic>*, core::num*>* d;
+ self::D<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*, (core::Null?) →* self::B<dynamic, dynamic>*, core::num*>* d;
}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/body_super_bounded_type.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/body_super_bounded_type.dart.outline.expect
index b719a1c..bef6eb8 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/body_super_bounded_type.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/body_super_bounded_type.dart.outline.expect
@@ -2,7 +2,7 @@
import self as self;
import "dart:core" as core;
-class A<T extends self::A<self::A::T>* = self::A<dynamic>*> extends core::Object {
+class A<T extends self::A<self::A::T*>* = self::A<dynamic>*> extends core::Object {
synthetic constructor •() → self::A<self::A::T*>*
;
}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/body_super_bounded_type.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/body_super_bounded_type.dart.strong.expect
index 093fa07c..77bf163 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/body_super_bounded_type.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/body_super_bounded_type.dart.strong.expect
@@ -2,7 +2,7 @@
import self as self;
import "dart:core" as core;
-class A<T extends self::A<self::A::T>* = self::A<dynamic>*> extends core::Object {
+class A<T extends self::A<self::A::T*>* = self::A<dynamic>*> extends core::Object {
synthetic constructor •() → self::A<self::A::T*>*
: super core::Object::•()
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/body_super_bounded_type.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/body_super_bounded_type.dart.strong.transformed.expect
index 093fa07c..77bf163 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/body_super_bounded_type.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/body_super_bounded_type.dart.strong.transformed.expect
@@ -2,7 +2,7 @@
import self as self;
import "dart:core" as core;
-class A<T extends self::A<self::A::T>* = self::A<dynamic>*> extends core::Object {
+class A<T extends self::A<self::A::T*>* = self::A<dynamic>*> extends core::Object {
synthetic constructor •() → self::A<self::A::T*>*
: super core::Object::•()
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/body_typedef_super_bounded_type.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/body_typedef_super_bounded_type.dart.outline.expect
index 9038ebd..dcce18a 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/body_typedef_super_bounded_type.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/body_typedef_super_bounded_type.dart.outline.expect
@@ -3,7 +3,7 @@
import "dart:core" as core;
typedef A<T extends core::Object* = dynamic> = (T*) →* dynamic;
-typedef B<U extends (U) →* dynamic = (dynamic) →* dynamic> = (U*) →* dynamic;
+typedef B<U extends (U*) →* dynamic = (dynamic) →* dynamic> = (U*) →* dynamic;
class C extends core::Object {
synthetic constructor •() → self::C*
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/body_typedef_super_bounded_type.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/body_typedef_super_bounded_type.dart.strong.expect
index a04653f..0ce72d7 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/body_typedef_super_bounded_type.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/body_typedef_super_bounded_type.dart.strong.expect
@@ -3,7 +3,7 @@
import "dart:core" as core;
typedef A<T extends core::Object* = dynamic> = (T*) →* dynamic;
-typedef B<U extends (U) →* dynamic = (dynamic) →* dynamic> = (U*) →* dynamic;
+typedef B<U extends (U*) →* dynamic = (dynamic) →* dynamic> = (U*) →* dynamic;
class C extends core::Object {
synthetic constructor •() → self::C*
: super core::Object::•()
diff --git a/pkg/front_end/testcases/instantiate_to_bound/body_typedef_super_bounded_type.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/body_typedef_super_bounded_type.dart.strong.transformed.expect
index a04653f..0ce72d7 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/body_typedef_super_bounded_type.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/body_typedef_super_bounded_type.dart.strong.transformed.expect
@@ -3,7 +3,7 @@
import "dart:core" as core;
typedef A<T extends core::Object* = dynamic> = (T*) →* dynamic;
-typedef B<U extends (U) →* dynamic = (dynamic) →* dynamic> = (U*) →* dynamic;
+typedef B<U extends (U*) →* dynamic = (dynamic) →* dynamic> = (U*) →* dynamic;
class C extends core::Object {
synthetic constructor •() → self::C*
: super core::Object::•()
diff --git a/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence.dart.outline.expect
index 941b9b6..38562f5 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence.dart.outline.expect
@@ -2,10 +2,10 @@
import self as self;
import "dart:core" as core;
-class C<X extends core::num* = core::num*, Y extends (self::C::X*) →* void = (core::Null*) →* void> extends core::Object {
+class C<X extends core::num* = core::num*, Y extends (self::C::X*) →* void = (core::Null?) →* void> extends core::Object {
synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
;
}
-static field self::C<core::num*, (core::Null*) →* void>* c;
+static field self::C<core::num*, (core::Null?) →* void>* c;
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence.dart.strong.expect
index 61e4ec3..6389a65 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence.dart.strong.expect
@@ -2,10 +2,10 @@
import self as self;
import "dart:core" as core;
-class C<X extends core::num* = core::num*, Y extends (self::C::X*) →* void = (core::Null*) →* void> extends core::Object {
+class C<X extends core::num* = core::num*, Y extends (self::C::X*) →* void = (core::Null?) →* void> extends core::Object {
synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
: super core::Object::•()
;
}
-static field self::C<core::num*, (core::Null*) →* void>* c;
+static field self::C<core::num*, (core::Null?) →* void>* c;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence.dart.strong.transformed.expect
index 61e4ec3..6389a65 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence.dart.strong.transformed.expect
@@ -2,10 +2,10 @@
import self as self;
import "dart:core" as core;
-class C<X extends core::num* = core::num*, Y extends (self::C::X*) →* void = (core::Null*) →* void> extends core::Object {
+class C<X extends core::num* = core::num*, Y extends (self::C::X*) →* void = (core::Null?) →* void> extends core::Object {
synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
: super core::Object::•()
;
}
-static field self::C<core::num*, (core::Null*) →* void>* c;
+static field self::C<core::num*, (core::Null?) →* void>* c;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence_in_literals.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence_in_literals.dart.outline.expect
index 28f1f4b..60fb2e3 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence_in_literals.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence_in_literals.dart.outline.expect
@@ -2,11 +2,11 @@
import self as self;
import "dart:core" as core;
-class C<X extends core::num* = core::num*, Y extends (self::C::X*) →* void = (core::Null*) →* void> extends core::Object {
+class C<X extends core::num* = core::num*, Y extends (self::C::X*) →* void = (core::Null?) →* void> extends core::Object {
synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
;
}
-static field core::List<self::C<core::num*, (core::Null*) →* void>*>* lc;
-static field core::Map<self::C<core::num*, (core::Null*) →* void>*, self::C<core::num*, (core::Null*) →* void>*>* mc;
+static field core::List<self::C<core::num*, (core::Null?) →* void>*>* lc;
+static field core::Map<self::C<core::num*, (core::Null?) →* void>*, self::C<core::num*, (core::Null?) →* void>*>* mc;
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence_in_literals.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence_in_literals.dart.strong.expect
index 72e6fc0..592f642 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence_in_literals.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence_in_literals.dart.strong.expect
@@ -2,11 +2,11 @@
import self as self;
import "dart:core" as core;
-class C<X extends core::num* = core::num*, Y extends (self::C::X*) →* void = (core::Null*) →* void> extends core::Object {
+class C<X extends core::num* = core::num*, Y extends (self::C::X*) →* void = (core::Null?) →* void> extends core::Object {
synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
: super core::Object::•()
;
}
-static field core::List<self::C<core::num*, (core::Null*) →* void>*>* lc = <self::C<core::num*, (core::Null*) →* void>*>[];
-static field core::Map<self::C<core::num*, (core::Null*) →* void>*, self::C<core::num*, (core::Null*) →* void>*>* mc = <self::C<core::num*, (core::Null*) →* void>*, self::C<core::num*, (core::Null*) →* void>*>{};
+static field core::List<self::C<core::num*, (core::Null?) →* void>*>* lc = <self::C<core::num*, (core::Null?) →* void>*>[];
+static field core::Map<self::C<core::num*, (core::Null?) →* void>*, self::C<core::num*, (core::Null?) →* void>*>* mc = <self::C<core::num*, (core::Null?) →* void>*, self::C<core::num*, (core::Null?) →* void>*>{};
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence_in_literals.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence_in_literals.dart.strong.transformed.expect
index 72e6fc0..592f642 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence_in_literals.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/contravariant_dependence_in_literals.dart.strong.transformed.expect
@@ -2,11 +2,11 @@
import self as self;
import "dart:core" as core;
-class C<X extends core::num* = core::num*, Y extends (self::C::X*) →* void = (core::Null*) →* void> extends core::Object {
+class C<X extends core::num* = core::num*, Y extends (self::C::X*) →* void = (core::Null?) →* void> extends core::Object {
synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
: super core::Object::•()
;
}
-static field core::List<self::C<core::num*, (core::Null*) →* void>*>* lc = <self::C<core::num*, (core::Null*) →* void>*>[];
-static field core::Map<self::C<core::num*, (core::Null*) →* void>*, self::C<core::num*, (core::Null*) →* void>*>* mc = <self::C<core::num*, (core::Null*) →* void>*, self::C<core::num*, (core::Null*) →* void>*>{};
+static field core::List<self::C<core::num*, (core::Null?) →* void>*>* lc = <self::C<core::num*, (core::Null?) →* void>*>[];
+static field core::Map<self::C<core::num*, (core::Null?) →* void>*, self::C<core::num*, (core::Null?) →* void>*>* mc = <self::C<core::num*, (core::Null?) →* void>*, self::C<core::num*, (core::Null?) →* void>*>{};
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence.dart.outline.expect
index 543c453..b99b029 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence.dart.outline.expect
@@ -2,15 +2,15 @@
import self as self;
import "dart:core" as core;
-class D<X extends (self::D::X, self::D::Y) →* void = (core::Null*, core::Null*) →* void, Y extends (self::D::X*, self::D::Y) →* void = (core::Null*, core::Null*) →* void> extends core::Object {
+class D<X extends (self::D::X*, self::D::Y*) →* void = (core::Null?, core::Null?) →* void, Y extends (self::D::X*, self::D::Y*) →* void = (core::Null?, core::Null?) →* void> extends core::Object {
synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
;
}
-class E<X extends (self::E::X) →* void = (core::Null*) →* void> extends core::Object {
+class E<X extends (self::E::X*) →* void = (core::Null?) →* void> extends core::Object {
synthetic constructor •() → self::E<self::E::X*>*
;
}
-static field self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>* d;
-static field self::E<(core::Null*) →* void>* e;
+static field self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>* d;
+static field self::E<(core::Null?) →* void>* e;
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence.dart.strong.expect
index 0867d26..cf5841c 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence.dart.strong.expect
@@ -2,16 +2,16 @@
import self as self;
import "dart:core" as core;
-class D<X extends (self::D::X, self::D::Y) →* void = (core::Null*, core::Null*) →* void, Y extends (self::D::X*, self::D::Y) →* void = (core::Null*, core::Null*) →* void> extends core::Object {
+class D<X extends (self::D::X*, self::D::Y*) →* void = (core::Null?, core::Null?) →* void, Y extends (self::D::X*, self::D::Y*) →* void = (core::Null?, core::Null?) →* void> extends core::Object {
synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
: super core::Object::•()
;
}
-class E<X extends (self::E::X) →* void = (core::Null*) →* void> extends core::Object {
+class E<X extends (self::E::X*) →* void = (core::Null?) →* void> extends core::Object {
synthetic constructor •() → self::E<self::E::X*>*
: super core::Object::•()
;
}
-static field self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>* d;
-static field self::E<(core::Null*) →* void>* e;
+static field self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>* d;
+static field self::E<(core::Null?) →* void>* e;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence.dart.strong.transformed.expect
index 0867d26..cf5841c 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence.dart.strong.transformed.expect
@@ -2,16 +2,16 @@
import self as self;
import "dart:core" as core;
-class D<X extends (self::D::X, self::D::Y) →* void = (core::Null*, core::Null*) →* void, Y extends (self::D::X*, self::D::Y) →* void = (core::Null*, core::Null*) →* void> extends core::Object {
+class D<X extends (self::D::X*, self::D::Y*) →* void = (core::Null?, core::Null?) →* void, Y extends (self::D::X*, self::D::Y*) →* void = (core::Null?, core::Null?) →* void> extends core::Object {
synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
: super core::Object::•()
;
}
-class E<X extends (self::E::X) →* void = (core::Null*) →* void> extends core::Object {
+class E<X extends (self::E::X*) →* void = (core::Null?) →* void> extends core::Object {
synthetic constructor •() → self::E<self::E::X*>*
: super core::Object::•()
;
}
-static field self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>* d;
-static field self::E<(core::Null*) →* void>* e;
+static field self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>* d;
+static field self::E<(core::Null?) →* void>* e;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence_in_literals.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence_in_literals.dart.outline.expect
index bcf89d2..41e06b4 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence_in_literals.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence_in_literals.dart.outline.expect
@@ -2,17 +2,17 @@
import self as self;
import "dart:core" as core;
-class D<X extends (self::D::X, self::D::Y) →* void = (core::Null*, core::Null*) →* void, Y extends (self::D::X*, self::D::Y) →* void = (core::Null*, core::Null*) →* void> extends core::Object {
+class D<X extends (self::D::X*, self::D::Y*) →* void = (core::Null?, core::Null?) →* void, Y extends (self::D::X*, self::D::Y*) →* void = (core::Null?, core::Null?) →* void> extends core::Object {
synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
;
}
-class E<X extends (self::E::X) →* void = (core::Null*) →* void> extends core::Object {
+class E<X extends (self::E::X*) →* void = (core::Null?) →* void> extends core::Object {
synthetic constructor •() → self::E<self::E::X*>*
;
}
-static field core::List<self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>*>* ld;
-static field core::Map<self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>*, self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>*>* md;
-static field core::List<self::E<(core::Null*) →* void>*>* le;
-static field core::Map<self::E<(core::Null*) →* void>*, self::E<(core::Null*) →* void>*>* me;
+static field core::List<self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>*>* ld;
+static field core::Map<self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>*, self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>*>* md;
+static field core::List<self::E<(core::Null?) →* void>*>* le;
+static field core::Map<self::E<(core::Null?) →* void>*, self::E<(core::Null?) →* void>*>* me;
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence_in_literals.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence_in_literals.dart.strong.expect
index 47b5906..b87ae59 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence_in_literals.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence_in_literals.dart.strong.expect
@@ -2,18 +2,18 @@
import self as self;
import "dart:core" as core;
-class D<X extends (self::D::X, self::D::Y) →* void = (core::Null*, core::Null*) →* void, Y extends (self::D::X*, self::D::Y) →* void = (core::Null*, core::Null*) →* void> extends core::Object {
+class D<X extends (self::D::X*, self::D::Y*) →* void = (core::Null?, core::Null?) →* void, Y extends (self::D::X*, self::D::Y*) →* void = (core::Null?, core::Null?) →* void> extends core::Object {
synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
: super core::Object::•()
;
}
-class E<X extends (self::E::X) →* void = (core::Null*) →* void> extends core::Object {
+class E<X extends (self::E::X*) →* void = (core::Null?) →* void> extends core::Object {
synthetic constructor •() → self::E<self::E::X*>*
: super core::Object::•()
;
}
-static field core::List<self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>*>* ld = <self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>*>[];
-static field core::Map<self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>*, self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>*>* md = <self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>*, self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>*>{};
-static field core::List<self::E<(core::Null*) →* void>*>* le = <self::E<(core::Null*) →* void>*>[];
-static field core::Map<self::E<(core::Null*) →* void>*, self::E<(core::Null*) →* void>*>* me = <self::E<(core::Null*) →* void>*, self::E<(core::Null*) →* void>*>{};
+static field core::List<self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>*>* ld = <self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>*>[];
+static field core::Map<self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>*, self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>*>* md = <self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>*, self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>*>{};
+static field core::List<self::E<(core::Null?) →* void>*>* le = <self::E<(core::Null?) →* void>*>[];
+static field core::Map<self::E<(core::Null?) →* void>*, self::E<(core::Null?) →* void>*>* me = <self::E<(core::Null?) →* void>*, self::E<(core::Null?) →* void>*>{};
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence_in_literals.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence_in_literals.dart.strong.transformed.expect
index 47b5906..b87ae59 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence_in_literals.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/contravariant_mutual_dependence_in_literals.dart.strong.transformed.expect
@@ -2,18 +2,18 @@
import self as self;
import "dart:core" as core;
-class D<X extends (self::D::X, self::D::Y) →* void = (core::Null*, core::Null*) →* void, Y extends (self::D::X*, self::D::Y) →* void = (core::Null*, core::Null*) →* void> extends core::Object {
+class D<X extends (self::D::X*, self::D::Y*) →* void = (core::Null?, core::Null?) →* void, Y extends (self::D::X*, self::D::Y*) →* void = (core::Null?, core::Null?) →* void> extends core::Object {
synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
: super core::Object::•()
;
}
-class E<X extends (self::E::X) →* void = (core::Null*) →* void> extends core::Object {
+class E<X extends (self::E::X*) →* void = (core::Null?) →* void> extends core::Object {
synthetic constructor •() → self::E<self::E::X*>*
: super core::Object::•()
;
}
-static field core::List<self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>*>* ld = <self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>*>[];
-static field core::Map<self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>*, self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>*>* md = <self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>*, self::D<(core::Null*, core::Null*) →* void, (core::Null*, core::Null*) →* void>*>{};
-static field core::List<self::E<(core::Null*) →* void>*>* le = <self::E<(core::Null*) →* void>*>[];
-static field core::Map<self::E<(core::Null*) →* void>*, self::E<(core::Null*) →* void>*>* me = <self::E<(core::Null*) →* void>*, self::E<(core::Null*) →* void>*>{};
+static field core::List<self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>*>* ld = <self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>*>[];
+static field core::Map<self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>*, self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>*>* md = <self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>*, self::D<(core::Null?, core::Null?) →* void, (core::Null?, core::Null?) →* void>*>{};
+static field core::List<self::E<(core::Null?) →* void>*>* le = <self::E<(core::Null?) →* void>*>[];
+static field core::Map<self::E<(core::Null?) →* void>*, self::E<(core::Null?) →* void>*>* me = <self::E<(core::Null?) →* void>*, self::E<(core::Null?) →* void>*>{};
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence.dart.outline.expect
index ab32947..ac077fd 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence.dart.outline.expect
@@ -10,15 +10,15 @@
synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
;
}
-class D<X extends self::B<self::D::X, self::D::Y>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y>* = self::C<dynamic, dynamic>*> extends core::Object {
+class D<X extends self::B<self::D::X*, self::D::Y*>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y*>* = self::C<dynamic, dynamic>*> extends core::Object {
synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
;
}
-class E<X extends self::B<self::E::X, self::E::Y>* = self::B<dynamic, dynamic>*, Y extends () →* self::E::X* = () →* dynamic> extends core::Object {
+class E<X extends self::B<self::E::X*, self::E::Y*>* = self::B<dynamic, dynamic>*, Y extends () →* self::E::X* = () →* dynamic> extends core::Object {
synthetic constructor •() → self::E<self::E::X*, self::E::Y*>*
;
}
-class F<X extends () →* self::F::X = () →* dynamic> extends core::Object {
+class F<X extends () →* self::F::X* = () →* dynamic> extends core::Object {
synthetic constructor •() → self::F<self::F::X*>*
;
}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence.dart.strong.expect
index 9dfe27e..30e09b1 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence.dart.strong.expect
@@ -12,17 +12,17 @@
: super core::Object::•()
;
}
-class D<X extends self::B<self::D::X, self::D::Y>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y>* = self::C<dynamic, dynamic>*> extends core::Object {
+class D<X extends self::B<self::D::X*, self::D::Y*>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y*>* = self::C<dynamic, dynamic>*> extends core::Object {
synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
: super core::Object::•()
;
}
-class E<X extends self::B<self::E::X, self::E::Y>* = self::B<dynamic, dynamic>*, Y extends () →* self::E::X* = () →* dynamic> extends core::Object {
+class E<X extends self::B<self::E::X*, self::E::Y*>* = self::B<dynamic, dynamic>*, Y extends () →* self::E::X* = () →* dynamic> extends core::Object {
synthetic constructor •() → self::E<self::E::X*, self::E::Y*>*
: super core::Object::•()
;
}
-class F<X extends () →* self::F::X = () →* dynamic> extends core::Object {
+class F<X extends () →* self::F::X* = () →* dynamic> extends core::Object {
synthetic constructor •() → self::F<self::F::X*>*
: super core::Object::•()
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence.dart.strong.transformed.expect
index 9dfe27e..30e09b1 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence.dart.strong.transformed.expect
@@ -12,17 +12,17 @@
: super core::Object::•()
;
}
-class D<X extends self::B<self::D::X, self::D::Y>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y>* = self::C<dynamic, dynamic>*> extends core::Object {
+class D<X extends self::B<self::D::X*, self::D::Y*>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y*>* = self::C<dynamic, dynamic>*> extends core::Object {
synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
: super core::Object::•()
;
}
-class E<X extends self::B<self::E::X, self::E::Y>* = self::B<dynamic, dynamic>*, Y extends () →* self::E::X* = () →* dynamic> extends core::Object {
+class E<X extends self::B<self::E::X*, self::E::Y*>* = self::B<dynamic, dynamic>*, Y extends () →* self::E::X* = () →* dynamic> extends core::Object {
synthetic constructor •() → self::E<self::E::X*, self::E::Y*>*
: super core::Object::•()
;
}
-class F<X extends () →* self::F::X = () →* dynamic> extends core::Object {
+class F<X extends () →* self::F::X* = () →* dynamic> extends core::Object {
synthetic constructor •() → self::F<self::F::X*>*
: super core::Object::•()
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence_in_literals.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence_in_literals.dart.outline.expect
index e9f5ac1..259a0da 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence_in_literals.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence_in_literals.dart.outline.expect
@@ -10,15 +10,15 @@
synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
;
}
-class D<X extends self::B<self::D::X, self::D::Y>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y>* = self::C<dynamic, dynamic>*> extends core::Object {
+class D<X extends self::B<self::D::X*, self::D::Y*>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y*>* = self::C<dynamic, dynamic>*> extends core::Object {
synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
;
}
-class E<X extends self::B<self::E::X, self::E::Y>* = self::B<dynamic, dynamic>*, Y extends () →* self::E::X* = () →* dynamic> extends core::Object {
+class E<X extends self::B<self::E::X*, self::E::Y*>* = self::B<dynamic, dynamic>*, Y extends () →* self::E::X* = () →* dynamic> extends core::Object {
synthetic constructor •() → self::E<self::E::X*, self::E::Y*>*
;
}
-class F<X extends () →* self::F::X = () →* dynamic> extends core::Object {
+class F<X extends () →* self::F::X* = () →* dynamic> extends core::Object {
synthetic constructor •() → self::F<self::F::X*>*
;
}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence_in_literals.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence_in_literals.dart.strong.expect
index 8818c9d4..f5ddef9 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence_in_literals.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence_in_literals.dart.strong.expect
@@ -12,17 +12,17 @@
: super core::Object::•()
;
}
-class D<X extends self::B<self::D::X, self::D::Y>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y>* = self::C<dynamic, dynamic>*> extends core::Object {
+class D<X extends self::B<self::D::X*, self::D::Y*>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y*>* = self::C<dynamic, dynamic>*> extends core::Object {
synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
: super core::Object::•()
;
}
-class E<X extends self::B<self::E::X, self::E::Y>* = self::B<dynamic, dynamic>*, Y extends () →* self::E::X* = () →* dynamic> extends core::Object {
+class E<X extends self::B<self::E::X*, self::E::Y*>* = self::B<dynamic, dynamic>*, Y extends () →* self::E::X* = () →* dynamic> extends core::Object {
synthetic constructor •() → self::E<self::E::X*, self::E::Y*>*
: super core::Object::•()
;
}
-class F<X extends () →* self::F::X = () →* dynamic> extends core::Object {
+class F<X extends () →* self::F::X* = () →* dynamic> extends core::Object {
synthetic constructor •() → self::F<self::F::X*>*
: super core::Object::•()
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence_in_literals.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence_in_literals.dart.strong.transformed.expect
index 8818c9d4..f5ddef9 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence_in_literals.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/covariant_mutual_dependence_in_literals.dart.strong.transformed.expect
@@ -12,17 +12,17 @@
: super core::Object::•()
;
}
-class D<X extends self::B<self::D::X, self::D::Y>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y>* = self::C<dynamic, dynamic>*> extends core::Object {
+class D<X extends self::B<self::D::X*, self::D::Y*>* = self::B<dynamic, dynamic>*, Y extends self::C<self::D::X*, self::D::Y*>* = self::C<dynamic, dynamic>*> extends core::Object {
synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
: super core::Object::•()
;
}
-class E<X extends self::B<self::E::X, self::E::Y>* = self::B<dynamic, dynamic>*, Y extends () →* self::E::X* = () →* dynamic> extends core::Object {
+class E<X extends self::B<self::E::X*, self::E::Y*>* = self::B<dynamic, dynamic>*, Y extends () →* self::E::X* = () →* dynamic> extends core::Object {
synthetic constructor •() → self::E<self::E::X*, self::E::Y*>*
: super core::Object::•()
;
}
-class F<X extends () →* self::F::X = () →* dynamic> extends core::Object {
+class F<X extends () →* self::F::X* = () →* dynamic> extends core::Object {
synthetic constructor •() → self::F<self::F::X*>*
: super core::Object::•()
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/dependence.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/dependence.dart.outline.expect
index e767b17..87dce27 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/dependence.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/dependence.dart.outline.expect
@@ -6,15 +6,15 @@
synthetic constructor •() → self::A<self::A::X*>*
;
}
-class C<X extends core::Object* = dynamic, Y extends (self::C::X*) →* self::C::X* = (core::Null*) →* dynamic> extends core::Object {
+class C<X extends core::Object* = dynamic, Y extends (self::C::X*) →* self::C::X* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
;
}
-class D<X extends core::num* = core::num*, Y extends (self::D::X*) →* self::D::X* = (core::Null*) →* core::num*> extends core::Object {
+class D<X extends core::num* = core::num*, Y extends (self::D::X*) →* self::D::X* = (core::Null?) →* core::num*> extends core::Object {
synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
;
}
-static field self::C<dynamic, (core::Null*) →* dynamic>* c;
-static field self::D<core::num*, (core::Null*) →* core::num*>* d;
+static field self::C<dynamic, (core::Null?) →* dynamic>* c;
+static field self::D<core::num*, (core::Null?) →* core::num*>* d;
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/dependence.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/dependence.dart.strong.expect
index 6159d34..96c2e9a 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/dependence.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/dependence.dart.strong.expect
@@ -7,16 +7,16 @@
: super core::Object::•()
;
}
-class C<X extends core::Object* = dynamic, Y extends (self::C::X*) →* self::C::X* = (core::Null*) →* dynamic> extends core::Object {
+class C<X extends core::Object* = dynamic, Y extends (self::C::X*) →* self::C::X* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
: super core::Object::•()
;
}
-class D<X extends core::num* = core::num*, Y extends (self::D::X*) →* self::D::X* = (core::Null*) →* core::num*> extends core::Object {
+class D<X extends core::num* = core::num*, Y extends (self::D::X*) →* self::D::X* = (core::Null?) →* core::num*> extends core::Object {
synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
: super core::Object::•()
;
}
-static field self::C<dynamic, (core::Null*) →* dynamic>* c;
-static field self::D<core::num*, (core::Null*) →* core::num*>* d;
+static field self::C<dynamic, (core::Null?) →* dynamic>* c;
+static field self::D<core::num*, (core::Null?) →* core::num*>* d;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/dependence.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/dependence.dart.strong.transformed.expect
index 6159d34..96c2e9a 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/dependence.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/dependence.dart.strong.transformed.expect
@@ -7,16 +7,16 @@
: super core::Object::•()
;
}
-class C<X extends core::Object* = dynamic, Y extends (self::C::X*) →* self::C::X* = (core::Null*) →* dynamic> extends core::Object {
+class C<X extends core::Object* = dynamic, Y extends (self::C::X*) →* self::C::X* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
: super core::Object::•()
;
}
-class D<X extends core::num* = core::num*, Y extends (self::D::X*) →* self::D::X* = (core::Null*) →* core::num*> extends core::Object {
+class D<X extends core::num* = core::num*, Y extends (self::D::X*) →* self::D::X* = (core::Null?) →* core::num*> extends core::Object {
synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
: super core::Object::•()
;
}
-static field self::C<dynamic, (core::Null*) →* dynamic>* c;
-static field self::D<core::num*, (core::Null*) →* core::num*>* d;
+static field self::C<dynamic, (core::Null?) →* dynamic>* c;
+static field self::D<core::num*, (core::Null?) →* core::num*>* d;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/dependence_in_literals.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/dependence_in_literals.dart.outline.expect
index 04e5fdf..0eaaf49 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/dependence_in_literals.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/dependence_in_literals.dart.outline.expect
@@ -6,17 +6,17 @@
synthetic constructor •() → self::A<self::A::X*>*
;
}
-class C<X extends core::Object* = dynamic, Y extends (self::C::X*) →* self::C::X* = (core::Null*) →* dynamic> extends core::Object {
+class C<X extends core::Object* = dynamic, Y extends (self::C::X*) →* self::C::X* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
;
}
-class D<X extends core::num* = core::num*, Y extends (self::D::X*) →* self::D::X* = (core::Null*) →* core::num*> extends core::Object {
+class D<X extends core::num* = core::num*, Y extends (self::D::X*) →* self::D::X* = (core::Null?) →* core::num*> extends core::Object {
synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
;
}
-static field core::List<self::C<dynamic, (core::Null*) →* dynamic>*>* lc;
-static field core::Map<self::C<dynamic, (core::Null*) →* dynamic>*, self::C<dynamic, (core::Null*) →* dynamic>*>* mc;
-static field core::List<self::D<core::num*, (core::Null*) →* core::num*>*>* ld;
-static field core::Map<self::D<core::num*, (core::Null*) →* core::num*>*, self::D<core::num*, (core::Null*) →* core::num*>*>* md;
+static field core::List<self::C<dynamic, (core::Null?) →* dynamic>*>* lc;
+static field core::Map<self::C<dynamic, (core::Null?) →* dynamic>*, self::C<dynamic, (core::Null?) →* dynamic>*>* mc;
+static field core::List<self::D<core::num*, (core::Null?) →* core::num*>*>* ld;
+static field core::Map<self::D<core::num*, (core::Null?) →* core::num*>*, self::D<core::num*, (core::Null?) →* core::num*>*>* md;
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/dependence_in_literals.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/dependence_in_literals.dart.strong.expect
index 99233e6..1483925 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/dependence_in_literals.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/dependence_in_literals.dart.strong.expect
@@ -7,18 +7,18 @@
: super core::Object::•()
;
}
-class C<X extends core::Object* = dynamic, Y extends (self::C::X*) →* self::C::X* = (core::Null*) →* dynamic> extends core::Object {
+class C<X extends core::Object* = dynamic, Y extends (self::C::X*) →* self::C::X* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
: super core::Object::•()
;
}
-class D<X extends core::num* = core::num*, Y extends (self::D::X*) →* self::D::X* = (core::Null*) →* core::num*> extends core::Object {
+class D<X extends core::num* = core::num*, Y extends (self::D::X*) →* self::D::X* = (core::Null?) →* core::num*> extends core::Object {
synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
: super core::Object::•()
;
}
-static field core::List<self::C<dynamic, (core::Null*) →* dynamic>*>* lc = <self::C<dynamic, (core::Null*) →* dynamic>*>[];
-static field core::Map<self::C<dynamic, (core::Null*) →* dynamic>*, self::C<dynamic, (core::Null*) →* dynamic>*>* mc = <self::C<dynamic, (core::Null*) →* dynamic>*, self::C<dynamic, (core::Null*) →* dynamic>*>{};
-static field core::List<self::D<core::num*, (core::Null*) →* core::num*>*>* ld = <self::D<core::num*, (core::Null*) →* core::num*>*>[];
-static field core::Map<self::D<core::num*, (core::Null*) →* core::num*>*, self::D<core::num*, (core::Null*) →* core::num*>*>* md = <self::D<core::num*, (core::Null*) →* core::num*>*, self::D<core::num*, (core::Null*) →* core::num*>*>{};
+static field core::List<self::C<dynamic, (core::Null?) →* dynamic>*>* lc = <self::C<dynamic, (core::Null?) →* dynamic>*>[];
+static field core::Map<self::C<dynamic, (core::Null?) →* dynamic>*, self::C<dynamic, (core::Null?) →* dynamic>*>* mc = <self::C<dynamic, (core::Null?) →* dynamic>*, self::C<dynamic, (core::Null?) →* dynamic>*>{};
+static field core::List<self::D<core::num*, (core::Null?) →* core::num*>*>* ld = <self::D<core::num*, (core::Null?) →* core::num*>*>[];
+static field core::Map<self::D<core::num*, (core::Null?) →* core::num*>*, self::D<core::num*, (core::Null?) →* core::num*>*>* md = <self::D<core::num*, (core::Null?) →* core::num*>*, self::D<core::num*, (core::Null?) →* core::num*>*>{};
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/dependence_in_literals.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/dependence_in_literals.dart.strong.transformed.expect
index 99233e6..1483925 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/dependence_in_literals.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/dependence_in_literals.dart.strong.transformed.expect
@@ -7,18 +7,18 @@
: super core::Object::•()
;
}
-class C<X extends core::Object* = dynamic, Y extends (self::C::X*) →* self::C::X* = (core::Null*) →* dynamic> extends core::Object {
+class C<X extends core::Object* = dynamic, Y extends (self::C::X*) →* self::C::X* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
: super core::Object::•()
;
}
-class D<X extends core::num* = core::num*, Y extends (self::D::X*) →* self::D::X* = (core::Null*) →* core::num*> extends core::Object {
+class D<X extends core::num* = core::num*, Y extends (self::D::X*) →* self::D::X* = (core::Null?) →* core::num*> extends core::Object {
synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
: super core::Object::•()
;
}
-static field core::List<self::C<dynamic, (core::Null*) →* dynamic>*>* lc = <self::C<dynamic, (core::Null*) →* dynamic>*>[];
-static field core::Map<self::C<dynamic, (core::Null*) →* dynamic>*, self::C<dynamic, (core::Null*) →* dynamic>*>* mc = <self::C<dynamic, (core::Null*) →* dynamic>*, self::C<dynamic, (core::Null*) →* dynamic>*>{};
-static field core::List<self::D<core::num*, (core::Null*) →* core::num*>*>* ld = <self::D<core::num*, (core::Null*) →* core::num*>*>[];
-static field core::Map<self::D<core::num*, (core::Null*) →* core::num*>*, self::D<core::num*, (core::Null*) →* core::num*>*>* md = <self::D<core::num*, (core::Null*) →* core::num*>*, self::D<core::num*, (core::Null*) →* core::num*>*>{};
+static field core::List<self::C<dynamic, (core::Null?) →* dynamic>*>* lc = <self::C<dynamic, (core::Null?) →* dynamic>*>[];
+static field core::Map<self::C<dynamic, (core::Null?) →* dynamic>*, self::C<dynamic, (core::Null?) →* dynamic>*>* mc = <self::C<dynamic, (core::Null?) →* dynamic>*, self::C<dynamic, (core::Null?) →* dynamic>*>{};
+static field core::List<self::D<core::num*, (core::Null?) →* core::num*>*>* ld = <self::D<core::num*, (core::Null?) →* core::num*>*>[];
+static field core::Map<self::D<core::num*, (core::Null?) →* core::num*>*, self::D<core::num*, (core::Null?) →* core::num*>*>* md = <self::D<core::num*, (core::Null?) →* core::num*>*, self::D<core::num*, (core::Null?) →* core::num*>*>{};
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.outline.expect
index 4b449c4..6a0bd29 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.outline.expect
@@ -2,7 +2,7 @@
import self as self;
import "dart:core" as core;
-class B<T extends core::Comparable<self::B::T>* = core::Comparable<dynamic>*> extends core::Object {
+class B<T extends core::Comparable<self::B::T*>* = core::Comparable<dynamic>*> extends core::Object {
synthetic constructor •() → self::B<self::B::T*>*
;
}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.expect
index d1590e7..feb336e 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.expect
@@ -14,7 +14,7 @@
import self as self;
import "dart:core" as core;
-class B<T extends core::Comparable<self::B::T>* = core::Comparable<dynamic>*> extends core::Object {
+class B<T extends core::Comparable<self::B::T*>* = core::Comparable<dynamic>*> extends core::Object {
synthetic constructor •() → self::B<self::B::T*>*
: super core::Object::•()
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.transformed.expect
index d1590e7..feb336e 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.transformed.expect
@@ -14,7 +14,7 @@
import self as self;
import "dart:core" as core;
-class B<T extends core::Comparable<self::B::T>* = core::Comparable<dynamic>*> extends core::Object {
+class B<T extends core::Comparable<self::B::T*>* = core::Comparable<dynamic>*> extends core::Object {
synthetic constructor •() → self::B<self::B::T*>*
: super core::Object::•()
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart.outline.expect
index 556a2ee..a1afe46 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart.outline.expect
@@ -7,21 +7,6 @@
// class I<T extends U, U extends Y, V extends Function(W), W extends Function(X),
// ^
//
-// pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart:41:22: Error: Type 'U' is a bound of itself via 'Y', 'Z', 'T'.
-// Try breaking the cycle by removing at least on of the 'extends' clauses in the cycle.
-// class I<T extends U, U extends Y, V extends Function(W), W extends Function(X),
-// ^
-//
-// pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart:42:28: Error: Type 'Y' is a bound of itself via 'Z', 'T', 'U'.
-// Try breaking the cycle by removing at least on of the 'extends' clauses in the cycle.
-// X extends Function(V), Y extends Z, Z extends T> {}
-// ^
-//
-// pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart:42:41: Error: Type 'Z' is a bound of itself via 'T', 'U', 'Y'.
-// Try breaking the cycle by removing at least on of the 'extends' clauses in the cycle.
-// X extends Function(V), Y extends Z, Z extends T> {}
-// ^
-//
import self as self;
import "dart:core" as core;
@@ -37,32 +22,32 @@
synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
;
}
-class D<X extends self::A<self::D::X>* = self::A<dynamic>*, Y extends self::A<self::D::Y>* = self::A<dynamic>*> extends core::Object {
+class D<X extends self::A<self::D::X*>* = self::A<dynamic>*, Y extends self::A<self::D::Y*>* = self::A<dynamic>*> extends core::Object {
synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
;
}
-class E<W extends self::B<self::E::W, self::E::X>* = self::B<dynamic, dynamic>*, X extends self::C<self::E::W*, self::E::X>* = self::C<dynamic, dynamic>*, Y extends self::B<self::E::Y, self::E::Z>* = self::B<dynamic, dynamic>*, Z extends self::C<self::E::Y*, self::E::Z>* = self::C<dynamic, dynamic>*> extends core::Object {
+class E<W extends self::B<self::E::W*, self::E::X*>* = self::B<dynamic, dynamic>*, X extends self::C<self::E::W*, self::E::X*>* = self::C<dynamic, dynamic>*, Y extends self::B<self::E::Y*, self::E::Z*>* = self::B<dynamic, dynamic>*, Z extends self::C<self::E::Y*, self::E::Z*>* = self::C<dynamic, dynamic>*> extends core::Object {
synthetic constructor •() → self::E<self::E::W*, self::E::X*, self::E::Y*, self::E::Z*>*
;
}
-class F<V extends core::num* = core::num*, W extends self::B<self::F::W, self::F::X>* = self::B<dynamic, dynamic>*, X extends self::C<self::F::W*, self::F::X>* = self::C<dynamic, dynamic>*, Y extends self::B<self::F::W*, self::F::X*>* = self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, Z extends self::C<self::F::Y*, self::F::Z>* = self::C<self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, dynamic>*> extends core::Object {
+class F<V extends core::num* = core::num*, W extends self::B<self::F::W*, self::F::X*>* = self::B<dynamic, dynamic>*, X extends self::C<self::F::W*, self::F::X*>* = self::C<dynamic, dynamic>*, Y extends self::B<self::F::W*, self::F::X*>* = self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, Z extends self::C<self::F::Y*, self::F::Z*>* = self::C<self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, dynamic>*> extends core::Object {
synthetic constructor •() → self::F<self::F::V*, self::F::W*, self::F::X*, self::F::Y*, self::F::Z*>*
;
}
-class G<V extends core::num* = core::num*, W extends self::B<self::G::V*, self::G::X>* = self::B<core::num*, dynamic>*, X extends self::C<self::G::W*, self::G::V*>* = self::C<dynamic, core::num*>*, Y extends self::B<self::G::W*, self::G::X*>* = self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, Z extends self::C<self::G::Y*, self::G::Z>* = self::C<self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, dynamic>*> extends core::Object {
+class G<V extends core::num* = core::num*, W extends self::B<self::G::V*, self::G::X*>* = self::B<core::num*, dynamic>*, X extends self::C<self::G::W*, self::G::V*>* = self::C<dynamic, core::num*>*, Y extends self::B<self::G::W*, self::G::X*>* = self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, Z extends self::C<self::G::Y*, self::G::Z*>* = self::C<self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, dynamic>*> extends core::Object {
synthetic constructor •() → self::G<self::G::V*, self::G::W*, self::G::X*, self::G::Y*, self::G::Z*>*
;
}
-class H<S extends self::A<self::H::S>* = self::A<dynamic>*, T extends self::B<self::H::T, self::H::U>* = self::B<dynamic, dynamic>*, U extends self::C<self::H::T*, self::H::U>* = self::C<dynamic, dynamic>*, V extends self::A<self::H::V>* = self::A<dynamic>*, W extends self::H::S* = self::A<dynamic>*, X extends self::H::T* = self::B<dynamic, dynamic>*, Y extends self::H::U* = self::C<dynamic, dynamic>*, Z extends self::H::V* = self::A<dynamic>*> extends core::Object {
+class H<S extends self::A<self::H::S*>* = self::A<dynamic>*, T extends self::B<self::H::T*, self::H::U*>* = self::B<dynamic, dynamic>*, U extends self::C<self::H::T*, self::H::U*>* = self::C<dynamic, dynamic>*, V extends self::A<self::H::V*>* = self::A<dynamic>*, W extends self::H::S* = self::A<dynamic>*, X extends self::H::T* = self::B<dynamic, dynamic>*, Y extends self::H::U* = self::C<dynamic, dynamic>*, Z extends self::H::V* = self::A<dynamic>*> extends core::Object {
synthetic constructor •() → self::H<self::H::S*, self::H::T*, self::H::U*, self::H::V*, self::H::W*, self::H::X*, self::H::Y*, self::H::Z*>*
;
}
-class I<T extends self::I::U = dynamic, U extends self::I::Y = dynamic, V extends (self::I::W) →* dynamic = (core::Null*) →* dynamic, W extends (self::I::X) →* dynamic = (core::Null*) →* dynamic, X extends (self::I::V*) →* dynamic = (core::Null*) →* dynamic, Y extends self::I::Z = dynamic, Z extends self::I::T = dynamic> extends core::Object {
- synthetic constructor •() → self::I<self::I::T, self::I::U, self::I::V*, self::I::W*, self::I::X*, self::I::Y, self::I::Z>*
+class I<T extends invalid-type = invalid-type, U extends self::I::Y* = invalid-type, V extends (self::I::W*) →* dynamic = (core::Null?) →* dynamic, W extends (self::I::X*) →* dynamic = (core::Null?) →* dynamic, X extends (self::I::V*) →* dynamic = (core::Null?) →* dynamic, Y extends self::I::Z* = invalid-type, Z extends self::I::T* = invalid-type> extends core::Object {
+ synthetic constructor •() → self::I<self::I::T*, self::I::U*, self::I::V*, self::I::W*, self::I::X*, self::I::Y*, self::I::Z*>*
;
}
-class J<S extends (self::J::U) →* self::J::T = (core::Null*) →* dynamic, T extends (self::J::S*) →* self::J::U = (core::Null*) →* dynamic, U extends (self::J::T*) →* self::J::S* = (core::Null*) →* dynamic, V extends self::J::W = dynamic, W extends self::J::X = dynamic, X extends (self::J::V) →* self::J::Y = (core::Null*) →* dynamic, Y extends self::J::Z = dynamic, Z extends self::J::X* = dynamic> extends core::Object {
- synthetic constructor •() → self::J<self::J::S*, self::J::T*, self::J::U*, self::J::V, self::J::W, self::J::X*, self::J::Y, self::J::Z*>*
+class J<S extends (self::J::U*) →* self::J::T* = (core::Null?) →* dynamic, T extends (self::J::S*) →* self::J::U* = (core::Null?) →* dynamic, U extends (self::J::T*) →* self::J::S* = (core::Null?) →* dynamic, V extends self::J::W* = dynamic, W extends self::J::X* = dynamic, X extends (self::J::V*) →* self::J::Y* = (core::Null?) →* dynamic, Y extends self::J::Z* = dynamic, Z extends self::J::X* = dynamic> extends core::Object {
+ synthetic constructor •() → self::J<self::J::S*, self::J::T*, self::J::U*, self::J::V*, self::J::W*, self::J::X*, self::J::Y*, self::J::Z*>*
;
}
static field self::D<self::A<dynamic>*, self::A<dynamic>*>* d;
@@ -70,7 +55,7 @@
static field self::F<core::num*, self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*, self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, self::C<self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, dynamic>*>* f;
static field self::G<core::num*, self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*, self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, self::C<self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, dynamic>*>* g;
static field self::H<self::A<dynamic>*, self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*, self::A<dynamic>*, self::A<dynamic>*, self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*, self::A<dynamic>*>* h;
-static field self::I<dynamic, dynamic, (core::Null*) →* dynamic, (core::Null*) →* dynamic, (core::Null*) →* dynamic, dynamic, dynamic>* i;
-static field self::J<(core::Null*) →* dynamic, (core::Null*) →* dynamic, (core::Null*) →* dynamic, dynamic, dynamic, (core::Null*) →* dynamic, dynamic, dynamic>* j;
+static field self::I<invalid-type, invalid-type, (core::Null?) →* dynamic, (core::Null?) →* dynamic, (core::Null?) →* dynamic, invalid-type, invalid-type>* i;
+static field self::J<(core::Null?) →* dynamic, (core::Null?) →* dynamic, (core::Null?) →* dynamic, dynamic, dynamic, (core::Null?) →* dynamic, dynamic, dynamic>* j;
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart.strong.expect
index cc78f70..f195645 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart.strong.expect
@@ -7,21 +7,6 @@
// class I<T extends U, U extends Y, V extends Function(W), W extends Function(X),
// ^
//
-// pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart:41:22: Error: Type 'U' is a bound of itself via 'Y', 'Z', 'T'.
-// Try breaking the cycle by removing at least on of the 'extends' clauses in the cycle.
-// class I<T extends U, U extends Y, V extends Function(W), W extends Function(X),
-// ^
-//
-// pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart:42:28: Error: Type 'Y' is a bound of itself via 'Z', 'T', 'U'.
-// Try breaking the cycle by removing at least on of the 'extends' clauses in the cycle.
-// X extends Function(V), Y extends Z, Z extends T> {}
-// ^
-//
-// pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart:42:41: Error: Type 'Z' is a bound of itself via 'T', 'U', 'Y'.
-// Try breaking the cycle by removing at least on of the 'extends' clauses in the cycle.
-// X extends Function(V), Y extends Z, Z extends T> {}
-// ^
-//
import self as self;
import "dart:core" as core;
@@ -40,38 +25,38 @@
: super core::Object::•()
;
}
-class D<X extends self::A<self::D::X>* = self::A<dynamic>*, Y extends self::A<self::D::Y>* = self::A<dynamic>*> extends core::Object {
+class D<X extends self::A<self::D::X*>* = self::A<dynamic>*, Y extends self::A<self::D::Y*>* = self::A<dynamic>*> extends core::Object {
synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
: super core::Object::•()
;
}
-class E<W extends self::B<self::E::W, self::E::X>* = self::B<dynamic, dynamic>*, X extends self::C<self::E::W*, self::E::X>* = self::C<dynamic, dynamic>*, Y extends self::B<self::E::Y, self::E::Z>* = self::B<dynamic, dynamic>*, Z extends self::C<self::E::Y*, self::E::Z>* = self::C<dynamic, dynamic>*> extends core::Object {
+class E<W extends self::B<self::E::W*, self::E::X*>* = self::B<dynamic, dynamic>*, X extends self::C<self::E::W*, self::E::X*>* = self::C<dynamic, dynamic>*, Y extends self::B<self::E::Y*, self::E::Z*>* = self::B<dynamic, dynamic>*, Z extends self::C<self::E::Y*, self::E::Z*>* = self::C<dynamic, dynamic>*> extends core::Object {
synthetic constructor •() → self::E<self::E::W*, self::E::X*, self::E::Y*, self::E::Z*>*
: super core::Object::•()
;
}
-class F<V extends core::num* = core::num*, W extends self::B<self::F::W, self::F::X>* = self::B<dynamic, dynamic>*, X extends self::C<self::F::W*, self::F::X>* = self::C<dynamic, dynamic>*, Y extends self::B<self::F::W*, self::F::X*>* = self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, Z extends self::C<self::F::Y*, self::F::Z>* = self::C<self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, dynamic>*> extends core::Object {
+class F<V extends core::num* = core::num*, W extends self::B<self::F::W*, self::F::X*>* = self::B<dynamic, dynamic>*, X extends self::C<self::F::W*, self::F::X*>* = self::C<dynamic, dynamic>*, Y extends self::B<self::F::W*, self::F::X*>* = self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, Z extends self::C<self::F::Y*, self::F::Z*>* = self::C<self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, dynamic>*> extends core::Object {
synthetic constructor •() → self::F<self::F::V*, self::F::W*, self::F::X*, self::F::Y*, self::F::Z*>*
: super core::Object::•()
;
}
-class G<V extends core::num* = core::num*, W extends self::B<self::G::V*, self::G::X>* = self::B<core::num*, dynamic>*, X extends self::C<self::G::W*, self::G::V*>* = self::C<dynamic, core::num*>*, Y extends self::B<self::G::W*, self::G::X*>* = self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, Z extends self::C<self::G::Y*, self::G::Z>* = self::C<self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, dynamic>*> extends core::Object {
+class G<V extends core::num* = core::num*, W extends self::B<self::G::V*, self::G::X*>* = self::B<core::num*, dynamic>*, X extends self::C<self::G::W*, self::G::V*>* = self::C<dynamic, core::num*>*, Y extends self::B<self::G::W*, self::G::X*>* = self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, Z extends self::C<self::G::Y*, self::G::Z*>* = self::C<self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, dynamic>*> extends core::Object {
synthetic constructor •() → self::G<self::G::V*, self::G::W*, self::G::X*, self::G::Y*, self::G::Z*>*
: super core::Object::•()
;
}
-class H<S extends self::A<self::H::S>* = self::A<dynamic>*, T extends self::B<self::H::T, self::H::U>* = self::B<dynamic, dynamic>*, U extends self::C<self::H::T*, self::H::U>* = self::C<dynamic, dynamic>*, V extends self::A<self::H::V>* = self::A<dynamic>*, W extends self::H::S* = self::A<dynamic>*, X extends self::H::T* = self::B<dynamic, dynamic>*, Y extends self::H::U* = self::C<dynamic, dynamic>*, Z extends self::H::V* = self::A<dynamic>*> extends core::Object {
+class H<S extends self::A<self::H::S*>* = self::A<dynamic>*, T extends self::B<self::H::T*, self::H::U*>* = self::B<dynamic, dynamic>*, U extends self::C<self::H::T*, self::H::U*>* = self::C<dynamic, dynamic>*, V extends self::A<self::H::V*>* = self::A<dynamic>*, W extends self::H::S* = self::A<dynamic>*, X extends self::H::T* = self::B<dynamic, dynamic>*, Y extends self::H::U* = self::C<dynamic, dynamic>*, Z extends self::H::V* = self::A<dynamic>*> extends core::Object {
synthetic constructor •() → self::H<self::H::S*, self::H::T*, self::H::U*, self::H::V*, self::H::W*, self::H::X*, self::H::Y*, self::H::Z*>*
: super core::Object::•()
;
}
-class I<T extends self::I::U = dynamic, U extends self::I::Y = dynamic, V extends (self::I::W) →* dynamic = (core::Null*) →* dynamic, W extends (self::I::X) →* dynamic = (core::Null*) →* dynamic, X extends (self::I::V*) →* dynamic = (core::Null*) →* dynamic, Y extends self::I::Z = dynamic, Z extends self::I::T = dynamic> extends core::Object {
- synthetic constructor •() → self::I<self::I::T, self::I::U, self::I::V*, self::I::W*, self::I::X*, self::I::Y, self::I::Z>*
+class I<T extends invalid-type = invalid-type, U extends self::I::Y* = invalid-type, V extends (self::I::W*) →* dynamic = (core::Null?) →* dynamic, W extends (self::I::X*) →* dynamic = (core::Null?) →* dynamic, X extends (self::I::V*) →* dynamic = (core::Null?) →* dynamic, Y extends self::I::Z* = invalid-type, Z extends self::I::T* = invalid-type> extends core::Object {
+ synthetic constructor •() → self::I<self::I::T*, self::I::U*, self::I::V*, self::I::W*, self::I::X*, self::I::Y*, self::I::Z*>*
: super core::Object::•()
;
}
-class J<S extends (self::J::U) →* self::J::T = (core::Null*) →* dynamic, T extends (self::J::S*) →* self::J::U = (core::Null*) →* dynamic, U extends (self::J::T*) →* self::J::S* = (core::Null*) →* dynamic, V extends self::J::W = dynamic, W extends self::J::X = dynamic, X extends (self::J::V) →* self::J::Y = (core::Null*) →* dynamic, Y extends self::J::Z = dynamic, Z extends self::J::X* = dynamic> extends core::Object {
- synthetic constructor •() → self::J<self::J::S*, self::J::T*, self::J::U*, self::J::V, self::J::W, self::J::X*, self::J::Y, self::J::Z*>*
+class J<S extends (self::J::U*) →* self::J::T* = (core::Null?) →* dynamic, T extends (self::J::S*) →* self::J::U* = (core::Null?) →* dynamic, U extends (self::J::T*) →* self::J::S* = (core::Null?) →* dynamic, V extends self::J::W* = dynamic, W extends self::J::X* = dynamic, X extends (self::J::V*) →* self::J::Y* = (core::Null?) →* dynamic, Y extends self::J::Z* = dynamic, Z extends self::J::X* = dynamic> extends core::Object {
+ synthetic constructor •() → self::J<self::J::S*, self::J::T*, self::J::U*, self::J::V*, self::J::W*, self::J::X*, self::J::Y*, self::J::Z*>*
: super core::Object::•()
;
}
@@ -80,6 +65,6 @@
static field self::F<core::num*, self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*, self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, self::C<self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, dynamic>*>* f;
static field self::G<core::num*, self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*, self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, self::C<self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, dynamic>*>* g;
static field self::H<self::A<dynamic>*, self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*, self::A<dynamic>*, self::A<dynamic>*, self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*, self::A<dynamic>*>* h;
-static field self::I<dynamic, dynamic, (core::Null*) →* dynamic, (core::Null*) →* dynamic, (core::Null*) →* dynamic, dynamic, dynamic>* i;
-static field self::J<(core::Null*) →* dynamic, (core::Null*) →* dynamic, (core::Null*) →* dynamic, dynamic, dynamic, (core::Null*) →* dynamic, dynamic, dynamic>* j;
+static field self::I<invalid-type, invalid-type, (core::Null?) →* dynamic, (core::Null?) →* dynamic, (core::Null?) →* dynamic, invalid-type, invalid-type>* i;
+static field self::J<(core::Null?) →* dynamic, (core::Null?) →* dynamic, (core::Null?) →* dynamic, dynamic, dynamic, (core::Null?) →* dynamic, dynamic, dynamic>* j;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart.strong.transformed.expect
index cc78f70..f195645 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart.strong.transformed.expect
@@ -7,21 +7,6 @@
// class I<T extends U, U extends Y, V extends Function(W), W extends Function(X),
// ^
//
-// pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart:41:22: Error: Type 'U' is a bound of itself via 'Y', 'Z', 'T'.
-// Try breaking the cycle by removing at least on of the 'extends' clauses in the cycle.
-// class I<T extends U, U extends Y, V extends Function(W), W extends Function(X),
-// ^
-//
-// pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart:42:28: Error: Type 'Y' is a bound of itself via 'Z', 'T', 'U'.
-// Try breaking the cycle by removing at least on of the 'extends' clauses in the cycle.
-// X extends Function(V), Y extends Z, Z extends T> {}
-// ^
-//
-// pkg/front_end/testcases/instantiate_to_bound/multiple_strongly_connected.dart:42:41: Error: Type 'Z' is a bound of itself via 'T', 'U', 'Y'.
-// Try breaking the cycle by removing at least on of the 'extends' clauses in the cycle.
-// X extends Function(V), Y extends Z, Z extends T> {}
-// ^
-//
import self as self;
import "dart:core" as core;
@@ -40,38 +25,38 @@
: super core::Object::•()
;
}
-class D<X extends self::A<self::D::X>* = self::A<dynamic>*, Y extends self::A<self::D::Y>* = self::A<dynamic>*> extends core::Object {
+class D<X extends self::A<self::D::X*>* = self::A<dynamic>*, Y extends self::A<self::D::Y*>* = self::A<dynamic>*> extends core::Object {
synthetic constructor •() → self::D<self::D::X*, self::D::Y*>*
: super core::Object::•()
;
}
-class E<W extends self::B<self::E::W, self::E::X>* = self::B<dynamic, dynamic>*, X extends self::C<self::E::W*, self::E::X>* = self::C<dynamic, dynamic>*, Y extends self::B<self::E::Y, self::E::Z>* = self::B<dynamic, dynamic>*, Z extends self::C<self::E::Y*, self::E::Z>* = self::C<dynamic, dynamic>*> extends core::Object {
+class E<W extends self::B<self::E::W*, self::E::X*>* = self::B<dynamic, dynamic>*, X extends self::C<self::E::W*, self::E::X*>* = self::C<dynamic, dynamic>*, Y extends self::B<self::E::Y*, self::E::Z*>* = self::B<dynamic, dynamic>*, Z extends self::C<self::E::Y*, self::E::Z*>* = self::C<dynamic, dynamic>*> extends core::Object {
synthetic constructor •() → self::E<self::E::W*, self::E::X*, self::E::Y*, self::E::Z*>*
: super core::Object::•()
;
}
-class F<V extends core::num* = core::num*, W extends self::B<self::F::W, self::F::X>* = self::B<dynamic, dynamic>*, X extends self::C<self::F::W*, self::F::X>* = self::C<dynamic, dynamic>*, Y extends self::B<self::F::W*, self::F::X*>* = self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, Z extends self::C<self::F::Y*, self::F::Z>* = self::C<self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, dynamic>*> extends core::Object {
+class F<V extends core::num* = core::num*, W extends self::B<self::F::W*, self::F::X*>* = self::B<dynamic, dynamic>*, X extends self::C<self::F::W*, self::F::X*>* = self::C<dynamic, dynamic>*, Y extends self::B<self::F::W*, self::F::X*>* = self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, Z extends self::C<self::F::Y*, self::F::Z*>* = self::C<self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, dynamic>*> extends core::Object {
synthetic constructor •() → self::F<self::F::V*, self::F::W*, self::F::X*, self::F::Y*, self::F::Z*>*
: super core::Object::•()
;
}
-class G<V extends core::num* = core::num*, W extends self::B<self::G::V*, self::G::X>* = self::B<core::num*, dynamic>*, X extends self::C<self::G::W*, self::G::V*>* = self::C<dynamic, core::num*>*, Y extends self::B<self::G::W*, self::G::X*>* = self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, Z extends self::C<self::G::Y*, self::G::Z>* = self::C<self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, dynamic>*> extends core::Object {
+class G<V extends core::num* = core::num*, W extends self::B<self::G::V*, self::G::X*>* = self::B<core::num*, dynamic>*, X extends self::C<self::G::W*, self::G::V*>* = self::C<dynamic, core::num*>*, Y extends self::B<self::G::W*, self::G::X*>* = self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, Z extends self::C<self::G::Y*, self::G::Z*>* = self::C<self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, dynamic>*> extends core::Object {
synthetic constructor •() → self::G<self::G::V*, self::G::W*, self::G::X*, self::G::Y*, self::G::Z*>*
: super core::Object::•()
;
}
-class H<S extends self::A<self::H::S>* = self::A<dynamic>*, T extends self::B<self::H::T, self::H::U>* = self::B<dynamic, dynamic>*, U extends self::C<self::H::T*, self::H::U>* = self::C<dynamic, dynamic>*, V extends self::A<self::H::V>* = self::A<dynamic>*, W extends self::H::S* = self::A<dynamic>*, X extends self::H::T* = self::B<dynamic, dynamic>*, Y extends self::H::U* = self::C<dynamic, dynamic>*, Z extends self::H::V* = self::A<dynamic>*> extends core::Object {
+class H<S extends self::A<self::H::S*>* = self::A<dynamic>*, T extends self::B<self::H::T*, self::H::U*>* = self::B<dynamic, dynamic>*, U extends self::C<self::H::T*, self::H::U*>* = self::C<dynamic, dynamic>*, V extends self::A<self::H::V*>* = self::A<dynamic>*, W extends self::H::S* = self::A<dynamic>*, X extends self::H::T* = self::B<dynamic, dynamic>*, Y extends self::H::U* = self::C<dynamic, dynamic>*, Z extends self::H::V* = self::A<dynamic>*> extends core::Object {
synthetic constructor •() → self::H<self::H::S*, self::H::T*, self::H::U*, self::H::V*, self::H::W*, self::H::X*, self::H::Y*, self::H::Z*>*
: super core::Object::•()
;
}
-class I<T extends self::I::U = dynamic, U extends self::I::Y = dynamic, V extends (self::I::W) →* dynamic = (core::Null*) →* dynamic, W extends (self::I::X) →* dynamic = (core::Null*) →* dynamic, X extends (self::I::V*) →* dynamic = (core::Null*) →* dynamic, Y extends self::I::Z = dynamic, Z extends self::I::T = dynamic> extends core::Object {
- synthetic constructor •() → self::I<self::I::T, self::I::U, self::I::V*, self::I::W*, self::I::X*, self::I::Y, self::I::Z>*
+class I<T extends invalid-type = invalid-type, U extends self::I::Y* = invalid-type, V extends (self::I::W*) →* dynamic = (core::Null?) →* dynamic, W extends (self::I::X*) →* dynamic = (core::Null?) →* dynamic, X extends (self::I::V*) →* dynamic = (core::Null?) →* dynamic, Y extends self::I::Z* = invalid-type, Z extends self::I::T* = invalid-type> extends core::Object {
+ synthetic constructor •() → self::I<self::I::T*, self::I::U*, self::I::V*, self::I::W*, self::I::X*, self::I::Y*, self::I::Z*>*
: super core::Object::•()
;
}
-class J<S extends (self::J::U) →* self::J::T = (core::Null*) →* dynamic, T extends (self::J::S*) →* self::J::U = (core::Null*) →* dynamic, U extends (self::J::T*) →* self::J::S* = (core::Null*) →* dynamic, V extends self::J::W = dynamic, W extends self::J::X = dynamic, X extends (self::J::V) →* self::J::Y = (core::Null*) →* dynamic, Y extends self::J::Z = dynamic, Z extends self::J::X* = dynamic> extends core::Object {
- synthetic constructor •() → self::J<self::J::S*, self::J::T*, self::J::U*, self::J::V, self::J::W, self::J::X*, self::J::Y, self::J::Z*>*
+class J<S extends (self::J::U*) →* self::J::T* = (core::Null?) →* dynamic, T extends (self::J::S*) →* self::J::U* = (core::Null?) →* dynamic, U extends (self::J::T*) →* self::J::S* = (core::Null?) →* dynamic, V extends self::J::W* = dynamic, W extends self::J::X* = dynamic, X extends (self::J::V*) →* self::J::Y* = (core::Null?) →* dynamic, Y extends self::J::Z* = dynamic, Z extends self::J::X* = dynamic> extends core::Object {
+ synthetic constructor •() → self::J<self::J::S*, self::J::T*, self::J::U*, self::J::V*, self::J::W*, self::J::X*, self::J::Y*, self::J::Z*>*
: super core::Object::•()
;
}
@@ -80,6 +65,6 @@
static field self::F<core::num*, self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*, self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, self::C<self::B<self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*>*, dynamic>*>* f;
static field self::G<core::num*, self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*, self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, self::C<self::B<self::B<core::num*, dynamic>*, self::C<dynamic, core::num*>*>*, dynamic>*>* g;
static field self::H<self::A<dynamic>*, self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*, self::A<dynamic>*, self::A<dynamic>*, self::B<dynamic, dynamic>*, self::C<dynamic, dynamic>*, self::A<dynamic>*>* h;
-static field self::I<dynamic, dynamic, (core::Null*) →* dynamic, (core::Null*) →* dynamic, (core::Null*) →* dynamic, dynamic, dynamic>* i;
-static field self::J<(core::Null*) →* dynamic, (core::Null*) →* dynamic, (core::Null*) →* dynamic, dynamic, dynamic, (core::Null*) →* dynamic, dynamic, dynamic>* j;
+static field self::I<invalid-type, invalid-type, (core::Null?) →* dynamic, (core::Null?) →* dynamic, (core::Null?) →* dynamic, invalid-type, invalid-type>* i;
+static field self::J<(core::Null?) →* dynamic, (core::Null?) →* dynamic, (core::Null?) →* dynamic, dynamic, dynamic, (core::Null?) →* dynamic, dynamic, dynamic>* j;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence.dart.outline.expect
index 78b6d1c..e4d29b4 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence.dart.outline.expect
@@ -6,50 +6,50 @@
synthetic constructor •() → self::B<self::B::X*, self::B::Y*>*
;
}
-class C1<X extends (self::C1::Y) →* self::C1::X = (core::Null*) →* dynamic, Y extends (self::C1::Y) →* self::C1::X* = (core::Null*) →* dynamic> extends core::Object {
+class C1<X extends (self::C1::Y*) →* self::C1::X* = (core::Null?) →* dynamic, Y extends (self::C1::Y*) →* self::C1::X* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::C1<self::C1::X*, self::C1::Y*>*
;
}
-class C2<X extends (self::C2::Y) →* self::C2::X = (core::Null*) →* dynamic, Y extends (self::C2::X*) →* self::C2::Y = (core::Null*) →* dynamic> extends core::Object {
+class C2<X extends (self::C2::Y*) →* self::C2::X* = (core::Null?) →* dynamic, Y extends (self::C2::X*) →* self::C2::Y* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::C2<self::C2::X*, self::C2::Y*>*
;
}
-class C3<X extends (self::C3::X, self::C3::Y) →* self::C3::X = (core::Null*, core::Null*) →* dynamic, Y extends (self::C3::X*, self::C3::Y) →* self::C3::X* = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class C3<X extends (self::C3::X*, self::C3::Y*) →* self::C3::X* = (core::Null?, core::Null?) →* dynamic, Y extends (self::C3::X*, self::C3::Y*) →* self::C3::X* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::C3<self::C3::X*, self::C3::Y*>*
;
}
-class C4<X extends (self::C4::X, self::C4::Y) →* self::C4::X = (core::Null*, core::Null*) →* dynamic, Y extends (self::C4::X*, self::C4::Y) →* self::C4::Y = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class C4<X extends (self::C4::X*, self::C4::Y*) →* self::C4::X* = (core::Null?, core::Null?) →* dynamic, Y extends (self::C4::X*, self::C4::Y*) →* self::C4::Y* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::C4<self::C4::X*, self::C4::Y*>*
;
}
-class D1<X extends self::B<self::D1::X, self::D1::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D1::Y) →* self::D1::X* = (core::Null*) →* dynamic> extends core::Object {
+class D1<X extends self::B<self::D1::X*, self::D1::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D1::Y*) →* self::D1::X* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::D1<self::D1::X*, self::D1::Y*>*
;
}
-class D2<X extends self::B<self::D2::X, self::D2::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D2::X*) →* self::D2::Y = (core::Null*) →* dynamic> extends core::Object {
+class D2<X extends self::B<self::D2::X*, self::D2::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D2::X*) →* self::D2::Y* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::D2<self::D2::X*, self::D2::Y*>*
;
}
-class D3<X extends self::B<self::D3::X, self::D3::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D3::X*, self::D3::Y) →* self::D3::X* = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class D3<X extends self::B<self::D3::X*, self::D3::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D3::X*, self::D3::Y*) →* self::D3::X* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::D3<self::D3::X*, self::D3::Y*>*
;
}
-class D4<X extends self::B<self::D4::X, self::D4::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D4::X*, self::D4::Y) →* self::D4::Y = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class D4<X extends self::B<self::D4::X*, self::D4::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D4::X*, self::D4::Y*) →* self::D4::Y* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::D4<self::D4::X*, self::D4::Y*>*
;
}
-class E<X extends (self::E::X) →* self::E::X = (core::Null*) →* dynamic> extends core::Object {
+class E<X extends (self::E::X*) →* self::E::X* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::E<self::E::X*>*
;
}
-static field self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>* c1;
-static field self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>* c2;
-static field self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>* c3;
-static field self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>* c4;
-static field self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>* d1;
-static field self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>* d2;
-static field self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>* d3;
-static field self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>* d4;
-static field self::E<(core::Null*) →* dynamic>* e;
+static field self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>* c1;
+static field self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>* c2;
+static field self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>* c3;
+static field self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>* c4;
+static field self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>* d1;
+static field self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>* d2;
+static field self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>* d3;
+static field self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>* d4;
+static field self::E<(core::Null?) →* dynamic>* e;
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence.dart.strong.expect
index ecb02f3..c56a66f 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence.dart.strong.expect
@@ -7,58 +7,58 @@
: super core::Object::•()
;
}
-class C1<X extends (self::C1::Y) →* self::C1::X = (core::Null*) →* dynamic, Y extends (self::C1::Y) →* self::C1::X* = (core::Null*) →* dynamic> extends core::Object {
+class C1<X extends (self::C1::Y*) →* self::C1::X* = (core::Null?) →* dynamic, Y extends (self::C1::Y*) →* self::C1::X* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::C1<self::C1::X*, self::C1::Y*>*
: super core::Object::•()
;
}
-class C2<X extends (self::C2::Y) →* self::C2::X = (core::Null*) →* dynamic, Y extends (self::C2::X*) →* self::C2::Y = (core::Null*) →* dynamic> extends core::Object {
+class C2<X extends (self::C2::Y*) →* self::C2::X* = (core::Null?) →* dynamic, Y extends (self::C2::X*) →* self::C2::Y* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::C2<self::C2::X*, self::C2::Y*>*
: super core::Object::•()
;
}
-class C3<X extends (self::C3::X, self::C3::Y) →* self::C3::X = (core::Null*, core::Null*) →* dynamic, Y extends (self::C3::X*, self::C3::Y) →* self::C3::X* = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class C3<X extends (self::C3::X*, self::C3::Y*) →* self::C3::X* = (core::Null?, core::Null?) →* dynamic, Y extends (self::C3::X*, self::C3::Y*) →* self::C3::X* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::C3<self::C3::X*, self::C3::Y*>*
: super core::Object::•()
;
}
-class C4<X extends (self::C4::X, self::C4::Y) →* self::C4::X = (core::Null*, core::Null*) →* dynamic, Y extends (self::C4::X*, self::C4::Y) →* self::C4::Y = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class C4<X extends (self::C4::X*, self::C4::Y*) →* self::C4::X* = (core::Null?, core::Null?) →* dynamic, Y extends (self::C4::X*, self::C4::Y*) →* self::C4::Y* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::C4<self::C4::X*, self::C4::Y*>*
: super core::Object::•()
;
}
-class D1<X extends self::B<self::D1::X, self::D1::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D1::Y) →* self::D1::X* = (core::Null*) →* dynamic> extends core::Object {
+class D1<X extends self::B<self::D1::X*, self::D1::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D1::Y*) →* self::D1::X* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::D1<self::D1::X*, self::D1::Y*>*
: super core::Object::•()
;
}
-class D2<X extends self::B<self::D2::X, self::D2::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D2::X*) →* self::D2::Y = (core::Null*) →* dynamic> extends core::Object {
+class D2<X extends self::B<self::D2::X*, self::D2::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D2::X*) →* self::D2::Y* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::D2<self::D2::X*, self::D2::Y*>*
: super core::Object::•()
;
}
-class D3<X extends self::B<self::D3::X, self::D3::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D3::X*, self::D3::Y) →* self::D3::X* = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class D3<X extends self::B<self::D3::X*, self::D3::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D3::X*, self::D3::Y*) →* self::D3::X* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::D3<self::D3::X*, self::D3::Y*>*
: super core::Object::•()
;
}
-class D4<X extends self::B<self::D4::X, self::D4::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D4::X*, self::D4::Y) →* self::D4::Y = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class D4<X extends self::B<self::D4::X*, self::D4::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D4::X*, self::D4::Y*) →* self::D4::Y* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::D4<self::D4::X*, self::D4::Y*>*
: super core::Object::•()
;
}
-class E<X extends (self::E::X) →* self::E::X = (core::Null*) →* dynamic> extends core::Object {
+class E<X extends (self::E::X*) →* self::E::X* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::E<self::E::X*>*
: super core::Object::•()
;
}
-static field self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>* c1;
-static field self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>* c2;
-static field self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>* c3;
-static field self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>* c4;
-static field self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>* d1;
-static field self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>* d2;
-static field self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>* d3;
-static field self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>* d4;
-static field self::E<(core::Null*) →* dynamic>* e;
+static field self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>* c1;
+static field self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>* c2;
+static field self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>* c3;
+static field self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>* c4;
+static field self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>* d1;
+static field self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>* d2;
+static field self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>* d3;
+static field self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>* d4;
+static field self::E<(core::Null?) →* dynamic>* e;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence.dart.strong.transformed.expect
index ecb02f3..c56a66f 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence.dart.strong.transformed.expect
@@ -7,58 +7,58 @@
: super core::Object::•()
;
}
-class C1<X extends (self::C1::Y) →* self::C1::X = (core::Null*) →* dynamic, Y extends (self::C1::Y) →* self::C1::X* = (core::Null*) →* dynamic> extends core::Object {
+class C1<X extends (self::C1::Y*) →* self::C1::X* = (core::Null?) →* dynamic, Y extends (self::C1::Y*) →* self::C1::X* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::C1<self::C1::X*, self::C1::Y*>*
: super core::Object::•()
;
}
-class C2<X extends (self::C2::Y) →* self::C2::X = (core::Null*) →* dynamic, Y extends (self::C2::X*) →* self::C2::Y = (core::Null*) →* dynamic> extends core::Object {
+class C2<X extends (self::C2::Y*) →* self::C2::X* = (core::Null?) →* dynamic, Y extends (self::C2::X*) →* self::C2::Y* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::C2<self::C2::X*, self::C2::Y*>*
: super core::Object::•()
;
}
-class C3<X extends (self::C3::X, self::C3::Y) →* self::C3::X = (core::Null*, core::Null*) →* dynamic, Y extends (self::C3::X*, self::C3::Y) →* self::C3::X* = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class C3<X extends (self::C3::X*, self::C3::Y*) →* self::C3::X* = (core::Null?, core::Null?) →* dynamic, Y extends (self::C3::X*, self::C3::Y*) →* self::C3::X* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::C3<self::C3::X*, self::C3::Y*>*
: super core::Object::•()
;
}
-class C4<X extends (self::C4::X, self::C4::Y) →* self::C4::X = (core::Null*, core::Null*) →* dynamic, Y extends (self::C4::X*, self::C4::Y) →* self::C4::Y = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class C4<X extends (self::C4::X*, self::C4::Y*) →* self::C4::X* = (core::Null?, core::Null?) →* dynamic, Y extends (self::C4::X*, self::C4::Y*) →* self::C4::Y* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::C4<self::C4::X*, self::C4::Y*>*
: super core::Object::•()
;
}
-class D1<X extends self::B<self::D1::X, self::D1::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D1::Y) →* self::D1::X* = (core::Null*) →* dynamic> extends core::Object {
+class D1<X extends self::B<self::D1::X*, self::D1::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D1::Y*) →* self::D1::X* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::D1<self::D1::X*, self::D1::Y*>*
: super core::Object::•()
;
}
-class D2<X extends self::B<self::D2::X, self::D2::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D2::X*) →* self::D2::Y = (core::Null*) →* dynamic> extends core::Object {
+class D2<X extends self::B<self::D2::X*, self::D2::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D2::X*) →* self::D2::Y* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::D2<self::D2::X*, self::D2::Y*>*
: super core::Object::•()
;
}
-class D3<X extends self::B<self::D3::X, self::D3::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D3::X*, self::D3::Y) →* self::D3::X* = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class D3<X extends self::B<self::D3::X*, self::D3::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D3::X*, self::D3::Y*) →* self::D3::X* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::D3<self::D3::X*, self::D3::Y*>*
: super core::Object::•()
;
}
-class D4<X extends self::B<self::D4::X, self::D4::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D4::X*, self::D4::Y) →* self::D4::Y = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class D4<X extends self::B<self::D4::X*, self::D4::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D4::X*, self::D4::Y*) →* self::D4::Y* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::D4<self::D4::X*, self::D4::Y*>*
: super core::Object::•()
;
}
-class E<X extends (self::E::X) →* self::E::X = (core::Null*) →* dynamic> extends core::Object {
+class E<X extends (self::E::X*) →* self::E::X* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::E<self::E::X*>*
: super core::Object::•()
;
}
-static field self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>* c1;
-static field self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>* c2;
-static field self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>* c3;
-static field self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>* c4;
-static field self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>* d1;
-static field self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>* d2;
-static field self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>* d3;
-static field self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>* d4;
-static field self::E<(core::Null*) →* dynamic>* e;
+static field self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>* c1;
+static field self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>* c2;
+static field self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>* c3;
+static field self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>* c4;
+static field self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>* d1;
+static field self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>* d2;
+static field self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>* d3;
+static field self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>* d4;
+static field self::E<(core::Null?) →* dynamic>* e;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence_in_literals.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence_in_literals.dart.outline.expect
index 0db7d67..c60f956 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence_in_literals.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence_in_literals.dart.outline.expect
@@ -6,59 +6,59 @@
synthetic constructor •() → self::B<self::B::X*, self::B::Y*>*
;
}
-class C1<X extends (self::C1::Y) →* self::C1::X = (core::Null*) →* dynamic, Y extends (self::C1::Y) →* self::C1::X* = (core::Null*) →* dynamic> extends core::Object {
+class C1<X extends (self::C1::Y*) →* self::C1::X* = (core::Null?) →* dynamic, Y extends (self::C1::Y*) →* self::C1::X* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::C1<self::C1::X*, self::C1::Y*>*
;
}
-class C2<X extends (self::C2::Y) →* self::C2::X = (core::Null*) →* dynamic, Y extends (self::C2::X*) →* self::C2::Y = (core::Null*) →* dynamic> extends core::Object {
+class C2<X extends (self::C2::Y*) →* self::C2::X* = (core::Null?) →* dynamic, Y extends (self::C2::X*) →* self::C2::Y* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::C2<self::C2::X*, self::C2::Y*>*
;
}
-class C3<X extends (self::C3::X, self::C3::Y) →* self::C3::X = (core::Null*, core::Null*) →* dynamic, Y extends (self::C3::X*, self::C3::Y) →* self::C3::X* = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class C3<X extends (self::C3::X*, self::C3::Y*) →* self::C3::X* = (core::Null?, core::Null?) →* dynamic, Y extends (self::C3::X*, self::C3::Y*) →* self::C3::X* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::C3<self::C3::X*, self::C3::Y*>*
;
}
-class C4<X extends (self::C4::X, self::C4::Y) →* self::C4::X = (core::Null*, core::Null*) →* dynamic, Y extends (self::C4::X*, self::C4::Y) →* self::C4::Y = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class C4<X extends (self::C4::X*, self::C4::Y*) →* self::C4::X* = (core::Null?, core::Null?) →* dynamic, Y extends (self::C4::X*, self::C4::Y*) →* self::C4::Y* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::C4<self::C4::X*, self::C4::Y*>*
;
}
-class D1<X extends self::B<self::D1::X, self::D1::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D1::Y) →* self::D1::X* = (core::Null*) →* dynamic> extends core::Object {
+class D1<X extends self::B<self::D1::X*, self::D1::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D1::Y*) →* self::D1::X* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::D1<self::D1::X*, self::D1::Y*>*
;
}
-class D2<X extends self::B<self::D2::X, self::D2::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D2::X*) →* self::D2::Y = (core::Null*) →* dynamic> extends core::Object {
+class D2<X extends self::B<self::D2::X*, self::D2::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D2::X*) →* self::D2::Y* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::D2<self::D2::X*, self::D2::Y*>*
;
}
-class D3<X extends self::B<self::D3::X, self::D3::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D3::X*, self::D3::Y) →* self::D3::X* = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class D3<X extends self::B<self::D3::X*, self::D3::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D3::X*, self::D3::Y*) →* self::D3::X* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::D3<self::D3::X*, self::D3::Y*>*
;
}
-class D4<X extends self::B<self::D4::X, self::D4::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D4::X*, self::D4::Y) →* self::D4::Y = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class D4<X extends self::B<self::D4::X*, self::D4::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D4::X*, self::D4::Y*) →* self::D4::Y* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::D4<self::D4::X*, self::D4::Y*>*
;
}
-class E<X extends (self::E::X) →* self::E::X = (core::Null*) →* dynamic> extends core::Object {
+class E<X extends (self::E::X*) →* self::E::X* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::E<self::E::X*>*
;
}
-static field core::List<self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>* lc1;
-static field core::Map<self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*, self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>* mc1;
-static field core::List<self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>* lc2;
-static field core::Map<self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*, self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>* mc2;
-static field core::List<self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>* lc3;
-static field core::Map<self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*, self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>* mc3;
-static field core::List<self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>* lc4;
-static field core::Map<self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*, self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>* mc4;
-static field core::List<self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>* ld1;
-static field core::Map<self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*, self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>* md1;
-static field core::List<self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>* ld2;
-static field core::Map<self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*, self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>* md2;
-static field core::List<self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>* ld3;
-static field core::Map<self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*, self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>* md3;
-static field core::List<self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>* ld4;
-static field core::Map<self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*, self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>* md4;
-static field core::List<self::E<(core::Null*) →* dynamic>*>* le;
-static field core::Map<self::E<(core::Null*) →* dynamic>*, self::E<(core::Null*) →* dynamic>*>* me;
+static field core::List<self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* lc1;
+static field core::Map<self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*, self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* mc1;
+static field core::List<self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* lc2;
+static field core::Map<self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*, self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* mc2;
+static field core::List<self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>* lc3;
+static field core::Map<self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*, self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>* mc3;
+static field core::List<self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>* lc4;
+static field core::Map<self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*, self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>* mc4;
+static field core::List<self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>* ld1;
+static field core::Map<self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*, self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>* md1;
+static field core::List<self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>* ld2;
+static field core::Map<self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*, self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>* md2;
+static field core::List<self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>* ld3;
+static field core::Map<self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*, self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>* md3;
+static field core::List<self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>* ld4;
+static field core::Map<self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*, self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>* md4;
+static field core::List<self::E<(core::Null?) →* dynamic>*>* le;
+static field core::Map<self::E<(core::Null?) →* dynamic>*, self::E<(core::Null?) →* dynamic>*>* me;
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence_in_literals.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence_in_literals.dart.strong.expect
index f7a9579..fad1c97 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence_in_literals.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence_in_literals.dart.strong.expect
@@ -7,67 +7,67 @@
: super core::Object::•()
;
}
-class C1<X extends (self::C1::Y) →* self::C1::X = (core::Null*) →* dynamic, Y extends (self::C1::Y) →* self::C1::X* = (core::Null*) →* dynamic> extends core::Object {
+class C1<X extends (self::C1::Y*) →* self::C1::X* = (core::Null?) →* dynamic, Y extends (self::C1::Y*) →* self::C1::X* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::C1<self::C1::X*, self::C1::Y*>*
: super core::Object::•()
;
}
-class C2<X extends (self::C2::Y) →* self::C2::X = (core::Null*) →* dynamic, Y extends (self::C2::X*) →* self::C2::Y = (core::Null*) →* dynamic> extends core::Object {
+class C2<X extends (self::C2::Y*) →* self::C2::X* = (core::Null?) →* dynamic, Y extends (self::C2::X*) →* self::C2::Y* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::C2<self::C2::X*, self::C2::Y*>*
: super core::Object::•()
;
}
-class C3<X extends (self::C3::X, self::C3::Y) →* self::C3::X = (core::Null*, core::Null*) →* dynamic, Y extends (self::C3::X*, self::C3::Y) →* self::C3::X* = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class C3<X extends (self::C3::X*, self::C3::Y*) →* self::C3::X* = (core::Null?, core::Null?) →* dynamic, Y extends (self::C3::X*, self::C3::Y*) →* self::C3::X* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::C3<self::C3::X*, self::C3::Y*>*
: super core::Object::•()
;
}
-class C4<X extends (self::C4::X, self::C4::Y) →* self::C4::X = (core::Null*, core::Null*) →* dynamic, Y extends (self::C4::X*, self::C4::Y) →* self::C4::Y = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class C4<X extends (self::C4::X*, self::C4::Y*) →* self::C4::X* = (core::Null?, core::Null?) →* dynamic, Y extends (self::C4::X*, self::C4::Y*) →* self::C4::Y* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::C4<self::C4::X*, self::C4::Y*>*
: super core::Object::•()
;
}
-class D1<X extends self::B<self::D1::X, self::D1::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D1::Y) →* self::D1::X* = (core::Null*) →* dynamic> extends core::Object {
+class D1<X extends self::B<self::D1::X*, self::D1::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D1::Y*) →* self::D1::X* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::D1<self::D1::X*, self::D1::Y*>*
: super core::Object::•()
;
}
-class D2<X extends self::B<self::D2::X, self::D2::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D2::X*) →* self::D2::Y = (core::Null*) →* dynamic> extends core::Object {
+class D2<X extends self::B<self::D2::X*, self::D2::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D2::X*) →* self::D2::Y* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::D2<self::D2::X*, self::D2::Y*>*
: super core::Object::•()
;
}
-class D3<X extends self::B<self::D3::X, self::D3::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D3::X*, self::D3::Y) →* self::D3::X* = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class D3<X extends self::B<self::D3::X*, self::D3::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D3::X*, self::D3::Y*) →* self::D3::X* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::D3<self::D3::X*, self::D3::Y*>*
: super core::Object::•()
;
}
-class D4<X extends self::B<self::D4::X, self::D4::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D4::X*, self::D4::Y) →* self::D4::Y = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class D4<X extends self::B<self::D4::X*, self::D4::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D4::X*, self::D4::Y*) →* self::D4::Y* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::D4<self::D4::X*, self::D4::Y*>*
: super core::Object::•()
;
}
-class E<X extends (self::E::X) →* self::E::X = (core::Null*) →* dynamic> extends core::Object {
+class E<X extends (self::E::X*) →* self::E::X* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::E<self::E::X*>*
: super core::Object::•()
;
}
-static field core::List<self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>* lc1 = <self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>[];
-static field core::Map<self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*, self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>* mc1 = <self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*, self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>{};
-static field core::List<self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>* lc2 = <self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>[];
-static field core::Map<self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*, self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>* mc2 = <self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*, self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>{};
-static field core::List<self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>* lc3 = <self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>[];
-static field core::Map<self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*, self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>* mc3 = <self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*, self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>{};
-static field core::List<self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>* lc4 = <self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>[];
-static field core::Map<self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*, self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>* mc4 = <self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*, self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>{};
-static field core::List<self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>* ld1 = <self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>[];
-static field core::Map<self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*, self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>* md1 = <self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*, self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>{};
-static field core::List<self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>* ld2 = <self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>[];
-static field core::Map<self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*, self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>* md2 = <self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*, self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>{};
-static field core::List<self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>* ld3 = <self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>[];
-static field core::Map<self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*, self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>* md3 = <self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*, self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>{};
-static field core::List<self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>* ld4 = <self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>[];
-static field core::Map<self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*, self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>* md4 = <self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*, self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>{};
-static field core::List<self::E<(core::Null*) →* dynamic>*>* le = <self::E<(core::Null*) →* dynamic>*>[];
-static field core::Map<self::E<(core::Null*) →* dynamic>*, self::E<(core::Null*) →* dynamic>*>* me = <self::E<(core::Null*) →* dynamic>*, self::E<(core::Null*) →* dynamic>*>{};
+static field core::List<self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* lc1 = <self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>[];
+static field core::Map<self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*, self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* mc1 = <self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*, self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>{};
+static field core::List<self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* lc2 = <self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>[];
+static field core::Map<self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*, self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* mc2 = <self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*, self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>{};
+static field core::List<self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>* lc3 = <self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>[];
+static field core::Map<self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*, self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>* mc3 = <self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*, self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>{};
+static field core::List<self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>* lc4 = <self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>[];
+static field core::Map<self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*, self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>* mc4 = <self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*, self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>{};
+static field core::List<self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>* ld1 = <self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>[];
+static field core::Map<self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*, self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>* md1 = <self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*, self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>{};
+static field core::List<self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>* ld2 = <self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>[];
+static field core::Map<self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*, self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>* md2 = <self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*, self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>{};
+static field core::List<self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>* ld3 = <self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>[];
+static field core::Map<self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*, self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>* md3 = <self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*, self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>{};
+static field core::List<self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>* ld4 = <self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>[];
+static field core::Map<self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*, self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>* md4 = <self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*, self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>{};
+static field core::List<self::E<(core::Null?) →* dynamic>*>* le = <self::E<(core::Null?) →* dynamic>*>[];
+static field core::Map<self::E<(core::Null?) →* dynamic>*, self::E<(core::Null?) →* dynamic>*>* me = <self::E<(core::Null?) →* dynamic>*, self::E<(core::Null?) →* dynamic>*>{};
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence_in_literals.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence_in_literals.dart.strong.transformed.expect
index f7a9579..fad1c97 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence_in_literals.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/mutual_dependence_in_literals.dart.strong.transformed.expect
@@ -7,67 +7,67 @@
: super core::Object::•()
;
}
-class C1<X extends (self::C1::Y) →* self::C1::X = (core::Null*) →* dynamic, Y extends (self::C1::Y) →* self::C1::X* = (core::Null*) →* dynamic> extends core::Object {
+class C1<X extends (self::C1::Y*) →* self::C1::X* = (core::Null?) →* dynamic, Y extends (self::C1::Y*) →* self::C1::X* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::C1<self::C1::X*, self::C1::Y*>*
: super core::Object::•()
;
}
-class C2<X extends (self::C2::Y) →* self::C2::X = (core::Null*) →* dynamic, Y extends (self::C2::X*) →* self::C2::Y = (core::Null*) →* dynamic> extends core::Object {
+class C2<X extends (self::C2::Y*) →* self::C2::X* = (core::Null?) →* dynamic, Y extends (self::C2::X*) →* self::C2::Y* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::C2<self::C2::X*, self::C2::Y*>*
: super core::Object::•()
;
}
-class C3<X extends (self::C3::X, self::C3::Y) →* self::C3::X = (core::Null*, core::Null*) →* dynamic, Y extends (self::C3::X*, self::C3::Y) →* self::C3::X* = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class C3<X extends (self::C3::X*, self::C3::Y*) →* self::C3::X* = (core::Null?, core::Null?) →* dynamic, Y extends (self::C3::X*, self::C3::Y*) →* self::C3::X* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::C3<self::C3::X*, self::C3::Y*>*
: super core::Object::•()
;
}
-class C4<X extends (self::C4::X, self::C4::Y) →* self::C4::X = (core::Null*, core::Null*) →* dynamic, Y extends (self::C4::X*, self::C4::Y) →* self::C4::Y = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class C4<X extends (self::C4::X*, self::C4::Y*) →* self::C4::X* = (core::Null?, core::Null?) →* dynamic, Y extends (self::C4::X*, self::C4::Y*) →* self::C4::Y* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::C4<self::C4::X*, self::C4::Y*>*
: super core::Object::•()
;
}
-class D1<X extends self::B<self::D1::X, self::D1::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D1::Y) →* self::D1::X* = (core::Null*) →* dynamic> extends core::Object {
+class D1<X extends self::B<self::D1::X*, self::D1::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D1::Y*) →* self::D1::X* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::D1<self::D1::X*, self::D1::Y*>*
: super core::Object::•()
;
}
-class D2<X extends self::B<self::D2::X, self::D2::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D2::X*) →* self::D2::Y = (core::Null*) →* dynamic> extends core::Object {
+class D2<X extends self::B<self::D2::X*, self::D2::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D2::X*) →* self::D2::Y* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::D2<self::D2::X*, self::D2::Y*>*
: super core::Object::•()
;
}
-class D3<X extends self::B<self::D3::X, self::D3::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D3::X*, self::D3::Y) →* self::D3::X* = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class D3<X extends self::B<self::D3::X*, self::D3::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D3::X*, self::D3::Y*) →* self::D3::X* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::D3<self::D3::X*, self::D3::Y*>*
: super core::Object::•()
;
}
-class D4<X extends self::B<self::D4::X, self::D4::Y>* = self::B<dynamic, dynamic>*, Y extends (self::D4::X*, self::D4::Y) →* self::D4::Y = (core::Null*, core::Null*) →* dynamic> extends core::Object {
+class D4<X extends self::B<self::D4::X*, self::D4::Y*>* = self::B<dynamic, dynamic>*, Y extends (self::D4::X*, self::D4::Y*) →* self::D4::Y* = (core::Null?, core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::D4<self::D4::X*, self::D4::Y*>*
: super core::Object::•()
;
}
-class E<X extends (self::E::X) →* self::E::X = (core::Null*) →* dynamic> extends core::Object {
+class E<X extends (self::E::X*) →* self::E::X* = (core::Null?) →* dynamic> extends core::Object {
synthetic constructor •() → self::E<self::E::X*>*
: super core::Object::•()
;
}
-static field core::List<self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>* lc1 = <self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>[];
-static field core::Map<self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*, self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>* mc1 = <self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*, self::C1<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>{};
-static field core::List<self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>* lc2 = <self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>[];
-static field core::Map<self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*, self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>* mc2 = <self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*, self::C2<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>{};
-static field core::List<self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>* lc3 = <self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>[];
-static field core::Map<self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*, self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>* mc3 = <self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*, self::C3<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>{};
-static field core::List<self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>* lc4 = <self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>[];
-static field core::Map<self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*, self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>* mc4 = <self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*, self::C4<(core::Null*, core::Null*) →* dynamic, (core::Null*, core::Null*) →* dynamic>*>{};
-static field core::List<self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>* ld1 = <self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>[];
-static field core::Map<self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*, self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>* md1 = <self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*, self::D1<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>{};
-static field core::List<self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>* ld2 = <self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>[];
-static field core::Map<self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*, self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>* md2 = <self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*, self::D2<self::B<dynamic, dynamic>*, (core::Null*) →* dynamic>*>{};
-static field core::List<self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>* ld3 = <self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>[];
-static field core::Map<self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*, self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>* md3 = <self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*, self::D3<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>{};
-static field core::List<self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>* ld4 = <self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>[];
-static field core::Map<self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*, self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>* md4 = <self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*, self::D4<self::B<dynamic, dynamic>*, (core::Null*, core::Null*) →* dynamic>*>{};
-static field core::List<self::E<(core::Null*) →* dynamic>*>* le = <self::E<(core::Null*) →* dynamic>*>[];
-static field core::Map<self::E<(core::Null*) →* dynamic>*, self::E<(core::Null*) →* dynamic>*>* me = <self::E<(core::Null*) →* dynamic>*, self::E<(core::Null*) →* dynamic>*>{};
+static field core::List<self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* lc1 = <self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>[];
+static field core::Map<self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*, self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* mc1 = <self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*, self::C1<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>{};
+static field core::List<self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* lc2 = <self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>[];
+static field core::Map<self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*, self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* mc2 = <self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*, self::C2<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>{};
+static field core::List<self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>* lc3 = <self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>[];
+static field core::Map<self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*, self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>* mc3 = <self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*, self::C3<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>{};
+static field core::List<self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>* lc4 = <self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>[];
+static field core::Map<self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*, self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>* mc4 = <self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*, self::C4<(core::Null?, core::Null?) →* dynamic, (core::Null?, core::Null?) →* dynamic>*>{};
+static field core::List<self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>* ld1 = <self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>[];
+static field core::Map<self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*, self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>* md1 = <self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*, self::D1<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>{};
+static field core::List<self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>* ld2 = <self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>[];
+static field core::Map<self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*, self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>* md2 = <self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*, self::D2<self::B<dynamic, dynamic>*, (core::Null?) →* dynamic>*>{};
+static field core::List<self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>* ld3 = <self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>[];
+static field core::Map<self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*, self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>* md3 = <self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*, self::D3<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>{};
+static field core::List<self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>* ld4 = <self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>[];
+static field core::Map<self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*, self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>* md4 = <self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*, self::D4<self::B<dynamic, dynamic>*, (core::Null?, core::Null?) →* dynamic>*>{};
+static field core::List<self::E<(core::Null?) →* dynamic>*>* le = <self::E<(core::Null?) →* dynamic>*>[];
+static field core::Map<self::E<(core::Null?) →* dynamic>*, self::E<(core::Null?) →* dynamic>*>* me = <self::E<(core::Null?) →* dynamic>*, self::E<(core::Null?) →* dynamic>*>{};
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_for_each.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_for_each.dart.outline.expect
index 09fd8ad..c3b608e 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_for_each.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_for_each.dart.outline.expect
@@ -21,7 +21,7 @@
import self as self;
import "dart:core" as core;
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
;
}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_for_each.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_for_each.dart.strong.expect
index 10af610..ab85dcf 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_for_each.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_for_each.dart.strong.expect
@@ -21,7 +21,7 @@
import self as self;
import "dart:core" as core;
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
: super core::Object::•()
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_for_each.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_for_each.dart.strong.transformed.expect
index 10af610..ab85dcf 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_for_each.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_for_each.dart.strong.transformed.expect
@@ -21,7 +21,7 @@
import self as self;
import "dart:core" as core;
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
: super core::Object::•()
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.outline.expect
index b4a29e8..450c215 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.outline.expect
@@ -9,11 +9,11 @@
import self as self;
import "dart:core" as core;
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
;
}
-class Fisk<TypeY extends <TypeZ extends self::Hest<core::Null*>* = dynamic>(TypeZ) →* dynamic = dynamic> extends core::Object {
+class Fisk<TypeY extends <TypeZ extends self::Hest<core::Null*>* = dynamic>(TypeZ*) →* dynamic = dynamic> extends core::Object {
synthetic constructor •() → self::Fisk<self::Fisk::TypeY*>*
;
}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.expect
index 4983685..8f79b89 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.expect
@@ -9,12 +9,12 @@
import self as self;
import "dart:core" as core;
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
: super core::Object::•()
;
}
-class Fisk<TypeY extends <TypeZ extends self::Hest<core::Null*>* = dynamic>(TypeZ) →* dynamic = dynamic> extends core::Object {
+class Fisk<TypeY extends <TypeZ extends self::Hest<core::Null*>* = dynamic>(TypeZ*) →* dynamic = dynamic> extends core::Object {
synthetic constructor •() → self::Fisk<self::Fisk::TypeY*>*
: super core::Object::•()
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.transformed.expect
index 4983685..8f79b89 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.transformed.expect
@@ -9,12 +9,12 @@
import self as self;
import "dart:core" as core;
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
: super core::Object::•()
;
}
-class Fisk<TypeY extends <TypeZ extends self::Hest<core::Null*>* = dynamic>(TypeZ) →* dynamic = dynamic> extends core::Object {
+class Fisk<TypeY extends <TypeZ extends self::Hest<core::Null*>* = dynamic>(TypeZ*) →* dynamic = dynamic> extends core::Object {
synthetic constructor •() → self::Fisk<self::Fisk::TypeY*>*
: super core::Object::•()
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_many.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_many.dart.outline.expect
index cda7cca..b131c3a 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_many.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_many.dart.outline.expect
@@ -21,11 +21,11 @@
import self as self;
import "dart:core" as core;
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
;
}
-class Fisk<TypeY extends self::Fisk<self::Fisk::TypeY>* = self::Fisk<dynamic>*> extends core::Object {
+class Fisk<TypeY extends self::Fisk<self::Fisk::TypeY*>* = self::Fisk<dynamic>*> extends core::Object {
synthetic constructor •() → self::Fisk<self::Fisk::TypeY*>*
;
}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_many.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_many.dart.strong.expect
index 2e957c6..ec10848 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_many.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_many.dart.strong.expect
@@ -21,12 +21,12 @@
import self as self;
import "dart:core" as core;
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
: super core::Object::•()
;
}
-class Fisk<TypeY extends self::Fisk<self::Fisk::TypeY>* = self::Fisk<dynamic>*> extends core::Object {
+class Fisk<TypeY extends self::Fisk<self::Fisk::TypeY*>* = self::Fisk<dynamic>*> extends core::Object {
synthetic constructor •() → self::Fisk<self::Fisk::TypeY*>*
: super core::Object::•()
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_many.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_many.dart.strong.transformed.expect
index 2e957c6..ec10848 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_many.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_many.dart.strong.transformed.expect
@@ -21,12 +21,12 @@
import self as self;
import "dart:core" as core;
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
: super core::Object::•()
;
}
-class Fisk<TypeY extends self::Fisk<self::Fisk::TypeY>* = self::Fisk<dynamic>*> extends core::Object {
+class Fisk<TypeY extends self::Fisk<self::Fisk::TypeY*>* = self::Fisk<dynamic>*> extends core::Object {
synthetic constructor •() → self::Fisk<self::Fisk::TypeY*>*
: super core::Object::•()
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_no_dup.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_no_dup.dart.outline.expect
index 2337453..7b8d8f1 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_no_dup.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_no_dup.dart.outline.expect
@@ -13,7 +13,7 @@
import self as self;
import "dart:core" as core;
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
;
}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_no_dup.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_no_dup.dart.strong.expect
index 2950575..87f748c 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_no_dup.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_no_dup.dart.strong.expect
@@ -13,7 +13,7 @@
import self as self;
import "dart:core" as core;
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
: super core::Object::•()
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_no_dup.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_no_dup.dart.strong.transformed.expect
index 2950575..87f748c 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_no_dup.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_no_dup.dart.strong.transformed.expect
@@ -13,7 +13,7 @@
import self as self;
import "dart:core" as core;
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
: super core::Object::•()
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_suppress_consequence.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_suppress_consequence.dart.outline.expect
index bd2bd0e..1dfb185 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_suppress_consequence.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_suppress_consequence.dart.outline.expect
@@ -13,7 +13,7 @@
import self as self;
import "dart:core" as core;
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
;
}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_suppress_consequence.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_suppress_consequence.dart.strong.expect
index 5a73de7..37c1f7b 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_suppress_consequence.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_suppress_consequence.dart.strong.expect
@@ -13,7 +13,7 @@
import self as self;
import "dart:core" as core;
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
: super core::Object::•()
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_suppress_consequence.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_suppress_consequence.dart.strong.transformed.expect
index 5a73de7..37c1f7b 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_suppress_consequence.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_suppress_consequence.dart.strong.transformed.expect
@@ -13,7 +13,7 @@
import self as self;
import "dart:core" as core;
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
: super core::Object::•()
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_variables_from_same.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_variables_from_same.dart.outline.expect
index 2097fc5..4c04e3b 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_variables_from_same.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_variables_from_same.dart.outline.expect
@@ -13,7 +13,7 @@
import self as self;
import "dart:core" as core;
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
;
}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_variables_from_same.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_variables_from_same.dart.strong.expect
index 6c8df32..3bf035e 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_variables_from_same.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_variables_from_same.dart.strong.expect
@@ -13,7 +13,7 @@
import self as self;
import "dart:core" as core;
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
: super core::Object::•()
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_variables_from_same.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_variables_from_same.dart.strong.transformed.expect
index 6c8df32..3bf035e 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_variables_from_same.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_variables_from_same.dart.strong.transformed.expect
@@ -13,7 +13,7 @@
import self as self;
import "dart:core" as core;
-class Hest<TypeX extends self::Hest<self::Hest::TypeX>* = self::Hest<dynamic>*> extends core::Object {
+class Hest<TypeX extends self::Hest<self::Hest::TypeX*>* = self::Hest<dynamic>*> extends core::Object {
synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
: super core::Object::•()
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/super_bounded_in_bound.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/super_bounded_in_bound.dart.outline.expect
index 040e2a3..4b818fd 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/super_bounded_in_bound.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/super_bounded_in_bound.dart.outline.expect
@@ -2,7 +2,7 @@
import self as self;
import "dart:core" as core;
-class A<X extends core::Comparable<self::A::X>* = core::Comparable<dynamic>*> extends core::Object {
+class A<X extends core::Comparable<self::A::X*>* = core::Comparable<dynamic>*> extends core::Object {
synthetic constructor •() → self::A<self::A::X*>*
;
}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/super_bounded_in_bound.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/super_bounded_in_bound.dart.strong.expect
index 2682021..bccb0a0 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/super_bounded_in_bound.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/super_bounded_in_bound.dart.strong.expect
@@ -2,7 +2,7 @@
import self as self;
import "dart:core" as core;
-class A<X extends core::Comparable<self::A::X>* = core::Comparable<dynamic>*> extends core::Object {
+class A<X extends core::Comparable<self::A::X*>* = core::Comparable<dynamic>*> extends core::Object {
synthetic constructor •() → self::A<self::A::X*>*
: super core::Object::•()
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/super_bounded_in_bound.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/super_bounded_in_bound.dart.strong.transformed.expect
index 2682021..bccb0a0 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/super_bounded_in_bound.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/super_bounded_in_bound.dart.strong.transformed.expect
@@ -2,7 +2,7 @@
import self as self;
import "dart:core" as core;
-class A<X extends core::Comparable<self::A::X>* = core::Comparable<dynamic>*> extends core::Object {
+class A<X extends core::Comparable<self::A::X*>* = core::Comparable<dynamic>*> extends core::Object {
synthetic constructor •() → self::A<self::A::X*>*
: super core::Object::•()
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/super_bounded_type.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/super_bounded_type.dart.outline.expect
index 2075628..6a8424b 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/super_bounded_type.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/super_bounded_type.dart.outline.expect
@@ -2,7 +2,7 @@
import self as self;
import "dart:core" as core;
-class A<T extends self::A<self::A::T>* = self::A<dynamic>*> extends core::Object {
+class A<T extends self::A<self::A::T*>* = self::A<dynamic>*> extends core::Object {
synthetic constructor •() → self::A<self::A::T*>*
;
}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/super_bounded_type.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/super_bounded_type.dart.strong.expect
index 35d7d8a..e533635 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/super_bounded_type.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/super_bounded_type.dart.strong.expect
@@ -2,7 +2,7 @@
import self as self;
import "dart:core" as core;
-class A<T extends self::A<self::A::T>* = self::A<dynamic>*> extends core::Object {
+class A<T extends self::A<self::A::T*>* = self::A<dynamic>*> extends core::Object {
synthetic constructor •() → self::A<self::A::T*>*
: super core::Object::•()
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/super_bounded_type.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/super_bounded_type.dart.strong.transformed.expect
index 35d7d8a..e533635 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/super_bounded_type.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/super_bounded_type.dart.strong.transformed.expect
@@ -2,7 +2,7 @@
import self as self;
import "dart:core" as core;
-class A<T extends self::A<self::A::T>* = self::A<dynamic>*> extends core::Object {
+class A<T extends self::A<self::A::T*>* = self::A<dynamic>*> extends core::Object {
synthetic constructor •() → self::A<self::A::T*>*
: super core::Object::•()
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/typedef_super_bounded_type.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/typedef_super_bounded_type.dart.outline.expect
index 7fd0a96..bbce9e4 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/typedef_super_bounded_type.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/typedef_super_bounded_type.dart.outline.expect
@@ -3,7 +3,7 @@
import "dart:core" as core;
typedef A<T extends core::Object* = dynamic> = (T*) →* dynamic;
-typedef B<S extends (S) →* dynamic = (dynamic) →* dynamic> = (S*) →* dynamic;
+typedef B<S extends (S*) →* dynamic = (dynamic) →* dynamic> = (S*) →* dynamic;
static field ((dynamic) →* dynamic) →* dynamic b;
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/typedef_super_bounded_type.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/typedef_super_bounded_type.dart.strong.expect
index 9bc70a4..d59e608 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/typedef_super_bounded_type.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/typedef_super_bounded_type.dart.strong.expect
@@ -3,6 +3,6 @@
import "dart:core" as core;
typedef A<T extends core::Object* = dynamic> = (T*) →* dynamic;
-typedef B<S extends (S) →* dynamic = (dynamic) →* dynamic> = (S*) →* dynamic;
+typedef B<S extends (S*) →* dynamic = (dynamic) →* dynamic> = (S*) →* dynamic;
static field ((dynamic) →* dynamic) →* dynamic b;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/typedef_super_bounded_type.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/typedef_super_bounded_type.dart.strong.transformed.expect
index 9bc70a4..d59e608 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/typedef_super_bounded_type.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/typedef_super_bounded_type.dart.strong.transformed.expect
@@ -3,6 +3,6 @@
import "dart:core" as core;
typedef A<T extends core::Object* = dynamic> = (T*) →* dynamic;
-typedef B<S extends (S) →* dynamic = (dynamic) →* dynamic> = (S*) →* dynamic;
+typedef B<S extends (S*) →* dynamic = (dynamic) →* dynamic> = (S*) →* dynamic;
static field ((dynamic) →* dynamic) →* dynamic b;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/late.dart.outline.expect b/pkg/front_end/testcases/nnbd/late.dart.outline.expect
index 3ab3586..4c3658f 100644
--- a/pkg/front_end/testcases/nnbd/late.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/late.dart.outline.expect
@@ -3,16 +3,16 @@
import "dart:core" as core;
class Class extends core::Object {
- late field core::int* lateInstanceField;
- late final field core::int* finalLateInstanceField;
- late static field core::int* lateStaticField;
- late static final field core::int* finalLateStaticField;
+ late field core::int lateInstanceField;
+ late final field core::int finalLateInstanceField;
+ late static field core::int lateStaticField;
+ late static final field core::int finalLateStaticField;
synthetic constructor •() → self::Class*
;
method method() → dynamic
;
}
-late static field core::int* lateStaticField;
-late static final field core::int* finalLateStaticField;
+late static field core::int lateStaticField;
+late static final field core::int finalLateStaticField;
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/nnbd/late.dart.strong.expect b/pkg/front_end/testcases/nnbd/late.dart.strong.expect
index 2315067..06376e9 100644
--- a/pkg/front_end/testcases/nnbd/late.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/late.dart.strong.expect
@@ -3,18 +3,18 @@
import "dart:core" as core;
class Class extends core::Object {
- late field core::int* lateInstanceField = null;
- late final field core::int* finalLateInstanceField = 0;
- late static field core::int* lateStaticField = null;
- late static final field core::int* finalLateStaticField = 0;
+ late field core::int lateInstanceField = null;
+ late final field core::int finalLateInstanceField = 0;
+ late static field core::int lateStaticField = null;
+ late static final field core::int finalLateStaticField = 0;
synthetic constructor •() → self::Class*
: super core::Object::•()
;
method method() → dynamic {
- late core::int* lateVariable;
- late final core::int* lateFinalVariable = 0;
+ late core::int lateVariable;
+ late final core::int lateFinalVariable = 0;
}
}
-late static field core::int* lateStaticField;
-late static final field core::int* finalLateStaticField;
+late static field core::int lateStaticField;
+late static final field core::int finalLateStaticField;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/late.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/late.dart.strong.transformed.expect
index 2315067..06376e9 100644
--- a/pkg/front_end/testcases/nnbd/late.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/late.dart.strong.transformed.expect
@@ -3,18 +3,18 @@
import "dart:core" as core;
class Class extends core::Object {
- late field core::int* lateInstanceField = null;
- late final field core::int* finalLateInstanceField = 0;
- late static field core::int* lateStaticField = null;
- late static final field core::int* finalLateStaticField = 0;
+ late field core::int lateInstanceField = null;
+ late final field core::int finalLateInstanceField = 0;
+ late static field core::int lateStaticField = null;
+ late static final field core::int finalLateStaticField = 0;
synthetic constructor •() → self::Class*
: super core::Object::•()
;
method method() → dynamic {
- late core::int* lateVariable;
- late final core::int* lateFinalVariable = 0;
+ late core::int lateVariable;
+ late final core::int lateFinalVariable = 0;
}
}
-late static field core::int* lateStaticField;
-late static final field core::int* finalLateStaticField;
+late static field core::int lateStaticField;
+late static final field core::int finalLateStaticField;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/nullable_param.dart.outline.expect b/pkg/front_end/testcases/nnbd/nullable_param.dart.outline.expect
index 0a3ac11..18fe203 100644
--- a/pkg/front_end/testcases/nnbd/nullable_param.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/nullable_param.dart.outline.expect
@@ -20,12 +20,12 @@
import "dart:core" as core;
class Foo extends core::Object {
- field core::int* field;
+ field core::int? field;
synthetic constructor •() → self::Foo*
;
- abstract method bar(core::int* x) → core::int*;
+ abstract method bar(core::int? x) → core::int?;
}
static method main() → dynamic
;
-static method test_nullable_function_type_formal_param({() →* core::int* f}) → core::int*
+static method test_nullable_function_type_formal_param({() →* core::int f}) → core::int
;
diff --git a/pkg/front_end/testcases/nnbd/nullable_param.dart.strong.expect b/pkg/front_end/testcases/nnbd/nullable_param.dart.strong.expect
index f6ff7b9..977546a 100644
--- a/pkg/front_end/testcases/nnbd/nullable_param.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/nullable_param.dart.strong.expect
@@ -20,20 +20,20 @@
import "dart:core" as core;
class Foo extends core::Object {
- field core::int* field = null;
+ field core::int? field = null;
synthetic constructor •() → self::Foo*
: super core::Object::•()
;
- abstract method bar(core::int* x) → core::int*;
+ abstract method bar(core::int? x) → core::int?;
}
static method main() → dynamic {
- self::Foo* foo = new self::Foo::•();
+ self::Foo foo = new self::Foo::•();
foo.{self::Foo::field} = 5;
foo.{self::Foo::bar}(6);
self::test_nullable_function_type_formal_param(f: () → core::int* => 2);
}
-static method test_nullable_function_type_formal_param({() →* core::int* f = #C1}) → core::int* {
- return let final core::int* #t1 = f.call() in #t1.==(null) ?{core::int*} 1.{core::int::unary-}() : #t1;
+static method test_nullable_function_type_formal_param({() →* core::int f = #C1}) → core::int {
+ return let final core::int #t1 = f.call() in #t1.==(null) ?{core::int*} 1.{core::int::unary-}() : #t1;
}
constants {
diff --git a/pkg/front_end/testcases/nnbd/nullable_param.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/nullable_param.dart.strong.transformed.expect
index f6ff7b9..977546a 100644
--- a/pkg/front_end/testcases/nnbd/nullable_param.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/nullable_param.dart.strong.transformed.expect
@@ -20,20 +20,20 @@
import "dart:core" as core;
class Foo extends core::Object {
- field core::int* field = null;
+ field core::int? field = null;
synthetic constructor •() → self::Foo*
: super core::Object::•()
;
- abstract method bar(core::int* x) → core::int*;
+ abstract method bar(core::int? x) → core::int?;
}
static method main() → dynamic {
- self::Foo* foo = new self::Foo::•();
+ self::Foo foo = new self::Foo::•();
foo.{self::Foo::field} = 5;
foo.{self::Foo::bar}(6);
self::test_nullable_function_type_formal_param(f: () → core::int* => 2);
}
-static method test_nullable_function_type_formal_param({() →* core::int* f = #C1}) → core::int* {
- return let final core::int* #t1 = f.call() in #t1.==(null) ?{core::int*} 1.{core::int::unary-}() : #t1;
+static method test_nullable_function_type_formal_param({() →* core::int f = #C1}) → core::int {
+ return let final core::int #t1 = f.call() in #t1.==(null) ?{core::int*} 1.{core::int::unary-}() : #t1;
}
constants {
diff --git a/pkg/front_end/testcases/nnbd/required.dart.outline.expect b/pkg/front_end/testcases/nnbd/required.dart.outline.expect
index 97154f2..044b885 100644
--- a/pkg/front_end/testcases/nnbd/required.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/required.dart.outline.expect
@@ -2,16 +2,16 @@
import self as self;
import "dart:core" as core;
-typedef Typedef1 = ({a: core::int*, required b: core::int*}) →* dynamic;
-typedef Typedef2 = ({a: core::int*, required b: core::int*}) →* dynamic;
+typedef Typedef1 = ({a: core::int, required b: core::int}) →* dynamic;
+typedef Typedef2 = ({a: core::int, required b: core::int}) →* dynamic;
class Class extends core::Object {
synthetic constructor •() → self::Class*
;
- method method({core::int* a, required core::int* b, required final core::int* c, required covariant final core::int* d}) → dynamic
+ method method({core::int a, required core::int b, required final core::int c, required covariant final core::int d}) → dynamic
;
}
-static field ({a: core::int*, required b: core::int*}) →* dynamic field;
-static method method({core::int* a, required core::int* b, required final core::int* c}) → dynamic
+static field ({a: core::int, required b: core::int}) →* dynamic field;
+static method method({core::int a, required core::int b, required final core::int c}) → dynamic
;
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/nnbd/required.dart.strong.expect b/pkg/front_end/testcases/nnbd/required.dart.strong.expect
index 7ba4cd1..a23a59d 100644
--- a/pkg/front_end/testcases/nnbd/required.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/required.dart.strong.expect
@@ -2,16 +2,16 @@
import self as self;
import "dart:core" as core;
-typedef Typedef1 = ({a: core::int*, required b: core::int*}) →* dynamic;
-typedef Typedef2 = ({a: core::int*, required b: core::int*}) →* dynamic;
+typedef Typedef1 = ({a: core::int, required b: core::int}) →* dynamic;
+typedef Typedef2 = ({a: core::int, required b: core::int}) →* dynamic;
class Class extends core::Object {
synthetic constructor •() → self::Class*
: super core::Object::•()
;
- method method({core::int* a = #C1, required core::int* b = #C1, required final core::int* c = #C1, required covariant final core::int* d = #C1}) → dynamic {}
+ method method({core::int a = #C1, required core::int b = #C1, required final core::int c = #C1, required covariant final core::int d = #C1}) → dynamic {}
}
-static field ({a: core::int*, required b: core::int*}) →* dynamic field;
-static method method({core::int* a = #C1, required core::int* b = #C1, required final core::int* c = #C1}) → dynamic {}
+static field ({a: core::int, required b: core::int}) →* dynamic field;
+static method method({core::int a = #C1, required core::int b = #C1, required final core::int c = #C1}) → dynamic {}
static method main() → dynamic {}
constants {
diff --git a/pkg/front_end/testcases/nnbd/required.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/required.dart.strong.transformed.expect
index 7ba4cd1..a23a59d 100644
--- a/pkg/front_end/testcases/nnbd/required.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/required.dart.strong.transformed.expect
@@ -2,16 +2,16 @@
import self as self;
import "dart:core" as core;
-typedef Typedef1 = ({a: core::int*, required b: core::int*}) →* dynamic;
-typedef Typedef2 = ({a: core::int*, required b: core::int*}) →* dynamic;
+typedef Typedef1 = ({a: core::int, required b: core::int}) →* dynamic;
+typedef Typedef2 = ({a: core::int, required b: core::int}) →* dynamic;
class Class extends core::Object {
synthetic constructor •() → self::Class*
: super core::Object::•()
;
- method method({core::int* a = #C1, required core::int* b = #C1, required final core::int* c = #C1, required covariant final core::int* d = #C1}) → dynamic {}
+ method method({core::int a = #C1, required core::int b = #C1, required final core::int c = #C1, required covariant final core::int d = #C1}) → dynamic {}
}
-static field ({a: core::int*, required b: core::int*}) →* dynamic field;
-static method method({core::int* a = #C1, required core::int* b = #C1, required final core::int* c = #C1}) → dynamic {}
+static field ({a: core::int, required b: core::int}) →* dynamic field;
+static method method({core::int a = #C1, required core::int b = #C1, required final core::int c = #C1}) → dynamic {}
static method main() → dynamic {}
constants {
diff --git a/pkg/front_end/testcases/old_dills/dart2js.version.30.compile.1.dill b/pkg/front_end/testcases/old_dills/dart2js.version.30.compile.1.dill
new file mode 100644
index 0000000..aff0e19
--- /dev/null
+++ b/pkg/front_end/testcases/old_dills/dart2js.version.30.compile.1.dill
Binary files differ
diff --git a/pkg/front_end/testcases/old_dills/dart2js.version.31.compile.1.dill b/pkg/front_end/testcases/old_dills/dart2js.version.31.compile.1.dill
new file mode 100644
index 0000000..d38cb21
--- /dev/null
+++ b/pkg/front_end/testcases/old_dills/dart2js.version.31.compile.1.dill
Binary files differ
diff --git a/pkg/front_end/testcases/outline.status b/pkg/front_end/testcases/outline.status
index 4037f63..38b00e3 100644
--- a/pkg/front_end/testcases/outline.status
+++ b/pkg/front_end/testcases/outline.status
@@ -13,6 +13,7 @@
general/override_check_after_inference: TypeCheckError
general/override_check_basic: TypeCheckError
general/override_check_with_covariant_modifier: TypeCheckError
+general/override_setter_with_field: TypeCheckError
inference/conflicting_fields: TypeCheckError
inference/conflicts_can_happen2: Fail
diff --git a/pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart.strong.expect b/pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart.strong.expect
index 8fc1e32..391c477 100644
--- a/pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart.strong.expect
+++ b/pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart.strong.expect
@@ -1,7 +1,10 @@
//
// Problems in component:
//
-// pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart:5:18: Error: Can't have a non-constant List literal within a const context.
+// pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart:5:18: Error: Constant evaluation error:
+// main(arguments = [x]) {
+// ^
+// pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart:5:18: Context: Can't have a non-constant List literal within a const context.
// main(arguments = [x]) {
// ^
// pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart:5:6: Context: While analyzing:
diff --git a/pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart.strong.transformed.expect
index 8fc1e32..391c477 100644
--- a/pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart.strong.transformed.expect
@@ -1,7 +1,10 @@
//
// Problems in component:
//
-// pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart:5:18: Error: Can't have a non-constant List literal within a const context.
+// pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart:5:18: Error: Constant evaluation error:
+// main(arguments = [x]) {
+// ^
+// pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart:5:18: Context: Can't have a non-constant List literal within a const context.
// main(arguments = [x]) {
// ^
// pkg/front_end/testcases/rasta/mandatory_parameter_initializer.dart:5:6: Context: While analyzing:
diff --git a/pkg/front_end/testcases/regress/issue_30838.dart.outline.expect b/pkg/front_end/testcases/regress/issue_30838.dart.outline.expect
index d54f1ce..6e2c9f6 100644
--- a/pkg/front_end/testcases/regress/issue_30838.dart.outline.expect
+++ b/pkg/front_end/testcases/regress/issue_30838.dart.outline.expect
@@ -4,7 +4,7 @@
typedef Foo<S extends core::Object* = dynamic> = <T extends core::Object* = dynamic>(T*) →* S*;
class A extends core::Object {
- field <T extends core::Object* = dynamic>(T) →* core::int* f;
+ field <T extends core::Object* = dynamic>(T*) →* core::int* f;
synthetic constructor •() → self::A*
;
method test() → void
@@ -12,7 +12,7 @@
}
static method foo<T extends core::Object* = dynamic>(self::foo::T* x) → core::int*
;
-static method bar() → <T extends core::Object* = dynamic>(T) →* core::int*
+static method bar() → <T extends core::Object* = dynamic>(T*) →* core::int*
;
static method test1() → void
;
diff --git a/pkg/front_end/testcases/regress/issue_30838.dart.strong.expect b/pkg/front_end/testcases/regress/issue_30838.dart.strong.expect
index f47c10a..604c9c1 100644
--- a/pkg/front_end/testcases/regress/issue_30838.dart.strong.expect
+++ b/pkg/front_end/testcases/regress/issue_30838.dart.strong.expect
@@ -4,7 +4,7 @@
typedef Foo<S extends core::Object* = dynamic> = <T extends core::Object* = dynamic>(T*) →* S*;
class A extends core::Object {
- field <T extends core::Object* = dynamic>(T) →* core::int* f = null;
+ field <T extends core::Object* = dynamic>(T*) →* core::int* f = null;
synthetic constructor •() → self::A*
: super core::Object::•()
;
@@ -14,7 +14,7 @@
}
static method foo<T extends core::Object* = dynamic>(self::foo::T* x) → core::int*
return 3;
-static method bar() → <T extends core::Object* = dynamic>(T) →* core::int*
+static method bar() → <T extends core::Object* = dynamic>(T*) →* core::int*
return #C1;
static method test1() → void {
self::bar().call<core::String*>("hello");
diff --git a/pkg/front_end/testcases/regress/issue_30838.dart.strong.transformed.expect b/pkg/front_end/testcases/regress/issue_30838.dart.strong.transformed.expect
index f47c10a..604c9c1 100644
--- a/pkg/front_end/testcases/regress/issue_30838.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/regress/issue_30838.dart.strong.transformed.expect
@@ -4,7 +4,7 @@
typedef Foo<S extends core::Object* = dynamic> = <T extends core::Object* = dynamic>(T*) →* S*;
class A extends core::Object {
- field <T extends core::Object* = dynamic>(T) →* core::int* f = null;
+ field <T extends core::Object* = dynamic>(T*) →* core::int* f = null;
synthetic constructor •() → self::A*
: super core::Object::•()
;
@@ -14,7 +14,7 @@
}
static method foo<T extends core::Object* = dynamic>(self::foo::T* x) → core::int*
return 3;
-static method bar() → <T extends core::Object* = dynamic>(T) →* core::int*
+static method bar() → <T extends core::Object* = dynamic>(T*) →* core::int*
return #C1;
static method test1() → void {
self::bar().call<core::String*>("hello");
diff --git a/pkg/front_end/testcases/regress/issue_31181.dart.outline.expect b/pkg/front_end/testcases/regress/issue_31181.dart.outline.expect
index 8187fe8..bff625e 100644
--- a/pkg/front_end/testcases/regress/issue_31181.dart.outline.expect
+++ b/pkg/front_end/testcases/regress/issue_31181.dart.outline.expect
@@ -3,6 +3,6 @@
import "dart:core" as core;
typedef Foo<T extends core::Object* = dynamic> = <T extends core::Object* = dynamic>(T*) →* T*;
-static field <T extends core::Object* = dynamic>(T) →* T x;
+static field <T extends core::Object* = dynamic>(T*) →* T* x;
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/regress/issue_31181.dart.strong.expect b/pkg/front_end/testcases/regress/issue_31181.dart.strong.expect
index f1a3bea..c685791 100644
--- a/pkg/front_end/testcases/regress/issue_31181.dart.strong.expect
+++ b/pkg/front_end/testcases/regress/issue_31181.dart.strong.expect
@@ -3,5 +3,5 @@
import "dart:core" as core;
typedef Foo<T extends core::Object* = dynamic> = <T extends core::Object* = dynamic>(T*) →* T*;
-static field <T extends core::Object* = dynamic>(T) →* T x;
+static field <T extends core::Object* = dynamic>(T*) →* T* x;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/regress/issue_31181.dart.strong.transformed.expect b/pkg/front_end/testcases/regress/issue_31181.dart.strong.transformed.expect
index f1a3bea..c685791 100644
--- a/pkg/front_end/testcases/regress/issue_31181.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/regress/issue_31181.dart.strong.transformed.expect
@@ -3,5 +3,5 @@
import "dart:core" as core;
typedef Foo<T extends core::Object* = dynamic> = <T extends core::Object* = dynamic>(T*) →* T*;
-static field <T extends core::Object* = dynamic>(T) →* T x;
+static field <T extends core::Object* = dynamic>(T*) →* T* x;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/regress/issue_31213.dart.outline.expect b/pkg/front_end/testcases/regress/issue_31213.dart.outline.expect
index 64d7ec6..52693de 100644
--- a/pkg/front_end/testcases/regress/issue_31213.dart.outline.expect
+++ b/pkg/front_end/testcases/regress/issue_31213.dart.outline.expect
@@ -3,7 +3,7 @@
import "dart:core" as core;
typedef C<A extends core::Object* = dynamic, K extends core::Object* = dynamic> = <B extends core::Object* = dynamic>(A*, K*, B*) →* core::int*;
-typedef D<K extends core::Object* = dynamic> = <A extends core::Object* = dynamic>(core::int*) →* <B extends core::Object* = dynamic>(A*, K*, B) →* core::int*;
+typedef D<K extends core::Object* = dynamic> = <A extends core::Object* = dynamic>(core::int*) →* <B extends core::Object* = dynamic>(A*, K*, B*) →* core::int*;
static method producer<K extends core::Object* = dynamic>() → dynamic
;
static method main() → dynamic
diff --git a/pkg/front_end/testcases/regress/issue_31213.dart.strong.expect b/pkg/front_end/testcases/regress/issue_31213.dart.strong.expect
index b01d4ea..cc1d463 100644
--- a/pkg/front_end/testcases/regress/issue_31213.dart.strong.expect
+++ b/pkg/front_end/testcases/regress/issue_31213.dart.strong.expect
@@ -3,12 +3,12 @@
import "dart:core" as core;
typedef C<A extends core::Object* = dynamic, K extends core::Object* = dynamic> = <B extends core::Object* = dynamic>(A*, K*, B*) →* core::int*;
-typedef D<K extends core::Object* = dynamic> = <A extends core::Object* = dynamic>(core::int*) →* <B extends core::Object* = dynamic>(A*, K*, B) →* core::int*;
+typedef D<K extends core::Object* = dynamic> = <A extends core::Object* = dynamic>(core::int*) →* <B extends core::Object* = dynamic>(A*, K*, B*) →* core::int*;
static method producer<K extends core::Object* = dynamic>() → dynamic {
return <A extends core::Object* = dynamic>(core::int* v1) → <B extends core::Object* = dynamic>(A*, self::producer::K*, B*) →* core::int* {
return <B extends core::Object* = dynamic>(A* v2, self::producer::K* v3, B* v4) → core::int* => 0;
};
}
static method main() → dynamic {
- assert(self::producer<core::String*>() is <A extends core::Object* = dynamic>(core::int*) →* <B extends core::Object* = dynamic>(A, core::String*, B) →* core::int*);
+ assert(self::producer<core::String*>() is <A extends core::Object* = dynamic>(core::int*) →* <B extends core::Object* = dynamic>(A*, core::String*, B*) →* core::int*);
}
diff --git a/pkg/front_end/testcases/regress/issue_31213.dart.strong.transformed.expect b/pkg/front_end/testcases/regress/issue_31213.dart.strong.transformed.expect
index b01d4ea..cc1d463 100644
--- a/pkg/front_end/testcases/regress/issue_31213.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/regress/issue_31213.dart.strong.transformed.expect
@@ -3,12 +3,12 @@
import "dart:core" as core;
typedef C<A extends core::Object* = dynamic, K extends core::Object* = dynamic> = <B extends core::Object* = dynamic>(A*, K*, B*) →* core::int*;
-typedef D<K extends core::Object* = dynamic> = <A extends core::Object* = dynamic>(core::int*) →* <B extends core::Object* = dynamic>(A*, K*, B) →* core::int*;
+typedef D<K extends core::Object* = dynamic> = <A extends core::Object* = dynamic>(core::int*) →* <B extends core::Object* = dynamic>(A*, K*, B*) →* core::int*;
static method producer<K extends core::Object* = dynamic>() → dynamic {
return <A extends core::Object* = dynamic>(core::int* v1) → <B extends core::Object* = dynamic>(A*, self::producer::K*, B*) →* core::int* {
return <B extends core::Object* = dynamic>(A* v2, self::producer::K* v3, B* v4) → core::int* => 0;
};
}
static method main() → dynamic {
- assert(self::producer<core::String*>() is <A extends core::Object* = dynamic>(core::int*) →* <B extends core::Object* = dynamic>(A, core::String*, B) →* core::int*);
+ assert(self::producer<core::String*>() is <A extends core::Object* = dynamic>(core::int*) →* <B extends core::Object* = dynamic>(A*, core::String*, B*) →* core::int*);
}
diff --git a/pkg/front_end/testcases/regress/issue_31846.dart.strong.expect b/pkg/front_end/testcases/regress/issue_31846.dart.strong.expect
index f501b52..a9152eb 100644
--- a/pkg/front_end/testcases/regress/issue_31846.dart.strong.expect
+++ b/pkg/front_end/testcases/regress/issue_31846.dart.strong.expect
@@ -6,10 +6,10 @@
core::print((#C1) is () →* dynamic);
core::print((<T extends core::Object* = dynamic>(T* x) → T* => x).{core::Object::runtimeType});
core::print((<T extends core::num* = core::num*>(T* x) → T* => x).{core::Object::runtimeType});
- core::print((<T extends core::Comparable<T>* = core::Comparable<dynamic>*>(T* x) → T* => x).{core::Object::runtimeType});
- core::print((<T extends core::Comparable<S>* = core::Comparable<dynamic>*, S extends core::Object* = dynamic>(T* x) → T* => x).{core::Object::runtimeType});
- core::print((<T extends (T) →* dynamic = (core::Null*) →* dynamic>(T* x) → T* => x).{core::Object::runtimeType});
- core::print((<T extends core::List<core::List<T>*>* = core::List<core::List<dynamic>*>*>(T* x) → T* => x).{core::Object::runtimeType});
+ core::print((<T extends core::Comparable<T*>* = core::Comparable<dynamic>*>(T* x) → T* => x).{core::Object::runtimeType});
+ core::print((<T extends core::Comparable<S*>* = core::Comparable<dynamic>*, S extends core::Object* = dynamic>(T* x) → T* => x).{core::Object::runtimeType});
+ core::print((<T extends (T*) →* dynamic = (core::Null?) →* dynamic>(T* x) → T* => x).{core::Object::runtimeType});
+ core::print((<T extends core::List<core::List<T*>*>* = core::List<core::List<dynamic>*>*>(T* x) → T* => x).{core::Object::runtimeType});
}
constants {
diff --git a/pkg/front_end/testcases/regress/issue_31846.dart.strong.transformed.expect b/pkg/front_end/testcases/regress/issue_31846.dart.strong.transformed.expect
index f501b52..a9152eb 100644
--- a/pkg/front_end/testcases/regress/issue_31846.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/regress/issue_31846.dart.strong.transformed.expect
@@ -6,10 +6,10 @@
core::print((#C1) is () →* dynamic);
core::print((<T extends core::Object* = dynamic>(T* x) → T* => x).{core::Object::runtimeType});
core::print((<T extends core::num* = core::num*>(T* x) → T* => x).{core::Object::runtimeType});
- core::print((<T extends core::Comparable<T>* = core::Comparable<dynamic>*>(T* x) → T* => x).{core::Object::runtimeType});
- core::print((<T extends core::Comparable<S>* = core::Comparable<dynamic>*, S extends core::Object* = dynamic>(T* x) → T* => x).{core::Object::runtimeType});
- core::print((<T extends (T) →* dynamic = (core::Null*) →* dynamic>(T* x) → T* => x).{core::Object::runtimeType});
- core::print((<T extends core::List<core::List<T>*>* = core::List<core::List<dynamic>*>*>(T* x) → T* => x).{core::Object::runtimeType});
+ core::print((<T extends core::Comparable<T*>* = core::Comparable<dynamic>*>(T* x) → T* => x).{core::Object::runtimeType});
+ core::print((<T extends core::Comparable<S*>* = core::Comparable<dynamic>*, S extends core::Object* = dynamic>(T* x) → T* => x).{core::Object::runtimeType});
+ core::print((<T extends (T*) →* dynamic = (core::Null?) →* dynamic>(T* x) → T* => x).{core::Object::runtimeType});
+ core::print((<T extends core::List<core::List<T*>*>* = core::List<core::List<dynamic>*>*>(T* x) → T* => x).{core::Object::runtimeType});
}
constants {
diff --git a/pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart.outline.expect b/pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart.outline.expect
index 4aaa576..45e4a38 100644
--- a/pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart.outline.expect
+++ b/pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart.outline.expect
@@ -2,9 +2,8 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart:48:7: Error: The return type of the method 'M.y' is 'int', which does not match the return type, 'Object', of the overridden method, 'I.y'.
+// pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart:48:7: Error: The field 'M.y' has type 'int', which does not match the corresponding type, 'Object', in the overridden setter, 'I.y'.
// - 'Object' is from 'dart:core'.
-// Change to a subtype of 'Object'.
// int y;
// ^
// pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart:43:12: Context: This is the overridden method ('y').
diff --git a/pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart.strong.expect b/pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart.strong.expect
index 2d7f586..2d52e9b 100644
--- a/pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart.strong.expect
+++ b/pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart.strong.expect
@@ -2,9 +2,8 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart:48:7: Error: The return type of the method 'M.y' is 'int', which does not match the return type, 'Object', of the overridden method, 'I.y'.
+// pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart:48:7: Error: The field 'M.y' has type 'int', which does not match the corresponding type, 'Object', in the overridden setter, 'I.y'.
// - 'Object' is from 'dart:core'.
-// Change to a subtype of 'Object'.
// int y;
// ^
// pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart:43:12: Context: This is the overridden method ('y').
diff --git a/pkg/front_end/testcases/strong.status b/pkg/front_end/testcases/strong.status
index 3cd71a8..df68cb5 100644
--- a/pkg/front_end/testcases/strong.status
+++ b/pkg/front_end/testcases/strong.status
@@ -6,7 +6,9 @@
# Kernel ASTs directly, that is, code in pkg/fasta/lib/src/kernel/ with
# strong-mode enabled.
-extensions/extension_methods: RuntimeError
+extensions/instance_access_of_static: RuntimeError
+extensions/invalid_explicit_access: RuntimeError
+extensions/static_access_of_instance: RuntimeError
general/abstract_members: TypeCheckError
general/accessors: RuntimeError
general/ambiguous_exports: RuntimeError # Expected, this file exports two main methods.
@@ -23,6 +25,9 @@
general/duplicated_declarations: TypeCheckError
general/duplicated_field_initializer: RuntimeError
general/dynamic_and_void: InstrumentationMismatch # Test assumes Dart 1.0 semantics
+general/error_locations/error_location_01: RuntimeError
+general/error_locations/error_location_02: RuntimeError
+general/error_locations/error_location_03: RuntimeError
general/expressions: RuntimeError
general/external_import: RuntimeError # The native extension to import doesn't exist. This is ok.
general/fallthrough: ExpectationFileMismatch
@@ -44,6 +49,7 @@
general/override_check_after_inference: TypeCheckError # Issue #31620
general/override_check_basic: TypeCheckError # Issue #31620
general/override_check_with_covariant_modifier: TypeCheckError # Issue #31620
+general/override_setter_with_field: TypeCheckError
general/reject_generic_function_types_in_bounds: RuntimeError # Expected
general/spread_collection: RuntimeError
general/statements: Crash
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index 3a7d406..35ef84e 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -8,16 +8,34 @@
expression/eval: TextSerializationFailure # Was: Pass
expression/main: TextSerializationFailure # Was: Pass
-extensions/explicit_this: TextSerializationFailure
-extensions/extension_methods: TextSerializationFailure
-extensions/implicit_this: TextSerializationFailure
extensions/direct_instance_access: TextSerializationFailure
extensions/direct_static_access: TextSerializationFailure
+extensions/explicit_extension_access: TextSerializationFailure
+extensions/explicit_extension_inference: TextSerializationFailure
+extensions/explicit_generic_extension_access: TextSerializationFailure
+extensions/explicit_this: TextSerializationFailure
+extensions/extension_methods: TextSerializationFailure
+extensions/implicit_extension_inference: TextSerializationFailure
+extensions/implicit_this: TextSerializationFailure
+extensions/index: TextSerializationFailure
+extensions/instance_access: TextSerializationFailure
+extensions/instance_access_of_static: TextSerializationFailure
extensions/instance_members: TextSerializationFailure
+extensions/instance_tearoff: TextSerializationFailure
+extensions/invalid_explicit_access: TextSerializationFailure
+extensions/nested_on_types: TextSerializationFailure
+extensions/on_type_inference: TextSerializationFailure
+extensions/on_type_variable_inference: TextSerializationFailure
+extensions/operators: TextSerializationFailure
extensions/other_kinds: TextSerializationFailure
extensions/static_access: TextSerializationFailure
+extensions/static_access_of_instance: TextSerializationFailure
extensions/type_variables: TextSerializationFailure
extensions/use_this: TextSerializationFailure
+general/error_locations/error_location_01: TextSerializationFailure
+general/error_locations/error_location_02: TextSerializationFailure
+general/error_locations/error_location_03: TextSerializationFailure
+general/error_locations/error_location_04: TextSerializationFailure
general/abstract_members: TypeCheckError
general/abstract_overrides_concrete_with_no_such_method: TextSerializationFailure
general/accessors: TextSerializationFailure # Was: RuntimeError
@@ -183,6 +201,7 @@
general/override_check_with_covariant_modifier: TypeCheckError # Issue #31620
general/override_inference_for_setters: TextSerializationFailure
general/override_inference_named_parameters_ordering: TextSerializationFailure
+general/override_setter_with_field: TypeCheckError
general/part_as_entry_point: TextSerializationFailure # Was: Pass
general/part_as_entry_point_lib: TextSerializationFailure # Was: Pass
general/part_not_part_of: TextSerializationFailure
diff --git a/pkg/front_end/testing.json b/pkg/front_end/testing.json
index 8119cab..2c8c9b8 100644
--- a/pkg/front_end/testing.json
+++ b/pkg/front_end/testing.json
@@ -1,10 +1,8 @@
{
-"":"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.md file.",
-
+ "": "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.md file.",
"packages": "../../.packages",
-
"suites": [
{
"name": "messages",
@@ -12,12 +10,9 @@
"source": "test/fasta/messages_test.dart",
"path": "./",
"status": "messages.status",
- "pattern": [
- ],
- "exclude": [
- ]
+ "pattern": [],
+ "exclude": []
},
-
{
"name": "scanner",
"kind": "Chain",
@@ -27,10 +22,8 @@
"pattern": [
"\\.dart$"
],
- "exclude": [
- ]
+ "exclude": []
},
-
{
"name": "parser",
"kind": "Chain",
@@ -49,7 +42,6 @@
"/sdk/generated/"
]
},
-
{
"name": "outline",
"kind": "Chain",
@@ -67,11 +59,10 @@
"/testcases/expression/"
]
},
-
{
"name": "strong",
"kind": "Chain",
- "source": "test/fasta/strong_test.dart",
+ "source": "test/fasta/strong_tester.dart",
"path": "testcases/",
"status": "testcases/strong.status",
"pattern": [
@@ -85,7 +76,6 @@
"/testcases/expression/"
]
},
-
{
"name": "text_serialization",
"kind": "Chain",
@@ -103,7 +93,6 @@
"/testcases/expression/"
]
},
-
{
"name": "incremental",
"kind": "Chain",
@@ -113,8 +102,7 @@
"pattern": [
"\\.incremental\\.yaml$"
],
- "exclude": [
- ]
+ "exclude": []
},
{
"name": "expression",
@@ -125,8 +113,7 @@
"pattern": [
"\\.expression\\.yaml$"
],
- "exclude": [
- ]
+ "exclude": []
},
{
"name": "incremental_load_from_dill",
@@ -137,10 +124,8 @@
"pattern": [
"\\.yaml$"
],
- "exclude": [
- ]
+ "exclude": []
},
-
{
"name": "incremental_bulk_compiler_smoke",
"kind": "Chain",
@@ -167,10 +152,8 @@
"/language_2/script2_negative_test\\.dart$",
"/language_2/unbalanced_brace_test\\.dart$"
],
- "exclude": [
- ]
+ "exclude": []
},
-
{
"name": "incremental_bulk_compiler_full",
"kind": "Chain",
@@ -180,10 +163,8 @@
"pattern": [
"language_2/.*_test\\.dart$"
],
- "exclude": [
- ]
+ "exclude": []
},
-
{
"name": "old_dill_test",
"kind": "Chain",
@@ -193,10 +174,8 @@
"pattern": [
".*\\.dill$"
],
- "exclude": [
- ]
+ "exclude": []
},
-
{
"name": "lint_test",
"kind": "Chain",
@@ -210,21 +189,20 @@
"src/fasta/fasta_codes_generated\\.dart$"
]
},
-
{
"name": "spelling_test_src_test",
"kind": "Chain",
"source": "test/spelling_test_src_test.dart",
- "path": "lib/",
+ "path": "../",
"status": "test/spelling_test.status",
"pattern": [
- ".*\\.dart$"
+ "front_end/lib/.*\\.dart$",
+ "kernel/lib/.*\\.dart$"
],
"exclude": [
"src/fasta/fasta_codes_generated\\.dart$"
]
},
-
{
"name": "spelling_test_not_src_test",
"kind": "Chain",
@@ -272,7 +250,17 @@
"tool/_fasta/abcompile\\.dart$"
]
},
-
+ {
+ "name": "spelling_test_external_targets",
+ "kind": "Chain",
+ "source": "test/spelling_test_external_targets.dart",
+ "path": "../../",
+ "status": "test/spelling_test.status",
+ "pattern": [
+ ".*\\.dart$"
+ ],
+ "exclude": []
+ },
{
"name": "sdk",
"kind": "Chain",
@@ -300,7 +288,6 @@
"/sdk/tests/language_2/setter_override_test\\.dart$"
]
},
-
{
"note": "Tests dart2js fully, excluding browser-only tests.",
"name": "dart2js",
@@ -314,7 +301,6 @@
"-cdart2js -rd8 dart2js_extra dart2js_native"
]
},
-
{
"note": "Minimal testing of Fasta.",
"name": "fasta_min",
@@ -328,7 +314,6 @@
"-cdartk -rvm"
]
},
-
{
"note": "Tests Fasta fully, including the above dart2js tests.",
"name": "fasta_max",
@@ -343,7 +328,6 @@
"-cdart2js -rd8 dart2js_extra dart2js_native"
]
},
-
{
"note": "Runs dart2js in a mode where it invokes Fasta.",
"name": "dart2js_with_kernel",
@@ -355,7 +339,6 @@
"-cdart2js -rd8 --use-sdk --minified language language_2 dart2js_extra dart2js_native corelib corelib_2"
]
},
-
{
"name": "type_promotion_look_ahead",
"kind": "Chain",
@@ -374,12 +357,8 @@
]
}
],
-
-
"analyze": {
-
"options": "analysis_options_no_lints.yaml",
-
"uris": [
"lib/",
"../analyzer/lib/src/generated/parser_fasta.dart",
@@ -388,16 +367,16 @@
"../kernel/lib/",
"../testing/"
],
-
"git grep": {
- "pathspecs": [ "*.dart" ],
+ "pathspecs": [
+ "*.dart"
+ ],
"patterns": [
"package:front_end/",
"package:kernel/",
"package:testing/"
]
},
-
"exclude": [
"^pkg/analysis_server/lib/src/analysis_server\\.dart",
"test/extensions/data/",
@@ -409,4 +388,4 @@
"test/flow_analysis/type_promotion/data/"
]
}
-}
+}
\ No newline at end of file
diff --git a/pkg/front_end/tool/_fasta/bulk_compile.dart b/pkg/front_end/tool/_fasta/bulk_compile.dart
index 79ec59a..c50da92 100644
--- a/pkg/front_end/tool/_fasta/bulk_compile.dart
+++ b/pkg/front_end/tool/_fasta/bulk_compile.dart
@@ -39,7 +39,7 @@
..packagesFileUri ??= Uri.base.resolve(".packages")
..linkedDependencies = <Uri>[
computePlatformBinariesLocation(forceBuildDir: true)
- .resolve("vm_platform.dill")
+ .resolve("vm_platform_strong.dill")
]
..fileSystem = (new FileBackedMemoryFileSystem()
..entities[mainUri.path] =
diff --git a/pkg/front_end/tool/_fasta/entry_points.dart b/pkg/front_end/tool/_fasta/entry_points.dart
index 4fc6d9d..f9178e3 100644
--- a/pkg/front_end/tool/_fasta/entry_points.dart
+++ b/pkg/front_end/tool/_fasta/entry_points.dart
@@ -304,6 +304,7 @@
Future<void> compilePlatform(List<String> arguments) async {
await withGlobalOptions("compile_platform", arguments, false,
(CompilerContext c, List<String> restArguments) {
+ c.compilingPlatform = true;
Uri hostPlatform = Uri.base.resolveUri(new Uri.file(restArguments[2]));
Uri outlineOutput = Uri.base.resolveUri(new Uri.file(restArguments[4]));
return compilePlatformInternal(
diff --git a/pkg/front_end/tool/fasta.dart b/pkg/front_end/tool/fasta.dart
index 77f1115..a136179 100644
--- a/pkg/front_end/tool/fasta.dart
+++ b/pkg/front_end/tool/fasta.dart
@@ -4,7 +4,9 @@
import 'dart:io';
-final String repoDir = _computeRepoDir();
+import '../test/utils/io_utils.dart' show computeRepoDir;
+
+final String repoDir = computeRepoDir();
final String toolDir = '$repoDir/pkg/front_end/tool/_fasta';
@@ -94,14 +96,6 @@
exitCode = await process.exitCode;
}
-String _computeRepoDir() {
- ProcessResult result = Process.runSync(
- 'git', ['rev-parse', '--show-toplevel'],
- runInShell: true,
- workingDirectory: new File.fromUri(Platform.script).parent.path);
- return (result.stdout as String).trim();
-}
-
void stop(String message) {
stderr.write(message);
exit(2);
diff --git a/pkg/front_end/tool/smoke_test_quick.dart b/pkg/front_end/tool/smoke_test_quick.dart
index 1448d38..9b148a0 100644
--- a/pkg/front_end/tool/smoke_test_quick.dart
+++ b/pkg/front_end/tool/smoke_test_quick.dart
@@ -2,15 +2,19 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import 'dart:io';
+import 'dart:io' show Platform, Process, ProcessResult, exitCode;
-final String repoDir = _computeRepoDir();
+import '../test/utils/io_utils.dart' show computeRepoDir;
+
+final String repoDir = computeRepoDir();
String get dartVm => Platform.executable;
main(List<String> args) async {
Stopwatch stopwatch = new Stopwatch()..start();
List<Future> futures = new List<Future>();
+ futures.add(
+ run("pkg/front_end/test/explicit_creation_test.dart", [], filter: false));
futures.add(run(
"pkg/front_end/test/fasta/messages_test.dart",
["-DfastOnly=true"],
@@ -18,6 +22,7 @@
futures.add(run("pkg/front_end/test/spelling_test_not_src_test.dart", []));
futures.add(run("pkg/front_end/test/spelling_test_src_test.dart", []));
futures.add(run("pkg/front_end/test/lint_test.dart", []));
+ futures.add(run("pkg/front_end/test/deps_test.dart", [], filter: false));
await Future.wait(futures);
print("\n-----------------------\n");
print("Done with exitcode $exitCode in ${stopwatch.elapsedMilliseconds} ms");
@@ -51,18 +56,18 @@
}
stdout = stdout.trim();
if (stdout.isNotEmpty) {
+ print("--- stdout start ---");
print(stdout);
- print("-----");
+ print("--- stdout end ---");
+ }
+
+ String stderr = result.stderr.toString().trim();
+ if (stderr.isNotEmpty) {
+ print("--- stderr start ---");
+ print(stderr);
+ print("--- stderr end ---");
}
} else {
print("Running: $runWhat: Done in ${stopwatch.elapsedMilliseconds} ms.");
}
}
-
-String _computeRepoDir() {
- ProcessResult result = Process.runSync(
- 'git', ['rev-parse', '--show-toplevel'],
- runInShell: true,
- workingDirectory: new File.fromUri(Platform.script).parent.path);
- return (result.stdout as String).trim();
-}
diff --git a/pkg/kernel/bin/transform.dart b/pkg/kernel/bin/transform.dart
index 81bfe53..8285315 100755
--- a/pkg/kernel/bin/transform.dart
+++ b/pkg/kernel/bin/transform.dart
@@ -20,7 +20,6 @@
import 'package:kernel/transformations/empty.dart' as empty;
import 'package:kernel/transformations/method_call.dart' as method_call;
import 'package:kernel/transformations/mixin_full_resolution.dart' as mix;
-import 'package:kernel/transformations/coq.dart' as coq;
import 'package:kernel/vm/constants_native_effects.dart';
ArgParser parser = new ArgParser()
@@ -98,9 +97,6 @@
mix.transformLibraries(
new NoneTarget(null), coreTypes, hierarchy, component.libraries);
break;
- case 'coq':
- component = coq.transformComponent(coreTypes, component);
- break;
case 'constants':
final VmConstantsBackend backend = new VmConstantsBackend(coreTypes);
component = constants.transformComponent(
diff --git a/pkg/kernel/binary.md b/pkg/kernel/binary.md
index 267cdf4..cad20ee 100644
--- a/pkg/kernel/binary.md
+++ b/pkg/kernel/binary.md
@@ -57,7 +57,7 @@
type RList<T> {
T[length] elements;
- Uint32 length;
+ UInt32 length;
}
// Untagged pairs.
@@ -101,6 +101,10 @@
List<Byte> importUriUtf8Bytes;
}
+type String {
+ List<Byte> utf8Bytes;
+}
+
type UriSource {
UInt32 length;
SourceInfo[length] source;
@@ -139,7 +143,7 @@
type ComponentFile {
UInt32 magic = 0x90ABCDEF;
- UInt32 formatVersion = 29;
+ UInt32 formatVersion = 31;
List<String> problemsAsJson; // Described in problems.md.
Library[] libraries;
UriSource sourceMap;
@@ -168,6 +172,7 @@
// which allows to skip to any other field in this component index,
// which again allows to skip to what it points to.
type ComponentIndex {
+ Byte[] 8bitAlignment; // 0-bytes to make the entire component (!) 8-byte aligned.
UInt32 binaryOffsetForSourceTable;
UInt32 binaryOffsetForCanonicalNames;
UInt32 binaryOffsetForMetadataPayloads;
@@ -237,6 +242,7 @@
List<LibraryPart> libraryParts;
List<Typedef> typedefs;
List<Class> classes;
+ List<Extension> extensions;
List<Field> fields;
List<Procedure> procedures;
@@ -274,8 +280,8 @@
List<TypeParameter> typeParameters;
DartType type;
List<TypeParameter> typeParametersOfFunctionType;
- List<VariableDeclaration> positionalParameters;
- List<VariableDeclaration> namedParameters;
+ List<VariableDeclarationPlain> positionalParameters;
+ List<VariableDeclarationPlain> namedParameters;
}
type Combinator {
@@ -331,6 +337,26 @@
UInt32 procedureCount = procedures.length;
}
+type Extension extends Node {
+ Byte tag = 115;
+ CanonicalNameReference canonicalName;
+ StringReference name;
+ UriReference fileUri;
+ FileOffset fileOffset;
+ List<TypeParameter> typeParameters;
+ DartType onType;
+ List<ExtensionMemberDescriptor> members;
+}
+
+enum ExtensionMemberKind { Field = 0, Method = 1, Getter = 2, Setter = 3, Operator = 4, TearOff = 5, }
+
+type ExtensionMemberDescriptor {
+ StringReference name;
+ ExtensionMemberKind kind;
+ Byte flags (isStatic, isExternal);
+ MemberReference member;
+}
+
abstract type Member extends Node {}
type Field extends Member {
@@ -381,7 +407,7 @@
FileOffset fileOffset; // Offset of the procedure name.
FileOffset fileEndOffset;
Byte kind; // Index into the ProcedureKind enum above.
- Uint flags (isStatic, isAbstract, isExternal, isConst, isForwardingStub,
+ UInt flags (isStatic, isAbstract, isExternal, isConst, isForwardingStub,
isForwardingSemiStub, isRedirectingFactoryConstructor,
isNoSuchMethodForwarder, isExtensionMember);
Name name;
@@ -394,7 +420,7 @@
}
type RedirectingFactoryConstructor extends Member {
- Byte tag = 107;
+ Byte tag = 108;
CanonicalNameReference canonicalName;
UriReference fileUri;
FileOffset fileOffset;
@@ -407,8 +433,8 @@
List<TypeParameter> typeParameters;
UInt parameterCount; // positionalParameters.length + namedParameters.length.
UInt requiredParameterCount;
- List<VariableDeclaration> positionalParameters;
- List<VariableDeclaration> namedParameters;
+ List<VariableDeclarationPlain> positionalParameters;
+ List<VariableDeclarationPlain> namedParameters;
}
abstract type Initializer extends Node {}
@@ -444,7 +470,7 @@
type LocalInitializer extends Initializer {
Byte tag = 11;
Byte isSynthetic;
- VariableDeclaration variable;
+ VariableDeclarationPlain variable;
}
type AssertInitializer extends Initializer {
@@ -472,8 +498,8 @@
List<TypeParameter> typeParameters;
UInt parameterCount; // positionalParameters.length + namedParameters.length.
UInt requiredParameterCount;
- List<VariableDeclaration> positionalParameters;
- List<VariableDeclaration> namedParameters;
+ List<VariableDeclarationPlain> positionalParameters;
+ List<VariableDeclarationPlain> namedParameters;
DartType returnType;
Option<Statement> body;
}
@@ -729,11 +755,18 @@
FileOffset fileOffset;
CanonicalNameReference class;
List<DartType> typeArguments;
- List<[FieldReference, Expression]> fieldValues;
+ List<Pair<FieldReference, Expression>> fieldValues;
List<AssertStatement> asserts;
List<Expression> unusedArguments;
}
+type FileUriExpression extends Expression {
+ Byte tag = 116;
+ UriReference fileUri;
+ FileOffset fileOffset;
+ Expression expression;
+}
+
type IsExpression extends Expression {
Byte tag = 37;
FileOffset fileOffset;
@@ -754,22 +787,24 @@
StringReference value;
}
-type SpecializedIntLiteral extends Expression {
+type IntegerLiteral extends Expression {}
+
+type SpecializedIntLiteral extends IntegerLiteral {
Byte tag = 144 + N; // Where 0 <= N < 8.
// Integer literal with value (N - 3), that is, an integer in range -3..4.
}
-type PositiveIntLiteral extends Expression {
+type PositiveIntLiteral extends IntegerLiteral {
Byte tag = 55;
UInt value;
}
-type NegativeIntLiteral extends Expression {
+type NegativeIntLiteral extends IntegerLiteral {
Byte tag = 56;
UInt absoluteValue;
}
-type BigIntLiteral extends Expression {
+type BigIntLiteral extends IntegerLiteral {
Byte tag = 57;
StringReference valueString;
}
@@ -879,7 +914,7 @@
type Let extends Expression {
Byte tag = 53;
- VariableDeclaration variable;
+ VariableDeclarationPlain variable;
Expression body;
}
@@ -912,13 +947,10 @@
ConstantReference constantReference;
}
-type Deprecated_ConstantExpression extends Expression {
- Byte tag = 107;
- ConstantReference constantReference;
+abstract type Constant extends Node {
+ Byte tag;
}
-abstract type Constant extends Node {}
-
type NullConstant extends Constant {
Byte tag = 0;
}
@@ -930,7 +962,7 @@
type IntConstant extends Constant {
Byte tag = 2;
- PositiveIntLiteral | NegativeIntLiteral | SpecializedIntLiteral | BigIntLiteral value;
+ IntegerLiteral value;
}
type DoubleConstant extends Constant {
@@ -953,7 +985,7 @@
Byte tag = 6;
DartType keyType;
DartType valueType;
- List<[ConstantReference, ConstantReference]> keyValueList;
+ List<Pair<ConstantReference, ConstantReference>> keyValueList;
}
type ListConstant extends Constant {
@@ -972,7 +1004,7 @@
Byte tag = 8;
CanonicalNameReference class;
List<DartType> typeArguments;
- List<[FieldReference, ConstantReference]> values;
+ List<Pair<FieldReference, ConstantReference>> values;
}
type PartialInstantiationConstant extends Constant {
@@ -1058,7 +1090,7 @@
type ForStatement extends Statement {
Byte tag = 69;
FileOffset fileOffset;
- List<VariableDeclaration> variables;
+ List<VariableDeclarationPlain> variables;
Option<Expression> condition;
List<Expression> updates;
Statement body;
@@ -1068,7 +1100,7 @@
Byte tag = 70;
FileOffset fileOffset;
FileOffset bodyOffset;
- VariableDeclaration variable;
+ VariableDeclarationPlain variable;
Expression iterable;
Statement body;
}
@@ -1077,7 +1109,7 @@
Byte tag = 80; // Note: tag is out of order.
FileOffset fileOffset;
FileOffset bodyOffset;
- VariableDeclaration variable;
+ VariableDeclarationPlain variable;
Expression iterable;
Statement body;
}
@@ -1137,8 +1169,8 @@
type Catch {
FileOffset fileOffset;
DartType guard;
- Option<VariableDeclaration> exception;
- Option<VariableDeclaration> stackTrace;
+ Option<VariableDeclarationPlain> exception;
+ Option<VariableDeclarationPlain> stackTrace;
Statement body;
}
@@ -1155,12 +1187,12 @@
Expression expression;
}
-type VariableDeclarationStatement extends Statement {
+type VariableDeclaration extends Statement {
Byte tag = 78;
- VariableDeclaration variable;
+ VariableDeclarationPlain variable;
}
-type VariableDeclaration {
+type VariableDeclarationPlain {
// The offset for the variable declaration, i.e. the offset of the start of
// the declaration.
FileOffset fileOffset;
@@ -1192,7 +1224,7 @@
// within the function for use as a self-reference.
// Some of the fields in the variable are redundant, but its presence here
// simplifies the rule for variable indexing.
- VariableDeclaration variable;
+ VariableDeclarationPlain variable;
FunctionNode function;
}
@@ -1200,6 +1232,10 @@
abstract type DartType extends Node {}
+type BottomType extends DartType {
+ Byte tag = 89;
+}
+
type InvalidType extends DartType {
Byte tag = 90;
}
@@ -1243,7 +1279,6 @@
Byte tag = 97; // Note: tag is out of order.
Byte nullability; // Index into the Nullability enum above.
List<DartType> positionalParameters;
- List<StringReference> positionalParameterNames;
DartType returnType;
// Equivalent to a FunctionType with no type parameters or named parameters,
// and where all positional parameters are required.
diff --git a/pkg/kernel/coq/Common.v b/pkg/kernel/coq/Common.v
deleted file mode 100644
index 38653bc..0000000
--- a/pkg/kernel/coq/Common.v
+++ /dev/null
@@ -1,190 +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. *)
-
-Require Export List.
-Require Export Coq.FSets.FMapWeakList.
-Require Export Coq.FSets.FMapFacts.
-Require Export Coq.Structures.DecidableTypeEx.
-Require Export Coq.Structures.Equalities.
-Require Export Coq.Strings.String.
-Require Import CpdtTactics.
-
-(** * Auxiliary definitions. *)
-
-(** Strings are used as keys in maps of getters, setters, and methods of
- interface types. For maps we use the list-based unordered representation,
- because it only requires decidability on the domain of keys. [String_as_MDT]
- and [String_as_UDT] below are auxiliary modules to define [StringMap]. *)
-
-Module String_as_MDT.
- Definition t := string.
- Definition eq_dec := string_dec.
-End String_as_MDT.
-
-Module String_as_UDT := Equalities.Make_UDT(String_as_MDT).
-
-(** [NatMap] is used to map type variables to type locations and to map type
- locations to type values. *)
-Module NatMap := FMapWeakList.Make(Nat_as_DT).
-Module NatMapFacts := FMapFacts.Facts NatMap.
-
-(** [StringMap] is used to map identifiers to getters, setters, and methods. *)
-Module StringMap := FMapWeakList.Make(String_as_UDT).
-
-(* A "comp A" denotes a partial function that may not terminate on some inputs
- or terminate without an answer on others. *)
-Module ComputationMonad.
-
- Definition comp (A : Type) := nat -> option A.
-
- Definition comp_return {A : Type} (a : A) : comp A := fun _ => Some a.
- Definition abort {A : Type} : comp A := fun _ => None.
-
- Definition comp_bind {A : Type} {B : Type} (x : comp A) (y : A -> comp B) : comp B :=
- fun n => match x n with None => None | Some a => y a n end.
- Definition comp_unsome {A : Type} (v : option A) : comp A := fun _ => v.
-
- Notation "[ x ]" := (comp_return x) (at level 0, x at level 200).
- Notation "[[ x ]]" := (comp_unsome x) (at level 0, x at level 99).
- Notation "x <- m1 ; m2" := (comp_bind m1 (fun x => m2)) (at level 70, right associativity).
-
- Fixpoint comp_fix' (A : Type) (B : Type) (f : (A -> comp B) -> (A -> comp B)) (a : A) (n : nat) {struct n} : option B :=
- match n with
- | O => None
- | (S n) => let rec := fun (a : A) => comp_unsome (comp_fix' _ _ f a n) in f rec a n
- end.
-
- Definition Fix {A : Type} {B : Type} (f : (A -> comp B) -> (A -> comp B)) : A -> comp B :=
- fun a => fun n => comp_fix' _ _ f a n.
-
- Module Continuity.
-
- Definition continuous {A: Type} (f: comp A) : Prop :=
- forall n k v, n <= k -> f n = Some v -> f k = Some v.
-
- Lemma return_cont {A: Type} : forall a : A, continuous (comp_return a).
- intros.
- unfold comp_return.
- unfold continuous.
- auto.
- Qed.
-
- Lemma abort_cont {A : Type} : continuous (@abort A).
- unfold abort.
- unfold continuous.
- auto.
- Qed.
-
- End Continuity.
-
-End ComputationMonad.
-
-Module OptionMonad.
-
- Notation "[ x ]" := (Some x) (at level 0, x at level 200).
-
- Definition opt_bind {A B} (x : option A) (f : A -> option B) : option B :=
- match x with
- | None => None
- | Some v => f v
- end.
-
- Notation "x <- m1 ; m2" := (opt_bind m1 (fun x => m2)) (at level 70, right associativity).
-
-End OptionMonad.
-
-Module ListExtensions.
- Import ComputationMonad.
-
- Fixpoint mmap {A B} (f : A -> comp B) (l : list A) : comp (list B) :=
- match l with
- | nil => [nil]
- | (x::xs) => (x' <- f x; xs' <- mmap f xs; [x' :: xs'])
- end.
-
- Lemma foldr_mono {A} {B} :
- forall (P : A -> A -> Prop) (l : list B) (a0 : A) (f : B -> A -> A),
- (forall x, P x x) ->
- (forall x y z, P x y -> P y z -> P x z) ->
- (forall a b, P a (f b a)) ->
- P a0 (List.fold_right f a0 l).
- Proof.
- induction l; crush.
- pose proof (IHl a0 f H H0 H1).
- pose proof (H1 (fold_right f a0 l) a).
- pose proof (H0 _ _ _ H2 H3).
- crush.
- Qed.
-
- Lemma foldr_preserve {A} {B} :
- forall (P : A -> Prop) (l : list B) (a0 : A) (f : B -> A -> A),
- (forall a b, P a -> P (f b a)) ->
- P a0 -> P (List.fold_right f a0 l).
- Proof.
- induction l; crush.
- Qed.
-
- Fixpoint list_all {A} (f : A -> Prop) (l : list A) :=
- match l with
- | nil => True
- | (x::xs) => f x /\ list_all f xs
- end.
-
- Lemma forall_list_all : forall A P (l : list A), Forall P l <-> list_all P l.
- intros.
- apply conj.
- intro f.
- induction f; crush.
- induction l; crush.
- Qed.
-End ListExtensions.
-
-(* These could be generalized and factored into a functor, like FMapFacts, but
- * right now there's no need. *)
-Module MoreNatMapFacts.
-
-Module N := Coq.Arith.PeanoNat.Nat.
-
-Lemma add_3 {A} : forall m x (y y' : A), NatMap.MapsTo x y m /\ NatMap.MapsTo x y' m -> y = y'.
- intuition.
- set (Fx := NatMap.find x m).
- assert (Fx = NatMap.find x m) by auto.
- pose proof (NatMap.find_1 H0).
- pose proof (NatMap.find_1 H1).
- crush.
-Qed.
-
-Lemma maps_in_mapsto :
- forall A (m : NatMap.t A) key,
- NatMap.In key m ->
- exists el, NatMap.MapsTo key el m.
-Proof.
- intros.
- pose proof (NatMapFacts.find_mapsto_iff m key).
- pose proof (NatMapFacts.in_find_iff m key).
- unfold iff in H1. destruct H1 as [H1a H1b].
- pose proof (H1a H).
- destruct (NatMap.find key m) eqn:?.
- exists a. pose proof (H0 a). unfold iff in H2. destruct H2 as [H2a H2b].
- apply H2b. congruence.
- contradiction.
-Qed.
-
-Lemma maps_mapsto_in :
- forall A (m : NatMap.t A) key,
- (exists el, NatMap.MapsTo key el m) ->
- NatMap.In key m.
-Proof.
- intros.
- destruct H as (el & H1).
- pose proof (NatMapFacts.find_mapsto_iff m key el).
- unfold iff in H. destruct H as [H2 H3].
- pose proof (H2 H1).
- assert (Some el <> None). discriminate.
- rewrite <- H in H0.
- apply NatMapFacts.in_find_iff in H0.
- auto.
-Qed.
-
-End MoreNatMapFacts.
diff --git a/pkg/kernel/coq/CommonTactics.v b/pkg/kernel/coq/CommonTactics.v
deleted file mode 100644
index 6a92448..0000000
--- a/pkg/kernel/coq/CommonTactics.v
+++ /dev/null
@@ -1,75 +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. *)
-
-Require Import Common.
-Require Export CpdtTactics.
-
-Import OptionMonad.
-
-Ltac extract E x y := set (x := E); assert (y : E = x); [auto|rewrite y in *].
-
-Ltac force_expr E H :=
- let v1 := fresh in
- let v2 := fresh in
- extract E v1 v2; destruct v1; [idtac|simpl in H; contradict H; congruence].
-
-Lemma bind_some : forall A B x f, @opt_bind A B (Some x) f = f x.
-Proof.
- auto.
-Qed.
-
-Lemma simpl_if : forall A (e1 e2 : A), (if true then e1 else e2) = e1.
- auto.
-Qed.
-
- (* remember (expression_type CE (NatMap.add v s TE) arg) as EXP. *)
-(* destruct EXP; [rewrite bind_some in H1|simpl in H1; contradict H1; congruence]. *)
-Ltac force_option :=
- match goal with
- | [ H : (opt_bind ?y (fun x => ?z)) = Some ?w |- _ ] =>
- force_expr y H; rewrite bind_some in H
- | [ H : (if ?cond then ?x else None) = Some ?w |- _ ] =>
- force_expr cond H; rewrite simpl_if in H
- | [ H : (match ?x with _ => _ end) = Some ?w |- _ ] =>
- force_expr x H
- end.
-
-Ltac force_options := repeat force_option.
-
-Inductive ltac_no_arg : Set :=
-| Ltac_No_Arg : ltac_no_arg.
-
-Ltac extract_head_2 term H varid eqid :=
- match type of H with
- | context[term ?X] => extract_head_2 (term X) H varid eqid
- | context[term] => remember term as varid eqn:eqid
- end.
-
-Ltac extract_head_1 term H varid := let eqid := fresh varid "Eq" in extract_head_2 term H varid eqid.
-Ltac extract_head_0 term H := let varid := fresh H in extract_head_1 term H varid.
-
-Ltac extract_head_goal_2 term varid eqid :=
- match goal with
- | [ |- context[term ?X] ] => extract_head_goal_2 (term X) varid eqid
- | [ |- context[term] ] => remember term as varid eqn:eqid
- end.
-
-Ltac extract_head_goal_1 term varid := let eqid := fresh varid "Eq" in extract_head_goal_2 term varid eqid.
-Ltac extract_head_goal_0 term := let varid := fresh "G" in extract_head_goal_1 term varid.
-
-Tactic Notation "extract_head" constr(term) "in" constr(H) := extract_head_0 term H.
-Tactic Notation "extract_head" constr(term) "in" constr(H) "as" ident(name) := extract_head_1 term H name.
-Tactic Notation "extract_head" constr(term) "in" constr(H) "as" ident(name) "," ident(name2) := extract_head_2 term H name name2.
-
-Tactic Notation "extract_head" constr(term) := extract_head_goal_0 term.
-Tactic Notation "extract_head" constr(term) "as" ident(name) := extract_head_goal_1 term name.
-Tactic Notation "extract_head" constr(term) "as" ident(name) "," ident(name2) := extract_head_goal_2 term name name2.
-
-Ltac continue_with H :=
- match type of H with
- | ?X -> ?Y =>
- let K := fresh H in
- let H' := fresh H in
- assert (X) as K; [idtac|pose proof (H K) as H']
- end.
diff --git a/pkg/kernel/coq/ObjectModel.v b/pkg/kernel/coq/ObjectModel.v
deleted file mode 100644
index 746b72e..0000000
--- a/pkg/kernel/coq/ObjectModel.v
+++ /dev/null
@@ -1,1057 +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. *)
-
-Require Import Common.
-Require Import CommonTactics.
-Require Import Syntax.
-Require Import Coq.Strings.String.
-(* This is for convenience, we could remove it with some refactoring if we so wished. *)
-Require Import Coq.Logic.FunctionalExtensionality.
-
-Import Common.OptionMonad.
-Import Common.ListExtensions.
-Import Common.NatMapFacts.
-Import Common.MoreNatMapFacts.
-
-Module N := Coq.Arith.PeanoNat.Nat.
-
-(* The subtyping function doesn't satisfy the ordinary subterm totality
- condition due to the contravariant property function parameter types.
- Instead, we prove it terminates by induction on the sum of both types'
- syntactic sizes. *)
-Section Dart_Type_Pair_Size_Properties.
- Fixpoint size (d : dart_type) : nat :=
- match d with
- | DT_Interface_Type (Interface_Type n) => 1
- | DT_Function_Type (Function_Type p r) => size p + size r + 1
- end.
-
- Definition pair_size (d : dart_type * dart_type) :=
- let (x, y) := d in size x + size y.
-
- Definition pair_size_order (d e : dart_type * dart_type) := pair_size d < pair_size e.
- Hint Constructors Acc.
- Lemma pair_size_order_wf' : forall sz, forall d, pair_size d < sz -> Acc pair_size_order d.
- Proof.
- unfold pair_size_order; induction sz; crush.
- Defined.
- Theorem pair_size_order_wf : well_founded pair_size_order.
- red; intros; eapply pair_size_order_wf'; eauto.
- Defined.
-End Dart_Type_Pair_Size_Properties.
-
-Module Subtyping.
-
- Local Definition subtype_rec
- (p : dart_type * dart_type)
- (subtype : forall p' : dart_type * dart_type, pair_size_order p' p -> bool) : bool.
- refine (
- match p as p' return (p = p' -> bool) with
- | (DT_Interface_Type (Interface_Type s_class),
- DT_Interface_Type (Interface_Type t_class)) =>
- fun H1 => N.eqb s_class t_class
- | (DT_Function_Type (Function_Type s_param s_ret),
- DT_Function_Type (Function_Type t_param t_ret)) =>
- fun H2 => andb (subtype (t_param, s_param) _) (subtype (s_ret, t_ret) _)
- | _ => fun _ => false
- end (eq_refl : p = p));
- destruct p;
- destruct d1; destruct d2; crush;
- unfold pair_size_order;
- crush.
- Defined.
-
- Definition subtype : dart_type * dart_type -> bool :=
- Fix pair_size_order_wf (fun _ => bool) subtype_rec.
-
- Notation "s ◁ t" := (subtype (s, t) = true) (at level 70, no associativity).
-
- Local Ltac destruct_types :=
- repeat match goal with
- | [H : interface_type |- _] => destruct H
- | [H : function_type |- _] => destruct H
- end.
-
- Local Lemma subtype_rec_equiv :
- forall (x : dart_type * dart_type)
- (f g : forall y : dart_type * dart_type, pair_size_order y x -> bool),
- (forall (y : dart_type * dart_type) (p : pair_size_order y x), f y p = g y p) ->
- subtype_rec x f = subtype_rec x g.
- Proof.
- intros;
- destruct x;
- destruct d;
- destruct d0;
- destruct_types;
- cbv;
- crush.
- Qed.
-
- Definition subtype_rewrite :=
- Fix_eq pair_size_order_wf (fun _ => bool) subtype_rec subtype_rec_equiv.
-
- Local Ltac unfold_subtype' H :=
- match type of H with
- | ltac_no_arg =>
- unfold subtype;
- rewrite subtype_rewrite;
- unfold subtype_rec at 1;
- fold subtype
- | _ =>
- unfold subtype in H;
- rewrite subtype_rewrite in H;
- unfold subtype_rec at 1 in H;
- fold subtype in H
- end.
-
- Tactic Notation "unfold_subtype" := unfold_subtype' Ltac_No_Arg.
- Tactic Notation "unfold_subtype" constr(x) := unfold_subtype' x.
-
- Hint Rewrite N.eqb_eq.
- Hint Unfold subtype.
-
- Lemma subtype_refl : forall s : dart_type, s ◁ s.
- apply
- (dart_type_ind_mutual
- (fun s => s ◁ s)
- (fun i => DT_Interface_Type i ◁ DT_Interface_Type i)
- (fun f => DT_Function_Type f ◁ DT_Function_Type f)); crush.
- cbv; crush.
- unfold_subtype; crush.
- Qed.
-
- Definition trans_at t := forall s r, s ◁ t /\ t ◁ r -> s ◁ r.
-
- Hint Unfold trans_at.
-
- (* TODO(sjindel): how can we generalize this? *)
- Ltac simplify_subtypes :=
- repeat ( intuition; repeat ( destruct_types || match goal with
- | [ H : DT_Interface_Type (Interface_Type _) ◁ _ |- _ ] =>
- unfold_subtype H
- | [ H : DT_Function_Type (Function_Type _ _) ◁ _ |- _ ] =>
- unfold_subtype H
- | [ H : _ ◁ DT_Interface_Type (Interface_Type _) |- _ ] =>
- unfold_subtype H
- | [ H : _ ◁ DT_Function_Type (Function_Type _ _) |- _ ] =>
- unfold_subtype H
- | [ |- DT_Interface_Type (Interface_Type _) ◁ _ ] =>
- unfold_subtype
- | [ |- DT_Function_Type (Function_Type _ _) ◁ _ ] =>
- unfold_subtype
- | [ |- _ ◁ DT_Interface_Type (Interface_Type _) ] =>
- unfold_subtype
- | [ |- _ ◁ DT_Function_Type (Function_Type _ _) ] =>
- unfold_subtype
- end)).
-
- Local Lemma interface_type_trans : forall (n : nat), trans_at (DT_Interface_Type (Interface_Type n)).
- Proof.
- intros.
- unfold trans_at.
- intros.
- destruct s; destruct r; simplify_subtypes; crush.
- Qed.
- Hint Immediate interface_type_trans.
-
- Local Lemma function_type_trans :
- forall d, trans_at d -> forall d', trans_at d' ->
- trans_at (DT_Function_Type (Function_Type d d')).
- Proof.
- intros; unfold trans_at in *; intros; destruct s; destruct r.
- crush.
- simplify_subtypes.
- crush.
- simplify_subtypes.
- rewrite Bool.andb_true_iff in *.
- crush.
- Qed.
- Hint Immediate function_type_trans.
-
- Lemma subtype_trans : forall t s r, s ◁ t /\ t ◁ r -> s ◁ r.
- apply (dart_type_induction trans_at); crush.
- Qed.
- Hint Resolve subtype_trans.
-
-End Subtyping.
-Import Subtyping.
-
-Record procedure_desc : Type := mk_procedure_desc {
- pr_name : string;
- pr_ref : nat;
- pr_type : function_type;
-}.
-
-Record getter_desc : Type := mk_getter_desc {
- gt_name : string;
- gt_ref : nat;
- gt_type : dart_type;
-}.
-
-Record interface : Type := mk_interface {
- procedures : list procedure_desc;
- getters : list getter_desc;
-}.
-
-Inductive member_desc : Type :=
- | MD_Method : procedure_desc -> member_desc
- | MD_Getter : getter_desc -> member_desc
-.
-
-(** Type envronment maps class IDs to their interface type. *)
-Definition class_env : Type := NatMap.t interface.
-
-Definition type_env : Type := NatMap.t dart_type.
-
-Fixpoint expression_type
- (CE : class_env) (TE : type_env) (e : expression) :
- option dart_type :=
- match e with
- | E_Variable_Get (Variable_Get v) => NatMap.find v TE
- | E_Property_Get (Property_Get rec prop) =>
- rec_type <- expression_type CE TE rec;
- let (prop_name) := prop in
- match rec_type with
- | DT_Function_Type _ =>
- if string_dec prop_name "call" then [rec_type] else None
- | DT_Interface_Type (Interface_Type class) =>
- interface <- NatMap.find class CE;
- proc_desc <- List.find (fun P =>
- if string_dec (pr_name P) prop_name then true else false)
- (procedures interface);
- [DT_Function_Type (pr_type proc_desc)]
- end
- | E_Invocation_Expression (IE_Constructor_Invocation (Constructor_Invocation class)) =>
- _ <- NatMap.find class CE;
- [DT_Interface_Type (Interface_Type class)]
- | E_Invocation_Expression (IE_Method_Invocation (Method_Invocation rec method args _)) =>
- rec_type <- expression_type CE TE rec;
- let (arg_exp) := args in
- arg_type <- expression_type CE TE arg_exp;
- let (method_name) := method in
- fun_type <-
- match rec_type with
- | DT_Function_Type fn_type =>
- if string_dec "call" method_name then [fn_type] else None
- | DT_Interface_Type (Interface_Type class) =>
- interface <- NatMap.find class CE;
- proc_desc <- List.find (fun P =>
- if string_dec (pr_name P) method_name then true else false)
- (procedures interface);
- [pr_type proc_desc]
- end;
- let (param_type, ret_type) := fun_type in
- if subtype (arg_type, param_type) then [ret_type] else None
- end
-.
-
-Fixpoint statement_type (CE : class_env) (TE : type_env) (s : statement) (r: dart_type) :
- option type_env :=
- match s with
- | S_Expression_Statement (Expression_Statement e) =>
- _ <- expression_type CE TE e; [TE]
- | S_Return_Statement (Return_Statement re) =>
- rt <- expression_type CE TE re;
- if subtype (rt, r) then [TE] else None
- | S_Variable_Declaration (Variable_Declaration _ _ None) => None
- | S_Variable_Declaration (Variable_Declaration var type (Some init)) =>
- init_type <- expression_type CE TE init;
- if subtype (init_type, type) then
- [NatMap.add var type TE]
- else
- None
- | S_Block (Block stmts) =>
- let process_statements := fix process_statements TE stmts :=
- match stmts with
- | nil => [TE]
- | (s::ss) =>
- TE' <- statement_type CE TE s r;
- process_statements TE' ss
- end in
- process_statements TE stmts
- end
-.
-
-Definition procedure_type (CE : class_env) (p : procedure) : bool :=
- let (_, _, fn) := p in
- let (param, ret_type, body) := fn in
- let (param_var, param_type, _) := param in
- let TE := NatMap.add param_var param_type (NatMap.empty _) in
- match statement_type CE TE body ret_type with Some _ => true | None => false end
-.
-
-Definition class_type (CE : class_env) (c : class) : bool :=
- let (nn_data, _, procedures) := c in
- forallb (procedure_type CE) procedures
-.
-
-Section Typing_Equivalence_Homomorphism.
-
- Definition subtype_at (e : expression) :=
- forall CE TE v s t es,
- expression_type CE (NatMap.add v s TE) e = [es] /\ t ◁ s ->
- exists et, expression_type CE (NatMap.add v t TE) e = [et] /\ et ◁ es.
-
- Hint Resolve NatMap.add_1.
- Hint Resolve NatMap.add_2.
- Hint Resolve NatMap.find_1.
- Hint Resolve subtype_refl.
- Lemma subtype_at_variable_get :
- forall v, subtype_at (E_Variable_Get (Variable_Get v)).
- Proof.
- unfold subtype_at.
- intros.
- destruct (N.eq_dec v v0).
- rewrite e in *.
- exists t.
- assert (es = s).
- unfold expression_type in H.
- assert (NatMap.find v0 (NatMap.add v0 s TE) = Some s) by crush.
- rewrite H0 in H.
- crush.
- intuition.
- unfold expression_type.
- crush.
- crush.
- destruct H.
- unfold expression_type in H.
- apply NatMap.find_2 in H.
- exists es.
- unfold expression_type in *.
- pose proof (@NatMap.add_3 dart_type TE v0 v es s (not_eq_sym n) H).
- crush.
- Qed.
- Hint Immediate subtype_at_variable_get.
-
- Hint Rewrite N.eqb_eq.
- Lemma subtype_at_property_get :
- forall rec prop, subtype_at rec -> subtype_at (E_Property_Get (Property_Get rec prop)).
- Proof.
- unfold subtype_at.
- intros.
- intuition.
- destruct prop.
- unfold expression_type in H1.
- fold expression_type in H1.
- extract (expression_type CE (NatMap.add v s TE) rec) Orig H0.
-
- (* Go by cases on the original type of the receiver. *)
- destruct Orig; [idtac|crush].
- simpl in H1.
- destruct d.
-
- (* Case 1: receiver has interface type. *)
- destruct i.
- extract (NatMap.find n CE) iface H3.
- destruct iface; [idtac|crush].
- simpl in H1.
- pose proof (H CE TE v s t (DT_Interface_Type (Interface_Type n)) (conj H0 H2)).
- destruct H4 as [new_rec_type].
- destruct H4.
- destruct new_rec_type.
- destruct i0.
- unfold_subtype H5.
- exists es.
- crush.
- unfold_subtype H5.
- destruct f.
- crush.
-
- (* Case 2: receiver has function type. *)
- destruct f.
- force_options.
- pose proof (H CE TE v s t (DT_Function_Type (Function_Type d d0)) (conj H0 H2)).
- destruct H3 as [new_rec_type].
- destruct H3.
- exists new_rec_type.
- intuition; [idtac|crush].
- unfold expression_type.
- fold expression_type.
- rewrite H3.
- simpl.
- destruct new_rec_type.
- destruct i.
- unfold_subtype H5.
- crush.
- crush.
- Qed.
- Hint Immediate subtype_at_property_get.
-
- Lemma subtype_at_ctor_invo :
- forall c, subtype_at (E_Invocation_Expression (IE_Constructor_Invocation c)).
- Proof.
- unfold subtype_at; intros; exists es; crush.
- Qed.
- Hint Immediate subtype_at_ctor_invo.
-
- Lemma subtype_at_meth_invo :
- forall rec arg name n, subtype_at rec -> subtype_at arg ->
- subtype_at (E_Invocation_Expression (IE_Method_Invocation (Method_Invocation rec name (Arguments arg) n))).
- Proof.
- unfold subtype_at; intros.
- unfold expression_type in H.
- fold expression_type in H.
- destruct H1.
- unfold expression_type in H1.
- fold expression_type in H1.
- force_expr (expression_type CE (NatMap.add v s TE) rec) H1.
- destruct d.
-
- (* Case 1: receiver has interface type. *)
- exists es.
- simpl in H1.
- force_options.
- destruct name.
- force_options.
- destruct f.
- force_options.
- destruct i.
- force_options.
- (* The receiver class must be the same. *)
- assert (expression_type CE (NatMap.add v t TE) rec = [DT_Interface_Type (Interface_Type n0)]).
- pose proof (H CE TE v s t (DT_Interface_Type (Interface_Type n0)) (conj H4 H2)) as IH_rec.
- destruct IH_rec.
- destruct H3.
- destruct x.
- destruct i0.
- unfold_subtype H10.
- crush.
- unfold_subtype H10.
- destruct f.
- crush.
- (* The function called must have the same type. *)
- unfold expression_type.
- fold expression_type.
- rewrite H3; simpl.
- (* The argument is still well typed. *)
- pose proof (H0 CE TE v s t d (conj H5 H2)) as IH_arg.
- destruct IH_arg.
- destruct H10.
- rewrite H10.
- simpl.
- intuition; crush.
- rewrite H6.
- assert (x ◁ d0).
- pose proof (subtype_trans d x d0 (conj H11 H7)); crush.
- rewrite H1; crush.
-
- (* Case 2: The receiver has function type. *)
- rewrite bind_some in H1.
- force_options.
- destruct name.
- force_options.
- destruct f0.
- force_options.
- pose proof (H CE TE v s t (DT_Function_Type f) (conj H4 H2)).
- destruct H3.
- destruct H3.
- destruct x.
- unfold_subtype H9.
- destruct i.
- crush.
- destruct f; destruct f0.
- simplify_subtypes.
- rewrite Bool.andb_true_iff in H9; destruct H9.
- assert (es = d3) by crush.
- exists d5.
- intuition; [idtac|crush].
- unfold expression_type.
- fold expression_type.
- rewrite H3.
- rewrite bind_some.
- pose proof (H0 CE TE v s t d (conj H5 H2)).
- destruct H12.
- destruct H12.
- rewrite H12.
- rewrite bind_some.
- rewrite H7.
- rewrite bind_some.
- assert (d2 = d0) by crush.
- rewrite H11 in *; clear H11.
- rewrite H14 in *; clear H14.
- assert (x ◁ d0).
- refine (subtype_trans d x d0 _); auto.
- assert (x ◁ d4).
- refine (subtype_trans d0 x d4 _); auto.
- rewrite H14.
- crush.
- Qed.
- Hint Immediate subtype_at_meth_invo.
-
- Theorem subtype_homo_expr : forall e, subtype_at e.
- Hint Extern 1 =>
- match goal with
- [ x : arguments |- _ ] => destruct x
- end.
- apply (expr_induction subtype_at); crush.
- Qed.
-
- Definition type_env_subtype (TE': type_env) (TE: type_env) :=
- forall v s, NatMap.MapsTo v s TE -> exists t, NatMap.MapsTo v t TE' /\ t ◁ s.
-
- Notation "X ◂ Y" := (type_env_subtype X Y) (at level 71, no associativity).
-
- Lemma type_env_subtype_refl : forall TE, TE ◂ TE.
- unfold type_env_subtype.
- intros.
- exists s.
- crush.
- Qed.
- Hint Immediate type_env_subtype_refl.
-
- Lemma type_env_subtype_1 :
- forall v d d' TE TE', TE ◂ TE' -> d ◁ d' -> NatMap.add v d TE ◂ NatMap.add v d' TE'.
- intros.
- unfold type_env_subtype in *.
- intros.
- destruct (N.eq_dec v0 v).
- rewrite e in *; clear e.
- exists d.
- crush.
- assert (s = d') by
- (rewrite NatMapFacts.add_mapsto_iff in H1; crush).
- crush.
-
- rewrite NatMapFacts.add_mapsto_iff in H1.
- destruct H1; [crush|idtac].
- destruct H1.
- destruct (H v0 s H2).
- exists x.
- crush.
- Qed.
- Hint Resolve type_env_subtype_1.
-
- Definition expr_extra_irrelevance_at e :=
- forall CE TE et v t,
- ~NatMap.In v TE ->
- expression_type CE TE e = [et] ->
- expression_type CE (NatMap.add v t TE) e = [et].
-
- Theorem expr_extra_irrelvance : forall e, expr_extra_irrelevance_at e.
- apply (expr_induction expr_extra_irrelevance_at).
- crush.
- crush.
- crush.
-
- unfold expr_extra_irrelevance_at.
- intros.
- simpl in *.
- apply NatMap.find_1.
- apply NatMap.find_2 in H0.
- assert (v <> n).
- contradict H.
- unfold NatMap.MapsTo in *.
- unfold NatMap.In in *.
- unfold NatMap.Raw.PX.In in *.
- exists et; crush.
- crush.
-
- unfold expr_extra_irrelevance_at.
- intros.
- simpl in H1.
- force_options.
- pose proof (H _ _ _ _ t H0 H3).
- crush.
-
- crush.
- crush.
-
- unfold expr_extra_irrelevance_at.
- intros.
- unfold expression_type in H2.
- fold expression_type in H2.
- remember (expression_type CE TE e) as E.
- destruct E; [idtac|simpl in H1; contradict H1; crush].
- pose proof (H _ _ _ _ t H1 (eq_sym HeqE)).
- rewrite bind_some in H2.
- destruct a.
- force_options.
- pose proof (H0 _ _ _ _ t H1 H5).
- destruct n.
- unfold expression_type.
- fold expression_type.
- rewrite H3.
- rewrite H4.
- rewrite bind_some.
- rewrite bind_some.
- crush.
-
-
- unfold expr_extra_irrelevance_at.
- crush.
-
- crush.
- Qed.
-
- Theorem subtype_homo_env_expr :
- forall e CE TE TE' es,
- expression_type CE TE e = [es] /\ TE' ◂ TE ->
- (exists et, expression_type CE TE' e = [et] /\ et ◁ es).
- Proof.
- (* This is tedious to prove in Coq, but it follows directly from
- subtype_homo_expr and expr_extra_irrelevance, along with the finiteness
- of finite maps. *)
- Admitted.
-
- Definition subtype_at_stmt (st: statement) :=
- forall CE X X' Y r,
- statement_type CE X st r = [X'] /\ Y ◂ X ->
- exists Y', statement_type CE Y st r = [Y'] /\ Y' ◂ X'.
-
- Local Lemma subtype_at_return : forall r, subtype_at_stmt (S_Return_Statement r).
- Proof.
- unfold subtype_at_stmt.
- intros.
- destruct r.
- unfold statement_type in *.
- intuition.
- force_options.
- inversion H0.
- pose proof (subtype_homo_env_expr e _ _ _ _ (conj H2 H1)).
- destruct H.
- exists Y.
- crush.
- assert (x ◁ r0) by (refine (subtype_trans d x r0 _); auto).
- crush.
- Qed.
- Hint Immediate subtype_at_return.
-
- Local Lemma subtype_at_vardecl : forall vd, subtype_at_stmt (S_Variable_Declaration vd).
- Proof.
- unfold subtype_at_stmt.
- intros.
- unfold statement_type in *.
- destruct vd.
- destruct o; [idtac|crush].
- intuition.
- force_options.
- assert (forall A (x y : A), [x] = [y] -> x = y) as R by crush.
- apply R in H0; clear R.
- pose proof (subtype_homo_env_expr e _ _ _ _ (conj H2 H1)).
- destruct H.
- intuition.
- rewrite H4.
- simpl.
- assert (x ◁ d) by
- (refine (subtype_trans d0 x d _); crush).
- exists (NatMap.add n d Y).
- crush.
- Qed.
- Hint Immediate subtype_at_vardecl.
-
- Local Lemma subtype_at_exprstmt : forall es, subtype_at_stmt (S_Expression_Statement es).
- Proof.
- unfold subtype_at_stmt.
- unfold statement_type in *.
- intros.
- destruct es.
- intuition; force_options.
- inversion H0; clear H0.
- exists Y.
- pose proof (subtype_homo_env_expr e _ _ _ _ (conj H2 H1)).
- destruct H.
- intuition.
- rewrite H0.
- crush.
- crush.
- Qed.
- Hint Immediate subtype_at_exprstmt.
-
- Local Lemma subtype_at_block : forall ss, Forall subtype_at_stmt ss -> subtype_at_stmt (S_Block (Block ss)).
- Proof.
- induction ss.
-
- unfold subtype_at_stmt.
- intros.
- simpl.
- exists Y.
- crush.
-
- intros.
- rewrite forall_list_all in H.
- simpl in H.
- destruct H.
- unfold subtype_at_stmt.
- intros.
- unfold statement_type in *.
- fold statement_type in *.
- unfold subtype_at_stmt in H.
- extract_head statement_type in H1.
- destruct H2; [idtac|simpl in H1; crush].
- simpl in H1.
- destruct H1.
- pose proof (H _ _ _ _ _ (conj (eq_sym H2Eq) H2)) as Z.
- destruct Z.
- destruct H3.
- intuition.
- simpl.
- match type of H1 with
- | ?Y _ _ = ?W => remember Y as PS
- end.
-
- (* We need to prove a lemma about the inline helper function. *)
- assert (
- forall X Y Y',
- X ◂ Y -> PS Y ss = [Y'] ->
- exists X', PS X ss = [X'] /\ X' ◂ Y') as L.
- generalize H0.
- generalize ss as l.
- clear - HeqPS.
- induction l.
- intros.
- exists X; crush.
-
- intros.
- destruct H0.
- rewrite HeqPS in H1.
- rewrite <- HeqPS in H1.
- force_options.
- rewrite HeqPS.
- rewrite <- HeqPS.
- pose proof (H0 _ _ _ _ _ (conj H4 H)).
- destruct H3; destruct H3.
- rewrite H3; simpl.
- apply (IHl H2 x t); crush.
-
- clear HeqPS.
- clear H.
- rewrite H3.
- simpl.
- pose proof (L x t X' H4 H1).
- destruct H as (Y', H).
- destruct H.
- exists Y'.
- crush.
- Qed.
- Hint Immediate subtype_at_block.
-
- Theorem subtype_homo_stmt : forall s, subtype_at_stmt s.
- Proof.
- apply (statement_induction subtype_at_stmt); auto.
- Qed.
-
-End Typing_Equivalence_Homomorphism.
-
-Section Environments.
-
-(** Function environment maps defined functions to their procedure type. Used
- for direct method invocation, direct property get etc. *)
-Definition member_env : Type := NatMap.t member.
-
-Definition procedure_dissect (envs: class_env * member_env) (p : procedure) :=
- let (CE, ME) := envs in
- let (memb, _, fn) := p in
- let (nn, name) := memb in
- let (name_str) := name in
- let (ref) := nn in
- let (id) := ref in
- let (param, ret_type, _) := fn in
- let (_, param_type, _) := param in
- let proc := mk_procedure_desc name_str id (Function_Type param_type ret_type) in
- (proc, (CE, NatMap.add id (M_Procedure p) ME)).
-
-Definition procedure_to_env p envs := snd (procedure_dissect envs p).
-Definition procedure_to_desc envs p := fst (procedure_dissect envs p).
-
-Definition class_to_env (c : class) (envs: class_env * member_env) :=
- let (nn, name, procs) := c in
- let (ref) := nn in
- let (id) := ref in
- let envs' := List.fold_right procedure_to_env envs procs in
- let procedures := List.map (procedure_to_desc envs') procs in
- let getters := List.map (fun P => mk_getter_desc (pr_name P) (pr_ref P) (DT_Function_Type (pr_type P))) procedures in
- let (CE, ME) := envs' in
- (NatMap.add id (mk_interface procedures getters) CE, ME).
-
-Definition lib_to_env (l: library) : class_env * member_env :=
- let (_, classes, top_procs) := l in
- let envs := List.fold_right class_to_env (NatMap.empty _, NatMap.empty _) classes in
- List.fold_right procedure_to_env envs top_procs.
-
-Local Ltac destruct_types :=
- repeat match goal with
- | [H : interface_type |- _] => destruct H
- | [H : function_type |- _] => destruct H
- | [H : procedure |- _] => destruct H
- | [H : member_data |- _] => destruct H
- | [H : named_node_data |- _] => destruct H
- | [H : function_node |- _] => destruct H
- | [H : procedure_desc |- _] => destruct H
- | [H : getter_desc |- _] => destruct H
- | [H : name |- _] => destruct H
- | [H : reference |- _] => destruct H
- | [H : variable_declaration |- _] => destruct H
- | [H : class |- _] => destruct H
- end.
-
-Local Lemma proc_desc_noenv : forall env env', procedure_to_desc env = procedure_to_desc env'.
-Proof.
- intros.
- apply functional_extensionality.
- intros.
- unfold procedure_to_desc.
- unfold procedure_dissect.
- destruct env; destruct env'.
- destruct_types.
- crush.
-Qed.
-
-Local Definition mono
- (envs: class_env * member_env)
- (envs': class_env * member_env) : Prop :=
- let (CE, ME) := envs in
- let (CE', ME') := envs' in
- (forall n, NatMap.In n CE -> NatMap.In n CE') /\
- (forall n, NatMap.In n ME -> NatMap.In n ME').
-
-Local Lemma mono_trans : forall x y z, mono x y -> mono y z -> mono x z.
-Proof.
- intros.
- destruct x; destruct y; destruct z.
- unfold mono in *.
- crush.
-Qed.
-
-Local Lemma mono_sym : forall x, mono x x.
-Proof.
- crush.
-Qed.
-
-Hint Rewrite add_in_iff.
-Local Lemma proc_mono :
- forall E1 E2 p p',
- procedure_dissect E1 p = (p', E2) -> mono E1 E2.
-Proof.
- intros.
- unfold procedure_dissect in H.
- destruct_types.
- destruct E1; destruct E2.
- unfold mono.
- inject H.
- crush.
-Qed.
-Hint Resolve proc_mono.
-
-Local Lemma class_mono :
- forall E1 E2 c, class_to_env c E1 = E2 -> mono E1 E2.
-Proof.
- intros.
- destruct E1; destruct E2.
- unfold class_to_env in H.
- destruct_types.
- extract_head fold_right in H.
- assert (mono (c0, m) H0).
- pose proof (foldr_mono mono l (c0, m) procedure_to_env mono_sym mono_trans) as X.
- continue_with X.
- intros.
- unfold procedure_to_env.
- remember (procedure_dissect a b) as P.
- destruct P.
- simpl.
- apply (proc_mono _ _ _ _ (eq_sym HeqP)).
- crush.
-
- destruct H0.
- assert (mono (c, m) (t, m0)) by
- (inversion H;
- unfold mono;
- crush); crush.
-Qed.
-
-Local Lemma fold_proc_invar :
- forall E1 E2 ps,
- List.fold_right procedure_to_env E1 ps = E2 ->
- fst E1 = fst E2.
-Proof.
- intros.
- destruct E1 as (CE, ME); destruct E2 as (CE' , ME').
- pose (x := @foldr_preserve (class_env * member_env) procedure (fun env => let (CE', _) := env in CE = CE') ps (CE, ME) procedure_to_env).
- continue_with x.
- crush.
- destruct_types.
- crush.
- continue_with x.
- crush.
- continue_with x3; crush.
- rewrite H in H3.
- assumption.
-Qed.
-
-Local Lemma class_env_invar :
- forall CE ME CE' ME' id id' intf n ps,
- id <> id' ->
- class_to_env (Class (Named_Node (Reference id')) n ps) (CE, ME) = (CE', ME') ->
- (NatMap.MapsTo id intf CE' -> NatMap.MapsTo id intf CE).
-Proof.
- unfold class_to_env.
- intros.
- extract_head fold_right in H0 as F.
- destruct F as (CE_f, ME_f).
- inversion H0; clear H0.
- rewrite H4 in *; clear H4.
- assert (NatMap.MapsTo id intf CE_f).
- rewrite <- H3 in H1.
- apply (NatMap.add_3 (not_eq_sym H) H1).
- apply eq_sym in FEq.
- apply fold_proc_invar in FEq.
- simpl in FEq.
- crush.
-Qed.
-
-Hint Resolve NatMap.add_1.
-Local Lemma program_wf': forall cs CE ME class_id intf proc_desc,
- List.fold_right class_to_env (NatMap.empty _, NatMap.empty _) cs = (CE, ME)
- -> NatMap.MapsTo class_id intf CE
- -> List.In proc_desc (procedures intf)
- -> NatMap.In (pr_ref proc_desc) ME.
-Proof.
- intro cs.
- induction cs.
-
- (* Base case: no classes in the library. Contradiction. *)
- intros.
- unfold fold_right in H.
- inversion H.
- contradict H0.
- pose proof (@NatMap.empty_1 interface).
- rewrite <- H3 in *.
- clear H3; clear CE.
- unfold NatMap.Empty in *.
- unfold NatMap.empty in H0.
- unfold NatMap.empty.
- unfold NatMap.MapsTo.
- simpl in *.
- unfold NatMap.Raw.Empty in H0.
- generalize class_id intf.
- assumption.
-
- (* Inductive case: consider whether top class is ours or not. *)
- intros.
- simpl in *.
- destruct a; destruct n; destruct r.
- destruct (N.eq_dec n class_id).
-
- (* Case 1.1: head class is different. *)
- Focus 2.
- extract_head fold_right in H as Fold.
- destruct Fold as (CE_f, ME_f).
-
- (* class_id must map to the same interface after applying the previous classes. *)
- assert (NatMap.MapsTo class_id intf CE_f).
- pose proof (class_env_invar CE_f ME_f CE ME class_id n intf s l (not_eq_sym n0)) as H2.
- continue_with H2; crush.
-
- (* Apply the induction hypothesis. *)
- pose proof (IHcs CE_f ME_f class_id intf proc_desc eq_refl H2 H1) as IH.
- assert (mono (CE_f, ME_f) (CE, ME)).
- apply (class_mono _ _ ((Class (Named_Node (Reference n)) s l))); crush.
- crush.
-
- (* Case 1.2: head class is the same. *)
- extract_head fold_right in H as Fold.
- unfold class_to_env in H.
- extract_head fold_right in H as FoldP.
- destruct FoldP as (CE_f, ME_f).
- inversion H; clear H.
- rewrite H4 in *; clear H4.
- rewrite e in *; clear e.
- extract_head mk_interface in H3 as I, IEq.
- assert (NatMap.MapsTo class_id I CE) by crush.
- pose proof (@MoreNatMapFacts.add_3 _ CE class_id intf I (conj H0 H)).
- rewrite H2 in *; clear H2.
- clear H0.
- clear H.
- simpl in H1.
- clear IHcs.
- rewrite IEq in *.
- clear IEq.
- clear I.
- generalize H1.
- generalize FoldPEq.
- generalize CE_f ME.
- clear H1.
- clear FoldPEq.
- clear H3.
- induction l.
- intros.
- unfold In in H1.
- simpl in H1.
- crush.
- intros.
- destruct a; destruct n0; destruct r.
- destruct proc_desc.
- simpl.
- simpl in H1.
- destruct H1.
- unfold procedure_to_desc in H.
- unfold procedure_dissect in H.
- destruct_types.
- simpl in H.
- inversion H.
- rewrite H1 in *; clear H1.
- rewrite H2 in *; clear H2.
- rewrite H3 in *; clear H3.
- rewrite H4 in *; clear H4.
- clear H.
- simpl in FoldPEq.
- extract_head (fold_right procedure_to_env) in FoldPEq as Rest.
- destruct Rest.
- unfold procedure_to_env in FoldPEq.
- unfold procedure_dissect in FoldPEq.
- simpl in FoldPEq.
- inject FoldPEq.
- crush.
-
- simpl in FoldPEq.
- simpl in IHl.
- extract_head fold_right in FoldPEq as InnerFold.
- destruct InnerFold as (CE_i, ME_i).
- unfold procedure_to_env in FoldPEq.
- unfold procedure_dissect in FoldPEq.
- destruct_types.
- simpl in FoldPEq.
- rewrite (proc_desc_noenv (CE_f0, ME0) (CE_i, ME_i)) in H.
- pose proof (IHl CE_i ME_i eq_refl H).
- inversion FoldPEq.
- clear FoldPEq.
- clear H2.
- crush.
-Qed.
-
-Lemma program_wf: forall l CE ME class_id intf proc_desc,
- lib_to_env l = (CE, ME)
- -> NatMap.MapsTo class_id intf CE
- -> List.In proc_desc (procedures intf)
- -> NatMap.In (pr_ref proc_desc) ME.
-Proof.
- intros.
- destruct l.
- unfold lib_to_env in *.
- extract_head (fold_right class_to_env) in H as Inner.
- destruct Inner as (CE_i, ME_i).
- assert (NatMap.MapsTo class_id intf CE_i).
-
- apply eq_sym in InnerEq.
- apply (fold_proc_invar _ _ _) in H.
- simpl in H.
- crush.
-
- pose proof (program_wf' l CE_i ME_i class_id intf proc_desc (eq_sym InnerEq) H2 H1).
- assert (mono (CE_i, ME_i) (CE, ME)).
- rewrite <- H.
- apply foldr_mono.
- exact mono_sym.
- exact mono_trans.
- intros.
- unfold procedure_to_env in *.
- remember (procedure_dissect a b) as Z.
- destruct Z.
- simpl.
- apply (proc_mono a p0 b p).
- auto.
- unfold mono in H4.
- crush.
-Qed.
-
-End Environments.
diff --git a/pkg/kernel/coq/OperationalSemantics.v b/pkg/kernel/coq/OperationalSemantics.v
deleted file mode 100644
index 99a923e..0000000
--- a/pkg/kernel/coq/OperationalSemantics.v
+++ /dev/null
@@ -1,1385 +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. *)
-
-
-Require Import Coq.Lists.List.
-Require Import Common.
-Require Import Syntax.
-Require Import ObjectModel.
-
-
-Import ObjectModel.Subtyping.
-
-Notation "s <: t" := (subtype (s, t) = true) (at level 70, no associativity).
-
-
-Section OperationalSemantics.
-
-
-(** The well-formedness hypothesis is that the environments are built via
- [lib_to_env] function from the object model module. [program_wf] theorem
- defined there provides the rest of the well-formedness properties. In
- [OperationalSemantics] sections we don't need the hypothesis itself, just the
- environments. *)
-Variable CE : class_env.
-Variable ME : member_env.
-
-
-(** [runtime_value] represents the runtime values used in the abstract machine
- during program execution. The values are typed and have some relation to
- syntactic types and internal representation of their interfaces. Currently a
- runtime value doesn't have a state, it only has a type. It should have a
- state when a broader subset of Kernel is formalized. *)
-Record runtime_value := mk_runtime_value {
-
- (** Null is currently modelled using None as the value of [runtime_type].
- It may change in future once [dart_type] includes a constructor for Null
- or Bottom. Also, in the current subset of Kernel type Null can't be
- expressed syntactically; therefore, it can't be a declared type of a method
- parameter, a declared type of a variable, etc. The only use of Null in the
- current subset of Kernel is that of a runtime type of a runtime value. In
- that case the declared type of the variable holding such value and the
- runtime type of the value do not match. *)
- runtime_type : option dart_type;
-}.
-
-
-(** [value_of_type] defines the meaning of statement "the runtime value has the
- given interface and the given type". *)
-Inductive value_of_type :
- runtime_value -> interface -> option dart_type -> Prop :=
-
- (** If the type of the runtime value is an interface type, then the
- corresponding interface should be in the global class environment. *)
- | RFS_Interface_Type :
- forall val intf type class_id,
- type = DT_Interface_Type (Interface_Type class_id) ->
- NatMap.find class_id CE = Some intf ->
- (runtime_type val) = Some type ->
- value_of_type val intf (Some type)
-
- (** If the type of the runtime value is a function type, then the
- corresponding interface may or may not be in the global class environment,
- but should have a particular shape. *)
- | RFS_Function_Type :
- forall val intf ftype memb_id proc,
- (procedures intf) = (mk_procedure_desc "call" memb_id ftype) :: nil ->
- (getters intf) =
- (mk_getter_desc "call" memb_id (DT_Function_Type ftype)) :: nil ->
- NatMap.MapsTo memb_id (M_Procedure proc) ME ->
- (runtime_type val) = Some (DT_Function_Type ftype) ->
- value_of_type val intf (Some (DT_Function_Type ftype))
-
- (** Null values are currently represented as runtime values that have [None]
- in place of their type. In future, for example when the Bottom type or
- explicit Null type are added to the syntax of dart types, the
- representation may change. *)
- | RFS_Null_Type :
- forall val intf,
- (procedures intf) = nil ->
- (getters intf) = nil ->
- (runtime_type val) = None ->
- value_of_type val intf None.
-
-
-(** Describes that the given dart type has a method with the given name. The
- predicate can be applied to runtime types of values, so it should accept None
- as the first parameter to account for `null` values.
-
- Currently, values of function type only have "call" methods, and null doesn't
- have any methods. *)
-Inductive method_exists : option dart_type -> string -> Prop :=
-
- | ME_Interface_Type :
- forall name intf desc class_id type,
- type = (DT_Interface_Type (Interface_Type class_id)) ->
- (* TODO(dmitryas): Replace `value_of_type` here with a relation that binds
- together the interface and the type, avoiding the construction of the
- value. *)
- value_of_type (mk_runtime_value (Some type)) intf (Some type) ->
- List.In desc (procedures intf) ->
- ((pr_name desc) = name)%string ->
- method_exists (Some type) name
-
- | ME_Function_Type :
- forall type intf desc ftype,
- type = (DT_Function_Type ftype) ->
- (* TODO(dmitryas): Replace `value_of_type` here with a relation that binds
- together the interface and the type, avoiding the construction of the
- value. *)
- value_of_type (mk_runtime_value (Some type)) intf (Some type) ->
- List.In desc (procedures intf) ->
- ((pr_name desc) = "call")%string ->
- method_exists (Some type) "call".
-
-
-(** Describes that the method with the given name of the given dart type
- accepts arguments of the given type. The predicate can be applied to runtime
- types of values, so it should accept None as the first parameter to account
- for `null` values.
-
- Currently, values of function type only have "call" methods, and null doesn't
- have any methods. *)
-Inductive method_accepts :
- option dart_type -> string -> option dart_type -> Prop :=
-
- | MA_Non_Null :
- forall name intf desc rcvr_type arg_type par_type ret_type,
- method_exists (Some rcvr_type) name ->
- (* TODO(dmitryas): Replace `value_of_type` here with a relation that binds
- together the interface and the type, avoiding the construction of the
- value. *)
- value_of_type (mk_runtime_value (Some rcvr_type)) intf (Some rcvr_type) ->
- List.In desc (procedures intf) ->
- ((pr_name desc) = name)%string ->
- (pr_type desc) = Function_Type par_type ret_type ->
- arg_type <: par_type ->
- method_accepts (Some rcvr_type) name (Some arg_type)
-
- | MA_Null :
- forall rcvr_type_opt name,
- method_exists rcvr_type_opt name ->
- method_accepts rcvr_type_opt name None.
-
-
-(** Describes that the method with the given name of the given dart type
- returns a value of the given type. The predicate can be applied to runtime
- types of values, so it should accept None as the first parameter to account
- for `null` values.
-
- Currently, values of function type only have "call" methods, and null doesn't
- have any methods. *)
-Inductive method_returns :
- option dart_type -> string -> dart_type -> Prop :=
-
- | Method_Returns :
- forall name intf desc rcvr_type par_type ret_type,
- method_exists (Some rcvr_type) name ->
- (* TODO(dmitryas): Replace `value_of_type` here with a relation that binds
- together the interface and the type, avoiding the construction of the
- value. *)
- value_of_type (mk_runtime_value (Some rcvr_type)) intf (Some rcvr_type) ->
- List.In desc (procedures intf) ->
- ((pr_name desc) = name)%string ->
- (pr_type desc) = Function_Type par_type ret_type ->
- method_returns (Some rcvr_type) name ret_type.
-
-
-(** Describes that the given dart type has a getter with the given name. The
- predicate can be applied to runtime types of values, so it should accept None
- as the first parameter to account for `null` values.
-
- Currently, values of function type only have "call" getters, and null doesn't
- have any getters. *)
-Inductive getter_exists : option dart_type -> string -> Prop :=
-
- | GE_Interface_Type :
- forall name intf desc class_id type,
- type = (DT_Interface_Type (Interface_Type class_id)) ->
- (* TODO(dmitryas): Replace `value_of_type` here with a relation that binds
- together the interface and the type, avoiding the construction of the
- value. *)
- value_of_type (mk_runtime_value (Some type)) intf (Some type) ->
- List.In desc (getters intf) ->
- ((gt_name desc) = name)%string ->
- getter_exists (Some type) name
-
- | GE_Function_Type :
- forall type intf desc ftype,
- type = (DT_Function_Type ftype) ->
- (* TODO(dmitryas): Replace `value_of_type` here with a relation that binds
- together the interface and the type, avoiding the construction of the
- value. *)
- value_of_type (mk_runtime_value (Some type)) intf (Some type) ->
- List.In desc (getters intf) ->
- ((gt_name desc) = "call")%string ->
- getter_exists (Some type) "call".
-
-
-(** Describes that the getter with the given name of the given dart type
- returns a value of the given type. The predicate can be applied to runtime
- types of values, so it should accept None as the first parameter to account
- for `null` values.
-
- Currently, values of function type only have "call" getters, and null doesn't
- have any getters. *)
-Inductive getter_returns :
- option dart_type -> string -> dart_type -> Prop :=
-
- | Getter_Returns :
- forall name intf desc rcvr_type,
- getter_exists (Some rcvr_type) name ->
- value_of_type (mk_runtime_value (Some rcvr_type)) intf (Some rcvr_type) ->
- List.In desc (getters intf) ->
- ((gt_name desc) = name)%string ->
- getter_returns (Some rcvr_type) name (gt_type desc).
-
-
-(** The environment that is used by the abstract machine to map the currently
- visible set of variables to their types and runtime values is represented as
- a list of records.
-
- [var_type] represents the declared type of the variable and may not match
- the runtime type of the [value] in case the latter is Null. This is because
- in the current subset of Kernel Null can't be represented syntactically. *)
-Record env_entry := mk_env_entry {
- var_ref : nat;
- var_type : dart_type;
- value : runtime_value;
-}.
-
-Definition environment := list env_entry.
-
-Definition env_get
- (var : nat)
- (env : environment)
- : option env_entry :=
- List.find (fun entry => Nat.eqb var (var_ref entry)) env.
-
-Definition env_extend
- (var : nat)
- (type : dart_type)
- (val : runtime_value)
- (env : environment)
- : environment :=
- (mk_env_entry var type val) :: env.
-
-Definition env_in
- (var : nat)
- (env : environment)
- : Prop :=
- match List.find (fun entry => Nat.eqb var (var_ref entry)) env with
- | None => False
- | Some _ => True
- end.
-
-Definition empty_env : environment := nil.
-
-Definition env_to_type_env : environment -> type_env :=
- fun env => List.fold_left
- (fun TE entry => NatMap.add (var_ref entry) (var_type entry) TE)
- env
- (NatMap.empty dart_type).
-
-
-(** TODO(dmitryas): Write descriptive comments.
-
- First, [untyped_expression_continuation] is defined. Its only difference
- from [expression_continuation] is that the value expected by the continuation
- is untyped; [expression_continuation] pairs an
- [untyped_expression_continuation] and a [dart_type], giving the expected
- value a type. It is done to simplify the extraction of the type from an
- expression continuation in predicates. *)
-Inductive untyped_expression_continuation : Set :=
-
- (** The constructor receives the following parameters:
-
- - an [environment]
- - a [expression_continuation]
- - a [statement_continuation] *)
- | Expression_Ek :
- environment
- -> expression_continuation
- -> statement_continuation
- -> untyped_expression_continuation
-
- (** The constructor receives the following parameters:
-
- - a [string]
- - an [expression]
- - an [environment]
- - a [expression_continuation] *)
- | Method_Invocation_Ek :
- string
- -> expression
- -> environment
- -> expression_continuation
- -> untyped_expression_continuation
-
- (** The constructor receives the following parameters:
-
- - a [runtime_value]
- - a [string]
- - an [environment]
- - a [expression_continuation] *)
- | Invocation_Ek :
- runtime_value
- -> string
- -> environment
- -> expression_continuation
- -> untyped_expression_continuation
-
- (** The constructor receives the following parameters:
-
- - a [string]
- - a [expression_continuation] *)
- | Property_Get_Ek :
- string
- -> expression_continuation
- -> untyped_expression_continuation
-
- (** The constructor receives the following parameters:
-
- - a [nat]
- - a [dart_type]
- - an [environment]
- - a [statement_continuation] *)
- | Var_Declaration_Ek :
- nat
- -> dart_type
- -> environment
- -> statement_continuation
- -> untyped_expression_continuation
-
- (** [Halt_Ek] represents the end of program execution. The main procedure
- returns a value (or null) to this expression continuation. The value is
- then ignored, and the program execution halts. The constructor doesn't
- receive any parameters. *)
- | Halt_Ek :
- untyped_expression_continuation
-
-(** TODO(dmitryas): Write descriptive comments. *)
-with statement_continuation : Set :=
-
- (** The constructor receives the following parameters:
-
- - a [expression_continuation]
- - a [runtime_value] *)
- | Exit_Sk :
- expression_continuation
- -> runtime_value
- -> statement_continuation
-
- (** The constructor receives the following parameters:
-
- - a list of [statement]s
- - an [environment]
- - a [expression_continuation]
- - a [statement_continuation] *)
- | Block_Sk :
- list statement
- -> environment
- -> expression_continuation
- -> statement_continuation
- -> statement_continuation
-
-(** A [expression_continuation] encapsulates a [dart_type] that signifies
- the type of the value expected by the expression continuation as the
- input.
-
- In the current subset of Kernel the Null type can't be described
- syntactically, so it can't be a type of a typed expression or statement.
- Therefore, the type of the value expected by the expression continuation
- can't be Null, and it's expressed as [dart_type], not [option dart_type]. *)
-with expression_continuation : Set :=
-
- | Expression_Continuation :
- untyped_expression_continuation
- -> dart_type
- -> expression_continuation.
-
-
-(** [configuration] represents configurations of the CESK abstract machine that
- is used for defining the operational semantics. A transition of the machine
- represents a small step of the small-step operational semantics. There are
- the following types of configurations:
-
- - [Eval_Configuration] — encapsulates a syntactic expression and an
- expression continuation. After evaluation of the expression the resulting
- value is passed to the expression configuration.
- - [Exec_Configuration] — encapsulates a syntactic statement. Represents the
- execution of the statement.
- - [Value_Passing_Configuration] — encapsulates a value and an expression
- continuation. The value is passed to the expression continuation.
- - [Forward_Configuration] — encapsulates a statement continuation.
- The execution of the program proceeds to the associated statement. *)
-Inductive configuration : Set :=
-
- (** [Eval_Configuration] represents the beginning of an expression
- evaluation. The constructor receives the following parameters:
-
- - an [expression] — the expression to be evaluated;
- - an [environment] — the mapping from variables to values that is to be
- used during the expression evaluation;
- - a [expression_continuation] — the continuation that will receive
- the value of the expression after its evaluation. *)
- | Eval_Configuration :
- expression
- -> environment
- -> expression_continuation
- -> configuration
-
- (** [Exec_Configuration] represents the beginning of a statement execution.
- The constructor receives the following parameters:
-
- - a [statement] — the statement to be executed;
- - an [environment] — the mapping from variables to values that is to be
- used during the statement execution;
- - a [expression_continuation] — in case the executed statement
- returns a value, this continuation will receive this value;
- - a [statement_continuation] — in case the executed statement
- doesn't return a value, this continuation represents the rest of the
- program execution. *)
- | Exec_Configuration :
- statement
- -> environment
- -> expression_continuation
- -> statement_continuation
- -> configuration
-
- (** [Value_Passing_Configuration] represents the end of an expression
- evaluation. The constructor receives the following parameters:
-
- - a [expression_continuation] — the continuation that receives the
- value which is the result of the expression evaluation;
- - a [value] — the result of the expression evaluation. *)
- | Value_Passing_Configuration :
- expression_continuation
- -> runtime_value
- -> configuration
-
- (** [Forward_Configuration] represents the rest of the program execution.
- The constructor receives the following parameters:
-
- - a [statement_continuation] — represents the rest of the program
- execution;
- - an [environment] — the mapping from variables to values that is to be
- used during the execution of the rest of the program. *)
- | Forward_Configuration :
- statement_continuation
- -> environment
- -> configuration.
-
-
-(** Represents steps (a.k.a. transitions) of the abstract machine. *)
-Inductive step : configuration -> configuration -> Prop :=
-
- (** <Block(stmt :: stmts), ρ, κE, κS>exec ==>
- <stmt, ρ, κE, BlockSK(stmts, ρ, κE, κS)>exec *)
- | Exec_Block :
- forall stmt stmts env ret_cont next_cont,
- step (Exec_Configuration
- (S_Block (Block (stmt :: stmts)))
- env ret_cont next_cont)
- (Exec_Configuration
- stmt env ret_cont
- (Block_Sk stmts env ret_cont next_cont))
-
- (** <Block(#[]#), ρ, κE, κS>exec ==> <κS, ρ>forward *)
- | Exec_Block_Empty :
- forall env ret_cont next_cont,
- step (Exec_Configuration
- (S_Block (Block nil)) env ret_cont next_cont)
- (Forward_Configuration next_cont env)
-
- (** <BlockSK(stmt :: stmts, ρ, κE, κS), ρ'>forward ==>
- <stmt, ρ', κE, BlockSK(stmts, ρ, κE, κS)>exec *)
- | Forward_Block_Sk :
- forall stmt stmts env ret_cont next_cont env',
- step (Forward_Configuration
- (Block_Sk (stmt :: stmts) env ret_cont next_cont)
- env')
- (Exec_Configuration
- stmt env' ret_cont
- (Block_Sk stmts env ret_cont next_cont))
-
- (** <BlockSK(#[]#, ρ, κE, κS), ρ'>forward ==> <κS, ρ>forward *)
- | Forward_Block_Sk_Empty :
- forall env ret_cont next_cont env',
- step (Forward_Configuration
- (Block_Sk nil env ret_cont next_cont)
- env')
- (Forward_Configuration next_cont env)
-
- (** <ExpressionStatement(expr), ρ, κE, κS>exec ==>
- <expr, ρ, ExpressionEK(ρ, κE, κS)>eval *)
- | Exec_Expression_Statement :
- forall expr env ret_cont next_cont ret_type,
- expression_type CE (env_to_type_env env) expr = Some ret_type ->
- step (Exec_Configuration
- (S_Expression_Statement (Expression_Statement expr))
- env ret_cont next_cont)
- (Eval_Configuration
- expr env
- (Expression_Continuation
- (Expression_Ek env ret_cont next_cont)
- ret_type))
-
- (** <ReturnStatement(expr), ρ, κE, κS>exec ==> <expr, ρ, κE>eval *)
- | Exec_Return_Statement :
- forall expr env ret_cont next_cont,
- step (Exec_Configuration
- (S_Return_Statement (Return_Statement expr))
- env ret_cont next_cont)
- (Eval_Configuration expr env ret_cont)
-
- (** <VariableGet(var), ρ, κE>eval ==> <κE, ρ(var)>pass *)
- | Eval_Variable_Get :
- forall var_id env ret_cont entry,
- env_get var_id env = Some entry ->
- step (Eval_Configuration
- (E_Variable_Get (Variable_Get var_id)) env ret_cont)
- (Value_Passing_Configuration
- ret_cont (value entry))
-
- (** <MethodInvocation(rcvr, name, arg), ρ, κE>eval ==>
- <rcvr, ρ, MethodInvocationEK(name, arg, ρ, κE)>eval *)
- | Eval_Method_Invocation :
- (* TODO(dmitryas): Remove [ref] after interfaceTargetReference is removed
- from constructor [Method_Invocation]. *)
- forall rcvr_expr rcvr_type name arg env ret_cont ref,
- expression_type CE (env_to_type_env env) rcvr_expr = Some rcvr_type ->
- step (Eval_Configuration
- (E_Invocation_Expression (IE_Method_Invocation
- (Method_Invocation rcvr_expr (Name name) (Arguments arg) ref)))
- env ret_cont)
- (Eval_Configuration rcvr_expr env
- (Expression_Continuation
- (Method_Invocation_Ek name arg env ret_cont)
- rcvr_type))
-
- (** <MethodInvocationEK(name, arg, ρ, κE), rcvrVal)pass ==>
- <arg, ρ, InvocationEK(rcvrVal, name, ρ, κE)>eval,
- rcvrVall != null *)
- | Pass_Method_Invocation_Ek_Non_Null :
- forall name arg_expr arg_type env ret_cont
- rcvr_val rcvr_type expected_rcvr_type,
- runtime_type rcvr_val = Some rcvr_type ->
- expression_type CE (env_to_type_env env) arg_expr = Some arg_type ->
- step (Value_Passing_Configuration
- (Expression_Continuation
- (Method_Invocation_Ek name arg_expr env ret_cont)
- expected_rcvr_type)
- rcvr_val)
- (Eval_Configuration arg_expr env
- (Expression_Continuation
- (Invocation_Ek rcvr_val name env ret_cont)
- arg_type))
-
- (** <InvocationEK(rcvrVal, name, ρ, κE), argVal>pass ==>
- <block, ρ', κE, κS>exec,
- where ρ' = ρ0#[#this = rcvrVal#][#arg(f) = argVal#]#,
- block = body(f),
- κS = ExitSK(κE, nullVal),
- f = methods(class(rcvrVal))(name),
- ρ0 — empty environment *)
- | Pass_Invocation_Ek :
- forall rcvr_val rcvr_intf rcvr_type_opt
- proc_desc memb_data named_data func_node
- var_id var_type var_init ret_type body
- name arg_val arg_type env env'
- ret_cont next_cont null_val,
- (* TODO(dmitryas): Add the mapping: this -> rcvr_val to env'. *)
- value_of_type rcvr_val rcvr_intf rcvr_type_opt ->
- List.In proc_desc (procedures rcvr_intf) ->
- NatMap.MapsTo
- (pr_ref proc_desc)
- (M_Procedure (Procedure memb_data named_data func_node))
- ME ->
- func_node =
- Function_Node
- (Variable_Declaration var_id var_type var_init)
- ret_type
- body ->
- env' = env_extend var_id var_type arg_val empty_env ->
- next_cont = Exit_Sk ret_cont null_val ->
- value_of_type null_val (mk_interface nil nil) None ->
- step (Value_Passing_Configuration
- (Expression_Continuation
- (Invocation_Ek rcvr_val name env ret_cont)
- arg_type)
- arg_val)
- (Exec_Configuration body env' ret_cont next_cont)
-
- (** <PropertyGet(rcvr, name), ρ, κE>eval ==>
- <rcvr, ρ, PropertyGetEK(name, κE)>eval *)
- | Eval_Property_Get :
- forall rcvr_expr rcvr_type name env ret_cont,
- expression_type CE (env_to_type_env env) rcvr_expr = Some rcvr_type ->
- step (Eval_Configuration
- (E_Property_Get (Property_Get rcvr_expr (Name name)))
- env ret_cont)
- (Eval_Configuration
- rcvr_expr env
- (Expression_Continuation
- (Property_Get_Ek name ret_cont)
- rcvr_type))
-
- (** <PropertyGetEK(name, κE), rcvrVal)pass ==> <κE, f>pass,
- where f = methods(class(rcvrVal))(name) *)
- | Pass_Property_Get_Ek :
- forall rcvr_val rcvr_intf rcvr_type_opt expected_rcvr_type
- name memb_id ret_type
- ret_val ret_intf
- ret_cont,
- value_of_type rcvr_val rcvr_intf rcvr_type_opt ->
- List.In (mk_getter_desc name memb_id ret_type) (getters rcvr_intf) ->
- value_of_type ret_val ret_intf (Some ret_type) ->
- step (Value_Passing_Configuration
- (Expression_Continuation
- (Property_Get_Ek name ret_cont)
- expected_rcvr_type)
- rcvr_val)
- (Value_Passing_Configuration
- ret_cont ret_val)
-
- (** <ExitSK(κE, val), ρ>forward ==> <κE, val>pass *)
- | Forward_Exit_Sk :
- forall ret_cont val env,
- step (Forward_Configuration (Exit_Sk ret_cont val) env)
- (Value_Passing_Configuration ret_cont val)
-
- (** <ConstructorInvocation(cls), ρ, κE>eval ==> <κE, newVal>pass,
- where newVal = new runtime value of syntactic type cls *)
- | Eval_Constructor_Invocation :
- forall env ret_cont new_val intf type_opt class_id,
- NatMap.MapsTo class_id intf CE ->
- value_of_type new_val intf type_opt ->
- step (Eval_Configuration
- (E_Invocation_Expression (IE_Constructor_Invocation
- (Constructor_Invocation class_id)))
- env ret_cont)
- (Value_Passing_Configuration ret_cont new_val)
-
- (** <VariableDeclaration(var, type, NONE), ρ, κE, κS>exec ==>
- <κS, ρ'>forward,
- where ρ' = ρ#[#var = nullVal#]# *)
- | Exec_Variable_Declaration_Non_Init :
- forall var type env ret_cont next_cont null_val env',
- value_of_type null_val (mk_interface nil nil) None ->
- env' = env_extend var type null_val env ->
- step (Exec_Configuration
- (S_Variable_Declaration (Variable_Declaration var type None))
- env ret_cont next_cont)
- (Forward_Configuration next_cont env')
-
- (** <VariableDeclaration(var, type, expr), ρ, κE, κS>exec ==>
- <expr, ρ, VarDeclarationEK(var, ρ, κS)>eval *)
- | Exec_Variable_Declaration_Init :
- forall var var_type init_type expr env ret_cont next_cont,
- expression_type CE (env_to_type_env env) expr = Some init_type ->
- step (Exec_Configuration
- (S_Variable_Declaration
- (Variable_Declaration var var_type (Some expr)))
- env ret_cont next_cont)
- (Eval_Configuration expr env
- (Expression_Continuation
- (Var_Declaration_Ek var var_type env next_cont)
- init_type))
-
- (** <VarDeclarationEK(var, ρ, κS), val>pass ==> <κS, ρ'>forward,
- where ρ' = ρ#[#var = val#]# *)
- | Pass_Var_Declaration_Ek :
- forall var var_type init_type env next_cont val env',
- env' = env_extend var var_type val env ->
- step (Value_Passing_Configuration
- (Expression_Continuation
- (Var_Declaration_Ek var var_type env next_cont)
- init_type)
- val)
- (Forward_Configuration next_cont env')
-
- (** <ExpressionEK(ρ, κE, κS), val>pass ==> <κS, ρ>forward *)
- | Pass_Expression_Ek :
- forall env ret_cont next_cont val val_type,
- step (Value_Passing_Configuration
- (Expression_Continuation
- (Expression_Ek env ret_cont next_cont)
- val_type)
- val)
- (Forward_Configuration next_cont env)
-
- (** <MethodInvocationEK(name, arg, ρ, κE), null)pass ==>
- <HaltEK, null>pass *)
- | Pass_Method_Invocation_Ek_Null :
- forall name arg_expr arg_type env ret_cont expected_rcvr_type,
- step (Value_Passing_Configuration
- (Expression_Continuation
- (Method_Invocation_Ek name arg_expr env ret_cont)
- expected_rcvr_type)
- (mk_runtime_value None))
- (Value_Passing_Configuration
- (Expression_Continuation
- Halt_Ek
- arg_type)
- (mk_runtime_value None))
-
- (** <PropertyGetEK(name, κE), null)pass ==> <HaltEK, null>pass *)
- | Pass_Property_Get_Ek_Null :
- forall name ret_cont expected_rcvr_type,
- step (Value_Passing_Configuration
- (Expression_Continuation
- (Property_Get_Ek name ret_cont)
- expected_rcvr_type)
- (mk_runtime_value None))
- (Value_Passing_Configuration
- (Expression_Continuation
- Halt_Ek
- expected_rcvr_type)
- (mk_runtime_value None)).
-
-(* TODO(dmitryas): Add transitions to final states. *)
-
-
-(** Well-formedness property over configurations is understood as the property
- of being a valid l.h.s. to the [step] relation. The abstract machine may or
- may not end up in a well-formed configuration several steps after its
- configuration was well-formed. *)
-Inductive configuration_wf : configuration -> Prop :=
-
- (** Well-formed variable-gets should have the variable in the environment. *)
- | Eval_Variable_Get_Configuration_Wf :
- forall var env ret_cont,
- env_in var env ->
- configuration_wf
- (Eval_Configuration
- (E_Variable_Get (Variable_Get var))
- env ret_cont)
-
- (** Configurations that are the beginning of a method-invocation evaluation
- are well-formed if the expression that represents the receiver is
- well-typed, because the machine proceed to evaluation of the receiver, and
- the continuation that awaits for the receiver value should be typed. *)
- | Eval_Method_Invocation_Configuration_Wf :
- forall rcvr_expr rcvr_type name arg_expr ref env ret_cont,
- expression_type CE (env_to_type_env env) rcvr_expr = Some rcvr_type ->
- configuration_wf
- (Eval_Configuration
- (E_Invocation_Expression (IE_Method_Invocation
- (Method_Invocation rcvr_expr (Name name) (Arguments arg_expr) ref)))
- env ret_cont)
-
- (** Configurations that are the beginning of a property-get evaluation are
- well-formed if the receiver expression is well-typed, because the machine
- always proceed to evaluation of the receiver, and the continuation that
- awaits for the receiver value should be typed. *)
- | Eval_Property_Get_Configuration_Wf :
- forall rcvr_expr rcvr_type name env ret_cont,
- expression_type CE (env_to_type_env env) rcvr_expr = Some rcvr_type ->
- configuration_wf
- (Eval_Configuration
- (E_Property_Get (Property_Get rcvr_expr (Name name)))
- env ret_cont)
-
- (** A constructor invocation is well-formed if the referred class exists in
- the class environment. *)
- | Eval_Constructor_Invocation_Configuration_Wf :
- forall class_id env ret_cont,
- NatMap.In class_id CE ->
- configuration_wf
- (Eval_Configuration
- (E_Invocation_Expression (IE_Constructor_Invocation
- (Constructor_Invocation class_id)))
- env ret_cont)
-
- (** TODO(dmitryas): Write descriptive comment here. *)
- | Exec_Variable_Declaration_Init_Wf :
- forall var var_type init_expr init_type env ret_cont next_cont,
- expression_type CE (env_to_type_env env) init_expr = Some init_type ->
- configuration_wf
- (Exec_Configuration
- (S_Variable_Declaration
- (Variable_Declaration var var_type (Some init_expr)))
- env ret_cont next_cont)
-
- (** TODO(dmitryas): Write descriptive comment here. *)
- | Exec_Variable_Declaration_Non_Init_Wf :
- forall var var_type env ret_cont next_cont,
- configuration_wf
- (Exec_Configuration
- (S_Variable_Declaration
- (Variable_Declaration var var_type None))
- env ret_cont next_cont)
-
- (** TODO(dmitryas): Write descriptive comment here. *)
- | Exec_Return_Statement_Wf :
- forall expr env ret_cont next_cont,
- configuration_wf
- (Exec_Configuration
- (S_Return_Statement (Return_Statement expr))
- env ret_cont next_cont)
-
- (** TODO(dmitryas): Write descriptive comment here. *)
- | Exec_Expression_Statement_Wf :
- forall expr expr_type env ret_cont next_cont,
- expression_type CE (env_to_type_env env) expr = Some expr_type ->
- configuration_wf
- (Exec_Configuration
- (S_Expression_Statement (Expression_Statement expr))
- env ret_cont next_cont)
-
- (** TODO(dmitryas): Write descriptive comment here. *)
- | Exec_Block_Wf :
- forall stmts env ret_cont next_cont,
- configuration_wf
- (Exec_Configuration (S_Block (Block stmts)) env ret_cont next_cont)
-
- (** These configurations pass the receiver to the continuation that is the
- rest of the method invocation. These configurations are well-formed if the
- argument expression is well-typed, because the machine procedes to the
- evaluation of the argument, and the expression continuation that awaits for
- the argument value needs to be typed. *)
- | Pass_Method_Invocation_Ek_Non_Null_Configuration_Wf :
- forall name arg_expr arg_type env ret_cont
- expected_rcvr_type rcvr_type rcvr_val,
- runtime_type rcvr_val = Some rcvr_type ->
- expression_type CE (env_to_type_env env) arg_expr = Some arg_type ->
- configuration_wf
- (Value_Passing_Configuration
- (Expression_Continuation
- (Method_Invocation_Ek name arg_expr env ret_cont)
- expected_rcvr_type)
- rcvr_val)
-
- (** These configurations pass the evaluated argument to the rest of the
- method invocation. The precondition is that the method with such name
- exists. *)
- | Pass_Invocation_Ek_Configuration_Wf :
- forall rcvr_val name ret_cont arg_val arg_type env,
- method_exists (runtime_type rcvr_val) name ->
- configuration_wf
- (Value_Passing_Configuration
- (Expression_Continuation
- (Invocation_Ek rcvr_val name env ret_cont)
- arg_type)
- arg_val)
-
- (** These configurations pass the evaluated receiver to the rest of the
- property get. The preconditions is that the getter with such name
- exists. *)
- | Pass_Property_Get_Ek_Non_Null_Configuration_Wf :
- forall name ret_cont expected_rcvr_type rcvr_type rcvr_val,
- runtime_type rcvr_val = Some rcvr_type ->
- getter_exists (runtime_type rcvr_val) name ->
- configuration_wf
- (Value_Passing_Configuration
- (Expression_Continuation
- (Property_Get_Ek name ret_cont)
- expected_rcvr_type)
- rcvr_val)
-
- (** In the currently formalized subset of Kernel all forward configurations
- are well-formed. The machine either proceeds to the execution of a
- a statement or proceeds to the next continuation. *)
- | Forward_Configuration_Wf :
- forall next_cont env,
- configuration_wf (Forward_Configuration next_cont env)
-
- (** TODO(dmitryas): Write descriptive comments. *)
- | Pass_Expression_Ek_Configuration_Wf :
- forall env ret_cont next_cont val val_type,
- configuration_wf
- (Value_Passing_Configuration
- (Expression_Continuation
- (Expression_Ek env ret_cont next_cont)
- val_type)
- val)
-
- (** TODO(dmitryas): Write descriptive comments. *)
- | Pass_Var_Declaration_Ek_Configuration_Wf :
- forall var var_type env next_cont init_type val,
- configuration_wf
- (Value_Passing_Configuration
- (Expression_Continuation
- (Var_Declaration_Ek var var_type env next_cont)
- init_type)
- val)
-
- (** Invoking a method on `null` always puts the abstract machine in a final
- state, so passing `null` to MethodInvocationEK is always well-formed. *)
- | Pass_Method_Invocation_Ek_Null_Configuration_Wf :
- forall name arg_expr env ret_cont rcvr_type rcvr_val,
- runtime_type rcvr_val = None ->
- configuration_wf
- (Value_Passing_Configuration
- (Expression_Continuation
- (Method_Invocation_Ek name arg_expr env ret_cont)
- rcvr_type)
- rcvr_val)
-
- (** Getting a property of `null` always puts the abstract machine in a final
- state, so passing `null` to propertyGetEK is always well-formed. *)
- | Pass_Property_Get_Ek_Null_Configuration_Wf :
- forall name ret_cont rcvr_type rcvr_val,
- runtime_type rcvr_val = None ->
- configuration_wf
- (Value_Passing_Configuration
- (Expression_Continuation (Property_Get_Ek name ret_cont) rcvr_type)
- rcvr_val).
-
-
-Inductive configuration_final : configuration -> Prop :=
-
- | Configuration_Final :
- forall val ret_type,
- configuration_final
- (Value_Passing_Configuration
- (Expression_Continuation Halt_Ek ret_type)
- val).
-
-
-Inductive ref_in_dart_type : nat -> dart_type -> Prop :=
-
- | RDT_Interface_Type :
- forall ref,
- ref_in_dart_type ref (DT_Interface_Type (Interface_Type ref))
-
- | RDT_Function_Type :
- forall ref param_type ret_type,
- (ref_in_dart_type ref param_type \/
- ref_in_dart_type ref ret_type) ->
- ref_in_dart_type ref (DT_Function_Type
- (Function_Type param_type ret_type)).
-
-
-Inductive dart_type_valid : option dart_type -> Prop :=
-
- | DTV_Null :
- dart_type_valid None
-
- | DTV_Non_Null :
- forall class_id type,
- ref_in_dart_type class_id type ->
- NatMap.In class_id CE ->
- dart_type_valid (Some type).
-
-
-Inductive runtime_value_valid (val : runtime_value) : Prop :=
-
- | RTV_Not_Null :
- forall intf type,
- (runtime_type val) = Some type ->
- dart_type_valid (Some type) ->
- value_of_type val intf (runtime_type val) ->
- runtime_value_valid val
-
- | RTV_Null :
- value_of_type val (mk_interface nil nil) None ->
- runtime_value_valid val.
-
-
-(** [expression_wf] is a well-formedness condition for expression w.r.t. the
- class and member environments. It requires that all class and member
- references in the expression are present in [CE] and [ME] respectively. *)
-Inductive expression_wf : expression -> Prop :=
-
- | EXPWF_Variable_Get :
- forall var_get_expr,
- expression_wf (E_Variable_Get var_get_expr)
-
- | EXPWF_Property_Get :
- forall rcvr_expr name,
- expression_wf rcvr_expr ->
- expression_wf (E_Property_Get (Property_Get rcvr_expr name))
-
- | EXPWF_Method_Invocation :
- (* TODO(dmitryas): Remove [ref] when the corresponding element is removed
- from the AST. *)
- forall rcvr_expr name arg_expr ref,
- expression_wf rcvr_expr ->
- expression_wf arg_expr ->
- expression_wf (E_Invocation_Expression (IE_Method_Invocation
- (Method_Invocation rcvr_expr name (Arguments arg_expr) ref)))
-
- | EXPWF_Constructor_Invocation :
- forall ref,
- NatMap.In ref CE ->
- expression_wf (E_Invocation_Expression (IE_Constructor_Invocation
- (Constructor_Invocation ref))).
-
-
-(** [statement_wf] is a property that is analogous to [expression_wf], but is
- defined for statements. *)
-Inductive statement_wf : statement -> Prop :=
-
- | STWF_Expression_Statement :
- forall expr,
- expression_wf expr ->
- statement_wf (S_Expression_Statement (Expression_Statement expr))
-
- | STWF_Block_Empty :
- statement_wf (S_Block (Block nil))
-
- | STWF_Block_Non_Empty :
- forall stmt stmts,
- statement_wf stmt ->
- statement_wf (S_Block (Block stmts)) ->
- statement_wf (S_Block (Block (stmt :: stmts)))
-
- | STWF_Return_Statement :
- forall expr,
- expression_wf expr ->
- statement_wf (S_Return_Statement (Return_Statement expr))
-
- | STWF_Variable_Declaration_Non_Init :
- forall var_id type,
- (forall class_id,
- ref_in_dart_type class_id type -> NatMap.In class_id CE) ->
- statement_wf (S_Variable_Declaration
- (Variable_Declaration var_id type None))
-
- | STWF_Variable_Declaration_Init :
- forall var_id type init_expr,
- dart_type_valid (Some type) ->
- expression_wf init_expr ->
- statement_wf (S_Variable_Declaration
- (Variable_Declaration var_id type (Some init_expr))).
-
-
-(** [environment_valid] is a property of environment validity with respect
- to the class and method environments. For each variable in the environment
- there should be a valid interface, so that [value_of_type] predicate for the
- variable is true. *)
-Inductive environment_valid : environment -> Prop :=
-
- | EV_Empty :
- environment_valid nil
-
- | EV_Non_Empty_Null :
- forall entry env,
- dart_type_valid (Some (var_type entry)) ->
- (runtime_type (value entry)) = None ->
- environment_valid env ->
- environment_valid (entry :: env)
-
- | EV_Non_Empty_Non_Null :
- forall entry env,
- dart_type_valid (Some (var_type entry)) ->
- (runtime_type (value entry)) = Some (var_type entry) ->
- environment_valid env ->
- environment_valid (entry :: env).
-
-
-(** The given syntactic type is accepted by the given expression continuation.
-
- None is accepted as the second argument, because runtime type of values can
- be checkec agains the expression continuation. *)
-Inductive econt_accepts :
- expression_continuation -> option dart_type -> Prop :=
-
- | EA_Null :
- forall econt,
- econt_accepts econt None
-
- | EA_Non_Null :
- forall cont expected_type type,
- type <: expected_type ->
- econt_accepts
- (Expression_Continuation cont expected_type)
- (Some type).
-
-
-(** The syntactic type of the expression matches the syntactic type of the
- value expected by the expression continuation. *)
-Inductive econt_accepts_expr :
- expression_continuation -> expression -> environment -> Prop :=
-
- | Econt_Accepts_Expr :
- forall econt expr env expr_type,
- expression_type CE (env_to_type_env env) expr = Some expr_type ->
- econt_accepts econt (Some expr_type) ->
- econt_accepts_expr econt expr env.
-
-
-(** The syntactic type returned by the statement (if any) matches the syntactic
- type of the value expected by the expression continuation. *)
-Inductive econt_accepts_stmt :
- expression_continuation -> statement -> environment -> Prop :=
-
- | Econt_Accepts_Stmt :
- forall econt stmt env ret_type te,
- statement_type CE (env_to_type_env env) stmt ret_type = Some te ->
- econt_accepts econt (Some ret_type) ->
- econt_accepts_stmt econt stmt env.
-
-
-(** The syntactic type of the value matches the syntactic type of the value
- expected by the expression continuation. *)
-Definition econt_accepts_val :
- expression_continuation -> runtime_value -> Prop :=
- fun econt val => econt_accepts econt (runtime_type val).
-
-
-(** Each free variable referenced from the expression is present in the
- environment. *)
-Inductive eval_environment_sufficient : environment -> expression -> Prop :=
-
- | EES_Variable_Get :
- forall var env,
- env_in var env ->
- eval_environment_sufficient env (E_Variable_Get (Variable_Get var))
-
- | EES_Property_Get :
- forall expr name env,
- eval_environment_sufficient env expr ->
- eval_environment_sufficient env (E_Property_Get (Property_Get expr name))
-
- | EES_Constructor_Invocation :
- forall class_id env,
- eval_environment_sufficient
- env
- (E_Invocation_Expression
- (IE_Constructor_Invocation
- (Constructor_Invocation class_id)))
-
- | EES_Method_Invocation :
- (* TODO(dmitryas): Remove ref when it's removed from the AST. *)
- forall rcvr_expr arg_expr name ref env,
- eval_environment_sufficient env rcvr_expr ->
- eval_environment_sufficient env arg_expr ->
- eval_environment_sufficient
- env
- (E_Invocation_Expression
- (IE_Method_Invocation
- (Method_Invocation rcvr_expr name (Arguments arg_expr) ref))).
-
-
-(** [exec_environment_sufficient] represents the property of the environment
- w.r.t. the given statement. The property shows if the given environment is
- sufficient to evaluate all expressions in the given statement. *)
-Inductive exec_environment_sufficient : environment -> statement -> Prop :=
-
- | EES_Expression_Statement :
- forall env expr,
- eval_environment_sufficient env expr ->
- exec_environment_sufficient
- env
- (S_Expression_Statement (Expression_Statement expr))
-
- | EES_Block_Empty :
- forall env,
- exec_environment_sufficient env (S_Block (Block nil))
-
- | EES_Block_Non_Empty :
- forall env stmt stmts,
- exec_environment_sufficient env stmt ->
- exec_environment_sufficient env (S_Block (Block stmts)) ->
- exec_environment_sufficient env (S_Block (Block (stmt :: stmts)))
-
- | EES_Return_Statement :
- forall env expr,
- eval_environment_sufficient env expr ->
- exec_environment_sufficient
- env
- (S_Return_Statement (Return_Statement expr))
-
- | EES_Variable_Declaration_Non_Init :
- forall env var type,
- exec_environment_sufficient
- env
- (S_Variable_Declaration (Variable_Declaration var type None))
-
- | EES_Variable_Declaration_Init :
- forall env var type init_expr,
- eval_environment_sufficient env init_expr ->
- exec_environment_sufficient
- env
- (S_Variable_Declaration
- (Variable_Declaration var type (Some init_expr))).
-
-
-(** Validity property for expression continuations [econt_valid] and statement
- continuations [scont_valid] is mutually inductive, because instances of one
- may refer to instances of the other. *)
-Inductive econt_valid : expression_continuation -> Prop :=
-
- | CV_Expression_Ek :
- forall expr_type env ret_cont next_cont,
- environment_valid env ->
- econt_valid ret_cont ->
- scont_valid next_cont ->
- dart_type_valid (Some expr_type) ->
- econt_valid
- (Expression_Continuation
- (Expression_Ek env ret_cont next_cont)
- expr_type)
-
- | CV_Method_Invocation_Ek :
- forall rcvr_type name arg_exp arg_type ret_type env ret_cont,
- environment_valid env ->
- dart_type_valid (Some rcvr_type) ->
- method_accepts (Some rcvr_type) name (Some arg_type) ->
- method_returns (Some rcvr_type) name ret_type ->
- expression_wf arg_exp ->
- eval_environment_sufficient env arg_exp ->
- expression_type CE (env_to_type_env env) arg_exp = Some arg_type ->
- dart_type_valid (Some arg_type) ->
- econt_valid ret_cont ->
- dart_type_valid (Some ret_type) ->
- econt_accepts ret_cont (Some ret_type) ->
- econt_valid
- (Expression_Continuation
- (Method_Invocation_Ek name arg_exp env ret_cont)
- rcvr_type)
-
- | CV_Invocation_Ek :
- forall rcvr_val name env ret_cont arg_type ret_type,
- environment_valid env ->
- runtime_value_valid rcvr_val ->
- method_accepts (runtime_type rcvr_val) name (Some arg_type) ->
- method_returns (runtime_type rcvr_val) name ret_type ->
- dart_type_valid (Some arg_type) ->
- econt_valid ret_cont ->
- dart_type_valid (Some ret_type) ->
- econt_accepts ret_cont (Some ret_type) ->
- econt_valid
- (Expression_Continuation
- (Invocation_Ek rcvr_val name env ret_cont)
- arg_type)
-
- | CV_Property_Get_Ek :
- forall name ret_cont rcvr_type ret_type,
- dart_type_valid (Some rcvr_type) ->
- getter_returns (Some rcvr_type) name ret_type ->
- econt_valid ret_cont ->
- dart_type_valid (Some ret_type) ->
- econt_accepts ret_cont (Some ret_type) ->
- econt_valid
- (Expression_Continuation
- (Property_Get_Ek name ret_cont)
- rcvr_type)
-
- | CV_Var_Declaration_Ek :
- forall var var_type env next_cont init_type,
- environment_valid env ->
- dart_type_valid (Some var_type) ->
- dart_type_valid (Some init_type) ->
- init_type <: var_type ->
- scont_valid next_cont ->
- econt_valid
- (Expression_Continuation
- (Var_Declaration_Ek var var_type env next_cont)
- init_type)
-
-with scont_valid : statement_continuation -> Prop :=
-
- | CV_Exit_Sk :
- forall ret_cont val,
- econt_valid ret_cont ->
- runtime_value_valid val ->
- econt_accepts_val ret_cont val ->
- scont_valid (Exit_Sk ret_cont val)
-
- | CV_Block_Sk_Empty :
- forall env ret_cont next_cont,
- environment_valid env ->
- econt_valid ret_cont ->
- scont_valid next_cont ->
- scont_valid (Block_Sk nil env ret_cont next_cont)
-
- | CV_Block_Sk_Expression_Statement :
- forall stmt expr expr_type stmts env ret_cont next_cont,
- environment_valid env ->
- stmt = S_Expression_Statement (Expression_Statement expr) ->
- statement_wf stmt ->
- expression_type CE (env_to_type_env env) expr = Some expr_type ->
- scont_valid (Block_Sk stmts env ret_cont next_cont) ->
- econt_valid ret_cont ->
- scont_valid next_cont ->
- scont_valid (Block_Sk (stmt :: stmts) env ret_cont next_cont)
-
- | CV_Block_Sk_Block :
- forall stmt block_stmts stmts env ret_cont next_cont,
- environment_valid env ->
- stmt = S_Block (Block block_stmts) ->
- statement_wf stmt ->
- scont_valid (Block_Sk stmts env ret_cont next_cont) ->
- scont_valid
- (Block_Sk block_stmts env ret_cont
- (Block_Sk stmts env ret_cont next_cont)) ->
- econt_valid ret_cont ->
- scont_valid next_cont ->
- scont_valid (Block_Sk (stmt :: stmts) env ret_cont next_cont)
-
- | CV_Block_Sk_Return_Statement :
- forall stmt expr expr_type stmts env ret_cont next_cont,
- environment_valid env ->
- stmt = S_Return_Statement (Return_Statement expr) ->
- statement_wf stmt ->
- expression_type CE (env_to_type_env env) expr = Some expr_type ->
- dart_type_valid (Some expr_type) ->
- econt_valid ret_cont ->
- econt_accepts ret_cont (Some expr_type) ->
- (* TODO(dmitryas): Do we really need the validity of the dead code? *)
- scont_valid (Block_Sk stmts env ret_cont next_cont) ->
- scont_valid next_cont ->
- scont_valid (Block_Sk (stmt :: stmts) env ret_cont next_cont)
-
- | CV_Block_Sk_Variable_Declaration_Init :
- forall stmt var var_type init_expr init_expr_type
- stmts env env' ret_cont next_cont,
- environment_valid env ->
- stmt = S_Variable_Declaration
- (Variable_Declaration var var_type (Some init_expr)) ->
- statement_wf stmt ->
- expression_type CE (env_to_type_env env) init_expr = Some init_expr_type ->
- init_expr_type <: var_type ->
- env' = env_extend var var_type (mk_runtime_value (Some var_type)) env ->
- scont_valid (Block_Sk stmts env' ret_cont next_cont) ->
- econt_valid ret_cont ->
- scont_valid next_cont ->
- scont_valid (Block_Sk (stmt :: stmts) env ret_cont next_cont)
-
- | CV_Block_Sk_Variable_Declaration_Non_Init :
- forall stmt var var_type stmts env env' ret_cont next_cont,
- environment_valid env ->
- stmt = S_Variable_Declaration
- (Variable_Declaration var var_type None) ->
- statement_wf stmt ->
- env' = env_extend var var_type (mk_runtime_value None) env ->
- scont_valid (Block_Sk stmts env' ret_cont next_cont) ->
- econt_valid ret_cont ->
- scont_valid next_cont ->
- scont_valid (Block_Sk (stmt :: stmts) env ret_cont next_cont).
-
-
-Inductive configuration_valid : configuration -> Prop :=
-
- | Eval_Configuration_Valid :
- forall exp env cont,
- expression_wf exp ->
- environment_valid env ->
- econt_valid cont ->
- eval_environment_sufficient env exp ->
- econt_accepts_expr cont exp env ->
- configuration_valid (Eval_Configuration exp env cont)
-
- | Exec_Configuration_Valid :
- forall stmt env ret_cont next_cont,
- statement_wf stmt ->
- environment_valid env ->
- econt_valid ret_cont ->
- scont_valid next_cont ->
- exec_environment_sufficient env stmt ->
- econt_accepts_stmt ret_cont stmt env ->
- configuration_valid (Exec_Configuration stmt env ret_cont next_cont)
-
- | Value_Passing_Configuration_Valid :
- forall cont val,
- econt_valid cont ->
- runtime_value_valid val ->
- econt_accepts_val cont val ->
- configuration_valid (Value_Passing_Configuration cont val)
-
- | Forward_Configuration_Valid :
- forall cont env,
- scont_valid cont ->
- environment_valid env ->
- configuration_valid (Forward_Configuration cont env).
-
-
-Inductive steps : configuration -> configuration -> Prop :=
-
- | steps_zero :
- forall conf,
- steps conf conf
-
- | steps_trans_right :
- forall conf1 conf2 conf3,
- steps conf1 conf2 ->
- step conf2 conf3 ->
- steps conf1 conf3.
-
-
-End OperationalSemantics.
diff --git a/pkg/kernel/coq/OperationalSemanticsProof.v b/pkg/kernel/coq/OperationalSemanticsProof.v
deleted file mode 100644
index 5cbbb77..0000000
--- a/pkg/kernel/coq/OperationalSemanticsProof.v
+++ /dev/null
@@ -1,717 +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. *)
-
-
-Require Import Coq.Lists.SetoidList.
-Require Import Coq.Init.Wf.
-Require Import Omega.
-
-Require Import Common.
-Require Import Syntax.
-Require Import ObjectModel.
-Require Import OperationalSemantics.
-
-Import Common.NatMapFacts.
-Import Common.MoreNatMapFacts.
-Import ObjectModel.Subtyping.
-
-
-Section OperationalSemanticsSpec.
-
-
-(** The well-formedness hypothesis is that the environments are built via
- [lib_to_env] function from the object model module. [program_wf] theorem
- defined there provides the rest of the well-formedness properties. *)
-Variable L : library.
-Variable CE : class_env.
-Variable ME : member_env.
-
-Hypothesis program_wf_hyp: lib_to_env L = (CE, ME).
-
-
-(** Auxiliary well-formedness hypothesis that should be a corollary of
- [program_wf_hyp], but requires additional facts about the object model to be
- proven. *)
-Inductive ref_in_intf : nat -> interface -> Prop :=
-
- | RI_Method :
- forall ref proc_desc intf,
- List.In proc_desc (procedures intf) ->
- ref_in_dart_type ref (DT_Function_Type (pr_type proc_desc)) ->
- ref_in_intf ref intf
-
- | RI_Getter :
- forall ref get_desc intf,
- List.In get_desc (getters intf) ->
- ref_in_dart_type ref (gt_type get_desc) ->
- ref_in_intf ref intf.
-
-Hypothesis intf_refs_wf:
- forall class_id intf ref,
- NatMap.MapsTo class_id intf CE ->
- ref_in_intf ref intf ->
- NatMap.In ref CE.
-
-
-(** Yet another hypothesis about well-formedness of getters. *)
-Hypothesis program_getters_wf:
- forall class_id intf get_desc,
- NatMap.MapsTo class_id intf CE ->
- List.In get_desc (getters intf) ->
- NatMap.In (gt_ref get_desc) ME.
-
-
-Lemma runtime_value_interface_procedures_wf :
- forall val intf type_opt proc_desc,
- value_of_type CE ME val intf type_opt ->
- List.In proc_desc (procedures intf) ->
- NatMap.In (pr_ref proc_desc) ME.
-Proof.
- intros. destruct H.
-
- (* Case 1. Value of Interface Type. *)
- pose proof (program_wf L CE ME class_id intf proc_desc program_wf_hyp).
- apply H3.
- apply NatMapFacts.find_mapsto_iff. auto.
- auto.
-
- (* Case 2. Value of Function Type. *)
- rewrite H in H0.
- pose proof (List.in_inv H0).
- destruct H4.
- rewrite <- H4. simpl. apply MoreNatMapFacts.maps_in_mapsto.
- apply MoreNatMapFacts.maps_mapsto_in. exists (M_Procedure proc).
- auto.
- pose proof (List.in_nil H4). contradiction.
-
- (* Case 3. Null Value. *)
- rewrite H in H0. pose proof (List.in_nil H0). contradiction.
-Qed.
-
-
-Lemma method_exists_desc :
- forall type name,
- method_exists CE ME type name ->
- (* TODO(dmitryas): Replace `value_of_type` here with a relation that binds
- together the interface and the type, avoiding the construction of the
- value. *)
- exists intf desc,
- (value_of_type CE ME (mk_runtime_value type) intf type /\
- List.In desc (procedures intf) /\
- ((pr_name desc) = name)%string).
-Proof.
- intros. destruct H; (
-
- (* Cases of Interface Type and Function Type are analogous. *)
- exists intf, desc; split; auto
-
- ).
-Qed.
-
-
-Lemma subtype_means_equals :
- forall type_pair, subtype type_pair = true -> fst type_pair = snd type_pair.
-Proof.
- intro.
- apply well_founded_ind with (R := pair_size_order) (a := type_pair).
- apply pair_size_order_wf.
- intros.
-
- assert ((fst x) <: (snd x)).
- destruct x. simpl. auto.
- destruct (fst x) eqn:?. destruct (snd x) eqn:?.
- (* t1 : Interface Type, t2 : Interface Type. *)
- simplify_subtypes.
- apply N.eqb_eq in H1. rewrite H1. reflexivity.
- (* t1 : Interface Type, t2 : Function Type. *)
- simplify_subtypes.
- destruct (snd x) eqn :?.
- (* t1 : Function Type, t2 : Interface Type. *)
- simplify_subtypes.
- (* t1 : Function Type, t2 : Function Type. *)
- simplify_subtypes.
- apply andb_true_iff in H1. destruct H1.
- assert (d = d1).
- apply H with (y := (d, d1)).
- unfold pair_size_order. destruct x.
- simpl in Heqd. simpl in Heqd0. rewrite Heqd, Heqd0.
- unfold pair_size. simpl.
- omega.
- auto.
- assert (d2 = d0).
- apply H with (y := (d2, d0)).
- unfold pair_size_order. destruct x.
- simpl in Heqd. simpl in Heqd0. rewrite Heqd, Heqd0.
- unfold pair_size. simpl.
- omega.
- auto.
- rewrite H3, H4.
- reflexivity.
-Qed.
-
-
-Lemma structural_subtype_methods :
- forall type1 type2 name,
- method_exists CE ME (Some type1) name ->
- type2 <: type1 ->
- method_exists CE ME (Some type2) name.
-Proof.
- intros.
- apply subtype_means_equals in H0. simpl in H0. rewrite H0. auto.
-Qed.
-
-
-Lemma structural_subtype_getters :
- forall type1 type2 name,
- getter_exists CE ME (Some type1) name ->
- type2 <: type1 ->
- getter_exists CE ME (Some type2) name.
-Proof.
- intros.
- apply subtype_means_equals in H0. simpl in H0. rewrite H0. auto.
-Qed.
-
-
-Theorem step_configuration_wf :
- forall conf1, configuration_wf CE ME conf1 ->
- exists conf2, step CE ME conf1 conf2.
-Proof.
- intros.
-
- (* Construct the second configuration from the preconditions of
- well-formedness of the first configuration. *)
- destruct H.
-
- (* Case 1. Eval Variable Get. *)
- unfold env_in in H.
- destruct (
- List.find
- (fun entry : env_entry => Nat.eqb var (var_ref entry))
- env
- ) eqn:?; try contradiction.
- exists (Value_Passing_Configuration ret_cont (value e)).
- constructor.
- unfold env_get. auto.
-
- (* Case 2. Eval Method Invocation. *)
- exists
- (Eval_Configuration rcvr_expr env
- (Expression_Continuation
- (Method_Invocation_Ek name arg_expr env ret_cont)
- rcvr_type)).
- constructor. auto.
-
- (* Case 3. Eval Property Get. *)
- exists
- (Eval_Configuration rcvr_expr env
- (Expression_Continuation
- (Property_Get_Ek name ret_cont)
- rcvr_type)).
- constructor. auto.
-
- (* Case 4. Eval Constructor Invocation. *)
- pose proof (MoreNatMapFacts.maps_in_mapsto interface CE class_id H).
- destruct H0 as (intf & H1).
- set (type := DT_Interface_Type (Interface_Type class_id)).
- set (new_val := mk_runtime_value (Some type)).
- exists (Value_Passing_Configuration ret_cont new_val).
- constructor 14 with (intf := intf) (type_opt := Some type); try auto.
- constructor 1 with (class_id := class_id); try (simpl; auto).
- apply NatMapFacts.find_mapsto_iff. auto.
-
- (* Case 6. Exec Variable Declaration with Initializer. *)
- exists
- (Eval_Configuration init_expr env
- (Expression_Continuation
- (Var_Declaration_Ek var var_type env next_cont)
- init_type)).
- constructor. auto.
-
- (* Case 7. Exec Variable Declaration without Initializer. *)
- set (null_val := mk_runtime_value None).
- set (env' := env_extend var var_type null_val env).
- exists (Forward_Configuration next_cont env').
- constructor 15 with (null_val := null_val).
- constructor 3. simpl. congruence.
- simpl. congruence.
- trivial. trivial.
-
- (* Case 8. Exec Return Statement. *)
- exists (Eval_Configuration expr env ret_cont).
- constructor.
-
- (* Case 9. Exec Expression Statement. *)
- exists
- (Eval_Configuration expr env
- (Expression_Continuation
- (Expression_Ek env ret_cont next_cont)
- expr_type)).
- constructor. auto.
-
- (* Case 10. Exec Block. *)
- destruct stmts eqn:?.
-
- (* Case 10.1. Exec Empty Block. *)
- exists (Forward_Configuration next_cont env).
- constructor.
-
- (* Case 10.2. Exec Non-Empty Block. *)
- exists (Exec_Configuration s env ret_cont
- (Block_Sk l env ret_cont next_cont)).
- constructor.
-
- (* Case 11. Pass Value to MethodInvocationEK. *)
- exists
- (Eval_Configuration arg_expr env
- (Expression_Continuation
- (Invocation_Ek rcvr_val name env ret_cont)
- arg_type)).
- constructor 9 with (rcvr_type := rcvr_type). auto. auto.
-
- (* Case 12. Pass Value to InvocationEK. *)
- pose proof (method_exists_desc (runtime_type rcvr_val) name H).
- destruct H0 as (intf & desc & H1). destruct H1. destruct H1.
- pose proof
- (runtime_value_interface_procedures_wf
- (mk_runtime_value (runtime_type rcvr_val))
- intf (runtime_type rcvr_val) desc H0).
- pose proof (H3 H1).
- apply MoreNatMapFacts.maps_in_mapsto in H4.
- destruct H4 as (mbr & H5). destruct mbr eqn:?. destruct p eqn:?.
- destruct f eqn:?. destruct v eqn:?.
- set (env' := env_extend n0 d0 arg_val empty_env).
- set (null_val := mk_runtime_value None).
- set (next_cont := Exit_Sk ret_cont null_val).
- exists (Exec_Configuration s env' ret_cont next_cont).
- constructor 10 with
- (rcvr_intf := intf)
- (rcvr_type_opt := (runtime_type rcvr_val))
- (proc_desc := desc)
- (func_node := f)
- (var_id := n0)
- (var_type := d0)
- (var_init := o)
- (ret_type := d)
- (null_val := null_val)
- (memb_data := m)
- (named_data := n).
- destruct rcvr_val. simpl. simpl in H0. auto.
- auto.
- rewrite Heqf0; auto.
- auto.
- trivial.
- trivial.
- constructor; simpl; congruence.
-
- (* Case 13. Pass Value to PropertyGetEK. *)
- set (type := runtime_type rcvr_val).
- assert (mk_runtime_value type = rcvr_val).
- destruct rcvr_val. subst type. simpl. congruence.
- destruct H0.
- destruct (gt_type desc) eqn:?.
-
- (* Case 13.1. Getting a Value of Interface Type from a Value of Interface
- Type. *)
- assert (runtime_type rcvr_val = type).
- rewrite <- H1. simpl. auto.
- subst type. rewrite H1 in H2. rewrite H0 in H2.
- destruct H2 eqn:?;
- try (rewrite e1 in H5; rewrite H0 in H5; discriminate H5).
- assert (type0 = type).
- rewrite e1 in H5. injection H5. intros. auto.
- destruct i eqn:?.
- assert (NatMap.In n CE).
- apply intf_refs_wf with (class_id := class_id0) (intf := intf) (ref := n).
- apply NatMapFacts.find_mapsto_iff. auto.
- constructor 2 with (get_desc := desc).
- auto.
- rewrite Heqd. constructor.
- pose proof (MoreNatMapFacts.maps_in_mapsto interface CE n H7).
- destruct H8 as (el & H9).
- set (ret_type := DT_Interface_Type (Interface_Type n)).
- set (ret_intf := el).
- set (ret_val := mk_runtime_value (Some ret_type)).
- exists (Value_Passing_Configuration ret_cont ret_val).
- constructor 12 with
- (rcvr_intf := intf)
- (rcvr_type_opt := Some type)
- (memb_id := gt_ref desc)
- (ret_intf := ret_intf)
- (ret_type := ret_type).
- auto.
- set (get_desc_alt := mk_getter_desc name (gt_ref desc) ret_type).
- assert (desc = get_desc_alt).
- destruct desc. subst get_desc_alt. simpl.
- simpl in H4. rewrite H4.
- simpl in Heqd. rewrite Heqd. subst ret_type.
- congruence.
- rewrite <- H8.
- auto.
- constructor 1 with (class_id := n).
- auto.
- apply NatMapFacts.find_mapsto_iff. subst ret_intf. auto.
- simpl. congruence.
-
- (* Case 13.2. Getting a Value of Function Type from a Value of Interface
- Type. *)
- set (ret_type := DT_Function_Type f).
- set (ret_intf := mk_interface
- ((mk_procedure_desc "call" (gt_ref desc) f) :: nil)
- ((mk_getter_desc "call" (gt_ref desc) (DT_Function_Type f)) :: nil)).
- set (ret_val := mk_runtime_value (Some ret_type)).
-
- assert (runtime_type rcvr_val = Some type0).
- subst type. rewrite <- H1. simpl. auto.
- subst type. rewrite H1 in H2. rewrite H0 in H2.
- destruct H2 eqn:?;
- try (rewrite e1 in H5; rewrite H0 in H5; discriminate H5).
- assert (type0 = type).
- rewrite e1 in H5. injection H5. intros. auto.
- assert (class_id0 = class_id).
- rewrite e in H6. rewrite H0 in H6.
- injection H6. intros. auto.
-
- exists (Value_Passing_Configuration ret_cont ret_val).
- constructor 12 with
- (rcvr_intf := intf)
- (rcvr_type_opt := Some type)
- (memb_id := gt_ref desc)
- (ret_intf := ret_intf)
- (ret_type := ret_type).
- constructor 1 with (class_id := class_id0); auto.
-
- set (get_desc_alt := mk_getter_desc name (gt_ref desc) ret_type).
- assert (desc = get_desc_alt).
- destruct desc. subst get_desc_alt. simpl.
- simpl in H4. rewrite H4.
- simpl in Heqd. rewrite Heqd. subst ret_type.
- congruence.
- rewrite <- H8. auto.
-
- clear Heqv.
- destruct H2;
- try (rewrite e1 in H5; rewrite H0 in H5; discriminate H5).
- apply NatMapFacts.find_mapsto_iff in e0.
- pose proof (program_getters_wf class_id0 intf desc e0).
- pose proof (H10 H3).
- apply MoreNatMapFacts.maps_in_mapsto in H11.
- destruct H11 as (mbr & H12).
-
- destruct mbr.
- constructor 2 with (memb_id := gt_ref desc) (proc := p).
- simpl. congruence.
- simpl. congruence.
- auto.
- simpl. subst ret_type. congruence.
-
- (* Case 13.3. Getting a Value from a Value of Function Type. *)
- subst type. rewrite H1 in H2. rewrite H in H2.
- destruct H2 eqn:?; try (
- clear Heqv;
- rewrite <- H1 in e1;
- simpl in e1;
- rewrite H0 in e1;
- rewrite e in e1;
- discriminate e1
- ).
-
- assert (ftype0 = ftype).
- rewrite H0 in H. injection H. intros. auto.
-
- exists (Value_Passing_Configuration ret_cont val).
- constructor 12 with
- (rcvr_intf := intf)
- (rcvr_type_opt := Some type0)
- (memb_id := gt_ref desc)
- (ret_intf := intf)
- (ret_type := type0).
- rewrite H. auto.
-
- pose proof H2.
- rewrite e0 in H3.
- pose proof (List.in_inv H3).
- destruct H7.
- clear Heqv. rewrite H7 in H3. rewrite H7 in e0. rewrite <- H7. simpl.
- rewrite <- e0 in H3. rewrite H5 in H7. rewrite <- H0 in H7.
- rewrite H7. auto.
- pose proof (List.in_nil H7). contradiction.
- rewrite H0; rewrite <- H5; auto.
-
- (* Case 13.4. Getting a Value from Null. *)
- rewrite e0 in H3.
- pose proof (List.in_nil H3).
- contradiction.
-
- (* Case 9. Forward. *)
- destruct next_cont.
-
- (* Case 9.1. Forward to Exit. *)
- exists (Value_Passing_Configuration e r).
- constructor.
-
- (* Case 9.2. Forward to the Next Statement in Block. *)
- destruct l.
-
- (* Case 9.2.1. Block is Empty. *)
- exists (Forward_Configuration next_cont e).
- constructor.
-
- (* Case 9.2.2. Block is Non-Empty. *)
- exists (Exec_Configuration s env e0 (Block_Sk l e e0 next_cont)).
- constructor.
-
- (* Case 10. Pass Value to ExpressionEk. *)
- exists (Forward_Configuration next_cont env).
- constructor.
-
- (* Case 11. Pass Value to VarDeclarationEk. *)
- set (env' := env_extend var var_type val env).
- exists (Forward_Configuration next_cont env').
- constructor.
- auto.
-
- (* Case 12. Pass Value to MethodInvocationEK: No Such Method. *)
- exists
- (Value_Passing_Configuration
- (Expression_Continuation Halt_Ek rcvr_type)
- (mk_runtime_value None)).
- assert (rcvr_val = mk_runtime_value None).
- destruct rcvr_val. simpl in H. rewrite H. reflexivity.
- rewrite H0.
- constructor 19.
-
- (* Case 13. Pass Value to PropertyGetEK: No Such Getter. *)
- exists
- (Value_Passing_Configuration
- (Expression_Continuation Halt_Ek rcvr_type)
- (mk_runtime_value None)).
- assert (rcvr_val = mk_runtime_value None).
- destruct rcvr_val. simpl in H. rewrite H. reflexivity.
- rewrite H0.
- constructor 20.
-Qed.
-
-
-Lemma configuration_valid_wf :
- forall conf, configuration_valid CE ME conf -> configuration_wf CE ME conf.
-Proof.
- intros. destruct H.
-
- (* Case 1. Eval Configuration. *)
- destruct H2.
-
- (* Case 1.1. Eval Variable Get. *)
- constructor. auto.
-
- (* Case 1.2. Eval Property Get. *)
- remember (E_Property_Get (Property_Get expr name)) as expr0.
- destruct H3.
- assert (
- exists rcvr_type,
- expression_type CE (env_to_type_env env) expr = Some rcvr_type
- ).
- rewrite Heqexpr0 in H3. simpl in H3.
- destruct (expression_type CE (env_to_type_env env) expr) eqn:?;
- try discriminate H3.
- exists d. reflexivity.
- destruct H5 as (rcvr_type & H6).
- rewrite Heqexpr0. destruct name.
- constructor 3 with (rcvr_type := rcvr_type).
- auto.
-
- (* Case 1.3. Eval Constructor Invocation. *)
- constructor.
- remember
- (E_Invocation_Expression
- (IE_Constructor_Invocation
- (Constructor_Invocation class_id)))
- as expr.
- destruct H; try discriminate Heqexpr.
- assert (ref = class_id).
- injection Heqexpr. intros. auto.
- rewrite <- H2. auto.
-
- (* Case 1.4. Eval Method Invocation. *)
- remember
- (E_Invocation_Expression
- (IE_Method_Invocation
- (Method_Invocation rcvr_expr name (Arguments arg_expr) ref)))
- as expr.
- destruct H3.
- assert (
- exists rcvr_type,
- expression_type CE (env_to_type_env env) rcvr_expr = Some rcvr_type
- ).
- rewrite Heqexpr in H2. simpl in H2.
- destruct (expression_type CE (env_to_type_env env) rcvr_expr) eqn:?;
- try discriminate H2.
- exists d. reflexivity.
- destruct H4 as (rcvr_type & H5).
- rewrite Heqexpr. destruct name.
- constructor 2 with (rcvr_type := rcvr_type).
- auto.
-
- (* Case 2. Exec Configuration. *)
- destruct H3.
-
- (* Case 2.1. Exec Expression Statement. *)
- remember
- (S_Expression_Statement
- (Expression_Statement expr))
- as stmt.
- destruct H4.
- assert (
- exists expr_type,
- expression_type CE (env_to_type_env env) expr = Some expr_type
- ).
- rewrite Heqstmt in H4. simpl in H4.
- destruct (expression_type CE (env_to_type_env env) expr) eqn:?;
- try discriminate H4.
- exists d. auto.
- destruct H6 as (expr_type & H7).
- rewrite Heqstmt.
- constructor 8 with (expr_type := expr_type).
- auto.
-
- (* Case 2.2. Exec Empty Block. *)
- constructor.
-
- (* Case 2.3. Exec Non-Empty Block. *)
- constructor.
-
- (* Case 2.4. Exec Return Statement. *)
- constructor.
-
- (* Case 2.5. Exec Variable Declaration without Initializer. *)
- constructor.
-
- (* Case 2.6. Exec Variable Declaration with Initializer. *)
- remember
- (S_Variable_Declaration
- (Variable_Declaration var type (Some init_expr)))
- as stmt.
- destruct H4.
- assert (
- exists init_type,
- expression_type CE (env_to_type_env env) init_expr = Some init_type
- ).
- rewrite Heqstmt in H4. simpl in H4.
- destruct (expression_type CE (env_to_type_env env) init_expr) eqn:?;
- try discriminate H4.
- exists d. auto.
- destruct H6 as (init_type & H7).
- rewrite Heqstmt.
- constructor 5 with (init_type := init_type).
- auto.
-
- (* Case 3. Value Passing Configuration *)
- destruct cont. destruct u.
-
- (* Case 3.1. Pass Value to ExpressionEK. *)
- constructor.
-
- (* Case 3.2. Pass Value to MethodInvocationEK. *)
- destruct (runtime_type val) eqn:?.
-
- (* Case 3.2.1. Non Null Value. Actual Invocation. *)
- remember (Expression_Continuation (Method_Invocation_Ek s e e0 e1) d)
- as econt.
- destruct H; try discriminate Heqecont.
- constructor 10 with (arg_type := arg_type) (rcvr_type := d0).
- auto.
- auto.
-
- (* Case 3.2.2. Null Value. No Such Method. *)
- assert (val = mk_runtime_value None).
- destruct val. simpl in Heqo. rewrite Heqo. reflexivity.
- rewrite H2.
- constructor.
- rewrite <- H2. auto.
-
- (* Case 3.3. Pass Value to InvocationEK. *)
- remember (Expression_Continuation (Invocation_Ek r s e e0) d) as econt.
- destruct H; try discriminate Heqecont.
- remember (runtime_type rcvr_val) as rcvr_val_type.
- destruct H3; constructor; rewrite <- Heqrcvr_val_type; auto.
-
- (* Case 3.4. Pass Value to PropertyGetEK. *)
- destruct (runtime_type val) eqn:?.
- assert (val = mk_runtime_value (Some d0)).
- destruct val. rewrite <- Heqo. simpl. reflexivity.
-
- (* Case 3.4.1. Non Null Value. Actual Invocation. *)
- constructor 12 with (rcvr_type := d0).
- auto.
- rewrite H2. simpl.
- remember (Expression_Continuation (Property_Get_Ek s e) d) as econt.
- destruct H1; try discriminate Heqo.
- assert (type = d0). injection Heqo. intros. auto.
- rewrite H3 in *.
- remember (Expression_Continuation cont expected_type) as econt.
- destruct H; try discriminate Heqecont.
- remember (Some rcvr_type) as rt.
- destruct H4.
- assert (rcvr_type0 = rcvr_type). injection Heqrt. intros. auto.
- rewrite H11 in *.
- assert (rcvr_type = expected_type). injection Heqecont0. intros. auto.
- rewrite H12 in *.
- apply structural_subtype_getters with
- (type1 := expected_type) (type2 := d0).
- auto.
- assert (name = s). injection Heqecont. intros. auto.
- rewrite <- H13.
- auto.
- auto.
-
- (* Case 3.4.2. Null Value. No Such Getter. *)
- constructor. auto.
-
- (* Case 3.5. Pass Value to Var Declaration. *)
- constructor.
-
- (* Case 3.6. Pass Value to Halt. *)
- remember (Expression_Continuation Halt_Ek d) as econt.
- destruct H; discriminate Heqecont.
-
- (* Case 4. Forward Configuration. *)
- constructor.
-Qed.
-
-
-Lemma configuration_valid_step :
- forall conf1 conf2,
- configuration_valid CE ME conf1 ->
- step CE ME conf1 conf2 ->
- configuration_valid CE ME conf2 \/ configuration_final conf2.
-Proof.
- admit.
-Admitted.
-
-
-Theorem progress:
- forall conf1,
- configuration_valid CE ME conf1 ->
- exists conf2, step CE ME conf1 conf2 /\
- (configuration_valid CE ME conf2 \/ configuration_final conf2).
-Proof.
- intros.
- admit.
-Admitted.
-
-
-Lemma preservation_eval:
- forall conf1 conf2 exp val env cont val_type exp_type,
- configuration_valid CE ME conf1 ->
- conf1 = Eval_Configuration exp env cont ->
- conf2 = Value_Passing_Configuration cont val ->
- steps CE ME conf1 conf2 ->
- expression_type CE (env_to_type_env env) exp = Some exp_type ->
- (runtime_type val) = Some val_type ->
- subtype (val_type, exp_type) = true.
-Proof.
- admit.
-Admitted.
-
-
-End OperationalSemanticsSpec.
diff --git a/pkg/kernel/coq/Syntax.v b/pkg/kernel/coq/Syntax.v
deleted file mode 100644
index b508f8e..0000000
--- a/pkg/kernel/coq/Syntax.v
+++ /dev/null
@@ -1,61 +0,0 @@
-Require Export SyntaxRaw.
-Require Import Common.
-
-Scheme dart_type_ind_mutual := Induction for dart_type Sort Prop
- with interface_type_ind_mutual := Induction for interface_type Sort Prop
- with function_type_ind_mutual := Induction for function_type Sort Prop.
-
-Scheme expression_ind_mutual := Induction for expression Sort Prop
- with variable_get_ind_mutual := Induction for variable_get Sort Prop
- with property_get_ind_mutual := Induction for property_get Sort Prop
- with invocation_expression_ind_mutual := Induction for invocation_expression Sort Prop
- with method_invocation_ind_mutual := Induction for method_invocation Sort Prop
- with constructor_invocation_ind_mutual := Induction for constructor_invocation Sort Prop
- with arguments_ind_mutual := Induction for arguments Sort Prop.
-
-Scheme statement_ind_mutual := Induction for statement Sort Prop
- with expression_statement_ind_mutual := Induction for expression_statement Sort Prop
- with block_ind_mutual := Induction for block Sort Prop
- with return_ind_mutual := Induction for return_statement Sort Prop
- with variable_declaration_ind_mutual := Induction for variable_declaration Sort Prop
-.
-
-Definition dart_type_induction prop :=
- dart_type_ind_mutual
- prop
- (fun i => prop (DT_Interface_Type i))
- (fun f => prop (DT_Function_Type f)).
-
-Definition expr_induction prop :=
- expression_ind_mutual
- (fun e => prop e)
- (fun v => prop (E_Variable_Get v))
- (fun p => prop (E_Property_Get p))
- (fun ie => prop (E_Invocation_Expression ie))
- (fun mi => prop (E_Invocation_Expression (IE_Method_Invocation mi)))
- (fun ci => prop (E_Invocation_Expression (IE_Constructor_Invocation ci)))
- (fun args => let (param) := args in prop param).
-
-(* Since blocks contain lists of statements, we can't just use Scheme to
- generate a good induction prinicple. *)
-Section Statement_Mutual_Induction.
- Variable P : statement -> Prop.
- Hypothesis Return : forall r, P (S_Return_Statement r).
- Hypothesis VarDecl : forall vd, P (S_Variable_Declaration vd).
- Hypothesis Expr : forall e, P (S_Expression_Statement e).
- Hypothesis Blk : forall ss, Forall P ss -> P (S_Block (Block ss)).
-
- Fixpoint statement_induction s : P s :=
- match s with
- | S_Return_Statement r => Return r
- | S_Expression_Statement e => Expr e
- | S_Variable_Declaration vd => VarDecl vd
- | S_Block (Block ss) =>
- let ss_all := (fix rec (ss : list statement) : Forall P ss :=
- match ss with
- | nil => Forall_nil _
- | (s::ss) => Forall_cons _ (statement_induction s) (rec ss)
- end) ss in
- Blk ss ss_all
- end.
-End Statement_Mutual_Induction.
diff --git a/pkg/kernel/coq/SyntaxRaw.v b/pkg/kernel/coq/SyntaxRaw.v
deleted file mode 100644
index 36c3083..0000000
--- a/pkg/kernel/coq/SyntaxRaw.v
+++ /dev/null
@@ -1,148 +0,0 @@
-Require Import Common.
-
-Inductive named_node_data : Set :=
- | Named_Node :
- reference (* reference *)
- -> named_node_data
-
-with named_node : Set :=
- | NN_Library : library -> named_node
- | NN_Class : class -> named_node
- | NN_Member : member -> named_node
-
-
-with reference : Set :=
- | Reference :
- nat
- -> reference
-
-with library : Set :=
- | Library :
- named_node_data
- -> list class (* classes *)
- -> list procedure (* procedures *)
- -> library
-
-with class : Set :=
- | Class :
- named_node_data
- -> string (* name *)
- -> list procedure (* procedures *)
- -> class
-
-with member_data : Set :=
- | Member :
- named_node_data
- -> name (* name *)
- -> member_data
-
-with member : Set :=
- | M_Procedure : procedure -> member
-
-
-with procedure : Set :=
- | Procedure :
- member_data
- -> named_node_data
- -> function_node (* function *)
- -> procedure
-
-with function_node : Set :=
- | Function_Node :
- variable_declaration (* positionalParameters *)
- -> dart_type (* returnType *)
- -> statement (* body *)
- -> function_node
-
-with expression : Set :=
- | E_Variable_Get : variable_get -> expression
- | E_Property_Get : property_get -> expression
- | E_Invocation_Expression : invocation_expression -> expression
-
-
-with variable_get : Set :=
- | Variable_Get :
- nat (* variable *)
- -> variable_get
-
-with property_get : Set :=
- | Property_Get :
- expression (* receiver *)
- -> name (* name *)
- -> property_get
-
-with arguments : Set :=
- | Arguments :
- expression (* positional *)
- -> arguments
-
-with invocation_expression : Set :=
- | IE_Method_Invocation : method_invocation -> invocation_expression
- | IE_Constructor_Invocation : constructor_invocation -> invocation_expression
-
-
-with method_invocation : Set :=
- | Method_Invocation :
- expression (* receiver *)
- -> name (* name *)
- -> arguments (* arguments *)
- -> nat (* interfaceTargetReference *)
- -> method_invocation
-
-with constructor_invocation : Set :=
- | Constructor_Invocation :
- nat (* targetReference *)
- -> constructor_invocation
-
-with statement : Set :=
- | S_Expression_Statement : expression_statement -> statement
- | S_Block : block -> statement
- | S_Return_Statement : return_statement -> statement
- | S_Variable_Declaration : variable_declaration -> statement
-
-
-with expression_statement : Set :=
- | Expression_Statement :
- expression (* expression *)
- -> expression_statement
-
-with block : Set :=
- | Block :
- list statement (* statements *)
- -> block
-
-with return_statement : Set :=
- | Return_Statement :
- expression (* expression *)
- -> return_statement
-
-with variable_declaration : Set :=
- | Variable_Declaration :
- nat
- -> dart_type (* type *)
- -> option expression (* initializer *)
- -> variable_declaration
-
-with name : Set :=
- | Name :
- string (* name *)
- -> name
-
-with dart_type : Set :=
- | DT_Interface_Type : interface_type -> dart_type
- | DT_Function_Type : function_type -> dart_type
-
-
-with interface_type : Set :=
- | Interface_Type :
- nat (* className *)
- -> interface_type
-
-with function_type : Set :=
- | Function_Type :
- dart_type (* positionalParameters *)
- -> dart_type (* returnType *)
- -> function_type
-
-.
-
diff --git a/pkg/kernel/coq/_CoqProject b/pkg/kernel/coq/_CoqProject
deleted file mode 100644
index 93bae87..0000000
--- a/pkg/kernel/coq/_CoqProject
+++ /dev/null
@@ -1,9 +0,0 @@
--R . Kernel
-./Syntax.v
-./OperationalSemanticsProof.v
-./CommonTactics.v
-./Common.v
-./SyntaxRaw.v
-./ObjectModel.v
-./OperationalSemantics.v
-./CpdtTactics.v
diff --git a/pkg/kernel/coq/build.sh b/pkg/kernel/coq/build.sh
deleted file mode 100755
index 87d249e..0000000
--- a/pkg/kernel/coq/build.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/bash
-coq_makefile -f _CoqProject -o Makefile && make
diff --git a/pkg/kernel/coq/ho-interpreter.sml b/pkg/kernel/coq/ho-interpreter.sml
deleted file mode 100644
index 12a2750..0000000
--- a/pkg/kernel/coq/ho-interpreter.sml
+++ /dev/null
@@ -1,202 +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.
- *)
-
-(* Syntax of Henry I, more or less.
-
- Some things are different, for example ReturnStatement has an optional
- expression. References are implemented as SML ref types though in a real
- implementation they would have to be option refs, provided the tree was built
- bottom up, so that they could be initialized to ref NONE.
-
- Integer ids are assigned to variable declarations and classes, so that they
- can be compared for identity or so-called pointer equality.
- *)
-structure Syntax
-= struct
- type identifier = string
-
- datatype type_
- = InterfaceType of {class: class ref}
- | FunctionType of {returnType: type_, parameterType: type_}
- and expression
- = VariableGet of {variable: variable_declaration ref}
- | MethodInvocation of
- {receiver: expression,
- name: identifier,
- argument: expression}
- | ConstructorInvocation of {class: class ref}
- | PropertyGet of {receiver: expression, name: identifier}
- and statement
- = ExpressionStatement of {expression: expression}
- | ReturnStatement of {expression: expression option}
- | Block of {statements: statement list}
- and member
- = Class of class
- | Procedure of procedure
- withtype variable_declaration = {id: int, type_: type_}
- and procedure =
- {returnType: type_,
- name: identifier,
- parameter: variable_declaration,
- body: statement}
- and class = {id: int, procedures: procedure list}
-
- type library = {members: member list}
- end
-
-(* The higher-order interpreter. *)
-structure Semantics
-= struct
- structure S = Syntax
-
- (* The environment maps variable declaration ids to their values. It is
- implemented as a list of pairs.
-
- There is a non-exhaustive pattern match which should not be reached for
- well-formed Henry I programs.
- *)
- type 'a environment = (int * 'a) list
- fun apply_env ((i, v) :: env, d: S.variable_declaration ref)
- = if i = #id (!d) then v else apply_env (env, d)
-
- (* - A (runtime) class is a pair of the class id and a getter suite.
- - A getter suite is a map from getter names (identifiers) to getters.
- - A getter is a function from receiver to result values. In Henry I
- getters are method tearoffs and so they have no effects (they cannot
- throw, for example).
- - Object values have only a class (objects have no fields in Henry I).
- Null and NoSuchMethod are objects with distinguished classes.
- - Functions are method tearoffs. They also have a getter suite because
- they can have getters (e.g., "call" or "equals"). They hold a method
- which is a function taking the single argument and a error and return
- continuations.
- *)
- datatype value
- = ObjectValue of class
- | FunctionValue of class * (value * (value -> unit) * (value -> unit) -> unit)
- withtype getter = value -> value
- and getter_suite = (S.identifier * getter) list
- and class = int * getter_suite
-
- (* Given a name and a value, lookup a getter which may not exist. *)
- fun lookup_getter (name, v)
- = let fun find_in nil
- = NONE
- | find_in ((x, f) :: gs)
- = if name = x then SOME f else find_in gs
- in case v
- of ObjectValue (_, gs)
- => find_in gs
- | FunctionValue ((_, gs), _)
- => find_in gs
- end
-
- (* A class table is a map from a class id to its getter suite.
-
- There is a non-exhaustive pattern match which should not be reached for
- well-formed Henry I programs.
- *)
- type class_table = (int * getter_suite) list
- fun lookup_class (c: S.class ref, (cid, gs) :: ct)
- = if #id (!c) = cid then gs else lookup_class (c, ct)
-
- (* For convenience we just use a global class table because it's annoying to
- pass it. It is immutable and doesn't change once initialized before
- program execution.
- *)
- val ct: class_table option ref = ref NONE
- fun class_table () = Option.valOf (!ct)
-
- (* Getter suites for builtin in classes. *)
- (* The getter that tears off the call method of a FunctionValue is cute. *)
- fun function_class (): class = (~1, [("call", fn v => v)])
- fun null_class (): class = (~2, nil)
- fun no_such_method_class(): class = (~3, nil)
-
- fun apply (v0 as ObjectValue _, v1, ek, k)
- = (case lookup_getter ("call", v0)
- of NONE => ek (ObjectValue (no_such_method_class ()))
- | SOME g => apply (g v0, v1, ek, k))
- | apply (FunctionValue (_, f), v, ek, k)
- = f (v, ek, k)
-
- fun eval (S.VariableGet {variable = d}, env, ek, k)
- = k (apply_env (env, d))
- | eval (S.MethodInvocation {receiver = e0, name = x, argument = e1},
- env, ek, k)
- = eval (e0, env, ek,
- fn v0 =>
- (case lookup_getter (x, v0)
- of NONE
- => eval (e1, env, ek,
- fn _ =>
- ek (ObjectValue (no_such_method_class ())))
- | SOME g
- => let val f = g v0
- in eval (e1, env, ek, fn v1 => apply (f, v1, ek, k))
- end))
- | eval (S.ConstructorInvocation {class = c}, env, ek, k)
- = k (ObjectValue (#id (!c), lookup_class (c, class_table ())))
- | eval (S.PropertyGet {receiver = e, name = x}, env, ek, k)
- = eval (e, env, ek,
- fn v =>
- (case lookup_getter (x, v)
- of NONE
- => ek (ObjectValue (no_such_method_class ()))
- | SOME g
- => k (g v)))
-
- fun exec (S.ExpressionStatement {expression = e}, env, rk, ek, sk)
- = eval (e, env, ek, fn _ => sk ())
- | exec (S.ReturnStatement {expression = NONE}, env, rk, ek, sk)
- = rk (ObjectValue (null_class ()))
- | exec (S.ReturnStatement {expression = SOME e}, env, rk, ek, sk)
- = eval (e, env, ek, rk)
- | exec (S.Block {statements = ss}, env, rk, ek, sk)
- = exec_stmts (ss, env, rk, ek, sk)
- and exec_stmts (nil, env, rk, ek, sk)
- = sk ()
- | exec_stmts (s :: ss, env, rk, ek, sk)
- = exec (s, env, rk, ek,
- fn () => exec_stmts (ss, env, rk, ek, sk))
-
- (* Loading the class table. A procedure in a class induces a getter which
- tears off the procedure.
- *)
- fun process_procedure ({returnType = t,
- name = x,
- parameter = p,
- body = b}: S.procedure): S.identifier * getter
- = (x, fn _ =>
- FunctionValue
- (function_class (),
- fn (v, ek, k) =>
- exec (b, [(#id p, v)], ek, k,
- fn () => k (ObjectValue (null_class ())))))
-
- fun process_class ({id = n, procedures = ps}: S.class): int * getter_suite
- = (n, List.map process_procedure ps)
-
- fun run {members = ms}
- = let fun process_members nil
- = nil
- | process_members (S.Class c :: ms)
- = process_class c :: process_members ms
- | process_members (S.Procedure p :: ms)
- = process_members ms
- val _ = ct := SOME (process_members ms)
- (* There is a non-exhaustive pattern match below which should not
- be possible for well-formed Henry I programs.
- *)
- fun find_main (S.Class c :: ms)
- = find_main ms
- | find_main (S.Procedure p :: ms)
- = if #name p = "main" then p else find_main ms
- in exec (#body (find_main ms), nil,
- fn v => print "done",
- fn e => print "error",
- fn () => print "done")
- end
-end
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index 6fdda00..4f83479 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -76,13 +76,12 @@
import 'text/ast_to_text.dart';
import 'type_algebra.dart';
import 'type_environment.dart';
-import 'coq_annot.dart';
/// Any type of node in the IR.
abstract class Node {
const Node();
- accept(Visitor v);
+ R accept<R>(Visitor<R> v);
void visitChildren(Visitor v);
/// Returns the textual representation of this node for use in debugging.
@@ -115,8 +114,8 @@
/// not available (this is the default if none is specifically set).
int fileOffset = noOffset;
- accept(TreeVisitor v);
- visitChildren(Visitor v);
+ R accept<R>(TreeVisitor<R> v);
+ void visitChildren(Visitor v);
transformChildren(Transformer v);
/// Replaces [child] with [replacement].
@@ -174,9 +173,7 @@
///
/// There is a single [reference] belonging to this node, providing a level of
/// indirection that is needed during serialization.
-@coq
abstract class NamedNode extends TreeNode {
- @coqdef
final Reference reference;
NamedNode(Reference reference)
@@ -200,11 +197,9 @@
/// Indirection between a reference and its definition.
///
/// There is only one reference object per [NamedNode].
-@coqref
class Reference {
CanonicalName canonicalName;
- @nocoq
NamedNode node;
String toString() {
@@ -271,7 +266,6 @@
// LIBRARIES and CLASSES
// ------------------------------------------------------------------------
-@coq
class Library extends NamedNode
implements Annotatable, Comparable<Library>, FileUriNode {
/// An import path to this library.
@@ -285,15 +279,15 @@
Uri fileUri;
// TODO(jensj): Do we have a better option than this?
- static int defaultLangaugeVersionMajor = 2;
- static int defaultLangaugeVersionMinor = 4;
+ static int defaultLanguageVersionMajor = 2;
+ static int defaultLanguageVersionMinor = 6;
int _languageVersionMajor;
int _languageVersionMinor;
int get languageVersionMajor =>
- _languageVersionMajor ?? defaultLangaugeVersionMajor;
+ _languageVersionMajor ?? defaultLanguageVersionMajor;
int get languageVersionMinor =>
- _languageVersionMinor ?? defaultLangaugeVersionMinor;
+ _languageVersionMinor ?? defaultLanguageVersionMinor;
void setLanguageVersion(int languageVersionMajor, int languageVersionMinor) {
if (languageVersionMajor == null || languageVersionMinor == null) {
throw new StateError("Trying to set langauge version 'null'");
@@ -336,7 +330,6 @@
/// list is empty.
List<String> problemsAsJson;
- @nocoq
final List<Expression> annotations;
final List<LibraryDependency> dependencies;
@@ -344,7 +337,6 @@
/// References to nodes exported by `export` declarations that:
/// - aren't ambiguous, or
/// - aren't hidden by local declarations.
- @nocoq
final List<Reference> additionalExports = <Reference>[];
@informative
@@ -455,6 +447,10 @@
canonicalName.getChild(class_.name).bindTo(class_.reference);
class_.computeCanonicalNames();
}
+ for (int i = 0; i < extensions.length; ++i) {
+ Extension extension = extensions[i];
+ canonicalName.getChild(extension.name).bindTo(extension.reference);
+ }
}
void addDependency(LibraryDependency node) {
@@ -465,7 +461,7 @@
parts.add(node..parent = this);
}
- accept(TreeVisitor v) => v.visitLibrary(this);
+ R accept<R>(TreeVisitor<R> v) => v.visitLibrary(this);
visitChildren(Visitor v) {
visitList(annotations, v);
@@ -473,6 +469,7 @@
visitList(parts, v);
visitList(typedefs, v);
visitList(classes, v);
+ visitList(extensions, v);
visitList(procedures, v);
visitList(fields, v);
}
@@ -483,6 +480,7 @@
transformList(parts, v, this);
transformList(typedefs, v, this);
transformList(classes, v, this);
+ transformList(extensions, v, this);
transformList(procedures, v, this);
transformList(fields, v, this);
}
@@ -566,7 +564,7 @@
annotations.add(annotation..parent = this);
}
- accept(TreeVisitor v) => v.visitLibraryDependency(this);
+ R accept<R>(TreeVisitor<R> v) => v.visitLibraryDependency(this);
visitChildren(Visitor v) {
visitList(annotations, v);
@@ -596,7 +594,7 @@
annotations.add(annotation..parent = this);
}
- accept(TreeVisitor v) => v.visitLibraryPart(this);
+ R accept<R>(TreeVisitor<R> v) => v.visitLibraryPart(this);
visitChildren(Visitor v) {
visitList(annotations, v);
@@ -622,7 +620,7 @@
bool get isHide => !isShow;
@override
- accept(TreeVisitor v) => v.visitCombinator(this);
+ R accept<R>(TreeVisitor<R> v) => v.visitCombinator(this);
@override
visitChildren(Visitor v) {}
@@ -669,7 +667,7 @@
return new TypedefType(this, _getAsTypeArguments(typeParameters));
}
- accept(TreeVisitor v) {
+ R accept<R>(TreeVisitor<R> v) {
return v.visitTypedef(this);
}
@@ -753,7 +751,6 @@
/// use those from its mixed-in type. However, the IR does not enforce this
/// rule directly, as doing so can obstruct transformations. It is possible to
/// transform a mixin application to become a regular class, and vice versa.
-@coq
class Class extends NamedNode implements Annotatable, FileUriNode {
/// Start offset of the class in the source file it comes from.
///
@@ -776,7 +773,6 @@
///
/// This defaults to an immutable empty list. Use [addAnnotation] to add
/// annotations if needed.
- @nocoq
List<Expression> annotations = const <Expression>[];
/// Name of the class.
@@ -786,7 +782,6 @@
/// The name may contain characters that are not valid in a Dart identifier,
/// in particular, the symbol '&' is used in class names generated for mixin
/// applications.
- @coq
String name;
// Must match serialized bit positions.
@@ -1040,8 +1035,8 @@
node.parent = this;
}
- accept(TreeVisitor v) => v.visitClass(this);
- acceptReference(Visitor v) => v.visitClassReference(this);
+ R accept<R>(TreeVisitor<R> v) => v.visitClass(this);
+ R acceptReference<R>(Visitor<R> v) => v.visitClassReference(this);
/// If true, the class is part of an external library, that is, it is defined
/// in another build unit. Only a subset of its members are present.
@@ -1059,18 +1054,15 @@
return new Supertype(this, _getAsTypeArguments(typeParameters));
}
- @nocoq
InterfaceType _rawType;
InterfaceType get rawType => _rawType ??= new InterfaceType(this);
- @nocoq
InterfaceType _thisType;
InterfaceType get thisType {
return _thisType ??=
new InterfaceType(this, _getAsTypeArguments(typeParameters));
}
- @nocoq
InterfaceType _bottomType;
InterfaceType get bottomType {
return _bottomType ??= new InterfaceType(this,
@@ -1155,22 +1147,44 @@
Reference reference})
: this.typeParameters = typeParameters ?? <TypeParameter>[],
this.members = members ?? <ExtensionMemberDescriptor>[],
- super(reference);
+ super(reference) {
+ setParents(this.typeParameters, this);
+ }
Library get enclosingLibrary => parent;
@override
- accept(TreeVisitor v) => v.visitExtension(this);
+ R accept<R>(TreeVisitor<R> v) => v.visitExtension(this);
@override
- visitChildren(Visitor v) {}
+ visitChildren(Visitor v) {
+ visitList(typeParameters, v);
+ onType?.accept(v);
+ }
@override
- transformChildren(Transformer v) => v.visitExtension(this);
+ transformChildren(Transformer v) {
+ transformList(typeParameters, v, this);
+ if (onType != null) {
+ onType = v.visitDartType(onType);
+ }
+ }
+}
+
+enum ExtensionMemberKind {
+ Field,
+ Method,
+ Getter,
+ Setter,
+ Operator,
+ TearOff,
}
/// Information about an member declaration in an extension.
class ExtensionMemberDescriptor {
+ static const int FlagStatic = 1 << 0; // Must match serialized bit positions.
+ static const int FlagExternal = 1 << 1;
+
/// The name of the extension member.
///
/// The name of the generated top-level member is mangled to ensure
@@ -1178,10 +1192,7 @@
/// extension itself.
Name name;
- /// [ProcedureKind] kind of the original member, if the extension is a
- /// [Procedure] and `null` otherwise.
- ///
- /// This can be either `Method`, `Getter`, `Setter`, or `Operator`.
+ /// [ExtensionMemberKind] kind of the original member.
///
/// An extension method is converted into a regular top-level method. For
/// instance:
@@ -1201,7 +1212,7 @@
/// where `B|get#bar` is the synthesized name of the top-level method and
/// `#this` is the synthesized parameter that holds represents `this`.
///
- ProcedureKind kind;
+ ExtensionMemberKind kind;
int flags = 0;
@@ -1219,21 +1230,17 @@
}
/// Return `true` if the extension method was declared as `static`.
- bool get isStatic => flags & Procedure.FlagStatic != 0;
+ bool get isStatic => flags & FlagStatic != 0;
/// Return `true` if the extension method was declared as `external`.
- bool get isExternal => flags & Procedure.FlagExternal != 0;
+ bool get isExternal => flags & FlagExternal != 0;
void set isStatic(bool value) {
- flags = value
- ? (flags | Procedure.FlagStatic)
- : (flags & ~Procedure.FlagStatic);
+ flags = value ? (flags | FlagStatic) : (flags & ~FlagStatic);
}
void set isExternal(bool value) {
- flags = value
- ? (flags | Procedure.FlagExternal)
- : (flags & ~Procedure.FlagExternal);
+ flags = value ? (flags | FlagExternal) : (flags & ~FlagExternal);
}
}
@@ -1241,7 +1248,6 @@
// MEMBERS
// ------------------------------------------------------------------------
-@coq
abstract class Member extends NamedNode implements Annotatable, FileUriNode {
/// End offset in the source file it comes from.
///
@@ -1254,7 +1260,6 @@
///
/// This defaults to an immutable empty list. Use [addAnnotation] to add
/// annotations if needed.
- @nocoq
List<Expression> annotations = const <Expression>[];
Name name;
@@ -1284,7 +1289,7 @@
Class get enclosingClass => parent is Class ? parent : null;
Library get enclosingLibrary => parent is Class ? parent.parent : parent;
- accept(MemberVisitor v);
+ R accept<R>(MemberVisitor<R> v);
acceptReference(MemberReferenceVisitor v);
/// If true, the member is part of an external library, that is, it is defined
@@ -1494,7 +1499,7 @@
if (value) throw 'Fields cannot be external';
}
- accept(MemberVisitor v) => v.visitField(this);
+ R accept<R>(MemberVisitor<R> v) => v.visitField(this);
acceptReference(MemberReferenceVisitor v) => v.visitFieldReference(this);
@@ -1509,7 +1514,7 @@
type = v.visitDartType(type);
transformList(annotations, v, this);
if (initializer != null) {
- initializer = initializer.accept(v);
+ initializer = initializer.accept<TreeNode>(v);
initializer?.parent = this;
}
}
@@ -1593,7 +1598,7 @@
@override
bool get isExtensionMember => false;
- accept(MemberVisitor v) => v.visitConstructor(this);
+ R accept<R>(MemberVisitor<R> v) => v.visitConstructor(this);
acceptReference(MemberReferenceVisitor v) =>
v.visitConstructorReference(this);
@@ -1609,7 +1614,7 @@
transformList(annotations, v, this);
transformList(initializers, v, this);
if (function != null) {
- function = function.accept(v);
+ function = function.accept<TreeNode>(v);
function?.parent = this;
}
}
@@ -1730,7 +1735,7 @@
targetReference = getMemberReference(member);
}
- accept(MemberVisitor v) => v.visitRedirectingFactoryConstructor(this);
+ R accept<R>(MemberVisitor<R> v) => v.visitRedirectingFactoryConstructor(this);
acceptReference(MemberReferenceVisitor v) =>
v.visitRedirectingFactoryConstructorReference(this);
@@ -1770,7 +1775,6 @@
/// For index-getters/setters, this is `[]` and `[]=`.
/// For operators, this is the token for the operator, e.g. `+` or `==`,
/// except for the unary minus operator, whose name is `unary-`.
-@coq
class Procedure extends Member {
/// Start offset of the function in the source file it comes from.
///
@@ -1981,7 +1985,7 @@
forwardingStubInterfaceTargetReference = getMemberReference(target);
}
- accept(MemberVisitor v) => v.visitProcedure(this);
+ R accept<R>(MemberVisitor<R> v) => v.visitProcedure(this);
acceptReference(MemberReferenceVisitor v) => v.visitProcedureReference(this);
@@ -1994,7 +1998,7 @@
transformChildren(Transformer v) {
transformList(annotations, v, this);
if (function != null) {
- function = function.accept(v);
+ function = function.accept<TreeNode>(v);
function?.parent = this;
}
}
@@ -2032,7 +2036,7 @@
@informative
bool isSynthetic = false;
- accept(InitializerVisitor v);
+ R accept<R>(InitializerVisitor<R> v);
}
/// An initializer with a compile-time error.
@@ -2042,7 +2046,7 @@
// DESIGN TODO: The frontend should use this in a lot more cases to catch
// invalid cases.
class InvalidInitializer extends Initializer {
- accept(InitializerVisitor v) => v.visitInvalidInitializer(this);
+ R accept<R>(InitializerVisitor<R> v) => v.visitInvalidInitializer(this);
visitChildren(Visitor v) {}
transformChildren(Transformer v) {}
@@ -2074,7 +2078,7 @@
fieldReference = field?.reference;
}
- accept(InitializerVisitor v) => v.visitFieldInitializer(this);
+ R accept<R>(InitializerVisitor<R> v) => v.visitFieldInitializer(this);
visitChildren(Visitor v) {
field?.acceptReference(v);
@@ -2083,7 +2087,7 @@
transformChildren(Transformer v) {
if (value != null) {
- value = value.accept(v);
+ value = value.accept<TreeNode>(v);
value?.parent = this;
}
}
@@ -2116,7 +2120,7 @@
targetReference = getMemberReference(target);
}
- accept(InitializerVisitor v) => v.visitSuperInitializer(this);
+ R accept<R>(InitializerVisitor<R> v) => v.visitSuperInitializer(this);
visitChildren(Visitor v) {
target?.acceptReference(v);
@@ -2125,7 +2129,7 @@
transformChildren(Transformer v) {
if (arguments != null) {
- arguments = arguments.accept(v);
+ arguments = arguments.accept<TreeNode>(v);
arguments?.parent = this;
}
}
@@ -2154,7 +2158,7 @@
targetReference = getMemberReference(target);
}
- accept(InitializerVisitor v) => v.visitRedirectingInitializer(this);
+ R accept<R>(InitializerVisitor<R> v) => v.visitRedirectingInitializer(this);
visitChildren(Visitor v) {
target?.acceptReference(v);
@@ -2163,7 +2167,7 @@
transformChildren(Transformer v) {
if (arguments != null) {
- arguments = arguments.accept(v);
+ arguments = arguments.accept<TreeNode>(v);
arguments?.parent = this;
}
}
@@ -2180,7 +2184,7 @@
variable?.parent = this;
}
- accept(InitializerVisitor v) => v.visitLocalInitializer(this);
+ R accept<R>(InitializerVisitor<R> v) => v.visitLocalInitializer(this);
visitChildren(Visitor v) {
variable?.accept(v);
@@ -2188,7 +2192,7 @@
transformChildren(Transformer v) {
if (variable != null) {
- variable = variable.accept(v);
+ variable = variable.accept<TreeNode>(v);
variable?.parent = this;
}
}
@@ -2201,14 +2205,14 @@
statement.parent = this;
}
- accept(InitializerVisitor v) => v.visitAssertInitializer(this);
+ R accept<R>(InitializerVisitor<R> v) => v.visitAssertInitializer(this);
visitChildren(Visitor v) {
statement.accept(v);
}
transformChildren(Transformer v) {
- statement = statement.accept(v);
+ statement = statement.accept<TreeNode>(v);
statement.parent = this;
}
}
@@ -2221,7 +2225,6 @@
///
/// This may occur in a procedure, constructor, function expression, or local
/// function declaration.
-@coq
class FunctionNode extends TreeNode {
/// End offset in the source file it comes from. Valid values are from 0 and
/// up, or -1 ([TreeNode.noOffset]) if the file end offset is not available
@@ -2246,9 +2249,7 @@
List<TypeParameter> typeParameters;
int requiredParameterCount;
- @coqsingledef
List<VariableDeclaration> positionalParameters;
- @nocoq
List<VariableDeclaration> namedParameters;
DartType returnType; // Not null.
Statement _body;
@@ -2319,7 +2320,7 @@
requiredParameterCount: requiredParameterCount);
}
- accept(TreeVisitor v) => v.visitFunctionNode(this);
+ R accept<R>(TreeVisitor<R> v) => v.visitFunctionNode(this);
visitChildren(Visitor v) {
visitList(typeParameters, v);
@@ -2335,7 +2336,7 @@
transformList(namedParameters, v, this);
returnType = v.visitDartType(returnType);
if (body != null) {
- body = body.accept(v);
+ body = body.accept<TreeNode>(v);
body?.parent = this;
}
}
@@ -2390,7 +2391,6 @@
// EXPRESSIONS
// ------------------------------------------------------------------------
-@coq
abstract class Expression extends TreeNode {
/// Returns the static type of the expression.
///
@@ -2435,13 +2435,16 @@
return superclass.rawType;
}
- accept(ExpressionVisitor v);
- accept1(ExpressionVisitor1 v, arg);
+ R accept<R>(ExpressionVisitor<R> v);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg);
}
/// An expression containing compile-time errors.
///
/// Should throw a runtime error when evaluated.
+///
+/// The [fileOffset] of an [InvalidExpression] indicates the location in the
+/// tree where the expression occurs, rather than the location of the error.
class InvalidExpression extends Expression {
String message;
@@ -2449,18 +2452,17 @@
DartType getStaticType(TypeEnvironment types) => const BottomType();
- accept(ExpressionVisitor v) => v.visitInvalidExpression(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitInvalidExpression(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitInvalidExpression(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitInvalidExpression(this, arg);
visitChildren(Visitor v) {}
transformChildren(Transformer v) {}
}
/// Read a local variable, a local function, or a function parameter.
-@coq
class VariableGet extends Expression {
VariableDeclaration variable;
- @nocoq
DartType promotedType; // Null if not promoted.
VariableGet(this.variable, [this.promotedType]);
@@ -2469,8 +2471,9 @@
return promotedType ?? variable.type;
}
- accept(ExpressionVisitor v) => v.visitVariableGet(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitVariableGet(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitVariableGet(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitVariableGet(this, arg);
visitChildren(Visitor v) {
promotedType?.accept(v);
@@ -2496,8 +2499,9 @@
DartType getStaticType(TypeEnvironment types) => value.getStaticType(types);
- accept(ExpressionVisitor v) => v.visitVariableSet(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitVariableSet(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitVariableSet(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitVariableSet(this, arg);
visitChildren(Visitor v) {
value?.accept(v);
@@ -2505,7 +2509,7 @@
transformChildren(Transformer v) {
if (value != null) {
- value = value.accept(v);
+ value = value.accept<TreeNode>(v);
value?.parent = this;
}
}
@@ -2514,13 +2518,10 @@
/// Expression of form `x.field`.
///
/// This may invoke a getter, read a field, or tear off a method.
-@coq
class PropertyGet extends Expression {
Expression receiver;
- @coq
Name name;
- @nocoq
Reference interfaceTargetReference;
PropertyGet(Expression receiver, Name name, [Member interfaceTarget])
@@ -2555,8 +2556,9 @@
return const DynamicType();
}
- accept(ExpressionVisitor v) => v.visitPropertyGet(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitPropertyGet(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitPropertyGet(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitPropertyGet(this, arg);
visitChildren(Visitor v) {
receiver?.accept(v);
@@ -2565,7 +2567,7 @@
transformChildren(Transformer v) {
if (receiver != null) {
- receiver = receiver.accept(v);
+ receiver = receiver.accept<TreeNode>(v);
receiver?.parent = this;
}
}
@@ -2602,8 +2604,9 @@
DartType getStaticType(TypeEnvironment types) => value.getStaticType(types);
- accept(ExpressionVisitor v) => v.visitPropertySet(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitPropertySet(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitPropertySet(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitPropertySet(this, arg);
visitChildren(Visitor v) {
receiver?.accept(v);
@@ -2613,11 +2616,11 @@
transformChildren(Transformer v) {
if (receiver != null) {
- receiver = receiver.accept(v);
+ receiver = receiver.accept<TreeNode>(v);
receiver?.parent = this;
}
if (value != null) {
- value = value.accept(v);
+ value = value.accept<TreeNode>(v);
value?.parent = this;
}
}
@@ -2648,13 +2651,14 @@
transformChildren(Transformer v) {
if (receiver != null) {
- receiver = receiver.accept(v);
+ receiver = receiver.accept<TreeNode>(v);
receiver?.parent = this;
}
}
- accept(ExpressionVisitor v) => v.visitDirectPropertyGet(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitDirectPropertyGet(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitDirectPropertyGet(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitDirectPropertyGet(this, arg);
DartType getStaticType(TypeEnvironment types) {
Class superclass = target.enclosingClass;
@@ -2695,17 +2699,18 @@
transformChildren(Transformer v) {
if (receiver != null) {
- receiver = receiver.accept(v);
+ receiver = receiver.accept<TreeNode>(v);
receiver?.parent = this;
}
if (value != null) {
- value = value.accept(v);
+ value = value.accept<TreeNode>(v);
value?.parent = this;
}
}
- accept(ExpressionVisitor v) => v.visitDirectPropertySet(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitDirectPropertySet(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitDirectPropertySet(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitDirectPropertySet(this, arg);
DartType getStaticType(TypeEnvironment types) => value.getStaticType(types);
}
@@ -2742,17 +2747,17 @@
transformChildren(Transformer v) {
if (receiver != null) {
- receiver = receiver.accept(v);
+ receiver = receiver.accept<TreeNode>(v);
receiver?.parent = this;
}
if (arguments != null) {
- arguments = arguments.accept(v);
+ arguments = arguments.accept<TreeNode>(v);
arguments?.parent = this;
}
}
- accept(ExpressionVisitor v) => v.visitDirectMethodInvocation(this);
- accept1(ExpressionVisitor1 v, arg) =>
+ R accept<R>(ExpressionVisitor<R> v) => v.visitDirectMethodInvocation(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
v.visitDirectMethodInvocation(this, arg);
DartType getStaticType(TypeEnvironment types) {
@@ -2799,8 +2804,9 @@
.substituteType(interfaceTarget.getterType);
}
- accept(ExpressionVisitor v) => v.visitSuperPropertyGet(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitSuperPropertyGet(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitSuperPropertyGet(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitSuperPropertyGet(this, arg);
visitChildren(Visitor v) {
name?.accept(v);
@@ -2836,8 +2842,9 @@
DartType getStaticType(TypeEnvironment types) => value.getStaticType(types);
- accept(ExpressionVisitor v) => v.visitSuperPropertySet(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitSuperPropertySet(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitSuperPropertySet(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitSuperPropertySet(this, arg);
visitChildren(Visitor v) {
name?.accept(v);
@@ -2846,7 +2853,7 @@
transformChildren(Transformer v) {
if (value != null) {
- value = value.accept(v);
+ value = value.accept<TreeNode>(v);
value?.parent = this;
}
}
@@ -2869,8 +2876,9 @@
DartType getStaticType(TypeEnvironment types) => target.getterType;
- accept(ExpressionVisitor v) => v.visitStaticGet(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitStaticGet(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitStaticGet(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitStaticGet(this, arg);
visitChildren(Visitor v) {
target?.acceptReference(v);
@@ -2902,8 +2910,9 @@
DartType getStaticType(TypeEnvironment types) => value.getStaticType(types);
- accept(ExpressionVisitor v) => v.visitStaticSet(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitStaticSet(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitStaticSet(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitStaticSet(this, arg);
visitChildren(Visitor v) {
target?.acceptReference(v);
@@ -2912,7 +2921,7 @@
transformChildren(Transformer v) {
if (value != null) {
- value = value.accept(v);
+ value = value.accept<TreeNode>(v);
value?.parent = this;
}
}
@@ -2920,11 +2929,8 @@
/// The arguments to a function call, divided into type arguments,
/// positional arguments, and named arguments.
-@coq
class Arguments extends TreeNode {
- @nocoq
final List<DartType> types;
- @coqsingle
final List<Expression> positional;
List<NamedExpression> named;
@@ -2952,7 +2958,7 @@
.toList());
}
- accept(TreeVisitor v) => v.visitArguments(this);
+ R accept<R>(TreeVisitor<R> v) => v.visitArguments(this);
visitChildren(Visitor v) {
visitList(types, v);
@@ -2976,7 +2982,7 @@
value?.parent = this;
}
- accept(TreeVisitor v) => v.visitNamedExpression(this);
+ R accept<R>(TreeVisitor<R> v) => v.visitNamedExpression(this);
visitChildren(Visitor v) {
value?.accept(v);
@@ -2984,7 +2990,7 @@
transformChildren(Transformer v) {
if (value != null) {
- value = value.accept(v);
+ value = value.accept<TreeNode>(v);
value?.parent = this;
}
}
@@ -2992,7 +2998,6 @@
/// Common super class for [DirectMethodInvocation], [MethodInvocation],
/// [SuperMethodInvocation], [StaticInvocation], and [ConstructorInvocation].
-@coq
abstract class InvocationExpression extends Expression {
Arguments get arguments;
set arguments(Arguments value);
@@ -3004,7 +3009,6 @@
}
/// Expression of form `x.foo(y)`.
-@coq
class MethodInvocation extends InvocationExpression {
Expression receiver;
Name name;
@@ -3068,8 +3072,9 @@
return const DynamicType();
}
- accept(ExpressionVisitor v) => v.visitMethodInvocation(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitMethodInvocation(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitMethodInvocation(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitMethodInvocation(this, arg);
visitChildren(Visitor v) {
receiver?.accept(v);
@@ -3079,11 +3084,11 @@
transformChildren(Transformer v) {
if (receiver != null) {
- receiver = receiver.accept(v);
+ receiver = receiver.accept<TreeNode>(v);
receiver?.parent = this;
}
if (arguments != null) {
- arguments = arguments.accept(v);
+ arguments = arguments.accept<TreeNode>(v);
arguments?.parent = this;
}
}
@@ -3124,8 +3129,9 @@
.substituteType(returnType);
}
- accept(ExpressionVisitor v) => v.visitSuperMethodInvocation(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitSuperMethodInvocation(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitSuperMethodInvocation(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitSuperMethodInvocation(this, arg);
visitChildren(Visitor v) {
name?.accept(v);
@@ -3134,7 +3140,7 @@
transformChildren(Transformer v) {
if (arguments != null) {
- arguments = arguments.accept(v);
+ arguments = arguments.accept<TreeNode>(v);
arguments?.parent = this;
}
}
@@ -3174,8 +3180,9 @@
.substituteType(target.function.returnType);
}
- accept(ExpressionVisitor v) => v.visitStaticInvocation(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitStaticInvocation(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitStaticInvocation(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitStaticInvocation(this, arg);
visitChildren(Visitor v) {
target?.acceptReference(v);
@@ -3184,7 +3191,7 @@
transformChildren(Transformer v) {
if (arguments != null) {
- arguments = arguments.accept(v);
+ arguments = arguments.accept<TreeNode>(v);
arguments?.parent = this;
}
}
@@ -3197,10 +3204,8 @@
// DESIGN TODO: Should we pass type arguments in a separate field
// `classTypeArguments`? They are quite different from type arguments to
// generic functions.
-@coq
class ConstructorInvocation extends InvocationExpression {
Reference targetReference;
- @nocoq
Arguments arguments;
bool isConst;
@@ -3228,8 +3233,9 @@
: new InterfaceType(target.enclosingClass, arguments.types);
}
- accept(ExpressionVisitor v) => v.visitConstructorInvocation(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitConstructorInvocation(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitConstructorInvocation(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitConstructorInvocation(this, arg);
visitChildren(Visitor v) {
target?.acceptReference(v);
@@ -3238,7 +3244,7 @@
transformChildren(Transformer v) {
if (arguments != null) {
- arguments = arguments.accept(v);
+ arguments = arguments.accept<TreeNode>(v);
arguments?.parent = this;
}
}
@@ -3265,8 +3271,9 @@
.substituteType(type.withoutTypeParameters);
}
- accept(ExpressionVisitor v) => v.visitInstantiation(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitInstantiation(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitInstantiation(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitInstantiation(this, arg);
visitChildren(Visitor v) {
expression?.accept(v);
@@ -3275,7 +3282,7 @@
transformChildren(Transformer v) {
if (expression != null) {
- expression = expression.accept(v);
+ expression = expression.accept<TreeNode>(v);
expression?.parent = this;
}
transformTypeList(typeArguments, v);
@@ -3295,8 +3302,8 @@
DartType getStaticType(TypeEnvironment types) => types.boolType;
- accept(ExpressionVisitor v) => v.visitNot(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitNot(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitNot(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) => v.visitNot(this, arg);
visitChildren(Visitor v) {
operand?.accept(v);
@@ -3304,7 +3311,7 @@
transformChildren(Transformer v) {
if (operand != null) {
- operand = operand.accept(v);
+ operand = operand.accept<TreeNode>(v);
operand?.parent = this;
}
}
@@ -3323,8 +3330,9 @@
DartType getStaticType(TypeEnvironment types) => types.boolType;
- accept(ExpressionVisitor v) => v.visitLogicalExpression(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitLogicalExpression(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitLogicalExpression(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitLogicalExpression(this, arg);
visitChildren(Visitor v) {
left?.accept(v);
@@ -3333,11 +3341,11 @@
transformChildren(Transformer v) {
if (left != null) {
- left = left.accept(v);
+ left = left.accept<TreeNode>(v);
left?.parent = this;
}
if (right != null) {
- right = right.accept(v);
+ right = right.accept<TreeNode>(v);
right?.parent = this;
}
}
@@ -3361,8 +3369,9 @@
DartType getStaticType(TypeEnvironment types) => staticType;
- accept(ExpressionVisitor v) => v.visitConditionalExpression(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitConditionalExpression(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitConditionalExpression(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitConditionalExpression(this, arg);
visitChildren(Visitor v) {
condition?.accept(v);
@@ -3373,15 +3382,15 @@
transformChildren(Transformer v) {
if (condition != null) {
- condition = condition.accept(v);
+ condition = condition.accept<TreeNode>(v);
condition?.parent = this;
}
if (then != null) {
- then = then.accept(v);
+ then = then.accept<TreeNode>(v);
then?.parent = this;
}
if (otherwise != null) {
- otherwise = otherwise.accept(v);
+ otherwise = otherwise.accept<TreeNode>(v);
otherwise?.parent = this;
}
if (staticType != null) {
@@ -3406,8 +3415,9 @@
DartType getStaticType(TypeEnvironment types) => types.stringType;
- accept(ExpressionVisitor v) => v.visitStringConcatenation(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitStringConcatenation(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitStringConcatenation(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitStringConcatenation(this, arg);
visitChildren(Visitor v) {
visitList(expressions, v);
@@ -3437,8 +3447,9 @@
return types.literalListType(typeArgument);
}
- accept(ExpressionVisitor v) => v.visitListConcatenation(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitListConcatenation(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitListConcatenation(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitListConcatenation(this, arg);
visitChildren(Visitor v) {
typeArgument?.accept(v);
@@ -3473,8 +3484,9 @@
return types.literalSetType(typeArgument);
}
- accept(ExpressionVisitor v) => v.visitSetConcatenation(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitSetConcatenation(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitSetConcatenation(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitSetConcatenation(this, arg);
visitChildren(Visitor v) {
typeArgument?.accept(v);
@@ -3512,8 +3524,9 @@
return types.literalMapType(keyType, valueType);
}
- accept(ExpressionVisitor v) => v.visitMapConcatenation(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitMapConcatenation(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitMapConcatenation(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitMapConcatenation(this, arg);
visitChildren(Visitor v) {
keyType?.accept(v);
@@ -3530,7 +3543,7 @@
/// Create an instance directly from the field values.
///
-/// This expression arises from const constructor calls when one or more field
+/// These expressions arise from const constructor calls when one or more field
/// initializing expressions, field initializers, assert initializers or unused
/// arguments contain unevaluated expressions. They only ever occur within
/// unevaluated constants in constant expressions.
@@ -3552,8 +3565,9 @@
: new InterfaceType(classNode, typeArguments);
}
- accept(ExpressionVisitor v) => v.visitInstanceCreation(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitInstanceCreation(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitInstanceCreation(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitInstanceCreation(this, arg);
visitChildren(Visitor v) {
classReference.asClass.acceptReference(v);
@@ -3570,7 +3584,7 @@
transformChildren(Transformer v) {
fieldValues.forEach((Reference fieldRef, Expression value) {
- Expression transformed = value.accept(v);
+ Expression transformed = value.accept<TreeNode>(v);
if (transformed != null && !identical(value, transformed)) {
fieldValues[fieldRef] = transformed;
transformed.parent = this;
@@ -3581,6 +3595,43 @@
}
}
+/// A marker indicating that a subexpression originates in a different source
+/// file than the surrounding context.
+///
+/// These expressions arise from inlining of const variables during constant
+/// evaluation. They only ever occur within unevaluated constants in constant
+/// expressions.
+class FileUriExpression extends Expression implements FileUriNode {
+ /// The URI of the source file in which the subexpression is located.
+ /// Can be different from the file containing the [FileUriExpression].
+ Uri fileUri;
+
+ Expression expression;
+
+ FileUriExpression(this.expression, this.fileUri) {
+ expression.parent = this;
+ }
+
+ DartType getStaticType(TypeEnvironment types) =>
+ expression.getStaticType(types);
+
+ R accept<R>(ExpressionVisitor<R> v) => v.visitFileUriExpression(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitFileUriExpression(this, arg);
+
+ visitChildren(Visitor v) {
+ expression.accept(v);
+ }
+
+ transformChildren(Transformer v) {
+ expression = expression.accept<TreeNode>(v)..parent = this;
+ }
+
+ Location _getLocationInEnclosingFile(int offset) {
+ return _getLocationInComponent(enclosingComponent, fileUri, offset);
+ }
+}
+
/// Expression of form `x is T`.
class IsExpression extends Expression {
Expression operand;
@@ -3592,8 +3643,9 @@
DartType getStaticType(TypeEnvironment types) => types.boolType;
- accept(ExpressionVisitor v) => v.visitIsExpression(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitIsExpression(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitIsExpression(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitIsExpression(this, arg);
visitChildren(Visitor v) {
operand?.accept(v);
@@ -3602,7 +3654,7 @@
transformChildren(Transformer v) {
if (operand != null) {
- operand = operand.accept(v);
+ operand = operand.accept<TreeNode>(v);
operand?.parent = this;
}
type = v.visitDartType(type);
@@ -3634,8 +3686,9 @@
DartType getStaticType(TypeEnvironment types) => type;
- accept(ExpressionVisitor v) => v.visitAsExpression(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitAsExpression(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitAsExpression(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitAsExpression(this, arg);
visitChildren(Visitor v) {
operand?.accept(v);
@@ -3644,7 +3697,7 @@
transformChildren(Transformer v) {
if (operand != null) {
- operand = operand.accept(v);
+ operand = operand.accept<TreeNode>(v);
operand?.parent = this;
}
type = v.visitDartType(type);
@@ -3666,8 +3719,9 @@
DartType getStaticType(TypeEnvironment types) => types.stringType;
- accept(ExpressionVisitor v) => v.visitStringLiteral(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitStringLiteral(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitStringLiteral(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitStringLiteral(this, arg);
}
class IntLiteral extends BasicLiteral {
@@ -3681,8 +3735,9 @@
DartType getStaticType(TypeEnvironment types) => types.intType;
- accept(ExpressionVisitor v) => v.visitIntLiteral(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitIntLiteral(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitIntLiteral(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitIntLiteral(this, arg);
}
class DoubleLiteral extends BasicLiteral {
@@ -3692,8 +3747,9 @@
DartType getStaticType(TypeEnvironment types) => types.doubleType;
- accept(ExpressionVisitor v) => v.visitDoubleLiteral(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitDoubleLiteral(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitDoubleLiteral(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitDoubleLiteral(this, arg);
}
class BoolLiteral extends BasicLiteral {
@@ -3703,8 +3759,9 @@
DartType getStaticType(TypeEnvironment types) => types.boolType;
- accept(ExpressionVisitor v) => v.visitBoolLiteral(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitBoolLiteral(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitBoolLiteral(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitBoolLiteral(this, arg);
}
class NullLiteral extends BasicLiteral {
@@ -3712,8 +3769,9 @@
DartType getStaticType(TypeEnvironment types) => types.nullType;
- accept(ExpressionVisitor v) => v.visitNullLiteral(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitNullLiteral(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitNullLiteral(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitNullLiteral(this, arg);
}
class SymbolLiteral extends Expression {
@@ -3723,8 +3781,9 @@
DartType getStaticType(TypeEnvironment types) => types.symbolType;
- accept(ExpressionVisitor v) => v.visitSymbolLiteral(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitSymbolLiteral(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitSymbolLiteral(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitSymbolLiteral(this, arg);
visitChildren(Visitor v) {}
transformChildren(Transformer v) {}
@@ -3737,8 +3796,9 @@
DartType getStaticType(TypeEnvironment types) => types.typeType;
- accept(ExpressionVisitor v) => v.visitTypeLiteral(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitTypeLiteral(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitTypeLiteral(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitTypeLiteral(this, arg);
visitChildren(Visitor v) {
type?.accept(v);
@@ -3752,8 +3812,9 @@
class ThisExpression extends Expression {
DartType getStaticType(TypeEnvironment types) => types.thisType;
- accept(ExpressionVisitor v) => v.visitThisExpression(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitThisExpression(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitThisExpression(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitThisExpression(this, arg);
visitChildren(Visitor v) {}
transformChildren(Transformer v) {}
@@ -3762,8 +3823,9 @@
class Rethrow extends Expression {
DartType getStaticType(TypeEnvironment types) => const BottomType();
- accept(ExpressionVisitor v) => v.visitRethrow(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitRethrow(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitRethrow(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitRethrow(this, arg);
visitChildren(Visitor v) {}
transformChildren(Transformer v) {}
@@ -3778,8 +3840,8 @@
DartType getStaticType(TypeEnvironment types) => const BottomType();
- accept(ExpressionVisitor v) => v.visitThrow(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitThrow(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitThrow(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) => v.visitThrow(this, arg);
visitChildren(Visitor v) {
expression?.accept(v);
@@ -3787,7 +3849,7 @@
transformChildren(Transformer v) {
if (expression != null) {
- expression = expression.accept(v);
+ expression = expression.accept<TreeNode>(v);
expression?.parent = this;
}
}
@@ -3808,8 +3870,9 @@
return types.literalListType(typeArgument);
}
- accept(ExpressionVisitor v) => v.visitListLiteral(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitListLiteral(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitListLiteral(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitListLiteral(this, arg);
visitChildren(Visitor v) {
typeArgument?.accept(v);
@@ -3837,8 +3900,9 @@
return types.literalSetType(typeArgument);
}
- accept(ExpressionVisitor v) => v.visitSetLiteral(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitSetLiteral(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitSetLiteral(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitSetLiteral(this, arg);
visitChildren(Visitor v) {
typeArgument?.accept(v);
@@ -3870,8 +3934,9 @@
return types.literalMapType(keyType, valueType);
}
- accept(ExpressionVisitor v) => v.visitMapLiteral(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitMapLiteral(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitMapLiteral(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitMapLiteral(this, arg);
visitChildren(Visitor v) {
keyType?.accept(v);
@@ -3895,7 +3960,7 @@
value?.parent = this;
}
- accept(TreeVisitor v) => v.visitMapEntry(this);
+ R accept<R>(TreeVisitor<R> v) => v.visitMapEntry(this);
visitChildren(Visitor v) {
key?.accept(v);
@@ -3904,11 +3969,11 @@
transformChildren(Transformer v) {
if (key != null) {
- key = key.accept(v);
+ key = key.accept<TreeNode>(v);
key?.parent = this;
}
if (value != null) {
- value = value.accept(v);
+ value = value.accept<TreeNode>(v);
value?.parent = this;
}
}
@@ -3926,8 +3991,9 @@
return types.unfutureType(operand.getStaticType(types));
}
- accept(ExpressionVisitor v) => v.visitAwaitExpression(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitAwaitExpression(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitAwaitExpression(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitAwaitExpression(this, arg);
visitChildren(Visitor v) {
operand?.accept(v);
@@ -3935,7 +4001,7 @@
transformChildren(Transformer v) {
if (operand != null) {
- operand = operand.accept(v);
+ operand = operand.accept<TreeNode>(v);
operand?.parent = this;
}
}
@@ -3958,8 +4024,9 @@
DartType getStaticType(TypeEnvironment types) => function.functionType;
- accept(ExpressionVisitor v) => v.visitFunctionExpression(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitFunctionExpression(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitFunctionExpression(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitFunctionExpression(this, arg);
visitChildren(Visitor v) {
function?.accept(v);
@@ -3967,7 +4034,7 @@
transformChildren(Transformer v) {
if (function != null) {
- function = function.accept(v);
+ function = function.accept<TreeNode>(v);
function?.parent = this;
}
}
@@ -3983,8 +4050,9 @@
DartType getStaticType(TypeEnvironment types) => type;
- accept(ExpressionVisitor v) => v.visitConstantExpression(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitConstantExpression(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitConstantExpression(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitConstantExpression(this, arg);
visitChildren(Visitor v) {
constant?.acceptReference(v);
@@ -4009,8 +4077,8 @@
DartType getStaticType(TypeEnvironment types) => body.getStaticType(types);
- accept(ExpressionVisitor v) => v.visitLet(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitLet(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitLet(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) => v.visitLet(this, arg);
visitChildren(Visitor v) {
variable?.accept(v);
@@ -4019,11 +4087,11 @@
transformChildren(Transformer v) {
if (variable != null) {
- variable = variable.accept(v);
+ variable = variable.accept<TreeNode>(v);
variable?.parent = this;
}
if (body != null) {
- body = body.accept(v);
+ body = body.accept<TreeNode>(v);
body?.parent = this;
}
}
@@ -4040,8 +4108,9 @@
DartType getStaticType(TypeEnvironment types) => value.getStaticType(types);
- accept(ExpressionVisitor v) => v.visitBlockExpression(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitBlockExpression(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitBlockExpression(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitBlockExpression(this, arg);
visitChildren(Visitor v) {
body?.accept(v);
@@ -4050,11 +4119,11 @@
transformChildren(Transformer v) {
if (body != null) {
- body = body.accept(v);
+ body = body.accept<TreeNode>(v);
body?.parent = this;
}
if (value != null) {
- value = value.accept(v);
+ value = value.accept<TreeNode>(v);
value?.parent = this;
}
}
@@ -4082,8 +4151,9 @@
return types.futureType(const DynamicType());
}
- accept(ExpressionVisitor v) => v.visitLoadLibrary(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitLoadLibrary(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitLoadLibrary(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitLoadLibrary(this, arg);
visitChildren(Visitor v) {}
transformChildren(Transformer v) {}
@@ -4100,8 +4170,9 @@
return types.objectType;
}
- accept(ExpressionVisitor v) => v.visitCheckLibraryIsLoaded(this);
- accept1(ExpressionVisitor1 v, arg) => v.visitCheckLibraryIsLoaded(this, arg);
+ R accept<R>(ExpressionVisitor<R> v) => v.visitCheckLibraryIsLoaded(this);
+ R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+ v.visitCheckLibraryIsLoaded(this, arg);
visitChildren(Visitor v) {}
transformChildren(Transformer v) {}
@@ -4111,13 +4182,11 @@
// STATEMENTS
// ------------------------------------------------------------------------
-@coq
abstract class Statement extends TreeNode {
- accept(StatementVisitor v);
- accept1(StatementVisitor1 v, arg);
+ R accept<R>(StatementVisitor<R> v);
+ R accept1<R, A>(StatementVisitor1<R, A> v, A arg);
}
-@coq
class ExpressionStatement extends Statement {
Expression expression;
@@ -4125,8 +4194,9 @@
expression?.parent = this;
}
- accept(StatementVisitor v) => v.visitExpressionStatement(this);
- accept1(StatementVisitor1 v, arg) => v.visitExpressionStatement(this, arg);
+ R accept<R>(StatementVisitor<R> v) => v.visitExpressionStatement(this);
+ R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+ v.visitExpressionStatement(this, arg);
visitChildren(Visitor v) {
expression?.accept(v);
@@ -4134,13 +4204,12 @@
transformChildren(Transformer v) {
if (expression != null) {
- expression = expression.accept(v);
+ expression = expression.accept<TreeNode>(v);
expression?.parent = this;
}
}
}
-@coq
class Block extends Statement {
final List<Statement> statements;
@@ -4153,8 +4222,8 @@
setParents(statements, this);
}
- accept(StatementVisitor v) => v.visitBlock(this);
- accept1(StatementVisitor1 v, arg) => v.visitBlock(this, arg);
+ R accept<R>(StatementVisitor<R> v) => v.visitBlock(this);
+ R accept1<R, A>(StatementVisitor1<R, A> v, A arg) => v.visitBlock(this, arg);
visitChildren(Visitor v) {
visitList(statements, v);
@@ -4187,8 +4256,9 @@
setParents(statements, this);
}
- accept(StatementVisitor v) => v.visitAssertBlock(this);
- accept1(StatementVisitor1 v, arg) => v.visitAssertBlock(this, arg);
+ R accept<R>(StatementVisitor<R> v) => v.visitAssertBlock(this);
+ R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+ v.visitAssertBlock(this, arg);
transformChildren(Transformer v) {
transformList(statements, v, this);
@@ -4205,8 +4275,9 @@
}
class EmptyStatement extends Statement {
- accept(StatementVisitor v) => v.visitEmptyStatement(this);
- accept1(StatementVisitor1 v, arg) => v.visitEmptyStatement(this, arg);
+ R accept<R>(StatementVisitor<R> v) => v.visitEmptyStatement(this);
+ R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+ v.visitEmptyStatement(this, arg);
visitChildren(Visitor v) {}
transformChildren(Transformer v) {}
@@ -4224,8 +4295,9 @@
message?.parent = this;
}
- accept(StatementVisitor v) => v.visitAssertStatement(this);
- accept1(StatementVisitor1 v, arg) => v.visitAssertStatement(this, arg);
+ R accept<R>(StatementVisitor<R> v) => v.visitAssertStatement(this);
+ R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+ v.visitAssertStatement(this, arg);
visitChildren(Visitor v) {
condition?.accept(v);
@@ -4234,11 +4306,11 @@
transformChildren(Transformer v) {
if (condition != null) {
- condition = condition.accept(v);
+ condition = condition.accept<TreeNode>(v);
condition?.parent = this;
}
if (message != null) {
- message = message.accept(v);
+ message = message.accept<TreeNode>(v);
message?.parent = this;
}
}
@@ -4256,8 +4328,9 @@
body?.parent = this;
}
- accept(StatementVisitor v) => v.visitLabeledStatement(this);
- accept1(StatementVisitor1 v, arg) => v.visitLabeledStatement(this, arg);
+ R accept<R>(StatementVisitor<R> v) => v.visitLabeledStatement(this);
+ R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+ v.visitLabeledStatement(this, arg);
visitChildren(Visitor v) {
body?.accept(v);
@@ -4265,7 +4338,7 @@
transformChildren(Transformer v) {
if (body != null) {
- body = body.accept(v);
+ body = body.accept<TreeNode>(v);
body?.parent = this;
}
}
@@ -4296,8 +4369,9 @@
BreakStatement(this.target);
- accept(StatementVisitor v) => v.visitBreakStatement(this);
- accept1(StatementVisitor1 v, arg) => v.visitBreakStatement(this, arg);
+ R accept<R>(StatementVisitor<R> v) => v.visitBreakStatement(this);
+ R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+ v.visitBreakStatement(this, arg);
visitChildren(Visitor v) {}
transformChildren(Transformer v) {}
@@ -4312,8 +4386,9 @@
body?.parent = this;
}
- accept(StatementVisitor v) => v.visitWhileStatement(this);
- accept1(StatementVisitor1 v, arg) => v.visitWhileStatement(this, arg);
+ R accept<R>(StatementVisitor<R> v) => v.visitWhileStatement(this);
+ R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+ v.visitWhileStatement(this, arg);
visitChildren(Visitor v) {
condition?.accept(v);
@@ -4322,11 +4397,11 @@
transformChildren(Transformer v) {
if (condition != null) {
- condition = condition.accept(v);
+ condition = condition.accept<TreeNode>(v);
condition?.parent = this;
}
if (body != null) {
- body = body.accept(v);
+ body = body.accept<TreeNode>(v);
body?.parent = this;
}
}
@@ -4341,8 +4416,9 @@
condition?.parent = this;
}
- accept(StatementVisitor v) => v.visitDoStatement(this);
- accept1(StatementVisitor1 v, arg) => v.visitDoStatement(this, arg);
+ R accept<R>(StatementVisitor<R> v) => v.visitDoStatement(this);
+ R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+ v.visitDoStatement(this, arg);
visitChildren(Visitor v) {
body?.accept(v);
@@ -4351,11 +4427,11 @@
transformChildren(Transformer v) {
if (body != null) {
- body = body.accept(v);
+ body = body.accept<TreeNode>(v);
body?.parent = this;
}
if (condition != null) {
- condition = condition.accept(v);
+ condition = condition.accept<TreeNode>(v);
condition?.parent = this;
}
}
@@ -4374,8 +4450,9 @@
body?.parent = this;
}
- accept(StatementVisitor v) => v.visitForStatement(this);
- accept1(StatementVisitor1 v, arg) => v.visitForStatement(this, arg);
+ R accept<R>(StatementVisitor<R> v) => v.visitForStatement(this);
+ R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+ v.visitForStatement(this, arg);
visitChildren(Visitor v) {
visitList(variables, v);
@@ -4387,12 +4464,12 @@
transformChildren(Transformer v) {
transformList(variables, v, this);
if (condition != null) {
- condition = condition.accept(v);
+ condition = condition.accept<TreeNode>(v);
condition?.parent = this;
}
transformList(updates, v, this);
if (body != null) {
- body = body.accept(v);
+ body = body.accept<TreeNode>(v);
body?.parent = this;
}
}
@@ -4417,8 +4494,9 @@
body?.parent = this;
}
- accept(StatementVisitor v) => v.visitForInStatement(this);
- accept1(StatementVisitor1 v, arg) => v.visitForInStatement(this, arg);
+ R accept<R>(StatementVisitor<R> v) => v.visitForInStatement(this);
+ R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+ v.visitForInStatement(this, arg);
visitChildren(Visitor v) {
variable?.accept(v);
@@ -4428,15 +4506,15 @@
transformChildren(Transformer v) {
if (variable != null) {
- variable = variable.accept(v);
+ variable = variable.accept<TreeNode>(v);
variable?.parent = this;
}
if (iterable != null) {
- iterable = iterable.accept(v);
+ iterable = iterable.accept<TreeNode>(v);
iterable?.parent = this;
}
if (body != null) {
- body = body.accept(v);
+ body = body.accept<TreeNode>(v);
body?.parent = this;
}
}
@@ -4455,8 +4533,9 @@
setParents(cases, this);
}
- accept(StatementVisitor v) => v.visitSwitchStatement(this);
- accept1(StatementVisitor1 v, arg) => v.visitSwitchStatement(this, arg);
+ R accept<R>(StatementVisitor<R> v) => v.visitSwitchStatement(this);
+ R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+ v.visitSwitchStatement(this, arg);
visitChildren(Visitor v) {
expression?.accept(v);
@@ -4465,7 +4544,7 @@
transformChildren(Transformer v) {
if (expression != null) {
- expression = expression.accept(v);
+ expression = expression.accept<TreeNode>(v);
expression?.parent = this;
}
transformList(cases, v, this);
@@ -4500,7 +4579,7 @@
body = null,
isDefault = false;
- accept(TreeVisitor v) => v.visitSwitchCase(this);
+ R accept<R>(TreeVisitor<R> v) => v.visitSwitchCase(this);
visitChildren(Visitor v) {
visitList(expressions, v);
@@ -4510,7 +4589,7 @@
transformChildren(Transformer v) {
transformList(expressions, v, this);
if (body != null) {
- body = body.accept(v);
+ body = body.accept<TreeNode>(v);
body?.parent = this;
}
}
@@ -4522,8 +4601,8 @@
ContinueSwitchStatement(this.target);
- accept(StatementVisitor v) => v.visitContinueSwitchStatement(this);
- accept1(StatementVisitor1 v, arg) =>
+ R accept<R>(StatementVisitor<R> v) => v.visitContinueSwitchStatement(this);
+ R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
v.visitContinueSwitchStatement(this, arg);
visitChildren(Visitor v) {}
@@ -4541,8 +4620,9 @@
otherwise?.parent = this;
}
- accept(StatementVisitor v) => v.visitIfStatement(this);
- accept1(StatementVisitor1 v, arg) => v.visitIfStatement(this, arg);
+ R accept<R>(StatementVisitor<R> v) => v.visitIfStatement(this);
+ R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+ v.visitIfStatement(this, arg);
visitChildren(Visitor v) {
condition?.accept(v);
@@ -4552,21 +4632,20 @@
transformChildren(Transformer v) {
if (condition != null) {
- condition = condition.accept(v);
+ condition = condition.accept<TreeNode>(v);
condition?.parent = this;
}
if (then != null) {
- then = then.accept(v);
+ then = then.accept<TreeNode>(v);
then?.parent = this;
}
if (otherwise != null) {
- otherwise = otherwise.accept(v);
+ otherwise = otherwise.accept<TreeNode>(v);
otherwise?.parent = this;
}
}
}
-@coq
class ReturnStatement extends Statement {
Expression expression; // May be null.
@@ -4574,8 +4653,9 @@
expression?.parent = this;
}
- accept(StatementVisitor v) => v.visitReturnStatement(this);
- accept1(StatementVisitor1 v, arg) => v.visitReturnStatement(this, arg);
+ R accept<R>(StatementVisitor<R> v) => v.visitReturnStatement(this);
+ R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+ v.visitReturnStatement(this, arg);
visitChildren(Visitor v) {
expression?.accept(v);
@@ -4583,7 +4663,7 @@
transformChildren(Transformer v) {
if (expression != null) {
- expression = expression.accept(v);
+ expression = expression.accept<TreeNode>(v);
expression?.parent = this;
}
}
@@ -4599,8 +4679,9 @@
setParents(catches, this);
}
- accept(StatementVisitor v) => v.visitTryCatch(this);
- accept1(StatementVisitor1 v, arg) => v.visitTryCatch(this, arg);
+ R accept<R>(StatementVisitor<R> v) => v.visitTryCatch(this);
+ R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+ v.visitTryCatch(this, arg);
visitChildren(Visitor v) {
body?.accept(v);
@@ -4609,7 +4690,7 @@
transformChildren(Transformer v) {
if (body != null) {
- body = body.accept(v);
+ body = body.accept<TreeNode>(v);
body?.parent = this;
}
transformList(catches, v, this);
@@ -4630,7 +4711,7 @@
body?.parent = this;
}
- accept(TreeVisitor v) => v.visitCatch(this);
+ R accept<R>(TreeVisitor<R> v) => v.visitCatch(this);
visitChildren(Visitor v) {
guard?.accept(v);
@@ -4642,15 +4723,15 @@
transformChildren(Transformer v) {
guard = v.visitDartType(guard);
if (exception != null) {
- exception = exception.accept(v);
+ exception = exception.accept<TreeNode>(v);
exception?.parent = this;
}
if (stackTrace != null) {
- stackTrace = stackTrace.accept(v);
+ stackTrace = stackTrace.accept<TreeNode>(v);
stackTrace?.parent = this;
}
if (body != null) {
- body = body.accept(v);
+ body = body.accept<TreeNode>(v);
body?.parent = this;
}
}
@@ -4665,8 +4746,9 @@
finalizer?.parent = this;
}
- accept(StatementVisitor v) => v.visitTryFinally(this);
- accept1(StatementVisitor1 v, arg) => v.visitTryFinally(this, arg);
+ R accept<R>(StatementVisitor<R> v) => v.visitTryFinally(this);
+ R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+ v.visitTryFinally(this, arg);
visitChildren(Visitor v) {
body?.accept(v);
@@ -4675,11 +4757,11 @@
transformChildren(Transformer v) {
if (body != null) {
- body = body.accept(v);
+ body = body.accept<TreeNode>(v);
body?.parent = this;
}
if (finalizer != null) {
- finalizer = finalizer.accept(v);
+ finalizer = finalizer.accept<TreeNode>(v);
finalizer?.parent = this;
}
}
@@ -4713,8 +4795,9 @@
flags = value ? (flags | FlagNative) : (flags & ~FlagNative);
}
- accept(StatementVisitor v) => v.visitYieldStatement(this);
- accept1(StatementVisitor1 v, arg) => v.visitYieldStatement(this, arg);
+ R accept<R>(StatementVisitor<R> v) => v.visitYieldStatement(this);
+ R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+ v.visitYieldStatement(this, arg);
visitChildren(Visitor v) {
expression?.accept(v);
@@ -4722,7 +4805,7 @@
transformChildren(Transformer v) {
if (expression != null) {
- expression = expression.accept(v);
+ expression = expression.accept<TreeNode>(v);
expression?.parent = this;
}
}
@@ -4736,7 +4819,6 @@
/// When this occurs as a statement, it must be a direct child of a [Block].
//
// DESIGN TODO: Should we remove the 'final' modifier from variables?
-@coqref
class VariableDeclaration extends Statement {
/// Offset of the equals sign in the source file it comes from.
///
@@ -4767,7 +4849,6 @@
/// For parameters, this is the default value.
///
/// Should be null in other cases.
- @coqopt
Expression initializer; // May be null.
VariableDeclaration(this.name,
@@ -4889,8 +4970,9 @@
annotations.add(annotation..parent = this);
}
- accept(StatementVisitor v) => v.visitVariableDeclaration(this);
- accept1(StatementVisitor1 v, arg) => v.visitVariableDeclaration(this, arg);
+ R accept<R>(StatementVisitor<R> v) => v.visitVariableDeclaration(this);
+ R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+ v.visitVariableDeclaration(this, arg);
visitChildren(Visitor v) {
visitList(annotations, v);
@@ -4902,7 +4984,7 @@
transformList(annotations, v, this);
type = v.visitDartType(type);
if (initializer != null) {
- initializer = initializer.accept(v);
+ initializer = initializer.accept<TreeNode>(v);
initializer?.parent = this;
}
}
@@ -4924,8 +5006,9 @@
function?.parent = this;
}
- accept(StatementVisitor v) => v.visitFunctionDeclaration(this);
- accept1(StatementVisitor1 v, arg) => v.visitFunctionDeclaration(this, arg);
+ R accept<R>(StatementVisitor<R> v) => v.visitFunctionDeclaration(this);
+ R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
+ v.visitFunctionDeclaration(this, arg);
visitChildren(Visitor v) {
variable?.accept(v);
@@ -4934,11 +5017,11 @@
transformChildren(Transformer v) {
if (variable != null) {
- variable = variable.accept(v);
+ variable = variable.accept<TreeNode>(v);
variable?.parent = this;
}
if (function != null) {
- function = function.accept(v);
+ function = function.accept<TreeNode>(v);
function?.parent = this;
}
}
@@ -4958,14 +5041,10 @@
///
/// The [toString] method returns a human-readable string that includes the
/// library name for private names; uniqueness is not guaranteed.
-@coq
abstract class Name implements Node {
final int hashCode;
- @coq
final String name;
- @nocoq
Reference get libraryName;
- @nocoq
Library get library;
bool get isPrivate;
@@ -4989,7 +5068,7 @@
return other is Name && name == other.name && library == other.library;
}
- accept(Visitor v) => v.visitName(this);
+ R accept<R>(Visitor<R> v) => v.visitName(this);
visitChildren(Visitor v) {
// DESIGN TODO: Should we visit the library as a library reference?
@@ -5075,12 +5154,11 @@
///
/// The `==` operator on [DartType]s compare based on type equality, not
/// object identity.
-@coq
abstract class DartType extends Node {
const DartType();
- accept(DartTypeVisitor v);
- accept1(DartTypeVisitor1 v, arg);
+ R accept<R>(DartTypeVisitor<R> v);
+ R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg);
bool operator ==(Object other);
@@ -5106,13 +5184,14 @@
const InvalidType();
- accept(DartTypeVisitor v) => v.visitInvalidType(this);
- accept1(DartTypeVisitor1 v, arg) => v.visitInvalidType(this, arg);
+ R accept<R>(DartTypeVisitor<R> v) => v.visitInvalidType(this);
+ R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) =>
+ v.visitInvalidType(this, arg);
visitChildren(Visitor v) {}
bool operator ==(Object other) => other is InvalidType;
- Nullability get nullability => throw "InvalidType doesn't have nullabiliity";
+ Nullability get nullability => throw "InvalidType doesn't have nullability";
}
class DynamicType extends DartType {
@@ -5120,8 +5199,9 @@
const DynamicType();
- accept(DartTypeVisitor v) => v.visitDynamicType(this);
- accept1(DartTypeVisitor1 v, arg) => v.visitDynamicType(this, arg);
+ R accept<R>(DartTypeVisitor<R> v) => v.visitDynamicType(this);
+ R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) =>
+ v.visitDynamicType(this, arg);
visitChildren(Visitor v) {}
bool operator ==(Object other) => other is DynamicType;
@@ -5134,8 +5214,9 @@
const VoidType();
- accept(DartTypeVisitor v) => v.visitVoidType(this);
- accept1(DartTypeVisitor1 v, arg) => v.visitVoidType(this, arg);
+ R accept<R>(DartTypeVisitor<R> v) => v.visitVoidType(this);
+ R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) =>
+ v.visitVoidType(this, arg);
visitChildren(Visitor v) {}
bool operator ==(Object other) => other is VoidType;
@@ -5148,8 +5229,9 @@
const BottomType();
- accept(DartTypeVisitor v) => v.visitBottomType(this);
- accept1(DartTypeVisitor1 v, arg) => v.visitBottomType(this, arg);
+ R accept<R>(DartTypeVisitor<R> v) => v.visitBottomType(this);
+ R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) =>
+ v.visitBottomType(this, arg);
visitChildren(Visitor v) {}
bool operator ==(Object other) => other is BottomType;
@@ -5157,13 +5239,11 @@
Nullability get nullability => Nullability.nonNullable;
}
-@coq
class InterfaceType extends DartType {
Reference className;
final Nullability nullability;
- @nocoq
final List<DartType> typeArguments;
/// The [typeArguments] list must not be modified after this call. If the
@@ -5189,8 +5269,9 @@
}
}
- accept(DartTypeVisitor v) => v.visitInterfaceType(this);
- accept1(DartTypeVisitor1 v, arg) => v.visitInterfaceType(this, arg);
+ R accept<R>(DartTypeVisitor<R> v) => v.visitInterfaceType(this);
+ R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) =>
+ v.visitInterfaceType(this, arg);
visitChildren(Visitor v) {
classNode.acceptReference(v);
@@ -5221,11 +5302,9 @@
}
/// A possibly generic function type.
-@coq
class FunctionType extends DartType {
final List<TypeParameter> typeParameters;
final int requiredParameterCount;
- @coqsingle
final List<DartType> positionalParameters;
final List<NamedType> namedParameters; // Must be sorted.
final Nullability nullability;
@@ -5246,13 +5325,13 @@
this.requiredParameterCount =
requiredParameterCount ?? positionalParameters.length;
- @nocoq
Reference get typedefReference => typedefType?.typedefReference;
Typedef get typedef => typedefReference?.asTypedef;
- accept(DartTypeVisitor v) => v.visitFunctionType(this);
- accept1(DartTypeVisitor1 v, arg) => v.visitFunctionType(this, arg);
+ R accept<R>(DartTypeVisitor<R> v) => v.visitFunctionType(this);
+ R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) =>
+ v.visitFunctionType(this, arg);
visitChildren(Visitor v) {
visitList(typeParameters, v);
@@ -5372,8 +5451,9 @@
Typedef get typedefNode => typedefReference.asTypedef;
- accept(DartTypeVisitor v) => v.visitTypedefType(this);
- accept1(DartTypeVisitor1 v, arg) => v.visitTypedefType(this, arg);
+ R accept<R>(DartTypeVisitor<R> v) => v.visitTypedefType(this);
+ R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) =>
+ v.visitTypedefType(this, arg);
visitChildren(Visitor v) {
visitList(typeArguments, v);
@@ -5436,7 +5516,7 @@
int compareTo(NamedType other) => name.compareTo(other.name);
- accept(Visitor v) => v.visitNamedType(this);
+ R accept<R>(Visitor<R> v) => v.visitNamedType(this);
void visitChildren(Visitor v) {
type.accept(v);
@@ -5458,8 +5538,38 @@
/// is the same as the [TypeParameter]'s bound. This allows one to detect
/// whether the bound has been promoted.
class TypeParameterType extends DartType {
- /// Declared by the programmer on the type.
- final Nullability declaredNullability;
+ /// The nullability declared on the type.
+ ///
+ /// Declarations of type-parameter types can set it to [Nullability.nullable]
+ /// or [Nullability.legacy]. Otherwise, it's computed from the nullability
+ /// of the type parameter bound.
+ Nullability declaredNullability;
+
+ TypeParameter parameter;
+
+ /// An optional promoted bound on the type parameter.
+ ///
+ /// 'null' indicates that the type parameter's bound has not been promoted and
+ /// is therefore the same as the bound of [parameter].
+ DartType promotedBound;
+
+ TypeParameterType(this.parameter,
+ [this.promotedBound, this.declaredNullability = Nullability.legacy]);
+
+ R accept<R>(DartTypeVisitor<R> v) => v.visitTypeParameterType(this);
+ R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) =>
+ v.visitTypeParameterType(this, arg);
+
+ visitChildren(Visitor v) {}
+
+ bool operator ==(Object other) {
+ return other is TypeParameterType && parameter == other.parameter;
+ }
+
+ int get hashCode => _temporaryHashCodeTable[parameter] ?? parameter.hashCode;
+
+ /// Returns the bound of the type parameter, accounting for promotions.
+ DartType get bound => promotedBound ?? parameter.bound;
/// Actual nullability of the type, calculated from its parts.
///
@@ -5480,35 +5590,25 @@
/// }
/// }
/// }
- final Nullability nullability;
+ Nullability get nullability =>
+ getNullability(parameter, promotedBound, declaredNullability);
- TypeParameter parameter;
-
- /// An optional promoted bound on the type parameter.
- ///
- /// 'null' indicates that the type parameter's bound has not been promoted and
- /// is therefore the same as the bound of [parameter].
- DartType promotedBound;
-
- TypeParameterType(this.parameter,
- [this.promotedBound, this.declaredNullability = Nullability.legacy])
- : this.nullability =
- getNullability(parameter, promotedBound, declaredNullability);
-
- accept(DartTypeVisitor v) => v.visitTypeParameterType(this);
- accept1(DartTypeVisitor1 v, arg) => v.visitTypeParameterType(this, arg);
-
- visitChildren(Visitor v) {}
-
- bool operator ==(Object other) {
- return other is TypeParameterType && parameter == other.parameter;
+ static Nullability computeNullabilityFromBound(TypeParameter typeParameter) {
+ // If the bound is nullable, both nullable and non-nullable types can be
+ // passed in for the type parameter, making the corresponding type
+ // parameter types 'neither.' Otherwise, the nullability matches that of
+ // the bound.
+ DartType bound = typeParameter.bound;
+ if (bound == null) {
+ throw new StateError("Can't compute nullability from absent bound.");
+ }
+ Nullability boundNullability =
+ bound is InvalidType ? Nullability.neither : bound.nullability;
+ return boundNullability == Nullability.nullable
+ ? Nullability.neither
+ : boundNullability;
}
- int get hashCode => _temporaryHashCodeTable[parameter] ?? parameter.hashCode;
-
- /// Returns the bound of the type parameter, accounting for promotions.
- DartType get bound => promotedBound ?? parameter.bound;
-
/// Get nullability of [TypeParameterType] from arguments to its constructor.
///
/// This method is supposed to be used only in the constructor of
@@ -5521,7 +5621,7 @@
// by nullability.
// If promotedBound isn't null, getNullability returns the nullability of an
- // instesection of the left-hand side (referred to as LHS below) and the
+ // intersection of the left-hand side (referred to as LHS below) and the
// right-hand side (referred to as RHS below). LHS is parameter followed by
// nullability, and RHS is promotedBound. That is, getNullability returns
// the nullability of either T & P or T? & P where T is parameter, P is
@@ -5530,22 +5630,12 @@
Nullability lhsNullability;
- // If the nullability is explicitly nullable, that is, if the type parameter
- // type is followed by '?' in the code, the nullability of the type is
- // 'nullable.'
- if (declaredNullability == Nullability.nullable) {
- lhsNullability = Nullability.nullable;
+ // If the nullability is declared explicitly, use it as the nullability of
+ // the LHS of the intersection. Otherwise, compute it from the bound.
+ if (declaredNullability != null) {
+ lhsNullability = declaredNullability;
} else {
- // If the bound is nullable, both nullable and non-nullable types can be
- // passed in for the type parameter, making the corresponding type
- // parameter types 'neither.' Otherwise, the nullability matches that of
- // the bound.
- DartType bound = parameter.bound ?? const DynamicType();
- Nullability boundNullability =
- bound is InvalidType ? Nullability.neither : bound.nullability;
- lhsNullability = boundNullability == Nullability.nullable
- ? Nullability.neither
- : boundNullability;
+ lhsNullability = computeNullabilityFromBound(parameter);
}
if (promotedBound == null) {
return lhsNullability;
@@ -5678,7 +5768,7 @@
annotations.add(annotation..parent = this);
}
- accept(TreeVisitor v) => v.visitTypeParameter(this);
+ R accept<R>(TreeVisitor<R> v) => v.visitTypeParameter(this);
visitChildren(Visitor v) {
visitList(annotations, v);
@@ -5712,7 +5802,7 @@
Class get classNode => className.asClass;
- accept(Visitor v) => v.visitSupertype(this);
+ R accept<R>(Visitor<R> v) => v.visitSupertype(this);
visitChildren(Visitor v) {
classNode.acceptReference(v);
@@ -5759,10 +5849,10 @@
visitChildren(Visitor v);
/// Calls the `visit*Constant()` method on the visitor [v].
- accept(ConstantVisitor v);
+ R accept<R>(ConstantVisitor<R> v);
/// Calls the `visit*ConstantReference()` method on the visitor [v].
- acceptReference(Visitor v);
+ R acceptReference<R>(Visitor<R> v);
/// The Kernel AST will reference [Constant]s via [ConstantExpression]s. The
/// constants are not required to be canonicalized, but they have to be deeply
@@ -5795,8 +5885,8 @@
NullConstant() : super(null);
visitChildren(Visitor v) {}
- accept(ConstantVisitor v) => v.visitNullConstant(this);
- acceptReference(Visitor v) => v.visitNullConstantReference(this);
+ R accept<R>(ConstantVisitor<R> v) => v.visitNullConstant(this);
+ R acceptReference<R>(Visitor<R> v) => v.visitNullConstantReference(this);
DartType getType(TypeEnvironment types) => types.nullType;
}
@@ -5805,8 +5895,8 @@
BoolConstant(bool value) : super(value);
visitChildren(Visitor v) {}
- accept(ConstantVisitor v) => v.visitBoolConstant(this);
- acceptReference(Visitor v) => v.visitBoolConstantReference(this);
+ R accept<R>(ConstantVisitor<R> v) => v.visitBoolConstant(this);
+ R acceptReference<R>(Visitor<R> v) => v.visitBoolConstantReference(this);
DartType getType(TypeEnvironment types) => types.boolType;
}
@@ -5815,8 +5905,8 @@
IntConstant(int value) : super(value);
visitChildren(Visitor v) {}
- accept(ConstantVisitor v) => v.visitIntConstant(this);
- acceptReference(Visitor v) => v.visitIntConstantReference(this);
+ R accept<R>(ConstantVisitor<R> v) => v.visitIntConstant(this);
+ R acceptReference<R>(Visitor<R> v) => v.visitIntConstantReference(this);
DartType getType(TypeEnvironment types) => types.intType;
}
@@ -5825,8 +5915,8 @@
DoubleConstant(double value) : super(value);
visitChildren(Visitor v) {}
- accept(ConstantVisitor v) => v.visitDoubleConstant(this);
- acceptReference(Visitor v) => v.visitDoubleConstantReference(this);
+ R accept<R>(ConstantVisitor<R> v) => v.visitDoubleConstant(this);
+ R acceptReference<R>(Visitor<R> v) => v.visitDoubleConstantReference(this);
int get hashCode => value.isNaN ? 199 : super.hashCode;
bool operator ==(Object other) =>
@@ -5841,8 +5931,8 @@
}
visitChildren(Visitor v) {}
- accept(ConstantVisitor v) => v.visitStringConstant(this);
- acceptReference(Visitor v) => v.visitStringConstantReference(this);
+ R accept<R>(ConstantVisitor<R> v) => v.visitStringConstant(this);
+ R acceptReference<R>(Visitor<R> v) => v.visitStringConstantReference(this);
DartType getType(TypeEnvironment types) => types.stringType;
}
@@ -5855,8 +5945,8 @@
visitChildren(Visitor v) {}
- accept(ConstantVisitor v) => v.visitSymbolConstant(this);
- acceptReference(Visitor v) => v.visitSymbolConstantReference(this);
+ R accept<R>(ConstantVisitor<R> v) => v.visitSymbolConstant(this);
+ R acceptReference<R>(Visitor<R> v) => v.visitSymbolConstantReference(this);
String toString() {
return libraryReference != null
@@ -5891,8 +5981,8 @@
}
}
- accept(ConstantVisitor v) => v.visitMapConstant(this);
- acceptReference(Visitor v) => v.visitMapConstantReference(this);
+ R accept<R>(ConstantVisitor<R> v) => v.visitMapConstant(this);
+ R acceptReference<R>(Visitor<R> v) => v.visitMapConstantReference(this);
String toString() => '${this.runtimeType}<$keyType, $valueType>($entries)';
@@ -5939,8 +6029,8 @@
}
}
- accept(ConstantVisitor v) => v.visitListConstant(this);
- acceptReference(Visitor v) => v.visitListConstantReference(this);
+ R accept<R>(ConstantVisitor<R> v) => v.visitListConstant(this);
+ R acceptReference<R>(Visitor<R> v) => v.visitListConstantReference(this);
String toString() => '${this.runtimeType}<$typeArgument>($entries)';
@@ -5973,8 +6063,8 @@
}
}
- accept(ConstantVisitor v) => v.visitSetConstant(this);
- acceptReference(Visitor v) => v.visitSetConstantReference(this);
+ R accept<R>(ConstantVisitor<R> v) => v.visitSetConstant(this);
+ R acceptReference<R>(Visitor<R> v) => v.visitSetConstantReference(this);
String toString() => '${this.runtimeType}<$typeArgument>($entries)';
@@ -6013,8 +6103,8 @@
}
}
- accept(ConstantVisitor v) => v.visitInstanceConstant(this);
- acceptReference(Visitor v) => v.visitInstanceConstantReference(this);
+ R accept<R>(ConstantVisitor<R> v) => v.visitInstanceConstant(this);
+ R acceptReference<R>(Visitor<R> v) => v.visitInstanceConstantReference(this);
String toString() {
final sb = new StringBuffer();
@@ -6063,8 +6153,9 @@
visitList(types, v);
}
- accept(ConstantVisitor v) => v.visitPartialInstantiationConstant(this);
- acceptReference(Visitor v) =>
+ R accept<R>(ConstantVisitor<R> v) =>
+ v.visitPartialInstantiationConstant(this);
+ R acceptReference<R>(Visitor<R> v) =>
v.visitPartialInstantiationConstantReference(this);
String toString() {
@@ -6106,17 +6197,18 @@
procedureReference.asProcedure.acceptReference(v);
}
- accept(ConstantVisitor v) => v.visitTearOffConstant(this);
- acceptReference(Visitor v) => v.visitTearOffConstantReference(this);
+ R accept<R>(ConstantVisitor<R> v) => v.visitTearOffConstant(this);
+ R acceptReference<R>(Visitor<R> v) => v.visitTearOffConstantReference(this);
String toString() {
return '${runtimeType}(${procedure})';
}
- int get hashCode => procedure.hashCode;
+ int get hashCode => procedureReference.hashCode;
bool operator ==(Object other) {
- return other is TearOffConstant && other.procedure == procedure;
+ return other is TearOffConstant &&
+ other.procedureReference == procedureReference;
}
FunctionType getType(TypeEnvironment types) =>
@@ -6132,8 +6224,9 @@
type.accept(v);
}
- accept(ConstantVisitor v) => v.visitTypeLiteralConstant(this);
- acceptReference(Visitor v) => v.visitTypeLiteralConstantReference(this);
+ R accept<R>(ConstantVisitor<R> v) => v.visitTypeLiteralConstant(this);
+ R acceptReference<R>(Visitor<R> v) =>
+ v.visitTypeLiteralConstantReference(this);
String toString() => '${runtimeType}(${type})';
@@ -6157,8 +6250,9 @@
expression.accept(v);
}
- accept(ConstantVisitor v) => v.visitUnevaluatedConstant(this);
- acceptReference(Visitor v) => v.visitUnevaluatedConstantReference(this);
+ R accept<R>(ConstantVisitor<R> v) => v.visitUnevaluatedConstant(this);
+ R acceptReference<R>(Visitor<R> v) =>
+ v.visitUnevaluatedConstantReference(this);
DartType getType(TypeEnvironment types) => expression.getStaticType(types);
@@ -6241,7 +6335,7 @@
mainMethodName = getMemberReference(main);
}
- accept(TreeVisitor v) => v.visitComponent(this);
+ R accept<R>(TreeVisitor<R> v) => v.visitComponent(this);
visitChildren(Visitor v) {
visitList(libraries, v);
@@ -6557,6 +6651,18 @@
return class_.canonicalName;
}
+/// Returns the canonical name of [extension], or throws an exception if the
+/// class has not been assigned a canonical name yet.
+///
+/// Returns `null` if the extension is `null`.
+CanonicalName getCanonicalNameOfExtension(Extension extension) {
+ if (extension == null) return null;
+ if (extension.canonicalName == null) {
+ throw '$extension has no canonical name';
+ }
+ return extension.canonicalName;
+}
+
/// Returns the canonical name of [library], or throws an exception if the
/// library has not been assigned a canonical name yet.
///
diff --git a/pkg/kernel/lib/binary/ast_from_binary.dart b/pkg/kernel/lib/binary/ast_from_binary.dart
index a66a437..120d1bb 100644
--- a/pkg/kernel/lib/binary/ast_from_binary.dart
+++ b/pkg/kernel/lib/binary/ast_from_binary.dart
@@ -415,6 +415,7 @@
}
List<int> _indexComponents() {
+ _checkEmptyInput();
int savedByteOffset = _byteOffset;
_byteOffset = _bytes.length - 4;
List<int> index = <int>[];
@@ -431,6 +432,10 @@
return new List.from(index.reversed);
}
+ void _checkEmptyInput() {
+ if (_bytes.length == 0) throw new StateError("Empty input given.");
+ }
+
/// Deserializes a kernel component and stores it in [component].
///
/// When linking with a non-empty component, canonical names must have been
@@ -438,6 +443,8 @@
///
/// The input bytes may contain multiple files concatenated.
void readComponent(Component component, {bool checkCanonicalNames: false}) {
+ _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.
int offset = _byteOffset;
@@ -576,10 +583,10 @@
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 filesize should be $componentFileSize but other component indexes'
- ' has indicated that the size should be '
- '${result.componentFileSizeInBytes}.';
+ 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}.";
}
// Skip to the start of the index.
@@ -873,6 +880,11 @@
return readClass(classOffsets[index + 1]);
}, library);
_byteOffset = classOffsets.last;
+
+ _mergeNamedNodeList(library.extensions, (index) {
+ return readExtension();
+ }, library);
+
_mergeNamedNodeList(library.fields, (index) => readField(), library);
_mergeNamedNodeList(library.procedures, (index) {
_byteOffset = procedureOffsets[index];
@@ -1057,6 +1069,57 @@
return node;
}
+ Extension readExtension() {
+ int tag = readByte();
+ assert(tag == Tag.Extension);
+
+ CanonicalName canonicalName = readCanonicalNameReference();
+ Reference reference = canonicalName.getReference();
+ Extension node = reference.node;
+ if (alwaysCreateNewNamedNodes) {
+ node = null;
+ }
+ bool shouldWriteData = node == null || _isReadingLibraryImplementation;
+ if (node == null) {
+ node = new Extension(reference: reference);
+ }
+
+ String name = readStringOrNullIfEmpty();
+ assert(() {
+ debugPath.add(node.name ?? 'extension');
+ return true;
+ }());
+
+ Uri fileUri = readUriReference();
+ node.fileOffset = readOffset();
+
+ readAndPushTypeParameterList(node.typeParameters, node);
+ DartType onType = readDartType();
+ typeParameterStack.length = 0;
+
+ if (shouldWriteData) {
+ node.name = name;
+ node.fileUri = fileUri;
+ node.onType = onType;
+ }
+
+ int length = readUInt();
+ for (int i = 0; i < length; i++) {
+ Name name = readName();
+ int kind = readByte();
+ int flags = readByte();
+ CanonicalName canonicalName = readCanonicalNameReference();
+ if (shouldWriteData) {
+ node.members.add(new ExtensionMemberDescriptor(
+ name: name,
+ kind: ExtensionMemberKind.values[kind],
+ member: canonicalName.getReference())
+ ..flags = flags);
+ }
+ }
+ return node;
+ }
+
int getAndResetTransformerFlags() {
int flags = _transformerFlags;
_transformerFlags = 0;
@@ -1601,6 +1664,11 @@
return new InstanceCreation(classReference, typeArguments, fieldValues,
asserts, unusedArguments)
..fileOffset = offset;
+ case Tag.FileUriExpression:
+ Uri fileUri = readUriReference();
+ int offset = readOffset();
+ return new FileUriExpression(readExpression(), fileUri)
+ ..fileOffset = offset;
case Tag.IsExpression:
int offset = readOffset();
return new IsExpression(readExpression(), readDartType())
diff --git a/pkg/kernel/lib/binary/ast_to_binary.dart b/pkg/kernel/lib/binary/ast_to_binary.dart
index 824c145..ac32edd 100644
--- a/pkg/kernel/lib/binary/ast_to_binary.dart
+++ b/pkg/kernel/lib/binary/ast_to_binary.dart
@@ -326,6 +326,15 @@
}
}
+ void writeExtensionNodeList(List<Extension> nodes) {
+ final len = nodes.length;
+ writeUInt30(len);
+ for (int i = 0; i < len; i++) {
+ final node = nodes[i];
+ writeExtensionNode(node);
+ }
+ }
+
void writeConstructorNodeList(List<Constructor> nodes) {
final len = nodes.length;
writeUInt30(len);
@@ -421,6 +430,13 @@
node.accept(this);
}
+ void writeExtensionNode(Extension node) {
+ if (_metadataSubsections != null) {
+ _writeNodeMetadata(node);
+ }
+ node.accept(this);
+ }
+
void writeConstructorNode(Constructor node) {
if (_metadataSubsections != null) {
_writeNodeMetadata(node);
@@ -932,6 +948,7 @@
classOffsets = new List<int>();
writeClassNodeList(node.classes);
classOffsets.add(getBufferOffset());
+ writeExtensionNodeList(node.extensions);
writeFieldNodeList(node.fields);
procedureOffsets = new List<int>();
writeProcedureNodeList(node.procedures);
@@ -1553,6 +1570,14 @@
}
@override
+ void visitFileUriExpression(FileUriExpression node) {
+ writeByte(Tag.FileUriExpression);
+ writeUriReference(node.fileUri);
+ writeOffset(node.fileOffset);
+ writeNode(node.expression);
+ }
+
+ @override
void visitIsExpression(IsExpression node) {
writeByte(Tag.IsExpression);
writeOffset(node.fileOffset);
@@ -2096,8 +2121,29 @@
@override
void visitExtension(Extension node) {
- // TODO(johnniwinther): Support serialization of extension nodes.
- throw new UnsupportedError('serialization of extension nodes');
+ if (node.canonicalName == null) {
+ throw new ArgumentError('Missing canonical name for $node');
+ }
+ writeByte(Tag.Extension);
+ writeNonNullCanonicalNameReference(getCanonicalNameOfExtension(node));
+ writeStringReference(node.name ?? '');
+ writeUriReference(node.fileUri);
+ writeOffset(node.fileOffset);
+
+ enterScope(typeParameters: node.typeParameters);
+ writeNodeList(node.typeParameters);
+ writeDartType(node.onType);
+ leaveScope(typeParameters: node.typeParameters);
+
+ final int len = node.members.length;
+ writeUInt30(len);
+ for (int i = 0; i < len; i++) {
+ final ExtensionMemberDescriptor descriptor = node.members[i];
+ writeName(descriptor.name);
+ writeByte(descriptor.kind.index);
+ writeByte(descriptor.flags);
+ writeNonNullCanonicalNameReference(descriptor.member.canonicalName);
+ }
}
// ================================================================
@@ -2215,7 +2261,7 @@
@override
void visitLibraryDependency(LibraryDependency node) {
- throw new UnsupportedError('serialization of LibraryDependencys');
+ throw new UnsupportedError('serialization of LibraryDependencies');
}
@override
@@ -2664,7 +2710,7 @@
* Returns
* * Non-negative on success (the new index in [target]).
* * -1 when [target] doesn't have enough space. Note that [target] can be
- * poluted starting at [index].
+ * polluted starting at [index].
* * -2 on input error, i.e. an unpaired lead or tail surrogate.
*/
static int writeUtf8(List<int> target, int index, String source,
diff --git a/pkg/kernel/lib/binary/tag.dart b/pkg/kernel/lib/binary/tag.dart
index 3fcad11..dc93073 100644
--- a/pkg/kernel/lib/binary/tag.dart
+++ b/pkg/kernel/lib/binary/tag.dart
@@ -8,6 +8,7 @@
static const int Something = 1;
static const int Class = 2;
+ static const int Extension = 115;
static const int FunctionNode = 3;
@@ -80,6 +81,7 @@
static const int ConstMapLiteral = 59;
static const int SetLiteral = 109;
static const int ConstSetLiteral = 110;
+ static const int FileUriExpression = 116;
// Statements
static const int ExpressionStatement = 61;
@@ -117,16 +119,8 @@
static const int SimpleInterfaceType = 96;
static const int SimpleFunctionType = 97;
- // References
- static const int NullReference = 99;
- static const int ClassReference = 100;
- static const int MemberReference = 101;
-
static const int ConstantExpression = 106;
- // Tag is deprecated since version 24.
- static const int Deprecated_ConstantExpression = 107;
-
/// 108 is occupied by [RedirectingFactoryConstructor] (member).
/// 109 is occupied by [SetLiteral] (expression).
/// 110 is occupied by [ConstSetLiteral] (expression).
@@ -134,6 +128,8 @@
/// 112 is occupied by [SetConcatenation] (expression).
/// 113 is occupied by [MapConcatenation] (expression).
/// 114 is occupied by [InstanceCreation] (expression).
+ /// 115 is occupied by [Extension].
+ /// 116 is occupied by [FileUriExpression] (expression).
static const int SpecializedTagHighBit = 0x80; // 10000000
static const int SpecializedTagMask = 0xF8; // 11111000
@@ -150,7 +146,7 @@
/// Internal version of kernel binary format.
/// Bump it when making incompatible changes in kernel binaries.
/// Keep in sync with runtime/vm/kernel_binary.h, pkg/kernel/binary.md.
- static const int BinaryFormatVersion = 29;
+ static const int BinaryFormatVersion = 31;
}
abstract class ConstantTag {
diff --git a/pkg/kernel/lib/canonical_name.dart b/pkg/kernel/lib/canonical_name.dart
index 76fd5d8..29aeac4 100644
--- a/pkg/kernel/lib/canonical_name.dart
+++ b/pkg/kernel/lib/canonical_name.dart
@@ -20,6 +20,10 @@
/// Canonical name of enclosing library
/// Name of class
///
+/// Extension:
+/// Canonical name of enclosing library
+/// Name of extension
+///
/// Constructor:
/// Canonical name of enclosing class or library
/// "@constructors"
diff --git a/pkg/kernel/lib/class_hierarchy.dart b/pkg/kernel/lib/class_hierarchy.dart
index 7be58d1..73cd12a 100644
--- a/pkg/kernel/lib/class_hierarchy.dart
+++ b/pkg/kernel/lib/class_hierarchy.dart
@@ -41,7 +41,7 @@
/// [unordered], they are not included.
Iterable<Class> getOrderedClasses(Iterable<Class> unordered);
- // Returns the instantition of each generic supertype implemented by this
+ // Returns the instantiation of each generic supertype implemented by this
// class (e.g. getClassAsInstanceOf applied to all superclasses and
// interfaces).
List<Supertype> genericSupertypesOf(Class class_);
@@ -377,7 +377,7 @@
@override
Member getSingleTargetForInterfaceInvocation(Member interfaceTarget,
{bool setter: false}) {
- if (invalidated) throw "This datastructure has been invalidated";
+ if (invalidated) throw "This data structure has been invalidated";
Name name = interfaceTarget.name;
Member target = null;
ClassSet subtypes = getSubtypesOf(interfaceTarget.enclosingClass);
@@ -398,7 +398,7 @@
@override
ClassSet getSubtypesOf(Class class_) {
- if (invalidated) throw "This datastructure has been invalidated";
+ if (invalidated) throw "This data structure has been invalidated";
Set<Class> result = new Set<Class>();
Uint32List list = _infoMap[class_].subtypeIntervalList;
for (int i = 0; i < list.length; i += 2) {
diff --git a/pkg/kernel/lib/clone.dart b/pkg/kernel/lib/clone.dart
index 62b3a7b..e0dc4e7 100644
--- a/pkg/kernel/lib/clone.dart
+++ b/pkg/kernel/lib/clone.dart
@@ -13,7 +13,7 @@
///
/// It is safe to clone members, but cloning a class or library is not
/// supported.
-class CloneVisitor implements TreeVisitor {
+class CloneVisitor implements TreeVisitor<TreeNode> {
final Map<VariableDeclaration, VariableDeclaration> variables =
<VariableDeclaration, VariableDeclaration>{};
final Map<LabeledStatement, LabeledStatement> labels =
@@ -222,6 +222,10 @@
node.unusedArguments.map(clone).toList());
}
+ visitFileUriExpression(FileUriExpression node) {
+ return new FileUriExpression(clone(node.expression), _activeFileUri);
+ }
+
visitIsExpression(IsExpression node) {
return new IsExpression(clone(node.operand), visitType(node.type));
}
diff --git a/pkg/kernel/lib/coq_annot.dart b/pkg/kernel/lib/coq_annot.dart
deleted file mode 100644
index 551ce79..0000000
--- a/pkg/kernel/lib/coq_annot.dart
+++ /dev/null
@@ -1,28 +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.
-//
-// Please see the comments in `pkg/kernel/lib/transformations/coq.dart` for more
-// info.
-
-library kernel.coq_annot;
-
-const coq = 1; // field or class
-const coqref = 2; // class only
-const nocoq = 3; // field only
-const coqopt = 4; // field only
-const coqsingle = 5; // treat List<A> as just A
-const coqdef = 6;
-const coqsingledef = 7;
-
-// library only
-class CoqLib {
- final String destPathRelative;
- const CoqLib(this.destPathRelative);
-}
-
-// TODO(30609): Since fasta currently throws away annotations on Enums, we use a
-// list to identify which enums to convert.
-//
-// We'll uncomment these enums once the Coq formalization is sufficiently complete.
-var coqEnums = [/*"kernel.ast::ProcedureKind", "kernel.ast::AsyncMarker"*/];
diff --git a/pkg/kernel/lib/src/bounds_checks.dart b/pkg/kernel/lib/src/bounds_checks.dart
index a165582..040d266 100644
--- a/pkg/kernel/lib/src/bounds_checks.dart
+++ b/pkg/kernel/lib/src/bounds_checks.dart
@@ -110,7 +110,7 @@
}
}
-DartType instantiateToBounds(DartType type, Class object) {
+DartType instantiateToBounds(DartType type, Class objectClass) {
if (type is InterfaceType) {
for (var typeArgument in type.typeArguments) {
// If at least one of the arguments is not dynamic, we assume that the
@@ -120,8 +120,8 @@
return type;
}
}
- return new InterfaceType.byReference(
- type.className, calculateBounds(type.classNode.typeParameters, object));
+ return new InterfaceType.byReference(type.className,
+ calculateBounds(type.classNode.typeParameters, objectClass));
}
if (type is TypedefType) {
for (var typeArgument in type.typeArguments) {
@@ -130,7 +130,7 @@
}
}
return new TypedefType.byReference(type.typedefReference,
- calculateBounds(type.typedefNode.typeParameters, object));
+ calculateBounds(type.typedefNode.typeParameters, objectClass));
}
return type;
}
@@ -142,15 +142,16 @@
/// (https://github.com/dart-lang/sdk/blob/master/docs/language/informal/instantiate-to-bound.md)
/// of the algorithm for details.
List<DartType> calculateBounds(
- List<TypeParameter> typeParameters, Class object) {
+ List<TypeParameter> typeParameters, Class objectClass) {
List<DartType> bounds = new List<DartType>(typeParameters.length);
for (int i = 0; i < typeParameters.length; i++) {
DartType bound = typeParameters[i].bound;
if (bound == null) {
bound = const DynamicType();
- } else if (bound is InterfaceType && bound.classNode == object) {
+ } else if (bound is InterfaceType && bound.classNode == objectClass) {
DartType defaultType = typeParameters[i].defaultType;
- if (!(defaultType is InterfaceType && defaultType.classNode == object)) {
+ if (!(defaultType is InterfaceType &&
+ defaultType.classNode == objectClass)) {
bound = const DynamicType();
}
}
diff --git a/pkg/kernel/lib/target/targets.dart b/pkg/kernel/lib/target/targets.dart
index 6b88491..64e3b5b 100644
--- a/pkg/kernel/lib/target/targets.dart
+++ b/pkg/kernel/lib/target/targets.dart
@@ -84,7 +84,22 @@
/// A list of URIs of required libraries, not including dart:core.
///
/// Libraries will be loaded in order.
- List<String> get extraRequiredLibraries => <String>[];
+ List<String> get extraRequiredLibraries => const <String>[];
+
+ /// A list of URIs of extra required libraries when compiling the platform.
+ ///
+ /// Libraries will be loaded in order after the [extraRequiredLibraries]
+ /// above.
+ ///
+ /// Normally not needed, but can be useful if removing libraries from the
+ /// [extraRequiredLibraries] list so libraries will still be available in the
+ /// platform if having a weird mix of current and not-quite-current as can
+ /// sometimes be the case.
+ List<String> get extraRequiredLibrariesPlatform => const <String>[];
+
+ /// A list of URIs of libraries to be indexed in the CoreTypes index, not
+ /// including dart:_internal, dart:async, dart:core and dart:mirrors.
+ List<String> get extraIndexedLibraries => const <String>[];
/// Additional declared variables implied by this target.
///
diff --git a/pkg/kernel/lib/text/ast_to_text.dart b/pkg/kernel/lib/text/ast_to_text.dart
index dd19365..ccff048 100644
--- a/pkg/kernel/lib/text/ast_to_text.dart
+++ b/pkg/kernel/lib/text/ast_to_text.dart
@@ -4,6 +4,7 @@
library kernel.ast_to_text;
import 'dart:core' hide MapEntry;
+import 'dart:core' as core show MapEntry;
import 'dart:convert' show json;
@@ -30,8 +31,30 @@
String getName(Constant constant) {
if (!map.containsKey(constant)) {
- // Name everything in post-order visit of DAG.
- constant.visitChildren(this);
+ // When printing a non-fully linked kernel AST (i.e. some [Reference]s
+ // are not bound) to text, we need to avoid dereferencing any
+ // references.
+ //
+ // The normal visitor API causes references to be dereferenced in order
+ // to call the `visit<name>(<name>)` / `visit<name>Reference(<name>)`.
+ //
+ // We therefore handle any subclass of [Constant] which has [Reference]s
+ // specially here.
+ //
+ if (constant is InstanceConstant) {
+ // Avoid visiting `InstanceConstant.classReference`.
+ for (final value in constant.fieldValues.values) {
+ // Name everything in post-order visit of DAG.
+ getName(value);
+ }
+ } else if (constant is TearOffConstant) {
+ // We only care about naming the constants themselves. [TearOffConstant]
+ // has no Constant children.
+ // Avoid visiting `TearOffConstant.procedureReference`.
+ } else {
+ // Name everything in post-order visit of DAG.
+ constant.visitChildren(this);
+ }
}
return super.getName(constant);
}
@@ -39,6 +62,11 @@
defaultConstantReference(Constant constant) {
getName(constant);
}
+
+ defaultDartType(DartType type) {
+ // No need to recurse into dart types, we only care about naming the
+ // constants themselves.
+ }
}
class Disambiguator<T, U> {
@@ -671,7 +699,7 @@
if (name?.name == '') {
writeWord(emptyNameString);
} else {
- writeWord(name?.name ?? '<anon>'); // TODO: write library name
+ writeWord(name?.name ?? '<anonymous>'); // TODO: write library name
}
}
@@ -1163,10 +1191,25 @@
writeIndentation();
writeModifier(descriptor.isExternal, 'external');
writeModifier(descriptor.isStatic, 'static');
- if (descriptor.member.asMember is Procedure) {
- writeWord(procedureKindToString(descriptor.kind));
- } else {
- writeWord('field');
+ switch (descriptor.kind) {
+ case ExtensionMemberKind.Method:
+ writeWord('method');
+ break;
+ case ExtensionMemberKind.Getter:
+ writeWord('get');
+ break;
+ case ExtensionMemberKind.Setter:
+ writeWord('set');
+ break;
+ case ExtensionMemberKind.Operator:
+ writeWord('operator');
+ break;
+ case ExtensionMemberKind.Field:
+ writeWord('field');
+ break;
+ case ExtensionMemberKind.TearOff:
+ writeWord('tearoff');
+ break;
}
writeName(descriptor.name);
writeSpaced('=');
@@ -1394,6 +1437,10 @@
writeSymbol('}');
}
+ visitFileUriExpression(FileUriExpression node) {
+ writeExpression(node.expression);
+ }
+
visitIsExpression(IsExpression node) {
writeExpression(node.operand, Precedence.BITWISE_OR);
writeSpaced('is');
@@ -1999,19 +2046,39 @@
endLine(': ${node.runtimeType}');
}
- writeNullability(Nullability nullability) {
+ void writeNullability(Nullability nullability, {bool inComment = false}) {
switch (nullability) {
case Nullability.legacy:
writeSymbol('*');
- state = WORD; // Disallow a word immediately after the '*'.
+ if (!inComment) {
+ state = WORD; // Disallow a word immediately after the '*'.
+ }
break;
case Nullability.nullable:
- writeSymbol('?'); // Disallow a word immediately after the '?'.
+ writeSymbol('?');
+ if (!inComment) {
+ state = WORD; // Disallow a word immediately after the '?'.
+ }
break;
case Nullability.neither:
- case Nullability.nonNullable:
- // Do nothing.
+ writeSymbol('%');
+ if (!inComment) {
+ state = WORD; // Disallow a word immediately after the '%'.
+ }
break;
+ case Nullability.nonNullable:
+ if (inComment) {
+ writeSymbol("!");
+ }
+ break;
+ }
+ }
+
+ void writeDartTypeNullability(DartType type, {bool inComment = false}) {
+ if (type is InvalidType) {
+ writeNullability(Nullability.neither);
+ } else {
+ writeNullability(type.nullability, inComment: inComment);
}
}
@@ -2052,12 +2119,18 @@
visitTypeParameterType(TypeParameterType node) {
writeTypeParameterReference(node.parameter);
- writeNullability(node.nullability);
+ writeNullability(node.declaredNullability);
if (node.promotedBound != null) {
- writeSpace();
- writeWord('extends');
- writeSpace();
+ writeSpaced('&');
writeType(node.promotedBound);
+
+ writeWord("/* '");
+ writeNullability(node.declaredNullability, inComment: true);
+ writeWord("' & '");
+ writeDartTypeNullability(node.promotedBound, inComment: true);
+ writeWord("' = '");
+ writeNullability(node.nullability, inComment: true);
+ writeWord("' */");
}
}
@@ -2130,14 +2203,20 @@
writeConstantReference(node);
writeSpaced('=');
writeClassReferenceFromReference(node.classReference);
- if (!node.classNode.typeParameters.isEmpty) {
+ if (!node.typeArguments.isEmpty) {
writeSymbol('<');
writeList(node.typeArguments, writeType);
writeSymbol('>');
}
+
writeSymbol(' {');
- writeList(node.fieldValues.entries, (entry) {
- writeWord('${entry.key.asField.name.name}');
+ writeList(node.fieldValues.entries,
+ (core.MapEntry<Reference, Constant> entry) {
+ if (entry.key.node != null) {
+ writeWord('${entry.key.asField.name.name}');
+ } else {
+ writeWord('${entry.key.canonicalName.name}');
+ }
writeSymbol(':');
writeConstantReference(entry.value);
});
@@ -2299,10 +2378,3 @@
}
throw 'illegal ProcedureKind: $kind';
}
-
-class ExpressionPrinter {
- final Printer writeer;
- final int minimumPrecedence;
-
- ExpressionPrinter(this.writeer, this.minimumPrecedence);
-}
diff --git a/pkg/kernel/lib/text/text_serialization_verifier.dart b/pkg/kernel/lib/text/text_serialization_verifier.dart
index b29e0e0..18e2cd5 100644
--- a/pkg/kernel/lib/text/text_serialization_verifier.dart
+++ b/pkg/kernel/lib/text/text_serialization_verifier.dart
@@ -396,6 +396,12 @@
}
@override
+ void visitFileUriExpression(FileUriExpression node) {
+ storeLastSeenUriAndOffset(node);
+ node.visitChildren(this);
+ }
+
+ @override
void visitSymbolConstant(SymbolConstant node) {
storeLastSeenUriAndOffset(node);
node.visitChildren(this);
diff --git a/pkg/kernel/lib/transformations/argument_extraction.dart b/pkg/kernel/lib/transformations/argument_extraction.dart
deleted file mode 100644
index 98af6a5..0000000
--- a/pkg/kernel/lib/transformations/argument_extraction.dart
+++ /dev/null
@@ -1,64 +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.
-
-library kernel.transformations.argument_extraction;
-
-import '../ast.dart'
- show
- Constructor,
- FieldInitializer,
- Initializer,
- Library,
- LocalInitializer,
- Component,
- VariableDeclaration,
- VariableGet;
-import '../core_types.dart' show CoreTypes;
-import '../visitor.dart' show Transformer;
-
-Component transformComponent(CoreTypes coreTypes, Component component) {
- new ArgumentExtractionForTesting().visitComponent(component);
- return component;
-}
-
-void transformLibraries(CoreTypes coreTypes, List<Library> libraries) {
- var transformer = new ArgumentExtractionForTesting();
- for (var library in libraries) {
- transformer.visitLibrary(library);
- }
-}
-
-class ArgumentExtractionForTesting extends Transformer {
- visitConstructor(Constructor node) {
- var newInits = <Initializer>[];
-
- int nameCounter = 0;
- for (var fieldInit in node.initializers) {
- if (fieldInit is FieldInitializer &&
- !fieldInit.field.name.name.endsWith("_li")) {
- // Move the body of the initializer to a new local initializer, and
- // eta-expand the reference to the local initializer in the body of the
- // field initializer.
- var value = fieldInit.value;
-
- var decl = new VariableDeclaration('#li_$nameCounter');
- decl.initializer = value;
- var localInit = new LocalInitializer(decl);
- localInit.parent = node;
- newInits.add(localInit);
-
- fieldInit.value = new VariableGet(decl);
- fieldInit.value.parent = fieldInit;
-
- ++nameCounter;
- newInits.add(fieldInit);
- } else {
- newInits.add(fieldInit);
- }
- }
-
- node.initializers = newInits;
- return super.visitConstructor(node);
- }
-}
diff --git a/pkg/kernel/lib/transformations/async.dart b/pkg/kernel/lib/transformations/async.dart
index 3ea9fe2..caa4ffd 100644
--- a/pkg/kernel/lib/transformations/async.dart
+++ b/pkg/kernel/lib/transformations/async.dart
@@ -80,7 +80,9 @@
ExpressionLifter(this.continuationRewriter);
- Block blockOf(List<Statement> stmts) => new Block(stmts.reversed.toList());
+ Block blockOf(List<Statement> statements) {
+ return new Block(statements.reversed.toList());
+ }
/// Rewrite a toplevel expression (toplevel wrt. a statement).
///
@@ -92,7 +94,7 @@
assert(statements.isEmpty);
var saved = seenAwait;
seenAwait = false;
- Expression result = expression.accept(this);
+ Expression result = expression.accept<TreeNode>(this);
outer.addAll(statements.reversed);
statements.clear();
seenAwait = seenAwait || saved;
@@ -211,25 +213,25 @@
TreeNode visitPropertySet(PropertySet expr) {
return transform(expr, () {
- expr.value = expr.value.accept(this)..parent = expr;
- expr.receiver = expr.receiver.accept(this)..parent = expr;
+ expr.value = expr.value.accept<TreeNode>(this)..parent = expr;
+ expr.receiver = expr.receiver.accept<TreeNode>(this)..parent = expr;
});
}
TreeNode visitDirectPropertySet(DirectPropertySet expr) {
return transform(expr, () {
- expr.value = expr.value.accept(this)..parent = expr;
- expr.receiver = expr.receiver.accept(this)..parent = expr;
+ expr.value = expr.value.accept<TreeNode>(this)..parent = expr;
+ expr.receiver = expr.receiver.accept<TreeNode>(this)..parent = expr;
});
}
TreeNode visitArguments(Arguments args) {
for (var named in args.named.reversed) {
- named.value = named.value.accept(this)..parent = named;
+ named.value = named.value.accept<TreeNode>(this)..parent = named;
}
var positional = args.positional;
for (var i = positional.length - 1; i >= 0; --i) {
- positional[i] = positional[i].accept(this)..parent = args;
+ positional[i] = positional[i].accept<TreeNode>(this)..parent = args;
}
// Returns the arguments, which is assumed at the call sites because they do
// not replace the arguments or set parent pointers.
@@ -239,14 +241,14 @@
TreeNode visitMethodInvocation(MethodInvocation expr) {
return transform(expr, () {
visitArguments(expr.arguments);
- expr.receiver = expr.receiver.accept(this)..parent = expr;
+ expr.receiver = expr.receiver.accept<TreeNode>(this)..parent = expr;
});
}
TreeNode visitDirectMethodInvocation(DirectMethodInvocation expr) {
return transform(expr, () {
visitArguments(expr.arguments);
- expr.receiver = expr.receiver.accept(this)..parent = expr;
+ expr.receiver = expr.receiver.accept<TreeNode>(this)..parent = expr;
});
}
@@ -272,7 +274,7 @@
return transform(expr, () {
var expressions = expr.expressions;
for (var i = expressions.length - 1; i >= 0; --i) {
- expressions[i] = expressions[i].accept(this)..parent = expr;
+ expressions[i] = expressions[i].accept<TreeNode>(this)..parent = expr;
}
});
}
@@ -281,7 +283,8 @@
return transform(expr, () {
var expressions = expr.expressions;
for (var i = expressions.length - 1; i >= 0; --i) {
- expressions[i] = expr.expressions[i].accept(this)..parent = expr;
+ expressions[i] = expr.expressions[i].accept<TreeNode>(this)
+ ..parent = expr;
}
});
}
@@ -289,8 +292,8 @@
TreeNode visitMapLiteral(MapLiteral expr) {
return transform(expr, () {
for (var entry in expr.entries.reversed) {
- entry.value = entry.value.accept(this)..parent = entry;
- entry.key = entry.key.accept(this)..parent = entry;
+ entry.value = entry.value.accept<TreeNode>(this)..parent = entry;
+ entry.key = entry.key.accept<TreeNode>(this)..parent = entry;
}
});
}
@@ -302,15 +305,16 @@
// Right is delimited because it is conditionally evaluated.
var rightStatements = <Statement>[];
seenAwait = false;
- expr.right = delimit(() => expr.right.accept(this), rightStatements)
- ..parent = expr;
+ expr.right =
+ delimit(() => expr.right.accept<TreeNode>(this), rightStatements)
+ ..parent = expr;
var rightAwait = seenAwait;
if (rightStatements.isEmpty) {
// Easy case: right did not emit any statements.
seenAwait = shouldName;
return transform(expr, () {
- expr.left = expr.left.accept(this)..parent = expr;
+ expr.left = expr.left.accept<TreeNode>(this)..parent = expr;
seenAwait = seenAwait || rightAwait;
});
}
@@ -348,7 +352,7 @@
statements.add(new ExpressionStatement(new VariableSet(result, test)));
seenAwait = false;
- test.receiver = test.receiver.accept(this)..parent = test;
+ test.receiver = test.receiver.accept<TreeNode>(this)..parent = test;
++nameIndex;
seenAwait = seenAwait || rightAwait;
@@ -362,22 +366,22 @@
var thenStatements = <Statement>[];
seenAwait = false;
- expr.then = delimit(() => expr.then.accept(this), thenStatements)
+ expr.then = delimit(() => expr.then.accept<TreeNode>(this), thenStatements)
..parent = expr;
var thenAwait = seenAwait;
var otherwiseStatements = <Statement>[];
seenAwait = false;
- expr.otherwise =
- delimit(() => expr.otherwise.accept(this), otherwiseStatements)
- ..parent = expr;
+ expr.otherwise = delimit(
+ () => expr.otherwise.accept<TreeNode>(this), otherwiseStatements)
+ ..parent = expr;
var otherwiseAwait = seenAwait;
if (thenStatements.isEmpty && otherwiseStatements.isEmpty) {
// Easy case: neither then nor otherwise emitted any statements.
seenAwait = shouldName;
return transform(expr, () {
- expr.condition = expr.condition.accept(this)..parent = expr;
+ expr.condition = expr.condition.accept<TreeNode>(this)..parent = expr;
seenAwait = seenAwait || thenAwait || otherwiseAwait;
});
}
@@ -401,7 +405,7 @@
statements.add(branch);
seenAwait = false;
- branch.condition = branch.condition.accept(this)..parent = branch;
+ branch.condition = branch.condition.accept<TreeNode>(this)..parent = branch;
++nameIndex;
seenAwait = seenAwait || thenAwait || otherwiseAwait;
@@ -445,7 +449,8 @@
seenAwait = false;
var index = nameIndex;
- arguments.positional[0] = expr.operand.accept(this)..parent = arguments;
+ arguments.positional[0] = expr.operand.accept<TreeNode>(this)
+ ..parent = arguments;
if (shouldName && index + 1 > nameIndex) nameIndex = index + 1;
seenAwait = true;
@@ -458,7 +463,7 @@
}
TreeNode visitLet(Let expr) {
- var body = expr.body.accept(this);
+ var body = expr.body.accept<TreeNode>(this);
VariableDeclaration variable = expr.variable;
if (seenAwait) {
@@ -479,7 +484,7 @@
statements.add(variable);
var index = nameIndex;
seenAwait = false;
- variable.initializer = variable.initializer.accept(this)
+ variable.initializer = variable.initializer.accept<TreeNode>(this)
..parent = variable;
// Temporaries used in the initializer or the body are not live but the
// temporary used for the body is.
@@ -492,7 +497,7 @@
return transform(expr, () {
// The body has already been translated.
expr.body = body..parent = expr;
- variable.initializer = variable.initializer.accept(this)
+ variable.initializer = variable.initializer.accept<TreeNode>(this)
..parent = variable;
});
}
@@ -506,10 +511,10 @@
TreeNode visitBlockExpression(BlockExpression expr) {
return transform(expr, () {
- expr.value = expr.value.accept(this)..parent = expr;
+ expr.value = expr.value.accept<TreeNode>(this)..parent = expr;
List<Statement> body = <Statement>[];
for (Statement stmt in expr.body.statements.reversed) {
- Statement translation = stmt.accept(this);
+ Statement translation = stmt.accept<TreeNode>(this);
if (translation != null) body.add(translation);
}
expr.body = new Block(body.reversed.toList())..parent = expr;
diff --git a/pkg/kernel/lib/transformations/continuation.dart b/pkg/kernel/lib/transformations/continuation.dart
index a45f713..3e87ef2 100644
--- a/pkg/kernel/lib/transformations/continuation.dart
+++ b/pkg/kernel/lib/transformations/continuation.dart
@@ -16,6 +16,7 @@
static const awaitJumpVar = ':await_jump_var';
static const awaitContextVar = ':await_ctx_var';
static const asyncStackTraceVar = ':async_stack_trace';
+ static const controllerStreamVar = ':controller_stream';
static const exceptionParam = ':exception';
static const stackTraceParam = ':stack_trace';
@@ -59,11 +60,11 @@
RecursiveContinuationRewriter(this.helper);
Component rewriteComponent(Component node) {
- return node.accept(this);
+ return node.accept<TreeNode>(this);
}
Library rewriteLibrary(Library node) {
- return node.accept(this);
+ return node.accept<TreeNode>(this);
}
visitProcedure(Procedure node) {
@@ -135,7 +136,7 @@
TreeNode visitTryCatch(TryCatch node) {
if (node.body != null) {
++currentTryDepth;
- node.body = node.body.accept(this);
+ node.body = node.body.accept<TreeNode>(this);
node.body?.parent = node;
--currentTryDepth;
}
@@ -149,13 +150,13 @@
TreeNode visitTryFinally(TryFinally node) {
if (node.body != null) {
++currentTryDepth;
- node.body = node.body.accept(this);
+ node.body = node.body.accept<TreeNode>(this);
node.body?.parent = node;
--currentTryDepth;
}
if (node.finalizer != null) {
++currentCatchDepth;
- node.finalizer = node.finalizer.accept(this);
+ node.finalizer = node.finalizer.accept<TreeNode>(this);
node.finalizer?.parent = node;
--currentCatchDepth;
}
@@ -233,14 +234,14 @@
// :iterator.isYieldEach=
// and return `true` as long as it did something and `false` when it's done.
return new Block(<Statement>[
- enclosingFunction.body.accept(this),
+ enclosingFunction.body.accept<TreeNode>(this),
new ReturnStatement(new BoolLiteral(false))
..fileOffset = enclosingFunction.fileEndOffset
]);
}
visitYieldStatement(YieldStatement node) {
- Expression transformedExpression = node.expression.accept(this);
+ Expression transformedExpression = node.expression.accept<TreeNode>(this);
var statements = <Statement>[];
if (node.isYieldStar) {
@@ -398,7 +399,7 @@
var saved = statements;
statements = <Statement>[];
for (var statement in stmt.statements) {
- statement.accept(this);
+ statement.accept<TreeNode>(this);
}
saved.add(new Block(statements));
statements = saved;
@@ -414,7 +415,7 @@
var saved = statements;
statements = <Statement>[];
for (var statement in stmt.statements) {
- statement.accept(this);
+ statement.accept<TreeNode>(this);
}
saved.add(new Block(statements));
statements = saved;
@@ -483,7 +484,7 @@
Statement visitDelimited(Statement stmt) {
var saved = statements;
statements = <Statement>[];
- stmt.accept(this);
+ stmt.accept<TreeNode>(this);
Statement result =
statements.length == 1 ? statements.first : new Block(statements);
statements = saved;
@@ -635,7 +636,7 @@
// Place the loop variable declarations at the beginning of the body
// statements and move their initializers to a guarded list of statements.
- // Add assignments to the loop variables from the previous iteration's temp
+ // Add assignments to the loop variables from the previous iterations temp
// variables before the updates.
//
// temps.first is the flag 'first'.
@@ -811,7 +812,7 @@
iteratorVariable,
tryFinally
]);
- block.accept(this);
+ block.accept<TreeNode>(this);
} else {
stmt.iterable = expressionRewriter.rewrite(stmt.iterable, statements)
..parent = stmt;
@@ -892,7 +893,7 @@
}
TreeNode visitFunctionDeclaration(FunctionDeclaration stmt) {
- stmt.function = stmt.function.accept(this)..parent = stmt;
+ stmt.function = stmt.function.accept<TreeNode>(this)..parent = stmt;
statements.add(stmt);
return null;
}
@@ -919,7 +920,7 @@
// dynamic :controller_stream;
VariableDeclaration controllerStreamVariable =
- new VariableDeclaration(":controller_stream");
+ new VariableDeclaration(ContinuationVariables.controllerStreamVar);
statements.add(controllerStreamVariable);
setupAsyncContinuations(statements);
diff --git a/pkg/kernel/lib/transformations/coq.dart b/pkg/kernel/lib/transformations/coq.dart
deleted file mode 100644
index f668737..0000000
--- a/pkg/kernel/lib/transformations/coq.dart
+++ /dev/null
@@ -1,528 +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.
-//
-// This transformations outputs a Coq definitions to resemble the Dart syntax
-// tree.
-//
-// Classes that are supposed to be converted are marked with the `@coq`
-// annotation. Some fields within these classes will be converted according to
-// the following rules:
-//
-// 1. A field labeled `@nocoq` will not be converted.
-//
-// 2. A field labeled `@coq` or `@coqopt` will be converted unless it's type is
-// unuspported, in which case an exception will be raised.
-//
-// 3. An unannotated field will be converted if it has type `T` or `List<T>`,
-// where `T` is a class marked for conversion.
-//
-// Classes marked `@coqref` are referenced by natural numbered IDs wherever
-// fields of their type appear, and we have a finite map resolving these IDs.
-// This breaks cycles in the AST graph and provides a way to identify nodes for
-// substitution.
-//
-// All classes with data members are given an induction type definition with a
-// single constructor, holding the data members of that class. Classes with
-// subclasses are also given an inductive definition enumerating all (converted)
-// subclasses. Their data-member type definition will appear inline in the data
-// member definitions for their leaf subclasses. Due to this representation,
-// converted classes with subclasses must be abstract.
-//
-// Since the whole syntax tree is mutually recursive, all the types are dumped
-// into one big "Inductive ... with ... with ... " definition.
-
-library kernel.transformations.coq;
-
-import 'dart:io';
-import '../ast.dart';
-import '../coq_annot.dart' as coq_annot;
-import '../core_types.dart' show CoreTypes;
-
-enum RefStyle { direct, identified }
-
-enum FieldStyle { list, optional, normal }
-
-class CoqFieldInfo {
- // Only one of these two may be non-null.
- final CoqClassInfo type;
- final String primitiveCoqType;
-
- final String dartName;
- final FieldStyle style;
- bool definitional = false;
-
- String get innerRefType => type == null ? primitiveCoqType : type.refType;
-
- String get refType {
- if (type != null) {
- var rt = definitional ? type.coqType : type.refType;
- if (style == FieldStyle.list) {
- return "list $rt";
- } else if (style == FieldStyle.optional) {
- return "option $rt";
- } else {
- return rt;
- }
- } else {
- if (style == FieldStyle.list) {
- return "list " + primitiveCoqType;
- } else if (style == FieldStyle.optional) {
- return "option " + primitiveCoqType;
- } else {
- return primitiveCoqType;
- }
- }
- }
-
- CoqFieldInfo(this.dartName, this.type, this.primitiveCoqType, this.style);
-}
-
-class CoqClassInfo {
- final Class cls;
- final RefStyle refStyle;
-
- List<CoqClassInfo> subs = <CoqClassInfo>[];
- List<CoqFieldInfo> fields = <CoqFieldInfo>[];
-
- bool needsOption = false;
- bool needsList = false;
-
- String get coqType => coqifyName(cls.name);
- String get coqTypeCaps => coqifyName(cls.name, capitalize: true);
- String get abbrevName => abbrev(cls.name);
- String get abbrevNameCaps => abbrev(cls.name, capitalize: true);
- String get refType => refStyle == RefStyle.direct ? coqType : "nat";
-
- CoqClassInfo(this.cls, this.refStyle);
-
- Iterable<CoqClassInfo> supersWithData(CoqLibInfo info) sync* {
- for (Supertype st = cls.supertype;
- st != null;
- st = st.classNode.supertype) {
- Class spr = st.classNode;
- var sprInfo = info.classes[spr];
- if (sprInfo == null) break;
- if (sprInfo.fields.length == 0) continue;
- yield sprInfo;
- }
- }
-}
-
-class CoqLibInfo {
- final Map<Class, CoqClassInfo> classes = <Class, CoqClassInfo>{};
- CoqLibInfo();
-}
-
-// Get the number associated with the annotation from `coq_annot.dart` on a
-// [Field] or [Class] if one exists, and 0 otherwise. Throws an exception if
-// invalid or multiple annotations are discoverted.
-int getCoqAnnot(NamedNode N, List<Expression> annotations) {
- if (coq_annot.coqEnums.contains("$N")) {
- return coq_annot.coq;
- }
-
- int annot = 0;
- for (var A in annotations) {
- if (A is StaticGet) {
- var target = A.targetReference.node;
- var parent = target.parent;
- if (parent is Library) {
- if (parent is NamedNode && parent.name == "kernel.coq_annot") {
- if (target is Field) {
- if (annot != 0) {
- throw new Exception("ERROR: Multiple Coq annotations on ${N}!");
- }
- switch ("${target.name}") {
- case "coq":
- annot = coq_annot.coq;
- break;
- case "coqref":
- annot = coq_annot.coqref;
- break;
- case "nocoq":
- annot = coq_annot.nocoq;
- break;
- case "coqopt":
- annot = coq_annot.coqopt;
- break;
- case "coqsingle":
- annot = coq_annot.coqsingle;
- break;
- case "coqdef":
- annot = coq_annot.coqdef;
- break;
- case "coqsingledef":
- annot = coq_annot.coqsingledef;
- break;
- default:
- throw new Exception("ERROR: Invalid Coq annotation on ${N}!");
- }
- } else {
- throw new Exception("ERROR: Invalid Coq annotation on ${N}!");
- }
- }
- }
- }
- }
- return annot;
-}
-
-// Determine which classes we're going to convert.
-class CoqPass1 extends RecursiveVisitor {
- CoqLibInfo info;
- CoqPass1(this.info);
-
- visitClass(Class C) {
- int annot = getCoqAnnot(C, C.annotations);
- if (annot == 0) return;
-
- if (annot != coq_annot.coq && annot != coq_annot.coqref) {
- throw new Exception("ERROR: Invalid Coq annotation on ${C.name}!");
- }
-
- info.classes[C] = new CoqClassInfo(
- C, annot == coq_annot.coq ? RefStyle.direct : RefStyle.identified);
- }
-}
-
-// Determine which fields we're going to convert and which classes have
-// converted subclasses.
-class CoqPass2 extends RecursiveVisitor {
- CoqLibInfo info;
- CoreTypes coreTypes;
- CoqPass2(this.info, this.coreTypes);
-
- CoqClassInfo currentClass = null;
-
- String getCoqPrimitiveType(Class cls) {
- if (cls == coreTypes.stringClass) {
- return "string";
- } else if (cls == coreTypes.boolClass) {
- return "bool";
- } else if (cls == coreTypes.intClass) {
- return "nat";
- } else {
- return null;
- }
- }
-
- visitClass(Class C) {
- var classInfo = info.classes[C];
- if (classInfo == null) return;
-
- if (C.supertype != null) {
- Class spr = C.supertype.classNode;
- var sprInfo = info.classes[spr];
- if (sprInfo != null) {
- sprInfo.subs.add(classInfo);
- }
- }
-
- currentClass = classInfo;
- C.visitChildren(this);
- currentClass = null;
- }
-
- visitField(Field F) {
- if (currentClass == null) return;
-
- int annot = getCoqAnnot(F, F.annotations);
- if (annot == coq_annot.nocoq) return;
-
- var type = F.type;
- if (type is! InterfaceType) return;
-
- var interfaceType = type as InterfaceType;
-
- var cls = null;
- bool isList = false;
-
- if (interfaceType.classNode == coreTypes.listClass) {
- isList = annot != coq_annot.coqsingle && annot != coq_annot.coqsingledef;
- if (interfaceType.typeArguments.length != 1) return;
- var elemType = interfaceType.typeArguments[0];
- if (elemType is InterfaceType) {
- cls = elemType.classNode;
- } else if (annot == coq_annot.coqopt) {
- throw new Exception("ERROR: Field $F may not be optional.");
- }
- } else {
- cls = interfaceType.classNode;
- }
-
- FieldStyle style = isList
- ? FieldStyle.list
- : (annot == coq_annot.coqopt ? FieldStyle.optional : FieldStyle.normal);
-
- CoqFieldInfo fieldInfo = null;
- var primitive = getCoqPrimitiveType(cls);
- var fieldName = F.name.name;
-
- if (primitive != null) {
- if (annot == 0) return;
- fieldInfo = new CoqFieldInfo(fieldName, null, primitive, style);
- } else {
- var fieldClassInfo = info.classes[cls];
- if (fieldClassInfo == null) {
- return;
- }
- fieldInfo = new CoqFieldInfo(fieldName, fieldClassInfo, null, style);
-
- if (style == FieldStyle.optional) {
- fieldClassInfo.needsOption = true;
- } else if (style == FieldStyle.list) {
- fieldClassInfo.needsList = true;
- }
-
- if (annot == coq_annot.coqdef || annot == coq_annot.coqsingledef) {
- fieldInfo.definitional = true;
- }
- }
-
- currentClass.fields.add(fieldInfo);
- }
-}
-
-// Conventional Coq code uses underscores instead of camelCase as Dart code
-// does. This function converts the Dart convention to the Coq convention.
-final coqReserved = <String>["let"];
-String coqifyName(String S, {bool capitalize: false}) {
- List<int> codes = <int>[];
- bool skipUnderscore = false;
- for (int i = 0; i < S.length; ++i) {
- var c = S.codeUnitAt(i);
- if (c >= "A".codeUnits[0] && c <= "Z".codeUnits[0]) {
- if (i > 0 && !skipUnderscore) {
- codes.add("_".codeUnitAt(0));
- }
- if (!capitalize) c += ("a".codeUnits[0] - "A".codeUnits[0]);
- codes.add(c);
- } else {
- codes.add(c);
- }
- skipUnderscore = c == "_".codeUnits[0];
- }
- var name = new String.fromCharCodes(codes);
- if (coqReserved.contains(name)) {
- name = "dart_" + name;
- }
- return name;
-}
-
-// Give an abbreviation of a identifying by combining the capital letters of the
-// identifier. For example, "ProcedureKind" becomes "pk" or "PK".
-String abbrev(String S, {bool capitalize: false}) {
- List<int> codes = <int>[];
- for (var c in S.codeUnits)
- if (c >= 65 && c <= 90) codes.add(capitalize ? c : c + 32);
- return new String.fromCharCodes(codes);
-}
-
-void outputCoqImports() {
- print("""
-Require Import Common.
-""");
-}
-
-void outputCoqSyntax(CoqLibInfo info) {
- int defN = 0;
- defkw() => defN++ > 0 ? "with" : "Inductive";
- for (var classInfo in info.classes.values) {
- bool isAbstract = classInfo.subs.length > 0;
-
- Class cls = classInfo.cls;
- var coqName = classInfo.coqType;
-
- if (classInfo.cls.isEnum) {
- var enums = [];
- for (var fld in classInfo.fields) {
- if (fld.dartName == "values") continue;
- enums.add(coqifyName(fld.dartName, capitalize: true));
- }
- print("${defkw()} $coqName : Set := ${enums.join(" | ")}\n");
- continue;
- }
-
- if (!isAbstract || classInfo.fields.length > 0) {
- var suffix = isAbstract ? "_data" : "";
- var dataTypeName = coqName + suffix;
- var dataCtorName = coqifyName(cls.name, capitalize: true);
-
- print("${defkw()} ${dataTypeName} : Set :=");
- print(" | ${dataCtorName} : ");
-
- // Insert fields for superclasses.
- int arw = 0;
- arrow() => arw++ == 0 ? "" : "-> ";
-
- if (classInfo.refStyle == RefStyle.identified) {
- print(" ${arrow()}nat");
- }
-
- for (var sprInfo in classInfo.supersWithData(info)) {
- print(" ${arrow()}${sprInfo.coqType}_data");
- }
-
- for (CoqFieldInfo fld in classInfo.fields) {
- print(" ${arrow()}${fld.refType} (* ${fld.dartName} *)");
- }
-
- print(" ${arrow()}$dataTypeName\n");
- }
-
- if (classInfo.subs.length > 0) {
- print("${defkw()} $coqName : Set :=");
-
- var abbrevName = abbrev(cls.name, capitalize: true);
- for (var sub in classInfo.subs) {
- var subTypeName = coqifyName(sub.cls.name);
- var ctorName = coqifyName(sub.cls.name, capitalize: true);
- print(" | ${abbrevName}_${ctorName} : ${subTypeName} -> $coqName");
- }
-
- print("\n");
- }
- }
- print(".\n");
-}
-
-void outputCoqStore(info) {
- print("Record ast_store : Type := Ast_Store {");
- for (var classInfo in info.classes.values) {
- if (classInfo.refStyle != RefStyle.identified) continue;
- print(" ${classInfo.abbrevName}_refs : NatMap.t ${classInfo.coqType};");
- }
- print("}.\n");
-}
-
-void outputCoqSyntaxValidity(CoqLibInfo info) {
- int defN = 0;
- defkw() => defN++ > 0 ? "with" : "Fixpoint";
-
- validityPredicate(CoqClassInfo CI) {
- if (CI.refStyle == RefStyle.identified) {
- var mapName = "${CI.abbrevName}_refs";
- return (X) => "NatMap.In $X ($mapName ast)";
- } else {
- return (X) => "${CI.coqType}_validity ast $X";
- }
- }
-
- for (var CI in info.classes.values) {
- stdout.write(
- "${defkw()} ${CI.coqType}_validity (ast : ast_store) (T : ${CI.coqType}) {struct T} : Prop :=");
- if (CI.cls.isEnum) {
- stdout.write(" True\n");
- continue;
- } else {
- stdout.write("\n");
- }
-
- print(" match T with");
- for (var sub in CI.subs) {
- print(
- " | ${CI.abbrevNameCaps}_${sub.coqTypeCaps} ST => ${sub.coqType}_validity ast ST");
- }
-
- if (CI.subs.length > 0) {
- print("end");
- if (CI.fields.length == 0) continue;
- print(
- "${defkw()} ${CI.coqType}_data_validity (ast : ast_store) (T : ${CI.coqType}_data) {struct T}: Prop :=");
- print(" match T with");
- }
-
- int i = 0;
- var fieldNames = [];
- var validityClauses = [];
-
- for (var SI in CI.supersWithData(info)) {
- var f = "f${i++}";
- fieldNames.add(f);
- validityClauses.add("${SI.coqType}_data_validity ast $f");
- }
-
- for (var fld in CI.fields) {
- if (fld.type == null) {
- fieldNames.add("_");
- continue;
- }
-
- var f = "f${i++}";
- fieldNames.add(f);
-
- var pred;
- if (fld.style == FieldStyle.normal) {
- pred = validityPredicate(fld.type)(f);
- } else if (fld.style == FieldStyle.list) {
- pred = "${fld.type.coqType}_list_validity ast $f";
- } else if (fld.style == FieldStyle.optional) {
- pred = "${fld.type.coqType}_option_validity ast $f";
- }
-
- validityClauses.add(pred);
- }
-
- var clause = "True";
- if (validityClauses.length > 0) {
- clause = validityClauses.join(" /\\\n ");
- }
-
- print(
- " | ${CI.coqTypeCaps} ${fieldNames.join(" ")} =>\n $clause");
- print(" end");
- }
-
- for (var CI in info.classes.values) {
- var pred = validityPredicate(CI)("X");
- if (CI.needsList) {
- var def = """
-with ${CI.coqType}_list_validity (ast : ast_store) (L : ${CI.coqType}_list) {struct L} : Prop :=
- match L with
- | ${CI.coqType}_nil => True
- | ${CI.coqType}_cons X XS => $pred /\\ ${CI.coqType}_list_validity ast XS
- end""";
- print(def);
- }
- if (CI.needsOption) {
- var def = """
-with ${CI.coqType}_option_validity (ast : ast_store) (O : ${CI.coqType}_option) {struct O} : Prop :=
- match O with
- | ${CI.coqType}_none => True
- | ${CI.coqType}_some X => $pred
- end""";
- print(def);
- }
- }
-
- print(".\n");
-}
-
-void outputCoqStoreValidity(CoqLibInfo info) {
- var clauses = [];
- for (var CI in info.classes.values) {
- if (CI.refStyle != RefStyle.identified) continue;
- var mapName = "${CI.abbrevName}_refs";
- clauses.add(
- " forall (n : nat), forall (X : ${CI.coqType}), NatMap.MapsTo n X ($mapName ast) -> ${CI.coqType}_validity ast X");
- }
- var clause = clauses.join(" /\\\n");
- print(
- "Definition ast_store_validity (ast : ast_store) : Prop := \n$clause\n.");
-}
-
-Component transformComponent(CoreTypes coreTypes, Component component) {
- for (Library lib in component.libraries) {
- // TODO(30610): Ideally we'd output to the file in the coq annotation on the
- // library name, but currently fasta throws away annotations on libraries.
- // Instead, we just special case "kernel.ast" and output to stdout.
- if ("$lib" != "kernel.ast") continue;
- var info = new CoqLibInfo();
- (new CoqPass1(info)).visitLibrary(lib);
- (new CoqPass2(info, coreTypes)).visitLibrary(lib);
- outputCoqImports();
- outputCoqSyntax(info);
- }
- return component;
-}
diff --git a/pkg/kernel/lib/transformations/mixin_full_resolution.dart b/pkg/kernel/lib/transformations/mixin_full_resolution.dart
index 4a401fa..5081b9e 100644
--- a/pkg/kernel/lib/transformations/mixin_full_resolution.dart
+++ b/pkg/kernel/lib/transformations/mixin_full_resolution.dart
@@ -181,7 +181,7 @@
if (src.positionalParameters.length !=
dst.positionalParameters.length ||
src.namedParameters.length != dst.namedParameters.length) {
- // A compile time error has already occured, but don't crash below,
+ // A compile time error has already occurred, but don't crash below,
// and don't add several procedures with the same name to the class.
continue outer;
}
diff --git a/pkg/kernel/lib/transformations/sanitize_for_vm.dart b/pkg/kernel/lib/transformations/sanitize_for_vm.dart
deleted file mode 100644
index afe812d..0000000
--- a/pkg/kernel/lib/transformations/sanitize_for_vm.dart
+++ /dev/null
@@ -1,24 +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.
-library kernel.transformations.fixvm;
-
-import '../ast.dart';
-
-/// Ensures that classes all have either a constructor or a procedure.
-///
-/// VM-specific constraints that don't fit in anywhere else can be put here.
-class SanitizeForVM {
- void transform(Component component) {
- for (var library in component.libraries) {
- for (var class_ in library.classes) {
- if (class_.constructors.isEmpty && class_.procedures.isEmpty) {
- class_.addMember(new Constructor(
- new FunctionNode(new EmptyStatement()),
- name: new Name(''),
- isSynthetic: true));
- }
- }
- }
- }
-}
diff --git a/pkg/kernel/lib/transformations/setup_builtin_library.dart b/pkg/kernel/lib/transformations/setup_builtin_library.dart
deleted file mode 100644
index 07adcb4..0000000
--- a/pkg/kernel/lib/transformations/setup_builtin_library.dart
+++ /dev/null
@@ -1,50 +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.
-
-library kernel.transformations.setup_builtin_library;
-
-import '../ast.dart';
-
-// The DartVM has a special `dart:_builtin` library which exposes a
-// `_getMainClosure()` method. We need to change this method to return a
-// closure of `main()`.
-Component transformComponent(Component component,
- {String libraryUri: 'dart:_builtin'}) {
- Procedure mainMethod = component.mainMethod;
-
- Library builtinLibrary;
- for (Library library in component.libraries) {
- if (library.importUri.toString() == libraryUri) {
- builtinLibrary = library;
- break;
- }
- }
-
- if (builtinLibrary == null) {
- throw new Exception('Could not find "dart:_builtin" library');
- }
-
- FunctionNode getMainClosure;
- for (Procedure procedure in builtinLibrary.procedures) {
- if (procedure.name.name == '_getMainClosure') {
- getMainClosure = procedure.function;
- break;
- }
- }
-
- if (getMainClosure == null) {
- throw new Exception('Could not find "_getMainClosure" in "$libraryUri"');
- }
-
- if (mainMethod != null) {
- var returnMainStatement = new ReturnStatement(new StaticGet(mainMethod));
- getMainClosure.body = returnMainStatement;
- returnMainStatement.parent = getMainClosure;
- } else {
- // TODO(ahe): This should throw no such method error.
- getMainClosure.body = null;
- }
-
- return component;
-}
diff --git a/pkg/kernel/lib/type_algebra.dart b/pkg/kernel/lib/type_algebra.dart
index d847558..d368c2d 100644
--- a/pkg/kernel/lib/type_algebra.dart
+++ b/pkg/kernel/lib/type_algebra.dart
@@ -241,8 +241,8 @@
/// [first] if they overlap.
///
/// Neither substitution is applied to the results of the other, so this does
- /// *not* correspond to a sequence of two subsitutions. For example, combining
- /// `{T -> List<G>}` with `{G -> String}` does not correspond to
+ /// *not* correspond to a sequence of two substitutions. For example,
+ /// combining `{T -> List<G>}` with `{G -> String}` does not correspond to
/// `{T -> List<String>}` because the result from substituting `T` is not
/// searched for occurences of `G`.
static Substitution combine(Substitution first, Substitution second) {
diff --git a/pkg/kernel/lib/type_checker.dart b/pkg/kernel/lib/type_checker.dart
index 8faae52..6c9af84 100644
--- a/pkg/kernel/lib/type_checker.dart
+++ b/pkg/kernel/lib/type_checker.dart
@@ -725,6 +725,11 @@
}
@override
+ DartType visitFileUriExpression(FileUriExpression node) {
+ return visitExpression(node.expression);
+ }
+
+ @override
DartType visitStringLiteral(StringLiteral node) {
return environment.stringType;
}
diff --git a/pkg/kernel/lib/verifier.dart b/pkg/kernel/lib/verifier.dart
index 1bfcb8b..503655e 100644
--- a/pkg/kernel/lib/verifier.dart
+++ b/pkg/kernel/lib/verifier.dart
@@ -202,6 +202,14 @@
currentLibrary = null;
}
+ visitExtension(Extension node) {
+ declareTypeParameters(node.typeParameters);
+ final oldParent = enterParent(node);
+ node.visitChildren(this);
+ exitParent(oldParent);
+ undeclareTypeParameters(node.typeParameters);
+ }
+
void checkTypedef(Typedef node) {
var state = typedefState[node];
if (state == TypedefState.Done) return;
diff --git a/pkg/kernel/lib/visitor.dart b/pkg/kernel/lib/visitor.dart
index bdea433..d3dc88e 100644
--- a/pkg/kernel/lib/visitor.dart
+++ b/pkg/kernel/lib/visitor.dart
@@ -43,6 +43,7 @@
R visitSetConcatenation(SetConcatenation node) => defaultExpression(node);
R visitMapConcatenation(MapConcatenation node) => defaultExpression(node);
R visitInstanceCreation(InstanceCreation node) => defaultExpression(node);
+ R visitFileUriExpression(FileUriExpression node) => defaultExpression(node);
R visitIsExpression(IsExpression node) => defaultExpression(node);
R visitAsExpression(AsExpression node) => defaultExpression(node);
R visitSymbolLiteral(SymbolLiteral node) => defaultExpression(node);
@@ -170,6 +171,7 @@
R visitSetConcatenation(SetConcatenation node) => defaultExpression(node);
R visitMapConcatenation(MapConcatenation node) => defaultExpression(node);
R visitInstanceCreation(InstanceCreation node) => defaultExpression(node);
+ R visitFileUriExpression(FileUriExpression node) => defaultExpression(node);
R visitIsExpression(IsExpression node) => defaultExpression(node);
R visitAsExpression(AsExpression node) => defaultExpression(node);
R visitSymbolLiteral(SymbolLiteral node) => defaultExpression(node);
@@ -403,7 +405,7 @@
/// value for each subnode. The visitor caches the computed values ensuring that
/// each subnode is only visited once.
class ComputeOnceConstantVisitor<R> implements _ConstantCallback<R> {
- _ConstantCallbackVisitor _visitor;
+ _ConstantCallbackVisitor<R> _visitor;
Map<Constant, R> cache = new LinkedHashMap.identity();
ComputeOnceConstantVisitor() {
@@ -685,6 +687,8 @@
defaultExpression(node, arg);
R visitInstanceCreation(InstanceCreation node, T arg) =>
defaultExpression(node, arg);
+ R visitFileUriExpression(FileUriExpression node, T arg) =>
+ defaultExpression(node, arg);
R visitIsExpression(IsExpression node, T arg) => defaultExpression(node, arg);
R visitAsExpression(AsExpression node, T arg) => defaultExpression(node, arg);
R visitSymbolLiteral(SymbolLiteral node, T arg) =>
diff --git a/pkg/kernel/pubspec.yaml b/pkg/kernel/pubspec.yaml
index 2ee72eb..d28cdb0 100644
--- a/pkg/kernel/pubspec.yaml
+++ b/pkg/kernel/pubspec.yaml
@@ -1,7 +1,7 @@
name: kernel
# Currently, kernel API is not stable and users should
# not depend on semver semantics when depending on this package.
-version: 0.3.23
+version: 0.3.24
author: Dart Team <misc@dartlang.org>
description: Dart IR (Intermediate Representation)
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/kernel
diff --git a/pkg/kernel/test/verify_test.dart b/pkg/kernel/test/verify_test.dart
index affbf9f..7f32330 100644
--- a/pkg/kernel/test/verify_test.dart
+++ b/pkg/kernel/test/verify_test.dart
@@ -99,14 +99,14 @@
negativeTest(
'Class type parameter from another class',
"Type parameter 'test_lib::OtherClass::OtherT' referenced out of scope,"
- " parent is: 'test_lib::OtherClass'.", (TestHarness test) {
+ " parent is: 'test_lib::OtherClass'.", (TestHarness test) {
test.addNode(
TypeLiteral(new TypeParameterType(test.otherClass.typeParameters[0])));
});
negativeTest(
'Class type parameter in static method',
"Type parameter 'test_lib::TestClass::T' referenced from static context,"
- " parent is: 'test_lib::TestClass'.", (TestHarness test) {
+ " parent is: 'test_lib::TestClass'.", (TestHarness test) {
test.addNode(Procedure(
new Name('bar'),
ProcedureKind.Method,
@@ -117,7 +117,7 @@
negativeTest(
'Class type parameter in static field',
"Type parameter 'test_lib::TestClass::T' referenced from static context,"
- " parent is: 'test_lib::TestClass'.", (TestHarness test) {
+ " parent is: 'test_lib::TestClass'.", (TestHarness test) {
test.addNode(Field(new Name('field'),
initializer:
new TypeLiteral(new TypeParameterType(test.classTypeParameter)),
@@ -147,13 +147,13 @@
negativeTest(
'Interface type arity too low',
"Type test_lib::OtherClass* provides 0 type arguments"
- " but the class declares 1 parameters.", (TestHarness test) {
+ " but the class declares 1 parameters.", (TestHarness test) {
test.addNode(TypeLiteral(new InterfaceType(test.otherClass, [])));
});
negativeTest(
'Interface type arity too high',
"Type test_lib::OtherClass<dynamic, dynamic>* provides 2 type arguments"
- " but the class declares 1 parameters.", (TestHarness test) {
+ " but the class declares 1 parameters.", (TestHarness test) {
test.addNode(TypeLiteral(new InterfaceType(
test.otherClass, [new DynamicType(), new DynamicType()])));
});
@@ -173,7 +173,7 @@
negativeTest(
'Missing block parent pointer',
"Incorrect parent pointer on ReturnStatement:"
- " expected 'Block', but found: 'Null'.", (TestHarness test) {
+ " expected 'Block', but found: 'Null'.", (TestHarness test) {
var block = new Block([]);
block.statements.add(new ReturnStatement());
test.addNode(block);
@@ -181,7 +181,7 @@
negativeTest(
'Missing function parent pointer',
"Incorrect parent pointer on FunctionNode:"
- " expected 'Procedure', but found: 'Null'.", (TestHarness test) {
+ " expected 'Procedure', but found: 'Null'.", (TestHarness test) {
var procedure = new Procedure(new Name('bar'), ProcedureKind.Method, null);
procedure.function = new FunctionNode(new EmptyStatement());
test.addNode(procedure);
@@ -212,7 +212,7 @@
negativeTest(
'StaticInvocation with too many parameters',
"StaticInvocation with incompatible arguments for"
- " 'test_lib::TestClass::bar'.", (TestHarness test) {
+ " 'test_lib::TestClass::bar'.", (TestHarness test) {
var method = new Procedure(new Name('bar'), ProcedureKind.Method,
new FunctionNode(new EmptyStatement()),
isStatic: true);
@@ -222,7 +222,7 @@
negativeTest(
'StaticInvocation with too few parameters',
"StaticInvocation with incompatible arguments for"
- " 'test_lib::TestClass::bar'.", (TestHarness test) {
+ " 'test_lib::TestClass::bar'.", (TestHarness test) {
var method = new Procedure(
new Name('bar'),
ProcedureKind.Method,
@@ -235,7 +235,7 @@
negativeTest(
'StaticInvocation with unmatched named parameter',
"StaticInvocation with incompatible arguments for"
- " 'test_lib::TestClass::bar'.", (TestHarness test) {
+ " 'test_lib::TestClass::bar'.", (TestHarness test) {
var method = new Procedure(new Name('bar'), ProcedureKind.Method,
new FunctionNode(new EmptyStatement()),
isStatic: true);
@@ -248,7 +248,7 @@
negativeTest(
'StaticInvocation with missing type argument',
"StaticInvocation with wrong number of type arguments for"
- " 'test_lib::TestClass::bar'.", (TestHarness test) {
+ " 'test_lib::TestClass::bar'.", (TestHarness test) {
var method = new Procedure(
new Name('bar'),
ProcedureKind.Method,
@@ -261,7 +261,7 @@
negativeTest(
'ConstructorInvocation with missing type argument',
"ConstructorInvocation with wrong number of type arguments for"
- " 'test_lib::TestClass::foo'.", (TestHarness test) {
+ " 'test_lib::TestClass::foo'.", (TestHarness test) {
var class_ = new Class(
name: 'Test',
typeParameters: [test.makeTypeParameter()],
@@ -309,7 +309,7 @@
negativeTest(
'Invalid typedef Foo = Foo',
"The typedef 'typedef Foo = test_lib::Foo;\n'"
- " refers to itself", (TestHarness test) {
+ " refers to itself", (TestHarness test) {
var typedef_ = new Typedef('Foo', null);
typedef_.type = new TypedefType(typedef_);
test.addNode(typedef_);
@@ -317,7 +317,7 @@
negativeTest(
'Invalid typedef Foo = `(Foo) => void`',
"The typedef 'typedef Foo = (test_lib::Foo) →* void;\n'"
- " refers to itself", (TestHarness test) {
+ " refers to itself", (TestHarness test) {
var typedef_ = new Typedef('Foo', null);
typedef_.type =
new FunctionType([new TypedefType(typedef_)], const VoidType());
@@ -326,7 +326,7 @@
negativeTest(
'Invalid typedef Foo = `() => Foo`',
"The typedef 'typedef Foo = () →* test_lib::Foo;\n'"
- " refers to itself", (TestHarness test) {
+ " refers to itself", (TestHarness test) {
var typedef_ = new Typedef('Foo', null);
typedef_.type = new FunctionType([], new TypedefType(typedef_));
test.addNode(typedef_);
@@ -334,7 +334,7 @@
negativeTest(
'Invalid typedef Foo = C<Foo>',
"The typedef 'typedef Foo = test_lib::OtherClass<test_lib::Foo>*;\n'"
- " refers to itself", (TestHarness test) {
+ " refers to itself", (TestHarness test) {
var typedef_ = new Typedef('Foo', null);
typedef_.type =
new InterfaceType(test.otherClass, [new TypedefType(typedef_)]);
@@ -343,7 +343,7 @@
negativeTest(
'Invalid typedefs Foo = Bar, Bar = Foo',
"The typedef 'typedef Foo = test_lib::Bar;\n'"
- " refers to itself", (TestHarness test) {
+ " refers to itself", (TestHarness test) {
var foo = new Typedef('Foo', null);
var bar = new Typedef('Bar', null);
foo.type = new TypedefType(bar);
@@ -354,7 +354,7 @@
negativeTest(
'Invalid typedefs Foo = Bar, Bar = C<Foo>',
"The typedef 'typedef Foo = test_lib::Bar;\n'"
- " refers to itself", (TestHarness test) {
+ " refers to itself", (TestHarness test) {
var foo = new Typedef('Foo', null);
var bar = new Typedef('Bar', null);
foo.type = new TypedefType(bar);
@@ -365,7 +365,7 @@
negativeTest(
'Invalid typedefs Foo = C<Bar>, Bar = C<Foo>',
"The typedef 'typedef Foo = test_lib::OtherClass<test_lib::Bar>*;\n'"
- " refers to itself", (TestHarness test) {
+ " refers to itself", (TestHarness test) {
var foo = new Typedef('Foo', null);
var bar = new Typedef('Bar', null);
foo.type = new InterfaceType(test.otherClass, [new TypedefType(bar)]);
@@ -385,7 +385,7 @@
negativeTest(
'Invalid long typedefs C20 = C19 = ... = C1 = C0 = C20',
"The typedef 'typedef C0 = test_lib::C19;\n'"
- " refers to itself", (TestHarness test) {
+ " refers to itself", (TestHarness test) {
var typedef_ = new Typedef('C0', null);
test.enclosingLibrary.addTypedef(typedef_);
var first = typedef_;
@@ -427,7 +427,7 @@
negativeTest(
'Invalid typedefs Foo<T extends Bar<T>>, Bar<T extends Foo<T>>',
"The typedef 'typedef Foo<T extends test_lib::Bar<T*>> = dynamic;\n'"
- " refers to itself", (TestHarness test) {
+ " refers to itself", (TestHarness test) {
var fooParam = test.makeTypeParameter('T');
var foo =
new Typedef('Foo', const DynamicType(), typeParameters: [fooParam]);
@@ -443,8 +443,8 @@
negativeTest(
'Invalid typedef Foo<T extends Foo<dynamic> = C<T>',
"The typedef 'typedef Foo<T extends test_lib::Foo<dynamic>> = "
- "test_lib::OtherClass<T>*;\n'"
- " refers to itself", (TestHarness test) {
+ "test_lib::OtherClass<T*>*;\n'"
+ " refers to itself", (TestHarness test) {
var param = new TypeParameter('T', null);
var foo = new Typedef('Foo',
new InterfaceType(test.otherClass, [new TypeParameterType(param)]),
@@ -455,7 +455,7 @@
negativeTest(
'Typedef arity error',
"The typedef type test_lib::Foo provides 0 type arguments"
- " but the typedef declares 1 parameters.", (TestHarness test) {
+ " but the typedef declares 1 parameters.", (TestHarness test) {
var param = test.makeTypeParameter('T');
var foo =
new Typedef('Foo', test.otherClass.rawType, typeParameters: [param]);
@@ -467,7 +467,7 @@
negativeTest(
'Dangling typedef reference',
"Dangling reference to 'typedef Foo = test_lib::OtherClass<dynamic>*;\n'"
- ", parent is: 'null'", (TestHarness test) {
+ ", parent is: 'null'", (TestHarness test) {
var foo = new Typedef('Foo', test.otherClass.rawType, typeParameters: []);
var field = new Field(new Name('field'),
type: new TypedefType(foo, []), isStatic: true);
diff --git a/pkg/meta/lib/meta.dart b/pkg/meta/lib/meta.dart
index eefb621..285356d 100644
--- a/pkg/meta/lib/meta.dart
+++ b/pkg/meta/lib/meta.dart
@@ -89,8 +89,8 @@
/// Tools, such as the analyzer, can provide feedback if
///
/// * the annotation is associated with anything other than a method, or
-/// * the annotation is associated with a method that has this annotation that
-/// can return anything other than a newly allocated object or `null`.
+/// * a method that has this annotation can return anything other than a newly
+/// allocated object or `null`.
const _Factory factory = const _Factory();
/// Used to annotate a class `C`. Indicates that `C` and all subtypes of `C`
@@ -149,10 +149,10 @@
/// without invoking the overridden method.
const _MustCallSuper mustCallSuper = const _MustCallSuper();
-/// Used to annotate a class declaration `C`. Indicates that any type arguments
-/// declared on `C` are to be treated as optional. Tools such as the analyzer
-/// and linter can use this information to suppress warnings that would
-/// otherwise require type arguments to be provided for instances of `C`.
+/// Used to annotate a class, mixin, or extension declaration `C`. Indicates
+/// that any type arguments declared on `C` are to be treated as optional.
+/// Tools such as the analyzer and linter can use this information to suppress
+/// warnings that would otherwise require type arguments on `C` to be provided.
const _OptionalTypeArgs optionalTypeArgs = const _OptionalTypeArgs();
/// Used to annotate an instance member (method, getter, setter, operator, or
@@ -168,9 +168,10 @@
/// * the annotation is associated with anything other than an instance member,
/// or
/// * an invocation of a member that has this annotation is used outside of an
-/// instance member defined on a class that extends or mixes in the class in
-/// which the protected member is defined, or that uses a receiver other than
-/// `this`.
+/// instance member defined on a class that extends or mixes in (or a mixin
+/// constrained to) the class in which the protected member is defined.
+/// * an invocation of a member that has this annotation is used within an
+/// instance method, but the receiver is something other than `this`.
const _Protected protected = const _Protected();
/// Used to annotate a named parameter `p` in a method or function `f`.
@@ -216,7 +217,7 @@
/// Tools, such as the analyzer, can provide feedback if
///
/// * the annotation is associated with a declaration other than a public
-/// instance member in a class, or
+/// instance member in a class or mixin, or
/// * the member is referenced outside of the defining library.
const _VisibleForOverriding visibleForOverriding =
const _VisibleForOverriding();
@@ -227,7 +228,8 @@
/// Tools, such as the analyzer, can provide feedback if
///
/// * the annotation is associated with a declaration not in the `lib` folder
-/// of a package, or
+/// of a package, or a private declaration, or a declaration in an unnamed
+/// static extension, or
/// * the declaration is referenced outside of its the defining library or a
/// library which is in the `test` folder of the defining package.
const _VisibleForTesting visibleForTesting = const _VisibleForTesting();
@@ -240,7 +242,7 @@
final String reason;
/// Initialize a newly created instance to have the given [reason].
- const Immutable([this.reason]);
+ const Immutable([this.reason = '']);
}
/// Used to annotate a named parameter `p` in a method or function `f`.
@@ -259,7 +261,7 @@
final String reason;
/// Initialize a newly created instance to have the given [reason].
- const Required([this.reason]);
+ const Required([this.reason = '']);
}
class _AlwaysThrows {
diff --git a/pkg/nnbd_migration/lib/src/already_migrated_code_decorator.dart b/pkg/nnbd_migration/lib/src/already_migrated_code_decorator.dart
index a01cb83..f34d762 100644
--- a/pkg/nnbd_migration/lib/src/already_migrated_code_decorator.dart
+++ b/pkg/nnbd_migration/lib/src/already_migrated_code_decorator.dart
@@ -2,8 +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:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/generated/resolver.dart';
import 'package:nnbd_migration/src/decorated_type.dart';
import 'package:nnbd_migration/src/nullability_node.dart';
@@ -13,7 +15,9 @@
class AlreadyMigratedCodeDecorator {
final NullabilityGraph _graph;
- AlreadyMigratedCodeDecorator(this._graph);
+ final TypeProvider _typeProvider;
+
+ AlreadyMigratedCodeDecorator(this._graph, this._typeProvider);
/// Transforms [type], which should have come from code that has already been
/// migrated to NNBD, into the corresponding [DecoratedType].
@@ -21,12 +25,10 @@
if (type.isVoid || type.isDynamic) {
return DecoratedType(type, _graph.always);
}
+ NullabilityNode node;
var nullabilitySuffix = (type as TypeImpl).nullabilitySuffix;
if (nullabilitySuffix == NullabilitySuffix.question) {
- // TODO(paulberry): add support for depending on already-migrated packages
- // containing nullable types.
- throw UnimplementedError(
- 'Migration depends on an already-migrated nullable type');
+ node = _graph.always;
} else {
// Currently, all types passed to this method have nullability suffix `star`
// because (a) we don't yet have a migrated SDK, and (b) we haven't added
@@ -34,11 +36,18 @@
// migrated with NNBD enabled.
// TODO(paulberry): fix this assertion when things change.
assert(nullabilitySuffix == NullabilitySuffix.star);
+ node = _graph.never;
}
if (type is FunctionType) {
- if (type.typeFormals.isNotEmpty) {
- throw UnimplementedError('Decorating generic function type');
- }
+ var typeFormalBounds = type.typeFormals.map((e) {
+ var bound = e.bound;
+ if (bound == null) {
+ return decorate((_typeProvider.objectType as TypeImpl)
+ .withNullability(NullabilitySuffix.question));
+ } else {
+ return decorate(bound);
+ }
+ }).toList();
var positionalParameters = <DecoratedType>[];
var namedParameters = <String, DecoratedType>{};
for (var parameter in type.parameters) {
@@ -48,23 +57,44 @@
namedParameters[parameter.name] = decorate(parameter.type);
}
}
- return DecoratedType(type, _graph.never,
+ return DecoratedType(type, node,
+ typeFormalBounds: typeFormalBounds,
returnType: decorate(type.returnType),
namedParameters: namedParameters,
positionalParameters: positionalParameters);
} else if (type is InterfaceType) {
if (type.typeParameters.isNotEmpty) {
assert(type.typeArguments.length == type.typeParameters.length);
- return DecoratedType(type, _graph.never,
+ return DecoratedType(type, node,
typeArguments: type.typeArguments.map(decorate).toList());
}
- return DecoratedType(type, _graph.never);
+ return DecoratedType(type, node);
} else if (type is TypeParameterType) {
- return DecoratedType(type, _graph.never);
+ return DecoratedType(type, node);
} else {
// TODO(paulberry)
throw UnimplementedError(
'Unable to decorate already-migrated type $type');
}
}
+
+ /// Get all the decorated immediate supertypes of the non-migrated class
+ /// [class_].
+ Iterable<DecoratedType> getImmediateSupertypes(ClassElement class_) {
+ var allSupertypes = <DartType>[];
+ var supertype = class_.supertype;
+ if (supertype != null) {
+ allSupertypes.add(supertype);
+ }
+ allSupertypes.addAll(class_.superclassConstraints);
+ allSupertypes.addAll(class_.interfaces);
+ allSupertypes.addAll(class_.mixins);
+ var type = class_.type;
+ if (type.isDartAsyncFuture) {
+ // Add FutureOr<T> as a supertype of Future<T>.
+ allSupertypes
+ .add(_typeProvider.futureOrType.instantiate(type.typeArguments));
+ }
+ return allSupertypes.map(decorate);
+ }
}
diff --git a/pkg/nnbd_migration/lib/src/decorated_class_hierarchy.dart b/pkg/nnbd_migration/lib/src/decorated_class_hierarchy.dart
index 40a4d8d..8c46c9e 100644
--- a/pkg/nnbd_migration/lib/src/decorated_class_hierarchy.dart
+++ b/pkg/nnbd_migration/lib/src/decorated_class_hierarchy.dart
@@ -4,7 +4,6 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/dart/element/handle.dart';
import 'package:nnbd_migration/src/decorated_type.dart';
import 'package:nnbd_migration/src/node_builder.dart';
import 'package:nnbd_migration/src/nullability_node.dart';
@@ -26,26 +25,6 @@
DecoratedClassHierarchy(this._variables, this._graph);
- /// Retrieves a [DecoratedType] describing how [class_] implements
- /// [superclass].
- ///
- /// If [class_] does not implement [superclass], raises an exception.
- ///
- /// Note that the returned [DecoratedType] will have a node of `never`,
- /// because the relationship between a class and its superclass is not
- /// nullable.
- DecoratedType getDecoratedSupertype(
- ClassElement class_, ClassElement superclass) {
- assert(!(class_.library.isDartCore && class_.name == 'Null'));
- assert(class_ is! ClassElementHandle);
- assert(superclass is! ClassElementHandle);
- if (superclass.typeParameters.isEmpty) {
- return DecoratedType(superclass.type, _graph.never);
- }
- return _getGenericSupertypeDecorations(class_)[superclass] ??
- (throw StateError('Unrelated types'));
- }
-
/// Retrieves a [DecoratedType] describing how [type] implements [superclass].
///
/// If [type] is not an interface type, or it does not implement [superclass],
@@ -62,6 +41,24 @@
return result.withNode(type.node);
}
+ /// Retrieves a [DecoratedType] describing how [class_] implements
+ /// [superclass].
+ ///
+ /// If [class_] does not implement [superclass], raises an exception.
+ ///
+ /// Note that the returned [DecoratedType] will have a node of `never`,
+ /// because the relationship between a class and its superclass is not
+ /// nullable.
+ DecoratedType getDecoratedSupertype(
+ ClassElement class_, ClassElement superclass) {
+ assert(!(class_.library.isDartCore && class_.name == 'Null'));
+ if (superclass.typeParameters.isEmpty) {
+ return DecoratedType(superclass.type, _graph.never);
+ }
+ return _getGenericSupertypeDecorations(class_)[superclass] ??
+ (throw StateError('Unrelated types: $class_ and $superclass'));
+ }
+
/// Computes a map whose keys are all the superclasses of [class_], and whose
/// values indicate how [class_] implements each superclass.
Map<ClassElement, DecoratedType> _getGenericSupertypeDecorations(
@@ -70,7 +67,7 @@
if (decorations == null) {
// Call ourselves recursively to compute how each of [class_]'s direct
// superclasses relates to all of its transitive superclasses.
- decorations = _genericSupertypeDecorations[class_] = {};
+ decorations = {};
var decoratedDirectSupertypes =
_variables.decoratedDirectSupertypes(class_);
for (var entry in decoratedDirectSupertypes.entries) {
@@ -96,6 +93,7 @@
// superclass.
decorations[superclass] ??= decoratedSupertype;
}
+ _genericSupertypeDecorations[class_] = decorations;
}
return decorations;
}
diff --git a/pkg/nnbd_migration/lib/src/decorated_type.dart b/pkg/nnbd_migration/lib/src/decorated_type.dart
index 1480f7e..9982d1f 100644
--- a/pkg/nnbd_migration/lib/src/decorated_type.dart
+++ b/pkg/nnbd_migration/lib/src/decorated_type.dart
@@ -70,7 +70,7 @@
for (int i = 0; i < typeFormalBounds.length; i++) {
var declaredBound = type.typeFormals[i].bound;
if (declaredBound == null) {
- assert(typeFormalBounds[i].type.isDartCoreObject);
+ assert(typeFormalBounds[i].type.toString() == 'Object');
} else {
assert(typeFormalBounds[i].type == declaredBound);
}
@@ -140,20 +140,38 @@
/// nodes everywhere that don't correspond to any source location. These
/// nodes can later be unioned with other nodes.
factory DecoratedType.forImplicitType(
- TypeProvider typeProvider, DartType type, NullabilityGraph graph) {
+ TypeProvider typeProvider, DartType type, NullabilityGraph graph,
+ {List<DecoratedType> typeArguments}) {
if (type.isDynamic || type.isVoid) {
+ assert(typeArguments == null);
return DecoratedType(type, graph.always);
} else if (type is InterfaceType) {
+ assert(() {
+ if (typeArguments != null) {
+ assert(typeArguments.length == type.typeArguments.length);
+ for (var i = 0; i < typeArguments.length; ++i) {
+ assert(typeArguments[i].type == type.typeArguments[i]);
+ }
+ }
+ return true;
+ }());
+
+ typeArguments ??= type.typeArguments
+ .map((t) => DecoratedType.forImplicitType(typeProvider, t, graph))
+ .toList();
return DecoratedType(type, NullabilityNode.forInferredType(),
- typeArguments: type.typeArguments
- .map((t) => DecoratedType.forImplicitType(typeProvider, t, graph))
- .toList());
+ typeArguments: typeArguments);
} else if (type is FunctionType) {
+ if (typeArguments != null) {
+ throw "Not supported: implicit function type with explicit type arguments";
+ }
return DecoratedType.forImplicitFunction(
typeProvider, type, NullabilityNode.forInferredType(), graph);
} else if (type is TypeParameterType) {
+ assert(typeArguments == null);
return DecoratedType(type, NullabilityNode.forInferredType());
} else if (type is BottomTypeImpl) {
+ assert(typeArguments == null);
return DecoratedType(type, NullabilityNode.forInferredType());
}
// TODO(paulberry)
@@ -163,8 +181,7 @@
/// Creates a [DecoratedType] for a synthetic type parameter, to be used
/// during comparison of generic function types.
- DecoratedType._forTypeParameterSubstitution(
- TypeParameterElementImpl parameter)
+ DecoratedType._forTypeParameterSubstitution(TypeParameterElement parameter)
: type = TypeParameterTypeImpl(parameter),
node = null,
returnType = null,
@@ -290,6 +307,7 @@
DecoratedType instantiate(List<DecoratedType> argumentTypes) {
var type = this.type as FunctionType;
var typeFormals = type.typeFormals;
+ assert(argumentTypes.length == typeFormals.length);
List<DartType> undecoratedArgumentTypes = [];
Map<TypeParameterElement, DecoratedType> substitution = {};
for (int i = 0; i < argumentTypes.length; i++) {
@@ -323,7 +341,7 @@
@override
String toString() {
- var trailing = node.debugSuffix;
+ var trailing = node == null ? '' : node.debugSuffix;
var type = this.type;
if (type is TypeParameterType || type is VoidType) {
return '$type$trailing';
@@ -382,8 +400,27 @@
DartType undecoratedResult) {
var type = this.type;
if (type is FunctionType && undecoratedResult is FunctionType) {
- assert(type.typeFormals.isEmpty); // TODO(paulberry)
- return _substituteFunctionAfterFormals(undecoratedResult, substitution);
+ var typeFormals = type.typeFormals;
+ assert(typeFormals.length == undecoratedResult.typeFormals.length);
+ var newTypeFormalBounds = <DecoratedType>[];
+ if (typeFormals.isNotEmpty) {
+ // The analyzer sometimes allocates fresh type variables when performing
+ // substitutions, so we need to reflect that in our decorations by
+ // substituting to use the type variables the analyzer used.
+ substitution =
+ Map<TypeParameterElement, DecoratedType>.from(substitution);
+ for (int i = 0; i < typeFormals.length; i++) {
+ substitution[typeFormals[i]] =
+ DecoratedType._forTypeParameterSubstitution(
+ undecoratedResult.typeFormals[i]);
+ }
+ for (int i = 0; i < typeFormalBounds.length; i++) {
+ newTypeFormalBounds.add(typeFormalBounds[i]._substitute(
+ substitution, typeFormals[i].bound ?? typeFormalBounds[i].type));
+ }
+ }
+ return _substituteFunctionAfterFormals(undecoratedResult, substitution,
+ newTypeFormalBounds: newTypeFormalBounds);
} else if (type is InterfaceType && undecoratedResult is InterfaceType) {
List<DecoratedType> newTypeArguments = [];
for (int i = 0; i < typeArguments.length; i++) {
@@ -400,10 +437,10 @@
return inner
.withNode(NullabilityNode.forSubstitution(inner.node, node));
}
- } else if (type is VoidType) {
+ } else if (type.isVoid || type.isDynamic) {
return this;
}
- throw '$type.substitute($substitution)'; // TODO(paulberry)
+ throw '$type.substitute($type | $substitution)'; // TODO(paulberry)
}
/// Performs the logic that is common to substitution and function type
@@ -411,20 +448,31 @@
/// is [undecoratedResult], and whose return type, positional parameters, and
/// named parameters are formed by performing the given [substitution].
DecoratedType _substituteFunctionAfterFormals(FunctionType undecoratedResult,
- Map<TypeParameterElement, DecoratedType> substitution) {
+ Map<TypeParameterElement, DecoratedType> substitution,
+ {List<DecoratedType> newTypeFormalBounds = const []}) {
var newPositionalParameters = <DecoratedType>[];
+ var numRequiredParameters = undecoratedResult.normalParameterTypes.length;
for (int i = 0; i < positionalParameters.length; i++) {
- var numRequiredParameters = undecoratedResult.normalParameterTypes.length;
var undecoratedParameterType = i < numRequiredParameters
? undecoratedResult.normalParameterTypes[i]
: undecoratedResult.optionalParameterTypes[i - numRequiredParameters];
newPositionalParameters.add(positionalParameters[i]
._substitute(substitution, undecoratedParameterType));
}
+ var newNamedParameters = <String, DecoratedType>{};
+ for (var entry in namedParameters.entries) {
+ var name = entry.key;
+ var undecoratedParameterType =
+ undecoratedResult.namedParameterTypes[name];
+ newNamedParameters[name] =
+ (entry.value._substitute(substitution, undecoratedParameterType));
+ }
return DecoratedType(undecoratedResult, node,
+ typeFormalBounds: newTypeFormalBounds,
returnType:
returnType._substitute(substitution, undecoratedResult.returnType),
- positionalParameters: newPositionalParameters);
+ positionalParameters: newPositionalParameters,
+ namedParameters: newNamedParameters);
}
List<DecoratedType> _substituteList(List<DecoratedType> list,
diff --git a/pkg/nnbd_migration/lib/src/edge_builder.dart b/pkg/nnbd_migration/lib/src/edge_builder.dart
index d6bdee5..5a73336 100644
--- a/pkg/nnbd_migration/lib/src/edge_builder.dart
+++ b/pkg/nnbd_migration/lib/src/edge_builder.dart
@@ -37,6 +37,9 @@
@override
final TypeSystem _typeSystem;
+ @override
+ final TypeProvider _typeProvider;
+
final NullabilityGraph _graph;
/// Tests should fill in this map with the bounds of any type parameters being
@@ -46,8 +49,8 @@
@override
final DecoratedClassHierarchy _decoratedClassHierarchy;
- AssignmentCheckerForTesting(
- this._typeSystem, this._graph, this._decoratedClassHierarchy);
+ AssignmentCheckerForTesting(this._typeSystem, this._typeProvider, this._graph,
+ this._decoratedClassHierarchy);
void checkAssignment(EdgeOrigin origin,
{@required DecoratedType source,
@@ -95,6 +98,8 @@
final NullabilityGraph _graph;
+ TypeProvider _typeProvider;
+
@override
final Source source;
@@ -122,6 +127,9 @@
/// For convenience, a [DecoratedType] representing `Null`.
final DecoratedType _nullType;
+ /// For convenience, a [DecoratedType] representing `dynamic`.
+ final DecoratedType _dynamicType;
+
/// The [DecoratedType] of the innermost function or method being visited, or
/// `null` if the visitor is not inside any function or method.
///
@@ -130,11 +138,25 @@
DecoratedType _currentFunctionType;
/// The [DecoratedType] of the innermost list or set literal being visited, or
- /// `null` if the visitor is not inside any function or method.
+ /// `null` if the visitor is not inside any list or set.
///
/// This is needed to construct the appropriate nullability constraints for
- /// ui as code list elements.
- DecoratedType _currentLiteralType;
+ /// ui as code elements.
+ DecoratedType _currentLiteralElementType;
+
+ /// The key [DecoratedType] of the innermost map literal being visited, or
+ /// `null` if the visitor is not inside any map.
+ ///
+ /// This is needed to construct the appropriate nullability constraints for
+ /// ui as code elements.
+ DecoratedType _currentMapKeyType;
+
+ /// The value [DecoratedType] of the innermost map literal being visited, or
+ /// `null` if the visitor is not inside any map.
+ ///
+ /// This is needed to construct the appropriate nullability constraints for
+ /// ui as code elements.
+ DecoratedType _currentMapValueType;
/// Information about the most recently visited binary expression whose
/// boolean value could possibly affect nullability analysis.
@@ -164,41 +186,33 @@
/// nullable.
final Map<Expression, NullabilityNode> _conditionalNodes = {};
- EdgeBuilder(TypeProvider typeProvider, this._typeSystem, this._variables,
+ List<String> _objectGetNames;
+
+ EdgeBuilder(this._typeProvider, this._typeSystem, this._variables,
this._graph, this.source, this.listener)
: _decoratedClassHierarchy = DecoratedClassHierarchy(_variables, _graph),
_inheritanceManager = InheritanceManager3(_typeSystem),
- _notNullType = DecoratedType(typeProvider.objectType, _graph.never),
+ _notNullType = DecoratedType(_typeProvider.objectType, _graph.never),
_nonNullableBoolType =
- DecoratedType(typeProvider.boolType, _graph.never),
+ DecoratedType(_typeProvider.boolType, _graph.never),
_nonNullableTypeType =
- DecoratedType(typeProvider.typeType, _graph.never),
- _nullType = DecoratedType(typeProvider.nullType, _graph.always);
+ DecoratedType(_typeProvider.typeType, _graph.never),
+ _nullType = DecoratedType(_typeProvider.nullType, _graph.always),
+ _dynamicType = DecoratedType(_typeProvider.dynamicType, _graph.always);
/// Gets the decorated type of [element] from [_variables], performing any
/// necessary substitutions.
DecoratedType getOrComputeElementType(Element element,
{DecoratedType targetType}) {
Map<TypeParameterElement, DecoratedType> substitution;
- Element baseElement;
- if (element is Member) {
- assert(targetType != null);
- baseElement = element.baseElement;
- var targetTypeType = targetType.type;
- if (targetTypeType is InterfaceType &&
- baseElement is ClassMemberElement) {
- var enclosingClass = baseElement.enclosingElement as ClassElement;
- assert(targetTypeType.element == enclosingClass); // TODO(paulberry)
- substitution = <TypeParameterElement, DecoratedType>{};
- assert(enclosingClass.typeParameters.length ==
- targetTypeType.typeArguments.length); // TODO(paulberry)
- for (int i = 0; i < enclosingClass.typeParameters.length; i++) {
- substitution[enclosingClass.typeParameters[i]] =
- targetType.typeArguments[i];
- }
+ Element baseElement = element is Member ? element.baseElement : element;
+ if (targetType != null) {
+ var classElement = baseElement.enclosingElement as ClassElement;
+ if (classElement.typeParameters.isNotEmpty) {
+ substitution = _decoratedClassHierarchy
+ .asInstanceOf(targetType, classElement)
+ .asSubstitution;
}
- } else {
- baseElement = element;
}
DecoratedType decoratedBaseType;
if (baseElement is PropertyAccessorElement &&
@@ -224,6 +238,8 @@
elementType = element.type;
} else if (element is ConstructorElement) {
elementType = element.type;
+ } else if (element is PropertyAccessorMember) {
+ elementType = element.type;
} else {
throw element.runtimeType; // TODO(paulberry)
}
@@ -235,8 +251,9 @@
@override
DecoratedType visitAsExpression(AsExpression node) {
- // TODO(brianwilkerson)
- _unimplemented(node, 'AsExpression');
+ final typeNode = _variables.decoratedTypeAnnotation(source, node.type);
+ _handleAssignment(node.expression, destinationType: typeNode);
+ return typeNode;
}
@override
@@ -256,13 +273,16 @@
@override
DecoratedType visitAssignmentExpression(AssignmentExpression node) {
- if (node.operator.type != TokenType.EQ) {
- // TODO(paulberry)
- _unimplemented(node, 'Assignment with operator ${node.operator.lexeme}');
+ _CompoundOperatorInfo compoundOperatorInfo;
+ if (node.operator.type == TokenType.QUESTION_QUESTION_EQ) {
+ _unimplemented(node, 'Assignment with operator ??=');
+ } else if (node.operator.type != TokenType.EQ) {
+ compoundOperatorInfo = _CompoundOperatorInfo(
+ node.staticElement, node.operator.offset, node.staticType);
}
- _postDominatedLocals.removeReferenceFromAllScopes(node.leftHandSide);
var expressionType = _handleAssignment(node.rightHandSide,
- destinationExpression: node.leftHandSide);
+ destinationExpression: node.leftHandSide,
+ compoundOperatorInfo: compoundOperatorInfo);
var conditionalNode = _conditionalNodes[node.leftHandSide];
if (conditionalNode != null) {
expressionType = expressionType.withNode(
@@ -325,14 +345,19 @@
} else if (operatorType == TokenType.QUESTION_QUESTION) {
DecoratedType expressionType;
var leftType = node.leftOperand.accept(this);
+ _flowAnalysis.ifNullExpression_rightBegin();
try {
_guards.add(leftType.node);
- var rightType = node.rightOperand.accept(this);
+ DecoratedType rightType;
+ _postDominatedLocals.doScoped(action: () {
+ rightType = node.rightOperand.accept(this);
+ });
var ifNullNode = NullabilityNode.forIfNotNull();
expressionType = DecoratedType(node.staticType, ifNullNode);
_connect(rightType.node, expressionType.node,
IfNullOrigin(source, node.offset));
} finally {
+ _flowAnalysis.ifNullExpression_end();
_guards.removeLast();
}
_variables.recordDecoratedExpressionType(node, expressionType);
@@ -387,6 +412,7 @@
@override
DecoratedType visitCatchClause(CatchClause node) {
+ _flowAnalysis.tryCatchStatement_catchBegin();
node.exceptionType?.accept(this);
for (var identifier in [
node.exceptionParameter,
@@ -397,7 +423,10 @@
assigned: true);
}
}
- node.body.accept(this);
+ // The catch clause may not execute, so create a new scope for
+ // post-dominators.
+ _postDominatedLocals.doScoped(action: () => node.body.accept(this));
+ _flowAnalysis.tryCatchStatement_catchEnd();
return null;
}
@@ -523,7 +552,8 @@
@override
DecoratedType visitDoStatement(DoStatement node) {
- _flowAnalysis.doStatement_bodyBegin(node, _assignedVariables[node]);
+ _flowAnalysis.doStatement_bodyBegin(
+ node, _assignedVariables.writtenInNode(node));
node.body.accept(this);
_flowAnalysis.doStatement_conditionBegin();
_checkExpressionNotNull(node.condition);
@@ -580,13 +610,15 @@
@override
DecoratedType visitForElement(ForElement node) {
- _handleForLoopParts(node, node.forLoopParts, node.body);
+ _handleForLoopParts(node, node.forLoopParts, node.body,
+ (body) => _handleCollectionElement(body as CollectionElement));
return null;
}
@override
DecoratedType visitForStatement(ForStatement node) {
- _handleForLoopParts(node, node.forLoopParts, node.body);
+ _handleForLoopParts(
+ node, node.forLoopParts, node.body, (body) => body.accept(this));
return null;
}
@@ -632,7 +664,7 @@
FunctionExpressionInvocation node) {
DecoratedType calleeType = node.function.accept(this);
return _handleInvocationArguments(node, node.argumentList.arguments,
- node.typeArguments, calleeType, null);
+ node.typeArguments, node.typeArgumentTypes, calleeType, null);
}
@override
@@ -726,8 +758,10 @@
}
var callee = node.staticElement;
if (callee == null) {
- // TODO(paulberry)
- _unimplemented(node, 'Index expression with no static type');
+ // Dynamic dispatch. The return type is `dynamic`.
+ // TODO(paulberry): would it be better to assume a return type of `Never`
+ // so that we don't unnecessarily propagate nullabilities everywhere?
+ return _dynamicType;
}
var calleeType = getOrComputeElementType(callee, targetType: targetType);
// TODO(paulberry): substitute if necessary
@@ -745,20 +779,32 @@
InstanceCreationExpression node) {
var callee = node.staticElement;
var typeParameters = callee.enclosingElement.typeParameters;
+ List<DartType> typeArgumentTypes;
List<DecoratedType> decoratedTypeArguments;
var typeArguments = node.constructorName.type.typeArguments;
if (typeArguments != null) {
+ typeArgumentTypes = typeArguments.arguments.map((t) => t.type).toList();
decoratedTypeArguments = typeArguments.arguments
.map((t) => _variables.decoratedTypeAnnotation(source, t))
.toList();
} else {
- decoratedTypeArguments = const [];
+ var staticType = node.staticType;
+ if (staticType is InterfaceType) {
+ typeArgumentTypes = staticType.typeArguments;
+ decoratedTypeArguments = typeArgumentTypes
+ .map((t) => DecoratedType.forImplicitType(_typeProvider, t, _graph))
+ .toList();
+ } else {
+ // Note: this could happen if the code being migrated has errors.
+ typeArgumentTypes = const [];
+ decoratedTypeArguments = const [];
+ }
}
var createdType = DecoratedType(node.staticType, _graph.never,
typeArguments: decoratedTypeArguments);
var calleeType = getOrComputeElementType(callee, targetType: createdType);
_handleInvocationArguments(node, node.argumentList.arguments, typeArguments,
- calleeType, typeParameters);
+ typeArgumentTypes, calleeType, typeParameters);
return createdType;
}
@@ -792,42 +838,42 @@
@override
DecoratedType visitLibraryDirective(LibraryDirective node) {
- // skip directives
+ // skip directives, but not their metadata
+ node.metadata.accept(this);
return null;
}
@override
DecoratedType visitListLiteral(ListLiteral node) {
- var listType = node.staticType as InterfaceType;
- if (node.typeArguments == null) {
- // TODO(brianwilkerson) We might want to create a fake node in the graph
- // to represent the type argument so that we can still create edges from
- // the elements to it.
- // TODO(brianwilkerson)
- _unimplemented(node, 'List literal with no type arguments');
- } else {
- var typeArgumentType = _variables.decoratedTypeAnnotation(
- source, node.typeArguments.arguments[0]);
- if (typeArgumentType == null) {
- _unimplemented(node, 'Could not compute type argument type');
+ final previousLiteralType = _currentLiteralElementType;
+ try {
+ var listType = node.staticType as InterfaceType;
+ if (node.typeArguments == null) {
+ _currentLiteralElementType = DecoratedType.forImplicitType(
+ _typeProvider, listType.typeArguments[0], _graph);
+ } else {
+ _currentLiteralElementType = _variables.decoratedTypeAnnotation(
+ source, node.typeArguments.arguments[0]);
}
- final previousLiteralType = _currentLiteralType;
- try {
- _currentLiteralType = typeArgumentType;
- node.elements.forEach(_handleCollectionElement);
- } finally {
- _currentLiteralType = previousLiteralType;
- }
+ node.elements.forEach(_handleCollectionElement);
return DecoratedType(listType, _graph.never,
- typeArguments: [typeArgumentType]);
+ typeArguments: [_currentLiteralElementType]);
+ } finally {
+ _currentLiteralElementType = previousLiteralType;
}
}
@override
+ DecoratedType visitMapLiteralEntry(MapLiteralEntry node) {
+ assert(_currentMapKeyType != null);
+ assert(_currentMapValueType != null);
+ _handleAssignment(node.key, destinationType: _currentMapKeyType);
+ _handleAssignment(node.value, destinationType: _currentMapValueType);
+ return null;
+ }
+
+ @override
DecoratedType visitMethodDeclaration(MethodDeclaration node) {
- if (node.typeParameters != null) {
- _unimplemented(node, 'Generic method');
- }
_handleExecutableDeclaration(node, node.declaredElement, node.metadata,
node.returnType, node.parameters, null, node.body, null);
return null;
@@ -838,25 +884,37 @@
DecoratedType targetType;
var target = node.realTarget;
bool isConditional = _isConditionalExpression(node);
+ var callee = node.methodName.staticElement;
+ bool calleeIsStatic = callee is ExecutableElement && callee.isStatic;
if (target != null) {
- if (isConditional) {
+ if (_isPrefix(target)) {
+ // Nothing to do.
+ } else if (calleeIsStatic) {
+ target.accept(this);
+ } else if (isConditional) {
targetType = target.accept(this);
} else {
- _checkNonObjectMember(node.methodName.name); // TODO(paulberry)
- targetType = _checkExpressionNotNull(target);
+ targetType = _handleTarget(target, node.methodName.name);
}
}
- var callee = node.methodName.staticElement;
if (callee == null) {
- // TODO(paulberry)
- _unimplemented(node, 'Unresolved method name');
+ // Dynamic dispatch. The return type is `dynamic`.
+ // TODO(paulberry): would it be better to assume a return type of `Never`
+ // so that we don't unnecessarily propagate nullabilities everywhere?
+ return _dynamicType;
}
var calleeType = getOrComputeElementType(callee, targetType: targetType);
if (callee is PropertyAccessorElement) {
calleeType = calleeType.returnType;
}
- var expressionType = _handleInvocationArguments(node,
- node.argumentList.arguments, node.typeArguments, calleeType, null);
+ var expressionType = _handleInvocationArguments(
+ node,
+ node.argumentList.arguments,
+ node.typeArguments,
+ node.typeArgumentTypes,
+ calleeType,
+ null,
+ invokeType: node.staticInvokeType);
if (isConditional) {
expressionType = expressionType.withNode(
NullabilityNode.forLUB(targetType.node, expressionType.node));
@@ -867,7 +925,8 @@
@override
DecoratedType visitNamespaceDirective(NamespaceDirective node) {
- // skip directives
+ // skip directives, but not their metadata
+ node.metadata.accept(this);
return null;
}
@@ -882,6 +941,13 @@
}
@override
+ DecoratedType visitPartOfDirective(PartOfDirective node) {
+ // skip directives, but not their metadata
+ node.metadata.accept(this);
+ return null;
+ }
+
+ @override
DecoratedType visitPostfixExpression(PostfixExpression node) {
var operatorType = node.operator.type;
if (operatorType == TokenType.PLUS_PLUS ||
@@ -921,6 +987,7 @@
var targetType = _checkExpressionNotNull(node.operand);
var operatorType = node.operator.type;
if (operatorType == TokenType.BANG) {
+ _flowAnalysis.logicalNot_end(node, node.operand);
return _nonNullableBoolType;
} else if (operatorType == TokenType.PLUS_PLUS ||
operatorType == TokenType.MINUS_MINUS) {
@@ -941,7 +1008,7 @@
} else {
var callee = node.staticElement;
var calleeType = getOrComputeElementType(callee, targetType: targetType);
- return _handleInvocationArguments(node, [], null, calleeType, null);
+ return _handleInvocationArguments(node, [], null, null, calleeType, null);
}
}
@@ -956,11 +1023,17 @@
var callee = node.staticElement;
var calleeType = _variables.decoratedElementType(callee);
_handleInvocationArguments(
- node, node.argumentList.arguments, null, calleeType, null);
+ node, node.argumentList.arguments, null, null, calleeType, null);
return null;
}
@override
+ DecoratedType visitRethrowExpression(RethrowExpression node) {
+ _flowAnalysis.handleExit();
+ return DecoratedType(node.staticType, _graph.never);
+ }
+
+ @override
DecoratedType visitReturnStatement(ReturnStatement node) {
DecoratedType returnType = _currentFunctionType.returnType;
Expression returnValue = node.expression;
@@ -990,51 +1063,54 @@
@override
DecoratedType visitSetOrMapLiteral(SetOrMapLiteral node) {
- var listType = node.staticType as InterfaceType;
+ var setOrMapType = node.staticType as InterfaceType;
var typeArguments = node.typeArguments?.arguments;
- if (typeArguments == null) {
- // TODO(brianwilkerson) We might want to create fake nodes in the graph to
- // represent the type arguments so that we can still create edges from
- // the elements to them.
- // TODO(brianwilkerson)
- _unimplemented(node, 'Set or map literal with no type arguments');
- } else if (typeArguments.length == 1) {
- var elementType =
- _variables.decoratedTypeAnnotation(source, typeArguments[0]);
- for (var element in node.elements) {
- if (element is Expression) {
- _handleAssignment(element, destinationType: elementType);
+
+ if (node.isSet) {
+ final previousLiteralType = _currentLiteralElementType;
+ try {
+ if (typeArguments == null) {
+ assert(setOrMapType.typeArguments.length == 1);
+ _currentLiteralElementType = DecoratedType.forImplicitType(
+ _typeProvider, setOrMapType.typeArguments[0], _graph);
} else {
- // Handle spread and control flow elements.
- element.accept(this);
- // TODO(brianwilkerson)
- _unimplemented(node, 'Spread or control flow element');
+ assert(typeArguments.length == 1);
+ _currentLiteralElementType =
+ _variables.decoratedTypeAnnotation(source, typeArguments[0]);
}
+ node.elements.forEach(_handleCollectionElement);
+ return DecoratedType(setOrMapType, _graph.never,
+ typeArguments: [_currentLiteralElementType]);
+ } finally {
+ _currentLiteralElementType = previousLiteralType;
}
- return DecoratedType(listType, _graph.never,
- typeArguments: [elementType]);
- } else if (typeArguments.length == 2) {
- var keyType =
- _variables.decoratedTypeAnnotation(source, typeArguments[0]);
- var valueType =
- _variables.decoratedTypeAnnotation(source, typeArguments[1]);
- for (var element in node.elements) {
- if (element is MapLiteralEntry) {
- _handleAssignment(element.key, destinationType: keyType);
- _handleAssignment(element.value, destinationType: valueType);
- } else {
- // Handle spread and control flow elements.
- element.accept(this);
- // TODO(brianwilkerson)
- _unimplemented(node, 'Spread or control flow element');
- }
- }
- return DecoratedType(listType, _graph.never,
- typeArguments: [keyType, valueType]);
} else {
- // TODO(brianwilkerson)
- _unimplemented(
- node, 'Set or map literal with more than two type arguments');
+ assert(node.isMap);
+
+ final previousKeyType = _currentMapKeyType;
+ final previousValueType = _currentMapValueType;
+ try {
+ if (typeArguments == null) {
+ assert(setOrMapType.typeArguments.length == 2);
+ _currentMapKeyType = DecoratedType.forImplicitType(
+ _typeProvider, setOrMapType.typeArguments[0], _graph);
+ _currentMapValueType = DecoratedType.forImplicitType(
+ _typeProvider, setOrMapType.typeArguments[1], _graph);
+ } else {
+ assert(typeArguments.length == 2);
+ _currentMapKeyType =
+ _variables.decoratedTypeAnnotation(source, typeArguments[0]);
+ _currentMapValueType =
+ _variables.decoratedTypeAnnotation(source, typeArguments[1]);
+ }
+
+ node.elements.forEach(_handleCollectionElement);
+ return DecoratedType(setOrMapType, _graph.never,
+ typeArguments: [_currentMapKeyType, _currentMapValueType]);
+ } finally {
+ _currentMapKeyType = previousKeyType;
+ _currentMapValueType = previousValueType;
+ }
}
}
@@ -1055,7 +1131,7 @@
return staticElement.isGetter
? elementType.returnType
: elementType.positionalParameters[0];
- } else if (staticElement is ClassElement) {
+ } else if (staticElement is TypeDefiningElement) {
return _nonNullableTypeType;
} else {
// TODO(paulberry)
@@ -1065,6 +1141,42 @@
}
@override
+ DecoratedType visitSpreadElement(SpreadElement node) {
+ final spreadType = node.expression.staticType;
+ if (_typeSystem.isSubtypeOf(
+ spreadType, _typeProvider.mapObjectObjectType)) {
+ assert(_currentMapKeyType != null && _currentMapValueType != null);
+ final expectedType = _typeSystem.instantiateType(_typeProvider.mapType,
+ [_currentMapKeyType.type, _currentMapValueType.type]);
+ final expectedDecoratedType = DecoratedType.forImplicitType(
+ _typeProvider, expectedType, _graph,
+ typeArguments: [_currentMapKeyType, _currentMapValueType]);
+
+ _handleAssignment(node.expression,
+ destinationType: expectedDecoratedType);
+ } else if (_typeSystem.isSubtypeOf(
+ spreadType, _typeProvider.iterableDynamicType)) {
+ assert(_currentLiteralElementType != null);
+ final expectedType = _typeSystem.instantiateType(
+ _typeProvider.iterableType, [_currentLiteralElementType.type]);
+ final expectedDecoratedType = DecoratedType.forImplicitType(
+ _typeProvider, expectedType, _graph,
+ typeArguments: [_currentLiteralElementType]);
+
+ _handleAssignment(node.expression,
+ destinationType: expectedDecoratedType);
+ } else {
+ // Downcast. We can't assume nullability here, so do nothing.
+ }
+
+ if (!node.isNullAware) {
+ _checkExpressionNotNull(node.expression);
+ }
+
+ return null;
+ }
+
+ @override
DecoratedType visitStringLiteral(StringLiteral node) {
node.visitChildren(this);
return DecoratedType(node.staticType, _graph.never);
@@ -1076,6 +1188,26 @@
}
@override
+ DecoratedType visitSwitchStatement(SwitchStatement node) {
+ node.expression.accept(this);
+ _flowAnalysis.switchStatement_expressionEnd(node);
+ var notPromoted = _assignedVariables.writtenInNode(node);
+ var hasDefault = false;
+ for (var member in node.members) {
+ var hasLabel = member.labels.isNotEmpty;
+ _flowAnalysis.switchStatement_beginCase(hasLabel, notPromoted);
+ if (member is SwitchCase) {
+ member.expression.accept(this);
+ } else {
+ hasDefault = true;
+ }
+ member.statements.accept(this);
+ }
+ _flowAnalysis.switchStatement_end(hasDefault);
+ return null;
+ }
+
+ @override
DecoratedType visitSymbolLiteral(SymbolLiteral node) {
return DecoratedType(node.staticType, _graph.never);
}
@@ -1089,6 +1221,7 @@
DecoratedType visitThrowExpression(ThrowExpression node) {
node.expression.accept(this);
// TODO(paulberry): do we need to check the expression type? I think not.
+ _flowAnalysis.handleExit();
return DecoratedType(node.staticType, _graph.never);
}
@@ -1108,6 +1241,33 @@
}
@override
+ DecoratedType visitTryStatement(TryStatement node) {
+ var finallyBlock = node.finallyBlock;
+ if (finallyBlock != null) {
+ _flowAnalysis.tryFinallyStatement_bodyBegin();
+ }
+ var catchClauses = node.catchClauses;
+ if (catchClauses.isNotEmpty) {
+ _flowAnalysis.tryCatchStatement_bodyBegin();
+ }
+ var body = node.body;
+ body.accept(this);
+ var assignedInBody = _assignedVariables.writtenInNode(body);
+ if (catchClauses.isNotEmpty) {
+ _flowAnalysis.tryCatchStatement_bodyEnd(assignedInBody);
+ catchClauses.accept(this);
+ _flowAnalysis.tryCatchStatement_end();
+ }
+ if (finallyBlock != null) {
+ _flowAnalysis.tryFinallyStatement_finallyBegin(assignedInBody);
+ finallyBlock.accept(this);
+ _flowAnalysis.tryFinallyStatement_end(
+ _assignedVariables.writtenInNode(finallyBlock));
+ }
+ return null;
+ }
+
+ @override
DecoratedType visitTypeName(TypeName typeName) {
var typeArguments = typeName.typeArguments?.arguments;
var element = typeName.name.staticElement;
@@ -1189,7 +1349,8 @@
DecoratedType visitWhileStatement(WhileStatement node) {
// Note: we do not create guards. A null check here is *very* unlikely to be
// unnecessary after analysis.
- _flowAnalysis.whileStatement_conditionBegin(_assignedVariables[node]);
+ _flowAnalysis
+ .whileStatement_conditionBegin(_assignedVariables.writtenInNode(node));
_checkExpressionNotNull(node.condition);
_flowAnalysis.whileStatement_bodyBegin(node, node.condition);
_postDominatedLocals.doScoped(action: () => node.body.accept(this));
@@ -1214,19 +1375,25 @@
// type of the expression, since all we are doing is causing a single graph
// edge to be built; it is sufficient to pass in any decorated type whose
// node is `never`.
+ if (_isPrefix(expression)) {
+ throw ArgumentError('cannot check non-nullability of a prefix');
+ }
return _handleAssignment(expression, destinationType: _notNullType);
}
- /// Double checks that [name] is not the name of a method or getter declared
- /// on [Object].
- ///
- /// TODO(paulberry): get rid of this method and put the correct logic into the
- /// call sites.
- void _checkNonObjectMember(String name) {
- assert(name != 'toString');
- assert(name != 'hashCode');
- assert(name != 'noSuchMethod');
- assert(name != 'runtimeType');
+ List<String> _computeObjectGetNames() {
+ var result = <String>[];
+ var objectClass = _typeProvider.objectType.element;
+ for (var accessor in objectClass.accessors) {
+ assert(accessor.isGetter);
+ assert(!accessor.name.startsWith('_'));
+ result.add(accessor.name);
+ }
+ for (var method in objectClass.methods) {
+ assert(!method.name.startsWith('_'));
+ result.add(method.name);
+ }
+ return result;
}
@override
@@ -1367,6 +1534,7 @@
DecoratedType _handleAssignment(Expression expression,
{DecoratedType destinationType,
Expression destinationExpression,
+ _CompoundOperatorInfo compoundOperatorInfo,
bool canInsertChecks = true}) {
assert(
(destinationExpression == null) != (destinationType == null),
@@ -1392,14 +1560,45 @@
'(${expression.toSource()}) offset=${expression.offset}');
}
ExpressionChecks expressionChecks;
- if (canInsertChecks) {
+ if (canInsertChecks && !sourceType.type.isDynamic) {
expressionChecks = ExpressionChecks(expression.end);
_variables.recordExpressionChecks(source, expression, expressionChecks);
}
- _checkAssignment(expressionChecks,
- source: sourceType,
- destination: destinationType,
- hard: _postDominatedLocals.isReferenceInScope(expression));
+ if (compoundOperatorInfo != null) {
+ var compoundOperatorMethod = compoundOperatorInfo.method;
+ if (compoundOperatorMethod != null) {
+ _checkAssignment(
+ CompoundAssignmentOrigin(source, compoundOperatorInfo.offset),
+ source: destinationType,
+ destination: _notNullType,
+ hard:
+ _postDominatedLocals.isReferenceInScope(destinationExpression));
+ DecoratedType compoundOperatorType =
+ getOrComputeElementType(compoundOperatorMethod);
+ assert(compoundOperatorType.positionalParameters.length > 0);
+ _checkAssignment(expressionChecks,
+ source: sourceType,
+ destination: compoundOperatorType.positionalParameters[0],
+ hard: _postDominatedLocals.isReferenceInScope(expression));
+ sourceType = _fixNumericTypes(compoundOperatorType.returnType,
+ compoundOperatorInfo.undecoratedType);
+ _checkAssignment(
+ CompoundAssignmentOrigin(source, compoundOperatorInfo.offset),
+ source: sourceType,
+ destination: destinationType,
+ hard: false);
+ } else {
+ sourceType = _dynamicType;
+ }
+ } else {
+ _checkAssignment(expressionChecks,
+ source: sourceType,
+ destination: destinationType,
+ hard: _postDominatedLocals.isReferenceInScope(expression));
+ }
+ if (destinationExpression != null) {
+ _postDominatedLocals.removeReferenceFromAllScopes(destinationExpression);
+ }
if (destinationLocalVariable != null) {
_flowAnalysis.write(destinationLocalVariable);
}
@@ -1408,8 +1607,9 @@
DecoratedType _handleCollectionElement(CollectionElement element) {
if (element is Expression) {
- assert(_currentLiteralType != null);
- return _handleAssignment(element, destinationType: _currentLiteralType);
+ assert(_currentLiteralElementType != null);
+ return _handleAssignment(element,
+ destinationType: _currentLiteralElementType);
} else {
return element.accept(this);
}
@@ -1423,10 +1623,14 @@
}
var redirectedClass = callee.enclosingElement;
var calleeType = _variables.decoratedElementType(callee);
+ var typeArguments = redirectedConstructor.type.typeArguments;
+ var typeArgumentTypes =
+ typeArguments?.arguments?.map((t) => t.type)?.toList();
_handleInvocationArguments(
redirectedConstructor,
parameters.parameters,
- redirectedConstructor.type.typeArguments,
+ typeArguments,
+ typeArgumentTypes,
calleeType,
redirectedClass.typeParameters);
}
@@ -1539,31 +1743,37 @@
}
}
- void _handleForLoopParts(AstNode node, ForLoopParts parts, AstNode body) {
+ void _handleForLoopParts(AstNode node, ForLoopParts parts, AstNode body,
+ DecoratedType Function(AstNode) bodyHandler) {
if (parts is ForParts) {
if (parts is ForPartsWithDeclarations) {
parts.variables?.accept(this);
} else if (parts is ForPartsWithExpression) {
parts.initialization?.accept(this);
}
+ _flowAnalysis.for_conditionBegin(_assignedVariables.writtenInNode(node));
if (parts.condition != null) {
_checkExpressionNotNull(parts.condition);
}
+ _flowAnalysis.for_bodyBegin(
+ node is Statement ? node : null, parts.condition);
} else if (parts is ForEachParts) {
if (parts is ForEachPartsWithDeclaration) {
_flowAnalysis.add(parts.loopVariable.declaredElement, assigned: true);
}
_checkExpressionNotNull(parts.iterable);
- _flowAnalysis.forEach_bodyBegin(_assignedVariables[node]);
+ _flowAnalysis.forEach_bodyBegin(_assignedVariables.writtenInNode(node));
}
// The condition may fail/iterable may be empty, so the body gets a new
// post-dominator scope.
_postDominatedLocals.doScoped(action: () {
- body.accept(this);
+ bodyHandler(body);
if (parts is ForParts) {
+ _flowAnalysis.for_updaterBegin();
parts.updaters.accept(this);
+ _flowAnalysis.for_end();
} else {
_flowAnalysis.forEach_end();
}
@@ -1579,8 +1789,10 @@
AstNode node,
Iterable<AstNode> arguments,
TypeArgumentList typeArguments,
+ List<DartType> typeArgumentTypes,
DecoratedType calleeType,
- List<TypeParameterElement> constructorTypeParameters) {
+ List<TypeParameterElement> constructorTypeParameters,
+ {DartType invokeType}) {
var typeFormals = constructorTypeParameters ?? calleeType.typeFormals;
if (typeFormals.isNotEmpty) {
if (typeArguments != null) {
@@ -1595,7 +1807,21 @@
calleeType = calleeType.instantiate(argumentTypes);
}
} else {
- _unimplemented(node, 'Inferred type parameters in invocation');
+ if (invokeType is FunctionType) {
+ var argumentTypes = typeArgumentTypes
+ .map((argType) =>
+ DecoratedType.forImplicitType(_typeProvider, argType, _graph))
+ .toList();
+ calleeType = calleeType.instantiate(argumentTypes);
+ } else if (constructorTypeParameters != null) {
+ // No need to instantiate; caller has already substituted in the
+ // correct type arguments.
+ } else {
+ assert(
+ false,
+ 'invoke type should be a non-null function type, or '
+ 'dynamic/Function, which have no type arguments.');
+ }
}
}
int i = 0;
@@ -1644,16 +1870,20 @@
Expression node, Expression target, SimpleIdentifier propertyName) {
DecoratedType targetType;
bool isConditional = _isConditionalExpression(node);
- if (isConditional) {
+ var callee = propertyName.staticElement;
+ bool calleeIsStatic = callee is ExecutableElement && callee.isStatic;
+ if (_isPrefix(target)) {
+ return propertyName.accept(this);
+ } else if (calleeIsStatic) {
+ target.accept(this);
+ } else if (isConditional) {
targetType = target.accept(this);
} else {
- _checkNonObjectMember(propertyName.name); // TODO(paulberry)
- targetType = _checkExpressionNotNull(target);
+ targetType = _handleTarget(target, propertyName.name);
}
- var callee = propertyName.staticElement;
if (callee == null) {
- // TODO(paulberry)
- _unimplemented(node, 'Unresolved property access');
+ // Dynamic dispatch.
+ return _dynamicType;
}
var calleeType = getOrComputeElementType(callee, targetType: targetType);
// TODO(paulberry): substitute if necessary
@@ -1675,6 +1905,14 @@
}
}
+ DecoratedType _handleTarget(Expression target, String name) {
+ if ((_objectGetNames ??= _computeObjectGetNames()).contains(name)) {
+ return target.accept(this);
+ } else {
+ return _checkExpressionNotNull(target);
+ }
+ }
+
bool _isConditionalExpression(Expression expression) {
Token token;
if (expression is MethodInvocation) {
@@ -1698,6 +1936,9 @@
}
}
+ bool _isPrefix(Expression e) =>
+ e is SimpleIdentifier && e.staticElement is PrefixElement;
+
bool _isUntypedParameter(NormalFormalParameter parameter) {
if (parameter is SimpleFormalParameter) {
return parameter.type == null;
@@ -1773,6 +2014,8 @@
NullabilityGraph get _graph;
+ TypeProvider get _typeProvider;
+
TypeSystem get _typeSystem;
/// Creates the necessary constraint(s) for an assignment from [source] to
@@ -1783,8 +2026,43 @@
@required DecoratedType destination,
@required bool hard}) {
_connect(source.node, destination.node, origin, hard: hard);
+ _checkAssignment_recursion(origin,
+ source: source, destination: destination);
+ }
+
+ /// Does the recursive part of [_checkAssignment], visiting all of the types
+ /// constituting [source] and [destination], and creating the appropriate
+ /// edges between them.
+ void _checkAssignment_recursion(EdgeOrigin origin,
+ {@required DecoratedType source, @required DecoratedType destination}) {
var sourceType = source.type;
var destinationType = destination.type;
+ if (destinationType.isDartAsyncFutureOr) {
+ // (From the subtyping spec):
+ // if T1 is FutureOr<S1> then T0 <: T1 iff any of the following hold:
+ // - either T0 <: Future<S1>
+ var s1 = destination.typeArguments[0];
+ if (_typeSystem.isSubtypeOf(
+ sourceType, _typeProvider.futureType.instantiate([s1.type]))) {
+ // E.g. FutureOr<int> = (... as Future<int>)
+ // This is handled by the InterfaceType logic below, since we treat
+ // FutureOr as a supertype of Future.
+ }
+ // - or T0 <: S1
+ else if (_typeSystem.isSubtypeOf(sourceType, s1.type)) {
+ // E.g. FutureOr<int> = (... as int)
+ _checkAssignment_recursion(origin, source: source, destination: s1);
+ return;
+ }
+ // - or T0 is X0 and X0 has bound S0 and S0 <: T1
+ // - or T0 is X0 & S0 and S0 <: T1
+ else if (sourceType is TypeParameterType) {
+ throw UnimplementedError('TODO(paulberry)');
+ } else {
+ // Not a subtype; this must be a downcast.
+ throw UnimplementedError('TODO(paulberry)');
+ }
+ }
if (sourceType.isBottom || sourceType.isDartCoreNull) {
// No further edges need to be created, since all types are trivially
// supertypes of bottom (and of Null, in the pre-migration world).
@@ -1872,6 +2150,9 @@
}
} else if (destinationType.isDynamic || sourceType.isDynamic) {
// ok; nothing further to do.
+ } else if (destinationType is InterfaceType && sourceType is FunctionType) {
+ // Either this is an upcast to Function or Object, or it is erroneous
+ // code. In either case we don't need to create any additional edges.
} else {
throw '$destination <= $source'; // TODO(paulberry)
}
@@ -1885,6 +2166,14 @@
DecoratedType _getTypeParameterTypeBound(DecoratedType type);
}
+class _CompoundOperatorInfo {
+ final MethodElement method;
+ final int offset;
+ final DartType undecoratedType;
+
+ _CompoundOperatorInfo(this.method, this.offset, this.undecoratedType);
+}
+
/// Information about a binary expression whose boolean value could possibly
/// affect nullability analysis.
class _ConditionInfo {
diff --git a/pkg/nnbd_migration/lib/src/edge_origin.dart b/pkg/nnbd_migration/lib/src/edge_origin.dart
index 9c52df8..efc646b 100644
--- a/pkg/nnbd_migration/lib/src/edge_origin.dart
+++ b/pkg/nnbd_migration/lib/src/edge_origin.dart
@@ -16,6 +16,12 @@
AlwaysNullableTypeOrigin(Source source, int offset) : super(source, offset);
}
+/// Edge origin resulting from the use of a value on the LHS of a compound
+/// assignment.
+class CompoundAssignmentOrigin extends EdgeOriginWithLocation {
+ CompoundAssignmentOrigin(Source source, int offset) : super(source, offset);
+}
+
/// Common interface for classes providing information about how an edge came
/// to be; that is, what was found in the source code that led the migration
/// tool to create the edge.
diff --git a/pkg/nnbd_migration/lib/src/node_builder.dart b/pkg/nnbd_migration/lib/src/node_builder.dart
index 9ab1383..01061d1 100644
--- a/pkg/nnbd_migration/lib/src/node_builder.dart
+++ b/pkg/nnbd_migration/lib/src/node_builder.dart
@@ -60,22 +60,37 @@
final TypeProvider _typeProvider;
+ /// For convenience, a [DecoratedType] representing `dynamic`.
+ final DecoratedType _dynamicType;
+
/// For convenience, a [DecoratedType] representing non-nullable `Object`.
final DecoratedType _nonNullableObjectType;
+ /// For convenience, a [DecoratedType] representing non-nullable `StackTrace`.
+ final DecoratedType _nonNullableStackTraceType;
+
NodeBuilder(this._variables, this.source, this.listener, this._graph,
this._typeProvider)
- : _nonNullableObjectType =
- DecoratedType(_typeProvider.objectType, _graph.never);
+ : _dynamicType = DecoratedType(_typeProvider.dynamicType, _graph.always),
+ _nonNullableObjectType =
+ DecoratedType(_typeProvider.objectType, _graph.never),
+ _nonNullableStackTraceType =
+ DecoratedType(_typeProvider.stackTraceType, _graph.never);
@override
DecoratedType visitCatchClause(CatchClause node) {
DecoratedType exceptionType = node.exceptionType?.accept(this);
if (node.exceptionParameter != null) {
- exceptionType ??= DecoratedType(_typeProvider.objectType, _graph.never);
+ // If there is no `on Type` part of the catch clause, the type is dynamic.
+ exceptionType ??= _dynamicType;
_variables.recordDecoratedElementType(
node.exceptionParameter.staticElement, exceptionType);
}
+ if (node.stackTraceParameter != null) {
+ // The type of stack traces is always StackTrace (non-nullable).
+ _variables.recordDecoratedElementType(
+ node.stackTraceParameter.staticElement, _nonNullableStackTraceType);
+ }
node.stackTraceParameter?.accept(this);
node.body?.accept(this);
return null;
@@ -366,18 +381,26 @@
parent is ImplementsClause ||
parent is WithClause ||
parent is OnClause ||
- parent is ClassTypeAlias ||
- parent is CatchClause) {
+ parent is ClassTypeAlias) {
nullabilityNode = _graph.never;
} else {
nullabilityNode = NullabilityNode.forTypeAnnotation(node.end);
}
- var decoratedType = DecoratedType(type, nullabilityNode,
- typeArguments: typeArguments,
- returnType: decoratedReturnType,
- positionalParameters: positionalParameters,
- namedParameters: namedParameters,
- typeFormalBounds: typeFormalBounds);
+ DecoratedType decoratedType;
+ if (type is FunctionType && node is! GenericFunctionType) {
+ // node is a reference to a typedef. Treat it like an inferred type (we
+ // synthesize new nodes for it). These nodes will be unioned with the
+ // typedef nodes by the edge builder.
+ decoratedType = DecoratedType.forImplicitFunction(
+ _typeProvider, type, nullabilityNode, _graph);
+ } else {
+ decoratedType = DecoratedType(type, nullabilityNode,
+ typeArguments: typeArguments,
+ returnType: decoratedReturnType,
+ positionalParameters: positionalParameters,
+ namedParameters: namedParameters,
+ typeFormalBounds: typeFormalBounds);
+ }
_variables.recordDecoratedTypeAnnotation(
source,
node,
diff --git a/pkg/nnbd_migration/lib/src/nullability_migration_impl.dart b/pkg/nnbd_migration/lib/src/nullability_migration_impl.dart
index d6baf2e..53c75ec 100644
--- a/pkg/nnbd_migration/lib/src/nullability_migration_impl.dart
+++ b/pkg/nnbd_migration/lib/src/nullability_migration_impl.dart
@@ -18,7 +18,7 @@
class NullabilityMigrationImpl implements NullabilityMigration {
final NullabilityMigrationListener listener;
- final Variables _variables;
+ Variables _variables;
final NullabilityGraph _graph;
@@ -34,22 +34,26 @@
{bool permissive: false})
: this._(listener, NullabilityGraph(), permissive);
- NullabilityMigrationImpl._(this.listener, this._graph, this._permissive)
- : _variables = Variables(_graph);
+ NullabilityMigrationImpl._(this.listener, this._graph, this._permissive);
void finish() {
_graph.propagate();
if (_graph.unsatisfiedSubstitutions.isNotEmpty) {
- throw new UnimplementedError('Need to report unsatisfied substitutions');
+ // TODO(paulberry): for now we just ignore unsatisfied substitutions, to
+ // work around https://github.com/dart-lang/sdk/issues/38257
+ // throw new UnimplementedError('Need to report unsatisfied substitutions');
}
// TODO(paulberry): it would be nice to report on unsatisfied edges as well,
// however, since every `!` we add has an unsatisfied edge associated with
// it, we can't report on every unsatisfied edge. We need to figure out a
// way to report unsatisfied edges that isn't too overwhelming.
- broadcast(_variables, listener);
+ if (_variables != null) {
+ broadcast(_variables, listener);
+ }
}
void prepareInput(ResolvedUnitResult result) {
+ _variables ??= Variables(_graph, result.typeProvider);
var unit = result.unit;
unit.accept(NodeBuilder(_variables, unit.declaredElement.source,
_permissive ? listener : null, _graph, result.typeProvider));
diff --git a/pkg/nnbd_migration/lib/src/nullability_node.dart b/pkg/nnbd_migration/lib/src/nullability_node.dart
index 96ef894..244df1e 100644
--- a/pkg/nnbd_migration/lib/src/nullability_node.dart
+++ b/pkg/nnbd_migration/lib/src/nullability_node.dart
@@ -81,6 +81,10 @@
/// propagation.
static const _debugBeforePropagation = false;
+ /// Set this const to `true` to dump the nullability graph just before
+ /// propagation.
+ static const _debugAfterPropagation = false;
+
/// Set containing all [NullabilityNode]s that have been passed as the
/// `sourceNode` argument to [connect].
final _allSourceNodes = Set<NullabilityNode>.identity();
@@ -157,6 +161,7 @@
_propagateAlways();
_propagateUpstream();
_propagateDownstream();
+ if (_debugAfterPropagation) _debugDump();
}
/// Records that nodes [x] and [y] should have exactly the same nullability.
@@ -344,20 +349,29 @@
/// testing.
@visibleForTesting
class NullabilityGraphForTesting extends NullabilityGraph {
- /// Iterates through all edges that have this node as one of their sources.
- ///
- /// There is no guarantee of uniqueness of the iterated edges.
- @visibleForTesting
- Iterable<NullabilityEdge> getDownstreamEdges(NullabilityNode node) {
- return node._downstreamEdges;
+ final List<NullabilityEdge> _allEdges = [];
+
+ /// Prints out a representation of the graph nodes. Useful in debugging
+ /// broken tests.
+ void debugDump() {
+ _debugDump();
}
- /// Iterates through all edges that have this node as their destination.
- ///
- /// There is no guarantee of uniqueness of the iterated nodes.
+ /// Iterates through all edges in the graph.
@visibleForTesting
- Iterable<NullabilityEdge> getUpstreamEdges(NullabilityNode node) {
- return node._upstreamEdges;
+ Iterable<NullabilityEdge> getAllEdges() {
+ return _allEdges;
+ }
+
+ @override
+ NullabilityEdge _connect(
+ List<NullabilityNode> sources,
+ NullabilityNode destinationNode,
+ _NullabilityEdgeKind kind,
+ EdgeOrigin origin) {
+ var edge = super._connect(sources, destinationNode, kind, origin);
+ _allEdges.add(edge);
+ return edge;
}
}
diff --git a/pkg/nnbd_migration/lib/src/variables.dart b/pkg/nnbd_migration/lib/src/variables.dart
index 21f5a7b..e1e88ee 100644
--- a/pkg/nnbd_migration/lib/src/variables.dart
+++ b/pkg/nnbd_migration/lib/src/variables.dart
@@ -7,6 +7,7 @@
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/handle.dart';
import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:nnbd_migration/src/already_migrated_code_decorator.dart';
import 'package:nnbd_migration/src/conditional_discard.dart';
@@ -32,14 +33,15 @@
final AlreadyMigratedCodeDecorator _alreadyMigratedCodeDecorator;
- Variables(this._graph)
- : _alreadyMigratedCodeDecorator = AlreadyMigratedCodeDecorator(_graph);
+ Variables(this._graph, TypeProvider typeProvider)
+ : _alreadyMigratedCodeDecorator =
+ AlreadyMigratedCodeDecorator(_graph, typeProvider);
@override
Map<ClassElement, DecoratedType> decoratedDirectSupertypes(
ClassElement class_) {
assert(class_ is! ClassElementHandle);
- return _decoratedDirectSupertypes[class_] ??
+ return _decoratedDirectSupertypes[class_] ??=
_decorateDirectSupertypes(class_);
}
@@ -230,9 +232,9 @@
}
DecoratedType decoratedType;
- if (element is ExecutableElement) {
+ if (element is FunctionTypedElement) {
decoratedType = _alreadyMigratedCodeDecorator.decorate(element.type);
- } else if (element is TopLevelVariableElement) {
+ } else if (element is VariableElement) {
decoratedType = _alreadyMigratedCodeDecorator.decorate(element.type);
} else {
// TODO(paulberry)
@@ -246,9 +248,8 @@
Map<ClassElement, DecoratedType> _decorateDirectSupertypes(
ClassElement class_) {
var result = <ClassElement, DecoratedType>{};
- for (var supertype in class_.allSupertypes) {
- var decoratedSupertype =
- _alreadyMigratedCodeDecorator.decorate(supertype);
+ for (var decoratedSupertype
+ in _alreadyMigratedCodeDecorator.getImmediateSupertypes(class_)) {
assert(identical(decoratedSupertype.node, _graph.never));
var class_ = (decoratedSupertype.type as InterfaceType).element;
if (class_ is ClassElementHandle) {
diff --git a/pkg/nnbd_migration/test/already_migrated_code_decorator_test.dart b/pkg/nnbd_migration/test/already_migrated_code_decorator_test.dart
index d257f73..b2b058c 100644
--- a/pkg/nnbd_migration/test/already_migrated_code_decorator_test.dart
+++ b/pkg/nnbd_migration/test/already_migrated_code_decorator_test.dart
@@ -2,10 +2,12 @@
// 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/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/testing/element_factory.dart';
import 'package:analyzer/src/generated/testing/test_type_provider.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:nnbd_migration/src/already_migrated_code_decorator.dart';
@@ -29,40 +31,71 @@
final NullabilityGraphForTesting graph;
factory _AlreadyMigratedCodeDecoratorTest() {
- return _AlreadyMigratedCodeDecoratorTest._(NullabilityGraphForTesting());
+ return _AlreadyMigratedCodeDecoratorTest._(
+ NullabilityGraphForTesting(), TestTypeProvider());
}
- _AlreadyMigratedCodeDecoratorTest._(this.graph)
- : typeProvider = TestTypeProvider(),
- decorator = AlreadyMigratedCodeDecorator(graph);
+ _AlreadyMigratedCodeDecoratorTest._(this.graph, this.typeProvider)
+ : decorator = AlreadyMigratedCodeDecorator(graph, typeProvider);
+
+ NullabilityNode get always => graph.always;
+
+ NullabilityNode get never => graph.never;
void checkDynamic(DecoratedType decoratedType) {
expect(decoratedType.type, same(typeProvider.dynamicType));
- expect(decoratedType.node, same(graph.always));
+ expect(decoratedType.node, same(always));
}
- void checkInt(DecoratedType decoratedType) {
- expect(decoratedType.type, typeProvider.intType);
- expect(decoratedType.node, same(graph.never));
- }
-
- void checkIterable(
- DecoratedType decoratedType, void Function(DecoratedType) checkArgument) {
- expect(decoratedType.type, typeProvider.iterableDynamicType);
- expect(decoratedType.node, same(graph.never));
+ void checkFutureOr(
+ DecoratedType decoratedType,
+ NullabilityNode expectedNullability,
+ void Function(DecoratedType) checkArgument) {
+ expect(decoratedType.type.element, typeProvider.futureOrType.element);
+ expect(decoratedType.node, expectedNullability);
checkArgument(decoratedType.typeArguments[0]);
}
+ void checkInt(
+ DecoratedType decoratedType, NullabilityNode expectedNullability) {
+ expect(decoratedType.type.element, typeProvider.intType.element);
+ expect(decoratedType.node, expectedNullability);
+ }
+
+ void checkIterable(
+ DecoratedType decoratedType,
+ NullabilityNode expectedNullability,
+ void Function(DecoratedType) checkArgument) {
+ expect(
+ decoratedType.type.element, typeProvider.iterableDynamicType.element);
+ expect(decoratedType.node, expectedNullability);
+ checkArgument(decoratedType.typeArguments[0]);
+ }
+
+ void checkNum(
+ DecoratedType decoratedType, NullabilityNode expectedNullability) {
+ expect(decoratedType.type.element, typeProvider.numType.element);
+ expect(decoratedType.node, expectedNullability);
+ }
+
+ void checkObject(
+ DecoratedType decoratedType, NullabilityNode expectedNullability) {
+ expect(decoratedType.type.element, typeProvider.objectType.element);
+ expect(decoratedType.node, expectedNullability);
+ }
+
void checkTypeParameter(
- DecoratedType decoratedType, TypeParameterElementImpl expectedElement) {
+ DecoratedType decoratedType,
+ NullabilityNode expectedNullability,
+ TypeParameterElement expectedElement) {
var type = decoratedType.type as TypeParameterTypeImpl;
expect(type.element, same(expectedElement));
- expect(decoratedType.node, same(graph.never));
+ expect(decoratedType.node, expectedNullability);
}
void checkVoid(DecoratedType decoratedType) {
expect(decoratedType.type, same(typeProvider.voidType));
- expect(decoratedType.node, same(graph.always));
+ expect(decoratedType.node, same(always));
}
DecoratedType decorate(DartType type) {
@@ -75,6 +108,25 @@
checkDynamic(decorate(typeProvider.dynamicType));
}
+ test_decorate_functionType_generic_bounded() {
+ var typeFormal = TypeParameterElementImpl.synthetic('T')
+ ..bound = typeProvider.numType;
+ var decoratedType = decorate(FunctionTypeImpl.synthetic(
+ TypeParameterTypeImpl(typeFormal), [typeFormal], []));
+ expect(decoratedType.typeFormalBounds, hasLength(1));
+ checkNum(decoratedType.typeFormalBounds[0], never);
+ checkTypeParameter(decoratedType.returnType, never, typeFormal);
+ }
+
+ test_decorate_functionType_generic_no_explicit_bound() {
+ var typeFormal = TypeParameterElementImpl.synthetic('T');
+ var decoratedType = decorate(FunctionTypeImpl.synthetic(
+ TypeParameterTypeImpl(typeFormal), [typeFormal], []));
+ expect(decoratedType.typeFormalBounds, hasLength(1));
+ checkObject(decoratedType.typeFormalBounds[0], always);
+ checkTypeParameter(decoratedType.returnType, never, typeFormal);
+ }
+
test_decorate_functionType_named_parameter() {
checkDynamic(
decorate(FunctionTypeImpl.synthetic(typeProvider.voidType, [], [
@@ -99,6 +151,14 @@
])).positionalParameters[0]);
}
+ test_decorate_functionType_question() {
+ expect(
+ decorate(FunctionTypeImpl.synthetic(typeProvider.voidType, [], [],
+ nullabilitySuffix: NullabilitySuffix.question))
+ .node,
+ same(always));
+ }
+
test_decorate_functionType_returnType() {
checkDynamic(
decorate(FunctionTypeImpl.synthetic(typeProvider.dynamicType, [], []))
@@ -110,17 +170,35 @@
decorate(FunctionTypeImpl.synthetic(typeProvider.voidType, [], [],
nullabilitySuffix: NullabilitySuffix.star))
.node,
- same(graph.never));
+ same(never));
+ }
+
+ test_decorate_interfaceType_simple_question() {
+ checkInt(
+ decorate(InterfaceTypeImpl(typeProvider.intType.element,
+ nullabilitySuffix: NullabilitySuffix.question)),
+ always);
}
test_decorate_interfaceType_simple_star() {
- checkInt(decorate(InterfaceTypeImpl(typeProvider.intType.element,
- nullabilitySuffix: NullabilitySuffix.star)));
+ checkInt(
+ decorate(InterfaceTypeImpl(typeProvider.intType.element,
+ nullabilitySuffix: NullabilitySuffix.star)),
+ never);
}
test_decorate_iterable_dynamic() {
var decorated = decorate(typeProvider.iterableDynamicType);
- checkIterable(decorated, checkDynamic);
+ checkIterable(decorated, never, checkDynamic);
+ }
+
+ test_decorate_typeParameterType_question() {
+ var element = TypeParameterElementImpl.synthetic('T');
+ checkTypeParameter(
+ decorate(TypeParameterTypeImpl(element,
+ nullabilitySuffix: NullabilitySuffix.question)),
+ always,
+ element);
}
test_decorate_typeParameterType_star() {
@@ -128,10 +206,70 @@
checkTypeParameter(
decorate(TypeParameterTypeImpl(element,
nullabilitySuffix: NullabilitySuffix.star)),
+ never,
element);
}
test_decorate_void() {
checkVoid(decorate(typeProvider.voidType));
}
+
+ test_getImmediateSupertypes_future() {
+ var element = typeProvider.futureType.element;
+ var decoratedSupertypes =
+ decorator.getImmediateSupertypes(element).toList();
+ var typeParam = element.typeParameters[0];
+ expect(decoratedSupertypes, hasLength(2));
+ checkObject(decoratedSupertypes[0], never);
+ // Since Future<T> is a subtype of FutureOr<T>, we consider FutureOr<T> to
+ // be an immediate supertype, even though the class declaration for Future
+ // doesn't mention FutureOr.
+ checkFutureOr(decoratedSupertypes[1], never,
+ (t) => checkTypeParameter(t, never, typeParam));
+ }
+
+ test_getImmediateSupertypes_generic() {
+ var t = ElementFactory.typeParameterElement('T');
+ var class_ = ElementFactory.classElement3(
+ name: 'C',
+ typeParameters: [t],
+ supertype: typeProvider.iterableType.instantiate([t.type]));
+ var decoratedSupertypes = decorator.getImmediateSupertypes(class_).toList();
+ expect(decoratedSupertypes, hasLength(1));
+ checkIterable(decoratedSupertypes[0], never,
+ (type) => checkTypeParameter(type, never, t));
+ }
+
+ test_getImmediateSupertypes_interface() {
+ var class_ = ElementFactory.classElement('C', typeProvider.objectType);
+ class_.interfaces = [typeProvider.numType];
+ var decoratedSupertypes = decorator.getImmediateSupertypes(class_).toList();
+ expect(decoratedSupertypes, hasLength(2));
+ checkObject(decoratedSupertypes[0], never);
+ checkNum(decoratedSupertypes[1], never);
+ }
+
+ test_getImmediateSupertypes_mixin() {
+ var class_ = ElementFactory.classElement('C', typeProvider.objectType);
+ class_.mixins = [typeProvider.numType];
+ var decoratedSupertypes = decorator.getImmediateSupertypes(class_).toList();
+ expect(decoratedSupertypes, hasLength(2));
+ checkObject(decoratedSupertypes[0], never);
+ checkNum(decoratedSupertypes[1], never);
+ }
+
+ test_getImmediateSupertypes_superclassConstraint() {
+ var class_ = ElementFactory.mixinElement(
+ name: 'C', constraints: [typeProvider.numType]);
+ var decoratedSupertypes = decorator.getImmediateSupertypes(class_).toList();
+ expect(decoratedSupertypes, hasLength(1));
+ checkNum(decoratedSupertypes[0], never);
+ }
+
+ test_getImmediateSupertypes_supertype() {
+ var class_ = ElementFactory.classElement('C', typeProvider.objectType);
+ var decoratedSupertypes = decorator.getImmediateSupertypes(class_).toList();
+ expect(decoratedSupertypes, hasLength(1));
+ checkObject(decoratedSupertypes[0], never);
+ }
}
diff --git a/pkg/nnbd_migration/test/api_test.dart b/pkg/nnbd_migration/test/api_test.dart
index c00be10..e7593d2 100644
--- a/pkg/nnbd_migration/test/api_test.dart
+++ b/pkg/nnbd_migration/test/api_test.dart
@@ -91,6 +91,86 @@
await _checkSingleFileChanges(content, expected);
}
+ test_catch_simple() async {
+ var content = '''
+void f() {
+ try {} catch (ex, st) {}
+}
+''';
+ var expected = '''
+void f() {
+ try {} catch (ex, st) {}
+}
+''';
+ await _checkSingleFileChanges(content, expected);
+ }
+
+ test_catch_simple_with_modifications() async {
+ var content = '''
+void f(String x, StackTrace y) {
+ try {} catch (ex, st) {
+ ex = x;
+ st = y;
+ }
+}
+main() {
+ f(null, null);
+}
+''';
+ var expected = '''
+void f(String? x, StackTrace? y) {
+ try {} catch (ex, st) {
+ ex = x;
+ st = y!;
+ }
+}
+main() {
+ f(null, null);
+}
+''';
+ await _checkSingleFileChanges(content, expected);
+ }
+
+ test_catch_with_on() async {
+ var content = '''
+void f() {
+ try {} on String catch (ex, st) {}
+}
+''';
+ var expected = '''
+void f() {
+ try {} on String catch (ex, st) {}
+}
+''';
+ await _checkSingleFileChanges(content, expected);
+ }
+
+ test_catch_with_on_with_modifications() async {
+ var content = '''
+void f(String x, StackTrace y) {
+ try {} on String catch (ex, st) {
+ ex = x;
+ st = y;
+ }
+}
+main() {
+ f(null, null);
+}
+''';
+ var expected = '''
+void f(String? x, StackTrace? y) {
+ try {} on String? catch (ex, st) {
+ ex = x;
+ st = y!;
+ }
+}
+main() {
+ f(null, null);
+}
+''';
+ await _checkSingleFileChanges(content, expected);
+ }
+
test_class_alias_synthetic_constructor_with_parameters() async {
var content = '''
void main() {
@@ -821,6 +901,72 @@
await _checkSingleFileChanges(content, expected);
}
+ test_dynamic_method_call() async {
+ var content = '''
+class C {
+ int g(int i) => i;
+}
+int f(bool b, dynamic d) {
+ if (b) return 0;
+ return d.g(null);
+}
+main() {
+ f(true, null);
+ f(false, C());
+}
+''';
+ // `d.g(null)` is a dynamic call, so we can't tell that it will target `C.g`
+ // at runtime. So we can't figure out that we need to make g's argument and
+ // return types nullable.
+ //
+ // We do, however, make f's return type nullable, since there is no way of
+ // knowing whether a dynamic call will return `null`.
+ var expected = '''
+class C {
+ int g(int i) => i;
+}
+int? f(bool b, dynamic d) {
+ if (b) return 0;
+ return d.g(null);
+}
+main() {
+ f(true, null);
+ f(false, C());
+}
+''';
+ await _checkSingleFileChanges(content, expected);
+ }
+
+ test_dynamic_property_access() async {
+ var content = '''
+class C {
+ int get g => 0;
+}
+int f(bool b, dynamic d) {
+ if (b) return 0;
+ return d.g;
+}
+main() {
+ f(true, null);
+ f(false, C());
+}
+''';
+ var expected = '''
+class C {
+ int get g => 0;
+}
+int? f(bool b, dynamic d) {
+ if (b) return 0;
+ return d.g;
+}
+main() {
+ f(true, null);
+ f(false, C());
+}
+''';
+ await _checkSingleFileChanges(content, expected);
+ }
+
test_field_formal_param_typed() async {
var content = '''
class C {
@@ -935,6 +1081,54 @@
await _checkSingleFileChanges(content, expected);
}
+ test_field_initializer_untyped_list_literal() async {
+ var content = '''
+class C {
+ List<int> f;
+ C() : f = [null];
+}
+''';
+ var expected = '''
+class C {
+ List<int?> f;
+ C() : f = [null];
+}
+''';
+ await _checkSingleFileChanges(content, expected);
+ }
+
+ test_field_initializer_untyped_map_literal() async {
+ var content = '''
+class C {
+ Map<String, int> f;
+ C() : f = {"foo": null};
+}
+''';
+ var expected = '''
+class C {
+ Map<String, int?> f;
+ C() : f = {"foo": null};
+}
+''';
+ await _checkSingleFileChanges(content, expected);
+ }
+
+ test_field_initializer_untyped_set_literal() async {
+ var content = '''
+class C {
+ Set<int> f;
+ C() : f = {null};
+}
+''';
+ var expected = '''
+class C {
+ Set<int?> f;
+ C() : f = {null};
+}
+''';
+ await _checkSingleFileChanges(content, expected);
+ }
+
test_field_type_inferred() async {
var content = '''
int f() => null;
@@ -960,6 +1154,36 @@
await _checkSingleFileChanges(content, expected);
}
+ test_flow_analysis_complex() async {
+ var content = '''
+int f(int x) {
+ while (x == null) {
+ x = g(x);
+ }
+ return x;
+}
+int g(int x) => x == null ? 1 : null;
+main() {
+ f(null);
+}
+''';
+ // Flow analysis can tell that the loop only exits if x is non-null, so the
+ // return type of `f` can remain `int`, and no null check is needed.
+ var expected = '''
+int f(int? x) {
+ while (x == null) {
+ x = g(x);
+ }
+ return x;
+}
+int? g(int? x) => x == null ? 1 : null;
+main() {
+ f(null);
+}
+''';
+ await _checkSingleFileChanges(content, expected);
+ }
+
test_flow_analysis_simple() async {
var content = '''
int f(int x) {
@@ -1448,6 +1672,77 @@
await _checkSingleFileChanges(content, expected);
}
+ @failingTest
+ test_map_nullable_input() async {
+ // TODO(paulberry): we're currently migrating this example incorrectly.
+ // See discussion at https://dart-review.googlesource.com/c/sdk/+/115766
+ var content = '''
+Iterable<int> f(List<int> x) => x.map((y) => g(y));
+int g(int x) => x + 1;
+main() {
+ f([null]);
+}
+''';
+ var expected = '''
+Iterable<int> f(List<int?> x) => x.map((y) => g(y!));
+int g(int x) => x + 1;
+main() {
+ f([null]);
+}
+''';
+ await _checkSingleFileChanges(content, expected);
+ }
+
+ test_map_nullable_output() async {
+ var content = '''
+Iterable<int> f(List<int> x) => x.map((y) => g(y));
+int g(int x) => null;
+main() {
+ f([1]);
+}
+''';
+ var expected = '''
+Iterable<int?> f(List<int> x) => x.map((y) => g(y));
+int? g(int x) => null;
+main() {
+ f([1]);
+}
+''';
+ await _checkSingleFileChanges(content, expected);
+ }
+
+ test_methodInvocation_typeArguments_explicit() async {
+ var content = '''
+T f<T>(T t) => t;
+void g() {
+ int x = f<int>(null);
+}
+''';
+ var expected = '''
+T f<T>(T t) => t;
+void g() {
+ int? x = f<int?>(null);
+}
+''';
+ await _checkSingleFileChanges(content, expected);
+ }
+
+ test_methodInvocation_typeArguments_inferred() async {
+ var content = '''
+T f<T>(T t) => t;
+void g() {
+ int x = f(null);
+}
+''';
+ var expected = '''
+T f<T>(T t) => t;
+void g() {
+ int? x = f(null);
+}
+''';
+ await _checkSingleFileChanges(content, expected);
+ }
+
test_multiDeclaration_innerUsage() async {
var content = '''
void test() {
@@ -2036,6 +2331,36 @@
await _checkSingleFileChanges(content, expected);
}
+ test_prefixes() async {
+ var root = '/home/test/lib';
+ var path1 = convertPath('$root/file1.dart');
+ var file1 = '''
+import 'file2.dart';
+int x;
+int f() => null;
+''';
+ var expected1 = '''
+import 'file2.dart';
+int? x;
+int? f() => null;
+''';
+ var path2 = convertPath('$root/file2.dart');
+ var file2 = '''
+import 'file1.dart' as f1;
+void main() {
+ f1.x = f1.f();
+}
+''';
+ var expected2 = '''
+import 'file1.dart' as f1;
+void main() {
+ f1.x = f1.f();
+}
+''';
+ await _checkMultipleFileChanges(
+ {path1: file1, path2: file2}, {path1: expected1, path2: expected2});
+ }
+
test_prefixExpression_bang() async {
var content = '''
bool f(bool b) => !b;
diff --git a/pkg/nnbd_migration/test/edge_builder_flow_analysis_test.dart b/pkg/nnbd_migration/test/edge_builder_flow_analysis_test.dart
index 07b8aeb..3643d8a 100644
--- a/pkg/nnbd_migration/test/edge_builder_flow_analysis_test.dart
+++ b/pkg/nnbd_migration/test/edge_builder_flow_analysis_test.dart
@@ -230,6 +230,78 @@
assertEdge(iNode, jNode, hard: false);
}
+ test_catch_cancels_promotions_based_on_assignments_in_body() async {
+ await analyze('''
+void f(int i) {
+ if (i == null) return;
+ try {
+ g(i);
+ i = null;
+ if (i == null) return;
+ g(i);
+ } catch (_) {
+ h(i);
+ }
+}
+void g(int j) {}
+void h(int k) {}
+''');
+ var iNode = decoratedTypeAnnotation('int i').node;
+ var jNode = decoratedTypeAnnotation('int j').node;
+ var kNode = decoratedTypeAnnotation('int k').node;
+ // No edge from i to j because i is promoted at the time of both calls to g.
+ assertNoEdge(iNode, jNode);
+ // But there is an edge from i to k, because there is no guarantee that i is
+ // promoted at all times during the execution of the try block.
+ assertEdge(iNode, kNode, hard: false);
+ }
+
+ test_catch_falls_through_to_after_try() async {
+ await analyze('''
+void f(int i) {
+ try {
+ g(i);
+ return;
+ } catch (_) {
+ if (i == null) return;
+ }
+ h(i);
+}
+void g(int j) {}
+void h(int k) {}
+''');
+ var iNode = decoratedTypeAnnotation('int i').node;
+ var jNode = decoratedTypeAnnotation('int j').node;
+ var kNode = decoratedTypeAnnotation('int k').node;
+ // No edge from i to k because i's type is promoted to non-nullable
+ assertNoEdge(iNode, kNode);
+ // But there is an edge from i to j.
+ assertEdge(iNode, jNode, hard: true);
+ }
+
+ test_catch_resets_to_state_before_try() async {
+ await analyze('''
+void f(int i) {
+ try {
+ if (i == null) return;
+ g(i);
+ } catch (_) {
+ h(i);
+ }
+}
+void g(int j) {}
+void h(int k) {}
+''');
+ var iNode = decoratedTypeAnnotation('int i').node;
+ var jNode = decoratedTypeAnnotation('int j').node;
+ var kNode = decoratedTypeAnnotation('int k').node;
+ // No edge from i to j because i's type is promoted to non-nullable
+ assertNoEdge(iNode, jNode);
+ // But there is an edge from i to k, since we assume an exception might
+ // occur at any time during the body of the try.
+ assertEdge(iNode, kNode, hard: false);
+ }
+
test_conditionalExpression() async {
await analyze('''
int f(int i) => i == null ? g(i) : h(i);
@@ -455,6 +527,191 @@
// field doesn't cause flow analysis to crash.
}
+ test_finally_promotions_are_preserved() async {
+ await analyze('''
+void f(int i) {
+ try {
+ g(i);
+ } finally {
+ if (i == null) return;
+ }
+ h(i);
+}
+void g(int j) {}
+void h(int k) {}
+''');
+ var iNode = decoratedTypeAnnotation('int i').node;
+ var jNode = decoratedTypeAnnotation('int j').node;
+ var kNode = decoratedTypeAnnotation('int k').node;
+ // No edge from i to k because i's type is promoted to non-nullable in the
+ // finally block.
+ assertNoEdge(iNode, kNode);
+ // But there is an edge from i to j.
+ assertEdge(iNode, jNode, hard: true);
+ }
+
+ test_finally_temporarily_resets_to_state_before_try() async {
+ await analyze('''
+void f(int i) {
+ try {
+ if (i == null) return;
+ g(i);
+ } finally {
+ h(i);
+ }
+}
+void g(int j) {}
+void h(int k) {}
+''');
+ var iNode = decoratedTypeAnnotation('int i').node;
+ var jNode = decoratedTypeAnnotation('int j').node;
+ var kNode = decoratedTypeAnnotation('int k').node;
+ // No edge from i to j because i's type is promoted to non-nullable in the
+ // try-block.
+ assertNoEdge(iNode, jNode);
+ // But there is an edge from i to k, since we assume an exception might
+ // occur at any time during the body of the try.
+ assertEdge(iNode, kNode, hard: false);
+ }
+
+ test_for_break_target() async {
+ await analyze('''
+void f(int i) {
+ L: for (;;) {
+ for (;;) {
+ if (i != null) break L;
+ if (b()) break;
+ }
+ g(i);
+ }
+ h(i);
+}
+bool b() => true;
+void g(int j) {}
+void h(int k) {}
+''');
+ var iNode = decoratedTypeAnnotation('int i').node;
+ var jNode = decoratedTypeAnnotation('int j').node;
+ var kNode = decoratedTypeAnnotation('int k').node;
+ // No edge from i to k because i is promoted at the time of the call to h.
+ assertNoEdge(iNode, kNode);
+ // But there is an edge from i to j, because i is not promoted at the time
+ // of the call to g.
+ assertEdge(iNode, jNode, hard: false);
+ }
+
+ test_for_cancels_promotions_for_assignments_in_body() async {
+ await analyze('''
+void f(int i, int j) {
+ if (i == null) return;
+ if (j == null) return;
+ for (;;) {
+ i.isEven;
+ j.isEven;
+ j = null;
+ }
+}
+''');
+ var iNode = decoratedTypeAnnotation('int i').node;
+ var jNode = decoratedTypeAnnotation('int j').node;
+ // No edge from i to never because is is promoted.
+ assertNoEdge(iNode, never);
+ // But there is an edge from j to never because its promotion was cancelled.
+ assertEdge(jNode, never, hard: false);
+ }
+
+ test_for_cancels_promotions_for_assignments_in_updaters() async {
+ await analyze('''
+void f(int i, int j) {
+ if (i == null) return;
+ if (j == null) return;
+ for (;; j = null) {
+ i.isEven;
+ j.isEven;
+ }
+}
+''');
+ var iNode = decoratedTypeAnnotation('int i').node;
+ var jNode = decoratedTypeAnnotation('int j').node;
+ // No edge from i to never because is is promoted.
+ assertNoEdge(iNode, never);
+ // But there is an edge from j to never because its promotion was cancelled.
+ assertEdge(jNode, never, hard: false);
+ }
+
+ test_for_collection_cancels_promotions_for_assignments_in_body() async {
+ await analyze('''
+void f(int i, int j) {
+ if (i == null) return;
+ if (j == null) return;
+ <Object>[for (;;) <Object>[i.isEven, j.isEven, (j = null)]];
+}
+''');
+ var iNode = decoratedTypeAnnotation('int i').node;
+ var jNode = decoratedTypeAnnotation('int j').node;
+ // No edge from i to never because is is promoted.
+ assertNoEdge(iNode, never);
+ // But there is an edge from j to never because its promotion was cancelled.
+ assertEdge(jNode, never, hard: false);
+ }
+
+ test_for_collection_cancels_promotions_for_assignments_in_updaters() async {
+ await analyze('''
+void f(int i, int j) {
+ if (i == null) return;
+ if (j == null) return;
+ <Object>[for (;; j = null) <Object>[i.isEven, j.isEven]];
+}
+''');
+ var iNode = decoratedTypeAnnotation('int i').node;
+ var jNode = decoratedTypeAnnotation('int j').node;
+ // No edge from i to never because is is promoted.
+ assertNoEdge(iNode, never);
+ // But there is an edge from j to never because its promotion was cancelled.
+ assertEdge(jNode, never, hard: false);
+ }
+
+ test_for_collection_preserves_promotions_for_assignments_in_initializer() async {
+ await analyze('''
+void f(int i, int j) {
+ if (i == null) return;
+ <Object>[for(var v = h(i.isEven && j.isEven && g(i = null));;) null];
+}
+bool g(int k) => true;
+int h(bool b) => 0;
+''');
+ var iNode = decoratedTypeAnnotation('int i').node;
+ var jNode = decoratedTypeAnnotation('int j').node;
+ // No edge from i to never because it is promoted.
+ assertNoEdge(iNode, never);
+ // But there is an edge from j to never.
+ assertEdge(jNode, never, hard: false);
+ }
+
+ test_for_continue_target() async {
+ await analyze('''
+void f(int i) {
+ L: for (; b(); h(i)) {
+ for (; b(); g(i)) {
+ if (i != null) continue L;
+ }
+ return;
+ }
+}
+bool b() => true;
+void g(int j) {}
+void h(int k) {}
+''');
+ var iNode = decoratedTypeAnnotation('int i').node;
+ var jNode = decoratedTypeAnnotation('int j').node;
+ var kNode = decoratedTypeAnnotation('int k').node;
+ // No edge from i to k because i is promoted at the time of the call to h.
+ assertNoEdge(iNode, kNode);
+ // But there is an edge from i to j, because i is not promoted at the time
+ // of the call to g.
+ assertEdge(iNode, jNode, hard: false);
+ }
+
test_for_each_cancels_promotions_for_assignments_in_body() async {
await analyze('''
void f(int i, int j, Iterable<Object> x) {
@@ -525,6 +782,23 @@
assertEdge(jNode, never, hard: false);
}
+ test_for_preserves_promotions_for_assignments_in_initializer() async {
+ await analyze('''
+void f(int i, int j) {
+ if (i == null) return;
+ for(var v = h(i.isEven && j.isEven && g(i = null));;) {}
+}
+bool g(int k) => true;
+int h(bool b) => 0;
+''');
+ var iNode = decoratedTypeAnnotation('int i').node;
+ var jNode = decoratedTypeAnnotation('int j').node;
+ // No edge from i to never because it is promoted.
+ assertNoEdge(iNode, never);
+ // But there is an edge from j to never.
+ assertEdge(jNode, never, hard: false);
+ }
+
test_functionDeclaration() async {
await analyze('''
void f(int i, int j) {
@@ -632,6 +906,25 @@
assertEdge(iNode, jNode, hard: false, guards: [iNode]);
}
+ test_ifNull() async {
+ await analyze('''
+void f(int i, int x) {
+ x ?? (i == null ? throw 'foo' : g(i));
+ h(i);
+}
+int g(int j) => 0;
+void h(int k) {}
+''');
+ var iNode = decoratedTypeAnnotation('int i').node;
+ var jNode = decoratedTypeAnnotation('int j').node;
+ var kNode = decoratedTypeAnnotation('int k').node;
+ // No edge from i to j because i's type is promoted to non-nullable
+ assertNoEdge(iNode, jNode);
+ // But there is an edge from i to k, because the RHS of the `??` isn't
+ // guaranteed to execute.
+ assertEdge(iNode, kNode, hard: true);
+ }
+
test_local_function_parameters() async {
await analyze('''
void f() {
@@ -650,6 +943,49 @@
assertEdge(jNode, never, hard: false);
}
+ test_not() async {
+ await analyze('''
+void f(int i) {
+ if (!(i == null)) {
+ h(i);
+ } else {
+ g(i);
+ }
+}
+void g(int j) {}
+void h(int k) {}
+''');
+ var iNode = decoratedTypeAnnotation('int i').node;
+ var jNode = decoratedTypeAnnotation('int j').node;
+ var kNode = decoratedTypeAnnotation('int k').node;
+ // No edge from i to k because i is known to be non-nullable at the site of
+ // the call to h()
+ assertNoEdge(iNode, kNode);
+ // But there is an edge from i to j
+ assertEdge(iNode, jNode, hard: false);
+ }
+
+ test_rethrow() async {
+ await analyze('''
+void f(int i, int j) {
+ try {
+ g();
+ } catch (_) {
+ if (i == null) rethrow;
+ print(i.isEven);
+ print(j.isEven);
+ }
+}
+void g() {}
+''');
+ var iNode = decoratedTypeAnnotation('int i').node;
+ var jNode = decoratedTypeAnnotation('int j').node;
+ // No edge from i to `never` because i's type is promoted to non-nullable
+ assertNoEdge(iNode, never);
+ // But there is an edge from j to `never`.
+ assertEdge(jNode, never, hard: false);
+ }
+
test_return() async {
await analyze('''
void f(int i, int j) {
@@ -666,6 +1002,108 @@
assertEdge(jNode, never, hard: false);
}
+ test_switch_break_target() async {
+ await analyze('''
+void f(int i, int x, int y) {
+ L: switch (x) {
+ default:
+ switch (y) {
+ default:
+ if (i != null) break L;
+ if (b()) break;
+ return;
+ }
+ g(i);
+ return;
+ }
+ h(i);
+}
+bool b() => true;
+void g(int j) {}
+void h(int k) {}
+''');
+ var iNode = decoratedTypeAnnotation('int i').node;
+ var jNode = decoratedTypeAnnotation('int j').node;
+ var kNode = decoratedTypeAnnotation('int k').node;
+ // No edge from i to k because i is promoted at the time of the call to h.
+ assertNoEdge(iNode, kNode);
+ // But there is an edge from i to j, because i is not promoted at the time
+ // of the call to g.
+ assertEdge(iNode, jNode, hard: false);
+ }
+
+ test_switch_cancels_promotions_for_labeled_cases() async {
+ await analyze('''
+void f(int i, int x, bool b) {
+ if (i == null) return;
+ switch (x) {
+ L:
+ case 1:
+ g(i);
+ break;
+ case 2:
+ h(i);
+ i = null;
+ if (b) continue L;
+ break;
+ }
+}
+void g(int j) {}
+void h(int k) {}
+''');
+ var iNode = decoratedTypeAnnotation('int i').node;
+ var jNode = decoratedTypeAnnotation('int j').node;
+ var kNode = decoratedTypeAnnotation('int k').node;
+ // No edge from i to k because i's type is promoted to non-nullable at the
+ // time of the call to h.
+ assertNoEdge(iNode, kNode);
+ // But there is an edge from i to j.
+ assertEdge(iNode, jNode, hard: false);
+ }
+
+ test_switch_default() async {
+ await analyze('''
+void f(int i, int j, int x, int y) {
+ if (i == null) {
+ switch (x) {
+ default: return;
+ }
+ }
+ if (j == null) {
+ switch (y) {
+ case 0: return;
+ }
+ }
+ i.isEven;
+ j.isEven;
+}
+''');
+ var iNode = decoratedTypeAnnotation('int i').node;
+ var jNode = decoratedTypeAnnotation('int j').node;
+ // No edge from i to `never` because the switch statement is guaranteed to
+ // complete by returning, so i is promoted to non-nullable.
+ assertNoEdge(iNode, never);
+ // But there is an edge from j to never, because the switch statement is not
+ // guaranteed to complete by returning, so j is not promoted.
+ assertEdge(jNode, never, hard: false);
+ }
+
+ test_throw() async {
+ await analyze('''
+void f(int i, int j) {
+ if (i == null) throw 'foo';
+ print(i.isEven);
+ print(j.isEven);
+}
+''');
+ var iNode = decoratedTypeAnnotation('int i').node;
+ var jNode = decoratedTypeAnnotation('int j').node;
+ // No edge from i to `never` because i's type is promoted to non-nullable
+ assertNoEdge(iNode, never);
+ // But there is an edge from j to `never`.
+ assertEdge(jNode, never, hard: true);
+ }
+
test_topLevelVar_initializer() async {
await analyze('''
bool b1 = true;
@@ -676,6 +1114,29 @@
// top level variable doesn't cause flow analysis to crash.
}
+ test_try_falls_through_to_after_try() async {
+ await analyze('''
+void f(int i) {
+ try {
+ g(i);
+ if (i == null) return;
+ } catch (_) {
+ return;
+ }
+ h(i);
+}
+void g(int j) {}
+void h(int k) {}
+''');
+ var iNode = decoratedTypeAnnotation('int i').node;
+ var jNode = decoratedTypeAnnotation('int j').node;
+ var kNode = decoratedTypeAnnotation('int k').node;
+ // No edge from i to k because i's type is promoted to non-nullable
+ assertNoEdge(iNode, kNode);
+ // But there is an edge from i to j.
+ assertEdge(iNode, jNode, hard: true);
+ }
+
test_while_break_target() async {
await analyze('''
void f(int i) {
diff --git a/pkg/nnbd_migration/test/edge_builder_test.dart b/pkg/nnbd_migration/test/edge_builder_test.dart
index fa14641..079cf85 100644
--- a/pkg/nnbd_migration/test/edge_builder_test.dart
+++ b/pkg/nnbd_migration/test/edge_builder_test.dart
@@ -48,8 +48,8 @@
var typeProvider = TestTypeProvider();
var graph = NullabilityGraphForTesting();
var decoratedClassHierarchy = _DecoratedClassHierarchyForTesting();
- var checker = AssignmentCheckerForTesting(
- Dart2TypeSystem(typeProvider), graph, decoratedClassHierarchy);
+ var checker = AssignmentCheckerForTesting(Dart2TypeSystem(typeProvider),
+ typeProvider, graph, decoratedClassHierarchy);
var assignmentCheckerTest =
AssignmentCheckerTest._(typeProvider, graph, checker);
decoratedClassHierarchy.assignmentCheckerTest = assignmentCheckerTest;
@@ -83,7 +83,7 @@
var t = list(object());
assign(bottom, t);
assertEdge(never, t.node, hard: false);
- expect(graph.getUpstreamEdges(t.typeArguments[0].node), isEmpty);
+ assertNoEdge(anyNode, t.typeArguments[0].node);
}
void test_bottom_to_simple() {
@@ -165,11 +165,19 @@
assertEdge(t1.returnType.node, t2.returnType.node, hard: false);
}
+ void test_future_int_to_future_or_int() {
+ var t1 = future(int_());
+ var t2 = futureOr(int_());
+ assign(t1, t2, hard: true);
+ assertEdge(t1.node, t2.node, hard: true);
+ assertEdge(t1.typeArguments[0].node, t2.typeArguments[0].node, hard: false);
+ }
+
test_generic_to_dynamic() {
var t = list(object());
assign(t, dynamic_);
assertEdge(t.node, always, hard: false);
- expect(graph.getDownstreamEdges(t.typeArguments[0].node), isEmpty);
+ assertNoEdge(t.typeArguments[0].node, anyNode);
}
test_generic_to_generic_downcast() {
@@ -185,10 +193,7 @@
// - the supertype of MyListOfList<T> is List<List<T?C>>
var c = _myListOfListSupertype.typeArguments[0].typeArguments[0].node;
// Then there should be an edge from b to substitute(a, c)
- var substitutionNode = graph.getDownstreamEdges(b).single.destinationNode
- as NullabilityNodeForSubstitution;
- expect(substitutionNode.innerNode, same(a));
- expect(substitutionNode.outerNode, same(c));
+ assertEdge(b, substitutionNode(a, c), hard: false);
}
test_generic_to_generic_same_element() {
@@ -212,10 +217,7 @@
// - the supertype of MyListOfList<T> is List<List<T?C>>
var c = _myListOfListSupertype.typeArguments[0].typeArguments[0].node;
// Then there should be an edge from substitute(a, c) to b.
- var substitutionNode = graph.getUpstreamEdges(b).single.primarySource
- as NullabilityNodeForSubstitution;
- expect(substitutionNode.innerNode, same(a));
- expect(substitutionNode.outerNode, same(c));
+ assertEdge(substitutionNode(a, c), b, hard: false);
}
test_generic_to_object() {
@@ -223,21 +225,36 @@
var t2 = object();
assign(t1, t2);
assertEdge(t1.node, t2.node, hard: false);
- expect(graph.getDownstreamEdges(t1.typeArguments[0].node), isEmpty);
+ assertNoEdge(t1.typeArguments[0].node, anyNode);
}
test_generic_to_void() {
var t = list(object());
assign(t, void_);
assertEdge(t.node, always, hard: false);
- expect(graph.getDownstreamEdges(t.typeArguments[0].node), isEmpty);
+ assertNoEdge(t.typeArguments[0].node, anyNode);
+ }
+
+ void test_int_to_future_or_int() {
+ var t1 = int_();
+ var t2 = futureOr(int_());
+ assign(t1, t2, hard: true);
+ // Note: given code like:
+ // int x = null;
+ // FutureOr<int> y = x;
+ // There are two possible migrations for `FutureOr<int>`: we could change it
+ // to either `FutureOr<int?>` or `FutureOr<int>?`. We choose to do
+ // `FutureOr<int>?` because it is a narrower type, so it is less likely to
+ // cause a proliferation of nullable types in the user's program.
+ assertEdge(t1.node, t2.node, hard: true);
+ assertNoEdge(t1.node, t2.typeArguments[0].node);
}
void test_null_to_generic() {
var t = list(object());
assign(null_, t);
assertEdge(always, t.node, hard: false);
- expect(graph.getUpstreamEdges(t.typeArguments[0].node), isEmpty);
+ assertNoEdge(anyNode, t.typeArguments[0].node);
}
void test_null_to_simple() {
@@ -330,7 +347,7 @@
// upstream from it.
if (node == never) return;
- for (var edge in graph.getUpstreamEdges(node)) {
+ for (var edge in getEdges(anyNode, node)) {
expect(edge.primarySource, never);
}
}
@@ -358,6 +375,42 @@
return variables.decoratedExpressionType(findNode.expression(text));
}
+ test_as_dynamic() async {
+ await analyze('''
+void f(Object o) {
+ (o as dynamic).gcd(1);
+}
+''');
+ assertEdge(decoratedTypeAnnotation('Object o').node,
+ decoratedTypeAnnotation('dynamic').node,
+ hard: true);
+ // TODO(mfairhurst): these should probably be hard edges.
+ assertEdge(decoratedTypeAnnotation('dynamic').node, never, hard: false);
+ }
+
+ test_as_int() async {
+ await analyze('''
+void f(Object o) {
+ (o as int).gcd(1);
+}
+''');
+ assertEdge(decoratedTypeAnnotation('Object o').node,
+ decoratedTypeAnnotation('int').node,
+ hard: true);
+ // TODO(mfairhurst): these should probably be hard edges.
+ assertEdge(decoratedTypeAnnotation('int').node, never, hard: false);
+ }
+
+ test_already_migrated_field() async {
+ await analyze('''
+double f() => double.NAN;
+''');
+ var nanElement = typeProvider.doubleType.element.getField('NAN');
+ assertEdge(variables.decoratedElementType(nanElement).node,
+ decoratedTypeAnnotation('double f').node,
+ hard: false);
+ }
+
test_assert_demonstrates_non_null_intent() async {
await analyze('''
void f(int i) {
@@ -384,6 +437,100 @@
hard: false);
}
+ test_assign_dynamic_to_other_type() async {
+ await analyze('''
+int f(dynamic d) => d;
+''');
+ // There is no explicit null check necessary, since `dynamic` is
+ // downcastable to any type, nullable or not.
+ expect(checkExpression('d;'), isNull);
+ // But we still create an edge, to make sure that the possibility of `null`
+ // propagates to callees.
+ assertEdge(decoratedTypeAnnotation('dynamic').node,
+ decoratedTypeAnnotation('int').node,
+ hard: true);
+ }
+
+ test_assign_function_type_to_function_interface_type() async {
+ await analyze('''
+Function f(void Function() x) => x;
+''');
+ assertEdge(decoratedGenericFunctionTypeAnnotation('void Function()').node,
+ decoratedTypeAnnotation('Function f').node,
+ hard: true);
+ }
+
+ test_assign_future_to_futureOr_complex() async {
+ await analyze('''
+import 'dart:async';
+FutureOr<List<int>> f(Future<List<int>> x) => x;
+''');
+ // If `x` is `Future<List<int?>>`, then the only way to migrate is to make
+ // the return type `FutureOr<List<int?>>`.
+ assertEdge(decoratedTypeAnnotation('int>> x').node,
+ decoratedTypeAnnotation('int>> f').node,
+ hard: false);
+ assertNoEdge(decoratedTypeAnnotation('int>> x').node,
+ decoratedTypeAnnotation('List<int>> f').node);
+ assertNoEdge(decoratedTypeAnnotation('int>> x').node,
+ decoratedTypeAnnotation('FutureOr<List<int>> f').node);
+ }
+
+ test_assign_future_to_futureOr_simple() async {
+ await analyze('''
+import 'dart:async';
+FutureOr<int> f(Future<int> x) => x;
+''');
+ // If `x` is nullable, then there are two migrations possible: we could make
+ // the return type `FutureOr<int?>` or we could make it `FutureOr<int>?`.
+ // We choose `FutureOr<int>?` because it's strictly more conservative (it's
+ // a subtype of `FutureOr<int?>`).
+ assertEdge(decoratedTypeAnnotation('Future<int> x').node,
+ decoratedTypeAnnotation('FutureOr<int>').node,
+ hard: true);
+ assertNoEdge(decoratedTypeAnnotation('Future<int> x').node,
+ decoratedTypeAnnotation('int> f').node);
+ // If `x` is `Future<int?>`, then the only way to migrate is to make the
+ // return type `FutureOr<int?>`.
+ assertEdge(substitutionNode(decoratedTypeAnnotation('int> x').node, never),
+ decoratedTypeAnnotation('int> f').node,
+ hard: false);
+ assertNoEdge(decoratedTypeAnnotation('int> x').node,
+ decoratedTypeAnnotation('FutureOr<int>').node);
+ }
+
+ test_assign_non_future_to_futureOr_complex() async {
+ await analyze('''
+import 'dart:async';
+FutureOr<List<int>> f(List<int> x) => x;
+''');
+ // If `x` is `List<int?>`, then the only way to migrate is to make the
+ // return type `FutureOr<List<int?>>`.
+ assertEdge(decoratedTypeAnnotation('int> x').node,
+ decoratedTypeAnnotation('int>> f').node,
+ hard: false);
+ assertNoEdge(decoratedTypeAnnotation('int> x').node,
+ decoratedTypeAnnotation('List<int>> f').node);
+ assertNoEdge(decoratedTypeAnnotation('int> x').node,
+ decoratedTypeAnnotation('FutureOr<List<int>> f').node);
+ }
+
+ test_assign_non_future_to_futureOr_simple() async {
+ await analyze('''
+import 'dart:async';
+FutureOr<int> f(int x) => x;
+''');
+ // If `x` is nullable, then there are two migrations possible: we could make
+ // the return type `FutureOr<int?>` or we could make it `FutureOr<int>?`.
+ // We choose `FutureOr<int>?` because it's strictly more conservative (it's
+ // a subtype of `FutureOr<int?>`).
+ assertEdge(decoratedTypeAnnotation('int x').node,
+ decoratedTypeAnnotation('FutureOr<int>').node,
+ hard: true);
+ assertNoEdge(decoratedTypeAnnotation('int x').node,
+ decoratedTypeAnnotation('int>').node);
+ }
+
test_assign_null_to_generic_type() async {
await analyze('''
main() {
@@ -421,12 +568,76 @@
var iterableInt = decoratedTypeAnnotation('Iterable<int>');
var listInt = decoratedTypeAnnotation('List<int>');
assertEdge(listInt.node, iterableInt.node, hard: true);
- var substitution = graph
- .getUpstreamEdges(iterableInt.typeArguments[0].node)
- .single
- .primarySource as NullabilityNodeForSubstitution;
- expect(substitution.innerNode, same(listInt.typeArguments[0].node));
- expect(substitution.outerNode, same(never));
+ assertEdge(substitutionNode(listInt.typeArguments[0].node, never),
+ iterableInt.typeArguments[0].node,
+ hard: false);
+ }
+
+ test_assignmentExpression_compound_dynamic() async {
+ await analyze('''
+void f(dynamic x, int y) {
+ x += y;
+}
+''');
+ // No assertions; just making sure this doesn't crash.
+ }
+
+ test_assignmentExpression_compound_simple() async {
+ var code = '''
+abstract class C {
+ C operator+(C x);
+}
+C f(C y, C z) => (y += z);
+''';
+ await analyze(code);
+ var targetEdge =
+ assertEdge(decoratedTypeAnnotation('C y').node, never, hard: true);
+ expect((targetEdge.origin as CompoundAssignmentOrigin).offset,
+ code.indexOf('+='));
+ assertNullCheck(
+ checkExpression('z);'),
+ assertEdge(decoratedTypeAnnotation('C z').node,
+ decoratedTypeAnnotation('C x').node,
+ hard: true));
+ var operatorReturnEdge = assertEdge(
+ decoratedTypeAnnotation('C operator').node,
+ decoratedTypeAnnotation('C y').node,
+ hard: false);
+ expect((operatorReturnEdge.origin as CompoundAssignmentOrigin).offset,
+ code.indexOf('+='));
+ var fReturnEdge = assertEdge(decoratedTypeAnnotation('C operator').node,
+ decoratedTypeAnnotation('C f').node,
+ hard: false);
+ assertNullCheck(checkExpression('(y += z)'), fReturnEdge);
+ }
+
+ test_assignmentExpression_compound_withSubstitution() async {
+ var code = '''
+abstract class C<T> {
+ C<T> operator+(C<T> x);
+}
+C<int> f(C<int> y, C<int> z) => (y += z);
+''';
+ await analyze(code);
+ var targetEdge =
+ assertEdge(decoratedTypeAnnotation('C<int> y').node, never, hard: true);
+ expect((targetEdge.origin as CompoundAssignmentOrigin).offset,
+ code.indexOf('+='));
+ assertNullCheck(
+ checkExpression('z);'),
+ assertEdge(decoratedTypeAnnotation('C<int> z').node,
+ decoratedTypeAnnotation('C<T> x').node,
+ hard: true));
+ var operatorReturnEdge = assertEdge(
+ decoratedTypeAnnotation('C<T> operator').node,
+ decoratedTypeAnnotation('C<int> y').node,
+ hard: false);
+ expect((operatorReturnEdge.origin as CompoundAssignmentOrigin).offset,
+ code.indexOf('+='));
+ var fReturnEdge = assertEdge(decoratedTypeAnnotation('C<T> operator').node,
+ decoratedTypeAnnotation('C<int> f').node,
+ hard: false);
+ assertNullCheck(checkExpression('(y += z)'), fReturnEdge);
}
test_assignmentExpression_field() async {
@@ -1362,6 +1573,15 @@
assertNoUpstreamNullability(decoratedTypeAnnotation('double').node);
}
+ test_export_metadata() async {
+ await analyze('''
+@deprecated
+export 'dart:async';
+''');
+ // No assertions needed; the AnnotationTracker mixin verifies that the
+ // metadata was visited.
+ }
+
test_field_metadata() async {
await analyze('''
class A {
@@ -1435,6 +1655,66 @@
decoratedTypeAnnotation('int i').node);
}
+ test_for_element_list() async {
+ await analyze('''
+void f(List<int> ints) {
+ <int>[for(int i in ints) i];
+}
+''');
+
+ assertNullCheck(
+ checkExpression('ints) i'),
+ assertEdge(decoratedTypeAnnotation('List<int> ints').node, never,
+ hard: true));
+ assertEdge(decoratedTypeAnnotation('int i').node,
+ decoratedTypeAnnotation('int>[').node,
+ hard: false);
+ }
+
+ test_for_element_map() async {
+ await analyze('''
+void f(List<String> strs, List<int> ints) {
+ <String, int>{
+ for (String s in strs)
+ for (int i in ints)
+ s: i,
+ };
+}
+''');
+
+ assertNullCheck(
+ checkExpression('strs)\n'),
+ assertEdge(decoratedTypeAnnotation('List<String> strs').node, never,
+ hard: true));
+ assertNullCheck(
+ checkExpression('ints)\n'),
+ assertEdge(decoratedTypeAnnotation('List<int> ints').node, never,
+ hard: false));
+
+ var keyTypeNode = decoratedTypeAnnotation('String, int>{').node;
+ var valueTypeNode = decoratedTypeAnnotation('int>{').node;
+ assertEdge(decoratedTypeAnnotation('String s').node, keyTypeNode,
+ hard: false);
+ assertEdge(decoratedTypeAnnotation('int i').node, valueTypeNode,
+ hard: false);
+ }
+
+ test_for_element_set() async {
+ await analyze('''
+void f(List<int> ints) {
+ <int>{for(int i in ints) i};
+}
+''');
+
+ assertNullCheck(
+ checkExpression('ints) i'),
+ assertEdge(decoratedTypeAnnotation('List<int> ints').node, never,
+ hard: true));
+ assertEdge(decoratedTypeAnnotation('int i').node,
+ decoratedTypeAnnotation('int>{').node,
+ hard: false);
+ }
+
test_for_with_declaration() async {
await analyze('''
main() {
@@ -1673,6 +1953,74 @@
hard: false));
}
+ test_genericMethodInvocation() async {
+ await analyze('''
+class Base {
+ T foo<T>(T x) => x;
+}
+class Derived extends Base {}
+int bar(Derived d, int i) => d.foo(i);
+''');
+ var implicitTypeArgumentMatcher = anyNode;
+ assertEdge(
+ decoratedTypeAnnotation('int i').node,
+ substitutionNode(
+ implicitTypeArgumentMatcher, decoratedTypeAnnotation('T x').node),
+ hard: true);
+ var implicitTypeArgumentNullability =
+ implicitTypeArgumentMatcher.matchingNode;
+ assertEdge(
+ substitutionNode(implicitTypeArgumentNullability,
+ decoratedTypeAnnotation('T foo').node),
+ decoratedTypeAnnotation('int bar').node,
+ hard: false);
+ }
+
+ test_genericMethodInvocation_withBoundSubstitution() async {
+ await analyze('''
+class Base<T> {
+ U foo<U extends T>(U x) => x;
+}
+class Derived<V> extends Base<Iterable<V>> {}
+bar(Derived<int> d, List<int> x) => d.foo(x);
+''');
+ // Don't bother checking any edges; the assertions in the DecoratedType
+ // constructor verify that we've substituted the bound correctly.
+ }
+
+ test_genericMethodInvocation_withSubstitution() async {
+ await analyze('''
+class Base<T> {
+ U foo<U>(U x, T y) => x;
+}
+class Derived<V> extends Base<List<V>> {}
+int bar(Derived<String> d, int i, List<String> j) => d.foo(i, j);
+''');
+ assertEdge(
+ decoratedTypeAnnotation('String> j').node,
+ substitutionNode(decoratedTypeAnnotation('String> d').node,
+ decoratedTypeAnnotation('V>>').node),
+ hard: false);
+ assertEdge(
+ decoratedTypeAnnotation('List<String> j').node,
+ substitutionNode(decoratedTypeAnnotation('List<V>>').node,
+ decoratedTypeAnnotation('T y').node),
+ hard: true);
+ var implicitTypeArgumentMatcher = anyNode;
+ assertEdge(
+ decoratedTypeAnnotation('int i').node,
+ substitutionNode(
+ implicitTypeArgumentMatcher, decoratedTypeAnnotation('U x').node),
+ hard: true);
+ var implicitTypeArgumentNullability =
+ implicitTypeArgumentMatcher.matchingNode;
+ assertEdge(
+ substitutionNode(implicitTypeArgumentNullability,
+ decoratedTypeAnnotation('U foo').node),
+ decoratedTypeAnnotation('int bar').node,
+ hard: false);
+ }
+
test_if_condition() async {
await analyze('''
void f(bool b) {
@@ -1685,22 +2033,41 @@
}
test_if_conditional_control_flow_after() async {
- // Asserts after ifs don't demonstrate non-null intent.
- // TODO(paulberry): if both branches complete normally, they should.
await analyze('''
-void f(bool b, int i) {
+void f(bool b, int i, int j) {
+ assert(j != null);
if (b) return;
assert(i != null);
}
''');
- assertNoEdge(always, decoratedTypeAnnotation('int i').node);
+ // Asserts after ifs don't demonstrate non-null intent.
+ assertNoEdge(decoratedTypeAnnotation('int i').node, never);
+ // But asserts before ifs do
+ assertEdge(decoratedTypeAnnotation('int j').node, never, hard: true);
+ }
+
+ test_if_conditional_control_flow_after_normal_completion() async {
+ await analyze('''
+void f(bool b1, bool b2, int i, int j) {
+ if (b1) {}
+ assert(j != null);
+ if (b2) return;
+ assert(i != null);
+}
+''');
+
+ // Asserts after `if (...) return` s don't demonstrate non-null intent.
+ assertNoEdge(decoratedTypeAnnotation('int i').node, never);
+ // But asserts after `if (...) {}` do, since both branches of the `if`
+ // complete normally, so the assertion is unconditionally reachable.
+ assertEdge(decoratedTypeAnnotation('int j').node, never, hard: true);
}
test_if_conditional_control_flow_within() async {
- // Asserts inside ifs don't demonstrate non-null intent.
await analyze('''
-void f(bool b, int i) {
+void f(bool b, int i, int j) {
+ assert(j != null);
if (b) {
assert(i != null);
} else {
@@ -1709,26 +2076,10 @@
}
''');
- assertNoEdge(always, decoratedTypeAnnotation('int i').node);
- }
-
- test_if_element() async {
- await analyze('''
-void f(bool b) {
- int i1 = null;
- int i2 = null;
- <int>[if (b) i1 else i2];
-}
-''');
-
- assertNullCheck(checkExpression('b) i1'),
- assertEdge(decoratedTypeAnnotation('bool b').node, never, hard: true));
- assertEdge(decoratedTypeAnnotation('int i1').node,
- decoratedTypeAnnotation('int>[').node,
- hard: false);
- assertEdge(decoratedTypeAnnotation('int i2').node,
- decoratedTypeAnnotation('int>[').node,
- hard: false);
+ // Asserts inside ifs don't demonstrate non-null intent.
+ assertNoEdge(decoratedTypeAnnotation('int i').node, never);
+ // But asserts outside ifs do.
+ assertEdge(decoratedTypeAnnotation('int j').node, never, hard: true);
}
@failingTest
@@ -1755,6 +2106,51 @@
expect(discard.pureCondition, true);
}
+ test_if_element_list() async {
+ await analyze('''
+void f(bool b) {
+ int i1 = null;
+ int i2 = null;
+ <int>[if (b) i1 else i2];
+}
+''');
+
+ assertNullCheck(checkExpression('b) i1'),
+ assertEdge(decoratedTypeAnnotation('bool b').node, never, hard: true));
+ assertEdge(decoratedTypeAnnotation('int i1').node,
+ decoratedTypeAnnotation('int>[').node,
+ hard: false);
+ assertEdge(decoratedTypeAnnotation('int i2').node,
+ decoratedTypeAnnotation('int>[').node,
+ hard: false);
+ }
+
+ test_if_element_map() async {
+ await analyze('''
+void f(bool b) {
+ int i1 = null;
+ int i2 = null;
+ String s1 = null;
+ String s2 = null;
+ <String, int>{if (b) s1: i1 else s2: i2};
+}
+''');
+
+ assertNullCheck(checkExpression('b) s1'),
+ assertEdge(decoratedTypeAnnotation('bool b').node, never, hard: true));
+
+ var keyTypeNode = decoratedTypeAnnotation('String, int>{').node;
+ var valueTypeNode = decoratedTypeAnnotation('int>{').node;
+ assertEdge(decoratedTypeAnnotation('String s1').node, keyTypeNode,
+ hard: false);
+ assertEdge(decoratedTypeAnnotation('String s2').node, keyTypeNode,
+ hard: false);
+ assertEdge(decoratedTypeAnnotation('int i1').node, valueTypeNode,
+ hard: false);
+ assertEdge(decoratedTypeAnnotation('int i2').node, valueTypeNode,
+ hard: false);
+ }
+
test_if_element_nested() async {
await analyze('''
void f(bool b1, bool b2) {
@@ -1782,6 +2178,25 @@
hard: false);
}
+ test_if_element_set() async {
+ await analyze('''
+void f(bool b) {
+ int i1 = null;
+ int i2 = null;
+ <int>{if (b) i1 else i2};
+}
+''');
+
+ assertNullCheck(checkExpression('b) i1'),
+ assertEdge(decoratedTypeAnnotation('bool b').node, never, hard: true));
+ assertEdge(decoratedTypeAnnotation('int i1').node,
+ decoratedTypeAnnotation('int>{').node,
+ hard: false);
+ assertEdge(decoratedTypeAnnotation('int i2').node,
+ decoratedTypeAnnotation('int>{').node,
+ hard: false);
+ }
+
test_if_guard_equals_null() async {
await analyze('''
int f(int i, int j, int k) {
@@ -1844,6 +2259,26 @@
assertEdge(nullable_i, nullable_return, hard: false));
}
+ test_import_metadata() async {
+ await analyze('''
+@deprecated
+import 'dart:async';
+''');
+ // No assertions needed; the AnnotationTracker mixin verifies that the
+ // metadata was visited.
+ }
+
+ test_indexExpression_dynamic() async {
+ await analyze('''
+int f(dynamic d, int i) {
+ return d[i];
+}
+''');
+ // We assume that the index expression might evaluate to anything, including
+ // `null`.
+ assertEdge(always, decoratedTypeAnnotation('int f').node, hard: false);
+ }
+
test_indexExpression_index() async {
await analyze('''
class C {
@@ -1932,6 +2367,33 @@
hard: false);
}
+ test_instanceCreation_generic_dynamic() async {
+ await analyze('''
+class C<T> {}
+C<Object> f() => C<dynamic>();
+''');
+ assertEdge(decoratedTypeAnnotation('dynamic').node,
+ decoratedTypeAnnotation('Object').node,
+ hard: false);
+ }
+
+ test_instanceCreation_generic_inferredParameterType() async {
+ await analyze('''
+class C<T> {
+ C(List<T> x);
+}
+C<int> f(List<int> x) => C(x);
+''');
+ var edge = assertEdge(anyNode, decoratedTypeAnnotation('int> f').node,
+ hard: false);
+ var inferredTypeArgument = edge.primarySource;
+ assertEdge(
+ decoratedTypeAnnotation('int> x').node,
+ substitutionNode(
+ inferredTypeArgument, decoratedTypeAnnotation('T> x').node),
+ hard: false);
+ }
+
test_instanceCreation_generic_parameter() async {
await analyze('''
class C<T> {
@@ -1951,6 +2413,25 @@
assertEdge(nullable_i, nullable_c_t_or_nullable_t, hard: true));
}
+ test_instanceCreation_generic_parameter_named() async {
+ await analyze('''
+class C<T> {
+ C({T t});
+}
+f(int i) => C<int>(t: i/*check*/);
+''');
+ var nullable_i = decoratedTypeAnnotation('int i').node;
+ var nullable_c_t = decoratedTypeAnnotation('C<int>').typeArguments[0].node;
+ var nullable_t = decoratedTypeAnnotation('T t').node;
+ var check_i = checkExpression('i/*check*/');
+ var nullable_c_t_or_nullable_t =
+ check_i.edges.single.destinationNode as NullabilityNodeForSubstitution;
+ expect(nullable_c_t_or_nullable_t.innerNode, same(nullable_c_t));
+ expect(nullable_c_t_or_nullable_t.outerNode, same(nullable_t));
+ assertNullCheck(check_i,
+ assertEdge(nullable_i, nullable_c_t_or_nullable_t, hard: true));
+ }
+
test_instanceCreation_parameter_named_optional() async {
await analyze('''
class C {
@@ -2028,6 +2509,15 @@
assertNoUpstreamNullability(decoratedTypeAnnotation('bool').node);
}
+ test_library_metadata() async {
+ await analyze('''
+@deprecated
+library foo;
+''');
+ // No assertions needed; the AnnotationTracker mixin verifies that the
+ // metadata was visited.
+ }
+
test_libraryDirective() async {
await analyze('''
library foo;
@@ -2035,31 +2525,38 @@
// Passes if no exceptions are thrown.
}
- @failingTest
test_listLiteral_noTypeArgument_noNullableElements() async {
- // Failing because we're not yet handling collection literals without a
- // type argument.
await analyze('''
List<String> f() {
return ['a', 'b'];
}
''');
assertNoUpstreamNullability(decoratedTypeAnnotation('List').node);
- // TODO(brianwilkerson) Add an assertion that there is an edge from the list
- // literal's fake type argument to the return type's type argument.
+ final returnTypeNode = decoratedTypeAnnotation('String').node;
+ final returnTypeEdges = getEdges(anyNode, returnTypeNode);
+
+ expect(returnTypeEdges.length, 1);
+ final returnTypeEdge = returnTypeEdges.single;
+
+ final listArgType = returnTypeEdge.primarySource;
+ assertNoUpstreamNullability(listArgType);
}
- @failingTest
test_listLiteral_noTypeArgument_nullableElement() async {
- // Failing because we're not yet handling collection literals without a
- // type argument.
await analyze('''
List<String> f() {
return ['a', null, 'c'];
}
''');
assertNoUpstreamNullability(decoratedTypeAnnotation('List').node);
- assertEdge(always, decoratedTypeAnnotation('String').node, hard: false);
+ final returnTypeNode = decoratedTypeAnnotation('String').node;
+ final returnTypeEdges = getEdges(anyNode, returnTypeNode);
+
+ expect(returnTypeEdges.length, 1);
+ final returnTypeEdge = returnTypeEdges.single;
+
+ final listArgType = returnTypeEdge.primarySource;
+ assertEdge(always, listArgType, hard: false);
}
test_listLiteral_typeArgument_noNullableElements() async {
@@ -2175,6 +2672,47 @@
assertEdge(decoratedTypeAnnotation('int k').node, never, hard: true);
}
+ test_methodInvocation_dynamic() async {
+ await analyze('''
+class C {
+ int g(int i) => i;
+}
+int f(dynamic d, int j) {
+ return d.g(j);
+}
+''');
+ // The call `d.g(j)` is dynamic, so we can't tell what method it resolves
+ // to. There's no reason to assume it resolves to `C.g`.
+ assertNoEdge(decoratedTypeAnnotation('int j').node,
+ decoratedTypeAnnotation('int i').node);
+ assertNoEdge(decoratedTypeAnnotation('int g').node,
+ decoratedTypeAnnotation('int f').node);
+ // We do, however, assume that it might return anything, including `null`.
+ assertEdge(always, decoratedTypeAnnotation('int f').node, hard: false);
+ }
+
+ test_methodInvocation_object_method() async {
+ await analyze('''
+String f(int i) => i.toString();
+''');
+ // No edge from i to `never` because it is safe to call `toString` on
+ // `null`.
+ assertNoEdge(decoratedTypeAnnotation('int').node, never);
+ }
+
+ test_methodInvocation_object_method_on_non_interface_type() async {
+ await analyze('''
+String f(void Function() g) => g.toString();
+''');
+ var toStringReturnType = variables
+ .decoratedElementType(
+ typeProvider.objectType.element.getMethod('toString'))
+ .returnType;
+ assertEdge(
+ toStringReturnType.node, decoratedTypeAnnotation('String f').node,
+ hard: false);
+ }
+
test_methodInvocation_parameter_contravariant() async {
await analyze('''
class C<T> {
@@ -2351,6 +2889,21 @@
assertEdge(lubNode, decoratedTypeAnnotation('bool f').node, hard: false);
}
+ test_methodInvocation_static_on_generic_class() async {
+ await analyze('''
+class C<T> {
+ static int f(int x) => 0;
+}
+int g(int y) => C.f(y);
+''');
+ assertEdge(decoratedTypeAnnotation('int y').node,
+ decoratedTypeAnnotation('int x').node,
+ hard: true);
+ assertEdge(decoratedTypeAnnotation('int f').node,
+ decoratedTypeAnnotation('int g').node,
+ hard: false);
+ }
+
test_methodInvocation_target_check() async {
await analyze('''
class C {
@@ -2405,6 +2958,95 @@
assertEdge(decoratedTypeAnnotation('C c').node, never, hard: true);
}
+ test_methodInvocation_target_generic_in_base_class() async {
+ await analyze('''
+abstract class B<T> {
+ void m(T/*1*/ t);
+}
+abstract class C extends B<int/*2*/> {}
+void f(C c, int/*3*/ i) {
+ c.m(i);
+}
+''');
+ // nullable(3) -> substitute(nullable(2), nullable(1))
+ var nullable1 = decoratedTypeAnnotation('T/*1*/').node;
+ var nullable2 = decoratedTypeAnnotation('int/*2*/').node;
+ var nullable3 = decoratedTypeAnnotation('int/*3*/').node;
+ assertEdge(nullable3, substitutionNode(nullable2, nullable1), hard: true);
+ }
+
+ test_methodInvocation_typeParameter_inferred() async {
+ await analyze('''
+T f<T>(T t) => t;
+void g() {
+ int y;
+ int x = f(y);
+}
+''');
+ var int_y = decoratedTypeAnnotation('int y').node;
+ var int_x = decoratedTypeAnnotation('int x').node;
+ var t_ret = decoratedTypeAnnotation('T f').node;
+ var t_param = decoratedTypeAnnotation('T t').node;
+
+ assertEdge(substitutionNode(anyNode, t_ret), int_x, hard: false);
+ assertEdge(int_y, substitutionNode(anyNode, t_param), hard: true);
+ assertEdge(t_param, t_ret, hard: true);
+ }
+
+ @failingTest
+ test_methodInvocation_typeParameter_inferred_inGenericClass() async {
+ // this creates an edge case because the typeArguments are not equal in
+ // length the the typeFormals of the calleeType, due to the enclosing
+ // generic class.
+ await analyze('''
+class C<T> {
+ void g() {
+ // use a local fn because generic methods aren't implemented.
+ T f<T>(T t) => t;
+ int y;
+ int x = f(y);
+ }
+}
+''');
+ var int_y = decoratedTypeAnnotation('int y').node;
+ var int_x = decoratedTypeAnnotation('int x').node;
+ var t_ret = decoratedTypeAnnotation('T f').node;
+ var t_param = decoratedTypeAnnotation('T t').node;
+
+ assertEdge(int_y, t_param, hard: true);
+ assertEdge(t_param, t_ret, hard: true);
+ assertEdge(t_ret, int_x, hard: false);
+ }
+
+ @failingTest
+ test_methodInvocation_typeParameter_inferred_inGenericExtreme() async {
+ // this creates an edge case because the typeArguments are not equal in
+ // length the the typeFormals of the calleeType, due to the enclosing
+ // generic class/functions.
+ await analyze('''
+class C<T> {
+ void g() {
+ // use local fns because generic methods aren't implemented.
+ void f2<R1>() {
+ void f3<R2>() {
+ T f<T>(T t) => t;
+ int y;
+ int x = f(y);
+ }
+ }
+ }
+}
+''');
+ var int_y = decoratedTypeAnnotation('int y').node;
+ var int_x = decoratedTypeAnnotation('int x').node;
+ var t_ret = decoratedTypeAnnotation('T f').node;
+ var t_param = decoratedTypeAnnotation('T t').node;
+
+ assertEdge(int_y, t_param, hard: true);
+ assertEdge(t_param, t_ret, hard: true);
+ assertEdge(t_ret, int_x, hard: false);
+ }
+
test_never() async {
await analyze('');
@@ -2572,6 +3214,62 @@
assertEdge(always, decoratedTypeAnnotation('int').node, hard: false));
}
+ test_part_metadata() async {
+ var pathContext = resourceProvider.pathContext;
+ addSource(pathContext.join(pathContext.dirname(testFile), 'part.dart'), '''
+part of test;
+''');
+ await analyze('''
+library test;
+@deprecated
+part 'part.dart';
+''');
+ // No assertions needed; the AnnotationTracker mixin verifies that the
+ // metadata was visited.
+ }
+
+ test_part_of_identifier() async {
+ var pathContext = resourceProvider.pathContext;
+ var testFileName = pathContext.basename(testFile);
+ addSource(pathContext.join(pathContext.dirname(testFile), 'lib.dart'), '''
+library test;
+part '$testFileName';
+''');
+ await analyze('''
+part of test;
+''');
+ // No assertions needed; the AnnotationTracker mixin verifies that the
+ // metadata was visited.
+ }
+
+ test_part_of_metadata() async {
+ var pathContext = resourceProvider.pathContext;
+ var testFileName = pathContext.basename(testFile);
+ addSource(pathContext.join(pathContext.dirname(testFile), 'lib.dart'), '''
+library test;
+part '$testFileName';
+''');
+ await analyze('''
+@deprecated
+part of test;
+''');
+ // No assertions needed; the AnnotationTracker mixin verifies that the
+ // metadata was visited.
+ }
+
+ test_part_of_path() async {
+ var pathContext = resourceProvider.pathContext;
+ var testFileName = pathContext.basename(testFile);
+ addSource(pathContext.join(pathContext.dirname(testFile), 'lib.dart'), '''
+part '$testFileName';
+''');
+ await analyze('''
+part of 'lib.dart';
+''');
+ // No assertions needed; the AnnotationTracker mixin verifies that the
+ // metadata was visited.
+ }
+
test_postDominators_assert() async {
await analyze('''
void test(bool b1, bool b2, bool b3, bool _b) {
@@ -2588,6 +3286,18 @@
assertEdge(decoratedTypeAnnotation('bool b3').node, never, hard: true);
}
+ test_postDominators_assignment_with_same_var_on_lhs_and_in_rhs() async {
+ await analyze('''
+void f(int i) {
+ i = g(i);
+}
+int g(int j) => 0;
+''');
+ assertEdge(decoratedTypeAnnotation('int i').node,
+ decoratedTypeAnnotation('int j').node,
+ hard: true);
+ }
+
test_postDominators_break() async {
await analyze('''
class C {
@@ -2953,6 +3663,22 @@
assertEdge(always, decoratedTypeAnnotation('int i').node, hard: false);
}
+ test_postDominators_questionQuestionOperator() async {
+ await analyze('''
+class C {
+ Object m() => null;
+}
+Object test(C x, C y) => x.m() ?? y.m();
+''');
+ // There is a hard edge from x to `never` because `x.m()` is unconditionally
+ // reachable from the top of `test`.
+ assertEdge(decoratedTypeAnnotation('C x').node, never, hard: true);
+ // However, the edge from y to `never` is soft because `y.m()` is only
+ // executed if `x.m()` returned `null`.
+ assertEdge(decoratedTypeAnnotation('C y').node, never,
+ hard: false, guards: [decoratedTypeAnnotation('Object m').node]);
+ }
+
test_postDominators_reassign() async {
await analyze('''
void test(bool b, int i1, int i2) {
@@ -3080,6 +3806,19 @@
assertEdge(decoratedTypeAnnotation('C c3').node, never, hard: false));
}
+ test_postDominators_tryCatch() async {
+ await analyze('''
+void test(int i) {
+ try {} catch (_) {
+ i.isEven;
+ }
+}
+''');
+ // Edge should not be hard because the call to `i.isEven` does not
+ // post-dominate the declaration of `i`.
+ assertEdge(decoratedTypeAnnotation('int i').node, never, hard: false);
+ }
+
test_postDominators_whileStatement_unconditional() async {
await analyze('''
class C {
@@ -3160,6 +3899,24 @@
hard: false);
}
+ test_prefixedIdentifier_getter_type_in_generic() async {
+ await analyze('''
+class C<T> {
+ List<T> _x;
+ List<T> get x => _x;
+}
+List<int> f(C<int> c) => c.x;
+''');
+ assertEdge(decoratedTypeAnnotation('List<T> get').node,
+ decoratedTypeAnnotation('List<int> f').node,
+ hard: false);
+ assertEdge(
+ substitutionNode(decoratedTypeAnnotation('int> c').node,
+ decoratedTypeAnnotation('T> get').node),
+ decoratedTypeAnnotation('int> f').node,
+ hard: false);
+ }
+
test_prefixedIdentifier_target_check() async {
await analyze('''
class C {
@@ -3262,6 +4019,32 @@
assertEdge(never, returnType, hard: false);
}
+ test_propertyAccess_dynamic() async {
+ await analyze('''
+class C {
+ int get g => 0;
+}
+int f(dynamic d) {
+ return d.g;
+}
+''');
+ // The call `d.g` is dynamic, so we can't tell what method it resolves
+ // to. There's no reason to assume it resolves to `C.g`.
+ assertNoEdge(decoratedTypeAnnotation('int get g').node,
+ decoratedTypeAnnotation('int f').node);
+ // We do, however, assume that it might return anything, including `null`.
+ assertEdge(always, decoratedTypeAnnotation('int f').node, hard: false);
+ }
+
+ test_propertyAccess_object_property() async {
+ await analyze('''
+int f(int i) => i.hashCode;
+''');
+ // No edge from i to `never` because it is safe to call `hashCode` on
+ // `null`.
+ assertNoEdge(decoratedTypeAnnotation('int i').node, never);
+ }
+
test_propertyAccess_return_type() async {
await analyze('''
class C {
@@ -3288,6 +4071,18 @@
assertEdge(lubNode, decoratedTypeAnnotation('bool f').node, hard: false);
}
+ test_propertyAccess_static_on_generic_class() async {
+ await analyze('''
+class C<T> {
+ static int x = 1;
+}
+int f() => C.x;
+''');
+ assertEdge(decoratedTypeAnnotation('int x').node,
+ decoratedTypeAnnotation('int f').node,
+ hard: false);
+ }
+
test_propertyAccess_target_check() async {
await analyze('''
class C {
@@ -3331,13 +4126,8 @@
var nullable_t1 = decoratedTypeAnnotation('T/*1*/').node;
var nullable_t2 = decoratedTypeAnnotation('T/*2*/').node;
var nullable_u3 = decoratedTypeAnnotation('U/*3*/').node;
- var nullable_t2_or_nullable_u3 = graph
- .getDownstreamEdges(nullable_t1)
- .single
- .destinationNode as NullabilityNodeForSubstitution;
- expect(nullable_t2_or_nullable_u3.innerNode, same(nullable_t2));
- expect(nullable_t2_or_nullable_u3.outerNode, same(nullable_u3));
- assertEdge(nullable_t1, nullable_t2_or_nullable_u3, hard: true);
+ assertEdge(nullable_t1, substitutionNode(nullable_t2, nullable_u3),
+ hard: true);
}
test_redirecting_constructor_factory_to_generic() async {
@@ -3352,13 +4142,8 @@
var nullable_i1 = decoratedTypeAnnotation('int/*1*/').node;
var nullable_i2 = decoratedTypeAnnotation('int/*2*/').node;
var nullable_t3 = decoratedTypeAnnotation('T/*3*/').node;
- var nullable_i2_or_nullable_t3 = graph
- .getDownstreamEdges(nullable_i1)
- .single
- .destinationNode as NullabilityNodeForSubstitution;
- expect(nullable_i2_or_nullable_t3.innerNode, same(nullable_i2));
- expect(nullable_i2_or_nullable_t3.outerNode, same(nullable_t3));
- assertEdge(nullable_i1, nullable_i2_or_nullable_t3, hard: true);
+ assertEdge(nullable_i1, substitutionNode(nullable_i2, nullable_t3),
+ hard: true);
}
test_redirecting_constructor_ordinary() async {
@@ -3457,60 +4242,74 @@
checkExpression('null'), assertEdge(always, tNode, hard: false));
}
- @failingTest
test_setOrMapLiteral_map_noTypeArgument_noNullableKeysAndValues() async {
- // Failing because we're not yet handling collection literals without a
- // type argument.
await analyze('''
Map<String, int> f() {
return {'a' : 1, 'b' : 2};
}
''');
- assertNoUpstreamNullability(decoratedTypeAnnotation('Map').node);
- // TODO(brianwilkerson) Add an assertion that there is an edge from the set
- // literal's fake type argument to the return type's type argument.
+ var keyNode = decoratedTypeAnnotation('String').node;
+ var valueNode = decoratedTypeAnnotation('int').node;
+ var mapNode = decoratedTypeAnnotation('Map').node;
+
+ assertNoUpstreamNullability(mapNode);
+ assertNoUpstreamNullability(
+ assertEdge(anyNode, keyNode, hard: false).primarySource);
+ assertNoUpstreamNullability(
+ assertEdge(anyNode, valueNode, hard: false).primarySource);
}
- @failingTest
test_setOrMapLiteral_map_noTypeArgument_nullableKey() async {
- // Failing because we're not yet handling collection literals without a
- // type argument.
await analyze('''
Map<String, int> f() {
return {'a' : 1, null : 2, 'c' : 3};
}
''');
- assertNoUpstreamNullability(decoratedTypeAnnotation('Map').node);
- assertEdge(always, decoratedTypeAnnotation('String').node, hard: false);
- assertNoUpstreamNullability(decoratedTypeAnnotation('int').node);
+ var keyNode = decoratedTypeAnnotation('String').node;
+ var valueNode = decoratedTypeAnnotation('int').node;
+ var mapNode = decoratedTypeAnnotation('Map').node;
+
+ assertNoUpstreamNullability(mapNode);
+ assertEdge(always, assertEdge(anyNode, keyNode, hard: false).primarySource,
+ hard: false);
+ assertNoUpstreamNullability(
+ assertEdge(anyNode, valueNode, hard: false).primarySource);
}
- @failingTest
test_setOrMapLiteral_map_noTypeArgument_nullableKeyAndValue() async {
- // Failing because we're not yet handling collection literals without a
- // type argument.
await analyze('''
Map<String, int> f() {
return {'a' : 1, null : null, 'c' : 3};
}
''');
- assertNoUpstreamNullability(decoratedTypeAnnotation('Map').node);
- assertEdge(always, decoratedTypeAnnotation('String').node, hard: false);
- assertEdge(always, decoratedTypeAnnotation('int').node, hard: false);
+ var keyNode = decoratedTypeAnnotation('String').node;
+ var valueNode = decoratedTypeAnnotation('int').node;
+ var mapNode = decoratedTypeAnnotation('Map').node;
+
+ assertNoUpstreamNullability(mapNode);
+ assertEdge(always, assertEdge(anyNode, keyNode, hard: false).primarySource,
+ hard: false);
+ assertEdge(
+ always, assertEdge(anyNode, valueNode, hard: false).primarySource,
+ hard: false);
}
- @failingTest
test_setOrMapLiteral_map_noTypeArgument_nullableValue() async {
- // Failing because we're not yet handling collection literals without a
- // type argument.
await analyze('''
Map<String, int> f() {
return {'a' : 1, 'b' : null, 'c' : 3};
}
''');
- assertNoUpstreamNullability(decoratedTypeAnnotation('Map').node);
- assertNoUpstreamNullability(decoratedTypeAnnotation('String').node);
- assertEdge(always, decoratedTypeAnnotation('int').node, hard: false);
+ var keyNode = decoratedTypeAnnotation('String').node;
+ var valueNode = decoratedTypeAnnotation('int').node;
+ var mapNode = decoratedTypeAnnotation('Map').node;
+
+ assertNoUpstreamNullability(mapNode);
+ assertNoUpstreamNullability(
+ assertEdge(anyNode, keyNode, hard: false).primarySource);
+ assertEdge(
+ always, assertEdge(anyNode, valueNode, hard: false).primarySource,
+ hard: false);
}
test_setOrMapLiteral_map_typeArguments_noNullableKeysAndValues() async {
@@ -3567,31 +4366,33 @@
assertEdge(always, decoratedTypeAnnotation('int>{').node, hard: false);
}
- @failingTest
test_setOrMapLiteral_set_noTypeArgument_noNullableElements() async {
- // Failing because we're not yet handling collection literals without a
- // type argument.
await analyze('''
Set<String> f() {
return {'a', 'b'};
}
''');
- assertNoUpstreamNullability(decoratedTypeAnnotation('Set').node);
- // TODO(brianwilkerson) Add an assertion that there is an edge from the set
- // literal's fake type argument to the return type's type argument.
+ var valueNode = decoratedTypeAnnotation('String').node;
+ var setNode = decoratedTypeAnnotation('Set').node;
+
+ assertNoUpstreamNullability(setNode);
+ assertNoUpstreamNullability(
+ assertEdge(anyNode, valueNode, hard: false).primarySource);
}
- @failingTest
test_setOrMapLiteral_set_noTypeArgument_nullableElement() async {
- // Failing because we're not yet handling collection literals without a
- // type argument.
await analyze('''
Set<String> f() {
return {'a', null, 'c'};
}
''');
- assertNoUpstreamNullability(decoratedTypeAnnotation('Set').node);
- assertEdge(always, decoratedTypeAnnotation('String').node, hard: false);
+ var valueNode = decoratedTypeAnnotation('String').node;
+ var setNode = decoratedTypeAnnotation('Set').node;
+
+ assertNoUpstreamNullability(setNode);
+ assertEdge(
+ always, assertEdge(anyNode, valueNode, hard: false).primarySource,
+ hard: false);
}
test_setOrMapLiteral_set_typeArgument_noNullableElements() async {
@@ -3691,6 +4492,103 @@
assertEdge(always, decoratedTypeAnnotation('int').node, hard: false);
}
+ test_spread_element_list() async {
+ await analyze('''
+void f(List<int> ints) {
+ <int>[...ints];
+}
+''');
+
+ assertEdge(decoratedTypeAnnotation('List<int>').node, never, hard: true);
+ assertEdge(
+ substitutionNode(decoratedTypeAnnotation('int> ints').node, anyNode),
+ decoratedTypeAnnotation('int>[').node,
+ hard: false);
+ }
+
+ test_spread_element_list_dynamic() async {
+ await analyze('''
+void f(dynamic ints) {
+ <int>[...ints];
+}
+''');
+
+ // Mostly just check this doesn't crash.
+ assertEdge(decoratedTypeAnnotation('dynamic').node, never, hard: true);
+ }
+
+ test_spread_element_list_nullable() async {
+ await analyze('''
+void f(List<int> ints) {
+ <int>[...?ints];
+}
+''');
+
+ assertNoEdge(decoratedTypeAnnotation('List<int>').node, never);
+ assertEdge(
+ substitutionNode(decoratedTypeAnnotation('int> ints').node, anyNode),
+ decoratedTypeAnnotation('int>[').node,
+ hard: false);
+ }
+
+ test_spread_element_map() async {
+ await analyze('''
+void f(Map<String, int> map) {
+ <String, int>{...map};
+}
+''');
+
+ assertEdge(decoratedTypeAnnotation('Map<String, int>').node, never,
+ hard: true);
+ assertEdge(decoratedTypeAnnotation('String, int> map').node,
+ decoratedTypeAnnotation('String, int>{').node,
+ hard: false);
+ assertEdge(decoratedTypeAnnotation('int> map').node,
+ decoratedTypeAnnotation('int>{').node,
+ hard: false);
+ }
+
+ test_spread_element_set() async {
+ await analyze('''
+void f(Set<int> ints) {
+ <int>{...ints};
+}
+''');
+
+ assertEdge(decoratedTypeAnnotation('Set<int>').node, never, hard: true);
+ assertEdge(
+ substitutionNode(decoratedTypeAnnotation('int> ints').node, anyNode),
+ decoratedTypeAnnotation('int>{').node,
+ hard: false);
+ }
+
+ test_spread_element_subtype() async {
+ await analyze('''
+abstract class C<T, R> implements Iterable<R> {}
+void f(C<dynamic, int> ints) {
+ <int>[...ints];
+}
+''');
+
+ assertEdge(decoratedTypeAnnotation('C<dynamic, int>').node, never,
+ hard: true);
+ assertEdge(
+ substitutionNode(decoratedTypeAnnotation('int> ints').node,
+ decoratedTypeAnnotation('R> {}').node),
+ decoratedTypeAnnotation('int>[').node,
+ hard: false);
+ }
+
+ test_static_method_call_prefixed() async {
+ await analyze('''
+import 'dart:async' as a;
+void f(void Function() callback) {
+ a.Timer.run(callback);
+}
+''');
+ // No assertions. Just making sure this doesn't crash.
+ }
+
test_stringLiteral() async {
// TODO(paulberry): also test string interpolations
await analyze('''
@@ -3837,7 +4735,15 @@
hard: true);
}
- test_typeName() async {
+ test_typeName_class() async {
+ await analyze('''
+class C {}
+Type f() => C;
+''');
+ assertNoUpstreamNullability(decoratedTypeAnnotation('Type').node);
+ }
+
+ test_typeName_from_sdk() async {
await analyze('''
Type f() {
return int;
@@ -3846,6 +4752,38 @@
assertNoUpstreamNullability(decoratedTypeAnnotation('Type').node);
}
+ test_typeName_from_sdk_prefixed() async {
+ await analyze('''
+import 'dart:async' as a;
+Type f() => a.Future;
+''');
+ assertEdge(never, decoratedTypeAnnotation('Type').node, hard: false);
+ }
+
+ test_typeName_functionTypeAlias() async {
+ await analyze('''
+typedef void F();
+Type f() => F;
+''');
+ assertNoUpstreamNullability(decoratedTypeAnnotation('Type').node);
+ }
+
+ test_typeName_genericTypeAlias() async {
+ await analyze('''
+typedef F = void Function();
+Type f() => F;
+''');
+ assertNoUpstreamNullability(decoratedTypeAnnotation('Type').node);
+ }
+
+ test_typeName_mixin() async {
+ await analyze('''
+mixin M {}
+Type f() => M;
+''');
+ assertNoUpstreamNullability(decoratedTypeAnnotation('Type').node);
+ }
+
test_typeName_union_with_bound() async {
await analyze('''
class C<T extends Object> {}
@@ -3905,6 +4843,11 @@
return assignmentCheckerTest._myListOfListSupertype
.substitute({class_.typeParameters[0]: type.typeArguments[0]});
}
+ if (class_.name == 'Future' && superclass.name == 'FutureOr') {
+ return DecoratedType(
+ superclass.type.instantiate([type.typeArguments[0].type]), type.node,
+ typeArguments: [type.typeArguments[0]]);
+ }
throw UnimplementedError(
'TODO(paulberry): asInstanceOf($type, $superclass)');
}
diff --git a/pkg/nnbd_migration/test/migration_visitor_test_base.dart b/pkg/nnbd_migration/test/migration_visitor_test_base.dart
index bf9d88c..f335eb45 100644
--- a/pkg/nnbd_migration/test/migration_visitor_test_base.dart
+++ b/pkg/nnbd_migration/test/migration_visitor_test_base.dart
@@ -21,6 +21,19 @@
import 'abstract_single_unit.dart';
+/// A [NodeMatcher] that matches any node, and records what node it matched to.
+class AnyNodeMatcher implements NodeMatcher {
+ final List<NullabilityNode> _matchingNodes = [];
+
+ NullabilityNode get matchingNode => _matchingNodes.single;
+
+ @override
+ bool matches(NullabilityNode node) {
+ _matchingNodes.add(node);
+ return true;
+ }
+}
+
/// Mixin allowing unit tests to create decorated types easily.
mixin DecoratedTypeTester implements DecoratedTypeTesterBase {
int _offset = 0;
@@ -66,6 +79,19 @@
namedParameters: named);
}
+ DecoratedType future(DecoratedType parameter, {NullabilityNode node}) {
+ return DecoratedType(typeProvider.futureType.instantiate([parameter.type]),
+ node ?? newNode(),
+ typeArguments: [parameter]);
+ }
+
+ DecoratedType futureOr(DecoratedType parameter, {NullabilityNode node}) {
+ return DecoratedType(
+ typeProvider.futureOrType.instantiate([parameter.type]),
+ node ?? newNode(),
+ typeArguments: [parameter]);
+ }
+
DecoratedType int_({NullabilityNode node}) =>
DecoratedType(typeProvider.intType, node ?? newNode());
@@ -99,12 +125,32 @@
TypeProvider get typeProvider;
}
+class EdgeBuilderTestBase extends MigrationVisitorTestBase {
+ /// Analyzes the given source code, producing constraint variables and
+ /// constraints for it.
+ @override
+ Future<CompilationUnit> analyze(String code) async {
+ var unit = await super.analyze(code);
+ unit.accept(EdgeBuilder(
+ typeProvider, typeSystem, variables, graph, testSource, null));
+ return unit;
+ }
+}
+
/// Mixin allowing unit tests to check for the presence of graph edges.
mixin EdgeTester {
+ /// Returns a [NodeMatcher] that matches any node whatsoever.
+ AnyNodeMatcher get anyNode => AnyNodeMatcher();
+
NullabilityGraphForTesting get graph;
- NullabilityEdge assertEdge(
- NullabilityNode source, NullabilityNode destination,
+ /// Asserts that an edge exists with a node matching [source] and a node
+ /// matching [destination], and with the given [hard]ness and [guards].
+ ///
+ /// [source] and [destination] are converted to [NodeMatcher] objects if they
+ /// aren't already. In practice this means that the caller can pass in either
+ // /// a [NodeMatcher] or a [NullabilityNode].
+ NullabilityEdge assertEdge(Object source, Object destination,
{@required bool hard, List<NullabilityNode> guards = const []}) {
var edges = getEdges(source, destination);
if (edges.length == 0) {
@@ -119,14 +165,25 @@
}
}
- void assertNoEdge(NullabilityNode source, NullabilityNode destination) {
+ /// Asserts that no edge exists with a node matching [source] and a node
+ /// matching [destination].
+ ///
+ /// [source] and [destination] are converted to [NodeMatcher] objects if they
+ /// aren't already. In practice this means that the caller can pass in either
+ /// a [NodeMatcher] or a [NullabilityNode].
+ void assertNoEdge(Object source, Object destination) {
var edges = getEdges(source, destination);
if (edges.isNotEmpty) {
fail('Expected no edge $source -> $destination, found ${edges.length}');
}
}
- void assertUnion(NullabilityNode x, NullabilityNode y) {
+ /// Asserts that a union-type edge exists between nodes [x] and [y].
+ ///
+ /// [x] and [y] are converted to [NodeMatcher] objects if they aren't already.
+ /// In practice this means that the caller can pass in either a [NodeMatcher]
+ /// or a [NullabilityNode].
+ void assertUnion(Object x, Object y) {
var edges = getEdges(x, y);
for (var edge in edges) {
if (edge.isUnion) {
@@ -137,12 +194,31 @@
fail('Expected union between $x and $y, not found');
}
- List<NullabilityEdge> getEdges(
- NullabilityNode source, NullabilityNode destination) =>
- graph
- .getUpstreamEdges(destination)
- .where((e) => e.primarySource == source)
- .toList();
+ /// Gets a list of all edges whose source matches [source] and whose
+ /// destination matches [destination].
+ ///
+ /// [source] and [destination] are converted to [NodeMatcher] objects if they
+ /// aren't already. In practice this means that the caller can pass in either
+ /// a [NodeMatcher] or a [NullabilityNode].
+ List<NullabilityEdge> getEdges(Object source, Object destination) {
+ var sourceMatcher = NodeMatcher(source);
+ var destinationMatcher = NodeMatcher(destination);
+ return graph
+ .getAllEdges()
+ .where((e) =>
+ sourceMatcher.matches(e.primarySource) &&
+ destinationMatcher.matches(e.destinationNode))
+ .toList();
+ }
+
+ /// Creates a [NodeMatcher] matching a substitution node whose inner and outer
+ /// nodes match [inner] and [outer].
+ ///
+ /// [inner] and [outer] are converted to [NodeMatcher] objects if they aren't
+ /// already. In practice this means that the caller can pass in either a
+ /// [NodeMatcher] or a [NullabilityNode].
+ NodeMatcher substitutionNode(Object inner, Object outer) =>
+ _SubstitutionNodeMatcher(NodeMatcher(inner), NodeMatcher(outer));
}
/// Mock representation of constraint variables.
@@ -155,7 +231,8 @@
final _possiblyOptional = <DefaultFormalParameter, NullabilityNode>{};
- InstrumentedVariables(NullabilityGraph graph) : super(graph);
+ InstrumentedVariables(NullabilityGraph graph, TypeProvider typeProvider)
+ : super(graph, typeProvider);
/// Gets the [ExpressionChecks] associated with the given [expression].
ExpressionChecks checkExpression(Expression expression) =>
@@ -209,27 +286,14 @@
}
}
-class EdgeBuilderTestBase extends MigrationVisitorTestBase {
- /// Analyzes the given source code, producing constraint variables and
- /// constraints for it.
- @override
- Future<CompilationUnit> analyze(String code) async {
- var unit = await super.analyze(code);
- unit.accept(EdgeBuilder(
- typeProvider, typeSystem, variables, graph, testSource, null));
- return unit;
- }
-}
-
class MigrationVisitorTestBase extends AbstractSingleUnitTest with EdgeTester {
- final InstrumentedVariables variables;
+ InstrumentedVariables variables;
final NullabilityGraphForTesting graph;
MigrationVisitorTestBase() : this._(NullabilityGraphForTesting());
- MigrationVisitorTestBase._(this.graph)
- : variables = InstrumentedVariables(graph);
+ MigrationVisitorTestBase._(this.graph);
NullabilityNode get always => graph.always;
@@ -241,6 +305,7 @@
Future<CompilationUnit> analyze(String code) async {
await resolveTestUnit(code);
+ variables = InstrumentedVariables(graph, typeProvider);
testUnit
.accept(NodeBuilder(variables, testSource, null, graph, typeProvider));
return testUnit;
@@ -284,3 +349,42 @@
return variables.conditionalDiscard(findNode.statement(text));
}
}
+
+/// Abstract base class representing a thing that can be matched against
+/// nullability nodes.
+abstract class NodeMatcher {
+ factory NodeMatcher(Object expectation) {
+ if (expectation is NodeMatcher) return expectation;
+ if (expectation is NullabilityNode) return _ExactNodeMatcher(expectation);
+ fail(
+ 'Unclear how to match node expectation of type ${expectation.runtimeType}');
+ }
+
+ bool matches(NullabilityNode node);
+}
+
+/// A [NodeMatcher] that matches exactly one node.
+class _ExactNodeMatcher implements NodeMatcher {
+ final NullabilityNode _expectation;
+
+ _ExactNodeMatcher(this._expectation);
+
+ @override
+ bool matches(NullabilityNode node) => node == _expectation;
+}
+
+/// A [NodeMatcher] that matches a substitution node with the given inner and
+/// outer nodes.
+class _SubstitutionNodeMatcher implements NodeMatcher {
+ final NodeMatcher inner;
+ final NodeMatcher outer;
+
+ _SubstitutionNodeMatcher(this.inner, this.outer);
+
+ @override
+ bool matches(NullabilityNode node) {
+ return node is NullabilityNodeForSubstitution &&
+ inner.matches(node.innerNode) &&
+ outer.matches(node.outerNode);
+ }
+}
diff --git a/pkg/nnbd_migration/test/node_builder_test.dart b/pkg/nnbd_migration/test/node_builder_test.dart
index 70c0fdbb..a85aed0 100644
--- a/pkg/nnbd_migration/test/node_builder_test.dart
+++ b/pkg/nnbd_migration/test/node_builder_test.dart
@@ -28,6 +28,66 @@
variables.decoratedTypeParameterBound(
findNode.typeParameter(search).declaredElement);
+ test_catch_clause_with_stacktrace_with_on() async {
+ await analyze('''
+void f() {
+ try {} on String catch (ex, st) {}
+}
+''');
+ var exceptionType =
+ variables.decoratedElementType(findNode.simple('ex').staticElement);
+ expect(exceptionType.node, TypeMatcher<NullabilityNodeMutable>());
+ var stackTraceType =
+ variables.decoratedElementType(findNode.simple('st').staticElement);
+ expect(stackTraceType.node, never);
+ }
+
+ test_catch_clause_with_stacktrace_without_on() async {
+ await analyze('''
+void f() {
+ try {} catch (ex, st) {}
+}
+''');
+ var exceptionType =
+ variables.decoratedElementType(findNode.simple('ex').staticElement);
+ expect(exceptionType.node, always);
+ var stackTraceType =
+ variables.decoratedElementType(findNode.simple('st').staticElement);
+ expect(stackTraceType.node, never);
+ }
+
+ test_catch_clause_without_catch() async {
+ await analyze('''
+void f() {
+ try {} on String {}
+}
+''');
+ // No assertions, since no variables are declared; we just want to make sure
+ // we don't crash.
+ }
+
+ test_catch_clause_without_stacktrace_with_on() async {
+ await analyze('''
+void f() {
+ try {} on String catch (ex) {}
+}
+''');
+ var exceptionType =
+ variables.decoratedElementType(findNode.simple('ex').staticElement);
+ expect(exceptionType.node, TypeMatcher<NullabilityNodeMutable>());
+ }
+
+ test_catch_clause_without_stacktrace_without_on() async {
+ await analyze('''
+void f() {
+ try {} catch (ex) {}
+}
+''');
+ var exceptionType =
+ variables.decoratedElementType(findNode.simple('ex').staticElement);
+ expect(exceptionType.node, always);
+ }
+
test_class_alias_synthetic_constructors_no_parameters() async {
await analyze('''
class C {
@@ -338,6 +398,19 @@
same(decoratedTypeAnnotation('V>;').node));
}
+ test_directSupertypes_dartCoreClass() async {
+ await analyze('''
+abstract class D<V> extends Iterable<V> {}
+''');
+ var types = decoratedDirectSupertypes('D');
+ var super_ = types.values.single;
+ expect(super_.type.toString(), 'Iterable<V>');
+ expect(super_.node, same(never));
+ expect(super_.typeArguments, hasLength(1));
+ expect(super_.typeArguments[0].node,
+ same(decoratedTypeAnnotation('V> {').node));
+ }
+
test_directSupertypes_mixin_extends_default() async {
await analyze('''
mixin C<T, U> {}
@@ -1459,6 +1532,80 @@
expect(bound.type, same(typeProvider.objectType));
}
+ test_typedef_reference_generic_instantiated() async {
+ await analyze('''
+typedef F<T> = T Function();
+F<int> f;
+''');
+ // The instantiation of F should produce fresh nullability nodes, distinct
+ // from the ones in the typedef (they will be unified by the edge builder).
+ // This is necessary because there is no guarantee of whether the typedef or
+ // its usage will be visited first.
+ var typedefDecoratedType =
+ variables.decoratedElementType(findElement.genericTypeAlias('F'));
+ var decoratedType = decoratedTypeAnnotation('F<int>');
+ expect(decoratedType.node, TypeMatcher<NullabilityNodeMutable>());
+ expect(decoratedType.node, isNot(same(typedefDecoratedType.node)));
+ expect(decoratedType.returnType.type.toString(), 'int');
+ expect(
+ decoratedType.returnType.node, TypeMatcher<NullabilityNodeMutable>());
+ expect(decoratedType.returnType.node,
+ isNot(same(typedefDecoratedType.returnType.node)));
+ expect(decoratedType.typeFormalBounds, isEmpty);
+ }
+
+ test_typedef_reference_generic_uninstantiated() async {
+ await analyze('''
+typedef F = T Function<T extends num>();
+F f;
+''');
+ // The instantiation of F should produce fresh nullability nodes, distinct
+ // from the ones in the typedef (they will be unified by the edge builder).
+ // This is necessary because there is no guarantee of whether the typedef or
+ // its usage will be visited first.
+ var typedefDecoratedType =
+ variables.decoratedElementType(findElement.genericTypeAlias('F'));
+ var decoratedType = decoratedTypeAnnotation('F f');
+ expect(decoratedType.node, TypeMatcher<NullabilityNodeMutable>());
+ expect(decoratedType.node, isNot(same(typedefDecoratedType.node)));
+ expect(decoratedType.returnType.type.toString(), 'T');
+ expect(
+ decoratedType.returnType.node, TypeMatcher<NullabilityNodeMutable>());
+ expect(decoratedType.returnType.node,
+ isNot(same(typedefDecoratedType.returnType.node)));
+ expect(decoratedType.typeFormalBounds, hasLength(1));
+ expect(decoratedType.typeFormalBounds[0].type.toString(), 'num');
+ expect(decoratedType.typeFormalBounds[0].node,
+ isNot(same(typedefDecoratedType.typeFormalBounds[0].node)));
+ }
+
+ test_typedef_reference_simple() async {
+ await analyze('''
+typedef int F(String s);
+F f;
+''');
+ // The instantiation of F should produce fresh nullability nodes, distinct
+ // from the ones in the typedef (they will be unified by the edge builder).
+ // This is necessary because there is no guarantee of whether the typedef or
+ // its usage will be visited first.
+ var typedefDecoratedType =
+ variables.decoratedElementType(findElement.genericTypeAlias('F'));
+ var decoratedType = decoratedTypeAnnotation('F f');
+ expect(decoratedType.node, TypeMatcher<NullabilityNodeMutable>());
+ expect(decoratedType.node, isNot(same(typedefDecoratedType.node)));
+ expect(decoratedType.returnType.type.toString(), 'int');
+ expect(
+ decoratedType.returnType.node, TypeMatcher<NullabilityNodeMutable>());
+ expect(decoratedType.returnType.node,
+ isNot(same(typedefDecoratedType.returnType.node)));
+ expect(decoratedType.positionalParameters[0].type.toString(), 'String');
+ expect(decoratedType.positionalParameters[0].node,
+ TypeMatcher<NullabilityNodeMutable>());
+ expect(decoratedType.positionalParameters[0].node,
+ isNot(same(typedefDecoratedType.positionalParameters[0].node)));
+ expect(decoratedType.typeFormalBounds, isEmpty);
+ }
+
test_variableDeclaration_type_simple() async {
await analyze('''
main() {
diff --git a/pkg/nnbd_migration/tool/trial_migration.dart b/pkg/nnbd_migration/tool/trial_migration.dart
index 3bb8f85..f207d07 100644
--- a/pkg/nnbd_migration/tool/trial_migration.dart
+++ b/pkg/nnbd_migration/tool/trial_migration.dart
@@ -45,6 +45,7 @@
.where((s) => s.endsWith('.dart'))
.toList();
print(' ${files.length} files found');
+ var previousExceptionCount = listener.numExceptions;
var migration = NullabilityMigration(listener, permissive: true);
for (var file in files) {
var resolvedUnit = await context.currentSession.getResolvedUnit(file);
@@ -55,6 +56,8 @@
migration.processInput(resolvedUnit);
}
migration.finish();
+ var exceptionCount = listener.numExceptions - previousExceptionCount;
+ print(' $exceptionCount exceptions in this package');
}
print('${listener.numTypesMadeNullable} types made nullable');
print('${listener.numNullChecksAdded} null checks added');
@@ -75,6 +78,11 @@
/// if its category contains the string.
const String categoryOfInterest = null;
+/// Set this to `true` to cause just the exception nodes to be printed when
+/// `categoryOfInterest` is non-null. Set this to `false` to cause the full
+/// stack trace to be printed.
+const bool printExceptionNodeOnly = false;
+
class _Listener implements NullabilityMigrationListener {
final groupedExceptions = <String, List<String>>{};
@@ -128,7 +136,11 @@
$stackTrace
''';
if (categoryOfInterest != null && category.contains(categoryOfInterest)) {
- print(detail);
+ if (printExceptionNodeOnly) {
+ print('$node');
+ } else {
+ print(detail);
+ }
}
(groupedExceptions[category] ??= []).add(detail);
++numExceptions;
diff --git a/pkg/pkg.status b/pkg/pkg.status
index cee0e7a..47913ba 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -39,7 +39,10 @@
front_end/test/fasta/rasta/*: SkipByDesign # Anything in rasta is input to fasta unit tests and shouldn't be run as tests.
front_end/test/fasta/sdk_test: SkipByDesign # sdk_test would take too long to complete, and should be run in a different way.
front_end/test/fasta/shaker_test: Skip # Issue http://dartbug.com/32531
-front_end/test/fasta/strong_test: Pass, ExtraSlow
+front_end/test/fasta/strong1_test: Pass, ExtraSlow
+front_end/test/fasta/strong2_test: Pass, ExtraSlow
+front_end/test/fasta/strong3_test: Pass, ExtraSlow
+front_end/test/fasta/strong4_test: Pass, ExtraSlow
front_end/test/fasta/text_serialization_test: Pass, ExtraSlow
front_end/test/fasta/types/dart2js_benchmark_test: Pass, Slow
front_end/test/fasta/types/large_app_benchmark_test: Pass, ExtraSlow
@@ -47,7 +50,7 @@
front_end/test/whole_program_test: Slow, Pass
front_end/testcases/*: Skip # These are not tests but input for tests.
front_end/tool/incremental_perf_test: Slow, Pass
-kernel/test/closures_test: Slow, Pass
+kernel/test/closures_test: Slow
kernel/testcases/*: Skip # These are not tests but input for tests.
vm/test/frontend_server_test: Slow
vm/test/transformations/type_flow/transformer_test: Slow
@@ -68,12 +71,6 @@
analyzer_plugin/test/*: SkipByDesign # Only meant to run on vm
analyzer_plugin/tool/*: SkipByDesign # Only meant to run on vm
build_integration/test/*: SkipByDesign # Only meant to run on vm, most use dart:mirrors and dart:io
-collection/test/equality_test/01: Fail # Issue 1533
-collection/test/equality_test/02: Fail # Issue 1533
-collection/test/equality_test/03: Fail # Issue 1533
-collection/test/equality_test/04: Fail # Issue 1533
-collection/test/equality_test/05: Fail # Issue 1533
-collection/test/equality_test/none: Pass, Fail # Issue 14348
compiler/tool/*: SkipByDesign # Only meant to run on vm
dartfix/test/*: SkipByDesign # Only meant to run on vm
front_end/test/*: SkipByDesign # Only meant to run on vm, most use dart:mirrors and dart:io
@@ -86,23 +83,15 @@
telemetry/test/*: SkipByDesign # Only meant to run on vm
test_runner/test/*: SkipByDesign # Only meant to run on vm
testing/*: SkipByDesign # Only meant to run on vm
-typed_data/test/typed_buffers_test/01: Fail # Not supporting Int64List, Uint64List.
[ $runtime == dart_precompiled ]
*: SkipByDesign # The pkg test framework imports dart:mirrors.
-[ $runtime == jsshell ]
-async/test/stream_zip_test: RuntimeError, OK # Issue 26103. Timers are not supported.
-front_end/test/*: RuntimeError, OK, Pass # Issue 26103. Timers are not supported.
-kernel/test/*: RuntimeError, OK # Issue 26103. Timers are not supported.
-
[ $runtime == vm ]
analysis_server/test/benchmarks_test: Slow
analysis_server/test/domain_completion_test: Slow
analysis_server/test/edit/refactoring_test: Slow
analysis_server/test/integration/*: Slow
-analysis_server/test/integration/analysis/package_root_test: Pass, RuntimeError # Issue 33382
-analysis_server/test/integration/search/find_top_level_declarations_test: Pass, RuntimeError # 31571
analysis_server/test/services/completion/dart/imported_reference_contributor_test: Slow
analysis_server/test/services/completion/dart/keyword_contributor_test: Slow
analysis_server/test/services/completion/dart/local_constructor_contributor_test: Slow
@@ -113,7 +102,6 @@
analysis_server/test/services/refactoring/inline_method_test: Slow
analysis_server/test/socket_server_test: Skip # Pass, Slow
analysis_server/test/src/plugin/plugin_manager_test: Slow
-analyzer/test/file_system/physical_resource_provider_watch_test: Pass, Fail # Issue 25472
analyzer/test/generated/hint_code_driver_test: Slow
analyzer/test/generated/non_error_resolver_kernel_test: Slow
analyzer/test/generated/strong_mode_driver_test: Slow
@@ -124,16 +112,13 @@
analyzer/test/src/task/strong/inferred_type_test: Slow
analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test: Slow
analyzer_plugin/test/src/utilities/completion/optype_test: Slow
-dartfix/test/src/driver_test: RuntimeError # dartbug.com/35478
mutation_observer: Skip # Skip tests on the VM if the package depends on dart:html
[ $runtime != vm ]
dev_compiler/test/options/*: SkipByDesign
front_end/test/hot_reload_e2e_test: Skip
vm/test/*: SkipByDesign # Only meant to run on vm
-
-[ $system == linux ]
-analysis_server/test/integration/analysis/package_root_test: Pass, RuntimeError # Issue 33382
+vm_service/test/*: SkipByDesign # Uses dart:io
[ $system == windows ]
analysis_server/test/integration/analysis/get_errors_nonStandard_sdk_test: Skip
@@ -154,9 +139,7 @@
analyzer_cli/*: SkipByDesign # Uses dart:io.
compiler/tool/*: SkipByDesign # Only meant to run on vm
front_end/tool/*: SkipByDesign # Only meant to run on vm
-http_server/test/*: Fail, OK # Uses dart:io.
kernel/test/*: SkipByDesign # Uses dart:io and bigints.
-observe/test/transformer_test: Fail, OK # Uses dart:io.
observe/test/unique_message_test: SkipByDesign # Uses dart:io.
status_file/*: SkipByDesign # Only meant to run on the standalone VM.
testing/test/analyze_test: SkipByDesign
@@ -164,10 +147,6 @@
[ $jscl ]
kernel/test/*: SkipByDesign # Uses dart:io and bigints.
-[ !$preview_dart_2 ]
-dev_compiler/*: SkipByDesign # uses Dart 2.
-smith/test/*: Skip # Uses optional new.
-
[ $arch == x64 && $runtime == vm && $system == windows && $checked ]
analyzer/test/src/task/strong/inferred_type_test: Slow
@@ -185,7 +164,7 @@
modular_test/test/src/find_sdk_root2_test: SkipByDesign
[ $compiler == dart2js && $runtime == chrome && $system == macos ]
-third_party/di_tests/di_test: Pass, Slow # Issue 22896
+third_party/di_tests/di_test: Slow # Issue 22896
[ $compiler == dart2js && $runtime == d8 ]
front_end/test/src/base/uri_resolver_test: SkipByDesign # Relies on access to file system
@@ -209,9 +188,7 @@
[ $runtime == vm && $system == windows ]
analysis_server/test/analysis/get_errors_test: Skip # runtime error, Issue 22180
-analysis_server/test/benchmarks_test: RuntimeError # Issue 32355
-analysis_server/test/src/plugin/plugin_manager_test: Pass, Slow, RuntimeError # Issue 34231
-analyzer/test/generated/non_error_resolver_kernel_test: RuntimeError # Issue 30785
+analysis_server/test/src/plugin/plugin_manager_test: Slow # Issue 34231
analyzer/test/src/task/strong/checker_test: Slow
analyzer/tool/task_dependency_graph/check_test: Slow
diff --git a/pkg/smith/lib/configuration.dart b/pkg/smith/lib/configuration.dart
index eb79e61..fc7883a 100644
--- a/pkg/smith/lib/configuration.dart
+++ b/pkg/smith/lib/configuration.dart
@@ -3,14 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
import 'dart:io';
-// TODO(rnystrom): Differences from test.dart's version:
-// - Remove special handling for "ff" as firefox.
-// - "windows" -> "win".
-// - "macos" -> "mac".
-// - toString() on enum classes is just name.
-// - builderTag and babel default to empty string, not null.
-// Need to migrate test.dart to not expect the above before it can use this.
-
// READ ME! If you add a new field to this, make sure to add it to
// [parse()], [optionsEqual()], [hashCode], and [toString()]. A good check is to
// comment out an existing field and see what breaks. Every error is a place
@@ -123,7 +115,7 @@
// Infer option values from the words in the configuration name.
var words = name.split("-").toSet();
- var optionsCopy = new Map.of(optionsJson);
+ var optionsCopy = Map.of(optionsJson);
T enumOption<T extends NamedEnum>(
String option, List<String> allowed, T Function(String) parse) {
@@ -210,7 +202,7 @@
throw FormatException('Option "$option" had value "$value", which is '
'not a List.');
}
- return new List<String>.from(value as List);
+ return List<String>.from(value as List);
}
// Extract options from the name and map.
@@ -220,10 +212,12 @@
var mode = enumOption("mode", Mode.names, Mode.find);
var runtime = enumOption("runtime", Runtime.names, Runtime.find);
var system = enumOption("system", System.names, System.find);
+ var nnbdMode = enumOption("nnbd", NnbdMode.names, NnbdMode.find);
// Fill in any missing values using defaults when possible.
architecture ??= Architecture.x64;
system ??= System.host;
+ nnbdMode ??= NnbdMode.legacy;
// Infer from compiler from runtime or vice versa.
if (compiler == null) {
@@ -247,17 +241,18 @@
var configuration = Configuration(
name, architecture, compiler, mode, runtime, system,
+ nnbdMode: nnbdMode,
babel: stringOption("babel"),
builderTag: stringOption("builder-tag"),
vmOptions: stringListOption("vm-options"),
dart2jsOptions: stringListOption("dart2js-options"),
+ experiments: stringListOption("experiments"),
timeout: intOption("timeout"),
enableAsserts: boolOption("enable-asserts"),
isChecked: boolOption("checked"),
isCsp: boolOption("csp"),
isHostChecked: boolOption("host-checked"),
isMinified: boolOption("minified"),
- previewDart2: boolOption("preview-dart-2"),
useAnalyzerCfe: boolOption("use-cfe"),
useAnalyzerFastaParser: boolOption("analyzer-use-fasta-parser"),
useBlobs: boolOption("use-blobs"),
@@ -268,7 +263,7 @@
// Should have consumed the whole map.
if (optionsCopy.isNotEmpty) {
- throw new FormatException('Unknown option "${optionsCopy.keys.first}".');
+ throw FormatException('Unknown option "${optionsCopy.keys.first}".');
}
return configuration;
@@ -286,6 +281,9 @@
final System system;
+ /// Which NNBD mode to run the test files under.
+ final NnbdMode nnbdMode;
+
final String babel;
final String builderTag;
@@ -294,6 +292,17 @@
final List<String> dart2jsOptions;
+ /// The names of the experiments to enable while running tests.
+ ///
+ /// A test may *require* an experiment to always be enabled by containing a
+ /// comment like:
+ ///
+ /// // SharedOptions=--enable-experiment=extension-methods
+ ///
+ /// Enabling an experiment here in the configuration allows running the same
+ /// test both with an experiment on and off.
+ final List<String> experiments;
+
final int timeout;
final bool enableAsserts;
@@ -308,9 +317,6 @@
final bool isMinified;
- // TODO(rnystrom): Remove this when Dart 1.0 is no longer supported.
- final bool previewDart2;
-
// TODO(whesse): Remove these when only fasta front end is in analyzer.
final bool useAnalyzerCfe;
final bool useAnalyzerFastaParser;
@@ -326,17 +332,18 @@
Configuration(this.name, this.architecture, this.compiler, this.mode,
this.runtime, this.system,
- {String babel,
+ {NnbdMode nnbdMode,
+ String babel,
String builderTag,
List<String> vmOptions,
List<String> dart2jsOptions,
+ List<String> experiments,
int timeout,
bool enableAsserts,
bool isChecked,
bool isCsp,
bool isHostChecked,
bool isMinified,
- bool previewDart2,
bool useAnalyzerCfe,
bool useAnalyzerFastaParser,
bool useBlobs,
@@ -344,17 +351,18 @@
bool useHotReload,
bool useHotReloadRollback,
bool useSdk})
- : babel = babel ?? "",
+ : nnbdMode = nnbdMode ?? NnbdMode.legacy,
+ babel = babel ?? "",
builderTag = builderTag ?? "",
vmOptions = vmOptions ?? <String>[],
dart2jsOptions = dart2jsOptions ?? <String>[],
+ experiments = experiments ?? <String>[],
timeout = timeout ?? -1,
enableAsserts = enableAsserts ?? false,
isChecked = isChecked ?? false,
isCsp = isCsp ?? false,
isHostChecked = isHostChecked ?? false,
isMinified = isMinified ?? false,
- previewDart2 = previewDart2 ?? true,
useAnalyzerCfe = useAnalyzerCfe ?? false,
useAnalyzerFastaParser = useAnalyzerFastaParser ?? false,
useBlobs = useBlobs ?? false,
@@ -371,17 +379,18 @@
mode == other.mode &&
runtime == other.runtime &&
system == other.system &&
+ nnbdMode == other.nnbdMode &&
babel == other.babel &&
builderTag == other.builderTag &&
- vmOptions.join(" & ") == other.vmOptions.join(" & ") &&
- dart2jsOptions.join(" & ") == other.dart2jsOptions.join(" & ") &&
+ _listsEqual(vmOptions, other.vmOptions) &&
+ _listsEqual(dart2jsOptions, other.dart2jsOptions) &&
+ _listsEqual(experiments, other.experiments) &&
timeout == other.timeout &&
enableAsserts == other.enableAsserts &&
isChecked == other.isChecked &&
isCsp == other.isCsp &&
isHostChecked == other.isHostChecked &&
isMinified == other.isMinified &&
- previewDart2 == other.previewDart2 &&
useAnalyzerCfe == other.useAnalyzerCfe &&
useAnalyzerFastaParser == other.useAnalyzerFastaParser &&
useBlobs == other.useBlobs &&
@@ -390,6 +399,20 @@
useHotReloadRollback == other.useHotReloadRollback &&
useSdk == other.useSdk;
+ /// Whether [a] and [b] contain the same strings, regardless of order.
+ bool _listsEqual(List<String> a, List<String> b) {
+ if (a.length != b.length) return false;
+
+ // Using sorted lists instead of sets in case there are duplicate strings
+ // in the lists. ["a"] should not be considered equal to ["a", "a"].
+ var aSorted = a.toList()..sort();
+ var bSorted = b.toList()..sort();
+ for (var i = 0; i < aSorted.length; i++) {
+ if (aSorted[i] != bSorted[i]) return false;
+ }
+ return true;
+ }
+
bool operator ==(Object other) =>
other is Configuration && name == other.name && optionsEqual(other);
@@ -403,10 +426,12 @@
mode.hashCode ^
runtime.hashCode ^
system.hashCode ^
+ nnbdMode.hashCode ^
babel.hashCode ^
builderTag.hashCode ^
vmOptions.join(" & ").hashCode ^
dart2jsOptions.join(" & ").hashCode ^
+ experiments.join(" & ").hashCode ^
timeout.hashCode ^
_toBinary([
enableAsserts,
@@ -414,7 +439,6 @@
isCsp,
isHostChecked,
isMinified,
- previewDart2,
useAnalyzerCfe,
useAnalyzerFastaParser,
useBlobs,
@@ -425,7 +449,7 @@
]);
String toString() {
- var buffer = new StringBuffer();
+ var buffer = StringBuffer();
buffer.write(name);
buffer.write("(");
@@ -436,19 +460,24 @@
fields.add("runtime: $runtime");
fields.add("system: $system");
+ if (nnbdMode != NnbdMode.legacy) fields.add("nnbd: $nnbdMode");
+
+ stringListField(String name, List<String> field) {
+ if (field.isEmpty) return;
+ fields.add("$name: [${field.join(", ")}]");
+ }
+
if (babel.isNotEmpty) fields.add("babel: $babel");
if (builderTag.isNotEmpty) fields.add("builder-tag: $builderTag");
- if (vmOptions.isNotEmpty)
- fields.add("vm-options: [${vmOptions.join(", ")}]");
- if (dart2jsOptions.isNotEmpty)
- fields.add("dart2js-options: [${dart2jsOptions.join(", ")}]");
+ stringListField("vm-options", vmOptions);
+ stringListField("dart2js-options", dart2jsOptions);
+ stringListField("experiments", experiments);
if (timeout > 0) fields.add("timeout: $timeout");
if (enableAsserts) fields.add("enable-asserts");
if (isChecked) fields.add("checked");
if (isCsp) fields.add("csp");
if (isHostChecked) fields.add("host-checked");
if (isMinified) fields.add("minified");
- if (previewDart2) fields.add("preview-dart-2");
if (useAnalyzerCfe) fields.add("use-cfe");
if (useAnalyzerFastaParser) fields.add("analyzer-use-fasta-parser");
if (useBlobs) fields.add("use-blobs");
@@ -462,7 +491,7 @@
}
String visualCompare(Configuration other) {
- var buffer = new StringBuffer();
+ var buffer = StringBuffer();
buffer.writeln(name);
buffer.writeln(other.name);
@@ -473,68 +502,44 @@
fields.add("runtime: $runtime ${other.runtime}");
fields.add("system: $system ${other.system}");
- if (babel.isNotEmpty || other.babel.isNotEmpty) {
- var ours = babel == "" ? "(none)" : babel;
- var theirs = other.babel == "" ? "(none)" : other.babel;
- fields.add("babel: $ours $theirs");
+ stringField(String name, String value, String otherValue) {
+ if (value.isEmpty && otherValue.isEmpty) return;
+ var ours = value.isEmpty ? "(none)" : value;
+ var theirs = otherValue.isEmpty ? "(none)" : otherValue;
+ fields.add("$name: $ours $theirs");
}
- if (builderTag.isNotEmpty || other.builderTag.isNotEmpty) {
- var ours = builderTag == "" ? "(none)" : builderTag;
- var theirs = other.builderTag == "" ? "(none)" : other.builderTag;
- fields.add("builder-tag: $ours $theirs");
+
+ stringListField(String name, List<String> value, List<String> otherValue) {
+ if (value.isEmpty && otherValue.isEmpty) return;
+ fields.add("$name: [${value.join(', ')}] [${otherValue.join(', ')}]");
}
- if (vmOptions.isNotEmpty || other.vmOptions.isNotEmpty) {
- var ours = "[${vmOptions.join(", ")}]";
- var theirs = "[${other.vmOptions.join(", ")}]";
- fields.add("vm-options: $ours $theirs");
+
+ boolField(String name, bool value, bool otherValue) {
+ if (!value && !otherValue) return;
+ fields.add("$name: $value $otherValue");
}
- if (dart2jsOptions.isNotEmpty || other.dart2jsOptions.isNotEmpty) {
- var ours = "[${dart2jsOptions.join(", ")}]";
- var theirs = "[${other.dart2jsOptions.join(", ")}]";
- fields.add("dart2js-options: $ours $theirs");
- }
+
+ fields.add("nnbd: $nnbdMode ${other.nnbdMode}");
+ stringField("babel", babel, other.babel);
+ stringField("builder-tag", builderTag, other.builderTag);
+ stringListField("vm-options", vmOptions, other.vmOptions);
+ stringListField("dart2js-options", dart2jsOptions, other.dart2jsOptions);
+ stringListField("experiments", experiments, other.experiments);
fields.add("timeout: $timeout ${other.timeout}");
- if (enableAsserts || other.enableAsserts) {
- fields.add("enable-asserts $enableAsserts ${other.enableAsserts}");
- }
- if (isChecked || other.isChecked) {
- fields.add("checked $isChecked ${other.isChecked}");
- }
- if (isCsp || other.isCsp) {
- fields.add("csp $isCsp ${other.isCsp}");
- }
- if (isHostChecked || other.isHostChecked) {
- fields.add("isHostChecked $isHostChecked ${other.isHostChecked}");
- }
- if (isMinified || other.isMinified) {
- fields.add("isMinified $isMinified ${other.isMinified}");
- }
- if (previewDart2 || other.previewDart2) {
- fields.add("previewDart2 $previewDart2 ${other.previewDart2}");
- }
- if (useAnalyzerCfe || other.useAnalyzerCfe) {
- fields.add("useAnalyzerCfe $useAnalyzerCfe ${other.useAnalyzerCfe}");
- }
- if (useAnalyzerFastaParser || other.useAnalyzerFastaParser) {
- fields.add("useAnalyzerFastaParser "
- "$useAnalyzerFastaParser ${other.useAnalyzerFastaParser}");
- }
- if (useBlobs || other.useBlobs) {
- fields.add("useBlobs $useBlobs ${other.useBlobs}");
- }
- if (useHotReload || other.useHotReload) {
- fields.add("useHotReload $useHotReload ${other.useHotReload}");
- }
- if (isHostChecked) {
- fields.add("host-checked $isHostChecked ${other.isHostChecked}");
- }
- if (useHotReloadRollback || other.useHotReloadRollback) {
- fields.add("useHotReloadRollback"
- " $useHotReloadRollback ${other.useHotReloadRollback}");
- }
- if (useSdk || other.useSdk) {
- fields.add("useSdk $useSdk ${other.useSdk}");
- }
+ boolField("enable-asserts", enableAsserts, other.enableAsserts);
+ boolField("checked", isChecked, other.isChecked);
+ boolField("csp", isCsp, other.isCsp);
+ boolField("host-checked", isHostChecked, other.isHostChecked);
+ boolField("minified", isMinified, other.isMinified);
+ boolField("use-cfe", useAnalyzerCfe, other.useAnalyzerCfe);
+ boolField("analyzer-use-fasta-parser", useAnalyzerFastaParser,
+ other.useAnalyzerFastaParser);
+ boolField("use-blobs", useBlobs, other.useBlobs);
+ boolField("host-checked", isHostChecked, other.isHostChecked);
+ boolField("hot-reload", useHotReload, other.useHotReload);
+ boolField("hot-reload-rollback", useHotReloadRollback,
+ other.useHotReloadRollback);
+ boolField("use-sdk", useSdk, other.useSdk);
buffer.write(fields.join("\n "));
buffer.write("\n");
@@ -543,22 +548,22 @@
}
class Architecture extends NamedEnum {
- static const ia32 = const Architecture._('ia32');
- static const x64 = const Architecture._('x64');
- static const arm = const Architecture._('arm');
- static const armv6 = const Architecture._('armv6');
- static const armv5te = const Architecture._('armv5te');
- static const arm64 = const Architecture._('arm64');
- static const simarm = const Architecture._('simarm');
- static const simarmv6 = const Architecture._('simarmv6');
- static const simarmv5te = const Architecture._('simarmv5te');
- static const simarm64 = const Architecture._('simarm64');
- static const simdbc = const Architecture._('simdbc');
- static const simdbc64 = const Architecture._('simdbc64');
+ static const ia32 = Architecture._('ia32');
+ static const x64 = Architecture._('x64');
+ static const arm = Architecture._('arm');
+ static const armv6 = Architecture._('armv6');
+ static const armv5te = Architecture._('armv5te');
+ static const arm64 = Architecture._('arm64');
+ static const simarm = Architecture._('simarm');
+ static const simarmv6 = Architecture._('simarmv6');
+ static const simarmv5te = Architecture._('simarmv5te');
+ static const simarm64 = Architecture._('simarm64');
+ static const simdbc = Architecture._('simdbc');
+ static const simdbc64 = Architecture._('simdbc64');
static final List<String> names = _all.keys.toList();
- static final _all = new Map<String, Architecture>.fromIterable([
+ static final _all = Map<String, Architecture>.fromIterable([
ia32,
x64,
arm,
@@ -577,29 +582,29 @@
var architecture = _all[name];
if (architecture != null) return architecture;
- throw new ArgumentError('Unknown architecture "$name".');
+ throw ArgumentError('Unknown architecture "$name".');
}
const Architecture._(String name) : super(name);
}
class Compiler extends NamedEnum {
- static const none = const Compiler._('none');
- static const dart2js = const Compiler._('dart2js');
- static const dart2analyzer = const Compiler._('dart2analyzer');
- static const compareAnalyzerCfe = const Compiler._('compare_analyzer_cfe');
- static const dartdevc = const Compiler._('dartdevc');
- static const dartdevk = const Compiler._('dartdevk');
- static const appJitk = const Compiler._('app_jitk');
- static const dartk = const Compiler._('dartk');
- static const dartkp = const Compiler._('dartkp');
- static const dartkb = const Compiler._('dartkb');
- static const specParser = const Compiler._('spec_parser');
- static const fasta = const Compiler._('fasta');
+ static const none = Compiler._('none');
+ static const dart2js = Compiler._('dart2js');
+ static const dart2analyzer = Compiler._('dart2analyzer');
+ static const compareAnalyzerCfe = Compiler._('compare_analyzer_cfe');
+ static const dartdevc = Compiler._('dartdevc');
+ static const dartdevk = Compiler._('dartdevk');
+ static const appJitk = Compiler._('app_jitk');
+ static const dartk = Compiler._('dartk');
+ static const dartkp = Compiler._('dartkp');
+ static const dartkb = Compiler._('dartkb');
+ static const specParser = Compiler._('spec_parser');
+ static const fasta = Compiler._('fasta');
static final List<String> names = _all.keys.toList();
- static final _all = new Map<String, Compiler>.fromIterable([
+ static final _all = Map<String, Compiler>.fromIterable([
none,
dart2js,
dart2analyzer,
@@ -618,7 +623,7 @@
var compiler = _all[name];
if (compiler != null) return compiler;
- throw new ArgumentError('Unknown compiler "$name".');
+ throw ArgumentError('Unknown compiler "$name".');
}
const Compiler._(String name) : super(name);
@@ -722,21 +727,20 @@
}
class Mode extends NamedEnum {
- static const debug = const Mode._('debug');
- static const product = const Mode._('product');
- static const release = const Mode._('release');
+ static const debug = Mode._('debug');
+ static const product = Mode._('product');
+ static const release = Mode._('release');
static final List<String> names = _all.keys.toList();
- static final _all = new Map<String, Mode>.fromIterable(
- [debug, product, release],
+ static final _all = Map<String, Mode>.fromIterable([debug, product, release],
key: (mode) => (mode as Mode).name);
static Mode find(String name) {
var mode = _all[name];
if (mode != null) return mode;
- throw new ArgumentError('Unknown mode "$name".');
+ throw ArgumentError('Unknown mode "$name".');
}
const Mode._(String name) : super(name);
@@ -745,25 +749,25 @@
}
class Runtime extends NamedEnum {
- static const vm = const Runtime._('vm');
- static const flutter = const Runtime._('flutter');
- static const dartPrecompiled = const Runtime._('dart_precompiled');
- static const d8 = const Runtime._('d8');
- static const jsshell = const Runtime._('jsshell');
- static const firefox = const Runtime._('firefox');
- static const chrome = const Runtime._('chrome');
- static const safari = const Runtime._('safari');
- static const ie9 = const Runtime._('ie9');
- static const ie10 = const Runtime._('ie10');
- static const ie11 = const Runtime._('ie11');
- static const edge = const Runtime._('edge');
- static const chromeOnAndroid = const Runtime._('chromeOnAndroid');
- static const selfCheck = const Runtime._('self_check');
- static const none = const Runtime._('none');
+ static const vm = Runtime._('vm');
+ static const flutter = Runtime._('flutter');
+ static const dartPrecompiled = Runtime._('dart_precompiled');
+ static const d8 = Runtime._('d8');
+ static const jsshell = Runtime._('jsshell');
+ static const firefox = Runtime._('firefox');
+ static const chrome = Runtime._('chrome');
+ static const safari = Runtime._('safari');
+ static const ie9 = Runtime._('ie9');
+ static const ie10 = Runtime._('ie10');
+ static const ie11 = Runtime._('ie11');
+ static const edge = Runtime._('edge');
+ static const chromeOnAndroid = Runtime._('chromeOnAndroid');
+ static const selfCheck = Runtime._('self_check');
+ static const none = Runtime._('none');
static final List<String> names = _all.keys.toList();
- static final _all = new Map<String, Runtime>.fromIterable([
+ static final _all = Map<String, Runtime>.fromIterable([
vm,
flutter,
dartPrecompiled,
@@ -785,7 +789,7 @@
var runtime = _all[name];
if (runtime != null) return runtime;
- throw new ArgumentError('Unknown runtime "$name".');
+ throw ArgumentError('Unknown runtime "$name".');
}
const Runtime._(String name) : super(name);
@@ -847,15 +851,15 @@
}
class System extends NamedEnum {
- static const android = const System._('android');
- static const fuchsia = const System._('fuchsia');
- static const linux = const System._('linux');
- static const mac = const System._('mac');
- static const win = const System._('win');
+ static const android = System._('android');
+ static const fuchsia = System._('fuchsia');
+ static const linux = System._('linux');
+ static const mac = System._('mac');
+ static const win = System._('win');
static final List<String> names = _all.keys.toList();
- static final _all = new Map<String, System>.fromIterable(
+ static final _all = Map<String, System>.fromIterable(
[android, fuchsia, linux, mac, win],
key: (system) => (system as System).name);
@@ -875,7 +879,7 @@
}
// TODO(rnystrom): What about ios?
- throw new ArgumentError('Unknown operating system "$name".');
+ throw ArgumentError('Unknown operating system "$name".');
}
const System._(String name) : super(name);
@@ -897,6 +901,34 @@
}
}
+/// What level of non-nullability support should be applied to the test files.
+class NnbdMode extends NamedEnum {
+ /// "Opted out" legacy mode with no NNBD features allowed.
+ static const legacy = NnbdMode._('legacy');
+
+ /// Opted in to NNBD features, but only static checking and weak runtime
+ /// checks.
+ static const optedIn = NnbdMode._('opted-in');
+
+ /// Opted in to NNBD features and with full sound runtime checks.
+ static const strong = NnbdMode._('strong');
+
+ static final List<String> names = _all.keys.toList();
+
+ static final _all = {
+ for (var mode in [legacy, optedIn, strong]) mode.name: mode
+ };
+
+ static NnbdMode find(String name) {
+ var mode = _all[name];
+ if (mode != null) return mode;
+
+ throw ArgumentError('Unknown NNBD mode "$name".');
+ }
+
+ const NnbdMode._(String name) : super(name);
+}
+
/// Base class for an enum-like class whose values are identified by name.
abstract class NamedEnum {
final String name;
diff --git a/pkg/smith/lib/test_matrix.dart b/pkg/smith/lib/test_matrix.dart
index 0bf2a5b..74adce7 100644
--- a/pkg/smith/lib/test_matrix.dart
+++ b/pkg/smith/lib/test_matrix.dart
@@ -13,7 +13,7 @@
/// Reads a test matrix from the file at [path].
static TestMatrix fromPath(String path) {
- var json = jsonDecode(new File(path).readAsStringSync());
+ var json = jsonDecode(File(path).readAsStringSync());
return fromJson(json as Map<String, dynamic>);
}
diff --git a/pkg/smith/test/configuration_test.dart b/pkg/smith/test/configuration_test.dart
index 9c77fb3..fcbbebf 100644
--- a/pkg/smith/test/configuration_test.dart
+++ b/pkg/smith/test/configuration_test.dart
@@ -198,39 +198,35 @@
test("other options from map", () {
expect(
Configuration.parse("dart2js", {
+ "nnbd": "opted-in",
"builder-tag": "the tag",
"vm-options": ["vm stuff", "more vm stuff"],
"dart2js-options": ["dart2js stuff", "more dart2js stuff"],
+ "experiments": ["semicolons", "interrobangs"],
"enable-asserts": true,
"checked": true,
"csp": true,
"host-checked": true,
"minified": true,
- "preview-dart-2": true,
"hot-reload": true,
"hot-reload-rollback": true,
- "use-sdk": true,
+ "use-sdk": true
}),
- equals(Configuration(
- "dart2js",
- Architecture.x64,
- Compiler.dart2js,
- Mode.release,
- Runtime.d8,
- System.host,
- builderTag: "the tag",
- vmOptions: ["vm stuff", "more vm stuff"],
- dart2jsOptions: ["dart2js stuff", "more dart2js stuff"],
- enableAsserts: true,
- isChecked: true,
- isCsp: true,
- isHostChecked: true,
- isMinified: true,
- previewDart2: true,
- useHotReload: true,
- useHotReloadRollback: true,
- useSdk: true,
- )));
+ equals(Configuration("dart2js", Architecture.x64, Compiler.dart2js,
+ Mode.release, Runtime.d8, System.host,
+ nnbdMode: NnbdMode.optedIn,
+ builderTag: "the tag",
+ vmOptions: ["vm stuff", "more vm stuff"],
+ dart2jsOptions: ["dart2js stuff", "more dart2js stuff"],
+ experiments: ["semicolons", "interrobangs"],
+ enableAsserts: true,
+ isChecked: true,
+ isCsp: true,
+ isHostChecked: true,
+ isMinified: true,
+ useHotReload: true,
+ useHotReloadRollback: true,
+ useSdk: true)));
});
test("neither compiler nor runtime specified", () {
@@ -238,7 +234,7 @@
"debug",
{},
'Must specify at least one of compiler or runtime in options or '
- 'configuration name.');
+ 'configuration name.');
});
test("empty string", () {
@@ -255,7 +251,7 @@
"dart2js-debug",
{"mode": "release"},
'Found mode "release" in options and "debug" in configuration '
- 'name.');
+ 'name.');
});
test("multiple values for same option in name", () {
@@ -263,7 +259,7 @@
"dart2js-debug-release",
{},
'Found multiple values for mode ("debug" and "release"), in '
- 'configuration name.');
+ 'configuration name.');
});
test("null bool option", () {
@@ -341,6 +337,103 @@
test("same options are equal", () {
expect(debugWithAsserts.optionsEqual(debugWithAsserts2), isTrue);
});
+
+ test("list elements are considered unordered", () {
+ var aThenB = Configuration("name", Architecture.x64, Compiler.dart2js,
+ Mode.release, Runtime.vm, System.linux,
+ vmOptions: ["a", "b"]);
+
+ var bThenA = Configuration("name", Architecture.x64, Compiler.dart2js,
+ Mode.release, Runtime.vm, System.linux,
+ vmOptions: ["b", "a"]);
+
+ expect(aThenB.optionsEqual(bThenA), isTrue);
+ });
+ });
+
+ group("visualCompare()", () {
+ var a = Configuration("dartdevc", Architecture.ia32, Compiler.dartdevc,
+ Mode.debug, Runtime.chrome, System.android,
+ builderTag: "a tag",
+ vmOptions: ["vm a1", "vm a2"],
+ dart2jsOptions: ["dart2js a1", "dart2js a2"],
+ experiments: ["experiment a1", "experiment a2"],
+ timeout: 1);
+
+ var b = Configuration(
+ "dart2js",
+ Architecture.x64,
+ Compiler.dart2js,
+ Mode.release,
+ Runtime.d8,
+ System.fuchsia,
+ nnbdMode: NnbdMode.strong,
+ builderTag: "b tag",
+ vmOptions: ["vm b1", "vm b2"],
+ dart2jsOptions: ["dart2js b1", "dart2js b2"],
+ experiments: ["experiment b1", "experiment b2"],
+ timeout: 2,
+ enableAsserts: true,
+ isChecked: true,
+ isCsp: true,
+ isHostChecked: true,
+ isMinified: true,
+ useAnalyzerCfe: true,
+ useAnalyzerFastaParser: true,
+ useBlobs: true,
+ useElf: true,
+ useHotReload: true,
+ useHotReloadRollback: true,
+ useSdk: true,
+ );
+
+ test("everything different", () {
+ expect(a.visualCompare(b), equals("""
+dartdevc
+dart2js
+architecture: ia32 x64
+ compiler: dartdevc dart2js
+ mode: debug release
+ runtime: chrome d8
+ system: android fuchsia
+ nnbd: legacy strong
+ builder-tag: a tag b tag
+ vm-options: [vm a1, vm a2] [vm b1, vm b2]
+ dart2js-options: [dart2js a1, dart2js a2] [dart2js b1, dart2js b2]
+ experiments: [experiment a1, experiment a2] [experiment b1, experiment b2]
+ timeout: 1 2
+ enable-asserts: false true
+ checked: false true
+ csp: false true
+ host-checked: false true
+ minified: false true
+ use-cfe: false true
+ analyzer-use-fasta-parser: false true
+ use-blobs: false true
+ host-checked: false true
+ hot-reload: false true
+ hot-reload-rollback: false true
+ use-sdk: false true
+"""));
+ });
+
+ test("everything the same", () {
+ expect(a.visualCompare(a), equals("""
+dartdevc
+dartdevc
+architecture: ia32 ia32
+ compiler: dartdevc dartdevc
+ mode: debug debug
+ runtime: chrome chrome
+ system: android android
+ nnbd: legacy legacy
+ builder-tag: a tag a tag
+ vm-options: [vm a1, vm a2] [vm a1, vm a2]
+ dart2js-options: [dart2js a1, dart2js a2] [dart2js a1, dart2js a2]
+ experiments: [experiment a1, experiment a2] [experiment a1, experiment a2]
+ timeout: 1 1
+"""));
+ });
});
});
}
diff --git a/pkg/status_file/bin/remove_non_essential_entries.dart b/pkg/status_file/bin/remove_non_essential_entries.dart
index 80cd930..409fbcd 100644
--- a/pkg/status_file/bin/remove_non_essential_entries.dart
+++ b/pkg/status_file/bin/remove_non_essential_entries.dart
@@ -19,6 +19,14 @@
//
// When using the option to keep crashes, there will be an additional line
// a: Crash
+//
+// The option -r can be used to also process expectations in lines with
+// comments. In this mode, deleted comments are collected and either printed
+// out or written to a separate file (with -w).
+//
+// The option -i (with -r) tries to resolve the status of issues mentioned in
+// comments and adds it to the collected comments. This requires an issue.log
+// file as described in [parseIssueFile].
import 'dart:io';
@@ -37,8 +45,93 @@
: StatusEntry(entry.path, entry.lineNumber, remaining, entry.comment);
}
-StatusFile removeNonEssentialEntries(
- StatusFile statusFile, List<Expectation> expectationsToKeep) {
+Map<String, Map<int, String>> issues;
+
+String getIssueState(String project, int issue) {
+ Map projectIssues = issues[project];
+ if (projectIssues == null) {
+ throw "Cannot find project $project, not one of {${issues.keys.join(",")}}";
+ }
+ String state = projectIssues[issue] ?? "";
+ return "\t$state";
+}
+
+// This method assumes the following data format:
+// <project>, <state>, <issue number>, <update timestamp>
+// sorted by issue number then timestamp ascending.
+//
+// The first line is expected to contain the field names and is skipped.
+void parseIssueFile() async {
+ issues = {};
+ String issuesLog = await File("issues.log").readAsString();
+ List<String> lines = issuesLog.split("\n");
+ for (String line in lines.skip(1).where((line) => line.isNotEmpty)) {
+ List<String> fields = line.split(",");
+ if (fields.length != 4) {
+ throw "invalid issue state line $line";
+ }
+ String project = fields[0];
+ String state = fields[1];
+ int issueNumber = int.parse(fields[2]);
+ issues.putIfAbsent(project, () => {})[issueNumber] = state;
+ }
+}
+
+List<RegExp> co19IssuePatterns = [
+ RegExp(r"https://github.com/dart-lang/co19/issues/(\d+)"),
+ RegExp(r"co19 issue (\d+)"),
+];
+
+List<RegExp> sdkIssuePatterns = [
+ RegExp(r"[Ii]ssue (\d+)"),
+ RegExp(r"#(\d+)"),
+ RegExp(r"^(\d+)$"),
+ RegExp(r"http://dartbug.com/(\d+)"),
+ RegExp(r"https://github.com/dart-lang/sdk/issues/(\d+)"),
+];
+
+String getIssueText(String comment, bool resolveState) {
+ int issue;
+ String prefix;
+ String project;
+ for (RegExp pattern in co19IssuePatterns) {
+ Match match = pattern.firstMatch(comment);
+ if (match != null) {
+ issue = int.tryParse(match[1]);
+ if (issue != null) {
+ prefix = "https://github.com/dart-lang/co19/issues/";
+ project = "dart-lang/co19";
+ break;
+ }
+ }
+ }
+ if (issue == null) {
+ for (RegExp pattern in sdkIssuePatterns) {
+ Match match = pattern.firstMatch(comment);
+ if (match != null) {
+ issue = int.tryParse(match[1]);
+ if (issue != null) {
+ prefix = "https://dartbug.com/";
+ project = "dart-lang/sdk";
+ break;
+ }
+ }
+ }
+ }
+ if (issue != null) {
+ String state = resolveState ? getIssueState(project, issue) : "";
+ return "$prefix$issue$state";
+ } else {
+ return "";
+ }
+}
+
+Future<StatusFile> removeNonEssentialEntries(
+ StatusFile statusFile,
+ List<Expectation> expectationsToKeep,
+ bool removeComments,
+ List<String> comments,
+ bool resolveIssueState) async {
List<StatusSection> sections = <StatusSection>[];
for (StatusSection section in statusFile.sections) {
bool hasStatusEntries = false;
@@ -46,12 +139,30 @@
for (Entry entry in section.entries) {
if (entry is EmptyEntry) {
entries.add(entry);
- } else if (entry is StatusEntry && entry.comment != null ||
- entry is CommentEntry) {
+ } else if (entry is CommentEntry) {
entries.add(entry);
hasStatusEntries = true;
} else if (entry is StatusEntry) {
- StatusEntry newEntry = filterExpectations(entry, expectationsToKeep);
+ StatusEntry newEntry = entry;
+ if (entry.comment == null) {
+ newEntry = filterExpectations(entry, expectationsToKeep);
+ } else if (removeComments) {
+ newEntry = filterExpectations(entry, expectationsToKeep);
+ // Store comment if entry will be removed.
+ if (newEntry == null) {
+ String comment = entry.comment.toString().substring(1).trim();
+ String testName = entry.path;
+ String expectations = entry.expectations.toString();
+ // Remove '[' and ']'.
+ expectations = expectations.substring(1, expectations.length - 1);
+ String conditionPrefix =
+ section.condition != null ? "${section.condition}" : "";
+ String issueText = await getIssueText(comment, resolveIssueState);
+ String statusLine = "$conditionPrefix\t$testName\t$expectations"
+ "\t$comment\t$issueText";
+ comments.add(statusLine);
+ }
+ }
if (newEntry != null) {
entries.add(newEntry);
hasStatusEntries = true;
@@ -83,6 +194,10 @@
help: "Overwrite input file with output.");
parser.addFlag("keep-crashes",
abbr: 'c', negatable: false, defaultsTo: false);
+ parser.addFlag("remove-comments",
+ abbr: 'r', negatable: false, defaultsTo: false);
+ parser.addFlag("resolve-issue-states",
+ abbr: 'i', negatable: false, defaultsTo: false);
parser.addFlag("help",
abbr: "h",
negatable: false,
@@ -97,7 +212,15 @@
print(parser.usage);
}
-main(List<String> arguments) {
+String formatComments(List<String> comments) {
+ StringBuffer sb = new StringBuffer();
+ for (String statusLine in comments) {
+ sb.writeln(statusLine);
+ }
+ return sb.toString();
+}
+
+main(List<String> arguments) async {
var parser = buildParser();
var results = parser.parse(arguments);
if (results["help"] || results.rest.isEmpty) {
@@ -117,15 +240,32 @@
expectationsToKeep.add(Expectation.crash);
}
+ bool removeComments = results["remove-comments"];
+
for (String path in results.rest) {
+ List<String> comments = [];
+
bool writeFile = results["overwrite"];
+ bool resolveGithubIssueState = results["resolve-issue-states"];
var statusFile = StatusFile.read(path);
- statusFile = removeNonEssentialEntries(statusFile, expectationsToKeep);
+ if (resolveGithubIssueState) {
+ await parseIssueFile();
+ }
+ statusFile = await removeNonEssentialEntries(statusFile, expectationsToKeep,
+ removeComments, comments, resolveGithubIssueState);
if (writeFile) {
- File(path).writeAsStringSync(statusFile.toString());
- print("Modified $path.");
+ await File(path).writeAsString(statusFile.toString());
+ print("Wrote $path.");
+ if (removeComments) {
+ await File("$path.csv").writeAsString(formatComments(comments));
+ print("Wrote $path.csv.");
+ }
} else {
print(statusFile);
+ if (removeComments) {
+ print("");
+ print(formatComments(comments));
+ }
}
}
}
diff --git a/pkg/test_runner/lib/src/browser_controller.dart b/pkg/test_runner/lib/src/browser_controller.dart
index 9f7cabc..4467399 100644
--- a/pkg/test_runner/lib/src/browser_controller.dart
+++ b/pkg/test_runner/lib/src/browser_controller.dart
@@ -200,7 +200,7 @@
.listen(_addStdout, onError: (error) {
// This should _never_ happen, but we really want this in the log
// if it actually does due to dart:io or vm bug.
- _logEvent("An error occured in the process stdout handling: $error");
+ _logEvent("An error occurred in the process stdout handling: $error");
}, onDone: closeStdout);
stderrSubscription = process.stderr
@@ -208,7 +208,7 @@
.listen(_addStderr, onError: (error) {
// This should _never_ happen, but we really want this in the log
// if it actually does due to dart:io or vm bug.
- _logEvent("An error occured in the process stderr handling: $error");
+ _logEvent("An error occurred in the process stderr handling: $error");
}, onDone: closeStderr);
process.exitCode.then((exitCode) {
@@ -1200,7 +1200,7 @@
}
void errorHandler(e) {
- if (!underTermination) print("Error occured in httpserver: $e");
+ if (!underTermination) print("Error occurred in httpserver: $e");
}
errorReportingServer.listen(errorReportingHandler, onError: errorHandler);
diff --git a/pkg/test_runner/lib/src/command.dart b/pkg/test_runner/lib/src/command.dart
index c3427a2..6732b5b 100644
--- a/pkg/test_runner/lib/src/command.dart
+++ b/pkg/test_runner/lib/src/command.dart
@@ -7,138 +7,24 @@
// CommandOutput.exitCode in subclasses of CommandOutput.
import 'dart:io' as io;
-import 'package:status_file/expectation.dart';
-
import 'command_output.dart';
import 'configuration.dart';
import 'path.dart';
import 'utils.dart';
/// A command executed as a step in a test case.
-class Command {
+abstract class Command {
static Command browserTest(String url, TestConfiguration configuration,
{bool retry}) {
return BrowserTestCommand._(url, configuration, retry);
}
- static Command compilation(
- String displayName,
- String outputFile,
- List<Uri> bootstrapDependencies,
- String executable,
- List<String> arguments,
- Map<String, String> environment,
- {bool alwaysCompile = false,
- String workingDirectory}) {
- return CompilationCommand._(displayName, outputFile, alwaysCompile,
- bootstrapDependencies, executable, arguments, environment,
- workingDirectory: workingDirectory);
- }
-
- static Command vmKernelCompilation(
- String outputFile,
- bool neverSkipCompilation,
- List<Uri> bootstrapDependencies,
- String executable,
- List<String> arguments,
- Map<String, String> environment,
- List<String> batchArgs) {
- return VMKernelCompilationCommand._(outputFile, neverSkipCompilation,
- bootstrapDependencies, executable, arguments, environment, batchArgs);
- }
-
- static Command analysis(String executable, List<String> arguments,
- Map<String, String> environmentOverrides) {
- return AnalysisCommand._(executable, arguments, environmentOverrides);
- }
-
- static Command compareAnalyzerCfe(String executable, List<String> arguments,
- Map<String, String> environmentOverrides) {
- return CompareAnalyzerCfeCommand._(
- executable, arguments, environmentOverrides);
- }
-
- static Command specParse(String executable, List<String> arguments,
- Map<String, String> environmentOverrides) {
- return SpecParseCommand._(executable, arguments, environmentOverrides);
- }
-
- static Command vm(String executable, List<String> arguments,
- Map<String, String> environmentOverrides) {
- return VmCommand._(executable, arguments, environmentOverrides);
- }
-
- static Command vmBatch(String executable, String tester,
- List<String> arguments, Map<String, String> environmentOverrides,
- {bool checked = true}) {
- return VmBatchCommand._(executable, tester, arguments, environmentOverrides,
- checked: checked);
- }
-
- static Command adbPrecompiled(
- String buildPath,
- String processTest,
- String testDirectory,
- List<String> arguments,
- bool useBlobs,
- bool useElf,
- List<String> extraLibs) {
- return AdbPrecompilationCommand._(buildPath, processTest, testDirectory,
- arguments, useBlobs, useElf, extraLibs);
- }
-
- static Command adbDartk(String buildPath, String processTest, String script,
- List<String> arguments, List<String> extraLibraries) {
- return AdbDartkCommand._(
- buildPath, processTest, script, arguments, extraLibraries);
- }
-
- static Command jsCommandLine(
- String displayName, String executable, List<String> arguments,
- [Map<String, String> environment]) {
- return JSCommandlineCommand._(
- displayName, executable, arguments, environment);
- }
-
- static Command process(
- String displayName, String executable, List<String> arguments,
- [Map<String, String> environment, String workingDirectory]) {
- return ProcessCommand._(
- displayName, executable, arguments, environment, workingDirectory);
- }
-
- static Command copy(String sourceDirectory, String destinationDirectory) {
- return CleanDirectoryCopyCommand._(sourceDirectory, destinationDirectory);
- }
-
- static Command makeSymlink(String link, String target) {
- return MakeSymlinkCommand._(link, target);
- }
-
- static Command fasta(
- Uri compilerLocation,
- Uri outputFile,
- List<Uri> bootstrapDependencies,
- Uri executable,
- List<String> arguments,
- Map<String, String> environment,
- Uri workingDirectory) {
- return FastaCompilationCommand._(
- compilerLocation,
- outputFile.toFilePath(),
- bootstrapDependencies,
- executable.toFilePath(),
- arguments,
- environment,
- workingDirectory?.toFilePath());
- }
-
/// A descriptive name for this command.
final String displayName;
/// When cloning a command object to run it multiple times, we give
/// the different copies distinct values for index.
- int index;
+ final int index;
/// Number of times this command *can* be retried.
int get maxNumRetries => 2;
@@ -156,9 +42,13 @@
/// Two clones with the same index will be equal, with different indices
/// will be distinct. Used to run tests multiple times, since identical
/// commands are only run once by the dependency graph scheduler.
- Command indexedCopy(int index) {
- return Command._(displayName, index: index);
- }
+ Command indexedCopy(int index);
+
+ CommandOutput createOutput(int exitCode, bool timedOut, List<int> stdout,
+ List<int> stderr, Duration time, bool compilationSkipped,
+ [int pid = 0]) =>
+ CommandOutput(this, exitCode, timedOut, stdout, stderr, time,
+ compilationSkipped, pid);
int get hashCode {
if (_cachedHashCode == null) {
@@ -174,7 +64,7 @@
(runtimeType == other.runtimeType && _equal(other as Command));
void _buildHashCode(HashCodeBuilder builder) {
- builder.addJson(displayName);
+ builder.add(displayName);
builder.add(index);
}
@@ -201,7 +91,7 @@
/// Working directory for the command.
final String workingDirectory;
- ProcessCommand._(String displayName, this.executable, this.arguments,
+ ProcessCommand(String displayName, this.executable, this.arguments,
[this.environmentOverrides, this.workingDirectory, int index = 0])
: super._(displayName, index: index) {
if (io.Platform.operatingSystem == 'windows') {
@@ -213,7 +103,7 @@
}
ProcessCommand indexedCopy(int index) {
- return ProcessCommand._(displayName, executable, arguments,
+ return ProcessCommand(displayName, executable, arguments,
environmentOverrides, workingDirectory, index);
}
@@ -264,30 +154,46 @@
final bool _alwaysCompile;
final List<Uri> _bootstrapDependencies;
- CompilationCommand._(
+ CompilationCommand(
String displayName,
this.outputFile,
- this._alwaysCompile,
this._bootstrapDependencies,
String executable,
List<String> arguments,
Map<String, String> environmentOverrides,
- {String workingDirectory,
+ {bool alwaysCompile,
+ String workingDirectory,
int index = 0})
- : super._(displayName, executable, arguments, environmentOverrides,
+ : _alwaysCompile = alwaysCompile ?? false,
+ super(displayName, executable, arguments, environmentOverrides,
workingDirectory, index);
- CompilationCommand indexedCopy(int index) => CompilationCommand._(
+ CompilationCommand indexedCopy(int index) => CompilationCommand(
displayName,
outputFile,
- _alwaysCompile,
_bootstrapDependencies,
executable,
arguments,
environmentOverrides,
+ alwaysCompile: _alwaysCompile,
workingDirectory: workingDirectory,
index: index);
+ CommandOutput createOutput(int exitCode, bool timedOut, List<int> stdout,
+ List<int> stderr, Duration time, bool compilationSkipped,
+ [int pid = 0]) {
+ if (displayName == 'precompiler' || displayName == 'app_jit') {
+ return VMCommandOutput(
+ this, exitCode, timedOut, stdout, stderr, time, pid);
+ } else if (displayName == 'dartdevc') {
+ return DevCompilerCommandOutput(this, exitCode, timedOut, stdout, stderr,
+ time, compilationSkipped, pid);
+ }
+
+ return CompilationCommandOutput(
+ this, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
+ }
+
bool get outputIsUpToDate {
if (_alwaysCompile) return false;
@@ -336,7 +242,7 @@
class FastaCompilationCommand extends CompilationCommand {
final Uri _compilerLocation;
- FastaCompilationCommand._(
+ FastaCompilationCommand(
this._compilerLocation,
String outputFile,
List<Uri> bootstrapDependencies,
@@ -345,12 +251,14 @@
Map<String, String> environmentOverrides,
String workingDirectory,
{int index = 0})
- : super._("fasta", outputFile, true, bootstrapDependencies, executable,
- arguments, environmentOverrides,
- workingDirectory: workingDirectory, index: index);
+ : super("fasta", outputFile, bootstrapDependencies, executable, arguments,
+ environmentOverrides,
+ alwaysCompile: true,
+ workingDirectory: workingDirectory,
+ index: index);
@override
- FastaCompilationCommand indexedCopy(int index) => FastaCompilationCommand._(
+ FastaCompilationCommand indexedCopy(int index) => FastaCompilationCommand(
_compilerLocation,
outputFile,
_bootstrapDependencies,
@@ -360,6 +268,12 @@
workingDirectory,
index: index);
+ FastaCommandOutput createOutput(int exitCode, bool timedOut, List<int> stdout,
+ List<int> stderr, Duration time, bool compilationSkipped,
+ [int pid = 0]) =>
+ FastaCommandOutput(
+ this, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
+
@override
List<String> get batchArguments {
return <String>[
@@ -427,29 +341,34 @@
class VMKernelCompilationCommand extends CompilationCommand {
final List<String> batchArgs;
- VMKernelCompilationCommand._(
+ VMKernelCompilationCommand(
String outputFile,
- bool alwaysCompile,
List<Uri> bootstrapDependencies,
String executable,
List<String> arguments,
Map<String, String> environmentOverrides,
this.batchArgs,
- {int index = 0})
- : super._('vm_compile_to_kernel $batchArgs', outputFile, alwaysCompile,
+ {bool alwaysCompile,
+ int index = 0})
+ : super('vm_compile_to_kernel $batchArgs', outputFile,
bootstrapDependencies, executable, arguments, environmentOverrides,
- index: index);
+ alwaysCompile: alwaysCompile, index: index);
VMKernelCompilationCommand indexedCopy(int index) =>
- VMKernelCompilationCommand._(
- outputFile,
- _alwaysCompile,
- _bootstrapDependencies,
- executable,
- arguments,
- environmentOverrides,
- batchArgs,
- index: index);
+ VMKernelCompilationCommand(outputFile, _bootstrapDependencies, executable,
+ arguments, environmentOverrides, batchArgs,
+ alwaysCompile: _alwaysCompile, index: index);
+
+ VMKernelCompilationCommandOutput createOutput(
+ int exitCode,
+ bool timedOut,
+ List<int> stdout,
+ List<int> stderr,
+ Duration time,
+ bool compilationSkipped,
+ [int pid = 0]) =>
+ VMKernelCompilationCommandOutput(
+ this, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
int get maxNumRetries => 1;
@@ -512,61 +431,94 @@
}
class AnalysisCommand extends ProcessCommand {
- AnalysisCommand._(String executable, List<String> arguments,
+ AnalysisCommand(String executable, List<String> arguments,
Map<String, String> environmentOverrides, {int index = 0})
- : super._('dart2analyzer', executable, arguments, environmentOverrides,
+ : super('dart2analyzer', executable, arguments, environmentOverrides,
null, index);
AnalysisCommand indexedCopy(int index) =>
- AnalysisCommand._(executable, arguments, environmentOverrides,
+ AnalysisCommand(executable, arguments, environmentOverrides,
index: index);
+
+ CommandOutput createOutput(int exitCode, bool timedOut, List<int> stdout,
+ List<int> stderr, Duration time, bool compilationSkipped,
+ [int pid = 0]) =>
+ AnalysisCommandOutput(
+ this, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
}
class CompareAnalyzerCfeCommand extends ProcessCommand {
- CompareAnalyzerCfeCommand._(String executable, List<String> arguments,
+ CompareAnalyzerCfeCommand(String executable, List<String> arguments,
Map<String, String> environmentOverrides, {int index = 0})
- : super._('compare_analyzer_cfe', executable, arguments,
+ : super('compare_analyzer_cfe', executable, arguments,
environmentOverrides, null, index);
CompareAnalyzerCfeCommand indexedCopy(int index) =>
- CompareAnalyzerCfeCommand._(executable, arguments, environmentOverrides,
+ CompareAnalyzerCfeCommand(executable, arguments, environmentOverrides,
index: index);
+
+ CompareAnalyzerCfeCommandOutput createOutput(
+ int exitCode,
+ bool timedOut,
+ List<int> stdout,
+ List<int> stderr,
+ Duration time,
+ bool compilationSkipped,
+ [int pid = 0]) =>
+ CompareAnalyzerCfeCommandOutput(
+ this, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
}
class SpecParseCommand extends ProcessCommand {
- SpecParseCommand._(String executable, List<String> arguments,
+ SpecParseCommand(String executable, List<String> arguments,
Map<String, String> environmentOverrides, {int index = 0})
- : super._('spec_parser', executable, arguments, environmentOverrides,
- null, index);
+ : super('spec_parser', executable, arguments, environmentOverrides, null,
+ index);
SpecParseCommand indexedCopy(int index) =>
- SpecParseCommand._(executable, arguments, environmentOverrides,
+ SpecParseCommand(executable, arguments, environmentOverrides,
index: index);
+
+ SpecParseCommandOutput createOutput(
+ int exitCode,
+ bool timedOut,
+ List<int> stdout,
+ List<int> stderr,
+ Duration time,
+ bool compilationSkipped,
+ [int pid = 0]) =>
+ SpecParseCommandOutput(
+ this, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
}
-class VmCommand extends ProcessCommand {
- VmCommand._(String executable, List<String> arguments,
+class VMCommand extends ProcessCommand {
+ VMCommand(String executable, List<String> arguments,
Map<String, String> environmentOverrides,
{int index = 0})
- : super._('vm', executable, arguments, environmentOverrides, null, index);
+ : super('vm', executable, arguments, environmentOverrides, null, index);
- VmCommand indexedCopy(int index) =>
- VmCommand._(executable, arguments, environmentOverrides, index: index);
+ VMCommand indexedCopy(int index) =>
+ VMCommand(executable, arguments, environmentOverrides, index: index);
+
+ CommandOutput createOutput(int exitCode, bool timedOut, List<int> stdout,
+ List<int> stderr, Duration time, bool compilationSkipped,
+ [int pid = 0]) =>
+ VMCommandOutput(this, exitCode, timedOut, stdout, stderr, time, pid);
}
-class VmBatchCommand extends ProcessCommand implements VmCommand {
+class VMBatchCommand extends ProcessCommand implements VMCommand {
final String dartFile;
final bool checked;
- VmBatchCommand._(String executable, String dartFile, List<String> arguments,
+ VMBatchCommand(String executable, String dartFile, List<String> arguments,
Map<String, String> environmentOverrides,
{this.checked = true, int index = 0})
: dartFile = dartFile,
- super._('vm-batch', executable, arguments, environmentOverrides, null,
+ super('vm-batch', executable, arguments, environmentOverrides, null,
index);
- VmBatchCommand indexedCopy(int index) =>
- VmBatchCommand._(executable, dartFile, arguments, environmentOverrides,
+ VMBatchCommand indexedCopy(int index) =>
+ VMBatchCommand(executable, dartFile, arguments, environmentOverrides,
checked: checked, index: index);
@override
@@ -574,7 +526,7 @@
checked ? ['--checked', dartFile] : [dartFile];
@override
- bool _equal(VmBatchCommand other) {
+ bool _equal(VMBatchCommand other) {
return super._equal(other) &&
dartFile == other.dartFile &&
checked == other.checked;
@@ -602,7 +554,7 @@
final bool useElf;
final List<String> extraLibraries;
- AdbPrecompilationCommand._(
+ AdbPrecompilationCommand(
this.buildPath,
this.processTestFilename,
this.precompiledTestDirectory,
@@ -613,7 +565,7 @@
{int index = 0})
: super._("adb_precompilation", index: index);
- AdbPrecompilationCommand indexedCopy(int index) => AdbPrecompilationCommand._(
+ AdbPrecompilationCommand indexedCopy(int index) => AdbPrecompilationCommand(
buildPath,
processTestFilename,
precompiledTestDirectory,
@@ -622,6 +574,12 @@
useElf,
extraLibraries,
index: index);
+
+ VMCommandOutput createOutput(int exitCode, bool timedOut, List<int> stdout,
+ List<int> stderr, Duration time, bool compilationSkipped,
+ [int pid = 0]) =>
+ VMCommandOutput(this, exitCode, timedOut, stdout, stderr, time, pid);
+
_buildHashCode(HashCodeBuilder builder) {
super._buildHashCode(builder);
builder.add(buildPath);
@@ -652,12 +610,12 @@
final List<String> arguments;
final List<String> extraLibraries;
- AdbDartkCommand._(this.buildPath, this.processTestFilename, this.kernelFile,
+ AdbDartkCommand(this.buildPath, this.processTestFilename, this.kernelFile,
this.arguments, this.extraLibraries,
{int index = 0})
: super._("adb_precompilation", index: index);
- AdbDartkCommand indexedCopy(int index) => AdbDartkCommand._(
+ AdbDartkCommand indexedCopy(int index) => AdbDartkCommand(
buildPath, processTestFilename, kernelFile, arguments, extraLibraries,
index: index);
_buildHashCode(HashCodeBuilder builder) {
@@ -679,15 +637,25 @@
'to an attached device. Uses (and requires) adb.';
}
-class JSCommandlineCommand extends ProcessCommand {
- JSCommandlineCommand._(
+class JSCommandLineCommand extends ProcessCommand {
+ JSCommandLineCommand(
String displayName, String executable, List<String> arguments,
[Map<String, String> environmentOverrides, int index = 0])
- : super._(displayName, executable, arguments, environmentOverrides, null,
+ : super(displayName, executable, arguments, environmentOverrides, null,
index);
- JSCommandlineCommand indexedCopy(int index) => JSCommandlineCommand._(
+ JSCommandLineCommand indexedCopy(int index) => JSCommandLineCommand(
displayName, executable, arguments, environmentOverrides, index);
+
+ JSCommandLineOutput createOutput(
+ int exitCode,
+ bool timedOut,
+ List<int> stdout,
+ List<int> stderr,
+ Duration time,
+ bool compilationSkipped,
+ [int pid = 0]) =>
+ JSCommandLineOutput(this, exitCode, timedOut, stdout, stderr, time);
}
/// [ScriptCommand]s are executed by dart code.
@@ -697,97 +665,3 @@
Future<ScriptCommandOutput> run();
}
-
-class CleanDirectoryCopyCommand extends ScriptCommand {
- final String _sourceDirectory;
- final String _destinationDirectory;
-
- CleanDirectoryCopyCommand._(this._sourceDirectory, this._destinationDirectory,
- {int index = 0})
- : super._('dir_copy', index: index);
-
- CleanDirectoryCopyCommand indexedCopy(int index) =>
- CleanDirectoryCopyCommand._(_sourceDirectory, _destinationDirectory,
- index: index);
-
- String get reproductionCommand =>
- "Copying '$_sourceDirectory' to '$_destinationDirectory'.";
-
- Future<ScriptCommandOutput> run() {
- var watch = Stopwatch()..start();
-
- var destination = io.Directory(_destinationDirectory);
-
- return destination.exists().then((bool exists) {
- Future cleanDirectoryFuture;
- if (exists) {
- cleanDirectoryFuture = TestUtils.deleteDirectory(_destinationDirectory);
- } else {
- cleanDirectoryFuture = Future.value(null);
- }
- return cleanDirectoryFuture.then((_) {
- return TestUtils.copyDirectory(_sourceDirectory, _destinationDirectory);
- });
- }).then((_) {
- return ScriptCommandOutput(this, Expectation.pass, "", watch.elapsed);
- }).catchError((error) {
- return ScriptCommandOutput(
- this, Expectation.fail, "An error occured: $error.", watch.elapsed);
- });
- }
-
- void _buildHashCode(HashCodeBuilder builder) {
- super._buildHashCode(builder);
- builder.addJson(_sourceDirectory);
- builder.addJson(_destinationDirectory);
- }
-
- bool _equal(CleanDirectoryCopyCommand other) =>
- super._equal(other) &&
- _sourceDirectory == other._sourceDirectory &&
- _destinationDirectory == other._destinationDirectory;
-}
-
-/// Makes a symbolic link to another directory.
-class MakeSymlinkCommand extends ScriptCommand {
- final String _link;
- final String _target;
-
- MakeSymlinkCommand._(this._link, this._target, {int index = 0})
- : super._('make_symlink', index: index);
-
- MakeSymlinkCommand indexedCopy(int index) =>
- MakeSymlinkCommand._(_link, _target, index: index);
-
- String get reproductionCommand =>
- "Make symbolic link '$_link' (target: $_target)'.";
-
- Future<ScriptCommandOutput> run() {
- var watch = Stopwatch()..start();
- var targetFile = io.Directory(_target);
- return targetFile.exists().then((bool targetExists) {
- if (!targetExists) {
- throw Exception("Target '$_target' does not exist");
- }
- var link = io.Link(_link);
-
- return link.exists().then((bool exists) {
- if (exists) link.deleteSync();
- }).then((_) => link.create(_target));
- }).then((_) {
- return ScriptCommandOutput(this, Expectation.pass, "", watch.elapsed);
- }).catchError((error) {
- return ScriptCommandOutput(
- this, Expectation.fail, "An error occured: $error.", watch.elapsed);
- });
- }
-
- void _buildHashCode(HashCodeBuilder builder) {
- super._buildHashCode(builder);
- builder.addJson(_link);
- builder.addJson(_target);
- }
-
- bool _equal(MakeSymlinkCommand other) =>
- super._equal(other) && _link == other._link && _target == other._target;
-}
diff --git a/pkg/test_runner/lib/src/command_output.dart b/pkg/test_runner/lib/src/command_output.dart
index 9e6d963..98f5983 100644
--- a/pkg/test_runner/lib/src/command_output.dart
+++ b/pkg/test_runner/lib/src/command_output.dart
@@ -8,7 +8,7 @@
import 'dart:io' as io;
import 'package:status_file/expectation.dart';
-import 'package:test_runner/src/test_file.dart';
+import 'package:test_runner/src/static_error.dart';
import 'browser_controller.dart';
import 'command.dart';
@@ -494,17 +494,6 @@
: super(command, exitCode, timedOut, stdout, stderr, time,
compilationSkipped, 0);
- @override
- void describe(TestCase testCase, Progress progress, OutputWriter output) {
- if (testCase.testFile.isStaticErrorTest) {
- _validateExpectedErrors(testCase, output);
- }
-
- if (!testCase.testFile.isStaticErrorTest || progress == Progress.verbose) {
- super.describe(testCase, progress, output);
- }
- }
-
Expectation result(TestCase testCase) {
// TODO(kustermann): If we run the analyzer not in batch mode, make sure
// that command.exitCodes matches 2 (errors), 1 (warnings), 0 (no warnings,
@@ -1097,50 +1086,6 @@
}
}
-CommandOutput createCommandOutput(Command command, int exitCode, bool timedOut,
- List<int> stdout, List<int> stderr, Duration time, bool compilationSkipped,
- [int pid = 0]) {
- if (command is AnalysisCommand) {
- return AnalysisCommandOutput(
- command, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
- } else if (command is CompareAnalyzerCfeCommand) {
- return CompareAnalyzerCfeCommandOutput(
- command, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
- } else if (command is SpecParseCommand) {
- return SpecParseCommandOutput(
- command, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
- } else if (command is VmCommand) {
- return VMCommandOutput(
- command, exitCode, timedOut, stdout, stderr, time, pid);
- } else if (command is VMKernelCompilationCommand) {
- return VMKernelCompilationCommandOutput(
- command, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
- } else if (command is AdbPrecompilationCommand) {
- return VMCommandOutput(
- command, exitCode, timedOut, stdout, stderr, time, pid);
- } else if (command is FastaCompilationCommand) {
- return FastaCommandOutput(
- command, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
- } else if (command is CompilationCommand) {
- if (command.displayName == 'precompiler' ||
- command.displayName == 'app_jit') {
- return VMCommandOutput(
- command, exitCode, timedOut, stdout, stderr, time, pid);
- } else if (command.displayName == 'dartdevc') {
- return DevCompilerCommandOutput(command, exitCode, timedOut, stdout,
- stderr, time, compilationSkipped, pid);
- }
- return CompilationCommandOutput(
- command, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
- } else if (command is JSCommandlineCommand) {
- return JSCommandLineOutput(
- command, exitCode, timedOut, stdout, stderr, time);
- }
-
- return CommandOutput(command, exitCode, timedOut, stdout, stderr, time,
- compilationSkipped, pid);
-}
-
/// Mixin for outputs from a command that implement a Dart front end which
/// reports static errors.
mixin _StaticErrorOutput on CommandOutput {
@@ -1174,11 +1119,18 @@
@override
void describe(TestCase testCase, Progress progress, OutputWriter output) {
- if (testCase.testFile.isStaticErrorTest) {
+ // Handle static error test output specially. We don't want to show the raw
+ // stdout if we can give the user the parsed expectations instead.
+ if (testCase.testFile.isStaticErrorTest && !hasCrashed && !hasTimedOut) {
_validateExpectedErrors(testCase, output);
}
- if (!testCase.testFile.isStaticErrorTest || progress == Progress.verbose) {
+ // Don't show the "raw" output unless something strange happened or the
+ // user explicitly requests all the output.
+ if (hasTimedOut ||
+ hasCrashed ||
+ !testCase.testFile.isStaticErrorTest ||
+ progress == Progress.verbose) {
super.describe(testCase, progress, output);
}
}
diff --git a/pkg/test_runner/lib/src/compiler_configuration.dart b/pkg/test_runner/lib/src/compiler_configuration.dart
index 7a54fce..62629db 100644
--- a/pkg/test_runner/lib/src/compiler_configuration.dart
+++ b/pkg/test_runner/lib/src/compiler_configuration.dart
@@ -36,13 +36,13 @@
bool get _isDebug => _configuration.mode.isDebug;
+ bool get _isProduct => _configuration.mode == Mode.product;
+
bool get _isHostChecked => _configuration.isHostChecked;
bool get _useSdk => _configuration.useSdk;
- bool get _useEnableAsserts => _configuration.useEnableAsserts;
-
- bool get previewDart2 => !_configuration.noPreviewDart2;
+ bool get _enableAsserts => _configuration.enableAsserts;
/// Whether to run the runtime on the compilation result of a test which
/// expects a compile-time error and the compiler did not emit one.
@@ -124,13 +124,12 @@
}
List<String> computeCompilerArguments(
- List<String> vmOptions,
- List<String> sharedOptions,
- List<String> dartOptions,
- List<String> dart2jsOptions,
- List<String> ddcOptions,
- List<String> args) {
- return [...sharedOptions, ..._configuration.sharedOptions, ...args];
+ TestFile testFile, List<String> vmOptions, List<String> args) {
+ return [
+ ...testFile.sharedOptions,
+ ..._configuration.sharedOptions,
+ ...args
+ ];
}
List<String> computeRuntimeArguments(
@@ -157,11 +156,7 @@
List<String> originalArguments,
CommandArtifact artifact) {
return [
- if (_isDebug)
- // Temporarily disable background compilation to avoid flaky crashes
- // (see http://dartbug.com/30016 for details).
- '--no-background-compilation',
- if (_useEnableAsserts) '--enable_asserts',
+ if (_enableAsserts) '--enable_asserts',
if (_configuration.hotReload)
'--hot-reload-test-mode'
else if (_configuration.hotReloadRollback)
@@ -206,14 +201,9 @@
@override
List<String> computeCompilerArguments(
- List<String> vmOptions,
- List<String> sharedOptions,
- List<String> dartOptions,
- List<String> dart2jsOptions,
- List<String> ddcOptions,
- List<String> args) {
+ TestFile testFile, List<String> vmOptions, List<String> args) {
return [
- ...sharedOptions,
+ ...testFile.sharedOptions,
..._configuration.sharedOptions,
...vmOptions,
...args
@@ -234,7 +224,7 @@
}
return [
- if (_useEnableAsserts) '--enable_asserts',
+ if (_enableAsserts) '--enable_asserts',
if (_configuration.hotReload)
'--hot-reload-test-mode'
else if (_configuration.hotReloadRollback)
@@ -327,17 +317,12 @@
}
List<String> computeCompilerArguments(
- List<String> vmOptions,
- List<String> sharedOptions,
- List<String> dartOptions,
- List<String> dart2jsOptions,
- List<String> ddcOptions,
- List<String> args) {
+ TestFile testFile, List<String> vmOptions, List<String> args) {
// The result will be passed as an input to [extractArguments]
// (i.e. the arguments to the [PipelineCommand]).
return [
...vmOptions,
- ...sharedOptions,
+ ...testFile.sharedOptions,
..._configuration.sharedOptions,
...args
];
@@ -394,7 +379,7 @@
arguments = arguments.toList();
arguments.add('--out=$outputFileName');
- return Command.compilation(moniker, outputFileName, bootstrapDependencies(),
+ return CompilationCommand(moniker, outputFileName, bootstrapDependencies(),
computeCompilerPath(), arguments, environmentOverrides,
alwaysCompile: !_useSdk);
}
@@ -417,16 +402,11 @@
: super('dart2js', configuration);
List<String> computeCompilerArguments(
- List<String> vmOptions,
- List<String> sharedOptions,
- List<String> dartOptions,
- List<String> dart2jsOptions,
- List<String> ddcOptions,
- List<String> args) {
+ TestFile testFile, List<String> vmOptions, List<String> args) {
return [
- ...sharedOptions,
+ ...testFile.sharedOptions,
..._configuration.sharedOptions,
- ...dart2jsOptions,
+ ...testFile.dart2jsOptions,
...args
];
}
@@ -474,7 +454,7 @@
uri.resolve('pkg/test_runner/lib/src/babel_transform.js').toFilePath();
var babelStandalone =
uri.resolve('third_party/babel/babel.min.js').toFilePath();
- return Command.compilation(
+ return CompilationCommand(
'babel',
output,
[],
@@ -498,16 +478,11 @@
}
List<String> computeCompilerArguments(
- List<String> vmOptions,
- List<String> sharedOptions,
- List<String> dartOptions,
- List<String> dart2jsOptions,
- List<String> ddcOptions,
- List<String> args) {
+ TestFile testFile, List<String> vmOptions, List<String> args) {
return [
- ...sharedOptions,
+ ...testFile.sharedOptions,
..._configuration.sharedOptions,
- ...ddcOptions,
+ ...testFile.ddcOptions,
// The file being compiled is the last argument.
args.last
];
@@ -581,7 +556,7 @@
var inputDir = Path(inputFile).append("..").canonicalize().toNativePath();
var displayName = useKernel ? 'dartdevk' : 'dartdevc';
- return Command.compilation(displayName, outputFile, bootstrapDependencies(),
+ return CompilationCommand(displayName, outputFile, bootstrapDependencies(),
computeCompilerPath(), args, environment,
workingDirectory: inputDir);
}
@@ -625,7 +600,7 @@
int get timeoutMultiplier {
var multiplier = 2;
if (_isDebug) multiplier *= 4;
- if (_useEnableAsserts) multiplier *= 2;
+ if (_enableAsserts) multiplier *= 2;
return multiplier;
}
@@ -675,7 +650,7 @@
args = [tempKernelFile(tempDir)];
}
- return Command.compilation('remove_kernel_file', tempDir,
+ return CompilationCommand('remove_kernel_file', tempDir,
bootstrapDependencies(), exec, args, environmentOverrides,
alwaysCompile: !_useSdk);
}
@@ -695,6 +670,8 @@
// TestConfiguration.validate().
assert(false);
}
+ } else if (_configuration.builderTag == "crossword") {
+ exec = "${buildDir}_X64/gen_snapshot";
} else {
exec = "$buildDir/gen_snapshot";
}
@@ -716,7 +693,7 @@
..._replaceDartFiles(arguments, tempKernelFile(tempDir))
];
- return Command.compilation('precompiler', tempDir, bootstrapDependencies(),
+ return CompilationCommand('precompiler', tempDir, bootstrapDependencies(),
exec, args, environmentOverrides,
alwaysCompile: !_useSdk);
}
@@ -778,7 +755,7 @@
'$tempDir/out.S'
];
- return Command.compilation('assemble', tempDir, bootstrapDependencies(), cc,
+ return CompilationCommand('assemble', tempDir, bootstrapDependencies(), cc,
args, environmentOverrides,
alwaysCompile: !_useSdk);
}
@@ -792,7 +769,7 @@
/// almost identical configurations are tested simultaneously.
Command computeRemoveAssemblyCommand(String tempDir, List arguments,
Map<String, String> environmentOverrides) {
- return Command.compilation('remove_assembly', tempDir,
+ return CompilationCommand('remove_assembly', tempDir,
bootstrapDependencies(), 'rm', ['$tempDir/out.S'], environmentOverrides,
alwaysCompile: !_useSdk);
}
@@ -807,18 +784,13 @@
}
List<String> computeCompilerArguments(
- List<String> vmOptions,
- List<String> sharedOptions,
- List<String> dartOptions,
- List<String> dart2jsOptions,
- List<String> ddcOptions,
- List<String> originalArguments) {
+ TestFile testFile, List<String> vmOptions, List<String> args) {
return [
- if (_useEnableAsserts) '--enable_asserts',
+ if (_enableAsserts) '--enable_asserts',
...filterVmOptions(vmOptions),
- ...sharedOptions,
+ ...testFile.sharedOptions,
..._configuration.sharedOptions,
- ...originalArguments
+ ...args
];
}
@@ -838,7 +810,7 @@
_replaceDartFiles(originalArguments, "$dir/out.aotsnapshot");
return [
- if (_useEnableAsserts) '--enable_asserts',
+ if (_enableAsserts) '--enable_asserts',
...vmOptions,
...testFile.sharedOptions,
..._configuration.sharedOptions,
@@ -855,7 +827,7 @@
int get timeoutMultiplier {
var multiplier = 1;
if (_isDebug) multiplier *= 2;
- if (_useEnableAsserts) multiplier *= 2;
+ if (_enableAsserts) multiplier *= 2;
return multiplier;
}
@@ -871,7 +843,7 @@
Command computeCompilationCommand(String tempDir, List<String> arguments,
Map<String, String> environmentOverrides) {
var snapshot = "$tempDir/out.jitsnapshot";
- return Command.compilation(
+ return CompilationCommand(
'app_jit',
tempDir,
bootstrapDependencies(),
@@ -882,19 +854,14 @@
}
List<String> computeCompilerArguments(
- List<String> vmOptions,
- List<String> sharedOptions,
- List<String> dartOptions,
- List<String> dart2jsOptions,
- List<String> ddcOptions,
- List<String> originalArguments) {
+ TestFile testFile, List<String> vmOptions, List<String> args) {
return [
- if (_useEnableAsserts) '--enable_asserts',
+ if (_enableAsserts) '--enable_asserts',
...vmOptions,
- ...sharedOptions,
+ ...testFile.sharedOptions,
..._configuration.sharedOptions,
- ...originalArguments,
- ...dartOptions
+ ...args,
+ ...testFile.dartOptions
];
}
@@ -905,7 +872,7 @@
List<String> originalArguments,
CommandArtifact artifact) {
return [
- if (_useEnableAsserts) '--enable_asserts',
+ if (_enableAsserts) '--enable_asserts',
...vmOptions,
...testFile.sharedOptions,
..._configuration.sharedOptions,
@@ -941,10 +908,6 @@
CommandArtifact computeCompilationArtifact(String tempDir,
List<String> arguments, Map<String, String> environmentOverrides) {
- if (!previewDart2) {
- throw ArgumentError('--no-preview-dart-2 not supported');
- }
-
var args = [
...arguments,
if (_configuration.useAnalyzerCfe) '--use-cfe',
@@ -953,7 +916,7 @@
// Since this is not a real compilation, no artifacts are produced.
return CommandArtifact(
- [Command.analysis(computeCompilerPath(), args, environmentOverrides)],
+ [AnalysisCommand(computeCompilerPath(), args, environmentOverrides)],
null,
null);
}
@@ -985,13 +948,9 @@
CommandArtifact computeCompilationArtifact(String tempDir,
List<String> arguments, Map<String, String> environmentOverrides) {
- if (!previewDart2) {
- throw ArgumentError('--no-preview-dart-2 not supported');
- }
-
// Since this is not a real compilation, no artifacts are produced.
return CommandArtifact([
- Command.compareAnalyzerCfe(
+ CompareAnalyzerCfeCommand(
computeCompilerPath(), arguments.toList(), environmentOverrides)
], null, null);
}
@@ -1019,7 +978,7 @@
// Since this is not a real compilation, no artifacts are produced.
return CommandArtifact([
- Command.specParse(computeCompilerPath(), arguments, environmentOverrides)
+ SpecParseCommand(computeCompilerPath(), arguments, environmentOverrides)
], null, null);
}
@@ -1041,9 +1000,11 @@
bool get _useSdk;
+ bool get _isProduct;
+
bool get _isAot;
- bool get _useEnableAsserts;
+ bool get _enableAsserts;
List<Uri> bootstrapDependencies();
@@ -1084,21 +1045,22 @@
name.startsWith('--packages=') ||
name.startsWith('--enable-experiment=')),
'-Ddart.developer.causal_async_stacks=$causalAsyncStacks',
- if (_useEnableAsserts ||
+ if (_enableAsserts ||
arguments.contains('--enable-asserts') ||
arguments.contains('--enable_asserts'))
'--enable-asserts',
if (_configuration.useKernelBytecode) ...[
'--gen-bytecode',
'--drop-ast',
- '--bytecode-options=source-positions,local-var-info'
+ '--bytecode-options=source-positions${_isProduct ? '' : ',local-var-info,debugger-stops'}'
]
];
var batchArgs = [if (useAbiVersion != null) useAbiVersion];
- return Command.vmKernelCompilation(dillFile, true, bootstrapDependencies(),
- genKernel, args, environmentOverrides, batchArgs);
+ return VMKernelCompilationCommand(dillFile, bootstrapDependencies(),
+ genKernel, args, environmentOverrides, batchArgs,
+ alwaysCompile: true);
}
}
@@ -1110,8 +1072,6 @@
final Uri _vmExecutable;
- bool get _isLegacy => _configuration.noPreviewDart2;
-
factory FastaCompilerConfiguration(TestConfiguration configuration) {
var buildDirectory =
Uri.base.resolveUri(Uri.directory(configuration.buildDirectory));
@@ -1121,8 +1081,7 @@
dillDir = buildDirectory.resolve("dart-sdk/lib/_internal/");
}
- var suffix = !configuration.noPreviewDart2 ? "_strong" : "";
- var platformDill = dillDir.resolve("vm_platform$suffix.dill");
+ var platformDill = dillDir.resolve("vm_platform_strong.dill");
var vmExecutable = buildDirectory
.resolve(configuration.useSdk ? "dart-sdk/bin/dart" : "dart");
@@ -1149,7 +1108,6 @@
var compilerArguments = [
'--verify',
- if (_isLegacy) "--legacy-mode",
"-o",
outputFileName,
"--platform",
@@ -1158,26 +1116,24 @@
];
return CommandArtifact([
- Command.fasta(
+ FastaCompilationCommand(
_compilerLocation,
- output,
+ output.toFilePath(),
bootstrapDependencies(),
- _vmExecutable,
+ _vmExecutable.toFilePath(),
compilerArguments,
environmentOverrides,
- Repository.uri)
+ Repository.uri.toFilePath())
], outputFileName, "application/x.dill");
}
@override
List<String> computeCompilerArguments(
- List<String> vmOptions,
- List<String> sharedOptions,
- List<String> dartOptions,
- List<String> dart2jsOptions,
- List<String> ddcOptions,
- List<String> args) {
- var arguments = [...sharedOptions, ..._configuration.sharedOptions];
+ TestFile testFile, List<String> vmOptions, List<String> args) {
+ var arguments = [
+ ...testFile.sharedOptions,
+ ..._configuration.sharedOptions
+ ];
for (var argument in args) {
if (argument == "--ignore-unrecognized-flags") continue;
arguments.add(argument);
diff --git a/pkg/test_runner/lib/src/configuration.dart b/pkg/test_runner/lib/src/configuration.dart
index da4bfbc..47dfdae 100644
--- a/pkg/test_runner/lib/src/configuration.dart
+++ b/pkg/test_runner/lib/src/configuration.dart
@@ -104,6 +104,7 @@
Mode get mode => configuration.mode;
Runtime get runtime => configuration.runtime;
System get system => configuration.system;
+ NnbdMode get nnbdMode => configuration.nnbdMode;
// Boolean getters
bool get hotReload => configuration.useHotReload;
@@ -112,13 +113,12 @@
bool get isHostChecked => configuration.isHostChecked;
bool get isCsp => configuration.isCsp;
bool get isMinified => configuration.isMinified;
- bool get noPreviewDart2 => !configuration.previewDart2;
bool get useAnalyzerCfe => configuration.useAnalyzerCfe;
bool get useAnalyzerFastaParser => configuration.useAnalyzerFastaParser;
bool get useBlobs => configuration.useBlobs;
bool get useElf => configuration.useElf;
bool get useSdk => configuration.useSdk;
- bool get useEnableAsserts => configuration.enableAsserts;
+ bool get enableAsserts => configuration.enableAsserts;
// Various file paths.
@@ -149,6 +149,17 @@
/// Extra VM options passed to the testing script.
List<String> get vmOptions => configuration.vmOptions;
+ /// The names of the experiments to enable while running tests.
+ ///
+ /// A test may *require* an experiment to always be enabled by containing a
+ /// comment like:
+ ///
+ /// // SharedOptions=--enable-experiment=extension-methods
+ ///
+ /// Enabling an experiment here in the configuration allows running the same
+ /// test both with an experiment on and off.
+ List<String> get experiments => configuration.experiments;
+
/// Extra general options passed to the testing script.
final List<String> sharedOptions;
@@ -244,7 +255,7 @@
if (isMinified) args.add("--minify");
if (isCsp) args.add("--csp");
- if (useEnableAsserts) args.add("--enable-asserts");
+ if (enableAsserts) args.add("--enable-asserts");
return args;
}
@@ -438,42 +449,6 @@
return normal;
}
-
- Map _summaryMap;
-
- /// [toSummaryMap] returns a map of configurations important to the running
- /// of a test. Flags and properties used for output are not included.
- /// The summary map can be used to serialize to json for test-output logging.
- Map toSummaryMap() {
- return _summaryMap ??= {
- 'mode': mode.name,
- 'arch': architecture.name,
- 'compiler': compiler.name,
- 'runtime': runtime.name,
- 'checked': isChecked,
- 'host_checked': isHostChecked,
- 'minified': isMinified,
- 'csp': isCsp,
- 'system': system.name,
- 'vm_options': vmOptions,
- 'dart2js_options': dart2jsOptions,
- 'fasta': usesFasta,
- 'use_sdk': useSdk,
- 'builder_tag': builderTag,
- 'timeout': timeout,
- 'no_preview_dart_2': noPreviewDart2,
- 'use_cfe': useAnalyzerCfe,
- 'analyzer_use_fasta_parser': useAnalyzerFastaParser,
- 'enable_asserts': useEnableAsserts,
- 'hot_reload': hotReload,
- 'hot_reload_rollback': hotReloadRollback,
- 'batch': batch,
- 'batch_dart2js': batchDart2JS,
- 'reset_browser_configuration': resetBrowser,
- 'selectors': selectors.keys.toList(),
- 'use_kernel_bytecode': useKernelBytecode,
- };
- }
}
class Progress {
diff --git a/pkg/test_runner/lib/src/environment.dart b/pkg/test_runner/lib/src/environment.dart
index b028db0..f012f12 100644
--- a/pkg/test_runner/lib/src/environment.dart
+++ b/pkg/test_runner/lib/src/environment.dart
@@ -20,7 +20,7 @@
"checked": _Variable.bool((c) => c.isChecked),
"compiler": _Variable((c) => c.compiler.name, Compiler.names),
"csp": _Variable.bool((c) => c.isCsp),
- "enable_asserts": _Variable.bool((c) => c.useEnableAsserts),
+ "enable_asserts": _Variable.bool((c) => c.enableAsserts),
"fasta": _Variable.bool((c) => c.usesFasta),
"host_checked": _Variable.bool((c) => c.isHostChecked),
"host_unchecked": _Variable.bool((c) => !c.isHostChecked),
@@ -30,11 +30,8 @@
"jscl": _Variable.bool((c) => c.runtime.isJSCommandLine),
"minified": _Variable.bool((c) => c.isMinified),
"mode": _Variable((c) => c.mode.name, Mode.names),
- "no_preview_dart_2": _Variable.bool((c) => c.noPreviewDart2),
- "preview_dart_2": _Variable.bool((c) => !c.noPreviewDart2),
"runtime": _Variable(_runtimeName, _runtimeNames),
"spec_parser": _Variable.bool((c) => c.compiler == Compiler.specParser),
- "strong": _Variable.bool((c) => !c.noPreviewDart2),
"system": _Variable(_systemName, _systemNames),
"use_sdk": _Variable.bool((c) => c.useSdk)
};
diff --git a/pkg/test_runner/lib/src/options.dart b/pkg/test_runner/lib/src/options.dart
index c819037..9de4b81 100644
--- a/pkg/test_runner/lib/src/options.dart
+++ b/pkg/test_runner/lib/src/options.dart
@@ -164,9 +164,6 @@
'Only run tests that are not marked `Slow` or `Timeout`.'),
_Option.bool('enable_asserts',
'Pass the --enable-asserts flag to dart2js or to the vm.'),
- _Option.bool('no_preview_dart_2',
- 'Enable legacy Dart 1 behavior for some runtimes and compilers.',
- hide: true),
_Option.bool('use_cfe', 'Pass the --use-cfe flag to analyzer', hide: true),
_Option.bool('analyzer_use_fasta_parser',
'Pass the --use-fasta-parser flag to analyzer',
@@ -233,6 +230,9 @@
_Option('chrome', 'Path to chrome browser executable.', hide: true),
_Option('safari', 'Path to safari browser executable.', hide: true),
_Option.bool('use_sdk', '''Use compiler or runtime from the SDK.'''),
+ _Option.bool('nnbd', '''Opt tests into non-nullable types.'''),
+ _Option.bool('nnbd_strong_checking',
+ '''Enable strong runtime checks of non-nullable types.'''),
// TODO(rnystrom): This does not appear to be used. Remove?
_Option('build_directory',
'The name of the build directory, where products are placed.',
@@ -284,9 +284,9 @@
_Option.int(
'test_driver_error_port', 'Port for http test driver server errors.',
defaultsTo: 0, hide: true),
- _Option('test_list', 'File containing a list of tests to be executed',
+ _Option('test_list', 'File containing a list of tests to be executed.',
hide: true),
- _Option('tests', 'A newline separated list of tests to be executed'),
+ _Option('tests', 'A newline separated list of tests to be executed.'),
_Option(
'builder_tag',
'''Machine specific options that is not captured by the regular test
@@ -297,6 +297,7 @@
_Option('dart2js_options', 'Extra options for dart2js compilation step.',
hide: true),
_Option('shared_options', 'Extra shared options.', hide: true),
+ _Option('experiments', 'Experiment flags to enable.'),
_Option(
'babel',
'''Transforms dart2js output with Babel. The value must be
@@ -380,9 +381,9 @@
return null;
}
if (arguments.contains("--list-configurations")) {
- final testMatrixFile = "tools/bots/test_matrix.json";
- TestMatrix testMatrix = TestMatrix.fromPath(testMatrixFile);
- for (final configuration in testMatrix.configurations
+ var testMatrixFile = "tools/bots/test_matrix.json";
+ var testMatrix = TestMatrix.fromPath(testMatrixFile);
+ for (var configuration in testMatrix.configurations
.map((configuration) => configuration.name)
.toList()
..sort()) {
@@ -390,10 +391,6 @@
}
return null;
}
- // Dart1 mode has been deprecated.
- if (arguments.contains("--no-preview-dart-2")) {
- return null;
- }
var configuration = <String, dynamic>{};
@@ -616,6 +613,7 @@
var dart2jsOptions = listOption("dart2js_options");
var vmOptions = listOption("vm_options");
var sharedOptions = listOption("shared_options");
+ var experiments = listOption("experiments");
// JSON reporting implies listing and reporting.
if (data['report_in_json'] as bool) {
@@ -697,9 +695,9 @@
isMinified: data["minified"] as bool,
vmOptions: vmOptions,
dart2jsOptions: dart2jsOptions,
+ experiments: experiments,
babel: data['babel'] as String,
- builderTag: data["builder_tag"] as String,
- previewDart2: true);
+ builderTag: data["builder_tag"] as String);
var configuration = TestConfiguration(
configuration: innerConfiguration,
progress: Progress.find(data["progress"] as String),
diff --git a/pkg/test_runner/lib/src/process_queue.dart b/pkg/test_runner/lib/src/process_queue.dart
index 8e660b0..72ab4c2 100644
--- a/pkg/test_runner/lib/src/process_queue.dart
+++ b/pkg/test_runner/lib/src/process_queue.dart
@@ -500,7 +500,7 @@
Future cleanup();
// TODO(kustermann): The [timeout] parameter should be a property of Command.
Future<CommandOutput> runCommand(
- Node<Command> node, covariant Command command, int timeout);
+ Node<Command> node, Command command, int timeout);
}
class CommandExecutorImpl implements CommandExecutor {
@@ -605,7 +605,7 @@
adbDevicePool.releaseDevice(device);
}
});
- } else if (command is VmBatchCommand) {
+ } else if (command is VMBatchCommand) {
var name = command.displayName;
return _getBatchRunner(command.displayName + command.dartFile)
.runCommand(name, command, timeout, command.arguments);
@@ -713,7 +713,7 @@
// immediately.
if (result.exitCode != 0) break;
}
- return createCommandOutput(command, result.exitCode, result.timedOut,
+ return command.createOutput(result.exitCode, result.timedOut,
utf8.encode('$writer'), [], stopwatch.elapsed, false);
}
@@ -773,7 +773,7 @@
// immediately.
if (result.exitCode != 0) break;
}
- return createCommandOutput(command, result.exitCode, result.timedOut,
+ return command.createOutput(result.exitCode, result.timedOut,
utf8.encode('$writer'), [], stopwatch.elapsed, false);
}
@@ -1009,7 +1009,7 @@
_arguments = arguments;
_processEnvironmentOverrides = command.environmentOverrides;
- // TOOD(jmesserly): this restarts `dartdevc --batch` to work around a
+ // TODO(jmesserly): this restarts `dartdevc --batch` to work around a
// memory leak, see https://github.com/dart-lang/sdk/issues/30314.
var clearMemoryLeak = command is CompilationCommand &&
command.displayName == 'dartdevc' &&
@@ -1085,8 +1085,7 @@
if (outcome == "CRASH") exitCode = unhandledCompilerExceptionExitCode;
if (outcome == "PARSE_FAIL") exitCode = parseFailExitCode;
if (outcome == "FAIL" || outcome == "TIMEOUT") exitCode = 1;
- var output = createCommandOutput(
- _command,
+ var output = _command.createOutput(
exitCode,
outcome == "TIMEOUT",
_testStdout.toList(),
diff --git a/pkg/test_runner/lib/src/runtime_configuration.dart b/pkg/test_runner/lib/src/runtime_configuration.dart
index 9bcff67..04f4629 100644
--- a/pkg/test_runner/lib/src/runtime_configuration.dart
+++ b/pkg/test_runner/lib/src/runtime_configuration.dart
@@ -187,8 +187,7 @@
// TODO(ahe): Avoid duplication of this method between d8 and jsshell.
checkArtifact(artifact);
return [
- Command.jsCommandLine(
- moniker, d8FileName, arguments, environmentOverrides)
+ JSCommandLineCommand(moniker, d8FileName, arguments, environmentOverrides)
];
}
@@ -209,7 +208,7 @@
bool isCrashExpected) {
checkArtifact(artifact);
return [
- Command.jsCommandLine(
+ JSCommandLineCommand(
moniker, jsShellFileName, arguments, environmentOverrides)
];
}
@@ -282,7 +281,7 @@
if (type == 'application/kernel-ir-fully-linked') {
executable = dartVmExecutableFileName;
}
- return [Command.vm(executable, arguments, environmentOverrides)];
+ return [VMCommand(executable, arguments, environmentOverrides)];
}
}
@@ -306,7 +305,7 @@
}
return [
- Command.vm(dartPrecompiledBinaryFileName, arguments, environmentOverrides)
+ VMCommand(dartPrecompiledBinaryFileName, arguments, environmentOverrides)
];
}
}
@@ -330,7 +329,7 @@
final String buildPath = buildDir;
final String processTest = processTestBinaryFileName;
return [
- Command.adbDartk(buildPath, processTest, script, arguments, extraLibs)
+ AdbDartkCommand(buildPath, processTest, script, arguments, extraLibs)
];
}
}
@@ -361,7 +360,7 @@
String processTest = processTestBinaryFileName;
return [
- Command.adbPrecompiled(
+ AdbPrecompilationCommand(
buildDir, processTest, script, arguments, useBlobs, useElf, extraLibs)
];
}
@@ -391,7 +390,7 @@
bool isCrashExpected) {
String executable = dartVmBinaryFileName;
return selfCheckers
- .map((String tester) => Command.vmBatch(
+ .map((String tester) => VMBatchCommand(
executable, tester, arguments, environmentOverrides,
checked: _configuration.isChecked))
.toList();
diff --git a/pkg/test_runner/lib/src/static_error.dart b/pkg/test_runner/lib/src/static_error.dart
new file mode 100644
index 0000000..518d91b
--- /dev/null
+++ b/pkg/test_runner/lib/src/static_error.dart
@@ -0,0 +1,508 @@
+// Copyright (c) 2019, 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.
+
+/// Describes a static error.
+///
+/// These can be parsed from comments in [TestFile]s, in which case they
+/// represent *expected* errors. If a test contains any of these, then it is a
+/// "static error test" and exists to validate that a conforming front end
+/// produces the expected compile-time errors.
+///
+/// Aside from location, there are two interesting attributes of an error that
+/// a test can verify: its error code and the error message. Currently, for
+/// analyzer we only care about the error code. The CFE does not report an
+/// error code and only reports a message. So this class takes advantage of
+/// that by allowing you to set expectations for analyzer and CFE independently
+/// by assuming the [code] field is only used for the former and the [message]
+/// for the latter.
+///
+/// This same class is also used for *reported* errors when parsing the output
+/// of a front end.
+class StaticError implements Comparable<StaticError> {
+ static const _unspecified = "unspecified";
+
+ /// Parses the set of static error expectations defined in the Dart source
+ /// file [source].
+ static List<StaticError> parseExpectations(String source) =>
+ _ErrorExpectationParser(source)._parse();
+
+ /// Collapses overlapping [errors] into a shorter list of errors where
+ /// possible.
+ ///
+ /// Two errors on the same location can be collapsed if one has an error code
+ /// but no message and the other has a message but no code.
+ static List<StaticError> simplify(List<StaticError> errors) {
+ var result = errors.toList();
+ result.sort();
+
+ for (var i = 0; i < result.length - 1; i++) {
+ var a = result[i];
+
+ // Look for a later error we can merge with this one. Usually, it will be
+ // adjacent to this one, but if there are multiple errors with no length
+ // on the same location, those will all be next to each other and their
+ // merge targets will come later. This happens when CFE reports multiple
+ // errors at the same location (messages but no length) and analyzer does
+ // too (codes and lengths but no messages).
+ for (var j = i + 1; j < result.length; j++) {
+ var b = result[j];
+
+ // Position must be the same. If the position is different, we can
+ // stop looking because all same-position errors will be adjacent.
+ if (a.line != b.line) break;
+ if (a.column != b.column) break;
+
+ // If they both have lengths that are different, we can't discard that
+ // information.
+ if (a.length != null && b.length != null && a.length != b.length) {
+ continue;
+ }
+
+ // Can't discard content.
+ if (a.code != null && b.code != null) continue;
+ if (a.message != null && b.message != null) continue;
+
+ result[i] = StaticError(
+ line: a.line,
+ column: a.column,
+ length: a.length ?? b.length,
+ code: a.code ?? b.code,
+ message: a.message ?? b.message);
+ result.removeAt(j);
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ /// Determines whether all [actualErrors] match the given [expectedErrors].
+ ///
+ /// If they match, returns `null`. Otherwise returns a string describing the
+ /// mismatches. This for a human-friendly explanation of the difference
+ /// between the two sets of errors, while also being simple to implement.
+ /// An expected error that is completely identical to an actual error is
+ /// treated as a match. Everything else is a failure.
+ ///
+ /// It treats line number as the "identity" of an error. So if there are two
+ /// errors on the same line that differ in other properties, it reports that
+ /// as a "wrong" error. Any expected error on a line containing no actual
+ /// error is reported as a "missing" error. Conversely, an actual error on a
+ /// line containing no expected error is an "unexpected" error.
+ ///
+ /// By not treating the error's index in the list to be its identity, we
+ /// gracefully handle extra or missing errors without causing cascading
+ /// failures for later errors in the lists.
+ static String validateExpectations(Iterable<StaticError> expectedErrors,
+ Iterable<StaticError> actualErrors) {
+ // Don't require the test or front end to output in any specific order.
+ var sortedExpected = expectedErrors.toList();
+ var sortedActual = actualErrors.toList();
+ sortedExpected.sort();
+ sortedActual.sort();
+
+ var buffer = StringBuffer();
+
+ describeError(String adjective, StaticError error, String verb) {
+ buffer.writeln("$adjective static error at ${error.location}:");
+ if (error.code == _unspecified) {
+ buffer.writeln("- $verb unspecified error code.");
+ } else if (error.code != null) {
+ buffer.writeln("- $verb error code ${error.code}.");
+ }
+
+ if (error.message == _unspecified) {
+ buffer.writeln("- $verb unspecified error message.");
+ } else if (error.message != null) {
+ buffer.writeln("- $verb error message '${error.message}'.");
+ }
+ buffer.writeln();
+ }
+
+ var expectedIndex = 0;
+ var actualIndex = 0;
+ for (;
+ expectedIndex < sortedExpected.length &&
+ actualIndex < sortedActual.length;) {
+ var expected = sortedExpected[expectedIndex];
+ var actual = sortedActual[actualIndex];
+ var differences = expected.describeDifferences(actual);
+ if (differences == null) {
+ expectedIndex++;
+ actualIndex++;
+ continue;
+ }
+
+ if (expected.line == actual.line) {
+ buffer.writeln("Wrong static error at ${expected.location}:");
+ for (var difference in differences) {
+ buffer.writeln("- $difference");
+ }
+ buffer.writeln();
+ expectedIndex++;
+ actualIndex++;
+ } else if (expected.line < actual.line) {
+ describeError("Missing", expected, "Expected");
+ expectedIndex++;
+ } else {
+ describeError("Unexpected", actual, "Had");
+ actualIndex++;
+ }
+ }
+
+ // Output any trailing expected or actual errors if the lengths of the
+ // lists differ.
+ for (; expectedIndex < sortedExpected.length; expectedIndex++) {
+ describeError("Missing", sortedExpected[expectedIndex], "Expected");
+ }
+
+ for (; actualIndex < sortedActual.length; actualIndex++) {
+ describeError("Unexpected", sortedActual[actualIndex], "Had");
+ }
+
+ if (buffer.isEmpty) return null;
+ return buffer.toString().trimRight();
+ }
+
+ /// The one-based line number of the beginning of the error's location.
+ final int line;
+
+ /// The one-based column number of the beginning of the error's location.
+ final int column;
+
+ /// The number of characters in the error location.
+ ///
+ /// This is optional. The CFE only reports error location, but not length.
+ final int length;
+
+ /// The expected analyzer error code for the error or `null` if this error
+ /// isn't expected to be reported by analyzer.
+ final String code;
+
+ /// The expected CFE error message or `null` if this error isn't expected to
+ /// be reported by the CFE.
+ final String message;
+
+ /// The zero-based index of the first line in the [TestFile] containing the
+ /// marker comments that define this error.
+ ///
+ /// If this error was not parsed from a file, this may be `null`.
+ final int markerStartLine;
+
+ /// The zero-based index of the last line in the [TestFile] containing the
+ /// marker comments that define this error, inclusive.
+ ///
+ /// If this error was not parsed from a file, this may be `null`.
+ final int markerEndLine;
+
+ /// Creates a new StaticError at the given location with the given expected
+ /// error code and message.
+ ///
+ /// In order to make it easier to incrementally add error tests before a
+ /// feature is fully implemented or specified, an error expectation can be in
+ /// an "unspecified" state for either or both platforms by having the error
+ /// code or message be the special string "unspecified". When an unspecified
+ /// error is tested, a front end is expected to report *some* error on that
+ /// error's line, but it can be any location, error code, or message.
+ StaticError(
+ {this.line,
+ this.column,
+ this.length,
+ this.code,
+ this.message,
+ this.markerStartLine,
+ this.markerEndLine}) {
+ // Must have a location.
+ assert(line != null);
+ assert(column != null);
+
+ // Must have at least one piece of description.
+ assert(code != null || message != null);
+ }
+
+ /// Whether this error should be reported by analyzer.
+ bool get isAnalyzer => code != null;
+
+ /// Whether this error should be reported by the CFE.
+ bool get isCfe => message != null;
+
+ /// A textual description of this error's location.
+ String get location {
+ var result = "line $line, column $column";
+ if (length != null) result += ", length $length";
+ return result;
+ }
+
+ String toString() {
+ var result = "Error at $location";
+ if (code != null) result += "\n$code";
+ if (message != null) result += "\n$message";
+ return result;
+ }
+
+ /// Orders errors primarily by location, then by other fields if needed.
+ @override
+ int compareTo(StaticError other) {
+ if (line != other.line) return line.compareTo(other.line);
+ if (column != other.column) return column.compareTo(other.column);
+
+ // Sort no length after all other lengths.
+ if (length == null && other.length != null) return 1;
+ if (length != null && other.length == null) return -1;
+ if (length != other.length) return length.compareTo(other.length);
+
+ var thisCode = code ?? "";
+ var otherCode = other.code ?? "";
+ if (thisCode != otherCode) return thisCode.compareTo(otherCode);
+
+ var thisMessage = message ?? "";
+ var otherMessage = other.message ?? "";
+ return thisMessage.compareTo(otherMessage);
+ }
+
+ /// Compares this error expectation to [actual].
+ ///
+ /// If this error correctly matches [actual], returns `null`. Otherwise
+ /// returns a list of strings describing the mismatch.
+ ///
+ /// Note that this does *not* check to see that [actual] matches the platforms
+ /// that this error expects. For example, if [actual] only reports an error
+ /// code (i.e. it is analyzer-only) and this error only specifies an error
+ /// message (i.e. it is CFE-only), this will still report differences in
+ /// location information. This method expects that error expectations have
+ /// already been filtered by platform so this will only be called in cases
+ /// where the platforms do match.
+ List<String> describeDifferences(StaticError actual) {
+ var differences = <String>[];
+
+ if (line != actual.line) {
+ differences.add("Expected on line $line but was on ${actual.line}.");
+ }
+
+ // If the error is unspecified on the front end being tested, the column
+ // and length can be any values.
+ var requirePreciseLocation = code != _unspecified && actual.isAnalyzer ||
+ message != _unspecified && actual.isCfe;
+ if (requirePreciseLocation) {
+ if (column != actual.column) {
+ differences
+ .add("Expected on column $column but was on ${actual.column}.");
+ }
+
+ // This error represents an expectation, so should have a length.
+ assert(length != null);
+ if (actual.length != null && length != actual.length) {
+ differences.add("Expected length $length but was ${actual.length}.");
+ }
+ }
+
+ if (code != null &&
+ code != _unspecified &&
+ actual.code != null &&
+ code != actual.code) {
+ differences.add("Expected error code $code but was ${actual.code}.");
+ }
+
+ if (message != null &&
+ message != _unspecified &&
+ actual.message != null &&
+ message != actual.message) {
+ differences.add(
+ "Expected error message '$message' but was '${actual.message}'.");
+ }
+
+ if (differences.isNotEmpty) return differences;
+ return null;
+ }
+}
+
+class _ErrorExpectationParser {
+ /// Marks the location of an expected error, like so:
+ ///
+ /// int i = "s";
+ /// // ^^^
+ ///
+ /// We look for a line that starts with a line comment followed by spaces and
+ /// carets.
+ static final _caretLocationRegExp = RegExp(r"^\s*//\s*(\^+)\s*$");
+
+ /// Matches an explicit error location with a length, like:
+ ///
+ /// // [error line 1, column 17, length 3]
+ static final _explicitLocationAndLengthRegExp =
+ RegExp(r"^\s*//\s*\[\s*error line\s+(\d+)\s*,\s*column\s+(\d+)\s*,\s*"
+ r"length\s+(\d+)\s*\]\s*$");
+
+ /// Matches an explicit error location without a length, like:
+ ///
+ /// // [error line 1, column 17]
+ static final _explicitLocationRegExp =
+ RegExp(r"^\s*//\s*\[\s*error line\s+(\d+)\s*,\s*column\s+(\d+)\s*\]\s*$");
+
+ /// An analyzer error expectation starts with `// [analyzer]`.
+ static final _analyzerErrorRegExp = RegExp(r"^\s*// \[analyzer\]\s*(.*)");
+
+ /// An analyzer error code is a dotted identifier or the magic string
+ /// "unspecified".
+ static final _errorCodeRegExp = RegExp(r"^\w+\.\w+|unspecified$");
+
+ /// The first line of a CFE error expectation starts with `// [cfe]`.
+ static final _cfeErrorRegExp = RegExp(r"^\s*// \[cfe\]\s*(.*)");
+
+ /// Any line-comment-only lines after the first line of a CFE error message
+ /// are part of it.
+ static final _errorMessageRestRegExp = RegExp(r"^\s*//\s*(.*)");
+
+ /// Matches the multitest marker and yields the preceding content.
+ final _stripMultitestRegExp = RegExp(r"(.*)//#");
+
+ final List<String> _lines;
+ final List<StaticError> _errors = [];
+ int _currentLine = 0;
+
+ // One-based index of the last line that wasn't part of an error expectation.
+ int _lastRealLine = -1;
+
+ _ErrorExpectationParser(String source) : _lines = source.split("\n");
+
+ List<StaticError> _parse() {
+ while (!_isAtEnd) {
+ var sourceLine = _peek(0);
+
+ var match = _caretLocationRegExp.firstMatch(sourceLine);
+ if (match != null) {
+ if (_lastRealLine == -1) {
+ _fail("An error expectation must follow some code.");
+ }
+
+ _parseErrorDetails(
+ line: _lastRealLine,
+ column: sourceLine.indexOf("^") + 1,
+ length: match.group(1).length);
+ _advance();
+ continue;
+ }
+
+ match = _explicitLocationAndLengthRegExp.firstMatch(sourceLine);
+ if (match != null) {
+ _parseErrorDetails(
+ line: int.parse(match.group(1)),
+ column: int.parse(match.group(2)),
+ length: int.parse(match.group(3)));
+ _advance();
+ continue;
+ }
+
+ match = _explicitLocationRegExp.firstMatch(sourceLine);
+ if (match != null) {
+ _parseErrorDetails(
+ line: int.parse(match.group(1)), column: int.parse(match.group(2)));
+ _advance();
+ continue;
+ }
+
+ _lastRealLine = _currentLine + 1;
+ _advance();
+ }
+
+ return _errors;
+ }
+
+ /// Finishes parsing an error expectation after parsing the location.
+ void _parseErrorDetails({int line, int column, int length}) {
+ String code;
+ String message;
+
+ var startLine = _currentLine;
+
+ // Look for an error code line.
+ if (!_isAtEnd) {
+ var match = _analyzerErrorRegExp.firstMatch(_peek(1));
+ if (match != null) {
+ code = match.group(1);
+
+ if (!_errorCodeRegExp.hasMatch(code)) {
+ _fail("An analyzer error expectation should be a dotted identifier.");
+ }
+
+ _advance();
+ }
+ }
+
+ // Look for an error message.
+ if (!_isAtEnd) {
+ var match = _cfeErrorRegExp.firstMatch(_peek(1));
+ if (match != null) {
+ message = match.group(1);
+ _advance();
+
+ // Consume as many additional error message lines as we find.
+ while (!_isAtEnd) {
+ var nextLine = _peek(1);
+
+ // A location line shouldn't be treated as a message.
+ if (_caretLocationRegExp.hasMatch(nextLine)) break;
+ if (_explicitLocationAndLengthRegExp.hasMatch(nextLine)) break;
+ if (_explicitLocationRegExp.hasMatch(nextLine)) break;
+
+ // Don't let users arbitrarily order the error code and message.
+ if (_analyzerErrorRegExp.hasMatch(nextLine)) {
+ _fail("An analyzer expectation must come before a CFE "
+ "expectation.");
+ }
+
+ var messageMatch = _errorMessageRestRegExp.firstMatch(nextLine);
+ if (messageMatch == null) break;
+
+ message += "\n" + messageMatch.group(1);
+ _advance();
+ }
+ }
+ }
+
+ if (code == null && message == null) {
+ _fail("An error expectation must specify at least an analyzer or CFE "
+ "error.");
+ }
+
+ // Hack: If the error is CFE-only and the length is one, treat it as no
+ // length. The CFE does not output length information, and when the update
+ // tool writes a CFE-only error, it implicitly uses a length of one. Thus,
+ // when we parse back in a length one CFE error, we ignore the length so
+ // that the error round-trips correctly.
+ // TODO(rnystrom): Stop doing this when the CFE reports error lengths.
+ if (code == null && length == 1) length = null;
+
+ _errors.add(StaticError(
+ line: line,
+ column: column,
+ length: length,
+ code: code,
+ message: message,
+ markerStartLine: startLine,
+ markerEndLine: _currentLine));
+ }
+
+ bool get _isAtEnd => _currentLine >= _lines.length;
+
+ void _advance() {
+ _currentLine++;
+ }
+
+ String _peek(int offset) {
+ var line = _lines[_currentLine + offset];
+
+ // Strip off any multitest marker.
+ var multitestMatch = _stripMultitestRegExp.firstMatch(line);
+ if (multitestMatch != null) {
+ line = multitestMatch.group(1).trimRight();
+ }
+
+ return line;
+ }
+
+ void _fail(String message) {
+ throw FormatException("Test error on line ${_currentLine + 1}: $message");
+ }
+}
diff --git a/pkg/test_runner/lib/src/test_case.dart b/pkg/test_runner/lib/src/test_case.dart
index 131ae7b..4e7e080 100644
--- a/pkg/test_runner/lib/src/test_case.dart
+++ b/pkg/test_runner/lib/src/test_case.dart
@@ -384,8 +384,7 @@
exitCode = nonUtfFakeExitCode;
}
}
- var commandOutput = createCommandOutput(
- command,
+ var commandOutput = command.createOutput(
exitCode,
timedOut,
stdoutData,
diff --git a/pkg/test_runner/lib/src/test_file.dart b/pkg/test_runner/lib/src/test_file.dart
index d60e708..f24719a 100644
--- a/pkg/test_runner/lib/src/test_file.dart
+++ b/pkg/test_runner/lib/src/test_file.dart
@@ -4,6 +4,7 @@
import 'dart:io';
import 'path.dart';
+import 'static_error.dart';
final _multiHtmlTestGroupRegExp = RegExp(r"\s*[^/]\s*group\('[^,']*");
final _multiHtmlTestRegExp = RegExp(r"useHtmlIndividualConfiguration\(\)");
@@ -37,312 +38,6 @@
return options;
}
-/// Describes a static error.
-///
-/// These can be parsed from comments in [TestFile]s, in which case they
-/// represent *expected* errors. If a test contains any of these, then it is a
-/// "static error test" and exists to validate that a conforming front end
-/// produces the expected compile-time errors.
-///
-/// Aside from location, there are two interesting attributes of an error that
-/// a test can verify: its error code and the error message. Currently, for
-/// analyzer we only care about the error code. The CFE does not report an
-/// error code and only reports a message. So this class takes advantage of
-/// that by allowing you to set expectations for analyzer and CFE independently
-/// by assuming the [code] field is only used for the former and the [message]
-/// for the latter.
-///
-/// This same class is also used for *reported* errors when parsing the output
-/// of a front end.
-class StaticError implements Comparable<StaticError> {
- static const _unspecified = "unspecified";
-
- /// Collapses overlapping [errors] into a shorter list of errors where
- /// possible.
- ///
- /// Two errors on the same location can be collapsed if one has an error code
- /// but no message and the other has a message but no code.
- static List<StaticError> simplify(List<StaticError> errors) {
- var result = errors.toList();
- result.sort();
-
- for (var i = 0; i < result.length - 1; i++) {
- var a = result[i];
-
- // Look for a later error we can merge with this one. Usually, it will be
- // adjacent to this one, but if there are multiple errors with no length
- // on the same location, those will all be next to each other and their
- // merge targets will come later. This happens when CFE reports multiple
- // errors at the same location (messages but no length) and analyzer does
- // too (codes and lengths but no messages).
- for (var j = i + 1; j < result.length; j++) {
- var b = result[j];
-
- // Position must be the same. If the position is different, we can
- // stop looking because all same-position errors will be adjacent.
- if (a.line != b.line) break;
- if (a.column != b.column) break;
-
- // If they both have lengths that are different, we can't discard that
- // information.
- if (a.length != null && b.length != null && a.length != b.length) {
- continue;
- }
-
- // Can't discard content.
- if (a.code != null && b.code != null) continue;
- if (a.message != null && b.message != null) continue;
-
- result[i] = StaticError(
- line: a.line,
- column: a.column,
- length: a.length ?? b.length,
- code: a.code ?? b.code,
- message: a.message ?? b.message);
- result.removeAt(j);
- break;
- }
- }
-
- return result;
- }
-
- /// Determines whether all [actualErrors] match the given [expectedErrors].
- ///
- /// If they match, returns `null`. Otherwise returns a string describing the
- /// mismatches. This for a human-friendly explanation of the difference
- /// between the two sets of errors, while also being simple to implement.
- /// An expected error that is completely identical to an actual error is
- /// treated as a match. Everything else is a failure.
- ///
- /// It treats line number as the "identity" of an error. So if there are two
- /// errors on the same line that differ in other properties, it reports that
- /// as a "wrong" error. Any expected error on a line containing no actual
- /// error is reported as a "missing" error. Conversely, an actual error on a
- /// line containing no expected error is an "unexpected" error.
- ///
- /// By not treating the error's index in the list to be its identity, we
- /// gracefully handle extra or missing errors without causing cascading
- /// failures for later errors in the lists.
- static String validateExpectations(Iterable<StaticError> expectedErrors,
- Iterable<StaticError> actualErrors) {
- // Don't require the test or front end to output in any specific order.
- var sortedExpected = expectedErrors.toList();
- var sortedActual = actualErrors.toList();
- sortedExpected.sort();
- sortedActual.sort();
-
- var buffer = StringBuffer();
-
- describeError(String adjective, StaticError error, String verb) {
- buffer.writeln("$adjective static error at ${error.location}:");
- if (error.code != null) {
- buffer.writeln("- $verb error code ${error.code}.");
- }
-
- if (error.message != null) {
- buffer.writeln("- $verb error message '${error.message}'.");
- }
- buffer.writeln();
- }
-
- var expectedIndex = 0;
- var actualIndex = 0;
- for (;
- expectedIndex < sortedExpected.length &&
- actualIndex < sortedActual.length;) {
- var expected = sortedExpected[expectedIndex];
- var actual = sortedActual[actualIndex];
- var differences = expected.describeDifferences(actual);
- if (differences == null) {
- expectedIndex++;
- actualIndex++;
- continue;
- }
-
- if (expected.line == actual.line) {
- buffer.writeln("Wrong static error at ${expected.location}:");
- for (var difference in differences) {
- buffer.writeln("- $difference");
- }
- buffer.writeln();
- expectedIndex++;
- actualIndex++;
- } else if (expected.line < actual.line) {
- describeError("Missing", expected, "Expected");
- expectedIndex++;
- } else {
- describeError("Unexpected", actual, "Had");
- actualIndex++;
- }
- }
-
- // Output any trailing expected or actual errors if the lengths of the
- // lists differ.
- for (; expectedIndex < sortedExpected.length; expectedIndex++) {
- describeError("Missing", sortedExpected[expectedIndex], "Expected");
- }
-
- for (; actualIndex < sortedActual.length; actualIndex++) {
- describeError("Unexpected", sortedActual[actualIndex], "Had");
- }
-
- if (buffer.isEmpty) return null;
- return buffer.toString().trimRight();
- }
-
- /// The one-based line number of the beginning of the error's location.
- final int line;
-
- /// The one-based column number of the beginning of the error's location.
- final int column;
-
- /// The number of characters in the error location.
- ///
- /// This is optional. The CFE only reports error location, but not length.
- final int length;
-
- /// The expected analyzer error code for the error or `null` if this error
- /// isn't expected to be reported by analyzer.
- final String code;
-
- /// The expected CFE error message or `null` if this error isn't expected to
- /// be reported by the CFE.
- final String message;
-
- /// The zero-based index of the first line in the [TestFile] containing the
- /// marker comments that define this error.
- ///
- /// If this error was not parsed from a file, this may be `null`.
- final int markerStartLine;
-
- /// The zero-based index of the last line in the [TestFile] containing the
- /// marker comments that define this error, inclusive.
- ///
- /// If this error was not parsed from a file, this may be `null`.
- final int markerEndLine;
-
- /// Creates a new StaticError at the given location with the given expected
- /// error code and message.
- ///
- /// In order to make it easier to incrementally add error tests before a
- /// feature is fully implemented or specified, an error expectation can be in
- /// an "unspecified" state for either or both platforms by having the error
- /// code or message be the special string "unspecified". When an unspecified
- /// error is tested, a front end is expected to report *some* error on that
- /// error's line, but it can be any location, error code, or message.
- StaticError(
- {this.line,
- this.column,
- this.length,
- this.code,
- this.message,
- this.markerStartLine,
- this.markerEndLine}) {
- // Must have a location.
- assert(line != null);
- assert(column != null);
-
- // Must have at least one piece of description.
- assert(code != null || message != null);
- }
-
- /// Whether this error should be reported by analyzer.
- bool get isAnalyzer => code != null;
-
- /// Whether this error should be reported by the CFE.
- bool get isCfe => message != null;
-
- /// A textual description of this error's location.
- String get location {
- var result = "line $line, column $column";
- if (length != null) result += ", length $length";
- return result;
- }
-
- String toString() {
- var result = "Error at $location";
- if (code != null) result += "\n$code";
- if (message != null) result += "\n$message";
- return result;
- }
-
- /// Orders errors primarily by location, then by other fields if needed.
- @override
- int compareTo(StaticError other) {
- if (line != other.line) return line.compareTo(other.line);
- if (column != other.column) return column.compareTo(other.column);
-
- // Sort no length after all other lengths.
- if (length == null && other.length != null) return 1;
- if (length != null && other.length == null) return -1;
- if (length != other.length) return length.compareTo(other.length);
-
- var thisCode = code ?? "";
- var otherCode = other.code ?? "";
- if (thisCode != otherCode) return thisCode.compareTo(otherCode);
-
- var thisMessage = message ?? "";
- var otherMessage = other.message ?? "";
- return thisMessage.compareTo(otherMessage);
- }
-
- /// Compares this error expectation to [actual].
- ///
- /// If this error correctly matches [actual], returns `null`. Otherwise
- /// returns a list of strings describing the mismatch.
- ///
- /// Note that this does *not* check to see that [actual] matches the platforms
- /// that this error expects. For example, if [actual] only reports an error
- /// code (i.e. it is analyzer-only) and this error only specifies an error
- /// message (i.e. it is CFE-only), this will still report differences in
- /// location information. This method expects that error expectations have
- /// already been filtered by platform so this will only be called in cases
- /// where the platforms do match.
- List<String> describeDifferences(StaticError actual) {
- var differences = <String>[];
-
- if (line != actual.line) {
- differences.add("Expected on line $line but was on ${actual.line}.");
- }
-
- // If the error is unspecified on the front end being tested, the column
- // and length can be any values.
- var requirePreciseLocation = code != _unspecified && actual.isAnalyzer ||
- message != _unspecified && actual.isCfe;
- if (requirePreciseLocation) {
- if (column != actual.column) {
- differences
- .add("Expected on column $column but was on ${actual.column}.");
- }
-
- // This error represents an expectation, so should have a length.
- assert(length != null);
- if (actual.length != null && length != actual.length) {
- differences.add("Expected length $length but was ${actual.length}.");
- }
- }
-
- if (code != null &&
- code != _unspecified &&
- actual.code != null &&
- code != actual.code) {
- differences.add("Expected error code $code but was ${actual.code}.");
- }
-
- if (message != null &&
- message != _unspecified &&
- actual.message != null &&
- message != actual.message) {
- differences.add(
- "Expected error message '$message' but was '${actual.message}'.");
- }
-
- if (differences.isNotEmpty) return differences;
- return null;
- }
-}
-
abstract class _TestFileBase {
/// The test suite directory containing this test.
final Path _suiteDirectory;
@@ -579,7 +274,7 @@
List<StaticError> errorExpectations;
try {
- errorExpectations = ErrorExpectationParser.parse(contents);
+ errorExpectations = StaticError.parseExpectations(contents);
} on FormatException catch (error) {
throw FormatException(
"Invalid error expectation syntax in $filePath:\n$error");
@@ -685,7 +380,7 @@
bool hasStaticWarning,
bool hasSyntaxError}) =>
_MultitestFile(
- this, path, multitestKey, ErrorExpectationParser.parse(contents),
+ this, path, multitestKey, StaticError.parseExpectations(contents),
hasCompileError: hasCompileError ?? false,
hasRuntimeError: hasRuntimeError ?? false,
hasStaticWarning: hasStaticWarning ?? false,
@@ -764,188 +459,3 @@
throw UnsupportedError(
"Can't derive a test from one already derived from a multitest.");
}
-
-class ErrorExpectationParser {
- static List<StaticError> parse(String source) =>
- ErrorExpectationParser._(source)._parse();
-
- /// Marks the location of an expected error, like so:
- ///
- /// int i = "s";
- /// // ^^^
- ///
- /// We look for a line that starts with a line comment followed by spaces and
- /// carets.
- static final _caretLocationRegExp = RegExp(r"^\s*//\s*(\^+)\s*$");
-
- /// Matches an explicit error location with a length, like:
- ///
- /// // [error line 1, column 17, length 3]
- static final _explicitLocationAndLengthRegExp =
- RegExp(r"^\s*//\s*\[\s*error line\s+(\d+)\s*,\s*column\s+(\d+)\s*,\s*"
- r"length\s+(\d+)\s*\]\s*$");
-
- /// Matches an explicit error location without a length, like:
- ///
- /// // [error line 1, column 17]
- static final _explicitLocationRegExp =
- RegExp(r"^\s*//\s*\[\s*error line\s+(\d+)\s*,\s*column\s+(\d+)\s*\]\s*$");
-
- /// An analyzer error expectation starts with `// [analyzer]`.
- static final _analyzerErrorRegExp = RegExp(r"^\s*// \[analyzer\]\s*(.*)");
-
- /// An analyzer error code is a dotted identifier or the magic string
- /// "unspecified".
- static final _errorCodeRegExp = RegExp(r"^\w+\.\w+|unspecified$");
-
- /// The first line of a CFE error expectation starts with `// [cfe]`.
- static final _cfeErrorRegExp = RegExp(r"^\s*// \[cfe\]\s*(.*)");
-
- /// Any line-comment-only lines after the first line of a CFE error message
- /// are part of it.
- static final _errorMessageRestRegExp = RegExp(r"^\s*//\s*(.*)");
-
- /// Matches the multitest marker and yields the preceding content.
- final _stripMultitestRegExp = RegExp(r"(.*)//#");
-
- final List<String> _lines;
- final List<StaticError> _errors = [];
- int _currentLine = 0;
-
- // One-based index of the last line that wasn't part of an error expectation.
- int _lastRealLine = -1;
-
- ErrorExpectationParser._(String source) : _lines = source.split("\n");
-
- List<StaticError> _parse() {
- while (!_isAtEnd) {
- var sourceLine = _peek(0);
-
- var match = _caretLocationRegExp.firstMatch(sourceLine);
- if (match != null) {
- if (_lastRealLine == -1) {
- _fail("An error expectation must follow some code.");
- }
-
- _parseErrorDetails(
- line: _lastRealLine,
- column: sourceLine.indexOf("^") + 1,
- length: match.group(1).length);
- _advance();
- continue;
- }
-
- match = _explicitLocationAndLengthRegExp.firstMatch(sourceLine);
- if (match != null) {
- _parseErrorDetails(
- line: int.parse(match.group(1)),
- column: int.parse(match.group(2)),
- length: int.parse(match.group(3)));
- _advance();
- continue;
- }
-
- match = _explicitLocationRegExp.firstMatch(sourceLine);
- if (match != null) {
- _parseErrorDetails(
- line: int.parse(match.group(1)), column: int.parse(match.group(2)));
- _advance();
- continue;
- }
-
- _lastRealLine = _currentLine + 1;
- _advance();
- }
-
- return _errors;
- }
-
- /// Finishes parsing an error expectation after parsing the location.
- void _parseErrorDetails({int line, int column, int length}) {
- String code;
- String message;
-
- var startLine = _currentLine;
-
- // Look for an error code line.
- if (!_isAtEnd) {
- var match = _analyzerErrorRegExp.firstMatch(_peek(1));
- if (match != null) {
- code = match.group(1);
-
- if (!_errorCodeRegExp.hasMatch(code)) {
- _fail("An analyzer error expectation should be a dotted identifier.");
- }
-
- _advance();
- }
- }
-
- // Look for an error message.
- if (!_isAtEnd) {
- var match = _cfeErrorRegExp.firstMatch(_peek(1));
- if (match != null) {
- message = match.group(1);
- _advance();
-
- // Consume as many additional error message lines as we find.
- while (!_isAtEnd) {
- var nextLine = _peek(1);
-
- // A location line shouldn't be treated as a message.
- if (_caretLocationRegExp.hasMatch(nextLine)) break;
- if (_explicitLocationAndLengthRegExp.hasMatch(nextLine)) break;
- if (_explicitLocationRegExp.hasMatch(nextLine)) break;
-
- // Don't let users arbitrarily order the error code and message.
- if (_analyzerErrorRegExp.hasMatch(nextLine)) {
- _fail("An analyzer expectation must come before a CFE "
- "expectation.");
- }
-
- var messageMatch = _errorMessageRestRegExp.firstMatch(nextLine);
- if (messageMatch == null) break;
-
- message += "\n" + messageMatch.group(1);
- _advance();
- }
- }
- }
-
- if (code == null && message == null) {
- _fail("An error expectation must specify at least an analyzer or CFE "
- "error.");
- }
-
- _errors.add(StaticError(
- line: line,
- column: column,
- length: length,
- code: code,
- message: message,
- markerStartLine: startLine,
- markerEndLine: _currentLine));
- }
-
- bool get _isAtEnd => _currentLine >= _lines.length;
-
- void _advance() {
- _currentLine++;
- }
-
- String _peek(int offset) {
- var line = _lines[_currentLine + offset];
-
- // Strip off any multitest marker.
- var multitestMatch = _stripMultitestRegExp.firstMatch(line);
- if (multitestMatch != null) {
- line = multitestMatch.group(1).trimRight();
- }
-
- return line;
- }
-
- void _fail(String message) {
- throw FormatException("Test error on line ${_currentLine + 1}: $message");
- }
-}
diff --git a/pkg/test_runner/lib/src/test_suite.dart b/pkg/test_runner/lib/src/test_suite.dart
index 71a5870..f2fb6c7 100644
--- a/pkg/test_runner/lib/src/test_suite.dart
+++ b/pkg/test_runner/lib/src/test_suite.dart
@@ -257,22 +257,20 @@
/// pubspec checkouts ...).
String createOutputDirectory(Path testPath) {
var checked = configuration.isChecked ? '-checked' : '';
- var legacy = configuration.noPreviewDart2 ? '-legacy' : '';
var minified = configuration.isMinified ? '-minified' : '';
var sdk = configuration.useSdk ? '-sdk' : '';
var dirName = "${configuration.compiler.name}-${configuration.runtime.name}"
- "$checked$legacy$minified$sdk";
+ "$checked$minified$sdk";
return createGeneratedTestDirectoryHelper("tests", dirName, testPath);
}
String createCompilationOutputDirectory(Path testPath) {
var checked = configuration.isChecked ? '-checked' : '';
- var legacy = configuration.noPreviewDart2 ? '-legacy' : '';
var minified = configuration.isMinified ? '-minified' : '';
var csp = configuration.isCsp ? '-csp' : '';
var sdk = configuration.useSdk ? '-sdk' : '';
var dirName = "${configuration.compiler.name}"
- "$checked$legacy$minified$csp$sdk";
+ "$checked$minified$csp$sdk";
return createGeneratedTestDirectoryHelper(
"compilations", dirName, testPath);
}
@@ -334,7 +332,7 @@
doTest = null;
if (onDone != null) onDone();
} catch (error, s) {
- print("Fatal error occured: $error");
+ print("Fatal error occurred: $error");
print(s);
exit(1);
}
@@ -362,23 +360,20 @@
hasStaticWarning: false,
hasCrash: testExpectation == Expectation.crash);
- var args = configuration.standardOptions.toList();
- if (configuration.compilerConfiguration.previewDart2) {
- var filename = configuration.architecture == Architecture.x64
- ? '$buildDir/gen/kernel-service.dart.snapshot'
- : '$buildDir/gen/kernel_service.dill';
- var dfePath = Path(filename).absolute.toNativePath();
+ var filename = configuration.architecture == Architecture.x64
+ ? '$buildDir/gen/kernel-service.dart.snapshot'
+ : '$buildDir/gen/kernel_service.dill';
+ var dfePath = Path(filename).absolute.toNativePath();
+ var args = [
+ if (expectations.contains(Expectation.crash)) '--suppress-core-dump',
// '--dfe' has to be the first argument for run_vm_test to pick it up.
- args.insert(0, '--dfe=$dfePath');
- args.addAll(configuration.vmOptions);
- }
- if (expectations.contains(Expectation.crash)) {
- args.insert(0, '--suppress-core-dump');
- }
+ '--dfe=$dfePath',
+ ...configuration.standardOptions,
+ ...configuration.vmOptions,
+ test.name
+ ];
- args.add(test.name);
-
- var command = Command.process(
+ var command = ProcessCommand(
'run_vm_unittest', targetRunnerPath, args, environmentOverrides);
enqueueNewTestCase(testFile, fullName, [command], expectations);
}
@@ -701,12 +696,7 @@
String tempDir;
if (compilerConfiguration.hasCompiler) {
compileTimeArguments = compilerConfiguration.computeCompilerArguments(
- vmOptions,
- testFile.sharedOptions,
- testFile.dartOptions,
- testFile.dart2jsOptions,
- testFile.ddcOptions,
- args);
+ testFile, vmOptions, args);
// Avoid doing this for analyzer.
var path = testFile.path;
if (vmOptionsVariant != 0) {
@@ -873,13 +863,8 @@
};
assert(supportedCompilers.contains(configuration.compiler));
- var args = configuration.compilerConfiguration.computeCompilerArguments(
- null,
- testFile.sharedOptions,
- null,
- testFile.dart2jsOptions,
- testFile.ddcOptions,
- commonArguments);
+ var args = configuration.compilerConfiguration
+ .computeCompilerArguments(testFile, null, commonArguments);
var compilation = configuration.compilerConfiguration
.computeCompilationArtifact(outputDir, args, environmentOverrides);
commands.addAll(compilation.commands);
diff --git a/pkg/test_runner/lib/src/testing_servers.dart b/pkg/test_runner/lib/src/testing_servers.dart
index 9831e6d..df7bf91 100644
--- a/pkg/test_runner/lib/src/testing_servers.dart
+++ b/pkg/test_runner/lib/src/testing_servers.dart
@@ -164,7 +164,7 @@
}
void _onError(e) {
- DebugLogger.error('HttpServer: an error occured', e);
+ DebugLogger.error('HttpServer: an error occurred', e);
}
Future<DispatchingServer> _startHttpServer(String host,
diff --git a/pkg/test_runner/lib/src/update_errors.dart b/pkg/test_runner/lib/src/update_errors.dart
index 19d81e4..f0fa6e4 100644
--- a/pkg/test_runner/lib/src/update_errors.dart
+++ b/pkg/test_runner/lib/src/update_errors.dart
@@ -1,7 +1,7 @@
// Copyright (c) 2019, 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 'test_file.dart';
+import 'static_error.dart';
/// Matches leading indentation in a string.
final _indentationRegExp = RegExp(r"^(\s*)");
@@ -19,7 +19,7 @@
removeAnalyzer ??= true;
removeCfe ??= true;
- var existingErrors = ErrorExpectationParser.parse(source);
+ var existingErrors = StaticError.parseExpectations(source);
var lines = source.split("\n");
// Keep track of the indentation on any existing expectation markers. If
@@ -67,12 +67,19 @@
}
var previousIndent = 0;
+ var codeLine = 1;
var result = <String>[];
for (var i = 0; i < lines.length; i++) {
// Keep the code.
if (lines[i] != null) {
result.add(lines[i]);
previousIndent = _countIndentation(lines[i]);
+
+ // Keep track of the resulting line number of the last line containing
+ // real code. We use this when outputting explicit line numbers instead
+ // the error's reported line to compensate for added or removed lines
+ // above the error.
+ codeLine = result.length;
}
// Add expectations for any errors reported on this line.
@@ -89,14 +96,15 @@
var comment = (" " * indent) + "//";
- // If the error can't fit in a line comment or doesn't have a length, use
- // an explicit location.
- if (error.length == null) {
- result.add("$comment [error line ${error.line}, column "
- "${error.column}]");
- } else if (error.column <= 2) {
- result.add("$comment [error line ${error.line}, column "
- "${error.column}, length ${error.length}]");
+ // If the error can't fit in a line comment, use an explicit location.
+ if (error.column <= 2) {
+ if (error.length == null) {
+ result.add("$comment [error line $codeLine, column "
+ "${error.column}]");
+ } else {
+ result.add("$comment [error line $codeLine, column "
+ "${error.column}, length ${error.length}]");
+ }
} else {
var spacing = " " * (error.column - 1 - 2 - indent);
// A CFE-only error may not have a length, so treat it as length 1.
diff --git a/pkg/test_runner/lib/src/utils.dart b/pkg/test_runner/lib/src/utils.dart
index 84482aa..197d995 100644
--- a/pkg/test_runner/lib/src/utils.dart
+++ b/pkg/test_runner/lib/src/utils.dart
@@ -432,12 +432,10 @@
configuration.compiler == Compiler.dartkb ||
configuration.compiler == Compiler.dartkp) {
var checked = configuration.isChecked ? '-checked' : '';
- var legacy = configuration.noPreviewDart2 ? '-legacy' : '';
var minified = configuration.isMinified ? '-minified' : '';
var csp = configuration.isCsp ? '-csp' : '';
var sdk = configuration.useSdk ? '-sdk' : '';
- var dirName = "${configuration.compiler.name}"
- "$checked$legacy$minified$csp$sdk";
+ var dirName = "${configuration.compiler.name}$checked$minified$csp$sdk";
var generatedPath =
configuration.buildDirectory + "/generated_compilations/$dirName";
if (FileSystemEntity.isDirectorySync(generatedPath)) {
diff --git a/pkg/test_runner/test/skipping_dart2js_compilations_test.dart b/pkg/test_runner/test/skipping_dart2js_compilations_test.dart
index f1b7df3..3d6fb75 100644
--- a/pkg/test_runner/test/skipping_dart2js_compilations_test.dart
+++ b/pkg/test_runner/test/skipping_dart2js_compilations_test.dart
@@ -151,7 +151,7 @@
..add(createFileScript)
..add(fileUtils.scriptOutputPath.toNativePath());
var bootstrapDeps = [Uri.parse("file://${fileUtils.testSnapshotFilePath}")];
- return Command.compilation('dart2js', fileUtils.testJsFilePath.toNativePath(),
+ return CompilationCommand('dart2js', fileUtils.testJsFilePath.toNativePath(),
bootstrapDeps, executable, arguments, {},
alwaysCompile: false);
}
diff --git a/pkg/test_runner/test/static_error_test.dart b/pkg/test_runner/test/static_error_test.dart
index f607ee9..806e077 100644
--- a/pkg/test_runner/test/static_error_test.dart
+++ b/pkg/test_runner/test/static_error_test.dart
@@ -4,7 +4,7 @@
import 'package:expect/expect.dart';
-import 'package:test_runner/src/test_file.dart';
+import 'package:test_runner/src/static_error.dart';
void main() {
testFlags();
@@ -512,6 +512,49 @@
Missing static error at line 7, column 2, length 3:
- Expected error code ERR.G.
- Expected error message '7.'.""");
+
+ // Unspecified errors.
+ expectValidate([
+ // Missing.
+ StaticError(line: 1, column: 2, length: 3, code: "unspecified"),
+ StaticError(line: 2, column: 2, length: 3, message: "unspecified"),
+ StaticError(
+ line: 3,
+ column: 2,
+ length: 3,
+ code: "unspecified",
+ message: "unspecified"),
+
+ // Right.
+ StaticError(line: 4, column: 2, length: 3, code: "unspecified"),
+ StaticError(line: 5, column: 2, length: 3, message: "unspecified"),
+ StaticError(
+ line: 6,
+ column: 2,
+ length: 3,
+ code: "unspecified",
+ message: "unspecified"),
+ ], [
+ StaticError(line: 4, column: 2, length: 3, code: "ACT.UAL"),
+ StaticError(line: 5, column: 2, length: 3, message: "Actual."),
+ StaticError(
+ line: 6, column: 2, length: 3, code: "ACT.UAL", message: "Actual."),
+
+ // Unexpected.
+ StaticError(line: 7, column: 9, length: 3, code: "ACT.UAL"),
+ ], """
+Missing static error at line 1, column 2, length 3:
+- Expected unspecified error code.
+
+Missing static error at line 2, column 2, length 3:
+- Expected unspecified error message.
+
+Missing static error at line 3, column 2, length 3:
+- Expected unspecified error code.
+- Expected unspecified error message.
+
+Unexpected static error at line 7, column 9, length 3:
+- Had error code ACT.UAL.""");
}
void expectNoDifferences(StaticError expectedError, StaticError actualError) {
diff --git a/pkg/test_runner/test/test_file_test.dart b/pkg/test_runner/test/test_file_test.dart
index aea3887..b35c116 100644
--- a/pkg/test_runner/test/test_file_test.dart
+++ b/pkg/test_runner/test/test_file_test.dart
@@ -6,6 +6,7 @@
import 'package:expect/expect.dart';
import 'package:test_runner/src/path.dart';
+import 'package:test_runner/src/static_error.dart';
import 'package:test_runner/src/test_file.dart';
// Note: This test file validates how some of the special markers used by the
@@ -457,6 +458,22 @@
/\/ ^^^
/\/ [analyzer] Not error code.
""");
+
+ // A CFE-only error with length one is treated as having no length.
+ expectParseErrorExpectations("""
+int i = "s";
+/\/ ^
+/\/ [cfe] Message.
+
+int j = "s";
+/\/ ^
+/\/ [analyzer] Error.BAD
+/\/ [cfe] Message.
+""", [
+ StaticError(line: 1, column: 9, length: null, message: "Message."),
+ StaticError(
+ line: 5, column: 9, length: 1, code: "Error.BAD", message: "Message."),
+ ]);
}
void testName() {
diff --git a/pkg/test_runner/test/test_runner_test.dart b/pkg/test_runner/test/test_runner_test.dart
index 385e73c..4123612 100644
--- a/pkg/test_runner/test/test_runner_test.dart
+++ b/pkg/test_runner/test/test_runner_test.dart
@@ -99,12 +99,12 @@
String name, Iterable<Expectation> expectations) {
var args = packageOptions();
args.addAll([Platform.script.toFilePath(), name]);
- var command = Command.process('custom', Platform.executable, args, {});
+ var command = ProcessCommand('custom', Platform.executable, args, {});
return _makeTestCase(name, DEFAULT_TIMEOUT, command, expectations);
}
TestCase _makeCrashTestCase(String name, Iterable<Expectation> expectations) {
- var crashCommand = Command.process(
+ var crashCommand = ProcessCommand(
'custom_crash', getProcessTestFileName(), ["0", "0", "1", "1"], {});
// The crash test sometimes times out. Run it with a large timeout
// to help diagnose the delay.
diff --git a/pkg/test_runner/test/update_errors_test.dart b/pkg/test_runner/test/update_errors_test.dart
index 03f0cc3..9d07b9c 100644
--- a/pkg/test_runner/test/update_errors_test.dart
+++ b/pkg/test_runner/test/update_errors_test.dart
@@ -4,7 +4,7 @@
import 'package:expect/expect.dart';
-import 'package:test_runner/src/test_file.dart';
+import 'package:test_runner/src/static_error.dart';
import 'package:test_runner/src/update_errors.dart';
// Note: This test file validates how some of the special markers used by the
@@ -192,12 +192,12 @@
/\/ [cfe] Error.
""");
- // Uses an explicit error location if there's no length.
+ // Uses length one if there's no length.
expectUpdate("""
int i = "bad";
""", errors: [StaticError(line: 1, column: 9, message: "Error.")], expected: """
int i = "bad";
-/\/ [error line 1, column 9]
+/\/ ^
/\/ [cfe] Error.
""");
@@ -212,6 +212,29 @@
/\/ [cfe] Error.
""");
+ // Handles shifted line numbers in explicit error locations.
+ // Note that the reported line is line 6, but the output is line 3 to take
+ // into account the three removed lines.
+ expectUpdate("""
+main() {
+/\/ ^^
+/\/ [analyzer] ERROR.CODE
+/\/ [cfe] Error.
+}
+Error here;
+""", errors: [
+ StaticError(line: 6, column: 1, length: 5, code: "NEW.ERROR"),
+ StaticError(line: 6, column: 2, length: 3, message: "Error."),
+ ], expected: """
+main() {
+}
+Error here;
+/\/ [error line 3, column 1, length 5]
+/\/ [analyzer] NEW.ERROR
+/\/ [error line 3, column 2, length 3]
+/\/ [cfe] Error.
+""");
+
// Inserts a blank line if a subsequent line comment would become part of the
// error message.
expectUpdate("""
@@ -246,6 +269,65 @@
/\/ ^^^^^
/\/ [cfe] Wrong 1.
""");
+
+ regression();
+}
+
+void regression() {
+ // https://github.com/dart-lang/sdk/issues/37990.
+ expectUpdate(
+ """
+int get xx => 3;
+int get yy => 3;
+
+class A {
+ void test() {
+ xx = 1;
+/\/ ^^^^^^^^^^^^^^
+/\/ [cfe] unspecified
+/\/ ^^^^^^^^^^^^^^
+/\/ [analyzer] unspecified
+
+
+ yy(4);
+/\/ ^^^^^^^^^^^^^^
+/\/ [cfe] unspecified
+/\/ ^^^^^^^^^^^^^^
+/\/ [analyzer] unspecified
+
+ }
+}
+""",
+ removeAnalyzer: false,
+ errors: [
+ StaticError(
+ line: 6, column: 5, length: 14, message: "Setter not found: 'xx'."),
+ StaticError(
+ line: 16,
+ column: 7,
+ message: "The method 'call' isn't defined for the class 'int'.")
+ ],
+ expected: """
+int get xx => 3;
+int get yy => 3;
+
+class A {
+ void test() {
+ xx = 1;
+/\/ ^^^^^^^^^^^^^^
+/\/ [analyzer] unspecified
+/\/ [cfe] Setter not found: 'xx'.
+
+
+ yy(4);
+/\/ ^^^^^^^^^^^^^^
+/\/ [analyzer] unspecified
+/\/ ^
+/\/ [cfe] The method 'call' isn't defined for the class 'int'.
+
+ }
+}
+""");
}
void expectUpdate(String original,
diff --git a/pkg/test_runner/tool/update_static_error_tests.dart b/pkg/test_runner/tool/update_static_error_tests.dart
index 46061c9..9fa7acb 100644
--- a/pkg/test_runner/tool/update_static_error_tests.dart
+++ b/pkg/test_runner/tool/update_static_error_tests.dart
@@ -11,6 +11,7 @@
import 'package:test_runner/src/command_output.dart';
import 'package:test_runner/src/path.dart';
+import 'package:test_runner/src/static_error.dart';
import 'package:test_runner/src/test_file.dart';
import 'package:test_runner/src/update_errors.dart';
import 'package:test_runner/src/utils.dart';
diff --git a/pkg/testing/lib/src/chain.dart b/pkg/testing/lib/src/chain.dart
index 1c0c748..8338073 100644
--- a/pkg/testing/lib/src/chain.dart
+++ b/pkg/testing/lib/src/chain.dart
@@ -111,7 +111,11 @@
ExpectationSet get expectationSet => ExpectationSet.Default;
- Future<Null> run(Chain suite, Set<String> selectors) async {
+ Future<Null> run(Chain suite, Set<String> selectors,
+ {int shards = 1, int shard = 0}) async {
+ assert(shards >= 1, "Invalid shards count: $shards");
+ assert(0 <= shard && shard < shards,
+ "Invalid shard index: $shard, not in range [0,$shards[.");
List<String> partialSelectors = selectors
.where((s) => s.endsWith('...'))
.map((s) => s.substring(0, s.length - 3))
@@ -124,6 +128,15 @@
}
List<TestDescription> descriptions = await stream.toList();
descriptions.sort();
+ if (shards > 1) {
+ List<TestDescription> shardDescriptions = [];
+ for (int index = 0; index < descriptions.length; index++) {
+ if (index % shards == shard) {
+ shardDescriptions.add(descriptions[index]);
+ }
+ }
+ descriptions = shardDescriptions;
+ }
Map<TestDescription, Result> unexpectedResults =
<TestDescription, Result>{};
Map<TestDescription, Set<Expectation>> unexpectedOutcomes =
diff --git a/pkg/testing/lib/src/run.dart b/pkg/testing/lib/src/run.dart
index 1d83c9b..d16cf30 100644
--- a/pkg/testing/lib/src/run.dart
+++ b/pkg/testing/lib/src/run.dart
@@ -55,7 +55,7 @@
/// `testing.json` isn't located in the current working directory and is a path
/// relative to [me] which defaults to `Platform.script`.
Future<Null> runMe(List<String> arguments, CreateContext f,
- [String configurationPath, Uri me]) {
+ {String configurationPath, Uri me, int shards = 1, int shard = 0}) {
me ??= Platform.script;
return withErrorHandling(() async {
TestRoot testRoot = await computeTestRoot(configurationPath, me);
@@ -65,7 +65,8 @@
if (me == suite.source) {
print("Running suite ${suite.name}...");
ChainContext context = await f(suite, cl.environment);
- await context.run(suite, new Set<String>.from(cl.selectors));
+ await context.run(suite, new Set<String>.from(cl.selectors),
+ shards: shards, shard: shard);
}
}
});
diff --git a/pkg/vm/lib/bytecode/assembler.dart b/pkg/vm/lib/bytecode/assembler.dart
index c287838..5926c77 100644
--- a/pkg/vm/lib/bytecode/assembler.dart
+++ b/pkg/vm/lib/bytecode/assembler.dart
@@ -5,6 +5,7 @@
library vm.bytecode.assembler;
import 'package:kernel/ast.dart' show TreeNode;
+import 'package:vm/bytecode/options.dart';
import 'dbc.dart';
import 'exceptions.dart' show ExceptionsTable;
@@ -56,10 +57,12 @@
final ExceptionsTable exceptionsTable = new ExceptionsTable();
final LocalVariableTable localVariableTable = new LocalVariableTable();
final SourcePositions sourcePositions = new SourcePositions();
+ final bool _emitSourcePositions;
bool isUnreachable = false;
int currentSourcePosition = TreeNode.noOffset;
- BytecodeAssembler();
+ BytecodeAssembler(BytecodeOptions options)
+ : _emitSourcePositions = options.emitSourcePositions;
int get offset => bytecode.length;
@@ -74,11 +77,27 @@
}
void emitSourcePosition() {
- if (currentSourcePosition != TreeNode.noOffset && !isUnreachable) {
+ if (_emitSourcePositions &&
+ !isUnreachable &&
+ currentSourcePosition != TreeNode.noOffset) {
sourcePositions.add(offset, currentSourcePosition);
}
}
+ // TreeNode.noOffset (-1) source position on calls is used to mark synthetic
+ // calls without corresponding source position. Debugger uses the absence of
+ // source position to distinguish these calls and avoid stopping at them
+ // while single stepping.
+ void emitSourcePositionForCall() {
+ if (_emitSourcePositions && !isUnreachable) {
+ sourcePositions.add(
+ offset,
+ currentSourcePosition == TreeNode.noOffset
+ ? SourcePositions.syntheticCodeMarker
+ : currentSourcePosition);
+ }
+ }
+
void emitYieldPointSourcePosition() {
if (!isUnreachable) {
sourcePositions.addYieldPoint(offset, currentSourcePosition);
@@ -371,32 +390,32 @@
}
void emitDirectCall(int rd, int rf) {
- emitSourcePosition();
+ emitSourcePositionForCall();
_emitInstructionDF(Opcode.kDirectCall, rd, rf);
}
void emitInterfaceCall(int rd, int rf) {
- emitSourcePosition();
+ emitSourcePositionForCall();
_emitInstructionDF(Opcode.kInterfaceCall, rd, rf);
}
void emitInstantiatedInterfaceCall(int rd, int rf) {
- emitSourcePosition();
+ emitSourcePositionForCall();
_emitInstructionDF(Opcode.kInstantiatedInterfaceCall, rd, rf);
}
void emitUncheckedClosureCall(int rd, int rf) {
- emitSourcePosition();
+ emitSourcePositionForCall();
_emitInstructionDF(Opcode.kUncheckedClosureCall, rd, rf);
}
void emitUncheckedInterfaceCall(int rd, int rf) {
- emitSourcePosition();
+ emitSourcePositionForCall();
_emitInstructionDF(Opcode.kUncheckedInterfaceCall, rd, rf);
}
void emitDynamicCall(int rd, int rf) {
- emitSourcePosition();
+ emitSourcePositionForCall();
_emitInstructionDF(Opcode.kDynamicCall, rd, rf);
}
diff --git a/pkg/vm/lib/bytecode/constant_pool.dart b/pkg/vm/lib/bytecode/constant_pool.dart
index 6804895..eeee7fc 100644
--- a/pkg/vm/lib/bytecode/constant_pool.dart
+++ b/pkg/vm/lib/bytecode/constant_pool.dart
@@ -31,20 +31,6 @@
Byte tag;
}
-enum InvocationKind {
- method, // x.foo(...) or foo(...)
- getter, // x.foo
- setter // x.foo = ...
-}
-
-type ConstantICData extends ConstantPoolEntry {
- Byte tag = 7;
- Byte flags(invocationKindBit0, invocationKindBit1, isDynamic);
- // Where invocationKind is index into InvocationKind.
- PackedObject targetName;
- ConstantIndex argDesc;
-}
-
type ConstantStaticField extends ConstantPoolEntry {
Byte tag = 9;
PackedObject field;
@@ -120,6 +106,13 @@
PackedObject staticReceiverType;
}
+// Occupies 2 entries in the constant pool
+type ConstantDynamicCall extends ConstantPoolEntry {
+ Byte tag = 31;
+ PackedObject selectorName;
+ PackedObject argDesc;
+}
+
*/
enum ConstantTag {
@@ -130,7 +123,7 @@
kUnused4,
kUnused5,
kUnused6,
- kICData,
+ kUnused6a,
kUnused7,
kStaticField,
kInstanceField,
@@ -154,6 +147,7 @@
kDirectCall,
kInterfaceCall,
kInstantiatedInterfaceCall,
+ kDynamicCall,
}
String constantTagToString(ConstantTag tag) =>
@@ -180,8 +174,6 @@
switch (tag) {
case ConstantTag.kInvalid:
break;
- case ConstantTag.kICData:
- return new ConstantICData.read(reader);
case ConstantTag.kStaticField:
return new ConstantStaticField.read(reader);
case ConstantTag.kInstanceField:
@@ -210,6 +202,8 @@
return new ConstantInterfaceCall.read(reader);
case ConstantTag.kInstantiatedInterfaceCall:
return new ConstantInstantiatedInterfaceCall.read(reader);
+ case ConstantTag.kDynamicCall:
+ return new ConstantDynamicCall.read(reader);
// Make analyzer happy.
case ConstantTag.kUnused1:
case ConstantTag.kUnused2:
@@ -217,6 +211,7 @@
case ConstantTag.kUnused4:
case ConstantTag.kUnused5:
case ConstantTag.kUnused6:
+ case ConstantTag.kUnused6a:
case ConstantTag.kUnused7:
case ConstantTag.kUnused8:
case ConstantTag.kUnused9:
@@ -232,67 +227,10 @@
}
}
-enum InvocationKind { method, getter, setter }
-
-String _invocationKindToString(InvocationKind kind) {
- switch (kind) {
- case InvocationKind.method:
- return '';
- case InvocationKind.getter:
- return 'get ';
- case InvocationKind.setter:
- return 'set ';
- }
- throw 'Unexpected InvocationKind $kind';
-}
-
-class ConstantICData extends ConstantPoolEntry {
- static const int invocationKindMask = 3;
- static const int flagDynamic = 1 << 2;
-
- final int _flags;
- final ObjectHandle targetName;
- final int argDescConstantIndex;
-
- ConstantICData(InvocationKind invocationKind, this.targetName,
- this.argDescConstantIndex, bool isDynamic)
- : assert(invocationKind.index <= invocationKindMask),
- _flags = invocationKind.index | (isDynamic ? flagDynamic : 0);
-
- InvocationKind get invocationKind =>
- InvocationKind.values[_flags & invocationKindMask];
-
- bool get isDynamic => (_flags & flagDynamic) != 0;
-
- @override
- ConstantTag get tag => ConstantTag.kICData;
-
- @override
- void writeValue(BufferedWriter writer) {
- writer.writeByte(_flags);
- writer.writePackedObject(targetName);
- writer.writePackedUInt30(argDescConstantIndex);
- }
-
- ConstantICData.read(BufferedReader reader)
- : _flags = reader.readByte(),
- targetName = reader.readPackedObject(),
- argDescConstantIndex = reader.readPackedUInt30();
-
- @override
- String toString() => 'ICData '
- '${isDynamic ? 'dynamic ' : ''}'
- '${_invocationKindToString(invocationKind)}'
- 'target-name $targetName, arg-desc CP#$argDescConstantIndex';
-
- // ConstantICData entries are created per call site and should not be merged,
- // so ConstantICData class uses identity [hashCode] and [operator ==].
-
- @override
- int get hashCode => identityHashCode(this);
-
- @override
- bool operator ==(other) => identical(this, other);
+enum InvocationKind {
+ method, // x.foo(...) or foo(...)
+ getter, // x.foo
+ setter // x.foo = ...
}
class ConstantStaticField extends ConstantPoolEntry {
@@ -693,6 +631,41 @@
this.staticReceiverType == other.staticReceiverType;
}
+class ConstantDynamicCall extends ConstantPoolEntry {
+ final ObjectHandle selectorName;
+ final ObjectHandle argDesc;
+
+ ConstantDynamicCall(this.selectorName, this.argDesc);
+
+ // Reserve 1 extra slot for arguments descriptor, following selector slot.
+ int get numReservedEntries => 1;
+
+ @override
+ ConstantTag get tag => ConstantTag.kDynamicCall;
+
+ @override
+ void writeValue(BufferedWriter writer) {
+ writer.writePackedObject(selectorName);
+ writer.writePackedObject(argDesc);
+ }
+
+ ConstantDynamicCall.read(BufferedReader reader)
+ : selectorName = reader.readPackedObject(),
+ argDesc = reader.readPackedObject();
+
+ @override
+ String toString() => 'DynamicCall $selectorName, $argDesc';
+
+ @override
+ int get hashCode => _combineHashes(selectorName.hashCode, argDesc.hashCode);
+
+ @override
+ bool operator ==(other) =>
+ other is ConstantDynamicCall &&
+ this.selectorName == other.selectorName &&
+ this.argDesc == other.argDesc;
+}
+
/// Reserved constant pool entry.
class _ReservedConstantPoolEntry extends ConstantPoolEntry {
const _ReservedConstantPoolEntry();
@@ -726,17 +699,6 @@
_add(new ConstantObjectRef(objectTable.getArgDescHandleByArguments(args,
hasReceiver: hasReceiver, isFactory: isFactory)));
- int addICData(
- InvocationKind invocationKind, Name targetName, int argDescCpIndex,
- {bool isDynamic: false}) =>
- _add(new ConstantICData(
- invocationKind,
- objectTable.getSelectorNameHandle(targetName,
- isGetter: invocationKind == InvocationKind.getter,
- isSetter: invocationKind == InvocationKind.setter),
- argDescCpIndex,
- isDynamic));
-
int addDirectCall(
InvocationKind invocationKind, Member target, ObjectHandle argDesc) =>
_add(new ConstantDirectCall(
@@ -762,12 +724,18 @@
argDesc,
objectTable.getHandle(staticReceiverType)));
+ int addDynamicCall(
+ InvocationKind invocationKind, Name selector, ObjectHandle argDesc) =>
+ _add(new ConstantDynamicCall(
+ objectTable.getSelectorNameHandle(selector,
+ isGetter: invocationKind == InvocationKind.getter,
+ isSetter: invocationKind == InvocationKind.setter),
+ argDesc));
+
int addInstanceCall(InvocationKind invocationKind, Member target,
Name targetName, ObjectHandle argDesc) =>
(target == null)
- ? addICData(
- invocationKind, targetName, _add(new ConstantObjectRef(argDesc)),
- isDynamic: true)
+ ? addDynamicCall(invocationKind, targetName, argDesc)
: addInterfaceCall(invocationKind, target, argDesc);
int addStaticField(Field field) =>
diff --git a/pkg/vm/lib/bytecode/dbc.dart b/pkg/vm/lib/bytecode/dbc.dart
index f091eab..790b10b6 100644
--- a/pkg/vm/lib/bytecode/dbc.dart
+++ b/pkg/vm/lib/bytecode/dbc.dart
@@ -10,7 +10,7 @@
/// Before bumping current bytecode version format, make sure that
/// all users have switched to a VM which is able to consume new
/// version of bytecode.
-const int currentBytecodeFormatVersion = 19;
+const int currentBytecodeFormatVersion = 20;
enum Opcode {
kUnusedOpcode000,
diff --git a/pkg/vm/lib/bytecode/declarations.dart b/pkg/vm/lib/bytecode/declarations.dart
index e3d72a2..a84a607 100644
--- a/pkg/vm/lib/bytecode/declarations.dart
+++ b/pkg/vm/lib/bytecode/declarations.dart
@@ -906,6 +906,7 @@
static const int isAsyncFlag = 1 << 4;
static const int isAsyncStarFlag = 1 << 5;
static const int isSyncStarFlag = 1 << 6;
+ static const int isDebuggableFlag = 1 << 7;
final int flags;
final ObjectHandle parent;
@@ -1130,6 +1131,9 @@
factory AnnotationsDeclaration.read(BufferedReader reader) {
return new AnnotationsDeclaration(reader.readPackedObject());
}
+
+ @override
+ String toString() => object.toString();
}
class _Section {
diff --git a/pkg/vm/lib/bytecode/gen_bytecode.dart b/pkg/vm/lib/bytecode/gen_bytecode.dart
index 5c7b744..cee493c 100644
--- a/pkg/vm/lib/bytecode/gen_bytecode.dart
+++ b/pkg/vm/lib/bytecode/gen_bytecode.dart
@@ -4,10 +4,6 @@
library vm.bytecode.gen_bytecode;
-// TODO(askesc): We should not need to call the constant evaluator
-// explicitly once constant-update-2018 is shipped.
-import 'package:front_end/src/api_prototype/constant_evaluator.dart'
- show ConstantEvaluator, EvaluationEnvironment;
import 'package:front_end/src/api_unstable/vm.dart'
show
CompilerContext,
@@ -26,8 +22,6 @@
import 'package:kernel/type_algebra.dart'
show Substitution, containsTypeVariable;
import 'package:kernel/type_environment.dart' show TypeEnvironment;
-import 'package:kernel/vm/constants_native_effects.dart'
- show VmConstantsBackend;
import 'assembler.dart';
import 'bytecode_serialization.dart' show StringTable;
import 'constant_pool.dart';
@@ -56,7 +50,6 @@
import 'recognized_methods.dart' show RecognizedMethods;
import 'recursive_types_validator.dart' show IllegalRecursiveTypeException;
import 'source_positions.dart' show LineStarts, SourcePositions;
-import '../constants_error_reporter.dart' show ForwardConstantEvaluationErrors;
import '../metadata/bytecode.dart';
import 'dart:convert' show utf8;
@@ -81,14 +74,10 @@
hierarchy ??= new ClassHierarchy(component,
onAmbiguousSupertypes: ignoreAmbiguousSupertypes);
final typeEnvironment = new TypeEnvironment(coreTypes, hierarchy);
- final constantsBackend = new VmConstantsBackend(coreTypes);
- final errorReporter = new ForwardConstantEvaluationErrors();
- final constantEvaluator = new ConstantEvaluator(constantsBackend,
- options.environmentDefines, typeEnvironment, errorReporter);
libraries ??= component.libraries;
try {
- final bytecodeGenerator = new BytecodeGenerator(component, coreTypes,
- hierarchy, typeEnvironment, constantEvaluator, options);
+ final bytecodeGenerator = new BytecodeGenerator(
+ component, coreTypes, hierarchy, typeEnvironment, options);
for (var library in libraries) {
bytecodeGenerator.visitLibrary(library);
}
@@ -103,7 +92,6 @@
final CoreTypes coreTypes;
final ClassHierarchy hierarchy;
final TypeEnvironment typeEnvironment;
- final ConstantEvaluator constantEvaluator;
final BytecodeOptions options;
final BytecodeMetadataRepository metadata = new BytecodeMetadataRepository();
final RecognizedMethods recognizedMethods;
@@ -145,7 +133,7 @@
int maxSourcePosition;
BytecodeGenerator(ast.Component component, this.coreTypes, this.hierarchy,
- this.typeEnvironment, this.constantEvaluator, this.options)
+ this.typeEnvironment, this.options)
: recognizedMethods = new RecognizedMethods(typeEnvironment),
formatVersion = currentBytecodeFormatVersion,
astUriToSource = component.uriToSource {
@@ -339,7 +327,7 @@
flags |= ClassDeclaration.hasSourcePositionsFlag;
position = library.fileOffset;
}
- Annotations annotations = getAnnotations(library.annotations);
+ Annotations annotations = getLibraryAnnotations(library);
if (annotations.object != null) {
flags |= ClassDeclaration.hasAnnotationsFlag;
if (annotations.hasPragma) {
@@ -374,8 +362,7 @@
if (nodes.isEmpty) {
return const Annotations(null, false);
}
- List<Constant> constants = constantEvaluator.withNewEnvironment(
- () => nodes.map(_evaluateConstantExpression).toList());
+ List<Constant> constants = nodes.map(_getConstant).toList();
bool hasPragma = constants.any(_isPragma);
if (!options.emitAnnotations) {
if (hasPragma) {
@@ -410,8 +397,7 @@
return const Annotations(null, false);
}
- List<Constant> functionConstants = constantEvaluator.withNewEnvironment(
- () => functionNodes.map(_evaluateConstantExpression).toList());
+ List<Constant> functionConstants = functionNodes.map(_getConstant).toList();
bool hasPragma = functionConstants.any(_isPragma);
if (!options.emitAnnotations && !hasPragma) {
return const Annotations(null, false);
@@ -423,8 +409,8 @@
bytecodeComponent.annotations.add(functionDecl);
for (final parameterNodes in parameterNodeLists) {
- List<Constant> parameterConstants = constantEvaluator.withNewEnvironment(
- () => parameterNodes.map(_evaluateConstantExpression).toList());
+ List<Constant> parameterConstants =
+ parameterNodes.map(_getConstant).toList();
final parameterObject = objectTable
.getHandle(new ListConstant(const DynamicType(), parameterConstants));
final parameterDecl = new AnnotationsDeclaration(parameterObject);
@@ -434,12 +420,72 @@
return new Annotations(functionDecl, hasPragma);
}
+ // Insert annotations for library and its dependencies into the
+ // annotations section. Returns annotations for the library only.
+ // Bytecode reader will implicitly find library dependencies by reading
+ // an extra object after reading library annotations.
+ Annotations getLibraryAnnotations(Library library) {
+ Annotations annotations = getAnnotations(library.annotations);
+ final bool emitDependencies =
+ options.emitAnnotations && library.dependencies.isNotEmpty;
+ if (annotations.object == null && !emitDependencies) {
+ return annotations;
+ }
+
+ // We need to emit both annotations and dependencies objects, appending
+ // null if an object is missing.
+ if (annotations.object == null) {
+ final annotationsDecl = new AnnotationsDeclaration(null);
+ bytecodeComponent.annotations.add(annotationsDecl);
+ annotations = new Annotations(annotationsDecl, false);
+ }
+ if (!emitDependencies) {
+ bytecodeComponent.annotations.add(new AnnotationsDeclaration(null));
+ return annotations;
+ }
+
+ // Create a constant object representing library dependencies.
+ // These objects are used by dart:mirrors and vm-service implementation.
+ final deps = <Constant>[];
+ for (var dependency in library.dependencies) {
+ final prefix = dependency.name != null
+ ? StringConstant(dependency.name)
+ : NullConstant();
+ final showNames = dependency.combinators
+ .where((c) => c.isShow)
+ .expand((c) => c.names)
+ .map((name) => StringConstant(name))
+ .toList();
+ final hideNames = dependency.combinators
+ .where((c) => c.isHide)
+ .expand((c) => c.names)
+ .map((name) => StringConstant(name))
+ .toList();
+ final depAnnots = dependency.annotations.map(_getConstant).toList();
+ deps.add(ListConstant(const DynamicType(), <Constant>[
+ StringConstant(dependency.targetLibrary.importUri.toString()),
+ BoolConstant(dependency.isExport),
+ BoolConstant(dependency.isDeferred),
+ prefix,
+ ListConstant(const DynamicType(), showNames),
+ ListConstant(const DynamicType(), hideNames),
+ ListConstant(const DynamicType(), depAnnots),
+ ]));
+ }
+ final ObjectHandle dependenciesObject =
+ objectTable.getHandle(ListConstant(const DynamicType(), deps));
+ final dependenciesDecl = new AnnotationsDeclaration(dependenciesObject);
+ bytecodeComponent.annotations.add(dependenciesDecl);
+
+ return annotations;
+ }
+
FieldDeclaration getFieldDeclaration(Field field, Code initializer) {
int flags = 0;
Constant value;
if (_hasTrivialInitializer(field)) {
if (field.initializer != null) {
- value = _evaluateConstantExpression(field.initializer);
+ value = _getConstant(field.initializer);
}
} else {
flags |= FieldDeclaration.hasInitializerFlag;
@@ -675,9 +721,11 @@
}
ParameterDeclaration getParameterDeclaration(VariableDeclaration variable) {
- final name = objectTable.getNameHandle(null, variable.name);
- final type = objectTable.getHandle(variable.type);
- return new ParameterDeclaration(name, type);
+ final name = variable.name;
+ final lib = name.startsWith('_') ? enclosingMember.enclosingLibrary : null;
+ final nameHandle = objectTable.getNameHandle(lib, name);
+ final typeHandle = objectTable.getHandle(variable.type);
+ return new ParameterDeclaration(nameHandle, typeHandle);
}
List<int> getParameterFlags(FunctionNode function) {
@@ -935,9 +983,7 @@
_dartFfiLibrary ??= libraryIndex.tryGetLibrary('dart:ffi');
void _recordSourcePosition(int fileOffset) {
- if (options.emitSourcePositions) {
- asm.currentSourcePosition = fileOffset;
- }
+ asm.currentSourcePosition = fileOffset;
maxSourcePosition = math.max(maxSourcePosition, fileOffset);
}
@@ -1029,23 +1075,24 @@
}
}
- Constant _evaluateConstantExpression(Expression expr) {
+ Constant _getConstant(Expression expr) {
if (expr is ConstantExpression) {
return expr.constant;
}
- final constant = constantEvaluator.evaluate(expr);
- if (constant is UnevaluatedConstant &&
- constant.expression is InvalidExpression) {
- // Compile-time error is already reported. Proceed with compilation
- // in order to report errors in other constant expressions.
- hasErrors = true;
- return new NullConstant();
- }
- return constant;
+
+ // Literals outside of const expressions are not transformed by the
+ // constant transformer, but they need to be treated as constants here.
+ if (expr is BoolLiteral) return new BoolConstant(expr.value);
+ if (expr is DoubleLiteral) return new DoubleConstant(expr.value);
+ if (expr is IntLiteral) return new IntConstant(expr.value);
+ if (expr is NullLiteral) return new NullConstant();
+ if (expr is StringLiteral) return new StringConstant(expr.value);
+
+ throw 'Expected constant, got ${expr.runtimeType}';
}
void _genPushConstExpr(Expression expr) {
- final constant = _evaluateConstantExpression(expr);
+ final constant = _getConstant(expr);
if (constant is NullConstant) {
asm.emitPushNull();
} else if (constant is BoolConstant) {
@@ -1302,16 +1349,11 @@
if (condition is BoolLiteral) {
return condition.value;
}
- Constant constant;
if (condition is ConstantExpression) {
- constant = condition.constant;
- } else if ((condition is StaticGet && condition.target.isConst) ||
- (condition is StaticInvocation && condition.isConst) ||
- (condition is VariableGet && condition.variable.isConst)) {
- constant = _evaluateConstantExpression(condition);
- }
- if (constant is BoolConstant) {
- return constant.value;
+ Constant constant = condition.constant;
+ if (constant is BoolConstant) {
+ return constant.value;
+ }
}
return null;
}
@@ -1324,6 +1366,29 @@
}
return;
}
+ if (condition is MethodInvocation &&
+ condition.name.name == '==' &&
+ (condition.receiver is NullLiteral ||
+ condition.arguments.positional.single is NullLiteral)) {
+ if (condition.receiver is NullLiteral) {
+ _generateNode(condition.arguments.positional.single);
+ } else {
+ _generateNode(condition.receiver);
+ }
+ if (options.emitDebuggerStops &&
+ condition.fileOffset != TreeNode.noOffset) {
+ final savedSourcePosition = asm.currentSourcePosition;
+ _recordSourcePosition(condition.fileOffset);
+ asm.emitDebugCheck();
+ asm.currentSourcePosition = savedSourcePosition;
+ }
+ if (value) {
+ asm.emitJumpIfNull(dest);
+ } else {
+ asm.emitJumpIfNotNull(dest);
+ }
+ return;
+ }
bool negated = _genCondition(condition);
if (value) {
_genJumpIfTrue(negated, dest);
@@ -1336,7 +1401,7 @@
if (param.initializer == null) {
return cp.addObjectRef(null);
}
- final constant = _evaluateConstantExpression(param.initializer);
+ final constant = _getConstant(param.initializer);
return cp.addObjectRef(constant);
}
@@ -1415,7 +1480,6 @@
new List<TypeParameter>.from(enclosingFunction.typeParameters);
functionTypeParametersSet = functionTypeParameters.toSet();
}
- constantEvaluator.env = new EvaluationEnvironment();
if (!hasCode) {
return;
}
@@ -1430,7 +1494,7 @@
initializedFields = null; // Tracked for constructors only.
nullableFields = const <ObjectHandle>[];
cp = new ConstantPool(stringTable, objectTable);
- asm = new BytecodeAssembler();
+ asm = new BytecodeAssembler(options);
savedAssemblers = <BytecodeAssembler>[];
currentLoopDepth = 0;
savedMaxSourcePositions = <int>[];
@@ -1537,7 +1601,6 @@
functionTypeParametersSet = null;
instantiatorTypeArguments = null;
locals = null;
- constantEvaluator.env = null;
labeledStatements = null;
switchCases = null;
tryCatches = null;
@@ -1603,7 +1666,6 @@
} else {
asm.emitEntry(locals.frameSize);
}
- asm.emitCheckStack(0);
if (isClosure) {
asm.emitPush(locals.closureVarIndexInFrame);
@@ -1611,6 +1673,10 @@
asm.emitPopLocal(locals.contextVarIndexInFrame);
}
+ // CheckStack must see a properly initialized context when stress-testing
+ // stack trace collection.
+ asm.emitCheckStack(0);
+
if (locals.hasFunctionTypeArgsVar) {
if (function.typeParameters.isNotEmpty) {
assert(!(node is Procedure && node.isFactory));
@@ -2045,20 +2111,13 @@
void _pushAssemblerState() {
savedAssemblers.add(asm);
- asm = new BytecodeAssembler();
+ asm = new BytecodeAssembler(options);
}
void _popAssemblerState() {
asm = savedAssemblers.removeLast();
}
- void _evaluateDefaultParameterValue(VariableDeclaration param) {
- if (param.initializer != null && param.initializer is! BasicLiteral) {
- final constant = _evaluateConstantExpression(param.initializer);
- param.initializer = new ConstantExpression(constant)..parent = param;
- }
- }
-
int _genClosureBytecode(
LocalFunction node, String name, FunctionNode function) {
_pushAssemblerState();
@@ -2082,12 +2141,6 @@
List<Label> savedYieldPoints = yieldPoints;
yieldPoints = locals.isSyncYieldingFrame ? <Label>[] : null;
- // Replace default values of optional parameters with constants,
- // as default value expressions could use local const variables which
- // are not available in bytecode.
- function.positionalParameters.forEach(_evaluateDefaultParameterValue);
- locals.sortedNamedParameters.forEach(_evaluateDefaultParameterValue);
-
final int closureIndex = closures.length;
final closure = getClosureDeclaration(node, function, name, closureIndex,
savedIsClosure ? parentFunction : enclosingMember);
@@ -2102,11 +2155,14 @@
parentFunction != null &&
(parentFunction.dartAsyncMarker == AsyncMarker.Async ||
parentFunction.dartAsyncMarker == AsyncMarker.AsyncStar)) {
+ final savedSourcePosition = asm.currentSourcePosition;
+ _recordSourcePosition(TreeNode.noOffset);
_genLoadVar(locals.asyncStackTraceVar,
currentContextLevel: locals.contextLevelAtEntry);
_genDirectCall(
setAsyncThreadStackTrace, objectTable.getArgDescHandle(1), 1);
asm.emitDrop1();
+ asm.currentSourcePosition = savedSourcePosition;
}
Label continuationSwitchLabel;
@@ -2190,6 +2246,7 @@
flags |= ClosureDeclaration.isSyncStarFlag;
break;
default:
+ flags |= ClosureDeclaration.isDebuggableFlag;
break;
}
@@ -2447,7 +2504,7 @@
/// the last finally block.
void _generateNonLocalControlTransfer(
TreeNode from, TreeNode to, GenerateContinuation continuation) {
- if (options.emitDebuggerStops) {
+ if (options.emitDebuggerStops && from.fileOffset != TreeNode.noOffset) {
asm.emitDebugCheck(); // Before context is unwound.
}
List<TryFinally> tryFinallyBlocks = _getEnclosingTryFinallyBlocks(from, to);
@@ -3063,6 +3120,10 @@
}
}
tryCatches[tryCatch].needsStackTrace = true;
+
+ if (options.emitDebuggerStops) {
+ asm.emitDebugCheck(); // Allow breakpoint on explicit rethrow statement.
+ }
_genRethrow(tryCatch);
}
@@ -3076,13 +3137,8 @@
initializer is NullLiteral) {
return true;
}
- Constant constValue;
- if (initializer is ConstantExpression) {
- constValue = initializer.constant;
- } else if (field.isConst) {
- constValue = _evaluateConstantExpression(initializer);
- }
- if (constValue is PrimitiveConstant) {
+ if (initializer is ConstantExpression &&
+ initializer.constant is PrimitiveConstant) {
return true;
}
return false;
@@ -3158,6 +3214,10 @@
final target = node.target;
if (target is Field) {
+ if (options.emitDebuggerStops &&
+ _variableSetNeedsDebugCheck(node.value)) {
+ asm.emitDebugCheck();
+ }
int cpIndex = cp.addStaticField(target);
asm.emitStoreStaticTOS(cpIndex);
} else {
@@ -3209,6 +3269,10 @@
@override
visitThrow(Throw node) {
_generateNode(node.expression);
+
+ if (options.emitDebuggerStops) {
+ asm.emitDebugCheck();
+ }
asm.emitThrow(0);
}
@@ -3273,7 +3337,8 @@
rhs is ConstantExpression ||
rhs is StaticGet ||
rhs is FunctionExpression ||
- rhs is VariableGet;
+ rhs is VariableGet ||
+ rhs is AsExpression;
void _genFutureNull() {
asm.emitPushNull();
@@ -3413,6 +3478,7 @@
// Front-end inserts implicit cast (type check) which ensures that
// result of iterable expression is Iterable<dynamic>.
+ _recordSourcePosition(node.iterable.fileOffset);
asm.emitInterfaceCall(
cp.addInterfaceCall(InvocationKind.getter, iterableIterator,
objectTable.getArgDescHandle(1)),
@@ -3454,6 +3520,7 @@
_genJumpIfFalse(/* negated = */ false, done);
_enterScope(node);
+ _recordSourcePosition(node.bodyOffset);
_genPushContextIfCaptured(node.variable);
@@ -3569,6 +3636,10 @@
_generateNode(expr);
_genReturnTOS();
} else {
+ if (options.emitDebuggerStops) {
+ // Stop on the return statement before executing finally blocks.
+ asm.emitDebugCheck();
+ }
if (expr is BasicLiteral) {
_addFinallyBlocks(tryFinallyBlocks, () {
_generateNode(expr);
@@ -3617,15 +3688,18 @@
if (switchCase.isDefault) {
defaultLabel = caseLabel;
} else {
- for (var expr in switchCase.expressions) {
+ final savedSourcePosition = asm.currentSourcePosition;
+ for (int i = 0; i < switchCase.expressions.length; ++i) {
+ _recordSourcePosition(switchCase.expressionOffsets[i]);
asm.emitPush(temp);
- _genPushConstExpr(expr);
+ _genPushConstExpr(switchCase.expressions[i]);
asm.emitInterfaceCall(
cp.addInterfaceCall(
InvocationKind.method, coreTypes.objectEquals, equalsArgDesc),
2);
_genJumpIfTrue(/* negated = */ false, caseLabel);
}
+ asm.currentSourcePosition = savedSourcePosition;
}
}
@@ -3786,7 +3860,9 @@
bool hasCatchAll = false;
+ final savedSourcePosition = asm.currentSourcePosition;
for (Catch catchClause in node.catches) {
+ _recordSourcePosition(catchClause.fileOffset);
tryBlock.types.add(cp.addType(catchClause.guard));
Label skipCatch;
@@ -3824,6 +3900,7 @@
asm.bind(skipCatch);
}
}
+ asm.currentSourcePosition = savedSourcePosition;
if (!hasCatchAll) {
tryBlock.needsStackTrace = true;
@@ -3874,10 +3951,7 @@
@override
visitVariableDeclaration(VariableDeclaration node) {
- if (node.isConst) {
- final Constant constant = _evaluateConstantExpression(node.initializer);
- constantEvaluator.env.addVariableValue(node, constant);
- } else {
+ if (!node.isConst) {
final bool isCaptured = locals.isCaptured(node);
if (isCaptured) {
_genPushContextForVariable(node);
@@ -3891,7 +3965,9 @@
asm.emitPushNull();
}
- if (options.emitDebuggerStops) {
+ if (options.emitDebuggerStops &&
+ (node.initializer == null ||
+ _variableSetNeedsDebugCheck(node.initializer))) {
final savedSourcePosition = asm.currentSourcePosition;
if (node.fileEqualsOffset != TreeNode.noOffset) {
_recordSourcePosition(node.fileEqualsOffset);
diff --git a/pkg/vm/lib/bytecode/local_vars.dart b/pkg/vm/lib/bytecode/local_vars.dart
index d2d32f0..4176254 100644
--- a/pkg/vm/lib/bytecode/local_vars.dart
+++ b/pkg/vm/lib/bytecode/local_vars.dart
@@ -390,6 +390,13 @@
_useVariable(_currentFrame.parent
.getSyntheticVar(ContinuationVariables.awaitContextVar));
+ // Debugger looks for :controller_stream variable among captured
+ // variables in a context, so make sure to capture it.
+ if (_currentFrame.parent.dartAsyncMarker == AsyncMarker.AsyncStar) {
+ _useVariable(_currentFrame.parent
+ .getSyntheticVar(ContinuationVariables.controllerStreamVar));
+ }
+
if (locals.options.causalAsyncStacks &&
(_currentFrame.parent.dartAsyncMarker == AsyncMarker.Async ||
_currentFrame.parent.dartAsyncMarker ==
diff --git a/pkg/vm/lib/bytecode/object_table.dart b/pkg/vm/lib/bytecode/object_table.dart
index 688f437..9b35141 100644
--- a/pkg/vm/lib/bytecode/object_table.dart
+++ b/pkg/vm/lib/bytecode/object_table.dart
@@ -6,6 +6,7 @@
import 'package:kernel/ast.dart' hide MapEntry;
import 'package:kernel/core_types.dart' show CoreTypes;
+import 'package:kernel/type_algebra.dart' show getFreshTypeParameters;
import 'bytecode_serialization.dart'
show
@@ -2059,8 +2060,27 @@
.getOrAddObject(new _TypeParameterHandle(parentHandle, indexInParent));
}
+ /// This is a workaround to <https://github.com/dart-lang/sdk/issues/37536>.
+ /// TODO(37536): remove this workaround once the issue is fixed.
+ ///
+ /// In certain cases, front-end produces function types with type parameters
+ /// which already belong to a closure. This results in the incorrect
+ /// canonicalization of types.
+ ///
+ /// This method corrects FunctionType by creating fresh type parameters.
+ FunctionType _fixTypeParameters(FunctionType type) {
+ for (var typeParam in type.typeParameters) {
+ if (typeParam.parent != null) {
+ final fresh = getFreshTypeParameters(type.typeParameters);
+ return fresh.applyToFunctionType(type);
+ }
+ }
+ return type;
+ }
+
@override
ObjectHandle visitFunctionType(FunctionType node) {
+ node = _fixTypeParameters(node);
final int numEnclosingTypeParameters = _typeParameters.length;
for (int i = 0; i < node.typeParameters.length; ++i) {
_typeParameters[node.typeParameters[i]] = objectTable.getOrAddObject(
diff --git a/pkg/vm/lib/bytecode/source_positions.dart b/pkg/vm/lib/bytecode/source_positions.dart
index ec56aa15..5d28c90 100644
--- a/pkg/vm/lib/bytecode/source_positions.dart
+++ b/pkg/vm/lib/bytecode/source_positions.dart
@@ -15,6 +15,9 @@
/// Maintains mapping between bytecode instructions and source positions.
class SourcePositions {
+ // Special value of fileOffset which marks synthetic code without source
+ // position.
+ static const syntheticCodeMarker = -1;
// Special value of fileOffset which marks yield point.
static const yieldPointMarker = -2;
@@ -26,7 +29,7 @@
void add(int pc, int fileOffset) {
assert(pc > _lastPc);
- assert(fileOffset >= 0);
+ assert((fileOffset >= 0) || (fileOffset == syntheticCodeMarker));
if (fileOffset != _lastOffset) {
_positions.add(pc);
_positions.add(fileOffset);
diff --git a/pkg/vm/lib/constants_error_reporter.dart b/pkg/vm/lib/constants_error_reporter.dart
deleted file mode 100644
index 724f5d8..0000000
--- a/pkg/vm/lib/constants_error_reporter.dart
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright (c) 2018, 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.
-
-/// Defines [ForwardConstantEvaluationErrors], an implementation of
-/// [constants.ErrorReporter] which uses package:front_end to report errors.
-library vm.constants_error_reporter;
-
-import 'package:front_end/src/api_prototype/constant_evaluator.dart'
- as constants;
-
-import 'package:front_end/src/api_unstable/vm.dart'
- show CompilerContext, LocatedMessage, Severity;
-
-import 'package:kernel/ast.dart' show InvalidExpression;
-
-class ForwardConstantEvaluationErrors implements constants.ErrorReporter {
- // This will get the currently active [CompilerContext] from a zone variable.
- // If there is no active context, this will throw.
- final CompilerContext compilerContext = CompilerContext.current;
-
- @override
- void report(LocatedMessage message, List<LocatedMessage> context) {
- compilerContext.options.report(message, Severity.error, context: context);
- }
-
- @override
- void reportInvalidExpression(InvalidExpression node) {
- // Assumed to be already reported.
- }
-}
diff --git a/pkg/vm/lib/kernel_front_end.dart b/pkg/vm/lib/kernel_front_end.dart
index ced23df..49262b7 100644
--- a/pkg/vm/lib/kernel_front_end.dart
+++ b/pkg/vm/lib/kernel_front_end.dart
@@ -13,11 +13,6 @@
import 'package:build_integration/file_system/multi_root.dart'
show MultiRootFileSystem, MultiRootFileSystemEntity;
-// TODO(askesc): We should not need to call the constant evaluator
-// explicitly once constant-update-2018 is shipped.
-import 'package:front_end/src/api_prototype/constant_evaluator.dart'
- as constants;
-
import 'package:front_end/src/api_unstable/vm.dart'
show
CompilerContext,
@@ -38,21 +33,18 @@
printDiagnosticMessage;
import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
-import 'package:kernel/ast.dart'
- show Component, Field, Library, Reference, StaticGet;
+import 'package:kernel/ast.dart' show Component, Library, Reference;
import 'package:kernel/binary/ast_to_binary.dart' show BinaryPrinter;
import 'package:kernel/binary/limited_ast_to_binary.dart'
show LimitedBinaryPrinter;
import 'package:kernel/core_types.dart' show CoreTypes;
import 'package:kernel/target/targets.dart' show Target, TargetFlags, getTarget;
-import 'package:kernel/vm/constants_native_effects.dart' as vm_constants;
import 'bytecode/bytecode_serialization.dart' show BytecodeSizeStatistics;
import 'bytecode/gen_bytecode.dart'
show generateBytecode, createFreshComponentWithBytecode;
import 'bytecode/options.dart' show BytecodeOptions;
-import 'constants_error_reporter.dart' show ForwardConstantEvaluationErrors;
import 'target/install.dart' show installAdditionalTargets;
import 'transformations/devirtualization.dart' as devirtualization
show transformComponent;
@@ -106,9 +98,6 @@
help: 'The values for the environment constants (e.g. -Dkey=value).');
args.addFlag('enable-asserts',
help: 'Whether asserts will be enabled.', defaultsTo: false);
- args.addFlag('enable-constant-evaluation',
- help: 'Whether kernel constant evaluation will be enabled.',
- defaultsTo: true);
args.addFlag('split-output-by-packages',
help:
'Split resulting kernel file into multiple files (one per package).',
@@ -167,7 +156,6 @@
final bool genBytecode = options['gen-bytecode'];
final bool dropAST = options['drop-ast'];
final bool enableAsserts = options['enable-asserts'];
- final bool enableConstantEvaluation = options['enable-constant-evaluation'];
final bool useProtobufTreeShaker = options['protobuf-tree-shaker'];
final bool splitOutputByPackages = options['split-output-by-packages'];
final List<String> experimentalFlags = options['enable-experiment'];
@@ -231,7 +219,6 @@
genBytecode: genBytecode,
bytecodeOptions: bytecodeOptions,
dropAST: dropAST && !splitOutputByPackages,
- enableConstantEvaluation: enableConstantEvaluation,
useProtobufTreeShaker: useProtobufTreeShaker);
errorPrinter.printCompilationMessages();
@@ -284,7 +271,6 @@
bool genBytecode: false,
BytecodeOptions bytecodeOptions,
bool dropAST: false,
- bool enableConstantEvaluation: true,
bool useProtobufTreeShaker: false}) async {
// Replace error handler to detect if there are compilation errors.
final errorDetector =
@@ -303,7 +289,6 @@
component,
useGlobalTypeFlowAnalysis,
environmentDefines,
- enableConstantEvaluation,
useProtobufTreeShaker,
errorDetector);
}
@@ -354,13 +339,11 @@
Component component,
bool useGlobalTypeFlowAnalysis,
Map<String, String> environmentDefines,
- bool enableConstantEvaluation,
bool useProtobufTreeShaker,
ErrorDetector errorDetector) async {
if (errorDetector.hasCompilationErrors) return;
final coreTypes = new CoreTypes(component);
- _patchVmConstants(coreTypes);
// TODO(alexmarkov, dmitryas): Consider doing canonicalization of identical
// mixin applications when creating mixin applications in frontend,
@@ -370,13 +353,6 @@
// when building a platform dill file for VM/JIT case.
mixin_deduplication.transformComponent(component);
- if (enableConstantEvaluation) {
- await _performConstantEvaluation(
- source, compilerOptions, component, coreTypes, environmentDefines);
-
- if (errorDetector.hasCompilationErrors) return;
- }
-
if (useGlobalTypeFlowAnalysis) {
globalTypeFlow.transformComponent(
compilerOptions.target, coreTypes, component);
@@ -427,40 +403,6 @@
});
}
-Future _performConstantEvaluation(
- Uri source,
- CompilerOptions compilerOptions,
- Component component,
- CoreTypes coreTypes,
- Map<String, String> environmentDefines) async {
- final vmConstants = new vm_constants.VmConstantsBackend(coreTypes);
-
- await runWithFrontEndCompilerContext(source, compilerOptions, component, () {
- // TFA will remove constants fields which are unused (and respects the
- // vm/embedder entrypoints).
- constants.transformComponent(component, vmConstants, environmentDefines,
- new ForwardConstantEvaluationErrors(),
- keepFields: true,
- evaluateAnnotations: true,
- desugarSets: !compilerOptions.target.supportsSetLiterals);
- });
-}
-
-void _patchVmConstants(CoreTypes coreTypes) {
- // Fix Endian.host to be a const field equal to Endial.little instead of
- // a final field. VM does not support big-endian architectures at the
- // moment.
- // Can't use normal patching process for this because CFE does not
- // support patching fields.
- // See http://dartbug.com/32836 for the background.
- final Field host =
- coreTypes.index.getMember('dart:typed_data', 'Endian', 'host');
- host.isConst = true;
- host.initializer = new StaticGet(
- coreTypes.index.getMember('dart:typed_data', 'Endian', 'little'))
- ..parent = host;
-}
-
class ErrorDetector {
final DiagnosticMessageHandler previousErrorHandler;
bool hasCompilationErrors = false;
diff --git a/pkg/vm/lib/target/dart_runner.dart b/pkg/vm/lib/target/dart_runner.dart
index 923898e..270f365 100644
--- a/pkg/vm/lib/target/dart_runner.dart
+++ b/pkg/vm/lib/target/dart_runner.dart
@@ -32,10 +32,10 @@
// PRODUCT mode.
'dart:mirrors',
- 'dart:profiler',
'dart:typed_data',
'dart:nativewrappers',
'dart:io',
+ 'dart:wasm',
// Required for dart_runner.
'dart:fuchsia.builtin',
@@ -43,4 +43,9 @@
'dart:fuchsia',
'dart:vmservice_io',
];
+
+ @override
+ List<String> get extraRequiredLibrariesPlatform => const <String>[
+ 'dart:profiler',
+ ];
}
diff --git a/pkg/vm/lib/target/flutter.dart b/pkg/vm/lib/target/flutter.dart
index ed4683c..8022a27 100644
--- a/pkg/vm/lib/target/flutter.dart
+++ b/pkg/vm/lib/target/flutter.dart
@@ -37,10 +37,10 @@
// PRODUCT mode.
'dart:mirrors',
- 'dart:profiler',
'dart:typed_data',
'dart:nativewrappers',
'dart:io',
+ 'dart:wasm',
// Required for flutter.
'dart:ui',
@@ -48,12 +48,20 @@
];
@override
+ List<String> get extraRequiredLibrariesPlatform => const <String>[
+ 'dart:profiler',
+ ];
+
+ @override
void performPreConstantEvaluationTransformations(
Component component,
CoreTypes coreTypes,
List<Library> libraries,
DiagnosticReporter diagnosticReporter,
{void logger(String msg)}) {
+ super.performPreConstantEvaluationTransformations(
+ component, coreTypes, libraries, diagnosticReporter,
+ logger: logger);
if (flags.trackWidgetCreation) {
if (_widgetTracker == null) {
_widgetTracker = WidgetCreatorTracker();
diff --git a/pkg/vm/lib/target/flutter_runner.dart b/pkg/vm/lib/target/flutter_runner.dart
index 9266f3a..53363e2 100644
--- a/pkg/vm/lib/target/flutter_runner.dart
+++ b/pkg/vm/lib/target/flutter_runner.dart
@@ -32,10 +32,10 @@
// PRODUCT mode.
'dart:mirrors',
- 'dart:profiler',
'dart:typed_data',
'dart:nativewrappers',
'dart:io',
+ 'dart:wasm',
// Required for flutter_runner.
'dart:fuchsia.builtin',
@@ -44,4 +44,9 @@
'dart:vmservice_io',
'dart:ui',
];
+
+ @override
+ List<String> get extraRequiredLibrariesPlatform => const <String>[
+ 'dart:profiler',
+ ];
}
diff --git a/pkg/vm/lib/target/vm.dart b/pkg/vm/lib/target/vm.dart
index 8a6dc24..23a6832 100644
--- a/pkg/vm/lib/target/vm.dart
+++ b/pkg/vm/lib/target/vm.dart
@@ -6,6 +6,7 @@
import 'dart:core' hide MapEntry;
import 'package:kernel/ast.dart';
+import 'package:kernel/clone.dart';
import 'package:kernel/class_hierarchy.dart';
import 'package:kernel/core_types.dart';
import 'package:kernel/target/targets.dart';
@@ -68,7 +69,6 @@
// PRODUCT mode.
'dart:mirrors',
- 'dart:profiler',
'dart:typed_data',
'dart:vmservice_io',
'dart:_vmservice',
@@ -76,6 +76,53 @@
'dart:nativewrappers',
'dart:io',
'dart:cli',
+ 'dart:wasm',
+ ];
+
+ @override
+ List<String> get extraRequiredLibrariesPlatform => const <String>[
+ 'dart:profiler',
+ ];
+
+ void _patchVmConstants(CoreTypes coreTypes) {
+ // Fix Endian.host to be a const field equal to Endian.little instead of
+ // a final field. VM does not support big-endian architectures at the
+ // moment.
+ // Can't use normal patching process for this because CFE does not
+ // support patching fields.
+ // See http://dartbug.com/32836 for the background.
+ final Field host =
+ coreTypes.index.getMember('dart:typed_data', 'Endian', 'host');
+ final Field little =
+ coreTypes.index.getMember('dart:typed_data', 'Endian', 'little');
+ host.isConst = true;
+ host.initializer = new CloneVisitor().clone(little.initializer)
+ ..parent = host;
+ }
+
+ @override
+ void performPreConstantEvaluationTransformations(
+ Component component,
+ CoreTypes coreTypes,
+ List<Library> libraries,
+ DiagnosticReporter diagnosticReporter,
+ {void logger(String msg)}) {
+ super.performPreConstantEvaluationTransformations(
+ component, coreTypes, libraries, diagnosticReporter,
+ logger: logger);
+ _patchVmConstants(coreTypes);
+ }
+
+ @override
+ List<String> get extraIndexedLibraries => const <String>[
+ // TODO(askesc): When the VM supports set literals, we no longer
+ // need to index dart:collection, as it is only needed for desugaring of
+ // const sets. We can remove it from this list at that time.
+ "dart:collection",
+ // TODO(askesc): This is for the VM host endian optimization, which
+ // could possibly be done more cleanly after the VM no longer supports
+ // doing constant evaluation on its own. See http://dartbug.com/32836
+ "dart:typed_data",
];
@override
@@ -307,6 +354,13 @@
]));
}
+ // In addition to the default implementation, we allow VM tests to import
+ // private platform libraries - such as `dart:_internal` - for testing
+ // purposes.
+ bool allowPlatformPrivateLibraryAccess(Uri importer, Uri imported) =>
+ super.allowPlatformPrivateLibraryAccess(importer, imported) ||
+ importer.path.contains('runtime/tests/vm/dart');
+
// TODO(sigmund,ahe): limit this to `dart-ext` libraries only (see
// https://github.com/dart-lang/sdk/issues/29763).
@override
diff --git a/pkg/vm/lib/transformations/ffi.dart b/pkg/vm/lib/transformations/ffi.dart
index 667a2e9..6b47324 100644
--- a/pkg/vm/lib/transformations/ffi.dart
+++ b/pkg/vm/lib/transformations/ffi.dart
@@ -186,6 +186,8 @@
final Constructor structFromPointer;
final Procedure libraryLookupMethod;
final Procedure abiMethod;
+ final Procedure pointerFromFunctionProcedure;
+ final Procedure nativeCallbackFunctionProcedure;
/// Classes corresponding to [NativeType], indexed by [NativeType].
final List<Class> nativeTypesClasses;
@@ -220,6 +222,10 @@
libraryLookupMethod =
index.getMember('dart:ffi', 'DynamicLibrary', 'lookup'),
abiMethod = index.getTopLevelMember('dart:ffi', '_abi'),
+ pointerFromFunctionProcedure =
+ index.getTopLevelMember('dart:ffi', '_pointerFromFunction'),
+ nativeCallbackFunctionProcedure =
+ index.getTopLevelMember('dart:ffi', '_nativeCallbackFunction'),
nativeTypesClasses = nativeTypeClassNames
.map((name) => index.getClass('dart:ffi', name))
.toList();
diff --git a/pkg/vm/lib/transformations/ffi_definitions.dart b/pkg/vm/lib/transformations/ffi_definitions.dart
index 8bef2ca..c82b64f 100644
--- a/pkg/vm/lib/transformations/ffi_definitions.dart
+++ b/pkg/vm/lib/transformations/ffi_definitions.dart
@@ -85,6 +85,12 @@
: super(index, coreTypes, hierarchy, diagnosticReporter) {}
@override
+ visitExtension(Extension node) {
+ // The extension and it's members are only metadata.
+ return node;
+ }
+
+ @override
visitClass(Class node) {
if (!hierarchy.isSubclassOf(node, structClass) || node == structClass) {
return node;
diff --git a/pkg/vm/lib/transformations/ffi_use_sites.dart b/pkg/vm/lib/transformations/ffi_use_sites.dart
index 58b0acd..d7cc4b5 100644
--- a/pkg/vm/lib/transformations/ffi_use_sites.dart
+++ b/pkg/vm/lib/transformations/ffi_use_sites.dart
@@ -6,12 +6,16 @@
import 'package:front_end/src/api_unstable/vm.dart'
show
+ messageFfiExceptionalReturnNull,
+ messageFfiExpectedConstant,
+ templateFfiDartTypeMismatch,
+ templateFfiExpectedExceptionalReturn,
+ templateFfiExpectedNoExceptionalReturn,
+ templateFfiExtendsOrImplementsSealedClass,
+ templateFfiNotStatic,
templateFfiTypeInvalid,
templateFfiTypeMismatch,
- templateFfiDartTypeMismatch,
- templateFfiTypeUnsized,
- templateFfiNotStatic,
- templateFfiExtendsOrImplementsSealedClass;
+ templateFfiTypeUnsized;
import 'package:kernel/ast.dart';
import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
@@ -55,7 +59,12 @@
final Map<Field, Procedure> replacedGetters;
final Map<Field, Procedure> replacedSetters;
- bool isFfiLibrary;
+ Library currentLibrary;
+ bool get isFfiLibrary => currentLibrary == ffiLibrary;
+
+ // Used to create private top-level fields with unique names for each
+ // callback.
+ int callbackCount = 0;
_FfiUseSiteTransformer(
LibraryIndex index,
@@ -68,7 +77,8 @@
@override
TreeNode visitLibrary(Library node) {
- isFfiLibrary = node == ffiLibrary;
+ currentLibrary = node;
+ callbackCount = 0;
return super.visitLibrary(node);
}
@@ -78,6 +88,11 @@
try {
_ensureNotExtendsOrImplementsSealedClass(node);
return super.visitClass(node);
+ } on _FfiStaticTypeError {
+ // It's OK to swallow the exception because the diagnostics issued will
+ // cause compilation to fail. By continuing, we can report more
+ // diagnostics before compilation ends.
+ return super.visitClass(node);
} finally {
env.thisType = null;
}
@@ -115,31 +130,89 @@
Member target = node.target;
try {
if (target == fromFunctionMethod) {
- DartType nativeType =
+ final DartType nativeType =
InterfaceType(nativeFunctionClass, [node.arguments.types[0]]);
- Expression func = node.arguments.positional[0];
- DartType dartType = func.getStaticType(env);
+ final Expression func = node.arguments.positional[0];
+ final DartType dartType = func.getStaticType(env);
- _ensureIsStatic(func);
+ _ensureIsStaticFunction(func);
+
// TODO(36730): Allow passing/returning structs by value.
_ensureNativeTypeValid(nativeType, node);
_ensureNativeTypeToDartType(nativeType, dartType, node);
// Check `exceptionalReturn`'s type.
final FunctionType funcType = dartType;
- final Expression exceptionalReturn = node.arguments.positional[1];
- final DartType returnType = exceptionalReturn.getStaticType(env);
+ final NativeType expectedReturn = getType(
+ ((node.arguments.types[0] as FunctionType).returnType
+ as InterfaceType)
+ .classNode);
- if (!env.isSubtypeOf(returnType, funcType.returnType)) {
- diagnosticReporter.report(
- templateFfiDartTypeMismatch.withArguments(
- returnType, funcType.returnType),
- exceptionalReturn.fileOffset,
- 1,
- exceptionalReturn.location.file);
+ if (expectedReturn == NativeType.kVoid ||
+ expectedReturn == NativeType.kPointer) {
+ if (node.arguments.positional.length > 1) {
+ diagnosticReporter.report(
+ templateFfiExpectedNoExceptionalReturn
+ .withArguments(funcType.returnType),
+ node.fileOffset,
+ 1,
+ node.location.file);
+ return node;
+ }
+ node.arguments.positional.add(NullLiteral()..parent = node);
+ } else {
+ // The exceptional return value is not optional for other return
+ // types.
+ if (node.arguments.positional.length < 2) {
+ diagnosticReporter.report(
+ templateFfiExpectedExceptionalReturn
+ .withArguments(funcType.returnType),
+ node.fileOffset,
+ 1,
+ node.location.file);
+ return node;
+ }
+
+ final Expression exceptionalReturn = node.arguments.positional[1];
+
+ // The exceptional return value must be a constant so that it be
+ // referenced by precompiled trampoline's object pool.
+ if (exceptionalReturn is! BasicLiteral &&
+ !(exceptionalReturn is ConstantExpression &&
+ exceptionalReturn.constant is PrimitiveConstant)) {
+ diagnosticReporter.report(messageFfiExpectedConstant,
+ node.fileOffset, 1, node.location.file);
+ return node;
+ }
+
+ // Moreover it may not be null.
+ if (exceptionalReturn is NullLiteral ||
+ (exceptionalReturn is ConstantExpression &&
+ exceptionalReturn.constant is NullConstant)) {
+ diagnosticReporter.report(messageFfiExceptionalReturnNull,
+ node.fileOffset, 1, node.location.file);
+ return node;
+ }
+
+ final DartType returnType = exceptionalReturn.getStaticType(env);
+
+ if (!env.isSubtypeOf(returnType, funcType.returnType)) {
+ diagnosticReporter.report(
+ templateFfiDartTypeMismatch.withArguments(
+ returnType, funcType.returnType),
+ exceptionalReturn.fileOffset,
+ 1,
+ exceptionalReturn.location.file);
+ return node;
+ }
}
+ return _replaceFromFunction(node);
}
- } catch (_FfiStaticTypeError) {}
+ } on _FfiStaticTypeError {
+ // It's OK to swallow the exception because the diagnostics issued will
+ // cause compilation to fail. By continuing, we can report more
+ // diagnostics before compilation ends.
+ }
return node;
}
@@ -151,10 +224,10 @@
// 'lookupFunction' are constants, so by inlining the call to 'asFunction' at
// the call-site, we ensure that there are no generic calls to 'asFunction'.
//
- // We will not detect dynamic invocations of 'asFunction' -- these are handled
- // by the stub in 'dynamic_library_patch.dart'. Dynamic invocations of
- // 'lookupFunction' (and 'asFunction') are not legal and throw a runtime
- // exception.
+ // We will not detect dynamic invocations of 'asFunction' and
+ // 'lookupFunction': these are handled by the stubs in 'ffi_patch.dart' and
+ // 'dynamic_library_patch.dart'. Dynamic invocations of 'lookupFunction' (and
+ // 'asFunction') are not legal and throw a runtime exception.
Expression _replaceLookupFunction(MethodInvocation node) {
// The generated code looks like:
//
@@ -176,6 +249,39 @@
Arguments([lookupResult], types: [dartSignature, nativeSignature]));
}
+ // We need to rewrite calls to 'fromFunction' into two calls, representing the
+ // compile-time and run-time aspects of creating the closure:
+ //
+ // final dynamic _#ffiCallback0 = Pointer.fromFunction<T>(f, e) =>
+ // _pointerFromFunction<NativeFunction<T>>(
+ // _nativeCallbackFunction<T>(f, e));
+ //
+ // ... _#ffiCallback0 ...
+ //
+ // We must implement this as a Kernel rewrite because <T> must be a
+ // compile-time constant to any invocation of '_nativeCallbackFunction'.
+ //
+ // Creating this closure requires a runtime call, so we save the result in a
+ // synthetic top-level field to avoid recomputing it.
+ Expression _replaceFromFunction(StaticInvocation node) {
+ final nativeFunctionType =
+ InterfaceType(nativeFunctionClass, node.arguments.types);
+ final Field field = Field(
+ Name("_#ffiCallback${callbackCount++}", currentLibrary),
+ type: InterfaceType(pointerClass, [nativeFunctionType]),
+ initializer: StaticInvocation(
+ pointerFromFunctionProcedure,
+ Arguments([
+ StaticInvocation(nativeCallbackFunctionProcedure, node.arguments)
+ ], types: [
+ nativeFunctionType
+ ])),
+ isStatic: true,
+ isFinal: true);
+ currentLibrary.addMember(field);
+ return StaticGet(field);
+ }
+
@override
visitMethodInvocation(MethodInvocation node) {
super.visitMethodInvocation(node);
@@ -233,7 +339,11 @@
_ensureNativeTypeSized(nativeType, node, target.name);
_ensureNativeTypeToDartType(nativeType, dartType, node);
}
- } catch (_FfiStaticTypeError) {}
+ } on _FfiStaticTypeError {
+ // It's OK to swallow the exception because the diagnostics issued will
+ // cause compilation to fail. By continuing, we can report more
+ // diagnostics before compilation ends.
+ }
return node;
}
@@ -322,22 +432,17 @@
return false;
}
- void _ensureIsStatic(Expression node) {
- if (!_isStatic(node)) {
- diagnosticReporter.report(
- templateFfiNotStatic.withArguments(fromFunctionMethod.name.name),
- node.fileOffset,
- 1,
- node.location.file);
- throw _FfiStaticTypeError();
+ void _ensureIsStaticFunction(Expression node) {
+ if ((node is StaticGet && node.target is Procedure) ||
+ (node is ConstantExpression && node.constant is TearOffConstant)) {
+ return;
}
- }
-
- bool _isStatic(Expression node) {
- if (node is StaticGet) {
- return node.target is Procedure;
- }
- return node is ConstantExpression;
+ diagnosticReporter.report(
+ templateFfiNotStatic.withArguments(fromFunctionMethod.name.name),
+ node.fileOffset,
+ 1,
+ node.location.file);
+ throw _FfiStaticTypeError();
}
Class _extendsOrImplementsSealedClass(Class klass) {
@@ -368,6 +473,7 @@
klass.fileOffset,
1,
klass.location.file);
+ throw _FfiStaticTypeError();
}
}
}
diff --git a/pkg/vm/lib/transformations/type_flow/analysis.dart b/pkg/vm/lib/transformations/type_flow/analysis.dart
index 9b322a9..2d434d2 100644
--- a/pkg/vm/lib/transformations/type_flow/analysis.dart
+++ b/pkg/vm/lib/transformations/type_flow/analysis.dart
@@ -111,9 +111,10 @@
// are cached in _InvocationsCache using selector and args as a key.
@override
bool operator ==(other) =>
+ identical(this, other) ||
(other is _Invocation) &&
- (this.selector == other.selector) &&
- (this.args == other.args);
+ (this.selector == other.selector) &&
+ (this.args == other.args);
@override
int get hashCode => (selector.hashCode ^ args.hashCode + 31) & kHashMask;
@@ -920,7 +921,9 @@
int get hashCode => _id;
@override
- bool operator ==(other) => (other is _ClassData) && (this._id == other._id);
+ bool operator ==(other) =>
+ identical(this, other) ||
+ (other is _ClassData) && (this._id == other._id);
@override
int compareTo(_ClassData other) => this._id.compareTo(other._id);
diff --git a/pkg/vm/lib/transformations/type_flow/calls.dart b/pkg/vm/lib/transformations/type_flow/calls.dart
index de3cabe..d0c284e 100644
--- a/pkg/vm/lib/transformations/type_flow/calls.dart
+++ b/pkg/vm/lib/transformations/type_flow/calls.dart
@@ -38,7 +38,8 @@
int get hashCode => callKind.hashCode;
@override
- bool operator ==(other) => other is Selector && other.callKind == callKind;
+ bool operator ==(other) =>
+ identical(this, other) || other is Selector && other.callKind == callKind;
/// Static approximation of Dart return type.
DartType get staticReturnType {
@@ -107,6 +108,7 @@
@override
bool operator ==(other) =>
+ identical(this, other) ||
other is DirectSelector && super == (other) && other.member == member;
@override
@@ -125,6 +127,7 @@
@override
bool operator ==(other) =>
+ identical(this, other) ||
other is InterfaceSelector && super == (other) && other.member == member;
@override
@@ -140,7 +143,8 @@
int get hashCode => (super.hashCode + 37) & kHashMask;
@override
- bool operator ==(other) => other is VirtualSelector && super == (other);
+ bool operator ==(other) =>
+ identical(this, other) || other is VirtualSelector && super == (other);
@override
String toString() => 'virtual ${_callKindPrefix}[$member]';
@@ -163,6 +167,7 @@
@override
bool operator ==(other) =>
+ identical(this, other) ||
other is DynamicSelector && super == (other) && other.name == name;
@override
@@ -207,6 +212,7 @@
@override
bool operator ==(other) {
+ if (identical(this, other)) return true;
if (other is Args<T> &&
(this.values.length == other.values.length) &&
(this.names.length == other.names.length)) {
diff --git a/pkg/vm/lib/transformations/type_flow/native_code.dart b/pkg/vm/lib/transformations/type_flow/native_code.dart
index 26f3c47..3f06a5d 100644
--- a/pkg/vm/lib/transformations/type_flow/native_code.dart
+++ b/pkg/vm/lib/transformations/type_flow/native_code.dart
@@ -55,15 +55,16 @@
@override
visitClass(Class klass) {
- if (!klass.isAbstract) {
- var type = _annotationsDefineRoot(klass.annotations);
- if (type != null) {
- if (type != PragmaEntryPointType.Default) {
- throw "Error: pragma entry-point definition on a class must evaluate "
- "to null, true or false. See entry_points_pragma.md.";
- }
+ final type = _annotationsDefineRoot(klass.annotations);
+ if (type != null) {
+ if (type != PragmaEntryPointType.Default) {
+ throw "Error: pragma entry-point definition on a class must evaluate "
+ "to null, true or false. See entry_points_pragma.md.";
+ }
+ if (!klass.isAbstract) {
entryPoints.addAllocatedClass(klass);
}
+ nativeCodeOracle.addClassReferencedFromNativeCode(klass);
}
currentClass = klass;
klass.visitChildren(this);
@@ -167,12 +168,20 @@
class NativeCodeOracle {
final LibraryIndex _libraryIndex;
final Set<Member> _membersReferencedFromNativeCode = new Set<Member>();
+ final Set<Class> _classesReferencedFromNativeCode = new Set<Class>();
final PragmaAnnotationParser _matcher;
NativeCodeOracle(this._libraryIndex, this._matcher) {
assertx(_matcher != null);
}
+ void addClassReferencedFromNativeCode(Class klass) {
+ _classesReferencedFromNativeCode.add(klass);
+ }
+
+ bool isClassReferencedFromNativeCode(Class klass) =>
+ _classesReferencedFromNativeCode.contains(klass);
+
void setMemberReferencedFromNativeCode(Member member) {
_membersReferencedFromNativeCode.add(member);
}
diff --git a/pkg/vm/lib/transformations/type_flow/summary_collector.dart b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
index d6f8fb3..7254e6c 100644
--- a/pkg/vm/lib/transformations/type_flow/summary_collector.dart
+++ b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
@@ -945,9 +945,16 @@
@override
TypeExpr visitMethodInvocation(MethodInvocation node) {
- final receiver = _visit(node.receiver);
+ final receiverNode = node.receiver;
+ final receiver = _visit(receiverNode);
final args = _visitArguments(receiver, node.arguments);
final target = node.interfaceTarget;
+ if (receiverNode is ConstantExpression && node.name.name == '[]') {
+ Constant constant = receiverNode.constant;
+ if (constant is ListConstant) {
+ return _handleIndexingIntoListConstant(constant);
+ }
+ }
if (target == null) {
if (node.name.name == '==') {
assertx(args.values.length == 2);
@@ -993,6 +1000,24 @@
}
}
+ TypeExpr _handleIndexingIntoListConstant(ListConstant list) {
+ final elementTypes = new Set<Type>();
+ for (var element in list.entries) {
+ elementTypes.add(constantAllocationCollector.typeFor(element));
+ }
+ switch (elementTypes.length) {
+ case 0:
+ return new Type.empty();
+ case 1:
+ return elementTypes.single;
+ default:
+ final join = new Join(null, list.typeArgument);
+ join.values.addAll(elementTypes);
+ _summary.add(join);
+ return join;
+ }
+ }
+
@override
TypeExpr visitPropertyGet(PropertyGet node) {
var receiver = _visit(node.receiver);
diff --git a/pkg/vm/lib/transformations/type_flow/transformer.dart b/pkg/vm/lib/transformations/type_flow/transformer.dart
index 5843438..a33eb29 100644
--- a/pkg/vm/lib/transformations/type_flow/transformer.dart
+++ b/pkg/vm/lib/transformations/type_flow/transformer.dart
@@ -349,6 +349,7 @@
final Set<Class> _usedClasses = new Set<Class>();
final Set<Class> _classesUsedInType = new Set<Class>();
final Set<Member> _usedMembers = new Set<Member>();
+ final Set<Extension> _usedExtensions = new Set<Extension>();
final Set<Typedef> _usedTypedefs = new Set<Typedef>();
_TreeShakerTypeVisitor typeVisitor;
_TreeShakerConstantVisitor constantVisitor;
@@ -367,10 +368,13 @@
_pass2.transform(component);
}
+ bool isClassReferencedFromNativeCode(Class c) =>
+ typeFlowAnalysis.nativeCodeOracle.isClassReferencedFromNativeCode(c);
bool isClassUsed(Class c) => _usedClasses.contains(c);
bool isClassUsedInType(Class c) => _classesUsedInType.contains(c);
bool isClassAllocated(Class c) => typeFlowAnalysis.isClassAllocated(c);
bool isMemberUsed(Member m) => _usedMembers.contains(m);
+ bool isExtensionUsed(Extension e) => _usedExtensions.contains(e);
bool isMemberBodyReachable(Member m) => typeFlowAnalysis.isMemberUsed(m);
bool isFieldInitializerReachable(Field f) =>
typeFlowAnalysis.isFieldInitializerUsed(f);
@@ -432,6 +436,27 @@
}
transformList(m.annotations, _pass1, m);
+
+ // If the member is kept alive we need to keep the extension alive.
+ if (m.isExtensionMember) {
+ // The AST should have exactly one [Extension] for [m].
+ final extension = m.enclosingLibrary.extensions.firstWhere((extension) {
+ return extension.members
+ .any((descriptor) => descriptor.member.asMember == m);
+ }, orElse: () => null);
+ assertx(extension != null);
+
+ // Ensure we retain the [Extension] itself (though members might be
+ // shaken)
+ addUsedExtension(extension);
+ }
+ }
+ }
+
+ void addUsedExtension(Extension node) {
+ if (_usedExtensions.add(node)) {
+ transformList(node.typeParameters, _pass1, node);
+ node.onType?.accept(typeVisitor);
}
}
@@ -580,8 +605,16 @@
}
@override
+ Extension visitExtension(Extension node) {
+ // The extension can be considered a weak node, we'll only retain it if
+ // normal code references any of it's members.
+ return node;
+ }
+
+ @override
TreeNode visitClass(Class node) {
- if (shaker.isClassAllocated(node)) {
+ if (shaker.isClassAllocated(node) ||
+ shaker.isClassReferencedFromNativeCode(node)) {
shaker.addClassUsedInType(node);
}
transformList(node.constructors, this, node);
@@ -987,6 +1020,31 @@
return node;
}
+ @override
+ Extension visitExtension(Extension node) {
+ if (shaker.isExtensionUsed(node)) {
+ int writeIndex = 0;
+ for (int i = 0; i < node.members.length; ++i) {
+ final ExtensionMemberDescriptor descriptor = node.members[i];
+
+ // To avoid depending on the order in which members and extensions are
+ // visited during the transformation, we handle both cases: either the
+ // member was already removed or it will be removed later.
+ final Reference memberReference = descriptor.member;
+ final bool isBound = memberReference.node != null;
+ if (isBound && shaker.isMemberUsed(memberReference.node)) {
+ node.members[writeIndex++] = descriptor;
+ }
+ }
+ node.members.length = writeIndex;
+
+ // We only retain the extension if at least one member is retained.
+ assertx(node.members.length > 0);
+ return node;
+ }
+ return null;
+ }
+
void _makeUnreachableBody(FunctionNode function) {
if (function.body != null) {
function.body = new ExpressionStatement(new Throw(new StringLiteral(
diff --git a/pkg/vm/lib/transformations/type_flow/types.dart b/pkg/vm/lib/transformations/type_flow/types.dart
index 9c52e34..9d34b39 100644
--- a/pkg/vm/lib/transformations/type_flow/types.dart
+++ b/pkg/vm/lib/transformations/type_flow/types.dart
@@ -215,6 +215,7 @@
@override
bool operator ==(other) =>
+ identical(this, other) ||
(other is NullableType) && (this.baseType == other.baseType);
@override
@@ -329,6 +330,7 @@
@override
bool operator ==(other) {
+ if (identical(this, other)) return true;
if ((other is SetType) && (types.length == other.types.length)) {
for (int i = 0; i < types.length; i++) {
if (types[i] != other.types[i]) {
@@ -502,6 +504,7 @@
@override
bool operator ==(other) =>
+ identical(this, other) ||
(other is ConeType) && (this.dartType == other.dartType);
@override
@@ -704,6 +707,7 @@
@override
bool operator ==(other) {
+ if (identical(this, other)) return true;
if (other is ConcreteType) {
if (this.classId != other.classId ||
this.numImmediateTypeArgs != other.numImmediateTypeArgs) {
@@ -870,6 +874,7 @@
@override
operator ==(other) {
+ if (identical(this, other)) return true;
if (other is RuntimeType) {
if (other._type != _type) return false;
assertx(numImmediateTypeArgs == other.numImmediateTypeArgs);
diff --git a/pkg/vm/test/frontend_server_flutter.dart b/pkg/vm/test/frontend_server_flutter.dart
index be1ee67..ee88962 100644
--- a/pkg/vm/test/frontend_server_flutter.dart
+++ b/pkg/vm/test/frontend_server_flutter.dart
@@ -52,6 +52,7 @@
f.uri.toString().contains("/packages/")) &&
f.uri.toString().endsWith("/.packages")));
+ List<String> allCompilationErrors = [];
for (File dotPackage in dotPackagesFiles) {
Directory tempDir;
Directory systemTempDir = Directory.systemTemp;
@@ -60,17 +61,35 @@
Directory testDir =
new Directory.fromUri(dotPackage.parent.uri.resolve("test/"));
if (!testDir.existsSync()) continue;
+ if (testDir.toString().contains("packages/flutter_web_plugins/test/")) {
+ // TODO(jensj): Figure out which tests are web-tests, and compile those
+ // in a setup that can handle that.
+ continue;
+ }
print("Go for $testDir");
- await attemptStuff(
+ List<String> compilationErrors = await attemptStuff(
tempDir, flutterPlatformDirectory, dotPackage, testDir);
+ if (compilationErrors.isNotEmpty) {
+ print("Notice that we had ${compilationErrors.length} "
+ "compilation errors for $testDir");
+ allCompilationErrors.addAll(compilationErrors);
+ }
} finally {
tempDir.delete(recursive: true);
}
}
+ if (allCompilationErrors.isNotEmpty) {
+ print("Had a total of ${allCompilationErrors.length} compilation errors:");
+ allCompilationErrors.forEach(print);
+ throw "Had a total of ${allCompilationErrors.length} compilation errors";
+ }
}
-void attemptStuff(Directory tempDir, Directory flutterPlatformDirectory,
- File dotPackage, Directory testDir) async {
+Future<List<String>> attemptStuff(
+ Directory tempDir,
+ Directory flutterPlatformDirectory,
+ File dotPackage,
+ Directory testDir) async {
File dillFile = new File('${tempDir.path}/dill.dill');
if (dillFile.existsSync()) {
throw "$dillFile already exists.";
@@ -90,10 +109,20 @@
// '--unsafe-package-serialization',
];
+ bool shouldSkip(File f) {
+ // TODO(jensj): Come up with a better way to (temporarily) skip some tests.
+ List<String> pathSegments = f.uri.pathSegments;
+ if (pathSegments.sublist(pathSegments.length - 5).join("/") ==
+ "packages/flutter/test/widgets/html_element_view_test.dart") {
+ return true;
+ }
+ return false;
+ }
+
List<File> testFiles = new List<File>.from(testDir
.listSync(recursive: true)
- .where((f) => f.path.endsWith("_test.dart")));
- if (testFiles.isEmpty) return;
+ .where((f) => f.path.endsWith("_test.dart") && !shouldSkip(f)));
+ if (testFiles.isEmpty) return [];
Stopwatch stopwatch = new Stopwatch()..start();
@@ -122,21 +151,32 @@
inputStreamController
.add('compile ${testFileIterator.current.path}\n'.codeUnits);
int compilations = 0;
+ List<String> compilationErrors = [];
receivedResults.stream.listen((Result compiledResult) {
stdout.write(" --- done in ${stopwatch2.elapsedMilliseconds} ms\n");
stopwatch2.reset();
- compiledResult.expectNoErrors();
-
- List<int> resultBytes = dillFile.readAsBytesSync();
- Component component = loadComponentFromBytes(platformData);
- component = loadComponentFromBytes(resultBytes, component);
- verifyComponent(component);
- print(" => verified in ${stopwatch2.elapsedMilliseconds} ms.");
+ bool error = false;
+ try {
+ compiledResult.expectNoErrors();
+ } catch (e) {
+ print("Got errors. Compiler output for this compile:");
+ outputParser.allReceived.forEach(print);
+ compilationErrors.add(testFileIterator.current.path);
+ error = true;
+ }
+ if (!error) {
+ List<int> resultBytes = dillFile.readAsBytesSync();
+ Component component = loadComponentFromBytes(platformData);
+ component = loadComponentFromBytes(resultBytes, component);
+ verifyComponent(component);
+ print(" => verified in ${stopwatch2.elapsedMilliseconds} ms.");
+ }
stopwatch2.reset();
inputStreamController.add('accept\n'.codeUnits);
inputStreamController.add('reset\n'.codeUnits);
compilations++;
+ outputParser.allReceived.clear();
if (!testFileIterator.moveNext()) {
inputStreamController.add('quit\n'.codeUnits);
@@ -160,6 +200,8 @@
print("Did $compilations compilations and verifications in "
"${stopwatch.elapsedMilliseconds} ms.");
+
+ return compilationErrors;
}
// The below is copied from incremental_compiler_test.dart,
@@ -176,7 +218,10 @@
String _boundaryKey;
bool _readingSources;
+ List<String> allReceived = new List<String>();
+
void listener(String s) {
+ allReceived.add(s);
if (_boundaryKey == null) {
const String RESULT_OUTPUT_SPACE = 'result ';
if (s.startsWith(RESULT_OUTPUT_SPACE)) {
diff --git a/pkg/vm/test/transformations/type_flow/annotation_matcher.dart b/pkg/vm/test/transformations/type_flow/annotation_matcher.dart
deleted file mode 100644
index 2b7f278..0000000
--- a/pkg/vm/test/transformations/type_flow/annotation_matcher.dart
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright (c) 2018, 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/core_types.dart';
-import 'package:vm/transformations/type_flow/utils.dart';
-import 'package:vm/transformations/pragma.dart';
-
-// Since we don't run the constants transformation in this test, we can't
-// recognize all pragma annotations precisely. Instead, we pattern match on
-// annotations which look like a pragma and assume that their options field
-// evaluates to true.
-class ExpressionPragmaAnnotationParser extends PragmaAnnotationParser {
- final CoreTypes coreTypes;
-
- ExpressionPragmaAnnotationParser(this.coreTypes);
-
- ParsedPragma parsePragma(Expression annotation) {
- assertx(annotation is! ConstantExpression);
-
- String pragmaName;
- Expression options;
-
- if (annotation is ConstructorInvocation) {
- if (annotation.constructedType.classNode != coreTypes.pragmaClass) {
- return null;
- }
-
- if (annotation.arguments.types.length != 0 ||
- (annotation.arguments.positional.length != 1 &&
- annotation.arguments.positional.length != 2) ||
- annotation.arguments.named.length != 0) {
- throw "Cannot evaluate pragma annotation $annotation";
- }
-
- var arguments = annotation.arguments.positional;
- var nameArg = arguments[0];
- if (nameArg is StringLiteral) {
- pragmaName = nameArg.value;
- } else {
- return null;
- }
-
- options = arguments.length > 1 ? arguments[1] : new NullLiteral();
- }
-
- switch (pragmaName) {
- case kEntryPointPragmaName:
- // We ignore the option because we can't properly evaluate it, assume
- // it's true.
- return new ParsedEntryPointPragma(PragmaEntryPointType.Default);
- case kExactResultTypePragmaName:
- if (options is TypeLiteral) {
- return new ParsedResultTypeByTypePragma(options.type);
- } else if (options is StringLiteral) {
- return new ParsedResultTypeByPathPragma(options.value);
- }
- throw "Could not recognize option to $kExactResultTypePragmaName";
- default:
- return null;
- }
- }
-}
diff --git a/pkg/vm/test/transformations/type_flow/summary_collector_test.dart b/pkg/vm/test/transformations/type_flow/summary_collector_test.dart
index a58eb82..4ab863b 100644
--- a/pkg/vm/test/transformations/type_flow/summary_collector_test.dart
+++ b/pkg/vm/test/transformations/type_flow/summary_collector_test.dart
@@ -4,8 +4,6 @@
import 'dart:io';
-import 'package:front_end/src/api_unstable/vm.dart'
- show defaultExperimentalFlags, ExperimentalFlag;
import 'package:kernel/ast.dart';
import 'package:kernel/class_hierarchy.dart';
import 'package:kernel/core_types.dart';
@@ -16,7 +14,6 @@
import 'package:vm/transformations/type_flow/native_code.dart';
import 'package:vm/transformations/type_flow/summary_collector.dart';
import 'package:vm/transformations/type_flow/analysis.dart';
-import 'annotation_matcher.dart' show ExpressionPragmaAnnotationParser;
import 'package:kernel/target/targets.dart';
import '../../common_test_utils.dart';
@@ -35,10 +32,7 @@
hierarchy,
new EmptyEntryPointsListener(),
new NativeCodeOracle(
- null,
- defaultExperimentalFlags[ExperimentalFlag.constantUpdate2018]
- ? new ConstantPragmaAnnotationParser(coreTypes)
- : new ExpressionPragmaAnnotationParser(coreTypes)),
+ null, new ConstantPragmaAnnotationParser(coreTypes)),
new GenericInterfacesInfoImpl(hierarchy));
String print(TreeNode node) {
diff --git a/pkg/vm/test/transformations/type_flow/transformer_test.dart b/pkg/vm/test/transformations/type_flow/transformer_test.dart
index ae4764a..b51cbd3 100644
--- a/pkg/vm/test/transformations/type_flow/transformer_test.dart
+++ b/pkg/vm/test/transformations/type_flow/transformer_test.dart
@@ -4,8 +4,6 @@
import 'dart:io';
-import 'package:front_end/src/api_unstable/vm.dart'
- show defaultExperimentalFlags, ExperimentalFlag;
import 'package:kernel/target/targets.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/core_types.dart';
@@ -15,7 +13,6 @@
show ConstantPragmaAnnotationParser;
import 'package:vm/transformations/type_flow/transformer.dart'
show transformComponent;
-import 'annotation_matcher.dart';
import '../../common_test_utils.dart';
@@ -28,13 +25,8 @@
final coreTypes = new CoreTypes(component);
- component = transformComponent(
- target,
- coreTypes,
- component,
- defaultExperimentalFlags[ExperimentalFlag.constantUpdate2018]
- ? new ConstantPragmaAnnotationParser(coreTypes)
- : new ExpressionPragmaAnnotationParser(coreTypes));
+ component = transformComponent(target, coreTypes, component,
+ new ConstantPragmaAnnotationParser(coreTypes));
final actual = kernelLibraryToString(component.mainMethod.enclosingLibrary);
diff --git a/pkg/vm/test/unlinked_ast_to_text_test.dart b/pkg/vm/test/unlinked_ast_to_text_test.dart
new file mode 100644
index 0000000..ee580e2
--- /dev/null
+++ b/pkg/vm/test/unlinked_ast_to_text_test.dart
@@ -0,0 +1,66 @@
+// Copyright (c) 2019, 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:args/args.dart';
+import 'package:expect/expect.dart';
+import 'package:kernel/kernel.dart';
+import 'package:kernel/binary/limited_ast_to_binary.dart';
+import 'package:vm/kernel_front_end.dart';
+
+main() async {
+ final outDir =
+ Directory.systemTemp.createTempSync("incremental_load_from_dill_test");
+
+ final dillFile = outDir.uri.resolve("dart2js.dart.dill").toFilePath();
+ final unlinkedDillFile =
+ outDir.uri.resolve("dart2js.dart.unlinked.dill").toFilePath();
+ final unlinkedDillTxtFile =
+ outDir.uri.resolve("dart2js.dart.unlinked dill.txt").toFilePath();
+
+ final executable = Platform.executable;
+ if (!executable.endsWith('out/ReleaseX64/dart')) {
+ return;
+ }
+
+ final platformDill = Uri.parse(executable).resolve('vm_platform.dill');
+
+ try {
+ final arguments = <String>[
+ '--no-link-platform',
+ '--platform=$platformDill',
+ '--output=$dillFile',
+ 'pkg/compiler/lib/src/dart2js.dart',
+ ];
+
+ // Compile dart2js.dart.
+ final ArgParser argParser = createCompilerArgParser();
+ final int exitCode =
+ await runCompiler(argParser.parse(arguments), '<usage>');
+ Expect.equals(0, exitCode);
+
+ // Load the dart2js.dart.dill and write the unlinked version.
+ final component = loadComponentFromBinary(dillFile);
+ final IOSink sink = new File(unlinkedDillFile).openWrite();
+ final printer = new LimitedBinaryPrinter(
+ sink, (lib) => lib.importUri.scheme != 'dart', false);
+ printer.writeComponentFile(component);
+ await sink.close();
+
+ // Ensure we can load the unlinked dill file and ensure it doesn't include
+ // core libraries.
+ final unlinkedComponent = loadComponentFromBinary(unlinkedDillFile);
+ final coreLibraryCount = unlinkedComponent.libraries
+ .where(
+ (lib) => lib.importUri.scheme == 'dart' && lib.members.isNotEmpty)
+ .length;
+ Expect.equals(0, coreLibraryCount);
+
+ // Ensure we can print the unlinked kernel to text.
+ writeComponentToText(unlinkedComponent, path: unlinkedDillTxtFile);
+ } finally {
+ outDir.deleteSync(recursive: true);
+ }
+}
diff --git a/pkg/vm/testcases/bytecode/async.dart.expect b/pkg/vm/testcases/bytecode/async.dart.expect
index 28dae68..74730b1 100644
--- a/pkg/vm/testcases/bytecode/async.dart.expect
+++ b/pkg/vm/testcases/bytecode/async.dart.expect
@@ -69,8 +69,8 @@
[32] = Reserved
[33] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
[34] = Reserved
- [35] = ObjectRef ArgDesc num-args 2, num-type-args 0, names []
- [36] = ICData dynamic target-name 'start', arg-desc CP#35
+ [35] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
+ [36] = Reserved
[37] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
[38] = Reserved
[39] = EndClosureFunctionScope
@@ -78,10 +78,10 @@
Closure #lib::asyncInFieldInitializer (field)::'<anonymous closure>' async (dart:async::Future < dart:core::int > x) -> dart:async::Future < dart:core::Null >
ClosureCode {
EntryFixed 2, 4
- CheckStack 0
Push FP[-6]
LoadFieldTOS CP#1
PopLocal r0
+ CheckStack 0
AllocateContext 0, 9
PopLocal r0
Push r0
@@ -162,7 +162,7 @@
LoadContextVar 0, 1
Push r0
LoadContextVar 0, 8
- DynamicCall CP#36, 2
+ DynamicCall CP#35, 2
Drop1
Push r0
LoadContextVar 0, 1
@@ -177,10 +177,10 @@
LoadConstant r2, CP#11
LoadConstant r3, CP#11
Frame 6
- CheckStack 0
Push r0
LoadFieldTOS CP#1
PopLocal r4
+ CheckStack 0
Push r4
LoadContextVar 0, 5
StoreLocal r5
@@ -321,7 +321,7 @@
Push r0
LoadContextVar 0, 0
Push r6
- DynamicCall CP#30, 2
+ DynamicCall CP#29, 2
Drop1
Push r0
LoadContextVar 0, 0
@@ -358,8 +358,8 @@
[26] = Reserved
[27] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
[28] = Reserved
- [29] = ObjectRef ArgDesc num-args 2, num-type-args 0, names []
- [30] = ICData dynamic target-name 'start', arg-desc CP#29
+ [29] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
+ [30] = Reserved
[31] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
[32] = Reserved
}
@@ -370,10 +370,10 @@
LoadConstant r2, CP#5
LoadConstant r3, CP#5
Frame 6
- CheckStack 0
Push r0
LoadFieldTOS CP#6
PopLocal r4
+ CheckStack 0
Push r4
LoadContextVar 0, 2
StoreLocal r5
@@ -505,7 +505,7 @@
LoadContextVar 0, 2
Push r0
LoadContextVar 0, 10
- DynamicCall CP#34, 2
+ DynamicCall CP#33, 2
Drop1
Push r0
LoadContextVar 0, 2
@@ -546,8 +546,8 @@
[30] = Reserved
[31] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
[32] = Reserved
- [33] = ObjectRef ArgDesc num-args 2, num-type-args 0, names []
- [34] = ICData dynamic target-name 'start', arg-desc CP#33
+ [33] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
+ [34] = Reserved
[35] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
[36] = Reserved
}
@@ -558,10 +558,10 @@
LoadConstant r2, CP#5
LoadConstant r3, CP#5
Frame 6
- CheckStack 0
Push r0
LoadFieldTOS CP#6
PopLocal r4
+ CheckStack 0
Push r4
LoadContextVar 0, 6
StoreLocal r5
@@ -760,7 +760,7 @@
LoadContextVar 0, 1
Push r0
LoadContextVar 0, 10
- DynamicCall CP#42, 2
+ DynamicCall CP#41, 2
Drop1
Push r0
LoadContextVar 0, 1
@@ -809,8 +809,8 @@
[38] = Reserved
[39] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
[40] = Reserved
- [41] = ObjectRef ArgDesc num-args 2, num-type-args 0, names []
- [42] = ICData dynamic target-name 'start', arg-desc CP#41
+ [41] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
+ [42] = Reserved
[43] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
[44] = Reserved
}
@@ -821,10 +821,10 @@
LoadConstant r2, CP#5
LoadConstant r3, CP#5
Frame 7
- CheckStack 0
Push r0
LoadFieldTOS CP#6
PopLocal r4
+ CheckStack 0
Push r4
LoadContextVar 0, 5
StoreLocal r5
@@ -1160,7 +1160,7 @@
LoadContextVar 0, 3
Push r0
LoadContextVar 0, 17
- DynamicCall CP#40, 2
+ DynamicCall CP#39, 2
Drop1
Push r0
LoadContextVar 0, 3
@@ -1207,8 +1207,8 @@
[36] = Reserved
[37] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
[38] = Reserved
- [39] = ObjectRef ArgDesc num-args 2, num-type-args 0, names []
- [40] = ICData dynamic target-name 'start', arg-desc CP#39
+ [39] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
+ [40] = Reserved
[41] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
[42] = Reserved
}
@@ -1219,10 +1219,10 @@
LoadConstant r2, CP#5
LoadConstant r3, CP#5
Frame 10
- CheckStack 0
Push r0
LoadFieldTOS CP#6
PopLocal r4
+ CheckStack 0
Push r4
LoadContextVar 0, 7
StoreLocal r5
@@ -1704,8 +1704,8 @@
[32] = Reserved
[33] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
[34] = Reserved
- [35] = ObjectRef ArgDesc num-args 2, num-type-args 0, names []
- [36] = ICData dynamic target-name 'start', arg-desc CP#35
+ [35] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
+ [36] = Reserved
[37] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
[38] = Reserved
[39] = EndClosureFunctionScope
@@ -1713,10 +1713,10 @@
Closure #lib::closure::'nested' async () -> dart:async::Future < dart:core::int >
ClosureCode {
EntryFixed 1, 4
- CheckStack 0
Push FP[-5]
LoadFieldTOS CP#1
PopLocal r0
+ CheckStack 0
AllocateContext 1, 9
StoreLocal r1
Push r1
@@ -1792,7 +1792,7 @@
LoadContextVar 1, 0
Push r0
LoadContextVar 1, 8
- DynamicCall CP#36, 2
+ DynamicCall CP#35, 2
Drop1
Push r0
LoadContextVar 1, 0
@@ -1807,10 +1807,10 @@
LoadConstant r2, CP#8
LoadConstant r3, CP#8
Frame 8
- CheckStack 0
Push r0
LoadFieldTOS CP#1
PopLocal r4
+ CheckStack 0
Push r4
LoadContextVar 1, 4
StoreLocal r5
@@ -2036,7 +2036,7 @@
LoadContextVar 0, 1
Push r0
LoadContextVar 0, 8
- DynamicCall CP#36, 2
+ DynamicCall CP#35, 2
Drop1
Push r0
LoadContextVar 0, 1
@@ -2079,8 +2079,8 @@
[32] = Reserved
[33] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
[34] = Reserved
- [35] = ObjectRef ArgDesc num-args 2, num-type-args 0, names []
- [36] = ICData dynamic target-name 'start', arg-desc CP#35
+ [35] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
+ [36] = Reserved
[37] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
[38] = Reserved
}
@@ -2091,10 +2091,10 @@
LoadConstant r2, CP#5
LoadConstant r3, CP#5
Frame 6
- CheckStack 0
Push r0
LoadFieldTOS CP#6
PopLocal r4
+ CheckStack 0
Push r4
LoadContextVar 0, 5
StoreLocal r5
diff --git a/pkg/vm/testcases/bytecode/bootstrapping.dart.expect b/pkg/vm/testcases/bytecode/bootstrapping.dart.expect
index 15d60a1..a5a1c78 100644
--- a/pkg/vm/testcases/bytecode/bootstrapping.dart.expect
+++ b/pkg/vm/testcases/bytecode/bootstrapping.dart.expect
@@ -210,8 +210,7 @@
Entry 2
CheckStack 0
LoadStatic CP#0
- EqualsNull
- JumpIfFalse L1
+ JumpIfNotNull L1
LoadStatic CP#1
DirectCall CP#2, 1
StoreLocal r1
@@ -383,8 +382,7 @@
Entry 2
CheckStack 0
LoadStatic CP#0
- EqualsNull
- JumpIfFalse L1
+ JumpIfNotNull L1
Allocate CP#1
StoreLocal r1
Push r1
@@ -583,8 +581,7 @@
Entry 1
CheckStack 0
LoadStatic CP#0
- EqualsNull
- JumpIfFalse L1
+ JumpIfNotNull L1
LoadStatic CP#1
EqualsNull
BooleanNegateTOS
@@ -597,7 +594,7 @@
Push r0
JumpIfFalse L3
LoadStatic CP#1
- DynamicCall CP#3, 1
+ DynamicCall CP#2, 1
StoreStaticTOS CP#0
L3:
LoadStatic CP#0
@@ -606,8 +603,8 @@
ConstantPool {
[0] = StaticField #lib::VMLibraryHooks::_cachedScript (field)
[1] = StaticField #lib::VMLibraryHooks::_computeScriptUri (field)
- [2] = ObjectRef ArgDesc num-args 1, num-type-args 0, names []
- [3] = ICData dynamic target-name 'call', arg-desc CP#2
+ [2] = DynamicCall 'call', ArgDesc num-args 1, num-type-args 0, names []
+ [3] = Reserved
}
Class 'Stdin', script = '#lib'
diff --git a/pkg/vm/testcases/bytecode/closures.dart.expect b/pkg/vm/testcases/bytecode/closures.dart.expect
index 8da319e..76d15ca 100644
--- a/pkg/vm/testcases/bytecode/closures.dart.expect
+++ b/pkg/vm/testcases/bytecode/closures.dart.expect
@@ -72,10 +72,10 @@
Closure #lib::simpleClosure::'<anonymous closure>' (dart:core::int y) -> dart:core::Null
ClosureCode {
EntryFixed 2, 3
- CheckStack 0
Push FP[-6]
LoadFieldTOS CP#1
PopLocal r0
+ CheckStack 0
JumpIfUnchecked L1
Push FP[-5]
PushConstant CP#3
@@ -318,10 +318,10 @@
Closure #lib::testPartialInstantiation::'foo' <dart:core::Object T> (#lib::testPartialInstantiation::Closure/0::TypeParam/0 t) -> void
ClosureCode {
EntryFixed 2, 3
- CheckStack 0
Push FP[-6]
LoadFieldTOS CP#1
PopLocal r1
+ CheckStack 0
Push FP[-6]
LoadFieldTOS CP#3
StoreLocal r0
@@ -661,10 +661,10 @@
Closure #lib::A::foo::'nested1' <dart:core::Object T5, dart:core::Object T6> () -> void
ClosureCode {
EntryFixed 1, 5
- CheckStack 0
Push FP[-5]
LoadFieldTOS CP#1
PopLocal r1
+ CheckStack 0
Push FP[-5]
LoadFieldTOS CP#3
StoreLocal r0
@@ -721,10 +721,10 @@
Closure #lib::A::foo::Closure/0::'nested2' <dart:core::Object T7, dart:core::Object T8> () -> void
ClosureCode {
EntryFixed 1, 5
- CheckStack 0
Push FP[-5]
LoadFieldTOS CP#1
PopLocal r1
+ CheckStack 0
Push FP[-5]
LoadFieldTOS CP#3
StoreLocal r0
@@ -774,10 +774,10 @@
Closure #lib::A::foo::Closure/1::'<anonymous closure>' () -> dart:core::Null
ClosureCode {
EntryFixed 1, 4
- CheckStack 0
Push FP[-5]
LoadFieldTOS CP#1
PopLocal r1
+ CheckStack 0
Push FP[-5]
LoadFieldTOS CP#6
PopLocal r0
@@ -1002,10 +1002,10 @@
Closure #lib::B::topLevel::'<anonymous closure>' (dart:core::int y) -> dart:core::Null
ClosureCode {
EntryFixed 2, 4
- CheckStack 0
Push FP[-6]
LoadFieldTOS CP#1
PopLocal r0
+ CheckStack 0
AllocateContext 1, 2
StoreLocal r1
Push r1
@@ -1075,10 +1075,10 @@
Closure #lib::B::topLevel::Closure/0::'closure2' () -> void
ClosureCode {
EntryFixed 1, 3
- CheckStack 0
Push FP[-5]
LoadFieldTOS CP#1
PopLocal r0
+ CheckStack 0
Push r0
LoadContextParent
Push r0
@@ -1103,10 +1103,10 @@
Closure #lib::B::topLevel::'<anonymous closure>' () -> dart:core::Null
ClosureCode {
EntryFixed 1, 3
- CheckStack 0
Push FP[-5]
LoadFieldTOS CP#1
PopLocal r0
+ CheckStack 0
Push r0
LoadContextVar 0, 0
Push r0
@@ -1269,10 +1269,10 @@
Closure #lib::C::testForLoop::'<anonymous closure>' () -> dart:core::int
ClosureCode {
EntryFixed 1, 2
- CheckStack 0
Push FP[-5]
LoadFieldTOS CP#5
PopLocal r0
+ CheckStack 0
Push r0
LoadContextVar 1, 0
Push r0
@@ -1285,10 +1285,10 @@
Closure #lib::C::testForLoop::'<anonymous closure>' (dart:core::int ii) -> dart:core::Null
ClosureCode {
EntryFixed 2, 3
- CheckStack 0
Push FP[-6]
LoadFieldTOS CP#5
PopLocal r0
+ CheckStack 0
JumpIfUnchecked L1
Push FP[-5]
PushConstant CP#21
@@ -1393,10 +1393,10 @@
Closure #lib::C::testForInLoop::'<anonymous closure>' () -> dart:core::Null
ClosureCode {
EntryFixed 1, 3
- CheckStack 0
Push FP[-5]
LoadFieldTOS CP#7
PopLocal r0
+ CheckStack 0
Push r0
Push r0
LoadContextVar 0, 0
@@ -1496,10 +1496,10 @@
Closure #lib::D::foo::'<anonymous closure>' () -> #lib::D::TypeParam/0
ClosureCode {
EntryFixed 1, 2
- CheckStack 0
Push FP[-5]
LoadFieldTOS CP#5
PopLocal r0
+ CheckStack 0
Push r0
LoadContextVar 0, 0
ReturnTOS
@@ -1560,10 +1560,10 @@
Closure #lib::D::bar::'<anonymous closure>' () -> dart:core::Null
ClosureCode {
EntryFixed 1, 4
- CheckStack 0
Push FP[-5]
LoadFieldTOS CP#1
PopLocal r0
+ CheckStack 0
AllocateClosure CP#3
StoreLocal r3
Push r3
@@ -1596,10 +1596,10 @@
Closure #lib::D::bar::Closure/0::'inner' () -> dart:core::Null
ClosureCode {
EntryFixed 1, 2
- CheckStack 0
Push FP[-5]
LoadFieldTOS CP#1
PopLocal r0
+ CheckStack 0
PushNull
ReturnTOS
}
diff --git a/pkg/vm/testcases/bytecode/super_calls.dart.expect b/pkg/vm/testcases/bytecode/super_calls.dart.expect
index 3217e51..aabc371 100644
--- a/pkg/vm/testcases/bytecode/super_calls.dart.expect
+++ b/pkg/vm/testcases/bytecode/super_calls.dart.expect
@@ -179,7 +179,7 @@
Push FP[-5]
DirectCall CP#1, 1
PushConstant CP#3
- DynamicCall CP#5, 3
+ DynamicCall CP#4, 3
ReturnTOS
}
ConstantPool {
@@ -187,8 +187,8 @@
[1] = DirectCall '#lib::Base1::get:bar', ArgDesc num-args 1, num-type-args 0, names []
[2] = Reserved
[3] = ObjectRef 'param'
- [4] = ObjectRef ArgDesc num-args 2, num-type-args 1, names []
- [5] = ICData dynamic target-name 'call', arg-desc CP#4
+ [4] = DynamicCall 'call', ArgDesc num-args 2, num-type-args 1, names []
+ [5] = Reserved
}
@@ -413,7 +413,7 @@
DirectCall CP#4, 4
DirectCall CP#6, 2
PushConstant CP#8
- DynamicCall CP#10, 3
+ DynamicCall CP#9, 3
ReturnTOS
}
ConstantPool {
@@ -426,8 +426,8 @@
[6] = DirectCall 'dart:core::Object::noSuchMethod', ArgDesc num-args 2, num-type-args 0, names []
[7] = Reserved
[8] = ObjectRef 'param'
- [9] = ObjectRef ArgDesc num-args 2, num-type-args 1, names []
- [10] = ICData dynamic target-name 'call', arg-desc CP#9
+ [9] = DynamicCall 'call', ArgDesc num-args 2, num-type-args 1, names []
+ [10] = Reserved
}
diff --git a/pkg/vm/testcases/bytecode/try_blocks.dart.expect b/pkg/vm/testcases/bytecode/try_blocks.dart.expect
index b31deef..47fd310 100644
--- a/pkg/vm/testcases/bytecode/try_blocks.dart.expect
+++ b/pkg/vm/testcases/bytecode/try_blocks.dart.expect
@@ -347,10 +347,10 @@
Closure #lib::testTryCatch3::'foo' () -> void
ClosureCode {
EntryFixed 1, 6
- CheckStack 0
Push FP[-5]
LoadFieldTOS CP#1
PopLocal r0
+ CheckStack 0
Push r0
PopLocal r2
Try #0 start:
@@ -383,10 +383,10 @@
Closure #lib::testTryCatch3::'bar' () -> void
ClosureCode {
EntryFixed 1, 6
- CheckStack 0
Push FP[-5]
LoadFieldTOS CP#1
PopLocal r0
+ CheckStack 0
Push r0
PopLocal r2
Try #0 start:
@@ -735,10 +735,10 @@
Closure #lib::testTryFinally2::'foo' () -> void
ClosureCode {
EntryFixed 1, 2
- CheckStack 0
Push FP[-5]
LoadFieldTOS CP#7
PopLocal r0
+ CheckStack 0
Push r0
LoadContextVar 0, 0
DirectCall CP#3, 1
@@ -800,7 +800,7 @@
DirectCall CP#3, 1
Drop1
Push r2
- DynamicCall CP#19, 1
+ DynamicCall CP#18, 1
Drop1
Push r3
Push r4
@@ -813,7 +813,7 @@
DirectCall CP#3, 1
Drop1
Push r2
- DynamicCall CP#20, 1
+ DynamicCall CP#18, 1
Drop1
Push r0
LoadContextParent
@@ -843,17 +843,16 @@
[15] = Reserved
[16] = InstanceField dart:core::_Closure::_function (field)
[17] = Reserved
- [18] = ObjectRef ArgDesc num-args 1, num-type-args 0, names []
- [19] = ICData dynamic target-name 'call', arg-desc CP#18
- [20] = ICData dynamic target-name 'call', arg-desc CP#18
+ [18] = DynamicCall 'call', ArgDesc num-args 1, num-type-args 0, names []
+ [19] = Reserved
}
Closure #lib::testTryFinally3::'<anonymous closure>' () -> dart:core::int
ClosureCode {
EntryFixed 1, 6
- CheckStack 0
Push FP[-5]
LoadFieldTOS CP#1
PopLocal r0
+ CheckStack 0
Push r0
LoadContextVar 0, 0
DirectCall CP#3, 1
diff --git a/pkg/vm/testcases/bytecode/type_ops.dart.expect b/pkg/vm/testcases/bytecode/type_ops.dart.expect
index 9804186..af14940 100644
--- a/pkg/vm/testcases/bytecode/type_ops.dart.expect
+++ b/pkg/vm/testcases/bytecode/type_ops.dart.expect
@@ -735,7 +735,7 @@
: super #lib::G::•()
;
method foo8<generic-covariant-impl Q extends #lib::H::T* = #lib::H::T*>(#lib::H::foo8::Q* a, dart.core::int* b, generic-covariant-impl #lib::H::T* c) → void {}
- forwarding-stub method foo7<generic-covariant-impl Q extends #lib::H::T*>(#lib::H::foo7::Q a, covariant dart.core::num* b, generic-covariant-impl #lib::H::T* c) → void
+ forwarding-stub method foo7<generic-covariant-impl Q extends #lib::H::T*>(#lib::H::foo7::Q* a, covariant dart.core::num* b, generic-covariant-impl #lib::H::T* c) → void
return super.{#lib::G::foo7}<#lib::H::foo7::Q*>(a, b, c);
}
static field dart.core::List<dart.core::Iterable<dynamic>*>* globalVar;
diff --git a/pkg/vm/testcases/transformations/type_flow/summary_collector/constants.dart b/pkg/vm/testcases/transformations/type_flow/summary_collector/constants.dart
new file mode 100644
index 0000000..5e77376
--- /dev/null
+++ b/pkg/vm/testcases/transformations/type_flow/summary_collector/constants.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2019, 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.
+
+smiLiteral() => 42;
+
+intLiteral() => 0x8000000000000000;
+
+strLiteral() => 'abc';
+
+const _constList1 = [1, 2, 3];
+indexingIntoConstantList1(int i) => _constList1[i];
+
+const _constList2 = ['hi', 33, null, -5];
+indexingIntoConstantList2(int i) => _constList2[i];
+
+main() {}
diff --git a/pkg/vm/testcases/transformations/type_flow/summary_collector/constants.dart.expect b/pkg/vm/testcases/transformations/type_flow/summary_collector/constants.dart.expect
new file mode 100644
index 0000000..39e0f94
--- /dev/null
+++ b/pkg/vm/testcases/transformations/type_flow/summary_collector/constants.dart.expect
@@ -0,0 +1,25 @@
+------------ #lib::smiLiteral ------------
+
+RESULT: _T (dart.core::_Smi)
+------------ #lib::intLiteral ------------
+
+RESULT: _T (dart.core::int*)+
+------------ #lib::strLiteral ------------
+
+RESULT: _T (dart.core::_OneByteString)
+------------ #lib::indexingIntoConstantList1 ------------
+%i = _Parameter #0 [_T (dart.core::int*)+?]
+RESULT: _T (dart.core::_Smi)
+------------ #lib::indexingIntoConstantList2 ------------
+%i = _Parameter #0 [_T (dart.core::int*)+?]
+t1 = _Join [dart.core::Object*] (_T (dart.core::_OneByteString), _T (dart.core::_Smi), _T {}?)
+RESULT: t1
+------------ #lib::main ------------
+
+RESULT: _T {}?
+------------ #lib::_constList1 ------------
+
+RESULT: _T (dart.core::_ImmutableList)
+------------ #lib::_constList2 ------------
+
+RESULT: _T (dart.core::_ImmutableList)
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/abstract_class_entry_point.dart b/pkg/vm/testcases/transformations/type_flow/transformer/abstract_class_entry_point.dart
new file mode 100644
index 0000000..84a66fd
--- /dev/null
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/abstract_class_entry_point.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that an abstract class with no members is retained if marked as an
+// entry-point.
+
+@pragma("vm:entry-point")
+abstract class AbstractEmptyClass {}
+
+main() {}
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/abstract_class_entry_point.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/abstract_class_entry_point.dart.expect
new file mode 100644
index 0000000..3864b4c
--- /dev/null
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/abstract_class_entry_point.dart.expect
@@ -0,0 +1,8 @@
+library #lib;
+import self as self;
+import "dart:core" as core;
+
+@#C3
+abstract class AbstractEmptyClass extends core::Object {
+}
+static method main() → dynamic {}
diff --git a/pkg/vm_service/CHANGELOG.md b/pkg/vm_service/CHANGELOG.md
index b4b0668..cd25650 100644
--- a/pkg/vm_service/CHANGELOG.md
+++ b/pkg/vm_service/CHANGELOG.md
@@ -1,5 +1,14 @@
# Changelog
+## 1.2.0
+- Support service protocol version 3.27:
+ - Added `getCpuSamples` and `clearCpuSamples` methods
+ - Added `CpuSamples`, `CpuSample`, and `ProfileFunction` classes.
+
+## 1.1.2
+- Fixed issue where `closureFunction` and `closureContext` were only expected in
+ `Instance` objects rather than `InstanceRef`.
+
## 1.1.1
- Fixed issue serializing list arguments for certain VM service methods.
- Issue #37872
diff --git a/pkg/vm_service/example/vm_service_assert.dart b/pkg/vm_service/example/vm_service_assert.dart
index df11b53..baaad58 100644
--- a/pkg/vm_service/example/vm_service_assert.dart
+++ b/pkg/vm_service/example/vm_service_assert.dart
@@ -28,6 +28,11 @@
return obj;
}
+dynamic assertDynamic(dynamic obj) {
+ assertNotNull(obj);
+ return obj;
+}
+
List<int> assertListOfInt(List<int> list) {
for (int elem in list) {
assertInt(elem);
@@ -429,6 +434,36 @@
return list;
}
+vms.CpuSamples assertCpuSamples(vms.CpuSamples obj) {
+ assertNotNull(obj);
+ assertString(obj.type);
+ assertInt(obj.samplePeriod);
+ assertInt(obj.maxStackDepth);
+ assertInt(obj.sampleCount);
+ assertInt(obj.timeSpan);
+ assertInt(obj.timeOriginMicros);
+ assertInt(obj.timeExtentMicros);
+ assertInt(obj.pid);
+ assertListOfProfileFunction(obj.functions);
+ assertListOfCpuSample(obj.samples);
+ return obj;
+}
+
+vms.CpuSample assertCpuSample(vms.CpuSample obj) {
+ assertNotNull(obj);
+ assertInt(obj.tid);
+ assertInt(obj.timestamp);
+ assertListOfInt(obj.stack);
+ return obj;
+}
+
+List<vms.CpuSample> assertListOfCpuSample(List<vms.CpuSample> list) {
+ for (vms.CpuSample elem in list) {
+ assertCpuSample(elem);
+ }
+ return list;
+}
+
vms.ErrorRef assertErrorRef(vms.ErrorRef obj) {
assertNotNull(obj);
assertString(obj.type);
@@ -773,6 +808,12 @@
return list;
}
+vms.NativeFunction assertNativeFunction(vms.NativeFunction obj) {
+ assertNotNull(obj);
+ assertString(obj.name);
+ return obj;
+}
+
vms.NullValRef assertNullValRef(vms.NullValRef obj) {
assertNotNull(obj);
assertString(obj.type);
@@ -821,6 +862,24 @@
return obj;
}
+vms.ProfileFunction assertProfileFunction(vms.ProfileFunction obj) {
+ assertNotNull(obj);
+ assertString(obj.kind);
+ assertInt(obj.inclusiveTicks);
+ assertInt(obj.exclusiveTicks);
+ assertString(obj.resolvedUrl);
+ assertDynamic(obj.function);
+ return obj;
+}
+
+List<vms.ProfileFunction> assertListOfProfileFunction(
+ List<vms.ProfileFunction> list) {
+ for (vms.ProfileFunction elem in list) {
+ assertProfileFunction(elem);
+ }
+ return list;
+}
+
vms.ReloadReport assertReloadReport(vms.ReloadReport obj) {
assertNotNull(obj);
assertString(obj.type);
diff --git a/pkg/vm_service/example/vm_service_tester.dart b/pkg/vm_service/example/vm_service_tester.dart
index 5d1f819..f02be8e 100644
--- a/pkg/vm_service/example/vm_service_tester.dart
+++ b/pkg/vm_service/example/vm_service_tester.dart
@@ -51,6 +51,7 @@
await new Future.delayed(new Duration(milliseconds: 500));
+ // ignore: deprecated_member_use_from_same_package
serviceClient = await vmServiceConnect(host, port, log: new StdoutLog());
print('socket connected');
@@ -126,7 +127,11 @@
IsolateRef isolateRef = isolates.first;
print(await serviceClient.resume(isolateRef.id));
+ print('waiting for client to shut down...');
serviceClient.dispose();
+
+ await serviceClient.onDone;
+ print('service client shut down');
});
}
@@ -158,9 +163,10 @@
});
await serviceClient.registerService(serviceName, serviceAlias);
VmService otherClient =
+ // ignore: deprecated_member_use_from_same_package
await vmServiceConnect(host, port, log: new StdoutLog());
Completer completer = new Completer();
- otherClient.onEvent('_Service').listen((e) async {
+ otherClient.onEvent('Service').listen((e) async {
if (e.service == serviceName && e.kind == EventKind.kServiceRegistered) {
assert(e.alias == serviceAlias);
Response response = await serviceClient.callMethod(
@@ -171,8 +177,9 @@
completer.complete();
}
});
- await otherClient.streamListen('_Service');
+ await otherClient.streamListen('Service');
await completer.future;
+ otherClient.dispose();
}
Future testScriptParse(IsolateRef isolateRef) async {
diff --git a/pkg/vm_service/java/.gitignore b/pkg/vm_service/java/.gitignore
index 4fef6d5..5f9d198 100644
--- a/pkg/vm_service/java/.gitignore
+++ b/pkg/vm_service/java/.gitignore
@@ -3,6 +3,7 @@
src/org/dartlang/vm/service/VmService.java
src/org/dartlang/vm/service/consumer/AllocationProfileConsumer.java
src/org/dartlang/vm/service/consumer/BreakpointConsumer.java
+src/org/dartlang/vm/service/consumer/CpuSamplesConsumer.java
src/org/dartlang/vm/service/consumer/EvaluateConsumer.java
src/org/dartlang/vm/service/consumer/EvaluateInFrameConsumer.java
src/org/dartlang/vm/service/consumer/FlagListConsumer.java
@@ -37,6 +38,8 @@
src/org/dartlang/vm/service/element/Context.java
src/org/dartlang/vm/service/element/ContextElement.java
src/org/dartlang/vm/service/element/ContextRef.java
+src/org/dartlang/vm/service/element/CpuSample.java
+src/org/dartlang/vm/service/element/CpuSamples.java
src/org/dartlang/vm/service/element/ErrorKind.java
src/org/dartlang/vm/service/element/ErrorObj.java
src/org/dartlang/vm/service/element/ErrorRef.java
@@ -67,10 +70,12 @@
src/org/dartlang/vm/service/element/MapAssociation.java
src/org/dartlang/vm/service/element/MemoryUsage.java
src/org/dartlang/vm/service/element/Message.java
+src/org/dartlang/vm/service/element/NativeFunction.java
src/org/dartlang/vm/service/element/Null.java
src/org/dartlang/vm/service/element/NullRef.java
src/org/dartlang/vm/service/element/Obj.java
src/org/dartlang/vm/service/element/ObjRef.java
+src/org/dartlang/vm/service/element/ProfileFunction.java
src/org/dartlang/vm/service/element/ReloadReport.java
src/org/dartlang/vm/service/element/Response.java
src/org/dartlang/vm/service/element/RetainingObject.java
diff --git a/pkg/vm_service/java/version.properties b/pkg/vm_service/java/version.properties
index 55a8c99..c025869 100644
--- a/pkg/vm_service/java/version.properties
+++ b/pkg/vm_service/java/version.properties
@@ -1 +1 @@
-version=3.26
+version=3.27
diff --git a/pkg/vm_service/lib/vm_service.dart b/pkg/vm_service/lib/vm_service.dart
index 0030b6b..2838a4e 100644
--- a/pkg/vm_service/lib/vm_service.dart
+++ b/pkg/vm_service/lib/vm_service.dart
@@ -17,7 +17,7 @@
export 'src/service_extension_registry.dart' show ServiceExtensionRegistry;
-const String vmServiceVersion = '3.26.0';
+const String vmServiceVersion = '3.27.0';
/// @optional
const String optional = 'optional';
@@ -102,6 +102,8 @@
'@Context': ContextRef.parse,
'Context': Context.parse,
'ContextElement': ContextElement.parse,
+ 'CpuSamples': CpuSamples.parse,
+ 'CpuSample': CpuSample.parse,
'@Error': ErrorRef.parse,
'Error': Error.parse,
'Event': Event.parse,
@@ -127,10 +129,12 @@
'MapAssociation': MapAssociation.parse,
'MemoryUsage': MemoryUsage.parse,
'Message': Message.parse,
+ 'NativeFunction': NativeFunction.parse,
'@Null': NullValRef.parse,
'Null': NullVal.parse,
'@Object': ObjRef.parse,
'Object': Obj.parse,
+ 'ProfileFunction': ProfileFunction.parse,
'ReloadReport': ReloadReport.parse,
'RetainingObject': RetainingObject.parse,
'RetainingPath': RetainingPath.parse,
@@ -161,11 +165,13 @@
'addBreakpoint': const ['Breakpoint'],
'addBreakpointWithScriptUri': const ['Breakpoint'],
'addBreakpointAtEntry': const ['Breakpoint'],
+ 'clearCpuSamples': const ['Success'],
'clearVMTimeline': const ['Success'],
'invoke': const ['InstanceRef', 'ErrorRef', 'Sentinel'],
'evaluate': const ['InstanceRef', 'ErrorRef', 'Sentinel'],
'evaluateInFrame': const ['InstanceRef', 'ErrorRef', 'Sentinel'],
'getAllocationProfile': const ['AllocationProfile'],
+ 'getCpuSamples': const ['CpuSamples'],
'getFlagList': const ['FlagList'],
'getInboundReferences': const ['InboundReferences', 'Sentinel'],
'getInstances': const ['InstanceSet'],
@@ -283,6 +289,11 @@
/// Note that breakpoints are added and removed on a per-isolate basis.
Future<Breakpoint> addBreakpointAtEntry(String isolateId, String functionId);
+ /// Clears all CPU profiling samples.
+ ///
+ /// See [Success].
+ Future<Success> clearCpuSamples(String isolateId);
+
/// Clears all VM timeline events.
///
/// See [Success].
@@ -410,6 +421,16 @@
Future<AllocationProfile> getAllocationProfile(String isolateId,
{bool reset, bool gc});
+ /// The `getCpuSamples` RPC is used to retrieve samples collected by the CPU
+ /// profiler. Only samples collected in the time range `[timeOriginMicros,
+ /// timeOriginMicros + timeExtentMicros]` will be reported.
+ ///
+ /// If the profiler is disabled, an error response will be returned.
+ ///
+ /// See [CpuSamples].
+ Future<CpuSamples> getCpuSamples(
+ String isolateId, int timeOriginMicros, int timeExtentMicros);
+
/// The `getFlagList` RPC returns a list of all command line flags in the VM
/// along with their current values.
///
@@ -921,6 +942,11 @@
params['functionId'],
);
break;
+ case 'clearCpuSamples':
+ response = await _serviceImplementation.clearCpuSamples(
+ params['isolateId'],
+ );
+ break;
case 'clearVMTimeline':
response = await _serviceImplementation.clearVMTimeline();
break;
@@ -958,6 +984,13 @@
gc: params['gc'],
);
break;
+ case 'getCpuSamples':
+ response = await _serviceImplementation.getCpuSamples(
+ params['isolateId'],
+ params['timeOriginMicros'],
+ params['timeExtentMicros'],
+ );
+ break;
case 'getFlagList':
response = await _serviceImplementation.getFlagList();
break;
@@ -1199,6 +1232,8 @@
StreamController<String> _onReceive =
new StreamController.broadcast(sync: true);
+ final Completer _onDoneCompleter = new Completer();
+
Map<String, StreamController<Event>> _eventControllers = {};
StreamController<Event> _getEventController(String eventName) {
@@ -1212,13 +1247,23 @@
DisposeHandler _disposeHandler;
- VmService(Stream<dynamic> /*String|List<int>*/ inStream,
- void writeMessage(String message),
- {Log log, DisposeHandler disposeHandler}) {
- _streamSub = inStream.listen(_processMessage);
+ VmService(
+ Stream<dynamic> /*String|List<int>*/ inStream,
+ void writeMessage(String message), {
+ Log log,
+ DisposeHandler disposeHandler,
+ Future streamClosed,
+ }) {
+ _streamSub = inStream.listen(_processMessage,
+ onDone: () => _onDoneCompleter.complete());
_writeMessage = writeMessage;
_log = log == null ? new _NullLog() : log;
_disposeHandler = disposeHandler;
+ streamClosed?.then((_) {
+ if (!_onDoneCompleter.isCompleted) {
+ _onDoneCompleter.complete();
+ }
+ });
}
@override
@@ -1294,6 +1339,11 @@
}
@override
+ Future<Success> clearCpuSamples(String isolateId) {
+ return _call('clearCpuSamples', {'isolateId': isolateId});
+ }
+
+ @override
Future<Success> clearVMTimeline() => _call('clearVMTimeline');
@override
@@ -1374,6 +1424,16 @@
}
@override
+ Future<CpuSamples> getCpuSamples(
+ String isolateId, int timeOriginMicros, int timeExtentMicros) {
+ return _call('getCpuSamples', {
+ 'isolateId': isolateId,
+ 'timeOriginMicros': timeOriginMicros,
+ 'timeExtentMicros': timeExtentMicros
+ });
+ }
+
+ @override
Future<FlagList> getFlagList() => _call('getFlagList');
@override
@@ -1626,9 +1686,16 @@
void dispose() {
_streamSub.cancel();
_completers.values.forEach((c) => c.completeError('disposed'));
- if (_disposeHandler != null) _disposeHandler();
+ if (_disposeHandler != null) {
+ _disposeHandler();
+ }
+ if (!_onDoneCompleter.isCompleted) {
+ _onDoneCompleter.complete();
+ }
}
+ Future get onDone => _onDoneCompleter.future;
+
Future<T> _call<T>(String method, [Map args]) {
String id = '${++_id}';
Completer<T> completer = new Completer<T>();
@@ -2713,6 +2780,144 @@
String toString() => '[ContextElement value: ${value}]';
}
+/// See [getCpuSamples] and [CpuSample].
+class CpuSamples extends Response {
+ static CpuSamples parse(Map<String, dynamic> json) =>
+ json == null ? null : new CpuSamples._fromJson(json);
+
+ /// The sampling rate for the profiler in microseconds.
+ int samplePeriod;
+
+ /// The maximum possible stack depth for samples.
+ int maxStackDepth;
+
+ /// The number of samples returned.
+ int sampleCount;
+
+ /// The timespan the set of returned samples covers, in microseconds.
+ int timeSpan;
+
+ /// The start of the period of time in which the returned samples were
+ /// collected.
+ int timeOriginMicros;
+
+ /// The duration of time covered by the returned samples.
+ int timeExtentMicros;
+
+ /// The process ID for the VM.
+ int pid;
+
+ /// A list of functions seen in the relevant samples. These references can be
+ /// looked up using the indicies provided in a `CpuSample` `stack` to
+ /// determine which function was on the stack.
+ List<ProfileFunction> functions;
+
+ /// A list of samples collected in the range `[timeOriginMicros,
+ /// timeOriginMicros + timeExtentMicros]`
+ List<CpuSample> samples;
+
+ CpuSamples();
+
+ CpuSamples._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
+ samplePeriod = json['samplePeriod'];
+ maxStackDepth = json['maxStackDepth'];
+ sampleCount = json['sampleCount'];
+ timeSpan = json['timeSpan'];
+ timeOriginMicros = json['timeOriginMicros'];
+ timeExtentMicros = json['timeExtentMicros'];
+ pid = json['pid'];
+ functions = new List<ProfileFunction>.from(
+ createServiceObject(json['functions'], const ['ProfileFunction']));
+ samples = new List<CpuSample>.from(
+ createServiceObject(json['samples'], const ['CpuSample']));
+ }
+
+ @override
+ Map<String, dynamic> toJson() {
+ var json = <String, dynamic>{};
+ json['type'] = 'CpuSamples';
+ json.addAll({
+ 'samplePeriod': samplePeriod,
+ 'maxStackDepth': maxStackDepth,
+ 'sampleCount': sampleCount,
+ 'timeSpan': timeSpan,
+ 'timeOriginMicros': timeOriginMicros,
+ 'timeExtentMicros': timeExtentMicros,
+ 'pid': pid,
+ 'functions': functions.map((f) => f.toJson()).toList(),
+ 'samples': samples.map((f) => f.toJson()).toList(),
+ });
+ return json;
+ }
+
+ String toString() => '[CpuSamples]';
+}
+
+/// See [getCpuSamples] and [CpuSamples].
+class CpuSample {
+ static CpuSample parse(Map<String, dynamic> json) =>
+ json == null ? null : new CpuSample._fromJson(json);
+
+ /// The thread ID representing the thread on which this sample was collected.
+ int tid;
+
+ /// The time this sample was collected in microseconds.
+ int timestamp;
+
+ /// The name of VM tag set when this sample was collected. Omitted if the VM
+ /// tag for the sample is not considered valid.
+ @optional
+ String vmTag;
+
+ /// The name of the User tag set when this sample was collected. Omitted if no
+ /// User tag was set when this sample was collected.
+ @optional
+ String userTag;
+
+ /// Provided and set to true if the sample's stack was truncated. This can
+ /// happen if the stack is deeper than the `stackDepth` in the `CpuSamples`
+ /// response.
+ @optional
+ bool truncated;
+
+ /// The call stack at the time this sample was collected. The stack is to be
+ /// interpreted as top to bottom. Each element in this array is a key into the
+ /// `functions` array in `CpuSamples`.
+ ///
+ /// Example:
+ ///
+ /// `functions[stack[0]] = @Function(bar())` `functions[stack[1]] =
+ /// @Function(foo())` `functions[stack[2]] = @Function(main())`
+ List<int> stack;
+
+ CpuSample();
+
+ CpuSample._fromJson(Map<String, dynamic> json) {
+ tid = json['tid'];
+ timestamp = json['timestamp'];
+ vmTag = json['vmTag'];
+ userTag = json['userTag'];
+ truncated = json['truncated'];
+ stack = new List<int>.from(json['stack']);
+ }
+
+ Map<String, dynamic> toJson() {
+ var json = <String, dynamic>{};
+ json.addAll({
+ 'tid': tid,
+ 'timestamp': timestamp,
+ 'stack': stack.map((f) => f).toList(),
+ });
+ _setIfNotNull(json, 'vmTag', vmTag);
+ _setIfNotNull(json, 'userTag', userTag);
+ _setIfNotNull(json, 'truncated', truncated);
+ return json;
+ }
+
+ String toString() =>
+ '[CpuSample tid: ${tid}, timestamp: ${timestamp}, stack: ${stack}]';
+}
+
/// `ErrorRef` is a reference to an `Error`.
class ErrorRef extends ObjRef {
static ErrorRef parse(Map<String, dynamic> json) =>
@@ -3492,6 +3697,20 @@
@optional
InstanceRef pattern;
+ /// The function associated with a Closure instance.
+ ///
+ /// Provided for instance kinds:
+ /// - Closure
+ @optional
+ FuncRef closureFunction;
+
+ /// The context associated with a Closure instance.
+ ///
+ /// Provided for instance kinds:
+ /// - Closure
+ @optional
+ ContextRef closureContext;
+
InstanceRef();
InstanceRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
@@ -3505,6 +3724,10 @@
parameterizedClass =
createServiceObject(json['parameterizedClass'], const ['ClassRef']);
pattern = createServiceObject(json['pattern'], const ['InstanceRef']);
+ closureFunction =
+ createServiceObject(json['closureFunction'], const ['FuncRef']);
+ closureContext =
+ createServiceObject(json['closureContext'], const ['ContextRef']);
}
@override
@@ -3523,6 +3746,8 @@
_setIfNotNull(json, 'typeClass', typeClass?.toJson());
_setIfNotNull(json, 'parameterizedClass', parameterizedClass?.toJson());
_setIfNotNull(json, 'pattern', pattern?.toJson());
+ _setIfNotNull(json, 'closureFunction', closureFunction?.toJson());
+ _setIfNotNull(json, 'closureContext', closureContext?.toJson());
return json;
}
@@ -3696,20 +3921,6 @@
@optional
String bytes;
- /// The function associated with a Closure instance.
- ///
- /// Provided for instance kinds:
- /// - Closure
- @optional
- FuncRef closureFunction;
-
- /// The context associated with a Closure instance.
- ///
- /// Provided for instance kinds:
- /// - Closure
- @optional
- ContextRef closureContext;
-
/// The referent of a MirrorReference instance.
///
/// Provided for instance kinds:
@@ -3816,10 +4027,6 @@
: new List<MapAssociation>.from(
_createSpecificObject(json['associations'], MapAssociation.parse));
bytes = json['bytes'];
- closureFunction =
- createServiceObject(json['closureFunction'], const ['FuncRef']);
- closureContext =
- createServiceObject(json['closureContext'], const ['ContextRef']);
mirrorReferent =
createServiceObject(json['mirrorReferent'], const ['InstanceRef']);
pattern = json['pattern'];
@@ -3859,8 +4066,6 @@
_setIfNotNull(
json, 'associations', associations?.map((f) => f?.toJson())?.toList());
_setIfNotNull(json, 'bytes', bytes);
- _setIfNotNull(json, 'closureFunction', closureFunction?.toJson());
- _setIfNotNull(json, 'closureContext', closureContext?.toJson());
_setIfNotNull(json, 'mirrorReferent', mirrorReferent?.toJson());
_setIfNotNull(json, 'pattern', pattern);
_setIfNotNull(json, 'isCaseSensitive', isCaseSensitive);
@@ -4491,6 +4696,32 @@
'size: ${size}]';
}
+/// A `NativeFunction` object is used to represent native functions in profiler
+/// samples. See [CpuSamples];
+class NativeFunction {
+ static NativeFunction parse(Map<String, dynamic> json) =>
+ json == null ? null : new NativeFunction._fromJson(json);
+
+ /// The name of the native function this object represents.
+ String name;
+
+ NativeFunction();
+
+ NativeFunction._fromJson(Map<String, dynamic> json) {
+ name = json['name'];
+ }
+
+ Map<String, dynamic> toJson() {
+ var json = <String, dynamic>{};
+ json.addAll({
+ 'name': name,
+ });
+ return json;
+ }
+
+ String toString() => '[NativeFunction name: ${name}]';
+}
+
/// `NullValRef` is a reference to an a `NullVal`.
class NullValRef extends InstanceRef {
static NullValRef parse(Map<String, dynamic> json) =>
@@ -4666,6 +4897,57 @@
String toString() => '[Obj type: ${type}, id: ${id}]';
}
+/// A `ProfileFunction` contains profiling information about a Dart or native
+/// function.
+///
+/// See [CpuSamples].
+class ProfileFunction {
+ static ProfileFunction parse(Map<String, dynamic> json) =>
+ json == null ? null : new ProfileFunction._fromJson(json);
+
+ /// The kind of function this object represents.
+ String kind;
+
+ /// The number of times function appeared on the stack during sampling events.
+ int inclusiveTicks;
+
+ /// The number of times function appeared on the top of the stack during
+ /// sampling events.
+ int exclusiveTicks;
+
+ /// The resolved URL for the script containing function.
+ String resolvedUrl;
+
+ /// The function captured during profiling.
+ dynamic function;
+
+ ProfileFunction();
+
+ ProfileFunction._fromJson(Map<String, dynamic> json) {
+ kind = json['kind'];
+ inclusiveTicks = json['inclusiveTicks'];
+ exclusiveTicks = json['exclusiveTicks'];
+ resolvedUrl = json['resolvedUrl'];
+ function = createServiceObject(json['function'], const ['dynamic']);
+ }
+
+ Map<String, dynamic> toJson() {
+ var json = <String, dynamic>{};
+ json.addAll({
+ 'kind': kind,
+ 'inclusiveTicks': inclusiveTicks,
+ 'exclusiveTicks': exclusiveTicks,
+ 'resolvedUrl': resolvedUrl,
+ 'function': function.toJson(),
+ });
+ return json;
+ }
+
+ String toString() => '[ProfileFunction ' //
+ 'kind: ${kind}, inclusiveTicks: ${inclusiveTicks}, exclusiveTicks: ${exclusiveTicks}, ' //
+ 'resolvedUrl: ${resolvedUrl}, function: ${function}]';
+}
+
class ReloadReport extends Response {
static ReloadReport parse(Map<String, dynamic> json) =>
json == null ? null : new ReloadReport._fromJson(json);
diff --git a/pkg/vm_service/lib/vm_service_io.dart b/pkg/vm_service/lib/vm_service_io.dart
index f7aa745..c95d0ac 100644
--- a/pkg/vm_service/lib/vm_service_io.dart
+++ b/pkg/vm_service/lib/vm_service_io.dart
@@ -7,20 +7,42 @@
import 'vm_service.dart';
+@Deprecated('Prefer vmServiceConnectUri')
Future<VmService> vmServiceConnect(String host, int port, {Log log}) async {
- WebSocket socket = await WebSocket.connect('ws://$host:$port/ws');
- StreamController<String> controller = new StreamController();
- socket.listen((data) => controller.add(data));
+ final WebSocket socket = await WebSocket.connect('ws://$host:$port/ws');
+ final StreamController<dynamic> controller = new StreamController();
+ final Completer streamClosedCompleter = new Completer();
+
+ socket.listen(
+ (data) => controller.add(data),
+ onDone: () => streamClosedCompleter.complete(),
+ );
+
return new VmService(
- controller.stream, (String message) => socket.add(message),
- log: log, disposeHandler: () => socket.close());
+ controller.stream,
+ (String message) => socket.add(message),
+ log: log,
+ disposeHandler: () => socket.close(),
+ streamClosed: streamClosedCompleter.future,
+ );
}
+/// Connect to the given uri and return a new [VmService] instance.
Future<VmService> vmServiceConnectUri(String wsUri, {Log log}) async {
- WebSocket socket = await WebSocket.connect(wsUri);
- StreamController<String> controller = new StreamController();
- socket.listen((data) => controller.add(data));
+ final WebSocket socket = await WebSocket.connect(wsUri);
+ final StreamController<dynamic> controller = new StreamController();
+ final Completer streamClosedCompleter = new Completer();
+
+ socket.listen(
+ (data) => controller.add(data),
+ onDone: () => streamClosedCompleter.complete(),
+ );
+
return new VmService(
- controller.stream, (String message) => socket.add(message),
- log: log, disposeHandler: () => socket.close());
+ controller.stream,
+ (String message) => socket.add(message),
+ log: log,
+ disposeHandler: () => socket.close(),
+ streamClosed: streamClosedCompleter.future,
+ );
}
diff --git a/pkg/vm_service/pubspec.yaml b/pkg/vm_service/pubspec.yaml
index 244e9f6..d5e62e2 100644
--- a/pkg/vm_service/pubspec.yaml
+++ b/pkg/vm_service/pubspec.yaml
@@ -2,7 +2,7 @@
description: >-
A library to communicate with a service implementing the Dart VM
service protocol.
-version: 1.1.1
+version: 1.2.0
author: Dart Team <misc@dartlang.org>
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/vm_service
diff --git a/pkg/vm_service/test/async_generator_breakpoint_test.dart b/pkg/vm_service/test/async_generator_breakpoint_test.dart
new file mode 100644
index 0000000..4d52ce4
--- /dev/null
+++ b/pkg/vm_service/test/async_generator_breakpoint_test.dart
@@ -0,0 +1,104 @@
+// Copyright (c) 2019, 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 'package:test/test.dart';
+import 'package:vm_service/vm_service.dart';
+import 'common/test_helper.dart';
+
+printSync() {
+ print('sync'); // Line 11
+}
+
+printAsync() async {
+ await null;
+ print('async'); // Line 16
+}
+
+printAsyncStar() async* {
+ await null;
+ print('async*'); // Line 21
+}
+
+printSyncStar() sync* {
+ print('sync*'); // Line 25
+}
+
+var testerReady = false;
+testeeDo() {
+ // We block here rather than allowing the isolate to enter the
+ // paused-on-exit state before the tester gets a chance to set
+ // the breakpoints because we need the event loop to remain
+ // operational for the async bodies to run.
+ print('testee waiting');
+ while (!testerReady) {}
+
+ printSync();
+ final future = printAsync();
+ final stream = printAsyncStar();
+ final iterator = printSyncStar();
+
+ print('middle'); // Line 42
+
+ future.then((v) => print(v));
+ stream.toList();
+ iterator.toList();
+}
+
+Future testAsync(VmService service, IsolateRef isolateRef) async {
+ final isolate = await service.getIsolate(isolateRef.id);
+ final lib = await service.getObject(isolate.id, isolate.rootLib.id);
+ final script = lib.scripts[0];
+
+ final bp1 = await service.addBreakpoint(isolate.id, script.id, 11);
+ expect(bp1, isNotNull);
+ expect(bp1 is Breakpoint, isTrue);
+
+ final bp2 = await service.addBreakpoint(isolate.id, script.id, 16);
+ expect(bp2, isNotNull);
+ expect(bp2 is Breakpoint, isTrue);
+
+ final bp3 = await service.addBreakpoint(isolate.id, script.id, 21);
+ expect(bp3, isNotNull);
+ expect(bp3 is Breakpoint, isTrue);
+
+ final bp4 = await service.addBreakpoint(isolate.id, script.id, 25);
+ expect(bp4, isNotNull);
+ expect(bp4 is Breakpoint, isTrue);
+
+ final bp5 = await service.addBreakpoint(isolate.id, script.id, 42);
+ expect(bp5, isNotNull);
+ expect(bp5 is Breakpoint, isTrue);
+
+ final hits = <Breakpoint>[];
+ await service.streamListen(EventStreams.kDebug);
+
+ // ignore: unawaited_futures
+ service
+ .evaluate(isolate.id, lib.id, 'testerReady = true')
+ .then((result) async {
+ result = await service.getObject(isolate.id, result.id);
+ print(result);
+ expect((result as Instance).valueAsString, equals('true'));
+ });
+
+ final stream = service.onDebugEvent;
+ await for (Event event in stream) {
+ if (event.kind == EventKind.kPauseBreakpoint) {
+ assert(event.pauseBreakpoints.isNotEmpty);
+ final bp = event.pauseBreakpoints.first;
+ hits.add(bp);
+ await service.resume(isolate.id);
+
+ if (hits.length == 5) break;
+ }
+ }
+
+ expect(hits, equals([bp1, bp5, bp4, bp2, bp3]));
+}
+
+final tests = <IsolateTest>[testAsync];
+
+main([args = const <String>[]]) =>
+ runIsolateTests(args, tests, testeeConcurrent: testeeDo);
diff --git a/pkg/vm_service/test/async_next_test.dart b/pkg/vm_service/test/async_next_test.dart
new file mode 100644
index 0000000..1d7387f
--- /dev/null
+++ b/pkg/vm_service/test/async_next_test.dart
@@ -0,0 +1,46 @@
+// Copyright (c) 2015, 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.
+// VMOptions=--verbose_debug
+
+import 'dart:developer';
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const int LINE_A = 18;
+const int LINE_B = 19;
+const int LINE_C = 20;
+
+foo() async {}
+
+doAsync(stop) async {
+ if (stop) debugger();
+ await foo(); // Line A.
+ await foo(); // Line B.
+ await foo(); // Line C.
+ return null;
+}
+
+testMain() {
+ // With two runs of doAsync floating around, async step should only cause
+ // us to stop in the run we started in.
+ doAsync(false);
+ doAsync(true);
+}
+
+var tests = <IsolateTest>[
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_A),
+ stepOver, // foo()
+ asyncNext,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_B),
+ stepOver, // foo()
+ asyncNext,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_C),
+ resumeIsolate,
+];
+
+main([args = const <String>[]]) =>
+ runIsolateTests(args, tests, testeeConcurrent: testMain);
diff --git a/pkg/vm_service/test/async_scope_test.dart b/pkg/vm_service/test/async_scope_test.dart
new file mode 100644
index 0000000..80813b6
--- /dev/null
+++ b/pkg/vm_service/test/async_scope_test.dart
@@ -0,0 +1,73 @@
+// Copyright (c) 2019, 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:developer';
+import 'package:vm_service/vm_service.dart';
+import 'package:test/test.dart';
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const int LINE_A = 20;
+const int LINE_B = 26;
+
+foo() {}
+
+doAsync(param1) async {
+ var local1 = param1 + 1;
+ foo(); // Line A.
+ await local1;
+}
+
+doAsyncStar(param2) async* {
+ var local2 = param2 + 1;
+ foo(); // Line B.
+ yield local2;
+}
+
+testeeDo() {
+ debugger();
+
+ doAsync(1).then((_) {
+ doAsyncStar(1).listen((_) {});
+ });
+}
+
+Future<void> checkAsyncVarDescriptors(
+ VmService service, IsolateRef isolateRef) async {
+ final stack = await service.getStack(isolateRef.id);
+ expect(stack.frames.length, greaterThanOrEqualTo(1));
+ final frame = stack.frames[0];
+ final vars = frame.vars.map((v) => v.name).join(' ');
+ expect(vars, 'param1 local1'); // no :async_op et al
+}
+
+Future checkAsyncStarVarDescriptors(
+ VmService service, IsolateRef isolateRef) async {
+ final stack = await service.getStack(isolateRef.id);
+ expect(stack.frames.length, greaterThanOrEqualTo(1));
+ final frame = stack.frames[0];
+ final vars = frame.vars.map((v) => v.name).join(' ');
+ expect(vars, 'param2 local2'); // no :async_op et al
+}
+
+var tests = <IsolateTest>[
+ hasStoppedAtBreakpoint, // debugger()
+ setBreakpointAtLine(LINE_A),
+ setBreakpointAtLine(LINE_B),
+ resumeIsolate,
+
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_A),
+ checkAsyncVarDescriptors,
+ resumeIsolate,
+
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_B),
+ checkAsyncStarVarDescriptors,
+ resumeIsolate,
+];
+
+main([args = const <String>[]]) =>
+ runIsolateTests(args, tests, testeeConcurrent: testeeDo);
diff --git a/pkg/vm_service/test/async_single_step_exception_test.dart b/pkg/vm_service/test/async_single_step_exception_test.dart
new file mode 100644
index 0000000..e36b6d8
--- /dev/null
+++ b/pkg/vm_service/test/async_single_step_exception_test.dart
@@ -0,0 +1,80 @@
+// Copyright (c) 2019, 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:developer';
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const LINE_A = 18;
+const LINE_B = 19;
+const LINE_C = 24;
+const LINE_D = 26;
+const LINE_E = 29;
+const LINE_F = 32;
+const LINE_G = 34;
+
+helper() async {
+ print('helper'); // LINE_A.
+ throw 'a'; // LINE_B.
+}
+
+testMain() async {
+ debugger();
+ print('mmmmm'); // LINE_C.
+ try {
+ await helper(); // LINE_D.
+ } catch (e) {
+ // arrive here on error.
+ print('error: $e'); // LINE_E.
+ } finally {
+ // arrive here in both cases.
+ print('foo'); // LINE_F.
+ }
+ print('z'); // LINE_G.
+}
+
+var tests = <IsolateTest>[
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_C), // print mmmm
+ smartNext,
+
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_D), // await helper
+ stepInto,
+
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_A), // print helper
+ smartNext,
+
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_B), // throw a
+ smartNext,
+
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(20), // } (weird dispatching)
+ smartNext,
+
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_D), // await helper (weird dispatching)
+ smartNext,
+
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_E), // print(error)
+ smartNext,
+
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_E), // print(error) (weird finally dispatching)
+ smartNext,
+
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_F), // print(foo)
+ smartNext,
+
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_G), // print(z)
+ resumeIsolate
+];
+
+main([args = const <String>[]]) =>
+ runIsolateTests(args, tests, testeeConcurrent: testMain);
diff --git a/pkg/vm_service/test/async_single_step_into_test.dart b/pkg/vm_service/test/async_single_step_into_test.dart
new file mode 100644
index 0000000..6d1072c
--- /dev/null
+++ b/pkg/vm_service/test/async_single_step_into_test.dart
@@ -0,0 +1,42 @@
+// Copyright (c) 2019, 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:developer';
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const LINE_A = 15;
+const LINE_B = 16;
+const LINE_C = 21;
+const LINE_D = 22;
+
+helper() async {
+ print('helper'); // LINE_A.
+ print('foobar'); // LINE_B.
+}
+
+testMain() {
+ debugger();
+ print('mmmmm'); // LINE_C.
+ helper(); // LINE_D.
+ print('z');
+}
+
+var tests = <IsolateTest>[
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_C),
+ stepOver, // print.
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_D),
+ stepInto,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_A),
+ stepOver, // print.
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_B),
+ resumeIsolate
+];
+
+main([args = const <String>[]]) =>
+ runIsolateTestsSynchronous(args, tests, testeeConcurrent: testMain);
diff --git a/pkg/vm_service/test/async_single_step_out_test.dart b/pkg/vm_service/test/async_single_step_out_test.dart
new file mode 100644
index 0000000..1b8eac7
--- /dev/null
+++ b/pkg/vm_service/test/async_single_step_out_test.dart
@@ -0,0 +1,58 @@
+// Copyright (c) 2019, 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:developer';
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const LINE_A = 16;
+const LINE_B = 17;
+const LINE_C = 22;
+const LINE_D = 23;
+const LINE_E = 24;
+
+helper() async {
+ print('helper'); // LINE_A.
+ return null; // LINE_B.
+}
+
+testMain() async {
+ debugger();
+ print('mmmmm'); // LINE_C.
+ await helper(); // LINE_D.
+ print('z'); // LINE_E.
+}
+
+var tests = <IsolateTest>[
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_C), // print mmmm
+ stepOver,
+
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_D), // await helper
+ stepInto,
+
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_A), // print.
+ stepOver,
+
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_B), // return null.
+ stepInto, // exit helper via a single step.
+
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(18), // return null (weird dispatching)
+ stepInto, // exit helper via a single step.
+
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(23), // await helper (weird dispatching)
+ smartNext,
+
+ hasStoppedAtBreakpoint, //19
+ stoppedAtLine(LINE_E), // arrive after the await.
+ resumeIsolate
+];
+
+main([args = const <String>[]]) =>
+ runIsolateTests(args, tests, testeeConcurrent: testMain);
diff --git a/pkg/vm_service/test/async_star_single_step_into_test.dart b/pkg/vm_service/test/async_star_single_step_into_test.dart
new file mode 100644
index 0000000..bb0f8da
--- /dev/null
+++ b/pkg/vm_service/test/async_star_single_step_into_test.dart
@@ -0,0 +1,65 @@
+// Copyright (c) 2019, 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:developer';
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const LINE_A = 17;
+const LINE_B = 18;
+const LINE_C = 22;
+const LINE_D = 26;
+const LINE_E = 32;
+const LINE_F = 33;
+
+foobar() async* {
+ yield 1; // LINE_A.
+ yield 2; // LINE_B.
+}
+
+helper() async {
+ print('helper'); // LINE_C.
+ // ignore: unused_local_variable
+ await for (var i in foobar()) {
+ debugger();
+ print('loop'); // LINE_D.
+ }
+}
+
+testMain() {
+ debugger();
+ print('mmmmm'); // LINE_E.
+ helper(); // LINE_F.
+ print('z');
+}
+
+var tests = <IsolateTest>[
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_E),
+ stepOver, // print.
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_F),
+ stepInto,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_C),
+ stepOver, // print.
+ hasStoppedAtBreakpoint,
+ stepInto,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_A),
+ // Resume here to exit the generator function.
+ // TODO(johnmccutchan): Implement support for step-out of async functions.
+ resumeIsolate,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_D),
+ stepOver, // print.
+ hasStoppedAtBreakpoint,
+ stepInto,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_B),
+ resumeIsolate,
+];
+
+main([args = const <String>[]]) =>
+ runIsolateTestsSynchronous(args, tests, testeeConcurrent: testMain);
diff --git a/pkg/vm_service/test/async_star_step_out_test.dart b/pkg/vm_service/test/async_star_step_out_test.dart
new file mode 100644
index 0000000..c1a532e
--- /dev/null
+++ b/pkg/vm_service/test/async_star_step_out_test.dart
@@ -0,0 +1,87 @@
+// Copyright (c) 2019, 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:developer';
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const LINE_A = 20;
+const LINE_B = 21;
+const LINE_C = 25;
+const LINE_D = 29;
+const LINE_E = 36;
+const LINE_F = 37;
+const LINE_G = 38;
+const LINE_H = 27;
+const LINE_I = 31;
+
+foobar() async* {
+ yield 1; // LINE_A.
+ yield 2; // LINE_B.
+}
+
+helper() async {
+ print('helper'); // LINE_C.
+ // ignore: unused_local_variable
+ await for (var i in foobar()) /* LINE_H */ {
+ debugger();
+ print('loop'); // LINE_D.
+ }
+ return null; // LINE_I.
+}
+
+testMain() {
+ debugger();
+ print('mmmmm'); // LINE_E.
+ helper(); // LINE_F.
+ print('z'); // LINE_G.
+}
+
+var tests = <IsolateTest>[
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_E),
+ stepOver, // print.
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_F),
+ stepInto,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_C),
+ stepOver, // print.
+ hasStoppedAtBreakpoint,
+ stepInto,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_A),
+ stepOut, // step out of generator.
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_H), // await for.
+ stepInto,
+ hasStoppedAtBreakpoint, // debugger().
+ stepInto,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_D), // print.
+ stepInto,
+ hasStoppedAtBreakpoint, // await for.
+ stepInto,
+ hasStoppedAtBreakpoint, // back in generator.
+ stoppedAtLine(LINE_B),
+ stepOut, // step out of generator.
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_H), // await for.
+ stepInto,
+ hasStoppedAtBreakpoint, // debugger().
+ stepInto,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_D), // print.
+ stepInto,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_H), // await for.
+ stepInto,
+ hasStoppedAtBreakpoint,
+ stepOut, // step out of generator.
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_I), // return null.
+];
+
+main([args = const <String>[]]) =>
+ runIsolateTestsSynchronous(args, tests, testeeConcurrent: testMain);
diff --git a/pkg/vm_service/test/async_step_out_test.dart b/pkg/vm_service/test/async_step_out_test.dart
new file mode 100644
index 0000000..4b80194
--- /dev/null
+++ b/pkg/vm_service/test/async_step_out_test.dart
@@ -0,0 +1,50 @@
+// Copyright (c) 2019, 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:developer';
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+const LINE_A = 17;
+const LINE_B = 18;
+const LINE_C = 19;
+const LINE_D = 24;
+const LINE_E = 25;
+const LINE_F = 26;
+
+helper() async {
+ await null; // LINE_A.
+ print('helper'); // LINE_B.
+ print('foobar'); // LINE_C.
+}
+
+testMain() async {
+ debugger();
+ print('mmmmm'); // LINE_D.
+ await helper(); // LINE_E.
+ print('z'); // LINE_F.
+}
+
+var tests = <IsolateTest>[
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_D),
+ stepOver, // print.
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_E),
+ stepInto,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_A),
+ asyncNext,
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_B),
+ stepOver, // print.
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_C),
+ stepOut, // out of helper to awaiter testMain.
+ hasStoppedAtBreakpoint,
+ stoppedAtLine(LINE_F),
+];
+
+main([args = const <String>[]]) =>
+ runIsolateTests(args, tests, testeeConcurrent: testMain);
diff --git a/pkg/vm_service/test/common/service_test_common.dart b/pkg/vm_service/test/common/service_test_common.dart
new file mode 100644
index 0000000..b6f32cb
--- /dev/null
+++ b/pkg/vm_service/test/common/service_test_common.dart
@@ -0,0 +1,205 @@
+// Copyright (c) 2019, 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.
+
+library service_test_common;
+
+import 'dart:async';
+import 'package:vm_service/vm_service.dart';
+import 'package:test/test.dart';
+
+typedef IsolateTest = Future<void> Function(
+ VmService service, IsolateRef isolate);
+typedef VMTest = Future<void> Function(VmService service);
+
+Future<void> smartNext(VmService service, IsolateRef isolateRef) async {
+ print('smartNext');
+ final isolate = await service.getIsolate(isolateRef.id);
+ if ((isolate.pauseEvent != null) &&
+ (isolate.pauseEvent.kind == EventKind.kPauseBreakpoint)) {
+ Event event = isolate.pauseEvent;
+ // TODO(bkonyi): remove needless refetching of isolate object.
+ if (event?.atAsyncSuspension ?? false) {
+ return asyncNext(service, isolateRef);
+ } else {
+ return syncNext(service, isolateRef);
+ }
+ } else {
+ throw 'The program is already running';
+ }
+}
+
+Future<void> asyncNext(VmService service, IsolateRef isolateRef) async {
+ print('asyncNext');
+ final isolate = await service.getIsolate(isolateRef.id);
+ if ((isolate.pauseEvent != null) &&
+ (isolate.pauseEvent.kind == EventKind.kPauseBreakpoint)) {
+ dynamic event = isolate.pauseEvent;
+ if (!event.atAsyncSuspension) {
+ throw 'No async continuation at this location';
+ } else {
+ return service.resume(isolateRef.id, step: 'OverAsyncSuspension');
+ }
+ } else {
+ throw 'The program is already running';
+ }
+}
+
+Future<void> syncNext(VmService service, IsolateRef isolateRef) async {
+ print('syncNext');
+ final isolate = await service.getIsolate(isolateRef.id);
+ if ((isolate.pauseEvent != null) &&
+ (isolate.pauseEvent.kind == EventKind.kPauseBreakpoint)) {
+ return service.resume(isolate.id, step: 'Over');
+ } else {
+ throw 'The program is already running';
+ }
+}
+
+Future<void> hasPausedFor(
+ VmService service, IsolateRef isolateRef, String kind) async {
+ var completer = Completer();
+ var subscription;
+ subscription = service.onDebugEvent.listen((event) async {
+ if ((isolateRef.id == event.isolate.id) && (event.kind == kind)) {
+ if (completer != null) {
+ try {
+ await service.streamCancel(EventStreams.kDebug);
+ } catch (_) {/* swallow exception */} finally {
+ subscription.cancel();
+ completer?.complete();
+ completer = null;
+ }
+ }
+ }
+ });
+ await service.streamListen(EventStreams.kDebug);
+
+ // Pause may have happened before we subscribed.
+ final isolate = await service.getIsolate(isolateRef.id);
+ if ((isolate.pauseEvent != null) && (isolate.pauseEvent.kind == kind)) {
+ if (completer != null) {
+ try {
+ await service.streamCancel(EventStreams.kDebug);
+ } catch (_) {/* swallow exception */} finally {
+ subscription.cancel();
+ completer?.complete();
+ }
+ }
+ }
+ return completer?.future; // Will complete when breakpoint hit.
+}
+
+Future<void> hasStoppedAtBreakpoint(VmService service, IsolateRef isolate) {
+ return hasPausedFor(service, isolate, EventKind.kPauseBreakpoint);
+}
+
+Future<void> hasStoppedPostRequest(VmService service, IsolateRef isolate) {
+ return hasPausedFor(service, isolate, EventKind.kPausePostRequest);
+}
+
+Future<void> hasStoppedWithUnhandledException(
+ VmService service, IsolateRef isolate) {
+ return hasPausedFor(service, isolate, EventKind.kPauseException);
+}
+
+Future<void> hasStoppedAtExit(VmService service, IsolateRef isolate) {
+ return hasPausedFor(service, isolate, EventKind.kPauseExit);
+}
+
+Future<void> hasPausedAtStart(VmService service, IsolateRef isolate) {
+ return hasPausedFor(service, isolate, EventKind.kPauseStart);
+}
+
+// Currying is your friend.
+IsolateTest setBreakpointAtLine(int line) {
+ return (VmService service, IsolateRef isolateRef) async {
+ print("Setting breakpoint for line $line");
+ final isolate = await service.getIsolate(isolateRef.id);
+ final lib = await service.getObject(isolate.id, isolate.rootLib.id);
+ final script = lib.scripts.first;
+
+ Breakpoint bpt = await service.addBreakpoint(isolate.id, script.id, line);
+ print("Breakpoint is $bpt");
+ };
+}
+
+int _tokenToLine(Script script, int tokenPos) {
+ final table = script.tokenPosTable;
+ for (List line in table) {
+ // Each entry begins with a line number...
+ int lineNumber = line[0];
+ for (var pos = 1; pos < line.length; pos += 2) {
+ // ...and is followed by (token offset, col number) pairs.
+ int tokenOffset = line[pos];
+ if (tokenOffset == tokenPos) {
+ return lineNumber;
+ }
+ }
+ }
+ throw ArgumentError('Invalid tokenPos: $tokenPos');
+}
+
+IsolateTest stoppedAtLine(int line) {
+ return (VmService service, IsolateRef isolateRef) async {
+ print("Checking we are at line $line");
+
+ // Make sure that the isolate has stopped.
+ final isolate = await service.getIsolate(isolateRef.id);
+ expect(isolate.pauseEvent != EventKind.kResume, isTrue);
+
+ final stack = await service.getStack(isolateRef.id);
+
+ final frames = stack.frames;
+ expect(frames.length, greaterThanOrEqualTo(1));
+
+ final top = frames[0];
+ final script = await service.getObject(isolate.id, top.location.script.id);
+ int actualLine = _tokenToLine(script, top.location.tokenPos);
+ if (actualLine != line) {
+ print("Actual: $actualLine Line: $line");
+ final sb = StringBuffer();
+ sb.write("Expected to be at line $line but actually at line $actualLine");
+ sb.write("\nFull stack trace:\n");
+ for (Frame f in stack.frames) {
+ sb.write(" $f [${_tokenToLine(script, f.location.tokenPos)}]\n");
+ }
+ throw sb.toString();
+ } else {
+ print('Program is stopped at line: $line');
+ }
+ };
+}
+
+Future<void> resumeIsolate(VmService service, IsolateRef isolate) async {
+ Completer completer = Completer();
+ var subscription;
+ subscription = service.onDebugEvent.listen((event) async {
+ if (event.kind == EventKind.kResume) {
+ try {
+ await service.streamCancel(EventStreams.kDebug);
+ } catch (_) {/* swallow exception */} finally {
+ subscription.cancel();
+ completer.complete();
+ }
+ }
+ });
+ await service.streamListen(EventStreams.kDebug);
+ await service.resume(isolate.id);
+ return completer.future;
+}
+
+Future<void> stepOver(VmService service, IsolateRef isolateRef) async {
+ await service.resume(isolateRef.id, step: 'Over');
+ return hasStoppedAtBreakpoint(service, isolateRef);
+}
+
+Future<void> stepInto(VmService service, IsolateRef isolateRef) async {
+ await service.resume(isolateRef.id, step: 'Into');
+ return hasStoppedAtBreakpoint(service, isolateRef);
+}
+
+Future<void> stepOut(VmService service, IsolateRef isolateRef) async {
+ await service.resume(isolateRef.id, step: 'Out');
+ return hasStoppedAtBreakpoint(service, isolateRef);
+}
diff --git a/pkg/vm_service/test/common/test_helper.dart b/pkg/vm_service/test/common/test_helper.dart
new file mode 100644
index 0000000..f57f3ee
--- /dev/null
+++ b/pkg/vm_service/test/common/test_helper.dart
@@ -0,0 +1,449 @@
+// Copyright (c) 2019, 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.
+
+library test_helper;
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+import 'package:vm_service/vm_service_io.dart';
+import 'package:vm_service/vm_service.dart';
+import 'package:test/test.dart';
+import 'service_test_common.dart';
+export 'service_test_common.dart' show IsolateTest, VMTest;
+
+/// Will be set to the http address of the VM's service protocol before
+/// any tests are invoked.
+String serviceHttpAddress;
+String serviceWebsocketAddress;
+
+const String _TESTEE_ENV_KEY = 'SERVICE_TEST_TESTEE';
+const Map<String, String> _TESTEE_SPAWN_ENV = {_TESTEE_ENV_KEY: 'true'};
+bool _isTestee() {
+ return Platform.environment.containsKey(_TESTEE_ENV_KEY);
+}
+
+Uri _getTestUri() {
+ if (Platform.script.scheme == 'data') {
+ // If we're using pub to run these tests this value isn't a file URI.
+ // We'll need to parse the actual URI out...
+ final fileRegExp = RegExp(r'file:\/\/\/.*\.dart');
+ final path = fileRegExp.stringMatch(Platform.script.data.contentAsString());
+ if (path == null) {
+ throw 'Unable to determine file path for script!';
+ }
+ return Uri.parse(path);
+ } else {
+ return Platform.script;
+ }
+}
+
+class _ServiceTesteeRunner {
+ Future run(
+ {Function() testeeBefore,
+ Function() testeeConcurrent,
+ bool pause_on_start = false,
+ bool pause_on_exit = false}) async {
+ if (!pause_on_start) {
+ if (testeeBefore != null) {
+ var result = testeeBefore();
+ if (result is Future) {
+ await result;
+ }
+ }
+ print(''); // Print blank line to signal that testeeBefore has run.
+ }
+ if (testeeConcurrent != null) {
+ var result = testeeConcurrent();
+ if (result is Future) {
+ await result;
+ }
+ }
+ if (!pause_on_exit) {
+ // Wait around for the process to be killed.
+ // ignore: unawaited_futures
+ stdin.first.then((_) => exit(0));
+ }
+ }
+
+ void runSync(
+ {void Function() testeeBeforeSync,
+ void Function() testeeConcurrentSync,
+ bool pause_on_start = false,
+ bool pause_on_exit = false}) {
+ if (!pause_on_start) {
+ if (testeeBeforeSync != null) {
+ testeeBeforeSync();
+ }
+ print(''); // Print blank line to signal that testeeBefore has run.
+ }
+ if (testeeConcurrentSync != null) {
+ testeeConcurrentSync();
+ }
+ if (!pause_on_exit) {
+ // Wait around for the process to be killed.
+ stdin.first.then((_) => exit(0));
+ }
+ }
+}
+
+class _ServiceTesteeLauncher {
+ Process process;
+ List<String> args;
+ bool killedByTester = false;
+
+ _ServiceTesteeLauncher() : args = [_getTestUri().toFilePath()];
+
+ // Spawn the testee process.
+ Future<Process> _spawnProcess(
+ bool pause_on_start,
+ bool pause_on_exit,
+ bool pause_on_unhandled_exceptions,
+ bool testeeControlsServer,
+ bool useAuthToken,
+ List<String> extraArgs,
+ ) {
+ assert(pause_on_start != null);
+ assert(pause_on_exit != null);
+ assert(pause_on_unhandled_exceptions != null);
+ assert(testeeControlsServer != null);
+ assert(useAuthToken != null);
+ return _spawnDartProcess(
+ pause_on_start,
+ pause_on_exit,
+ pause_on_unhandled_exceptions,
+ testeeControlsServer,
+ useAuthToken,
+ extraArgs);
+ }
+
+ Future<Process> _spawnDartProcess(
+ bool pause_on_start,
+ bool pause_on_exit,
+ bool pause_on_unhandled_exceptions,
+ bool testeeControlsServer,
+ bool useAuthToken,
+ List<String> extraArgs) {
+ String dartExecutable = Platform.executable;
+
+ var fullArgs = <String>[];
+ if (pause_on_start) {
+ fullArgs.add('--pause-isolates-on-start');
+ }
+ if (pause_on_exit) {
+ fullArgs.add('--pause-isolates-on-exit');
+ }
+ if (!useAuthToken) {
+ fullArgs.add('--disable-service-auth-codes');
+ }
+ if (pause_on_unhandled_exceptions) {
+ fullArgs.add('--pause-isolates-on-unhandled-exceptions');
+ }
+ fullArgs.add('--profiler');
+ if (extraArgs != null) {
+ fullArgs.addAll(extraArgs);
+ }
+
+ fullArgs.addAll(Platform.executableArguments);
+ if (!testeeControlsServer) {
+ fullArgs.add('--enable-vm-service:0');
+ }
+ fullArgs.addAll(args);
+
+ return _spawnCommon(dartExecutable, fullArgs, <String, String>{});
+ }
+
+ Future<Process> _spawnCommon(String executable, List<String> arguments,
+ Map<String, String> dartEnvironment) {
+ var environment = _TESTEE_SPAWN_ENV;
+ var bashEnvironment = StringBuffer();
+ environment.forEach((k, v) => bashEnvironment.write("$k=$v "));
+ if (dartEnvironment != null) {
+ dartEnvironment.forEach((k, v) {
+ arguments.insert(0, '-D$k=$v');
+ });
+ }
+ print('** Launching $bashEnvironment$executable ${arguments.join(' ')}');
+ return Process.start(executable, arguments, environment: environment);
+ }
+
+ Future<Uri> launch(
+ bool pause_on_start,
+ bool pause_on_exit,
+ bool pause_on_unhandled_exceptions,
+ bool testeeControlsServer,
+ bool useAuthToken,
+ List<String> extraArgs) {
+ return _spawnProcess(
+ pause_on_start,
+ pause_on_exit,
+ pause_on_unhandled_exceptions,
+ testeeControlsServer,
+ useAuthToken,
+ extraArgs)
+ .then((p) {
+ Completer<Uri> completer = Completer<Uri>();
+ process = p;
+ Uri uri;
+ var blank;
+ var first = true;
+ process.stdout
+ .transform(utf8.decoder)
+ .transform(LineSplitter())
+ .listen((line) {
+ const kObservatoryListening = 'Observatory listening on ';
+ if (line.startsWith(kObservatoryListening)) {
+ uri = Uri.parse(line.substring(kObservatoryListening.length));
+ }
+ if (pause_on_start || line == '') {
+ // Received blank line.
+ blank = true;
+ }
+ if ((uri != null) && (blank == true) && (first == true)) {
+ completer.complete(uri);
+ // Stop repeat completions.
+ first = false;
+ print('** Signaled to run test queries on $uri');
+ }
+ print('>testee>out> $line');
+ });
+ process.stderr
+ .transform(utf8.decoder)
+ .transform(LineSplitter())
+ .listen((line) {
+ print('>testee>err> $line');
+ });
+ process.exitCode.then((exitCode) {
+ if ((exitCode != 0) && !killedByTester) {
+ throw "Testee exited with $exitCode";
+ }
+ print("** Process exited");
+ });
+ return completer.future;
+ });
+ }
+
+ void requestExit() {
+ if (process != null) {
+ print('** Killing script');
+ if (process.kill()) {
+ killedByTester = true;
+ }
+ }
+ }
+}
+
+void setupAddresses(Uri serverAddress) {
+ serviceWebsocketAddress =
+ 'ws://${serverAddress.authority}${serverAddress.path}ws';
+ serviceHttpAddress = 'http://${serverAddress.authority}${serverAddress.path}';
+}
+
+class _ServiceTesterRunner {
+ Future run(
+ {List<String> mainArgs,
+ List<String> extraArgs,
+ List<VMTest> vmTests,
+ List<IsolateTest> isolateTests,
+ bool pause_on_start = false,
+ bool pause_on_exit = false,
+ bool verbose_vm = false,
+ bool pause_on_unhandled_exceptions = false,
+ bool testeeControlsServer = false,
+ bool useAuthToken = false}) async {
+ var process = _ServiceTesteeLauncher();
+ VmService vm;
+ IsolateRef isolate;
+ setUpAll(() async {
+ await process
+ .launch(pause_on_start, pause_on_exit, pause_on_unhandled_exceptions,
+ testeeControlsServer, useAuthToken, extraArgs)
+ .then((Uri serverAddress) async {
+ if (mainArgs.contains("--gdb")) {
+ var pid = process.process.pid;
+ var wait = Duration(seconds: 10);
+ print("Testee has pid $pid, waiting $wait before continuing");
+ sleep(wait);
+ }
+ setupAddresses(serverAddress);
+ vm = await vmServiceConnectUri(serviceWebsocketAddress);
+ print('Done loading VM');
+ isolate = await getFirstIsolate(vm);
+ });
+ });
+
+ final name = _getTestUri().pathSegments.last;
+
+ test(name, () async {
+ // Run vm tests.
+ if (vmTests != null) {
+ var testIndex = 1;
+ var totalTests = vmTests.length;
+ for (var t in vmTests) {
+ print('$name [$testIndex/$totalTests]');
+ await t(vm);
+ testIndex++;
+ }
+ }
+
+ // Run isolate tests.
+ if (isolateTests != null) {
+ var testIndex = 1;
+ var totalTests = isolateTests.length;
+ for (var t in isolateTests) {
+ print('$name [$testIndex/$totalTests]');
+ await t(vm, isolate);
+ testIndex++;
+ }
+ }
+ });
+
+ tearDownAll(() {
+ print('All service tests completed successfully.');
+ process.requestExit();
+ });
+ }
+
+ Future<IsolateRef> getFirstIsolate(VmService service) async {
+ var vm = await service.getVM();
+
+ if (vm.isolates.isNotEmpty) {
+ return vm.isolates.first;
+ }
+ var completer = Completer();
+ StreamSubscription subscription;
+ subscription = service.onIsolateEvent.listen((Event event) async {
+ if (completer == null) {
+ await subscription.cancel();
+ return;
+ }
+ if (event.kind == EventKind.kIsolateRunnable) {
+ vm = await service.getVM();
+ assert(vm.isolates.isNotEmpty);
+ await subscription.cancel();
+ completer.complete(vm.isolates.first);
+ completer = null;
+ }
+ });
+
+ // The isolate may have started before we subscribed.
+ vm = await service.getVM();
+ if (vm.isolates.isNotEmpty) {
+ await subscription.cancel();
+ completer.complete(vm.isolates.first);
+ completer = null;
+ }
+ return await completer.future;
+ }
+}
+
+/// Runs [tests] in sequence, each of which should take an [Isolate] and
+/// return a [Future]. Code for setting up state can run before and/or
+/// concurrently with the tests. Uses [mainArgs] to determine whether
+/// to run tests or testee in this invocation of the script.
+Future<void> runIsolateTests(
+ List<String> mainArgs,
+ List<IsolateTest> tests, {
+ testeeBefore(),
+ testeeConcurrent(),
+ bool pause_on_start = false,
+ bool pause_on_exit = false,
+ bool verbose_vm = false,
+ bool pause_on_unhandled_exceptions = false,
+ bool testeeControlsServer = false,
+ bool useAuthToken = false,
+ List<String> extraArgs,
+}) async {
+ assert(!pause_on_start || testeeBefore == null);
+ if (_isTestee()) {
+ await _ServiceTesteeRunner().run(
+ testeeBefore: testeeBefore,
+ testeeConcurrent: testeeConcurrent,
+ pause_on_start: pause_on_start,
+ pause_on_exit: pause_on_exit);
+ } else {
+ await _ServiceTesterRunner().run(
+ mainArgs: mainArgs,
+ extraArgs: extraArgs,
+ isolateTests: tests,
+ pause_on_start: pause_on_start,
+ pause_on_exit: pause_on_exit,
+ verbose_vm: verbose_vm,
+ pause_on_unhandled_exceptions: pause_on_unhandled_exceptions,
+ testeeControlsServer: testeeControlsServer,
+ useAuthToken: useAuthToken);
+ }
+}
+
+/// Runs [tests] in sequence, each of which should take an [Isolate] and
+/// return a [Future]. Code for setting up state can run before and/or
+/// concurrently with the tests. Uses [mainArgs] to determine whether
+/// to run tests or testee in this invocation of the script.
+///
+/// This is a special version of this test harness specifically for the
+/// pause_on_unhandled_exceptions_test, which cannot properly function
+/// in an async context (because exceptions are *always* handled in async
+/// functions).
+void runIsolateTestsSynchronous(
+ List<String> mainArgs,
+ List<IsolateTest> tests, {
+ void testeeBefore(),
+ void testeeConcurrent(),
+ bool pause_on_start = false,
+ bool pause_on_exit = false,
+ bool verbose_vm = false,
+ bool pause_on_unhandled_exceptions = false,
+ List<String> extraArgs,
+}) {
+ assert(!pause_on_start || testeeBefore == null);
+ if (_isTestee()) {
+ _ServiceTesteeRunner().runSync(
+ testeeBeforeSync: testeeBefore,
+ testeeConcurrentSync: testeeConcurrent,
+ pause_on_start: pause_on_start,
+ pause_on_exit: pause_on_exit);
+ } else {
+ _ServiceTesterRunner().run(
+ mainArgs: mainArgs,
+ extraArgs: extraArgs,
+ isolateTests: tests,
+ pause_on_start: pause_on_start,
+ pause_on_exit: pause_on_exit,
+ verbose_vm: verbose_vm,
+ pause_on_unhandled_exceptions: pause_on_unhandled_exceptions);
+ }
+}
+
+/// Runs [tests] in sequence, each of which should take an [Isolate] and
+/// return a [Future]. Code for setting up state can run before and/or
+/// concurrently with the tests. Uses [mainArgs] to determine whether
+/// to run tests or testee in this invocation of the script.
+Future<void> runVMTests(
+ List<String> mainArgs,
+ List<VMTest> tests, {
+ testeeBefore(),
+ testeeConcurrent(),
+ bool pause_on_start = false,
+ bool pause_on_exit = false,
+ bool verbose_vm = false,
+ bool pause_on_unhandled_exceptions = false,
+ List<String> extraArgs,
+}) async {
+ if (_isTestee()) {
+ await _ServiceTesteeRunner().run(
+ testeeBefore: testeeBefore,
+ testeeConcurrent: testeeConcurrent,
+ pause_on_start: pause_on_start,
+ pause_on_exit: pause_on_exit);
+ } else {
+ await _ServiceTesterRunner().run(
+ mainArgs: mainArgs,
+ extraArgs: extraArgs,
+ vmTests: tests,
+ pause_on_start: pause_on_start,
+ pause_on_exit: pause_on_exit,
+ verbose_vm: verbose_vm,
+ pause_on_unhandled_exceptions: pause_on_unhandled_exceptions);
+ }
+}
diff --git a/pkg/vm_service/test/coverage_leaf_function_test.dart b/pkg/vm_service/test/coverage_leaf_function_test.dart
new file mode 100644
index 0000000..fe28924
--- /dev/null
+++ b/pkg/vm_service/test/coverage_leaf_function_test.dart
@@ -0,0 +1,105 @@
+// Copyright (c) 2019, 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:developer';
+import 'package:test/test.dart';
+import 'package:vm_service/vm_service.dart';
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+String leafFunction() {
+ return "some constant";
+}
+
+void testFunction() {
+ debugger();
+ leafFunction();
+ debugger();
+}
+
+bool allRangesCompiled(coverage) {
+ for (int i = 0; i < coverage['ranges'].length; i++) {
+ if (!coverage['ranges'][i]['compiled']) {
+ return false;
+ }
+ }
+ return true;
+}
+
+var tests = <IsolateTest>[
+ hasStoppedAtBreakpoint,
+ (VmService service, IsolateRef isolateRef) async {
+ final isolate = await service.getIsolate(isolateRef.id);
+ final stack = await service.getStack(isolate.id);
+
+ // Make sure we are in the right place.
+ expect(stack.frames.length, greaterThanOrEqualTo(1));
+ expect(stack.frames[0].function.name, 'testFunction');
+
+ final root = await service.getObject(isolate.id, isolate.rootLib.id);
+ var func = root.functions.singleWhere((f) => f.name == 'leafFunction');
+ func = await service.getObject(isolate.id, func.id);
+
+ final expectedRange = {
+ 'scriptIndex': 0,
+ 'startPos': 397,
+ 'endPos': 447,
+ 'compiled': true,
+ 'coverage': {
+ 'hits': [],
+ 'misses': [397]
+ }
+ };
+
+ final report = await service.getSourceReport(
+ isolate.id, [SourceReportKind.kCoverage],
+ scriptId: func.location.script.id,
+ tokenPos: func.location.tokenPos,
+ endTokenPos: func.location.endTokenPos,
+ forceCompile: true);
+ expect(report.ranges.length, 1);
+ expect(report.ranges[0].toJson(), expectedRange);
+ expect(report.scripts.length, 1);
+ expect(report.scripts[0].uri, endsWith('coverage_leaf_function_test.dart'));
+ },
+ resumeIsolate,
+ hasStoppedAtBreakpoint,
+ (VmService service, IsolateRef isolateRef) async {
+ final isolate = await service.getIsolate(isolateRef.id);
+ final stack = await service.getStack(isolate.id);
+
+ // Make sure we are in the right place.
+ expect(stack.frames.length, greaterThanOrEqualTo(1));
+ expect(stack.frames[0].function.name, 'testFunction');
+
+ final root = await service.getObject(isolate.id, isolate.rootLib.id);
+ var func = root.functions.singleWhere((f) => f.name == 'leafFunction');
+ func = await service.getObject(isolate.id, func.id);
+
+ var expectedRange = {
+ 'scriptIndex': 0,
+ 'startPos': 397,
+ 'endPos': 447,
+ 'compiled': true,
+ 'coverage': {
+ 'hits': [397],
+ 'misses': []
+ }
+ };
+
+ final report = await service.getSourceReport(
+ isolate.id, [SourceReportKind.kCoverage],
+ scriptId: func.location.script.id,
+ tokenPos: func.location.tokenPos,
+ endTokenPos: func.location.endTokenPos,
+ forceCompile: true);
+ expect(report.ranges.length, 1);
+ expect(report.ranges[0].toJson(), expectedRange);
+ expect(report.scripts.length, 1);
+ expect(report.scripts[0].uri, endsWith('coverage_leaf_function_test.dart'));
+ },
+];
+
+main([args = const <String>[]]) =>
+ runIsolateTests(args, tests, testeeConcurrent: testFunction);
diff --git a/pkg/vm_service/test/evaluate_with_scope_test.dart b/pkg/vm_service/test/evaluate_with_scope_test.dart
new file mode 100644
index 0000000..ad4a106
--- /dev/null
+++ b/pkg/vm_service/test/evaluate_with_scope_test.dart
@@ -0,0 +1,63 @@
+// Copyright (c) 2019, 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 'package:vm_service/vm_service.dart';
+import 'package:test/test.dart';
+import 'common/test_helper.dart';
+
+int thing1;
+int thing2;
+
+testeeMain() {
+ thing1 = 3;
+ thing2 = 4;
+}
+
+Future evaluate(VmService service, isolate, target, x, y) async => await service
+ .evaluate(isolate.id, target.id, 'x + y', scope: {'x': x.id, 'y': y.id});
+
+final tests = <IsolateTest>[
+ (VmService service, IsolateRef isolateRef) async {
+ final isolate = await service.getIsolate(isolateRef.id);
+ final lib = await service.getObject(isolate.id, isolate.rootLib.id);
+
+ final field1 = await service.getObject(
+ isolate.id, lib.variables.singleWhere((v) => v.name == 'thing1').id);
+ final thing1 = (await service.getObject(isolate.id, field1.staticValue.id));
+
+ final field2 = await service.getObject(
+ isolate.id, lib.variables.singleWhere((v) => v.name == 'thing2').id);
+ final thing2 = (await service.getObject(isolate.id, field2.staticValue.id));
+
+ var result = await evaluate(service, isolate, lib, thing1, thing2);
+ expect(result.valueAsString, equals('7'));
+
+ bool didThrow = false;
+ try {
+ result = await evaluate(service, isolate, lib, lib, lib);
+ print(result);
+ } catch (e) {
+ didThrow = true;
+ expect(e.toString(),
+ contains("Cannot evaluate against a VM-internal object"));
+ }
+ expect(didThrow, isTrue);
+
+ didThrow = false;
+ try {
+ result = await service.evaluate(isolate.id, lib.id, "x + y",
+ scope: <String, String>{"not&an&identifier": thing1.id});
+ print(result);
+ } catch (e) {
+ didThrow = true;
+ expect(e.toString(), contains("invalid 'scope' parameter"));
+ }
+ expect(didThrow, isTrue);
+ }
+];
+
+main([args = const <String>[]]) =>
+ runIsolateTests(args, tests, testeeBefore: testeeMain);
diff --git a/pkg/vm_service/test/get_cpu_samples_rpc_test.dart b/pkg/vm_service/test/get_cpu_samples_rpc_test.dart
new file mode 100644
index 0000000..70f640e
--- /dev/null
+++ b/pkg/vm_service/test/get_cpu_samples_rpc_test.dart
@@ -0,0 +1,61 @@
+// Copyright (c) 2019, 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 'package:vm_service/vm_service.dart';
+import 'package:test/test.dart';
+
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+fib(n) {
+ if (n < 0) return 0;
+ if (n == 0) return 1;
+ return fib(n - 1) + fib(n - 2);
+}
+
+testeeDo() {
+ print("Testee doing something.");
+ fib(30);
+ print("Testee did something.");
+}
+
+Future checkSamples(VmService service, IsolateRef isolate) async {
+ // Grab all the samples.
+ final result = await service.getCpuSamples(isolate.id, 0, ~0);
+
+ final isString = TypeMatcher<String>();
+ final isInt = TypeMatcher<int>();
+ final isList = TypeMatcher<List>();
+ expect(result.functions.length, greaterThan(10),
+ reason: "Should have many functions");
+
+ final samples = result.samples;
+ expect(samples.length, greaterThan(10), reason: "Should have many samples");
+ expect(samples.length, result.sampleCount);
+
+ final sample = samples.first;
+ expect(sample.tid, isInt);
+ expect(sample.timestamp, isInt);
+ if (sample.vmTag != null) {
+ expect(sample.vmTag, isString);
+ }
+ if (sample.userTag != null) {
+ expect(sample.userTag, isString);
+ }
+ expect(sample.stack, isList);
+}
+
+var tests = <IsolateTest>[
+ (VmService service, IsolateRef i) => checkSamples(service, i),
+];
+
+var vmArgs = [
+ '--profiler=true',
+ '--profile-vm=false', // So this also works with DBC and KBC.
+];
+
+main(args) async =>
+ runIsolateTests(args, tests, testeeBefore: testeeDo, extraArgs: vmArgs);
diff --git a/pkg/vm_service/test/get_version_rpc_test.dart b/pkg/vm_service/test/get_version_rpc_test.dart
new file mode 100644
index 0000000..130bf21
--- /dev/null
+++ b/pkg/vm_service/test/get_version_rpc_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2019, 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:vm_service/vm_service.dart';
+import 'package:test/test.dart';
+
+import 'common/test_helper.dart';
+
+var tests = <VMTest>[
+ (VmService vm) async {
+ final result = await vm.getVersion();
+ expect(result.major > 0, isTrue);
+ expect(result.minor >= 0, isTrue);
+ },
+];
+
+main([args = const <String>[]]) async => await runVMTests(args, tests);
diff --git a/pkg/vm_service/test/invoke_test.dart b/pkg/vm_service/test/invoke_test.dart
new file mode 100644
index 0000000..dcbb16e
--- /dev/null
+++ b/pkg/vm_service/test/invoke_test.dart
@@ -0,0 +1,76 @@
+// Copyright (c) 2019, 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:developer';
+import 'package:test/test.dart';
+import 'package:vm_service/vm_service.dart';
+import 'common/service_test_common.dart';
+import 'common/test_helper.dart';
+
+libraryFunction() => "foobar1";
+
+class Klass {
+ static classFunction(x) => "foobar2" + x;
+ instanceFunction(x, y) => "foobar3" + x + y;
+}
+
+var instance;
+
+var apple;
+var banana;
+
+void testFunction() {
+ instance = Klass();
+ apple = "apple";
+ banana = "banana";
+ debugger();
+}
+
+var tests = <IsolateTest>[
+ hasStoppedAtBreakpoint,
+ (VmService service, IsolateRef isolateRef) async {
+ final isolate = await service.getIsolate(isolateRef.id);
+ final lib = await service.getObject(isolate.id, isolate.rootLib.id);
+ final cls = lib.classes.singleWhere((cls) => cls.name == "Klass");
+ FieldRef fieldRef =
+ lib.variables.singleWhere((field) => field.name == "instance");
+ Field field = await service.getObject(isolate.id, fieldRef.id);
+ final instance = await service.getObject(isolate.id, field.staticValue.id);
+
+ fieldRef = lib.variables.singleWhere((field) => field.name == "apple");
+ field = await service.getObject(isolate.id, fieldRef.id);
+ final apple = await service.getObject(isolate.id, field.staticValue.id);
+ fieldRef = lib.variables.singleWhere((field) => field.name == "banana");
+ field = await service.getObject(isolate.id, fieldRef.id);
+ Instance banana = await service.getObject(isolate.id, field.staticValue.id);
+
+ dynamic result =
+ await service.invoke(isolate.id, lib.id, 'libraryFunction', []);
+ expect(result.valueAsString, equals('foobar1'));
+
+ result =
+ await service.invoke(isolate.id, cls.id, "classFunction", [apple.id]);
+ expect(result.valueAsString, equals('foobar2apple'));
+
+ result = await service.invoke(
+ isolate.id, instance.id, "instanceFunction", [apple.id, banana.id]);
+ expect(result.valueAsString, equals('foobar3applebanana'));
+
+ // Wrong arity.
+ await expectError(() => service
+ .invoke(isolate.id, instance.id, "instanceFunction", [apple.id]));
+ // No such target.
+ await expectError(() => service
+ .invoke(isolate.id, instance.id, "functionDoesNotExist", [apple.id]));
+ },
+ resumeIsolate,
+];
+
+expectError(func) async {
+ dynamic result = await func();
+ expect(result.type == 'Error' || result.type == '@Error', isTrue);
+}
+
+main([args = const <String>[]]) =>
+ runIsolateTests(args, tests, testeeConcurrent: testFunction);
diff --git a/pkg/vm_service/tool/dart/generate_dart.dart b/pkg/vm_service/tool/dart/generate_dart.dart
index be4a182..0a5f50f 100644
--- a/pkg/vm_service/tool/dart/generate_dart.dart
+++ b/pkg/vm_service/tool/dart/generate_dart.dart
@@ -94,9 +94,16 @@
void dispose() {
_streamSub.cancel();
_completers.values.forEach((c) => c.completeError('disposed'));
- if (_disposeHandler != null) _disposeHandler();
+ if (_disposeHandler != null) {
+ _disposeHandler();
+ }
+ if (!_onDoneCompleter.isCompleted) {
+ _onDoneCompleter.complete();
+ }
}
+ Future get onDone => _onDoneCompleter.future;
+
Future<T> _call<T>(String method, [Map args]) {
String id = '${++_id}';
Completer<T> completer = new Completer<T>();
@@ -736,6 +743,8 @@
StreamController<String> _onSend = new StreamController.broadcast(sync: true);
StreamController<String> _onReceive = new StreamController.broadcast(sync: true);
+final Completer _onDoneCompleter = new Completer();
+
Map<String, StreamController<Event>> _eventControllers = {};
StreamController<Event> _getEventController(String eventName) {
@@ -751,12 +760,18 @@
VmService(Stream<dynamic> /*String|List<int>*/ inStream, void writeMessage(String message), {
Log log,
- DisposeHandler disposeHandler
+ DisposeHandler disposeHandler,
+ Future streamClosed,
}) {
- _streamSub = inStream.listen(_processMessage);
+ _streamSub = inStream.listen(_processMessage, onDone: ()=> _onDoneCompleter.complete());
_writeMessage = writeMessage;
_log = log == null ? new _NullLog() : log;
_disposeHandler = disposeHandler;
+ streamClosed?.then((_) {
+ if (!_onDoneCompleter.isCompleted) {
+ _onDoneCompleter.complete();
+ }
+ });
}
@override
@@ -816,6 +831,11 @@
return obj;
}
+dynamic assertDynamic(dynamic obj) {
+ assertNotNull(obj);
+ return obj;
+}
+
List<int> assertListOfInt(List<int> list) {
for (int elem in list) {
assertInt(elem);
@@ -910,6 +930,7 @@
'ClassHeapStats',
'CodeRegion',
'ContextElement',
+ 'CpuSample',
'Flag',
'Frame',
'InboundReference',
diff --git a/runtime/.clang-tidy b/runtime/.clang-tidy
new file mode 100644
index 0000000..633aabf
--- /dev/null
+++ b/runtime/.clang-tidy
@@ -0,0 +1 @@
+Checks: -*,readability-implicit-bool-conversion
diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc
index 9211fc0..97fd635 100644
--- a/runtime/bin/dartutils.cc
+++ b/runtime/bin/dartutils.cc
@@ -798,7 +798,7 @@
// objects. As these will be used by different threads the use of
// these depends on the fact that the marking internally in the
// Dart_CObject structure is not marking simple value objects.
-Dart_CObject CObject::api_null_ = {Dart_CObject_kNull, {0}};
+Dart_CObject CObject::api_null_ = {Dart_CObject_kNull, {false}};
Dart_CObject CObject::api_true_ = {Dart_CObject_kBool, {true}};
Dart_CObject CObject::api_false_ = {Dart_CObject_kBool, {false}};
CObject CObject::null_(&api_null_);
diff --git a/runtime/bin/dfe.cc b/runtime/bin/dfe.cc
index c7a7266..3e5eaf9 100644
--- a/runtime/bin/dfe.cc
+++ b/runtime/bin/dfe.cc
@@ -233,7 +233,7 @@
if (len > 2 && path[1] == ':') {
*s++ = '/';
}
- for (const char *p = path; *p; ++p, ++s) {
+ for (const char* p = path; *p != '\0'; ++p, ++s) {
*s = *p == '\\' ? '/' : *p;
}
*s = '\0';
diff --git a/runtime/bin/eventhandler_win.cc b/runtime/bin/eventhandler_win.cc
index 37b4f28..6ed0744 100644
--- a/runtime/bin/eventhandler_win.cc
+++ b/runtime/bin/eventhandler_win.cc
@@ -403,15 +403,19 @@
return true;
}
OverlappedBuffer* buffer = OverlappedBuffer::AllocateReadBuffer(kBufferSize);
+ // Set up pending_read_ before ReadDirectoryChangesW because it might be
+ // needed in ReadComplete invoked on event loop thread right away if data is
+ // also ready right away.
+ pending_read_ = buffer;
ASSERT(completion_port_ != INVALID_HANDLE_VALUE);
BOOL ok = ReadDirectoryChangesW(handle_, buffer->GetBufferStart(),
buffer->GetBufferSize(), recursive_, events_,
NULL, buffer->GetCleanOverlapped(), NULL);
if (ok || (GetLastError() == ERROR_IO_PENDING)) {
// Completing asynchronously.
- pending_read_ = buffer;
return true;
}
+ pending_read_ = nullptr;
OverlappedBuffer::DisposeBuffer(buffer);
return false;
}
@@ -1103,7 +1107,8 @@
// If out events (can write events) have been requested, and there
// are no pending writes, meaning any writes are already complete,
// post an out event immediately.
- if ((events & (1 << kOutEvent)) != 0) {
+ intptr_t out_event_mask = 1 << kOutEvent;
+ if ((events & out_event_mask) != 0) {
if (!handle->HasPendingWrite()) {
if (handle->is_client_socket()) {
if (reinterpret_cast<ClientSocket*>(handle)->is_connected()) {
@@ -1114,14 +1119,25 @@
}
}
} else {
- intptr_t event_mask = 1 << kOutEvent;
- if ((handle->Mask() & event_mask) != 0) {
- Dart_Port port = handle->NextNotifyDartPort(event_mask);
- DartUtils::PostInt32(port, event_mask);
+ if ((handle->Mask() & out_event_mask) != 0) {
+ Dart_Port port = handle->NextNotifyDartPort(out_event_mask);
+ DartUtils::PostInt32(port, out_event_mask);
}
}
}
}
+ // Similarly, if in events (can read events) have been requested, and
+ // there is pending data available, post an in event immediately.
+ intptr_t in_event_mask = 1 << kInEvent;
+ if ((events & in_event_mask) != 0) {
+ if (handle->data_ready_ != nullptr &&
+ !handle->data_ready_->IsEmpty()) {
+ if ((handle->Mask() & in_event_mask) != 0) {
+ Dart_Port port = handle->NextNotifyDartPort(in_event_mask);
+ DartUtils::PostInt32(port, in_event_mask);
+ }
+ }
+ }
} else if (IS_COMMAND(msg->data, kShutdownReadCommand)) {
ASSERT(handle->is_client_socket());
diff --git a/runtime/bin/ffi_test/ffi_test_functions.cc b/runtime/bin/ffi_test/ffi_test_functions.cc
index 6e6223e..85145b1 100644
--- a/runtime/bin/ffi_test/ffi_test_functions.cc
+++ b/runtime/bin/ffi_test/ffi_test_functions.cc
@@ -39,6 +39,9 @@
////////////////////////////////////////////////////////////////////////////////
// Tests for Dart -> native calls.
+//
+// Note: If this interface is changed please also update
+// sdk/runtime/tools/dartfuzz/ffiapi.dart
// Sums two ints and adds 42.
// Simple function to test trampolines.
@@ -309,7 +312,7 @@
// Coordinate.
// Used for testing function pointers with structs.
DART_EXPORT Coord* CoordinateUnOpTrice(CoordUnOp unop, Coord* coord) {
- std::cout << "CoordinateUnOpTrice(" << unop << ", " << coord << ")\n";
+ std::cout << "CoordinateUnOpTrice(" << &unop << ", " << coord << ")\n";
Coord* retval = unop(unop(unop(coord)));
std::cout << "returning " << retval << "\n";
return retval;
@@ -324,7 +327,7 @@
DART_EXPORT IntptrBinOp IntptrAdditionClosure() {
std::cout << "IntptrAdditionClosure()\n";
IntptrBinOp retval = [](intptr_t a, intptr_t b) { return a + b; };
- std::cout << "returning " << retval << "\n";
+ std::cout << "returning " << &retval << "\n";
return retval;
}
@@ -343,7 +346,7 @@
DART_EXPORT int64_t* NullableInt64ElemAt1(int64_t* a) {
std::cout << "NullableInt64ElemAt1(" << a << ")\n";
int64_t* retval;
- if (a) {
+ if (a != nullptr) {
std::cout << "not null pointer, address: " << a << "\n";
retval = a + 1;
} else {
@@ -436,7 +439,7 @@
retval += vls->k;
retval += vls->smallLastField;
std::cout << retval << "\n";
- if (vls->parent) {
+ if (vls->parent != nullptr) {
std::cout << "has parent\n";
retval += vls->parent->a;
}
@@ -756,7 +759,7 @@
}
DART_EXPORT int TestThrowExceptionPointer(void* (*fn)()) {
- CHECK_EQ(fn(), reinterpret_cast<void*>(42));
+ CHECK_EQ(fn(), nullptr);
return 0;
}
diff --git a/runtime/bin/file.cc b/runtime/bin/file.cc
index 3acf44a..a72d807 100644
--- a/runtime/bin/file.cc
+++ b/runtime/bin/file.cc
@@ -1507,7 +1507,7 @@
// Inspired by sdk/lib/core/uri.dart
UriDecoder::UriDecoder(const char* uri) : uri_(uri) {
const char* ch = uri;
- while ((*ch != 0) && (*ch != '%')) {
+ while ((*ch != '\0') && (*ch != '%')) {
ch++;
}
if (*ch == 0) {
@@ -1524,7 +1524,7 @@
strncpy(dest, uri, i);
decoded_ = dest;
dest += i;
- while (*ch) {
+ while (*ch != '\0') {
if (*ch != '%') {
*(dest++) = *(ch++);
continue;
diff --git a/runtime/bin/file_system_watcher_linux.cc b/runtime/bin/file_system_watcher_linux.cc
index c23c133..f16b87c 100644
--- a/runtime/bin/file_system_watcher_linux.cc
+++ b/runtime/bin/file_system_watcher_linux.cc
@@ -132,7 +132,7 @@
} else {
Dart_ListSetAt(event, 2, Dart_Null());
}
- Dart_ListSetAt(event, 3, Dart_NewBoolean(e->mask & IN_MOVED_TO));
+ Dart_ListSetAt(event, 3, Dart_NewBoolean((e->mask & IN_MOVED_TO) != 0u));
Dart_ListSetAt(event, 4, Dart_NewInteger(e->wd));
Dart_ListSetAt(events, i, event);
i++;
diff --git a/runtime/bin/file_system_watcher_win.cc b/runtime/bin/file_system_watcher_win.cc
index 990f905..33654c4 100644
--- a/runtime/bin/file_system_watcher_win.cc
+++ b/runtime/bin/file_system_watcher_win.cc
@@ -56,6 +56,10 @@
DirectoryWatchHandle* handle =
new DirectoryWatchHandle(dir, list_events, recursive);
+ // Issue a read directly, to be sure events are tracked from now on. This is
+ // okay, since in Dart, we create the socket and start reading immidiately.
+ handle->EnsureInitialized(EventHandler::delegate());
+ handle->IssueRead();
return reinterpret_cast<intptr_t>(handle);
}
diff --git a/runtime/bin/file_test.cc b/runtime/bin/file_test.cc
index 967eec8..60adf31 100644
--- a/runtime/bin/file_test.cc
+++ b/runtime/bin/file_test.cc
@@ -41,7 +41,7 @@
strlen(kFilename) * 3 + 1));
char* t = encoded;
// percent-encode all characters 'c'
- for (const char* p = kFilename; *p; p++) {
+ for (const char* p = kFilename; *p != '\0'; p++) {
if (*p == 'c') {
*t++ = '%';
*t++ = '6';
@@ -70,7 +70,7 @@
strlen(kFilename) * 3 + 1));
char* t = encoded;
// percent-encode all characters 'c'
- for (const char* p = kFilename; *p; p++) {
+ for (const char* p = kFilename; *p != '\0'; p++) {
if (*p == 'c') {
*t++ = '%';
*t++ = '6';
@@ -110,7 +110,7 @@
strlen(kFilename) * 3 + 1));
char* t = encoded;
// percent-encode all characters 'c'
- for (const char* p = kFilename; *p; p++) {
+ for (const char* p = kFilename; *p != '\0'; p++) {
if (*p == 'c') {
*t++ = '%';
*t++ = '6';
@@ -151,7 +151,7 @@
strlen(kFilename) * 3 + 1));
char* t = encoded;
// percent-encode all spaces
- for (const char* p = kFilename; *p; p++) {
+ for (const char* p = kFilename; *p != '\0'; p++) {
if (*p == ' ') {
*t++ = '%';
*t++ = '2';
@@ -180,7 +180,7 @@
strlen(kFilename) * 3 + 1));
char* t = encoded;
// percent-encode all characters 'c'
- for (const char* p = kFilename; *p; p++) {
+ for (const char* p = kFilename; *p != '\0'; p++) {
if (*p == 'c') {
*t++ = '%';
*t++ = 'f';
@@ -200,7 +200,7 @@
strlen(kFilename) * 3 + 1));
char* t = encoded;
// percent-encode all characters 'c'
- for (const char* p = kFilename; *p; p++) {
+ for (const char* p = kFilename; *p != '\0'; p++) {
if (*p == 'c') {
*t++ = '%';
*t++ = 'f';
diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc
index 63f940cd3..d7a2a4e 100644
--- a/runtime/bin/gen_snapshot.cc
+++ b/runtime/bin/gen_snapshot.cc
@@ -864,11 +864,6 @@
TimerUtils::InitOnce();
EventHandler::Start();
-#if !defined(PRODUCT)
- // Constant true in PRODUCT mode.
- vm_options.AddArgument("--load_deferred_eagerly");
-#endif
-
if (IsSnapshottingForPrecompilation()) {
vm_options.AddArgument("--precompilation");
} else if ((snapshot_kind == kCoreJIT) || (snapshot_kind == kAppJIT)) {
@@ -909,7 +904,7 @@
MapFile(load_vm_snapshot_instructions_filename, File::kReadExecute,
&init_params.vm_snapshot_instructions);
}
- if (load_isolate_snapshot_data_filename) {
+ if (load_isolate_snapshot_data_filename != nullptr) {
mapped_isolate_snapshot_data =
MapFile(load_isolate_snapshot_data_filename, File::kReadOnly,
&isolate_snapshot_data);
diff --git a/runtime/bin/io_natives.cc b/runtime/bin/io_natives.cc
index 935f2ea..f34671c 100644
--- a/runtime/bin/io_natives.cc
+++ b/runtime/bin/io_natives.cc
@@ -129,12 +129,12 @@
V(SecurityContext_TrustBuiltinRoots, 1) \
V(SecurityContext_UseCertificateChainBytes, 3) \
V(ServerSocket_Accept, 2) \
- V(ServerSocket_CreateBindListen, 6) \
+ V(ServerSocket_CreateBindListen, 7) \
V(SocketBase_IsBindError, 2) \
V(Socket_Available, 1) \
- V(Socket_CreateBindConnect, 4) \
+ V(Socket_CreateBindConnect, 5) \
V(Socket_CreateBindDatagram, 6) \
- V(Socket_CreateConnect, 3) \
+ V(Socket_CreateConnect, 4) \
V(Socket_GetPort, 1) \
V(Socket_GetRemotePeer, 1) \
V(Socket_GetError, 1) \
diff --git a/runtime/bin/loader.cc b/runtime/bin/loader.cc
index 772fbcc..f6a5bd6 100644
--- a/runtime/bin/loader.cc
+++ b/runtime/bin/loader.cc
@@ -619,7 +619,7 @@
return result;
}
if (tag == Dart_kImportExtensionTag) {
- if (strncmp(url_string, "dart-ext:", 9)) {
+ if (strncmp(url_string, "dart-ext:", 9) != 0) {
return DartUtils::NewError(
"Native extensions must use the dart-ext: scheme.");
}
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 54d9306..f23de40 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -275,7 +275,7 @@
}
} else {
result = DartUtils::ResolveScript(Dart_NewStringFromCString(script_uri));
- if (Dart_IsError(result)) return result;
+ if (Dart_IsError(result)) return result != nullptr;
if (isolate_group_data->kernel_buffer().get() != nullptr) {
// Various core-library parts will send requests to the Loader to resolve
@@ -284,7 +284,7 @@
// bypasses normal source code loading paths that initialize it.
const char* resolved_script_uri = NULL;
result = Dart_StringToCString(result, &resolved_script_uri);
- if (Dart_IsError(result)) return result;
+ if (Dart_IsError(result)) return result != nullptr;
Loader::InitForSnapshot(resolved_script_uri, isolate_data);
}
}
@@ -661,12 +661,12 @@
}
}
- if (flags->copy_parent_code && callback_data) {
- IsolateGroupData* parent_isolate_data =
- reinterpret_cast<IsolateGroupData*>(callback_data);
- parent_kernel_buffer = parent_isolate_data->kernel_buffer();
+ if (flags->copy_parent_code && callback_data != nullptr) {
+ auto parent_isolate_group_data =
+ reinterpret_cast<IsolateData*>(callback_data)->isolate_group_data();
+ parent_kernel_buffer = parent_isolate_group_data->kernel_buffer();
kernel_buffer = parent_kernel_buffer.get();
- kernel_buffer_size = parent_isolate_data->kernel_buffer_size();
+ kernel_buffer_size = parent_isolate_group_data->kernel_buffer_size();
}
if (kernel_buffer == NULL && !isolate_run_app_snapshot) {
@@ -1139,13 +1139,6 @@
&app_isolate_snapshot_instructions);
}
-#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
- // Constant true if PRODUCT or DART_PRECOMPILED_RUNTIME.
- if ((Options::gen_snapshot_kind() != kNone) || vm_run_app_snapshot) {
- vm_options.AddArgument("--load_deferred_eagerly");
- }
-#endif
-
if (Options::gen_snapshot_kind() == kAppJIT) {
vm_options.AddArgument("--fields_may_be_reset");
}
diff --git a/runtime/bin/main_options.cc b/runtime/bin/main_options.cc
index b356da5..ee4516e 100644
--- a/runtime/bin/main_options.cc
+++ b/runtime/bin/main_options.cc
@@ -340,7 +340,7 @@
return false;
}
int ver = 0;
- for (int i = 0; value[i]; ++i) {
+ for (int i = 0; value[i] != '\0'; ++i) {
if (value[i] >= '0' && value[i] <= '9') {
ver = (ver * 10) + value[i] - '0';
} else {
diff --git a/runtime/bin/run_vm_tests.cc b/runtime/bin/run_vm_tests.cc
index b4a5020..694577e 100644
--- a/runtime/bin/run_vm_tests.cc
+++ b/runtime/bin/run_vm_tests.cc
@@ -253,7 +253,7 @@
CHECK_RESULT(result);
// Setup kernel service as the main script for this isolate.
- if (kernel_service_buffer) {
+ if (kernel_service_buffer != nullptr) {
result = Dart_LoadScriptFromKernel(kernel_service_buffer,
kernel_service_buffer_size);
CHECK_RESULT(result);
diff --git a/runtime/bin/secure_socket_filter.cc b/runtime/bin/secure_socket_filter.cc
index c1d9f57..bcb9bee 100644
--- a/runtime/bin/secure_socket_filter.cc
+++ b/runtime/bin/secure_socket_filter.cc
@@ -677,7 +677,7 @@
bytes_processed =
BIO_write(socket_side_, buffers_[kReadEncrypted] + start, length);
if (bytes_processed <= 0) {
- bool retry = BIO_should_retry(socket_side_);
+ bool retry = BIO_should_retry(socket_side_) != 0;
if (!retry) {
if (SSL_LOG_DATA)
Syslog::Print("BIO_write failed in ReadEncryptedBuffer\n");
diff --git a/runtime/bin/secure_socket_utils.cc b/runtime/bin/secure_socket_utils.cc
index 362e891..259b06e 100644
--- a/runtime/bin/secure_socket_utils.cc
+++ b/runtime/bin/secure_socket_utils.cc
@@ -39,7 +39,7 @@
}
if ((path != NULL) && (line >= 0)) {
const char* file = strrchr(path, sep[0]);
- path = file ? file + 1 : path;
+ path = file != nullptr ? file + 1 : path;
text_buffer->Printf("(%s:%d)", path, line);
}
}
diff --git a/runtime/bin/security_context.cc b/runtime/bin/security_context.cc
index 3300b11..983e5e2 100644
--- a/runtime/bin/security_context.cc
+++ b/runtime/bin/security_context.cc
@@ -76,7 +76,7 @@
filter->callback_error = result;
return 0;
}
- return DartUtils::GetBooleanValue(result);
+ return static_cast<int>(DartUtils::GetBooleanValue(result));
}
SSLCertContext* SSLCertContext::GetSecurityContext(Dart_NativeArguments args) {
diff --git a/runtime/bin/socket.cc b/runtime/bin/socket.cc
index 0b590e6..33f6907 100644
--- a/runtime/bin/socket.cc
+++ b/runtime/bin/socket.cc
@@ -259,6 +259,12 @@
Dart_Handle port_arg = Dart_GetNativeArgument(args, 2);
int64_t port = DartUtils::GetInt64ValueCheckRange(port_arg, 0, 65535);
SocketAddress::SetAddrPort(&addr, static_cast<intptr_t>(port));
+ if (addr.addr.sa_family == AF_INET6) {
+ Dart_Handle scope_id_arg = Dart_GetNativeArgument(args, 3);
+ int64_t scope_id =
+ DartUtils::GetInt64ValueCheckRange(scope_id_arg, 0, 65535);
+ SocketAddress::SetAddrScope(&addr, scope_id);
+ }
intptr_t socket = Socket::CreateConnect(addr);
OSError error;
if (socket >= 0) {
@@ -278,6 +284,12 @@
SocketAddress::SetAddrPort(&addr, static_cast<intptr_t>(port));
RawAddr sourceAddr;
SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 3), &sourceAddr);
+ if (addr.addr.sa_family == AF_INET6) {
+ Dart_Handle scope_id_arg = Dart_GetNativeArgument(args, 4);
+ int64_t scope_id =
+ DartUtils::GetInt64ValueCheckRange(scope_id_arg, 0, 65535);
+ SocketAddress::SetAddrScope(&addr, scope_id);
+ }
intptr_t socket = Socket::CreateBindConnect(addr, sourceAddr);
OSError error;
if (socket >= 0) {
@@ -627,6 +639,12 @@
Dart_GetNativeArgument(args, 3), 0, 65535);
bool v6_only = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 4));
bool shared = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 5));
+ if (addr.addr.sa_family == AF_INET6) {
+ Dart_Handle scope_id_arg = Dart_GetNativeArgument(args, 6);
+ int64_t scope_id =
+ DartUtils::GetInt64ValueCheckRange(scope_id_arg, 0, 65535);
+ SocketAddress::SetAddrScope(&addr, scope_id);
+ }
Dart_Handle socket_object = Dart_GetNativeArgument(args, 0);
Dart_Handle result = ListeningSocketRegistry::Instance()->CreateBindListen(
@@ -664,7 +682,7 @@
array->SetAt(0, new CObjectInt32(CObject::NewInt32(0)));
for (intptr_t i = 0; i < addresses->count(); i++) {
SocketAddress* addr = addresses->GetAt(i);
- CObjectArray* entry = new CObjectArray(CObject::NewArray(3));
+ CObjectArray* entry = new CObjectArray(CObject::NewArray(4));
CObjectInt32* type =
new CObjectInt32(CObject::NewInt32(addr->GetType()));
@@ -678,6 +696,10 @@
CObjectUint8Array* data = SocketAddress::ToCObject(raw);
entry->SetAt(2, data);
+ CObjectInt64* scope_id = new CObjectInt64(
+ CObject::NewInt64(SocketAddress::GetAddrScope(raw)));
+ entry->SetAt(3, scope_id);
+
array->SetAt(i + 1, entry);
}
result = array;
diff --git a/runtime/bin/socket_base.cc b/runtime/bin/socket_base.cc
index 060c710..8789c43 100644
--- a/runtime/bin/socket_base.cc
+++ b/runtime/bin/socket_base.cc
@@ -49,7 +49,8 @@
return false;
}
return memcmp(&a.in6.sin6_addr, &b.in6.sin6_addr,
- sizeof(a.in6.sin6_addr)) == 0;
+ sizeof(a.in6.sin6_addr)) == 0 &&
+ a.in6.sin6_scope_id == b.in6.sin6_scope_id;
} else {
UNREACHABLE();
return false;
@@ -141,6 +142,18 @@
memmove(data->Buffer(), in_addr, in_addr_len);
return data;
}
+void SocketAddress::SetAddrScope(RawAddr* addr, intptr_t scope_id) {
+ if (addr->addr.sa_family != AF_INET6) return;
+ addr->in6.sin6_scope_id = scope_id;
+}
+
+intptr_t SocketAddress::GetAddrScope(const RawAddr& addr) {
+ if (addr.addr.sa_family == AF_INET6) {
+ return addr.in6.sin6_scope_id;
+ } else {
+ return 0;
+ }
+}
void FUNCTION_NAME(InternetAddress_Parse)(Dart_NativeArguments args) {
const char* address =
diff --git a/runtime/bin/socket_base.h b/runtime/bin/socket_base.h
index 8cab1aa..404357b 100644
--- a/runtime/bin/socket_base.h
+++ b/runtime/bin/socket_base.h
@@ -73,6 +73,8 @@
static intptr_t GetAddrPort(const RawAddr& addr);
static Dart_Handle ToTypedData(const RawAddr& addr);
static CObjectUint8Array* ToCObject(const RawAddr& addr);
+ static void SetAddrScope(RawAddr* addr, intptr_t scope_id);
+ static intptr_t GetAddrScope(const RawAddr& addr);
private:
char as_string_[INET6_ADDRSTRLEN];
diff --git a/runtime/bin/socket_base_linux.cc b/runtime/bin/socket_base_linux.cc
index 87aedbd..9a52d96 100644
--- a/runtime/bin/socket_base_linux.cc
+++ b/runtime/bin/socket_base_linux.cc
@@ -46,7 +46,7 @@
int len) {
socklen_t salen = SocketAddress::GetAddrLength(addr);
return (NO_RETRY_EXPECTED(getnameinfo(&addr.addr, salen, address, len, NULL,
- 0, NI_NUMERICHOST) == 0));
+ 0, NI_NUMERICHOST) == 0)) != 0;
}
bool SocketBase::IsBindError(intptr_t error_number) {
diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart
index d6149e6..c1336e3 100644
--- a/runtime/bin/socket_patch.dart
+++ b/runtime/bin/socket_patch.dart
@@ -137,6 +137,7 @@
final String address;
final String _host;
final Uint8List _in_addr;
+ final int _scope_id;
InternetAddressType get type => _in_addr.length == _IPv4AddrLength
? InternetAddressType.IPv4
@@ -185,7 +186,8 @@
Future<InternetAddress> reverse() => _NativeSocket.reverseLookup(this);
- _InternetAddress(this.address, this._host, this._in_addr);
+ _InternetAddress(this.address, this._host, this._in_addr,
+ [this._scope_id = 0]);
factory _InternetAddress.parse(String address) {
if (address is! String) {
@@ -387,7 +389,7 @@
} else {
return response.skip(1).map<InternetAddress>((result) {
var type = new InternetAddressType._from(result[0]);
- return new _InternetAddress(result[1], host, result[2]);
+ return new _InternetAddress(result[1], host, result[2], result[3]);
}).toList();
}
});
@@ -430,8 +432,40 @@
});
}
+ static String escapeLinkLocalAddress(String host) {
+ // if the host contains escape, host is an IPv6 address with scope ID.
+ // Remove '25' before feeding into native calls.
+ int index = host.indexOf('%');
+ if (index >= 0) {
+ if (!checkLinkLocalAddress(host)) {
+ // The only well defined usage is link-local address. Checks Section 4 of https://tools.ietf.org/html/rfc6874.
+ // If it is not a valid link-local address and contains escape character, throw an exception.
+ throw new FormatException(
+ '${host} is not a valid link-local address but contains %. Scope id should be used as part of link-local address.',
+ host,
+ index);
+ }
+ if (host.startsWith("25", index + 1)) {
+ // Remove '25' after '%' if present
+ host = host.replaceRange(index + 1, index + 3, '');
+ }
+ }
+ return host;
+ }
+
+ static bool checkLinkLocalAddress(String host) {
+ // The shortest possible link-local address is [fe80::1]
+ if (host.length < 7) return false;
+ var char = host[2];
+ return host.startsWith('fe') &&
+ (char == '8' || char == '9' || char == 'a' || char == 'b');
+ }
+
static Future<ConnectionTask<_NativeSocket>> startConnect(
host, int port, sourceAddress) {
+ if (host is String) {
+ host = escapeLinkLocalAddress(host);
+ }
_throwOnBadPort(port);
if (sourceAddress != null && sourceAddress is! _InternetAddress) {
if (sourceAddress is String) {
@@ -465,11 +499,12 @@
socket.localAddress = address;
var result;
if (sourceAddress == null) {
- result = socket.nativeCreateConnect(address._in_addr, port);
+ result = socket.nativeCreateConnect(
+ address._in_addr, port, address._scope_id);
} else {
assert(sourceAddress is _InternetAddress);
- result = socket.nativeCreateBindConnect(
- address._in_addr, port, sourceAddress._in_addr);
+ result = socket.nativeCreateBindConnect(address._in_addr, port,
+ sourceAddress._in_addr, address._scope_id);
}
if (result is OSError) {
// Keep first error, if present.
@@ -594,13 +629,15 @@
static Future<_NativeSocket> bind(
host, int port, int backlog, bool v6Only, bool shared) async {
_throwOnBadPort(port);
-
+ if (host is String) {
+ host = escapeLinkLocalAddress(host);
+ }
final address = await _resolveHost(host);
var socket = new _NativeSocket.listen();
socket.localAddress = address;
var result = socket.nativeCreateBindListen(
- address._in_addr, port, backlog, v6Only, shared);
+ address._in_addr, port, backlog, v6Only, shared, address._scope_id);
if (result is OSError) {
throw new SocketException("Failed to create server socket",
osError: result, address: address, port: port);
@@ -1183,12 +1220,13 @@
native "Socket_WriteList";
nativeSendTo(List<int> buffer, int offset, int bytes, Uint8List address,
int port) native "Socket_SendTo";
- nativeCreateConnect(Uint8List addr, int port) native "Socket_CreateConnect";
- nativeCreateBindConnect(Uint8List addr, int port, Uint8List sourceAddr)
- native "Socket_CreateBindConnect";
+ nativeCreateConnect(Uint8List addr, int port, int scope_id)
+ native "Socket_CreateConnect";
+ nativeCreateBindConnect(Uint8List addr, int port, Uint8List sourceAddr,
+ int scope_id) native "Socket_CreateBindConnect";
bool isBindError(int errorNumber) native "SocketBase_IsBindError";
nativeCreateBindListen(Uint8List addr, int port, int backlog, bool v6Only,
- bool shared) native "ServerSocket_CreateBindListen";
+ bool shared, int scope_id) native "ServerSocket_CreateBindListen";
nativeCreateBindDatagram(Uint8List addr, int port, bool reuseAddress,
bool reusePort, int ttl) native "Socket_CreateBindDatagram";
nativeAccept(_NativeSocket socket) native "ServerSocket_Accept";
diff --git a/runtime/bin/stdio_linux.cc b/runtime/bin/stdio_linux.cc
index 18e19e8..2ed9a90 100644
--- a/runtime/bin/stdio_linux.cc
+++ b/runtime/bin/stdio_linux.cc
@@ -86,7 +86,7 @@
}
bool Stdin::AnsiSupported(intptr_t fd, bool* supported) {
- *supported = isatty(fd) && TermHasXTerm();
+ *supported = (isatty(fd) != 0) && TermHasXTerm();
return true;
}
@@ -102,7 +102,7 @@
}
bool Stdout::AnsiSupported(intptr_t fd, bool* supported) {
- *supported = isatty(fd) && TermHasXTerm();
+ *supported = (isatty(fd) != 0) && TermHasXTerm();
return true;
}
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 7e60a43..3d060be 100644
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -3456,7 +3456,6 @@
* current VM. The instructions piece must be loaded with read and execute
* permissions; the data piece may be loaded as read-only.
*
- * - Requires the VM to have been started with --load-deferred-eagerly.
* - Requires the VM to have not been started with --precompilation.
* - Not supported when targeting IA32 or DBC.
* - The VM writing the snapshot and the VM reading the snapshot must be the
diff --git a/runtime/lib/developer.cc b/runtime/lib/developer.cc
index f1eab3a..bac0ef1 100644
--- a/runtime/lib/developer.cc
+++ b/runtime/lib/developer.cc
@@ -24,7 +24,7 @@
#if !defined(PRODUCT)
GET_NATIVE_ARGUMENT(String, msg, arguments->NativeArgAt(1));
Debugger* debugger = isolate->debugger();
- if (!debugger) {
+ if (debugger == nullptr) {
return when.raw();
}
if (when.value()) {
diff --git a/runtime/lib/ffi.cc b/runtime/lib/ffi.cc
index 347cd05..f103f2e 100644
--- a/runtime/lib/ffi.cc
+++ b/runtime/lib/ffi.cc
@@ -429,88 +429,6 @@
return Integer::New(SizeOf(type_arg));
}
-#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_PRECOMPILER) && \
- !defined(TARGET_ARCH_DBC)
-// Generates assembly to trampoline from native code into Dart.
-static uword CompileNativeCallback(const Function& c_signature,
- const Function& dart_target,
- const Instance& exceptional_return) {
- Thread* const thread = Thread::Current();
-
- uword entry_point = 0;
- const int32_t callback_id = thread->AllocateFfiCallbackId(&entry_point);
- ASSERT(NativeCallbackTrampolines::Enabled() == (entry_point != 0));
-
- // Create a new Function named 'FfiCallback' and stick it in the 'dart:ffi'
- // library. Note that these functions will never be invoked by Dart, so it
- // doesn't matter that they all have the same name.
- Zone* const Z = thread->zone();
- const String& name = String::Handle(Symbols::New(thread, "FfiCallback"));
- const Library& lib = Library::Handle(Z, Library::FfiLibrary());
- const Class& owner_class = Class::Handle(Z, lib.toplevel_class());
- const Function& function =
- Function::Handle(Z, Function::New(name, RawFunction::kFfiTrampoline,
- /*is_static=*/true,
- /*is_const=*/false,
- /*is_abstract=*/false,
- /*is_external=*/false,
- /*is_native=*/false, owner_class,
- TokenPosition::kMinSource));
- function.set_is_debuggable(false);
-
- // Set callback-specific fields which the flow-graph builder needs to generate
- // the body.
- function.SetFfiCSignature(c_signature);
- function.SetFfiCallbackId(callback_id);
- function.SetFfiCallbackTarget(dart_target);
-
- // We require that the exceptional return value for functions returning 'Void'
- // must be 'null', since native code should not look at the result.
- if (compiler::ffi::NativeTypeIsVoid(
- AbstractType::Handle(c_signature.result_type())) &&
- !exceptional_return.IsNull()) {
- Exceptions::ThrowUnsupportedError(
- "Only 'null' may be used as the exceptional return value for a "
- "callback returning void.");
- }
-
- // We need to load the exceptional return value as a constant in the generated
- // function. This means we need to ensure that it's in old space and has no
- // (transitively) mutable fields. This is done by checking (asserting) that
- // it's a built-in FFI class, whose fields are all immutable, or a
- // user-defined Pointer class, which has no fields.
- //
- // TODO(36730): We'll need to extend this when we support passing/returning
- // structs by value.
- ASSERT(exceptional_return.IsNull() || exceptional_return.IsNumber() ||
- exceptional_return.IsPointer());
- if (!exceptional_return.IsSmi() && exceptional_return.IsNew()) {
- function.SetFfiCallbackExceptionalReturn(
- Instance::Handle(exceptional_return.CopyShallowToOldSpace(thread)));
- } else {
- function.SetFfiCallbackExceptionalReturn(exceptional_return);
- }
-
- // We compile the callback immediately because we need to return a pointer to
- // the entry-point. Native calls do not use patching like Dart calls, so we
- // cannot compile it lazily.
- const Object& result =
- Object::Handle(Z, Compiler::CompileOptimizedFunction(thread, function));
- if (result.IsError()) {
- Exceptions::PropagateError(Error::Cast(result));
- }
- ASSERT(result.IsCode());
- const Code& code = Code::Cast(result);
-
- thread->SetFfiCallbackCode(callback_id, code);
-
- if (entry_point != 0) {
- return entry_point;
- } else {
- return code.EntryPoint();
- }
-}
-#endif
// Static invocations to this method are translated directly in streaming FGB
// and bytecode FGB. However, we can still reach this entrypoint in the bytecode
@@ -545,80 +463,6 @@
#endif
}
-DEFINE_NATIVE_ENTRY(Ffi_fromFunction, 1, 2) {
-#if defined(DART_PRECOMPILED_RUNTIME) || defined(DART_PRECOMPILER) || \
- defined(TARGET_ARCH_DBC)
- // https://github.com/dart-lang/sdk/issues/37295
- // FFI is supported, but callbacks are not.
- Exceptions::ThrowUnsupportedError(
- "FFI callbacks are not yet supported in AOT or on DBC.");
-#else
- GET_NATIVE_TYPE_ARGUMENT(type_arg, arguments->NativeTypeArgAt(0));
- GET_NON_NULL_NATIVE_ARGUMENT(Closure, closure, arguments->NativeArgAt(0));
- GET_NON_NULL_NATIVE_ARGUMENT(Instance, exceptional_return,
- arguments->NativeArgAt(1));
-
- if (!type_arg.IsInstantiated() || !type_arg.IsFunctionType()) {
- // TODO(35902): Remove this when dynamic invocations of fromFunction are
- // prohibited.
- Exceptions::ThrowUnsupportedError(
- "Type argument to fromFunction must an instantiated function type.");
- }
-
- const Function& native_signature =
- Function::Handle(Type::Cast(type_arg).signature());
- Function& func = Function::Handle(closure.function());
- TypeArguments& type_args = TypeArguments::Handle(zone);
- type_args = TypeArguments::New(1);
- type_args.SetTypeAt(Pointer::kNativeTypeArgPos, type_arg);
- type_args = type_args.Canonicalize();
-
- Class& native_function_class =
- Class::Handle(isolate->class_table()->At(kFfiNativeFunctionCid));
- const auto& error =
- Error::Handle(native_function_class.EnsureIsFinalized(Thread::Current()));
- if (!error.IsNull()) {
- Exceptions::PropagateError(error);
- }
-
- Type& native_function_type = Type::Handle(
- Type::New(native_function_class, type_args, TokenPosition::kNoSource));
- native_function_type ^=
- ClassFinalizer::FinalizeType(Class::Handle(), native_function_type);
- native_function_type ^= native_function_type.Canonicalize();
-
- // The FE verifies that the target of a 'fromFunction' is a static method, so
- // the value we see here must be a static tearoff. See ffi_use_sites.dart for
- // details.
- //
- // TODO(36748): Define hot-reload semantics of native callbacks. We may need
- // to look up the target by name.
- ASSERT(func.IsImplicitClosureFunction());
- func = func.parent_function();
- ASSERT(func.is_static());
-
- const AbstractType& return_type =
- AbstractType::Handle(native_signature.result_type());
- if (compiler::ffi::NativeTypeIsVoid(return_type)) {
- if (!exceptional_return.IsNull()) {
- const String& error = String::Handle(
- String::NewFormatted("Exceptional return argument to 'fromFunction' "
- "must be null for functions returning void."));
- Exceptions::ThrowArgumentError(error);
- }
- } else if (!compiler::ffi::NativeTypeIsPointer(return_type) &&
- exceptional_return.IsNull()) {
- const String& error = String::Handle(String::NewFormatted(
- "Exceptional return argument to 'fromFunction' must not be null."));
- Exceptions::ThrowArgumentError(error);
- }
-
- return Pointer::New(
- native_function_type,
- CompileNativeCallback(native_signature, func, exceptional_return));
-#endif
-}
-
DEFINE_NATIVE_ENTRY(Ffi_asExternalTypedData, 0, 2) {
GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(Integer, count, arguments->NativeArgAt(1));
@@ -692,8 +536,8 @@
const auto& typed_data_class =
Class::Handle(zone, isolate->class_table()->At(cid));
- const auto& error = Error::Handle(
- zone, typed_data_class.EnsureIsFinalized(Thread::Current()));
+ const auto& error =
+ Error::Handle(zone, typed_data_class.EnsureIsFinalized(thread));
if (!error.IsNull()) {
Exceptions::PropagateError(error);
}
@@ -703,6 +547,91 @@
Heap::kNew);
}
+DEFINE_NATIVE_ENTRY(Ffi_nativeCallbackFunction, 1, 2) {
+#if defined(TARGET_ARCH_DBC)
+ Exceptions::ThrowUnsupportedError(
+ "FFI callbacks are not yet supported on DBC.");
+#elif defined(DART_PRECOMPILED_RUNTIME) || defined(DART_PRECOMPILER)
+ // Calls to this function are removed by the flow-graph builder in AOT.
+ // See StreamingFlowGraphBuilder::BuildFfiNativeCallbackFunction().
+ UNREACHABLE();
+#else
+ GET_NATIVE_TYPE_ARGUMENT(type_arg, arguments->NativeTypeArgAt(0));
+ GET_NON_NULL_NATIVE_ARGUMENT(Closure, closure, arguments->NativeArgAt(0));
+ GET_NON_NULL_NATIVE_ARGUMENT(Instance, exceptional_return,
+ arguments->NativeArgAt(1));
+
+ ASSERT(type_arg.IsInstantiated() && type_arg.IsFunctionType());
+ const Function& native_signature =
+ Function::Handle(zone, Type::Cast(type_arg).signature());
+ Function& func = Function::Handle(zone, closure.function());
+
+ // The FE verifies that the target of a 'fromFunction' is a static method, so
+ // the value we see here must be a static tearoff. See ffi_use_sites.dart for
+ // details.
+ //
+ // TODO(36748): Define hot-reload semantics of native callbacks. We may need
+ // to look up the target by name.
+ ASSERT(func.IsImplicitClosureFunction());
+ func = func.parent_function();
+ ASSERT(func.is_static());
+
+ // We are returning an object which is not an Instance here. This is only OK
+ // because we know that the result will be passed directly to
+ // _pointerFromFunction and will not leak out into user code.
+ arguments->SetReturn(
+ Function::Handle(zone, compiler::ffi::NativeCallbackFunction(
+ native_signature, func, exceptional_return)));
+
+ // Because we have already set the return value.
+ return Object::sentinel().raw();
+#endif
+}
+
+DEFINE_NATIVE_ENTRY(Ffi_pointerFromFunction, 1, 1) {
+ GET_NATIVE_TYPE_ARGUMENT(type_arg, arguments->NativeTypeArgAt(0));
+ const Function& function =
+ Function::CheckedHandle(zone, arguments->NativeArg0());
+
+ Code& code = Code::Handle(zone);
+
+#if defined(DART_PRECOMPILED_RUNTIME)
+ code = function.CurrentCode();
+
+ // Blobs snapshots don't support BSS-relative relocations required by native
+ // callbacks (yet). Issue an error if the code has an unpatched relocation.
+ if (!code.VerifyBSSRelocations()) {
+ Exceptions::ThrowUnsupportedError(
+ "FFI callbacks are not yet supported in blobs snapshots. Please use "
+ "ELF or Assembly snapshots instead.");
+ }
+#else
+ // We compile the callback immediately because we need to return a pointer to
+ // the entry-point. Native calls do not use patching like Dart calls, so we
+ // cannot compile it lazily.
+ const Object& result = Object::Handle(
+ zone, Compiler::CompileOptimizedFunction(thread, function));
+ if (result.IsError()) {
+ Exceptions::PropagateError(Error::Cast(result));
+ }
+ ASSERT(result.IsCode());
+ code ^= result.raw();
+#endif
+
+ ASSERT(!code.IsNull());
+ thread->SetFfiCallbackCode(function.FfiCallbackId(), code);
+
+ uword entry_point = code.EntryPoint();
+#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(TARGET_ARCH_DBC)
+ if (NativeCallbackTrampolines::Enabled()) {
+ entry_point = isolate->native_callback_trampolines()->TrampolineForId(
+ function.FfiCallbackId());
+ }
+#endif
+
+ return Pointer::New(type_arg, entry_point);
+}
+
#if defined(TARGET_ARCH_DBC)
void FfiMarshalledArguments::SetFunctionAddress(uint64_t value) const {
diff --git a/runtime/lib/ffi_native_type_patch.dart b/runtime/lib/ffi_native_type_patch.dart
index edc43950..cd229de2 100644
--- a/runtime/lib/ffi_native_type_patch.dart
+++ b/runtime/lib/ffi_native_type_patch.dart
@@ -68,8 +68,8 @@
@patch
@pragma("vm:entry-point")
-class Void extends NativeType {}
+abstract class Void extends NativeType {}
@patch
@pragma("vm:entry-point")
-class NativeFunction<T extends Function> extends NativeType {}
+abstract class NativeFunction<T extends Function> extends NativeType {}
diff --git a/runtime/lib/ffi_patch.dart b/runtime/lib/ffi_patch.dart
index c16cd72..089f0c9 100644
--- a/runtime/lib/ffi_patch.dart
+++ b/runtime/lib/ffi_patch.dart
@@ -23,6 +23,25 @@
dynamic _asExternalTypedData(Pointer ptr, int count)
native "Ffi_asExternalTypedData";
+// Returns a Function object for a native callback.
+//
+// Calls to [Pointer.fromFunction] are re-written by the FE into calls to this
+// method + _pointerFromFunction. All three arguments must be constants.
+//
+// In AOT we evaluate calls to this function during precompilation and replace
+// them with Constant instruction referencing the callback trampoline, to ensure
+// that it will be precompiled.
+//
+// In all JIT modes we call a native runtime entry. We *cannot* use the IL
+// implementation, since that would pull the callback trampoline into JIT
+// snapshots. The callback trampolines can only be serialized into AOT snapshots
+// because they embed the addresses of runtime routines in JIT mode.
+Object _nativeCallbackFunction<NS extends Function>(Function target,
+ Object exceptionalReturn) native "Ffi_nativeCallbackFunction";
+
+Pointer<NS> _pointerFromFunction<NS extends NativeFunction>(Object function)
+ native "Ffi_pointerFromFunction";
+
@patch
@pragma("vm:entry-point")
class Pointer<T extends NativeType> {
@@ -32,10 +51,18 @@
@patch
factory Pointer.fromAddress(int ptr) => _fromAddress(ptr);
+ // All static calls to this method are replaced by the FE into
+ // _nativeCallbackFunction + _pointerFromFunction.
+ //
+ // We still need to throw an error on a dynamic invocations, invocations
+ // through tearoffs or reflective calls.
@patch
static Pointer<NativeFunction<T>> fromFunction<T extends Function>(
@DartRepresentationOf("T") Function f,
- Object exceptionalReturn) native "Ffi_fromFunction";
+ [Object exceptionalReturn]) {
+ throw UnsupportedError(
+ "Pointer.fromFunction cannot be called dynamically.");
+ }
// TODO(sjindel): When NNBD is available, we should change `value` to be
// non-null.
diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc
index f8a102c..058f2ec 100644
--- a/runtime/lib/isolate.cc
+++ b/runtime/lib/isolate.cc
@@ -128,7 +128,7 @@
}
~SpawnIsolateTask() override {
- if (parent_isolate_) {
+ if (parent_isolate_ != nullptr) {
parent_isolate_->DecrementSpawnCount();
}
}
diff --git a/runtime/lib/lib_prefix.dart b/runtime/lib/lib_prefix.dart
index fe12660..f588ee3 100644
--- a/runtime/lib/lib_prefix.dart
+++ b/runtime/lib/lib_prefix.dart
@@ -11,74 +11,7 @@
throw "Unreachable";
}
- bool _load() native "LibraryPrefix_load";
- Object _loadError() native "LibraryPrefix_loadError";
- bool isLoaded() native "LibraryPrefix_isLoaded";
- bool _invalidateDependentCode()
- native "LibraryPrefix_invalidateDependentCode";
+ bool isLoaded() => true;
- loadLibrary() {
- for (int i = 0; i < _outstandingLoadRequests.length; i++) {
- if (_outstandingLoadRequests[i][0] == this) {
- return _outstandingLoadRequests[i][1].future;
- }
- }
-
- var completer = new Completer<bool>();
- var pair = new List();
- pair.add(this);
- pair.add(completer);
- _outstandingLoadRequests.add(pair);
- Timer.run(() {
- var hasCompleted = this._load();
- // Loading can complete immediately, for example when the same
- // library has been loaded eagerly or through another deferred
- // prefix. If that is the case, we must invalidate the dependent
- // code and complete the future now since there will be no callback
- // from the VM.
- if (hasCompleted && !completer.isCompleted) {
- _invalidateDependentCode();
- completer.complete(true);
- _outstandingLoadRequests.remove(pair);
- }
- });
- return completer.future;
- }
-}
-
-// A list of two element lists. The first element is the _LibraryPrefix. The
-// second element is the Completer for the load request.
-var _outstandingLoadRequests = new List<List>();
-
-// Called from the VM when an outstanding load request has finished.
-@pragma("vm:entry-point", "call")
-_completeDeferredLoads() {
- // Determine which outstanding load requests have completed and complete
- // their completer (with an error or true). For outstanding load requests
- // which have not completed, remember them for next time in
- // stillOutstandingLoadRequests.
- var stillOutstandingLoadRequests = new List<List>();
-
- // Make a copy of the outstandingRequests because the call to _load below
- // may recursively trigger another call to |_completeDeferredLoads|, which
- // can cause |_outstandingLoadRequests| to be modified.
- var outstandingRequests = _outstandingLoadRequests.toList();
- for (int i = 0; i < outstandingRequests.length; i++) {
- var prefix = outstandingRequests[i][0];
- var completer = outstandingRequests[i][1];
- var error = prefix._loadError();
- if (completer.isCompleted) {
- // Already completed. Skip.
- continue;
- }
- if (error != null) {
- completer.completeError(error);
- } else if (prefix._load()) {
- prefix._invalidateDependentCode();
- completer.complete(true);
- } else {
- stillOutstandingLoadRequests.add(outstandingRequests[i]);
- }
- }
- _outstandingLoadRequests = stillOutstandingLoadRequests;
+ loadLibrary() => new Future.value(true);
}
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 3d291af..a76d721 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -253,20 +253,27 @@
args.SetAt(4, Bool::Get(func.is_static()));
intptr_t kind_flags = 0;
- kind_flags |= (func.is_abstract() << Mirrors::kAbstract);
- kind_flags |= (func.IsGetterFunction() << Mirrors::kGetter);
- kind_flags |= (func.IsSetterFunction() << Mirrors::kSetter);
+ kind_flags |=
+ (static_cast<intptr_t>(func.is_abstract()) << Mirrors::kAbstract);
+ kind_flags |=
+ (static_cast<intptr_t>(func.IsGetterFunction()) << Mirrors::kGetter);
+ kind_flags |=
+ (static_cast<intptr_t>(func.IsSetterFunction()) << Mirrors::kSetter);
bool is_ctor = (func.kind() == RawFunction::kConstructor);
- kind_flags |= (is_ctor << Mirrors::kConstructor);
- kind_flags |= ((is_ctor && func.is_const()) << Mirrors::kConstCtor);
+ kind_flags |= (static_cast<intptr_t>(is_ctor) << Mirrors::kConstructor);
+ kind_flags |= (static_cast<intptr_t>(is_ctor && func.is_const())
+ << Mirrors::kConstCtor);
kind_flags |=
- ((is_ctor && func.IsGenerativeConstructor()) << Mirrors::kGenerativeCtor);
+ (static_cast<intptr_t>(is_ctor && func.IsGenerativeConstructor())
+ << Mirrors::kGenerativeCtor);
+ kind_flags |= (static_cast<intptr_t>(is_ctor && func.is_redirecting())
+ << Mirrors::kRedirectingCtor);
+ kind_flags |= (static_cast<intptr_t>(is_ctor && func.IsFactory())
+ << Mirrors::kFactoryCtor);
kind_flags |=
- ((is_ctor && func.is_redirecting()) << Mirrors::kRedirectingCtor);
- kind_flags |= ((is_ctor && func.IsFactory()) << Mirrors::kFactoryCtor);
- kind_flags |= (func.is_external() << Mirrors::kExternal);
+ (static_cast<intptr_t>(func.is_external()) << Mirrors::kExternal);
bool is_synthetic = func.is_no_such_method_forwarder();
- kind_flags |= (is_synthetic << Mirrors::kSynthetic);
+ kind_flags |= (static_cast<intptr_t>(is_synthetic) << Mirrors::kSynthetic);
args.SetAt(5, Smi::Handle(Smi::New(kind_flags)));
return CreateMirror(Symbols::_LocalMethodMirror(), args);
@@ -366,11 +373,14 @@
static RawInstance* CreateLibraryDependencyMirror(Thread* thread,
const Instance& importer,
- const Namespace& ns,
+ const Library& importee,
+ const Array& show_names,
+ const Array& hide_names,
+ const Object& metadata,
const LibraryPrefix& prefix,
+ const String& prefix_name,
const bool is_import,
const bool is_deferred) {
- const Library& importee = Library::Handle(ns.library());
const Instance& importee_mirror =
Instance::Handle(CreateLibraryMirror(thread, importee));
if (importee_mirror.IsNull()) {
@@ -378,8 +388,6 @@
return Instance::null();
}
- const Array& show_names = Array::Handle(ns.show_names());
- const Array& hide_names = Array::Handle(ns.hide_names());
intptr_t n = show_names.IsNull() ? 0 : show_names.Length();
intptr_t m = hide_names.IsNull() ? 0 : hide_names.Length();
const Array& combinators = Array::Handle(Array::New(n + m));
@@ -396,12 +404,6 @@
combinators.SetAt(i++, t);
}
- Object& metadata = Object::Handle(ns.GetMetadata());
- if (metadata.IsError()) {
- Exceptions::PropagateError(Error::Cast(metadata));
- UNREACHABLE();
- }
-
const Array& args = Array::Handle(Array::New(7));
args.SetAt(0, importer);
if (importee.Loaded() || prefix.IsNull()) {
@@ -413,14 +415,109 @@
args.SetAt(1, prefix);
}
args.SetAt(2, combinators);
- args.SetAt(3, prefix.IsNull() ? Object::null_object()
- : String::Handle(prefix.name()));
+ args.SetAt(3, prefix_name);
args.SetAt(4, Bool::Get(is_import));
args.SetAt(5, Bool::Get(is_deferred));
args.SetAt(6, metadata);
return CreateMirror(Symbols::_LocalLibraryDependencyMirror(), args);
}
+static RawInstance* CreateLibraryDependencyMirror(Thread* thread,
+ const Instance& importer,
+ const Namespace& ns,
+ const LibraryPrefix& prefix,
+ const bool is_import,
+ const bool is_deferred) {
+ const Library& importee = Library::Handle(ns.library());
+ const Array& show_names = Array::Handle(ns.show_names());
+ const Array& hide_names = Array::Handle(ns.hide_names());
+
+ Object& metadata = Object::Handle(ns.GetMetadata());
+ if (metadata.IsError()) {
+ Exceptions::PropagateError(Error::Cast(metadata));
+ UNREACHABLE();
+ }
+
+ auto& prefix_name = String::Handle();
+ if (!prefix.IsNull()) {
+ prefix_name = prefix.name();
+ }
+
+ return CreateLibraryDependencyMirror(thread, importer, importee, show_names,
+ hide_names, metadata, prefix,
+ prefix_name, is_import, is_deferred);
+}
+
+static RawGrowableObjectArray* CreateBytecodeLibraryDependencies(
+ Thread* thread,
+ const Library& lib,
+ const Instance& lib_mirror) {
+ ASSERT(lib.is_declared_in_bytecode());
+
+ // Make sure top level class (containing annotations) is fully loaded.
+ lib.EnsureTopLevelClassIsFinalized();
+
+ const auto& deps = GrowableObjectArray::Handle(GrowableObjectArray::New());
+ Array& metadata = Array::Handle(lib.GetExtendedMetadata(lib, 1));
+ if (metadata.Length() == 0) {
+ return deps.raw();
+ }
+
+ // Library has the only element in the extended metadata.
+ metadata ^= metadata.At(0);
+ if (metadata.IsNull()) {
+ return deps.raw();
+ }
+
+ auto& desc = Array::Handle();
+ auto& target_uri = String::Handle();
+ auto& importee = Library::Handle();
+ auto& is_export = Bool::Handle();
+ auto& is_deferred = Bool::Handle();
+ auto& prefix_name = String::Handle();
+ auto& show_names = Array::Handle();
+ auto& hide_names = Array::Handle();
+ auto& dep_metadata = Instance::Handle();
+ auto& dep = Instance::Handle();
+ const auto& no_prefix = LibraryPrefix::Handle();
+
+ for (intptr_t i = 0, n = metadata.Length(); i < n; ++i) {
+ desc ^= metadata.At(i);
+ // Each dependency is represented as an array with the following layout:
+ // [0] = target library URI (String)
+ // [1] = is_export (bool)
+ // [2] = is_deferred (bool)
+ // [3] = prefix (String or null)
+ // [4] = list of show names (List<String>)
+ // [5] = list of hide names (List<String>)
+ // [6] = annotations
+ // The library dependencies are encoded by getLibraryAnnotations(),
+ // pkg/vm/lib/bytecode/gen_bytecode.dart.
+ target_uri ^= desc.At(0);
+ is_export ^= desc.At(1);
+ is_deferred ^= desc.At(2);
+ prefix_name ^= desc.At(3);
+ show_names ^= desc.At(4);
+ hide_names ^= desc.At(5);
+ dep_metadata ^= desc.At(6);
+
+ importee = Library::LookupLibrary(thread, target_uri);
+ if (importee.IsNull()) {
+ continue;
+ }
+ ASSERT(importee.Loaded());
+
+ dep = CreateLibraryDependencyMirror(
+ thread, lib_mirror, importee, show_names, hide_names, dep_metadata,
+ no_prefix, prefix_name, !is_export.value(), is_deferred.value());
+ if (!dep.IsNull()) {
+ deps.Add(dep);
+ }
+ }
+
+ return deps.raw();
+}
+
DEFINE_NATIVE_ENTRY(LibraryMirror_fromPrefix, 0, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(LibraryPrefix, prefix,
arguments->NativeArgAt(0));
@@ -436,6 +533,10 @@
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1));
const Library& lib = Library::Handle(ref.GetLibraryReferent());
+ if (lib.is_declared_in_bytecode()) {
+ return CreateBytecodeLibraryDependencies(thread, lib, lib_mirror);
+ }
+
Array& ports = Array::Handle();
Namespace& ns = Namespace::Handle();
Instance& dep = Instance::Handle();
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index 2c5f526..7d40155 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -184,37 +184,6 @@
return Smi::New(hash_val);
}
-DEFINE_NATIVE_ENTRY(LibraryPrefix_invalidateDependentCode, 0, 1) {
- const LibraryPrefix& prefix =
- LibraryPrefix::CheckedHandle(zone, arguments->NativeArgAt(0));
- prefix.InvalidateDependentCode();
- return Bool::Get(true).raw();
-}
-
-DEFINE_NATIVE_ENTRY(LibraryPrefix_load, 0, 1) {
- const LibraryPrefix& prefix =
- LibraryPrefix::CheckedHandle(zone, arguments->NativeArgAt(0));
- bool hasCompleted = prefix.LoadLibrary();
- return Bool::Get(hasCompleted).raw();
-}
-
-DEFINE_NATIVE_ENTRY(LibraryPrefix_loadError, 0, 1) {
- const LibraryPrefix& prefix =
- LibraryPrefix::CheckedHandle(zone, arguments->NativeArgAt(0));
- // Currently all errors are Dart instances, e.g. I/O errors
- // created by deferred loading code. LanguageErrors from
- // failed loading or finalization attempts are propagated and result
- // in the isolate's death.
- const Instance& error = Instance::Handle(zone, prefix.LoadError());
- return error.raw();
-}
-
-DEFINE_NATIVE_ENTRY(LibraryPrefix_isLoaded, 0, 1) {
- const LibraryPrefix& prefix =
- LibraryPrefix::CheckedHandle(zone, arguments->NativeArgAt(0));
- return Bool::Get(prefix.is_loaded()).raw();
-}
-
DEFINE_NATIVE_ENTRY(Internal_inquireIs64Bit, 0, 0) {
#if defined(ARCH_IS_64_BIT)
return Bool::True().raw();
diff --git a/runtime/lib/wasm.cc b/runtime/lib/wasm.cc
new file mode 100644
index 0000000..7d0c06f
--- /dev/null
+++ b/runtime/lib/wasm.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2019, 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.
+
+#include "platform/unicode.h"
+#include "vm/bootstrap_natives.h"
+#include "vm/dart_entry.h"
+
+namespace dart {
+
+int callWasm(const char* name, int n) {
+ return 100 * n;
+}
+
+// This is a temporary API for prototyping.
+DEFINE_NATIVE_ENTRY(Wasm_callFunction, 0, 2) {
+ GET_NON_NULL_NATIVE_ARGUMENT(String, fn_name, arguments->NativeArgAt(0));
+ GET_NON_NULL_NATIVE_ARGUMENT(Integer, arg, arguments->NativeArgAt(1));
+
+ intptr_t len = Utf8::Length(fn_name);
+ std::unique_ptr<char> name = std::unique_ptr<char>(new char[len + 1]);
+ fn_name.ToUTF8(reinterpret_cast<uint8_t*>(name.get()), len);
+ name.get()[len] = 0;
+
+ return Smi::New(callWasm(name.get(), arg.AsInt64Value()));
+}
+
+} // namespace dart
diff --git a/runtime/lib/wasm_patch.dart b/runtime/lib/wasm_patch.dart
new file mode 100644
index 0000000..2af1b20
--- /dev/null
+++ b/runtime/lib/wasm_patch.dart
@@ -0,0 +1,8 @@
+// Copyright (c) 2019, 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:_internal" show patch;
+
+@patch
+int _callWasm(String name, int arg) native "Wasm_callFunction";
diff --git a/runtime/lib/wasm_sources.gni b/runtime/lib/wasm_sources.gni
new file mode 100644
index 0000000..6067612
--- /dev/null
+++ b/runtime/lib/wasm_sources.gni
@@ -0,0 +1,7 @@
+# Copyright (c) 2019, 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.
+
+wasm_runtime_cc_files = [ "wasm.cc" ]
+
+wasm_runtime_dart_files = [ "wasm_patch.dart" ]
diff --git a/runtime/observatory/BUILD.gn b/runtime/observatory/BUILD.gn
index 1399468..22fb0fb 100644
--- a/runtime/observatory/BUILD.gn
+++ b/runtime/observatory/BUILD.gn
@@ -40,7 +40,9 @@
rebase_path(output),
"--packages=" + rebase_path(".packages"),
]
- if (!is_debug) {
+ if (is_debug) {
+ args += [ "--enable-asserts" ]
+ } else {
args += [ "--minify" ]
}
}
diff --git a/runtime/observatory/lib/object_graph.dart b/runtime/observatory/lib/object_graph.dart
index f4bd617..a2fa1dd 100644
--- a/runtime/observatory/lib/object_graph.dart
+++ b/runtime/observatory/lib/object_graph.dart
@@ -12,19 +12,12 @@
import 'package:logging/logging.dart';
class _ReadStream {
- final List<ByteData> _chunks;
- int _chunkIndex = 0;
- int _byteIndex = 0;
+ final Uint8List _buffer;
+ int _position = 0;
- _ReadStream(this._chunks);
+ _ReadStream(this._buffer);
- int readByte() {
- while (_byteIndex >= _chunks[_chunkIndex].lengthInBytes) {
- _chunkIndex++;
- _byteIndex = 0;
- }
- return _chunks[_chunkIndex].getUint8(_byteIndex++);
- }
+ int readByte() => _buffer[_position++];
/// Read one ULEB128 number.
int readUnsigned() {
@@ -342,15 +335,48 @@
}
}
+class _InstancesIterable extends IterableBase<SnapshotObject> {
+ final _SnapshotGraph _graph;
+ final int _cid;
+
+ _InstancesIterable(this._graph, this._cid);
+
+ Iterator<SnapshotObject> get iterator => new _InstancesIterator(_graph, _cid);
+}
+
+class _InstancesIterator implements Iterator<SnapshotObject> {
+ final _SnapshotGraph _graph;
+ final int _cid;
+
+ int _nextId = 0;
+ SnapshotObject current;
+
+ _InstancesIterator(this._graph, this._cid);
+
+ bool moveNext() {
+ while (_nextId < _graph._N) {
+ if (_graph._cids[_nextId] == _cid) {
+ current = new _SnapshotObject._(_nextId++, _graph, "");
+ return true;
+ }
+ _nextId++;
+ }
+ return false;
+ }
+}
+
abstract class SnapshotClass {
String get name;
int get externalSize;
int get shallowSize;
int get ownedSize;
int get instanceCount;
+ Iterable<SnapshotObject> get instances;
}
class _SnapshotClass implements SnapshotClass {
+ final _SnapshotGraph _graph;
+ final int _cid;
final String name;
final String libName;
final String libUri;
@@ -370,7 +396,10 @@
int get externalSize => liveExternalSize;
int get instanceCount => liveInstanceCount;
- _SnapshotClass(this.name, this.libName, this.libUri);
+ Iterable<SnapshotObject> get instances =>
+ new _InstancesIterable(_graph, _cid);
+
+ _SnapshotClass(this._graph, this._cid, this.name, this.libName, this.libUri);
}
abstract class SnapshotGraph {
@@ -384,7 +413,7 @@
Iterable<SnapshotClass> get classes;
Iterable<SnapshotObject> get objects;
- factory SnapshotGraph(List<ByteData> chunks) => new _SnapshotGraph(chunks);
+ factory SnapshotGraph(Uint8List encoded) => new _SnapshotGraph(encoded);
Stream<String> process();
}
@@ -403,7 +432,7 @@
const kUnknownFieldName = "<unknown>";
class _SnapshotGraph implements SnapshotGraph {
- _SnapshotGraph(List<ByteData> chunks) : this._chunks = chunks;
+ _SnapshotGraph(Uint8List encoded) : this._encoded = encoded;
int get size => _liveShallowSize + _liveExternalSize;
int get shallowSize => _liveShallowSize;
@@ -466,8 +495,8 @@
(() async {
// We build futures here instead of marking the steps as async to avoid the
// heavy lifting being inside a transformed method.
- var stream = new _ReadStream(_chunks);
- _chunks = null;
+ var stream = new _ReadStream(_encoded);
+ _encoded = null;
controller.add("Loading classes...");
await new Future(() => _readClasses(stream));
@@ -520,7 +549,7 @@
return controller.stream;
}
- List<ByteData> _chunks;
+ Uint8List _encoded;
int _kStackCid;
int _kFieldCid;
@@ -572,7 +601,7 @@
var K = stream.readUnsigned();
var classes = new List<_SnapshotClass>(K + 1);
- classes[0] = new _SnapshotClass("Root", "", "");
+ classes[0] = new _SnapshotClass(this, 0, "Root", "", "");
for (var cid = 1; cid <= K; cid++) {
int flags = stream.readUnsigned();
@@ -580,7 +609,7 @@
String libName = stream.readUtf8();
String libUri = stream.readUtf8();
String reserved = stream.readUtf8();
- var cls = new _SnapshotClass(name, libName, libUri);
+ final cls = new _SnapshotClass(this, cid, name, libName, libUri);
int edgeCount = stream.readUnsigned();
for (int i = 0; i < edgeCount; i++) {
int flags = stream.readUnsigned();
diff --git a/runtime/observatory/lib/repositories.dart b/runtime/observatory/lib/repositories.dart
index 51ea321..70cb593 100644
--- a/runtime/observatory/lib/repositories.dart
+++ b/runtime/observatory/lib/repositories.dart
@@ -13,7 +13,7 @@
import 'package:observatory/models.dart' as M;
import 'package:observatory/service.dart' as S;
import 'package:observatory/service_common.dart' as SC;
-import 'package:observatory/service_html.dart' as SH;
+import 'package:observatory/src/repositories/timeline_base.dart';
part 'src/repositories/allocation_profile.dart';
part 'src/repositories/breakpoint.dart';
diff --git a/runtime/observatory/lib/sample_profile.dart b/runtime/observatory/lib/sample_profile.dart
index e755ad3..914906d 100644
--- a/runtime/observatory/lib/sample_profile.dart
+++ b/runtime/observatory/lib/sample_profile.dart
@@ -5,7 +5,6 @@
library sample_profiler;
import 'dart:async';
-import 'dart:typed_data';
import 'package:logging/logging.dart';
import 'package:observatory/models.dart' as M;
import 'package:observatory/service.dart';
diff --git a/runtime/observatory/lib/service_common.dart b/runtime/observatory/lib/service_common.dart
index 4e47b95..66ff984 100644
--- a/runtime/observatory/lib/service_common.dart
+++ b/runtime/observatory/lib/service_common.dart
@@ -205,7 +205,7 @@
var dataLength = bytes.lengthInBytes - dataOffset;
var metadata = _utf8Decoder.convert(new Uint8List.view(
bytes.buffer, bytes.offsetInBytes + metadataOffset, metadataLength));
- var data = new ByteData.view(
+ var data = new Uint8List.view(
bytes.buffer, bytes.offsetInBytes + dataOffset, dataLength);
var map = _parseJSON(metadata);
if (map == null || map['method'] != 'streamNotify') {
diff --git a/runtime/observatory/lib/src/app/page.dart b/runtime/observatory/lib/src/app/page.dart
index bcc224a..d55dc86 100644
--- a/runtime/observatory/lib/src/app/page.dart
+++ b/runtime/observatory/lib/src/app/page.dart
@@ -179,6 +179,7 @@
];
}).catchError((e, stack) {
Logger.root.severe('VMPage visit error: $e');
+ Logger.root.severe('Stack: $stack');
// Reroute to vm-connect.
app.locationManager.go(Uris.vmConnect());
});
diff --git a/runtime/observatory/lib/src/elements/containers/virtual_collection.dart b/runtime/observatory/lib/src/elements/containers/virtual_collection.dart
index f921c44..1446716 100644
--- a/runtime/observatory/lib/src/elements/containers/virtual_collection.dart
+++ b/runtime/observatory/lib/src/elements/containers/virtual_collection.dart
@@ -199,7 +199,7 @@
int i = top - tail_length;
for (final HtmlElement e in _buffer.children) {
if (0 <= i && i < _items.length) {
- e..style.display = null;
+ e.style.display = null;
_update(e, _items[i], i);
} else {
e.style.display = 'hidden';
diff --git a/runtime/observatory/lib/src/elements/cpu_profile.dart b/runtime/observatory/lib/src/elements/cpu_profile.dart
index 320a7603..f6fafd0 100644
--- a/runtime/observatory/lib/src/elements/cpu_profile.dart
+++ b/runtime/observatory/lib/src/elements/cpu_profile.dart
@@ -116,7 +116,7 @@
selectedTag: _tag, queue: _r.queue)
..onTagChange.listen((e) {
_tag = e.element.selectedTag;
- _request(forceFetch: true);
+ _request();
}))
.element);
if (_progress.status == M.SampleProfileLoadingStatus.loaded) {
diff --git a/runtime/observatory/lib/src/elements/cpu_profile/virtual_tree.dart b/runtime/observatory/lib/src/elements/cpu_profile/virtual_tree.dart
index 77de515..a01d842 100644
--- a/runtime/observatory/lib/src/elements/cpu_profile/virtual_tree.dart
+++ b/runtime/observatory/lib/src/elements/cpu_profile/virtual_tree.dart
@@ -90,7 +90,6 @@
var create;
var update;
var search;
-
switch (type) {
case M.SampleProfileType.cpu:
create = _createCpuRow;
diff --git a/runtime/observatory/lib/src/elements/cpu_profile_table.dart b/runtime/observatory/lib/src/elements/cpu_profile_table.dart
index cd07545..e225e48 100644
--- a/runtime/observatory/lib/src/elements/cpu_profile_table.dart
+++ b/runtime/observatory/lib/src/elements/cpu_profile_table.dart
@@ -120,7 +120,7 @@
(new NavRefreshElement(queue: _r.queue)..onRefresh.listen(_refresh))
.element,
(new NavRefreshElement(label: 'Clear', queue: _r.queue)
- ..onRefresh.listen(_clearCpuProfile))
+ ..onRefresh.listen(_clearCpuSamples))
.element,
new NavNotifyElement(_notifications, queue: _r.queue).element
]),
@@ -152,7 +152,10 @@
createHeader: _createFunctionHeader,
search: _searchFunction,
queue: _r.queue);
- _functions.items = _progress.profile.functions.toList()
+ // If there's no samples, don't populate the function list.
+ _functions.items = (_progress.profile.sampleCount != 0)
+ ? _progress.profile.functions.toList()
+ : []
..sort(_createSorter(_Table.functions));
_functions.takeIntoView(_selected);
_callers = _callers ??
@@ -428,7 +431,7 @@
}
}
- Future _clearCpuProfile(RefreshEvent e) async {
+ Future _clearCpuSamples(RefreshEvent e) async {
e.element.disabled = true;
await _request(clear: true);
e.element.disabled = false;
@@ -461,12 +464,12 @@
}
switch (_sortingDirection[table]) {
case _SortingDirection.ascending:
- int sort(M.ProfileFunction a, M.ProfileFunction b) {
+ int sort(a, b) {
return getter(a).compareTo(getter(b));
}
return sort;
case _SortingDirection.descending:
- int sort(M.ProfileFunction a, M.ProfileFunction b) {
+ int sort(a, b) {
return getter(b).compareTo(getter(a));
}
return sort;
diff --git a/runtime/observatory/lib/src/elements/heap_snapshot.dart b/runtime/observatory/lib/src/elements/heap_snapshot.dart
index ee4664f..8460715 100644
--- a/runtime/observatory/lib/src/elements/heap_snapshot.dart
+++ b/runtime/observatory/lib/src/elements/heap_snapshot.dart
@@ -27,6 +27,7 @@
import 'package:observatory/src/elements/nav/refresh.dart';
import 'package:observatory/src/elements/nav/top_menu.dart';
import 'package:observatory/src/elements/nav/vm_menu.dart';
+import 'package:observatory/src/elements/tree_map.dart';
import 'package:observatory/utils.dart';
enum HeapSnapshotTreeMode {
@@ -35,9 +36,108 @@
mergedDominatorTree,
mergedDominatorTreeMap,
ownershipTable,
+ ownershipTreeMap,
+ classesTable,
+ classesTreeMap,
successors,
predecessors,
- classes,
+}
+
+class DominatorTreeMap extends TreeMap<SnapshotObject> {
+ HeapSnapshotElement element;
+ DominatorTreeMap(this.element);
+
+ int getSize(SnapshotObject node) => node.retainedSize;
+ String getType(SnapshotObject node) => node.klass.name;
+ String getLabel(SnapshotObject node) => node.description;
+ SnapshotObject getParent(SnapshotObject node) => node.parent;
+ Iterable<SnapshotObject> getChildren(SnapshotObject node) => node.children;
+ void onSelect(SnapshotObject node) {
+ element.selection = node.objects;
+ element._r.dirty();
+ }
+
+ void onDetails(SnapshotObject node) {
+ element.selection = node.objects;
+ element._mode = HeapSnapshotTreeMode.successors;
+ element._r.dirty();
+ }
+}
+
+class MergedDominatorTreeMap
+ extends TreeMap<M.HeapSnapshotMergedDominatorNode> {
+ HeapSnapshotElement element;
+ MergedDominatorTreeMap(this.element);
+
+ int getSize(M.HeapSnapshotMergedDominatorNode node) => node.retainedSize;
+ String getType(M.HeapSnapshotMergedDominatorNode node) => node.klass.name;
+ String getLabel(M.HeapSnapshotMergedDominatorNode node) =>
+ (node as dynamic).description;
+ M.HeapSnapshotMergedDominatorNode getParent(
+ M.HeapSnapshotMergedDominatorNode node) =>
+ (node as dynamic).parent;
+ Iterable<M.HeapSnapshotMergedDominatorNode> getChildren(
+ M.HeapSnapshotMergedDominatorNode node) =>
+ node.children;
+ void onSelect(M.HeapSnapshotMergedDominatorNode node) {
+ element.mergedSelection = node;
+ element._r.dirty();
+ }
+
+ void onDetails(M.HeapSnapshotMergedDominatorNode node) {
+ dynamic n = node;
+ element.selection = n.objects;
+ element._mode = HeapSnapshotTreeMode.successors;
+ element._r.dirty();
+ }
+}
+
+// Using `null` to represent the root.
+class ClassesShallowTreeMap extends TreeMap<SnapshotClass> {
+ HeapSnapshotElement element;
+ M.HeapSnapshot snapshot;
+
+ ClassesShallowTreeMap(this.element, this.snapshot);
+
+ int getSize(SnapshotClass node) =>
+ node == null ? snapshot.size : node.shallowSize;
+ String getType(SnapshotClass node) => node == null ? "Classes" : node.name;
+ String getLabel(SnapshotClass node) => node == null
+ ? "${snapshot.classes.length} classes"
+ : "${node.instanceCount} instances of ${node.name}";
+ SnapshotClass getParent(SnapshotClass node) => null;
+ Iterable<SnapshotClass> getChildren(SnapshotClass node) =>
+ node == null ? snapshot.classes : <SnapshotClass>[];
+ void onSelect(SnapshotClass node) {}
+ void onDetails(SnapshotClass node) {
+ element.selection = node.instances.toList();
+ element._mode = HeapSnapshotTreeMode.successors;
+ element._r.dirty();
+ }
+}
+
+// Using `null` to represent the root.
+class ClassesOwnershipTreeMap extends TreeMap<SnapshotClass> {
+ HeapSnapshotElement element;
+ M.HeapSnapshot snapshot;
+
+ ClassesOwnershipTreeMap(this.element, this.snapshot);
+
+ int getSize(SnapshotClass node) =>
+ node == null ? snapshot.size : node.ownedSize;
+ String getType(SnapshotClass node) => node == null ? "classes" : node.name;
+ String getLabel(SnapshotClass node) => node == null
+ ? "${snapshot.classes.length} Classes"
+ : "${node.instanceCount} instances of ${node.name}";
+ SnapshotClass getParent(SnapshotClass node) => null;
+ Iterable<SnapshotClass> getChildren(SnapshotClass node) =>
+ node == null ? snapshot.classes : <SnapshotClass>[];
+ void onSelect(SnapshotClass node) {}
+ void onDetails(SnapshotClass node) {
+ element.selection = node.instances.toList();
+ element._mode = HeapSnapshotTreeMode.successors;
+ element._r.dirty();
+ }
}
class HeapSnapshotElement extends CustomElement implements Renderable {
@@ -184,7 +284,7 @@
}
_save() async {
- var blob = new Blob(_snapshot.chunks, 'application/octet-stream');
+ var blob = new Blob([_snapshot.encoded], 'application/octet-stream');
var blobUrl = Url.createObjectUrl(blob);
var link = new AnchorElement();
link.href = blobUrl;
@@ -201,10 +301,9 @@
var file = input.files[0];
var reader = new FileReader();
reader.onLoad.listen((event) async {
- Uint8List blob = reader.result;
- var chunks = [new ByteData.view(blob.buffer)];
+ Uint8List encoded = reader.result;
var snapshot = new S.HeapSnapshot();
- await snapshot.loadProgress(null, chunks).last;
+ await snapshot.loadProgress(null, encoded).last;
_snapshot = snapshot;
selection = null;
mergedSelection = null;
@@ -298,7 +397,7 @@
]);
break;
case HeapSnapshotTreeMode.dominatorTreeMap:
- var content = new DivElement();
+ final content = new DivElement();
content.style.border = '1px solid black';
content.style.width = '100%';
content.style.height = '100%';
@@ -310,7 +409,7 @@
if (selection == null) {
selection = _snapshot.root.objects;
}
- _showTreemap(selection.first, content);
+ new DominatorTreeMap(this).showIn(selection.first, content);
});
final text =
@@ -342,7 +441,7 @@
]);
break;
case HeapSnapshotTreeMode.mergedDominatorTreeMap:
- var content = new DivElement();
+ final content = new DivElement();
content.style.border = '1px solid black';
content.style.width = '100%';
content.style.height = '100%';
@@ -354,7 +453,7 @@
if (mergedSelection == null) {
mergedSelection = _snapshot.mergedDominatorTree;
}
- _showTreemap(mergedSelection, content);
+ new MergedDominatorTreeMap(this).showIn(mergedSelection, content);
});
final text =
@@ -388,6 +487,33 @@
_tree.element
]);
break;
+ case HeapSnapshotTreeMode.ownershipTreeMap:
+ final content = new DivElement();
+ content.style.border = '1px solid black';
+ content.style.width = '100%';
+ content.style.height = '100%';
+ content.text = 'Performing layout...';
+ Timer.run(() {
+ // Generate the treemap after the content div has been added to the
+ // document so that we can ask the browser how much space is
+ // available for treemap layout.
+ new ClassesOwnershipTreeMap(this, _snapshot).showIn(null, content);
+ });
+ final text = 'An object X is said to "own" object Y if X is the only '
+ 'object that references Y, or X owns the only object that '
+ 'references Y. In particular, objects "own" the space of any '
+ 'unshared lists or maps they reference.';
+ report.addAll([
+ new DivElement()
+ ..classes = ['content-centered-big', 'explanation']
+ ..text = text,
+ new DivElement()
+ ..classes = ['content-centered-big']
+ ..style.width = '100%'
+ ..style.height = '100%'
+ ..children = [content]
+ ]);
+ break;
case HeapSnapshotTreeMode.successors:
if (selection == null) {
selection = _snapshot.root.objects;
@@ -424,7 +550,7 @@
_tree.element
]);
break;
- case HeapSnapshotTreeMode.classes:
+ case HeapSnapshotTreeMode.classesTable:
final items = _snapshot.classes.toList();
items.sort((a, b) => b.shallowSize - a.shallowSize);
_tree = new VirtualTreeElement(
@@ -432,7 +558,26 @@
items: items, queue: _r.queue);
report.add(_tree.element);
break;
-
+ case HeapSnapshotTreeMode.classesTreeMap:
+ final content = new DivElement();
+ content.style.border = '1px solid black';
+ content.style.width = '100%';
+ content.style.height = '100%';
+ content.text = 'Performing layout...';
+ Timer.run(() {
+ // Generate the treemap after the content div has been added to the
+ // document so that we can ask the browser how much space is
+ // available for treemap layout.
+ new ClassesShallowTreeMap(this, _snapshot).showIn(null, content);
+ });
+ report.addAll([
+ new DivElement()
+ ..classes = ['content-centered-big']
+ ..style.width = '100%'
+ ..style.height = '100%'
+ ..children = [content]
+ ]);
+ break;
default:
break;
}
@@ -734,198 +879,6 @@
element.children[5].text = node.name;
}
- String color(String string) {
- int hue = string.hashCode % 360;
- return "hsl($hue,60%,60%)";
- }
-
- String prettySize(num size) {
- if (size < 1024) return size.toStringAsFixed(0) + "B";
- size /= 1024;
- if (size < 1024) return size.toStringAsFixed(1) + "KiB";
- size /= 1024;
- if (size < 1024) return size.toStringAsFixed(1) + "MiB";
- size /= 1024;
- return size.toStringAsFixed(1) + "GiB";
- }
-
- /* SnapshotObject | M.MergedDominatorNode */
- void _showTreemap(dynamic node, DivElement content) {
- final w = content.offsetWidth.toDouble();
- final h = content.offsetHeight.toDouble();
- final topTile = _createTreemapTile(node, w, h, 0, content);
- topTile.style.width = "${w}px";
- topTile.style.height = "${h}px";
- topTile.style.border = "none";
- content.children = [topTile];
- }
-
- Element _createTreemapTile(dynamic node, double width, double height,
- int depth, DivElement content) {
- final div = new DivElement();
- div.className = "treemapTile";
- div.style.backgroundColor = color(node.klass.name);
- div.onDoubleClick.listen((event) {
- event.stopPropagation();
- if (depth == 0) {
- // Zoom out.
- if (node is SnapshotObject) {
- selection = node.parent.objects;
- } else {
- mergedSelection = node.parent;
- }
- } else {
- // Zoom in.
- if (node is SnapshotObject) {
- selection = node.objects;
- } else {
- mergedSelection = node;
- }
- }
- _r.dirty();
- });
- div.onContextMenu.listen((event) {
- event.stopPropagation();
- if (node is SnapshotObject) {
- selection = node.objects;
- _mode = HeapSnapshotTreeMode.successors;
- } else {
- selection = node.objects;
- _mode = HeapSnapshotTreeMode.successors;
- }
- _r.dirty();
- });
-
- double left = 0.0;
- double top = 0.0;
-
- const kPadding = 5;
- const kBorder = 1;
- left += kPadding - kBorder;
- top += kPadding - kBorder;
- width -= 2 * kPadding;
- height -= 2 * kPadding;
-
- final label = "${node.description} [${prettySize(node.retainedSize)}]";
- div.title = label; // I.e., tooltip.
-
- if (width < 10 || height < 10) {
- // Too small: don't render label or children.
- return div;
- }
-
- div.append(new SpanElement()..text = label);
- const kLabelHeight = 9.0;
- top += kLabelHeight;
- height -= kLabelHeight;
-
- if (depth > 2) {
- // Too deep: don't render children.
- return div;
- }
- if (width < 4 || height < 4) {
- // Too small: don't render children.
- return div;
- }
-
- final children = new List<dynamic>();
- for (var c in node.children) {
- // Size 0 children seem to confuse the layout algorithm (accumulating
- // rounding errors?).
- if (c.retainedSize > 0) {
- children.add(c);
- }
- }
- children.sort((a, b) => b.retainedSize - a.retainedSize);
-
- final double scale = width * height / node.retainedSize;
-
- // Bruls M., Huizing K., van Wijk J.J. (2000) Squarified Treemaps. In: de
- // Leeuw W.C., van Liere R. (eds) Data Visualization 2000. Eurographics.
- // Springer, Vienna.
- for (int rowStart = 0; // Index of first child in the next row.
- rowStart < children.length;) {
- // Prefer wider rectangles, the better to fit text labels.
- const double GOLDEN_RATIO = 1.61803398875;
- final bool verticalSplit = (width / height) > GOLDEN_RATIO;
-
- double space;
- if (verticalSplit) {
- space = height;
- } else {
- space = width;
- }
-
- double rowMin = children[rowStart].retainedSize * scale;
- double rowMax = rowMin;
- double rowSum = 0.0;
- double lastRatio = 0.0;
-
- int rowEnd; // One after index of last child in the next row.
- for (rowEnd = rowStart; rowEnd < children.length; rowEnd++) {
- double size = children[rowEnd].retainedSize * scale;
- if (size < rowMin) rowMin = size;
- if (size > rowMax) rowMax = size;
- rowSum += size;
-
- double ratio = Math.max((space * space * rowMax) / (rowSum * rowSum),
- (rowSum * rowSum) / (space * space * rowMin));
- if ((lastRatio != 0) && (ratio > lastRatio)) {
- // Adding the next child makes the aspect ratios worse: remove it and
- // add the row.
- rowSum -= size;
- break;
- }
- lastRatio = ratio;
- }
-
- double rowLeft = left;
- double rowTop = top;
- double rowSpace = rowSum / space;
-
- for (var i = rowStart; i < rowEnd; i++) {
- var child = children[i];
- double size = child.retainedSize * scale;
-
- double childWidth;
- double childHeight;
- if (verticalSplit) {
- childWidth = rowSpace;
- childHeight = size / childWidth;
- } else {
- childHeight = rowSpace;
- childWidth = size / childHeight;
- }
-
- var childDiv = _createTreemapTile(
- child, childWidth, childHeight, depth + 1, content);
- childDiv.style.left = "${rowLeft}px";
- childDiv.style.top = "${rowTop}px";
- // Oversize the final div by kBorder to make the borders overlap.
- childDiv.style.width = "${childWidth + kBorder}px";
- childDiv.style.height = "${childHeight + kBorder}px";
- div.append(childDiv);
-
- if (verticalSplit)
- rowTop += childHeight;
- else
- rowLeft += childWidth;
- }
-
- if (verticalSplit) {
- left += rowSpace;
- width -= rowSpace;
- } else {
- top += rowSpace;
- height -= rowSpace;
- }
-
- rowStart = rowEnd;
- }
-
- return div;
- }
-
static _updateLines(List<Element> lines, int n) {
n = Math.max(0, n);
while (lines.length > n) {
@@ -947,13 +900,17 @@
case HeapSnapshotTreeMode.mergedDominatorTreeMap:
return 'Dominators (treemap, siblings merged by class)';
case HeapSnapshotTreeMode.ownershipTable:
- return 'Ownership';
+ return 'Ownership (table)';
+ case HeapSnapshotTreeMode.ownershipTreeMap:
+ return 'Ownership (treemap)';
+ case HeapSnapshotTreeMode.classesTable:
+ return 'Classes (table)';
+ case HeapSnapshotTreeMode.classesTreeMap:
+ return 'Classes (treemap)';
case HeapSnapshotTreeMode.successors:
return 'Successors / outgoing references';
case HeapSnapshotTreeMode.predecessors:
return 'Predecessors / incoming references';
- case HeapSnapshotTreeMode.classes:
- return 'Classes';
}
throw new Exception('Unknown HeapSnapshotTreeMode: $mode');
}
diff --git a/runtime/observatory/lib/src/elements/native_memory_profiler.dart b/runtime/observatory/lib/src/elements/native_memory_profiler.dart
index 8936b31..4d874b5 100644
--- a/runtime/observatory/lib/src/elements/native_memory_profiler.dart
+++ b/runtime/observatory/lib/src/elements/native_memory_profiler.dart
@@ -106,7 +106,7 @@
selectedTag: _tag, queue: _r.queue)
..onTagChange.listen((e) {
_tag = e.element.selectedTag;
- _request(forceFetch: true);
+ _request();
}))
.element);
if (_progress.status == M.SampleProfileLoadingStatus.loaded) {
@@ -145,9 +145,6 @@
}
Future _request({bool forceFetch: false}) async {
- for (M.Isolate isolate in _vm.isolates) {
- await isolate.collectAllGarbage();
- }
_progress = null;
_progressStream = _profiles.get(_vm, _tag, forceFetch: forceFetch);
_r.dirty();
diff --git a/runtime/observatory/lib/src/elements/nav/reload.dart b/runtime/observatory/lib/src/elements/nav/reload.dart
index 64534d3..b6d1a5c 100644
--- a/runtime/observatory/lib/src/elements/nav/reload.dart
+++ b/runtime/observatory/lib/src/elements/nav/reload.dart
@@ -35,9 +35,9 @@
factory NavReloadElement(M.IsolateRef isolate, M.IsolateRepository isolates,
M.EventRepository events,
{RenderingQueue queue}) {
- assert(isolate == null);
- assert(isolates == null);
- assert(events == null);
+ assert(isolate != null);
+ assert(isolates != null);
+ assert(events != null);
NavReloadElement e = new NavReloadElement.created();
e._r = new RenderingScheduler<NavReloadElement>(e, queue: queue);
e._isolate = isolate;
diff --git a/runtime/observatory/lib/src/elements/sample_buffer_control.dart b/runtime/observatory/lib/src/elements/sample_buffer_control.dart
index 97adb22..10ba12f 100644
--- a/runtime/observatory/lib/src/elements/sample_buffer_control.dart
+++ b/runtime/observatory/lib/src/elements/sample_buffer_control.dart
@@ -160,7 +160,7 @@
final loadT = Utils.formatDurationInSeconds(_progress.loadingTime);
final sampleCount = _progress.profile.sampleCount;
final refreshT = new DateTime.now();
- final stackDepth = _progress.profile.stackDepth;
+ final maxStackDepth = _progress.profile.maxStackDepth;
final sampleRate = _progress.profile.sampleRate.toStringAsFixed(0);
final timeSpan = _progress.profile.sampleCount == 0
? '0s'
@@ -195,7 +195,7 @@
..text = 'Sampling',
new DivElement()
..classes = ['memberValue']
- ..text = '$stackDepth stack frames @ ${sampleRate}Hz'
+ ..text = '$maxStackDepth stack frames @ ${sampleRate}Hz'
],
];
if (_showTag) {
diff --git a/runtime/observatory/lib/src/elements/timeline/dashboard.dart b/runtime/observatory/lib/src/elements/timeline/dashboard.dart
index 584d8b8..8995be8 100644
--- a/runtime/observatory/lib/src/elements/timeline/dashboard.dart
+++ b/runtime/observatory/lib/src/elements/timeline/dashboard.dart
@@ -208,9 +208,9 @@
Future _refresh() async {
_flags = await _repository.getFlags(vm);
_r.dirty();
- final params =
- new Map<String, dynamic>.from(await _repository.getIFrameParams(vm));
- return _postMessage('refresh', params);
+ final traceData =
+ Map<String, dynamic>.from(await _repository.getTimeline(vm));
+ return _postMessage('refresh', traceData);
}
Future _clear() async {
diff --git a/runtime/observatory/lib/src/elements/timeline_page.dart b/runtime/observatory/lib/src/elements/timeline_page.dart
index f912239..7e54388 100644
--- a/runtime/observatory/lib/src/elements/timeline_page.dart
+++ b/runtime/observatory/lib/src/elements/timeline_page.dart
@@ -232,9 +232,8 @@
}
Future _refresh() async {
- final params =
- new Map<String, dynamic>.from(await _repository.getIFrameParams(vm));
- return _postMessage('refresh', params);
+ final traceData = await _repository.getTimeline(vm);
+ return _postMessage('refresh', traceData);
}
Future _clear() async {
diff --git a/runtime/observatory/lib/src/elements/tree_map.dart b/runtime/observatory/lib/src/elements/tree_map.dart
new file mode 100644
index 0000000..8db1728
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/tree_map.dart
@@ -0,0 +1,189 @@
+// Copyright (c) 2019, 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:html';
+import 'dart:math' as Math;
+
+String _color(String string) {
+ int hue = string.hashCode % 360;
+ return "hsl($hue,60%,60%)";
+}
+
+String _prettySize(num size) {
+ if (size < 1024) return size.toStringAsFixed(0) + "B";
+ size /= 1024;
+ if (size < 1024) return size.toStringAsFixed(1) + "KiB";
+ size /= 1024;
+ if (size < 1024) return size.toStringAsFixed(1) + "MiB";
+ size /= 1024;
+ return size.toStringAsFixed(1) + "GiB";
+}
+
+abstract class TreeMap<T> {
+ int getSize(T node);
+ String getType(T node);
+ String getLabel(T node);
+ T getParent(T node);
+ Iterable<T> getChildren(T node);
+ void onSelect(T node);
+ void onDetails(T node);
+
+ void showIn(T node, DivElement content) {
+ final w = content.offsetWidth.toDouble();
+ final h = content.offsetHeight.toDouble();
+ final topTile = _createTreemapTile(node, w, h, 0, content);
+ topTile.style.width = "${w}px";
+ topTile.style.height = "${h}px";
+ topTile.style.border = "none";
+ content.children = [topTile];
+ }
+
+ Element _createTreemapTile(
+ T node, double width, double height, int depth, DivElement content) {
+ final div = new DivElement();
+ div.className = "treemapTile";
+ div.style.backgroundColor = _color(getType(node));
+ div.onDoubleClick.listen((event) {
+ event.stopPropagation();
+ if (depth == 0) {
+ onSelect(getParent(node)); // Zoom out.
+ } else {
+ onSelect(node); // Zoom in.
+ }
+ });
+ div.onContextMenu.listen((event) {
+ event.stopPropagation();
+ onDetails(node);
+ });
+
+ double left = 0.0;
+ double top = 0.0;
+
+ const kPadding = 5;
+ const kBorder = 1;
+ left += kPadding - kBorder;
+ top += kPadding - kBorder;
+ width -= 2 * kPadding;
+ height -= 2 * kPadding;
+
+ final label = "${getLabel(node)} [${_prettySize(getSize(node))}]";
+ div.title = label; // I.e., tooltip.
+
+ if (width < 10 || height < 10) {
+ // Too small: don't render label or children.
+ return div;
+ }
+
+ div.append(new SpanElement()..text = label);
+ const kLabelHeight = 9.0;
+ top += kLabelHeight;
+ height -= kLabelHeight;
+
+ if (depth > 2) {
+ // Too deep: don't render children.
+ return div;
+ }
+ if (width < 4 || height < 4) {
+ // Too small: don't render children.
+ return div;
+ }
+
+ final children = <T>[];
+ for (T c in getChildren(node)) {
+ // Size 0 children seem to confuse the layout algorithm (accumulating
+ // rounding errors?).
+ if (getSize(c) > 0) {
+ children.add(c);
+ }
+ }
+ children.sort((a, b) => getSize(b) - getSize(a));
+
+ final double scale = width * height / getSize(node);
+
+ // Bruls M., Huizing K., van Wijk J.J. (2000) Squarified Treemaps. In: de
+ // Leeuw W.C., van Liere R. (eds) Data Visualization 2000. Eurographics.
+ // Springer, Vienna.
+ for (int rowStart = 0; // Index of first child in the next row.
+ rowStart < children.length;) {
+ // Prefer wider rectangles, the better to fit text labels.
+ const double GOLDEN_RATIO = 1.61803398875;
+ final bool verticalSplit = (width / height) > GOLDEN_RATIO;
+
+ double space;
+ if (verticalSplit) {
+ space = height;
+ } else {
+ space = width;
+ }
+
+ double rowMin = getSize(children[rowStart]) * scale;
+ double rowMax = rowMin;
+ double rowSum = 0.0;
+ double lastRatio = 0.0;
+
+ int rowEnd; // One after index of last child in the next row.
+ for (rowEnd = rowStart; rowEnd < children.length; rowEnd++) {
+ double size = getSize(children[rowEnd]) * scale;
+ if (size < rowMin) rowMin = size;
+ if (size > rowMax) rowMax = size;
+ rowSum += size;
+
+ double ratio = Math.max((space * space * rowMax) / (rowSum * rowSum),
+ (rowSum * rowSum) / (space * space * rowMin));
+ if ((lastRatio != 0) && (ratio > lastRatio)) {
+ // Adding the next child makes the aspect ratios worse: remove it and
+ // add the row.
+ rowSum -= size;
+ break;
+ }
+ lastRatio = ratio;
+ }
+
+ double rowLeft = left;
+ double rowTop = top;
+ double rowSpace = rowSum / space;
+
+ for (int i = rowStart; i < rowEnd; i++) {
+ T child = children[i];
+ double size = getSize(child) * scale;
+
+ double childWidth;
+ double childHeight;
+ if (verticalSplit) {
+ childWidth = rowSpace;
+ childHeight = size / childWidth;
+ } else {
+ childHeight = rowSpace;
+ childWidth = size / childHeight;
+ }
+
+ Element childDiv = _createTreemapTile(
+ child, childWidth, childHeight, depth + 1, content);
+ childDiv.style.left = "${rowLeft}px";
+ childDiv.style.top = "${rowTop}px";
+ // Oversize the final div by kBorder to make the borders overlap.
+ childDiv.style.width = "${childWidth + kBorder}px";
+ childDiv.style.height = "${childHeight + kBorder}px";
+ div.append(childDiv);
+
+ if (verticalSplit)
+ rowTop += childHeight;
+ else
+ rowLeft += childWidth;
+ }
+
+ if (verticalSplit) {
+ left += rowSpace;
+ width -= rowSpace;
+ } else {
+ top += rowSpace;
+ height -= rowSpace;
+ }
+
+ rowStart = rowEnd;
+ }
+
+ return div;
+ }
+}
diff --git a/runtime/observatory/lib/src/heap_snapshot/heap_snapshot.dart b/runtime/observatory/lib/src/heap_snapshot/heap_snapshot.dart
index c238385..1c27dbc 100644
--- a/runtime/observatory/lib/src/heap_snapshot/heap_snapshot.dart
+++ b/runtime/observatory/lib/src/heap_snapshot/heap_snapshot.dart
@@ -15,13 +15,13 @@
HeapSnapshotMergedDominatorNode mergedDominatorTree;
List<SnapshotClass> classes;
SnapshotObject get root => graph.root;
- List<ByteData> chunks;
+ Uint8List encoded;
- Stream<String> loadProgress(S.Isolate isolate, List<ByteData> chunks) {
+ Stream<String> loadProgress(S.Isolate isolate, Uint8List encoded) {
final progress = new StreamController<String>.broadcast();
progress.add('Loading...');
- this.chunks = chunks;
- graph = new SnapshotGraph(chunks);
+ this.encoded = encoded;
+ graph = new SnapshotGraph(encoded);
(() async {
timestamp = new DateTime.now();
final stream = graph.process();
diff --git a/runtime/observatory/lib/src/models/objects/heap_snapshot.dart b/runtime/observatory/lib/src/models/objects/heap_snapshot.dart
index f6630c0..36ba5ba 100644
--- a/runtime/observatory/lib/src/models/objects/heap_snapshot.dart
+++ b/runtime/observatory/lib/src/models/objects/heap_snapshot.dart
@@ -10,7 +10,7 @@
SnapshotObject get root;
HeapSnapshotMergedDominatorNode get mergedDominatorTree;
Iterable<SnapshotClass> get classes;
- List<ByteData> get chunks;
+ Uint8List get encoded;
}
abstract class HeapSnapshotMergedDominatorNode {
diff --git a/runtime/observatory/lib/src/models/objects/isolate.dart b/runtime/observatory/lib/src/models/objects/isolate.dart
index 039e0bd..f1d1147 100644
--- a/runtime/observatory/lib/src/models/objects/isolate.dart
+++ b/runtime/observatory/lib/src/models/objects/isolate.dart
@@ -14,9 +14,6 @@
/// A name identifying this isolate. Not guaranteed to be unique.
String get name;
-
- /// Trigger a full GC, collecting all unreachable or weakly reachable objects.
- Future collectAllGarbage();
}
enum IsolateStatus { loading, idle, running, paused }
diff --git a/runtime/observatory/lib/src/models/objects/sample_profile.dart b/runtime/observatory/lib/src/models/objects/sample_profile.dart
index ad0d7be..582e571 100644
--- a/runtime/observatory/lib/src/models/objects/sample_profile.dart
+++ b/runtime/observatory/lib/src/models/objects/sample_profile.dart
@@ -8,11 +8,11 @@
abstract class SampleProfile {
int get sampleCount;
- int get stackDepth;
+ int get maxStackDepth;
double get sampleRate;
double get timeSpan;
- Iterable<ProfileCode> get codes;
- Iterable<ProfileFunction> get functions;
+ List<ProfileCode> get codes;
+ List<ProfileFunction> get functions;
FunctionCallTree loadFunctionTree(ProfileTreeDirection direction);
CodeCallTree loadCodeTree(ProfileTreeDirection direction);
@@ -21,6 +21,8 @@
abstract class Profile {
double get normalizedExclusiveTicks;
double get normalizedInclusiveTicks;
+ void clearTicks();
+ void tickTag();
}
abstract class ProfileCode extends Profile {
@@ -31,6 +33,7 @@
abstract class ProfileFunction extends Profile {
FunctionRef get function;
+ String get resolvedUrl;
Map<ProfileFunction, int> get callers;
Map<ProfileFunction, int> get callees;
}
@@ -53,9 +56,13 @@
abstract class CallTreeNode {
double get percentage;
+ int get count;
int get inclusiveNativeAllocations;
int get exclusiveNativeAllocations;
Iterable<CallTreeNode> get children;
+ void sortChildren();
+
+ void tick(Map sample, {bool exclusive = false});
}
abstract class CodeCallTreeNode extends CallTreeNode {
diff --git a/runtime/observatory/lib/src/models/repositories/timeline.dart b/runtime/observatory/lib/src/models/repositories/timeline.dart
index bd8276e..3d528c9 100644
--- a/runtime/observatory/lib/src/models/repositories/timeline.dart
+++ b/runtime/observatory/lib/src/models/repositories/timeline.dart
@@ -8,5 +8,5 @@
Future<TimelineFlags> getFlags(VMRef ref);
Future setRecordedStreams(VMRef ref, Iterable<TimelineStream> streams);
Future clear(VMRef ref);
- Future<Map<String, dynamic>> getIFrameParams(VMRef ref);
+ Future<Map> getTimeline(VMRef ref);
}
diff --git a/runtime/observatory/lib/src/repositories/isolate.dart b/runtime/observatory/lib/src/repositories/isolate.dart
index d86365c..68b8ae1 100644
--- a/runtime/observatory/lib/src/repositories/isolate.dart
+++ b/runtime/observatory/lib/src/repositories/isolate.dart
@@ -11,7 +11,7 @@
_vm.services.where((S.Service s) => s.service == 'reloadSources');
IsolateRepository(this._vm) {
- assert(_vm == null);
+ assert(_vm != null);
}
Future<M.Isolate> get(M.IsolateRef i) async {
diff --git a/runtime/observatory/lib/src/repositories/sample_profile.dart b/runtime/observatory/lib/src/repositories/sample_profile.dart
index 27d03c5..944eaba 100644
--- a/runtime/observatory/lib/src/repositories/sample_profile.dart
+++ b/runtime/observatory/lib/src/repositories/sample_profile.dart
@@ -4,22 +4,6 @@
part of repositories;
-String _tagToString(M.SampleProfileTag tag) {
- switch (tag) {
- case M.SampleProfileTag.userVM:
- return 'UserVM';
- case M.SampleProfileTag.userOnly:
- return 'UserOnly';
- case M.SampleProfileTag.vmUser:
- return 'VMUser';
- case M.SampleProfileTag.vmOnly:
- return 'VMOnly';
- case M.SampleProfileTag.none:
- return 'None';
- }
- throw new Exception('Unknown SampleProfileTag: $tag');
-}
-
class SampleProfileLoadingProgressEvent
implements M.SampleProfileLoadingProgressEvent {
final SampleProfileLoadingProgress progress;
@@ -28,7 +12,7 @@
class SampleProfileLoadingProgress extends M.SampleProfileLoadingProgress {
StreamController<SampleProfileLoadingProgressEvent> _onProgress =
- new StreamController<SampleProfileLoadingProgressEvent>.broadcast();
+ StreamController<SampleProfileLoadingProgressEvent>.broadcast();
Stream<SampleProfileLoadingProgressEvent> get onProgress =>
_onProgress.stream;
@@ -40,8 +24,8 @@
M.SampleProfileLoadingStatus _status = M.SampleProfileLoadingStatus.fetching;
double _progress = 0.0;
- final Stopwatch _fetchingTime = new Stopwatch();
- final Stopwatch _loadingTime = new Stopwatch();
+ final _fetchingTime = Stopwatch();
+ final _loadingTime = Stopwatch();
SampleProfile _profile;
M.SampleProfileLoadingStatus get status => _status;
@@ -59,21 +43,20 @@
_fetchingTime.start();
try {
if (clear && (type == M.SampleProfileType.cpu)) {
- await owner.invokeRpc('_clearCpuProfile', {});
+ await owner.invokeRpc('clearCpuSamples', {});
}
var response;
if (type == M.SampleProfileType.cpu) {
response = cls != null
- ? await cls.getAllocationSamples(_tagToString(tag))
- : await owner
- .invokeRpc('_getCpuProfile', {'tags': _tagToString(tag)});
+ ? await cls.getAllocationSamples()
+ : await owner.invokeRpc('getCpuSamples', {'_code': true});
} else if (type == M.SampleProfileType.memory) {
assert(owner is M.VM);
- response = await owner.invokeRpc(
- '_getNativeAllocationSamples', {'tags': _tagToString(tag)});
+ response = await owner
+ .invokeRpc('_getNativeAllocationSamples', {'_code': true});
} else {
- throw new Exception('Unknown M.SampleProfileType: $type');
+ throw Exception('Unknown M.SampleProfileType: $type');
}
_fetchingTime.stop();
@@ -81,8 +64,7 @@
_status = M.SampleProfileLoadingStatus.loading;
_triggerOnProgress();
- SampleProfile profile = new SampleProfile();
-
+ SampleProfile profile = SampleProfile();
Stream<double> progress = profile.loadProgress(owner, response);
progress.listen((value) {
_progress = value;
@@ -91,6 +73,7 @@
await progress.drain();
+ profile.tagOrder = tag;
profile.buildFunctionCallerAndCallees();
_profile = profile;
@@ -111,14 +94,15 @@
}
void _triggerOnProgress() {
- _onProgress.add(new SampleProfileLoadingProgressEvent(this));
+ _onProgress.add(SampleProfileLoadingProgressEvent(this));
}
- void reuse() {
+ void reuse(M.SampleProfileTag t) {
+ _profile.tagOrder = t;
final onProgress =
- new StreamController<SampleProfileLoadingProgressEvent>.broadcast();
+ StreamController<SampleProfileLoadingProgressEvent>.broadcast();
Timer.run(() {
- onProgress.add(new SampleProfileLoadingProgressEvent(this));
+ onProgress.add(SampleProfileLoadingProgressEvent(this));
onProgress.close();
});
_onProgress = onProgress;
@@ -137,9 +121,9 @@
S.Isolate isolate = i as S.Isolate;
assert(isolate != null);
if ((_last != null) && !clear && !forceFetch && (_last.owner == isolate)) {
- _last.reuse();
+ _last.reuse(t);
} else {
- _last = new SampleProfileLoadingProgress(isolate, t, clear);
+ _last = SampleProfileLoadingProgress(isolate, t, clear);
}
return _last.onProgress;
}
@@ -153,8 +137,7 @@
S.Class cls = c as S.Class;
assert(isolate != null);
assert(cls != null);
- return new SampleProfileLoadingProgress(isolate, t, false, cls: cls)
- .onProgress;
+ return SampleProfileLoadingProgress(isolate, t, false, cls: cls).onProgress;
}
Future enable(M.IsolateRef i, M.ClassRef c) {
@@ -180,10 +163,10 @@
S.VM owner = vm as S.VM;
assert(owner != null);
- if ((_last != null) && !forceFetch) {
- _last.reuse();
+ if ((_last != null) && (_last.profile != null) && !forceFetch) {
+ _last.reuse(t);
} else {
- _last = new SampleProfileLoadingProgress(owner, t, false,
+ _last = SampleProfileLoadingProgress(owner, t, false,
type: M.SampleProfileType.memory);
}
return _last.onProgress;
diff --git a/runtime/observatory/lib/src/repositories/timeline.dart b/runtime/observatory/lib/src/repositories/timeline.dart
index c2695ef..7c0e4a7 100644
--- a/runtime/observatory/lib/src/repositories/timeline.dart
+++ b/runtime/observatory/lib/src/repositories/timeline.dart
@@ -4,7 +4,11 @@
part of repositories;
-class TimelineRepository implements M.TimelineRepository {
+class TimelineRepository extends TimelineRepositoryBase
+ implements M.TimelineRepository {
+ static const _kStackFrames = 'stackFrames';
+ static const _kTraceEvents = 'traceEvents';
+
Future<M.TimelineFlags> getFlags(M.VMRef ref) async {
S.VM vm = ref as S.VM;
S.ServiceMap response = await vm.invokeRpc('getVMTimelineFlags', {});
@@ -24,15 +28,52 @@
return vm.invokeRpc('clearVMTimeline', {});
}
- Future<Map<String, dynamic>> getIFrameParams(M.VMRef ref) async {
- final SH.WebSocketVM vm = ref as SH.WebSocketVM;
- assert(vm != null);
- await vm.reload();
- await vm.reloadIsolates();
+ Future<void> _formatSamples(
+ M.Isolate isolate, Map traceObject, S.ServiceMap cpuSamples) async {
+ const kRootFrameId = 0;
+ final profile = SampleProfile();
+ await profile.load(isolate as S.ServiceObjectOwner, cpuSamples);
+ final trie = profile.loadFunctionTree(M.ProfileTreeDirection.inclusive);
+ final root = trie.root;
+ int nextId = kRootFrameId;
+ processFrame(FunctionCallTreeNode current, FunctionCallTreeNode parent) {
+ int id = nextId;
+ ++nextId;
+ current.frameId = id;
+ // Skip the root.
+ if (id != kRootFrameId) {
+ final function = current.profileFunction.function;
+ final key = '${isolate.id}-$id';
+ traceObject[_kStackFrames][key] = {
+ 'category': 'Dart',
+ 'name': function.qualifiedName,
+ 'resolvedUrl': current.profileFunction.resolvedUrl,
+ if (parent != null && parent.frameId != kRootFrameId)
+ 'parent': '${isolate.id}-${parent.frameId}',
+ };
+ }
- return <String, dynamic>{
- 'vmAddress': vm.target.networkAddress,
- 'isolateIds': vm.isolates.map((i) => i.id).toList()
- };
+ for (final child in current.children) {
+ processFrame(child, current);
+ }
+ }
+
+ processFrame(root, null);
+
+ for (final sample in profile.samples) {
+ FunctionCallTreeNode trie = sample[SampleProfile.kTimelineFunctionTrie];
+
+ if (trie.frameId != kRootFrameId) {
+ traceObject[_kTraceEvents].add({
+ 'ph': 'P', // kind = sample event
+ 'name': '', // Blank to keep about:tracing happy
+ 'pid': profile.pid,
+ 'tid': sample['tid'],
+ 'ts': sample['timestamp'],
+ 'cat': 'Dart',
+ 'sf': '${isolate.id}-${trie.frameId}',
+ });
+ }
+ }
}
}
diff --git a/runtime/observatory/lib/src/repositories/timeline_base.dart b/runtime/observatory/lib/src/repositories/timeline_base.dart
new file mode 100644
index 0000000..9f6e113
--- /dev/null
+++ b/runtime/observatory/lib/src/repositories/timeline_base.dart
@@ -0,0 +1,103 @@
+// Copyright (c) 2019, 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 'package:observatory/sample_profile.dart';
+import 'package:observatory/models.dart' as M;
+import 'package:observatory/service.dart' as S;
+
+class TimelineRepositoryBase {
+ static const _kStackFrames = 'stackFrames';
+ static const _kTraceEvents = 'traceEvents';
+ static const kTimeOriginMicros = 'timeOriginMicros';
+ static const kTimeExtentMicros = 'timeExtentMicros';
+
+ Future<void> _formatSamples(
+ M.Isolate isolate, Map traceObject, S.ServiceMap cpuSamples) async {
+ const kRootFrameId = 0;
+ final profile = SampleProfile();
+ await profile.load(isolate as S.ServiceObjectOwner, cpuSamples);
+ final trie = profile.loadFunctionTree(M.ProfileTreeDirection.inclusive);
+ final root = trie.root;
+ int nextId = kRootFrameId;
+ processFrame(FunctionCallTreeNode current, FunctionCallTreeNode parent) {
+ int id = nextId;
+ ++nextId;
+ current.frameId = id;
+ // Skip the root.
+ if (id != kRootFrameId) {
+ final function = current.profileFunction.function;
+ final key = '${isolate.id}-$id';
+ traceObject[_kStackFrames][key] = {
+ 'category': 'Dart',
+ 'name': function.qualifiedName,
+ 'resolvedUrl': current.profileFunction.resolvedUrl,
+ if (parent != null && parent.frameId != kRootFrameId)
+ 'parent': '${isolate.id}-${parent.frameId}',
+ };
+ }
+
+ for (final child in current.children) {
+ processFrame(child, current);
+ }
+ }
+
+ processFrame(root, null);
+
+ for (final sample in profile.samples) {
+ FunctionCallTreeNode trie = sample[SampleProfile.kTimelineFunctionTrie];
+
+ if (trie.frameId != kRootFrameId) {
+ traceObject[_kTraceEvents].add({
+ 'ph': 'P', // kind = sample event
+ 'name': '', // Blank to keep about:tracing happy
+ 'pid': profile.pid,
+ 'tid': sample['tid'],
+ 'ts': sample['timestamp'],
+ 'cat': 'Dart',
+ 'sf': '${isolate.id}-${trie.frameId}',
+ });
+ }
+ }
+ }
+
+ Future<Map> getCpuProfileTimeline(M.VMRef ref,
+ {int timeOriginMicros, int timeExtentMicros}) async {
+ final S.VM vm = ref as S.VM;
+ final sampleRequests = <Future>[];
+
+ for (final isolate in vm.isolates) {
+ sampleRequests.add(vm.invokeRpc('getCpuSamples', {
+ 'isolateId': isolate.id,
+ if (timeOriginMicros != null) kTimeOriginMicros: timeOriginMicros,
+ if (timeExtentMicros != null) kTimeExtentMicros: timeExtentMicros,
+ }));
+ }
+
+ final completed = await Future.wait(sampleRequests);
+ final traceObject = <String, dynamic>{
+ _kStackFrames: {},
+ _kTraceEvents: [],
+ };
+ for (int i = 0; i < vm.isolates.length; ++i) {
+ await _formatSamples(vm.isolates[i], traceObject, completed[i]);
+ }
+ return traceObject;
+ }
+
+ Future<Map> getTimeline(M.VMRef ref) async {
+ final S.VM vm = ref as S.VM;
+ final S.ServiceMap vmTimelineResponse =
+ await vm.invokeRpc('getVMTimeline', {});
+ final timeOriginMicros = vmTimelineResponse[kTimeOriginMicros];
+ final timeExtentMicros = vmTimelineResponse[kTimeExtentMicros];
+ final traceObject = await getCpuProfileTimeline(
+ vm,
+ timeOriginMicros: timeOriginMicros,
+ timeExtentMicros: timeExtentMicros,
+ );
+ traceObject[_kTraceEvents].addAll(vmTimelineResponse[_kTraceEvents]);
+ return traceObject;
+ }
+}
diff --git a/runtime/observatory/lib/src/sample_profile/sample_profile.dart b/runtime/observatory/lib/src/sample_profile/sample_profile.dart
index 177713b..48667cc 100644
--- a/runtime/observatory/lib/src/sample_profile/sample_profile.dart
+++ b/runtime/observatory/lib/src/sample_profile/sample_profile.dart
@@ -7,36 +7,90 @@
abstract class CallTreeNode<NodeT extends M.CallTreeNode>
implements M.CallTreeNode {
final List<NodeT> children;
- final int count;
- final int inclusiveNativeAllocations;
- final int exclusiveNativeAllocations;
+ int get count => _count;
+ int _count = 0;
+ int inclusiveNativeAllocations = 0;
+ int exclusiveNativeAllocations = 0;
double get percentage => _percentage;
double _percentage = 0.0;
- final Set<String> attributes = new Set<String>();
+ final attributes = <String>{};
+
+ // Used for building timeline
+ int frameId = null;
+ int parentId = null;
// Either a ProfileCode or a ProfileFunction.
Object get profileData;
String get name;
- CallTreeNode(this.children, this.count, this.inclusiveNativeAllocations,
- this.exclusiveNativeAllocations);
+ CallTreeNode(this.children,
+ [this._count = 0,
+ this.inclusiveNativeAllocations = 0,
+ this.exclusiveNativeAllocations = 0]) {}
+
+ NodeT getChild(int index);
+
+ void sortChildren() {
+ children.sort((a, b) => b.count - a.count);
+ children.forEach((NodeT child) => child.sortChildren());
+ }
+
+ void tick(Map sample, {bool exclusive = false}) {
+ ++_count;
+ if (SampleProfile._isNativeAllocationSample(sample)) {
+ final allocationSize = sample[SampleProfile._kNativeAllocationSizeBytes];
+ if (exclusive) {
+ exclusiveNativeAllocations += allocationSize;
+ }
+ inclusiveNativeAllocations += allocationSize;
+ }
+ }
}
class CodeCallTreeNode extends CallTreeNode<CodeCallTreeNode>
implements M.CodeCallTreeNode {
final ProfileCode profileCode;
+ final SampleProfile profile;
Object get profileData => profileCode;
String get name => profileCode.code.name;
- final Set<String> attributes = new Set<String>();
+ final attributes = <String>{};
CodeCallTreeNode(this.profileCode, int count, int inclusiveNativeAllocations,
int exclusiveNativeAllocations)
- : super(new List<CodeCallTreeNode>(), count, inclusiveNativeAllocations,
+ : profile = profileCode.profile,
+ super(<CodeCallTreeNode>[], count, inclusiveNativeAllocations,
exclusiveNativeAllocations) {
attributes.addAll(profileCode.attributes);
}
+
+ CodeCallTreeNode.fromIndex(this.profile, int tableIndex)
+ : profileCode = profile.codes[tableIndex],
+ super(<CodeCallTreeNode>[]);
+
+ CodeCallTreeNode getChild(int codeTableIndex) {
+ final length = children.length;
+ int i = 0;
+ while (i < length) {
+ final child = children[i];
+ final childTableIndex = child.profileCode.tableIndex;
+ if (childTableIndex == codeTableIndex) {
+ return child;
+ }
+ if (childTableIndex > codeTableIndex) {
+ break;
+ }
+ ++i;
+ }
+ final child = CodeCallTreeNode.fromIndex(profile, codeTableIndex);
+ if (i < length) {
+ children.insert(i, child);
+ } else {
+ children.add(child);
+ }
+ return child;
+ }
}
class CallTree<NodeT extends CallTreeNode> {
@@ -58,7 +112,7 @@
}
CodeCallTree filtered(CallTreeNodeFilter filter) {
- var treeFilter = new _FilteredCodeCallTreeBuilder(filter, this);
+ final treeFilter = _FilteredCodeCallTreeBuilder(filter, this);
treeFilter.build();
if ((treeFilter.filtered.root.inclusiveNativeAllocations != null) &&
(treeFilter.filtered.root.inclusiveNativeAllocations != 0)) {
@@ -137,7 +191,8 @@
class FunctionCallTreeNode extends CallTreeNode<FunctionCallTreeNode>
implements M.FunctionCallTreeNode {
final ProfileFunction profileFunction;
- final codes = new List<FunctionCallTreeNodeCode>();
+ final SampleProfile profile;
+ final codes = <FunctionCallTreeNodeCode>[];
int _totalCodeTicks = 0;
int get totalCodesTicks => _totalCodeTicks;
@@ -146,69 +201,43 @@
FunctionCallTreeNode(this.profileFunction, int count,
inclusiveNativeAllocations, exclusiveNativeAllocations)
- : super(new List<FunctionCallTreeNode>(), count,
- inclusiveNativeAllocations, exclusiveNativeAllocations) {
+ : profile = profileFunction.profile,
+ super(<FunctionCallTreeNode>[], count, inclusiveNativeAllocations,
+ exclusiveNativeAllocations) {
profileFunction._addKindBasedAttributes(attributes);
}
- // Does this function have an optimized version of itself?
- bool hasOptimizedCode() {
- for (var nodeCode in codes) {
- var profileCode = nodeCode.code;
- if (!profileCode.code.isDartCode) {
- continue;
- }
- if (profileCode.code.function != profileFunction.function) {
- continue;
- }
- if (profileCode.code.isOptimized) {
- return true;
- }
- }
- return false;
- }
+ FunctionCallTreeNode.fromIndex(this.profile, int tableIndex)
+ : profileFunction = profile.functions[tableIndex],
+ super(<FunctionCallTreeNode>[]);
- // Does this function have an unoptimized version of itself?
- bool hasUnoptimizedCode() {
- for (var nodeCode in codes) {
- var profileCode = nodeCode.code;
- if (!profileCode.code.isDartCode) {
- continue;
+ FunctionCallTreeNode getChild(int functionTableIndex) {
+ final length = children.length;
+ int i = 0;
+ while (i < length) {
+ final child = children[i];
+ final childTableIndex = child.profileFunction.tableIndex;
+ if (childTableIndex == functionTableIndex) {
+ return child;
}
- if (profileCode.code.kind == M.CodeKind.stub) {
- continue;
+ if (childTableIndex > functionTableIndex) {
+ break;
}
- if (!profileCode.code.isOptimized) {
- return true;
- }
+ ++i;
}
- return false;
- }
-
- // Has this function been inlined in another function?
- bool isInlined() {
- for (var nodeCode in codes) {
- var profileCode = nodeCode.code;
- if (!profileCode.code.isDartCode) {
- continue;
- }
- if (profileCode.code.kind == M.CodeKind.stub) {
- continue;
- }
- // If the code's function isn't this function.
- if (profileCode.code.function != profileFunction.function) {
- return true;
- }
+ final child = FunctionCallTreeNode.fromIndex(profile, functionTableIndex);
+ if (i < length) {
+ children.insert(i, child);
+ } else {
+ children.add(child);
}
- return false;
+ return child;
}
-
- setCodeAttributes() {}
}
/// Predicate filter function. Returns true if path from root to [node] and all
/// of [node]'s children should be added to the filtered tree.
-typedef bool CallTreeNodeFilter(CallTreeNode node);
+typedef CallTreeNodeFilter = bool Function(CallTreeNode node);
/// Build a filter version of a FunctionCallTree.
abstract class _FilteredCallTreeBuilder<NodeT extends CallTreeNode> {
@@ -263,7 +292,6 @@
current.children.add(child);
}
current = child;
- assert(current.count == toAdd.count);
}
return current;
}
@@ -328,16 +356,16 @@
: super(
filter,
tree,
- new FunctionCallTree(
+ FunctionCallTree(
tree.inclusive,
- new FunctionCallTreeNode(
+ FunctionCallTreeNode(
tree.root.profileData,
tree.root.count,
tree.root.inclusiveNativeAllocations,
tree.root.exclusiveNativeAllocations)));
_copyNode(FunctionCallTreeNode node) {
- return new FunctionCallTreeNode(node.profileData, node.count,
+ return FunctionCallTreeNode(node.profileData, node.count,
node.inclusiveNativeAllocations, node.exclusiveNativeAllocations);
}
}
@@ -348,16 +376,16 @@
: super(
filter,
tree,
- new CodeCallTree(
+ CodeCallTree(
tree.inclusive,
- new CodeCallTreeNode(
+ CodeCallTreeNode(
tree.root.profileData,
tree.root.count,
tree.root.inclusiveNativeAllocations,
tree.root.exclusiveNativeAllocations)));
_copyNode(CodeCallTreeNode node) {
- return new CodeCallTreeNode(node.profileData, node.count,
+ return CodeCallTreeNode(node.profileData, node.count,
node.inclusiveNativeAllocations, node.exclusiveNativeAllocations);
}
}
@@ -375,7 +403,7 @@
}
FunctionCallTree filtered(CallTreeNodeFilter filter) {
- var treeFilter = new _FilteredFunctionCallTreeBuilder(filter, this);
+ final treeFilter = _FilteredFunctionCallTreeBuilder(filter, this);
treeFilter.build();
if ((treeFilter.filtered.root.inclusiveNativeAllocations != null) &&
(treeFilter.filtered.root.inclusiveNativeAllocations != 0)) {
@@ -464,24 +492,21 @@
}
class ProfileCode implements M.ProfileCode {
+ final int tableIndex;
final SampleProfile profile;
final Code code;
int exclusiveTicks;
int inclusiveTicks;
- int exclusiveNativeAllocations;
- int inclusiveNativeAllocations;
double normalizedExclusiveTicks = 0.0;
double normalizedInclusiveTicks = 0.0;
- final addressTicks = new Map<int, CodeTick>();
- final intervalTicks = new Map<int, InlineIntervalTick>();
+ final addressTicks = <int, CodeTick>{};
+ final intervalTicks = <int, InlineIntervalTick>{};
String formattedInclusiveTicks = '';
String formattedExclusiveTicks = '';
String formattedExclusivePercent = '';
- String formattedCpuTime = '';
- String formattedOnStackTime = '';
- final Set<String> attributes = new Set<String>();
- final Map<ProfileCode, int> callers = new Map<ProfileCode, int>();
- final Map<ProfileCode, int> callees = new Map<ProfileCode, int>();
+ final Set<String> attributes = <String>{};
+ final callers = <ProfileCode, int>{};
+ final callees = <ProfileCode, int>{};
void _processTicks(List<dynamic> profileTicks) {
assert(profileTicks != null);
@@ -492,7 +517,7 @@
var address = int.parse(profileTicks[i] as String, radix: 16);
var exclusive = profileTicks[i + 1] as int;
var inclusive = profileTicks[i + 2] as int;
- var tick = new CodeTick(exclusive, inclusive);
+ var tick = CodeTick(exclusive, inclusive);
addressTicks[address] = tick;
var interval = code.findInterval(address);
@@ -500,7 +525,7 @@
var intervalTick = intervalTicks[interval.start];
if (intervalTick == null) {
// Insert into map.
- intervalTick = new InlineIntervalTick(interval.start);
+ intervalTick = InlineIntervalTick(interval.start);
intervalTicks[interval.start] = intervalTick;
}
intervalTick._inclusiveTicks += inclusive;
@@ -509,7 +534,17 @@
}
}
- ProfileCode.fromMap(this.profile, this.code, Map data) {
+ void clearTicks() {
+ exclusiveTicks = 0;
+ inclusiveTicks = 0;
+ normalizedExclusiveTicks = 0;
+ normalizedInclusiveTicks = 0;
+ formattedInclusiveTicks = '';
+ formattedExclusiveTicks = '';
+ formattedExclusivePercent = '';
+ }
+
+ ProfileCode.fromMap(this.tableIndex, this.profile, this.code, Map data) {
assert(profile != null);
assert(code != null);
@@ -548,23 +583,9 @@
_processTicks(ticks);
}
- if (data.containsKey('exclusiveNativeAllocations') &&
- data.containsKey('inclusiveNativeAllocations')) {
- exclusiveNativeAllocations =
- int.parse(data['exclusiveNativeAllocations']);
- inclusiveNativeAllocations =
- int.parse(data['inclusiveNativeAllocations']);
- }
-
formattedExclusivePercent =
Utils.formatPercent(exclusiveTicks, profile.sampleCount);
- formattedCpuTime = Utils.formatTimeMilliseconds(
- profile.approximateMillisecondsForCount(exclusiveTicks));
-
- formattedOnStackTime = Utils.formatTimeMilliseconds(
- profile.approximateMillisecondsForCount(inclusiveTicks));
-
formattedInclusiveTicks =
'${Utils.formatPercent(inclusiveTicks, profile.sampleCount)} '
'($inclusiveTicks)';
@@ -589,15 +610,43 @@
}
callees[callee] = r + count;
}
+
+ void _normalizeTicks() {
+ normalizedExclusiveTicks = exclusiveTicks / profile.sampleCount;
+ normalizedInclusiveTicks = inclusiveTicks / profile.sampleCount;
+
+ formattedExclusivePercent =
+ Utils.formatPercent(exclusiveTicks, profile.sampleCount);
+
+ formattedInclusiveTicks =
+ '${Utils.formatPercent(inclusiveTicks, profile.sampleCount)} '
+ '($inclusiveTicks)';
+
+ formattedExclusiveTicks =
+ '${Utils.formatPercent(exclusiveTicks, profile.sampleCount)} '
+ '($exclusiveTicks)';
+ }
+
+ void tickTag() {
+ // All functions *except* those for tags are ticked in the VM while
+ // generating the CpuSamples response.
+ if (code.kind != M.CodeKind.tag) {
+ throw StateError('Only tags should be ticked. '
+ 'Attempted to tick: ${code.name}');
+ }
+ ++exclusiveTicks;
+ ++inclusiveTicks;
+ _normalizeTicks();
+ }
}
class ProfileFunction implements M.ProfileFunction {
+ final int tableIndex;
final SampleProfile profile;
final ServiceFunction function;
- // List of compiled code objects containing this function.
- final List<ProfileCode> profileCodes = new List<ProfileCode>();
- final Map<ProfileFunction, int> callers = new Map<ProfileFunction, int>();
- final Map<ProfileFunction, int> callees = new Map<ProfileFunction, int>();
+ final String resolvedUrl;
+ final callers = <ProfileFunction, int>{};
+ final callees = <ProfileFunction, int>{};
// Absolute ticks:
int exclusiveTicks = 0;
@@ -607,71 +656,19 @@
double normalizedExclusiveTicks = 0.0;
double normalizedInclusiveTicks = 0.0;
- // Native allocations:
- int exclusiveNativeAllocations = 0;
- int inclusiveNativeAllocations = 0;
-
String formattedInclusiveTicks = '';
String formattedExclusiveTicks = '';
String formattedExclusivePercent = '';
- String formattedCpuTime = '';
- String formattedOnStackTime = '';
- final Set<String> attributes = new Set<String>();
+ final attributes = <String>{};
- int _sortCodes(ProfileCode a, ProfileCode b) {
- if (a.code.isOptimized == b.code.isOptimized) {
- return b.code.profile.exclusiveTicks - a.code.profile.exclusiveTicks;
- }
- if (a.code.isOptimized) {
- return -1;
- }
- return 1;
- }
-
- // Does this function have an optimized version of itself?
- bool hasOptimizedCode() {
- for (var profileCode in profileCodes) {
- if (profileCode.code.function != function) {
- continue;
- }
- if (profileCode.code.isOptimized) {
- return true;
- }
- }
- return false;
- }
-
- // Does this function have an unoptimized version of itself?
- bool hasUnoptimizedCode() {
- for (var profileCode in profileCodes) {
- if (profileCode.code.kind == M.CodeKind.stub) {
- continue;
- }
- if (!profileCode.code.isDartCode) {
- continue;
- }
- if (!profileCode.code.isOptimized) {
- return true;
- }
- }
- return false;
- }
-
- // Has this function been inlined in another function?
- bool isInlined() {
- for (var profileCode in profileCodes) {
- if (profileCode.code.kind == M.CodeKind.stub) {
- continue;
- }
- if (!profileCode.code.isDartCode) {
- continue;
- }
- // If the code's function isn't this function.
- if (profileCode.code.function != function) {
- return true;
- }
- }
- return false;
+ void clearTicks() {
+ exclusiveTicks = 0;
+ inclusiveTicks = 0;
+ normalizedExclusiveTicks = 0;
+ normalizedInclusiveTicks = 0;
+ formattedInclusiveTicks = '';
+ formattedExclusiveTicks = '';
+ formattedExclusivePercent = '';
}
void _addKindBasedAttributes(Set<String> attribs) {
@@ -693,45 +690,14 @@
}
}
- ProfileFunction.fromMap(this.profile, this.function, Map data) {
+ ProfileFunction.fromMap(
+ this.tableIndex, this.profile, this.function, Map data)
+ : resolvedUrl = data['resolvedUrl'] {
function.profile = this;
- for (var codeIndex in data['codes']) {
- var profileCode = profile.codes[codeIndex];
- profileCodes.add(profileCode);
- }
- profileCodes.sort(_sortCodes);
-
_addKindBasedAttributes(attributes);
exclusiveTicks = data['exclusiveTicks'];
inclusiveTicks = data['inclusiveTicks'];
-
- normalizedExclusiveTicks = exclusiveTicks / profile.sampleCount;
- normalizedInclusiveTicks = inclusiveTicks / profile.sampleCount;
-
- if (data.containsKey('exclusiveNativeAllocations') &&
- data.containsKey('inclusiveNativeAllocations')) {
- exclusiveNativeAllocations =
- int.parse(data['exclusiveNativeAllocations']);
- inclusiveNativeAllocations =
- int.parse(data['inclusiveNativeAllocations']);
- }
-
- formattedExclusivePercent =
- Utils.formatPercent(exclusiveTicks, profile.sampleCount);
-
- formattedCpuTime = Utils.formatTimeMilliseconds(
- profile.approximateMillisecondsForCount(exclusiveTicks));
-
- formattedOnStackTime = Utils.formatTimeMilliseconds(
- profile.approximateMillisecondsForCount(inclusiveTicks));
-
- formattedInclusiveTicks =
- '${Utils.formatPercent(inclusiveTicks, profile.sampleCount)} '
- '($inclusiveTicks)';
-
- formattedExclusiveTicks =
- '${Utils.formatPercent(exclusiveTicks, profile.sampleCount)} '
- '($exclusiveTicks)';
+ _normalizeTicks();
}
_recordCaller(ProfileFunction caller, int count) {
@@ -749,6 +715,34 @@
}
callees[callee] = r + count;
}
+
+ void _normalizeTicks() {
+ normalizedExclusiveTicks = exclusiveTicks / profile.sampleCount;
+ normalizedInclusiveTicks = inclusiveTicks / profile.sampleCount;
+
+ formattedExclusivePercent =
+ Utils.formatPercent(exclusiveTicks, profile.sampleCount);
+
+ formattedInclusiveTicks =
+ '${Utils.formatPercent(inclusiveTicks, profile.sampleCount)} '
+ '($inclusiveTicks)';
+
+ formattedExclusiveTicks =
+ '${Utils.formatPercent(exclusiveTicks, profile.sampleCount)} '
+ '($exclusiveTicks)';
+ }
+
+ void tickTag() {
+ // All functions *except* those for functions are ticked in the VM while
+ // generating the CpuSamples response.
+ if (function.kind != M.FunctionKind.tag) {
+ throw StateError('Only tags should be ticked. '
+ 'Attempted to tick: ${function.name}');
+ }
+ ++exclusiveTicks;
+ ++inclusiveTicks;
+ _normalizeTicks();
+ }
}
class SampleProfile extends M.SampleProfile {
@@ -757,35 +751,66 @@
int sampleCount = 0;
int samplePeriod = 0;
double sampleRate = 0.0;
-
- int stackDepth = 0;
+ int pid = 0;
+ int maxStackDepth = 0;
double timeSpan = 0.0;
- final Map<String, List> tries = <String, List>{};
- final List<ProfileCode> codes = new List<ProfileCode>();
+ M.SampleProfileTag tagOrder = M.SampleProfileTag.none;
+
+ final _functionTagMapping = <String, int>{};
+ final _codeTagMapping = <String, int>{};
+
+ final List samples = [];
+ final codes = <ProfileCode>[];
bool _builtCodeCalls = false;
- final List<ProfileFunction> functions = new List<ProfileFunction>();
+ final functions = <ProfileFunction>[];
bool _builtFunctionCalls = false;
+ static const String _kCode = 'code';
+ static const String _kCodes = '_codes';
+ static const String _kCodeStack = '_codeStack';
+ static const String _kFunction = 'function';
+ static const String _kFunctions = 'functions';
+ static const String _kNativeAllocationSizeBytes =
+ '_nativeAllocationSizeBytes';
+ static const String _kPid = 'pid';
+ static const String _kSampleCount = 'sampleCount';
+ static const String _kSamplePeriod = 'samplePeriod';
+ static const String _kSamples = 'samples';
+ static const String _kStack = 'stack';
+ static const String _kMaxStackDepth = 'maxStackDepth';
+ static const String _kTimeSpan = 'timespan';
+ static const String _kUserTag = 'userTag';
+ static const String _kVmTag = 'vmTag';
+
+ // Names of special tag types.
+ static const String kNativeTag = 'Native';
+ static const String kRootTag = 'Root';
+ static const String kRuntimeTag = 'Runtime';
+ static const String kTruncatedTag = '[Truncated]';
+
+ // Used to stash trie information in samples for timeline processing.
+ static const String kTimelineFunctionTrie = 'timelineFunctionTrie';
+
CodeCallTree loadCodeTree(M.ProfileTreeDirection direction) {
switch (direction) {
case M.ProfileTreeDirection.inclusive:
- return _loadCodeTree(true, tries['inclusiveCodeTrie']);
+ return _loadCodeTree(true);
case M.ProfileTreeDirection.exclusive:
- return _loadCodeTree(false, tries['exclusiveCodeTrie']);
+ return _loadCodeTree(false);
}
- throw new Exception('Unknown ProfileTreeDirection');
+ throw Exception('Unknown ProfileTreeDirection');
}
FunctionCallTree loadFunctionTree(M.ProfileTreeDirection direction) {
switch (direction) {
case M.ProfileTreeDirection.inclusive:
- return _loadFunctionTree(true, tries['inclusiveFunctionTrie']);
+ return _loadFunctionTree(true);
case M.ProfileTreeDirection.exclusive:
- return _loadFunctionTree(false, tries['exclusiveFunctionTrie']);
+ return _loadFunctionTree(false);
}
- throw new Exception('Unknown ProfileTreeDirection');
+ throw Exception('Unknown ProfileTreeDirection');
}
buildCodeCallerAndCallees() {
@@ -807,14 +832,14 @@
}
clear() {
+ pid = -1;
sampleCount = 0;
samplePeriod = 0;
sampleRate = 0.0;
- stackDepth = 0;
+ maxStackDepth = 0;
timeSpan = 0.0;
codes.clear();
functions.clear();
- tries.clear();
_builtCodeCalls = false;
_builtFunctionCalls = false;
}
@@ -823,268 +848,403 @@
await loadProgress(owner, profile).drain();
}
- static Future sleep([Duration duration = const Duration(microseconds: 0)]) {
- final Completer completer = new Completer();
- new Timer(duration, () => completer.complete());
- return completer.future;
- }
+ static Future sleep([Duration duration = const Duration(microseconds: 0)]) =>
+ Future.delayed(duration);
- Stream<double> loadProgress(ServiceObjectOwner owner, ServiceMap profile) {
- Logger.root.info('sampling counters ${profile['counters']}');
-
- var progress = new StreamController<double>.broadcast();
-
- (() async {
- final Stopwatch watch = new Stopwatch();
- watch.start();
- int count = 0;
- var needToUpdate = () {
- count++;
- if (((count % 256) == 0) && (watch.elapsedMilliseconds > 16)) {
- watch.reset();
- return true;
- }
+ Future _loadCommon(ServiceObjectOwner owner, ServiceMap profile,
+ [StreamController<double> progress]) async {
+ final watch = Stopwatch();
+ watch.start();
+ int count = 0;
+ var needToUpdate = () {
+ if (progress == null) {
return false;
- };
- var signal = (double p) {
- progress.add(p);
- return sleep();
- };
- try {
- clear();
- progress.add(0.0);
- if (profile == null) {
- return;
- }
+ }
+ count++;
+ if (((count % 256) == 0) && (watch.elapsedMilliseconds > 16)) {
+ watch.reset();
+ return true;
+ }
+ return false;
+ };
+ var signal = (double p) {
+ if (progress == null) {
+ return null;
+ }
+ progress.add(p);
+ return sleep();
+ };
+ try {
+ clear();
+ progress?.add(0.0);
+ if (profile == null) {
+ return;
+ }
- if ((owner != null) && (owner is Isolate)) {
- isolate = owner;
- isolate.resetCachedProfileData();
- }
+ if ((owner != null) && (owner is Isolate)) {
+ isolate = owner;
+ isolate.resetCachedProfileData();
+ }
- sampleCount = profile['sampleCount'];
- samplePeriod = profile['samplePeriod'];
- sampleRate = (Duration.microsecondsPerSecond / samplePeriod);
- stackDepth = profile['stackDepth'];
- timeSpan = profile['timeSpan'];
+ pid = profile[_kPid];
+ sampleCount = profile[_kSampleCount];
+ samplePeriod = profile[_kSamplePeriod];
+ sampleRate = (Duration.microsecondsPerSecond / samplePeriod);
+ maxStackDepth = profile[_kMaxStackDepth];
+ timeSpan = profile[_kTimeSpan];
- num length = profile['codes'].length + profile['functions'].length;
+ num length = 0;
- // Process code table.
- for (var codeRegion in profile['codes']) {
+ if (profile.containsKey(_kCodes)) {
+ length += profile[_kCodes].length;
+ }
+ length += profile[_kFunctions].length;
+
+ // Process code table.
+ int tableIndex = 0;
+ if (profile.containsKey(_kCodes)) {
+ for (var codeRegion in profile[_kCodes]) {
if (needToUpdate()) {
await signal(count * 100.0 / length);
}
- Code code = codeRegion['code'];
+ Code code = codeRegion[_kCode];
assert(code != null);
- codes.add(new ProfileCode.fromMap(this, code, codeRegion));
+ codes.add(ProfileCode.fromMap(tableIndex, this, code, codeRegion));
+ ++tableIndex;
}
- // Process function table.
- for (var profileFunction in profile['functions']) {
- if (needToUpdate()) {
- await signal(count * 100 / length);
- }
- ServiceFunction function = profileFunction['function'];
- assert(function != null);
- functions.add(
- new ProfileFunction.fromMap(this, function, profileFunction));
- }
-
- tries['exclusiveCodeTrie'] =
- new Uint32List.fromList(profile['exclusiveCodeTrie'].cast<int>());
- tries['inclusiveCodeTrie'] =
- new Uint32List.fromList(profile['inclusiveCodeTrie'].cast<int>());
- tries['exclusiveFunctionTrie'] = new Uint32List.fromList(
- profile['exclusiveFunctionTrie'].cast<int>());
- tries['inclusiveFunctionTrie'] = new Uint32List.fromList(
- profile['inclusiveFunctionTrie'].cast<int>());
- } finally {
- progress.close();
}
- }());
+ // Process function table.
+ tableIndex = 0;
+ for (var profileFunction in profile[_kFunctions]) {
+ if (needToUpdate()) {
+ await signal(count * 100 / length);
+ }
+ ServiceFunction function = profileFunction[_kFunction];
+ assert(function != null);
+ functions.add(ProfileFunction.fromMap(
+ tableIndex, this, function, profileFunction));
+ ++tableIndex;
+ }
+ if (profile.containsKey(_kCodes)) {
+ _buildCodeTagMapping();
+ }
+
+ _buildFunctionTagMapping();
+
+ samples.addAll(profile[_kSamples]);
+ } finally {
+ progress?.close();
+ }
+ }
+
+ Stream<double> loadProgress(ServiceObjectOwner owner, ServiceMap profile) {
+ Logger.root.info('sampling counters ${profile['_counters']}');
+
+ var progress = StreamController<double>.broadcast();
+
+ _loadCommon(owner, profile, progress);
return progress.stream;
}
- // Data shared across calls to _read*TrieNode.
- int _dataCursor = 0;
+ // Helpers for reading optional flags from a sample.
+ static bool _isNativeEntryTag(Map sample) =>
+ sample.containsKey('nativeEntryTag');
+ static bool _isRuntimeEntryTag(Map sample) =>
+ sample.containsKey('runtimeEntryTag');
+ static bool _isTruncated(Map sample) => sample.containsKey('truncated');
+ static bool _isNativeAllocationSample(Map sample) =>
+ sample.containsKey('_nativeAllocationSizeBytes');
- // The code trie is serialized as a list of integers. Each node
- // is recreated by consuming some portion of the list. The format is as
- // follows:
- // [0] index into codeTable of code object.
- // [1] tick count (number of times this stack frame occured).
- // [2] child node count
- // Reading the trie is done by recursively reading the tree depth-first
- // pre-order.
- CodeCallTree _loadCodeTree(bool inclusive, List<int> data) {
- if (data == null) {
- return null;
+ int _getProfileFunctionTagIndex(String tag) {
+ if (_functionTagMapping.containsKey(tag)) {
+ return _functionTagMapping[tag];
}
- if (data.length < 3) {
- // Not enough for root node.
- return null;
- }
- // Read the tree, returns the root node.
- var root = _readCodeTrie(data);
- return new CodeCallTree(inclusive, root);
+ throw ArgumentError('$tag is not a valid tag!');
}
- CodeCallTreeNode _readCodeTrieNode(List<int> data) {
- // Lookup code object.
- var codeIndex = data[_dataCursor++];
- var code = codes[codeIndex];
- // Node tick counter.
- var count = data[_dataCursor++];
- // Child node count.
- var children = data[_dataCursor++];
- // Inclusive native allocations.
- var inclusiveNativeAllocations = data[_dataCursor++];
- // Exclusive native allocations.
- var exclusiveNativeAllocations = data[_dataCursor++];
- // Create node.
- var node = new CodeCallTreeNode(
- code, count, inclusiveNativeAllocations, exclusiveNativeAllocations);
- node.children.length = children;
- return node;
+ int _getProfileCodeTagIndex(String tag) {
+ if (_codeTagMapping.containsKey(tag)) {
+ return _codeTagMapping[tag];
+ }
+ throw ArgumentError('$tag is not a valid tag!');
}
- CodeCallTreeNode _readCodeTrie(List<int> data) {
- final nodeStack = new List<CodeCallTreeNode>();
- final childIndexStack = new List<int>();
+ void _buildFunctionTagMapping() {
+ for (int i = 0; i < functions.length; ++i) {
+ final function = functions[i].function;
+ if (function.kind == M.FunctionKind.tag) {
+ _functionTagMapping[function.name] = i;
+ }
+ }
+ }
- _dataCursor = 0;
- // Read root.
- var root = _readCodeTrieNode(data);
+ void _buildCodeTagMapping() {
+ for (int i = 0; i < codes.length; ++i) {
+ final code = codes[i].code;
+ if (code.kind == M.CodeKind.tag) {
+ _codeTagMapping[code.name] = i;
+ }
+ }
+ }
- // Push root onto stack.
- if (root.children.length > 0) {
- nodeStack.add(root);
- childIndexStack.add(0);
+ void _clearProfileFunctionTagTicks() =>
+ _functionTagMapping.forEach((String name, int tableIndex) {
+ // Truncated tag is ticked in the VM, so don't clear it.
+ if (name != kTruncatedTag) {
+ functions[tableIndex].clearTicks();
+ }
+ });
+
+ void _clearProfileCodeTagTicks() =>
+ _codeTagMapping.forEach((String name, int tableIndex) {
+ // Truncated tag is ticked in the VM, so don't clear it.
+ if (name != kTruncatedTag) {
+ codes[tableIndex].clearTicks();
+ }
+ });
+
+ NodeT _appendUserTag<NodeT extends CallTreeNode>(
+ String userTag, NodeT current, Map sample) {
+ bool isCode = (current is CodeCallTreeNode);
+ try {
+ final tableIndex = isCode
+ ? _getProfileCodeTagIndex(userTag)
+ : _getProfileFunctionTagIndex(userTag);
+ current = current.getChild(tableIndex);
+ current.tick(sample);
+ } catch (_) {/* invalid tag */} finally {
+ return current;
+ }
+ }
+
+ NodeT _appendTruncatedTag<NodeT extends CallTreeNode>(
+ NodeT current, Map sample) {
+ final isCode = (current is CodeCallTreeNode);
+ try {
+ final tableIndex = isCode
+ ? _getProfileCodeTagIndex(kTruncatedTag)
+ : _getProfileFunctionTagIndex(kTruncatedTag);
+ current = current.getChild(tableIndex);
+ current.tick(sample);
+ // We don't need to tick the tag itself since this is done in the VM for
+ // the truncated tag, unlike other VM and user tags.
+ } catch (_) {/* invalid tag */} finally {
+ return current;
+ }
+ }
+
+ FunctionCallTreeNode _getFunctionTagAndTick(
+ String tag, FunctionCallTreeNode current, Map sample) {
+ try {
+ final tableIndex = _getProfileFunctionTagIndex(tag);
+ current = current.getChild(tableIndex);
+ current.tick(sample);
+ } catch (_) {/* invalid tag */} finally {
+ return current;
+ }
+ }
+
+ CodeCallTreeNode _getCodeTagAndTick(
+ String tag, CodeCallTreeNode current, Map sample) {
+ try {
+ final tableIndex = _getProfileCodeTagIndex(tag);
+ current = current.getChild(tableIndex);
+ current.tick(sample);
+ } catch (_) {/* invalid tag */} finally {
+ return current;
+ }
+ }
+
+ NodeT _getTagAndTick<NodeT extends CallTreeNode>(
+ String tag, NodeT current, Map sample) {
+ if (current is FunctionCallTreeNode) {
+ return _getFunctionTagAndTick(tag, current, sample) as NodeT;
+ } else if (current is CodeCallTreeNode) {
+ return _getCodeTagAndTick(tag, current, sample) as NodeT;
+ }
+ throw ArgumentError('Unexpected tree type: $NodeT');
+ }
+
+ NodeT _appendVMTag<NodeT extends CallTreeNode>(
+ String vmTag, NodeT current, Map sample) {
+ if (_isNativeEntryTag(sample)) {
+ return _getTagAndTick(kNativeTag, current, sample);
+ } else if (_isRuntimeEntryTag(sample)) {
+ return _getTagAndTick(kRuntimeTag, current, sample);
+ } else {
+ return _getTagAndTick(vmTag, current, sample);
+ }
+ }
+
+ NodeT _appendSpecificNativeRuntimeEntryVMTag<NodeT extends CallTreeNode>(
+ NodeT current, Map sample) {
+ // Only Native and Runtime entries have a second VM tag.
+ if (!_isNativeEntryTag(sample) && !_isRuntimeEntryTag(sample)) {
+ return current;
+ }
+ final vmTag = sample[_kVmTag];
+ return _getTagAndTick(vmTag, current, sample);
+ }
+
+ NodeT _appendVMTags<NodeT extends CallTreeNode>(
+ String vmTag, NodeT current, Map sample) {
+ current = _appendVMTag(vmTag, current, sample);
+ current = _appendSpecificNativeRuntimeEntryVMTag(current, sample);
+ return current;
+ }
+
+ void _tickTags(String vmTag, String userTag, bool tickCode) {
+ if (tickCode) {
+ final vmTagIndex = _getProfileCodeTagIndex(vmTag);
+ codes[vmTagIndex].tickTag();
+
+ final userTagIndex = _getProfileCodeTagIndex(userTag);
+ codes[userTagIndex].tickTag();
+ } else {
+ final vmTagIndex = _getProfileFunctionTagIndex(vmTag);
+ functions[vmTagIndex].tickTag();
+
+ final userTagIndex = _getProfileFunctionTagIndex(userTag);
+ functions[userTagIndex].tickTag();
+ }
+ }
+
+ NodeT _appendTags<NodeT extends CallTreeNode>(
+ String vmTag, String userTag, NodeT current, Map sample) {
+ final tickCode = (current is M.CodeCallTreeNode);
+ _tickTags(vmTag, userTag, tickCode);
+ if (tagOrder == M.SampleProfileTag.none) {
+ return current;
+ }
+ // User first.
+ if (tagOrder == M.SampleProfileTag.userVM ||
+ tagOrder == M.SampleProfileTag.userOnly) {
+ current = _appendUserTag(userTag, current, sample);
+ // Only user.
+ if (tagOrder == M.SampleProfileTag.userOnly) {
+ return current;
+ }
+ return _appendVMTags(vmTag, current, sample);
}
- while (nodeStack.length > 0) {
- var lastIndex = nodeStack.length - 1;
- // Pop parent from stack.
- var parent = nodeStack[lastIndex];
- var childIndex = childIndexStack[lastIndex];
+ // VM first.
+ current = _appendVMTags(vmTag, current, sample);
+ // Only VM.
+ if (tagOrder == M.SampleProfileTag.vmOnly) {
+ return current;
+ }
+ return _appendUserTag(userTag, current, sample);
+ }
- // Read child node.
- assert(childIndex < parent.children.length);
- var node = _readCodeTrieNode(data);
- parent.children[childIndex++] = node;
+ NodeT _processFrame<NodeT extends CallTreeNode>(NodeT parent, int sampleIndex,
+ Map sample, List<int> stack, int frameIndex, bool inclusive) {
+ final child = parent.getChild(stack[frameIndex]);
+ child.tick(sample, exclusive: (frameIndex == 0));
+ return child;
+ }
- // If parent still has children, update child index.
- if (childIndex < parent.children.length) {
- childIndexStack[lastIndex] = childIndex;
+ FunctionCallTreeNode buildFunctionTrie(bool inclusive) {
+ final root = FunctionCallTreeNode.fromIndex(
+ this, _getProfileFunctionTagIndex(kRootTag));
+
+ for (int sampleIndex = 0; sampleIndex < samples.length; ++sampleIndex) {
+ final sample = samples[sampleIndex];
+ FunctionCallTreeNode current = root;
+ // Tick the root for each sample as we always visit the root node.
+ root.tick(sample);
+
+ // VM + User tags.
+ final vmTag = sample[_kVmTag];
+ final userTag = sample[_kUserTag];
+ final stack = sample[_kStack].cast<int>();
+ current = _appendTags(vmTag, userTag, current, sample);
+
+ if (inclusive) {
+ if (_isTruncated(sample)) {
+ current = _appendTruncatedTag(current, sample);
+ }
+ for (int frameIndex = stack.length - 1; frameIndex >= 0; --frameIndex) {
+ current = _processFrame(
+ current, sampleIndex, sample, stack, frameIndex, true);
+ }
+
+ // Used by the timeline to find the root of each sample.
+ sample[kTimelineFunctionTrie] = current;
} else {
- // Finished processing parent node.
- nodeStack.removeLast();
- childIndexStack.removeLast();
- }
+ for (int frameIndex = 0; frameIndex < stack.length; ++frameIndex) {
+ current = _processFrame(
+ current, sampleIndex, sample, stack, frameIndex, false);
+ }
- // If node has children, push onto stack.
- if (node.children.length > 0) {
- nodeStack.add(node);
- childIndexStack.add(0);
+ if (_isTruncated(sample)) {
+ current = _appendTruncatedTag(current, sample);
+ }
}
}
-
return root;
}
- FunctionCallTree _loadFunctionTree(bool inclusive, List<int> data) {
- if (data == null) {
- return null;
- }
- if (data.length < 3) {
- // Not enough integers for 1 node.
- return null;
- }
- // Read the tree, returns the root node.
- var root = _readFunctionTrie(data);
- return new FunctionCallTree(inclusive, root);
- }
+ CodeCallTreeNode buildCodeTrie(bool inclusive) {
+ final root =
+ CodeCallTreeNode.fromIndex(this, _getProfileCodeTagIndex(kRootTag));
- FunctionCallTreeNode _readFunctionTrieNode(List<int> data) {
- // Read index into function table.
- var index = data[_dataCursor++];
- // Lookup function object.
- var function = functions[index];
- // Counter.
- var count = data[_dataCursor++];
- // Inclusive native allocations.
- var inclusiveNativeAllocations = data[_dataCursor++];
- // Exclusive native allocations.
- var exclusiveNativeAllocations = data[_dataCursor++];
- // Create node.
- var node = new FunctionCallTreeNode(function, count,
- inclusiveNativeAllocations, exclusiveNativeAllocations);
- // Number of code index / count pairs.
- var codeCount = data[_dataCursor++];
- node.codes.length = codeCount;
- var totalCodeTicks = 0;
- for (var i = 0; i < codeCount; i++) {
- var codeIndex = data[_dataCursor++];
- var code = codes[codeIndex];
- assert(code != null);
- var codeTicks = data[_dataCursor++];
- totalCodeTicks += codeTicks;
- var nodeCode = new FunctionCallTreeNodeCode(code, codeTicks);
- node.codes[i] = nodeCode;
- }
- node.setCodeAttributes();
- node._totalCodeTicks = totalCodeTicks;
- // Number of children.
- var childCount = data[_dataCursor++];
- node.children.length = childCount;
- return node;
- }
+ for (int sampleIndex = 0; sampleIndex < samples.length; ++sampleIndex) {
+ final sample = samples[sampleIndex];
- FunctionCallTreeNode _readFunctionTrie(List<int> data) {
- final nodeStack = new List<FunctionCallTreeNode>();
- final childIndexStack = new List<int>();
+ CodeCallTreeNode current = root;
+ // Tick the root for each sample as we always visit the root node.
+ root.tick(sample);
- _dataCursor = 0;
+ // VM + User tags.
+ final vmTag = sample[_kVmTag];
+ final userTag = sample[_kUserTag];
+ final stack = sample[_kCodeStack].cast<int>();
+ current = _appendTags(vmTag, userTag, current, sample);
- // Read root.
- var root = _readFunctionTrieNode(data);
-
- // Push root onto stack.
- if (root.children.length > 0) {
- nodeStack.add(root);
- childIndexStack.add(0);
- }
-
- while (nodeStack.length > 0) {
- var lastIndex = nodeStack.length - 1;
- // Pop parent from stack.
- var parent = nodeStack[lastIndex];
- var childIndex = childIndexStack[lastIndex];
-
- // Read child node.
- assert(childIndex < parent.children.length);
- var node = _readFunctionTrieNode(data);
- parent.children[childIndex++] = node;
-
- // If parent still has children, update child index.
- if (childIndex < parent.children.length) {
- childIndexStack[lastIndex] = childIndex;
+ if (inclusive) {
+ if (_isTruncated(sample)) {
+ current = _appendTruncatedTag(current, sample);
+ }
+ for (int frameIndex = stack.length - 1; frameIndex >= 0; --frameIndex) {
+ current = _processFrame(
+ current, sampleIndex, sample, stack, frameIndex, true);
+ }
} else {
- // Finished processing parent node.
- nodeStack.removeLast();
- childIndexStack.removeLast();
- }
+ for (int frameIndex = 0; frameIndex < stack.length; ++frameIndex) {
+ current = _processFrame(
+ current, sampleIndex, sample, stack, frameIndex, false);
+ }
- // If node has children, push onto stack.
- if (node.children.length > 0) {
- nodeStack.add(node);
- childIndexStack.add(0);
+ if (_isTruncated(sample)) {
+ current = _appendTruncatedTag(current, sample);
+ }
}
}
-
return root;
}
+ FunctionCallTree _loadFunctionTree(bool inclusive) {
+ // Since we're only ticking tag functions when building the trie, we need
+ // to clean up ticks from previous tree builds.
+ _clearProfileFunctionTagTicks();
+
+ // Read the tree, returns the root node.
+ final root = buildFunctionTrie(inclusive);
+ root.sortChildren();
+ return FunctionCallTree(inclusive, root);
+ }
+
+ CodeCallTree _loadCodeTree(bool inclusive) {
+ // Since we're only ticking tag code when building the trie, we need
+ // to clean up ticks from previous tree builds.
+ _clearProfileCodeTagTicks();
+
+ // Read the tree, returns the root node.
+ final root = buildCodeTrie(inclusive);
+ root.sortChildren();
+ return CodeCallTree(inclusive, root);
+ }
+
int approximateMillisecondsForCount(count) {
return (count * samplePeriod) ~/ Duration.microsecondsPerMillisecond;
}
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index 866aed5..afbb7cc 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -220,6 +220,7 @@
obj = new Frame._empty(owner);
break;
case 'Function':
+ case 'NativeFunction':
obj = new ServiceFunction._empty(owner);
break;
case 'Gauge':
@@ -693,7 +694,7 @@
updateFromServiceMap({'name': 'vm', 'type': '@VM'});
}
- void postServiceEvent(String streamId, Map response, ByteData data) {
+ void postServiceEvent(String streamId, Map response, Uint8List data) {
var map = response;
assert(!map.containsKey('_data'));
if (data != null) {
@@ -1329,10 +1330,6 @@
}
}
- Future collectAllGarbage() {
- return invokeRpc('_collectAllGarbage', {});
- }
-
/// Fetches and builds the class hierarchy for this isolate. Returns the
/// Object class object.
Future<Class> getClassHierarchy() async {
@@ -1461,7 +1458,7 @@
DartError error;
StreamController _snapshotFetch;
- List<ByteData> _chunksInProgress;
+ List<Uint8List> _chunksInProgress;
List<Thread> get threads => _threads;
final List<Thread> _threads = new List<Thread>();
@@ -1475,6 +1472,20 @@
int get numScopedHandles => _numScopedHandles;
int _numScopedHandles;
+ static Uint8List _flatten(List<Uint8List> chunks) {
+ var length = 0;
+ for (var chunk in chunks) {
+ length += chunk.length;
+ }
+ var flattened = new Uint8List(length);
+ var position = 0;
+ for (var chunk in chunks) {
+ flattened.setRange(position, position + chunk.length, chunk);
+ position += chunk.length;
+ }
+ return flattened;
+ }
+
void _loadHeapSnapshot(ServiceEvent event) {
if (_snapshotFetch == null || _snapshotFetch.isClosed) {
// No outstanding snapshot request. Presumably another client asked for a
@@ -1494,11 +1505,11 @@
return;
}
- var loadedChunks = _chunksInProgress;
- _chunksInProgress = null;
+ var flattened = _flatten(_chunksInProgress);
+ _chunksInProgress = null; // Make chunks GC'able.
if (_snapshotFetch != null) {
- _snapshotFetch.add(loadedChunks);
+ _snapshotFetch.add(flattened);
_snapshotFetch.close();
}
}
@@ -2091,7 +2102,7 @@
DartError reloadError;
bool atAsyncSuspension;
Instance inspectee;
- ByteData data;
+ Uint8List data;
int count;
String reason;
String exceptions;
@@ -2558,8 +2569,10 @@
});
}
- Future<ServiceObject> getAllocationSamples([String tags = 'None']) {
- var params = {'tags': tags, 'classId': id};
+ Future<ServiceObject> getAllocationSamples() {
+ var params = {
+ 'classId': id,
+ };
return isolate.invokeRpc('_getAllocationSamples', params);
}
diff --git a/runtime/observatory/observatory_sources.gni b/runtime/observatory/observatory_sources.gni
index c69b433..1cd8af3 100644
--- a/runtime/observatory/observatory_sources.gni
+++ b/runtime/observatory/observatory_sources.gni
@@ -134,6 +134,7 @@
"lib/src/elements/subtypetestcache_view.dart",
"lib/src/elements/timeline/dashboard.dart",
"lib/src/elements/timeline_page.dart",
+ "lib/src/elements/tree_map.dart",
"lib/src/elements/type_arguments_ref.dart",
"lib/src/elements/unknown_ref.dart",
"lib/src/elements/unlinkedcall_ref.dart",
diff --git a/runtime/observatory/pubspec.yaml b/runtime/observatory/pubspec.yaml
index 2059c3d..8c4c378 100644
--- a/runtime/observatory/pubspec.yaml
+++ b/runtime/observatory/pubspec.yaml
@@ -1,3 +1,3 @@
name: observatory
environment:
- sdk: '>=2.2.0 <3.0.0'
+ sdk: '>=2.2.2 <3.0.0'
\ No newline at end of file
diff --git a/runtime/observatory/tests/service/collect_all_garbage_test.dart b/runtime/observatory/tests/service/collect_all_garbage_test.dart
deleted file mode 100644
index 8db2921..0000000
--- a/runtime/observatory/tests/service/collect_all_garbage_test.dart
+++ /dev/null
@@ -1,17 +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 'package:observatory/service_io.dart';
-import 'package:unittest/unittest.dart';
-
-import 'test_helper.dart';
-
-var tests = <IsolateTest>[
- (Isolate isolate) async {
- var result = await isolate.invokeRpcNoUpgrade('_collectAllGarbage', {});
- expect(result['type'], equals('Success'));
- },
-];
-
-main(args) async => runIsolateTests(args, tests);
diff --git a/runtime/observatory/tests/service/echo_test.dart b/runtime/observatory/tests/service/echo_test.dart
index fdd93cf..eda2f81 100644
--- a/runtime/observatory/tests/service/echo_test.dart
+++ b/runtime/observatory/tests/service/echo_test.dart
@@ -25,9 +25,9 @@
subscription = stream.listen((ServiceEvent event) {
assert(event.kind == '_Echo');
expect(event.data.lengthInBytes, equals(3));
- expect(event.data.getUint8(0), equals(0));
- expect(event.data.getUint8(1), equals(128));
- expect(event.data.getUint8(2), equals(255));
+ expect(event.data[0], equals(0));
+ expect(event.data[1], equals(128));
+ expect(event.data[2], equals(255));
subscription.cancel();
completer.complete();
});
diff --git a/runtime/observatory/tests/service/get_cpu_profile_timeline_rpc_test.dart b/runtime/observatory/tests/service/get_cpu_profile_timeline_rpc_test.dart
index 537a69d..a0d7f9e 100644
--- a/runtime/observatory/tests/service/get_cpu_profile_timeline_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_cpu_profile_timeline_rpc_test.dart
@@ -2,6 +2,7 @@
// 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:observatory/src/repositories/timeline_base.dart';
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
@@ -19,13 +20,8 @@
print("Testee did something.");
}
-Future checkTimeline(Isolate isolate, Map params) async {
- print(params);
- var result =
- await isolate.invokeRpcNoUpgrade('_getCpuProfileTimeline', params);
- print(result);
- expect(result['type'], equals('_CpuProfileTimeline'));
-
+Future checkTimeline(VM vm) async {
+ var result = await TimelineRepositoryBase().getCpuProfileTimeline(vm);
var isString = new isInstanceOf<String>();
var isInt = new isInstanceOf<int>();
Map frames = result['stackFrames'];
@@ -53,24 +49,14 @@
}
}
-var tests = <IsolateTest>[
- (Isolate i) => checkTimeline(i, {'tags': 'VMUser'}),
- (Isolate i) => checkTimeline(i, {'tags': 'VMUser', 'code': true}),
- (Isolate i) => checkTimeline(i, {'tags': 'VMUser', 'code': false}),
- (Isolate i) => checkTimeline(i, {'tags': 'VMOnly'}),
- (Isolate i) => checkTimeline(i, {'tags': 'VMOnly', 'code': true}),
- (Isolate i) => checkTimeline(i, {'tags': 'VMOnly', 'code': false}),
- (Isolate i) => checkTimeline(i, {'tags': 'None'}),
- (Isolate i) => checkTimeline(i, {'tags': 'None', 'code': true}),
- (Isolate i) => checkTimeline(i, {'tags': 'None', 'code': false}),
+var tests = <VMTest>[
+ (VM vm) => checkTimeline(vm),
];
var vmArgs = [
'--profiler=true',
'--profile-vm=false', // So this also works with DBC and KBC.
- '--timeline_recorder=ring',
- '--timeline_streams=Profiler'
];
main(args) async =>
- runIsolateTests(args, tests, testeeBefore: testeeDo, extraArgs: vmArgs);
+ runVMTests(args, tests, testeeBefore: testeeDo, extraArgs: vmArgs);
diff --git a/runtime/observatory/tests/service/get_cpu_samples_rpc_test.dart b/runtime/observatory/tests/service/get_cpu_samples_rpc_test.dart
new file mode 100644
index 0000000..aa55eb3
--- /dev/null
+++ b/runtime/observatory/tests/service/get_cpu_samples_rpc_test.dart
@@ -0,0 +1,62 @@
+// Copyright (c) 2019, 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:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+
+import 'test_helper.dart';
+
+fib(n) {
+ if (n < 0) return 0;
+ if (n == 0) return 1;
+ return fib(n - 1) + fib(n - 2);
+}
+
+testeeDo() {
+ print("Testee doing something.");
+ fib(30);
+ print("Testee did something.");
+}
+
+Future checkSamples(Isolate isolate) async {
+ final result =
+ await isolate.invokeRpcNoUpgrade('getCpuSamples', {'_code': true});
+ expect(result['type'], equals('CpuSamples'));
+
+ final isString = isInstanceOf<String>();
+ final isInt = isInstanceOf<int>();
+ final isList = isInstanceOf<List>();
+ final functions = result['functions'];
+ expect(functions.length, greaterThan(10),
+ reason: "Should have many functions");
+ final codes = result['_codes'];
+ expect(functions.length, greaterThan(10),
+ reason: "Should have many code objects");
+
+ final samples = result['samples'];
+ expect(samples.length, greaterThan(10), reason: "Should have many samples");
+ final sample = samples.first;
+ expect(sample['tid'], isInt);
+ expect(sample['timestamp'], isInt);
+ if (sample.containsKey('vmTag')) {
+ expect(sample['vmTag'], isString);
+ }
+ if (sample.containsKey('userTag')) {
+ expect(sample['userTag'], isString);
+ }
+ expect(sample['stack'], isList);
+ expect(sample['_codeStack'], isList);
+}
+
+var tests = <IsolateTest>[
+ (Isolate i) => checkSamples(i),
+];
+
+var vmArgs = [
+ '--profiler=true',
+ '--profile-vm=false', // So this also works with DBC and KBC.
+];
+
+main(args) async =>
+ runIsolateTests(args, tests, testeeBefore: testeeDo, extraArgs: vmArgs);
diff --git a/runtime/observatory/tests/service/get_native_allocation_samples_test.dart b/runtime/observatory/tests/service/get_native_allocation_samples_test.dart
index 97535e5..7ade11d 100644
--- a/runtime/observatory/tests/service/get_native_allocation_samples_test.dart
+++ b/runtime/observatory/tests/service/get_native_allocation_samples_test.dart
@@ -15,12 +15,12 @@
return;
}
-/* if (!(root is FunctionCallTreeNode)) {
+ if (!(root is FunctionCallTreeNode)) {
print('${root.profileCode.code.name}');
} else {
print('${root.profileFunction.function.name}');
}
-*/
+
int inclusiveAllocations = 0;
int exclusiveAllocations = 0;
@@ -57,7 +57,7 @@
// Verify inclusive tries.
(VM vm) async {
var response =
- await vm.invokeRpc('_getNativeAllocationSamples', {'tags': 'None'});
+ await vm.invokeRpc('_getNativeAllocationSamples', {'_code': true});
SampleProfile cpuProfile = new SampleProfile();
await cpuProfile.load(vm, response);
var codeTree = cpuProfile.loadCodeTree(M.ProfileTreeDirection.inclusive);
@@ -69,7 +69,7 @@
// Verify exclusive tries.
(VM vm) async {
var response =
- await vm.invokeRpc('_getNativeAllocationSamples', {'tags': 'None'});
+ await vm.invokeRpc('_getNativeAllocationSamples', {'_code': true});
SampleProfile cpuProfile = new SampleProfile();
await cpuProfile.load(vm, response);
var codeTreeExclusive =
diff --git a/runtime/observatory/tests/service/get_version_rpc_test.dart b/runtime/observatory/tests/service/get_version_rpc_test.dart
index 0a1fa50..f062d33 100644
--- a/runtime/observatory/tests/service/get_version_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_version_rpc_test.dart
@@ -12,7 +12,7 @@
var result = await vm.invokeRpcNoUpgrade('getVersion', {});
expect(result['type'], equals('Version'));
expect(result['major'], equals(3));
- expect(result['minor'], equals(26));
+ expect(result['minor'], equals(27));
expect(result['_privateMajor'], equals(0));
expect(result['_privateMinor'], equals(0));
},
diff --git a/runtime/observatory/tests/service/get_vm_timeline_rpc_test.dart b/runtime/observatory/tests/service/get_vm_timeline_rpc_test.dart
index f683ab7..637790f 100644
--- a/runtime/observatory/tests/service/get_vm_timeline_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_vm_timeline_rpc_test.dart
@@ -14,9 +14,10 @@
Timeline.instantSync('ISYNC', arguments: {'fruit': 'banana'});
Timeline.finishSync();
TimelineTask task = new TimelineTask();
- task.start('TASK1');
- task.instant('ITASK');
- task.finish();
+ task.start('TASK1', arguments: {'task1-start-key': 'task1-start-value'});
+ task.instant('ITASK',
+ arguments: {'task1-instant-key': 'task1-instant-value'});
+ task.finish(arguments: {'task1-finish-key': 'task1-finish-value'});
Flow flow = Flow.begin(id: 123);
Timeline.startSync('peach', flow: flow);
@@ -31,10 +32,23 @@
return events.where((event) => event['cat'] == 'Dart').toList();
}
-bool eventsContains(List events, String phase, String name) {
+bool mapContains(Map map, Map submap) {
+ for (var key in submap.keys) {
+ if (map[key] != submap[key]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool eventsContains(List events, String phase, String name, [Map arguments]) {
for (Map event in events) {
if ((event['ph'] == phase) && (event['name'] == name)) {
- return true;
+ if (arguments == null) {
+ return true;
+ } else if (mapContains(event['args'], arguments)) {
+ return true;
+ }
}
}
return false;
@@ -108,11 +122,21 @@
expect(dartEvents.length, equals(11));
allEventsHaveIsolateNumber(dartEvents);
allEventsHaveIsolateNumber(result['traceEvents']);
- expect(eventsContains(dartEvents, 'i', 'ISYNC'), isTrue);
+ expect(
+ eventsContains(dartEvents, 'i', 'ISYNC', {'fruit': 'banana'}), isTrue);
expect(eventsContains(dartEvents, 'X', 'apple'), isTrue);
- expect(eventsContains(dartEvents, 'b', 'TASK1'), isTrue);
- expect(eventsContains(dartEvents, 'e', 'TASK1'), isTrue);
- expect(eventsContains(dartEvents, 'n', 'ITASK'), isTrue);
+ expect(
+ eventsContains(
+ dartEvents, 'b', 'TASK1', {'task1-start-key': 'task1-start-value'}),
+ isTrue);
+ expect(
+ eventsContains(dartEvents, 'e', 'TASK1',
+ {'task1-finish-key': 'task1-finish-value'}),
+ isTrue);
+ expect(
+ eventsContains(dartEvents, 'n', 'ITASK',
+ {'task1-instant-key': 'task1-instant-value'}),
+ isTrue);
expect(eventsContains(dartEvents, 'q', 'ITASK'), isFalse);
expect(eventsContains(dartEvents, 'X', 'peach'), isTrue);
expect(eventsContains(dartEvents, 'X', 'watermelon'), isTrue);
diff --git a/runtime/observatory/tests/service/regress_28443_test.dart b/runtime/observatory/tests/service/regress_28443_test.dart
index 3590e51..bd585b9 100644
--- a/runtime/observatory/tests/service/regress_28443_test.dart
+++ b/runtime/observatory/tests/service/regress_28443_test.dart
@@ -38,28 +38,6 @@
}
}
-Future stepThroughProgram(Isolate isolate) async {
- Completer completer = new Completer();
- int pauseEventsSeen = 0;
-
- await subscribeToStream(isolate.vm, VM.kDebugStream,
- (ServiceEvent event) async {
- if (event.kind == ServiceEvent.kPauseBreakpoint) {
- // We are paused: Step further.
- pauseEventsSeen++;
- isolate.stepInto();
- } else if (event.kind == ServiceEvent.kPauseExit) {
- // We are at the exit: The test is done.
- expect(pauseEventsSeen > 20, true,
- reason: "Saw only $pauseEventsSeen pause events.");
- await cancelStreamSubscription(VM.kDebugStream);
- completer.complete();
- }
- });
- isolate.resume();
- return completer.future;
-}
-
var tests = <IsolateTest>[
hasPausedAtStart,
markDartColonLibrariesDebuggable,
diff --git a/runtime/observatory/tests/service/service.status b/runtime/observatory/tests/service/service.status
index 7550118..0cdbc33 100644
--- a/runtime/observatory/tests/service/service.status
+++ b/runtime/observatory/tests/service/service.status
@@ -47,12 +47,6 @@
[ $mode == debug && ($arch == simarm || $arch == simarm64) ]
*: SkipSlow
-[ !$preview_dart_2 && ($runtime == dart_precompiled || $runtime == vm) ]
-*: SkipByDesign # Deprecating all Dart1 modes of execution
-
-[ !$strong && ($compiler == dartk || $compiler == dartkp) ]
-*: Skip
-
# These tests are slow on simulators.
[ $arch == simarm || $arch == simarm64 ]
*: Pass, Slow
diff --git a/runtime/observatory/tests/service/service_kernel.status b/runtime/observatory/tests/service/service_kernel.status
index 8ac0c0f..3c70570 100644
--- a/runtime/observatory/tests/service/service_kernel.status
+++ b/runtime/observatory/tests/service/service_kernel.status
@@ -37,22 +37,6 @@
simple_reload_test: RuntimeError, Timeout # Issue 35506
unused_changes_in_last_reload_test: RuntimeError
-# Kernel works slightly different. There are kernel specific versions.
-# These are the non-kernel specific versions so skip tests and allow errors.
-[ $compiler == dartk ]
-add_breakpoint_rpc_test: SkipByDesign # non-kernel specific version of add_breakpoint_rpc_kernel_test.
-bad_reload_test: RuntimeError # Issue 34025
-coverage_optimized_function_test: Pass, Slow
-evaluate_activation_in_method_class_test: RuntimeError # Issue 35505
-evaluate_activation_test/instance: RuntimeError # http://dartbug.com/20047
-evaluate_activation_test/scope: RuntimeError # http://dartbug.com/20047
-get_source_report_test: RuntimeError # Should pass again when constant evaluation is relanded, see http://dartbug.com/36600
-pause_on_unhandled_async_exceptions2_test: Pass, Slow
-unused_changes_in_last_reload_test: RuntimeError
-
-[ $compiler == dartkb ]
-*: Skip # Debugging capabilities are not yet supported in bytecode modes.
-
[ $compiler == dartkp ]
*: SkipByDesign # Non-kernel also skips precompiled mode.
@@ -81,12 +65,15 @@
[ $arch == simdbc64 && $compiler == dartk && $mode == debug ]
eval_test: Pass, Slow
-[ $compiler == dartk && $mode == debug ]
+[ $compiler == dartkb && ($builder_tag == bytecode_interpreter || $builder_tag == bytecode_mixed) ]
+*: Skip # There are still timeouts in the interpreter and mixed modes which cause infra timeouts.
+
+[ $mode == debug && ($compiler == dartk || $compiler == dartkb) ]
isolate_lifecycle_test: Skip # Flaky.
pause_idle_isolate_test: Skip # Flaky
rewind_optimized_out_test: Pass, Slow
-[ $compiler == dartk && $system == windows ]
+[ $system == windows && ($compiler == dartk || $compiler == dartkb) ]
add_breakpoint_rpc_kernel_test: Skip # Timeout
break_on_default_constructor_test: Skip # Issues 32137 and 32138.
breakpoint_in_parts_class_test: Skip # Timeout
@@ -137,7 +124,7 @@
step_through_switch_test: Skip # Times out. Issue 32137.
step_through_switch_with_continue_test: Skip # Times out. Issue 32137.
-[ $compiler == dartk && ($arch == simarm || $arch == simarm64 || $arch == simdbc64) ]
+[ ($arch == simarm || $arch == simarm64 || $arch == simdbc64) && ($compiler == dartk || $compiler == dartkb) ]
add_breakpoint_rpc_kernel_test: RuntimeError # Issue #34736
async_generator_breakpoint_test: SkipByDesign # No incremental compiler available.
bad_reload_test: Skip # Times out on sim architectures, also RuntimeError.
@@ -172,3 +159,16 @@
simple_reload_test: RuntimeError, Timeout
unused_changes_in_last_reload_test: Skip # Times out on sim architectures.
valid_source_locations_test: Pass, Slow, Timeout # Issue 34736
+
+# Kernel works slightly different. There are kernel specific versions.
+# These are the non-kernel specific versions so skip tests and allow errors.
+[ $compiler == dartk || $compiler == dartkb ]
+add_breakpoint_rpc_test: SkipByDesign # non-kernel specific version of add_breakpoint_rpc_kernel_test.
+bad_reload_test: RuntimeError # Issue 34025
+coverage_optimized_function_test: Pass, Slow
+evaluate_activation_in_method_class_test: RuntimeError # Issue 35505
+evaluate_activation_test/instance: RuntimeError # http://dartbug.com/20047
+evaluate_activation_test/scope: RuntimeError # http://dartbug.com/20047
+get_source_report_test: RuntimeError # Should pass again when constant evaluation is relanded, see http://dartbug.com/36600
+pause_on_unhandled_async_exceptions2_test: Pass, Slow
+unused_changes_in_last_reload_test: RuntimeError
diff --git a/runtime/observatory/tests/service/write_cpu_profile_timeline_rpc_test.dart b/runtime/observatory/tests/service/write_cpu_profile_timeline_rpc_test.dart
deleted file mode 100644
index fad0eda..0000000
--- a/runtime/observatory/tests/service/write_cpu_profile_timeline_rpc_test.dart
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (c) 2019, 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:observatory/service_io.dart';
-import 'package:unittest/unittest.dart';
-
-import 'test_helper.dart';
-
-fib(n) {
- if (n < 0) return 0;
- if (n == 0) return 1;
- return fib(n - 1) + fib(n - 2);
-}
-
-testeeDo() {
- print("Testee doing something.");
- fib(30);
- print("Testee did something.");
-}
-
-var tests = <IsolateTest>[
- (Isolate isolate) async {
- var params = {'tags': 'None'};
- var result =
- await isolate.invokeRpcNoUpgrade('_writeCpuProfileTimeline', params);
- print(result);
- expect(result['type'], equals('Success'));
-
- result = await isolate.vm.invokeRpcNoUpgrade('getVMTimeline', {});
- expect(result['type'], equals('Timeline'));
- expect(result['traceEvents'], new isInstanceOf<List>());
-
- var events = result['traceEvents'];
- print(events);
- var profilerSampleEvents = result['traceEvents'].where((event) {
- return event['name'] == "Dart CPU sample";
- }).toList();
-
- var isString = new isInstanceOf<String>();
- var isInt = new isInstanceOf<int>();
-
- expect(profilerSampleEvents.length, greaterThan(10),
- reason: "Should have many samples");
- for (Map event in profilerSampleEvents) {
- print(event);
-
- // Sadly this is an "Instant" event because there is no way to add a
- // proper "Sample" event in Fuchsia's tracing.
- expect(event['ph'], equals('i'));
-
- expect(event['pid'], isInt);
- expect(event['tid'], isInt);
- expect(event['ts'], isInt);
- expect(event['cat'], equals("Profiler"));
- expect(event['args']['backtrace'], isString);
- }
- },
-];
-
-var vmArgs = [
- '--profiler=true',
- '--profile-vm=false', // So this also works with DBC and KBC.
- '--timeline_recorder=ring',
- '--timeline_streams=Profiler'
-];
-
-main(args) async =>
- runIsolateTests(args, tests, testeeBefore: testeeDo, extraArgs: vmArgs);
diff --git a/runtime/observatory/web/timeline.js b/runtime/observatory/web/timeline.js
index 8ed70cb..56afbbbe 100644
--- a/runtime/observatory/web/timeline.js
+++ b/runtime/observatory/web/timeline.js
@@ -4,7 +4,6 @@
// See also timeline_message_handler.js.
-var traceObject;
var pendingRequests;
var loadingOverlay;
@@ -542,16 +541,6 @@
p.then(onModelLoaded.bind(undefined, model), onImportFail);
}
-function fetchUri(uri, onLoad, onError) {
- var xhr = new XMLHttpRequest();
- xhr.open('GET', uri, true);
- xhr.responseType = 'text';
- xhr.addEventListener('load', onLoad);
- xhr.addEventListener('error', onError);
- xhr.send();
- console.log('GET ' + uri);
-}
-
function showLoadingOverlay(msg) {
if (!loadingOverlay) {
loadingOverlay = new tr.ui.b.Overlay();
@@ -569,102 +558,9 @@
loadingOverlay = undefined;
}
-function gotReponse() {
- pendingRequests--;
- if (pendingRequests === 0) {
- console.log('Got all timeline parts');
- updateTimeline(traceObject);
- hideLoadingOverlay();
- }
-}
-
-function processTimelineResponse(response) {
- if (response.error) {
- // Maybe profiling is disabled.
- console.log('ERROR ' + response.error.message);
- } else {
- var result = response['result'];
- var newStackFrames = result['stackFrames']; // Map.
- var newTraceEvents = result['traceEvents']; // List.
-
- // Merge in timeline events.
- traceObject.traceEvents = traceObject.traceEvents.concat(newTraceEvents);
- for (var key in newStackFrames) {
- if (newStackFrames.hasOwnProperty(key)) {
- traceObject.stackFrames[key] = newStackFrames[key];
- }
- }
- }
-
- gotReponse();
-}
-
-function fetchTimelineOnLoad(event) {
- var xhr = event.target;
- var response = JSON.parse(xhr.responseText);
- processTimelineResponse(response);
-}
-
-function fetchTimelineOnError(event) {
- var xhr = event.target;
- console.log(xhr.statusText);
- gotReponse();
-}
-
-function fetchCPUProfile(vmAddress, isolateIds, timeOrigin, timeExtent) {
- showLoadingOverlay('Fetching CPU profile(s) from Dart VM');
- var parser = document.createElement('a');
- parser.href = vmAddress;
- pendingRequests += isolateIds.length;
- for (var i = 0; i < isolateIds.length; i++) {
- var isolateId = isolateIds[i];
- var requestUri = 'http://' +
- parser.hostname +
- ':' +
- parser.port +
- parser.pathname.replace(/\/ws$/, "") +
- '/_getCpuProfileTimeline?tags=None&isolateId=' +
- isolateId +
- '&timeOriginMicros=' + timeOrigin +
- '&timeExtentMicros=' + timeExtent;
- fetchUri(requestUri, fetchTimelineOnLoad, fetchTimelineOnError);
- }
-}
-
-function fetchTimeline(vmAddress, isolateIds, mode) {
- // Reset combined timeline.
- traceObject = {
- 'stackFrames': {},
- 'traceEvents': []
- };
- timelineMode = mode;
- pendingRequests = 1;
-
- showLoadingOverlay('Fetching timeline from Dart VM');
- var parser = document.createElement('a');
- parser.href = vmAddress;
- var requestUri = 'http://' +
- parser.hostname +
- ':' +
- parser.port +
- parser.pathname.replace(/\/ws$/, "") +
- '/getVMTimeline';
- fetchUri(requestUri, function(event) {
- // Grab the response.
- var xhr = event.target;
- var response = JSON.parse(xhr.responseText);
- // Extract the time origin and extent.
- var timeOrigin = response['result']['timeOriginMicros'];
- var timeExtent = response['result']['timeExtentMicros'];
- console.assert(Number.isInteger(timeOrigin), timeOrigin);
- console.assert(Number.isInteger(timeExtent), timeExtent);
- console.log(timeOrigin);
- console.log(timeExtent);
- // fetchCPUProfile.
- fetchCPUProfile(vmAddress, isolateIds, timeOrigin, timeExtent);
- // This must happen after 'fetchCPUProfile';
- processTimelineResponse(response, mode);
- }, fetchTimelineOnError);
+function populateTimeline(traceObject) {
+ updateTimeline(traceObject);
+ hideLoadingOverlay();
}
function saveTimeline() {
@@ -762,11 +658,9 @@
timeline_loaded = true;
console.log('DOMContentLoaded');
document.getElementById('trace-viewer').highlightVSync = true;
- if (timeline_vm_address != undefined) {
- console.log('Triggering delayed timeline refresh.');
- fetchTimeline(timeline_vm_address, timeline_isolates);
- timeline_vm_address = undefined;
- timeline_isolates = undefined;
+ if (traceObject != undefined) {
+ refreshTimeline();
+ traceObject = undefined;
}
});
diff --git a/runtime/observatory/web/timeline_message_handler.js b/runtime/observatory/web/timeline_message_handler.js
index c265cfa..2fa3e77 100644
--- a/runtime/observatory/web/timeline_message_handler.js
+++ b/runtime/observatory/web/timeline_message_handler.js
@@ -5,11 +5,7 @@
// This file is loaded before the about:tracing code is loaded so that we have
// an event listener registered early.
-// Used to delay the initial timeline load until the timeline has finished
-// loading.
-timeline_loaded = false;
-timeline_vm_address = undefined;
-timeline_isolates = undefined;
+var traceObject;
function registerForMessages() {
window.addEventListener("message", onMessage, false);
@@ -25,12 +21,11 @@
console.log('method: ' + method)
switch (method) {
case 'refresh':
- if (!timeline_loaded) {
- timeline_vm_address = params['vmAddress'];
- timeline_isolates = params['isolateIds'];
- console.log('Delaying timeline refresh until loaded.');
+ if (typeof populateTimeline != 'undefined') {
+ populateTimeline(params);
} else {
- fetchTimeline(params['vmAddress'], params['isolateIds']);
+ console.log('populateTimeline is not yet defined');
+ traceObject = params;
}
break;
case 'clear':
diff --git a/runtime/platform/floating_point.h b/runtime/platform/floating_point.h
index 0d29a70..24bcde6 100644
--- a/runtime/platform/floating_point.h
+++ b/runtime/platform/floating_point.h
@@ -5,6 +5,8 @@
#ifndef RUNTIME_PLATFORM_FLOATING_POINT_H_
#define RUNTIME_PLATFORM_FLOATING_POINT_H_
+#include <math.h>
+
inline double fmod_ieee(double x, double y) {
return fmod(x, y);
}
diff --git a/runtime/platform/utils.cc b/runtime/platform/utils.cc
index 7093b19..2cfa649 100644
--- a/runtime/platform/utils.cc
+++ b/runtime/platform/utils.cc
@@ -50,6 +50,68 @@
return r;
}
+// Implementation according to H.S.Warren's "Hacker's Delight"
+// (Addison Wesley, 2002) Chapter 10 and T.Grablund, P.L.Montogomery's
+// "Division by Invariant Integers Using Multiplication" (PLDI 1994).
+void Utils::CalculateMagicAndShiftForDivRem(int64_t divisor,
+ int64_t* magic,
+ int64_t* shift) {
+ ASSERT(divisor <= -2 || divisor >= 2);
+ /* The magic number M and shift S can be calculated in the following way:
+ * Let nc be the most positive value of numerator(n) such that nc = kd - 1,
+ * where divisor(d) >= 2.
+ * Let nc be the most negative value of numerator(n) such that nc = kd + 1,
+ * where divisor(d) <= -2.
+ * Thus nc can be calculated like:
+ * nc = exp + exp % d - 1, where d >= 2 and exp = 2^63.
+ * nc = -exp + (exp + 1) % d, where d >= 2 and exp = 2^63.
+ *
+ * So the shift p is the smallest p satisfying
+ * 2^p > nc * (d - 2^p % d), where d >= 2
+ * 2^p > nc * (d + 2^p % d), where d <= -2.
+ *
+ * The magic number M is calculated by
+ * M = (2^p + d - 2^p % d) / d, where d >= 2
+ * M = (2^p - d - 2^p % d) / d, where d <= -2.
+ */
+ int64_t p = 63;
+ const uint64_t exp = 1LL << 63;
+
+ // Initialize the computations.
+ uint64_t abs_d = (divisor >= 0) ? divisor : -divisor;
+ uint64_t sign_bit = static_cast<uint64_t>(divisor) >> 63;
+ uint64_t tmp = exp + sign_bit;
+ uint64_t abs_nc = tmp - 1 - (tmp % abs_d);
+ uint64_t quotient1 = exp / abs_nc;
+ uint64_t remainder1 = exp % abs_nc;
+ uint64_t quotient2 = exp / abs_d;
+ uint64_t remainder2 = exp % abs_d;
+
+ // To avoid handling both positive and negative divisor,
+ // "Hacker's Delight" introduces a method to handle these
+ // two cases together to avoid duplication.
+ uint64_t delta;
+ do {
+ p++;
+ quotient1 = 2 * quotient1;
+ remainder1 = 2 * remainder1;
+ if (remainder1 >= abs_nc) {
+ quotient1++;
+ remainder1 = remainder1 - abs_nc;
+ }
+ quotient2 = 2 * quotient2;
+ remainder2 = 2 * remainder2;
+ if (remainder2 >= abs_d) {
+ quotient2++;
+ remainder2 = remainder2 - abs_d;
+ }
+ delta = abs_d - remainder2;
+ } while (quotient1 < delta || (quotient1 == delta && remainder1 == 0));
+
+ *magic = (divisor > 0) ? (quotient2 + 1) : (-quotient2 - 1);
+ *shift = p - 64;
+}
+
uint32_t Utils::StringHash(const char* data, int length) {
// This implementation is based on the public domain MurmurHash
// version 2.0. It assumes that the underlying CPU can read from
diff --git a/runtime/platform/utils.h b/runtime/platform/utils.h
index 993ff26..7e7aabe 100644
--- a/runtime/platform/utils.h
+++ b/runtime/platform/utils.h
@@ -150,6 +150,11 @@
static int CountLeadingZeros(uword x);
static int CountTrailingZeros(uword x);
+ // Computes magic numbers to implement DIV or MOD operator.
+ static void CalculateMagicAndShiftForDivRem(int64_t divisor,
+ int64_t* magic,
+ int64_t* shift);
+
// Computes a hash value for the given string.
static uint32_t StringHash(const char* data, int length);
diff --git a/runtime/platform/utils_android.h b/runtime/platform/utils_android.h
index dc16a73..6d91415 100644
--- a/runtime/platform/utils_android.h
+++ b/runtime/platform/utils_android.h
@@ -5,6 +5,10 @@
#ifndef RUNTIME_PLATFORM_UTILS_ANDROID_H_
#define RUNTIME_PLATFORM_UTILS_ANDROID_H_
+#if !defined(RUNTIME_PLATFORM_UTILS_H_)
+#error Do not include utils_android.h directly; use utils.h instead.
+#endif
+
#include <endian.h> // NOLINT
namespace dart {
diff --git a/runtime/platform/utils_linux.h b/runtime/platform/utils_linux.h
index a754ef4..4a49a6a 100644
--- a/runtime/platform/utils_linux.h
+++ b/runtime/platform/utils_linux.h
@@ -5,6 +5,10 @@
#ifndef RUNTIME_PLATFORM_UTILS_LINUX_H_
#define RUNTIME_PLATFORM_UTILS_LINUX_H_
+#if !defined(RUNTIME_PLATFORM_UTILS_H_)
+#error Do not include utils_linux.h directly; use utils.h instead.
+#endif
+
#include <endian.h> // NOLINT
namespace dart {
diff --git a/runtime/platform/utils_macos.h b/runtime/platform/utils_macos.h
index bc34193..e64711b 100644
--- a/runtime/platform/utils_macos.h
+++ b/runtime/platform/utils_macos.h
@@ -5,6 +5,10 @@
#ifndef RUNTIME_PLATFORM_UTILS_MACOS_H_
#define RUNTIME_PLATFORM_UTILS_MACOS_H_
+#if !defined(RUNTIME_PLATFORM_UTILS_H_)
+#error Do not include utils_macos.h directly; use utils.h instead.
+#endif
+
#include <AvailabilityMacros.h>
#include <libkern/OSByteOrder.h> // NOLINT
diff --git a/runtime/platform/utils_win.h b/runtime/platform/utils_win.h
index c3a67e7..ba5c9cc 100644
--- a/runtime/platform/utils_win.h
+++ b/runtime/platform/utils_win.h
@@ -5,6 +5,10 @@
#ifndef RUNTIME_PLATFORM_UTILS_WIN_H_
#define RUNTIME_PLATFORM_UTILS_WIN_H_
+#if !defined(RUNTIME_PLATFORM_UTILS_H_)
+#error Do not include utils_win.h directly; use utils.h instead.
+#endif
+
#include <intrin.h>
#include <stdlib.h>
diff --git a/runtime/tests/vm/dart/il_round_trip_deserialization_test.dart b/runtime/tests/vm/dart/il_round_trip_deserialization_test.dart
new file mode 100644
index 0000000..0a6f667
--- /dev/null
+++ b/runtime/tests/vm/dart/il_round_trip_deserialization_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2019, 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.
+
+// VMOptions=
+// VMOptions=--early-round-trip-serialization
+// VMOptions=--late-round-trip-serialization
+// VMOptions=--early-round-trip-serialization --late-round-trip-serialization
+// VMOptions=--deterministic
+// VMOptions=--deterministic --early-round-trip-serialization
+// VMOptions=--deterministic --late-round-trip-serialization
+// VMOptions=--deterministic --early-round-trip-serialization --late-round-trip-serialization
+
+// Just use the existing hello world test for now.
+// TODO(36882): Add more interesting code as the deserializer grows.
+import 'hello_world_test.dart' as test;
+
+main(args) {
+ test.main();
+}
diff --git a/runtime/tests/vm/dart/internal_platform_library_import_test.dart b/runtime/tests/vm/dart/internal_platform_library_import_test.dart
new file mode 100644
index 0000000..7f99459
--- /dev/null
+++ b/runtime/tests/vm/dart/internal_platform_library_import_test.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2019, 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:_internal';
+
+void main(List<String> args) {
+ // Ensure we can import and use members of `dart:_internal`.
+ print(unsafeCast);
+}
diff --git a/runtime/tests/vm/dart/isolates/spawn_function_test.dart b/runtime/tests/vm/dart/isolates/spawn_function_test.dart
new file mode 100644
index 0000000..f2a85ea
--- /dev/null
+++ b/runtime/tests/vm/dart/isolates/spawn_function_test.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2019, 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.
+
+// VMOptions=--enable-isolate-groups
+// VMOptions=--no-enable-isolate-groups
+
+import 'dart:isolate';
+import 'dart:async';
+
+import 'package:expect/expect.dart';
+
+void isolateEntry(args) {
+ final SendPort sendPort = args;
+ sendPort.send('hello world');
+}
+
+main() async {
+ final port = ReceivePort();
+ final exitPort = ReceivePort();
+
+ await Isolate.spawn(isolateEntry, port.sendPort, onExit: exitPort.sendPort);
+
+ final messages = StreamIterator(port);
+ Expect.isTrue(await messages.moveNext());
+ Expect.equals('hello world', messages.current);
+ await messages.cancel();
+
+ final exit = StreamIterator(exitPort);
+ Expect.isTrue(await exit.moveNext());
+ await exit.cancel();
+}
diff --git a/runtime/tests/vm/dart/regress_merge_blocks_with_phis_test.dart b/runtime/tests/vm/dart/regress_merge_blocks_with_phis_test.dart
new file mode 100644
index 0000000..a3edcce
--- /dev/null
+++ b/runtime/tests/vm/dart/regress_merge_blocks_with_phis_test.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2019, 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.
+//
+// VMOptions=--deterministic --optimization-counter-threshold=5 --use-bytecode-compiler
+//
+// Test that block merging takes phis into account.
+//
+// The problem only reproduces with bytecode compiler (--use-bytecode-compiler)
+// as bytecode doesn't have backward branches for the redundant loops.
+// OSR handling code inserts Phi instructions to JoinEntry
+// even when there is only one predecessor. This results in a flow graph
+// suitable for block merging with a successor block containing Phi.
+
+import 'package:expect/expect.dart';
+
+void testBottomUpInference() {
+ Expect.type<List<int>>([for (; false;) 1]);
+ Expect.type<List<int>>([for (; false;) 1]);
+ Expect.type<List<int>>([for (; false;) 1]);
+ Expect.type<List<int>>([for (; false;) 1]);
+ Expect.type<List<int>>([for (; false;) 1]);
+ Expect.type<List<int>>([for (; false;) 1]);
+ Expect.type<List<int>>([for (; false;) 1]);
+ Expect.type<List<int>>([for (; false;) 1]);
+ Expect.type<List<int>>([for (; false;) 1]);
+ Expect.type<List<int>>([for (; false;) 1]);
+ Expect.type<List<int>>([for (; false;) 1]);
+ Expect.type<List<int>>([for (; false;) 1]);
+ Expect.type<List<int>>([for (; false;) 1]);
+}
+
+main() {
+ testBottomUpInference();
+}
diff --git a/runtime/tests/vm/dart/v8_snapshot_profile_writer_test.dart b/runtime/tests/vm/dart/v8_snapshot_profile_writer_test.dart
index e3393a3..f6ece6d 100644
--- a/runtime/tests/vm/dart/v8_snapshot_profile_writer_test.dart
+++ b/runtime/tests/vm/dart/v8_snapshot_profile_writer_test.dart
@@ -88,7 +88,7 @@
}
final int actual = await File(snapshotPath).length();
final int expected = profile.accountedBytes;
- Expect.isTrue((actual - expected).abs() / actual < 0.01);
+ Expect.isTrue((actual - expected).abs() / actual < 0.02);
}
Match matchComplete(RegExp regexp, String line) {
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index da4d33f..22c5b32 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -72,9 +72,6 @@
dart/appjit_bytecode_simple_test: Skip # Issue 34393.
dart/disassemble_determinism_test: Slow # Times out on slower bots.
-[ !$strong ]
-dart/callee_side_type_checks_test: SkipByDesign
-
[ $arch == ia32 && $mode == debug && $system == windows ]
dart/transferable_test: Skip # This is performance test and somehow debug win ia32 bot's performance is unpredictable
@@ -137,9 +134,6 @@
[ $runtime == vm && $system == macos && ($compiler == dartk || $compiler == dartkb) ]
cc/IsolateReload_LibraryLookup: Fail, Crash
-[ $runtime == vm && !$checked && !$strong ]
-dart/redirection_type_shuffling_test/00: MissingCompileTimeError
-
[ $runtime == vm && ($compiler == dartk || $compiler == dartkb) ]
cc/DartAPI_LoadLibrary: Fail, Crash # Issue 33048.
cc/DebuggerAPI_BreakpointStubPatching: Fail
@@ -164,14 +158,6 @@
[ $checked && ($compiler == dartk || $compiler == dartkb) ]
dart/redirection_type_shuffling_test/00: Pass # Works in --checked mode but not in --strong mode.
-[ $strong && ($compiler == dartk || $compiler == dartkb) ]
-cc/DartGeneratedArrayLiteralMessages: Crash # Issue 32190
-cc/FullSnapshot1: Crash # Issue 32190
-cc/IsolateReload_LibraryLookup: Fail, Crash # Issue 32190
-cc/MismatchedSnapshotKinds: Fail, Crash, OK # Script snapshots not supported in Dart 2
-cc/ScriptSnapshot1: Fail, Crash, OK # Script snapshots not supported in Dart 2
-cc/ScriptSnapshotsUpdateSubclasses: Fail, Crash, OK # Script snapshots not supported in Dart 2
-
[ ($arch == simarm || $arch == simarm64 || $arch == simdbc || $arch == simdbc64) && ($compiler == dartk || $compiler == dartkb) ]
dart/appjit*: SkipSlow # DFE too slow
@@ -186,7 +172,7 @@
dart/data_uri_spawn_test: Skip # Timeout
dart/kernel_determinism_test: SkipSlow
-[ $arch == arm || $arch == arm64 || $compiler != dartkp ]
+[ $arch == arm || $arch == arm64 || $builder_tag == crossword || $compiler != dartkp ]
dart/v8_snapshot_profile_writer_test: SkipByDesign # Only relevant for AOT. Doesn't work in cross-compilation (has to run on the host).
[ $arch == arm || $arch == ia32 || $arch == simarm || $arch == simdbc || $arch == simdbc64 ]
@@ -250,6 +236,12 @@
[ $compiler == dartk || $compiler == dartkb ]
cc/DartAPI_New: Fail # Issue #33041
+cc/DartGeneratedArrayLiteralMessages: Crash # Issue 32190
+cc/FullSnapshot1: Crash # Issue 32190
+cc/IsolateReload_LibraryLookup: Fail, Crash # Issue 32190
+cc/MismatchedSnapshotKinds: Fail, Crash, OK # Script snapshots not supported in Dart 2
+cc/ScriptSnapshot1: Fail, Crash, OK # Script snapshots not supported in Dart 2
+cc/ScriptSnapshotsUpdateSubclasses: Fail, Crash, OK # Script snapshots not supported in Dart 2
dart/redirection_type_shuffling_test/00: RuntimeError, Pass
dart/redirection_type_shuffling_test/none: RuntimeError
diff --git a/runtime/tools/bin_to_coff.py b/runtime/tools/bin_to_coff.py
index 1925bcd..c8a8ebc 100644
--- a/runtime/tools/bin_to_coff.py
+++ b/runtime/tools/bin_to_coff.py
@@ -4,6 +4,8 @@
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
+# See also "PE Format" at https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
+
import argparse
from ctypes import create_string_buffer
from struct import *
@@ -19,6 +21,7 @@
SECTION_HEADER_TEXT = 0x20 # Contains executable code
SECTION_HEADER_DATA = 0x40 # Contains only initialized data
SECTION_HEADER_BSS = 0x80 # Contains uninitialized data
+SECTION_HEADER_ALIGN_32BYTES = 0x600000
# FILE HEADER FORMAT
# typedef struct {
@@ -176,17 +179,18 @@
offset += FILE_HEADER_SIZE
section_name = SECTION_NAME_RODATA
- section_type = SECTION_HEADER_DATA
+ section_flags = SECTION_HEADER_DATA
if args.executable:
section_name = SECTION_NAME_TEXT
- section_type = SECTION_HEADER_TEXT
+ section_flags = SECTION_HEADER_TEXT
+ section_flags |= SECTION_HEADER_ALIGN_32BYTES
# Populate the section header for a single section.
pack_into(SECTION_HEADER_FORMAT, buff, offset, section_name, SECTION_PADDR,
SECTION_VADDR, section_size + size_symbol_size,
SECTION_RAW_DATA_PTR, SECTION_RELOCATION_PTR,
SECTION_LINE_NUMS_PTR, SECTION_NUM_RELOCATION,
- SECTION_NUM_LINE_NUMS, section_type)
+ SECTION_NUM_LINE_NUMS, section_flags)
offset += SECTION_HEADER_SIZE
# Copy the binary data.
diff --git a/runtime/tools/dartfuzz/analysis_options.yaml b/runtime/tools/dartfuzz/analysis_options.yaml
new file mode 100644
index 0000000..73dd727
--- /dev/null
+++ b/runtime/tools/dartfuzz/analysis_options.yaml
@@ -0,0 +1,6 @@
+include: package:pedantic/analysis_options.yaml
+
+linter:
+ rules:
+ - directives_ordering
+ - prefer_generic_function_type_aliases
diff --git a/runtime/tools/dartfuzz/collect_data.py b/runtime/tools/dartfuzz/collect_data.py
index 5d4f677..25b5f5d 100755
--- a/runtime/tools/dartfuzz/collect_data.py
+++ b/runtime/tools/dartfuzz/collect_data.py
@@ -32,91 +32,106 @@
P_DIV = re.compile("(Isolate.+? !DIVERGENCE! (\n|.)+?)Isolate ", re.MULTILINE)
# Matches shard raw stdout to extract report summaries.
-P_SUM = re.compile(r"^Tests: (\d+) Success: (\d+) Not-Run: (\d+): "
- r"Time-Out: (\d+) Divergences: (\d+)$", re.MULTILINE)
+P_SUM = re.compile(
+ r"^Tests: (\d+) Success: (\d+) "
+ r"\(Rerun: (\d+)\) Skipped: (\d+) "
+ r"Timeout: (\d+) Divergences: (\d+)", re.MULTILINE)
# Matches uri to extract shard number.
P_SHARD = re.compile(r".*make_a_fuzz_shard_(\d+)")
def get_shard_links(uri):
- links = []
- resp = requests.get(uri)
- soup = BeautifulSoup(resp.text, "html.parser")
- for a in soup.findAll("a"):
- if a.text == "raw":
- href = a["href"]
- if ("make_a_fuzz_shard" in href and
- "__trigger__" not in href):
- links.append(href)
- return links
+ links = []
+ resp = requests.get(uri)
+ soup = BeautifulSoup(resp.text, "html.parser")
+ for a in soup.findAll("a"):
+ if a.text == "raw":
+ href = a["href"]
+ if ("make_a_fuzz_shard" in href and "__trigger__" not in href):
+ links.append(href)
+ return links
def print_reencoded(text):
- # Re-encoding avoids breaking some terminals.
- print(text.encode("ascii", errors="ignore").decode("unicode-escape"))
+ # Re-encoding avoids breaking some terminals.
+ print(text.encode("ascii", errors="ignore").decode("unicode-escape"))
def print_output_all(text):
- print_reencoded(text)
+ print_reencoded(text)
-def print_output_div(shard, text):
- sys.stderr.write("Shard: " + shard + " \r")
- m = P_DIV.findall(text)
- if m:
- print("Shard: " + shard)
- for x in m:
- print_reencoded(x[0])
+def print_output_div(shard, text, keywords):
+ sys.stderr.write("Shard: " + shard + " \r")
+ m = P_DIV.findall(text)
+ if m:
+ for x in m:
+ keep = True
+ for word in keywords:
+ if word in x[0]:
+ keep = False
+ break
+ if keep:
+ print_reencoded(x[0])
-def print_output_sum(shard, text, s=[0, 0, 0, 0, 0], divs=[]):
- m = P_SUM.findall(text)
- if not m:
- sys.stderr.write("Failed to parse shard %s stdout for summary" % shard)
- return
- for test in m:
- if int(test[-1]) == 1:
- divs.append(shard)
- for i in range(len(s)):
- s[i] += int(test[i])
- print("Tests: %d Success: %d Not-Run: %d Time-Out: %d Divergences: %d "
- "(failing shards: %s) \r"
- % tuple(s + [", ".join(divs) if divs else "none"]), end="")
+def print_output_sum(shard, text, s=[0, 0, 0, 0, 0, 0], divs=[]):
+ m = P_SUM.findall(text)
+ if not m:
+ sys.stderr.write("Failed to parse shard %s stdout for summary" % shard)
+ return
+ for test in m:
+ if int(test[-1]) == 1:
+ divs.append(shard)
+ for i in range(len(s)):
+ s[i] += int(test[i])
+ print(
+ "Tests: %d Success: %d (Rerun: %d) Skipped: %d Timeout: %d Divergences: %d"
+ "(failing shards: %s) \r" %
+ tuple(s + [", ".join(divs) if divs else "none"]),
+ end="")
-def get_stats(uri, output_type):
- resp = requests.get(uri)
+def get_stats(uri, output_type, keywords):
+ resp = requests.get(uri)
- if output_type == "all":
- print_output_all(resp.text)
- elif output_type == "div":
- shard = P_SHARD.findall(uri)[0]
- print_output_div(shard, resp.text)
- elif output_type == "sum":
- shard = P_SHARD.findall(uri)[0]
- print_output_sum(shard, resp.text)
+ if output_type == "all":
+ print_output_all(resp.text)
+ elif output_type == "div":
+ shard = P_SHARD.findall(uri)[0]
+ print_output_div(shard, resp.text, keywords)
+ elif output_type == "sum":
+ shard = P_SHARD.findall(uri)[0]
+ print_output_sum(shard, resp.text)
def main():
- parser = argparse.ArgumentParser(description=__doc__)
- parser.add_argument(
- "--type",
- choices=("div", "sum", "all"),
- required=True,
- help="Select output type (div: divergence report, sum: summary, all: complete stdout)"
- )
- parser.add_argument(
- "uri",
- type=str,
- help="Uri of one make_a_fuzz run from https://ci.chromium.org/p/dart/builders/ci.sandbox/fuzz-linux."
- )
- args = parser.parse_args()
- shard_links = get_shard_links(args.uri)
- for link in shard_links:
- get_stats(link, args.type)
- print("")
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument(
+ "--type",
+ choices=("div", "sum", "all"),
+ required=True,
+ help=
+ "Select output type (div: divergence report, sum: summary, all: complete stdout)"
+ )
+ parser.add_argument(
+ "--filter",
+ nargs="+",
+ default=[],
+ help="Do not include divergences containing these keywords.")
+ parser.add_argument(
+ "uri",
+ type=str,
+ help=
+ "Uri of one make_a_fuzz run from https://ci.chromium.org/p/dart/builders/ci.sandbox/fuzz-linux."
+ )
+ args = parser.parse_args()
+ shard_links = get_shard_links(args.uri)
+ for link in shard_links:
+ get_stats(link, args.type, args.filter)
+ print("")
if __name__ == "__main__":
- main()
+ main()
diff --git a/runtime/tools/dartfuzz/dartfuzz.dart b/runtime/tools/dartfuzz/dartfuzz.dart
index 97b9683..cc97ad8 100644
--- a/runtime/tools/dartfuzz/dartfuzz.dart
+++ b/runtime/tools/dartfuzz/dartfuzz.dart
@@ -9,11 +9,12 @@
import 'dartfuzz_values.dart';
import 'dartfuzz_api_table.dart';
+import 'dartfuzz_ffiapi.dart';
// Version of DartFuzz. Increase this each time changes are made
// to preserve the property that a given version of DartFuzz yields
// the same fuzzed program for a deterministic random seed.
-const String version = '1.23';
+const String version = '1.39';
// Restriction on statements and expressions.
const int stmtLength = 2;
@@ -27,30 +28,83 @@
const fieldName = 'fld';
const methodName = 'foo';
+/// Class that specifies the api for calling library and ffi functions (if
+/// enabled).
+class DartApi {
+ DartApi(bool ffi)
+ : intLibs = [
+ if (ffi) ...[
+ DartLib('intComputation', 'VIIII'),
+ DartLib('takeMaxUint16', 'VI'),
+ DartLib('sumPlus42', 'VII'),
+ DartLib('returnMaxUint8', 'VV'),
+ DartLib('returnMaxUint16', 'VV'),
+ DartLib('returnMaxUint32', 'VV'),
+ DartLib('returnMinInt8', 'VV'),
+ DartLib('returnMinInt16', 'VV'),
+ DartLib('returnMinInt32', 'VV'),
+ DartLib('takeMinInt16', 'VI'),
+ DartLib('takeMinInt32', 'VI'),
+ DartLib('uintComputation', 'VIIII'),
+ DartLib('sumSmallNumbers', 'VIIIIII'),
+ DartLib('takeMinInt8', 'VI'),
+ DartLib('takeMaxUint32', 'VI'),
+ DartLib('takeMaxUint8', 'VI'),
+ DartLib('minInt64', 'VV'),
+ DartLib('minInt32', 'VV'),
+ // Use small int to avoid overflow divergences due to size
+ // differences in intptr_t on 32-bit and 64-bit platforms.
+ DartLib('sumManyIntsOdd', 'Viiiiiiiiiii'),
+ DartLib('sumManyInts', 'Viiiiiiiiii'),
+ DartLib('regress37069', 'Viiiiiiiiiii'),
+ ],
+ ...DartLib.intLibs,
+ ],
+ doubleLibs = [
+ if (ffi) ...[
+ DartLib('times1_337Float', 'VD'),
+ DartLib('sumManyDoubles', 'VDDDDDDDDDD'),
+ DartLib('times1_337Double', 'VD'),
+ DartLib('sumManyNumbers', 'VIDIDIDIDIDIDIDIDIDID'),
+ DartLib('inventFloatValue', 'VV'),
+ DartLib('smallDouble', 'VV'),
+ ],
+ ...DartLib.doubleLibs,
+ ];
+
+ final boolLibs = DartLib.boolLibs;
+ final stringLibs = DartLib.stringLibs;
+ final listLibs = DartLib.listLibs;
+ final setLibs = DartLib.setLibs;
+ final mapLibs = DartLib.mapLibs;
+ final List<DartLib> intLibs;
+ final List<DartLib> doubleLibs;
+}
+
/// Class that generates a random, but runnable Dart program for fuzz testing.
class DartFuzz {
DartFuzz(this.seed, this.fp, this.ffi, this.file);
void run() {
// Initialize program variables.
- rand = new Random(seed);
+ rand = Random(seed);
indent = 0;
nest = 0;
currentClass = null;
currentMethod = null;
+ // Setup the library and ffi api.
+ api = DartApi(ffi);
// Setup the types.
- localVars = new List<DartType>();
- iterVars = new List<String>();
+ localVars = <DartType>[];
+ iterVars = <String>[];
globalVars = fillTypes1();
globalVars.addAll(DartType.allTypes); // always one each
globalMethods = fillTypes2();
- classFields = fillTypes2();
+ classFields = fillTypes2(limit: 8);
classMethods = fillTypes3(classFields.length);
+ classParents = <int>[];
// Setup optional ffi methods and types.
- List<bool> ffiStatus = new List<bool>();
- for (var m in globalMethods) {
- ffiStatus.add(false);
- }
+ final ffiStatus = <bool>[for (final _ in globalMethods) false];
if (ffi) {
List<List<DartType>> globalMethodsFfi = fillTypes2(isFfi: true);
for (var m in globalMethodsFfi) {
@@ -69,7 +123,7 @@
assert(currentMethod == null);
assert(indent == 0);
assert(nest == 0);
- assert(localVars.length == 0);
+ assert(localVars.isEmpty);
}
//
@@ -91,7 +145,10 @@
emitLn("import 'dart:isolate';");
emitLn("import 'dart:math';");
emitLn("import 'dart:typed_data';");
- if (ffi) emitLn("import 'dart:ffi' as ffi;");
+ if (ffi) {
+ emitLn("import 'dart:ffi' as ffi;");
+ emitLn(DartFuzzFfiApi.ffiapi);
+ }
}
void emitFfiCast(String dartFuncName, String ffiFuncName, String typeName,
@@ -106,7 +163,7 @@
}
emit(') ${dartFuncName} = ' +
'ffi.Pointer.fromFunction<${typeName}>(${ffiFuncName}, ');
- emitLiteral(0, pars[0]);
+ emitLiteral(0, pars[0], smallPositiveValue: true);
emitLn(').cast<ffi.NativeFunction<${typeName}>>().asFunction();');
}
@@ -123,13 +180,21 @@
emitLn('${method[0].name} $name$i(', newline: false);
}
emitParDecls(method);
+ if (!isFfiMethod && rand.nextInt(10) == 0) {
+ // Emit a method using "=>" syntax.
+ emit(') => ');
+ emitExpr(0, method[0]);
+ emit(';', newline: true);
+ currentMethod = null;
+ continue;
+ }
emit(') {', newline: true);
indent += 2;
- assert(localVars.length == 0);
+ assert(localVars.isEmpty);
if (emitStatements(0)) {
emitReturn();
}
- assert(localVars.length == 0);
+ assert(localVars.isEmpty);
indent -= 2;
emitLn('}');
if (isFfiMethod) {
@@ -144,7 +209,25 @@
void emitClasses() {
assert(classFields.length == classMethods.length);
for (int i = 0; i < classFields.length; i++) {
- emitLn('class X$i ${i == 0 ? "" : "extends X${i - 1}"} {');
+ if (i == 0) {
+ classParents.add(-1);
+ emitLn('class X0 {');
+ } else {
+ final int parentClass = rand.nextInt(i);
+ classParents.add(parentClass);
+ if (rand.nextInt(2) != 0) {
+ // Inheritance
+ emitLn('class X$i extends X${parentClass} {');
+ } else {
+ // Mixin
+ if (classParents[parentClass] >= 0) {
+ emitLn(
+ 'class X$i extends X${classParents[parentClass]} with X${parentClass} {');
+ } else {
+ emitLn('class X$i with X${parentClass} {');
+ }
+ }
+ }
indent += 2;
emitVarDecls('$fieldName${i}_', classFields[i]);
currentClass = i;
@@ -154,9 +237,9 @@
if (i > 0) {
emitLn('super.run();');
}
- assert(localVars.length == 0);
+ assert(localVars.isEmpty);
emitStatements(0);
- assert(localVars.length == 0);
+ assert(localVars.isEmpty);
indent -= 2;
emitLn('}');
indent -= 2;
@@ -166,16 +249,68 @@
}
}
+ void emitLoadFfiLib() {
+ if (ffi) {
+ emitLn(
+ '// The following throws an uncaught exception if the ffi library ' +
+ 'is not found.');
+ emitLn(
+ '// By not catching this exception, we terminate the program with ' +
+ 'a full stack trace');
+ emitLn('// which, in turn, flags the problem prominently');
+ emitLn('if (ffiTestFunctions == null) {');
+ indent += 2;
+ emitLn('print(\'Did not load ffi test functions\');');
+ indent -= 2;
+ emitLn('}');
+ }
+ }
+
void emitMain() {
emitLn('main() {');
indent += 2;
+
+ emitLoadFfiLib();
+
+ // Call each global method once.
+ for (int i = 0; i < globalMethods.length; i++) {
+ emitLn('try {');
+ indent += 2;
+ emitLn("", newline: false);
+ emitCall(1, "$methodName${i}", globalMethods[i]);
+ emit(";", newline: true);
+ indent -= 2;
+ emitLn('} catch (exception, stackTrace) {');
+ indent += 2;
+ emitLn("print('$methodName$i throws');");
+ indent -= 2;
+ emitLn('}');
+ }
+
+ // Call each class method once.
+ for (int i = 0; i < classMethods.length; i++) {
+ for (int j = 0; j < classMethods[i].length; j++) {
+ emitLn('try {');
+ indent += 2;
+ emitLn("", newline: false);
+ emitCall(1, "X${i}().$methodName${i}_${j}", classMethods[i][j]);
+ emit(";", newline: true);
+ indent -= 2;
+ emitLn('} catch (exception, stackTrace) {');
+ indent += 2;
+ emitLn("print('X${i}().$methodName${i}_${j}() throws');");
+ indent -= 2;
+ emitLn('}');
+ }
+ }
+
emitLn('try {');
indent += 2;
- emitLn('new X${classFields.length - 1}().run();');
+ emitLn('X${classFields.length - 1}().run();');
indent -= 2;
emitLn('} catch (exception, stackTrace) {');
indent += 2;
- emitLn("print('throws');");
+ emitLn("print('X${classFields.length - 1}().run() throws');");
indent -= 2;
emitLn('} finally {');
indent += 2;
@@ -356,7 +491,8 @@
bool emitForEach(int depth) {
final int i = localVars.length;
emitLn("", newline: false);
- emitScalarVar(DartType.INT_STRING_MAP, isLhs: true);
+ final emittedVar = emitScalarVar(DartType.INT_STRING_MAP, isLhs: false);
+ iterVars.add(emittedVar);
emit('.forEach(($localName$i, $localName${i + 1}) {\n');
indent += 2;
final int nestTmp = nest;
@@ -467,7 +603,7 @@
emit(';', newline: true);
indent += 2;
localVars.add(tp);
- bool b = emitStatements(depth + 1);
+ emitStatements(depth + 1);
localVars.removeLast();
indent -= 2;
emitLn('}');
@@ -632,8 +768,8 @@
void emitCollectionElement(int depth, DartType tp) {
int r = depth <= exprDepth ? rand.nextInt(10) : 10;
+ // TODO(ajcbik): renable, https://github.com/dart-lang/sdk/issues/38231
switch (r + 3) {
- // TODO(ajcbik): enable when on by default
// Favors elements over control-flow collections.
case 0:
emit('...'); // spread
@@ -695,11 +831,15 @@
emit(tp == DartType.INT_LIST ? ' ]' : ' }');
}
- void emitLiteral(int depth, DartType tp) {
+ void emitLiteral(int depth, DartType tp, {bool smallPositiveValue = false}) {
if (tp == DartType.BOOL) {
emitBool();
} else if (tp == DartType.INT) {
- emitInt();
+ if (smallPositiveValue) {
+ emitSmallPositiveInt();
+ } else {
+ emitInt();
+ }
} else if (tp == DartType.DOUBLE) {
emitDouble();
} else if (tp == DartType.STRING) {
@@ -713,9 +853,9 @@
}
}
- void emitScalarVar(DartType tp, {bool isLhs = false}) {
+ String emitScalarVar(DartType tp, {bool isLhs = false}) {
// Collect all choices from globals, fields, locals, and parameters.
- Set<String> choices = new Set<String>();
+ Set<String> choices = <String>{};
for (int i = 0; i < globalVars.length; i++) {
if (tp == globalVars[i]) choices.add('$varName$i');
}
@@ -734,19 +874,21 @@
if (tp == proto[i]) choices.add('$paramName$i');
}
}
- // Remove possible modification of the iteration variable from the loop
- // body.
+ // Make modification of the iteration variable from the loop
+ // body less likely.
if (isLhs) {
- if (rand.nextInt(10) != 0) {
+ if (rand.nextInt(100) != 0) {
Set<String> cleanChoices = choices.difference(Set.from(iterVars));
- if (cleanChoices.length > 0) {
+ if (cleanChoices.isNotEmpty) {
choices = cleanChoices;
}
}
}
// Then pick one.
- assert(choices.length > 0);
- emit('${choices.elementAt(rand.nextInt(choices.length))}');
+ assert(choices.isNotEmpty);
+ final emittedVar = '${choices.elementAt(rand.nextInt(choices.length))}';
+ emit(emittedVar);
+ return emittedVar;
}
void emitSubscriptedVar(int depth, DartType tp, {bool isLhs = false}) {
@@ -894,13 +1036,18 @@
}
}
+ // Emit call to a specific method.
+ void emitCall(int depth, String name, List<DartType> proto) {
+ emit(name);
+ emitExprList(depth + 1, proto);
+ }
+
// Helper for a method call.
bool pickedCall(
int depth, DartType tp, String name, List<List<DartType>> protos, int m) {
for (int i = m - 1; i >= 0; i--) {
if (tp == protos[i][0]) {
- emit('$name$i');
- emitExprList(depth + 1, protos[i]);
+ emitCall(depth + 1, "$name$i", protos[i]);
return true;
}
}
@@ -917,13 +1064,30 @@
return;
}
} else {
- // Inside a class: try to call backwards in class methods first.
- final int m1 = currentMethod == null
- ? classMethods[currentClass].length
- : currentMethod;
+ int classIndex = currentClass;
+ // Chase randomly up in class hierarchy.
+ while (classParents[classIndex] > 0) {
+ if (rand.nextInt(2) == 0) {
+ break;
+ }
+ classIndex = classParents[classIndex];
+ }
+ int m1 = 0;
+ // Inside a class: try to call backwards into current or parent class
+ // methods first.
+ if (currentMethod == null || classIndex != currentClass) {
+ // If currently emitting the 'run' method or calling into a parent class
+ // pick any of the current or parent class methods respectively.
+ m1 = classMethods[classIndex].length;
+ } else {
+ // If calling into the current class from any method other than 'run'
+ // pick one of the already emitted methods
+ // (to avoid infinite recursions).
+ m1 = currentMethod;
+ }
final int m2 = globalMethods.length;
- if (pickedCall(depth, tp, '$methodName${currentClass}_',
- classMethods[currentClass], m1) ||
+ if (pickedCall(depth, tp, '$methodName${classIndex}_',
+ classMethods[classIndex], m1) ||
pickedCall(depth, tp, methodName, globalMethods, m2)) {
return;
}
@@ -1058,22 +1222,21 @@
// Get a library method that returns given type.
DartLib getLibraryMethod(DartType tp) {
if (tp == DartType.BOOL) {
- return oneOf(DartLib.boolLibs);
+ return oneOf(api.boolLibs);
} else if (tp == DartType.INT) {
- return oneOf(DartLib.intLibs);
+ return oneOf(api.intLibs);
} else if (tp == DartType.DOUBLE) {
- return oneOf(DartLib.doubleLibs);
+ return oneOf(api.doubleLibs);
} else if (tp == DartType.STRING) {
- return oneOf(DartLib.stringLibs);
+ return oneOf(api.stringLibs);
} else if (tp == DartType.INT_LIST) {
- return oneOf(DartLib.listLibs);
+ return oneOf(api.listLibs);
} else if (tp == DartType.INT_SET) {
- return oneOf(DartLib.setLibs);
+ return oneOf(api.setLibs);
} else if (tp == DartType.INT_STRING_MAP) {
- return oneOf(DartLib.mapLibs);
- } else {
- assert(false);
+ return oneOf(api.mapLibs);
}
+ throw ArgumentError('Invalid DartType: $tp');
}
// Emit a library argument, possibly subject to restrictions.
@@ -1082,7 +1245,7 @@
case 'B':
emitExpr(depth, DartType.BOOL);
break;
- case 'i':
+ case 'i': // emit small int
emitSmallPositiveInt();
break;
case 'I':
@@ -1094,12 +1257,7 @@
case 'S':
emitExpr(depth, DartType.STRING);
break;
- case 's':
- // Emit string literal of 2 characters maximum length
- // for 'small string' parameters to avoid recursively constructed
- // strings which might lead to exponentially growing data structures
- // e.g. loop { var = 'x'.padLeft(8, var); }
- // TODO (felih): detect recursion to eliminate such cases specifically
+ case 's': // emit small string
emitString(length: 2);
break;
case 'L':
@@ -1112,7 +1270,7 @@
emitExpr(depth, DartType.INT_STRING_MAP);
break;
default:
- assert(false);
+ throw ArgumentError('Invalid p value: $p');
}
}
@@ -1135,32 +1293,33 @@
return DartType.INT_LIST;
case 5:
return DartType.INT_SET;
- case 6:
+ default:
return DartType.INT_STRING_MAP;
}
}
List<DartType> fillTypes1({bool isFfi = false}) {
- List<DartType> list = new List<DartType>();
+ final list = <DartType>[];
for (int i = 0, n = 1 + rand.nextInt(4); i < n; i++) {
- if (isFfi)
+ if (isFfi) {
list.add(fp ? oneOf([DartType.INT, DartType.DOUBLE]) : DartType.INT);
- else
+ } else {
list.add(getType());
+ }
}
return list;
}
- List<List<DartType>> fillTypes2({bool isFfi = false}) {
- List<List<DartType>> list = new List<List<DartType>>();
- for (int i = 0, n = 1 + rand.nextInt(4); i < n; i++) {
+ List<List<DartType>> fillTypes2({bool isFfi = false, int limit = 4}) {
+ final list = <List<DartType>>[];
+ for (int i = 0, n = 1 + rand.nextInt(limit); i < n; i++) {
list.add(fillTypes1(isFfi: isFfi));
}
return list;
}
List<List<List<DartType>>> fillTypes3(int n) {
- List<List<List<DartType>>> list = new List<List<List<DartType>>>();
+ final list = <List<List<DartType>>>[];
for (int i = 0; i < n; i++) {
list.add(fillTypes2());
}
@@ -1244,6 +1403,9 @@
// File used for output.
final RandomAccessFile file;
+ // Library and ffi api.
+ DartApi api;
+
// Program variables.
Random rand;
int indent;
@@ -1270,6 +1432,9 @@
// Prototypes of all methods over all classes (first element is return type).
List<List<List<DartType>>> classMethods;
+
+ // Parent class indices for all classes.
+ List<int> classParents;
}
// Generate seed. By default (no user-defined nonzero seed given),
@@ -1278,7 +1443,7 @@
int getSeed(String userSeed) {
int seed = int.parse(userSeed);
if (seed == 0) {
- Random rand = new Random();
+ Random rand = Random();
while (seed == 0) {
seed = rand.nextInt(1 << 32);
}
@@ -1288,7 +1453,7 @@
/// Main driver when dartfuzz.dart is run stand-alone.
main(List<String> arguments) {
- final parser = new ArgParser()
+ final parser = ArgParser()
..addOption('seed',
help: 'random seed (0 forces time-based seed)', defaultsTo: '0')
..addFlag('fp', help: 'enables floating-point operations', defaultsTo: true)
@@ -1299,8 +1464,8 @@
final seed = getSeed(results['seed']);
final fp = results['fp'];
final ffi = results['ffi'];
- final file = new File(results.rest.single).openSync(mode: FileMode.write);
- new DartFuzz(seed, fp, ffi, file).run();
+ final file = File(results.rest.single).openSync(mode: FileMode.write);
+ DartFuzz(seed, fp, ffi, file).run();
file.closeSync();
} catch (e) {
print('Usage: dart dartfuzz.dart [OPTIONS] FILENAME\n${parser.usage}\n$e');
diff --git a/runtime/tools/dartfuzz/dartfuzz_ffiapi.dart b/runtime/tools/dartfuzz/dartfuzz_ffiapi.dart
new file mode 100644
index 0000000..cb34993
--- /dev/null
+++ b/runtime/tools/dartfuzz/dartfuzz_ffiapi.dart
@@ -0,0 +1,243 @@
+// Copyright (c) 2019, 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.
+
+// Contains the Dart FFI interface to the c-library defined in
+// sdk/runtime/bin/ffi_test/ffi_test_functions.cc.
+// The code contained in this class is intended to be added to Dart programs
+// generated by dartfuzz.dart.
+class DartFuzzFfiApi {
+ static const ffiapi = """
+
+ffi.DynamicLibrary ffiTestFunctions =
+ ffi.DynamicLibrary.open("libffi_test_functions.so");
+
+typedef NativeBinaryOp = ffi.Int32 Function(ffi.Int32, ffi.Int32);
+typedef BinaryOp = int Function(int, int);
+BinaryOp sumPlus42 =
+ ffiTestFunctions.lookupFunction<NativeBinaryOp, BinaryOp>("SumPlus42");
+
+typedef NativeReturnMaxUint8 = ffi.Uint8 Function();
+int Function() returnMaxUint8 = ffiTestFunctions
+ .lookup("ReturnMaxUint8")
+ .cast<ffi.NativeFunction<NativeReturnMaxUint8>>()
+ .asFunction();
+
+typedef NativeReturnMaxUint16 = ffi.Uint16 Function();
+int Function() returnMaxUint16 = ffiTestFunctions
+ .lookup("ReturnMaxUint16")
+ .cast<ffi.NativeFunction<NativeReturnMaxUint16>>()
+ .asFunction();
+
+typedef NativeReturnMaxUint32 = ffi.Uint32 Function();
+int Function() returnMaxUint32 = ffiTestFunctions
+ .lookup("ReturnMaxUint32")
+ .cast<ffi.NativeFunction<NativeReturnMaxUint32>>()
+ .asFunction();
+
+typedef NativeReturnMinInt8 = ffi.Int8 Function();
+int Function() returnMinInt8 = ffiTestFunctions
+ .lookup("ReturnMinInt8")
+ .cast<ffi.NativeFunction<NativeReturnMinInt8>>()
+ .asFunction();
+
+typedef NativeReturnMinInt16 = ffi.Int16 Function();
+int Function() returnMinInt16 = ffiTestFunctions
+ .lookup("ReturnMinInt16")
+ .cast<ffi.NativeFunction<NativeReturnMinInt16>>()
+ .asFunction();
+
+typedef NativeReturnMinInt32 = ffi.Int32 Function();
+int Function() returnMinInt32 = ffiTestFunctions
+ .lookup("ReturnMinInt32")
+ .cast<ffi.NativeFunction<NativeReturnMinInt32>>()
+ .asFunction();
+
+typedef NativeTakeMaxUint8 = ffi.IntPtr Function(ffi.Uint8);
+int Function(int) takeMaxUint8 = ffiTestFunctions
+ .lookup("TakeMaxUint8")
+ .cast<ffi.NativeFunction<NativeTakeMaxUint8>>()
+ .asFunction();
+
+typedef NativeTakeMaxUint16 = ffi.IntPtr Function(ffi.Uint16);
+int Function(int) takeMaxUint16 = ffiTestFunctions
+ .lookup("TakeMaxUint16")
+ .cast<ffi.NativeFunction<NativeTakeMaxUint16>>()
+ .asFunction();
+
+typedef NativeTakeMaxUint32 = ffi.IntPtr Function(ffi.Uint32);
+int Function(int) takeMaxUint32 = ffiTestFunctions
+ .lookup("TakeMaxUint32")
+ .cast<ffi.NativeFunction<NativeTakeMaxUint32>>()
+ .asFunction();
+
+typedef NativeTakeMinInt8 = ffi.IntPtr Function(ffi.Int8);
+int Function(int) takeMinInt8 = ffiTestFunctions
+ .lookup("TakeMinInt8")
+ .cast<ffi.NativeFunction<NativeTakeMinInt8>>()
+ .asFunction();
+
+typedef NativeTakeMinInt16 = ffi.IntPtr Function(ffi.Int16);
+int Function(int) takeMinInt16 = ffiTestFunctions
+ .lookup("TakeMinInt16")
+ .cast<ffi.NativeFunction<NativeTakeMinInt16>>()
+ .asFunction();
+
+typedef NativeTakeMinInt32 = ffi.IntPtr Function(ffi.Int32);
+int Function(int) takeMinInt32 = ffiTestFunctions
+ .lookup("TakeMinInt32")
+ .cast<ffi.NativeFunction<NativeTakeMinInt32>>()
+ .asFunction();
+
+typedef NativeQuadOpSigned = ffi.Int64 Function(
+ ffi.Int8, ffi.Int16, ffi.Int32, ffi.Int64);
+typedef QuadOp = int Function(int, int, int, int);
+typedef IntComputationType = ffi.Int64 Function(
+ ffi.Int8, ffi.Int16, ffi.Int32, ffi.Int64);
+QuadOp intComputation = ffiTestFunctions
+ .lookupFunction<NativeQuadOpSigned, QuadOp>("IntComputation");
+
+typedef NativeQuadOpUnsigned = ffi.Uint64 Function(
+ ffi.Uint8, ffi.Uint16, ffi.Uint32, ffi.Uint64);
+typedef UintComputationType = ffi.Uint64 Function(
+ ffi.Uint8, ffi.Uint16, ffi.Uint32, ffi.Uint64);
+QuadOp uintComputation = ffiTestFunctions
+ .lookupFunction<NativeQuadOpUnsigned, QuadOp>("UintComputation");
+
+typedef DoubleUnaryOp = double Function(double);
+typedef NativeDoubleUnaryOp = ffi.Double Function(ffi.Double);
+DoubleUnaryOp times1_337Double = ffiTestFunctions
+ .lookupFunction<NativeDoubleUnaryOp, DoubleUnaryOp>("Times1_337Double");
+
+typedef NativeFloatUnaryOp = ffi.Float Function(ffi.Float);
+DoubleUnaryOp times1_337Float = ffiTestFunctions
+ .lookupFunction<NativeFloatUnaryOp, DoubleUnaryOp>("Times1_337Float");
+
+typedef DecenaryOp = int Function(
+ int, int, int, int, int, int, int, int, int, int);
+typedef NativeDecenaryOp = ffi.IntPtr Function(
+ ffi.IntPtr,
+ ffi.IntPtr,
+ ffi.IntPtr,
+ ffi.IntPtr,
+ ffi.IntPtr,
+ ffi.IntPtr,
+ ffi.IntPtr,
+ ffi.IntPtr,
+ ffi.IntPtr,
+ ffi.IntPtr);
+DecenaryOp sumManyInts = ffiTestFunctions
+ .lookupFunction<NativeDecenaryOp, DecenaryOp>("SumManyInts");
+
+UndenaryOp sumManyIntsOdd = ffiTestFunctions
+ .lookupFunction<NativeUndenaryOp, UndenaryOp>("SumManyIntsOdd");
+
+typedef NativeDoubleDecenaryOp = ffi.Double Function(
+ ffi.Double,
+ ffi.Double,
+ ffi.Double,
+ ffi.Double,
+ ffi.Double,
+ ffi.Double,
+ ffi.Double,
+ ffi.Double,
+ ffi.Double,
+ ffi.Double);
+typedef DoubleDecenaryOp = double Function(double, double, double, double,
+ double, double, double, double, double, double);
+DoubleDecenaryOp sumManyDoubles = ffiTestFunctions
+ .lookupFunction<NativeDoubleDecenaryOp, DoubleDecenaryOp>("SumManyDoubles");
+
+typedef NativeVigesimalOp = ffi.Double Function(
+ ffi.IntPtr,
+ ffi.Float,
+ ffi.IntPtr,
+ ffi.Double,
+ ffi.IntPtr,
+ ffi.Float,
+ ffi.IntPtr,
+ ffi.Double,
+ ffi.IntPtr,
+ ffi.Float,
+ ffi.IntPtr,
+ ffi.Double,
+ ffi.IntPtr,
+ ffi.Float,
+ ffi.IntPtr,
+ ffi.Double,
+ ffi.IntPtr,
+ ffi.Float,
+ ffi.IntPtr,
+ ffi.Double);
+typedef VigesimalOp = double Function(
+ int,
+ double,
+ int,
+ double,
+ int,
+ double,
+ int,
+ double,
+ int,
+ double,
+ int,
+ double,
+ int,
+ double,
+ int,
+ double,
+ int,
+ double,
+ int,
+ double);
+VigesimalOp sumManyNumbers = ffiTestFunctions
+ .lookupFunction<NativeVigesimalOp, VigesimalOp>("SumManyNumbers");
+
+typedef NativeSenaryOp = ffi.Int64 Function(
+ ffi.Int8, ffi.Int16, ffi.Int32, ffi.Uint8, ffi.Uint16, ffi.Uint32);
+typedef SenaryOp = int Function(int, int, int, int, int, int);
+SenaryOp sumSmallNumbers = ffiTestFunctions
+ .lookupFunction<NativeSenaryOp, SenaryOp>("SumSmallNumbers");
+
+typedef NativeFloatPointerToBool = ffi.Uint8 Function(ffi.Pointer<ffi.Float>);
+typedef FloatPointerToBool = int Function(ffi.Pointer<ffi.Float>);
+FloatPointerToBool isRoughly1337 = ffiTestFunctions.lookupFunction<
+ NativeFloatPointerToBool, FloatPointerToBool>("IsRoughly1337");
+
+typedef NativeVoidToFloat = ffi.Float Function();
+typedef VoidToDouble = double Function();
+VoidToDouble inventFloatValue = ffiTestFunctions
+ .lookupFunction<NativeVoidToFloat, VoidToDouble>("InventFloatValue");
+
+typedef NullaryOp = int Function();
+typedef NativeNullaryOp64 = ffi.Int64 Function();
+final minInt64 =
+ ffiTestFunctions.lookupFunction<NativeNullaryOp64, NullaryOp>("MinInt64");
+
+typedef NativeNullaryOp32 = ffi.Int32 Function();
+final minInt32 =
+ ffiTestFunctions.lookupFunction<NativeNullaryOp32, NullaryOp>("MinInt32");
+
+typedef NativeNullaryOpDouble = ffi.Double Function();
+typedef NullaryOpDbl = double Function();
+final smallDouble = ffiTestFunctions
+ .lookupFunction<NativeNullaryOpDouble, NullaryOpDbl>("SmallDouble");
+
+typedef NativeUndenaryOp = ffi.IntPtr Function(
+ ffi.IntPtr,
+ ffi.IntPtr,
+ ffi.IntPtr,
+ ffi.IntPtr,
+ ffi.IntPtr,
+ ffi.IntPtr,
+ ffi.IntPtr,
+ ffi.IntPtr,
+ ffi.IntPtr,
+ ffi.IntPtr,
+ ffi.IntPtr);
+typedef UndenaryOp = int Function(
+ int, int, int, int, int, int, int, int, int, int, int);
+final regress37069 = ffiTestFunctions
+ .lookupFunction<NativeUndenaryOp, UndenaryOp>("Regress37069");
+""";
+}
diff --git a/runtime/tools/dartfuzz/dartfuzz_test.dart b/runtime/tools/dartfuzz/dartfuzz_test.dart
index 6311961..e5cce1d 100644
--- a/runtime/tools/dartfuzz/dartfuzz_test.dart
+++ b/runtime/tools/dartfuzz/dartfuzz_test.dart
@@ -2,7 +2,6 @@
// 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:convert';
import 'dart:io';
import 'dart:isolate';
import 'dart:math';
@@ -29,7 +28,7 @@
/// Command runner.
TestResult runCommand(List<String> cmd, Map<String, String> env) {
ProcessResult res = Process.runSync(
- 'timeout', ['-s', '$sigkill', '$timeout'] + cmd,
+ 'timeout', ['-s', '$sigkill', '$timeout', ...cmd],
environment: env);
if (debug) {
print('\nrunning $cmd yields:\n'
@@ -44,7 +43,7 @@
String description;
// Factory.
- static TestRunner getTestRunner(String mode, bool ffi, String top, String tmp,
+ static TestRunner getTestRunner(String mode, String top, String tmp,
Map<String, String> env, String fileName, Random rand) {
String prefix = mode.substring(0, 3).toUpperCase();
String tag = getTag(mode);
@@ -79,18 +78,21 @@
prefix += '-NOINTRINSIFY';
extraFlags += ['--intrinsify=false'];
} else if (r == 2) {
- prefix += '-COMPACTEVERY';
- extraFlags += ['--gc_every=1000', '--use_compactor=true'];
+ final freq = rand.nextInt(1000) + 500;
+ prefix += '-COMPACTEVERY-${freq}';
+ extraFlags += ['--gc_every=${freq}', '--use_compactor=true'];
} else if (r == 3) {
- prefix += '-MARKSWEEPEVERY';
- extraFlags += ['--gc_every=1000', '--use_compactor=false'];
+ final freq = rand.nextInt(1000) + 500;
+ prefix += '-MARKSWEEPEVERY-${freq}';
+ extraFlags += ['--gc_every=${freq}', '--use_compactor=false'];
} else if (r == 4) {
- prefix += '-DEPOPTEVERY';
- extraFlags += ['--deoptimize_every=100'];
- } else if (r == 5 && !ffi) {
- // TODO: https://github.com/dart-lang/sdk/issues/37606
- prefix += '-STACKTRACEEVERY';
- extraFlags += ['--stacktrace_every=100'];
+ final freq = rand.nextInt(100) + 50;
+ prefix += '-DEPOPTEVERY-${freq}';
+ extraFlags += ['--deoptimize_every=${freq}'];
+ } else if (r == 5) {
+ final freq = rand.nextInt(100) + 50;
+ prefix += '-STACKTRACEEVERY-${freq}';
+ extraFlags += ['--stacktrace_every=${freq}'];
} else if (r == 6) {
prefix += '-OPTCOUNTER';
extraFlags += ['--optimization_counter_threshold=1'];
@@ -106,18 +108,26 @@
prefix += '-O3';
extraFlags += ['--optimization_level=3'];
}
+ // Every once in a while, use the slowpath flag.
+ if (!mode.startsWith('djs') && rand.nextInt(4) == 0) {
+ prefix += '-SLOWPATH';
+ extraFlags += ['--use-slow-path'];
+ }
+ // Every once in a while, use the deterministic flag.
+ if (!mode.startsWith('djs') && rand.nextInt(4) == 0) {
+ prefix += '-DET';
+ extraFlags += ['--deterministic'];
+ }
// Construct runner.
if (mode.startsWith('jit')) {
- return new TestRunnerJIT(
- prefix, tag, top, tmp, env, fileName, extraFlags);
+ return TestRunnerJIT(prefix, tag, top, tmp, env, fileName, extraFlags);
} else if (mode.startsWith('aot')) {
- return new TestRunnerAOT(
- prefix, tag, top, tmp, env, fileName, extraFlags);
+ return TestRunnerAOT(prefix, tag, top, tmp, env, fileName, extraFlags);
} else if (mode.startsWith('kbc')) {
- return new TestRunnerKBC(
+ return TestRunnerKBC(
prefix, tag, top, tmp, env, fileName, extraFlags, kbcSrc);
} else if (mode.startsWith('djs')) {
- return new TestRunnerDJS(prefix, tag, top, tmp, env, fileName);
+ return TestRunnerDJS(prefix, tag, top, tmp, env, fileName);
}
throw ('unknown runner in mode: $mode');
}
@@ -138,6 +148,9 @@
if (mode.endsWith('dbc64')) return 'ReleaseSIMDBC64';
throw ('unknown tag in mode: $mode');
}
+
+ // Print steps to reproduce build and run.
+ void printReproductionCommand();
}
/// Concrete test runner of Dart JIT.
@@ -146,13 +159,15 @@
this.fileName, List<String> extraFlags) {
description = '$prefix-$tag';
dart = '$top/out/$tag/dart';
- cmd = [dart, "--deterministic"] + extraFlags + [fileName];
+ cmd = [dart, ...extraFlags, fileName];
}
TestResult run() {
return runCommand(cmd, env);
}
+ void printReproductionCommand() => print(cmd.join(" "));
+
String description;
String dart;
String fileName;
@@ -170,23 +185,30 @@
snapshot = '$tmp/snapshot';
env = Map<String, String>.from(e);
env['DART_CONFIGURATION'] = tag;
- env['OPTIONS'] = extraFlags.join(' ');
+ cmd = [precompiler, ...extraFlags, fileName, snapshot];
}
TestResult run() {
- TestResult result = runCommand([precompiler, fileName, snapshot], env);
+ TestResult result = runCommand(cmd, env);
if (result.exitCode != 0) {
return result;
}
return runCommand([dart, snapshot], env);
}
+ void printReproductionCommand() {
+ print(
+ ["DART_CONFIGURATION=${env['DART_CONFIGURATION']}", ...cmd].join(" "));
+ print([dart, snapshot].join(" "));
+ }
+
String description;
String precompiler;
String dart;
String fileName;
String snapshot;
Map<String, String> env;
+ List<String> cmd;
}
/// Concrete test runner of bytecode.
@@ -196,12 +218,12 @@
description = '$prefix-$tag';
dart = '$top/out/$tag/dart';
if (kbcSrc) {
- cmd = [dart] + extraFlags + [fileName];
+ cmd = [dart, ...extraFlags, fileName];
} else {
generate = '$top/pkg/vm/tool/gen_kernel';
platform = '--platform=$top/out/$tag/vm_platform_strong.dill';
dill = '$tmp/out.dill';
- cmd = [dart] + extraFlags + [dill];
+ cmd = [dart, ...extraFlags, dill];
}
}
@@ -216,6 +238,12 @@
return runCommand(cmd, env);
}
+ void printReproductionCommand() {
+ print(
+ [generate, '--gen-bytecode', platform, '-o', dill, fileName].join(" "));
+ print(cmd.join(" "));
+ }
+
String description;
String generate;
String platform;
@@ -243,6 +271,11 @@
return runCommand(['nodejs', js], env);
}
+ void printReproductionCommand() {
+ print([dart2js, fileName, '-o', js].join(" "));
+ print(['nodejs', js].join(" "));
+ }
+
String description;
String dart2js;
String fileName;
@@ -286,28 +319,32 @@
}
void setup() {
- rand = new Random();
+ rand = Random();
tmpDir = Directory.systemTemp.createTempSync('dart_fuzz');
fileName = '${tmpDir.path}/fuzz.dart';
+ // Testcase generation flags.
+ // Necessary To avoid false divergences between 64 and 32 bit versions.
fp = samePrecision(mode1, mode2);
- ffi = ffiCapable(mode1, mode2);
- runner1 = TestRunner.getTestRunner(
- mode1, ffi, top, tmpDir.path, env, fileName, rand);
- runner2 = TestRunner.getTestRunner(
- mode2, ffi, top, tmpDir.path, env, fileName, rand);
+ // Occasionally test FFI.
+ ffi = ffiCapable(mode1, mode2) && (rand.nextInt(5) == 0);
+ runner1 =
+ TestRunner.getTestRunner(mode1, top, tmpDir.path, env, fileName, rand);
+ runner2 =
+ TestRunner.getTestRunner(mode2, top, tmpDir.path, env, fileName, rand);
isolate =
'Isolate (${tmpDir.path}) ${ffi ? "" : "NO-"}FFI ${fp ? "" : "NO-"}FP : '
'${runner1.description} - ${runner2.description}';
- start_time = new DateTime.now().millisecondsSinceEpoch;
+ start_time = DateTime.now().millisecondsSinceEpoch;
current_time = start_time;
report_time = start_time;
end_time = start_time + max(0, time - timeout) * 1000;
numTests = 0;
numSuccess = 0;
- numNotRun = 0;
- numTimeOut = 0;
+ numSkipped = 0;
+ numRerun = 0;
+ numTimeout = 0;
numDivergences = 0;
}
@@ -321,7 +358,7 @@
bool timeIsUp() {
if (time > 0) {
- current_time = new DateTime.now().millisecondsSinceEpoch;
+ current_time = DateTime.now().millisecondsSinceEpoch;
if (current_time > end_time) {
return true;
}
@@ -340,28 +377,36 @@
}
void showStatistics() {
- stdout.write('\rTests: $numTests Success: $numSuccess Not-Run: '
- '$numNotRun: Time-Out: $numTimeOut Divergences: $numDivergences');
+ stdout.write('\rTests: $numTests Success: $numSuccess (Rerun: $numRerun) '
+ 'Skipped: $numSkipped Timeout: $numTimeout '
+ 'Divergences: $numDivergences');
}
void generateTest() {
- final file = new File(fileName).openSync(mode: FileMode.write);
- new DartFuzz(seed, fp, ffi, file).run();
+ final file = File(fileName).openSync(mode: FileMode.write);
+ DartFuzz(seed, fp, ffi, file).run();
file.closeSync();
}
void runTest() {
TestResult result1 = runner1.run();
TestResult result2 = runner2.run();
- if (checkDivergence(result1, result2) == ReportStatus.rerun && rerun) {
+ var report = checkDivergence(result1, result2);
+ if (report == ReportStatus.rerun && rerun) {
print("\nCommencing re-run .... \n");
numDivergences--;
result1 = runner1.run();
result2 = runner2.run();
- if (checkDivergence(result1, result2) == ReportStatus.no_divergence) {
+ report = checkDivergence(result1, result2);
+ if (report == ReportStatus.no_divergence) {
print("\nNo error on re-run\n");
+ numRerun++;
}
}
+ if (report == ReportStatus.reported ||
+ (!rerun && report == ReportStatus.rerun)) {
+ showReproduce();
+ }
}
ReportStatus checkDivergence(TestResult result1, TestResult result2) {
@@ -379,11 +424,11 @@
break;
case -sigkill:
// Both had a time out.
- numTimeOut++;
+ numTimeout++;
break;
default:
// Both had an error.
- numNotRun++;
+ numSkipped++;
break;
}
} else {
@@ -392,7 +437,7 @@
// When only true divergences are requested, any divergence
// with at least one time out is treated as a regular time out.
if (result1.exitCode == -sigkill || result2.exitCode == -sigkill) {
- numTimeOut++;
+ numTimeout++;
return ReportStatus.ignored;
}
}
@@ -438,6 +483,17 @@
}
}
+ void showReproduce() {
+ print("\n-- BEGIN REPRODUCE --\n");
+ print("dartfuzz.dart --${ffi ? "" : "no-"}ffi --${fp ? "" : "no-"}fp"
+ "--seed ${seed} $fileName");
+ print("\n-- RUN 1 --\n");
+ runner1.printReproductionCommand();
+ print("\n-- RUN 2 --\n");
+ runner2.printReproductionCommand();
+ print("\n-- END REPRODUCE --\n");
+ }
+
// Context.
final Map<String, String> env;
final int repeat;
@@ -469,8 +525,9 @@
// Stats.
int numTests;
int numSuccess;
- int numNotRun;
- int numTimeOut;
+ int numSkipped;
+ int numRerun;
+ int numTimeout;
int numDivergences;
}
@@ -486,7 +543,7 @@
this.mode1,
this.mode2,
this.rerun)
- : top = getTop(tp) {}
+ : top = getTop(tp);
start() async {
print('\n**\n**** Dart Fuzz Testing Session\n**\n');
@@ -502,9 +559,9 @@
print('Show Stats : ${showStats}');
print('Dart Dev : ${top}');
// Fork.
- List<ReceivePort> ports = new List();
+ List<ReceivePort> ports = List();
for (int i = 0; i < isolates; i++) {
- ReceivePort r = new ReceivePort();
+ ReceivePort r = ReceivePort();
ports.add(r);
port = r.sendPort;
await Isolate.spawn(run, this);
@@ -528,7 +585,7 @@
try {
final m1 = getMode(session.mode1, null);
final m2 = getMode(session.mode2, m1);
- final fuzz = new DartFuzzTest(
+ final fuzz = DartFuzzTest(
Platform.environment,
session.repeat,
session.time,
@@ -561,7 +618,7 @@
// Random when not set.
if (mode == null || mode == '') {
// Pick a mode at random (cluster), different from other.
- Random rand = new Random();
+ Random rand = Random();
do {
mode = clusterModes[rand.nextInt(clusterModes.length)];
} while (mode == other);
@@ -648,7 +705,7 @@
/// Main driver for a fuzz testing session.
main(List<String> arguments) {
// Set up argument parser.
- final parser = new ArgParser()
+ final parser = ArgParser()
..addOption('isolates', help: 'number of isolates to use', defaultsTo: '1')
..addOption('repeat', help: 'number of tests to run', defaultsTo: '1000')
..addOption('time', help: 'time limit in seconds', defaultsTo: '0')
@@ -680,7 +737,7 @@
if (shards > 1) {
print('\nSHARD $shard OF $shards');
}
- new DartFuzzTestSession(
+ DartFuzzTestSession(
int.parse(results['isolates']),
int.parse(results['repeat']),
int.parse(results['time']),
diff --git a/runtime/tools/dartfuzz/dartfuzz_values.dart b/runtime/tools/dartfuzz/dartfuzz_values.dart
index 9849cf6..7886ae6 100644
--- a/runtime/tools/dartfuzz/dartfuzz_values.dart
+++ b/runtime/tools/dartfuzz/dartfuzz_values.dart
@@ -11,14 +11,14 @@
const DartType._withName(this.name);
- static const VOID = const DartType._withName('void');
- static const BOOL = const DartType._withName('bool');
- static const INT = const DartType._withName('int');
- static const DOUBLE = const DartType._withName('double');
- static const STRING = const DartType._withName('String');
- static const INT_LIST = const DartType._withName('List<int>');
- static const INT_SET = const DartType._withName('Set<int>');
- static const INT_STRING_MAP = const DartType._withName('Map<int, String>');
+ static const VOID = DartType._withName('void');
+ static const BOOL = DartType._withName('bool');
+ static const INT = DartType._withName('int');
+ static const DOUBLE = DartType._withName('double');
+ static const STRING = DartType._withName('String');
+ static const INT_LIST = DartType._withName('List<int>');
+ static const INT_SET = DartType._withName('Set<int>');
+ static const INT_STRING_MAP = DartType._withName('Map<int, String>');
// All value types.
static const allTypes = [
diff --git a/runtime/tools/dartfuzz/gen_api_table.dart b/runtime/tools/dartfuzz/gen_api_table.dart
index 4842ff0..1231006 100644
--- a/runtime/tools/dartfuzz/gen_api_table.dart
+++ b/runtime/tools/dartfuzz/gen_api_table.dart
@@ -14,9 +14,8 @@
import 'dart:io';
-import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
-import 'package:analyzer/dart/analysis/session.dart';
import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/dart/analysis/session.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
@@ -31,35 +30,35 @@
}
// Lists of recognized methods, organized by return type.
-var boolTable = List<DartLib>();
-var intTable = List<DartLib>();
-var doubleTable = List<DartLib>();
-var stringTable = List<DartLib>();
-var listTable = List<DartLib>();
-var setTable = List<DartLib>();
-var mapTable = List<DartLib>();
+var boolTable = <DartLib>[];
+var intTable = <DartLib>[];
+var doubleTable = <DartLib>[];
+var stringTable = <DartLib>[];
+var listTable = <DartLib>[];
+var setTable = <DartLib>[];
+var mapTable = <DartLib>[];
main() async {
// Set paths. Note that for this particular use case, packageRoot can be
// any directory. Here, we set it to the top of the SDK development, and
// derive the required sdkPath from there.
- String packageRoot = Platform.environment['DART_TOP'];
+ final String packageRoot = Platform.environment['DART_TOP'];
if (packageRoot == null) {
- throw new StateError('No environment variable DART_TOP');
+ throw StateError('No environment variable DART_TOP');
}
- String sdkPath = '$packageRoot/tools/sdks/dart-sdk';
+ final sdkPath = '$packageRoot/tools/sdks/dart-sdk';
// This does most of the hard work of getting the analyzer configured
// correctly. Typically the included paths are the files and directories
// that need to be analyzed, but the SDK is always available, so it isn't
// really important for this particular use case. We use the implementation
// class in order to pass in the sdkPath directly.
- PhysicalResourceProvider provider = PhysicalResourceProvider.INSTANCE;
- AnalysisContextCollection collection = new AnalysisContextCollectionImpl(
+ final provider = PhysicalResourceProvider.INSTANCE;
+ final collection = AnalysisContextCollectionImpl(
includedPaths: <String>[packageRoot],
resourceProvider: provider,
sdkPath: sdkPath);
- AnalysisSession session = collection.contexts[0].currentSession;
+ final AnalysisSession session = collection.contexts[0].currentSession;
// Visit libraries for table generation.
await visitLibraryAtUri(session, 'dart:async');
@@ -85,10 +84,10 @@
}
visitLibraryAtUri(AnalysisSession session, String uri) async {
- String libPath = session.uriConverter.uriToPath(Uri.parse(uri));
+ final String libPath = session.uriConverter.uriToPath(Uri.parse(uri));
ResolvedLibraryResult result = await session.getResolvedLibrary(libPath);
if (result.state != ResultState.VALID) {
- throw new StateError('Unable to resolve "$uri"');
+ throw StateError('Unable to resolve "$uri"');
}
visitLibrary(result.element);
}
@@ -140,7 +139,7 @@
for (ConstructorElement constructor in classElement.constructors) {
if (constructor.isPublic &&
constructor.isFactory &&
- !constructor.name.isEmpty) {
+ constructor.name.isNotEmpty) {
addToTable(
typeString(classElement.type),
'${classElement.name}.${constructor.name}',
@@ -244,6 +243,8 @@
return setTable;
case 'M':
return mapTable;
+ default:
+ throw ArgumentError('Invalid ret value: $ret');
}
}
diff --git a/runtime/tools/dartfuzz/pubspec.yaml b/runtime/tools/dartfuzz/pubspec.yaml
new file mode 100644
index 0000000..1e5277e
--- /dev/null
+++ b/runtime/tools/dartfuzz/pubspec.yaml
@@ -0,0 +1,7 @@
+name: dartfuzz
+
+environment:
+ sdk: '>=2.2.2 <3.0.0'
+
+dev_dependencies:
+ pedantic: 'any'
diff --git a/runtime/tools/run_clang_tidy.dart b/runtime/tools/run_clang_tidy.dart
new file mode 100644
index 0000000..d165e77
--- /dev/null
+++ b/runtime/tools/run_clang_tidy.dart
@@ -0,0 +1,163 @@
+// Copyright (c) 2019, 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 'dart:math';
+
+import 'package:pool/pool.dart';
+
+const String clangTidy = './buildtools/linux-x64/clang/bin/clang-tidy';
+
+List<String> compilerFlagsForFile(String filepath) {
+ final flags = <String>[
+ '-Iruntime',
+ '-Ithird_party',
+ '-Iruntime/include',
+ '-Ithird_party/tcmalloc/gperftools/src',
+ '-Ithird_party/boringssl/src/include',
+ '-Ithird_party/zlib',
+ '-DTARGET_ARCH_X64',
+ '-DDEBUG',
+ '-DTARGET_OS_LINUX',
+ '-DTESTING',
+ '-x',
+ 'c++',
+ ];
+ return flags;
+}
+
+Future<ProcessResult> runClangTidyOn(String filepath) async {
+ // The `runtime/.clang-tidy` file has the enabled checks in it.
+ final args = <String>['-quiet', filepath, '--']
+ ..addAll(compilerFlagsForFile(filepath));
+ return await Process.run(clangTidy, args);
+}
+
+final pool = new Pool(max(1, Platform.numberOfProcessors ~/ 2));
+
+// Exclude running the linter on those files.
+final Set<String> excludedFiles = Set<String>.from([
+ // These files are not valid cc files but rather cc templates
+ 'runtime/bin/abi_version_in.cc',
+ 'runtime/bin/builtin_in.cc',
+ 'runtime/bin/snapshot_in.cc',
+ 'runtime/lib/libgen_in.cc',
+ 'runtime/vm/version_in.cc',
+
+ // These files cannot be analyzed by itself (must be included indirectly).
+ 'runtime/bin/android.h',
+ 'runtime/bin/eventhandler_android.h',
+ 'runtime/bin/eventhandler_fuchsia.h',
+ 'runtime/bin/eventhandler_linux.h',
+ 'runtime/bin/eventhandler_macos.h',
+ 'runtime/bin/eventhandler_win.h',
+ 'runtime/bin/namespace_android.h',
+ 'runtime/bin/namespace_fuchsia.h',
+ 'runtime/bin/namespace_linux.h',
+ 'runtime/bin/namespace_macos.h',
+ 'runtime/bin/namespace_win.h',
+ 'runtime/bin/socket_base_android.h',
+ 'runtime/bin/socket_base_fuchsia.h',
+ 'runtime/bin/socket_base_linux.h',
+ 'runtime/bin/socket_base_macos.h',
+ 'runtime/bin/socket_base_win.h',
+ 'runtime/bin/thread_android.h',
+ 'runtime/bin/thread_fuchsia.h',
+ 'runtime/bin/thread_linux.h',
+ 'runtime/bin/thread_macos.h',
+ 'runtime/bin/thread_win.h',
+ 'runtime/platform/atomic_android.h',
+ 'runtime/platform/atomic_fuchsia.h',
+ 'runtime/platform/atomic_linux.h',
+ 'runtime/platform/atomic_macos.h',
+ 'runtime/platform/atomic_win.h',
+ 'runtime/platform/utils_android.h',
+ 'runtime/platform/utils_fuchsia.h',
+ 'runtime/platform/utils_linux.h',
+ 'runtime/platform/utils_macos.h',
+ 'runtime/platform/utils_win.h',
+ 'runtime/vm/compiler/assembler/assembler_arm64.h',
+ 'runtime/vm/compiler/assembler/assembler_arm.h',
+ 'runtime/vm/compiler/assembler/assembler_dbc.h',
+ 'runtime/vm/compiler/assembler/assembler_ia32.h',
+ 'runtime/vm/compiler/assembler/assembler_x64.h',
+ 'runtime/vm/compiler/runtime_offsets_extracted.h',
+ 'runtime/vm/constants_arm64.h',
+ 'runtime/vm/constants_arm.h',
+ 'runtime/vm/constants_dbc.h',
+ 'runtime/vm/constants_ia32.h',
+ 'runtime/vm/constants_x64.h',
+ 'runtime/vm/cpu_arm64.h',
+ 'runtime/vm/cpu_arm.h',
+ 'runtime/vm/cpu_dbc.h',
+ 'runtime/vm/cpu_ia32.h',
+ 'runtime/vm/cpu_x64.h',
+ 'runtime/vm/instructions_arm64.h',
+ 'runtime/vm/instructions_arm.h',
+ 'runtime/vm/instructions_dbc.h',
+ 'runtime/vm/instructions_ia32.h',
+ 'runtime/vm/instructions_x64.h',
+ 'runtime/vm/os_thread_android.h',
+ 'runtime/vm/os_thread_fuchsia.h',
+ 'runtime/vm/os_thread_linux.h',
+ 'runtime/vm/os_thread_macos.h',
+ 'runtime/vm/os_thread_win.h',
+ 'runtime/vm/regexp_assembler_bytecode_inl.h',
+ 'runtime/vm/simulator_arm64.h',
+ 'runtime/vm/simulator_arm.h',
+ 'runtime/vm/simulator_dbc.h',
+ 'runtime/vm/stack_frame_arm64.h',
+ 'runtime/vm/stack_frame_arm.h',
+ 'runtime/vm/stack_frame_dbc.h',
+ 'runtime/vm/stack_frame_ia32.h',
+ 'runtime/vm/stack_frame_x64.h',
+
+ // By default the gclient checkout doesn't have llvm pulled in.
+ 'runtime/llvm_codegen/bit/bit.h',
+ 'runtime/llvm_codegen/bit/main.cc',
+ 'runtime/llvm_codegen/bit/test.cc',
+ 'runtime/llvm_codegen/codegen/main.cc',
+
+ // Only available in special builds
+ 'runtime/bin/io_service_no_ssl.h',
+ 'runtime/bin/utils_win.h',
+ 'runtime/vm/compiler/backend/locations_helpers_arm.h',
+]);
+
+main(List<String> files) async {
+ bool isFirstFailure = true;
+
+ files = files.where((filepath) => !excludedFiles.contains(filepath)).toList();
+
+ // Analyze the [files] in parallel.
+ await Future.wait(files.map((String filepath) async {
+ final processResult =
+ await pool.withResource(() => runClangTidyOn(filepath));
+
+ final int exitCode = processResult.exitCode;
+ final String stdout = processResult.stdout.trim();
+ final String stderr = processResult.stderr.trim();
+
+ if (exitCode != 0 || stdout.isNotEmpty) {
+ if (!isFirstFailure) {
+ print('');
+ print('--------------------------------------------------------------');
+ print('');
+ }
+ isFirstFailure = false;
+ }
+
+ if (exitCode != 0) {
+ print('exit-code: $exitCode');
+ print('stdout:');
+ print('${stdout}');
+ print('stderr:');
+ print('${stderr}');
+ } else if (stdout.isNotEmpty) {
+ // The actual lints go to stdout.
+ print(stdout);
+ }
+ }));
+}
diff --git a/runtime/vm/BUILD.gn b/runtime/vm/BUILD.gn
index 6b9f82f..a526aec 100644
--- a/runtime/vm/BUILD.gn
+++ b/runtime/vm/BUILD.gn
@@ -16,6 +16,7 @@
import("../../sdk/lib/profiler/profiler_sources.gni")
import("../../sdk/lib/typed_data/typed_data_sources.gni")
import("../../sdk/lib/vmservice/vmservice_sources.gni")
+import("../../sdk/lib/wasm/wasm_sources.gni")
import("../../utils/compile_platform.gni")
import("../bin/cli_sources.gni")
import("../bin/io_sources.gni")
@@ -33,6 +34,7 @@
import("../lib/profiler_sources.gni")
import("../lib/typed_data_sources.gni")
import("../lib/vmservice_sources.gni")
+import("../lib/wasm_sources.gni")
import("../runtime_args.gni")
import("compiler/compiler_sources.gni")
import("heap/heap_sources.gni")
@@ -106,7 +108,7 @@
internal_runtime_cc_files + isolate_runtime_cc_files +
math_runtime_cc_files + mirrors_runtime_cc_files +
typed_data_runtime_cc_files + vmservice_runtime_cc_files +
- ffi_runtime_cc_files
+ ffi_runtime_cc_files + wasm_runtime_cc_files
sources = [ "bootstrap.cc" ] + rebase_path(allsources, ".", "../lib")
snapshot_sources = []
nosnapshot_sources = []
@@ -140,24 +142,13 @@
if (defined(invoker.exclude_source) && invoker.exclude_source) {
args += [ "--exclude-source" ]
}
- if (defined(invoker.legacy) && invoker.legacy) {
- args += [ "--legacy-mode" ]
- outline = "vm_outline_strong.dill"
- } else {
- outline = "vm_outline" + output_postfix + ".dill"
- }
+ outline = "vm_outline" + output_postfix + ".dill"
if (dart_platform_bytecode) {
args += [ "--bytecode" ]
}
}
}
-gen_vm_platform("vm_legacy_platform") {
- exclude_source = false
- legacy = true
- output_postfix = ""
-}
-
gen_vm_platform("vm_platform") {
add_implicit_vm_platform_dependency = false
exclude_source = false
@@ -172,7 +163,6 @@
group("kernel_platform_files") {
public_deps = [
- ":vm_legacy_platform",
":vm_platform",
":vm_platform_stripped",
]
diff --git a/runtime/vm/benchmark_test.cc b/runtime/vm/benchmark_test.cc
index a95642a..db49703 100644
--- a/runtime/vm/benchmark_test.cc
+++ b/runtime/vm/benchmark_test.cc
@@ -511,25 +511,13 @@
return reinterpret_cast<uint8_t*>(realloc(ptr, new_size));
}
-BENCHMARK_SIZE(CoreSnapshotSize) {
- const char* kScriptChars =
- "import 'dart:async';\n"
- "import 'dart:core';\n"
- "import 'dart:collection';\n"
- "import 'dart:_internal';\n"
- "import 'dart:math';\n"
- "import 'dart:isolate';\n"
- "import 'dart:mirrors';\n"
- "import 'dart:typed_data';\n"
- "\n";
-
- // Start an Isolate, load a script and create a full snapshot.
- uint8_t* vm_snapshot_data_buffer;
- uint8_t* isolate_snapshot_data_buffer;
+// Start an Isolate, load a script and create a full snapshot.
+static void BenchmarkSnapshotSize(Benchmark* benchmark, const char* script) {
// Need to load the script into the dart: core library due to
// the import of dart:_internal.
- TestCase::LoadCoreTestScript(kScriptChars, NULL);
+ TestCase::LoadCoreTestScript(script, nullptr);
+ Thread* thread = Thread::Current();
TransitionNativeToVM transition(thread);
StackZone zone(thread);
HANDLESCOPE(thread);
@@ -537,58 +525,63 @@
Api::CheckAndFinalizePendingClasses(thread);
// Write snapshot with object content.
+ uint8_t* vm_snapshot_data_buffer = nullptr;
+ uint8_t* isolate_snapshot_data_buffer = nullptr;
+ uint8_t* vm_snapshot_text_buffer = nullptr;
+ uint8_t* isolate_snapshot_text_buffer = nullptr;
+ BlobImageWriter vm_image_writer(thread, &vm_snapshot_text_buffer,
+ &malloc_allocator, 2 * MB /* initial_size */,
+ /*shared_objects=*/nullptr,
+ /*shared_instructions=*/nullptr,
+ /*reused_instructions=*/nullptr);
+ BlobImageWriter isolate_image_writer(thread, &isolate_snapshot_text_buffer,
+ &malloc_allocator,
+ 2 * MB /* initial_size */,
+ /*shared_objects=*/nullptr,
+ /*shared_instructions=*/nullptr,
+ /*reused_instructions=*/nullptr);
FullSnapshotWriter writer(Snapshot::kFull, &vm_snapshot_data_buffer,
&isolate_snapshot_data_buffer, &malloc_allocator,
- NULL, NULL /* image_writer */);
+ &vm_image_writer, &isolate_image_writer);
writer.WriteFullSnapshot();
const Snapshot* snapshot =
Snapshot::SetupFromBuffer(isolate_snapshot_data_buffer);
ASSERT(snapshot->kind() == Snapshot::kFull);
- benchmark->set_score(snapshot->length());
+ benchmark->set_score(writer.IsolateSnapshotSize() +
+ isolate_image_writer.data_size());
free(vm_snapshot_data_buffer);
+ free(vm_snapshot_text_buffer);
free(isolate_snapshot_data_buffer);
+ free(isolate_snapshot_text_buffer);
+}
+
+BENCHMARK_SIZE(CoreSnapshotSize) {
+ BenchmarkSnapshotSize(benchmark,
+ "import 'dart:async';\n"
+ "import 'dart:core';\n"
+ "import 'dart:collection';\n"
+ "import 'dart:_internal';\n"
+ "import 'dart:math';\n"
+ "import 'dart:isolate';\n"
+ "import 'dart:mirrors';\n"
+ "import 'dart:typed_data';\n"
+ "\n");
}
BENCHMARK_SIZE(StandaloneSnapshotSize) {
- const char* kScriptChars =
- "import 'dart:async';\n"
- "import 'dart:core';\n"
- "import 'dart:collection';\n"
- "import 'dart:convert';\n"
- "import 'dart:math';\n"
- "import 'dart:isolate';\n"
- "import 'dart:mirrors';\n"
- "import 'dart:typed_data';\n"
- "import 'dart:io';\n"
- "import 'dart:cli';\n"
- "\n";
-
- // Start an Isolate, load a script and create a full snapshot.
- uint8_t* vm_snapshot_data_buffer;
- uint8_t* isolate_snapshot_data_buffer;
- // Need to load the script into the dart: core library due to
- // the import of dart:_internal.
- TestCase::LoadCoreTestScript(kScriptChars, NULL);
-
- TransitionNativeToVM transition(thread);
- StackZone zone(thread);
- HANDLESCOPE(thread);
-
- Api::CheckAndFinalizePendingClasses(thread);
-
- // Write snapshot with object content.
- FullSnapshotWriter writer(Snapshot::kFull, &vm_snapshot_data_buffer,
- &isolate_snapshot_data_buffer, &malloc_allocator,
- NULL, NULL /* image_writer */);
- writer.WriteFullSnapshot();
- const Snapshot* snapshot =
- Snapshot::SetupFromBuffer(isolate_snapshot_data_buffer);
- ASSERT(snapshot->kind() == Snapshot::kFull);
- benchmark->set_score(snapshot->length());
-
- free(vm_snapshot_data_buffer);
- free(isolate_snapshot_data_buffer);
+ BenchmarkSnapshotSize(benchmark,
+ "import 'dart:async';\n"
+ "import 'dart:core';\n"
+ "import 'dart:collection';\n"
+ "import 'dart:convert';\n"
+ "import 'dart:math';\n"
+ "import 'dart:isolate';\n"
+ "import 'dart:mirrors';\n"
+ "import 'dart:typed_data';\n"
+ "import 'dart:io';\n"
+ "import 'dart:cli';\n"
+ "\n");
}
BENCHMARK(CreateMirrorSystem) {
diff --git a/runtime/vm/bootstrap.cc b/runtime/vm/bootstrap.cc
index 0cf802f..584baa3 100644
--- a/runtime/vm/bootstrap.cc
+++ b/runtime/vm/bootstrap.cc
@@ -60,6 +60,12 @@
field ^= fields.At(i);
field.set_is_unboxing_candidate(false);
}
+ // _Closure._hash field should be explicitly marked as nullable because
+ // VM creates instances of _Closure without compiling its constructors,
+ // so it won't get nullability info from a constructor.
+ field ^= fields.At(fields.Length() - 1);
+ ASSERT(String::Handle(zone, field.UserVisibleName()).Equals("_hash"));
+ field.RecordStore(Object::null_object());
#if defined(DEBUG)
// Verify that closure field offsets are identical in Dart and C++.
diff --git a/runtime/vm/bootstrap_natives.cc b/runtime/vm/bootstrap_natives.cc
index a0e99e3..f733331 100644
--- a/runtime/vm/bootstrap_natives.cc
+++ b/runtime/vm/bootstrap_natives.cc
@@ -141,6 +141,11 @@
ASSERT(!library.IsNull());
library.set_native_entry_resolver(resolver);
library.set_native_entry_symbol_resolver(symbol_resolver);
+
+ library = Library::WasmLibrary();
+ ASSERT(!library.IsNull());
+ library.set_native_entry_resolver(resolver);
+ library.set_native_entry_symbol_resolver(symbol_resolver);
}
bool Bootstrap::IsBootstrapResolver(Dart_NativeEntryResolver resolver) {
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 386d4fb..efccf88 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -12,6 +12,7 @@
namespace dart {
// List of bootstrap native entry points used in the core dart library.
+// V(function_name, argument_count)
#define BOOTSTRAP_NATIVE_LIST(V) \
V(AsyncStarMoveNext_debuggerStepCheck, 1) \
V(DartAsync_fatal, 1) \
@@ -352,10 +353,6 @@
V(WeakProperty_getValue, 1) \
V(WeakProperty_setValue, 2) \
V(Uri_isWindowsPlatform, 0) \
- V(LibraryPrefix_load, 1) \
- V(LibraryPrefix_invalidateDependentCode, 1) \
- V(LibraryPrefix_loadError, 1) \
- V(LibraryPrefix_isLoaded, 1) \
V(UserTag_new, 2) \
V(UserTag_label, 1) \
V(UserTag_defaultTag, 0) \
@@ -384,7 +381,8 @@
V(Ffi_cast, 1) \
V(Ffi_sizeOf, 0) \
V(Ffi_asFunctionInternal, 1) \
- V(Ffi_fromFunction, 2) \
+ V(Ffi_nativeCallbackFunction, 2) \
+ V(Ffi_pointerFromFunction, 1) \
V(Ffi_dl_open, 1) \
V(Ffi_dl_lookup, 2) \
V(Ffi_dl_getHandle, 1) \
@@ -392,7 +390,8 @@
V(Ffi_dl_processLibrary, 0) \
V(Ffi_dl_executableLibrary, 0) \
V(TransferableTypedData_factory, 2) \
- V(TransferableTypedData_materialize, 1)
+ V(TransferableTypedData_materialize, 1) \
+ V(Wasm_callFunction, 2)
// List of bootstrap native entry points used in the dart:mirror library.
#define MIRRORS_BOOTSTRAP_NATIVE_LIST(V) \
diff --git a/runtime/vm/bss_relocs.cc b/runtime/vm/bss_relocs.cc
new file mode 100644
index 0000000..7e01696
--- /dev/null
+++ b/runtime/vm/bss_relocs.cc
@@ -0,0 +1,17 @@
+// Copyright (c) 2019, 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.
+
+#include <vm/bss_relocs.h>
+#include <vm/runtime_entry.h>
+#include <vm/thread.h>
+
+namespace dart {
+
+void BSS::Initialize(Thread* current, uword* bss_start) {
+ bss_start[BSS::RelocationIndex(
+ BSS::Relocation::DRT_GetThreadForNativeCallback)] =
+ reinterpret_cast<uword>(DLRT_GetThreadForNativeCallback);
+}
+
+} // namespace dart
diff --git a/runtime/vm/bss_relocs.h b/runtime/vm/bss_relocs.h
new file mode 100644
index 0000000..aa3c1f7
--- /dev/null
+++ b/runtime/vm/bss_relocs.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#ifndef RUNTIME_VM_BSS_RELOCS_H_
+#define RUNTIME_VM_BSS_RELOCS_H_
+
+#include <platform/allocation.h>
+
+namespace dart {
+class Thread;
+
+class BSS : public AllStatic {
+ public:
+ enum class Relocation : intptr_t {
+ DRT_GetThreadForNativeCallback = 0,
+ NumRelocations = 1
+ };
+
+ static intptr_t RelocationIndex(Relocation reloc) {
+ return static_cast<intptr_t>(reloc);
+ }
+
+ static void Initialize(Thread* current, uword* bss);
+};
+
+} // namespace dart
+
+#endif // RUNTIME_VM_BSS_RELOCS_H_
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 7a33519..aa21dc9 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -1241,12 +1241,6 @@
sentinel.SetStaticValue(enum_value, true);
sentinel.RecordStore(enum_value);
- const GrowableObjectArray& pending_unevaluated_const_fields =
- GrowableObjectArray::Handle(zone,
- thread->isolate()
- ->object_store()
- ->pending_unevaluated_const_fields());
-
ASSERT(enum_cls.is_declared_in_bytecode() || enum_cls.kernel_offset() > 0);
Error& error = Error::Handle(zone);
for (intptr_t i = 0; i < fields.Length(); i++) {
@@ -1255,20 +1249,13 @@
(sentinel.raw() == field.raw())) {
continue;
}
- // The eager evaluation of the enum values is required for hot-reload (see
- // commit e3ecc87). However, while busy loading the constant table, we
- // need to postpone this evaluation until table is done.
+ // Hot-reload expects the static const fields to be evaluated when
+ // performing a reload.
if (!FLAG_precompiled_mode) {
if (field.IsUninitialized()) {
- if (pending_unevaluated_const_fields.IsNull()) {
- // Evaluate right away.
- error = field.Initialize();
- if (!error.IsNull()) {
- ReportError(error);
- }
- } else {
- // Postpone evaluation until we have a constant table.
- pending_unevaluated_const_fields.Add(field);
+ error = field.Initialize();
+ if (!error.IsNull()) {
+ ReportError(error);
}
}
}
diff --git a/runtime/vm/class_table.cc b/runtime/vm/class_table.cc
index 624c4bc..7a7f898 100644
--- a/runtime/vm/class_table.cc
+++ b/runtime/vm/class_table.cc
@@ -253,7 +253,12 @@
if (raw_cls == NULL) {
table_[index] = ClassAndSize(raw_cls, 0);
} else {
- table_[index] = ClassAndSize(raw_cls, Class::instance_size(raw_cls));
+ // Ensure we never change size for a given cid from one non-zero size to
+ // another non-zero size.
+ const intptr_t old_size = table_[index].size_;
+ const intptr_t new_size = Class::instance_size(raw_cls);
+ ASSERT(old_size == 0 || old_size == new_size);
+ table_[index] = ClassAndSize(raw_cls, new_size);
}
}
diff --git a/runtime/vm/class_table.h b/runtime/vm/class_table.h
index df677a5..3de2d46 100644
--- a/runtime/vm/class_table.h
+++ b/runtime/vm/class_table.h
@@ -193,6 +193,47 @@
explicit ClassTable(ClassTable* original);
~ClassTable();
+ void CopyBeforeHotReload(ClassAndSize** copy, intptr_t* copy_num_cids) {
+ // The [IsolateReloadContext] will need to maintain a copy of the old class
+ // table until instances have been morphed.
+ const intptr_t bytes = sizeof(ClassAndSize) * NumCids();
+ *copy_num_cids = NumCids();
+ *copy = static_cast<ClassAndSize*>(malloc(bytes));
+ memmove(*copy, table_, bytes);
+ }
+
+ void ResetBeforeHotReload() {
+ // The [IsolateReloadContext] is now source-of-truth for GC.
+ //
+ // Though we cannot clear out the class pointers, because a hot-reload
+ // contains only a diff: If e.g. a class included in the hot-reload has a
+ // super class not included in the diff, it will look up in this class table
+ // to find the super class (e.g. `cls.SuperClass` will cause us to come
+ // here).
+ for (intptr_t i = 0; i < top_; ++i) {
+ table_[i].size_ = 0;
+ }
+ }
+
+ void ResetAfterHotReload(ClassAndSize* old_table,
+ intptr_t num_old_cids,
+ bool is_rollback) {
+ // The [IsolateReloadContext] is no longer source-of-truth for GC after we
+ // return, so we restore size information for all classes.
+ if (is_rollback) {
+ SetNumCids(num_old_cids);
+ memmove(table_, old_table, num_old_cids * sizeof(ClassAndSize));
+ } else {
+ CopySizesFromClassObjects();
+ }
+
+ // Can't free this table immediately as another thread (e.g., concurrent
+ // marker or sweeper) may be between loading the table pointer and loading
+ // the table element. The table will be freed at the next major GC or
+ // isolate shutdown.
+ AddOldTable(old_table);
+ }
+
// Thread-safe.
RawClass* At(intptr_t index) const {
ASSERT(IsValidIndex(index));
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index dab1e6d..1939554 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -6,6 +6,7 @@
#include "platform/assert.h"
#include "vm/bootstrap.h"
+#include "vm/bss_relocs.h"
#include "vm/class_id.h"
#include "vm/code_observers.h"
#include "vm/compiler/backend/code_statistics.h"
@@ -613,7 +614,7 @@
func.SetInstructions(StubCode::InterpretCall());
} else if (FLAG_use_bytecode_compiler && func.HasBytecode()) {
func.SetInstructions(StubCode::LazyCompile());
-#endif // !defined(DART_PRECOMPILED_RUNTIME)
+#endif // !defined(DART_PRECOMPILED_RUNTIME)
} else {
func.ClearCode(); // Set code and entrypoint to lazy compile stub.
}
@@ -800,9 +801,12 @@
AutoTraceObject(data);
WriteFromTo(data);
- // TODO(37295): FFI callbacks shouldn't be written to a snapshot. They
- // should only be referenced by the callback registry in Thread.
- ASSERT(data->ptr()->callback_id_ == 0);
+ if (s->kind() == Snapshot::kFullAOT) {
+ s->WriteUnsigned(data->ptr()->callback_id_);
+ } else {
+ // FFI callbacks can only be written to AOT snapshots.
+ ASSERT(data->ptr()->callback_target_ == Object::null());
+ }
}
}
@@ -834,7 +838,8 @@
Deserializer::InitializeHeader(data, kFfiTrampolineDataCid,
FfiTrampolineData::InstanceSize());
ReadFromTo(data);
- data->ptr()->callback_id_ = 0;
+ data->ptr()->callback_id_ =
+ d->kind() == Snapshot::kFullAOT ? d->ReadUnsigned() : 0;
}
}
};
@@ -1622,8 +1627,7 @@
WriteFromTo(bytecode);
s->Write<int32_t>(bytecode->ptr()->instructions_binary_offset_);
s->Write<int32_t>(bytecode->ptr()->source_positions_binary_offset_);
- NOT_IN_PRODUCT(
- s->Write<int32_t>(bytecode->ptr()->local_variables_binary_offset_));
+ s->Write<int32_t>(bytecode->ptr()->local_variables_binary_offset_);
}
}
@@ -1658,8 +1662,7 @@
ReadFromTo(bytecode);
bytecode->ptr()->instructions_binary_offset_ = d->Read<int32_t>();
bytecode->ptr()->source_positions_binary_offset_ = d->Read<int32_t>();
- NOT_IN_PRODUCT(bytecode->ptr()->local_variables_binary_offset_ =
- d->Read<int32_t>());
+ bytecode->ptr()->local_variables_binary_offset_ = d->Read<int32_t>();
}
}
@@ -2841,7 +2844,6 @@
ReadFromTo(prefix);
prefix->ptr()->num_imports_ = d->Read<uint16_t>();
prefix->ptr()->is_deferred_load_ = d->Read<bool>();
- prefix->ptr()->is_loaded_ = !prefix->ptr()->is_deferred_load_;
}
}
};
@@ -3303,19 +3305,6 @@
}
void ReadFill(Deserializer* d) {}
-
- void PostLoad(const Array& refs, Snapshot::Kind kind, Zone* zone) {
- const Class& mint_cls =
- Class::Handle(zone, Isolate::Current()->object_store()->mint_class());
- mint_cls.set_constants(Object::empty_array());
- Object& number = Object::Handle(zone);
- for (intptr_t i = start_index_; i < stop_index_; i++) {
- number = refs.At(i);
- if (number.IsMint() && number.IsCanonical()) {
- mint_cls.InsertCanonicalMint(zone, Mint::Cast(number));
- }
- }
- }
};
#if !defined(DART_PRECOMPILED_RUNTIME)
@@ -4097,159 +4086,6 @@
};
#if !defined(DART_PRECOMPILED_RUNTIME)
-class OneByteStringSerializationCluster : public SerializationCluster {
- public:
- OneByteStringSerializationCluster() : SerializationCluster("OneByteString") {}
- ~OneByteStringSerializationCluster() {}
-
- void Trace(Serializer* s, RawObject* object) {
- RawOneByteString* str = reinterpret_cast<RawOneByteString*>(object);
- objects_.Add(str);
- }
-
- void WriteAlloc(Serializer* s) {
- s->WriteCid(kOneByteStringCid);
- intptr_t count = objects_.length();
- s->WriteUnsigned(count);
- for (intptr_t i = 0; i < count; i++) {
- RawOneByteString* str = objects_[i];
- s->AssignRef(str);
- AutoTraceObject(str);
- intptr_t length = Smi::Value(str->ptr()->length_);
- s->WriteUnsigned(length);
- }
- }
-
- void WriteFill(Serializer* s) {
- intptr_t count = objects_.length();
- for (intptr_t i = 0; i < count; i++) {
- RawOneByteString* str = objects_[i];
- AutoTraceObject(str);
- intptr_t length = Smi::Value(str->ptr()->length_);
- s->WriteUnsigned(length);
- s->Write<bool>(str->IsCanonical());
- intptr_t hash = String::GetCachedHash(str);
- s->Write<int32_t>(hash);
- s->WriteBytes(str->ptr()->data(), length);
- }
- }
-
- private:
- GrowableArray<RawOneByteString*> objects_;
-};
-#endif // !DART_PRECOMPILED_RUNTIME
-
-class OneByteStringDeserializationCluster : public DeserializationCluster {
- public:
- OneByteStringDeserializationCluster() {}
- ~OneByteStringDeserializationCluster() {}
-
- void ReadAlloc(Deserializer* d) {
- start_index_ = d->next_index();
- PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->ReadUnsigned();
- for (intptr_t i = 0; i < count; i++) {
- intptr_t length = d->ReadUnsigned();
- d->AssignRef(AllocateUninitialized(old_space,
- OneByteString::InstanceSize(length)));
- }
- stop_index_ = d->next_index();
- }
-
- void ReadFill(Deserializer* d) {
- for (intptr_t id = start_index_; id < stop_index_; id++) {
- RawOneByteString* str = reinterpret_cast<RawOneByteString*>(d->Ref(id));
- intptr_t length = d->ReadUnsigned();
- bool is_canonical = d->Read<bool>();
- Deserializer::InitializeHeader(str, kOneByteStringCid,
- OneByteString::InstanceSize(length),
- is_canonical);
- str->ptr()->length_ = Smi::New(length);
- String::SetCachedHash(str, d->Read<int32_t>());
- for (intptr_t j = 0; j < length; j++) {
- str->ptr()->data()[j] = d->Read<uint8_t>();
- }
- }
- }
-};
-
-#if !defined(DART_PRECOMPILED_RUNTIME)
-class TwoByteStringSerializationCluster : public SerializationCluster {
- public:
- TwoByteStringSerializationCluster() : SerializationCluster("TwoByteString") {}
- ~TwoByteStringSerializationCluster() {}
-
- void Trace(Serializer* s, RawObject* object) {
- RawTwoByteString* str = reinterpret_cast<RawTwoByteString*>(object);
- objects_.Add(str);
- }
-
- void WriteAlloc(Serializer* s) {
- s->WriteCid(kTwoByteStringCid);
- intptr_t count = objects_.length();
- s->WriteUnsigned(count);
- for (intptr_t i = 0; i < count; i++) {
- RawTwoByteString* str = objects_[i];
- s->AssignRef(str);
- AutoTraceObject(str);
- intptr_t length = Smi::Value(str->ptr()->length_);
- s->WriteUnsigned(length);
- }
- }
-
- void WriteFill(Serializer* s) {
- intptr_t count = objects_.length();
- for (intptr_t i = 0; i < count; i++) {
- RawTwoByteString* str = objects_[i];
- AutoTraceObject(str);
- intptr_t length = Smi::Value(str->ptr()->length_);
- s->WriteUnsigned(length);
- s->Write<bool>(str->IsCanonical());
- intptr_t hash = String::GetCachedHash(str);
- s->Write<int32_t>(hash);
- s->WriteBytes(reinterpret_cast<uint8_t*>(str->ptr()->data()), length * 2);
- }
- }
-
- private:
- GrowableArray<RawTwoByteString*> objects_;
-};
-#endif // !DART_PRECOMPILED_RUNTIME
-
-class TwoByteStringDeserializationCluster : public DeserializationCluster {
- public:
- TwoByteStringDeserializationCluster() {}
- ~TwoByteStringDeserializationCluster() {}
-
- void ReadAlloc(Deserializer* d) {
- start_index_ = d->next_index();
- PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->ReadUnsigned();
- for (intptr_t i = 0; i < count; i++) {
- intptr_t length = d->ReadUnsigned();
- d->AssignRef(AllocateUninitialized(old_space,
- TwoByteString::InstanceSize(length)));
- }
- stop_index_ = d->next_index();
- }
-
- void ReadFill(Deserializer* d) {
- for (intptr_t id = start_index_; id < stop_index_; id++) {
- RawTwoByteString* str = reinterpret_cast<RawTwoByteString*>(d->Ref(id));
- intptr_t length = d->ReadUnsigned();
- bool is_canonical = d->Read<bool>();
- Deserializer::InitializeHeader(str, kTwoByteStringCid,
- TwoByteString::InstanceSize(length),
- is_canonical);
- str->ptr()->length_ = Smi::New(length);
- String::SetCachedHash(str, d->Read<int32_t>());
- uint8_t* cdata = reinterpret_cast<uint8_t*>(str->ptr()->data());
- d->ReadBytes(cdata, length * 2);
- }
- }
-};
-
-#if !defined(DART_PRECOMPILED_RUNTIME)
class FakeSerializationCluster : public SerializationCluster {
public:
FakeSerializationCluster(const char* name, intptr_t size)
@@ -4369,16 +4205,10 @@
if (Snapshot::IncludesCode(kind_)) {
switch (cid) {
- case kPcDescriptorsCid:
- return new (Z) RODataSerializationCluster("(RO)PcDescriptors", cid);
case kCodeSourceMapCid:
return new (Z) RODataSerializationCluster("(RO)CodeSourceMap", cid);
case kStackMapCid:
return new (Z) RODataSerializationCluster("(RO)StackMap", cid);
- case kOneByteStringCid:
- return new (Z) RODataSerializationCluster("(RO)OneByteString", cid);
- case kTwoByteStringCid:
- return new (Z) RODataSerializationCluster("(RO)TwoByteString", cid);
}
}
@@ -4417,6 +4247,8 @@
#endif // !DART_PRECOMPILED_RUNTIME
case kObjectPoolCid:
return new (Z) ObjectPoolSerializationCluster();
+ case kPcDescriptorsCid:
+ return new (Z) RODataSerializationCluster("(RO)PcDescriptors", cid);
case kExceptionHandlersCid:
return new (Z) ExceptionHandlersSerializationCluster();
case kContextCid:
@@ -4466,9 +4298,9 @@
case kImmutableArrayCid:
return new (Z) ArraySerializationCluster(kImmutableArrayCid);
case kOneByteStringCid:
- return new (Z) OneByteStringSerializationCluster();
+ return new (Z) RODataSerializationCluster("(RO)OneByteString", cid);
case kTwoByteStringCid:
- return new (Z) TwoByteStringSerializationCluster();
+ return new (Z) RODataSerializationCluster("(RO)TwoByteString", cid);
default:
break;
}
@@ -4962,17 +4794,15 @@
zone_(thread->zone()),
kind_(kind),
stream_(buffer, size),
- image_reader_(NULL),
- refs_(NULL),
+ image_reader_(nullptr),
+ refs_(nullptr),
next_ref_index_(1),
- clusters_(NULL) {
- if (Snapshot::IncludesCode(kind)) {
- ASSERT(instructions_buffer != NULL);
- ASSERT(data_buffer != NULL);
- image_reader_ =
- new (zone_) ImageReader(data_buffer, instructions_buffer,
- shared_data_buffer, shared_instructions_buffer);
- }
+ clusters_(nullptr) {
+ ASSERT((instructions_buffer != nullptr) || !Snapshot::IncludesCode(kind));
+ ASSERT(data_buffer != nullptr);
+ image_reader_ =
+ new (zone_) ImageReader(data_buffer, instructions_buffer,
+ shared_data_buffer, shared_instructions_buffer);
stream_.SetPosition(offset);
}
@@ -5085,25 +4915,14 @@
return new (Z) ArrayDeserializationCluster(kArrayCid);
case kImmutableArrayCid:
return new (Z) ArrayDeserializationCluster(kImmutableArrayCid);
- case kOneByteStringCid: {
- if (Snapshot::IncludesCode(kind_)) {
- return new (Z) RODataDeserializationCluster();
- } else {
- return new (Z) OneByteStringDeserializationCluster();
- }
- }
- case kTwoByteStringCid: {
- if (Snapshot::IncludesCode(kind_)) {
- return new (Z) RODataDeserializationCluster();
- } else {
- return new (Z) TwoByteStringDeserializationCluster();
- }
- }
+ case kOneByteStringCid:
+ case kTwoByteStringCid:
+ return new (Z) RODataDeserializationCluster();
default:
break;
}
FATAL1("No cluster defined for cid %" Pd, cid);
- return NULL;
+ return nullptr;
}
RawApiError* Deserializer::VerifyImageAlignment() {
@@ -5144,7 +4963,7 @@
const char* version =
reinterpret_cast<const char*>(stream_.AddressOfCurrentPosition());
ASSERT(version != NULL);
- if (strncmp(version, expected_version, version_len)) {
+ if (strncmp(version, expected_version, version_len) != 0) {
const intptr_t kMessageBufferSize = 256;
char message_buffer[kMessageBufferSize];
char* actual_version = Utils::StrNDup(version, version_len);
@@ -5175,7 +4994,7 @@
}
if (features_length != expected_len ||
- strncmp(features, expected_features, expected_len)) {
+ (strncmp(features, expected_features, expected_len) != 0)) {
const intptr_t kMessageBufferSize = 1024;
char message_buffer[kMessageBufferSize];
char* actual_features = Utils::StrNDup(
@@ -5490,7 +5309,8 @@
intptr_t FullSnapshotWriter::WriteVMSnapshot() {
TIMELINE_DURATION(thread(), Isolate, "WriteVMSnapshot");
- ASSERT(vm_snapshot_data_buffer_ != NULL);
+ ASSERT(vm_snapshot_data_buffer_ != nullptr);
+ ASSERT(vm_image_writer_ != nullptr);
Serializer serializer(thread(), kind_, vm_snapshot_data_buffer_, alloc_,
kInitialSize, vm_image_writer_, /*vm=*/true,
profile_writer_);
@@ -5507,14 +5327,12 @@
serializer.FillHeader(serializer.kind());
clustered_vm_size_ = serializer.bytes_written();
- if (Snapshot::IncludesCode(kind_)) {
- vm_image_writer_->SetProfileWriter(profile_writer_);
- vm_image_writer_->Write(serializer.stream(), true);
- mapped_data_size_ += vm_image_writer_->data_size();
- mapped_text_size_ += vm_image_writer_->text_size();
- vm_image_writer_->ResetOffsets();
- vm_image_writer_->ClearProfileWriter();
- }
+ vm_image_writer_->SetProfileWriter(profile_writer_);
+ vm_image_writer_->Write(serializer.stream(), true);
+ mapped_data_size_ += vm_image_writer_->data_size();
+ mapped_text_size_ += vm_image_writer_->text_size();
+ vm_image_writer_->ResetOffsets();
+ vm_image_writer_->ClearProfileWriter();
// The clustered part + the direct mapped data part.
vm_isolate_snapshot_size_ = serializer.bytes_written();
@@ -5524,11 +5342,13 @@
void FullSnapshotWriter::WriteIsolateSnapshot(intptr_t num_base_objects) {
TIMELINE_DURATION(thread(), Isolate, "WriteIsolateSnapshot");
+ ASSERT(isolate_snapshot_data_buffer_ != nullptr);
+ ASSERT(isolate_image_writer_ != nullptr);
Serializer serializer(thread(), kind_, isolate_snapshot_data_buffer_, alloc_,
kInitialSize, isolate_image_writer_, /*vm=*/false,
profile_writer_);
ObjectStore* object_store = isolate()->object_store();
- ASSERT(object_store != NULL);
+ ASSERT(object_store != nullptr);
serializer.ReserveHeader();
serializer.WriteVersionAndFeatures(false);
@@ -5538,18 +5358,16 @@
serializer.FillHeader(serializer.kind());
clustered_isolate_size_ = serializer.bytes_written();
- if (Snapshot::IncludesCode(kind_)) {
- isolate_image_writer_->SetProfileWriter(profile_writer_);
- isolate_image_writer_->Write(serializer.stream(), false);
+ isolate_image_writer_->SetProfileWriter(profile_writer_);
+ isolate_image_writer_->Write(serializer.stream(), false);
#if defined(DART_PRECOMPILER)
- isolate_image_writer_->DumpStatistics();
+ isolate_image_writer_->DumpStatistics();
#endif
- mapped_data_size_ += isolate_image_writer_->data_size();
- mapped_text_size_ += isolate_image_writer_->text_size();
- isolate_image_writer_->ResetOffsets();
- isolate_image_writer_->ClearProfileWriter();
- }
+ mapped_data_size_ += isolate_image_writer_->data_size();
+ mapped_text_size_ += isolate_image_writer_->text_size();
+ isolate_image_writer_->ResetOffsets();
+ isolate_image_writer_->ClearProfileWriter();
// The clustered part + the direct mapped data part.
isolate_snapshot_size_ = serializer.bytes_written();
@@ -5670,11 +5488,11 @@
return api_error;
}
+ ASSERT(data_image_ != nullptr);
+ thread_->isolate()->SetupImagePage(data_image_,
+ /* is_executable */ false);
if (Snapshot::IncludesCode(kind_)) {
- ASSERT(data_image_ != NULL);
- thread_->isolate()->SetupImagePage(data_image_,
- /* is_executable */ false);
- ASSERT(instructions_image_ != NULL);
+ ASSERT(instructions_image_ != nullptr);
thread_->isolate()->SetupImagePage(instructions_image_,
/* is_executable */ true);
}
@@ -5701,18 +5519,18 @@
return api_error;
}
+ ASSERT(data_image_ != nullptr);
+ thread_->isolate()->SetupImagePage(data_image_,
+ /* is_executable */ false);
if (Snapshot::IncludesCode(kind_)) {
- ASSERT(data_image_ != NULL);
- thread_->isolate()->SetupImagePage(data_image_,
- /* is_executable */ false);
- ASSERT(instructions_image_ != NULL);
+ ASSERT(instructions_image_ != nullptr);
thread_->isolate()->SetupImagePage(instructions_image_,
/* is_executable */ true);
- if (shared_data_image_ != NULL) {
+ if (shared_data_image_ != nullptr) {
thread_->isolate()->SetupImagePage(shared_data_image_,
/* is_executable */ false);
}
- if (shared_instructions_image_ != NULL) {
+ if (shared_instructions_image_ != nullptr) {
thread_->isolate()->SetupImagePage(shared_instructions_image_,
/* is_executable */ true);
}
@@ -5750,6 +5568,17 @@
}
}
}
+
+ // Initialize symbols in the BSS, if present.
+ ASSERT(Snapshot::IncludesCode(kind_));
+ Image image(instructions_image_);
+ if (image.bss_offset() != 0) {
+ // The const cast is safe because we're translating from the start of the
+ // instructions (read-only) to the start of the BSS (read-write).
+ uword* const bss_start = const_cast<uword*>(reinterpret_cast<const uword*>(
+ instructions_image_ + image.bss_offset()));
+ BSS::Initialize(thread_, bss_start);
+ }
#endif // defined(DART_PRECOMPILED_RUNTIME)
return ApiError::null();
diff --git a/runtime/vm/clustered_snapshot.h b/runtime/vm/clustered_snapshot.h
index 2233715..f62744a 100644
--- a/runtime/vm/clustered_snapshot.h
+++ b/runtime/vm/clustered_snapshot.h
@@ -259,11 +259,6 @@
return WriteRefId(Object::null());
}
#endif // !DART_PRECOMPILED_RUNTIME
- if (object->IsSendPort()) {
- // TODO(rmacnak): Do a better job of resetting fields in
- // precompilation and assert this is unreachable.
- return WriteRefId(Object::null());
- }
FATAL("Missing ref");
}
}
@@ -533,7 +528,10 @@
for (RawObject** p = from; p <= to_snapshot; p++) {
*p = ReadRef();
}
- // TODO(sjindel/rmacnak): Is this really necessary?
+ // This is necessary because, unlike Object::Allocate, the clustered
+ // deserializer allocates object without null-initializing them. Instead,
+ // each deserialization cluster is responsible for initializing every field,
+ // ensuring that every field is written to exactly once.
for (RawObject** p = to_snapshot + 1; p <= to; p++) {
*p = Object::null();
}
diff --git a/runtime/vm/code_descriptors.cc b/runtime/vm/code_descriptors.cc
index 7d1b764..149de08 100644
--- a/runtime/vm/code_descriptors.cc
+++ b/runtime/vm/code_descriptors.cc
@@ -15,10 +15,13 @@
TokenPosition token_pos,
intptr_t try_index) {
ASSERT((kind == RawPcDescriptors::kRuntimeCall) ||
+ (kind == RawPcDescriptors::kBSSRelocation) ||
(kind == RawPcDescriptors::kOther) || (deopt_id != DeoptId::kNone));
- // When precompiling, we only use pc descriptors for exceptions.
- if (!FLAG_precompiled_mode || try_index != -1) {
+ // When precompiling, we only use pc descriptors for exceptions and
+ // relocations.
+ if (!FLAG_precompiled_mode || try_index != -1 ||
+ kind == RawPcDescriptors::kBSSRelocation) {
int32_t merged_kind_try =
RawPcDescriptors::MergedKindTry::Encode(kind, try_index);
diff --git a/runtime/vm/compilation_trace.cc b/runtime/vm/compilation_trace.cc
index af8d622..e2f4eb8 100644
--- a/runtime/vm/compilation_trace.cc
+++ b/runtime/vm/compilation_trace.cc
@@ -500,7 +500,7 @@
WriteString(str_);
WriteInt(field_.guarded_cid());
- WriteInt(field_.is_nullable());
+ WriteInt(static_cast<intptr_t>(field_.is_nullable()));
}
}
}
@@ -673,7 +673,7 @@
const char* version =
reinterpret_cast<const char*>(stream_->AddressOfCurrentPosition());
ASSERT(version != NULL);
- if (strncmp(version, expected_version, version_len)) {
+ if (strncmp(version, expected_version, version_len) != 0) {
const intptr_t kMessageBufferSize = 256;
char message_buffer[kMessageBufferSize];
char* actual_version = Utils::StrNDup(version, version_len);
@@ -695,7 +695,7 @@
ASSERT(features != NULL);
intptr_t buffer_len = Utils::StrNLen(features, stream_->PendingBytes());
if ((buffer_len != expected_len) ||
- strncmp(features, expected_features, expected_len)) {
+ (strncmp(features, expected_features, expected_len) != 0)) {
const String& msg = String::Handle(String::NewFormatted(
Heap::kOld,
"Feedback not compatible with the current VM configuration: "
@@ -783,7 +783,7 @@
field_.set_is_nullable(true);
} else {
field_.set_guarded_cid(guarded_cid);
- field_.set_is_nullable(is_nullable || field_.is_nullable());
+ field_.set_is_nullable((is_nullable != 0) || field_.is_nullable());
}
// TODO(rmacnak): Merge other field type feedback.
diff --git a/runtime/vm/compiler/aot/aot_call_specializer.cc b/runtime/vm/compiler/aot/aot_call_specializer.cc
index 5b1d22a..375e171 100644
--- a/runtime/vm/compiler/aot/aot_call_specializer.cc
+++ b/runtime/vm/compiler/aot/aot_call_specializer.cc
@@ -109,10 +109,9 @@
return false;
}
- const ICData& ic_data =
- ICData::ZoneHandle(Z, ICData::NewFrom(*call->ic_data(), 1));
- ic_data.AddReceiverCheck(cls.id(), target_function);
- call->set_ic_data(&ic_data);
+ call->SetTargets(
+ CallTargets::CreateMonomorphic(Z, cls.id(), target_function));
+ ASSERT(call->Targets().IsMonomorphic());
// If we know that the only noSuchMethod is Object.noSuchMethod then
// this call is guaranteed to either succeed or throw.
@@ -242,14 +241,9 @@
if ((op_kind == Token::kGET) && TryInlineInstanceGetter(call)) {
return true;
}
-
- const ICData& unary_checks =
- ICData::Handle(Z, call->ic_data()->AsUnaryClassChecks());
- if (!unary_checks.NumberOfChecksIs(0) && (op_kind == Token::kSET) &&
- TryInlineInstanceSetter(call, unary_checks)) {
+ if ((op_kind == Token::kSET) && TryInlineInstanceSetter(call)) {
return true;
}
-
return false;
}
@@ -445,12 +439,12 @@
right_definition = new (Z)
IntConverterInstr(kUnboxedInt32, kUnboxedInt64,
new (Z) Value(right_definition), DeoptId::kNone);
- InsertBefore(instr, right_definition, /*env=*/NULL, FlowGraph::kValue);
#else
Definition* right_definition = new (Z) UnboxedConstantInstr(
Smi::ZoneHandle(Z, Smi::New(modulus - 1)), kUnboxedInt64);
- InsertBefore(instr, right_definition, /*env=*/NULL, FlowGraph::kValue);
#endif
+ if (modulus == 1) return right_definition;
+ InsertBefore(instr, right_definition, /*env=*/NULL, FlowGraph::kValue);
right_value = new (Z) Value(right_definition);
return new (Z)
BinaryInt64OpInstr(Token::kBIT_AND, left_value, right_value,
@@ -787,22 +781,18 @@
return;
}
+ const CallTargets& targets = instr->Targets();
const intptr_t receiver_idx = instr->FirstArgIndex();
- const ICData& unary_checks =
- ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks());
- const intptr_t number_of_checks = unary_checks.NumberOfChecks();
if (I->can_use_strong_mode_types()) {
// In AOT strong mode, we avoid deopting speculation.
// TODO(ajcbik): replace this with actual analysis phase
// that determines if checks are removed later.
} else if (speculative_policy_->IsAllowedForInlining(instr->deopt_id()) &&
- number_of_checks > 0) {
- if ((op_kind == Token::kINDEX) &&
- TryReplaceWithIndexedOp(instr, &unary_checks)) {
+ !targets.is_empty()) {
+ if ((op_kind == Token::kINDEX) && TryReplaceWithIndexedOp(instr)) {
return;
}
- if ((op_kind == Token::kASSIGN_INDEX) &&
- TryReplaceWithIndexedOp(instr, &unary_checks)) {
+ if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) {
return;
}
if ((op_kind == Token::kEQ) && TryReplaceWithEqualityOp(instr, op_kind)) {
@@ -833,25 +823,22 @@
return;
}
- bool has_one_target = number_of_checks > 0 && unary_checks.HasOneTarget();
+ bool has_one_target = targets.HasSingleTarget();
if (has_one_target) {
// Check if the single target is a polymorphic target, if it is,
// we don't have one target.
- const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0));
+ const Function& target = targets.FirstTarget();
const bool polymorphic_target = MethodRecognizer::PolymorphicTarget(target);
has_one_target = !polymorphic_target;
}
if (has_one_target) {
- RawFunction::Kind function_kind =
- Function::Handle(Z, unary_checks.GetTargetAt(0)).kind();
+ const Function& target = targets.FirstTarget();
+ RawFunction::Kind function_kind = target.kind();
if (flow_graph()->CheckForInstanceCall(instr, function_kind) ==
FlowGraph::ToCheck::kNoCheck) {
- CallTargets* targets = CallTargets::Create(Z, unary_checks);
- ASSERT(targets->HasSingleTarget());
- const Function& target = targets->FirstTarget();
StaticCallInstr* call = StaticCallInstr::FromCall(
- Z, instr, target, targets->AggregateCallCount());
+ Z, instr, target, targets.AggregateCallCount());
instr->ReplaceWith(call, current_iterator());
return;
}
@@ -864,7 +851,7 @@
case Token::kLTE:
case Token::kGT:
case Token::kGTE: {
- if (HasOnlyTwoOf(*instr->ic_data(), kSmiCid) ||
+ if (instr->BinaryFeedback().OperandsAre(kSmiCid) ||
HasLikelySmiOperand(instr)) {
ASSERT(receiver_idx == 0);
Definition* left = instr->ArgumentAt(0);
@@ -885,7 +872,7 @@
case Token::kADD:
case Token::kSUB:
case Token::kMUL: {
- if (HasOnlyTwoOf(*instr->ic_data(), kSmiCid) ||
+ if (instr->BinaryFeedback().OperandsAre(kSmiCid) ||
HasLikelySmiOperand(instr)) {
ASSERT(receiver_idx == 0);
Definition* left = instr->ArgumentAt(0);
@@ -1033,7 +1020,8 @@
return;
} else if ((ic_data.raw() != ICData::null()) &&
!ic_data.NumberOfChecksIs(0)) {
- CallTargets* targets = CallTargets::Create(Z, ic_data);
+ const CallTargets* targets = CallTargets::Create(Z, ic_data);
+ ASSERT(!targets->is_empty());
PolymorphicInstanceCallInstr* call =
new (Z) PolymorphicInstanceCallInstr(instr, *targets,
/* complete = */ true);
@@ -1051,13 +1039,12 @@
// More than one target. Generate generic polymorphic call without
// deoptimization.
- if (instr->ic_data()->NumberOfUsedChecks() > 0) {
+ if (targets.length() > 0) {
ASSERT(!FLAG_polymorphic_with_deopt);
// OK to use checks with PolymorphicInstanceCallInstr since no
// deoptimization is allowed.
- CallTargets* targets = CallTargets::Create(Z, *instr->ic_data());
PolymorphicInstanceCallInstr* call =
- new (Z) PolymorphicInstanceCallInstr(instr, *targets,
+ new (Z) PolymorphicInstanceCallInstr(instr, targets,
/* complete = */ false);
instr->ReplaceWith(call, current_iterator());
return;
diff --git a/runtime/vm/compiler/aot/precompiler.cc b/runtime/vm/compiler/aot/precompiler.cc
index f6cc489..3e9c86ea 100644
--- a/runtime/vm/compiler/aot/precompiler.cc
+++ b/runtime/vm/compiler/aot/precompiler.cc
@@ -158,9 +158,11 @@
pending_functions_(
GrowableObjectArray::Handle(GrowableObjectArray::New())),
sent_selectors_(),
- enqueued_functions_(),
+ enqueued_functions_(
+ HashTables::New<FunctionSet>(/*initial_capacity=*/1024)),
fields_to_retain_(),
- functions_to_retain_(),
+ functions_to_retain_(
+ HashTables::New<FunctionSet>(/*initial_capacity=*/1024)),
classes_to_retain_(),
typeargs_to_retain_(),
types_to_retain_(),
@@ -173,6 +175,10 @@
}
Precompiler::~Precompiler() {
+ // We have to call Release() in DEBUG mode.
+ enqueued_functions_.Release();
+ functions_to_retain_.Release();
+
ASSERT(Precompiler::singleton_ == this);
Precompiler::singleton_ = NULL;
}
@@ -700,11 +706,11 @@
void Precompiler::AddTypesOf(const Function& function) {
if (function.IsNull()) return;
- if (functions_to_retain_.HasKey(&function)) return;
+ if (functions_to_retain_.ContainsKey(function)) return;
// We don't expect to see a reference to a redirecting factory. Only its
// target should remain.
ASSERT(!function.IsRedirectingFactory());
- functions_to_retain_.Insert(&Function::ZoneHandle(Z, function.raw()));
+ functions_to_retain_.Insert(function);
AbstractType& type = AbstractType::Handle(Z);
type = function.result_type();
@@ -938,9 +944,9 @@
}
void Precompiler::AddFunction(const Function& function) {
- if (enqueued_functions_.HasKey(&function)) return;
+ if (enqueued_functions_.ContainsKey(function)) return;
- enqueued_functions_.Insert(&Function::ZoneHandle(Z, function.raw()));
+ enqueued_functions_.Insert(function);
pending_functions_.Add(function);
changed_ = true;
}
@@ -1340,7 +1346,7 @@
functions = cls.functions();
for (intptr_t j = 0; j < functions.Length(); j++) {
function ^= functions.At(j);
- bool retain = enqueued_functions_.HasKey(&function);
+ bool retain = enqueued_functions_.ContainsKey(function);
if (!retain && function.HasImplicitClosureFunction()) {
// It can happen that all uses of an implicit closure inline their
// target function, leaving the target function uncompiled. Keep
@@ -1360,7 +1366,7 @@
closures = isolate()->object_store()->closure_functions();
for (intptr_t j = 0; j < closures.Length(); j++) {
function ^= closures.At(j);
- bool retain = enqueued_functions_.HasKey(&function);
+ bool retain = enqueued_functions_.ContainsKey(function);
if (retain) {
AddTypesOf(function);
@@ -1400,7 +1406,7 @@
retained_functions = GrowableObjectArray::New();
for (intptr_t j = 0; j < functions.Length(); j++) {
function ^= functions.At(j);
- bool retain = functions_to_retain_.HasKey(&function);
+ bool retain = functions_to_retain_.ContainsKey(function);
function.DropUncompiledImplicitClosureFunction();
if (retain) {
retained_functions.Add(function);
@@ -1426,7 +1432,7 @@
retained_functions = GrowableObjectArray::New();
for (intptr_t j = 0; j < closures.Length(); j++) {
function ^= closures.At(j);
- bool retain = functions_to_retain_.HasKey(&function);
+ bool retain = functions_to_retain_.ContainsKey(function);
if (retain) {
retained_functions.Add(function);
} else {
@@ -1763,7 +1769,7 @@
continue;
}
} else if (entry.IsFunction()) {
- if (functions_to_retain_.HasKey(&Function::Cast(entry))) {
+ if (functions_to_retain_.ContainsKey(Function::Cast(entry))) {
used++;
continue;
}
@@ -1999,10 +2005,11 @@
// finally clauses, and not all functions are compiled through the
// tree-shaker's queue
ProgramVisitor::VisitFunctions(&visitor);
- FunctionSet::Iterator it(enqueued_functions_.GetIterator());
- for (const Function** current = it.Next(); current != NULL;
- current = it.Next()) {
- visitor.Visit(**current);
+ FunctionSet::Iterator it(&enqueued_functions_);
+ Function& handle = Function::Handle();
+ while (it.MoveNext()) {
+ handle ^= enqueued_functions_.GetKey(it.Current());
+ visitor.Visit(handle);
}
}
@@ -2085,10 +2092,11 @@
// duplicated finally clauses, and not all functions are compiled through
// the tree-shaker's queue
ProgramVisitor::VisitFunctions(&visitor);
- FunctionSet::Iterator it(enqueued_functions_.GetIterator());
- for (const Function** current = it.Next(); current != NULL;
- current = it.Next()) {
- visitor.Visit(**current);
+ FunctionSet::Iterator it(&enqueued_functions_);
+ Function& current = Function::Handle();
+ while (it.MoveNext()) {
+ current ^= enqueued_functions_.GetKey(it.Current());
+ visitor.Visit(current);
}
}
#endif
@@ -2219,8 +2227,6 @@
function.set_unoptimized_code(code);
function.AttachCode(code);
}
- ASSERT(!parsed_function()->HasDeferredPrefixes());
- ASSERT(FLAG_load_deferred_eagerly);
}
// Return false if bailed out.
@@ -2285,7 +2291,12 @@
pass_state.reorder_blocks =
FlowGraph::ShouldReorderBlocks(function, optimized());
- if (optimized()) {
+ if (function.ForceOptimize()) {
+ ASSERT(optimized());
+ TIMELINE_DURATION(thread(), CompilerVerbose, "OptimizationPasses");
+ flow_graph = CompilerPass::RunForceOptimizedPipeline(CompilerPass::kAOT,
+ &pass_state);
+ } else if (optimized()) {
TIMELINE_DURATION(thread(), CompilerVerbose, "OptimizationPasses");
pass_state.inline_id_to_function.Add(&function);
@@ -2302,7 +2313,7 @@
&speculative_policy);
pass_state.call_specializer = &call_specializer;
- CompilerPass::RunPipeline(CompilerPass::kAOT, &pass_state);
+ flow_graph = CompilerPass::RunPipeline(CompilerPass::kAOT, &pass_state);
}
ASSERT(pass_state.inline_id_to_function.length() ==
diff --git a/runtime/vm/compiler/aot/precompiler.h b/runtime/vm/compiler/aot/precompiler.h
index 7dfa666..a6ceb59 100644
--- a/runtime/vm/compiler/aot/precompiler.h
+++ b/runtime/vm/compiler/aot/precompiler.h
@@ -72,37 +72,17 @@
typedef DirectChainedHashMap<UnlinkedCallKeyValueTrait> UnlinkedCallSet;
-static inline intptr_t SimplePointerHash(void* ptr) {
- return reinterpret_cast<intptr_t>(ptr) * 2654435761UL;
-}
-
-class FunctionKeyValueTrait {
- public:
- // Typedefs needed for the DirectChainedHashMap template.
- typedef const Function* Key;
- typedef const Function* Value;
- typedef const Function* Pair;
-
- static Key KeyOf(Pair kv) { return kv; }
-
- static Value ValueOf(Pair kv) { return kv; }
-
- static inline intptr_t Hashcode(Key key) {
- // We are using pointer hash for objects originating from Kernel because
- // Fasta currently does not assign any position information to them.
- if (key->kernel_offset() > 0) {
- return key->kernel_offset();
- } else {
- return key->token_pos().value();
- }
+// Traits for the HashTable template.
+struct FunctionKeyTraits {
+ static uint32_t Hash(const Object& key) { return Function::Cast(key).Hash(); }
+ static const char* Name() { return "FunctionKeyTraits"; }
+ static bool IsMatch(const Object& x, const Object& y) {
+ return x.raw() == y.raw();
}
-
- static inline bool IsKeyEqual(Pair pair, Key key) {
- return pair->raw() == key->raw();
- }
+ static bool ReportStats() { return false; }
};
-typedef DirectChainedHashMap<FunctionKeyValueTrait> FunctionSet;
+typedef UnorderedHashSet<FunctionKeyTraits> FunctionSet;
class FieldKeyValueTrait {
public:
diff --git a/runtime/vm/compiler/assembler/assembler.cc b/runtime/vm/compiler/assembler/assembler.cc
index f6c6175..6b5427d 100644
--- a/runtime/vm/compiler/assembler/assembler.cc
+++ b/runtime/vm/compiler/assembler/assembler.cc
@@ -30,6 +30,31 @@
namespace compiler {
+AssemblerBase::~AssemblerBase() {}
+
+intptr_t AssemblerBase::InsertAlignedRelocation(BSS::Relocation reloc) {
+ // We cannot put a relocation at the very start (it's not a valid
+ // instruction)!
+ ASSERT(CodeSize() != 0);
+
+ // Align to a target word boundary.
+ const intptr_t offset =
+ Utils::RoundUp(CodeSize(), compiler::target::kWordSize);
+
+ while (CodeSize() < offset) {
+ Breakpoint();
+ }
+ ASSERT(CodeSize() == offset);
+
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ buffer_.Emit<compiler::target::word>(BSS::RelocationIndex(reloc) *
+ compiler::target::kWordSize);
+
+ ASSERT(CodeSize() == (offset + compiler::target::kWordSize));
+
+ return offset;
+}
+
static uword NewContents(intptr_t capacity) {
Zone* zone = Thread::Current()->zone();
uword result = zone->AllocUnsafe(capacity);
diff --git a/runtime/vm/compiler/assembler/assembler.h b/runtime/vm/compiler/assembler/assembler.h
index cf4d6e6..645728a 100644
--- a/runtime/vm/compiler/assembler/assembler.h
+++ b/runtime/vm/compiler/assembler/assembler.h
@@ -305,7 +305,7 @@
prologue_offset_(-1),
has_single_entry_point_(true),
object_pool_builder_(object_pool_builder) {}
- virtual ~AssemblerBase() {}
+ virtual ~AssemblerBase();
intptr_t CodeSize() const { return buffer_.Size(); }
@@ -320,6 +320,10 @@
void Comment(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
static bool EmittingComments();
+ virtual void Breakpoint() = 0;
+
+ intptr_t InsertAlignedRelocation(BSS::Relocation reloc);
+
void Unimplemented(const char* message);
void Untested(const char* message);
void Unreachable(const char* message);
diff --git a/runtime/vm/compiler/assembler/assembler_arm.h b/runtime/vm/compiler/assembler/assembler_arm.h
index 7a55232..667f8a5 100644
--- a/runtime/vm/compiler/assembler/assembler_arm.h
+++ b/runtime/vm/compiler/assembler/assembler_arm.h
@@ -392,7 +392,7 @@
#endif // TESTING || DEBUG
// Debugging and bringup support.
- void Breakpoint() { bkpt(0); }
+ void Breakpoint() override { bkpt(0); }
void Stop(const char* message) override;
static void InitializeMemoryWithBreakpoints(uword data, intptr_t length);
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.h b/runtime/vm/compiler/assembler/assembler_arm64.h
index e8c565e..d945c0e 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.h
+++ b/runtime/vm/compiler/assembler/assembler_arm64.h
@@ -485,7 +485,7 @@
void set_use_far_branches(bool b) { use_far_branches_ = b; }
// Debugging and bringup support.
- void Breakpoint() { brk(0); }
+ void Breakpoint() override { brk(0); }
void Stop(const char* message) override;
static void InitializeMemoryWithBreakpoints(uword data, intptr_t length);
diff --git a/runtime/vm/compiler/assembler/assembler_dbc.h b/runtime/vm/compiler/assembler/assembler_dbc.h
index df2a83c..0737026 100644
--- a/runtime/vm/compiler/assembler/assembler_dbc.h
+++ b/runtime/vm/compiler/assembler/assembler_dbc.h
@@ -43,6 +43,7 @@
void MonomorphicCheckedEntryAOT() {}
// Debugging and bringup support.
+ void Breakpoint() override { Stop("Breakpoint!"); }
void Stop(const char* message) override;
static void InitializeMemoryWithBreakpoints(uword data, intptr_t length);
diff --git a/runtime/vm/compiler/assembler/assembler_ia32.h b/runtime/vm/compiler/assembler/assembler_ia32.h
index 586b7dd..8321841 100644
--- a/runtime/vm/compiler/assembler/assembler_ia32.h
+++ b/runtime/vm/compiler/assembler/assembler_ia32.h
@@ -835,7 +835,7 @@
Register temp);
// Debugging and bringup support.
- void Breakpoint() { int3(); }
+ void Breakpoint() override { int3(); }
void Stop(const char* message) override;
static void InitializeMemoryWithBreakpoints(uword data, intptr_t length);
diff --git a/runtime/vm/compiler/assembler/assembler_x64.cc b/runtime/vm/compiler/assembler/assembler_x64.cc
index e5f9e7d..8bc626a 100644
--- a/runtime/vm/compiler/assembler/assembler_x64.cc
+++ b/runtime/vm/compiler/assembler/assembler_x64.cc
@@ -1998,7 +1998,7 @@
nop(MAX_NOP_SIZE);
bytes_needed -= MAX_NOP_SIZE;
}
- if (bytes_needed) {
+ if (bytes_needed != 0) {
nop(bytes_needed);
}
ASSERT(((offset + buffer_.GetPosition()) & (alignment - 1)) == 0);
diff --git a/runtime/vm/compiler/assembler/assembler_x64.h b/runtime/vm/compiler/assembler/assembler_x64.h
index b519aae..9e69dc8 100644
--- a/runtime/vm/compiler/assembler/assembler_x64.h
+++ b/runtime/vm/compiler/assembler/assembler_x64.h
@@ -590,6 +590,7 @@
REGULAR_UNARY(not, 0xF7, 2)
REGULAR_UNARY(neg, 0xF7, 3)
REGULAR_UNARY(mul, 0xF7, 4)
+ REGULAR_UNARY(imul, 0xF7, 5)
REGULAR_UNARY(div, 0xF7, 6)
REGULAR_UNARY(idiv, 0xF7, 7)
REGULAR_UNARY(inc, 0xFF, 0)
@@ -937,7 +938,7 @@
void GenerateUnRelocatedPcRelativeCall(intptr_t offset_into_target = 0);
// Debugging and bringup support.
- void Breakpoint() { int3(); }
+ void Breakpoint() override { int3(); }
void Stop(const char* message) override;
static void InitializeMemoryWithBreakpoints(uword data, intptr_t length);
diff --git a/runtime/vm/compiler/assembler/assembler_x64_test.cc b/runtime/vm/compiler/assembler/assembler_x64_test.cc
index 92aa14d..2e4609f 100644
--- a/runtime/vm/compiler/assembler/assembler_x64_test.cc
+++ b/runtime/vm/compiler/assembler/assembler_x64_test.cc
@@ -855,6 +855,25 @@
"ret\n");
}
+ASSEMBLER_TEST_GENERATE(SignedMultiply64Implicit, assembler) {
+ __ movq(RAX, Immediate(7));
+ __ movq(RDX, Immediate(-3));
+ __ imulq(RDX); // // RDX:RAX = -21
+ __ addq(RAX, RDX);
+ __ ret();
+}
+
+ASSEMBLER_TEST_RUN(SignedMultiply64Implicit, test) {
+ typedef int (*SignedMultiply64Implicit)();
+ EXPECT_EQ(-22, reinterpret_cast<SignedMultiply64Implicit>(test->entry())());
+ EXPECT_DISASSEMBLY(
+ "movl rax,7\n"
+ "movq rdx,-3\n"
+ "imulq (rax,rdx),rdx\n"
+ "addq rax,rdx\n"
+ "ret\n");
+}
+
ASSEMBLER_TEST_GENERATE(SignedMultiply64, assembler) {
__ pushq(R15); // Callee saved.
__ movq(RAX, Immediate(2));
diff --git a/runtime/vm/compiler/assembler/disassembler_kbc.cc b/runtime/vm/compiler/assembler/disassembler_kbc.cc
index d2f0229..1cf9e00 100644
--- a/runtime/vm/compiler/assembler/disassembler_kbc.cc
+++ b/runtime/vm/compiler/assembler/disassembler_kbc.cc
@@ -315,7 +315,7 @@
hex_size - (i * kCharactersPerByte), " %02x", instr[i]);
}
}
- if (out_instr_size) {
+ if (out_instr_size != nullptr) {
*out_instr_size = instr_size;
}
diff --git a/runtime/vm/compiler/assembler/disassembler_x86.cc b/runtime/vm/compiler/assembler/disassembler_x86.cc
index 7e4c016..6fd177e 100644
--- a/runtime/vm/compiler/assembler/disassembler_x86.cc
+++ b/runtime/vm/compiler/assembler/disassembler_x86.cc
@@ -1767,7 +1767,7 @@
// mov reg8,imm8 or mov reg32,imm32
uint8_t opcode = *data;
data++;
- uint8_t is_not_8bit = (opcode >= 0xB8);
+ const bool is_not_8bit = opcode >= 0xB8;
int reg = (opcode & 0x7) | (rex_b() ? 8 : 0);
if (is_not_8bit) {
Print("mov%s %s,", operand_size_code(), NameOfCPURegister(reg));
@@ -1970,7 +1970,7 @@
remaining_size -= 2;
}
hex_buffer[hex_index] = '\0';
- if (out_instr_len) {
+ if (out_instr_len != nullptr) {
*out_instr_len = instruction_length;
}
diff --git a/runtime/vm/compiler/backend/flow_graph.cc b/runtime/vm/compiler/backend/flow_graph.cc
index 11312bc..c883852 100644
--- a/runtime/vm/compiler/backend/flow_graph.cc
+++ b/runtime/vm/compiler/backend/flow_graph.cc
@@ -54,7 +54,6 @@
prologue_info_(prologue_info),
loop_hierarchy_(nullptr),
loop_invariant_loads_(nullptr),
- deferred_prefixes_(parsed_function.deferred_prefixes()),
captured_parameters_(new (zone()) BitVector(zone(), variable_count())),
inlining_id_(-1),
should_print_(FlowGraphPrinter::ShouldPrint(parsed_function.function())) {
@@ -105,20 +104,6 @@
iterator->RemoveCurrentFromGraph();
}
-void FlowGraph::AddToDeferredPrefixes(
- ZoneGrowableArray<const LibraryPrefix*>* from) {
- ZoneGrowableArray<const LibraryPrefix*>* to = deferred_prefixes();
- for (intptr_t i = 0; i < from->length(); i++) {
- const LibraryPrefix* prefix = (*from)[i];
- for (intptr_t j = 0; j < to->length(); j++) {
- if ((*to)[j]->raw() == prefix->raw()) {
- return;
- }
- }
- to->Add(prefix);
- }
-}
-
bool FlowGraph::ShouldReorderBlocks(const Function& function,
bool is_optimized) {
return is_optimized && FLAG_reorder_basic_blocks &&
@@ -273,13 +258,19 @@
if (merged->Contains(block->postorder_number())) continue;
Instruction* last = block->last_instruction();
- BlockEntryInstr* successor = NULL;
- while ((!last->IsIndirectGoto()) && (last->SuccessorCount() == 1) &&
- (!last->SuccessorAt(0)->IsIndirectEntry()) &&
- (last->SuccessorAt(0)->PredecessorCount() == 1) &&
- (block->try_index() == last->SuccessorAt(0)->try_index())) {
- successor = last->SuccessorAt(0);
- ASSERT(last->IsGoto());
+ BlockEntryInstr* last_merged_block = nullptr;
+ while (auto goto_instr = last->AsGoto()) {
+ JoinEntryInstr* successor = goto_instr->successor();
+ if (successor->PredecessorCount() > 1) break;
+ if (block->try_index() != successor->try_index()) break;
+
+ // Replace all phis with their arguments prior to removing successor.
+ for (PhiIterator it(successor); !it.Done(); it.Advance()) {
+ PhiInstr* phi = it.Current();
+ Value* input = phi->InputAt(0);
+ phi->ReplaceUsesWith(input->definition());
+ input->RemoveFromUseList();
+ }
// Remove environment uses and unlink goto and block entry.
successor->UnuseAllInputs();
@@ -288,6 +279,7 @@
last = successor->last_instruction();
merged->Add(successor->postorder_number());
+ last_merged_block = successor;
changed = true;
if (FLAG_trace_optimization) {
THR_Print("Merged blocks B%" Pd " and B%" Pd "\n", block->block_id(),
@@ -296,8 +288,8 @@
}
// The new block inherits the block id of the last successor to maintain
// the order of phi inputs at its successors consistent with block ids.
- if (successor != NULL) {
- block->set_block_id(successor->block_id());
+ if (last_merged_block != nullptr) {
+ block->set_block_id(last_merged_block->block_id());
}
}
// Recompute block order after changes were made.
diff --git a/runtime/vm/compiler/backend/flow_graph.h b/runtime/vm/compiler/backend/flow_graph.h
index c138045..bbba0f1 100644
--- a/runtime/vm/compiler/backend/flow_graph.h
+++ b/runtime/vm/compiler/backend/flow_graph.h
@@ -341,12 +341,6 @@
bool IsCompiledForOsr() const { return graph_entry()->IsCompiledForOsr(); }
- void AddToDeferredPrefixes(ZoneGrowableArray<const LibraryPrefix*>* from);
-
- ZoneGrowableArray<const LibraryPrefix*>* deferred_prefixes() const {
- return deferred_prefixes_;
- }
-
BitVector* captured_parameters() const { return captured_parameters_; }
intptr_t inlining_id() const { return inlining_id_; }
@@ -532,7 +526,6 @@
LoopHierarchy* loop_hierarchy_;
ZoneGrowableArray<BitVector*>* loop_invariant_loads_;
- ZoneGrowableArray<const LibraryPrefix*>* deferred_prefixes_;
DirectChainedHashMap<ConstantPoolTrait> constant_instr_pool_;
BitVector* captured_parameters_;
diff --git a/runtime/vm/compiler/backend/flow_graph_checker.cc b/runtime/vm/compiler/backend/flow_graph_checker.cc
index 7e810b2..bde8521 100644
--- a/runtime/vm/compiler/backend/flow_graph_checker.cc
+++ b/runtime/vm/compiler/backend/flow_graph_checker.cc
@@ -224,6 +224,14 @@
void FlowGraphChecker::VisitInstruction(Instruction* instruction) {
ASSERT(!instruction->IsBlockEntry());
+
+ // In JIT mode, any instruction which may throw must have a deopt-id, except
+ // tail-call because it replaces the stack frame.
+#if !defined(DART_PRECOMPILER)
+ ASSERT(!instruction->MayThrow() || instruction->IsTailCall() ||
+ instruction->deopt_id() != DeoptId::kNone);
+#endif // !defined(DART_PRECOMPILER)
+
// Check all regular inputs.
for (intptr_t i = 0, n = instruction->InputCount(); i < n; ++i) {
VisitUseDef(instruction, instruction->InputAt(i), i, /*is_env*/ false);
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index a0db6a8..49597bb9 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -242,6 +242,13 @@
return isolate()->use_osr() && CanOptimizeFunction() && !is_optimizing();
}
+void FlowGraphCompiler::InsertBSSRelocation(BSS::Relocation reloc) {
+ const intptr_t offset = assembler()->InsertAlignedRelocation(reloc);
+ AddDescriptor(RawPcDescriptors::kBSSRelocation, /*pc_offset=*/offset,
+ /*deopt_id=*/DeoptId::kNone, TokenPosition::kNoSource,
+ /*try_index=*/-1);
+}
+
bool FlowGraphCompiler::ForceSlowPathForStackOverflow() const {
#if !defined(PRODUCT)
if ((FLAG_stacktrace_every > 0) || (FLAG_deoptimize_every > 0) ||
@@ -1401,7 +1408,9 @@
: ic_data.arguments_descriptor());
ASSERT(ArgumentsDescriptor(arguments_descriptor).TypeArgsLen() ==
args_info.type_args_len);
- if (is_optimizing() && !ForcedOptimization()) {
+ // Force-optimized functions lack the deopt info which allows patching of
+ // optimized static calls.
+ if (is_optimizing() && (!ForcedOptimization() || FLAG_precompiled_mode)) {
EmitOptimizedStaticCall(function, arguments_descriptor,
args_info.count_with_type_args, deopt_id, token_pos,
locs, entry_kind);
@@ -1413,6 +1422,7 @@
GetOrAddStaticCallICData(deopt_id, function, arguments_descriptor,
kNumArgsChecked, rebind_rule)
->raw();
+ call_ic_data = call_ic_data.Original();
}
AddCurrentDescriptor(RawPcDescriptors::kRewind, deopt_id, token_pos);
EmitUnoptimizedStaticCall(args_info.count_with_type_args, deopt_id,
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.h b/runtime/vm/compiler/backend/flow_graph_compiler.h
index fe10a80..f07d8d7 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.h
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.h
@@ -428,6 +428,8 @@
bool CanOSRFunction() const;
bool is_optimizing() const { return is_optimizing_; }
+ void InsertBSSRelocation(BSS::Relocation reloc);
+
// The function was fully intrinsified, so the body is unreachable.
//
// We still need to compile the body in unoptimized mode because the
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
index 57915ca..af3e2f5 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
@@ -1108,8 +1108,8 @@
ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0));
const ArgumentsDescriptor args_desc(arguments_descriptor);
const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(
- zone(), MegamorphicCacheTable::LookupOriginal(thread(), name,
- arguments_descriptor));
+ zone(),
+ MegamorphicCacheTable::Lookup(thread(), name, arguments_descriptor));
__ Comment("MegamorphicCall");
// Load receiver into R0.
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
index 192ec70..8c9f45d 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
@@ -1074,8 +1074,8 @@
ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0));
const ArgumentsDescriptor args_desc(arguments_descriptor);
const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(
- zone(), MegamorphicCacheTable::LookupOriginal(thread(), name,
- arguments_descriptor));
+ zone(),
+ MegamorphicCacheTable::Lookup(thread(), name, arguments_descriptor));
__ Comment("MegamorphicCall");
// Load receiver into R0.
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
index 3e1bd1f..5b1a9c3 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
@@ -969,8 +969,8 @@
ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0));
const ArgumentsDescriptor args_desc(arguments_descriptor);
const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(
- zone(), MegamorphicCacheTable::LookupOriginal(thread(), name,
- arguments_descriptor));
+ zone(),
+ MegamorphicCacheTable::Lookup(thread(), name, arguments_descriptor));
__ Comment("MegamorphicCall");
// Load receiver into EBX.
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
index ac328e6..78987ee 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
@@ -1094,8 +1094,8 @@
ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0));
const ArgumentsDescriptor args_desc(arguments_descriptor);
const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(
- zone(), MegamorphicCacheTable::LookupOriginal(thread(), name,
- arguments_descriptor));
+ zone(),
+ MegamorphicCacheTable::Lookup(thread(), name, arguments_descriptor));
__ Comment("MegamorphicCall");
// Load receiver into RDX.
__ movq(RDX, compiler::Address(RSP, (args_desc.Count() - 1) * kWordSize));
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index 7c47f30..e3479a4 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -650,16 +650,22 @@
return cids;
}
-Cids* Cids::CreateAndExpand(Zone* zone,
- const ICData& ic_data,
- int argument_number) {
+Cids* Cids::CreateForArgument(Zone* zone,
+ const BinaryFeedback& binary_feedback,
+ int argument_number) {
Cids* cids = new (zone) Cids(zone);
- cids->CreateHelper(zone, ic_data, argument_number,
- /* include_targets = */ false);
- cids->Sort(OrderById);
+ for (intptr_t i = 0; i < binary_feedback.feedback_.length(); i++) {
+ ASSERT((argument_number == 0) || (argument_number == 1));
+ const intptr_t cid = argument_number == 0
+ ? binary_feedback.feedback_[i].first
+ : binary_feedback.feedback_[i].second;
+ cids->Add(new (zone) CidRange(cid, cid));
+ }
- // Merge adjacent class id ranges.
- {
+ if (cids->length() != 0) {
+ cids->Sort(OrderById);
+
+ // Merge adjacent class id ranges.
int dest = 0;
for (int src = 1; src < cids->length(); src++) {
if (cids->cid_ranges_[dest]->cid_end + 1 >=
@@ -673,53 +679,6 @@
cids->SetLength(dest + 1);
}
- // Merging/extending cid ranges is also done in CallTargets::CreateAndExpand.
- // If changing this code, consider also adjusting CallTargets code.
-
- if (cids->length() > 1 && argument_number == 0 && ic_data.HasOneTarget()) {
- // Try harder to merge ranges if method lookups in the gaps result in the
- // same target method.
- const Function& target = Function::Handle(zone, ic_data.GetTargetAt(0));
- if (!MethodRecognizer::PolymorphicTarget(target)) {
- const auto& args_desc_array =
- Array::Handle(zone, ic_data.arguments_descriptor());
- ArgumentsDescriptor args_desc(args_desc_array);
- const auto& name = String::Handle(zone, ic_data.target_name());
- auto& fn = Function::Handle(zone);
-
- intptr_t dest = 0;
- for (intptr_t src = 1; src < cids->length(); src++) {
- // Inspect all cids in the gap and see if they all resolve to the same
- // target.
- bool can_merge = true;
- for (intptr_t cid = cids->cid_ranges_[dest]->cid_end + 1,
- end = cids->cid_ranges_[src]->cid_start;
- cid < end; ++cid) {
- bool class_is_abstract = false;
- if (FlowGraphCompiler::LookupMethodFor(cid, name, args_desc, &fn,
- &class_is_abstract)) {
- if (fn.raw() == target.raw()) {
- continue;
- }
- if (class_is_abstract) {
- continue;
- }
- }
- can_merge = false;
- break;
- }
-
- if (can_merge) {
- cids->cid_ranges_[dest]->cid_end = cids->cid_ranges_[src]->cid_end;
- } else {
- dest++;
- if (src != dest) cids->cid_ranges_[dest] = cids->cid_ranges_[src];
- }
- }
- cids->SetLength(dest + 1);
- }
- }
-
return cids;
}
@@ -740,64 +699,55 @@
return count;
}
-void Cids::CreateHelper(Zone* zone,
- const ICData& ic_data,
- int argument_number,
- bool include_targets) {
- ASSERT(argument_number < ic_data.NumArgsTested());
-
- if (ic_data.NumberOfChecks() == 0) return;
-
+void CallTargets::CreateHelper(Zone* zone, const ICData& ic_data) {
Function& dummy = Function::Handle(zone);
- bool check_one_arg = ic_data.NumArgsTested() == 1;
+ const intptr_t num_args_tested = ic_data.NumArgsTested();
- int checks = ic_data.NumberOfChecks();
- for (int i = 0; i < checks; i++) {
- if (ic_data.GetCountAt(i) == 0) continue;
- intptr_t id = 0;
- if (check_one_arg) {
+ for (int i = 0, n = ic_data.NumberOfChecks(); i < n; i++) {
+ if (ic_data.GetCountAt(i) == 0) {
+ continue;
+ }
+
+ intptr_t id = kDynamicCid;
+ if (num_args_tested == 0) {
+ } else if (num_args_tested == 1) {
ic_data.GetOneClassCheckAt(i, &id, &dummy);
} else {
+ ASSERT(num_args_tested == 2);
GrowableArray<intptr_t> arg_ids;
ic_data.GetCheckAt(i, &arg_ids, &dummy);
- id = arg_ids[argument_number];
+ id = arg_ids[0];
}
- if (include_targets) {
- Function& function = Function::ZoneHandle(zone, ic_data.GetTargetAt(i));
- intptr_t count = ic_data.GetCountAt(i);
- cid_ranges_.Add(new (zone) TargetInfo(id, id, &function, count,
- ic_data.GetExactnessAt(i)));
- } else {
- cid_ranges_.Add(new (zone) CidRange(id, id));
- }
+ Function& function = Function::ZoneHandle(zone, ic_data.GetTargetAt(i));
+ intptr_t count = ic_data.GetCountAt(i);
+ cid_ranges_.Add(new (zone) TargetInfo(id, id, &function, count,
+ ic_data.GetExactnessAt(i)));
}
if (ic_data.is_megamorphic()) {
+ ASSERT(num_args_tested == 1); // Only 1-arg ICData will turn megamorphic.
const String& name = String::Handle(zone, ic_data.target_name());
const Array& descriptor =
Array::Handle(zone, ic_data.arguments_descriptor());
+ Thread* thread = Thread::Current();
const MegamorphicCache& cache = MegamorphicCache::Handle(
- zone, MegamorphicCacheTable::LookupClone(Thread::Current(), name,
- descriptor));
+ zone, MegamorphicCacheTable::Lookup(thread, name, descriptor));
+ SafepointMutexLocker ml(thread->isolate()->megamorphic_mutex());
MegamorphicCacheEntries entries(Array::Handle(zone, cache.buckets()));
- for (intptr_t i = 0; i < entries.Length(); i++) {
+ for (intptr_t i = 0, n = entries.Length(); i < n; i++) {
const intptr_t id =
Smi::Value(entries[i].Get<MegamorphicCache::kClassIdIndex>());
if (id == kIllegalCid) {
continue;
}
- if (include_targets) {
- Function& function = Function::ZoneHandle(zone);
- function ^= entries[i].Get<MegamorphicCache::kTargetFunctionIndex>();
- const intptr_t filled_entry_count = cache.filled_entry_count();
- ASSERT(filled_entry_count > 0);
- cid_ranges_.Add(new (zone) TargetInfo(
- id, id, &function, Usage(function) / filled_entry_count,
- StaticTypeExactnessState::NotTracking()));
- } else {
- cid_ranges_.Add(new (zone) CidRange(id, id));
- }
+ Function& function = Function::ZoneHandle(zone);
+ function ^= entries[i].Get<MegamorphicCache::kTargetFunctionIndex>();
+ const intptr_t filled_entry_count = cache.filled_entry_count();
+ ASSERT(filled_entry_count > 0);
+ cid_ranges_.Add(new (zone) TargetInfo(
+ id, id, &function, Usage(function) / filled_entry_count,
+ StaticTypeExactnessState::NotTracking()));
}
}
}
@@ -812,6 +762,11 @@
return cid_ranges_[0]->cid_start;
}
+StaticTypeExactnessState CallTargets::MonomorphicExactness() const {
+ ASSERT(IsMonomorphic());
+ return TargetAt(0)->exactness;
+}
+
CheckClassInstr::CheckClassInstr(Value* value,
intptr_t deopt_id,
const Cids& cids,
@@ -1113,9 +1068,14 @@
GraphEntryInstr::GraphEntryInstr(const ParsedFunction& parsed_function,
intptr_t osr_id)
- : BlockEntryWithInitialDefs(0,
- kInvalidTryIndex,
- CompilerState::Current().GetNextDeoptId()),
+ : GraphEntryInstr(parsed_function,
+ osr_id,
+ CompilerState::Current().GetNextDeoptId()) {}
+
+GraphEntryInstr::GraphEntryInstr(const ParsedFunction& parsed_function,
+ intptr_t osr_id,
+ intptr_t deopt_id)
+ : BlockEntryWithInitialDefs(0, kInvalidTryIndex, deopt_id),
parsed_function_(parsed_function),
catch_entries_(),
indirect_entries_(),
@@ -1651,6 +1611,7 @@
auto goto_join = new GotoInstr(AsJoinEntry(),
CompilerState::Current().GetNextDeoptId());
+ ASSERT(parent != nullptr);
goto_join->CopyDeoptIdFrom(*parent);
osr_entry->LinkTo(goto_join);
@@ -2021,6 +1982,26 @@
(64 - RepresentationBits(r)));
}
+static int64_t TruncateTo(int64_t v, Representation r) {
+ switch (r) {
+ case kTagged: {
+ // Smi occupies word minus kSmiTagShift bits.
+ const intptr_t kTruncateBits =
+ (kBitsPerInt64 - kBitsPerWord) + kSmiTagShift;
+ return Utils::ShiftLeftWithTruncation(v, kTruncateBits) >> kTruncateBits;
+ }
+ case kUnboxedInt32:
+ return Utils::ShiftLeftWithTruncation(v, kBitsPerInt32) >> kBitsPerInt32;
+ case kUnboxedUint32:
+ return v & kMaxUint32;
+ case kUnboxedInt64:
+ return v;
+ default:
+ UNREACHABLE();
+ return 0;
+ }
+}
+
static bool ToIntegerConstant(Value* value, int64_t* result) {
if (!value->BindsToConstant()) {
UnboxInstr* unbox = value->definition()->AsUnbox();
@@ -2032,7 +2013,7 @@
case kUnboxedUint32:
if (ToIntegerConstant(unbox->value(), result)) {
- *result &= RepresentationMask(kUnboxedUint32);
+ *result = TruncateTo(*result, kUnboxedUint32);
return true;
}
break;
@@ -2380,8 +2361,8 @@
if (!result.IsNull()) {
if (is_truncating()) {
- int64_t truncated = result.AsTruncatedInt64Value();
- truncated &= RepresentationMask(representation());
+ const int64_t truncated =
+ TruncateTo(result.AsTruncatedInt64Value(), representation());
result = Integer::New(truncated, Heap::kOld);
ASSERT(IsRepresentable(result, representation()));
} else if (!IsRepresentable(result, representation())) {
@@ -2514,7 +2495,6 @@
return this;
}
- const int64_t range_mask = RepresentationMask(representation());
if (is_truncating()) {
switch (op_kind()) {
case Token::kMUL:
@@ -2523,7 +2503,7 @@
case Token::kBIT_AND:
case Token::kBIT_OR:
case Token::kBIT_XOR:
- rhs = (rhs & range_mask);
+ rhs = TruncateTo(rhs, representation());
break;
default:
break;
@@ -2566,21 +2546,21 @@
case Token::kBIT_AND:
if (rhs == 0) {
return right()->definition();
- } else if (rhs == range_mask) {
+ } else if (rhs == RepresentationMask(representation())) {
return left()->definition();
}
break;
case Token::kBIT_OR:
if (rhs == 0) {
return left()->definition();
- } else if (rhs == range_mask) {
+ } else if (rhs == RepresentationMask(representation())) {
return right()->definition();
}
break;
case Token::kBIT_XOR:
if (rhs == 0) {
return left()->definition();
- } else if (rhs == range_mask) {
+ } else if (rhs == RepresentationMask(representation())) {
UnaryIntegerOpInstr* bit_not = UnaryIntegerOpInstr::Make(
representation(), Token::kBIT_NOT, left()->CopyWithType(),
GetDeoptId(), range());
@@ -2611,6 +2591,12 @@
}
break;
+ case Token::kMOD:
+ if (std::abs(rhs) == 1) {
+ return CreateConstantResult(flow_graph, Object::smi_zero());
+ }
+ break;
+
case Token::kSHR:
if (rhs == 0) {
return left()->definition();
@@ -3124,10 +3110,18 @@
return replacement;
}
- IntConverterInstr* conv = value()->definition()->AsIntConverter();
- if (conv != NULL) {
- Definition* replacement = this;
+ // For all x, box(unbox(x)) = x.
+ if (auto unbox = value()->definition()->AsUnboxInt64()) {
+ if (unbox->speculative_mode() == kNotSpeculative) {
+ return unbox->value()->definition();
+ }
+ } else if (auto unbox = value()->definition()->AsUnboxedConstant()) {
+ return flow_graph->GetConstant(unbox->value());
+ }
+ // Find a more precise box instruction.
+ if (auto conv = value()->definition()->AsIntConverter()) {
+ Definition* replacement;
switch (conv->from()) {
case kUnboxedInt32:
replacement = new BoxInt32Instr(conv->value()->CopyWithType());
@@ -3139,11 +3133,7 @@
UNREACHABLE();
break;
}
-
- if (replacement != this) {
- flow_graph->InsertBefore(this, replacement, NULL, FlowGraph::kValue);
- }
-
+ flow_graph->InsertBefore(this, replacement, NULL, FlowGraph::kValue);
return replacement;
}
@@ -3772,19 +3762,58 @@
}
}
-CallTargets* CallTargets::Create(Zone* zone, const ICData& ic_data) {
+const BinaryFeedback* BinaryFeedback::Create(Zone* zone,
+ const ICData& ic_data) {
+ BinaryFeedback* result = new (zone) BinaryFeedback(zone);
+ if (ic_data.NumArgsTested() == 2) {
+ for (intptr_t i = 0, n = ic_data.NumberOfChecks(); i < n; i++) {
+ if (ic_data.GetCountAt(i) == 0) {
+ continue;
+ }
+ GrowableArray<intptr_t> arg_ids;
+ ic_data.GetClassIdsAt(i, &arg_ids);
+ result->feedback_.Add({arg_ids[0], arg_ids[1]});
+ }
+ }
+ return result;
+}
+
+const BinaryFeedback* BinaryFeedback::CreateMonomorphic(Zone* zone,
+ intptr_t receiver_cid,
+ intptr_t argument_cid) {
+ BinaryFeedback* result = new (zone) BinaryFeedback(zone);
+ result->feedback_.Add({receiver_cid, argument_cid});
+ return result;
+}
+
+const CallTargets* CallTargets::CreateMonomorphic(Zone* zone,
+ intptr_t receiver_cid,
+ const Function& target) {
CallTargets* targets = new (zone) CallTargets(zone);
- targets->CreateHelper(zone, ic_data, /* argument_number = */ 0,
- /* include_targets = */ true);
+ const intptr_t count = 1;
+ targets->cid_ranges_.Add(new (zone) TargetInfo(
+ receiver_cid, receiver_cid, &Function::ZoneHandle(zone, target.raw()),
+ count, StaticTypeExactnessState::NotTracking()));
+ return targets;
+}
+
+const CallTargets* CallTargets::Create(Zone* zone, const ICData& ic_data) {
+ CallTargets* targets = new (zone) CallTargets(zone);
+ targets->CreateHelper(zone, ic_data);
targets->Sort(OrderById);
targets->MergeIntoRanges();
return targets;
}
-CallTargets* CallTargets::CreateAndExpand(Zone* zone, const ICData& ic_data) {
+const CallTargets* CallTargets::CreateAndExpand(Zone* zone,
+ const ICData& ic_data) {
CallTargets& targets = *new (zone) CallTargets(zone);
- targets.CreateHelper(zone, ic_data, /* argument_number = */ 0,
- /* include_targets = */ true);
+ targets.CreateHelper(zone, ic_data);
+
+ if (targets.is_empty() || targets.IsMonomorphic()) {
+ return &targets;
+ }
+
targets.Sort(OrderById);
Array& args_desc_array = Array::Handle(zone, ic_data.arguments_descriptor());
@@ -3868,6 +3897,10 @@
}
void CallTargets::MergeIntoRanges() {
+ if (length() == 0) {
+ return; // For correctness not performance: must not update length to 1.
+ }
+
// Merge adjacent class id ranges.
int dest = 0;
// We merge entries that dispatch to the same target, but polymorphic targets
@@ -4239,6 +4272,30 @@
}
}
+const char* SpecialParameterInstr::KindToCString(SpecialParameterKind k) {
+ switch (k) {
+#define KIND_CASE(Name) \
+ case SpecialParameterKind::k##Name: \
+ return #Name;
+ FOR_EACH_SPECIAL_PARAMETER_KIND(KIND_CASE)
+#undef KIND_CASE
+ }
+ return nullptr;
+}
+
+bool SpecialParameterInstr::KindFromCString(const char* str,
+ SpecialParameterKind* out) {
+ ASSERT(str != nullptr && out != nullptr);
+#define KIND_CASE(Name) \
+ if (strcmp(str, #Name) == 0) { \
+ *out = SpecialParameterKind::k##Name; \
+ return true; \
+ }
+ FOR_EACH_SPECIAL_PARAMETER_KIND(KIND_CASE)
+#undef KIND_CASE
+ return false;
+}
+
LocationSummary* SpecialParameterInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
// Only appears in initial definitions, never in normal code.
@@ -4492,6 +4549,56 @@
args_desc, allow_add);
}
+const CallTargets& InstanceCallInstr::Targets() {
+ if (targets_ == nullptr) {
+ Zone* zone = Thread::Current()->zone();
+ if (HasICData()) {
+ targets_ = CallTargets::CreateAndExpand(zone, *ic_data());
+ } else {
+ targets_ = new (zone) CallTargets(zone);
+ ASSERT(targets_->is_empty());
+ }
+ }
+ return *targets_;
+}
+
+const BinaryFeedback& InstanceCallInstr::BinaryFeedback() {
+ if (binary_ == nullptr) {
+ Zone* zone = Thread::Current()->zone();
+ if (HasICData()) {
+ binary_ = BinaryFeedback::Create(zone, *ic_data());
+ } else {
+ binary_ = new (zone) class BinaryFeedback(zone);
+ }
+ }
+ return *binary_;
+}
+
+const CallTargets& StaticCallInstr::Targets() {
+ if (targets_ == nullptr) {
+ Zone* zone = Thread::Current()->zone();
+ if (HasICData()) {
+ targets_ = CallTargets::CreateAndExpand(zone, *ic_data());
+ } else {
+ targets_ = new (zone) CallTargets(zone);
+ ASSERT(targets_->is_empty());
+ }
+ }
+ return *targets_;
+}
+
+const BinaryFeedback& StaticCallInstr::BinaryFeedback() {
+ if (binary_ == nullptr) {
+ Zone* zone = Thread::Current()->zone();
+ if (HasICData()) {
+ binary_ = BinaryFeedback::Create(zone, *ic_data());
+ } else {
+ binary_ = new (zone) class BinaryFeedback(zone);
+ }
+ }
+ return *binary_;
+}
+
bool CallTargets::HasSingleRecognizedTarget() const {
if (!HasSingleTarget()) return false;
return MethodRecognizer::RecognizeKind(FirstTarget()) !=
@@ -4499,7 +4606,7 @@
}
bool CallTargets::HasSingleTarget() const {
- ASSERT(length() != 0);
+ if (length() == 0) return false;
for (int i = 0; i < length(); i++) {
if (TargetAt(i)->target->raw() != TargetAt(0)->target->raw()) return false;
}
@@ -4604,7 +4711,7 @@
// TODO(dartbug.com/37291): Allow this optimization, but accumulate affected
// InstanceCallInstrs and the corresponding reciever cids during compilation.
// After compilation, add receiver checks to the ICData for those call sites.
- if (ic_data()->NumberOfUsedChecks() == 0) return this;
+ if (Targets().is_empty()) return this;
const CallTargets* new_target =
FlowGraphCompiler::ResolveCallTargetsForReceiverCid(
@@ -4985,6 +5092,10 @@
EmitLoadFromBox(compiler);
} else if (CanConvertSmi() && (value_cid == kSmiCid)) {
EmitSmiConversion(compiler);
+ } else if (representation() == kUnboxedInt32 && value()->Type()->IsInt()) {
+ EmitLoadInt32FromBoxOrSmi(compiler);
+ } else if (representation() == kUnboxedInt64 && value()->Type()->IsInt()) {
+ EmitLoadInt64FromBoxOrSmi(compiler);
} else {
ASSERT(CanDeoptimize());
EmitLoadFromBoxWithDeopt(compiler);
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index ada13c7..fb2fc75 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -5,6 +5,8 @@
#ifndef RUNTIME_VM_COMPILER_BACKEND_IL_H_
#define RUNTIME_VM_COMPILER_BACKEND_IL_H_
+#include <utility>
+
#include "vm/allocation.h"
#include "vm/code_descriptors.h"
#include "vm/compiler/backend/compile_type.h"
@@ -24,6 +26,7 @@
namespace dart {
+class BinaryFeedback;
class BitVector;
class BlockEntryInstr;
class BlockEntryWithInitialDefs;
@@ -46,10 +49,10 @@
class Range;
class RangeAnalysis;
class RangeBoundary;
-class SExpression;
class SExpList;
-class UnboxIntegerInstr;
+class SExpression;
class TypeUsageInfo;
+class UnboxIntegerInstr;
namespace compiler {
class BlockBuilder;
@@ -573,14 +576,14 @@
// and PolymorphicInstanceCall instructions.
class Cids : public ZoneAllocated {
public:
- explicit Cids(Zone* zone) : zone_(zone) {}
+ explicit Cids(Zone* zone) : cid_ranges_(zone, 6) {}
// Creates the off-heap Cids object that reflects the contents
// of the on-VM-heap IC data.
// Ranges of Cids are merged if there is only one target function and
// it is used for all cids in the gaps between ranges.
- static Cids* CreateAndExpand(Zone* zone,
- const ICData& ic_data,
- int argument_number);
+ static Cids* CreateForArgument(Zone* zone,
+ const BinaryFeedback& binary_feedback,
+ int argument_number);
static Cids* CreateMonomorphic(Zone* zone, intptr_t cid);
bool Equals(const Cids& other) const;
@@ -609,12 +612,7 @@
intptr_t ComputeHighestCid() const;
protected:
- void CreateHelper(Zone* zone,
- const ICData& ic_data,
- int argument_number,
- bool include_targets);
GrowableArray<CidRange*> cid_ranges_;
- Zone* zone_;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(Cids);
@@ -623,18 +621,24 @@
class CallTargets : public Cids {
public:
explicit CallTargets(Zone* zone) : Cids(zone) {}
+
+ static const CallTargets* CreateMonomorphic(Zone* zone,
+ intptr_t receiver_cid,
+ const Function& target);
+
// Creates the off-heap CallTargets object that reflects the contents
// of the on-VM-heap IC data.
- static CallTargets* Create(Zone* zone, const ICData& ic_data);
+ static const CallTargets* Create(Zone* zone, const ICData& ic_data);
// This variant also expands the class-ids to neighbouring classes that
// inherit the same method.
- static CallTargets* CreateAndExpand(Zone* zone, const ICData& ic_data);
+ static const CallTargets* CreateAndExpand(Zone* zone, const ICData& ic_data);
TargetInfo* TargetAt(int i) const { return static_cast<TargetInfo*>(At(i)); }
intptr_t AggregateCallCount() const;
+ StaticTypeExactnessState MonomorphicExactness() const;
bool HasSingleTarget() const;
bool HasSingleRecognizedTarget() const;
const Function& FirstTarget() const;
@@ -642,10 +646,96 @@
void Print() const;
+ bool ReceiverIs(intptr_t cid) const {
+ return IsMonomorphic() && MonomorphicReceiverCid() == cid;
+ }
+ bool ReceiverIsSmiOrMint() const {
+ if (cid_ranges_.is_empty()) {
+ return false;
+ }
+ for (intptr_t i = 0, n = cid_ranges_.length(); i < n; i++) {
+ for (intptr_t j = cid_ranges_[i]->cid_start; j <= cid_ranges_[i]->cid_end;
+ j++) {
+ if (j != kSmiCid && j != kMintCid) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
private:
+ void CreateHelper(Zone* zone, const ICData& ic_data);
void MergeIntoRanges();
};
+// Represents type feedback for the binary operators, and a few recognized
+// static functions (see MethodRecognizer::NumArgsCheckedForStaticCall).
+class BinaryFeedback : public ZoneAllocated {
+ public:
+ explicit BinaryFeedback(Zone* zone) : feedback_(zone, 2) {}
+
+ static const BinaryFeedback* Create(Zone* zone, const ICData& ic_data);
+ static const BinaryFeedback* CreateMonomorphic(Zone* zone,
+ intptr_t receiver_cid,
+ intptr_t argument_cid);
+
+ bool ArgumentIs(intptr_t cid) const {
+ if (feedback_.is_empty()) {
+ return false;
+ }
+ for (intptr_t i = 0, n = feedback_.length(); i < n; i++) {
+ if (feedback_[i].second != cid) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool OperandsAreEither(intptr_t cid_a, intptr_t cid_b) const {
+ if (feedback_.is_empty()) {
+ return false;
+ }
+ for (intptr_t i = 0, n = feedback_.length(); i < n; i++) {
+ if ((feedback_[i].first != cid_a) && (feedback_[i].first != cid_b)) {
+ return false;
+ }
+ if ((feedback_[i].second != cid_a) && (feedback_[i].second != cid_b)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ bool OperandsAreSmiOrNull() const {
+ return OperandsAreEither(kSmiCid, kNullCid);
+ }
+ bool OperandsAreSmiOrMint() const {
+ return OperandsAreEither(kSmiCid, kMintCid);
+ }
+ bool OperandsAreSmiOrDouble() const {
+ return OperandsAreEither(kSmiCid, kDoubleCid);
+ }
+
+ bool OperandsAre(intptr_t cid) const {
+ if (feedback_.length() != 1) return false;
+ return (feedback_[0].first == cid) && (feedback_[0].second == cid);
+ }
+
+ bool IncludesOperands(intptr_t cid) const {
+ for (intptr_t i = 0, n = feedback_.length(); i < n; i++) {
+ if ((feedback_[i].first == cid) && (feedback_[i].second == cid)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private:
+ GrowableArray<std::pair<intptr_t, intptr_t>> feedback_;
+
+ friend class Cids;
+};
+
class Instruction : public ZoneAllocated {
public:
#define DECLARE_TAG(type, attrs) k##type,
@@ -1319,6 +1409,8 @@
BitVector* block_marks);
private:
+ friend class FlowGraphDeserializer; // Access to AddPredecessor().
+
virtual void RawSetInputAt(intptr_t i, Value* value) { UNREACHABLE(); }
virtual void ClearPredecessors() = 0;
@@ -1506,6 +1598,12 @@
PRINT_TO_SUPPORT
private:
+ friend class FlowGraphDeserializer; // For the constructor with deopt_id arg.
+
+ GraphEntryInstr(const ParsedFunction& parsed_function,
+ intptr_t osr_id,
+ intptr_t deopt_id);
+
virtual void ClearPredecessors() {}
virtual void AddPredecessor(BlockEntryInstr* predecessor) { UNREACHABLE(); }
@@ -1904,10 +2002,7 @@
explicit Definition(intptr_t deopt_id = DeoptId::kNone);
// Overridden by definitions that have call counts.
- virtual intptr_t CallCount() const {
- UNREACHABLE();
- return -1;
- }
+ virtual intptr_t CallCount() const { return -1; }
intptr_t temp_index() const { return temp_index_; }
void set_temp_index(intptr_t index) { temp_index_ = index; }
@@ -3272,13 +3367,25 @@
// the type arguments of a generic function or an arguments descriptor.
class SpecialParameterInstr : public TemplateDefinition<0, NoThrow> {
public:
- enum SpecialParameterKind {
- kContext,
- kTypeArgs,
- kArgDescriptor,
- kException,
- kStackTrace
- };
+#define FOR_EACH_SPECIAL_PARAMETER_KIND(M) \
+ M(Context) \
+ M(TypeArgs) \
+ M(ArgDescriptor) \
+ M(Exception) \
+ M(StackTrace)
+
+#define KIND_DECL(name) k##name,
+ enum SpecialParameterKind { FOR_EACH_SPECIAL_PARAMETER_KIND(KIND_DECL) };
+#undef KIND_DECL
+
+ // Defined as a static intptr_t instead of inside the enum since some
+ // switch statements depend on the exhaustibility checking.
+#define KIND_INC(name) +1
+ static const intptr_t kNumKinds = 0 FOR_EACH_SPECIAL_PARAMETER_KIND(KIND_INC);
+#undef KIND_INC
+
+ static const char* KindToCString(SpecialParameterKind k);
+ static bool KindFromCString(const char* str, SpecialParameterKind* out);
SpecialParameterInstr(SpecialParameterKind kind,
intptr_t deopt_id,
@@ -3305,23 +3412,6 @@
PRINT_OPERANDS_TO_SUPPORT
ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
- static const char* KindToCString(SpecialParameterKind kind) {
- switch (kind) {
- case kContext:
- return "kContext";
- case kTypeArgs:
- return "kTypeArgs";
- case kArgDescriptor:
- return "kArgDescriptor";
- case kException:
- return "kException";
- case kStackTrace:
- return "kStackTrace";
- }
- UNREACHABLE();
- return NULL;
- }
-
private:
const SpecialParameterKind kind_;
BlockEntryInstr* block_;
@@ -3440,6 +3530,7 @@
Code::EntryKind entry_kind() const { return entry_kind_; }
PRINT_OPERANDS_TO_SUPPORT
+ ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
private:
const Code::EntryKind entry_kind_;
@@ -3584,12 +3675,22 @@
void set_entry_kind(Code::EntryKind value) { entry_kind_ = value; }
+ const CallTargets& Targets();
+ void SetTargets(const CallTargets* targets) { targets_ = targets; }
+
+ const BinaryFeedback& BinaryFeedback();
+ void SetBinaryFeedback(const class BinaryFeedback* binary) {
+ binary_ = binary;
+ }
+
protected:
friend class CallSpecializer;
void set_ic_data(ICData* value) { ic_data_ = value; }
private:
const ICData* ic_data_;
+ const CallTargets* targets_ = nullptr;
+ const class BinaryFeedback* binary_ = nullptr;
const String& function_name_;
const Token::Kind token_kind_; // Binary op, unary op, kGET or kILLEGAL.
const intptr_t checked_argument_count_;
@@ -3713,6 +3814,7 @@
bool AttributesEqual(Instruction* other) const;
PRINT_OPERANDS_TO_SUPPORT
+ ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT;
private:
// True if the comparison must check for double or Mint and
@@ -4107,11 +4209,17 @@
virtual AliasIdentity Identity() const { return identity_; }
virtual void SetIdentity(AliasIdentity identity) { identity_ = identity; }
+ const CallTargets& Targets();
+ const BinaryFeedback& BinaryFeedback();
+
PRINT_OPERANDS_TO_SUPPORT
ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
+ ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
private:
const ICData* ic_data_;
+ const CallTargets* targets_ = nullptr;
+ const class BinaryFeedback* binary_ = nullptr;
const intptr_t call_count_;
const Function& function_;
const ICData::RebindRule rebind_rule_;
@@ -4190,10 +4298,7 @@
return false;
}
- virtual bool MayThrow() const {
- UNREACHABLE();
- return false;
- }
+ virtual bool MayThrow() const { return false; }
virtual TokenPosition token_pos() const { return TokenPosition::kTempMove; }
@@ -4238,10 +4343,7 @@
return false;
}
- virtual bool MayThrow() const {
- UNREACHABLE();
- return false;
- }
+ virtual bool MayThrow() const { return false; }
virtual TokenPosition token_pos() const { return TokenPosition::kTempMove; }
@@ -4445,6 +4547,8 @@
virtual bool HasUnknownSideEffects() const { return true; }
virtual Instruction* Canonicalize(FlowGraph* flow_graph);
+ ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
+
private:
const TokenPosition token_pos_;
const RawPcDescriptors::Kind stub_kind_;
@@ -4561,6 +4665,7 @@
PRINT_OPERANDS_TO_SUPPORT
ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
+ ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
private:
friend class JitCallSpecializer; // For ASSERT(initialization_).
@@ -7641,8 +7746,9 @@
virtual bool RecomputeType();
// CheckNull can implicitly call Dart code (NoSuchMethodError constructor),
- // so it can lazily deopt.
+ // so it needs a deopt ID in optimized and unoptimized code.
virtual bool ComputeCanDeoptimize() const { return true; }
+ virtual bool CanBecomeDeoptimizationTarget() const { return true; }
virtual Definition* Canonicalize(FlowGraph* flow_graph);
@@ -7653,6 +7759,8 @@
virtual Value* RedefinedValue() const;
+ ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
+
private:
const TokenPosition token_pos_;
const String& function_name_;
@@ -8454,6 +8562,7 @@
private:
friend class ShallowIterator;
friend class compiler::BlockBuilder; // For Environment constructor.
+ friend class FlowGraphDeserializer; // For constructor and deopt_id_.
Environment(intptr_t length,
intptr_t fixed_parameter_count,
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index e747e3e..6f00a18 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -1137,10 +1137,6 @@
}
void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- if (FLAG_precompiled_mode) {
- UNREACHABLE();
- }
-
// Constant pool cannot be used until we enter the actual Dart frame.
__ set_constant_pool_allowed(false);
@@ -1165,8 +1161,41 @@
// Load the thread object. If we were called by a trampoline, the thread is
// already loaded.
- //
- // TODO(35765): Fix linking issue on AOT.
+ if (FLAG_precompiled_mode) {
+ compiler::Label skip_reloc;
+ __ b(&skip_reloc);
+ compiler->InsertBSSRelocation(
+ BSS::Relocation::DRT_GetThreadForNativeCallback);
+ __ Bind(&skip_reloc);
+
+ // For historical reasons, the PC on ARM points 8 bytes (two instructions)
+ // past the current instruction.
+ __ sub(
+ R0, PC,
+ compiler::Operand(Instr::kPCReadOffset + compiler::target::kWordSize));
+
+ // R0 holds the address of the relocation.
+ __ ldr(R1, compiler::Address(R0));
+
+ // R1 holds the relocation itself: R0 - bss_start.
+ // R0 = R0 + (bss_start - R0) = bss_start
+ __ add(R0, R0, compiler::Operand(R1));
+
+ // R0 holds the start of the BSS section.
+ // Load the "get-thread" routine: *bss_start.
+ __ ldr(R1, compiler::Address(R0));
+ } else if (!NativeCallbackTrampolines::Enabled()) {
+ // In JIT mode, we can just paste the address of the runtime entry into the
+ // generated code directly. This is not a problem since we don't save
+ // callbacks into JIT snapshots.
+ ASSERT(kWordSize == compiler::target::kWordSize);
+ __ LoadImmediate(
+ R1, static_cast<compiler::target::uword>(
+ reinterpret_cast<uword>(DLRT_GetThreadForNativeCallback)));
+ }
+
+ // Load the thread object. If we were called by a trampoline, the thread is
+ // already loaded.
if (!NativeCallbackTrampolines::Enabled()) {
// Create another frame to align the frame before continuing in "native"
// code.
@@ -1174,8 +1203,6 @@
__ ReserveAlignedFrameSpace(0);
__ LoadImmediate(R0, callback_id_);
- __ LoadImmediate(
- R1, reinterpret_cast<int64_t>(DLRT_GetThreadForNativeCallback));
__ blx(R1);
__ mov(THR, compiler::Operand(R0));
@@ -6954,7 +6981,8 @@
break;
case kUnboxedFloat:
case kUnboxedDouble:
- summary->set_in(0, Location::RequiresFpuRegister());
+ // Choose an FPU register with corresponding D and S registers.
+ summary->set_in(0, Location::FpuRegisterLocation(Q0));
break;
default:
UNREACHABLE();
@@ -6970,7 +6998,8 @@
break;
case kUnboxedFloat:
case kUnboxedDouble:
- summary->set_out(0, Location::RequiresFpuRegister());
+ // Choose an FPU register with corresponding D and S registers.
+ summary->set_out(0, Location::FpuRegisterLocation(Q0));
break;
default:
UNREACHABLE();
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index ced71dd..b49dc6e 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -1020,10 +1020,6 @@
}
void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- if (FLAG_precompiled_mode) {
- UNREACHABLE();
- }
-
// Constant pool cannot be used until we enter the actual Dart frame.
__ set_constant_pool_allowed(false);
@@ -1052,8 +1048,33 @@
// Load the thread object. If we were called by a trampoline, the thread is
// already loaded.
- //
- // TODO(35765): Fix linking issue on AOT.
+ if (FLAG_precompiled_mode) {
+ compiler::Label skip_reloc;
+ __ b(&skip_reloc);
+ compiler->InsertBSSRelocation(
+ BSS::Relocation::DRT_GetThreadForNativeCallback);
+ __ Bind(&skip_reloc);
+
+ __ adr(R0, compiler::Immediate(-compiler::target::kWordSize));
+
+ // R0 holds the address of the relocation.
+ __ ldr(R1, compiler::Address(R0));
+
+ // R1 holds the relocation itself: R0 - bss_start.
+ // R0 = R0 + (bss_start - R0) = bss_start
+ __ add(R0, R0, compiler::Operand(R1));
+
+ // R0 holds the start of the BSS section.
+ // Load the "get-thread" routine: *bss_start.
+ __ ldr(R1, compiler::Address(R0));
+ } else if (!NativeCallbackTrampolines::Enabled()) {
+ // In JIT mode, we can just paste the address of the runtime entry into the
+ // generated code directly. This is not a problem since we don't save
+ // callbacks into JIT snapshots.
+ __ LoadImmediate(
+ R1, reinterpret_cast<int64_t>(DLRT_GetThreadForNativeCallback));
+ }
+
if (!NativeCallbackTrampolines::Enabled()) {
// Create another frame to align the frame before continuing in "native"
// code.
@@ -1061,8 +1082,6 @@
__ ReserveAlignedFrameSpace(0);
__ LoadImmediate(R0, callback_id_);
- __ LoadImmediate(
- R1, reinterpret_cast<int64_t>(DLRT_GetThreadForNativeCallback));
__ blr(R1);
__ mov(THR, R0);
diff --git a/runtime/vm/compiler/backend/il_deserializer.cc b/runtime/vm/compiler/backend/il_deserializer.cc
new file mode 100644
index 0000000..f4bf535
--- /dev/null
+++ b/runtime/vm/compiler/backend/il_deserializer.cc
@@ -0,0 +1,1760 @@
+// Copyright (c) 2019, 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.
+
+#if !defined(DART_PRECOMPILED_RUNTIME)
+
+#include "vm/compiler/backend/il_deserializer.h"
+
+#include "vm/compiler/backend/il_serializer.h"
+#include "vm/compiler/jit/compiler.h"
+#include "vm/flags.h"
+#include "vm/os.h"
+
+namespace dart {
+
+DEFINE_FLAG(bool,
+ trace_round_trip_serialization,
+ false,
+ "Print out tracing information during round trip serialization.");
+DEFINE_FLAG(bool,
+ print_json_round_trip_results,
+ false,
+ "Print out results of each round trip serialization in JSON form.");
+
+// Contains the contents of a single round-trip result.
+struct RoundTripResults : public ValueObject {
+ explicit RoundTripResults(Zone* zone, const Function& func)
+ : function(func), unhandled(zone, 2) {}
+
+ // The function for which a flow graph was being parsed.
+ const Function& function;
+ // Whether the round trip succeeded.
+ bool success = false;
+ // An array of unhandled instructions found in the flow graph.
+ GrowableArray<Instruction*> unhandled;
+ // The serialized form of the flow graph, if computed.
+ SExpression* serialized = nullptr;
+ // The error information from the deserializer, if an error occurred.
+ const char* error_message = nullptr;
+ SExpression* error_sexp = nullptr;
+};
+
+static void PrintRoundTripResults(Zone* zone, const RoundTripResults& results) {
+ THR_Print("Results of round trip serialization: {\"function\":\"%s\"",
+ results.function.ToFullyQualifiedCString());
+ THR_Print(",\"success\":%s", results.success ? "true" : "false");
+ if (!results.unhandled.is_empty()) {
+ CStringMap<intptr_t> count_map(zone);
+ for (auto inst : results.unhandled) {
+ auto const name = inst->DebugName();
+ auto const old_count = count_map.LookupValue(name);
+ count_map.Update({name, old_count + 1});
+ }
+ THR_Print(",\"unhandled\":{");
+ auto count_it = count_map.GetIterator();
+ auto first_kv = count_it.Next();
+ THR_Print("\"%s\":%" Pd "", first_kv->key, first_kv->value);
+ while (auto kv = count_it.Next()) {
+ THR_Print(",\"%s\":%" Pd "", kv->key, kv->value);
+ }
+ THR_Print("}");
+ }
+ if (results.serialized != nullptr) {
+ TextBuffer buf(1000);
+ results.serialized->SerializeTo(zone, &buf, "");
+ // Now that the S-expression has been serialized to the TextBuffer, we now
+ // want to take that version and escape it since we will use it as the
+ // contents of a JSON string. Thankfully, escaping can be done via
+ // TextBuffer::AddEscapedString, so we steal the current buffer and then
+ // re-print it in escaped form into the now-cleared buffer.
+ char* const unescaped_sexp = buf.Steal();
+ buf.AddEscapedString(unescaped_sexp);
+ free(unescaped_sexp);
+ THR_Print(",\"serialized\":\"%s\"", buf.buf());
+ }
+ if (results.error_message != nullptr) {
+ TextBuffer buf(1000);
+ ASSERT(results.error_sexp != nullptr);
+ // Same serialized S-expression juggling as in the results.serialized case.
+ // We also escape the error message, in case it included quotes.
+ buf.AddEscapedString(results.error_message);
+ char* const escaped_message = buf.Steal();
+ results.error_sexp->SerializeTo(zone, &buf, "");
+ char* const unescaped_sexp = buf.Steal();
+ buf.AddEscapedString(unescaped_sexp);
+ free(unescaped_sexp);
+ THR_Print(",\"error\":{\"message\":\"%s\",\"expression\":\"%s\"}",
+ escaped_message, buf.buf());
+ free(escaped_message);
+ }
+ THR_Print("}\n");
+}
+
+void FlowGraphDeserializer::RoundTripSerialization(CompilerPassState* state) {
+ auto const flow_graph = state->flow_graph;
+
+ // The deserialized flow graph must be in the same zone as the original flow
+ // graph, to ensure it has the right lifetime. Thus, we leave an explicit
+ // use of [flow_graph->zone()] in the deserializer construction.
+ //
+ // Otherwise, it would be nice to use a StackZone to limit the lifetime of the
+ // serialized form (and other values created with this [zone] variable), since
+ // it only needs to live for the dynamic extent of this method.
+ //
+ // However, creating a StackZone for it also changes the zone associated with
+ // the thread. Also, some parts of the VM used in later updates to the
+ // deserializer implicitly pick up the zone to use either from a passed-in
+ // thread or the current thread instead of taking an explicit zone.
+ //
+ // For now, just serialize into the same zone as the original flow graph, and
+ // we can revisit this if this causes a performance issue or if we can ensure
+ // that those VM parts mentioned can be passed an explicit zone.
+ Zone* const zone = flow_graph->zone();
+
+ // Final flow graph, if we successfully serialize and deserialize.
+ FlowGraph* new_graph = nullptr;
+
+ // Stored information for printing results if requested.
+ RoundTripResults results(zone, flow_graph->function());
+
+ FlowGraphDeserializer::AllUnhandledInstructions(flow_graph,
+ &results.unhandled);
+ if (results.unhandled.is_empty()) {
+ results.serialized = FlowGraphSerializer::SerializeToSExp(zone, flow_graph);
+
+ if (FLAG_trace_round_trip_serialization && results.serialized != nullptr) {
+ TextBuffer buf(1000);
+ results.serialized->SerializeTo(zone, &buf, "");
+ THR_Print("Serialized flow graph:\n%s\n", buf.buf());
+ }
+
+ // For the deserializer, use the thread from the compiler pass and zone
+ // associated with the existing flow graph to make sure the new flow graph
+ // has the right lifetime.
+ FlowGraphDeserializer d(state->thread, flow_graph->zone(),
+ results.serialized, &flow_graph->parsed_function());
+ new_graph = d.ParseFlowGraph();
+ if (new_graph == nullptr) {
+ ASSERT(d.error_message() != nullptr && d.error_sexp() != nullptr);
+ if (FLAG_trace_round_trip_serialization) {
+ THR_Print("Failure during deserialization: %s\n", d.error_message());
+ THR_Print("At S-expression %s\n", d.error_sexp()->ToCString(zone));
+ }
+ results.error_message = d.error_message();
+ results.error_sexp = d.error_sexp();
+ } else {
+ if (FLAG_trace_round_trip_serialization) {
+ THR_Print("Successfully deserialized graph for %s\n",
+ results.serialized->AsList()->At(0)->AsSymbol()->value());
+ }
+ results.success = true;
+ }
+ } else if (FLAG_trace_round_trip_serialization) {
+ THR_Print("Cannot serialize graph due to instruction: %s\n",
+ results.unhandled.At(0)->DebugName());
+ }
+
+ if (FLAG_print_json_round_trip_results) PrintRoundTripResults(zone, results);
+
+ if (new_graph != nullptr) state->flow_graph = new_graph;
+}
+
+#define HANDLED_CASE(name) \
+ if (inst->Is##name()) return true;
+bool FlowGraphDeserializer::IsHandledInstruction(Instruction* inst) {
+ if (auto const const_inst = inst->AsConstant()) {
+ return IsHandledConstant(const_inst->value());
+ }
+ FOR_EACH_HANDLED_BLOCK_TYPE_IN_DESERIALIZER(HANDLED_CASE)
+ FOR_EACH_HANDLED_INSTRUCTION_IN_DESERIALIZER(HANDLED_CASE)
+ return false;
+}
+#undef HANDLED_CASE
+
+void FlowGraphDeserializer::AllUnhandledInstructions(
+ const FlowGraph* graph,
+ GrowableArray<Instruction*>* unhandled) {
+ ASSERT(graph != nullptr);
+ ASSERT(unhandled != nullptr);
+ for (auto block_it = graph->reverse_postorder_iterator(); !block_it.Done();
+ block_it.Advance()) {
+ auto const entry = block_it.Current();
+ if (!IsHandledInstruction(entry)) unhandled->Add(entry);
+ // Don't check the Phi definitions in JoinEntrys, as those are now handled
+ // and also parsed differently from other definitions.
+ if (auto const def_block = entry->AsBlockEntryWithInitialDefs()) {
+ auto const defs = def_block->initial_definitions();
+ for (intptr_t i = 0; i < defs->length(); i++) {
+ auto const current = defs->At(i);
+ if (!IsHandledInstruction(current)) unhandled->Add(current);
+ }
+ }
+ for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) {
+ auto current = it.Current();
+ // We handle branches, so we need to check the comparison instruction.
+ if (current->IsBranch()) current = current->AsBranch()->comparison();
+ if (!IsHandledInstruction(current)) unhandled->Add(current);
+ }
+ }
+}
+
+// Keep in sync with work in ParseDartValue. Right now, this is just a shallow
+// check, not a deep one.
+bool FlowGraphDeserializer::IsHandledConstant(const Object& obj) {
+ if (obj.IsArray()) return Array::Cast(obj).IsImmutable();
+ return obj.IsNull() || obj.IsClass() || obj.IsFunction() || obj.IsField() ||
+ obj.IsInstance();
+}
+
+SExpression* FlowGraphDeserializer::Retrieve(SExpList* list, intptr_t index) {
+ if (list == nullptr) return nullptr;
+ if (list->Length() <= index) {
+ StoreError(list, "expected at least %" Pd " element(s) in list", index + 1);
+ return nullptr;
+ }
+ auto const elem = list->At(index);
+ if (elem == nullptr) {
+ StoreError(list, "null value at index %" Pd "", index);
+ }
+ return elem;
+}
+
+SExpression* FlowGraphDeserializer::Retrieve(SExpList* list, const char* key) {
+ if (list == nullptr) return nullptr;
+ if (!list->ExtraHasKey(key)) {
+ StoreError(list, "expected an extra info entry for key %s", key);
+ return nullptr;
+ }
+ auto const elem = list->ExtraLookupValue(key);
+ if (elem == nullptr) {
+ StoreError(list, "null value for key %s", key);
+ }
+ return elem;
+}
+
+FlowGraph* FlowGraphDeserializer::ParseFlowGraph() {
+ auto const root = CheckTaggedList(root_sexp_, "FlowGraph");
+ if (root == nullptr) return nullptr;
+
+ intptr_t deopt_id = DeoptId::kNone;
+ if (auto const deopt_id_sexp =
+ CheckInteger(root->ExtraLookupValue("deopt_id"))) {
+ deopt_id = deopt_id_sexp->value();
+ }
+ EntryInfo common_info = {0, kInvalidTryIndex, deopt_id};
+
+ auto const graph = DeserializeGraphEntry(root, common_info);
+
+ PrologueInfo pi(-1, -1);
+ flow_graph_ = new (zone()) FlowGraph(*parsed_function_, graph, 0, pi);
+ flow_graph_->CreateCommonConstants();
+
+ intptr_t pos = 2;
+ if (auto const pool = CheckTaggedList(Retrieve(root, pos), "Constants")) {
+ if (!ParseConstantPool(pool)) return nullptr;
+ pos++;
+ }
+
+ // The deopt environment for the graph entry may use entries from the
+ // constant pool, so that must be parsed first.
+ if (auto const env_sexp = CheckList(root->ExtraLookupValue("env"))) {
+ auto const env = ParseEnvironment(env_sexp);
+ if (env == nullptr) return nullptr;
+ env->DeepCopyTo(zone(), graph);
+ }
+
+ auto const entries_sexp = CheckTaggedList(Retrieve(root, pos), "Entries");
+ if (!ParseEntries(entries_sexp)) return nullptr;
+ pos++;
+
+ // Now prime the block worklist with entries. We keep the block worklist
+ // in reverse order so that we can just pop the next block for content
+ // parsing off the end.
+ BlockWorklist block_worklist(zone(), entries_sexp->Length() - 1);
+
+ const auto& indirect_entries = graph->indirect_entries();
+ for (auto indirect_entry : indirect_entries) {
+ block_worklist.Add(indirect_entry->block_id());
+ }
+
+ const auto& catch_entries = graph->catch_entries();
+ for (auto catch_entry : catch_entries) {
+ block_worklist.Add(catch_entry->block_id());
+ }
+
+ if (auto const osr_entry = graph->osr_entry()) {
+ block_worklist.Add(osr_entry->block_id());
+ }
+ if (auto const unchecked_entry = graph->unchecked_entry()) {
+ block_worklist.Add(unchecked_entry->block_id());
+ }
+ if (auto const normal_entry = graph->normal_entry()) {
+ block_worklist.Add(normal_entry->block_id());
+ }
+
+ // The graph entry doesn't push any arguments onto the stack. Adding a
+ // pushed_stack_map_ entry for it allows us to unify how function entries
+ // are handled vs. other types of blocks with regards to incoming pushed
+ // argument stacks.
+ auto const empty_stack = new (zone()) PushStack(zone(), 0);
+ pushed_stack_map_.Insert(0, empty_stack);
+
+ if (!ParseBlocks(root, pos, &block_worklist)) return nullptr;
+
+ // Before we return the new graph, make sure all definitions were found for
+ // all pending values.
+ if (values_map_.Length() > 0) {
+ auto it = values_map_.GetIterator();
+ auto const kv = it.Next();
+ // TODO(sstrickl): This assumes SSA variables.
+ auto const sym =
+ new (zone()) SExpSymbol(OS::SCreate(zone(), "v%" Pd "", kv->key));
+ StoreError(sym, "no definition found for variable index in flow graph");
+ return nullptr;
+ }
+
+ flow_graph_->set_max_block_id(max_block_id_);
+ flow_graph_->set_current_ssa_temp_index(max_ssa_index_ + 1);
+ // Now that the deserializer has finished re-creating all the blocks in the
+ // flow graph, the blocks must be rediscovered. In addition, if ComputeSSA
+ // has already been run, dominators must be recomputed as well.
+ flow_graph_->DiscoverBlocks();
+ // Currently we only handle SSA graphs, so always do this.
+ GrowableArray<BitVector*> dominance_frontier;
+ flow_graph_->ComputeDominators(&dominance_frontier);
+
+ return flow_graph_;
+}
+
+bool FlowGraphDeserializer::ParseConstantPool(SExpList* pool) {
+ ASSERT(flow_graph_ != nullptr);
+ if (pool == nullptr) return false;
+ // Definitions in the constant pool may refer to later definitions. However,
+ // there should be no cycles possible between constant objects, so using a
+ // worklist algorithm we should always be able to make progress.
+ // Since we will not be adding new definitions, we make the initial size of
+ // the worklist the number of definitions in the constant pool.
+ GrowableArray<SExpList*> worklist(zone(), pool->Length() - 1);
+ // We keep old_worklist in reverse order so that we can just RemoveLast
+ // to get elements in their original order.
+ for (intptr_t i = pool->Length() - 1; i > 0; i--) {
+ const auto def_sexp = CheckTaggedList(pool->At(i), "def");
+ if (def_sexp == nullptr) return false;
+ worklist.Add(def_sexp);
+ }
+ while (true) {
+ const intptr_t worklist_len = worklist.length();
+ GrowableArray<SExpList*> parse_failures(zone(), worklist_len);
+ while (!worklist.is_empty()) {
+ const auto def_sexp = worklist.RemoveLast();
+ auto& obj = Object::ZoneHandle(zone());
+ if (!ParseDartValue(Retrieve(def_sexp, 2), &obj)) {
+ parse_failures.Add(def_sexp);
+ continue;
+ }
+ ConstantInstr* def = flow_graph_->GetConstant(obj);
+ if (!ParseDefinitionWithParsedBody(def_sexp, def)) return false;
+ }
+ if (parse_failures.is_empty()) break;
+ // We've gone through the whole worklist without success, so return
+ // the last error we encountered.
+ if (parse_failures.length() == worklist_len) return false;
+ // worklist was added to in order, so we need to reverse its contents
+ // when we add them to old_worklist.
+ while (!parse_failures.is_empty()) {
+ worklist.Add(parse_failures.RemoveLast());
+ }
+ }
+ return true;
+}
+
+bool FlowGraphDeserializer::ParseEntries(SExpList* list) {
+ ASSERT(flow_graph_ != nullptr);
+ if (list == nullptr) return false;
+ for (intptr_t i = 1; i < list->Length(); i++) {
+ const auto entry = CheckTaggedList(Retrieve(list, i));
+ if (entry == nullptr) return false;
+ intptr_t block_id;
+ if (!ParseBlockId(CheckSymbol(Retrieve(entry, 1)), &block_id)) {
+ return false;
+ }
+ if (block_map_.LookupValue(block_id) != nullptr) {
+ StoreError(entry->At(1), "multiple entries for block found");
+ return false;
+ }
+ const auto tag = entry->At(0)->AsSymbol();
+ if (ParseBlockHeader(entry, block_id, tag) == nullptr) return false;
+ }
+ return true;
+}
+
+bool FlowGraphDeserializer::ParseBlocks(SExpList* list,
+ intptr_t pos,
+ BlockWorklist* worklist) {
+ // First, ensure that all the block headers have been parsed. Set up a
+ // map from block IDs to S-expressions and the max_block_id while we're at it.
+ IntMap<SExpList*> block_sexp_map(zone());
+ for (intptr_t i = pos, n = list->Length(); i < n; i++) {
+ auto const block_sexp = CheckTaggedList(Retrieve(list, i), "Block");
+ intptr_t block_id;
+ if (!ParseBlockId(CheckSymbol(Retrieve(block_sexp, 1)), &block_id)) {
+ return false;
+ }
+ if (block_sexp_map.LookupValue(block_id) != nullptr) {
+ StoreError(block_sexp->At(1), "multiple definitions of block found");
+ return false;
+ }
+ block_sexp_map.Insert(block_id, block_sexp);
+ auto const type_tag =
+ CheckSymbol(block_sexp->ExtraLookupValue("block_type"));
+ // Entry block headers are already parsed, but others aren't.
+ if (block_map_.LookupValue(block_id) == nullptr) {
+ if (ParseBlockHeader(block_sexp, block_id, type_tag) == nullptr) {
+ return false;
+ }
+ }
+ if (max_block_id_ < block_id) max_block_id_ = block_id;
+ }
+
+ // Now start parsing the contents of blocks from the worklist. We use an
+ // IntMap to keep track of what blocks have already been fully parsed.
+ IntMap<bool> fully_parsed_block_map(zone());
+ while (!worklist->is_empty()) {
+ auto const block_id = worklist->RemoveLast();
+
+ // If we've already encountered this block, skip it.
+ if (fully_parsed_block_map.LookupValue(block_id)) continue;
+
+ auto const block_sexp = block_sexp_map.LookupValue(block_id);
+ ASSERT(block_sexp != nullptr);
+
+ // Copy the pushed argument stack of the predecessor to begin the stack for
+ // this block. This is safe due to the worklist algorithm, since one
+ // predecessor has already been added when this block is first reached.
+ //
+ // For JoinEntry blocks, since the worklist algorithm is a depth-first
+ // search, we may not see all possible predecessors before the JoinEntry
+ // is parsed. To ensure consistency between predecessor stacks, we check
+ // the consistency in ParseBlockContents when updating predecessor
+ // information.
+ current_block_ = block_map_.LookupValue(block_id);
+ ASSERT(current_block_ != nullptr);
+ ASSERT(current_block_->PredecessorCount() > 0);
+ auto const pred_id = current_block_->PredecessorAt(0)->block_id();
+ auto const pred_stack = pushed_stack_map_.LookupValue(pred_id);
+ ASSERT(pred_stack != nullptr);
+ auto const new_stack = new (zone()) PushStack(zone(), pred_stack->length());
+ new_stack->AddArray(*pred_stack);
+ pushed_stack_map_.Insert(block_id, new_stack);
+
+ if (!ParseBlockContents(block_sexp, worklist)) return false;
+
+ // Mark this block as done.
+ fully_parsed_block_map.Insert(block_id, true);
+ }
+
+ // Double-check that all blocks were reached by the worklist algorithm.
+ auto it = block_sexp_map.GetIterator();
+ while (auto kv = it.Next()) {
+ if (!fully_parsed_block_map.LookupValue(kv->key)) {
+ StoreError(kv->value, "block unreachable in flow graph");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool FlowGraphDeserializer::ParseInitialDefinitions(SExpList* list) {
+ ASSERT(current_block_ != nullptr);
+ ASSERT(current_block_->IsBlockEntryWithInitialDefs());
+ auto const block = current_block_->AsBlockEntryWithInitialDefs();
+ if (list == nullptr) return false;
+ for (intptr_t i = 2; i < list->Length(); i++) {
+ const auto def_sexp = CheckTaggedList(Retrieve(list, i), "def");
+ const auto def = ParseDefinition(def_sexp);
+ if (def == nullptr) return false;
+ flow_graph_->AddToInitialDefinitions(block, def);
+ }
+ return true;
+}
+
+BlockEntryInstr* FlowGraphDeserializer::ParseBlockHeader(SExpList* list,
+ intptr_t block_id,
+ SExpSymbol* tag) {
+ ASSERT(flow_graph_ != nullptr);
+ // We should only parse block headers once.
+ ASSERT(block_map_.LookupValue(block_id) == nullptr);
+ if (list == nullptr) return nullptr;
+
+#if defined(DEBUG)
+ intptr_t parsed_block_id;
+ auto const id_sexp = CheckSymbol(Retrieve(list, 1));
+ if (!ParseBlockId(id_sexp, &parsed_block_id)) return nullptr;
+ ASSERT(block_id == parsed_block_id);
+#endif
+
+ auto const kind = FlowGraphSerializer::BlockEntryTagToKind(tag);
+
+ intptr_t deopt_id = DeoptId::kNone;
+ if (auto const deopt_int = CheckInteger(list->ExtraLookupValue("deopt_id"))) {
+ deopt_id = deopt_int->value();
+ }
+ intptr_t try_index = kInvalidTryIndex;
+ if (auto const try_int = CheckInteger(list->ExtraLookupValue("try_index"))) {
+ try_index = try_int->value();
+ }
+
+ BlockEntryInstr* block = nullptr;
+ EntryInfo common_info = {block_id, try_index, deopt_id};
+ switch (kind) {
+ case FlowGraphSerializer::kTarget:
+ block = DeserializeTargetEntry(list, common_info);
+ break;
+ case FlowGraphSerializer::kNormal:
+ block = DeserializeFunctionEntry(list, common_info);
+ if (block != nullptr) {
+ auto const graph = flow_graph_->graph_entry();
+ graph->set_normal_entry(block->AsFunctionEntry());
+ }
+ break;
+ case FlowGraphSerializer::kUnchecked: {
+ block = DeserializeFunctionEntry(list, common_info);
+ if (block != nullptr) {
+ auto const graph = flow_graph_->graph_entry();
+ graph->set_unchecked_entry(block->AsFunctionEntry());
+ }
+ break;
+ }
+ case FlowGraphSerializer::kJoin:
+ block = DeserializeJoinEntry(list, common_info);
+ break;
+ case FlowGraphSerializer::kInvalid:
+ StoreError(tag, "invalid block entry tag");
+ return nullptr;
+ default:
+ StoreError(tag, "unhandled block type");
+ return nullptr;
+ }
+ if (block == nullptr) return nullptr;
+
+ block_map_.Insert(block_id, block);
+ return block;
+}
+
+bool FlowGraphDeserializer::ParsePhis(SExpList* list) {
+ ASSERT(current_block_ != nullptr && current_block_->IsJoinEntry());
+ auto const join = current_block_->AsJoinEntry();
+ const intptr_t start_pos = 2;
+ auto const end_pos = SkipPhis(list);
+ if (end_pos < start_pos) return false;
+
+ for (intptr_t i = start_pos; i < end_pos; i++) {
+ auto const def_sexp = CheckTaggedList(Retrieve(list, i), "def");
+ auto const phi_sexp = CheckTaggedList(Retrieve(def_sexp, 2), "Phi");
+ // SkipPhis should already have checked which instructions, if any,
+ // are Phi definitions.
+ ASSERT(phi_sexp != nullptr);
+
+ // This is a generalization of FlowGraph::AddPhi where we let ParseValue
+ // create the values (as they may contain type information).
+ auto const phi = new (zone()) PhiInstr(join, phi_sexp->Length() - 1);
+ phi->mark_alive();
+ for (intptr_t i = 0, n = phi_sexp->Length() - 1; i < n; i++) {
+ auto const val = ParseValue(Retrieve(phi_sexp, i + 1));
+ if (val == nullptr) return false;
+ phi->SetInputAt(i, val);
+ val->definition()->AddInputUse(val);
+ }
+ join->InsertPhi(phi);
+
+ if (!ParseDefinitionWithParsedBody(def_sexp, phi)) return false;
+ }
+
+ return true;
+}
+
+intptr_t FlowGraphDeserializer::SkipPhis(SExpList* list) {
+ // All blocks are S-exps of the form (Block B# inst...), so skip the first
+ // two entries and then skip any Phi definitions.
+ for (intptr_t i = 2, n = list->Length(); i < n; i++) {
+ auto const def_sexp = CheckTaggedList(Retrieve(list, i), "def");
+ if (def_sexp == nullptr) return i;
+ auto const phi_sexp = CheckTaggedList(Retrieve(def_sexp, 2), "Phi");
+ if (phi_sexp == nullptr) return i;
+ }
+
+ StoreError(list, "block is empty or contains only Phi definitions");
+ return -1;
+}
+
+bool FlowGraphDeserializer::ParseBlockContents(SExpList* list,
+ BlockWorklist* worklist) {
+ ASSERT(current_block_ != nullptr);
+ auto const curr_stack =
+ pushed_stack_map_.LookupValue(current_block_->block_id());
+ ASSERT(curr_stack != nullptr);
+
+ // Parse any Phi definitions now before parsing the block environment.
+ if (current_block_->IsJoinEntry()) {
+ if (!ParsePhis(list)) return false;
+ }
+
+ // For blocks with initial definitions or phi definitions, this needs to be
+ // done after those are parsed. In addition, block environments can also use
+ // definitions from dominating blocks, so we need the contents of dominating
+ // blocks to first be parsed.
+ //
+ // However, we must parse the environment before parsing any instructions
+ // in the body of the block to ensure we don't mistakenly allow local
+ // definitions to appear in the environment.
+ if (auto const env_sexp = CheckList(list->ExtraLookupValue("env"))) {
+ auto const env = ParseEnvironment(env_sexp);
+ if (env == nullptr) return false;
+ env->DeepCopyTo(zone(), current_block_);
+ }
+
+ auto const pos = SkipPhis(list);
+ if (pos < 2) return false;
+ Instruction* last_inst = current_block_;
+ for (intptr_t i = pos, n = list->Length(); i < n; i++) {
+ auto const entry = CheckTaggedList(Retrieve(list, i));
+ if (entry == nullptr) return false;
+ Instruction* inst = nullptr;
+ if (strcmp(entry->At(0)->AsSymbol()->value(), "def") == 0) {
+ inst = ParseDefinition(entry);
+ } else {
+ inst = ParseInstruction(entry);
+ }
+ if (inst == nullptr) return false;
+ last_inst = last_inst->AppendInstruction(inst);
+ }
+
+ ASSERT(last_inst != nullptr && last_inst != current_block_);
+ if (last_inst->SuccessorCount() > 0) {
+ for (intptr_t i = last_inst->SuccessorCount() - 1; i >= 0; i--) {
+ auto const succ_block = last_inst->SuccessorAt(i);
+ // Check and make sure the stack we have is consistent with stacks
+ // from other predecessors.
+ if (!AreStacksConsistent(list, curr_stack, succ_block)) return false;
+ succ_block->AddPredecessor(current_block_);
+ worklist->Add(succ_block->block_id());
+ }
+ }
+
+ return true;
+}
+
+bool FlowGraphDeserializer::ParseDefinitionWithParsedBody(SExpList* list,
+ Definition* def) {
+ intptr_t index;
+ auto const name_sexp = CheckSymbol(Retrieve(list, 1));
+ if (name_sexp == nullptr) return false;
+
+ if (ParseSSATemp(name_sexp, &index)) {
+ if (definition_map_.HasKey(index)) {
+ StoreError(list, "multiple definitions for the same SSA index");
+ return false;
+ }
+ def->set_ssa_temp_index(index);
+ if (index > max_ssa_index_) max_ssa_index_ = index;
+ } else {
+ // TODO(sstrickl): Add temp support for non-SSA computed graphs.
+ StoreError(list, "unhandled name for definition");
+ return false;
+ }
+
+ if (auto const type_sexp =
+ CheckTaggedList(list->ExtraLookupValue("type"), "CompileType")) {
+ CompileType* typ = ParseCompileType(type_sexp);
+ if (typ == nullptr) return false;
+ def->UpdateType(*typ);
+ }
+
+ definition_map_.Insert(index, def);
+ FixPendingValues(index, def);
+ return true;
+}
+
+Definition* FlowGraphDeserializer::ParseDefinition(SExpList* list) {
+ auto const inst_sexp = CheckTaggedList(Retrieve(list, 2));
+ Instruction* const inst = ParseInstruction(inst_sexp);
+ if (inst == nullptr) return nullptr;
+ if (auto const def = inst->AsDefinition()) {
+ if (!ParseDefinitionWithParsedBody(list, def)) return nullptr;
+ return def;
+ } else {
+ StoreError(list, "instruction cannot be body of definition");
+ return nullptr;
+ }
+}
+
+Instruction* FlowGraphDeserializer::ParseInstruction(SExpList* list) {
+ if (list == nullptr) return nullptr;
+ auto const tag = list->At(0)->AsSymbol();
+
+ intptr_t deopt_id = DeoptId::kNone;
+ if (auto const deopt_int = CheckInteger(list->ExtraLookupValue("deopt_id"))) {
+ deopt_id = deopt_int->value();
+ }
+ InstrInfo common_info = {deopt_id, TokenPosition::kNoSource};
+
+ // Parse the environment before handling the instruction, as we may have
+ // references to PushArguments and parsing the instruction may pop
+ // PushArguments off the stack.
+ Environment* env = nullptr;
+ if (auto const env_sexp = CheckList(list->ExtraLookupValue("env"))) {
+ env = ParseEnvironment(env_sexp);
+ if (env == nullptr) return nullptr;
+ }
+
+ Instruction* inst = nullptr;
+
+#define HANDLE_CASE(name) \
+ case kHandled##name: \
+ inst = Deserialize##name(list, common_info); \
+ break;
+ switch (HandledInstructionForTag(tag)) {
+ FOR_EACH_HANDLED_INSTRUCTION_IN_DESERIALIZER(HANDLE_CASE)
+ case kHandledInvalid:
+ StoreError(tag, "unhandled instruction");
+ return nullptr;
+ }
+#undef HANDLE_CASE
+
+ if (inst == nullptr) return nullptr;
+ if (env != nullptr) env->DeepCopyTo(zone(), inst);
+ return inst;
+}
+
+FunctionEntryInstr* FlowGraphDeserializer::DeserializeFunctionEntry(
+ SExpList* sexp,
+ const EntryInfo& info) {
+ ASSERT(flow_graph_ != nullptr);
+ auto const graph = flow_graph_->graph_entry();
+ auto const block = new (zone())
+ FunctionEntryInstr(graph, info.block_id, info.try_index, info.deopt_id);
+ current_block_ = block;
+ if (!ParseInitialDefinitions(sexp)) return nullptr;
+ return block;
+}
+
+GraphEntryInstr* FlowGraphDeserializer::DeserializeGraphEntry(
+ SExpList* sexp,
+ const EntryInfo& info) {
+ auto const name_sexp = CheckSymbol(Retrieve(sexp, 1));
+ // TODO(sstrickl): If the FlowGraphDeserializer was constructed with a
+ // non-null ParsedFunction, we should check that the name matches here.
+ // If not, then we should create an appropriate ParsedFunction here.
+ if (name_sexp == nullptr) return nullptr;
+
+ intptr_t osr_id = Compiler::kNoOSRDeoptId;
+ if (auto const osr_id_sexp = CheckInteger(sexp->ExtraLookupValue("osr_id"))) {
+ osr_id = osr_id_sexp->value();
+ }
+
+ ASSERT(parsed_function_ != nullptr);
+ return new (zone()) GraphEntryInstr(*parsed_function_, osr_id, info.deopt_id);
+}
+
+JoinEntryInstr* FlowGraphDeserializer::DeserializeJoinEntry(
+ SExpList* sexp,
+ const EntryInfo& info) {
+ return new (zone())
+ JoinEntryInstr(info.block_id, info.try_index, info.deopt_id);
+}
+
+TargetEntryInstr* FlowGraphDeserializer::DeserializeTargetEntry(
+ SExpList* sexp,
+ const EntryInfo& info) {
+ return new (zone())
+ TargetEntryInstr(info.block_id, info.try_index, info.deopt_id);
+}
+
+AllocateObjectInstr* FlowGraphDeserializer::DeserializeAllocateObject(
+ SExpList* sexp,
+ const InstrInfo& info) {
+ auto& cls = Class::ZoneHandle(zone());
+ auto const cls_sexp = CheckTaggedList(Retrieve(sexp, 1), "Class");
+ if (!ParseDartValue(cls_sexp, &cls)) return nullptr;
+
+ intptr_t args_len = 0;
+ if (auto const len_sexp = CheckInteger(sexp->ExtraLookupValue("args_len"))) {
+ args_len = len_sexp->value();
+ }
+ auto const arguments = FetchPushedArguments(sexp, args_len);
+ if (arguments == nullptr) return nullptr;
+
+ auto const inst =
+ new (zone()) AllocateObjectInstr(info.token_pos, cls, arguments);
+
+ if (auto const closure_sexp = CheckTaggedList(
+ sexp->ExtraLookupValue("closure_function"), "Function")) {
+ auto& closure_function = Function::Handle(zone());
+ if (!ParseDartValue(closure_sexp, &closure_function)) return nullptr;
+ inst->set_closure_function(closure_function);
+ }
+
+ return inst;
+}
+
+BranchInstr* FlowGraphDeserializer::DeserializeBranch(SExpList* sexp,
+ const InstrInfo& info) {
+ auto const comp_sexp = CheckTaggedList(Retrieve(sexp, 1));
+ auto const comp_inst = ParseInstruction(comp_sexp);
+ if (comp_inst == nullptr) return nullptr;
+ if (!comp_inst->IsComparison()) {
+ StoreError(sexp->At(1), "expected comparison instruction");
+ return nullptr;
+ }
+ auto const comparison = comp_inst->AsComparison();
+
+ auto const true_block = FetchBlock(CheckSymbol(Retrieve(sexp, 2)));
+ if (true_block == nullptr) return nullptr;
+ if (!true_block->IsTargetEntry()) {
+ StoreError(sexp->At(2), "true successor is not a target block");
+ return nullptr;
+ }
+
+ auto const false_block = FetchBlock(CheckSymbol(Retrieve(sexp, 3)));
+ if (false_block == nullptr) return nullptr;
+ if (!false_block->IsTargetEntry()) {
+ StoreError(sexp->At(3), "false successor is not a target block");
+ return nullptr;
+ }
+
+ auto const branch = new (zone()) BranchInstr(comparison, info.deopt_id);
+ *branch->true_successor_address() = true_block->AsTargetEntry();
+ *branch->false_successor_address() = false_block->AsTargetEntry();
+ return branch;
+}
+
+CheckNullInstr* FlowGraphDeserializer::DeserializeCheckNull(
+ SExpList* sexp,
+ const InstrInfo& info) {
+ auto const val = ParseValue(Retrieve(sexp, 1));
+ if (val == nullptr) return nullptr;
+
+ auto& func_name = String::ZoneHandle(zone());
+ if (auto const name_sexp =
+ CheckString(sexp->ExtraLookupValue("function_name"))) {
+ func_name = String::New(name_sexp->value(), Heap::kOld);
+ }
+
+ return new (zone())
+ CheckNullInstr(val, func_name, info.deopt_id, info.token_pos);
+}
+
+CheckStackOverflowInstr* FlowGraphDeserializer::DeserializeCheckStackOverflow(
+ SExpList* sexp,
+ const InstrInfo& info) {
+ intptr_t stack_depth = 0;
+ if (auto const stack_sexp =
+ CheckInteger(sexp->ExtraLookupValue("stack_depth"))) {
+ stack_depth = stack_sexp->value();
+ }
+
+ intptr_t loop_depth = 0;
+ if (auto const loop_sexp =
+ CheckInteger(sexp->ExtraLookupValue("loop_depth"))) {
+ loop_depth = loop_sexp->value();
+ }
+
+ auto kind = CheckStackOverflowInstr::kOsrAndPreemption;
+ if (auto const kind_sexp = CheckSymbol(sexp->ExtraLookupValue("kind"))) {
+ ASSERT(strcmp(kind_sexp->value(), "OsrOnly") == 0);
+ kind = CheckStackOverflowInstr::kOsrOnly;
+ }
+
+ return new (zone()) CheckStackOverflowInstr(info.token_pos, stack_depth,
+ loop_depth, info.deopt_id, kind);
+}
+
+ConstantInstr* FlowGraphDeserializer::DeserializeConstant(
+ SExpList* sexp,
+ const InstrInfo& info) {
+ Object& obj = Object::ZoneHandle(zone());
+ if (!ParseDartValue(Retrieve(sexp, 1), &obj)) return nullptr;
+ return new (zone()) ConstantInstr(obj, info.token_pos);
+}
+
+DebugStepCheckInstr* FlowGraphDeserializer::DeserializeDebugStepCheck(
+ SExpList* sexp,
+ const InstrInfo& info) {
+ auto kind = RawPcDescriptors::kAnyKind;
+ if (auto const kind_sexp = CheckSymbol(Retrieve(sexp, "stub_kind"))) {
+ if (!RawPcDescriptors::KindFromCString(kind_sexp->value(), &kind)) {
+ StoreError(kind_sexp, "not a valid RawPcDescriptors::Kind name");
+ return nullptr;
+ }
+ }
+ return new (zone()) DebugStepCheckInstr(info.token_pos, kind, info.deopt_id);
+}
+
+GotoInstr* FlowGraphDeserializer::DeserializeGoto(SExpList* sexp,
+ const InstrInfo& info) {
+ auto const block = FetchBlock(CheckSymbol(Retrieve(sexp, 1)));
+ if (block == nullptr) return nullptr;
+ if (!block->IsJoinEntry()) {
+ StoreError(sexp->At(1), "target of goto must be join entry");
+ return nullptr;
+ }
+ return new (zone()) GotoInstr(block->AsJoinEntry(), info.deopt_id);
+}
+
+LoadFieldInstr* FlowGraphDeserializer::DeserializeLoadField(
+ SExpList* sexp,
+ const InstrInfo& info) {
+ auto const instance = ParseValue(Retrieve(sexp, 1));
+ if (instance == nullptr) return nullptr;
+
+ const Slot* slot;
+ if (!ParseSlot(CheckTaggedList(Retrieve(sexp, 2)), &slot)) return nullptr;
+
+ return new (zone()) LoadFieldInstr(instance, *slot, info.token_pos);
+}
+
+ParameterInstr* FlowGraphDeserializer::DeserializeParameter(
+ SExpList* sexp,
+ const InstrInfo& info) {
+ ASSERT(current_block_ != nullptr);
+ if (auto const index_sexp = CheckInteger(Retrieve(sexp, 1))) {
+ return new (zone()) ParameterInstr(index_sexp->value(), current_block_);
+ }
+ return nullptr;
+}
+
+PushArgumentInstr* FlowGraphDeserializer::DeserializePushArgument(
+ SExpList* sexp,
+ const InstrInfo& info) {
+ auto const val = ParseValue(Retrieve(sexp, 1));
+ if (val == nullptr) return nullptr;
+ auto const push = new (zone()) PushArgumentInstr(val);
+ auto const stack = pushed_stack_map_.LookupValue(current_block_->block_id());
+ ASSERT(stack != nullptr);
+ stack->Add(push);
+ return push;
+}
+
+ReturnInstr* FlowGraphDeserializer::DeserializeReturn(SExpList* list,
+ const InstrInfo& info) {
+ Value* val = ParseValue(Retrieve(list, 1));
+ if (val == nullptr) return nullptr;
+ return new (zone()) ReturnInstr(info.token_pos, val, info.deopt_id);
+}
+
+SpecialParameterInstr* FlowGraphDeserializer::DeserializeSpecialParameter(
+ SExpList* sexp,
+ const InstrInfo& info) {
+ ASSERT(current_block_ != nullptr);
+ auto const kind_sexp = CheckSymbol(Retrieve(sexp, 1));
+ if (kind_sexp == nullptr) return nullptr;
+ SpecialParameterInstr::SpecialParameterKind kind;
+ if (!SpecialParameterInstr::KindFromCString(kind_sexp->value(), &kind)) {
+ StoreError(kind_sexp, "unknown special parameter kind");
+ return nullptr;
+ }
+ return new (zone())
+ SpecialParameterInstr(kind, info.deopt_id, current_block_);
+}
+
+StaticCallInstr* FlowGraphDeserializer::DeserializeStaticCall(
+ SExpList* sexp,
+ const InstrInfo& info) {
+ auto& function = Function::ZoneHandle(zone());
+ auto const function_sexp = CheckTaggedList(Retrieve(sexp, 1), "Function");
+ if (!ParseDartValue(function_sexp, &function)) return nullptr;
+
+ intptr_t type_args_len = 0;
+ if (auto const type_args_len_sexp =
+ CheckInteger(sexp->ExtraLookupValue("type_args_len"))) {
+ type_args_len = type_args_len_sexp->value();
+ }
+
+ Array& argument_names = Array::ZoneHandle(zone());
+ if (auto const arg_names_sexp =
+ CheckList(sexp->ExtraLookupValue("arg_names"))) {
+ argument_names = Array::New(arg_names_sexp->Length(), Heap::kOld);
+ for (intptr_t i = 0, n = arg_names_sexp->Length(); i < n; i++) {
+ auto name_sexp = CheckString(Retrieve(arg_names_sexp, i));
+ if (name_sexp == nullptr) return nullptr;
+ tmp_string_ = String::New(name_sexp->value(), Heap::kOld);
+ argument_names.SetAt(i, tmp_string_);
+ }
+ }
+
+ intptr_t args_len = 0;
+ if (auto const args_len_sexp =
+ CheckInteger(sexp->ExtraLookupValue("args_len"))) {
+ args_len = args_len_sexp->value();
+ }
+
+ // Type arguments are wrapped in a TypeArguments array, so no matter how
+ // many there are, they are contained in a single pushed argument.
+ auto const all_args_len = (type_args_len > 0 ? 1 : 0) + args_len;
+ auto const arguments = FetchPushedArguments(sexp, all_args_len);
+ if (arguments == nullptr) return nullptr;
+
+ intptr_t call_count = 0;
+ if (auto const call_count_sexp =
+ CheckInteger(sexp->ExtraLookupValue("call_count"))) {
+ call_count = call_count_sexp->value();
+ }
+
+ auto rebind_rule = ICData::kInstance;
+ if (auto const rebind_sexp =
+ CheckSymbol(sexp->ExtraLookupValue("rebind_rule"))) {
+ if (!ICData::RebindRuleFromCString(rebind_sexp->value(), &rebind_rule)) {
+ StoreError(rebind_sexp, "unknown rebind rule value");
+ return nullptr;
+ }
+ }
+
+ return new (zone())
+ StaticCallInstr(info.token_pos, function, type_args_len, argument_names,
+ arguments, info.deopt_id, call_count, rebind_rule);
+}
+
+StoreInstanceFieldInstr* FlowGraphDeserializer::DeserializeStoreInstanceField(
+ SExpList* sexp,
+ const InstrInfo& info) {
+ auto const instance = ParseValue(Retrieve(sexp, 1));
+ if (instance == nullptr) return nullptr;
+
+ const Slot* slot = nullptr;
+ if (!ParseSlot(CheckTaggedList(Retrieve(sexp, 2), "Slot"), &slot)) {
+ return nullptr;
+ }
+
+ auto const value = ParseValue(Retrieve(sexp, 3));
+ if (value == nullptr) return nullptr;
+
+ auto barrier_type = kNoStoreBarrier;
+ if (auto const bar_sexp = CheckBool(sexp->ExtraLookupValue("emit_barrier"))) {
+ if (bar_sexp->value()) barrier_type = kEmitStoreBarrier;
+ }
+
+ auto kind = StoreInstanceFieldInstr::Kind::kOther;
+ if (auto const init_sexp = CheckBool(sexp->ExtraLookupValue("is_init"))) {
+ if (init_sexp->value()) kind = StoreInstanceFieldInstr::Kind::kInitializing;
+ }
+
+ return new (zone()) StoreInstanceFieldInstr(
+ *slot, instance, value, barrier_type, info.token_pos, kind);
+}
+
+StrictCompareInstr* FlowGraphDeserializer::DeserializeStrictCompare(
+ SExpList* sexp,
+ const InstrInfo& info) {
+ auto const token_sexp = CheckSymbol(Retrieve(sexp, 1));
+ if (token_sexp == nullptr) return nullptr;
+ Token::Kind kind;
+ if (!Token::FromStr(token_sexp->value(), &kind)) return nullptr;
+
+ auto const left = ParseValue(Retrieve(sexp, 2));
+ if (left == nullptr) return nullptr;
+
+ auto const right = ParseValue(Retrieve(sexp, 3));
+ if (right == nullptr) return nullptr;
+
+ bool needs_check = false;
+ if (auto const check_sexp = CheckBool(Retrieve(sexp, "needs_check"))) {
+ needs_check = check_sexp->value();
+ }
+
+ return new (zone()) StrictCompareInstr(info.token_pos, kind, left, right,
+ needs_check, info.deopt_id);
+}
+
+Value* FlowGraphDeserializer::ParseValue(SExpression* sexp,
+ bool allow_pending) {
+ auto name = sexp->AsSymbol();
+ CompileType* type = nullptr;
+ if (name == nullptr) {
+ auto const list = CheckTaggedList(sexp, "value");
+ name = CheckSymbol(Retrieve(list, 1));
+ if (name == nullptr) return nullptr;
+ if (auto const type_sexp =
+ CheckTaggedList(list->ExtraLookupValue("type"), "CompileType")) {
+ type = ParseCompileType(type_sexp);
+ if (type == nullptr) return nullptr;
+ }
+ }
+ intptr_t index;
+ if (!ParseUse(name, &index)) return nullptr;
+ auto const def = definition_map_.LookupValue(index);
+ Value* val;
+ if (def == nullptr) {
+ if (!allow_pending) {
+ StoreError(sexp, "found use prior to definition");
+ return nullptr;
+ }
+ val = AddNewPendingValue(index);
+ } else {
+ val = new (zone()) Value(def);
+ }
+ if (type != nullptr) val->SetReachingType(type);
+ return val;
+}
+
+CompileType* FlowGraphDeserializer::ParseCompileType(SExpList* sexp) {
+ // TODO(sstrickl): Currently we only print out nullable if it's false
+ // (or during verbose printing). Switch this when NNBD is the standard.
+ bool nullable = CompileType::kNullable;
+ if (auto const nullable_sexp =
+ CheckBool(sexp->ExtraLookupValue("nullable"))) {
+ nullable = nullable_sexp->value() ? CompileType::kNullable
+ : CompileType::kNonNullable;
+ }
+
+ // A cid as the second element means that the type is based off a concrete
+ // class.
+ intptr_t cid = kDynamicCid;
+ if (sexp->Length() > 1) {
+ if (auto const cid_sexp = CheckInteger(sexp->At(1))) {
+ // TODO(sstrickl): Check that the cid is a valid cid.
+ cid = cid_sexp->value();
+ } else {
+ return nullptr;
+ }
+ }
+
+ AbstractType* type = nullptr;
+ if (auto const type_sexp = CheckTaggedList(sexp->ExtraLookupValue("type"))) {
+ auto& type_handle = AbstractType::ZoneHandle(zone());
+ if (!ParseDartValue(type_sexp, &type_handle)) return nullptr;
+ type = &type_handle;
+ }
+ return new (zone()) CompileType(nullable, cid, type);
+}
+
+Environment* FlowGraphDeserializer::ParseEnvironment(SExpList* list) {
+ if (list == nullptr) return nullptr;
+ intptr_t fixed_param_count = 0;
+ if (auto const fpc_sexp =
+ CheckInteger(list->ExtraLookupValue("fixed_param_count"))) {
+ fixed_param_count = fpc_sexp->value();
+ }
+ Environment* outer_env = nullptr;
+ if (auto const outer_sexp = CheckList(list->ExtraLookupValue("outer"))) {
+ outer_env = ParseEnvironment(outer_sexp);
+ if (outer_env == nullptr) return nullptr;
+ if (auto const deopt_sexp =
+ CheckInteger(outer_sexp->ExtraLookupValue("deopt_id"))) {
+ outer_env->deopt_id_ = deopt_sexp->value();
+ }
+ }
+
+ auto const env = new (zone()) Environment(list->Length(), fixed_param_count,
+ *parsed_function_, outer_env);
+
+ auto const stack = pushed_stack_map_.LookupValue(current_block_->block_id());
+ ASSERT(stack != nullptr);
+ for (intptr_t i = 0; i < list->Length(); i++) {
+ auto const elem_sexp = Retrieve(list, i);
+ if (elem_sexp == nullptr) return nullptr;
+ auto val = ParseValue(elem_sexp, /*allow_pending=*/false);
+ if (val == nullptr) {
+ intptr_t index;
+ if (!ParseSymbolAsPrefixedInt(CheckSymbol(elem_sexp), 'a', &index)) {
+ StoreError(elem_sexp, "expected value or reference to pushed argument");
+ return nullptr;
+ }
+ if (index >= stack->length()) {
+ StoreError(elem_sexp, "out of range index for pushed argument");
+ return nullptr;
+ }
+ val = new (zone()) Value(stack->At(index));
+ }
+ env->PushValue(val);
+ }
+
+ return env;
+}
+
+bool FlowGraphDeserializer::ParseDartValue(SExpression* sexp, Object* out) {
+ ASSERT(out != nullptr);
+ if (sexp == nullptr) return false;
+ *out = Object::null();
+
+ if (auto const sym = sexp->AsSymbol()) {
+ // We'll use the null value in *out as a marker later, so go ahead and exit
+ // early if we parse one.
+ if (strcmp(sym->value(), "null") == 0) return true;
+
+ // The only other symbols that should appear in Dart value position are
+ // names of constant definitions.
+ auto const val = ParseValue(sym, /*allow_pending=*/false);
+ if (val == nullptr) return false;
+ if (!val->BindsToConstant()) {
+ StoreError(sym, "not a reference to a constant definition");
+ return false;
+ }
+ *out = val->BoundConstant().raw();
+ // Values used in constant definitions have already been canonicalized,
+ // so just exit.
+ return true;
+ }
+
+ // Other instance values may need to be canonicalized, so do that before
+ // returning.
+ if (auto const list = CheckTaggedList(sexp)) {
+ auto const tag = list->At(0)->AsSymbol();
+ if (strcmp(tag->value(), "Class") == 0) {
+ auto const cid_sexp = CheckInteger(Retrieve(list, 1));
+ if (cid_sexp == nullptr) return false;
+ ClassTable* table = thread()->isolate()->class_table();
+ if (!table->HasValidClassAt(cid_sexp->value())) {
+ StoreError(cid_sexp, "no valid class found for cid");
+ return false;
+ }
+ *out = table->At(cid_sexp->value());
+ } else if (strcmp(tag->value(), "Type") == 0) {
+ if (const auto cls_sexp = CheckTaggedList(Retrieve(list, 1), "Class")) {
+ auto& cls = Class::ZoneHandle(zone());
+ if (!ParseDartValue(cls_sexp, &cls)) return false;
+ auto& type_args = TypeArguments::ZoneHandle(zone());
+ if (const auto ta_sexp = CheckTaggedList(
+ list->ExtraLookupValue("type_args"), "TypeArguments")) {
+ if (!ParseDartValue(ta_sexp, &type_args)) return false;
+ }
+ *out = Type::New(cls, type_args, TokenPosition::kNoSource, Heap::kOld);
+ // Need to set this for canonicalization. We ensure in the serializer
+ // that only finalized types are successfully serialized.
+ Type::Cast(*out).SetIsFinalized();
+ }
+ // TODO(sstrickl): Handle types not derived from classes.
+ } else if (strcmp(tag->value(), "TypeArguments") == 0) {
+ *out = TypeArguments::New(list->Length() - 1, Heap::kOld);
+ auto& type_args = TypeArguments::Cast(*out);
+ for (intptr_t i = 1, n = list->Length(); i < n; i++) {
+ if (!ParseDartValue(Retrieve(list, i), &value_type_)) return false;
+ type_args.SetTypeAt(i - 1, value_type_);
+ }
+ } else if (strcmp(tag->value(), "Field") == 0) {
+ auto const name_sexp = CheckSymbol(Retrieve(list, 1));
+ if (!ParseCanonicalName(name_sexp, out)) return false;
+ } else if (strcmp(tag->value(), "Function") == 0) {
+ auto const name_sexp = CheckSymbol(Retrieve(list, 1));
+ if (!ParseCanonicalName(name_sexp, out)) return false;
+ // Check the kind expected by the S-expression if one was specified.
+ if (auto const kind_sexp = CheckSymbol(list->ExtraLookupValue("kind"))) {
+ RawFunction::Kind kind;
+ if (!RawFunction::KindFromCString(kind_sexp->value(), &kind)) {
+ StoreError(kind_sexp, "unexpected function kind");
+ return false;
+ }
+ auto& function = Function::Cast(*out);
+ if (function.kind() != kind) {
+ auto const kind_str = RawFunction::KindToCString(function.kind());
+ StoreError(list, "retrieved function has kind %s", kind_str);
+ return false;
+ }
+ }
+ } else if (strcmp(tag->value(), "TypeParameter") == 0) {
+ ASSERT(parsed_function_ != nullptr);
+ auto const name_sexp = CheckSymbol(Retrieve(list, 1));
+ if (name_sexp == nullptr) return false;
+ const auto& func = parsed_function_->function();
+ tmp_string_ = String::New(name_sexp->value());
+ *out = func.LookupTypeParameter(tmp_string_, nullptr);
+ if (out->IsNull()) {
+ // Check the owning class for the function as well.
+ value_class_ = func.Owner();
+ *out = value_class_.LookupTypeParameter(tmp_string_);
+ }
+ // We'll want a more specific error message than the generic unhandled
+ // Dart value one if this failed.
+ if (out->IsNull()) {
+ StoreError(name_sexp, "no type parameter found for name");
+ return false;
+ }
+ } else if (strcmp(tag->value(), "ImmutableList") == 0) {
+ // Since arrays can contain arrays, we must allocate a new handle here.
+ auto& arr =
+ Array::Handle(zone(), Array::New(list->Length() - 1, Heap::kOld));
+ for (intptr_t i = 1; i < list->Length(); i++) {
+ if (!ParseDartValue(Retrieve(list, i), &value_object_)) return false;
+ arr.SetAt(i - 1, value_object_);
+ }
+ if (auto type_args_sexp = CheckTaggedList(
+ list->ExtraLookupValue("type_args"), "TypeArguments")) {
+ if (!ParseDartValue(type_args_sexp, &value_type_args_)) return false;
+ arr.SetTypeArguments(value_type_args_);
+ }
+ arr.MakeImmutable();
+ *out = arr.raw();
+ } else if (strcmp(tag->value(), "Instance") == 0) {
+ if (!ParseInstance(list, reinterpret_cast<Instance*>(out))) return false;
+ } else if (strcmp(tag->value(), "Closure") == 0) {
+ auto& function = Function::ZoneHandle(zone());
+ if (!ParseDartValue(Retrieve(list, 1), &function)) return false;
+
+ auto& context = Context::ZoneHandle(zone());
+ if (list->ExtraLookupValue("context") != nullptr) {
+ StoreError(list, "closures with contexts currently unhandled");
+ return false;
+ }
+
+ auto& inst_type_args = TypeArguments::ZoneHandle(zone());
+ if (auto const type_args_sexp = CheckTaggedList(
+ Retrieve(list, "inst_type_args"), "TypeArguments")) {
+ if (!ParseDartValue(type_args_sexp, &inst_type_args)) return false;
+ }
+
+ auto& func_type_args = TypeArguments::ZoneHandle(zone());
+ if (auto const type_args_sexp = CheckTaggedList(
+ Retrieve(list, "func_type_args"), "TypeArguments")) {
+ if (!ParseDartValue(type_args_sexp, &func_type_args)) return false;
+ }
+
+ auto& delayed_type_args = TypeArguments::ZoneHandle(zone());
+ if (auto const type_args_sexp = CheckTaggedList(
+ Retrieve(list, "delayed_type_args"), "TypeArguments")) {
+ if (!ParseDartValue(type_args_sexp, &delayed_type_args)) return false;
+ }
+
+ *out = Closure::New(inst_type_args, func_type_args, delayed_type_args,
+ function, context, Heap::kOld);
+ }
+ } else if (auto const b = sexp->AsBool()) {
+ *out = Bool::Get(b->value()).raw();
+ } else if (auto const str = sexp->AsString()) {
+ *out = String::New(str->value(), Heap::kOld);
+ } else if (auto const i = sexp->AsInteger()) {
+ *out = Integer::New(i->value(), Heap::kOld);
+ } else if (auto const d = sexp->AsDouble()) {
+ *out = Double::New(d->value(), Heap::kOld);
+ }
+
+ // If we're here and still haven't gotten a non-null value, then something
+ // went wrong. (Likely an unrecognized value.)
+ if (out->IsNull()) {
+ StoreError(sexp, "unhandled Dart value");
+ return false;
+ }
+
+ if (out->IsInstance()) {
+ const char* error_str = nullptr;
+ // CheckAndCanonicalize uses the current zone for the passed in thread,
+ // not an explicitly provided zone. This means we cannot be run in a context
+ // where [thread()->zone()] does not match [zone()] (e.g., due to StackZone)
+ // until this is addressed.
+ *out = Instance::Cast(*out).CheckAndCanonicalize(thread(), &error_str);
+ if (out->IsNull()) {
+ if (error_str != nullptr) {
+ StoreError(sexp, "error during canonicalization: %s", error_str);
+ } else {
+ StoreError(sexp, "unexpected error during canonicalization");
+ }
+ return false;
+ }
+ }
+ return true;
+}
+
+bool FlowGraphDeserializer::ParseInstance(SExpList* list, Instance* out) {
+ auto const cid_sexp = CheckInteger(Retrieve(list, 1));
+ if (cid_sexp == nullptr) return false;
+
+ auto const table = thread()->isolate()->class_table();
+ if (!table->HasValidClassAt(cid_sexp->value())) {
+ StoreError(cid_sexp, "cid is not valid");
+ return false;
+ }
+
+ instance_class_ = table->At(cid_sexp->value());
+ *out = Instance::New(instance_class_, Heap::kOld);
+
+ if (list->Length() > 2) {
+ auto const fields_sexp = CheckTaggedList(Retrieve(list, 2), "Fields");
+ if (fields_sexp == nullptr) return false;
+ auto it = fields_sexp->ExtraIterator();
+ while (auto kv = it.Next()) {
+ tmp_string_ = String::New(kv->key);
+ instance_field_ = instance_class_.LookupFieldAllowPrivate(
+ tmp_string_, /*instance_only=*/true);
+ if (instance_field_.IsNull()) {
+ StoreError(list, "cannot find field %s", kv->key);
+ return false;
+ }
+
+ if (auto const inst = CheckTaggedList(kv->value, "Instance")) {
+ // Unsure if this will be necessary, so for now not doing fresh
+ // Instance/Class handle allocations unless it is.
+ StoreError(inst, "nested instances not handled yet");
+ return false;
+ }
+ if (!ParseDartValue(kv->value, &instance_object_)) return false;
+ out->SetField(instance_field_, instance_object_);
+ }
+ }
+ return true;
+}
+
+bool FlowGraphDeserializer::ParseCanonicalName(SExpSymbol* sym, Object* obj) {
+ if (sym == nullptr) return false;
+ auto const name = sym->value();
+ // TODO(sstrickl): No library URL, handle this better.
+ if (*name == ':') {
+ StoreError(sym, "expected non-empty library");
+ return false;
+ }
+ const char* lib_end = nullptr;
+ if (auto const first = strchr(name, ':')) {
+ lib_end = strchr(first + 1, ':');
+ if (lib_end == nullptr) lib_end = strchr(first + 1, '\0');
+ } else {
+ StoreError(sym, "malformed library");
+ return false;
+ }
+ tmp_string_ =
+ String::FromUTF8(reinterpret_cast<const uint8_t*>(name), lib_end - name);
+ name_library_ = Library::LookupLibrary(thread(), tmp_string_);
+ if (*lib_end == '\0') {
+ *obj = name_library_.raw();
+ return true;
+ }
+ const char* const class_start = lib_end + 1;
+ if (*class_start == '\0') {
+ StoreError(sym, "no class found after colon");
+ return false;
+ }
+ // If classes are followed by another part, it's either a function
+ // (separated by ':') or a field (separated by '.').
+ const char* class_end = strchr(class_start, ':');
+ if (class_end == nullptr) class_end = strchr(class_start, '.');
+ if (class_end == nullptr) class_end = strchr(class_start, '\0');
+ const bool empty_name = class_end == class_start;
+ name_class_ = Class::null();
+ if (empty_name) {
+ name_class_ = name_library_.toplevel_class();
+ } else {
+ tmp_string_ = String::FromUTF8(
+ reinterpret_cast<const uint8_t*>(class_start), class_end - class_start);
+ name_class_ = name_library_.LookupClassAllowPrivate(tmp_string_);
+ }
+ if (name_class_.IsNull()) {
+ StoreError(sym, "failure looking up class %s in library %s",
+ empty_name ? "at top level" : tmp_string_.ToCString(),
+ name_library_.ToCString());
+ return false;
+ }
+ if (*class_end == '\0') {
+ *obj = name_class_.raw();
+ return true;
+ }
+ if (*class_end == '.') {
+ if (class_end[1] == '\0') {
+ StoreError(sym, "no field name found after period");
+ return false;
+ }
+ const char* const field_start = class_end + 1;
+ const char* field_end = strchr(field_start, '\0');
+ tmp_string_ = String::FromUTF8(
+ reinterpret_cast<const uint8_t*>(field_start), field_end - field_start);
+ name_field_ = name_class_.LookupFieldAllowPrivate(tmp_string_);
+ if (name_field_.IsNull()) {
+ StoreError(sym, "failure looking up field %s in class %s",
+ tmp_string_.ToCString(),
+ empty_name ? "at top level" : name_class_.ToCString());
+ return false;
+ }
+ *obj = name_field_.raw();
+ return true;
+ }
+ if (class_end[1] == '\0') {
+ StoreError(sym, "no function name found after final colon");
+ return false;
+ }
+ const char* func_start = class_end + 1;
+ name_function_ = Function::null();
+ while (true) {
+ const char* func_end = strchr(func_start, ':');
+ intptr_t name_len = func_end - func_start;
+ bool is_forwarder = false;
+ if (func_end != nullptr && name_len == 3) {
+ // Special case for getters/setters, where they are prefixed with "get:"
+ // or "set:", as those colons should not be used as separators.
+ if (strncmp(func_start, "get", 3) == 0 ||
+ strncmp(func_start, "set", 3) == 0) {
+ func_end = strchr(func_end + 1, ':');
+ } else if (strncmp(func_start, "dyn", 3) == 0) {
+ // Dynamic invocation forwarders start with "dyn:" and we'll need to
+ // look up the base function and then retrieve the forwarder from it.
+ is_forwarder = true;
+ func_start = func_end + 1;
+ func_end = strchr(func_end + 1, ':');
+ }
+ }
+ if (func_end == nullptr) func_end = strchr(func_start, '\0');
+ name_len = func_end - func_start;
+
+ // Check for tearoff names before we overwrite the contents of tmp_string_.
+ if (!name_function_.IsNull()) {
+ ASSERT(!tmp_string_.IsNull());
+ auto const parent_name = tmp_string_.ToCString();
+ // ImplicitClosureFunctions (tearoffs) have the same name as the Function
+ // to which they are attached. We won't handle any further nesting.
+ if (name_function_.HasImplicitClosureFunction() && *func_end == '\0' &&
+ strncmp(parent_name, func_start, name_len) == 0) {
+ *obj = name_function_.ImplicitClosureFunction();
+ return true;
+ }
+ StoreError(sym, "no handling for local functions");
+ return false;
+ }
+
+ tmp_string_ = String::FromUTF8(reinterpret_cast<const uint8_t*>(func_start),
+ name_len);
+ name_function_ = name_class_.LookupFunctionAllowPrivate(tmp_string_);
+ if (name_function_.IsNull()) {
+ StoreError(sym, "failure looking up function %s in class %s",
+ tmp_string_.ToCString(), name_class_.ToCString());
+ return false;
+ }
+ if (is_forwarder) {
+ // Go back four characters to start at the 'dyn:' we stripped earlier.
+ tmp_string_ = String::FromUTF8(
+ reinterpret_cast<const uint8_t*>(func_start - 4), name_len + 4);
+ name_function_ =
+ name_function_.GetDynamicInvocationForwarder(tmp_string_);
+ }
+ if (func_end[0] == '\0') break;
+ if (func_end[1] == '\0') {
+ StoreError(sym, "no function name found after final colon");
+ return false;
+ }
+ func_start = func_end + 1;
+ }
+ *obj = name_function_.raw();
+ return true;
+}
+
+// Following the lead of BaseFlowGraphBuilder::MayCloneField here.
+const Field& FlowGraphDeserializer::MayCloneField(const Field& field) {
+ if ((Compiler::IsBackgroundCompilation() ||
+ FLAG_force_clone_compiler_objects) &&
+ field.IsOriginal()) {
+ return Field::ZoneHandle(zone(), field.CloneFromOriginal());
+ }
+ ASSERT(field.IsZoneHandle());
+ return field;
+}
+
+bool FlowGraphDeserializer::ParseSlot(SExpList* list, const Slot** out) {
+ ASSERT(out != nullptr);
+ const auto offset_sexp = CheckInteger(Retrieve(list, 1));
+ if (offset_sexp == nullptr) return false;
+ const auto offset = offset_sexp->value();
+
+ const auto kind_sexp = CheckSymbol(Retrieve(list, "kind"));
+ if (kind_sexp == nullptr) return false;
+ Slot::Kind kind;
+ if (!Slot::KindFromCString(kind_sexp->value(), &kind)) {
+ StoreError(kind_sexp, "unknown Slot kind");
+ return false;
+ }
+
+ switch (kind) {
+ case Slot::Kind::kDartField: {
+ auto& field = Field::ZoneHandle(zone());
+ const auto field_sexp = CheckTaggedList(Retrieve(list, "field"), "Field");
+ if (!ParseDartValue(field_sexp, &field)) return false;
+ *out = &Slot::Get(MayCloneField(field), parsed_function_);
+ break;
+ }
+ case Slot::Kind::kTypeArguments:
+ *out = &Slot::GetTypeArgumentsSlotAt(thread(), offset);
+ break;
+ case Slot::Kind::kCapturedVariable:
+ StoreError(kind_sexp, "unhandled Slot kind");
+ return false;
+ default:
+ *out = &Slot::GetNativeSlot(kind);
+ break;
+ }
+ return true;
+}
+
+bool FlowGraphDeserializer::ParseBlockId(SExpSymbol* sym, intptr_t* out) {
+ return ParseSymbolAsPrefixedInt(sym, 'B', out);
+}
+
+bool FlowGraphDeserializer::ParseSSATemp(SExpSymbol* sym, intptr_t* out) {
+ return ParseSymbolAsPrefixedInt(sym, 'v', out);
+}
+
+bool FlowGraphDeserializer::ParseUse(SExpSymbol* sym, intptr_t* out) {
+ // TODO(sstrickl): Handle non-SSA temp uses.
+ return ParseSSATemp(sym, out);
+}
+
+bool FlowGraphDeserializer::ParseSymbolAsPrefixedInt(SExpSymbol* sym,
+ char prefix,
+ intptr_t* out) {
+ ASSERT(out != nullptr);
+ if (sym == nullptr) return false;
+ auto const name = sym->value();
+ if (*name != prefix) {
+ StoreError(sym, "expected symbol starting with '%c'", prefix);
+ return false;
+ }
+ int64_t i;
+ if (!OS::StringToInt64(name + 1, &i)) {
+ StoreError(sym, "expected number following symbol prefix '%c'", prefix);
+ return false;
+ }
+ *out = i;
+ return true;
+}
+
+Value* FlowGraphDeserializer::AddNewPendingValue(intptr_t index) {
+ ASSERT(flow_graph_ != nullptr);
+ auto const val = new (zone()) Value(flow_graph_->constant_null());
+ AddPendingValue(index, val);
+ return val;
+}
+
+void FlowGraphDeserializer::AddPendingValue(intptr_t index, Value* val) {
+ ASSERT(!definition_map_.HasKey(index));
+ auto value_list = values_map_.LookupValue(index);
+ if (value_list == nullptr) {
+ value_list = new (zone()) ZoneGrowableArray<Value*>(zone(), 2);
+ values_map_.Insert(index, value_list);
+ }
+ value_list->Add(val);
+}
+
+void FlowGraphDeserializer::FixPendingValues(intptr_t index, Definition* def) {
+ if (auto value_list = values_map_.LookupValue(index)) {
+ for (intptr_t i = 0; i < value_list->length(); i++) {
+ auto const val = value_list->At(i);
+ val->BindTo(def);
+ }
+ values_map_.Remove(index);
+ }
+}
+
+PushArgumentsArray* FlowGraphDeserializer::FetchPushedArguments(SExpList* list,
+ intptr_t len) {
+ auto const stack = pushed_stack_map_.LookupValue(current_block_->block_id());
+ ASSERT(stack != nullptr);
+ auto const stack_len = stack->length();
+ if (len > stack_len) {
+ StoreError(list, "expected %" Pd " pushed arguments, only %" Pd " on stack",
+ len, stack_len);
+ return nullptr;
+ }
+ auto const arr = new (zone()) PushArgumentsArray(zone(), len);
+ for (intptr_t i = 0; i < len; i++) {
+ arr->Add(stack->At(stack_len - len + i));
+ }
+ stack->TruncateTo(stack_len - len);
+ return arr;
+}
+
+BlockEntryInstr* FlowGraphDeserializer::FetchBlock(SExpSymbol* sym) {
+ if (sym == nullptr) return nullptr;
+ intptr_t block_id;
+ if (!ParseBlockId(sym, &block_id)) return nullptr;
+ auto const entry = block_map_.LookupValue(block_id);
+ if (entry == nullptr) {
+ StoreError(sym, "reference to undefined block");
+ return nullptr;
+ }
+ return entry;
+}
+
+bool FlowGraphDeserializer::AreStacksConsistent(SExpList* list,
+ PushStack* curr_stack,
+ BlockEntryInstr* succ_block) {
+ auto const curr_stack_len = curr_stack->length();
+ for (intptr_t i = 0, n = succ_block->SuccessorCount(); i < n; i++) {
+ auto const pred_block = succ_block->PredecessorAt(i);
+ auto const pred_stack =
+ pushed_stack_map_.LookupValue(pred_block->block_id());
+ ASSERT(pred_stack != nullptr);
+ if (pred_stack->length() != curr_stack_len) {
+ StoreError(list->At(1),
+ "current pushed stack has %" Pd
+ " elements, "
+ "other pushed stack for B%" Pd " has %" Pd "",
+ curr_stack_len, pred_block->block_id(), pred_stack->length());
+ return false;
+ }
+ for (intptr_t i = 0; i < curr_stack_len; i++) {
+ // Leftover pushed arguments on the stack should come from dominating
+ // nodes, so they should be the same PushedArgumentInstr no matter the
+ // predecessor.
+ if (pred_stack->At(i) != curr_stack->At(i)) {
+ auto const pred_def = pred_stack->At(i)->value()->definition();
+ auto const curr_def = curr_stack->At(i)->value()->definition();
+ StoreError(list->At(1),
+ "current pushed stack has v%" Pd " at position %" Pd
+ ", "
+ "other pushed stack for B%" Pd " has v%" Pd "",
+ curr_def->ssa_temp_index(), i, pred_block->block_id(),
+ pred_def->ssa_temp_index());
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+#define BASE_CHECK_DEF(name, type) \
+ SExp##name* FlowGraphDeserializer::Check##name(SExpression* sexp) { \
+ if (sexp == nullptr) return nullptr; \
+ if (!sexp->Is##name()) { \
+ StoreError(sexp, "expected " #name); \
+ return nullptr; \
+ } \
+ return sexp->As##name(); \
+ }
+
+FOR_EACH_S_EXPRESSION(BASE_CHECK_DEF)
+
+#undef BASE_CHECK_DEF
+
+bool FlowGraphDeserializer::IsTag(SExpression* sexp, const char* label) {
+ auto const sym = CheckSymbol(sexp);
+ if (sym == nullptr) return false;
+ if (label != nullptr && strcmp(label, sym->value()) != 0) {
+ StoreError(sym, "expected symbol %s", label);
+ return false;
+ }
+ return true;
+}
+
+SExpList* FlowGraphDeserializer::CheckTaggedList(SExpression* sexp,
+ const char* label) {
+ auto const list = CheckList(sexp);
+ const intptr_t tag_pos = 0;
+ if (!IsTag(Retrieve(list, tag_pos), label)) return nullptr;
+ return list;
+}
+
+void FlowGraphDeserializer::StoreError(SExpression* sexp,
+ const char* format,
+ ...) {
+ va_list args;
+ va_start(args, format);
+ const char* const message = OS::VSCreate(zone(), format, args);
+ va_end(args);
+ error_sexp_ = sexp;
+ error_message_ = message;
+}
+
+void FlowGraphDeserializer::ReportError() const {
+ ASSERT(error_sexp_ != nullptr);
+ ASSERT(error_message_ != nullptr);
+ OS::PrintErr("Unable to deserialize flow_graph: %s\n", error_message_);
+ OS::PrintErr("Error at S-expression %s\n", error_sexp_->ToCString(zone()));
+ OS::Abort();
+}
+
+} // namespace dart
+
+#endif // !defined(DART_PRECOMPILED_RUNTIME)
diff --git a/runtime/vm/compiler/backend/il_deserializer.h b/runtime/vm/compiler/backend/il_deserializer.h
new file mode 100644
index 0000000..2ebb507
--- /dev/null
+++ b/runtime/vm/compiler/backend/il_deserializer.h
@@ -0,0 +1,362 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#ifndef RUNTIME_VM_COMPILER_BACKEND_IL_DESERIALIZER_H_
+#define RUNTIME_VM_COMPILER_BACKEND_IL_DESERIALIZER_H_
+
+#include "platform/assert.h"
+
+#include "vm/allocation.h"
+#include "vm/compiler/backend/flow_graph.h"
+#include "vm/compiler/backend/il.h"
+#include "vm/compiler/backend/sexpression.h"
+#include "vm/compiler/compiler_pass.h"
+#include "vm/object.h"
+#include "vm/parser.h"
+#include "vm/thread.h"
+#include "vm/zone.h"
+
+namespace dart {
+
+// Deserializes FlowGraphs from S-expressions.
+class FlowGraphDeserializer : ValueObject {
+ public:
+ // Adds to the given array all the instructions in the flow graph that are
+ // guaranteed not to be handled by the current implementation of the
+ // FlowGraphDeserializer. This way, we can filter out graphs that are
+ // guaranteed not to be deserializable before going through the round-trip
+ // serialization process.
+ //
+ // Note that there may be other reasons that the deserializer may fail on
+ // a given flow graph, so no new members of the array is necessary, but not
+ // sufficient, for a successful round-trip pass.
+ static void AllUnhandledInstructions(const FlowGraph* graph,
+ GrowableArray<Instruction*>* out);
+
+ // Takes the FlowGraph from [state] and runs it through the serializer
+ // and deserializer. If the deserializer successfully deserializes the
+ // graph, then the FlowGraph in [state] is replaced with the new one.
+ static void RoundTripSerialization(CompilerPassState* state);
+
+ FlowGraphDeserializer(Thread* thread,
+ Zone* zone,
+ SExpression* root,
+ const ParsedFunction* pf = nullptr)
+ : thread_(ASSERT_NOTNULL(thread)),
+ zone_(ASSERT_NOTNULL(zone)),
+ root_sexp_(ASSERT_NOTNULL(root)),
+ parsed_function_(pf),
+ block_map_(zone_),
+ pushed_stack_map_(zone_),
+ definition_map_(zone_),
+ values_map_(zone_),
+ instance_class_(Class::Handle(zone)),
+ instance_field_(Field::Handle(zone)),
+ instance_object_(Object::Handle(zone)),
+ name_class_(Class::Handle(zone)),
+ name_field_(Field::Handle(zone)),
+ name_function_(Function::Handle(zone)),
+ name_library_(Library::Handle(zone)),
+ value_class_(Class::Handle(zone)),
+ value_object_(Object::Handle(zone)),
+ value_type_(AbstractType::Handle(zone)),
+ value_type_args_(TypeArguments::Handle(zone)),
+ tmp_string_(String::Handle(zone)) {
+ // See canonicalization comment in ParseDartValue as to why this is
+ // currently necessary.
+ ASSERT(thread->zone() == zone);
+ }
+
+ // Walks [root_sexp_] and constructs a new FlowGraph.
+ FlowGraph* ParseFlowGraph();
+
+ const char* error_message() const { return error_message_; }
+ SExpression* error_sexp() const { return error_sexp_; }
+
+ // Prints the current error information to stderr and aborts.
+ DART_NORETURN void ReportError() const;
+
+ private:
+#define FOR_EACH_HANDLED_BLOCK_TYPE_IN_DESERIALIZER(M) \
+ M(FunctionEntry) \
+ M(GraphEntry) \
+ M(JoinEntry) \
+ M(TargetEntry)
+
+#define FOR_EACH_HANDLED_INSTRUCTION_IN_DESERIALIZER(M) \
+ M(AllocateObject) \
+ M(Branch) \
+ M(CheckNull) \
+ M(CheckStackOverflow) \
+ M(Constant) \
+ M(DebugStepCheck) \
+ M(Goto) \
+ M(LoadField) \
+ M(Parameter) \
+ M(PushArgument) \
+ M(Return) \
+ M(SpecialParameter) \
+ M(StaticCall) \
+ M(StoreInstanceField) \
+ M(StrictCompare)
+
+ // Helper methods for AllUnhandledInstructions.
+ static bool IsHandledInstruction(Instruction* inst);
+ static bool IsHandledConstant(const Object& obj);
+
+ // **GENERAL DESIGN NOTES FOR PARSING METHODS**
+ //
+ // For functions that take an SExpression or a subclass, they should return
+ // an error signal (false, nullptr, etc.) without changing the error state if
+ // passed in nullptr. This way, methods can be chained without intermediate
+ // checking.
+ //
+ // Also, for parsing methods for expressions that are known to be of a certain
+ // form, they will take the appropriate subclass of SExpression and assume
+ // that the form was already pre-checked by the caller. For forms that are
+ // tagged lists, this includes the fact that there is at least one element
+ // and the first element is a symbol. If the form can only have one possible
+ // tag, they also assume the tag has already been checked.
+
+ // Helper functions that do length/key exists checking and also check that
+ // the retrieved element is not nullptr. Notably, do not use these if the
+ // retrieved element is optional, to avoid changing the error state
+ // unnecessarily.
+ SExpression* Retrieve(SExpList* list, intptr_t index);
+ SExpression* Retrieve(SExpList* list, const char* key);
+
+ bool ParseConstantPool(SExpList* pool);
+ bool ParseEntries(SExpList* list);
+
+ using PushStack = ZoneGrowableArray<PushArgumentInstr*>;
+ using BlockWorklist = GrowableArray<intptr_t>;
+
+ // Starts parsing the contents of [list], where the blocks begin at position
+ // [pos] and [worklist] contains the blocks whose body instructions should
+ // be parsed first.
+ bool ParseBlocks(SExpList* list, intptr_t pos, BlockWorklist* worklist);
+
+ // Block parsing is split into two passes. This pass adds function entries
+ // to the flow graph and also parses initial definitions found in the Entries
+ // list. The block is added to the [block_map_] before returning.
+ BlockEntryInstr* ParseBlockHeader(SExpList* list,
+ intptr_t block_id,
+ SExpSymbol* tag);
+
+ // Expects [current_block_] to be set before calling.
+ bool ParseInitialDefinitions(SExpList* list);
+
+ // Expects [current_block_] to be set before calling.
+ // Takes the tagged list to parse and the index where parsing should start.
+ // Attempts to parse Phi definitions until the first non-Phi instruction.
+ bool ParsePhis(SExpList* list);
+
+ // Expects [current_block_] to be set before calling.
+ // Returns the position of the first non-Phi instruction in a block.
+ intptr_t SkipPhis(SExpList* list);
+
+ // Parses the deopt environment, Phi definitions for JoinEntrys, and the
+ // instructions in the body of the block. Adds the IDs of the block successors
+ // to the worklist, if any. [current_block_] and [pushed_stack_] must be set
+ // before calling.
+ bool ParseBlockContents(SExpList* list, BlockWorklist* worklist);
+
+ // Helper function used by ParseConstantPool, ParsePhis, and ParseDefinition.
+ // This handles all the extra information stored in (def ...) expressions,
+ // and also ensures the index of the definition is appropriately adjusted to
+ // match those found in the serialized form.
+ bool ParseDefinitionWithParsedBody(SExpList* list, Definition* def);
+
+ Definition* ParseDefinition(SExpList* list);
+ Instruction* ParseInstruction(SExpList* list);
+
+ struct EntryInfo {
+ intptr_t block_id;
+ intptr_t try_index;
+ intptr_t deopt_id;
+ };
+
+#define HANDLER_DECL(name) \
+ name##Instr* Deserialize##name(SExpList* list, const EntryInfo& info);
+
+ FOR_EACH_HANDLED_BLOCK_TYPE_IN_DESERIALIZER(HANDLER_DECL);
+
+#undef HANDLER_DECL
+
+ struct InstrInfo {
+ intptr_t deopt_id;
+ TokenPosition token_pos;
+ };
+
+ enum HandledInstruction {
+#define HANDLED_INST_DECL(name) kHandled##name,
+ FOR_EACH_HANDLED_INSTRUCTION_IN_DESERIALIZER(HANDLED_INST_DECL)
+#undef HANDLED_INST_DECL
+ // clang-format off
+ kHandledInvalid = -1,
+ // clang-format on
+ };
+
+#define HANDLE_CASE(name) \
+ if (strcmp(tag->value(), #name) == 0) return kHandled##name;
+ HandledInstruction HandledInstructionForTag(SExpSymbol* tag) {
+ ASSERT(tag != nullptr);
+ FOR_EACH_HANDLED_INSTRUCTION_IN_DESERIALIZER(HANDLE_CASE)
+ return kHandledInvalid;
+ }
+#undef HANDLE_CASE
+
+#define HANDLER_DECL(name) \
+ name##Instr* Deserialize##name(SExpList* list, const InstrInfo& info);
+
+ FOR_EACH_HANDLED_INSTRUCTION_IN_DESERIALIZER(HANDLER_DECL);
+
+#undef HANDLER_DECL
+
+ // Parses [sexp] as a value form, that is, either the binding name for
+ // a definition as a symbol or the form (value <name> { ... }).
+ // If [allow_pending], then values for definitions not already in the
+ // [definition_map_] will be added to the [values_map_], otherwise,
+ // values for definitions not yet seen cause an error to be stored and
+ // nullptr to be returned.
+ Value* ParseValue(SExpression* sexp, bool allow_pending = true);
+ CompileType* ParseCompileType(SExpList* list);
+
+ // Parses [list] as an environment form: a list containing either binding
+ // names for definitions or a# for pushed arguments (where # is the depth
+ // of the argument from the top of the stack). Requires [pushed_stack_] to
+ // be set if any references to pushed arguments are found.
+ Environment* ParseEnvironment(SExpList* list);
+
+ // Parsing functions for which there are no good distinguished error
+ // values, so use out parameters and a boolean return instead.
+
+ // Parses a Dart value and returns a canonicalized result.
+ bool ParseDartValue(SExpression* sexp, Object* out);
+
+ // Helper function for ParseDartValue for parsing instances.
+ // Does not canonicalize (that is currently done in ParseDartValue), so
+ // do not call this method directly.
+ bool ParseInstance(SExpList* list, Instance* out);
+
+ bool ParseCanonicalName(SExpSymbol* sym, Object* out);
+
+ const Field& MayCloneField(const Field& field);
+ bool ParseSlot(SExpList* list, const Slot** out);
+
+ bool ParseBlockId(SExpSymbol* sym, intptr_t* out);
+ bool ParseSSATemp(SExpSymbol* sym, intptr_t* out);
+ bool ParseUse(SExpSymbol* sym, intptr_t* out);
+ bool ParseSymbolAsPrefixedInt(SExpSymbol* sym, char prefix, intptr_t* out);
+
+ // Helper function for creating a placeholder value when the definition
+ // has not yet been seen.
+ Value* AddNewPendingValue(intptr_t index);
+
+ // Similar helper, but where we already have a created value.
+ void AddPendingValue(intptr_t index, Value* val);
+
+ // Helper function for rebinding pending values once the definition has
+ // been located.
+ void FixPendingValues(intptr_t index, Definition* def);
+
+ // Creates a PushArgumentsArray of size [len] from [pushed_stack_] if there
+ // are enough and pops the fetched arguments from the stack.
+ //
+ // The [sexp] argument should be the serialized form of the instruction that
+ // needs the pushed arguments and is only used for error reporting.
+ PushArgumentsArray* FetchPushedArguments(SExpList* sexp, intptr_t len);
+
+ // Retrieves the block corresponding to the given block ID symbol from
+ // [block_map_]. Assumes all blocks have had their header parsed.
+ BlockEntryInstr* FetchBlock(SExpSymbol* sym);
+
+ // Checks that the pushed argument stacks for all predecessors of [succ_block]
+ // are the same as [curr_stack]. This check ensures that we can choose an
+ // arbitrary predecessor's pushed argument stack when parsing [succ_block]'s
+ // contents. [list] is used for error reporting.
+ bool AreStacksConsistent(SExpList* list,
+ PushStack* curr_stack,
+ BlockEntryInstr* succ_block);
+
+ // Utility functions for checking the shape of an S-expression.
+ // If these functions return nullptr for a non-null argument, they have the
+ // side effect of setting the stored error message.
+#define BASE_CHECK_DECL(name, type) SExp##name* Check##name(SExpression* sexp);
+ FOR_EACH_S_EXPRESSION(BASE_CHECK_DECL)
+#undef BASE_CHECK_DECL
+
+ // Checks whether [sexp] is a symbol with the given label.
+ bool IsTag(SExpression* sexp, const char* label);
+
+ // A version of CheckList that also checks that the list has at least one
+ // element and that the first element is a symbol. If [label] is non-null,
+ // then the initial symbol element is checked against it.
+ SExpList* CheckTaggedList(SExpression* sexp, const char* label = nullptr);
+
+ // Stores appropriate error information using the SExpression as the location
+ // and the rest of the arguments as an error message for the user.
+ void StoreError(SExpression* s, const char* fmt, ...) PRINTF_ATTRIBUTE(3, 4);
+
+ Thread* thread() const { return thread_; }
+ Zone* zone() const { return zone_; }
+
+ Thread* const thread_;
+ Zone* const zone_;
+ SExpression* const root_sexp_;
+ const ParsedFunction* parsed_function_;
+
+ FlowGraph* flow_graph_ = nullptr;
+ BlockEntryInstr* current_block_ = nullptr;
+ intptr_t max_block_id_ = -1;
+ intptr_t max_ssa_index_ = -1;
+
+ // Map from block IDs to blocks. Does not contain an entry for block 0
+ // (the graph entry), since it is only used at known points and is already
+ // available via [flow_graph_].
+ IntMap<BlockEntryInstr*> block_map_;
+
+ // Map from block IDs to pushed argument stacks. Used for PushArgument
+ // instructions, environment parsing, and calls during block parsing. Also
+ // used to check that the final pushed argument stacks for predecessor blocks
+ // are consistent when parsing a JoinEntry.
+ IntMap<PushStack*> pushed_stack_map_;
+
+ // Map from variable indexes to definitions.
+ IntMap<Definition*> definition_map_;
+
+ // Map from variable indices to lists of values. The list of values are
+ // values that were parsed prior to the corresponding definition being found.
+ IntMap<ZoneGrowableArray<Value*>*> values_map_;
+
+ // Temporary handles used by functions that are not re-entrant or where the
+ // handle is not live after the re-entrant call. Comments show which handles
+ // are expected to only be used within a single method.
+ Class& instance_class_; // ParseInstance
+ Field& instance_field_; // ParseInstance
+ Object& instance_object_; // ParseInstance
+ Class& name_class_; // ParseCanonicalName
+ Field& name_field_; // ParseCanonicalName
+ Function& name_function_; // ParseCanonicalName
+ Library& name_library_; // ParseCanonicalName
+ Class& value_class_; // ParseDartValue
+ Object& value_object_; // ParseDartValue
+ AbstractType& value_type_; // ParseDartValue
+ TypeArguments& value_type_args_; // ParseDartValue
+ // Uses of string handles tend to be immediate, so we only need one.
+ String& tmp_string_;
+
+ // Stores a message appropriate to surfacing to the user when an error
+ // occurs.
+ const char* error_message_ = nullptr;
+ // Stores the location of the deserialization error by containing the
+ // S-expression which caused the failure.
+ SExpression* error_sexp_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(FlowGraphDeserializer);
+};
+
+} // namespace dart
+
+#endif // RUNTIME_VM_COMPILER_BACKEND_IL_DESERIALIZER_H_
diff --git a/runtime/vm/compiler/backend/il_ia32.cc b/runtime/vm/compiler/backend/il_ia32.cc
index 1729f42..72bc6b3 100644
--- a/runtime/vm/compiler/backend/il_ia32.cc
+++ b/runtime/vm/compiler/backend/il_ia32.cc
@@ -1036,15 +1036,16 @@
__ pushl(EDI);
// Load the thread object.
- // Linking in AOT is not relevant here since we don't support AOT for IA32.
+ //
// Create another frame to align the frame before continuing in "native" code.
// If we were called by a trampoline, it has already loaded the thread.
+ ASSERT(!FLAG_precompiled_mode); // No relocation for AOT linking.
if (!NativeCallbackTrampolines::Enabled()) {
__ EnterFrame(0);
__ ReserveAlignedFrameSpace(compiler::target::kWordSize);
__ movl(compiler::Address(SPREG, 0), compiler::Immediate(callback_id_));
- __ movl(EAX, compiler::Immediate(reinterpret_cast<int64_t>(
+ __ movl(EAX, compiler::Immediate(reinterpret_cast<intptr_t>(
DLRT_GetThreadForNativeCallback)));
__ call(EAX);
__ movl(THR, EAX);
diff --git a/runtime/vm/compiler/backend/il_serializer.cc b/runtime/vm/compiler/backend/il_serializer.cc
index 36b4542..5369159 100644
--- a/runtime/vm/compiler/backend/il_serializer.cc
+++ b/runtime/vm/compiler/backend/il_serializer.cc
@@ -35,23 +35,48 @@
void FlowGraphSerializer::SerializeToBuffer(const FlowGraph* flow_graph,
TextBuffer* buffer) {
- SerializeToBuffer(flow_graph->zone(), flow_graph, buffer);
+ SerializeToBuffer(Thread::Current()->zone(), flow_graph, buffer);
}
void FlowGraphSerializer::SerializeToBuffer(Zone* zone,
const FlowGraph* flow_graph,
TextBuffer* buffer) {
ASSERT(buffer != nullptr);
- FlowGraphSerializer serializer(zone, flow_graph);
- auto const sexp = serializer.FlowGraphToSExp();
+ auto const sexp = SerializeToSExp(zone, flow_graph);
if (FLAG_pretty_print_serialization) {
- sexp->SerializeTo(serializer.zone(), buffer, initial_indent);
+ sexp->SerializeTo(zone, buffer, initial_indent);
} else {
sexp->SerializeToLine(buffer);
}
buffer->AddString("\n\n");
}
+SExpression* FlowGraphSerializer::SerializeToSExp(const FlowGraph* flow_graph) {
+ return SerializeToSExp(Thread::Current()->zone(), flow_graph);
+}
+
+SExpression* FlowGraphSerializer::SerializeToSExp(Zone* zone,
+ const FlowGraph* flow_graph) {
+ FlowGraphSerializer serializer(zone, flow_graph);
+ return serializer.FlowGraphToSExp();
+}
+
+#define KIND_STR(name) #name,
+static const char* block_entry_kind_tags[FlowGraphSerializer::kNumEntryKinds] =
+ {FOR_EACH_BLOCK_ENTRY_KIND(KIND_STR)};
+#undef KIND_STR
+
+FlowGraphSerializer::BlockEntryKind FlowGraphSerializer::BlockEntryTagToKind(
+ SExpSymbol* tag) {
+ if (tag == nullptr) return kTarget;
+ auto const str = tag->value();
+ for (intptr_t i = 0; i < kNumEntryKinds; i++) {
+ auto const current = block_entry_kind_tags[i];
+ if (strcmp(str, current) == 0) return static_cast<BlockEntryKind>(i);
+ }
+ return kInvalid;
+}
+
void FlowGraphSerializer::AddBool(SExpList* sexp, bool b) {
sexp->Add(new (zone()) SExpBool(b));
}
@@ -101,7 +126,9 @@
ASSERT(!obj.IsNull());
if (obj.IsFunction()) {
const auto& function = Function::Cast(obj);
- tmp_string_ = function.UserVisibleName();
+ tmp_string_ = function.name();
+ // We only want private keys removed, no other changes.
+ tmp_string_ = String::RemovePrivateKey(tmp_string_);
const char* function_name = tmp_string_.ToCString();
// If this function is an inner closure then the parent points to its
// containing function, which will also be part of the canonical name.
@@ -159,34 +186,41 @@
return new (zone()) SExpSymbol(OS::SCreate(zone(), "%s", b.buf()));
}
+SExpSymbol* FlowGraphSerializer::BlockEntryKindToTag(BlockEntryKind k) {
+ ASSERT(k >= 0 && k < kNumEntryKinds);
+ return new (zone()) SExpSymbol(block_entry_kind_tags[k]);
+}
+
+#define KIND_TAG(name) block_entry_kind_tags[k##name]
SExpSymbol* FlowGraphSerializer::BlockEntryTag(const BlockEntryInstr* entry) {
if (entry == nullptr) return nullptr;
BlockEntryInstr* const to_test = const_cast<BlockEntryInstr*>(entry);
if (to_test->IsGraphEntry()) {
- return new (zone()) SExpSymbol("Graph");
+ return BlockEntryKindToTag(kGraph);
}
if (to_test->IsOsrEntry()) {
- return new (zone()) SExpSymbol("OSR");
+ return BlockEntryKindToTag(kOSR);
}
if (to_test->IsCatchBlockEntry()) {
- return new (zone()) SExpSymbol("Catch");
+ return BlockEntryKindToTag(kCatch);
}
if (to_test->IsIndirectEntry()) {
- return new (zone()) SExpSymbol("Indirect");
+ return BlockEntryKindToTag(kIndirect);
}
if (to_test->IsFunctionEntry()) {
if (entry == flow_graph()->graph_entry()->normal_entry()) {
- return new (zone()) SExpSymbol("Normal");
+ return BlockEntryKindToTag(kNormal);
}
if (entry == flow_graph()->graph_entry()->unchecked_entry()) {
- return new (zone()) SExpSymbol("Unchecked");
+ return BlockEntryKindToTag(kUnchecked);
}
}
if (to_test->IsJoinEntry()) {
- return new (zone()) SExpSymbol("Join");
+ return BlockEntryKindToTag(kJoin);
}
return nullptr;
}
+#undef KIND_TAG
SExpression* FlowGraphSerializer::FunctionEntryToSExp(BlockEntryInstr* entry) {
if (entry == nullptr) return nullptr;
@@ -199,6 +233,11 @@
sexp->Add(initial_defs->At(i)->ToSExpression(this));
}
}
+
+ // Also include the extra info here, to avoid having to find the
+ // corresponding block to get it.
+ entry->BlockEntryInstr::AddExtraInfoToSExpression(sexp, this);
+
return sexp;
}
@@ -325,6 +364,7 @@
ASSERT(t.IsType());
AddSymbol(sexp, "Type");
const auto& typ = Type::Cast(t);
+ ASSERT(typ.IsFinalized());
if (typ.HasTypeClass()) {
type_class_ = typ.type_class();
// This avoids re-entry as long as serializing a class doesn't involve
@@ -450,8 +490,9 @@
AddExtraSymbol(sexp, "native_name", tmp_string_.ToCString());
}
}
- if (FLAG_verbose_flow_graph_serialization) {
- AddExtraSymbol(sexp, "kind", Function::KindToCString(func.kind()));
+ if (func.kind() != RawFunction::Kind::kRegularFunction ||
+ FLAG_verbose_flow_graph_serialization) {
+ AddExtraSymbol(sexp, "kind", RawFunction::KindToCString(func.kind()));
}
function_type_args_ = func.type_parameters();
if (auto const ta_sexp = NonEmptyTypeArgumentsToSExp(function_type_args_)) {
@@ -474,6 +515,10 @@
array_elem = arr.At(i);
sexp->Add(DartValueToSExp(array_elem));
}
+ array_type_args_ = arr.GetTypeArguments();
+ if (auto const type_args_sexp = TypeArgumentsToSExp(array_type_args_)) {
+ sexp->AddExtra("type_args", type_args_sexp);
+ }
return sexp;
}
@@ -485,6 +530,10 @@
if (auto const func = FunctionToSExp(closure_function_)) {
sexp->Add(func);
}
+ closure_context_ = c.context();
+ if (auto const context = ContextToSExp(closure_context_)) {
+ sexp->AddExtra("context", context);
+ }
closure_type_args_ = c.function_type_arguments();
if (auto const type_args = NonEmptyTypeArgumentsToSExp(closure_type_args_)) {
sexp->AddExtra("func_type_args", type_args);
@@ -500,6 +549,23 @@
return sexp;
}
+SExpression* FlowGraphSerializer::ContextToSExp(const Context& c) {
+ if (c.IsNull()) return nullptr;
+ auto sexp = new (zone()) SExpList(zone());
+ AddSymbol(sexp, "Context");
+ for (intptr_t i = 0; i < c.num_variables(); i++) {
+ context_elem_ = c.At(i);
+ auto const elem_sexp = DartValueToSExp(context_elem_);
+ if (elem_sexp == nullptr) return nullptr;
+ sexp->Add(elem_sexp);
+ }
+ context_parent_ = c.parent();
+ if (auto const parent_sexp = ContextToSExp(context_parent_)) {
+ sexp->AddExtra("parent", parent_sexp);
+ }
+ return sexp;
+}
+
SExpression* FlowGraphSerializer::ObjectToSExp(const Object& dartval) {
if (dartval.IsNull()) {
return new (zone()) SExpSymbol("null");
@@ -603,10 +669,13 @@
void BlockEntryInstr::AddExtraInfoToSExpression(SExpList* sexp,
FlowGraphSerializer* s) const {
Instruction::AddExtraInfoToSExpression(sexp, s);
+ if (try_index() != kInvalidTryIndex) {
+ s->AddExtraInteger(sexp, "try_index", try_index());
+ }
+ if (auto const entry_tag = s->BlockEntryTag(this)) {
+ sexp->AddExtra("block_type", entry_tag);
+ }
if (FLAG_verbose_flow_graph_serialization) {
- if (auto const entry_tag = s->BlockEntryTag(this)) {
- sexp->AddExtra("block_type", entry_tag);
- }
if (PredecessorCount() > 0) {
auto const preds = new (s->zone()) SExpList(s->zone());
for (intptr_t i = 0; i < PredecessorCount(); i++) {
@@ -688,6 +757,7 @@
void SpecialParameterInstr::AddOperandsToSExpression(
SExpList* sexp,
FlowGraphSerializer* s) const {
+ ASSERT(kind() < SpecialParameterInstr::kNumKinds);
s->AddSymbol(sexp, KindToCString(kind()));
}
@@ -713,30 +783,13 @@
sexp->Add(s->LocalVariableToSExp(local()));
}
-static const char* SlotKindToCString(Slot::Kind kind) {
- switch (kind) {
- case Slot::Kind::kDartField:
- return "DartField";
- case Slot::Kind::kCapturedVariable:
- return "CapturedVariable";
- case Slot::Kind::kTypeArguments:
- return "TypeArguments";
- default:
- return "NativeSlot";
- }
-}
-
SExpression* FlowGraphSerializer::SlotToSExp(const Slot& slot) {
auto sexp = new (zone()) SExpList(zone());
AddSymbol(sexp, "Slot");
AddInteger(sexp, slot.offset_in_bytes());
- if (FLAG_verbose_flow_graph_serialization) {
- AddExtraSymbol(sexp, "kind", SlotKindToCString(slot.kind()));
- if (slot.IsDartField()) {
- sexp->AddExtra("field", DartValueToSExp(slot.field()));
- } else {
- AddExtraString(sexp, "name", slot.Name());
- }
+ AddExtraSymbol(sexp, "kind", Slot::KindToCString(slot.kind()));
+ if (slot.IsDartField()) {
+ sexp->AddExtra("field", DartValueToSExp(slot.field()));
}
return sexp;
}
@@ -755,6 +808,23 @@
sexp->Add(value()->ToSExpression(s));
}
+void StoreInstanceFieldInstr::AddExtraInfoToSExpression(
+ SExpList* sexp,
+ FlowGraphSerializer* s) const {
+ if (is_initialization_ || FLAG_verbose_flow_graph_serialization) {
+ s->AddExtraBool(sexp, "is_init", is_initialization_);
+ }
+ if (emit_store_barrier_ != kNoStoreBarrier ||
+ FLAG_verbose_flow_graph_serialization) {
+ // Make sure that we aren't seeing a new value added to the StoreBarrierType
+ // enum that isn't handled by the serializer.
+ ASSERT(emit_store_barrier_ == kNoStoreBarrier ||
+ emit_store_barrier_ == kEmitStoreBarrier);
+ s->AddExtraBool(sexp, "emit_barrier",
+ emit_store_barrier_ != kNoStoreBarrier);
+ }
+}
+
void LoadIndexedUnsafeInstr::AddExtraInfoToSExpression(
SExpList* sexp,
FlowGraphSerializer* s) const {
@@ -779,6 +849,15 @@
Instruction::AddOperandsToSExpression(sexp, s);
}
+void StrictCompareInstr::AddExtraInfoToSExpression(
+ SExpList* sexp,
+ FlowGraphSerializer* s) const {
+ Instruction::AddExtraInfoToSExpression(sexp, s);
+ if (needs_number_check_ || FLAG_verbose_flow_graph_serialization) {
+ s->AddExtraBool(sexp, "needs_check", needs_number_check_);
+ }
+}
+
void DoubleTestOpInstr::AddOperandsToSExpression(SExpList* sexp,
FlowGraphSerializer* s) const {
const bool negated = kind() != Token::kEQ;
@@ -800,6 +879,17 @@
sexp->Add(s->BlockIdToSExp(successor()->block_id()));
}
+void DebugStepCheckInstr::AddExtraInfoToSExpression(
+ SExpList* sexp,
+ FlowGraphSerializer* s) const {
+ if (stub_kind_ != RawPcDescriptors::kAnyKind ||
+ FLAG_verbose_flow_graph_serialization) {
+ auto const stub_kind_name = RawPcDescriptors::KindToCString(stub_kind_);
+ ASSERT(stub_kind_name != nullptr);
+ s->AddExtraSymbol(sexp, "stub_kind", stub_kind_name);
+ }
+}
+
void TailCallInstr::AddOperandsToSExpression(SExpList* sexp,
FlowGraphSerializer* s) const {
if (auto const code = s->DartValueToSExp(code_)) {
@@ -815,8 +905,8 @@
}
}
-template <>
-void TemplateDartCall<0l>::AddExtraInfoToSExpression(
+template <intptr_t kInputCount>
+void TemplateDartCall<kInputCount>::AddExtraInfoToSExpression(
SExpList* sexp,
FlowGraphSerializer* s) const {
Instruction::AddExtraInfoToSExpression(sexp, s);
@@ -824,17 +914,26 @@
s->AddExtraInteger(sexp, "type_args_len", type_args_len());
}
s->AddExtraInteger(sexp, "args_len", ArgumentCountWithoutTypeArgs());
+ if (this->CallCount() > 0 || FLAG_verbose_flow_graph_serialization) {
+ s->AddExtraInteger(sexp, "call_count", this->CallCount());
+ }
+ const auto& arg_names = argument_names();
+ if (!arg_names.IsNull()) {
+ auto arg_names_sexp = new (s->zone()) SExpList(s->zone());
+ auto& str = String::Handle(s->zone());
+ for (intptr_t i = 0; i < arg_names.Length(); i++) {
+ str = String::RawCast(arg_names.At(i));
+ arg_names_sexp->Add(s->ObjectToSExp(str));
+ }
+ sexp->AddExtra("arg_names", arg_names_sexp);
+ }
}
-template <>
-void TemplateDartCall<1l>::AddExtraInfoToSExpression(
- SExpList* sexp,
- FlowGraphSerializer* s) const {
- Instruction::AddExtraInfoToSExpression(sexp, s);
- if (type_args_len() > 0 || FLAG_verbose_flow_graph_serialization) {
- s->AddExtraInteger(sexp, "type_args_len", type_args_len());
- }
- s->AddExtraInteger(sexp, "args_len", ArgumentCountWithoutTypeArgs());
+void ClosureCallInstr::AddExtraInfoToSExpression(SExpList* sexp,
+ FlowGraphSerializer* s) const {
+ // For now, just here to ensure TemplateDartCall<1>::AddExtraInfoToSExpression
+ // gets instantiated.
+ TemplateDartCall<1>::AddExtraInfoToSExpression(sexp, s);
}
void StaticCallInstr::AddOperandsToSExpression(SExpList* sexp,
@@ -844,6 +943,18 @@
}
}
+void StaticCallInstr::AddExtraInfoToSExpression(SExpList* sexp,
+ FlowGraphSerializer* s) const {
+ TemplateDartCall<0>::AddExtraInfoToSExpression(sexp, s);
+
+ if (rebind_rule_ != ICData::kInstance ||
+ FLAG_verbose_flow_graph_serialization) {
+ auto const str = ICData::RebindRuleToCString(rebind_rule_);
+ ASSERT(str != nullptr);
+ s->AddExtraSymbol(sexp, "rebind_rule", str);
+ }
+}
+
void InstanceCallInstr::AddOperandsToSExpression(SExpList* sexp,
FlowGraphSerializer* s) const {
if (auto const target = s->DartValueToSExp(interface_target())) {
@@ -982,6 +1093,18 @@
if (in_loop() || FLAG_verbose_flow_graph_serialization) {
s->AddExtraInteger(sexp, "loop_depth", loop_depth());
}
+ if (kind_ != kOsrAndPreemption) {
+ ASSERT(kind_ == kOsrOnly);
+ s->AddExtraSymbol(sexp, "kind", "OsrOnly");
+ }
+}
+
+void CheckNullInstr::AddExtraInfoToSExpression(SExpList* sexp,
+ FlowGraphSerializer* s) const {
+ Instruction::AddExtraInfoToSExpression(sexp, s);
+ if (!function_name_.IsNull()) {
+ s->AddExtraString(sexp, "function_name", function_name_.ToCString());
+ }
}
SExpression* Value::ToSExpression(FlowGraphSerializer* s) const {
@@ -1013,6 +1136,8 @@
void CompileType::AddExtraInfoToSExpression(SExpList* sexp,
FlowGraphSerializer* s) const {
+ // TODO(sstrickl): Currently we only print out nullable if it's false
+ // (or during verbose printing). Switch this when NNBD is the standard.
if (!is_nullable() || FLAG_verbose_flow_graph_serialization) {
s->AddExtraBool(sexp, "nullable", is_nullable());
}
@@ -1032,7 +1157,7 @@
for (intptr_t i = 0; i < values_.length(); ++i) {
if (values_[i]->definition()->IsPushArgument()) {
- s->AddSymbol(sexp, OS::SCreate(s->zone(), "arg[%" Pd "]", arg_count++));
+ s->AddSymbol(sexp, OS::SCreate(s->zone(), "a%" Pd "", arg_count++));
} else {
sexp->Add(values_[i]->ToSExpression(s));
}
@@ -1043,7 +1168,11 @@
ASSERT(locations_ == nullptr || locations_[i].IsInvalid());
}
if (outer_ != NULL) {
- sexp->Add(outer_->ToSExpression(s));
+ auto outer_sexp = outer_->ToSExpression(s)->AsList();
+ if (outer_->deopt_id_ != DeoptId::kNone) {
+ s->AddExtraInteger(outer_sexp, "deopt_id", outer_->deopt_id_);
+ }
+ sexp->AddExtra("outer", outer_sexp);
}
return sexp;
}
diff --git a/runtime/vm/compiler/backend/il_serializer.h b/runtime/vm/compiler/backend/il_serializer.h
index 3390a53..753ce49 100644
--- a/runtime/vm/compiler/backend/il_serializer.h
+++ b/runtime/vm/compiler/backend/il_serializer.h
@@ -20,11 +20,38 @@
// Flow graph serialization.
class FlowGraphSerializer : ValueObject {
public:
+#define FOR_EACH_BLOCK_ENTRY_KIND(M) \
+ M(Target) \
+ M(Join) \
+ M(Graph) \
+ M(Normal) \
+ M(Unchecked) \
+ M(OSR) \
+ M(Catch) \
+ M(Indirect)
+
+ enum BlockEntryKind {
+#define KIND_DECL(name) k##name,
+ FOR_EACH_BLOCK_ENTRY_KIND(KIND_DECL)
+#undef KIND_DECL
+ // clang-format off
+ kNumEntryKinds,
+ kInvalid = -1,
+ // clang-format on
+ };
+
+ // Special case: returns kTarget for a nullptr input.
+ static BlockEntryKind BlockEntryTagToKind(SExpSymbol* tag);
+ SExpSymbol* BlockEntryKindToTag(BlockEntryKind k);
+ static bool BlockEntryKindHasInitialDefs(BlockEntryKind kind);
+
static void SerializeToBuffer(const FlowGraph* flow_graph,
TextBuffer* buffer);
static void SerializeToBuffer(Zone* zone,
const FlowGraph* flow_graph,
TextBuffer* buffer);
+ static SExpression* SerializeToSExp(const FlowGraph* flow_graph);
+ static SExpression* SerializeToSExp(Zone* zone, const FlowGraph* flow_graph);
const FlowGraph* flow_graph() const { return flow_graph_; }
Zone* zone() const { return zone_; }
@@ -45,6 +72,7 @@
SExpression* ArrayToSExp(const Array& arr);
SExpression* ClassToSExp(const Class& cls);
SExpression* ClosureToSExp(const Closure& c);
+ SExpression* ContextToSExp(const Context& c);
SExpression* CodeToSExp(const Code& c);
SExpression* FieldToSExp(const Field& f);
SExpression* FunctionToSExp(const Function& f);
@@ -83,9 +111,13 @@
: flow_graph_(ASSERT_NOTNULL(flow_graph)),
zone_(zone),
tmp_string_(String::Handle(zone_)),
+ array_type_args_((TypeArguments::Handle(zone_))),
+ closure_context_(Context::Handle(zone_)),
closure_function_(Function::Handle(zone_)),
closure_type_args_(TypeArguments::Handle(zone_)),
code_owner_(Object::Handle(zone_)),
+ context_parent_(Context::Handle(zone_)),
+ context_elem_(Object::Handle(zone_)),
function_type_args_(TypeArguments::Handle(zone_)),
instance_field_(Field::Handle(zone_)),
instance_type_args_(TypeArguments::Handle(zone_)),
@@ -94,7 +126,11 @@
serialize_parent_(Function::Handle(zone_)),
type_arguments_elem_(AbstractType::Handle(zone_)),
type_class_(Class::Handle(zone_)),
- type_ref_type_(AbstractType::Handle(zone_)) {}
+ type_ref_type_(AbstractType::Handle(zone_)) {
+ // Double-check that the zone in the flow graph is a parent of the
+ // zone we'll be using for serialization.
+ ASSERT(flow_graph->zone()->ContainsNestedZone(zone));
+ }
static const char* const initial_indent;
@@ -121,9 +157,13 @@
// DartValueToSExp with a sub-element of type Object, but any call to a
// FlowGraphSerializer method that may eventually enter one of the methods
// listed below should be examined with care.
+ TypeArguments& array_type_args_; // ArrayToSExp
+ Context& closure_context_; // ClosureToSExp
Function& closure_function_; // ClosureToSExp
TypeArguments& closure_type_args_; // ClosureToSExp
Object& code_owner_; // CodeToSExp
+ Context& context_parent_; // ContextToSExp
+ Object& context_elem_; // ContextToSExp
TypeArguments& function_type_args_; // FunctionToSExp
Field& instance_field_; // InstanceToSExp
TypeArguments& instance_type_args_; // InstanceToSExp
diff --git a/runtime/vm/compiler/backend/il_test_helper.cc b/runtime/vm/compiler/backend/il_test_helper.cc
index 0bc24f1..bdc039a 100644
--- a/runtime/vm/compiler/backend/il_test_helper.cc
+++ b/runtime/vm/compiler/backend/il_test_helper.cc
@@ -114,9 +114,9 @@
}
if (passes.size() > 0) {
- CompilerPass::RunPipelineWithPasses(pass_state_, passes);
+ flow_graph_ = CompilerPass::RunPipelineWithPasses(pass_state_, passes);
} else {
- CompilerPass::RunPipeline(mode_, pass_state_);
+ flow_graph_ = CompilerPass::RunPipeline(mode_, pass_state_);
}
}
diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc
index d65b984..c7612ed 100644
--- a/runtime/vm/compiler/backend/il_x64.cc
+++ b/runtime/vm/compiler/backend/il_x64.cc
@@ -1024,10 +1024,6 @@
}
void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- if (FLAG_precompiled_mode) {
- UNREACHABLE();
- }
-
__ Bind(compiler->GetJumpLabel(this));
// Create a dummy frame holding the pushed arguments. This simplifies
@@ -1055,9 +1051,38 @@
__ PushRegisters(CallingConventions::kCalleeSaveCpuRegisters,
CallingConventions::kCalleeSaveXmmRegisters);
- // Load the thread object.
- // TODO(35765): Fix linking issue on AOT.
- //
+ // Load the address of DLRT_GetThreadForNativeCallback without using Thread.
+ if (FLAG_precompiled_mode) {
+ compiler::Label skip_reloc;
+ __ jmp(&skip_reloc);
+ compiler->InsertBSSRelocation(
+ BSS::Relocation::DRT_GetThreadForNativeCallback);
+ const intptr_t reloc_end = __ CodeSize();
+ __ Bind(&skip_reloc);
+
+ const intptr_t kLeaqLength = 7;
+ __ leaq(RAX, compiler::Address::AddressRIPRelative(
+ -kLeaqLength - compiler::target::kWordSize));
+ ASSERT((__ CodeSize() - reloc_end) == kLeaqLength);
+
+ // RAX holds the address of the relocation.
+ __ movq(RCX, compiler::Address(RAX, 0));
+
+ // RCX holds the relocation itself: RAX - bss_start.
+ // RAX = RAX + (bss_start - RAX) = bss_start
+ __ addq(RAX, RCX);
+
+ // RAX holds the start of the BSS section.
+ // Load the "get-thread" routine: *bss_start.
+ __ movq(RAX, compiler::Address(RAX, 0));
+ } else if (!NativeCallbackTrampolines::Enabled()) {
+ // In JIT mode, we can just paste the address of the runtime entry into the
+ // generated code directly. This is not a problem since we don't save
+ // callbacks into JIT snapshots.
+ __ movq(RAX, compiler::Immediate(reinterpret_cast<intptr_t>(
+ DLRT_GetThreadForNativeCallback)));
+ }
+
// Create another frame to align the frame before continuing in "native" code.
// If we were called by a trampoline, it has already loaded the thread.
if (!NativeCallbackTrampolines::Enabled()) {
@@ -1066,8 +1091,6 @@
COMPILE_ASSERT(RAX != CallingConventions::kArg1Reg);
__ movq(CallingConventions::kArg1Reg, compiler::Immediate(callback_id_));
- __ movq(RAX, compiler::Immediate(reinterpret_cast<int64_t>(
- DLRT_GetThreadForNativeCallback)));
__ CallCFunction(RAX);
__ movq(THR, RAX);
@@ -4779,7 +4802,7 @@
void MathMinMaxInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
ASSERT((op_kind() == MethodRecognizer::kMathMin) ||
(op_kind() == MethodRecognizer::kMathMax));
- const intptr_t is_min = (op_kind() == MethodRecognizer::kMathMin);
+ const bool is_min = op_kind() == MethodRecognizer::kMathMin;
if (result_cid() == kDoubleCid) {
compiler::Label done, returns_nan, are_equal;
XmmRegister left = locs()->in(0).fpu_reg();
@@ -5690,6 +5713,64 @@
Register out) {
ASSERT(op_kind == Token::kMOD || op_kind == Token::kTRUNCDIV);
+ // Special case 64-bit div/mod by compile-time constant. Note that various
+ // special constants (such as powers of two) should have been optimized
+ // earlier in the pipeline. Div or mod by zero falls into general code
+ // to implement the exception.
+ if (auto c = instruction->right()->definition()->AsConstant()) {
+ if (c->value().IsInteger()) {
+ const int64_t divisor = Integer::Cast(c->value()).AsInt64Value();
+ if (divisor <= -2 || divisor >= 2) {
+ // For x DIV c or x MOD c: use magic operations.
+ compiler::Label pos;
+ int64_t magic = 0;
+ int64_t shift = 0;
+ Utils::CalculateMagicAndShiftForDivRem(divisor, &magic, &shift);
+ // RDX:RAX = magic * numerator.
+ ASSERT(left == RAX);
+ __ MoveRegister(TMP, RAX); // save numerator
+ __ LoadImmediate(RAX, compiler::Immediate(magic));
+ __ imulq(TMP);
+ // RDX +/-= numerator.
+ if (divisor > 0 && magic < 0) {
+ __ addq(RDX, TMP);
+ } else if (divisor < 0 && magic > 0) {
+ __ subq(RDX, TMP);
+ }
+ // Shift if needed.
+ if (shift != 0) {
+ __ sarq(RDX, compiler::Immediate(shift));
+ }
+ // RDX += 1 if RDX < 0.
+ __ movq(RAX, RDX);
+ __ shrq(RDX, compiler::Immediate(63));
+ __ addq(RDX, RAX);
+ // Finalize DIV or MOD.
+ if (op_kind == Token::kTRUNCDIV) {
+ ASSERT(out == RAX && tmp == RDX);
+ __ movq(RAX, RDX);
+ } else {
+ ASSERT(out == RDX && tmp == RAX);
+ __ movq(RAX, TMP);
+ __ LoadImmediate(TMP, compiler::Immediate(divisor));
+ __ imulq(RDX, TMP);
+ __ subq(RAX, RDX);
+ // Compensate for Dart's Euclidean view of MOD.
+ __ testq(RAX, RAX);
+ __ j(GREATER_EQUAL, &pos);
+ if (divisor > 0) {
+ __ addq(RAX, TMP);
+ } else {
+ __ subq(RAX, TMP);
+ }
+ __ Bind(&pos);
+ __ movq(RDX, RAX);
+ }
+ return;
+ }
+ }
+ }
+
// Prepare a slow path.
Range* right_range = instruction->right()->definition()->range();
Int64DivideSlowPath* slow_path = new (Z) Int64DivideSlowPath(
diff --git a/runtime/vm/compiler/backend/inliner.cc b/runtime/vm/compiler/backend/inliner.cc
index 8f5492a..2a18c66 100644
--- a/runtime/vm/compiler/backend/inliner.cc
+++ b/runtime/vm/compiler/backend/inliner.cc
@@ -979,21 +979,6 @@
// Install bailout jump.
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
- Isolate* isolate = Isolate::Current();
- // Makes sure no classes are loaded during parsing in background.
- const intptr_t loading_invalidation_gen_at_start =
- isolate->loading_invalidation_gen();
-
- if (Compiler::IsBackgroundCompilation()) {
- if ((loading_invalidation_gen_at_start !=
- isolate->loading_invalidation_gen())) {
- // Loading occured while parsing. We need to abort here because
- // state changed while compiling.
- Compiler::AbortBackgroundCompilation(
- DeoptId::kNone, "Loading occured while parsing in inliner");
- }
- }
-
// Load IC data for the callee.
ZoneGrowableArray<const ICData*>* ic_data_array =
new (Z) ZoneGrowableArray<const ICData*>();
@@ -1255,10 +1240,6 @@
caller_graph()->parsed_function().AddToGuardedFields(
callee_guarded_fields[i]);
}
- // When inlined, we add the deferred prefixes of the callee to the
- // caller's list of deferred prefixes.
- caller_graph()->AddToDeferredPrefixes(
- callee_graph->deferred_prefixes());
FlowGraphInliner::SetInliningId(
callee_graph,
@@ -1910,6 +1891,7 @@
// Unshared. Graft the normal entry on after the check class
// instruction.
auto target = callee_entry->AsGraphEntry()->normal_entry();
+ ASSERT(cursor != nullptr);
cursor->LinkTo(target->next());
target->ReplaceAsPredecessorWith(current_block);
// Unuse all inputs of the graph entry and the normal entry. They are
@@ -1970,6 +1952,7 @@
new TargetEntryInstr(AllocateBlockId(), try_idx, DeoptId::kNone);
below_target->InheritDeoptTarget(zone(), call_);
current_block->AddDominatedBlock(below_target);
+ ASSERT(cursor != nullptr); // read before overwrite
cursor = current_block = below_target;
*branch_top->true_successor_address() = below_target;
@@ -1987,9 +1970,9 @@
}
branch->InheritDeoptTarget(zone(), call_);
- cursor = AppendInstruction(cursor, branch);
+ AppendInstruction(cursor, branch);
+ cursor = nullptr;
current_block->set_last_instruction(branch);
- cursor = NULL;
// 2. Handle a match by linking to the inlined body. There are three
// cases (unshared, shared first predecessor, and shared subsequent
@@ -3322,15 +3305,16 @@
ForwardInstructionIterator* iterator,
InstanceCallInstr* call,
SpeculativeInliningPolicy* policy) {
- Function& target = Function::Handle(Z);
- GrowableArray<intptr_t> class_ids;
- call->ic_data()->GetCheckAt(0, &class_ids, &target);
- const intptr_t receiver_cid = class_ids[0];
+ const CallTargets& targets = call->Targets();
+ ASSERT(targets.IsMonomorphic());
+ const intptr_t receiver_cid = targets.MonomorphicReceiverCid();
+ const Function& target = targets.FirstTarget();
+ const auto exactness = targets.MonomorphicExactness();
+ ExactnessInfo exactness_info{exactness.IsExact(), false};
+
FunctionEntryInstr* entry = nullptr;
Instruction* last = nullptr;
Definition* result = nullptr;
- auto exactness = call->ic_data()->GetExactnessAt(0);
- ExactnessInfo exactness_info{exactness.IsExact(), false};
if (FlowGraphInliner::TryInlineRecognizedMethod(
flow_graph, receiver_cid, target, call,
call->Receiver()->definition(), call->token_pos(), call->ic_data(),
@@ -3353,8 +3337,7 @@
switch (check) {
case FlowGraph::ToCheck::kCheckCid: {
Instruction* check_class = flow_graph->CreateCheckClass(
- call->Receiver()->definition(),
- *Cids::CreateAndExpand(Z, *call->ic_data(), 0), call->deopt_id(),
+ call->Receiver()->definition(), targets, call->deopt_id(),
call->token_pos());
flow_graph->InsertBefore(call, check_class, call->env(),
FlowGraph::kEffect);
@@ -3384,7 +3367,7 @@
}
// Replace all uses of this definition with the result.
if (call->HasUses()) {
- ASSERT(result->HasSSATemp());
+ ASSERT(result != nullptr && result->HasSSATemp());
call->ReplaceUsesWith(result);
}
// Finally insert the sequence other definition in place of this one in the
@@ -3997,16 +3980,12 @@
case MethodRecognizer::kGrowableArraySetData:
ASSERT((receiver_cid == kGrowableObjectArrayCid) ||
((receiver_cid == kDynamicCid) && call->IsStaticCall()));
- ASSERT(call->IsStaticCall() ||
- (ic_data == NULL || ic_data->NumberOfChecksIs(1)));
return InlineGrowableArraySetter(
flow_graph, Slot::GrowableObjectArray_data(), kEmitStoreBarrier, call,
receiver, graph_entry, entry, last, result);
case MethodRecognizer::kGrowableArraySetLength:
ASSERT((receiver_cid == kGrowableObjectArrayCid) ||
((receiver_cid == kDynamicCid) && call->IsStaticCall()));
- ASSERT(call->IsStaticCall() ||
- (ic_data == NULL || ic_data->NumberOfChecksIs(1)));
return InlineGrowableArraySetter(
flow_graph, Slot::GrowableObjectArray_length(), kNoStoreBarrier, call,
receiver, graph_entry, entry, last, result);
diff --git a/runtime/vm/compiler/backend/linearscan.cc b/runtime/vm/compiler/backend/linearscan.cc
index 66101af..b196088 100644
--- a/runtime/vm/compiler/backend/linearscan.cc
+++ b/runtime/vm/compiler/backend/linearscan.cc
@@ -603,7 +603,8 @@
// Check if any values live into the loop can be spilled for free.
if (block->IsLoopHeader()) {
- current_interference_set = NULL;
+ ASSERT(loop_info != nullptr);
+ current_interference_set = nullptr;
for (BitVector::Iterator it(liveness_.GetLiveInSetAt(i)); !it.Done();
it.Advance()) {
LiveRange* range = GetLiveRange(it.Current());
diff --git a/runtime/vm/compiler/backend/locations.h b/runtime/vm/compiler/backend/locations.h
index 638fc84..b6e7777 100644
--- a/runtime/vm/compiler/backend/locations.h
+++ b/runtime/vm/compiler/backend/locations.h
@@ -572,7 +572,7 @@
void AddAllNonReservedRegisters(bool include_fpu_registers) {
for (intptr_t i = kNumberOfCpuRegisters - 1; i >= 0; --i) {
- if (kReservedCpuRegisters & (1 << i)) continue;
+ if ((kReservedCpuRegisters & (1 << i)) != 0u) continue;
Add(Location::RegisterLocation(static_cast<Register>(i)));
}
diff --git a/runtime/vm/compiler/backend/loops.cc b/runtime/vm/compiler/backend/loops.cc
index a641557..8c046a6 100644
--- a/runtime/vm/compiler/backend/loops.cc
+++ b/runtime/vm/compiler/backend/loops.cc
@@ -876,9 +876,9 @@
num_blocks++;
}
f.Print("#blocks=%" Pd, num_blocks);
- if (outer_) f.Print(" outer=%" Pd, outer_->id_);
- if (inner_) f.Print(" inner=%" Pd, inner_->id_);
- if (next_) f.Print(" next=%" Pd, next_->id_);
+ if (outer_ != nullptr) f.Print(" outer=%" Pd, outer_->id_);
+ if (inner_ != nullptr) f.Print(" inner=%" Pd, inner_->id_);
+ if (next_ != nullptr) f.Print(" next=%" Pd, next_->id_);
f.Print(" [");
for (intptr_t i = 0, n = back_edges_.length(); i < n; i++) {
f.Print(" B%" Pd, back_edges_[i]->block_id());
diff --git a/runtime/vm/compiler/backend/sexpression.cc b/runtime/vm/compiler/backend/sexpression.cc
index 53077b7..a314abf 100644
--- a/runtime/vm/compiler/backend/sexpression.cc
+++ b/runtime/vm/compiler/backend/sexpression.cc
@@ -19,6 +19,16 @@
return sexp;
}
+const char* SExpression::ToCString(Zone* zone) const {
+ TextBuffer buf(1 * KB);
+ SerializeToLine(&buf);
+ auto const buf_len = buf.length();
+ char* ret = zone->Alloc<char>(buf_len + 1);
+ strncpy(ret, buf.buf(), buf_len);
+ ret[buf_len] = '\0';
+ return ret;
+}
+
bool SExpBool::Equals(SExpression* sexp) const {
if (!sexp->IsBool()) return false;
return this->value() == sexp->AsBool()->value();
@@ -112,7 +122,7 @@
const intptr_t leading_length = leading_space ? 1 : 0;
if ((leading_length + single_line_width) < remaining) {
- if (leading_space != 0) buffer->AddChar(' ');
+ if (leading_space) buffer->AddChar(' ');
buffer->AddString(line_buffer->buf());
line_buffer->Clear();
return remaining - (leading_length + single_line_width);
@@ -498,7 +508,7 @@
SExpParser::Token* SExpParser::GetNextToken() {
intptr_t start_pos = cur_pos_;
while (start_pos < buffer_size_) {
- if (!isspace(buffer_[start_pos])) break;
+ if (isspace(buffer_[start_pos]) == 0) break;
start_pos++;
}
if (start_pos >= buffer_size_) return nullptr;
@@ -572,7 +582,7 @@
}
// If we find a character that can't appear in a number, then fall back
// to symbol-ness.
- if (!isdigit(start[len])) type = kSymbol;
+ if (isdigit(start[len]) == 0) type = kSymbol;
len++;
}
cur_pos_ = start_pos + len;
@@ -605,7 +615,7 @@
}
bool SExpParser::IsSymbolContinue(char c) {
- return !isspace(c) && c != '(' && c != ')' && c != ',' && c != '{' &&
+ return (isspace(c) == 0) && c != '(' && c != ')' && c != ',' && c != '{' &&
c != '}' && c != '"';
}
diff --git a/runtime/vm/compiler/backend/sexpression.h b/runtime/vm/compiler/backend/sexpression.h
index 9636b19..4a7d67e 100644
--- a/runtime/vm/compiler/backend/sexpression.h
+++ b/runtime/vm/compiler/backend/sexpression.h
@@ -9,7 +9,6 @@
#include "vm/allocation.h"
#include "vm/growable_array.h"
-#include "vm/hash.h"
#include "vm/hash_map.h"
#include "vm/zone.h"
@@ -61,6 +60,7 @@
static intptr_t const kInvalidPos = -1;
static SExpression* FromCString(Zone* zone, const char* cstr);
+ const char* ToCString(Zone* zone) const;
intptr_t start() const { return start_; }
#define S_EXPRESSION_TYPE_CHECK(name, value_type) \
@@ -132,36 +132,7 @@
explicit SExpList(Zone* zone, intptr_t start = kInvalidPos)
: SExpression(start), contents_(zone, 2), extra_info_(zone) {}
- template <typename V>
- class CStringPointerKeyValueTrait {
- public:
- typedef const char* Key;
- typedef V Value;
-
- struct Pair {
- Key key;
- Value value;
- Pair() : key(NULL), value() {}
- Pair(const Key key, const Value& value) : key(key), value(value) {}
- Pair(const Pair& other) : key(other.key), value(other.value) {}
- };
-
- static Key KeyOf(Pair kv) { return kv.key; }
- static Value ValueOf(Pair kv) { return kv.value; }
- static intptr_t Hashcode(Key key) {
- intptr_t hash = 0;
- for (size_t i = 0; i < strlen(key); i++) {
- hash = CombineHashes(hash, key[i]);
- }
- return FinalizeHash(hash, kBitsPerWord - 1);
- }
- static bool IsKeyEqual(Pair kv, Key key) {
- return kv.key == key || strcmp(kv.key, key) == 0;
- }
- };
-
- using ExtraInfoKeyValueTrait = CStringPointerKeyValueTrait<SExpression*>;
- using ExtraInfoHashMap = DirectChainedHashMap<ExtraInfoKeyValueTrait>;
+ using ExtraInfoHashMap = CStringMap<SExpression*>;
void Add(SExpression* sexp);
void AddExtra(const char* label, SExpression* value);
@@ -174,7 +145,7 @@
return extra_info_.GetIterator();
}
bool ExtraHasKey(const char* cstr) const { return extra_info_.HasKey(cstr); }
- ExtraInfoKeyValueTrait::Value ExtraLookupValue(const char* cstr) const {
+ SExpression* ExtraLookupValue(const char* cstr) const {
return extra_info_.LookupValue(cstr);
}
@@ -292,7 +263,7 @@
SExpression* TokenToSExpression(Token* token);
Token* GetNextToken();
void Reset();
- void StoreError(intptr_t pos, const char* format, ...);
+ void StoreError(intptr_t pos, const char* format, ...) PRINTF_ATTRIBUTE(3, 4);
static bool IsSymbolContinue(char c);
diff --git a/runtime/vm/compiler/backend/slot.cc b/runtime/vm/compiler/backend/slot.cc
index bb0c918..d928420 100644
--- a/runtime/vm/compiler/backend/slot.cc
+++ b/runtime/vm/compiler/backend/slot.cc
@@ -46,6 +46,55 @@
DirectChainedHashMap<PointerKeyValueTrait<const Slot> > fields_;
};
+#define NATIVE_SLOT_NAME(C, F, id, M) Kind::k##C##_##F
+#define NATIVE_TO_STR(C, F, id, M) #C "_" #F
+
+const char* Slot::KindToCString(Kind k) {
+ switch (k) {
+#define NATIVE_CASE(C, F, id, M) \
+ case NATIVE_SLOT_NAME(C, F, id, M): \
+ return NATIVE_TO_STR(C, F, id, M);
+ NATIVE_SLOTS_LIST(NATIVE_CASE)
+#undef NATIVE_CASE
+ case Kind::kTypeArguments:
+ return "TypeArguments";
+ case Kind::kCapturedVariable:
+ return "CapturedVariable";
+ case Kind::kDartField:
+ return "DartField";
+ default:
+ UNREACHABLE();
+ return nullptr;
+ }
+}
+
+bool Slot::KindFromCString(const char* str, Kind* out) {
+ ASSERT(str != nullptr && out != nullptr);
+#define NATIVE_CASE(C, F, id, M) \
+ if (strcmp(str, NATIVE_TO_STR(C, F, id, M)) == 0) { \
+ *out = NATIVE_SLOT_NAME(C, F, id, M); \
+ return true; \
+ }
+ NATIVE_SLOTS_LIST(NATIVE_CASE)
+#undef NATIVE_CASE
+ if (strcmp(str, "TypeArguments") == 0) {
+ *out = Kind::kTypeArguments;
+ return true;
+ }
+ if (strcmp(str, "CapturedVariable") == 0) {
+ *out = Kind::kCapturedVariable;
+ return true;
+ }
+ if (strcmp(str, "DartField") == 0) {
+ *out = Kind::kDartField;
+ return true;
+ }
+ return false;
+}
+
+#undef NATIVE_TO_STR
+#undef NATIVE_SLOT_NAME
+
const Slot& Slot::GetNativeSlot(Kind kind) {
// There is a fixed statically known number of native slots so we cache
// them statically.
diff --git a/runtime/vm/compiler/backend/slot.h b/runtime/vm/compiler/backend/slot.h
index 46141a9..361532b 100644
--- a/runtime/vm/compiler/backend/slot.h
+++ b/runtime/vm/compiler/backend/slot.h
@@ -102,6 +102,9 @@
};
// clang-format on
+ static const char* KindToCString(Kind k);
+ static bool KindFromCString(const char* str, Kind* k);
+
// Returns a slot that represents length field for the given [array_cid].
static const Slot& GetLengthFieldForArrayCid(intptr_t array_cid);
@@ -144,7 +147,7 @@
bool is_immutable() const { return IsImmutableBit::decode(flags_); }
intptr_t nullable_cid() const { return cid_; }
- intptr_t is_nullable() const { return IsNullableBit::decode(flags_); }
+ bool is_nullable() const { return IsNullableBit::decode(flags_); }
// Returns true if properties of this slot were based on the guarded state
// of the corresponding Dart field.
@@ -171,6 +174,8 @@
bool IsIdentical(const Slot& other) const { return this == &other; }
private:
+ friend class FlowGraphDeserializer; // For GetNativeSlot.
+
Slot(Kind kind,
int8_t bits,
int16_t cid,
diff --git a/runtime/vm/compiler/backend/type_propagator.cc b/runtime/vm/compiler/backend/type_propagator.cc
index 7043c36..bbf2391 100644
--- a/runtime/vm/compiler/backend/type_propagator.cc
+++ b/runtime/vm/compiler/backend/type_propagator.cc
@@ -662,7 +662,7 @@
}
CompileType CompileType::Int32() {
-#if defined(TARGET_ARCH_X64) || defined(TARGET_ARCH_ARM64)
+#if defined(TARGET_ARCH_IS_64_BIT)
return FromCid(kSmiCid);
#else
return Int();
@@ -1066,12 +1066,6 @@
return CompileType(CompileType::kNonNullable, cid, &type);
}
- if (function.HasBytecode() &&
- graph_entry->parsed_function().scope() == nullptr) {
- // TODO(alexmarkov): Consider adding scope.
- return CompileType::Dynamic();
- }
-
const bool is_unchecked_entry_param =
graph_entry->unchecked_entry() == block_;
@@ -1079,8 +1073,13 @@
LocalScope* scope = graph_entry->parsed_function().scope();
// Note: in catch-blocks we have ParameterInstr for each local variable
// not only for normal parameters.
- if (index() < scope->num_variables()) {
- const LocalVariable* param = scope->VariableAt(index());
+ const LocalVariable* param = nullptr;
+ if (scope != nullptr && (index() < scope->num_variables())) {
+ param = scope->VariableAt(index());
+ } else if (index() < function.NumParameters()) {
+ param = graph_entry->parsed_function().RawParameterVariable(index());
+ }
+ if (param != nullptr) {
CompileType* inferred_type = NULL;
if (!block_->IsCatchBlockEntry()) {
inferred_type = param->parameter_type();
diff --git a/runtime/vm/compiler/call_specializer.cc b/runtime/vm/compiler/call_specializer.cc
index 0626731..5e93802 100644
--- a/runtime/vm/compiler/call_specializer.cc
+++ b/runtime/vm/compiler/call_specializer.cc
@@ -40,131 +40,19 @@
return (cid == kSmiCid) || (cid == kDoubleCid);
}
-static bool ClassIdIsOneOf(intptr_t class_id,
- const GrowableArray<intptr_t>& class_ids) {
- for (intptr_t i = 0; i < class_ids.length(); i++) {
- ASSERT(class_ids[i] != kIllegalCid);
- if (class_ids[i] == class_id) {
- return true;
- }
- }
- return false;
-}
-
-// Returns true if ICData tests two arguments and all ICData cids are in the
-// required sets 'receiver_class_ids' or 'argument_class_ids', respectively.
-static bool ICDataHasOnlyReceiverArgumentClassIds(
- const ICData& ic_data,
- const GrowableArray<intptr_t>& receiver_class_ids,
- const GrowableArray<intptr_t>& argument_class_ids) {
- if (ic_data.NumArgsTested() != 2) {
- return false;
- }
- const intptr_t len = ic_data.NumberOfChecks();
- GrowableArray<intptr_t> class_ids;
- for (intptr_t i = 0; i < len; i++) {
- if (ic_data.IsUsedAt(i)) {
- ic_data.GetClassIdsAt(i, &class_ids);
- ASSERT(class_ids.length() == 2);
- if (!ClassIdIsOneOf(class_ids[0], receiver_class_ids) ||
- !ClassIdIsOneOf(class_ids[1], argument_class_ids)) {
- return false;
- }
- }
- }
- return true;
-}
-
-static bool ICDataHasReceiverArgumentClassIds(const ICData& ic_data,
- intptr_t receiver_class_id,
- intptr_t argument_class_id) {
- if (ic_data.NumArgsTested() != 2) {
- return false;
- }
- const intptr_t len = ic_data.NumberOfChecks();
- for (intptr_t i = 0; i < len; i++) {
- if (ic_data.IsUsedAt(i)) {
- GrowableArray<intptr_t> class_ids;
- ic_data.GetClassIdsAt(i, &class_ids);
- ASSERT(class_ids.length() == 2);
- if ((class_ids[0] == receiver_class_id) &&
- (class_ids[1] == argument_class_id)) {
- return true;
- }
- }
- }
- return false;
-}
-
-static bool HasOnlyOneSmi(const ICData& ic_data) {
- return (ic_data.NumberOfUsedChecks() == 1) &&
- ic_data.HasReceiverClassId(kSmiCid);
-}
-
-static bool HasOnlySmiOrMint(const ICData& ic_data) {
- if (ic_data.NumberOfUsedChecks() == 1) {
- return ic_data.HasReceiverClassId(kSmiCid) ||
- ic_data.HasReceiverClassId(kMintCid);
- }
- return (ic_data.NumberOfUsedChecks() == 2) &&
- ic_data.HasReceiverClassId(kSmiCid) &&
- ic_data.HasReceiverClassId(kMintCid);
-}
-
-bool CallSpecializer::HasOnlyTwoOf(const ICData& ic_data, intptr_t cid) {
- if (ic_data.NumberOfUsedChecks() != 1) {
- return false;
- }
- GrowableArray<intptr_t> first;
- GrowableArray<intptr_t> second;
- ic_data.GetUsedCidsForTwoArgs(&first, &second);
- return (first[0] == cid) && (second[0] == cid);
-}
-
-// Returns false if the ICData contains anything other than the 4 combinations
-// of Mint and Smi for the receiver and argument classes.
-static bool HasTwoMintOrSmi(const ICData& ic_data) {
- GrowableArray<intptr_t> first;
- GrowableArray<intptr_t> second;
- ic_data.GetUsedCidsForTwoArgs(&first, &second);
- for (intptr_t i = 0; i < first.length(); i++) {
- if ((first[i] != kSmiCid) && (first[i] != kMintCid)) {
- return false;
- }
- if ((second[i] != kSmiCid) && (second[i] != kMintCid)) {
- return false;
- }
- }
- return true;
-}
-
-// Returns false if the ICData contains anything other than the 4 combinations
-// of Double and Smi for the receiver and argument classes.
-static bool HasTwoDoubleOrSmi(const ICData& ic_data) {
- GrowableArray<intptr_t> class_ids(2);
- class_ids.Add(kSmiCid);
- class_ids.Add(kDoubleCid);
- return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids);
-}
-
-static bool HasOnlyOneDouble(const ICData& ic_data) {
- return (ic_data.NumberOfUsedChecks() == 1) &&
- ic_data.HasReceiverClassId(kDoubleCid);
-}
-
-static bool ShouldSpecializeForDouble(const ICData& ic_data) {
+static bool ShouldSpecializeForDouble(const BinaryFeedback& binary_feedback) {
// Don't specialize for double if we can't unbox them.
if (!CanUnboxDouble()) {
return false;
}
// Unboxed double operation can't handle case of two smis.
- if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
+ if (binary_feedback.IncludesOperands(kSmiCid)) {
return false;
}
- // Check that it have seen only smis and doubles.
- return HasTwoDoubleOrSmi(ic_data);
+ // Check that the call site has seen only smis and doubles.
+ return binary_feedback.OperandsAreSmiOrDouble();
}
// Optimize instance calls using ICData.
@@ -208,7 +96,8 @@
bool CallSpecializer::TryCreateICData(InstanceCallInstr* call) {
ASSERT(call->HasICData());
- if (call->ic_data()->NumberOfUsedChecks() > 0) {
+
+ if (call->Targets().length() > 0) {
// This occurs when an instance call has too many checks, will be converted
// to megamorphic call.
return false;
@@ -272,17 +161,14 @@
return false;
}
- // Create new ICData, do not modify the one attached to the instruction
- // since it is attached to the assembly instruction itself.
- const ICData& ic_data = ICData::ZoneHandle(
- Z, ICData::NewFrom(*call->ic_data(), class_ids.length()));
- if (class_ids.length() > 1) {
- ic_data.AddCheck(class_ids, function);
- } else {
- ASSERT(class_ids.length() == 1);
- ic_data.AddReceiverCheck(class_ids[0], function);
+ // Update the CallTargets attached to the instruction with our speculative
+ // target. The next round of CallSpecializer::VisitInstanceCall will make
+ // use of this.
+ call->SetTargets(CallTargets::CreateMonomorphic(Z, class_ids[0], function));
+ if (class_ids.length() == 2) {
+ call->SetBinaryFeedback(
+ BinaryFeedback::CreateMonomorphic(Z, class_ids[0], class_ids[1]));
}
- call->set_ic_data(&ic_data);
return true;
}
@@ -365,11 +251,11 @@
}
void CallSpecializer::AddChecksForArgNr(InstanceCallInstr* call,
- Definition* instr,
+ Definition* argument,
int argument_number) {
const Cids* cids =
- Cids::CreateAndExpand(Z, *call->ic_data(), argument_number);
- AddCheckClass(instr, *cids, call->deopt_id(), call->env(), call);
+ Cids::CreateForArgument(zone(), call->BinaryFeedback(), argument_number);
+ AddCheckClass(argument, *cids, call->deopt_id(), call->env(), call);
}
void CallSpecializer::AddCheckNull(Value* to_check,
@@ -390,30 +276,12 @@
}
}
-static bool ArgIsAlways(intptr_t cid,
- const ICData& ic_data,
- intptr_t arg_number) {
- ASSERT(ic_data.NumArgsTested() > arg_number);
- if (ic_data.NumberOfUsedChecks() == 0) {
- return false;
+bool CallSpecializer::TryReplaceWithIndexedOp(InstanceCallInstr* call) {
+ if (call->Targets().IsMonomorphic()) {
+ return FlowGraphInliner::TryReplaceInstanceCallWithInline(
+ flow_graph_, current_iterator(), call, speculative_policy_);
}
- const intptr_t num_checks = ic_data.NumberOfChecks();
- for (intptr_t i = 0; i < num_checks; i++) {
- if (ic_data.IsUsedAt(i) && ic_data.GetClassIdAt(i, arg_number) != cid) {
- return false;
- }
- }
- return true;
-}
-
-bool CallSpecializer::TryReplaceWithIndexedOp(InstanceCallInstr* call,
- const ICData* unary_checks) {
- // Check for monomorphic IC data.
- if (!unary_checks->NumberOfChecksIs(1)) {
- return false;
- }
- return FlowGraphInliner::TryReplaceInstanceCallWithInline(
- flow_graph_, current_iterator(), call, speculative_policy_);
+ return false;
}
// Return true if d is a string of length one (a constant or result from
@@ -436,7 +304,7 @@
// E.g., detect str[x] == "x"; and use an integer comparison of char-codes.
bool CallSpecializer::TryStringLengthOneEquality(InstanceCallInstr* call,
Token::Kind op_kind) {
- ASSERT(HasOnlyTwoOf(*call->ic_data(), kOneByteStringCid));
+ ASSERT(call->BinaryFeedback().OperandsAre(kOneByteStringCid));
// Check that left and right are length one strings (either string constants
// or results of string-from-char-code.
Definition* left = call->ArgumentAt(0);
@@ -516,8 +384,7 @@
bool CallSpecializer::TryReplaceWithEqualityOp(InstanceCallInstr* call,
Token::Kind op_kind) {
- const ICData& ic_data = *call->ic_data();
- ASSERT(ic_data.NumArgsTested() == 2);
+ const BinaryFeedback& binary_feedback = call->BinaryFeedback();
ASSERT(call->type_args_len() == 0);
ASSERT(call->ArgumentCount() == 2);
@@ -525,9 +392,9 @@
Definition* const right = call->ArgumentAt(1);
intptr_t cid = kIllegalCid;
- if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) {
+ if (binary_feedback.OperandsAre(kOneByteStringCid)) {
return TryStringLengthOneEquality(call, op_kind);
- } else if (HasOnlyTwoOf(ic_data, kSmiCid)) {
+ } else if (binary_feedback.OperandsAre(kSmiCid)) {
InsertBefore(call,
new (Z) CheckSmiInstr(new (Z) Value(left), call->deopt_id(),
call->token_pos()),
@@ -537,15 +404,15 @@
call->token_pos()),
call->env(), FlowGraph::kEffect);
cid = kSmiCid;
- } else if (HasTwoMintOrSmi(ic_data) &&
+ } else if (binary_feedback.OperandsAreSmiOrMint() &&
FlowGraphCompiler::SupportsUnboxedInt64()) {
cid = kMintCid;
- } else if (HasTwoDoubleOrSmi(ic_data) && CanUnboxDouble()) {
+ } else if (binary_feedback.OperandsAreSmiOrDouble() && CanUnboxDouble()) {
// Use double comparison.
if (SmiFitsInDouble()) {
cid = kDoubleCid;
} else {
- if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
+ if (binary_feedback.IncludesOperands(kSmiCid)) {
// We cannot use double comparison on two smis. Need polymorphic
// call.
return false;
@@ -562,11 +429,7 @@
// Check if ICDData contains checks with Smi/Null combinations. In that case
// we can still emit the optimized Smi equality operation but need to add
// checks for null or Smi.
- GrowableArray<intptr_t> smi_or_null(2);
- smi_or_null.Add(kSmiCid);
- smi_or_null.Add(kNullCid);
- if (ICDataHasOnlyReceiverArgumentClassIds(ic_data, smi_or_null,
- smi_or_null)) {
+ if (binary_feedback.OperandsAreSmiOrNull()) {
AddChecksForArgNr(call, left, /* arg_number = */ 0);
AddChecksForArgNr(call, right, /* arg_number = */ 1);
@@ -599,16 +462,15 @@
bool CallSpecializer::TryReplaceWithRelationalOp(InstanceCallInstr* call,
Token::Kind op_kind) {
- const ICData& ic_data = *call->ic_data();
- ASSERT(ic_data.NumArgsTested() == 2);
-
ASSERT(call->type_args_len() == 0);
ASSERT(call->ArgumentCount() == 2);
+
+ const BinaryFeedback& binary_feedback = call->BinaryFeedback();
Definition* left = call->ArgumentAt(0);
Definition* right = call->ArgumentAt(1);
intptr_t cid = kIllegalCid;
- if (HasOnlyTwoOf(ic_data, kSmiCid)) {
+ if (binary_feedback.OperandsAre(kSmiCid)) {
InsertBefore(call,
new (Z) CheckSmiInstr(new (Z) Value(left), call->deopt_id(),
call->token_pos()),
@@ -618,15 +480,15 @@
call->token_pos()),
call->env(), FlowGraph::kEffect);
cid = kSmiCid;
- } else if (HasTwoMintOrSmi(ic_data) &&
+ } else if (binary_feedback.OperandsAreSmiOrMint() &&
FlowGraphCompiler::SupportsUnboxedInt64()) {
cid = kMintCid;
- } else if (HasTwoDoubleOrSmi(ic_data) && CanUnboxDouble()) {
+ } else if (binary_feedback.OperandsAreSmiOrDouble() && CanUnboxDouble()) {
// Use double comparison.
if (SmiFitsInDouble()) {
cid = kDoubleCid;
} else {
- if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
+ if (binary_feedback.IncludesOperands(kSmiCid)) {
// We cannot use double comparison on two smis. Need polymorphic
// call.
return false;
@@ -654,31 +516,33 @@
Token::Kind op_kind) {
intptr_t operands_type = kIllegalCid;
ASSERT(call->HasICData());
- const ICData& ic_data = *call->ic_data();
+ const BinaryFeedback& binary_feedback = call->BinaryFeedback();
switch (op_kind) {
case Token::kADD:
case Token::kSUB:
case Token::kMUL:
- if (HasOnlyTwoOf(ic_data, kSmiCid)) {
+ if (binary_feedback.OperandsAre(kSmiCid)) {
// Don't generate smi code if the IC data is marked because
// of an overflow.
- operands_type = ic_data.HasDeoptReason(ICData::kDeoptBinarySmiOp)
- ? kMintCid
- : kSmiCid;
- } else if (HasTwoMintOrSmi(ic_data) &&
+ operands_type =
+ call->ic_data()->HasDeoptReason(ICData::kDeoptBinarySmiOp)
+ ? kMintCid
+ : kSmiCid;
+ } else if (binary_feedback.OperandsAreSmiOrMint() &&
FlowGraphCompiler::SupportsUnboxedInt64()) {
// Don't generate mint code if the IC data is marked because of an
// overflow.
- if (ic_data.HasDeoptReason(ICData::kDeoptBinaryInt64Op)) return false;
+ if (call->ic_data()->HasDeoptReason(ICData::kDeoptBinaryInt64Op))
+ return false;
operands_type = kMintCid;
- } else if (ShouldSpecializeForDouble(ic_data)) {
+ } else if (ShouldSpecializeForDouble(binary_feedback)) {
operands_type = kDoubleCid;
- } else if (HasOnlyTwoOf(ic_data, kFloat32x4Cid)) {
+ } else if (binary_feedback.OperandsAre(kFloat32x4Cid)) {
operands_type = kFloat32x4Cid;
- } else if (HasOnlyTwoOf(ic_data, kInt32x4Cid)) {
+ } else if (binary_feedback.OperandsAre(kInt32x4Cid)) {
ASSERT(op_kind != Token::kMUL); // Int32x4 doesn't have a multiply op.
operands_type = kInt32x4Cid;
- } else if (HasOnlyTwoOf(ic_data, kFloat64x2Cid)) {
+ } else if (binary_feedback.OperandsAre(kFloat64x2Cid)) {
operands_type = kFloat64x2Cid;
} else {
return false;
@@ -686,12 +550,12 @@
break;
case Token::kDIV:
if (!FlowGraphCompiler::SupportsHardwareDivision()) return false;
- if (ShouldSpecializeForDouble(ic_data) ||
- HasOnlyTwoOf(ic_data, kSmiCid)) {
+ if (ShouldSpecializeForDouble(binary_feedback) ||
+ binary_feedback.OperandsAre(kSmiCid)) {
operands_type = kDoubleCid;
- } else if (HasOnlyTwoOf(ic_data, kFloat32x4Cid)) {
+ } else if (binary_feedback.OperandsAre(kFloat32x4Cid)) {
operands_type = kFloat32x4Cid;
- } else if (HasOnlyTwoOf(ic_data, kFloat64x2Cid)) {
+ } else if (binary_feedback.OperandsAre(kFloat64x2Cid)) {
operands_type = kFloat64x2Cid;
} else {
return false;
@@ -700,11 +564,11 @@
case Token::kBIT_AND:
case Token::kBIT_OR:
case Token::kBIT_XOR:
- if (HasOnlyTwoOf(ic_data, kSmiCid)) {
+ if (binary_feedback.OperandsAre(kSmiCid)) {
operands_type = kSmiCid;
- } else if (HasTwoMintOrSmi(ic_data)) {
+ } else if (binary_feedback.OperandsAreSmiOrMint()) {
operands_type = kMintCid;
- } else if (HasOnlyTwoOf(ic_data, kInt32x4Cid)) {
+ } else if (binary_feedback.OperandsAre(kInt32x4Cid)) {
operands_type = kInt32x4Cid;
} else {
return false;
@@ -712,22 +576,22 @@
break;
case Token::kSHR:
case Token::kSHL:
- if (HasOnlyTwoOf(ic_data, kSmiCid)) {
+ if (binary_feedback.OperandsAre(kSmiCid)) {
// Left shift may overflow from smi into mint or big ints.
// Don't generate smi code if the IC data is marked because
// of an overflow.
- if (ic_data.HasDeoptReason(ICData::kDeoptBinaryInt64Op)) {
+ if (call->ic_data()->HasDeoptReason(ICData::kDeoptBinaryInt64Op)) {
return false;
}
- operands_type = ic_data.HasDeoptReason(ICData::kDeoptBinarySmiOp)
- ? kMintCid
- : kSmiCid;
- } else if (HasTwoMintOrSmi(ic_data) &&
- HasOnlyOneSmi(ICData::Handle(
- Z, ic_data.AsUnaryClassChecksForArgNr(1)))) {
+ operands_type =
+ call->ic_data()->HasDeoptReason(ICData::kDeoptBinarySmiOp)
+ ? kMintCid
+ : kSmiCid;
+ } else if (binary_feedback.OperandsAreSmiOrMint() &&
+ binary_feedback.ArgumentIs(kSmiCid)) {
// Don't generate mint code if the IC data is marked because of an
// overflow.
- if (ic_data.HasDeoptReason(ICData::kDeoptBinaryInt64Op)) {
+ if (call->ic_data()->HasDeoptReason(ICData::kDeoptBinaryInt64Op)) {
return false;
}
// Check for smi/mint << smi or smi/mint >> smi.
@@ -739,8 +603,8 @@
case Token::kMOD:
case Token::kTRUNCDIV:
if (!FlowGraphCompiler::SupportsHardwareDivision()) return false;
- if (HasOnlyTwoOf(ic_data, kSmiCid)) {
- if (ic_data.HasDeoptReason(ICData::kDeoptBinarySmiOp)) {
+ if (binary_feedback.OperandsAre(kSmiCid)) {
+ if (call->ic_data()->HasDeoptReason(ICData::kDeoptBinarySmiOp)) {
return false;
}
operands_type = kSmiCid;
@@ -844,7 +708,7 @@
ASSERT(call->ArgumentCount() == 1);
Definition* input = call->ArgumentAt(0);
Definition* unary_op = NULL;
- if (HasOnlyOneSmi(*call->ic_data())) {
+ if (call->Targets().ReceiverIs(kSmiCid)) {
InsertBefore(call,
new (Z) CheckSmiInstr(new (Z) Value(input), call->deopt_id(),
call->token_pos()),
@@ -852,11 +716,11 @@
unary_op = new (Z)
UnarySmiOpInstr(op_kind, new (Z) Value(input), call->deopt_id());
} else if ((op_kind == Token::kBIT_NOT) &&
- HasOnlySmiOrMint(*call->ic_data()) &&
+ call->Targets().ReceiverIsSmiOrMint() &&
FlowGraphCompiler::SupportsUnboxedInt64()) {
unary_op = new (Z)
UnaryInt64OpInstr(op_kind, new (Z) Value(input), call->deopt_id());
- } else if (HasOnlyOneDouble(*call->ic_data()) &&
+ } else if (call->Targets().ReceiverIs(kDoubleCid) &&
(op_kind == Token::kNEGATE) && CanUnboxDouble()) {
AddReceiverCheck(call);
unary_op = new (Z) UnaryDoubleOpInstr(Token::kNEGATE, new (Z) Value(input),
@@ -869,33 +733,16 @@
return true;
}
-// Lookup field with the given name in the given class.
-RawField* CallSpecializer::GetField(intptr_t class_id,
- const String& field_name) {
- Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id));
- Field& field = Field::Handle(Z);
- while (!cls.IsNull()) {
- field = cls.LookupInstanceField(field_name);
- if (!field.IsNull()) {
- return should_clone_fields_ ? field.CloneFromOriginal() : field.raw();
- }
- cls = cls.SuperClass();
- }
- return Field::null();
-}
-
bool CallSpecializer::TryInlineImplicitInstanceGetter(InstanceCallInstr* call) {
- ASSERT(call->HasICData());
- const ICData& ic_data = *call->ic_data();
- ASSERT(ic_data.HasOneTarget());
- GrowableArray<intptr_t> class_ids;
- ic_data.GetClassIdsAt(0, &class_ids);
- ASSERT(class_ids.length() == 1);
+ const CallTargets& targets = call->Targets();
+ ASSERT(targets.HasSingleTarget());
+
// Inline implicit instance getter.
- const String& field_name =
- String::Handle(Z, Field::NameFromGetter(call->function_name()));
- const Field& field = Field::ZoneHandle(Z, GetField(class_ids[0], field_name));
+ Field& field = Field::ZoneHandle(Z, targets.FirstTarget().accessor_field());
ASSERT(!field.IsNull());
+ if (should_clone_fields_) {
+ field = field.CloneFromOriginal();
+ }
switch (
flow_graph()->CheckForInstanceCall(call, RawFunction::kImplicitGetter)) {
@@ -935,35 +782,23 @@
}
}
-bool CallSpecializer::TryInlineInstanceSetter(InstanceCallInstr* instr,
- const ICData& unary_ic_data) {
- ASSERT(!unary_ic_data.NumberOfChecksIs(0) &&
- (unary_ic_data.NumArgsTested() == 1));
- ASSERT(instr->HasICData());
- if (unary_ic_data.NumberOfChecksIs(0)) {
- // No type feedback collected.
- return false;
- }
- if (!unary_ic_data.HasOneTarget()) {
+bool CallSpecializer::TryInlineInstanceSetter(InstanceCallInstr* instr) {
+ const CallTargets& targets = instr->Targets();
+ if (!targets.HasSingleTarget()) {
// Polymorphic sites are inlined like normal method calls by conventional
// inlining.
return false;
}
- Function& target = Function::Handle(Z);
- intptr_t class_id;
- unary_ic_data.GetOneClassCheckAt(0, &class_id, &target);
+ const Function& target = targets.FirstTarget();
if (target.kind() != RawFunction::kImplicitSetter) {
// Non-implicit setter are inlined like normal method calls.
return false;
}
- // Inline implicit instance setter.
- String& field_name = String::Handle(Z, instr->function_name().raw());
- if (Function::IsDynamicInvocationForwarderName(field_name)) {
- field_name = Function::DemangleDynamicInvocationForwarderName(field_name);
- }
- field_name = Field::NameFromSetter(field_name);
- const Field& field = Field::ZoneHandle(Z, GetField(class_id, field_name));
+ Field& field = Field::ZoneHandle(Z, target.accessor_field());
ASSERT(!field.IsNull());
+ if (should_clone_fields_) {
+ field = field.CloneFromOriginal();
+ }
switch (
flow_graph()->CheckForInstanceCall(instr, RawFunction::kImplicitSetter)) {
@@ -984,10 +819,10 @@
// True if we can use unchecked entry into the setter.
bool is_unchecked_call = false;
if (!FLAG_precompiled_mode) {
- if (unary_ic_data.NumberOfChecks() == 1 &&
- unary_ic_data.GetExactnessAt(0).IsExact()) {
- if (unary_ic_data.GetExactnessAt(0).IsTriviallyExact()) {
- flow_graph()->AddExactnessGuard(instr, unary_ic_data.GetCidAt(0));
+ if (targets.IsMonomorphic() && targets.MonomorphicExactness().IsExact()) {
+ if (targets.MonomorphicExactness().IsTriviallyExact()) {
+ flow_graph()->AddExactnessGuard(instr,
+ targets.MonomorphicReceiverCid());
}
is_unchecked_call = true;
}
@@ -1109,20 +944,13 @@
// Only unique implicit instance getters can be currently handled.
bool CallSpecializer::TryInlineInstanceGetter(InstanceCallInstr* call) {
- ASSERT(call->HasICData());
- const ICData& ic_data = *call->ic_data();
- if (ic_data.NumberOfUsedChecks() == 0) {
- // No type feedback collected.
- return false;
- }
-
- if (!ic_data.HasOneTarget()) {
+ const CallTargets& targets = call->Targets();
+ if (!targets.HasSingleTarget()) {
// Polymorphic sites are inlined like normal methods by conventional
// inlining in FlowGraphInliner.
return false;
}
-
- const Function& target = Function::Handle(Z, ic_data.GetTargetAt(0));
+ const Function& target = targets.FirstTarget();
if (target.kind() != RawFunction::kImplicitGetter) {
// Non-implicit getters are inlined like normal methods by conventional
// inlining in FlowGraphInliner.
@@ -1148,28 +976,26 @@
// Inline only simple, frequently called core library methods.
bool CallSpecializer::TryInlineInstanceMethod(InstanceCallInstr* call) {
- ASSERT(call->HasICData());
- const ICData& ic_data = *call->ic_data();
- if (ic_data.NumberOfUsedChecks() != 1) {
+ const CallTargets& targets = call->Targets();
+ if (!targets.IsMonomorphic()) {
// No type feedback collected or multiple receivers/targets found.
return false;
}
- Function& target = Function::Handle(Z);
- GrowableArray<intptr_t> class_ids;
- ic_data.GetCheckAt(0, &class_ids, &target);
+ const Function& target = targets.FirstTarget();
+ intptr_t receiver_cid = targets.MonomorphicReceiverCid();
MethodRecognizer::Kind recognized_kind =
MethodRecognizer::RecognizeKind(target);
if (CanUnboxDouble() &&
(recognized_kind == MethodRecognizer::kIntegerToDouble)) {
- if (class_ids[0] == kSmiCid) {
+ if (receiver_cid == kSmiCid) {
AddReceiverCheck(call);
ReplaceCall(call,
new (Z) SmiToDoubleInstr(new (Z) Value(call->ArgumentAt(0)),
call->token_pos()));
return true;
- } else if ((class_ids[0] == kMintCid) && CanConvertInt64ToDouble()) {
+ } else if ((receiver_cid == kMintCid) && CanConvertInt64ToDouble()) {
AddReceiverCheck(call);
ReplaceCall(call,
new (Z) Int64ToDoubleInstr(new (Z) Value(call->ArgumentAt(0)),
@@ -1178,7 +1004,7 @@
}
}
- if (class_ids[0] == kDoubleCid) {
+ if (receiver_cid == kDoubleCid) {
if (!CanUnboxDouble()) {
return false;
}
@@ -1281,7 +1107,7 @@
: Class::IsSubtypeOf(cls, Object::null_type_arguments(), type_class,
Object::null_type_arguments(), Heap::kOld);
results->Add(cls.id());
- results->Add(is_subtype);
+ results->Add(static_cast<intptr_t>(is_subtype));
if (prev.IsNull()) {
prev = Bool::Get(is_subtype).raw();
} else {
@@ -1480,22 +1306,20 @@
MethodRecognizer::Kind recognized_kind =
MethodRecognizer::RecognizeKind(call->function());
+ const CallTargets& targets = call->Targets();
+ const BinaryFeedback& binary_feedback = call->BinaryFeedback();
switch (recognized_kind) {
case MethodRecognizer::kMathMin:
case MethodRecognizer::kMathMax: {
// We can handle only monomorphic min/max call sites with both arguments
// being either doubles or smis.
- if (CanUnboxDouble() && call->HasICData() &&
- call->ic_data()->NumberOfChecksIs(1) &&
+ if (CanUnboxDouble() && targets.IsMonomorphic() &&
(call->FirstArgIndex() == 0)) {
- const ICData& ic_data = *call->ic_data();
intptr_t result_cid = kIllegalCid;
- if (ICDataHasReceiverArgumentClassIds(ic_data, kDoubleCid,
- kDoubleCid)) {
+ if (binary_feedback.IncludesOperands(kDoubleCid)) {
result_cid = kDoubleCid;
- } else if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid,
- kSmiCid)) {
+ } else if (binary_feedback.IncludesOperands(kSmiCid)) {
result_cid = kSmiCid;
}
if (result_cid != kIllegalCid) {
@@ -1503,8 +1327,7 @@
recognized_kind, new (Z) Value(call->ArgumentAt(0)),
new (Z) Value(call->ArgumentAt(1)), call->deopt_id(),
result_cid);
- const Cids* cids =
- Cids::CreateAndExpand(Z, ic_data, /* argument_number =*/0);
+ const Cids* cids = Cids::CreateMonomorphic(Z, result_cid);
AddCheckClass(min_max->left()->definition(), *cids,
call->deopt_id(), call->env(), call);
AddCheckClass(min_max->right()->definition(), *cids,
@@ -1516,17 +1339,16 @@
break;
}
case MethodRecognizer::kDoubleFromInteger: {
- if (call->HasICData() && call->ic_data()->NumberOfChecksIs(1) &&
+ if (call->HasICData() && targets.IsMonomorphic() &&
(call->FirstArgIndex() == 0)) {
- const ICData& ic_data = *call->ic_data();
if (CanUnboxDouble()) {
- if (ArgIsAlways(kSmiCid, ic_data, 1)) {
+ if (binary_feedback.ArgumentIs(kSmiCid)) {
Definition* arg = call->ArgumentAt(1);
AddCheckSmi(arg, call->deopt_id(), call->env(), call);
ReplaceCall(call, new (Z) SmiToDoubleInstr(new (Z) Value(arg),
call->token_pos()));
return;
- } else if (ArgIsAlways(kMintCid, ic_data, 1) &&
+ } else if (binary_feedback.ArgumentIs(kMintCid) &&
CanConvertInt64ToDouble()) {
Definition* arg = call->ArgumentAt(1);
ReplaceCall(call, new (Z) Int64ToDoubleInstr(new (Z) Value(arg),
@@ -1569,7 +1391,7 @@
bool result) {
if (!CidTestResultsContains(*results, test_cid)) {
results->Add(test_cid);
- results->Add(result);
+ results->Add(static_cast<intptr_t>(result));
}
}
@@ -1605,7 +1427,7 @@
(*results)[i] = (*results)[i - 2];
}
(*results)[0] = kSmiCid;
- (*results)[1] = smi_is_subtype;
+ (*results)[1] = static_cast<intptr_t>(smi_is_subtype);
}
ASSERT(type.IsInstantiated());
diff --git a/runtime/vm/compiler/call_specializer.h b/runtime/vm/compiler/call_specializer.h
index 2b1e4ee..78e442f 100644
--- a/runtime/vm/compiler/call_specializer.h
+++ b/runtime/vm/compiler/call_specializer.h
@@ -67,8 +67,7 @@
Zone* zone() const { return flow_graph_->zone(); }
const Function& function() const { return flow_graph_->function(); }
- bool TryReplaceWithIndexedOp(InstanceCallInstr* call,
- const ICData* unary_checks);
+ bool TryReplaceWithIndexedOp(InstanceCallInstr* call);
bool TryReplaceWithBinaryOp(InstanceCallInstr* call, Token::Kind op_kind);
bool TryReplaceWithUnaryOp(InstanceCallInstr* call, Token::Kind op_kind);
@@ -77,8 +76,7 @@
bool TryReplaceWithRelationalOp(InstanceCallInstr* call, Token::Kind op_kind);
bool TryInlineInstanceGetter(InstanceCallInstr* call);
- bool TryInlineInstanceSetter(InstanceCallInstr* call,
- const ICData& unary_ic_data);
+ bool TryInlineInstanceSetter(InstanceCallInstr* call);
bool TryInlineInstanceMethod(InstanceCallInstr* call);
void ReplaceWithInstanceOf(InstanceCallInstr* instr);
@@ -93,8 +91,8 @@
// Add a class check for the call's first argument (receiver).
void AddReceiverCheck(InstanceCallInstr* call) {
- AddChecksForArgNr(call, call->Receiver()->definition(),
- /* argument_number = */ 0);
+ AddCheckClass(call->Receiver()->definition(), call->Targets(),
+ call->deopt_id(), call->env(), call);
}
// Insert a null check if needed.
@@ -107,8 +105,6 @@
// Attempt to build ICData for call using propagated class-ids.
virtual bool TryCreateICData(InstanceCallInstr* call);
- static bool HasOnlyTwoOf(const ICData& ic_data, intptr_t cid);
-
virtual bool TryReplaceInstanceOfWithRangeCheck(InstanceCallInstr* call,
const AbstractType& type);
@@ -143,7 +139,7 @@
// call, using the call's IC data to determine the check, and the call's
// deopt ID and deoptimization environment if the check fails.
void AddChecksForArgNr(InstanceCallInstr* call,
- Definition* instr,
+ Definition* argument,
int argument_number);
bool InlineSimdBinaryOp(InstanceCallInstr* call,
@@ -164,8 +160,6 @@
bool TryStringLengthOneEquality(InstanceCallInstr* call, Token::Kind op_kind);
- RawField* GetField(intptr_t class_id, const String& field_name);
-
void SpecializePolymorphicInstanceCall(PolymorphicInstanceCallInstr* call);
// Tries to add cid tests to 'results' so that no deoptimization is
diff --git a/runtime/vm/compiler/compiler_pass.cc b/runtime/vm/compiler/compiler_pass.cc
index 6aba24a..110498d 100644
--- a/runtime/vm/compiler/compiler_pass.cc
+++ b/runtime/vm/compiler/compiler_pass.cc
@@ -10,6 +10,7 @@
#include "vm/compiler/backend/branch_optimizer.h"
#include "vm/compiler/backend/constant_propagator.h"
#include "vm/compiler/backend/flow_graph_checker.h"
+#include "vm/compiler/backend/il_deserializer.h"
#include "vm/compiler/backend/il_printer.h"
#include "vm/compiler/backend/il_serializer.h"
#include "vm/compiler/backend/inliner.h"
@@ -55,6 +56,14 @@
"List of comma separated compilation passes flags. "
"Use -Name to disable a pass, Name to print IL after it. "
"Do --compiler-passes=help for more information.");
+DEFINE_FLAG(bool,
+ early_round_trip_serialization,
+ false,
+ "Perform early round trip serialization compiler pass.");
+DEFINE_FLAG(bool,
+ late_round_trip_serialization,
+ false,
+ "Perform late round trip serialization compiler pass.");
DECLARE_FLAG(bool, print_flow_graph);
DECLARE_FLAG(bool, print_flow_graph_optimized);
@@ -227,9 +236,47 @@
INVOKE_PASS(TryOptimizePatterns);
}
-void CompilerPass::RunPipeline(PipelineMode mode,
- CompilerPassState* pass_state) {
+FlowGraph* CompilerPass::RunForceOptimizedPipeline(
+ PipelineMode mode,
+ CompilerPassState* pass_state) {
INVOKE_PASS(ComputeSSA);
+ if (FLAG_early_round_trip_serialization) {
+ INVOKE_PASS(RoundTripSerialization);
+ }
+ INVOKE_PASS(TypePropagation);
+ INVOKE_PASS(Canonicalize);
+ INVOKE_PASS(BranchSimplify);
+ INVOKE_PASS(IfConvert);
+ INVOKE_PASS(ConstantPropagation);
+ INVOKE_PASS(TypePropagation);
+ INVOKE_PASS(WidenSmiToInt32);
+ INVOKE_PASS(SelectRepresentations);
+ INVOKE_PASS(TypePropagation);
+ INVOKE_PASS(TryCatchOptimization);
+ INVOKE_PASS(EliminateEnvironments);
+ INVOKE_PASS(EliminateDeadPhis);
+ INVOKE_PASS(Canonicalize);
+ INVOKE_PASS(WriteBarrierElimination);
+ INVOKE_PASS(FinalizeGraph);
+#if defined(DART_PRECOMPILER)
+ if (mode == kAOT) {
+ INVOKE_PASS(SerializeGraph);
+ }
+#endif
+ if (FLAG_late_round_trip_serialization) {
+ INVOKE_PASS(RoundTripSerialization);
+ }
+ INVOKE_PASS(AllocateRegisters);
+ INVOKE_PASS(ReorderBlocks);
+ return pass_state->flow_graph;
+}
+
+FlowGraph* CompilerPass::RunPipeline(PipelineMode mode,
+ CompilerPassState* pass_state) {
+ INVOKE_PASS(ComputeSSA);
+ if (FLAG_early_round_trip_serialization) {
+ INVOKE_PASS(RoundTripSerialization);
+ }
#if defined(DART_PRECOMPILER)
if (mode == kAOT) {
INVOKE_PASS(ApplyClassIds);
@@ -296,16 +343,21 @@
INVOKE_PASS(SerializeGraph);
}
#endif
+ if (FLAG_late_round_trip_serialization) {
+ INVOKE_PASS(RoundTripSerialization);
+ }
INVOKE_PASS(AllocateRegisters);
INVOKE_PASS(ReorderBlocks);
+ return pass_state->flow_graph;
}
-void CompilerPass::RunPipelineWithPasses(
+FlowGraph* CompilerPass::RunPipelineWithPasses(
CompilerPassState* state,
std::initializer_list<CompilerPass::Id> passes) {
for (auto pass_id : passes) {
passes_[pass_id]->Run(state);
}
+ return state->flow_graph;
}
COMPILER_PASS(ComputeSSA, {
@@ -519,6 +571,11 @@
});
#endif
+COMPILER_PASS(RoundTripSerialization, {
+ FlowGraphDeserializer::RoundTripSerialization(state);
+ ASSERT(state->flow_graph != nullptr);
+})
+
} // namespace dart
#endif // DART_PRECOMPILED_RUNTIME
diff --git a/runtime/vm/compiler/compiler_pass.h b/runtime/vm/compiler/compiler_pass.h
index b8475d1..2d9b6d0 100644
--- a/runtime/vm/compiler/compiler_pass.h
+++ b/runtime/vm/compiler/compiler_pass.h
@@ -40,6 +40,7 @@
V(OptimizeTypedDataAccesses) \
V(RangeAnalysis) \
V(ReorderBlocks) \
+ V(RoundTripSerialization) \
V(SelectRepresentations) \
V(SerializeGraph) \
V(SetOuterInliningId) \
@@ -76,7 +77,7 @@
}
Thread* const thread;
- FlowGraph* const flow_graph;
+ FlowGraph* flow_graph;
Precompiler* const precompiler;
int inlining_depth;
AllocationSinking* sinking;
@@ -146,12 +147,27 @@
static void RunInliningPipeline(PipelineMode mode, CompilerPassState* state);
- static void RunPipeline(PipelineMode mode, CompilerPassState* state);
-
- static void RunPipelineWithPasses(
+ // RunPipeline(WithPasses) may have the side effect of changing the FlowGraph
+ // stored in the CompilerPassState. However, existing callers may depend on
+ // the old invariant that the FlowGraph stored in the CompilerPassState was
+ // always updated, never entirely replaced.
+ //
+ // To make sure callers are updated properly, these methods also return
+ // the final FlowGraph and we add a check that callers use this result.
+ DART_WARN_UNUSED_RESULT
+ static FlowGraph* RunPipeline(PipelineMode mode, CompilerPassState* state);
+ DART_WARN_UNUSED_RESULT
+ static FlowGraph* RunPipelineWithPasses(
CompilerPassState* state,
std::initializer_list<CompilerPass::Id> passes);
+ // Pipeline which is used for "force-optimized" functions.
+ //
+ // Must not include speculative or inter-procedural optimizations.
+ DART_WARN_UNUSED_RESULT
+ static FlowGraph* RunForceOptimizedPipeline(PipelineMode mode,
+ CompilerPassState* state);
+
protected:
// This function executes the pass. If it returns true then
// we will run Canonicalize on the graph and execute the pass
diff --git a/runtime/vm/compiler/compiler_sources.gni b/runtime/vm/compiler/compiler_sources.gni
index 321a629..a722851 100644
--- a/runtime/vm/compiler/compiler_sources.gni
+++ b/runtime/vm/compiler/compiler_sources.gni
@@ -63,6 +63,8 @@
"backend/il_arm.cc",
"backend/il_arm64.cc",
"backend/il_dbc.cc",
+ "backend/il_deserializer.cc",
+ "backend/il_deserializer.h",
"backend/il_ia32.cc",
"backend/il_printer.cc",
"backend/il_printer.h",
diff --git a/runtime/vm/compiler/compiler_state.h b/runtime/vm/compiler/compiler_state.h
index 76326b2..be14d0b 100644
--- a/runtime/vm/compiler/compiler_state.h
+++ b/runtime/vm/compiler/compiler_state.h
@@ -115,15 +115,6 @@
// TODO(vegorov): disambiguate slots for different context IDs.
LocalVariable* GetDummyCapturedVariable(intptr_t context_id, intptr_t index);
- ZoneGrowableArray<const MegamorphicCache*>& cloned_megamorphic_caches() {
- if (cloned_megamorphic_caches_ == nullptr) {
- Zone* Z = Thread::Current()->zone();
- cloned_megamorphic_caches_ =
- new (Z) ZoneGrowableArray<const MegamorphicCache*>(Z, 12);
- }
- return *cloned_megamorphic_caches_;
- }
-
private:
CHA cha_;
intptr_t deopt_id_ = 0;
@@ -136,9 +127,6 @@
ZoneGrowableArray<ZoneGrowableArray<const Slot*>*>* dummy_slots_ = nullptr;
ZoneGrowableArray<LocalVariable*>* dummy_captured_vars_ = nullptr;
- ZoneGrowableArray<const MegamorphicCache*>* cloned_megamorphic_caches_ =
- nullptr;
-
CompilerState* previous_;
};
diff --git a/runtime/vm/compiler/ffi.cc b/runtime/vm/compiler/ffi.cc
index 5313922..3b3ce8c 100644
--- a/runtime/vm/compiler/ffi.cc
+++ b/runtime/vm/compiler/ffi.cc
@@ -210,6 +210,58 @@
#if !defined(TARGET_ARCH_DBC)
+RawFunction* NativeCallbackFunction(const Function& c_signature,
+ const Function& dart_target,
+ const Instance& exceptional_return) {
+ Thread* const thread = Thread::Current();
+ const int32_t callback_id = thread->AllocateFfiCallbackId();
+
+ // Create a new Function named '<target>_FfiCallback' and stick it in the
+ // 'dart:ffi' library. Note that these functions will never be invoked by
+ // Dart, so they have may have duplicate names.
+ Zone* const zone = thread->zone();
+ const auto& name = String::Handle(
+ zone, Symbols::FromConcat(thread, Symbols::FfiCallback(),
+ String::Handle(zone, dart_target.name())));
+ const Library& lib = Library::Handle(zone, Library::FfiLibrary());
+ const Class& owner_class = Class::Handle(zone, lib.toplevel_class());
+ const Function& function =
+ Function::Handle(zone, Function::New(name, RawFunction::kFfiTrampoline,
+ /*is_static=*/true,
+ /*is_const=*/false,
+ /*is_abstract=*/false,
+ /*is_external=*/false,
+ /*is_native=*/false, owner_class,
+ TokenPosition::kNoSource));
+ function.set_is_debuggable(false);
+
+ // Set callback-specific fields which the flow-graph builder needs to generate
+ // the body.
+ function.SetFfiCSignature(c_signature);
+ function.SetFfiCallbackId(callback_id);
+ function.SetFfiCallbackTarget(dart_target);
+
+ // We need to load the exceptional return value as a constant in the generated
+ // function. Even though the FE ensures that it is a constant, it could still
+ // be a literal allocated in new space. We need to copy it into old space in
+ // that case.
+ //
+ // Exceptional return values currently cannot be pointers because we don't
+ // have constant pointers.
+ //
+ // TODO(36730): We'll need to extend this when we support passing/returning
+ // structs by value.
+ ASSERT(exceptional_return.IsNull() || exceptional_return.IsNumber());
+ if (!exceptional_return.IsSmi() && exceptional_return.IsNew()) {
+ function.SetFfiCallbackExceptionalReturn(Instance::Handle(
+ zone, exceptional_return.CopyShallowToOldSpace(thread)));
+ } else {
+ function.SetFfiCallbackExceptionalReturn(exceptional_return);
+ }
+
+ return function.raw();
+}
+
ZoneGrowableArray<Representation>* ArgumentRepresentations(
const Function& signature) {
return ArgumentRepresentationsBase<CallingConventions>(signature);
@@ -650,27 +702,6 @@
#endif // defined(TARGET_ARCH_DBC)
-bool IsAsFunctionInternal(Zone* zone, Isolate* isolate, const Function& func) {
- Object& asFunctionInternal =
- Object::Handle(zone, isolate->object_store()->ffi_as_function_internal());
- if (asFunctionInternal.raw() == Object::null()) {
- // Cache the reference.
- const Library& ffi =
- Library::Handle(zone, isolate->object_store()->ffi_library());
- asFunctionInternal =
- ffi.LookupFunctionAllowPrivate(Symbols::AsFunctionInternal());
- // Cannot assert that 'asFunctionInternal' is found because it may have been
- // tree-shaken.
- if (asFunctionInternal.IsNull()) {
- // Set the entry in the object store to a sentinel so we don't try to look
- // it up again.
- asFunctionInternal = Object::sentinel().raw();
- }
- isolate->object_store()->set_ffi_as_function_internal(asFunctionInternal);
- }
- return func.raw() == asFunctionInternal.raw();
-}
-
#endif // !defined(DART_PRECOMPILED_RUNTIME)
} // namespace ffi
diff --git a/runtime/vm/compiler/ffi.h b/runtime/vm/compiler/ffi.h
index 5c743d4..7922a80 100644
--- a/runtime/vm/compiler/ffi.h
+++ b/runtime/vm/compiler/ffi.h
@@ -56,6 +56,10 @@
#if !defined(TARGET_ARCH_DBC)
+RawFunction* NativeCallbackFunction(const Function& c_signature,
+ const Function& dart_target,
+ const Instance& exceptional_return);
+
// Unboxed representations of the arguments to a C signature function.
ZoneGrowableArray<Representation>* ArgumentRepresentations(
const Function& signature);
@@ -145,11 +149,8 @@
intptr_t argument_slots_used_ = 0;
intptr_t argument_slots_required_ = 0;
};
-
#endif // defined(TARGET_ARCH_DBC)
-bool IsAsFunctionInternal(Zone* zone, Isolate* isolate, const Function& func);
-
} // namespace ffi
} // namespace compiler
diff --git a/runtime/vm/compiler/frontend/bytecode_fingerprints.cc b/runtime/vm/compiler/frontend/bytecode_fingerprints.cc
index aa3e4b7..8a42a1e 100644
--- a/runtime/vm/compiler/frontend/bytecode_fingerprints.cc
+++ b/runtime/vm/compiler/frontend/bytecode_fingerprints.cc
@@ -173,15 +173,17 @@
uint32_t BytecodeFingerprintHelper::CalculateFunctionFingerprint(
const Function& function) {
ASSERT(function.is_declared_in_bytecode());
+ const intptr_t kHashBits = 30;
+ uint32_t fp = 0;
+ fp = CombineHashes(fp, String::Handle(function.UserVisibleName()).Hash());
if (function.is_abstract()) {
- return 0;
+ return FinalizeHash(fp, kHashBits);
}
if (!function.HasBytecode()) {
kernel::BytecodeReader::ReadFunctionBytecode(Thread::Current(), function);
}
const Bytecode& code = Bytecode::Handle(function.bytecode());
const ObjectPool& pool = ObjectPool::Handle(code.object_pool());
- uint32_t fp = 0;
const KBCInstr* const start =
reinterpret_cast<const KBCInstr*>(code.instructions());
for (const KBCInstr* instr = start; (instr - start) < code.Size();
@@ -200,7 +202,7 @@
}
}
- return FinalizeHash(fp, 30);
+ return FinalizeHash(fp, kHashBits);
}
} // namespace kernel
diff --git a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc
index 4afe636..a330e14 100644
--- a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc
+++ b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc
@@ -234,6 +234,14 @@
TokenPosition::kNoSource, TokenPosition::kNoSource, name, type);
param_var->set_index(var_index);
+ if (!function().IsNonImplicitClosureFunction() &&
+ (function().is_static() ||
+ ((function().name() != Symbols::Call().raw()) &&
+ !parsed_function()->IsCovariantParameter(param_index) &&
+ !parsed_function()->IsGenericCovariantImplParameter(param_index)))) {
+ param_var->set_type_check_mode(LocalVariable::kTypeCheckedByCaller);
+ }
+
if (var_index.value() <= 0) {
local_vars_[-var_index.value()] = param_var;
}
@@ -799,9 +807,14 @@
const Function& target = Function::Cast(ConstantAt(DecodeOperandD()).value());
const intptr_t argc = DecodeOperandF().value();
- if (compiler::ffi::IsAsFunctionInternal(Z, isolate(), target)) {
+ const auto recognized_kind = MethodRecognizer::RecognizeKind(target);
+ if (recognized_kind == MethodRecognizer::kFfiAsFunctionInternal) {
BuildFfiAsFunction();
return;
+ } else if (FLAG_precompiled_mode &&
+ recognized_kind == MethodRecognizer::kFfiNativeCallbackFunction) {
+ BuildFfiNativeCallbackFunction();
+ return;
}
// Recognize identical() call.
@@ -818,7 +831,7 @@
}
if (!FLAG_causal_async_stacks &&
- target.recognized_kind() == MethodRecognizer::kAsyncStackTraceHelper) {
+ recognized_kind == MethodRecognizer::kAsyncStackTraceHelper) {
ASSERT(argc == 1);
// Drop the ignored parameter to _asyncStackTraceHelper(:async_op).
code_ += B->Drop();
@@ -826,7 +839,7 @@
return;
}
- if (target.recognized_kind() == MethodRecognizer::kStringBaseInterpolate) {
+ if (recognized_kind == MethodRecognizer::kStringBaseInterpolate) {
ASSERT(argc == 1);
code_ += B->StringInterpolate(position_);
return;
@@ -1216,8 +1229,6 @@
UNIMPLEMENTED(); // TODO(alexmarkov): interpreter
}
- BuildDebugStepCheck();
-
LoadStackSlots(1);
Operand cp_index = DecodeOperandD();
@@ -1569,8 +1580,6 @@
UNIMPLEMENTED(); // TODO(alexmarkov): interpreter
}
- BuildDebugStepCheck();
-
if (DecodeOperandA().value() == 0) {
// throw
LoadStackSlots(1);
@@ -1820,6 +1829,45 @@
code_ += B->BuildFfiAsFunctionInternalCall(type_args);
}
+// Builds graph for a call to 'dart:ffi::_nativeCallbackFunction'.
+// The call-site must look like this (guaranteed by the FE which inserts it):
+//
+// _nativeCallbackFunction<NativeSignatureType>(target, exceptionalReturn)
+//
+// Therefore the stack shall look like:
+//
+// <exceptional return value> => ensured (by FE) to be a constant
+// <target> => closure, ensured (by FE) to be a (non-partially-instantiated)
+// static tearoff
+// <type args> => [NativeSignatureType]
+void BytecodeFlowGraphBuilder::BuildFfiNativeCallbackFunction() {
+#if defined(TARGET_ARCH_DBC)
+ UNREACHABLE();
+#else
+ const TypeArguments& type_args =
+ TypeArguments::Cast(B->Peek(/*depth=*/2)->AsConstant()->value());
+ ASSERT(type_args.IsInstantiated() && type_args.Length() == 1);
+ const Function& native_sig = Function::Handle(
+ Z, Type::Cast(AbstractType::Handle(Z, type_args.TypeAt(0))).signature());
+
+ const Closure& target_closure =
+ Closure::Cast(B->Peek(/*depth=*/1)->AsConstant()->value());
+ ASSERT(!target_closure.IsNull());
+ Function& target = Function::Handle(Z, target_closure.function());
+ ASSERT(!target.IsNull() && target.IsImplicitClosureFunction());
+ target = target.parent_function();
+
+ const Instance& exceptional_return =
+ Instance::Cast(B->Peek(/*depth=*/0)->AsConstant()->value());
+
+ const Function& result =
+ Function::ZoneHandle(Z, compiler::ffi::NativeCallbackFunction(
+ native_sig, target, exceptional_return));
+ code_ += B->Constant(result);
+ code_ += B->DropTempsPreserveTop(3);
+#endif
+}
+
void BytecodeFlowGraphBuilder::BuildDebugStepCheck() {
#if !defined(PRODUCT)
if (build_debug_step_checks_) {
@@ -1965,9 +2013,9 @@
Array::ZoneHandle(Z, handlers.GetHandledTypes(try_index));
CatchBlockEntryInstr* entry = new (Z) CatchBlockEntryInstr(
- TokenPosition::kNoSource, handler_info.is_generated,
+ TokenPosition::kNoSource, handler_info.is_generated != 0,
B->AllocateBlockId(), handler_info.outer_try_index, graph_entry,
- handler_types, try_index, handler_info.needs_stacktrace,
+ handler_types, try_index, handler_info.needs_stacktrace != 0,
B->GetNextDeoptId(), nullptr, nullptr, exception_var_, stacktrace_var_);
graph_entry->AddCatchEntry(entry);
@@ -2026,34 +2074,62 @@
}
}
-#if !defined(PRODUCT)
-intptr_t BytecodeFlowGraphBuilder::UpdateContextLevel(const Bytecode& bytecode,
- intptr_t pc) {
- ASSERT(B->is_recording_context_levels());
-
- kernel::BytecodeLocalVariablesIterator iter(Z, bytecode);
- intptr_t context_level = 0;
- intptr_t next_pc = bytecode_length_;
- while (iter.MoveNext()) {
- if (iter.IsScope()) {
- if (iter.StartPC() <= pc) {
- if (pc < iter.EndPC()) {
- // Found enclosing scope. Keep looking as we might find more
- // scopes (the last one is the most specific).
- context_level = iter.ContextLevel();
- next_pc = iter.EndPC();
- }
- } else {
- next_pc = Utils::Minimum(next_pc, iter.StartPC());
- break;
- }
+intptr_t BytecodeFlowGraphBuilder::UpdateScope(
+ BytecodeLocalVariablesIterator* iter,
+ intptr_t pc) {
+ // Leave scopes that have ended.
+ while ((current_scope_ != nullptr) && (current_scope_->end_pc_ <= pc)) {
+ for (LocalVariable* local : current_scope_->hidden_vars_) {
+ local_vars_[-local->index().value()] = local;
}
+ current_scope_ = current_scope_->parent_;
}
- B->set_context_depth(context_level);
+ // Enter scopes that have started.
+ intptr_t next_pc = bytecode_length_;
+ while (!iter->IsDone()) {
+ if (iter->IsScope()) {
+ if (iter->StartPC() > pc) {
+ next_pc = iter->StartPC();
+ break;
+ }
+ if (iter->EndPC() > pc) {
+ // Push new scope and declare its variables.
+ current_scope_ = new (Z) BytecodeScope(
+ Z, iter->EndPC(), iter->ContextLevel(), current_scope_);
+ if (!seen_parameters_scope_) {
+ // Skip variables from the first scope as it may contain variables
+ // which were used in prologue (parameters, function type arguments).
+ // The already used variables should not be replaced with new ones.
+ seen_parameters_scope_ = true;
+ iter->MoveNext();
+ continue;
+ }
+ while (iter->MoveNext() && iter->IsVariableDeclaration()) {
+ const intptr_t index = iter->Index();
+ if (!iter->IsCaptured() && (index >= 0)) {
+ LocalVariable* local = new (Z) LocalVariable(
+ TokenPosition::kNoSource, TokenPosition::kNoSource,
+ String::ZoneHandle(Z, iter->Name()),
+ AbstractType::ZoneHandle(Z, iter->Type()));
+ local->set_index(VariableIndex(-index));
+ ASSERT(local_vars_[index]->index().value() == -index);
+ current_scope_->hidden_vars_.Add(local_vars_[index]);
+ local_vars_[index] = local;
+ }
+ }
+ continue;
+ }
+ }
+ iter->MoveNext();
+ }
+ if (current_scope_ != nullptr && next_pc > current_scope_->end_pc_) {
+ next_pc = current_scope_->end_pc_;
+ }
+ B->set_context_depth(
+ current_scope_ != nullptr ? current_scope_->context_level_ : 0);
return next_pc;
}
-#endif // !defined(PRODUCT)
FlowGraph* BytecodeFlowGraphBuilder::BuildGraph() {
const Bytecode& bytecode = Bytecode::Handle(Z, function().bytecode());
@@ -2077,10 +2153,9 @@
kernel::BytecodeSourcePositionsIterator source_pos_iter(Z, bytecode);
bool update_position = source_pos_iter.MoveNext();
-#if !defined(PRODUCT)
- intptr_t next_pc_to_update_context_level =
- B->is_recording_context_levels() ? 0 : bytecode_length_;
-#endif
+ kernel::BytecodeLocalVariablesIterator local_vars_iter(Z, bytecode);
+ intptr_t next_pc_to_update_scope =
+ local_vars_iter.MoveNext() ? 0 : bytecode_length_;
code_ = Fragment(normal_entry);
@@ -2114,11 +2189,9 @@
update_position = source_pos_iter.MoveNext();
}
-#if !defined(PRODUCT)
- if (pc_ >= next_pc_to_update_context_level) {
- next_pc_to_update_context_level = UpdateContextLevel(bytecode, pc_);
+ if (pc_ >= next_pc_to_update_scope) {
+ next_pc_to_update_scope = UpdateScope(&local_vars_iter, pc_);
}
-#endif
BuildInstruction(KernelBytecode::DecodeOpcode(bytecode_instr_));
diff --git a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h
index 9e7edac..1e84f92 100644
--- a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h
+++ b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h
@@ -14,6 +14,8 @@
namespace dart {
namespace kernel {
+class BytecodeLocalVariablesIterator;
+
// This class builds flow graph from bytecode. It is used either to compile
// from bytecode, or generate bytecode interpreter (the latter is not
// fully implemented yet).
@@ -107,6 +109,24 @@
const Object& value_;
};
+ // Scope declared in bytecode local variables information.
+ class BytecodeScope : public ZoneAllocated {
+ public:
+ BytecodeScope(Zone* zone,
+ intptr_t end_pc,
+ intptr_t context_level,
+ BytecodeScope* parent)
+ : end_pc_(end_pc),
+ context_level_(context_level),
+ parent_(parent),
+ hidden_vars_(zone, 4) {}
+
+ const intptr_t end_pc_;
+ const intptr_t context_level_;
+ BytecodeScope* const parent_;
+ ZoneGrowableArray<LocalVariable*> hidden_vars_;
+ };
+
Operand DecodeOperandA();
Operand DecodeOperandB();
Operand DecodeOperandC();
@@ -152,6 +172,7 @@
void BuildInstruction(KernelBytecode::Opcode opcode);
void BuildFfiAsFunction();
+ void BuildFfiNativeCallbackFunction();
void BuildDebugStepCheck();
#define DECLARE_BUILD_METHOD(name, encoding, kind, op1, op2, op3) \
@@ -167,11 +188,9 @@
const ExceptionHandlers& handlers,
GraphEntryInstr* graph_entry);
-#if !defined(PRODUCT)
- // Update context level for the given bytecode PC. returns
- // next PC where context level might need an update.
- intptr_t UpdateContextLevel(const Bytecode& bytecode, intptr_t pc);
-#endif
+ // Update current scope, context level and local variables for the given PC.
+ // Returns next PC where scope might need an update.
+ intptr_t UpdateScope(BytecodeLocalVariablesIterator* iter, intptr_t pc);
// Figure out entry points style.
UncheckedEntryPointStyle ChooseEntryPointStyle(
@@ -214,6 +233,8 @@
GraphEntryInstr* graph_entry_ = nullptr;
UncheckedEntryPointStyle entry_point_style_ = UncheckedEntryPointStyle::kNone;
bool build_debug_step_checks_ = false;
+ bool seen_parameters_scope_ = false;
+ BytecodeScope* current_scope_ = nullptr;
};
} // namespace kernel
diff --git a/runtime/vm/compiler/frontend/bytecode_reader.cc b/runtime/vm/compiler/frontend/bytecode_reader.cc
index 8e221e8..870a42e 100644
--- a/runtime/vm/compiler/frontend/bytecode_reader.cc
+++ b/runtime/vm/compiler/frontend/bytecode_reader.cc
@@ -47,20 +47,6 @@
const Function& function = parsed_function->function();
ASSERT(function.is_declared_in_bytecode());
- // No parsing is needed if function has bytecode attached.
- // With one exception: implicit functions with artificial are still handled
- // by shared flow graph builder which requires scopes/parsing.
- if (function.HasBytecode() &&
- (function.kind() != RawFunction::kImplicitGetter) &&
- (function.kind() != RawFunction::kImplicitSetter) &&
- (function.kind() != RawFunction::kImplicitStaticGetter) &&
- (function.kind() != RawFunction::kMethodExtractor) &&
- (function.kind() != RawFunction::kInvokeFieldDispatcher) &&
- (function.kind() != RawFunction::kDynamicInvocationForwarder) &&
- (function.kind() != RawFunction::kNoSuchMethodDispatcher)) {
- return;
- }
-
BytecodeComponentData bytecode_component(
&Array::Handle(helper_->zone_, GetBytecodeComponent()));
BytecodeReaderHelper bytecode_reader(&H, active_class_, &bytecode_component);
@@ -68,38 +54,6 @@
bytecode_reader.ParseBytecodeFunction(parsed_function, function);
}
-static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 10,
- "Cleanup support for old bytecode format versions");
-bool BytecodeMetadataHelper::ReadMembers(intptr_t node_offset,
- const Class& cls,
- bool discard_fields) {
- TIMELINE_DURATION(Thread::Current(), Compiler,
- "BytecodeMetadataHelper::ReadMembers");
-
- ASSERT(node_offset > 0);
- const intptr_t md_offset = GetNextMetadataPayloadOffset(node_offset);
- if (md_offset < 0) {
- return false;
- }
-
- ASSERT(Thread::Current()->IsMutatorThread());
-
- BytecodeComponentData bytecode_component(
- &Array::Handle(helper_->zone_, GetBytecodeComponent()));
- BytecodeReaderHelper bytecode_reader(&H, active_class_, &bytecode_component);
-
- AlternativeReadingScope alt(&bytecode_reader.reader(), md_offset);
-
- intptr_t members_offset = bytecode_component.GetMembersOffset() +
- bytecode_reader.reader().ReadUInt();
-
- AlternativeReadingScope alt2(&bytecode_reader.reader(), members_offset);
-
- bytecode_reader.ReadMembers(cls, discard_fields);
-
- return true;
-}
-
bool BytecodeMetadataHelper::ReadLibraries() {
TIMELINE_DURATION(Thread::Current(), Compiler,
"BytecodeMetadataHelper::ReadLibraries");
@@ -112,12 +66,6 @@
BytecodeComponentData bytecode_component(
&Array::Handle(helper_->zone_, GetBytecodeComponent()));
- static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 10,
- "Cleanup condition");
- if (bytecode_component.GetVersion() < 10) {
- return false;
- }
-
BytecodeReaderHelper bytecode_reader(&H, active_class_, &bytecode_component);
AlternativeReadingScope alt(&bytecode_reader.reader(),
bytecode_component.GetLibraryIndexOffset());
@@ -167,10 +115,10 @@
*is_empty_program = (bytecode_component.GetNumLibraries() == 0);
}
if (p_num_classes != nullptr) {
- *p_num_classes = (bytecode_component.GetNumClasses() == 0);
+ *p_num_classes = bytecode_component.GetNumClasses();
}
if (p_num_procedures != nullptr) {
- *p_num_procedures = (bytecode_component.GetNumCodes() == 0);
+ *p_num_procedures = bytecode_component.GetNumCodes();
}
return true;
}
@@ -231,7 +179,11 @@
ASSERT(Thread::Current()->IsMutatorThread());
ASSERT(!function.IsImplicitGetterFunction() &&
!function.IsImplicitSetterFunction());
- ASSERT(code_offset > 0);
+ if (code_offset == 0) {
+ FATAL2("Function %s (kind %s) doesn't have bytecode",
+ function.ToFullyQualifiedCString(),
+ Function::KindToCString(function.kind()));
+ }
AlternativeReadingScope alt(&reader_, code_offset);
// This scope is needed to set active_class_->enclosing_ which is used to
@@ -503,6 +455,7 @@
const int kIsAsyncFlag = 1 << 4;
const int kIsAsyncStarFlag = 1 << 5;
const int kIsSyncStarFlag = 1 << 6;
+ const int kIsDebuggableFlag = 1 << 7;
const intptr_t flags = reader_.ReadUInt();
@@ -542,6 +495,7 @@
if (Function::Cast(parent).IsAsyncOrGenerator()) {
closure.set_is_generated_body(true);
}
+ closure.set_is_debuggable((flags & kIsDebuggableFlag) != 0);
closures_->SetAt(closureIndex, closure);
@@ -727,7 +681,7 @@
kUnused4,
kUnused5,
kUnused6,
- kICData,
+ kICData, // Obsolete in bytecode v20.
kUnused7,
kStaticField,
kInstanceField,
@@ -751,6 +705,7 @@
kDirectCall,
kInterfaceCall,
kInstantiatedInterfaceCall,
+ kDynamicCall,
};
enum InvocationKind {
@@ -768,7 +723,6 @@
Field& field = Field::Handle(Z);
Class& cls = Class::Handle(Z);
String& name = String::Handle(Z);
- const String* simpleInstanceOf = nullptr;
const intptr_t obj_count = pool.Length();
for (intptr_t i = start_index; i < obj_count; ++i) {
const intptr_t tag = reader_.ReadTag();
@@ -776,6 +730,8 @@
case ConstantPoolTag::kInvalid:
UNREACHABLE();
case ConstantPoolTag::kICData: {
+ static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 20,
+ "Cleanup ICData constant pool entry");
intptr_t flags = reader_.ReadByte();
InvocationKind kind =
static_cast<InvocationKind>(flags & kInvocationKindMask);
@@ -785,10 +741,6 @@
intptr_t arg_desc_index = reader_.ReadUInt();
ASSERT(arg_desc_index < i);
array ^= pool.ObjectAt(arg_desc_index);
- if (simpleInstanceOf == nullptr) {
- simpleInstanceOf =
- &Library::PrivateCoreLibName(Symbols::_simpleInstanceOf());
- }
// Do not mangle == or call:
// * operator == takes an Object so its either not checked or checked
// at the entry because the parameter is marked covariant, neither
@@ -924,6 +876,37 @@
// 3) Static receiver type.
obj = ReadObject();
} break;
+ case ConstantPoolTag::kDynamicCall: {
+ name ^= ReadObject();
+ ASSERT(name.IsSymbol());
+ array ^= ReadObject();
+ // Do not mangle == or call:
+ // * operator == takes an Object so it is either not checked or
+ // checked at the entry because the parameter is marked covariant,
+ // neither of those cases require a dynamic invocation forwarder;
+ // * we assume that all closures are entered in a checked way.
+ if (!Field::IsGetterName(name) && !FLAG_precompiled_mode &&
+ I->should_emit_strong_mode_checks() &&
+ (name.raw() != Symbols::EqualOperator().raw()) &&
+ (name.raw() != Symbols::Call().raw())) {
+ name = Function::CreateDynamicInvocationForwarderName(name);
+ }
+ static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 20,
+ "Can use 2 slots in object pool");
+ // DynamicCall constant occupies 2 entries: selector and arguments
+ // descriptor. For backwards compatibility with ICData constants
+ // selector and arguments descriptor are packaged into UnlinkedCall
+ // object. The 2nd slot is filled with null.
+ obj = UnlinkedCall::New();
+ UnlinkedCall::Cast(obj).set_target_name(name);
+ UnlinkedCall::Cast(obj).set_args_descriptor(array);
+ pool.SetTypeAt(i, ObjectPool::EntryType::kTaggedObject,
+ ObjectPool::Patchability::kNotPatchable);
+ pool.SetObjectAt(i, obj);
+ ++i;
+ ASSERT(i < obj_count);
+ obj = Object::null();
+ } break;
default:
UNREACHABLE();
}
@@ -962,7 +945,7 @@
if (try_block_count > 0) {
const ObjectPool& pool = ObjectPool::Handle(Z, bytecode.object_pool());
AbstractType& handler_type = AbstractType::Handle(Z);
- Array& handler_types = Array::ZoneHandle(Z);
+ Array& handler_types = Array::Handle(Z);
DescriptorList* pc_descriptors_list = new (Z) DescriptorList(64);
ExceptionHandlerList* exception_handlers_list =
new (Z) ExceptionHandlerList();
@@ -1003,9 +986,13 @@
DeoptId::kNone,
TokenPosition::kNoSource, -1);
+ // The exception handler keeps a zone handle of the types array, rather
+ // than a raw pointer. Do not share the handle across iterations to avoid
+ // clobbering the array.
exception_handlers_list->AddHandler(
try_index, outer_try_index, handler_pc, TokenPosition::kNoSource,
- is_generated, handler_types, needs_stacktrace);
+ is_generated, Array::ZoneHandle(Z, handler_types.raw()),
+ needs_stacktrace);
}
const PcDescriptors& descriptors = PcDescriptors::Handle(
Z, pc_descriptors_list->FinalizePcDescriptors(bytecode.PayloadStart()));
@@ -1037,13 +1024,9 @@
return;
}
- intptr_t offset = reader_.ReadUInt();
- USE(offset);
-
-#if !defined(PRODUCT)
+ const intptr_t offset = reader_.ReadUInt();
bytecode.set_local_variables_binary_offset(
bytecode_component_->GetLocalVariablesOffset() + offset);
-#endif
}
RawTypedData* BytecodeReaderHelper::NativeEntry(const Function& function,
@@ -1157,23 +1140,14 @@
reader_.ReadUInt32(); // Skip main.numItems
const intptr_t main_offset = start_offset + reader_.ReadUInt32();
- intptr_t num_libraries = 0;
- intptr_t library_index_offset = 0;
- intptr_t libraries_offset = 0;
- intptr_t num_classes = 0;
- intptr_t classes_offset = 0;
- static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 10,
- "Cleanup condition");
- if (version >= 10) {
- num_libraries = reader_.ReadUInt32();
- library_index_offset = start_offset + reader_.ReadUInt32();
+ const intptr_t num_libraries = reader_.ReadUInt32();
+ const intptr_t library_index_offset = start_offset + reader_.ReadUInt32();
- reader_.ReadUInt32(); // Skip libraries.numItems
- libraries_offset = start_offset + reader_.ReadUInt32();
+ reader_.ReadUInt32(); // Skip libraries.numItems
+ const intptr_t libraries_offset = start_offset + reader_.ReadUInt32();
- num_classes = reader_.ReadUInt32();
- classes_offset = start_offset + reader_.ReadUInt32();
- }
+ const intptr_t num_classes = reader_.ReadUInt32();
+ const intptr_t classes_offset = start_offset + reader_.ReadUInt32();
reader_.ReadUInt32(); // Skip members.numItems
const intptr_t members_offset = start_offset + reader_.ReadUInt32();
@@ -1184,25 +1158,14 @@
reader_.ReadUInt32(); // Skip sourcePositions.numItems
const intptr_t source_positions_offset = start_offset + reader_.ReadUInt32();
- intptr_t source_files_offset = 0;
- intptr_t line_starts_offset = 0;
- static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 10,
- "Cleanup condition");
- if (version >= 10) {
- reader_.ReadUInt32(); // Skip sourceFiles.numItems
- source_files_offset = start_offset + reader_.ReadUInt32();
+ reader_.ReadUInt32(); // Skip sourceFiles.numItems
+ const intptr_t source_files_offset = start_offset + reader_.ReadUInt32();
- reader_.ReadUInt32(); // Skip lineStarts.numItems
- line_starts_offset = start_offset + reader_.ReadUInt32();
- }
+ reader_.ReadUInt32(); // Skip lineStarts.numItems
+ const intptr_t line_starts_offset = start_offset + reader_.ReadUInt32();
- intptr_t local_variables_offset = 0;
- static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 9,
- "Cleanup condition");
- if (version >= 9) {
- reader_.ReadUInt32(); // Skip localVariables.numItems
- local_variables_offset = start_offset + reader_.ReadUInt32();
- }
+ reader_.ReadUInt32(); // Skip localVariables.numItems
+ const intptr_t local_variables_offset = start_offset + reader_.ReadUInt32();
reader_.ReadUInt32(); // Skip annotations.numItems
const intptr_t annotations_offset = start_offset + reader_.ReadUInt32();
@@ -1303,8 +1266,6 @@
RawObject* BytecodeReaderHelper::ReadObjectContents(uint32_t header) {
ASSERT(((header & kReferenceBit) == 0));
- static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 10,
- "Cleanup obsolete object kinds");
// Must be in sync with enum ObjectKind in
// pkg/vm/lib/bytecode/object_table.dart.
enum ObjectKind {
@@ -1313,13 +1274,13 @@
kClass,
kMember,
kClosure,
- kSimpleType, // obsolete in v10
- kTypeParameter, // obsolete in v10
- kGenericType, // obsolete in v10
- kFunctionType, // obsolete in v10
+ kUnused1,
+ kUnused2,
+ kUnused3,
+ kUnused4,
kName,
kTypeArguments,
- kFinalizedGenericType, // obsolete in v10
+ kUnused5,
kConstObject,
kArgDesc,
kScript,
@@ -1331,19 +1292,6 @@
const intptr_t kFlagIsField = kFlagBit0;
const intptr_t kFlagIsConstructor = kFlagBit1;
- // SimpleType flags, must be in sync with _SimpleTypeHandle constants in
- // pkg/vm/lib/bytecode/object_table.dart.
- const intptr_t kFlagIsDynamic = kFlagBit0;
- const intptr_t kFlagIsVoid = kFlagBit1;
-
- static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 10,
- "Cleanup old FunctionType flags");
- // FunctionType flags, must be in sync with _FunctionTypeHandle constants in
- // pkg/vm/lib/bytecode/object_table.dart.
- const int kFlagHasOptionalPositionalParams = kFlagBit0;
- const int kFlagHasOptionalNamedParams = kFlagBit1;
- const int kFlagHasTypeParams = kFlagBit2;
-
// ArgDesc flags, must be in sync with _ArgDescHandle constants in
// pkg/vm/lib/bytecode/object_table.dart.
const int kFlagHasNamedArgs = kFlagBit0;
@@ -1361,16 +1309,8 @@
UNREACHABLE();
break;
case kLibrary: {
- String& uri = String::Handle(Z);
- static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 10,
- "Cleanup condition");
- if (bytecode_component_->GetVersion() < 10) {
- uri = ReadString();
- } else {
- uri ^= ReadObject();
- }
+ String& uri = String::CheckedHandle(Z, ReadObject());
RawLibrary* library = Library::LookupLibrary(thread_, uri);
- NoSafepointScope no_safepoint_scope(thread_);
if (library == Library::null()) {
// We do not register expression evaluation libraries with the VM:
// The expression evaluation functions should be GC-able as soon as
@@ -1379,7 +1319,15 @@
ASSERT(expression_evaluation_library_ != nullptr);
return expression_evaluation_library_->raw();
}
+#if !defined(PRODUCT)
+ ASSERT(Isolate::Current()->HasAttemptedReload());
+ const String& msg = String::Handle(
+ Z,
+ String::NewFormatted("Unable to find library %s", uri.ToCString()));
+ Report::LongJump(LanguageError::Handle(Z, LanguageError::New(msg)));
+#else
FATAL1("Unable to find library %s", uri.ToCString());
+#endif
}
return library;
}
@@ -1395,13 +1343,21 @@
return cls;
}
RawClass* cls = library.LookupLocalClass(class_name);
- NoSafepointScope no_safepoint_scope(thread_);
if (cls == Class::null()) {
if (IsExpressionEvaluationLibrary(library)) {
return H.GetExpressionEvaluationRealClass();
}
+#if !defined(PRODUCT)
+ ASSERT(Isolate::Current()->HasAttemptedReload());
+ const String& msg = String::Handle(
+ Z,
+ String::NewFormatted("Unable to find class %s in %s",
+ class_name.ToCString(), library.ToCString()));
+ Report::LongJump(LanguageError::Handle(Z, LanguageError::New(msg)));
+#else
FATAL2("Unable to find class %s in %s", class_name.ToCString(),
library.ToCString());
+#endif
}
return cls;
}
@@ -1410,10 +1366,17 @@
String& name = String::CheckedHandle(Z, ReadObject());
if ((flags & kFlagIsField) != 0) {
RawField* field = cls.LookupField(name);
- NoSafepointScope no_safepoint_scope(thread_);
if (field == Field::null()) {
+#if !defined(PRODUCT)
+ ASSERT(Isolate::Current()->HasAttemptedReload());
+ const String& msg = String::Handle(
+ Z, String::NewFormatted("Unable to find field %s in %s",
+ name.ToCString(), cls.ToCString()));
+ Report::LongJump(LanguageError::Handle(Z, LanguageError::New(msg)));
+#else
FATAL2("Unable to find field %s in %s", name.ToCString(),
cls.ToCString());
+#endif
}
return field;
} else {
@@ -1426,10 +1389,6 @@
return scoped_function_.raw();
}
RawFunction* function = cls.LookupFunction(name);
- {
- // To verify that it's OK to hold raw function pointer at this point.
- NoSafepointScope no_safepoint_scope(thread_);
- }
if (function == Function::null()) {
// When requesting a getter, also return method extractors.
if (Field::IsGetterName(name)) {
@@ -1444,8 +1403,16 @@
}
}
}
+#if !defined(PRODUCT)
+ ASSERT(Isolate::Current()->HasAttemptedReload());
+ const String& msg = String::Handle(
+ Z, String::NewFormatted("Unable to find function %s in %s",
+ name.ToCString(), cls.ToCString()));
+ Report::LongJump(LanguageError::Handle(Z, LanguageError::New(msg)));
+#else
FATAL2("Unable to find function %s in %s", name.ToCString(),
cls.ToCString());
+#endif
}
return function;
}
@@ -1455,80 +1422,6 @@
const intptr_t closure_index = reader_.ReadUInt();
return closures_->At(closure_index);
}
- case kSimpleType: {
- static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 10,
- "Cleanup");
- const Class& cls = Class::CheckedHandle(Z, ReadObject());
- if ((flags & kFlagIsDynamic) != 0) {
- ASSERT(cls.IsNull());
- return AbstractType::dynamic_type().raw();
- }
- if ((flags & kFlagIsVoid) != 0) {
- ASSERT(cls.IsNull());
- return AbstractType::void_type().raw();
- }
- return cls.DeclarationType();
- }
- case kTypeParameter: {
- static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 10,
- "Cleanup");
- Object& parent = Object::Handle(Z, ReadObject());
- const intptr_t index_in_parent = reader_.ReadUInt();
- TypeArguments& type_parameters = TypeArguments::Handle(Z);
- if (parent.IsClass()) {
- type_parameters = Class::Cast(parent).type_parameters();
- } else if (parent.IsFunction()) {
- if (Function::Cast(parent).IsFactory()) {
- // For factory constructors VM uses type parameters of a class
- // instead of constructor's type parameters.
- parent = Function::Cast(parent).Owner();
- type_parameters = Class::Cast(parent).type_parameters();
- } else {
- type_parameters = Function::Cast(parent).type_parameters();
- }
- } else if (parent.IsNull()) {
- ASSERT(function_type_type_parameters_ != nullptr);
- type_parameters = function_type_type_parameters_->raw();
- } else {
- UNREACHABLE();
- }
- AbstractType& type =
- AbstractType::Handle(Z, type_parameters.TypeAt(index_in_parent));
- // TODO(alexmarkov): figure out how to skip this type finalization
- // (consider finalizing type parameters of classes/functions eagerly).
- return ClassFinalizer::FinalizeType(*active_class_->klass, type);
- }
- case kGenericType: {
- static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 10,
- "Cleanup");
- const Class& cls = Class::CheckedHandle(Z, ReadObject());
- const TypeArguments& type_arguments =
- TypeArguments::Handle(Z, ReadTypeArguments());
- const Type& type = Type::Handle(
- Z, Type::New(cls, type_arguments, TokenPosition::kNoSource));
- return ClassFinalizer::FinalizeType(*active_class_->klass, type);
- }
- case kFunctionType: {
- static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 10,
- "Cleanup");
- Function& signature_function = Function::ZoneHandle(
- Z, Function::NewSignatureFunction(*active_class_->klass,
- active_class_->enclosing != NULL
- ? *active_class_->enclosing
- : Function::null_function(),
- TokenPosition::kNoSource));
-
- // This scope is needed to set active_class_->enclosing_ which is used
- // to assign parent function for function types.
- ActiveEnclosingFunctionScope active_enclosing_function(
- active_class_, &signature_function);
-
- return ReadFunctionSignature(
- signature_function, (flags & kFlagHasOptionalPositionalParams) != 0,
- (flags & kFlagHasOptionalNamedParams) != 0,
- (flags & kFlagHasTypeParams) != 0,
- /* has_positional_param_names = */ false);
- }
case kName: {
const Library& library = Library::CheckedHandle(Z, ReadObject());
if (library.IsNull()) {
@@ -1542,17 +1435,6 @@
case kTypeArguments: {
return ReadTypeArguments();
}
- case kFinalizedGenericType: {
- static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 10,
- "Cleanup");
- const Class& cls = Class::CheckedHandle(Z, ReadObject());
- const TypeArguments& type_arguments =
- TypeArguments::CheckedHandle(Z, ReadObject());
- const Type& type = Type::Handle(
- Z, Type::New(cls, type_arguments, TokenPosition::kNoSource));
- type.SetIsFinalized();
- return type.Canonicalize();
- }
case kConstObject: {
const intptr_t tag = flags / kFlagBit0;
return ReadConstObject(tag);
@@ -2827,11 +2709,14 @@
const KBCInstr* instr =
reinterpret_cast<const KBCInstr*>(bytecode.PayloadStart());
if (KernelBytecode::IsEntryOptionalOpcode(instr)) {
- const intptr_t num_fixed_params = KernelBytecode::DecodeA(instr);
+ // Note that number of fixed parameters may not match 'A' operand of
+ // EntryOptional bytecode as [function] could be an implicit closure
+ // function with an extra implicit argument, while bytecode corresponds
+ // to a static function without any implicit arguments.
+ const intptr_t num_fixed_params = function.num_fixed_parameters();
const intptr_t num_opt_pos_params = KernelBytecode::DecodeB(instr);
const intptr_t num_opt_named_params = KernelBytecode::DecodeC(instr);
instr = KernelBytecode::Next(instr);
- ASSERT(num_fixed_params == function.num_fixed_parameters());
ASSERT(num_opt_pos_params == function.NumOptionalPositionalParameters());
ASSERT(num_opt_named_params == function.NumOptionalNamedParameters());
ASSERT((num_opt_pos_params == 0) || (num_opt_named_params == 0));
@@ -2877,41 +2762,37 @@
void BytecodeReaderHelper::ParseBytecodeFunction(
ParsedFunction* parsed_function,
const Function& function) {
+ // Handle function kinds which don't have a user-defined body first.
switch (function.kind()) {
case RawFunction::kImplicitClosureFunction:
ParseForwarderFunction(parsed_function, function,
Function::Handle(Z, function.parent_function()));
- break;
+ return;
case RawFunction::kDynamicInvocationForwarder:
ParseForwarderFunction(
parsed_function, function,
Function::Handle(Z,
function.GetTargetOfDynamicInvocationForwarder()));
- break;
+ return;
case RawFunction::kImplicitGetter:
case RawFunction::kImplicitSetter:
- BytecodeScopeBuilder(parsed_function).BuildScopes();
- break;
- case RawFunction::kImplicitStaticGetter: {
- if (IsStaticFieldGetterGeneratedAsInitializer(function, Z)) {
- ReadCode(function, function.bytecode_offset());
- } else {
- BytecodeScopeBuilder(parsed_function).BuildScopes();
- }
- break;
- }
- case RawFunction::kFieldInitializer:
- ReadCode(function, function.bytecode_offset());
- break;
case RawFunction::kMethodExtractor:
BytecodeScopeBuilder(parsed_function).BuildScopes();
- break;
+ return;
+ case RawFunction::kImplicitStaticGetter: {
+ if (IsStaticFieldGetterGeneratedAsInitializer(function, Z)) {
+ break;
+ } else {
+ BytecodeScopeBuilder(parsed_function).BuildScopes();
+ return;
+ }
+ }
case RawFunction::kRegularFunction:
case RawFunction::kGetterFunction:
case RawFunction::kSetterFunction:
case RawFunction::kClosureFunction:
case RawFunction::kConstructor:
- ReadCode(function, function.bytecode_offset());
+ case RawFunction::kFieldInitializer:
break;
case RawFunction::kNoSuchMethodDispatcher:
case RawFunction::kInvokeFieldDispatcher:
@@ -2921,6 +2802,28 @@
UNREACHABLE();
break;
}
+
+ // We only reach here if function has a bytecode body. Make sure it is
+ // loaded and collect information about covariant parameters.
+
+ if (!function.HasBytecode()) {
+ ReadCode(function, function.bytecode_offset());
+ ASSERT(function.HasBytecode());
+ }
+
+ // TODO(alexmarkov): simplify access to covariant / generic_covariant_impl
+ // flags of parameters so we won't need to read them separately.
+ if (!parsed_function->HasCovariantParametersInfo()) {
+ const intptr_t num_params = function.NumParameters();
+ BitVector* covariant_parameters = new (Z) BitVector(Z, num_params);
+ BitVector* generic_covariant_impl_parameters =
+ new (Z) BitVector(Z, num_params);
+ ReadParameterCovariance(function, covariant_parameters,
+ generic_covariant_impl_parameters);
+ parsed_function->SetCovariantParameters(covariant_parameters);
+ parsed_function->SetGenericCovariantImplParameters(
+ generic_covariant_impl_parameters);
+ }
}
void BytecodeReaderHelper::ParseForwarderFunction(
diff --git a/runtime/vm/compiler/frontend/bytecode_reader.h b/runtime/vm/compiler/frontend/bytecode_reader.h
index 3ca2ad45..ec915dd 100644
--- a/runtime/vm/compiler/frontend/bytecode_reader.h
+++ b/runtime/vm/compiler/frontend/bytecode_reader.h
@@ -26,11 +26,6 @@
void ParseBytecodeFunction(ParsedFunction* parsed_function);
- // Reads members associated with given [node_offset] and fills in [cls].
- // Discards fields if [discard_fields] is true.
- // Returns true if class members are loaded.
- bool ReadMembers(intptr_t node_offset, const Class& cls, bool discard_fields);
-
// Read all library declarations.
bool ReadLibraries();
@@ -369,8 +364,9 @@
class BytecodeSourcePositionsIterator : ValueObject {
public:
- // This constant should match corresponding constant in class SourcePositions
- // (pkg/vm/lib/bytecode/source_positions.dart).
+ // These constants should match corresponding constants in class
+ // SourcePositions (pkg/vm/lib/bytecode/source_positions.dart).
+ static const intptr_t kSyntheticCodeMarker = -1;
static const intptr_t kYieldPointMarker = -2;
BytecodeSourcePositionsIterator(Zone* zone, const Bytecode& bytecode)
@@ -400,7 +396,11 @@
uword PcOffset() const { return cur_bci_; }
- TokenPosition TokenPos() const { return TokenPosition(cur_token_pos_); }
+ TokenPosition TokenPos() const {
+ return (cur_token_pos_ == kSyntheticCodeMarker)
+ ? TokenPosition::kNoSource
+ : TokenPosition(cur_token_pos_);
+ }
bool IsYieldPoint() const { return is_yield_point_; }
@@ -412,7 +412,6 @@
bool is_yield_point_ = false;
};
-#if !defined(PRODUCT)
class BytecodeLocalVariablesIterator : ValueObject {
public:
// These constants should match corresponding constants in
@@ -465,6 +464,7 @@
return true;
}
+ bool IsDone() const { return entries_remaining_ == 0; }
intptr_t Kind() const { return cur_kind_and_flags_ & kKindMask; }
bool IsScope() const { return Kind() == kScope; }
bool IsVariableDeclaration() const { return Kind() == kVariableDeclaration; }
@@ -522,7 +522,6 @@
TokenPosition cur_declaration_token_pos_ = TokenPosition::kNoSource;
TokenPosition cur_end_token_pos_ = TokenPosition::kNoSource;
};
-#endif // !defined(PRODUCT)
bool IsStaticFieldGetterGeneratedAsInitializer(const Function& function,
Zone* zone);
diff --git a/runtime/vm/compiler/frontend/bytecode_scope_builder.cc b/runtime/vm/compiler/frontend/bytecode_scope_builder.cc
index e3d3f50c..8da6b6e 100644
--- a/runtime/vm/compiler/frontend/bytecode_scope_builder.cc
+++ b/runtime/vm/compiler/frontend/bytecode_scope_builder.cc
@@ -73,7 +73,7 @@
// Type check all parameters by default.
// This may be overridden with parameter flags in
- // BytecodeReaderHelper::ParseImplicitClosureFunction.
+ // BytecodeReaderHelper::ParseForwarderFunction.
AddParameters(function, LocalVariable::kDoTypeCheck);
break;
}
@@ -114,7 +114,7 @@
// Type check all parameters by default.
// This may be overridden with parameter flags in
- // BytecodeReaderHelper::ParseImplicitClosureFunction.
+ // BytecodeReaderHelper::ParseForwarderFunction.
AddParameters(function, LocalVariable::kDoTypeCheck);
break;
}
diff --git a/runtime/vm/compiler/frontend/constant_evaluator.cc b/runtime/vm/compiler/frontend/constant_evaluator.cc
index e433e26..b8409a8 100644
--- a/runtime/vm/compiler/frontend/constant_evaluator.cc
+++ b/runtime/vm/compiler/frontend/constant_evaluator.cc
@@ -98,6 +98,7 @@
case kSetConcatenation:
case kMapConcatenation:
case kInstanceCreation:
+ case kFileUriExpression:
// These only occur inside unevaluated constants, so if we decide to
// remove support for late evaluation of environment constants from
// dill files in the VM, an implementation here will not be necessary.
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index fa00a60..7068b74 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -1164,8 +1164,9 @@
case kSetConcatenation:
case kMapConcatenation:
case kInstanceCreation:
- // Collection concatenation and instance creation operations are removed
- // by the constant evaluator.
+ case kFileUriExpression:
+ // Collection concatenation, instance creation operations and
+ // in-expression URI changes are removed by the constant evaluator.
UNREACHABLE();
break;
case kIsExpression:
@@ -3056,8 +3057,12 @@
++argument_count;
}
- if (compiler::ffi::IsAsFunctionInternal(Z, H.isolate(), target)) {
+ const auto recognized_kind = MethodRecognizer::RecognizeKind(target);
+ if (recognized_kind == MethodRecognizer::kFfiAsFunctionInternal) {
return BuildFfiAsFunctionInternal();
+ } else if (FLAG_precompiled_mode &&
+ recognized_kind == MethodRecognizer::kFfiNativeCallbackFunction) {
+ return BuildFfiNativeCallbackFunction();
}
Fragment instructions;
@@ -3065,7 +3070,7 @@
const bool special_case_nop_async_stack_trace_helper =
!FLAG_causal_async_stacks &&
- target.recognized_kind() == MethodRecognizer::kAsyncStackTraceHelper;
+ recognized_kind == MethodRecognizer::kAsyncStackTraceHelper;
const bool special_case_unchecked_cast =
klass.IsTopLevel() && (klass.library() == Library::InternalLibrary()) &&
@@ -5040,6 +5045,65 @@
return code;
}
+Fragment StreamingFlowGraphBuilder::BuildFfiNativeCallbackFunction() {
+#if defined(TARGET_ARCH_DBC)
+ UNREACHABLE();
+#else
+ // The call-site must look like this (guaranteed by the FE which inserts it):
+ //
+ // _nativeCallbackFunction<NativeSignatureType>(target, exceptionalReturn)
+ //
+ // The FE also guarantees that all three arguments are constants.
+
+ const intptr_t argc = ReadUInt(); // read argument count
+ ASSERT(argc == 2); // target, exceptionalReturn
+
+ const intptr_t list_length = ReadListLength(); // read types list length
+ ASSERT(list_length == 1); // native signature
+ const TypeArguments& type_arguments =
+ T.BuildTypeArguments(list_length); // read types.
+ ASSERT(type_arguments.Length() == 1 && type_arguments.IsInstantiated());
+ const Function& native_sig = Function::Handle(
+ Z, Type::Cast(AbstractType::Handle(Z, type_arguments.TypeAt(0)))
+ .signature());
+
+ Fragment code;
+ const intptr_t positional_count =
+ ReadListLength(); // read positional argument count
+ ASSERT(positional_count == 2);
+
+ // Read target expression and extract the target function.
+ code += BuildExpression(); // build first positional argument (target)
+ Definition* target_def = B->Peek();
+ ASSERT(target_def->IsConstant());
+ const Closure& target_closure =
+ Closure::Cast(target_def->AsConstant()->value());
+ ASSERT(!target_closure.IsNull());
+ Function& target = Function::Handle(Z, target_closure.function());
+ ASSERT(!target.IsNull() && target.IsImplicitClosureFunction());
+ target = target.parent_function();
+ code += Drop();
+
+ // Build second positional argument (exceptionalReturn).
+ code += BuildExpression();
+ Definition* exceptional_return_def = B->Peek();
+ ASSERT(exceptional_return_def->IsConstant());
+ const Instance& exceptional_return =
+ Instance::Cast(exceptional_return_def->AsConstant()->value());
+ code += Drop();
+
+ const intptr_t named_args_len =
+ ReadListLength(); // skip (empty) named arguments list
+ ASSERT(named_args_len == 0);
+
+ const Function& result =
+ Function::ZoneHandle(Z, compiler::ffi::NativeCallbackFunction(
+ native_sig, target, exceptional_return));
+ code += Constant(result);
+ return code;
+#endif
+}
+
} // namespace kernel
} // namespace dart
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
index e8b36bd..0eab5b9b 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
@@ -353,6 +353,10 @@
// Kernel buffer and pushes the resulting closure.
Fragment BuildFfiAsFunctionInternal();
+ // Build build FG for '_nativeCallbackFunction'. Reads an Arguments from the
+ // Kernel buffer and pushes the resulting Function object.
+ Fragment BuildFfiNativeCallbackFunction();
+
FlowGraphBuilder* flow_graph_builder_;
ActiveClass* const active_class_;
TypeTranslator type_translator_;
diff --git a/runtime/vm/compiler/frontend/kernel_fingerprints.cc b/runtime/vm/compiler/frontend/kernel_fingerprints.cc
index bed6c0f..2f8fc9f 100644
--- a/runtime/vm/compiler/frontend/kernel_fingerprints.cc
+++ b/runtime/vm/compiler/frontend/kernel_fingerprints.cc
@@ -461,8 +461,9 @@
case kSetConcatenation:
case kMapConcatenation:
case kInstanceCreation:
- // Collection concatenation and instance creation operations are removed
- // by the constant evaluator.
+ case kFileUriExpression:
+ // Collection concatenation, instance creation operations and
+ // in-expression URI changes are removed by the constant evaluator.
UNREACHABLE();
break;
case kIsExpression:
@@ -645,7 +646,7 @@
ReadPosition(); // read jth position.
CalculateExpressionFingerprint(); // read jth expression.
}
- BuildHash(ReadBool()); // read is_default.
+ BuildHash(static_cast<uint32_t>(ReadBool())); // read is_default.
CalculateStatementFingerprint(); // read body.
}
return;
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index 2169ebd..fbca763 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -2397,6 +2397,7 @@
// do not appear in the type arguments to a any Pointer classes in an FFI
// signature.
ASSERT(args.IsNull() || args.IsInstantiated());
+ args = args.Canonicalize();
Fragment code;
code += Constant(args);
@@ -2450,14 +2451,6 @@
const Representation native_representation) {
Fragment body;
- // Return 0 for void.
- if (compiler::ffi::NativeTypeIsVoid(ffi_type)) {
- body += Drop();
- body += IntConstant(0);
- body += UnboxTruncate(kUnboxedFfiIntPtr);
- return body;
- }
-
// Check for 'null'.
body += LoadLocal(MakeTemporary());
body <<= new (Z) CheckNullInstr(Pop(), String::ZoneHandle(Z, function.name()),
@@ -2614,9 +2607,20 @@
/*needs_stacktrace=*/false, /*is_synthesized=*/true);
// Return the "exceptional return" value given in 'fromFunction'.
- catch_body += Constant(
- Instance::ZoneHandle(Z, function.FfiCallbackExceptionalReturn()));
- catch_body += FfiConvertArgumentToNative(function, ffi_type, result_rep);
+ //
+ // For pointer and void return types, the exceptional return is always null --
+ // return 0 instead.
+ if (compiler::ffi::NativeTypeIsPointer(ffi_type) ||
+ compiler::ffi::NativeTypeIsVoid(ffi_type)) {
+ ASSERT(function.FfiCallbackExceptionalReturn() == Object::null());
+ catch_body += IntConstant(0);
+ catch_body += UnboxTruncate(kUnboxedFfiIntPtr);
+ } else {
+ catch_body += Constant(
+ Instance::ZoneHandle(Z, function.FfiCallbackExceptionalReturn()));
+ catch_body += FfiConvertArgumentToNative(function, ffi_type, result_rep);
+ }
+
catch_body += NativeReturn(result_rep);
--catch_depth_;
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.cc b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
index 90b63be..4469fce 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.cc
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
@@ -2248,8 +2248,9 @@
case kSetConcatenation:
case kMapConcatenation:
case kInstanceCreation:
- // Collection concatenation and instance creation operations are removed
- // by the constant evaluator.
+ case kFileUriExpression:
+ // Collection concatenation, instance creation operations and
+ // in-expression URI changes are removed by the constant evaluator.
UNREACHABLE();
break;
case kIsExpression:
@@ -2806,6 +2807,9 @@
const Class& klass = Class::Handle(Z, H.LookupClassByKernelClass(klass_name));
ASSERT(!klass.IsNull());
+ if (klass.is_declared_in_bytecode()) {
+ klass.EnsureDeclarationLoaded();
+ }
if (simple) {
if (finalize_ || klass.is_type_finalized()) {
// Fast path for non-generic types: retrieve or populate the class's only
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.h b/runtime/vm/compiler/frontend/kernel_translation_helper.h
index 87a593b..8f9371b 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.h
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.h
@@ -689,12 +689,12 @@
void SetNext(Field field) { next_read_ = field; }
void SetJustRead(Field field) { next_read_ = field + 1; }
- bool is_abstract() const { return flags_ & Flag::kIsAbstract; }
+ bool is_abstract() const { return (flags_ & Flag::kIsAbstract) != 0; }
- bool is_enum_class() const { return flags_ & Flag::kIsEnumClass; }
+ bool is_enum_class() const { return (flags_ & Flag::kIsEnumClass) != 0; }
bool is_transformed_mixin_application() const {
- return flags_ & Flag::kIsEliminatedMixin;
+ return (flags_ & Flag::kIsEliminatedMixin) != 0;
}
NameIndex canonical_name_;
diff --git a/runtime/vm/compiler/frontend/scope_builder.cc b/runtime/vm/compiler/frontend/scope_builder.cc
index fcf01e8..8e4a4c6 100644
--- a/runtime/vm/compiler/frontend/scope_builder.cc
+++ b/runtime/vm/compiler/frontend/scope_builder.cc
@@ -789,8 +789,9 @@
case kSetConcatenation:
case kMapConcatenation:
case kInstanceCreation:
- // Collection concatenation and instance creation operations are removed
- // by the constant evaluator.
+ case kFileUriExpression:
+ // Collection concatenation, instance creation operations and
+ // in-expression URI changes are removed by the constant evaluator.
UNREACHABLE();
break;
case kIsExpression:
@@ -1637,6 +1638,7 @@
raw_variable =
new LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
symbol, AbstractType::dynamic_type());
+ raw_variable->set_is_forced_stack();
const bool ok = scope_->AddVariable(raw_variable);
ASSERT(ok);
} else {
diff --git a/runtime/vm/compiler/graph_intrinsifier.cc b/runtime/vm/compiler/graph_intrinsifier.cc
index d251b3e..728aee5 100644
--- a/runtime/vm/compiler/graph_intrinsifier.cc
+++ b/runtime/vm/compiler/graph_intrinsifier.cc
@@ -278,15 +278,22 @@
// Value check/conversion.
switch (array_cid) {
+ case kTypedDataUint8ClampedArrayCid:
+ case kExternalTypedDataUint8ClampedArrayCid:
+#if defined(TARGET_ARCH_IS_32_BIT)
+ // On 32-bit architectures, clamping operations need the exact value
+ // for proper operations. On 64-bit architectures, kUnboxedIntPtr
+ // maps to kUnboxedInt64. All other situations get away with
+ // truncating even non-smi values.
+ builder.AddInstruction(new CheckSmiInstr(new Value(value), DeoptId::kNone,
+ builder.TokenPos()));
+ FALL_THROUGH;
+#endif
case kTypedDataInt8ArrayCid:
case kTypedDataInt16ArrayCid:
case kTypedDataUint8ArrayCid:
- case kTypedDataUint8ClampedArrayCid:
case kTypedDataUint16ArrayCid:
case kExternalTypedDataUint8ArrayCid:
- case kExternalTypedDataUint8ClampedArrayCid:
- builder.AddInstruction(new CheckSmiInstr(new Value(value), DeoptId::kNone,
- builder.TokenPos()));
value = builder.AddUnboxInstr(kUnboxedIntPtr, new Value(value),
/* is_checked = */ false);
value->AsUnboxInteger()->mark_truncating();
diff --git a/runtime/vm/compiler/jit/compiler.cc b/runtime/vm/compiler/jit/compiler.cc
index b2b2c29..5bf7d0a 100644
--- a/runtime/vm/compiler/jit/compiler.cc
+++ b/runtime/vm/compiler/jit/compiler.cc
@@ -119,7 +119,6 @@
// These flags are constants with PRODUCT and DART_PRECOMPILED_RUNTIME.
FLAG_deoptimize_alot = false; // Used in some tests.
FLAG_deoptimize_every = 0; // Used in some tests.
- FLAG_load_deferred_eagerly = true;
FLAG_use_osr = false;
#endif
}
@@ -335,9 +334,7 @@
: parsed_function_(parsed_function),
optimized_(optimized),
osr_id_(osr_id),
- thread_(Thread::Current()),
- loading_invalidation_gen_at_start_(
- isolate()->loading_invalidation_gen()) {}
+ thread_(Thread::Current()) {}
RawCode* Compile(CompilationPipeline* pipeline);
@@ -347,9 +344,6 @@
intptr_t osr_id() const { return osr_id_; }
Thread* thread() const { return thread_; }
Isolate* isolate() const { return thread_->isolate(); }
- intptr_t loading_invalidation_gen_at_start() const {
- return loading_invalidation_gen_at_start_;
- }
RawCode* FinalizeCompilation(compiler::Assembler* assembler,
FlowGraphCompiler* graph_compiler,
FlowGraph* flow_graph);
@@ -359,7 +353,6 @@
const bool optimized_;
const intptr_t osr_id_;
Thread* const thread_;
- const intptr_t loading_invalidation_gen_at_start_;
DISALLOW_COPY_AND_ASSIGN(CompileParsedFunctionHelper);
};
@@ -439,13 +432,6 @@
}
}
}
- if (loading_invalidation_gen_at_start() !=
- isolate()->loading_invalidation_gen()) {
- code_is_valid = false;
- if (trace_compiler) {
- THR_Print("--> FAIL: Loading invalidation.");
- }
- }
if (!thread()
->compiler_state()
.cha()
@@ -504,14 +490,6 @@
function.SetUsageCounter(0);
}
}
- if (parsed_function()->HasDeferredPrefixes()) {
- ASSERT(!FLAG_load_deferred_eagerly);
- ZoneGrowableArray<const LibraryPrefix*>* prefixes =
- parsed_function()->deferred_prefixes();
- for (intptr_t i = 0; i < prefixes->length(); i++) {
- (*prefixes)[i]->RegisterDependentCode(code);
- }
- }
return code.raw();
}
@@ -629,7 +607,12 @@
CompilerPassState pass_state(thread(), flow_graph, &speculative_policy);
pass_state.reorder_blocks = reorder_blocks;
- if (optimized()) {
+ if (function.ForceOptimize()) {
+ ASSERT(optimized());
+ TIMELINE_DURATION(thread(), CompilerVerbose, "OptimizationPasses");
+ flow_graph = CompilerPass::RunForceOptimizedPipeline(CompilerPass::kJIT,
+ &pass_state);
+ } else if (optimized()) {
TIMELINE_DURATION(thread(), CompilerVerbose, "OptimizationPasses");
pass_state.inline_id_to_function.Add(&function);
@@ -644,7 +627,7 @@
JitCallSpecializer call_specializer(flow_graph, &speculative_policy);
pass_state.call_specializer = &call_specializer;
- CompilerPass::RunPipeline(CompilerPass::kJIT, &pass_state);
+ flow_graph = CompilerPass::RunPipeline(CompilerPass::kJIT, &pass_state);
}
ASSERT(pass_state.inline_id_to_function.length() ==
@@ -743,11 +726,12 @@
intptr_t osr_id) {
ASSERT(!FLAG_precompiled_mode);
ASSERT(!optimized || function.WasCompiled() || function.ForceOptimize());
+ ASSERT(function.is_background_optimizable() ||
+ !Compiler::IsBackgroundCompilation());
if (function.ForceOptimize()) optimized = true;
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
Thread* const thread = Thread::Current();
- Isolate* const isolate = thread->isolate();
StackZone stack_zone(thread);
Zone* const zone = stack_zone.GetZone();
const bool trace_compiler =
@@ -768,8 +752,6 @@
function.token_pos().ToCString(), token_size);
}
// Makes sure no classes are loaded during parsing in background.
- const intptr_t loading_invalidation_gen_at_start =
- isolate->loading_invalidation_gen();
{
HANDLESCOPE(thread);
pipeline->ParseFunction(parsed_function);
@@ -777,17 +759,6 @@
CompileParsedFunctionHelper helper(parsed_function, optimized, osr_id);
- if (Compiler::IsBackgroundCompilation()) {
- ASSERT(function.is_background_optimizable());
- if ((loading_invalidation_gen_at_start !=
- isolate->loading_invalidation_gen())) {
- // Loading occured while parsing. We need to abort here because state
- // changed while compiling.
- Compiler::AbortBackgroundCompilation(
- DeoptId::kNone,
- "Invalidated state during parsing because of script loading");
- }
- }
const Code& result = Code::Handle(helper.Compile(pipeline));
diff --git a/runtime/vm/compiler/jit/jit_call_specializer.cc b/runtime/vm/compiler/jit/jit_call_specializer.cc
index 4abf730..a13bffc 100644
--- a/runtime/vm/compiler/jit/jit_call_specializer.cc
+++ b/runtime/vm/compiler/jit/jit_call_specializer.cc
@@ -51,15 +51,14 @@
}
void JitCallSpecializer::ReplaceWithStaticCall(InstanceCallInstr* instr,
- const ICData& unary_checks,
const Function& target,
intptr_t call_count) {
StaticCallInstr* call =
StaticCallInstr::FromCall(Z, instr, target, call_count);
- if (unary_checks.NumberOfChecks() == 1 &&
- unary_checks.GetExactnessAt(0).IsExact()) {
- if (unary_checks.GetExactnessAt(0).IsTriviallyExact()) {
- flow_graph()->AddExactnessGuard(instr, unary_checks.GetCidAt(0));
+ const CallTargets& targets = instr->Targets();
+ if (targets.IsMonomorphic() && targets.MonomorphicExactness().IsExact()) {
+ if (targets.MonomorphicExactness().IsTriviallyExact()) {
+ flow_graph()->AddExactnessGuard(instr, targets.MonomorphicReceiverCid());
}
call->set_entry_kind(Code::EntryKind::kUnchecked);
}
@@ -71,9 +70,11 @@
// TODO(dartbug.com/30635) Evaluate how much this can be shared with
// AotCallSpecializer.
void JitCallSpecializer::VisitInstanceCall(InstanceCallInstr* instr) {
- if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) {
- return;
+ const CallTargets& targets = instr->Targets();
+ if (targets.is_empty()) {
+ return; // No feedback.
}
+
const Token::Kind op_kind = instr->token_kind();
// Type test is special as it always gets converted into inlined code.
@@ -82,15 +83,10 @@
return;
}
- const ICData& unary_checks =
- ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks());
-
- if ((op_kind == Token::kASSIGN_INDEX) &&
- TryReplaceWithIndexedOp(instr, &unary_checks)) {
+ if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) {
return;
}
- if ((op_kind == Token::kINDEX) &&
- TryReplaceWithIndexedOp(instr, &unary_checks)) {
+ if ((op_kind == Token::kINDEX) && TryReplaceWithIndexedOp(instr)) {
return;
}
@@ -114,22 +110,18 @@
if ((op_kind == Token::kGET) && TryInlineInstanceGetter(instr)) {
return;
}
- if ((op_kind == Token::kSET) &&
- TryInlineInstanceSetter(instr, unary_checks)) {
+ if ((op_kind == Token::kSET) && TryInlineInstanceSetter(instr)) {
return;
}
if (TryInlineInstanceMethod(instr)) {
return;
}
- const CallTargets& targets = *CallTargets::CreateAndExpand(Z, unary_checks);
-
bool has_one_target = targets.HasSingleTarget();
-
if (has_one_target) {
// Check if the single target is a polymorphic target, if it is,
// we don't have one target.
- const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0));
+ const Function& target = targets.FirstTarget();
if (target.recognized_kind() == MethodRecognizer::kObjectRuntimeType) {
has_one_target = PolymorphicInstanceCallInstr::ComputeRuntimeType(
targets) != Type::null();
@@ -141,12 +133,10 @@
}
if (has_one_target) {
- const Function& target =
- Function::ZoneHandle(Z, unary_checks.GetTargetAt(0));
+ const Function& target = targets.FirstTarget();
if (flow_graph()->CheckForInstanceCall(instr, target.kind()) ==
FlowGraph::ToCheck::kNoCheck) {
- ReplaceWithStaticCall(instr, unary_checks, target,
- targets.AggregateCallCount());
+ ReplaceWithStaticCall(instr, target, targets.AggregateCallCount());
return;
}
}
@@ -163,30 +153,13 @@
// non-deopting megamorphic call stub when it sees new receiver classes.
if (has_one_target && FLAG_polymorphic_with_deopt &&
(!instr->ic_data()->HasDeoptReason(ICData::kDeoptCheckClass) ||
- unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) {
+ targets.length() <= FLAG_max_polymorphic_checks)) {
// Type propagation has not run yet, we cannot eliminate the check.
- // TODO(erikcorry): The receiver check should use the off-heap targets
- // array, not the IC array.
-
- // After we determined `targets.HasSingleTarget()` the mutator might have
- // updated the megamorphic cache by adding more entries with *different*
- // targets.
- //
- // We therefore have to ensure the class check we insert is only valid for
- // precisely the [targets] classes we have based our decision upon.
- //
- // (i.e. we cannot use [AddReceiverCheck]/[AddCheckClass], since it
- // internally consults megmorphic cache again, which can return a superset
- // of the classes - possibly with different targets)
- //
- AddCheckClass(instr->Receiver()->definition(), targets, instr->deopt_id(),
- instr->env(), instr);
+ AddReceiverCheck(instr);
// Call can still deoptimize, do not detach environment from instr.
- const Function& target =
- Function::ZoneHandle(Z, unary_checks.GetTargetAt(0));
- ReplaceWithStaticCall(instr, unary_checks, target,
- targets.AggregateCallCount());
+ const Function& target = targets.FirstTarget();
+ ReplaceWithStaticCall(instr, target, targets.AggregateCallCount());
} else {
PolymorphicInstanceCallInstr* call =
new (Z) PolymorphicInstanceCallInstr(instr, targets,
diff --git a/runtime/vm/compiler/jit/jit_call_specializer.h b/runtime/vm/compiler/jit/jit_call_specializer.h
index 19c1aae..ea35fa9 100644
--- a/runtime/vm/compiler/jit/jit_call_specializer.h
+++ b/runtime/vm/compiler/jit/jit_call_specializer.h
@@ -36,7 +36,6 @@
Value* context_value);
void ReplaceWithStaticCall(InstanceCallInstr* instr,
- const ICData& unary_checks,
const Function& target,
intptr_t call_count);
diff --git a/runtime/vm/compiler/recognized_methods_list.h b/runtime/vm/compiler/recognized_methods_list.h
index 4b0c880..27e1bb1 100644
--- a/runtime/vm/compiler/recognized_methods_list.h
+++ b/runtime/vm/compiler/recognized_methods_list.h
@@ -145,6 +145,8 @@
V(::, _classRangeCheck, ClassRangeCheck, 0x2ae76b84) \
V(::, _asyncStackTraceHelper, AsyncStackTraceHelper, 0) \
V(::, _abi, FfiAbi, 0x0) \
+ V(::, _asFunctionInternal, FfiAsFunctionInternal, 0x0) \
+ V(::, _nativeCallbackFunction, FfiNativeCallbackFunction, 0x0) \
// List of intrinsics:
// (class-name, function-name, intrinsification method, fingerprint).
diff --git a/runtime/vm/compiler/runtime_api.cc b/runtime/vm/compiler/runtime_api.cc
index 1d651dc..e7f6f80 100644
--- a/runtime/vm/compiler/runtime_api.cc
+++ b/runtime/vm/compiler/runtime_api.cc
@@ -357,7 +357,7 @@
}
intptr_t Class::NumTypeArguments(const dart::Class& klass) {
- return klass.NumTypeArguments() > 0;
+ return klass.NumTypeArguments();
}
bool Class::HasTypeArgumentsField(const dart::Class& klass) {
diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h
index cb38030..ef2bc61 100644
--- a/runtime/vm/compiler/runtime_api.h
+++ b/runtime/vm/compiler/runtime_api.h
@@ -21,6 +21,7 @@
#include "platform/globals.h"
#include "vm/allocation.h"
#include "vm/bitfield.h"
+#include "vm/bss_relocs.h"
#include "vm/class_id.h"
#include "vm/code_entry_kind.h"
#include "vm/constants.h"
diff --git a/runtime/vm/compiler/stub_code_compiler_arm.cc b/runtime/vm/compiler/stub_code_compiler_arm.cc
index 2ab5d44..3e8a5a4 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm.cc
@@ -397,7 +397,7 @@
__ ldr(R1, Address(PC, 0));
__ b(&call);
__ Emit(
- reinterpret_cast<int32_t>(&DLRT_GetThreadForNativeCallbackTrampoline));
+ reinterpret_cast<intptr_t>(&DLRT_GetThreadForNativeCallbackTrampoline));
__ Bind(&call);
__ blx(R1);
diff --git a/runtime/vm/constants_kbc.h b/runtime/vm/constants_kbc.h
index bda63cc..f8d4489 100644
--- a/runtime/vm/constants_kbc.h
+++ b/runtime/vm/constants_kbc.h
@@ -745,11 +745,11 @@
// Magic value of bytecode files.
static const intptr_t kMagicValue = 0x44424332; // 'DBC2'
// Minimum bytecode format version supported by VM.
- static const intptr_t kMinSupportedBytecodeFormatVersion = 7;
+ static const intptr_t kMinSupportedBytecodeFormatVersion = 10;
// Maximum bytecode format version supported by VM.
// The range of supported versions should include version produced by bytecode
// generator (currentBytecodeFormatVersion in pkg/vm/lib/bytecode/dbc.dart).
- static const intptr_t kMaxSupportedBytecodeFormatVersion = 19;
+ static const intptr_t kMaxSupportedBytecodeFormatVersion = 20;
enum Opcode {
#define DECLARE_BYTECODE(name, encoding, kind, op1, op2, op3) k##name,
@@ -978,8 +978,6 @@
// - The bytecode compiler may emit a DebugStepCheck call.
DART_FORCE_INLINE static bool IsDebugCheckedOpcode(const KBCInstr* instr) {
switch (DecodeOpcode(instr)) {
- case KernelBytecode::kStoreStaticTOS:
- case KernelBytecode::kStoreStaticTOS_Wide:
case KernelBytecode::kDebugCheck:
case KernelBytecode::kDirectCall:
case KernelBytecode::kDirectCall_Wide:
@@ -994,7 +992,6 @@
case KernelBytecode::kDynamicCall:
case KernelBytecode::kDynamicCall_Wide:
case KernelBytecode::kReturnTOS:
- case KernelBytecode::kThrow:
case KernelBytecode::kEqualsNull:
case KernelBytecode::kNegateInt:
case KernelBytecode::kNegateDouble:
diff --git a/runtime/vm/cpu_arm.h b/runtime/vm/cpu_arm.h
index 35e7dd8..6f5b774 100644
--- a/runtime/vm/cpu_arm.h
+++ b/runtime/vm/cpu_arm.h
@@ -5,6 +5,10 @@
#ifndef RUNTIME_VM_CPU_ARM_H_
#define RUNTIME_VM_CPU_ARM_H_
+#if !defined(RUNTIME_VM_CPU_H_)
+#error Do not include cpu_arm.h directly; use cpu.h instead.
+#endif
+
#include "vm/allocation.h"
#include "vm/simulator.h"
diff --git a/runtime/vm/cpu_arm64.h b/runtime/vm/cpu_arm64.h
index 25481cb..5fa7b2e 100644
--- a/runtime/vm/cpu_arm64.h
+++ b/runtime/vm/cpu_arm64.h
@@ -5,6 +5,10 @@
#ifndef RUNTIME_VM_CPU_ARM64_H_
#define RUNTIME_VM_CPU_ARM64_H_
+#if !defined(RUNTIME_VM_CPU_H_)
+#error Do not include cpu_arm64.h directly; use cpu.h instead.
+#endif
+
#include "vm/allocation.h"
#include "vm/simulator.h"
diff --git a/runtime/vm/cpu_dbc.h b/runtime/vm/cpu_dbc.h
index 08a4a83..5e0064b 100644
--- a/runtime/vm/cpu_dbc.h
+++ b/runtime/vm/cpu_dbc.h
@@ -5,6 +5,10 @@
#ifndef RUNTIME_VM_CPU_DBC_H_
#define RUNTIME_VM_CPU_DBC_H_
+#if !defined(RUNTIME_VM_CPU_H_)
+#error Do not include cpu_dbc.h directly; use cpu.h instead.
+#endif
+
#include "vm/allocation.h"
#include "vm/simulator.h"
diff --git a/runtime/vm/cpu_ia32.h b/runtime/vm/cpu_ia32.h
index d486327..a740fb5 100644
--- a/runtime/vm/cpu_ia32.h
+++ b/runtime/vm/cpu_ia32.h
@@ -5,6 +5,10 @@
#ifndef RUNTIME_VM_CPU_IA32_H_
#define RUNTIME_VM_CPU_IA32_H_
+#if !defined(RUNTIME_VM_CPU_H_)
+#error Do not include cpu_ia32.h directly; use cpu.h instead.
+#endif
+
#include "vm/allocation.h"
#include "vm/flags.h"
diff --git a/runtime/vm/cpu_x64.h b/runtime/vm/cpu_x64.h
index 716c5880..e87d2d5 100644
--- a/runtime/vm/cpu_x64.h
+++ b/runtime/vm/cpu_x64.h
@@ -5,6 +5,10 @@
#ifndef RUNTIME_VM_CPU_X64_H_
#define RUNTIME_VM_CPU_X64_H_
+#if !defined(RUNTIME_VM_CPU_H_)
+#error Do not include cpu_x64.h directly; use cpu.h instead.
+#endif
+
#include "vm/allocation.h"
#include "vm/flags.h"
diff --git a/runtime/vm/custom_isolate_test.cc b/runtime/vm/custom_isolate_test.cc
index cf87025..a9c024d 100644
--- a/runtime/vm/custom_isolate_test.cc
+++ b/runtime/vm/custom_isolate_test.cc
@@ -242,7 +242,7 @@
EXPECT_VALID(toString);
const char* c_str = NULL;
EXPECT_VALID(Dart_StringToCString(toString, &c_str));
- if (saved_echo) {
+ if (saved_echo != nullptr) {
free(saved_echo);
}
saved_echo = strdup(c_str);
@@ -333,7 +333,7 @@
OS::PrintErr("-- Starting event loop --\n");
Event* event = event_queue->Get();
- while (event) {
+ while (event != nullptr) {
event->Process();
delete event;
event = event_queue->Get();
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index cc408ee..59f903a 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -648,7 +648,7 @@
// Initialize the new isolate.
Thread* T = Thread::Current();
Isolate* I = T->isolate();
-#if defined(SUPPORT_TIMLINE)
+#if defined(SUPPORT_TIMELINE)
TimelineDurationScope tds(T, Timeline::GetIsolateStream(),
"InitializeIsolate");
tds.SetNumArguments(1);
@@ -859,6 +859,14 @@
#else
#error What architecture?
#endif
+ } else {
+#if defined(ARCH_IS_32_BIT)
+ buffer.AddString(" 32-bit");
+#elif defined(ARCH_IS_64_BIT)
+ buffer.AddString(" 64-bit");
+#else
+#error What word size?
+#endif
}
if (FLAG_precompiled_mode && FLAG_dwarf_stack_traces) {
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index fc9608a..4b259aa 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1643,10 +1643,6 @@
DARTSCOPE(Thread::Current());
API_TIMELINE_DURATION(T);
Isolate* I = T->isolate();
- if (!FLAG_load_deferred_eagerly) {
- return Api::NewError(
- "Creating full snapshots requires --load_deferred_eagerly");
- }
if (vm_snapshot_data_buffer != NULL && vm_snapshot_data_size == NULL) {
RETURN_NULL_ERROR(vm_snapshot_data_size);
}
@@ -1670,10 +1666,21 @@
Symbols::Compact();
+ uint8_t* vm_snapshot_instruction_buffer = nullptr;
+ BlobImageWriter vm_image_writer(T, &vm_snapshot_instruction_buffer,
+ ApiReallocate, 2 * MB /* initial_size */,
+ /*shared_objects=*/nullptr,
+ /*shared_instructions=*/nullptr,
+ /*reused_instructions=*/nullptr);
+ uint8_t* isolate_snapshot_instruction_buffer = nullptr;
+ BlobImageWriter isolate_image_writer(T, &isolate_snapshot_instruction_buffer,
+ ApiReallocate, 2 * MB /* initial_size */,
+ /*shared_objects=*/nullptr,
+ /*shared_instructions=*/nullptr,
+ /*reused_instructions=*/nullptr);
FullSnapshotWriter writer(Snapshot::kFull, vm_snapshot_data_buffer,
isolate_snapshot_data_buffer, ApiReallocate,
- NULL /* vm_image_writer */,
- NULL /* isolate_image_writer */);
+ &vm_image_writer, &isolate_image_writer);
writer.WriteFullSnapshot();
if (vm_snapshot_data_buffer != NULL) {
*vm_snapshot_data_size = writer.VmIsolateSnapshotSize();
@@ -5392,7 +5399,6 @@
DART_EXPORT Dart_Handle Dart_LibraryHandleError(Dart_Handle library_in,
Dart_Handle error_in) {
DARTSCOPE(Thread::Current());
- Isolate* I = T->isolate();
const Library& lib = Api::UnwrapLibraryHandle(Z, library_in);
if (lib.IsNull()) {
@@ -5404,15 +5410,6 @@
}
CHECK_CALLBACK_STATE(T);
- const GrowableObjectArray& pending_deferred_loads =
- GrowableObjectArray::Handle(Z,
- I->object_store()->pending_deferred_loads());
- for (intptr_t i = 0; i < pending_deferred_loads.Length(); i++) {
- if (pending_deferred_loads.At(i) == lib.raw()) {
- lib.SetLoadError(err);
- return Api::Null();
- }
- }
return error_in;
}
@@ -5503,9 +5500,6 @@
// instead of freelists.
BumpAllocateScope bump_allocate_scope(T);
- // TODO(hausner): move the remaining code below (finalization and
- // invoking of _completeDeferredLoads) into Isolate::DoneLoading().
-
// Finalize all classes if needed.
Dart_Handle state = Api::CheckAndFinalizePendingClasses(T);
if (Api::IsError(state)) {
@@ -5534,22 +5528,6 @@
}
#endif
- if (complete_futures) {
- const Library& corelib = Library::Handle(Z, Library::CoreLibrary());
- const String& function_name =
- String::Handle(Z, String::New("_completeDeferredLoads"));
- const Function& function =
- Function::Handle(Z, corelib.LookupFunctionAllowPrivate(function_name));
- ASSERT(!function.IsNull());
- const Array& args = Array::empty_array();
-
- const Object& res =
- Object::Handle(Z, DartEntry::InvokeFunction(function, args));
- I->object_store()->clear_pending_deferred_loads();
- if (res.IsError() || res.IsUnhandledException()) {
- return Api::NewHandle(T, res.raw());
- }
- }
return Api::Success();
}
@@ -6160,7 +6138,6 @@
"Isolate is not precompiled. "
"Did you forget to call Dart_Precompile?");
}
- ASSERT(FLAG_load_deferred_eagerly);
CHECK_NULL(callback);
TIMELINE_DURATION(T, Isolate, "WriteAppAOTSnapshot");
@@ -6296,7 +6273,6 @@
"Isolate is not precompiled. "
"Did you forget to call Dart_Precompile?");
}
- ASSERT(FLAG_load_deferred_eagerly);
CHECK_NULL(vm_snapshot_data_buffer);
CHECK_NULL(vm_snapshot_data_size);
CHECK_NULL(vm_snapshot_instructions_buffer);
@@ -6400,10 +6376,6 @@
DARTSCOPE(Thread::Current());
API_TIMELINE_DURATION(T);
Isolate* I = T->isolate();
- if (!FLAG_load_deferred_eagerly) {
- return Api::NewError(
- "Creating full snapshots requires --load_deferred_eagerly");
- }
CHECK_NULL(vm_snapshot_data_buffer);
CHECK_NULL(vm_snapshot_data_size);
CHECK_NULL(vm_snapshot_instructions_buffer);
@@ -6463,10 +6435,6 @@
DARTSCOPE(Thread::Current());
API_TIMELINE_DURATION(T);
Isolate* I = T->isolate();
- if (!FLAG_load_deferred_eagerly) {
- return Api::NewError(
- "Creating full snapshots requires --load_deferred_eagerly");
- }
CHECK_NULL(isolate_snapshot_data_buffer);
CHECK_NULL(isolate_snapshot_data_size);
CHECK_NULL(isolate_snapshot_instructions_buffer);
@@ -6479,7 +6447,7 @@
BackgroundCompiler::Stop(I);
DropRegExpMatchCode(Z);
- if (reused_instructions) {
+ if (reused_instructions != nullptr) {
DropCodeWithoutReusableInstructions(reused_instructions);
}
ProgramVisitor::Dedup();
@@ -6506,7 +6474,7 @@
*isolate_snapshot_instructions_size =
isolate_image_writer.InstructionsBlobSize();
- if (reused_instructions) {
+ if (reused_instructions != nullptr) {
*isolate_snapshot_instructions_buffer = NULL;
}
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index bf716b7..5d444dc 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -4509,9 +4509,9 @@
}
const char* function_name = obj.ToCString();
ASSERT(function_name != NULL);
- if (!strcmp(function_name, "TestNativeFieldsAccess_init")) {
+ if (strcmp(function_name, "TestNativeFieldsAccess_init") == 0) {
return reinterpret_cast<Dart_NativeFunction>(&TestNativeFieldsAccess_init);
- } else if (!strcmp(function_name, "TestNativeFieldsAccess_access")) {
+ } else if (strcmp(function_name, "TestNativeFieldsAccess_access") == 0) {
return reinterpret_cast<Dart_NativeFunction>(
&TestNativeFieldsAccess_access);
} else {
@@ -5754,9 +5754,9 @@
*auto_scope_setup = true;
const char* function_name = obj.ToCString();
ASSERT(function_name != NULL);
- if (!strcmp(function_name, "NativeArgument_Create")) {
+ if (strcmp(function_name, "NativeArgument_Create") == 0) {
return reinterpret_cast<Dart_NativeFunction>(&NativeArgumentCreate);
- } else if (!strcmp(function_name, "NativeArgument_Access")) {
+ } else if (strcmp(function_name, "NativeArgument_Access") == 0) {
return reinterpret_cast<Dart_NativeFunction>(&NativeArgumentAccess);
}
return NULL;
@@ -6958,13 +6958,13 @@
const char* kNativeFoo2 = "NativeFoo2";
const char* kNativeFoo3 = "NativeFoo3";
const char* kNativeFoo4 = "NativeFoo4";
- if (!strncmp(function_name, kNativeFoo1, strlen(kNativeFoo1))) {
+ if (strncmp(function_name, kNativeFoo1, strlen(kNativeFoo1)) == 0) {
return &NativeFoo1;
- } else if (!strncmp(function_name, kNativeFoo2, strlen(kNativeFoo2))) {
+ } else if (strncmp(function_name, kNativeFoo2, strlen(kNativeFoo2)) == 0) {
return &NativeFoo2;
- } else if (!strncmp(function_name, kNativeFoo3, strlen(kNativeFoo3))) {
+ } else if (strncmp(function_name, kNativeFoo3, strlen(kNativeFoo3)) == 0) {
return &NativeFoo3;
- } else if (!strncmp(function_name, kNativeFoo4, strlen(kNativeFoo4))) {
+ } else if (strncmp(function_name, kNativeFoo4, strlen(kNativeFoo4)) == 0) {
return &NativeFoo4;
} else {
UNREACHABLE();
@@ -7098,13 +7098,13 @@
const char* kNativeFoo2 = "StaticNativeFoo2";
const char* kNativeFoo3 = "StaticNativeFoo3";
const char* kNativeFoo4 = "StaticNativeFoo4";
- if (!strncmp(function_name, kNativeFoo1, strlen(kNativeFoo1))) {
+ if (strncmp(function_name, kNativeFoo1, strlen(kNativeFoo1)) == 0) {
return &StaticNativeFoo1;
- } else if (!strncmp(function_name, kNativeFoo2, strlen(kNativeFoo2))) {
+ } else if (strncmp(function_name, kNativeFoo2, strlen(kNativeFoo2)) == 0) {
return &StaticNativeFoo2;
- } else if (!strncmp(function_name, kNativeFoo3, strlen(kNativeFoo3))) {
+ } else if (strncmp(function_name, kNativeFoo3, strlen(kNativeFoo3)) == 0) {
return &StaticNativeFoo3;
- } else if (!strncmp(function_name, kNativeFoo4, strlen(kNativeFoo4))) {
+ } else if (strncmp(function_name, kNativeFoo4, strlen(kNativeFoo4)) == 0) {
return &StaticNativeFoo4;
} else {
UNREACHABLE();
diff --git a/runtime/vm/dart_api_message.cc b/runtime/vm/dart_api_message.cc
index ee4aa1d..e598ded 100644
--- a/runtime/vm/dart_api_message.cc
+++ b/runtime/vm/dart_api_message.cc
@@ -2,6 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+#include <memory>
+
#include "vm/dart_api_message.h"
#include "platform/unicode.h"
#include "vm/object.h"
@@ -557,29 +559,43 @@
return object;
}
-#define READ_TYPED_DATA_HEADER(type) \
- intptr_t len = ReadSmiValue(); \
- Dart_CObject* object = \
- AllocateDartCObjectTypedData(Dart_TypedData_k##type, len); \
- AddBackRef(object_id, object, kIsDeserialized);
-
-#define READ_TYPED_DATA(type, ctype) \
+#define READ_TYPED_DATA(tname, ctype) \
{ \
- READ_TYPED_DATA_HEADER(type); \
- uint8_t* p = \
- reinterpret_cast<uint8_t*>(object->value.as_typed_data.values); \
- ReadBytes(p, len * sizeof(ctype)); \
+ intptr_t len = ReadSmiValue(); \
+ auto type = Dart_TypedData_k##tname; \
+ intptr_t length_in_bytes = GetTypedDataSizeInBytes(type) * len; \
+ Dart_CObject* object = \
+ reinterpret_cast<Dart_CObject*>(allocator(sizeof(Dart_CObject))); \
+ ASSERT(object != NULL); \
+ object->type = Dart_CObject_kTypedData; \
+ object->value.as_typed_data.type = type; \
+ object->value.as_typed_data.length = length_in_bytes; \
+ if (len > 0) { \
+ Align(Zone::kAlignment); \
+ object->value.as_typed_data.values = \
+ const_cast<uint8_t*>(CurrentBufferAddress()); \
+ Advance(length_in_bytes); \
+ } else { \
+ object->value.as_typed_data.values = NULL; \
+ } \
+ AddBackRef(object_id, object, kIsDeserialized); \
return object; \
}
-#define READ_EXTERNAL_TYPED_DATA(type, ctype) \
+#define READ_EXTERNAL_TYPED_DATA(tname, ctype) \
{ \
- READ_TYPED_DATA_HEADER(type); \
- uint8_t* p = \
- reinterpret_cast<uint8_t*>(object->value.as_typed_data.values); \
- FinalizableData finalizable_data = finalizable_data_->Take(); \
- memmove(p, finalizable_data.data, len * sizeof(ctype)); \
- finalizable_data.callback(NULL, NULL, finalizable_data.peer); \
+ intptr_t len = ReadSmiValue(); \
+ auto type = Dart_TypedData_k##tname; \
+ intptr_t length_in_bytes = GetTypedDataSizeInBytes(type) * len; \
+ Dart_CObject* object = \
+ reinterpret_cast<Dart_CObject*>(allocator(sizeof(Dart_CObject))); \
+ ASSERT(object != NULL); \
+ object->type = Dart_CObject_kTypedData; \
+ object->value.as_typed_data.type = type; \
+ object->value.as_typed_data.length = length_in_bytes; \
+ object->value.as_typed_data.values = \
+ reinterpret_cast<uint8_t*>(finalizable_data_->Get().data); \
+ AddBackRef(object_id, object, kIsDeserialized); \
return object; \
}
@@ -635,7 +651,6 @@
#undef READ_TYPED_DATA
#undef READ_EXTERNAL_TYPED_DATA
#undef READ_TYPED_DATA_VIEW
-#undef READ_TYPED_DATA_HEADER
case kGrowableObjectArrayCid: {
// A GrowableObjectArray is serialized as its type arguments and
@@ -1069,11 +1084,13 @@
case kTypedDataInt8ArrayCid:
case kTypedDataUint8ArrayCid: {
uint8_t* bytes = object->value.as_typed_data.values;
+ Align(Zone::kAlignment);
WriteBytes(bytes, len);
break;
}
case kTypedDataUint32ArrayCid: {
uint8_t* bytes = object->value.as_typed_data.values;
+ Align(Zone::kAlignment);
WriteBytes(bytes, len * sizeof(uint32_t));
break;
}
diff --git a/runtime/vm/datastream.h b/runtime/vm/datastream.h
index 13bd393..da4c450 100644
--- a/runtime/vm/datastream.h
+++ b/runtime/vm/datastream.h
@@ -89,7 +89,7 @@
const uint8_t* AddressOfCurrentPosition() const { return current_; }
void Advance(intptr_t value) {
- ASSERT((end_ - current_) > value);
+ ASSERT((end_ - current_) >= value);
current_ = current_ + value;
}
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 81d31da..0dd231a 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -841,6 +841,8 @@
return Object::null();
}
GetVarDescriptors();
+ intptr_t var_ctxt_level = -1;
+ intptr_t ctxt_slot = -1;
intptr_t var_desc_len = var_descriptors_.Length();
for (intptr_t i = 0; i < var_desc_len; i++) {
RawLocalVarDescriptors::VarInfo var_info;
@@ -855,21 +857,29 @@
return GetStackVar(variable_index);
} else {
ASSERT(kind == RawLocalVarDescriptors::kContextVar);
- if (!live_frame_) {
- ASSERT(!ctx_.IsNull());
- // Compiled code uses relative context levels, i.e. the frame context
- // level is always 0 on entry.
- // Bytecode uses absolute context levels, i.e. the frame context level
- // on entry must be calculated.
- const intptr_t frame_ctx_level =
- function().is_declared_in_bytecode() ? ctx_.GetLevel() : 0;
- return GetRelativeContextVar(var_info.scope_id,
- variable_index.value(), frame_ctx_level);
+ // Variable descriptors constructed from bytecode have all variables of
+ // enclosing functions, even shadowed by the current function.
+ // Pick the variable with the highest context level.
+ if (var_info.scope_id > var_ctxt_level) {
+ var_ctxt_level = var_info.scope_id;
+ ctxt_slot = variable_index.value();
}
- return GetContextVar(var_info.scope_id, variable_index.value());
}
}
}
+ if (var_ctxt_level >= 0) {
+ if (!live_frame_) {
+ ASSERT(!ctx_.IsNull());
+ // Compiled code uses relative context levels, i.e. the frame context
+ // level is always 0 on entry.
+ // Bytecode uses absolute context levels, i.e. the frame context level
+ // on entry must be calculated.
+ const intptr_t frame_ctx_level =
+ function().is_declared_in_bytecode() ? ctx_.GetLevel() : 0;
+ return GetRelativeContextVar(var_ctxt_level, ctxt_slot, frame_ctx_level);
+ }
+ return GetContextVar(var_ctxt_level, ctxt_slot);
+ }
return Object::null();
}
@@ -987,6 +997,8 @@
intptr_t ActivationFrame::GetAwaitJumpVariable() {
GetVarDescriptors();
+ intptr_t var_ctxt_level = -1;
+ intptr_t ctxt_slot = -1;
intptr_t var_desc_len = var_descriptors_.Length();
intptr_t await_jump_var = -1;
for (intptr_t i = 0; i < var_desc_len; i++) {
@@ -998,16 +1010,18 @@
ASSERT(!ctx_.IsNull());
// Variable descriptors constructed from bytecode have all variables of
// enclosing functions, even shadowed by the current function.
- // Check context level in order to pick correct :await_jump_var variable.
- if (function().is_declared_in_bytecode() &&
- (ctx_.GetLevel() != var_info.scope_id)) {
- continue;
+ // Pick the :await_jump_var variable with the highest context level.
+ if (var_info.scope_id > var_ctxt_level) {
+ var_ctxt_level = var_info.scope_id;
+ ctxt_slot = var_info.index();
}
- Object& await_jump_index = Object::Handle(ctx_.At(var_info.index()));
- ASSERT(await_jump_index.IsSmi());
- await_jump_var = Smi::Cast(await_jump_index).Value();
}
}
+ if (var_ctxt_level >= 0) {
+ Object& await_jump_index = Object::Handle(ctx_.At(ctxt_slot));
+ ASSERT(await_jump_index.IsSmi());
+ await_jump_var = Smi::Cast(await_jump_index).Value();
+ }
return await_jump_var;
}
@@ -1170,6 +1184,10 @@
const Instance& exc_obj) const {
for (intptr_t frame_index = 0; frame_index < Length(); frame_index++) {
ActivationFrame* frame = FrameAt(frame_index);
+ if (FLAG_trace_debugger_stacktrace) {
+ OS::PrintErr("GetHandlerFrame: #%04" Pd " %s", frame_index,
+ frame->ToCString());
+ }
if (frame->HandlesException(exc_obj)) {
return frame;
}
@@ -1592,6 +1610,10 @@
}
const char* ActivationFrame::ToCString() {
+ if (function().IsNull()) {
+ return Thread::Current()->zone()->PrintToString("[ Frame kind: %s]\n",
+ KindToCString(kind_));
+ }
const String& url = String::Handle(SourceUrl());
intptr_t line = LineNumber();
const char* func_name = Debugger::QualifiedFunctionName(function());
@@ -1616,7 +1638,7 @@
"\turl = %s\n"
"\tline = %" Pd
"\n"
- "\tcontext = %s\n",
+ "\tcontext = %s]\n",
IsInterpreted() ? "bytecode" : "code", func_name, url.ToCString(), line,
ctx_.ToCString());
}
@@ -1945,7 +1967,7 @@
ActivationFrame* top_frame = TopDartFrame();
if (!IsAtAsyncJump(top_frame)) {
// Not at an async operation.
- if (error) {
+ if (error != nullptr) {
*error = "Isolate must be paused at an async suspension point";
}
return false;
@@ -1957,7 +1979,7 @@
Breakpoint* bpt = SetBreakpointAtActivation(Instance::Cast(closure), true);
if (bpt == NULL) {
// Unable to set the breakpoint.
- if (error) {
+ if (error != nullptr) {
*error = "Unable to set breakpoint at async suspension point";
}
return false;
@@ -1968,7 +1990,7 @@
bool Debugger::SetResumeAction(ResumeAction action,
intptr_t frame_index,
const char** error) {
- if (error) {
+ if (error != nullptr) {
*error = NULL;
}
resume_frame_index_ = -1;
@@ -2149,7 +2171,7 @@
RawArray* Debugger::DeoptimizeToArray(Thread* thread,
StackFrame* frame,
const Code& code) {
- ASSERT(code.is_optimized());
+ ASSERT(code.is_optimized() && !code.is_force_optimized());
Isolate* isolate = thread->isolate();
// Create the DeoptContext for this deoptimization.
DeoptContext* deopt_context =
@@ -2223,6 +2245,16 @@
Array* deopt_frame) {
#if !defined(DART_PRECOMPILED_RUNTIME)
if (code->is_optimized()) {
+ if (code->is_force_optimized()) {
+ if (FLAG_trace_debugger_stacktrace) {
+ const Function& function = Function::Handle(zone, code->function());
+ ASSERT(!function.IsNull());
+ OS::PrintErr(
+ "CollectStackTrace: skipping force-optimized function: %s\n",
+ function.ToFullyQualifiedCString());
+ }
+ return; // Skip frame of force-optimized (and non-debuggable) function.
+ }
// TODO(rmacnak): Use CodeSourceMap
*deopt_frame = DeoptimizeToArray(thread, frame, *code);
for (InlinedFunctionsIterator it(*code, frame->pc()); !it.Done();
@@ -2445,6 +2477,18 @@
} else {
code = frame->LookupDartCode();
if (code.is_optimized()) {
+ if (code.is_force_optimized()) {
+ if (FLAG_trace_debugger_stacktrace) {
+ function = code.function();
+ ASSERT(!function.IsNull());
+ OS::PrintErr(
+ "CollectAwaiterReturnStackTrace: "
+ "skipping force-optimized function: %s\n",
+ function.ToFullyQualifiedCString());
+ }
+ // Skip frame of force-optimized (and non-debuggable) function.
+ continue;
+ }
deopt_frame = DeoptimizeToArray(thread, frame, code);
bool found_async_awaiter = false;
bool abort_attempt_to_navigate_through_sync_async = false;
@@ -2469,8 +2513,8 @@
if (FLAG_trace_debugger_stacktrace) {
ASSERT(!function.IsNull());
OS::PrintErr(
- "CollectAwaiterReturnStackTrace: visiting inlined function: "
- "%s\n",
+ "CollectAwaiterReturnStackTrace: "
+ "visiting inlined function: %s\n ",
function.ToFullyQualifiedCString());
}
intptr_t deopt_frame_offset = it.GetDeoptFpOffset();
@@ -2982,7 +3026,8 @@
TokenPosition::kMaxSource;
while (iter2.MoveNext()) {
const TokenPosition next = iter2.TokenPos();
- if (next < next_closest_token_position && next > pos) {
+ if (next.IsReal() && next < next_closest_token_position &&
+ next > pos) {
next_closest_token_position = next;
}
}
@@ -3154,9 +3199,13 @@
pc = bytecode.GetDebugCheckedOpcodeReturnAddress(pc_offset,
iter.PcOffset());
pc_offset = kUwordMax;
- // TODO(regis): We may want to find all PCs for a token position,
- // e.g. in the case of duplicated bytecode in finally clauses.
- break;
+ if (pc != 0) {
+ // TODO(regis): We may want to find all PCs for a token position,
+ // e.g. in the case of duplicated bytecode in finally clauses.
+ break;
+ }
+ // This range does not contain a 'debug checked' opcode or the
+ // first DebugCheck opcode of the function is not reached yet.
}
if (iter.TokenPos() == loc->token_pos_) {
pc_offset = iter.PcOffset();
@@ -3177,6 +3226,12 @@
if (code_bpt == NULL) {
// No code breakpoint for this code exists; create one.
code_bpt = new CodeBreakpoint(bytecode, loc->token_pos_, pc);
+ if (FLAG_verbose_debug) {
+ OS::PrintErr("Setting bytecode breakpoint at pos %s pc %#" Px
+ " offset %#" Px "\n",
+ loc->token_pos_.ToCString(), pc,
+ pc - bytecode.PayloadStart());
+ }
RegisterCodeBreakpoint(code_bpt);
}
code_bpt->set_bpt_location(loc);
@@ -3210,6 +3265,12 @@
// No code breakpoint for this code exists; create one.
code_bpt =
new CodeBreakpoint(code, loc->token_pos_, lowest_pc, lowest_kind);
+ if (FLAG_verbose_debug) {
+ OS::PrintErr("Setting code breakpoint at pos %s pc %#" Px
+ " offset %#" Px "\n",
+ loc->token_pos_.ToCString(), lowest_pc,
+ lowest_pc - code.PayloadStart());
+ }
RegisterCodeBreakpoint(code_bpt);
}
code_bpt->set_bpt_location(loc);
@@ -3493,10 +3554,10 @@
intptr_t line_number;
intptr_t column_number;
script.GetTokenLocation(breakpoint_pos, &line_number, &column_number);
- OS::PrintErr(
- "Resolved BP for "
- "function '%s' at line %" Pd " col %" Pd "\n",
- func.ToFullyQualifiedCString(), line_number, column_number);
+ OS::PrintErr("Resolved %s breakpoint for function '%s' at line %" Pd
+ " col %" Pd "\n",
+ in_bytecode ? "bytecode" : "code",
+ func.ToFullyQualifiedCString(), line_number, column_number);
}
return loc;
}
@@ -3933,6 +3994,11 @@
// Step out to the awaiter.
ASSERT(async_op.IsClosure());
AsyncStepInto(Closure::Cast(async_op));
+ if (FLAG_verbose_debug) {
+ OS::PrintErr("HandleSteppingRequest- kContinue to async_op %s\n",
+ Function::Handle(Closure::Cast(async_op).function())
+ .ToFullyQualifiedCString());
+ }
return;
}
}
@@ -4007,7 +4073,7 @@
DebuggerStackTrace* stack = Isolate::Current()->debugger()->StackTrace();
intptr_t num_frames = stack->Length();
if (frame_index < 1 || frame_index >= num_frames) {
- if (error) {
+ if (error != nullptr) {
*error = Thread::Current()->zone()->PrintToString(
"Frame must be in bounds [1..%" Pd
"]: "
@@ -4703,8 +4769,8 @@
} else {
if (FLAG_verbose_debug) {
OS::PrintErr(
- "Pending BP remains unresolved in inner bytecode function "
- "'%s'\n",
+ "Pending breakpoint remains unresolved in "
+ "inner bytecode function '%s'\n",
inner_function.ToFullyQualifiedCString());
}
}
@@ -4716,7 +4782,8 @@
ASSERT(!inner_function.HasCode());
if (FLAG_verbose_debug) {
OS::PrintErr(
- "Pending BP remains unresolved in inner function '%s'\n",
+ "Pending breakpoint remains unresolved in "
+ "inner function '%s'\n",
inner_function.ToFullyQualifiedCString());
}
continue;
@@ -4730,6 +4797,8 @@
// There is no local function within func that contains the
// breakpoint token position. Resolve the breakpoint if necessary
// and set the code breakpoints.
+ const bool resolved_in_bytecode =
+ !bytecode_loaded && loc->IsResolved(/* in_bytecode = */ true);
if (!loc->IsResolved(bytecode_loaded)) {
// Resolve source breakpoint in the newly compiled function.
TokenPosition bp_pos = ResolveBreakpointPos(
@@ -4738,7 +4807,7 @@
if (!bp_pos.IsDebugPause()) {
if (FLAG_verbose_debug) {
OS::PrintErr("Failed resolving breakpoint for function '%s'\n",
- String::Handle(func.name()).ToCString());
+ func.ToFullyQualifiedCString());
}
continue;
}
@@ -4749,15 +4818,18 @@
while (bpt != NULL) {
if (FLAG_verbose_debug) {
OS::PrintErr(
- "Resolved BP %" Pd
- " to pos %s, "
- "function '%s' (requested range %s-%s, "
+ "Resolved breakpoint %" Pd
+ " to pos %s, function '%s' (requested range %s-%s, "
"requested col %" Pd ")\n",
bpt->id(), loc->token_pos().ToCString(),
func.ToFullyQualifiedCString(), requested_pos.ToCString(),
requested_end_pos.ToCString(), loc->requested_column_number());
}
- SendBreakpointEvent(ServiceEvent::kBreakpointResolved, bpt);
+ // Do not signal resolution in code if already signaled resolution
+ // in bytecode.
+ if (!resolved_in_bytecode) {
+ SendBreakpointEvent(ServiceEvent::kBreakpointResolved, bpt);
+ }
bpt = bpt->next();
}
}
@@ -4767,7 +4839,7 @@
while (bpt != NULL) {
OS::PrintErr("Setting breakpoint %" Pd " for %s '%s'\n", bpt->id(),
func.IsClosureFunction() ? "closure" : "function",
- String::Handle(func.name()).ToCString());
+ func.ToFullyQualifiedCString());
bpt = bpt->next();
}
}
diff --git a/runtime/vm/elf.cc b/runtime/vm/elf.cc
index 38a1d15..6306029 100644
--- a/runtime/vm/elf.cc
+++ b/runtime/vm/elf.cc
@@ -82,8 +82,6 @@
static const intptr_t kElfSymbolHashTableEntrySize = 4;
#endif
-static const intptr_t kPageSize = 4096;
-
class Section : public ZoneAllocated {
public:
Section() {}
@@ -115,23 +113,34 @@
public:
ProgramBits(bool allocate,
bool executable,
+ bool writable,
const uint8_t* bytes,
- intptr_t size) {
+ intptr_t filesz,
+ intptr_t memsz = -1) {
+ if (memsz == -1) memsz = filesz;
+
section_type = SHT_PROGBITS;
if (allocate) {
section_flags = SHF_ALLOC;
if (executable) section_flags |= SHF_EXECINSTR;
+ if (writable) section_flags |= SHF_WRITE;
segment_type = PT_LOAD;
segment_flags = PF_R;
if (executable) segment_flags |= PF_X;
+ if (writable) segment_flags |= PF_W;
}
bytes_ = bytes;
- file_size = memory_size = size;
+ file_size = filesz;
+ memory_size = memsz;
}
- void Write(Elf* stream) { stream->WriteBytes(bytes_, memory_size); }
+ void Write(Elf* stream) {
+ if (bytes_ != nullptr) {
+ stream->WriteBytes(bytes_, file_size);
+ }
+ }
const uint8_t* bytes_;
};
@@ -247,7 +256,7 @@
static uint32_t ElfHash(const unsigned char* name) {
uint32_t h = 0;
- while (*name) {
+ while (*name != '\0') {
h = (h << 4) + *name++;
uint32_t g = h & 0xf0000000;
h ^= g;
@@ -371,7 +380,7 @@
// Elf::segments_.
static const intptr_t kNumImplicitSegments = 3;
-static const intptr_t kProgramTableSegmentSize = kPageSize;
+static const intptr_t kProgramTableSegmentSize = Elf::kPageSize;
Elf::Elf(Zone* zone, StreamingWriteStream* stream)
: zone_(zone), stream_(stream), memory_offset_(0) {
@@ -415,7 +424,7 @@
}
intptr_t Elf::AddText(const char* name, const uint8_t* bytes, intptr_t size) {
- ProgramBits* image = new (zone_) ProgramBits(true, true, bytes, size);
+ ProgramBits* image = new (zone_) ProgramBits(true, true, false, bytes, size);
image->section_name = shstrtab_->AddString(".text");
AddSection(image);
AddSegment(image);
@@ -434,8 +443,29 @@
return symbol->offset;
}
+intptr_t Elf::AddBSSData(const char* name, intptr_t size) {
+ ProgramBits* image = new (zone_)
+ ProgramBits(true, false, true, nullptr, /*filesz=*/0, /*memsz=*/size);
+ image->section_name = shstrtab_->AddString(".bss");
+ AddSection(image);
+ AddSegment(image);
+
+ Symbol* symbol = new (zone_) Symbol();
+ symbol->cstr = name;
+ symbol->name = symstrtab_->AddString(name);
+ symbol->info = (STB_GLOBAL << 4) | STT_OBJECT;
+ symbol->section = image->section_index;
+ // For shared libraries, this is the offset from the DSO base. For static
+ // libraries, this is section relative.
+ symbol->offset = image->memory_offset;
+ symbol->size = size;
+ symtab_->AddSymbol(symbol);
+
+ return symbol->offset;
+}
+
intptr_t Elf::AddROData(const char* name, const uint8_t* bytes, intptr_t size) {
- ProgramBits* image = new (zone_) ProgramBits(true, false, bytes, size);
+ ProgramBits* image = new (zone_) ProgramBits(true, false, false, bytes, size);
image->section_name = shstrtab_->AddString(".rodata");
AddSection(image);
AddSegment(image);
@@ -455,7 +485,8 @@
}
void Elf::AddDebug(const char* name, const uint8_t* bytes, intptr_t size) {
- ProgramBits* image = new (zone_) ProgramBits(false, false, bytes, size);
+ ProgramBits* image =
+ new (zone_) ProgramBits(false, false, false, bytes, size);
image->section_name = shstrtab_->AddString(name);
AddSection(image);
}
diff --git a/runtime/vm/elf.h b/runtime/vm/elf.h
index d6d63b7..882c917 100644
--- a/runtime/vm/elf.h
+++ b/runtime/vm/elf.h
@@ -23,9 +23,12 @@
public:
Elf(Zone* zone, StreamingWriteStream* stream);
+ static const intptr_t kPageSize = 4096;
+
intptr_t NextMemoryOffset();
intptr_t AddText(const char* name, const uint8_t* bytes, intptr_t size);
intptr_t AddROData(const char* name, const uint8_t* bytes, intptr_t size);
+ intptr_t AddBSSData(const char* name, intptr_t size);
void AddDebug(const char* name, const uint8_t* bytes, intptr_t size);
void Finalize();
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index a341cad..aa3fd63 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -515,12 +515,16 @@
{
DartFrameIterator frames(thread,
StackFrameIterator::kNoCrossThreadIteration);
- StackFrame* frame = frames.NextFrame();
- while ((frame != NULL) && (frame->fp() < frame_pointer)) {
+ for (StackFrame* frame = frames.NextFrame(); frame != nullptr;
+ frame = frames.NextFrame()) {
+ if (frame->is_interpreted()) {
+ continue;
+ } else if (frame->fp() >= frame_pointer) {
+ break;
+ }
if (frame->IsMarkedForLazyDeopt()) {
frame->UnmarkForLazyDeopt();
}
- frame = frames.NextFrame();
}
}
diff --git a/runtime/vm/exceptions_test.cc b/runtime/vm/exceptions_test.cc
index fe090d6..722ffef 100644
--- a/runtime/vm/exceptions_test.cc
+++ b/runtime/vm/exceptions_test.cc
@@ -76,7 +76,7 @@
int num_entries = sizeof(BuiltinEntries) / sizeof(struct NativeEntries);
for (int i = 0; i < num_entries; i++) {
struct NativeEntries* entry = &(BuiltinEntries[i]);
- if (!strcmp(function_name, entry->name_) &&
+ if ((strcmp(function_name, entry->name_) == 0) &&
(argument_count == entry->argument_count_)) {
return reinterpret_cast<Dart_NativeFunction>(entry->function_);
}
diff --git a/runtime/vm/ffi_callback_trampolines.cc b/runtime/vm/ffi_callback_trampolines.cc
index 5516ddb..af987dc 100644
--- a/runtime/vm/ffi_callback_trampolines.cc
+++ b/runtime/vm/ffi_callback_trampolines.cc
@@ -14,7 +14,22 @@
DECLARE_FLAG(bool, disassemble_stubs);
#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(TARGET_ARCH_DBC)
-uword NativeCallbackTrampolines::AllocateTrampoline() {
+uword NativeCallbackTrampolines::TrampolineForId(int32_t callback_id) {
+#if defined(DART_PRECOMPILER)
+ ASSERT(!Enabled());
+ UNREACHABLE();
+#else
+ const intptr_t trampolines_per_page = NumCallbackTrampolinesPerPage();
+ const intptr_t page_index = callback_id / trampolines_per_page;
+ const uword entry_point = trampoline_pages_[page_index]->start();
+
+ return entry_point +
+ (callback_id % trampolines_per_page) *
+ compiler::StubCodeCompiler::kNativeCallbackTrampolineSize;
+#endif
+}
+
+void NativeCallbackTrampolines::AllocateTrampoline() {
#if defined(DART_PRECOMPILER)
ASSERT(!Enabled());
UNREACHABLE();
@@ -76,16 +91,11 @@
}
#endif
- next_callback_trampoline_ = memory->start();
trampolines_left_on_page_ = NumCallbackTrampolinesPerPage();
}
trampolines_left_on_page_--;
next_callback_id_++;
- const uword entrypoint = next_callback_trampoline_;
- next_callback_trampoline_ +=
- compiler::StubCodeCompiler::kNativeCallbackTrampolineSize;
- return entrypoint;
#endif // defined(DART_PRECOMPILER)
}
#endif // !defined(DART_PRECOMPILED_RUNTIME) && !defined(TARGET_ARCH_DBC)
diff --git a/runtime/vm/ffi_callback_trampolines.h b/runtime/vm/ffi_callback_trampolines.h
index 65c2a37ec..77822d5 100644
--- a/runtime/vm/ffi_callback_trampolines.h
+++ b/runtime/vm/ffi_callback_trampolines.h
@@ -57,11 +57,13 @@
// Allocates a callback trampoline corresponding to the callback id
// 'next_callback_id()'. Returns an entrypoint to the trampoline.
- uword AllocateTrampoline();
+ void AllocateTrampoline();
+
+ // Get the entrypoint for a previously allocated callback ID.
+ uword TrampolineForId(int32_t callback_id);
private:
MallocGrowableArray<VirtualMemory*> trampoline_pages_;
- uword next_callback_trampoline_ = 0;
intptr_t trampolines_left_on_page_ = 0;
intptr_t next_callback_id_ = 0;
diff --git a/runtime/vm/finalizable_data.h b/runtime/vm/finalizable_data.h
index df383d2..acea96c 100644
--- a/runtime/vm/finalizable_data.h
+++ b/runtime/vm/finalizable_data.h
@@ -20,10 +20,11 @@
class MessageFinalizableData {
public:
- MessageFinalizableData() : records_(0), position_(0), external_size_(0) {}
+ MessageFinalizableData()
+ : records_(0), get_position_(0), take_position_(0), external_size_(0) {}
~MessageFinalizableData() {
- for (intptr_t i = position_; i < records_.length(); i++) {
+ for (intptr_t i = take_position_; i < records_.length(); i++) {
records_[i].callback(nullptr, nullptr, records_[i].peer);
}
}
@@ -46,13 +47,22 @@
external_size_ += external_size;
}
+ // Retrieve the next FinalizableData, but still run its finalizer when |this|
+ // is destroyed.
+ FinalizableData Get() {
+ ASSERT(get_position_ < records_.length());
+ return records_[get_position_++];
+ }
+
+ // Retrieve the next FinalizableData, and skip its finalizer when |this| is
+ // destroyed.
FinalizableData Take() {
- ASSERT(position_ < records_.length());
- return records_[position_++];
+ ASSERT(take_position_ < records_.length());
+ return records_[take_position_++];
}
void SerializationSucceeded() {
- for (intptr_t i = position_; i < records_.length(); i++) {
+ for (intptr_t i = 0; i < records_.length(); i++) {
if (records_[i].successful_write_callback != nullptr) {
records_[i].successful_write_callback(nullptr, nullptr,
records_[i].peer);
@@ -64,7 +74,8 @@
private:
MallocGrowableArray<FinalizableData> records_;
- intptr_t position_;
+ intptr_t get_position_;
+ intptr_t take_position_;
intptr_t external_size_;
DISALLOW_COPY_AND_ASSIGN(MessageFinalizableData);
diff --git a/runtime/vm/flag_list.h b/runtime/vm/flag_list.h
index eb8434a..42d44cc 100644
--- a/runtime/vm/flag_list.h
+++ b/runtime/vm/flag_list.h
@@ -116,8 +116,6 @@
P(interpret_irregexp, bool, USING_DBC, "Use irregexp bytecode interpreter") \
P(lazy_dispatchers, bool, true, "Generate dispatchers lazily") \
P(link_natives_lazily, bool, false, "Link native calls lazily") \
- C(load_deferred_eagerly, true, true, bool, false, \
- "Load deferred libraries eagerly.") \
R(log_marker_tasks, false, bool, false, \
"Log debugging information for old gen GC marking tasks.") \
P(marker_tasks, int, USING_MULTICORE ? 2 : 0, \
diff --git a/runtime/vm/frame_layout.h b/runtime/vm/frame_layout.h
index 3242353..4327050 100644
--- a/runtime/vm/frame_layout.h
+++ b/runtime/vm/frame_layout.h
@@ -5,6 +5,9 @@
#ifndef RUNTIME_VM_FRAME_LAYOUT_H_
#define RUNTIME_VM_FRAME_LAYOUT_H_
+#include "platform/assert.h"
+#include "platform/globals.h"
+
// FrameLayout structure captures configuration specific properties of the
// frame layout used by the runtime system and compiler.
//
diff --git a/runtime/vm/gdb_helpers.cc b/runtime/vm/gdb_helpers.cc
index 44ba132..b32297c 100644
--- a/runtime/vm/gdb_helpers.cc
+++ b/runtime/vm/gdb_helpers.cc
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
#include "lib/stacktrace.h"
+#include "vm/heap/safepoint.h"
#include "vm/object.h"
#include "vm/stack_frame.h"
@@ -39,12 +40,48 @@
Thread::Current(),
StackFrameIterator::kNoCrossThreadIteration);
StackFrame* frame = frames.NextFrame();
- while (frame != NULL) {
+ while (frame != nullptr) {
OS::PrintErr("%s\n", frame->ToCString());
frame = frames.NextFrame();
}
}
+#if !defined(TARGET_ARCH_DBC)
+// Like _printDartStackTrace, but works when stopped in generated code.
+// Must be called with the current fp, sp, and pc.
+DART_EXPORT
+void _printGeneratedStackTrace(uword fp, uword sp, uword pc) {
+ StackFrameIterator frames(fp, sp, pc, ValidationPolicy::kDontValidateFrames,
+ Thread::Current(),
+ StackFrameIterator::kNoCrossThreadIteration);
+ StackFrame* frame = frames.NextFrame();
+ while (frame != nullptr) {
+ OS::PrintErr("%s\n", frame->ToCString());
+ frame = frames.NextFrame();
+ }
+}
+
+// Like _printDartStackTrace, but works in the interpreter loop.
+// Must be called with the current interpreter fp, sp, and pc.
+// Note that sp[0] is not modified, but sp[1] will be trashed.
+DART_EXPORT
+void _printInterpreterStackTrace(RawObject** fp,
+ RawObject** sp,
+ const KBCInstr* pc) {
+ Thread* thread = Thread::Current();
+ sp[1] = Function::null();
+ sp[2] = Bytecode::null();
+ sp[3] = reinterpret_cast<RawObject*>(reinterpret_cast<uword>(pc));
+ sp[4] = reinterpret_cast<RawObject*>(fp);
+ RawObject** exit_fp = sp + 1 + kKBCDartFrameFixedSize;
+ thread->set_top_exit_frame_info(reinterpret_cast<uword>(exit_fp));
+ thread->set_execution_state(Thread::kThreadInVM);
+ _printDartStackTrace();
+ thread->set_execution_state(Thread::kThreadInGenerated);
+ thread->set_top_exit_frame_info(0);
+}
+#endif // !defined(TARGET_ARCH_DBC)
+
class PrintObjectPointersVisitor : public ObjectPointerVisitor {
public:
PrintObjectPointersVisitor() : ObjectPointerVisitor(Isolate::Current()) {}
@@ -64,7 +101,7 @@
Thread::Current(),
StackFrameIterator::kNoCrossThreadIteration);
StackFrame* frame = frames.NextFrame();
- while (frame != NULL) {
+ while (frame != nullptr) {
OS::PrintErr("%s\n", frame->ToCString());
frame->VisitObjectPointers(&visitor);
frame = frames.NextFrame();
diff --git a/runtime/vm/hash.h b/runtime/vm/hash.h
index b4fc808..cbd4c83 100644
--- a/runtime/vm/hash.h
+++ b/runtime/vm/hash.h
@@ -5,6 +5,8 @@
#ifndef RUNTIME_VM_HASH_H_
#define RUNTIME_VM_HASH_H_
+#include "platform/globals.h"
+
namespace dart {
inline uint32_t CombineHashes(uint32_t hash, uint32_t other_hash) {
diff --git a/runtime/vm/hash_map.h b/runtime/vm/hash_map.h
index 4f2efda..04bfdd1 100644
--- a/runtime/vm/hash_map.h
+++ b/runtime/vm/hash_map.h
@@ -6,6 +6,7 @@
#define RUNTIME_VM_HASH_MAP_H_
#include "vm/growable_array.h" // For Malloc, EmptyBase
+#include "vm/hash.h"
#include "vm/zone.h"
namespace dart {
@@ -34,9 +35,19 @@
allocator_->template Free<HashMapListElement>(lists_, lists_size_);
}
+ // Assumes that no existing pair in the map has a key equal to [kv.key].
void Insert(typename KeyValueTrait::Pair kv);
bool Remove(typename KeyValueTrait::Key key);
+ // If a pair already exists in the map with an equal key, replace that pair
+ // with this one. Otherwise, insert the pair as a new entry.
+ //
+ // Note: Insert operates in constant time, while Update must walk the chained
+ // entries for a given hash value, checking keys for equality. However, if
+ // multiple value updates are needed for the same key, only using Update
+ // guarantees constant space usage whereas Insert does not.
+ void Update(typename KeyValueTrait::Pair kv);
+
typename KeyValueTrait::Value LookupValue(
typename KeyValueTrait::Key key) const;
@@ -286,6 +297,8 @@
KeyValueTrait::ValueOf(typename KeyValueTrait::Pair());
ASSERT(KeyValueTrait::ValueOf(kv) != kNoValue);
+ // TODO(dartbug.com/38018): Add assert that Lookup returns nullptr for key.
+
// Resizing when half of the hashtable is filled up.
if (count_ >= array_size_ >> 1) Resize(array_size_ << 1);
ASSERT(count_ < array_size_);
@@ -311,13 +324,31 @@
}
template <typename KeyValueTrait, typename B, typename Allocator>
+void BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::Update(
+ typename KeyValueTrait::Pair kv) {
+ const typename KeyValueTrait::Value kNoValue =
+ KeyValueTrait::ValueOf(typename KeyValueTrait::Pair());
+
+ ASSERT(KeyValueTrait::ValueOf(kv) != kNoValue);
+ if (auto const old_kv = Lookup(KeyValueTrait::KeyOf(kv))) {
+ *old_kv = kv;
+ } else {
+ Insert(kv);
+ }
+}
+
+template <typename KeyValueTrait, typename B, typename Allocator>
bool BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::Remove(
typename KeyValueTrait::Key key) {
+ const typename KeyValueTrait::Value kNoValue =
+ KeyValueTrait::ValueOf(typename KeyValueTrait::Pair());
+
uword pos = Bound(static_cast<uword>(KeyValueTrait::Hashcode(key)));
// Check to see if the first element in the bucket is the one we want to
// remove.
- if (KeyValueTrait::KeyOf(array_[pos].kv) == key) {
+ if (KeyValueTrait::ValueOf(array_[pos].kv) == kNoValue) return false;
+ if (KeyValueTrait::IsKeyEqual(array_[pos].kv, key)) {
if (array_[pos].next == kNil) {
array_[pos] = HashMapListElement();
} else {
@@ -341,7 +372,7 @@
// Check the case where the second element in the bucket is the one to be
// removed.
- if (KeyValueTrait::KeyOf(lists_[current].kv) == key) {
+ if (KeyValueTrait::IsKeyEqual(lists_[current].kv, key)) {
array_[pos].next = lists_[current].next;
lists_[current] = HashMapListElement();
lists_[current].next = free_list_head_;
@@ -353,7 +384,7 @@
// Finally, iterate through the rest of the bucket to see if we can find the
// entry that matches our key.
intptr_t previous;
- while (KeyValueTrait::KeyOf(lists_[current].kv) != key) {
+ while (!KeyValueTrait::IsKeyEqual(lists_[current].kv, key)) {
previous = current;
current = lists_[current].next;
@@ -459,6 +490,38 @@
};
template <typename V>
+class CStringKeyValueTrait : public RawPointerKeyValueTrait<const char, V> {
+ public:
+ typedef typename RawPointerKeyValueTrait<const char, V>::Key Key;
+ typedef typename RawPointerKeyValueTrait<const char, V>::Value Value;
+ typedef typename RawPointerKeyValueTrait<const char, V>::Pair Pair;
+
+ static intptr_t Hashcode(Key key) {
+ ASSERT(key != nullptr);
+ intptr_t hash = 0;
+ for (size_t i = 0; i < strlen(key); i++) {
+ hash = CombineHashes(hash, key[i]);
+ }
+ return FinalizeHash(hash, kBitsPerWord - 1);
+ }
+ static bool IsKeyEqual(Pair kv, Key key) {
+ ASSERT(kv.key != nullptr && key != nullptr);
+ return kv.key == key || strcmp(kv.key, key) == 0;
+ }
+};
+
+template <typename V>
+class CStringMap : public DirectChainedHashMap<CStringKeyValueTrait<V>> {
+ public:
+ CStringMap() : DirectChainedHashMap<CStringKeyValueTrait<V>>() {}
+ explicit CStringMap(Zone* zone)
+ : DirectChainedHashMap<CStringKeyValueTrait<V>>(zone) {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CStringMap);
+};
+
+template <typename V>
class IntKeyRawPointerValueTrait {
public:
typedef intptr_t Key;
diff --git a/runtime/vm/hash_map_test.cc b/runtime/vm/hash_map_test.cc
index 6a1e4f3..a040869 100644
--- a/runtime/vm/hash_map_test.cc
+++ b/runtime/vm/hash_map_test.cc
@@ -172,4 +172,132 @@
EXPECT(sum == 15);
}
+TEST_CASE(CStringMap) {
+ const char* const kConst1 = "test";
+ const char* const kConst2 = "test 2";
+
+ char* const str1 = OS::SCreate(nullptr, "%s", kConst1);
+ char* const str2 = OS::SCreate(nullptr, "%s", kConst2);
+ char* const str3 = OS::SCreate(nullptr, "%s", kConst1);
+
+ // Make sure these strings are pointer-distinct, but C-string-equal.
+ EXPECT_NE(str1, str3);
+ EXPECT_STREQ(str1, str3);
+
+ const intptr_t i1 = 1;
+ const intptr_t i2 = 2;
+
+ CStringMap<intptr_t> map;
+ EXPECT(map.IsEmpty());
+
+ map.Insert({str1, i1});
+ EXPECT_NOTNULL(map.Lookup(str1));
+ EXPECT_EQ(i1, map.LookupValue(str1));
+ EXPECT_NULLPTR(map.Lookup(str2));
+ EXPECT_NOTNULL(map.Lookup(str3));
+ EXPECT_EQ(i1, map.LookupValue(str3));
+
+ map.Insert({str2, i2});
+ EXPECT_NOTNULL(map.Lookup(str1));
+ EXPECT_EQ(i1, map.LookupValue(str1));
+ EXPECT_NOTNULL(map.Lookup(str2));
+ EXPECT_EQ(i2, map.LookupValue(str2));
+ EXPECT_NOTNULL(map.Lookup(str3));
+ EXPECT_EQ(i1, map.LookupValue(str3));
+
+ EXPECT(map.Remove(str3));
+ EXPECT_NULLPTR(map.Lookup(str1));
+ EXPECT_NOTNULL(map.Lookup(str2));
+ EXPECT_EQ(i2, map.LookupValue(str2));
+ EXPECT_NULLPTR(map.Lookup(str3));
+
+ EXPECT(!map.Remove(str3));
+ EXPECT(map.Remove(str2));
+ EXPECT(map.IsEmpty());
+
+ free(str3);
+ free(str2);
+ free(str1);
+}
+
+TEST_CASE(CStringMapUpdate) {
+ const char* const kConst1 = "test";
+ const char* const kConst2 = "test 2";
+
+ char* str1 = OS::SCreate(nullptr, "%s", kConst1);
+ char* str2 = OS::SCreate(nullptr, "%s", kConst2);
+ char* str3 = OS::SCreate(nullptr, "%s", kConst1);
+ char* str4 = OS::SCreate(nullptr, "%s", kConst1); // Only used for lookup.
+
+ // Make sure these strings are pointer-distinct, but C-string-equal.
+ EXPECT_NE(str1, str3);
+ EXPECT_NE(str1, str4);
+ EXPECT_NE(str3, str4);
+ EXPECT_STREQ(str1, str3);
+ EXPECT_STREQ(str1, str4);
+
+ CStringKeyValueTrait<intptr_t>::Pair p1 = {str1, 1};
+ CStringKeyValueTrait<intptr_t>::Pair p2 = {str2, 2};
+ CStringKeyValueTrait<intptr_t>::Pair p3 = {str3, 3};
+
+ CStringMap<intptr_t> map;
+ EXPECT(map.IsEmpty());
+
+ map.Update(p1);
+ EXPECT_NOTNULL(map.Lookup(str1));
+ EXPECT_EQ(p1.value, map.LookupValue(str1));
+ EXPECT_NULLPTR(map.Lookup(str2));
+ EXPECT_NOTNULL(map.Lookup(str3));
+ EXPECT_EQ(p1.value, map.LookupValue(str3));
+ EXPECT_NOTNULL(map.Lookup(str4));
+ EXPECT_EQ(p1.value, map.LookupValue(str4));
+
+ map.Update(p2);
+ EXPECT_NOTNULL(map.Lookup(str1));
+ EXPECT_EQ(p1.value, map.LookupValue(str1));
+ EXPECT_NOTNULL(map.Lookup(str2));
+ EXPECT_EQ(p2.value, map.LookupValue(str2));
+ EXPECT_NOTNULL(map.Lookup(str3));
+ EXPECT_EQ(p1.value, map.LookupValue(str3));
+ EXPECT_NOTNULL(map.Lookup(str4));
+ EXPECT_EQ(p1.value, map.LookupValue(str4));
+
+ // Check Lookup after Update.
+ map.Update(p3);
+ EXPECT_NOTNULL(map.Lookup(str1));
+ EXPECT_EQ(p3.value, map.LookupValue(str1));
+ EXPECT_NOTNULL(map.Lookup(str2));
+ EXPECT_EQ(p2.value, map.LookupValue(str2));
+ EXPECT_NOTNULL(map.Lookup(str3));
+ EXPECT_EQ(p3.value, map.LookupValue(str3));
+ EXPECT_NOTNULL(map.Lookup(str4));
+ EXPECT_EQ(p3.value, map.LookupValue(str4));
+
+ // Check that single Remove after only Updates ensures Lookup fails after.
+ EXPECT(map.Remove(str3));
+ EXPECT_NULLPTR(map.Lookup(str1));
+ EXPECT_NOTNULL(map.Lookup(str2));
+ EXPECT_EQ(p2.value, map.LookupValue(str2));
+ EXPECT_NULLPTR(map.Lookup(str3));
+ EXPECT_NULLPTR(map.Lookup(str4));
+
+ EXPECT(!map.Remove(str3));
+ EXPECT(map.Remove(str2));
+ EXPECT(map.IsEmpty());
+
+ // Quick double-check that these weren't side-effected by the implementation
+ // of hash maps (p1 especially).
+ EXPECT_EQ(str1, p1.key);
+ EXPECT_EQ(1, p1.value);
+ EXPECT_EQ(str2, p2.key);
+ EXPECT_EQ(2, p2.value);
+ EXPECT_EQ(str3, p3.key);
+ EXPECT_EQ(3, p3.value);
+
+ free(str4);
+ free(str3);
+ free(str2);
+ free(str1);
+}
+
} // namespace dart
diff --git a/runtime/vm/heap/become.cc b/runtime/vm/heap/become.cc
index d6feee1..ef95366 100644
--- a/runtime/vm/heap/become.cc
+++ b/runtime/vm/heap/become.cc
@@ -191,15 +191,15 @@
OS::PrintErr("DETECTED FATAL ISSUE IN BECOME MAPPINGS\n");
OS::PrintErr("BEFORE ADDRESS: %p\n", before_obj);
- OS::PrintErr("BEFORE IS HEAP OBJECT: %s",
+ OS::PrintErr("BEFORE IS HEAP OBJECT: %s\n",
before_obj->IsHeapObject() ? "YES" : "NO");
- OS::PrintErr("BEFORE IN VMISOLATE HEAP OBJECT: %s",
+ OS::PrintErr("BEFORE IN VMISOLATE HEAP OBJECT: %s\n",
before_obj->InVMIsolateHeap() ? "YES" : "NO");
OS::PrintErr("AFTER ADDRESS: %p\n", after_obj);
- OS::PrintErr("AFTER IS HEAP OBJECT: %s",
+ OS::PrintErr("AFTER IS HEAP OBJECT: %s\n",
after_obj->IsHeapObject() ? "YES" : "NO");
- OS::PrintErr("AFTER IN VMISOLATE HEAP OBJECT: %s",
+ OS::PrintErr("AFTER IN VMISOLATE HEAP OBJECT: %s\n",
after_obj->InVMIsolateHeap() ? "YES" : "NO");
if (before_obj->IsHeapObject()) {
diff --git a/runtime/vm/heap/freelist_test.cc b/runtime/vm/heap/freelist_test.cc
index d3a0ae9..aee898f 100644
--- a/runtime/vm/heap/freelist_test.cc
+++ b/runtime/vm/heap/freelist_test.cc
@@ -10,7 +10,7 @@
static uword Allocate(FreeList* free_list, intptr_t size, bool is_protected) {
uword result = free_list->TryAllocate(size, is_protected);
- if (result && is_protected) {
+ if ((result != 0u) && is_protected) {
VirtualMemory::Protect(reinterpret_cast<void*>(result), size,
VirtualMemory::kReadExecute);
}
diff --git a/runtime/vm/heap/heap.cc b/runtime/vm/heap/heap.cc
index 59a7e0b..2e9d7f4 100644
--- a/runtime/vm/heap/heap.cc
+++ b/runtime/vm/heap/heap.cc
@@ -432,6 +432,16 @@
} else if (old_space_.ShouldPerformIdleMarkSweep(deadline)) {
TIMELINE_FUNCTION_GC_DURATION(thread, "IdleGC");
CollectOldSpaceGarbage(thread, kMarkSweep, kIdle);
+ } else if (old_space_.NeedsGarbageCollection()) {
+ // Even though the following GC may exceed our idle deadline, we need to
+ // ensure than that promotions during idle scavenges do not lead to
+ // unbounded growth of old space. If a program is allocating only in new
+ // space and all scavenges happen during idle time, then NotifyIdle will be
+ // the only place that checks the old space allocation limit.
+ // Compare the tail end of Heap::CollectNewSpaceGarbage.
+ CollectOldSpaceGarbage(thread, kMarkSweep, kIdle); // Blocks for O(heap)
+ } else {
+ CheckStartConcurrentMarking(thread, kIdle); // Blocks for up to O(roots)
}
}
@@ -575,7 +585,7 @@
if (old_space_.AlmostNeedsGarbageCollection()) {
if (BeginOldSpaceGC(thread)) {
TIMELINE_FUNCTION_GC_DURATION_BASIC(thread, "StartConcurrentMarking");
- old_space_.CollectGarbage(kMarkSweep, false /* finish */);
+ old_space_.CollectGarbage(/*compact=*/false, /*finalize=*/false);
EndOldSpaceGC();
}
}
@@ -867,26 +877,39 @@
void Heap::ForwardWeakEntries(RawObject* before_object,
RawObject* after_object) {
+ const auto before_space =
+ before_object->IsNewObject() ? Heap::kNew : Heap::kOld;
+ const auto after_space =
+ after_object->IsNewObject() ? Heap::kNew : Heap::kOld;
+
for (int sel = 0; sel < Heap::kNumWeakSelectors; sel++) {
- WeakTable* before_table =
- GetWeakTable(before_object->IsNewObject() ? Heap::kNew : Heap::kOld,
- static_cast<Heap::WeakSelector>(sel));
+ const auto selector = static_cast<Heap::WeakSelector>(sel);
+ auto before_table = GetWeakTable(before_space, selector);
intptr_t entry = before_table->RemoveValue(before_object);
if (entry != 0) {
- WeakTable* after_table =
- GetWeakTable(after_object->IsNewObject() ? Heap::kNew : Heap::kOld,
- static_cast<Heap::WeakSelector>(sel));
+ auto after_table = GetWeakTable(after_space, selector);
after_table->SetValue(after_object, entry);
}
}
+
+ // We only come here during hot reload, in which case we assume that none of
+ // the isolates is in the middle of sending messages.
+ RELEASE_ASSERT(isolate()->forward_table_new() == nullptr);
+ RELEASE_ASSERT(isolate()->forward_table_old() == nullptr);
}
void Heap::ForwardWeakTables(ObjectPointerVisitor* visitor) {
+ // NOTE: This method is only used by the compactor, so there is no need to
+ // process the `Heap::kNew` tables.
for (int sel = 0; sel < Heap::kNumWeakSelectors; sel++) {
WeakSelector selector = static_cast<Heap::WeakSelector>(sel);
- GetWeakTable(Heap::kNew, selector)->Forward(visitor);
GetWeakTable(Heap::kOld, selector)->Forward(visitor);
}
+
+ // Isolates might have forwarding tables (used for during snapshoting in
+ // isolate communication).
+ auto table_old = isolate()->forward_table_old();
+ if (table_old != nullptr) table_old->Forward(visitor);
}
#ifndef PRODUCT
diff --git a/runtime/vm/heap/pages.cc b/runtime/vm/heap/pages.cc
index 7ec1f0c..4a85864 100644
--- a/runtime/vm/heap/pages.cc
+++ b/runtime/vm/heap/pages.cc
@@ -355,8 +355,8 @@
page->set_next(large_pages_);
large_pages_ = page;
- // Only one object in this page (at least until String::MakeExternal or
- // Array::MakeFixedLength is called).
+ // Only one object in this page (at least until Array::MakeFixedLength
+ // is called).
page->set_object_end(page->object_start() + size);
}
return page;
@@ -410,6 +410,9 @@
}
void PageSpace::FreeLargePage(HeapPage* page, HeapPage* previous_page) {
+ // Thread should be at a safepoint when this code is called and hence
+ // it is not necessary to lock large_pages_.
+ ASSERT(Thread::Current()->IsAtSafepoint());
IncreaseCapacityInWords(-(page->memory_->size() >> kWordSizeLog2));
// Remove the page from the list.
if (previous_page != NULL) {
@@ -775,6 +778,7 @@
}
void PageSpace::VisitRememberedCards(ObjectPointerVisitor* visitor) const {
+ ASSERT(Thread::Current()->IsAtSafepoint());
for (HeapPage* page = large_pages_; page != NULL; page = page->next()) {
page->VisitRememberedCards(visitor);
}
@@ -1498,11 +1502,7 @@
idle_gc_threshold_in_words_ =
after.CombinedCapacityInWords() + 2 * kPageSizeInWords;
- if (FLAG_log_growth) {
- THR_Print("%s: threshold=%" Pd "kB, idle_threshold=%" Pd "kB, reason=gc\n",
- heap_->isolate()->name(), gc_threshold_in_words_ / KBInWords,
- idle_gc_threshold_in_words_ / KBInWords);
- }
+ RecordUpdate(before, after, "gc");
}
void PageSpaceController::EvaluateAfterLoading(SpaceUsage after) {
@@ -1526,11 +1526,30 @@
idle_gc_threshold_in_words_ =
after.CombinedCapacityInWords() + 2 * kPageSizeInWords;
+ RecordUpdate(after, after, "loaded");
+}
+
+void PageSpaceController::RecordUpdate(SpaceUsage before,
+ SpaceUsage after,
+ const char* reason) {
+#if defined(SUPPORT_TIMELINE)
+ TIMELINE_FUNCTION_GC_DURATION(Thread::Current(), "UpdateGrowthLimit");
+ tds.SetNumArguments(5);
+ tds.CopyArgument(0, "Reason", reason);
+ tds.FormatArgument(1, "Before.CombinedCapacity (kB)", "%" Pd "",
+ RoundWordsToKB(before.CombinedCapacityInWords()));
+ tds.FormatArgument(2, "After.CombinedCapacity (kB)", "%" Pd "",
+ RoundWordsToKB(after.CombinedCapacityInWords()));
+ tds.FormatArgument(3, "Threshold (kB)", "%" Pd "",
+ RoundWordsToKB(gc_threshold_in_words_));
+ tds.FormatArgument(4, "Idle Threshold (kB)", "%" Pd "",
+ RoundWordsToKB(idle_gc_threshold_in_words_));
+#endif
+
if (FLAG_log_growth) {
- THR_Print("%s: threshold=%" Pd "kB, idle_threshold=%" Pd
- "kB, reason=loaded\n",
+ THR_Print("%s: threshold=%" Pd "kB, idle_threshold=%" Pd "kB, reason=%s\n",
heap_->isolate()->name(), gc_threshold_in_words_ / KBInWords,
- idle_gc_threshold_in_words_ / KBInWords);
+ idle_gc_threshold_in_words_ / KBInWords, reason);
}
}
diff --git a/runtime/vm/heap/pages.h b/runtime/vm/heap/pages.h
index 6eb1e32..736fa30 100644
--- a/runtime/vm/heap/pages.h
+++ b/runtime/vm/heap/pages.h
@@ -232,6 +232,8 @@
bool is_enabled() { return is_enabled_; }
private:
+ void RecordUpdate(SpaceUsage before, SpaceUsage after, const char* reason);
+
Heap* heap_;
bool is_enabled_;
@@ -257,9 +259,6 @@
// Perform a synchronous GC when capacity exceeds this amount.
intptr_t gc_threshold_in_words_;
- // Perform a synchronous GC when external allocations exceed this amount.
- intptr_t gc_external_threshold_in_words_;
-
// Start considering idle GC when capacity exceeds this amount.
intptr_t idle_gc_threshold_in_words_;
diff --git a/runtime/vm/heap/safepoint.cc b/runtime/vm/heap/safepoint.cc
index 0c25411..3bf198b 100644
--- a/runtime/vm/heap/safepoint.cc
+++ b/runtime/vm/heap/safepoint.cc
@@ -45,16 +45,17 @@
Isolate* I = T->isolate();
ASSERT(I != NULL);
- Heap* heap = I->heap();
- current_growth_controller_state_ = heap->GrowthControlState();
- heap->DisableGrowthControl();
-
SafepointHandler* handler = I->group()->safepoint_handler();
ASSERT(handler != NULL);
// Signal all threads to get to a safepoint and wait for them to
// get to a safepoint.
handler->SafepointThreads(T);
+
+ // N.B.: Change growth policy inside the safepoint to prevent racy access.
+ Heap* heap = I->heap();
+ current_growth_controller_state_ = heap->GrowthControlState();
+ heap->DisableGrowthControl();
}
ForceGrowthSafepointOperationScope::~ForceGrowthSafepointOperationScope() {
@@ -63,14 +64,15 @@
Isolate* I = T->isolate();
ASSERT(I != NULL);
+ // N.B.: Change growth policy inside the safepoint to prevent racy access.
+ Heap* heap = I->heap();
+ heap->SetGrowthControlState(current_growth_controller_state_);
+
// Resume all threads which are blocked for the safepoint operation.
SafepointHandler* handler = I->safepoint_handler();
ASSERT(handler != NULL);
handler->ResumeThreads(T);
- Heap* heap = I->heap();
- heap->SetGrowthControlState(current_growth_controller_state_);
-
if (current_growth_controller_state_) {
ASSERT(T->CanCollectGarbage());
// Check if we passed the growth limit during the scope.
diff --git a/runtime/vm/heap/scavenger.cc b/runtime/vm/heap/scavenger.cc
index 966b581..accb638 100644
--- a/runtime/vm/heap/scavenger.cc
+++ b/runtime/vm/heap/scavenger.cc
@@ -847,12 +847,8 @@
}
void Scavenger::ProcessWeakReferences() {
- // Rehash the weak tables now that we know which objects survive this cycle.
- for (int sel = 0; sel < Heap::kNumWeakSelectors; sel++) {
- WeakTable* table =
- heap_->GetWeakTable(Heap::kNew, static_cast<Heap::WeakSelector>(sel));
- heap_->SetWeakTable(Heap::kNew, static_cast<Heap::WeakSelector>(sel),
- WeakTable::NewFrom(table));
+ auto rehash_weak_table = [](WeakTable* table, WeakTable* replacement_new,
+ WeakTable* replacement_old) {
intptr_t size = table->size();
for (intptr_t i = 0; i < size; i++) {
if (table->IsValidEntryAt(i)) {
@@ -864,16 +860,40 @@
// The object has survived. Preserve its record.
uword new_addr = ForwardedAddr(header);
raw_obj = RawObject::FromAddr(new_addr);
- heap_->SetWeakEntry(raw_obj, static_cast<Heap::WeakSelector>(sel),
- table->ValueAt(i));
+ auto replacement =
+ raw_obj->IsNewObject() ? replacement_new : replacement_old;
+ replacement->SetValue(raw_obj, table->ValueAt(i));
}
}
}
+ };
+
+ // Rehash the weak tables now that we know which objects survive this cycle.
+ for (int sel = 0; sel < Heap::kNumWeakSelectors; sel++) {
+ const auto selector = static_cast<Heap::WeakSelector>(sel);
+ auto table = heap_->GetWeakTable(Heap::kNew, selector);
+ auto table_old = heap_->GetWeakTable(Heap::kOld, selector);
+
+ // Create a new weak table for the new-space.
+ auto table_new = WeakTable::NewFrom(table);
+ rehash_weak_table(table, table_new, table_old);
+ heap_->SetWeakTable(Heap::kNew, selector, table_new);
+
// Remove the old table as it has been replaced with the newly allocated
// table above.
delete table;
}
+ // Each isolate might have a weak table used for fast snapshot writing (i.e.
+ // isolate communication). Rehash those tables if need be.
+ auto isolate = heap_->isolate();
+ auto table = isolate->forward_table_new();
+ if (table != NULL) {
+ auto replacement = WeakTable::NewFrom(table);
+ rehash_weak_table(table, replacement, isolate->forward_table_old());
+ isolate->set_forward_table_new(replacement);
+ }
+
// The queued weak properties at this point do not refer to reachable keys,
// so we clear their key and value fields.
{
diff --git a/runtime/vm/heap/spaces.h b/runtime/vm/heap/spaces.h
index 2885ef5..e2737e4 100644
--- a/runtime/vm/heap/spaces.h
+++ b/runtime/vm/heap/spaces.h
@@ -5,6 +5,8 @@
#ifndef RUNTIME_VM_HEAP_SPACES_H_
#define RUNTIME_VM_HEAP_SPACES_H_
+#include "platform/globals.h"
+
// This file contains utilities shared by old and new space.
// TODO(koda): Create Space base class with Space::CurrentUsage().
diff --git a/runtime/vm/heap/sweeper.cc b/runtime/vm/heap/sweeper.cc
index 81d4f0b..cfe0874 100644
--- a/runtime/vm/heap/sweeper.cc
+++ b/runtime/vm/heap/sweeper.cc
@@ -89,8 +89,8 @@
words_to_end = (raw_obj->HeapSize() >> kWordSizeLog2);
}
#ifdef DEBUG
- // String::MakeExternal and Array::MakeFixedLength create trailing filler
- // objects, but they are always unreachable. Verify that they are not marked.
+ // Array::MakeFixedLength creates trailing filler objects,
+ // but they are always unreachable. Verify that they are not marked.
uword current = RawObject::ToAddr(raw_obj) + raw_obj->HeapSize();
uword end = page->object_end();
while (current < end) {
diff --git a/runtime/vm/image_snapshot.cc b/runtime/vm/image_snapshot.cc
index 84c0316..03672dc 100644
--- a/runtime/vm/image_snapshot.cc
+++ b/runtime/vm/image_snapshot.cc
@@ -556,6 +556,11 @@
void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
Zone* zone = Thread::Current()->zone();
+#if defined(DART_PRECOMPILER)
+ const char* bss_symbol =
+ vm ? "_kDartVmSnapshotBss" : "_kDartIsolateSnapshotBss";
+#endif
+
const char* instructions_symbol =
vm ? "_kDartVmSnapshotInstructions" : "_kDartIsolateSnapshotInstructions";
assembly_stream_.Print(".text\n");
@@ -570,8 +575,16 @@
// look like a HeapPage.
intptr_t instructions_length = next_text_offset_;
WriteWordLiteralText(instructions_length);
+
+#if defined(DART_PRECOMPILER)
+ assembly_stream_.Print("%s %s - %s\n", kLiteralPrefix, bss_symbol,
+ instructions_symbol);
+#else
+ WriteWordLiteralText(0); // No relocations.
+#endif
+
intptr_t header_words = Image::kHeaderSize / sizeof(compiler::target::uword);
- for (intptr_t i = 1; i < header_words; i++) {
+ for (intptr_t i = Image::kHeaderFields; i < header_words; i++) {
WriteWordLiteralText(0);
}
@@ -579,6 +592,7 @@
Object& owner = Object::Handle(zone);
String& str = String::Handle(zone);
+ PcDescriptors& descriptors = PcDescriptors::Handle(zone);
ObjectStore* object_store = Isolate::Current()->object_store();
@@ -613,6 +627,7 @@
const Instructions& insns = *data.insns_;
const Code& code = *data.code_;
+ descriptors = data.code_->pc_descriptors();
if (profile_writer_ != nullptr) {
const intptr_t offset = Image::kHeaderSize + text_offset;
@@ -717,7 +732,27 @@
ASSERT(Utils::IsAligned(entry, sizeof(uword)));
ASSERT(Utils::IsAligned(end, sizeof(uword)));
+#if defined(DART_PRECOMPILER)
+ PcDescriptors::Iterator iterator(descriptors,
+ RawPcDescriptors::kBSSRelocation);
+ uword next_reloc_offset = iterator.MoveNext() ? iterator.PcOffset() : -1;
+
+ for (uword cursor = entry; cursor < end;
+ cursor += sizeof(compiler::target::uword*)) {
+ compiler::target::uword data =
+ *reinterpret_cast<compiler::target::uword*>(cursor);
+ if ((cursor - entry) == next_reloc_offset) {
+ assembly_stream_.Print("%s %s - (.) + %" Pd "\n", kLiteralPrefix,
+ bss_symbol, /*addend=*/data);
+ next_reloc_offset = iterator.MoveNext() ? iterator.PcOffset() : -1;
+ } else {
+ WriteWordLiteralText(data);
+ }
+ }
+ text_offset += end - entry;
+#else
text_offset += WriteByteSequence(entry, end);
+#endif
}
ASSERT((text_offset - instr_start) == insns.raw()->HeapSize());
@@ -725,6 +760,16 @@
FrameUnwindEpilogue();
+#if defined(DART_PRECOMPILER)
+ assembly_stream_.Print(".bss\n");
+ assembly_stream_.Print("%s:\n", bss_symbol);
+
+ // Currently we only put one symbol in the data section, the address of
+ // DLRT_GetThreadForNativeCallback, which is populated when the snapshot is
+ // loaded.
+ WriteWordLiteralText(0);
+#endif
+
#if defined(TARGET_OS_LINUX) || defined(TARGET_OS_ANDROID) || \
defined(TARGET_OS_FUCHSIA)
assembly_stream_.Print(".section .rodata\n");
@@ -860,24 +905,42 @@
}
void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
+ const intptr_t instructions_length = next_text_offset_;
#ifdef DART_PRECOMPILER
intptr_t segment_base = 0;
if (elf_ != nullptr) {
segment_base = elf_->NextMemoryOffset();
}
+
+ // Calculate the start of the BSS section based on the known size of the
+ // text section and page alignment.
+ intptr_t bss_base = 0;
+ if (elf_ != nullptr) {
+ bss_base =
+ Utils::RoundUp(segment_base + instructions_length, Elf::kPageSize);
+ }
#endif
// This header provides the gap to make the instructions snapshot look like a
// HeapPage.
- intptr_t instructions_length = next_text_offset_;
instructions_blob_stream_.WriteWord(instructions_length);
+#if defined(DART_PRECOMPILER)
+ instructions_blob_stream_.WriteWord(elf_ != nullptr ? bss_base - segment_base
+ : 0);
+#else
+ instructions_blob_stream_.WriteWord(0); // No relocations.
+#endif
intptr_t header_words = Image::kHeaderSize / sizeof(uword);
- for (intptr_t i = 1; i < header_words; i++) {
+ for (intptr_t i = Image::kHeaderFields; i < header_words; i++) {
instructions_blob_stream_.WriteWord(0);
}
intptr_t text_offset = 0;
+#if defined(DART_PRECOMPILER)
+ PcDescriptors& descriptors = PcDescriptors::Handle();
+#endif
+
NoSafepointScope no_safepoint;
for (intptr_t i = 0; i < instructions_.length(); i++) {
auto& data = instructions_[i];
@@ -928,6 +991,8 @@
marked_tags |= static_cast<uword>(insns.raw_ptr()->hash_) << 32;
#endif
+ intptr_t payload_stream_start = 0;
+
#if defined(IS_SIMARM_X64)
const intptr_t start_offset = instructions_blob_stream_.bytes_written();
const intptr_t size_in_bytes = InstructionsSizeInSnapshot(insns.Size());
@@ -938,6 +1003,7 @@
instructions_blob_stream_.WriteFixed<uint32_t>(
insns.raw_ptr()->unchecked_entrypoint_pc_offset_);
instructions_blob_stream_.Align(kSimarmX64InstructionsAlignment);
+ payload_stream_start = instructions_blob_stream_.Position();
instructions_blob_stream_.WriteBytes(
reinterpret_cast<const void*>(insns.PayloadStart()), insns.Size());
instructions_blob_stream_.Align(kSimarmX64InstructionsAlignment);
@@ -945,16 +1011,61 @@
text_offset += (end_offset - start_offset);
USE(end);
#else // defined(IS_SIMARM_X64)
+ payload_stream_start = instructions_blob_stream_.Position() +
+ (insns.PayloadStart() - beginning);
+
instructions_blob_stream_.WriteWord(marked_tags);
text_offset += sizeof(uword);
beginning += sizeof(uword);
text_offset += WriteByteSequence(beginning, end);
#endif // defined(IS_SIMARM_X64)
+#if defined(DART_PRECOMPILER)
+ // Don't patch the relocation if we're not generating ELF. The regular blobs
+ // format does not yet support these relocations. Use
+ // Code::VerifyBSSRelocations to check whether the relocations are patched
+ // or not after loading.
+ if (elf_ != nullptr) {
+ const intptr_t current_stream_position =
+ instructions_blob_stream_.Position();
+
+ descriptors = data.code_->pc_descriptors();
+
+ PcDescriptors::Iterator iterator(
+ descriptors, /*kind_mask=*/RawPcDescriptors::kBSSRelocation);
+
+ while (iterator.MoveNext()) {
+ const intptr_t reloc_offset = iterator.PcOffset();
+
+ // The instruction stream at the relocation position holds an offset
+ // into BSS corresponding to the symbol being resolved. This addend is
+ // factored into the relocation.
+ const auto addend = *reinterpret_cast<compiler::target::word*>(
+ insns.PayloadStart() + reloc_offset);
+
+ // Overwrite the relocation position in the instruction stream with the
+ // (positive) offset of the start of the payload from the start of the
+ // BSS segment plus the addend in the relocation.
+ instructions_blob_stream_.SetPosition(payload_stream_start +
+ reloc_offset);
+
+ const uword offset =
+ bss_base - (segment_base + payload_stream_start + reloc_offset) +
+ addend;
+ instructions_blob_stream_.WriteTargetWord(offset);
+ }
+
+ // Restore stream position after the relocation was patched.
+ instructions_blob_stream_.SetPosition(current_stream_position);
+ }
+#endif
+
ASSERT((text_offset - instr_start) ==
ImageWriter::SizeInSnapshot(insns.raw()));
}
+ ASSERT(instructions_blob_stream_.bytes_written() == instructions_length);
+
#ifdef DART_PRECOMPILER
if (elf_ != nullptr) {
const char* instructions_symbol = vm ? "_kDartVmSnapshotInstructions"
@@ -963,6 +1074,9 @@
elf_->AddText(instructions_symbol, instructions_blob_stream_.buffer(),
instructions_blob_stream_.bytes_written());
ASSERT(segment_base == segment_base2);
+
+ const intptr_t real_bss_base = elf_->AddBSSData("_kDartVMBSSData", 8);
+ ASSERT(bss_base == real_bss_base);
}
#endif
}
@@ -976,7 +1090,6 @@
shared_data_image_(shared_data_image),
shared_instructions_image_(shared_instructions_image) {
ASSERT(data_image != NULL);
- ASSERT(instructions_image != NULL);
}
RawApiError* ImageReader::VerifyAlignment() const {
@@ -993,6 +1106,7 @@
}
RawInstructions* ImageReader::GetInstructionsAt(int32_t offset) const {
+ ASSERT(instructions_image_ != nullptr);
ASSERT(Utils::IsAligned(offset, OS::PreferredCodeAlignment()));
RawObject* result;
diff --git a/runtime/vm/image_snapshot.h b/runtime/vm/image_snapshot.h
index 5acb75d..deb94ef 100644
--- a/runtime/vm/image_snapshot.h
+++ b/runtime/vm/image_snapshot.h
@@ -48,6 +48,11 @@
return snapshot_size - kHeaderSize;
}
+ uword bss_offset() const {
+ return *(reinterpret_cast<const uword*>(raw_memory_) + 1);
+ }
+
+ static constexpr intptr_t kHeaderFields = 2;
static const intptr_t kHeaderSize = OS::kMaxPreferredCodeAlignment;
private:
@@ -314,8 +319,15 @@
void FrameUnwindPrologue();
void FrameUnwindEpilogue();
intptr_t WriteByteSequence(uword start, uword end);
+
+#if defined(TARGET_ARCH_IS_64_BIT)
+ const char* kLiteralPrefix = ".quad";
+#else
+ const char* kLiteralPrefix = ".long";
+#endif
+
void WriteWordLiteralText(compiler::target::uword value) {
-// Padding is helpful for comparing the .S with --disassemble.
+ // Padding is helpful for comparing the .S with --disassemble.
#if defined(TARGET_ARCH_IS_64_BIT)
assembly_stream_.Print(".quad 0x%0.16" Px "\n", value);
#else
diff --git a/runtime/vm/interpreter.cc b/runtime/vm/interpreter.cc
index fa8075c..77bd91d 100644
--- a/runtime/vm/interpreter.cc
+++ b/runtime/vm/interpreter.cc
@@ -13,6 +13,7 @@
#include "vm/compiler/assembler/assembler.h"
#include "vm/compiler/assembler/disassembler_kbc.h"
+#include "vm/compiler/backend/flow_graph_compiler.h"
#include "vm/compiler/frontend/bytecode_reader.h"
#include "vm/compiler/jit/compiler.h"
#include "vm/cpu.h"
@@ -389,6 +390,9 @@
}
}
#endif
+ // Make sure interpreter's unboxing view is consistent with compiler.
+ supports_unboxed_doubles_ = FlowGraphCompiler::SupportsUnboxedDoubles();
+ supports_unboxed_simd128_ = FlowGraphCompiler::SupportsUnboxedSimd128();
}
Interpreter::~Interpreter() {
@@ -1780,7 +1784,6 @@
{
BYTECODE(Throw, A);
- DEBUG_CHECK;
{
SP[1] = 0; // Space for result.
Exit(thread, FP, SP + 2, pc);
@@ -2264,7 +2267,6 @@
{
BYTECODE(StoreStaticTOS, D);
- DEBUG_CHECK;
RawField* field = reinterpret_cast<RawField*>(LOAD_CONSTANT(rD));
RawInstance* value = static_cast<RawInstance*>(*SP--);
field->StorePointer(&field->ptr()->value_.static_value_, value, thread);
@@ -2318,7 +2320,7 @@
(field->ptr()->is_nullable_ != kNullCid) &&
Field::UnboxingCandidateBit::decode(field->ptr()->kind_bits_);
classid_t guarded_cid = field->ptr()->guarded_cid_;
- if (unboxing && (guarded_cid == kDoubleCid)) {
+ if (unboxing && (guarded_cid == kDoubleCid) && supports_unboxed_doubles_) {
double raw_value = Double::RawCast(value)->ptr()->value_;
ASSERT(*(reinterpret_cast<RawDouble**>(instance->ptr()) +
offset_in_words) == null_value); // Initializing store.
@@ -2330,7 +2332,8 @@
instance->StorePointer(
reinterpret_cast<RawDouble**>(instance->ptr()) + offset_in_words, box,
thread);
- } else if (unboxing && (guarded_cid == kFloat32x4Cid)) {
+ } else if (unboxing && (guarded_cid == kFloat32x4Cid) &&
+ supports_unboxed_simd128_) {
simd128_value_t raw_value;
raw_value.readFrom(Float32x4::RawCast(value)->ptr()->value_);
ASSERT(*(reinterpret_cast<RawFloat32x4**>(instance->ptr()) +
@@ -2343,7 +2346,8 @@
instance->StorePointer(
reinterpret_cast<RawFloat32x4**>(instance->ptr()) + offset_in_words,
box, thread);
- } else if (unboxing && (guarded_cid == kFloat64x2Cid)) {
+ } else if (unboxing && (guarded_cid == kFloat64x2Cid) &&
+ supports_unboxed_simd128_) {
simd128_value_t raw_value;
raw_value.readFrom(Float64x2::RawCast(value)->ptr()->value_);
ASSERT(*(reinterpret_cast<RawFloat64x2**>(instance->ptr()) +
@@ -2590,7 +2594,7 @@
{
BYTECODE(AssertBoolean, A);
RawObject* value = SP[0];
- if (rA) { // Should we perform type check?
+ if (rA != 0u) { // Should we perform type check?
if ((value == true_value) || (value == false_value)) {
goto AssertBooleanOk;
}
@@ -3079,20 +3083,23 @@
(field->ptr()->is_nullable_ != kNullCid) &&
Field::UnboxingCandidateBit::decode(field->ptr()->kind_bits_);
classid_t guarded_cid = field->ptr()->guarded_cid_;
- if (unboxing && (guarded_cid == kDoubleCid)) {
+ if (unboxing && (guarded_cid == kDoubleCid) && supports_unboxed_doubles_) {
+ ASSERT(FlowGraphCompiler::SupportsUnboxedDoubles());
double raw_value = Double::RawCast(value)->ptr()->value_;
// AllocateDouble places result at SP[0]
if (!AllocateDouble(thread, raw_value, pc, FP, SP)) {
HANDLE_EXCEPTION;
}
- } else if (unboxing && (guarded_cid == kFloat32x4Cid)) {
+ } else if (unboxing && (guarded_cid == kFloat32x4Cid) &&
+ supports_unboxed_simd128_) {
simd128_value_t raw_value;
raw_value.readFrom(Float32x4::RawCast(value)->ptr()->value_);
// AllocateFloat32x4 places result at SP[0]
if (!AllocateFloat32x4(thread, raw_value, pc, FP, SP)) {
HANDLE_EXCEPTION;
}
- } else if (unboxing && (guarded_cid == kFloat64x2Cid)) {
+ } else if (unboxing && (guarded_cid == kFloat64x2Cid) &&
+ supports_unboxed_simd128_) {
simd128_value_t raw_value;
raw_value.readFrom(Float64x2::RawCast(value)->ptr()->value_);
// AllocateFloat64x2 places result at SP[0]
@@ -3194,20 +3201,22 @@
(field->ptr()->is_nullable_ != kNullCid) &&
Field::UnboxingCandidateBit::decode(field->ptr()->kind_bits_);
classid_t guarded_cid = field->ptr()->guarded_cid_;
- if (unboxing && (guarded_cid == kDoubleCid)) {
+ if (unboxing && (guarded_cid == kDoubleCid) && supports_unboxed_doubles_) {
double raw_value = Double::RawCast(value)->ptr()->value_;
RawDouble* box =
*(reinterpret_cast<RawDouble**>(instance->ptr()) + offset_in_words);
ASSERT(box != null_value); // Non-initializing store.
box->ptr()->value_ = raw_value;
- } else if (unboxing && (guarded_cid == kFloat32x4Cid)) {
+ } else if (unboxing && (guarded_cid == kFloat32x4Cid) &&
+ supports_unboxed_simd128_) {
simd128_value_t raw_value;
raw_value.readFrom(Float32x4::RawCast(value)->ptr()->value_);
RawFloat32x4* box = *(reinterpret_cast<RawFloat32x4**>(instance->ptr()) +
offset_in_words);
ASSERT(box != null_value); // Non-initializing store.
raw_value.writeTo(box->ptr()->value_);
- } else if (unboxing && (guarded_cid == kFloat64x2Cid)) {
+ } else if (unboxing && (guarded_cid == kFloat64x2Cid) &&
+ supports_unboxed_simd128_) {
simd128_value_t raw_value;
raw_value.readFrom(Float64x2::RawCast(value)->ptr()->value_);
RawFloat64x2* box = *(reinterpret_cast<RawFloat64x2**>(instance->ptr()) +
diff --git a/runtime/vm/interpreter.h b/runtime/vm/interpreter.h
index fd40ec5..4889a5a 100644
--- a/runtime/vm/interpreter.h
+++ b/runtime/vm/interpreter.h
@@ -275,7 +275,11 @@
bool is_debugging_;
#endif // !PRODUCT
+ bool supports_unboxed_doubles_;
+ bool supports_unboxed_simd128_;
+
friend class InterpreterSetjmpBuffer;
+
DISALLOW_COPY_AND_ASSIGN(Interpreter);
};
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index a31c59b..c341416 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -79,11 +79,6 @@
FLAG_concurrent_mark = false; // Timing dependent.
FLAG_concurrent_sweep = false; // Timing dependent.
FLAG_random_seed = 0x44617274; // "Dart"
-#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
- FLAG_load_deferred_eagerly = true;
-#else
- COMPILE_ASSERT(FLAG_load_deferred_eagerly);
-#endif
}
}
@@ -676,7 +671,7 @@
I->ScheduleInterrupts(Thread::kMessageInterrupt);
}
Dart_MessageNotifyCallback callback = I->message_notify_callback();
- if (callback) {
+ if (callback != nullptr) {
// Allow the embedder to handle message notification.
(*callback)(Api::CastIsolate(I));
}
@@ -2009,6 +2004,15 @@
}
#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
+void Isolate::set_forward_table_new(WeakTable* table) {
+ std::unique_ptr<WeakTable> value(table);
+ forward_table_new_ = std::move(value);
+}
+void Isolate::set_forward_table_old(WeakTable* table) {
+ std::unique_ptr<WeakTable> value(table);
+ forward_table_old_ = std::move(value);
+}
+
void Isolate::Shutdown() {
ASSERT(this == Isolate::Current());
BackgroundCompiler::Stop(this);
@@ -2810,7 +2814,7 @@
// SafepointMonitorLocker to ensure the lock has safepoint checks.
SafepointMonitorLocker ml(isolates_list_monitor_);
Isolate* current = isolates_list_head_;
- while (current) {
+ while (current != nullptr) {
visitor->VisitIsolate(current);
current = current->next_;
}
@@ -2878,7 +2882,7 @@
}
Isolate* previous = nullptr;
Isolate* current = isolates_list_head_;
- while (current) {
+ while (current != nullptr) {
if (current == isolate) {
ASSERT(previous != nullptr);
previous->next_ = current->next_;
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index e8df2bb..48895f3 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -90,6 +90,7 @@
class StubCode;
class ThreadRegistry;
class UserTag;
+class WeakTable;
class PendingLazyDeopt {
public:
@@ -779,18 +780,6 @@
isolate_flags_ = RemappingCidsBit::update(value, isolate_flags_);
}
- static const intptr_t kInvalidGen = 0;
-
- void IncrLoadingInvalidationGen() {
- AtomicOperations::IncrementBy(&loading_invalidation_gen_, 1);
- if (loading_invalidation_gen_ == kInvalidGen) {
- AtomicOperations::IncrementBy(&loading_invalidation_gen_, 1);
- }
- }
- intptr_t loading_invalidation_gen() {
- return AtomicOperations::LoadRelaxed(&loading_invalidation_gen_);
- }
-
// Used by background compiler which field became boxed and must trigger
// deoptimization in the mutator thread.
void AddDeoptimizingBoxedField(const Field& field);
@@ -957,6 +946,14 @@
void MaybeIncreaseReloadEveryNStackOverflowChecks();
+ // The weak table used in the snapshot writer for the purpose of fast message
+ // sending.
+ WeakTable* forward_table_new() { return forward_table_new_.get(); }
+ void set_forward_table_new(WeakTable* table);
+
+ WeakTable* forward_table_old() { return forward_table_old_.get(); }
+ void set_forward_table_old(WeakTable* table);
+
static void NotifyLowMemory();
private:
@@ -1170,11 +1167,6 @@
// Isolate list next pointer.
Isolate* next_ = nullptr;
- // Invalidation generations; used to track events occurring in parallel
- // to background compilation. The counters may overflow, which is OK
- // since we check for equality to detect if an event occured.
- intptr_t loading_invalidation_gen_ = kInvalidGen;
-
// Protect access to boxed_field_list_.
Mutex field_list_mutex_;
// List of fields that became boxed and that trigger deoptimization.
@@ -1193,6 +1185,10 @@
ReversePcLookupCache* reverse_pc_lookup_cache_ = nullptr;
+ // Used during message sending of messages between isolates.
+ std::unique_ptr<WeakTable> forward_table_new_;
+ std::unique_ptr<WeakTable> forward_table_old_;
+
static Dart_IsolateGroupCreateCallback create_group_callback_;
static Dart_InitializeIsolateCallback initialize_callback_;
static Dart_IsolateShutdownCallback shutdown_callback_;
diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc
index c4bbc70..640c358 100644
--- a/runtime/vm/isolate_reload.cc
+++ b/runtime/vm/isolate_reload.cc
@@ -83,7 +83,7 @@
}
void InstanceMorpher::ComputeMapping() {
- if (from_.NumTypeArguments()) {
+ if (from_.NumTypeArguments() > 0) {
// Add copying of the optional type argument field.
intptr_t from_offset = from_.type_arguments_field_offset();
ASSERT(from_offset != Class::kNoTypeArguments);
@@ -217,7 +217,7 @@
void InstanceMorpher::DumpFormatFor(const Class& cls) const {
THR_Print("%s\n", cls.ToCString());
- if (cls.NumTypeArguments()) {
+ if (cls.NumTypeArguments() > 0) {
intptr_t field_offset = cls.type_arguments_field_offset();
ASSERT(field_offset != Class::kNoTypeArguments);
THR_Print(" - @%" Pd " <type arguments>\n", field_offset);
@@ -377,18 +377,14 @@
if (obj.IsLibrary()) {
return Library::Cast(obj).UrlHash();
} else if (obj.IsClass()) {
- if (Class::Cast(obj).id() == kFreeListElement) {
- return 0;
- }
return String::HashRawSymbol(Class::Cast(obj).Name());
} else if (obj.IsField()) {
return String::HashRawSymbol(Field::Cast(obj).name());
- } else if (obj.IsInstance()) {
- Object& hashObj = Object::Handle(Instance::Cast(obj).HashCode());
- if (hashObj.IsError()) {
- Exceptions::PropagateError(Error::Cast(hashObj));
- }
- return Smi::Cast(hashObj).Value();
+ } else if (obj.IsClosure()) {
+ return String::HashRawSymbol(
+ Function::Handle(Closure::Cast(obj).function()).name());
+ } else {
+ FATAL1("Unexpected type in become: %s\n", obj.ToCString());
}
return 0;
}
@@ -730,7 +726,7 @@
// Ensure all functions on the stack have unoptimized code.
EnsuredUnoptimizedCodeForStack();
// Deoptimize all code that had optimizing decisions that are dependent on
- // assumptions from field guards or CHA or deferred library prefixes.
+ // assumptions from field guards or CHA.
// TODO(johnmccutchan): Deoptimizing dependent code here (before the reload)
// is paranoid. This likely can be moved to the commit phase.
DeoptimizeDependentCode();
@@ -958,8 +954,6 @@
}
DeoptimizeTypeTestingStubs();
-
- // TODO(johnmccutchan): Also call LibraryPrefix::InvalidateDependentCode.
}
void IsolateReloadContext::CheckpointClasses() {
@@ -976,9 +970,8 @@
// Copy the size of the class table.
saved_num_cids_ = I->class_table()->NumCids();
- // Copy of the class table.
- ClassAndSize* local_saved_class_table = reinterpret_cast<ClassAndSize*>(
- malloc(sizeof(ClassAndSize) * saved_num_cids_));
+ ClassAndSize* saved_class_table = nullptr;
+ class_table->CopyBeforeHotReload(&saved_class_table, &saved_num_cids_);
// Copy classes into saved_class_table_ first. Make sure there are no
// safepoints until saved_class_table_ is filled up and saved so class raw
@@ -986,18 +979,12 @@
{
NoSafepointScope no_safepoint_scope(Thread::Current());
- for (intptr_t i = 0; i < saved_num_cids_; i++) {
- if (class_table->IsValidIndex(i) && class_table->HasValidClassAt(i)) {
- // Copy the class into the saved class table.
- local_saved_class_table[i] = class_table->PairAt(i);
- } else {
- // No class at this index, mark it as NULL.
- local_saved_class_table[i] = ClassAndSize(NULL);
- }
- }
+ // The saved_class_table_ is now source of truth for GC.
+ AtomicOperations::StoreRelease(&saved_class_table_, saved_class_table);
- // Elements of saved_class_table_ are now visible to GC.
- saved_class_table_ = local_saved_class_table;
+ // We can therefore wipe out all of the old entries (if that table is used
+ // for GC during the hot-reload we have a bug).
+ class_table->ResetBeforeHotReload();
}
// Add classes to the set. Set is stored in the Array, so adding an element
@@ -1030,20 +1017,6 @@
return (*file_modified_callback_)(url_chars, since);
}
-static void PropagateLibraryModified(
- const ZoneGrowableArray<ZoneGrowableArray<intptr_t>*>* imported_by,
- intptr_t lib_index,
- BitVector* modified_libs) {
- ZoneGrowableArray<intptr_t>* dep_libs = (*imported_by)[lib_index];
- for (intptr_t i = 0; i < dep_libs->length(); i++) {
- intptr_t dep_lib_index = (*dep_libs)[i];
- if (!modified_libs->Contains(dep_lib_index)) {
- modified_libs->Add(dep_lib_index);
- PropagateLibraryModified(imported_by, dep_lib_index, modified_libs);
- }
- }
-}
-
static bool ContainsScriptUri(const GrowableArray<const char*>& seen_uris,
const char* uri) {
for (intptr_t i = 0; i < seen_uris.length(); i++) {
@@ -1116,109 +1089,6 @@
}
}
-BitVector* IsolateReloadContext::FindModifiedLibraries(bool force_reload,
- bool root_lib_modified) {
- Thread* thread = Thread::Current();
- int64_t last_reload = I->last_reload_timestamp();
-
- const GrowableObjectArray& libs =
- GrowableObjectArray::Handle(object_store()->libraries());
- Library& lib = Library::Handle();
- Array& scripts = Array::Handle();
- Script& script = Script::Handle();
- intptr_t num_libs = libs.Length();
-
- // Construct the imported-by graph.
- ZoneGrowableArray<ZoneGrowableArray<intptr_t>*>* imported_by = new (zone_)
- ZoneGrowableArray<ZoneGrowableArray<intptr_t>*>(zone_, num_libs);
- imported_by->SetLength(num_libs);
- for (intptr_t i = 0; i < num_libs; i++) {
- (*imported_by)[i] = new (zone_) ZoneGrowableArray<intptr_t>(zone_, 0);
- }
- Array& ports = Array::Handle();
- Namespace& ns = Namespace::Handle();
- Library& target = Library::Handle();
-
- for (intptr_t lib_idx = 0; lib_idx < num_libs; lib_idx++) {
- lib ^= libs.At(lib_idx);
- ASSERT(lib_idx == lib.index());
- if (lib.is_dart_scheme()) {
- // We don't care about imports among dart scheme libraries.
- continue;
- }
-
- // Add imports to the import-by graph.
- ports = lib.imports();
- for (intptr_t import_idx = 0; import_idx < ports.Length(); import_idx++) {
- ns ^= ports.At(import_idx);
- if (!ns.IsNull()) {
- target = ns.library();
- (*imported_by)[target.index()]->Add(lib.index());
- }
- }
-
- // Add exports to the import-by graph.
- ports = lib.exports();
- for (intptr_t export_idx = 0; export_idx < ports.Length(); export_idx++) {
- ns ^= ports.At(export_idx);
- if (!ns.IsNull()) {
- target = ns.library();
- (*imported_by)[target.index()]->Add(lib.index());
- }
- }
-
- // Add prefixed imports to the import-by graph.
- DictionaryIterator entries(lib);
- Object& entry = Object::Handle();
- LibraryPrefix& prefix = LibraryPrefix::Handle();
- while (entries.HasNext()) {
- entry = entries.GetNext();
- if (entry.IsLibraryPrefix()) {
- prefix ^= entry.raw();
- ports = prefix.imports();
- for (intptr_t import_idx = 0; import_idx < ports.Length();
- import_idx++) {
- ns ^= ports.At(import_idx);
- if (!ns.IsNull()) {
- target = ns.library();
- (*imported_by)[target.index()]->Add(lib.index());
- }
- }
- }
- }
- }
-
- BitVector* modified_libs = new (Z) BitVector(Z, num_libs);
-
- if (root_lib_modified) {
- // The root library was either moved or replaced. Mark it as modified to
- // force a reload of the potential root library replacement.
- lib = object_store()->root_library();
- modified_libs->Add(lib.index());
- }
-
- for (intptr_t lib_idx = 0; lib_idx < num_libs; lib_idx++) {
- lib ^= libs.At(lib_idx);
- if (lib.is_dart_scheme() || modified_libs->Contains(lib_idx)) {
- // We don't consider dart scheme libraries during reload. If
- // the modified libs set already contains this library, then we
- // have already visited it.
- continue;
- }
- scripts = lib.LoadedScripts();
- for (intptr_t script_idx = 0; script_idx < scripts.Length(); script_idx++) {
- script ^= scripts.At(script_idx);
- if (force_reload || ScriptModifiedSince(script, last_reload)) {
- modified_libs->Add(lib_idx);
- PropagateLibraryModified(imported_by, lib_idx, modified_libs);
- break;
- }
- }
- }
-
- return modified_libs;
-}
-
void IsolateReloadContext::CheckpointLibraries() {
TIMELINE_SCOPE(CheckpointLibraries);
TIR_Print("---- CHECKPOINTING LIBRARIES\n");
@@ -1276,16 +1146,8 @@
TIR_Print("---- ROLLING BACK CLASS TABLE\n");
ASSERT(saved_num_cids_ > 0);
ASSERT(saved_class_table_ != NULL);
- ClassTable* class_table = I->class_table();
- class_table->SetNumCids(saved_num_cids_);
- // Overwrite classes in class table with the saved classes.
- for (intptr_t i = 0; i < saved_num_cids_; i++) {
- if (class_table->IsValidIndex(i)) {
- class_table->SetAt(i, saved_class_table_[i].get_raw_class());
- }
- }
- DiscardSavedClassTable();
+ DiscardSavedClassTable(/*is_rollback=*/true);
}
void IsolateReloadContext::RollbackLibraries() {
@@ -1381,8 +1243,7 @@
return;
}
- ASSERT(new_cls.is_finalized() == old_cls.is_finalized());
- if (!new_cls.is_finalized()) {
+ if (!old_cls.is_finalized()) {
if (new_cls.SourceFingerprint() == old_cls.SourceFingerprint()) {
return;
}
@@ -1391,6 +1252,7 @@
changed_in_last_reload.Add(new_cls);
return;
}
+ ASSERT(new_cls.is_finalized());
Zone* zone = Thread::Current()->zone();
const Array& functions = Array::Handle(zone, new_cls.functions());
@@ -1680,7 +1542,7 @@
TIMELINE_SCOPE(MorphInstances);
if (!HasInstanceMorphers()) {
// Fast path: no class had a shape change.
- DiscardSavedClassTable();
+ DiscardSavedClassTable(/*is_rollback=*/false);
return;
}
@@ -1702,7 +1564,7 @@
intptr_t count = locator.count();
if (count == 0) {
// Fast path: classes with shape change have no instances.
- DiscardSavedClassTable();
+ DiscardSavedClassTable(/*is_rollback=*/false);
return;
}
@@ -1746,8 +1608,10 @@
saved_class_table_[i] = ClassAndSize(nullptr, -1);
}
#endif
- free(saved_class_table_);
- saved_class_table_ = nullptr;
+
+ // We accepted the hot-reload and morphed instances. So now we can commit to
+ // the changed class table and deleted the saved one.
+ DiscardSavedClassTable(/*is_rollback=*/false);
Become::ElementsForwardIdentity(before, after);
// The heap now contains only instances with the new size. Ordinary GC is safe
@@ -1812,7 +1676,7 @@
RawClass* IsolateReloadContext::GetClassForHeapWalkAt(intptr_t cid) {
ClassAndSize* class_table =
- AtomicOperations::LoadRelaxed(&saved_class_table_);
+ AtomicOperations::LoadAcquire(&saved_class_table_);
if (class_table != NULL) {
ASSERT(cid > 0);
ASSERT(cid < saved_num_cids_);
@@ -1824,7 +1688,7 @@
intptr_t IsolateReloadContext::GetClassSizeForHeapWalkAt(intptr_t cid) {
ClassAndSize* class_table =
- AtomicOperations::LoadRelaxed(&saved_class_table_);
+ AtomicOperations::LoadAcquire(&saved_class_table_);
if (class_table != NULL) {
ASSERT(cid > 0);
ASSERT(cid < saved_num_cids_);
@@ -1834,14 +1698,12 @@
}
}
-void IsolateReloadContext::DiscardSavedClassTable() {
+void IsolateReloadContext::DiscardSavedClassTable(bool is_rollback) {
ClassAndSize* local_saved_class_table = saved_class_table_;
- saved_class_table_ = nullptr;
- // Can't free this table immediately as another thread (e.g., concurrent
- // marker or sweeper) may be between loading the table pointer and loading the
- // table element. The table will be freed at the next major GC or isolate
- // shutdown.
- I->class_table()->AddOldTable(local_saved_class_table);
+ I->class_table()->ResetAfterHotReload(local_saved_class_table,
+ saved_num_cids_, is_rollback);
+ AtomicOperations::StoreRelease(&saved_class_table_,
+ static_cast<ClassAndSize*>(nullptr));
}
RawLibrary* IsolateReloadContext::saved_root_library() const {
diff --git a/runtime/vm/isolate_reload.h b/runtime/vm/isolate_reload.h
index 3f8fa18..300195e 100644
--- a/runtime/vm/isolate_reload.h
+++ b/runtime/vm/isolate_reload.h
@@ -173,7 +173,7 @@
// Prefers old classes when we are in the middle of a reload.
RawClass* GetClassForHeapWalkAt(intptr_t cid);
intptr_t GetClassSizeForHeapWalkAt(intptr_t cid);
- void DiscardSavedClassTable();
+ void DiscardSavedClassTable(bool is_rollback);
void RegisterClass(const Class& new_cls);
@@ -236,7 +236,6 @@
void CheckpointClasses();
bool ScriptModifiedSince(const Script& script, int64_t since);
- BitVector* FindModifiedLibraries(bool force_reload, bool root_lib_modified);
void FindModifiedSources(Thread* thread,
bool force_reload,
Dart_SourceFile** modified_sources,
diff --git a/runtime/vm/isolate_reload_test.cc b/runtime/vm/isolate_reload_test.cc
index 02e02bf..42d125f 100644
--- a/runtime/vm/isolate_reload_test.cc
+++ b/runtime/vm/isolate_reload_test.cc
@@ -2151,6 +2151,7 @@
" final int zero = 0;\n"
"}\n"
"main() {\n"
+ " return new Fruit().zero.toString();\n"
"}\n";
Dart_Handle result = TestCase::ReloadTestScript(kReloadScript);
@@ -2163,12 +2164,12 @@
" final int zero = 0;\n"
"}\n"
"main() {\n"
- " return 'yes';\n"
+ " return new Fruit().zero.toString();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
- EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
+ EXPECT_STREQ("0", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
"enum Fruit {\n"
diff --git a/runtime/vm/json_stream.cc b/runtime/vm/json_stream.cc
index 30cddd2..33a990c 100644
--- a/runtime/vm/json_stream.cc
+++ b/runtime/vm/json_stream.cc
@@ -270,7 +270,7 @@
const char* JSONStream::LookupParam(const char* key) const {
for (int i = 0; i < num_params(); i++) {
- if (!strcmp(key, param_keys_[i])) {
+ if (strcmp(key, param_keys_[i]) == 0) {
return param_values_[i];
}
}
diff --git a/runtime/vm/kernel_binary.h b/runtime/vm/kernel_binary.h
index bad2258..009cab2 100644
--- a/runtime/vm/kernel_binary.h
+++ b/runtime/vm/kernel_binary.h
@@ -20,13 +20,14 @@
// Both version numbers are inclusive.
static const uint32_t kMinSupportedKernelFormatVersion = 18;
-static const uint32_t kMaxSupportedKernelFormatVersion = 29;
+static const uint32_t kMaxSupportedKernelFormatVersion = 31;
// Keep in sync with package:kernel/lib/binary/tag.dart
#define KERNEL_TAG_LIST(V) \
V(Nothing, 0) \
V(Something, 1) \
V(Class, 2) \
+ V(Extension, 115) \
V(FunctionNode, 3) \
V(Field, 4) \
V(Constructor, 5) \
@@ -66,6 +67,7 @@
V(SetConcatenation, 112) \
V(MapConcatenation, 113) \
V(InstanceCreation, 114) \
+ V(FileUriExpression, 116) \
V(IsExpression, 37) \
V(AsExpression, 38) \
V(StringLiteral, 39) \
@@ -123,9 +125,6 @@
V(TypeParameterType, 95) \
V(SimpleInterfaceType, 96) \
V(SimpleFunctionType, 97) \
- V(NullReference, 99) \
- V(ClassReference, 100) \
- V(MemberReference, 101) \
V(ConstantExpression, 106) \
V(Deprecated_ConstantExpression, 107) \
V(SpecializedVariableGet, 128) \
diff --git a/runtime/vm/kernel_loader.cc b/runtime/vm/kernel_loader.cc
index 44c558a..b591aef 100644
--- a/runtime/vm/kernel_loader.cc
+++ b/runtime/vm/kernel_loader.cc
@@ -1139,23 +1139,33 @@
ActiveClassScope active_class_scope(&active_class_, &toplevel_class);
- if (FLAG_enable_interpreter || FLAG_use_bytecode_compiler) {
- static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 10,
- "Cleanup support for old bytecode format versions");
- ASSERT(!toplevel_class.is_declared_in_bytecode());
- if (bytecode_metadata_helper_.ReadMembers(library_kernel_offset_,
- toplevel_class, false)) {
- ASSERT(toplevel_class.is_loaded());
- return;
- }
- }
-
// Offsets within library index are whole program offsets and not
// relative to the library.
const intptr_t correction = correction_offset_ - library_kernel_offset_;
helper_.SetOffset(library_index.ClassOffset(library_index.class_count()) +
correction);
+ if (kernel_binary_version_ >= 30) {
+ const intptr_t extension_count = helper_.ReadListLength();
+ for (intptr_t i = 0; i < extension_count; ++i) {
+ helper_.ReadTag(); // read tag.
+ helper_.SkipCanonicalNameReference(); // skip canonical name.
+ helper_.SkipStringReference(); // skip name.
+ helper_.ReadUInt(); // read source uri index.
+ helper_.ReadPosition(); // read file offset.
+ helper_.SkipTypeParametersList(); // skip type parameter list.
+ helper_.SkipDartType(); // skip on-type.
+
+ const intptr_t extension_member_count = helper_.ReadListLength();
+ for (intptr_t j = 0; j < extension_member_count; ++j) {
+ helper_.SkipName(); // skip name.
+ helper_.ReadByte(); // read kind.
+ helper_.ReadByte(); // read flags.
+ helper_.SkipCanonicalNameReference(); // skip member reference
+ }
+ }
+ }
+
fields_.Clear();
functions_.Clear();
@@ -1295,7 +1305,7 @@
for (intptr_t n = 0; n < name_count; ++n) {
String& show_hide_name =
H.DartSymbolObfuscate(helper_.ReadStringReference());
- if (flags & LibraryDependencyHelper::Show) {
+ if ((flags & LibraryDependencyHelper::Show) != 0) {
show_list.Add(show_hide_name, Heap::kOld);
} else {
hide_list.Add(show_hide_name, Heap::kOld);
@@ -1330,7 +1340,7 @@
}
String& prefix = H.DartSymbolPlain(dependency_helper.name_index_);
ns = Namespace::New(target_library, show_names, hide_names);
- if (dependency_helper.flags_ & LibraryDependencyHelper::Export) {
+ if ((dependency_helper.flags_ & LibraryDependencyHelper::Export) != 0) {
library->AddExport(ns);
} else {
if (prefix.IsNull() || prefix.Length() == 0) {
@@ -1342,7 +1352,8 @@
} else {
library_prefix = LibraryPrefix::New(
prefix, ns,
- dependency_helper.flags_ & LibraryDependencyHelper::Deferred,
+ (dependency_helper.flags_ & LibraryDependencyHelper::Deferred) !=
+ 0,
*library);
library->AddObject(library_prefix, prefix);
}
@@ -1499,18 +1510,6 @@
// fields.
const bool discard_fields = klass.InjectCIDFields();
- if (FLAG_enable_interpreter || FLAG_use_bytecode_compiler) {
- static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 10,
- "Cleanup support for old bytecode format versions");
- ASSERT(!klass.is_declared_in_bytecode());
- if (bytecode_metadata_helper_.ReadMembers(
- klass.kernel_offset() + library_kernel_offset_, klass,
- discard_fields)) {
- ASSERT(klass.is_loaded());
- return;
- }
- }
-
fields_.Clear();
functions_.Clear();
if (!discard_fields) {
diff --git a/runtime/vm/malloc_hooks_test.cc b/runtime/vm/malloc_hooks_test.cc
index 28c6009..80dc9d1 100644
--- a/runtime/vm/malloc_hooks_test.cc
+++ b/runtime/vm/malloc_hooks_test.cc
@@ -180,7 +180,7 @@
char* var = static_cast<char*>(malloc(16 * sizeof(char)));
JSONStream js;
- ProfilerService::PrintNativeAllocationJSON(&js, Profile::kNoTags, -1, -1);
+ ProfilerService::PrintNativeAllocationJSON(&js, -1, -1, false);
const char* json = js.ToCString();
// Check that all the stack frames from the current down to main are actually
diff --git a/runtime/vm/megamorphic_cache_table.cc b/runtime/vm/megamorphic_cache_table.cc
index 3edc7b2..19deb0a 100644
--- a/runtime/vm/megamorphic_cache_table.cc
+++ b/runtime/vm/megamorphic_cache_table.cc
@@ -13,10 +13,9 @@
namespace dart {
-RawMegamorphicCache* MegamorphicCacheTable::LookupOriginal(
- Thread* thread,
- const String& name,
- const Array& descriptor) {
+RawMegamorphicCache* MegamorphicCacheTable::Lookup(Thread* thread,
+ const String& name,
+ const Array& descriptor) {
Isolate* isolate = thread->isolate();
// Multiple compilation threads could access this lookup.
SafepointMutexLocker ml(isolate->megamorphic_mutex());
@@ -45,31 +44,6 @@
return cache.raw();
}
-RawMegamorphicCache* MegamorphicCacheTable::LookupClone(
- Thread* thread,
- const String& name,
- const Array& descriptor) {
- if (!Compiler::IsBackgroundCompilation()) {
- return LookupOriginal(thread, name, descriptor);
- }
-
- auto& cloned_caches = thread->compiler_state().cloned_megamorphic_caches();
- for (intptr_t i = 0; i < cloned_caches.length(); i++) {
- const MegamorphicCache& cache = *cloned_caches[i];
- if ((cache.target_name() == name.raw()) &&
- (cache.arguments_descriptor() == descriptor.raw())) {
- return cache.raw();
- }
- }
-
- const auto& original =
- MegamorphicCache::Handle(LookupOriginal(thread, name, descriptor));
- const auto& clone =
- MegamorphicCache::ZoneHandle(MegamorphicCache::Clone(original));
- cloned_caches.Add(&clone);
- return clone.raw();
-}
-
RawFunction* MegamorphicCacheTable::miss_handler(Isolate* isolate) {
ASSERT(isolate->object_store()->megamorphic_miss_function() !=
Function::null());
diff --git a/runtime/vm/megamorphic_cache_table.h b/runtime/vm/megamorphic_cache_table.h
index c3c40d5..6b68c6c 100644
--- a/runtime/vm/megamorphic_cache_table.h
+++ b/runtime/vm/megamorphic_cache_table.h
@@ -39,16 +39,9 @@
static void ReInitMissHandlerCode(Isolate* isolate,
compiler::ObjectPoolBuilder* wrapper));
- // Lookup a cache for querying type feedback. The result may not be mutated by
- // another thread.
- static RawMegamorphicCache* LookupClone(Thread* thread,
- const String& name,
- const Array& descriptor);
- // Lookup a cache for insertion into compiled code. The result may be mutated
- // by the another thread.
- static RawMegamorphicCache* LookupOriginal(Thread* thread,
- const String& name,
- const Array& descriptor);
+ static RawMegamorphicCache* Lookup(Thread* thread,
+ const String& name,
+ const Array& descriptor);
static void PrintSizes(Isolate* isolate);
};
diff --git a/runtime/vm/message_handler.cc b/runtime/vm/message_handler.cc
index 0951509..d945b97 100644
--- a/runtime/vm/message_handler.cc
+++ b/runtime/vm/message_handler.cc
@@ -130,7 +130,7 @@
MonitorLocker ml(&monitor_);
if (FLAG_trace_isolates) {
Isolate* source_isolate = Isolate::Current();
- if (source_isolate) {
+ if (source_isolate != nullptr) {
OS::PrintErr(
"[>] Posting message:\n"
"\tlen: %" Pd "\n\tsource: (%" Pd64
@@ -416,7 +416,7 @@
#endif // !defined(PRODUCT)
if (status == kOK) {
- if (start_callback_) {
+ if (start_callback_ != nullptr) {
// Initialize the message handler by running its start function,
// if we have one. For an isolate, this will run the isolate's
// main() function.
diff --git a/runtime/vm/native_api_impl.cc b/runtime/vm/native_api_impl.cc
index 2739b43..f1306b1 100644
--- a/runtime/vm/native_api_impl.cc
+++ b/runtime/vm/native_api_impl.cc
@@ -139,14 +139,18 @@
auto port =
::Dart_NewNativePort("service-rpc", &Utils::HandleResponse, false);
if (port == ILLEGAL_PORT) {
- return Api::NewError("Was unable to create native port.");
+ if (error != nullptr) {
+ *error = strdup("Was unable to create native port.");
+ }
+ return false;
}
// Before sending the message we'll lock the monitor, which the receiver
// will later on notify once the answer has been received.
MonitorLocker monitor(vm_service_call_monitor);
- if (ServiceIsolate::SendServiceRpc(request_json, request_json_length, port)) {
+ if (ServiceIsolate::SendServiceRpc(request_json, request_json_length, port,
+ error)) {
// We posted successfully and expect the vm-service to send the reply, so
// we will wait for it now.
auto wait_result = monitor.Wait();
@@ -170,14 +174,6 @@
// We couldn't post the message and will not receive any reply. Therefore we
// clean up the port and return an error.
Dart_CloseNativePort(port);
-
- if (error != nullptr) {
- if (ServiceIsolate::Port() == ILLEGAL_PORT) {
- *error = strdup("No service isolate port was found.");
- } else {
- *error = strdup("Was unable to post message to service isolate.");
- }
- }
return false;
}
}
@@ -251,20 +247,20 @@
DART_EXPORT void* Dart_ExecuteInternalCommand(const char* command, void* arg) {
if (!FLAG_enable_testing_pragmas) return nullptr;
- if (!strcmp(command, "gc-on-nth-allocation")) {
+ if (strcmp(command, "gc-on-nth-allocation") == 0) {
TransitionNativeToVM _(Thread::Current());
intptr_t argument = reinterpret_cast<intptr_t>(arg);
ASSERT(argument > 0);
Isolate::Current()->heap()->CollectOnNthAllocation(argument);
return nullptr;
- } else if (!strcmp(command, "gc-now")) {
+ } else if (strcmp(command, "gc-now") == 0) {
ASSERT(arg == nullptr); // Don't pass an argument to this command.
TransitionNativeToVM _(Thread::Current());
Isolate::Current()->heap()->CollectAllGarbage();
return nullptr;
- } else if (!strcmp(command, "is-mutator-in-native")) {
+ } else if (strcmp(command, "is-mutator-in-native") == 0) {
Isolate* const isolate = reinterpret_cast<Isolate*>(arg);
if (isolate->mutator_thread()->execution_state() ==
Thread::kThreadInNative) {
@@ -273,7 +269,7 @@
return nullptr;
}
- } else if (!strcmp(command, "run-in-safepoint-and-rw-code")) {
+ } else if (strcmp(command, "run-in-safepoint-and-rw-code") == 0) {
const RunInSafepointAndRWCodeArgs* const args =
reinterpret_cast<RunInSafepointAndRWCodeArgs*>(arg);
Thread::EnterIsolateAsHelper(args->isolate, Thread::TaskKind::kUnknownTask);
diff --git a/runtime/vm/native_arguments.h b/runtime/vm/native_arguments.h
index ab948de..8d07143 100644
--- a/runtime/vm/native_arguments.h
+++ b/runtime/vm/native_arguments.h
@@ -120,7 +120,8 @@
if ((function_bits & (kClosureFunctionBit | kInstanceFunctionBit)) ==
(kClosureFunctionBit | kInstanceFunctionBit)) {
// Retrieve the receiver from the context.
- const int closure_index = (function_bits & kGenericFunctionBit) ? 1 : 0;
+ const int closure_index =
+ (function_bits & kGenericFunctionBit) != 0 ? 1 : 0;
const Object& closure = Object::Handle(ArgAt(closure_index));
const Context& context =
Context::Handle(Closure::Cast(closure).context());
@@ -268,17 +269,17 @@
// Returns true if the arguments are those of an instance function call.
bool ToInstanceFunction() const {
- return (FunctionBits::decode(argc_tag_) & kInstanceFunctionBit);
+ return (FunctionBits::decode(argc_tag_) & kInstanceFunctionBit) != 0;
}
// Returns true if the arguments are those of a closure function call.
bool ToClosureFunction() const {
- return (FunctionBits::decode(argc_tag_) & kClosureFunctionBit);
+ return (FunctionBits::decode(argc_tag_) & kClosureFunctionBit) != 0;
}
// Returns true if the arguments are those of a generic function call.
bool ToGenericFunction() const {
- return (FunctionBits::decode(argc_tag_) & kGenericFunctionBit);
+ return (FunctionBits::decode(argc_tag_) & kGenericFunctionBit) != 0;
}
int NumHiddenArgs(int function_bits) const {
diff --git a/runtime/vm/native_entry.h b/runtime/vm/native_entry.h
index a4a5ee5..6878c45 100644
--- a/runtime/vm/native_entry.h
+++ b/runtime/vm/native_entry.h
@@ -35,15 +35,6 @@
#define NATIVE_ENTRY_FUNCTION(name) BootstrapNatives::DN_##name
-#ifdef DEBUG
-#define SET_NATIVE_RETVAL(args, value) \
- RawObject* retval = value; \
- ASSERT(retval->IsDartInstance()); \
- arguments->SetReturnUnsafe(retval);
-#else
-#define SET_NATIVE_RETVAL(arguments, value) arguments->SetReturnUnsafe(value);
-#endif
-
#define DEFINE_NATIVE_ENTRY(name, type_argument_count, argument_count) \
static RawObject* DN_Helper##name(Isolate* isolate, Thread* thread, \
Zone* zone, NativeArguments* arguments); \
@@ -63,9 +54,15 @@
Isolate* isolate = thread->isolate(); \
TransitionGeneratedToVM transition(thread); \
StackZone zone(thread); \
- SET_NATIVE_RETVAL( \
- arguments, \
- DN_Helper##name(isolate, thread, zone.GetZone(), arguments)); \
+ /* Be careful holding return_value_unsafe without a handle here. */ \
+ /* A return of Object::sentinel means the return value has already */ \
+ /* been set. */ \
+ RawObject* return_value_unsafe = \
+ DN_Helper##name(isolate, thread, zone.GetZone(), arguments); \
+ if (return_value_unsafe != Object::sentinel().raw()) { \
+ ASSERT(return_value_unsafe->IsDartInstance()); \
+ arguments->SetReturnUnsafe(return_value_unsafe); \
+ } \
DEOPTIMIZE_ALOT; \
} \
VERIFY_ON_TRANSITION; \
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 93e43d5..5dbc67b 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -90,6 +90,7 @@
DECLARE_FLAG(bool, trace_reload);
DECLARE_FLAG(bool, write_protect_code);
DECLARE_FLAG(bool, precompiled_mode);
+DECLARE_FLAG(int, max_polymorphic_checks);
static const char* const kGetterPrefix = "get:";
static const intptr_t kGetterPrefixLength = strlen(kGetterPrefix);
@@ -552,19 +553,19 @@
}
// Allocate and initialize the null class.
- cls = Class::New<Instance>(kNullCid);
+ cls = Class::New<Instance>(kNullCid, isolate);
cls.set_num_type_arguments(0);
isolate->object_store()->set_null_class(cls);
// Allocate and initialize the free list element class.
- cls = Class::New<FreeListElement::FakeInstance>(kFreeListElement);
+ cls = Class::New<FreeListElement::FakeInstance>(kFreeListElement, isolate);
cls.set_num_type_arguments(0);
cls.set_is_finalized();
cls.set_is_declaration_loaded();
cls.set_is_type_finalized();
// Allocate and initialize the forwarding corpse class.
- cls = Class::New<ForwardingCorpse::FakeInstance>(kForwardingCorpse);
+ cls = Class::New<ForwardingCorpse::FakeInstance>(kForwardingCorpse, isolate);
cls.set_num_type_arguments(0);
cls.set_is_finalized();
cls.set_is_declaration_loaded();
@@ -588,138 +589,138 @@
}
// Allocate the remaining VM internal classes.
- cls = Class::New<TypeArguments>();
+ cls = Class::New<TypeArguments>(isolate);
type_arguments_class_ = cls.raw();
- cls = Class::New<PatchClass>();
+ cls = Class::New<PatchClass>(isolate);
patch_class_class_ = cls.raw();
- cls = Class::New<Function>();
+ cls = Class::New<Function>(isolate);
function_class_ = cls.raw();
- cls = Class::New<ClosureData>();
+ cls = Class::New<ClosureData>(isolate);
closure_data_class_ = cls.raw();
- cls = Class::New<SignatureData>();
+ cls = Class::New<SignatureData>(isolate);
signature_data_class_ = cls.raw();
- cls = Class::New<RedirectionData>();
+ cls = Class::New<RedirectionData>(isolate);
redirection_data_class_ = cls.raw();
- cls = Class::New<FfiTrampolineData>();
+ cls = Class::New<FfiTrampolineData>(isolate);
ffi_trampoline_data_class_ = cls.raw();
- cls = Class::New<Field>();
+ cls = Class::New<Field>(isolate);
field_class_ = cls.raw();
- cls = Class::New<Script>();
+ cls = Class::New<Script>(isolate);
script_class_ = cls.raw();
- cls = Class::New<Library>();
+ cls = Class::New<Library>(isolate);
library_class_ = cls.raw();
- cls = Class::New<Namespace>();
+ cls = Class::New<Namespace>(isolate);
namespace_class_ = cls.raw();
- cls = Class::New<KernelProgramInfo>();
+ cls = Class::New<KernelProgramInfo>(isolate);
kernel_program_info_class_ = cls.raw();
- cls = Class::New<Code>();
+ cls = Class::New<Code>(isolate);
code_class_ = cls.raw();
- cls = Class::New<Bytecode>();
+ cls = Class::New<Bytecode>(isolate);
bytecode_class_ = cls.raw();
- cls = Class::New<Instructions>();
+ cls = Class::New<Instructions>(isolate);
instructions_class_ = cls.raw();
- cls = Class::New<ObjectPool>();
+ cls = Class::New<ObjectPool>(isolate);
object_pool_class_ = cls.raw();
- cls = Class::New<PcDescriptors>();
+ cls = Class::New<PcDescriptors>(isolate);
pc_descriptors_class_ = cls.raw();
- cls = Class::New<CodeSourceMap>();
+ cls = Class::New<CodeSourceMap>(isolate);
code_source_map_class_ = cls.raw();
- cls = Class::New<StackMap>();
+ cls = Class::New<StackMap>(isolate);
stackmap_class_ = cls.raw();
- cls = Class::New<LocalVarDescriptors>();
+ cls = Class::New<LocalVarDescriptors>(isolate);
var_descriptors_class_ = cls.raw();
- cls = Class::New<ExceptionHandlers>();
+ cls = Class::New<ExceptionHandlers>(isolate);
exception_handlers_class_ = cls.raw();
- cls = Class::New<Context>();
+ cls = Class::New<Context>(isolate);
context_class_ = cls.raw();
- cls = Class::New<ContextScope>();
+ cls = Class::New<ContextScope>(isolate);
context_scope_class_ = cls.raw();
- cls = Class::New<ParameterTypeCheck>();
+ cls = Class::New<ParameterTypeCheck>(isolate);
dyncalltypecheck_class_ = cls.raw();
- cls = Class::New<SingleTargetCache>();
+ cls = Class::New<SingleTargetCache>(isolate);
singletargetcache_class_ = cls.raw();
- cls = Class::New<UnlinkedCall>();
+ cls = Class::New<UnlinkedCall>(isolate);
unlinkedcall_class_ = cls.raw();
- cls = Class::New<ICData>();
+ cls = Class::New<ICData>(isolate);
icdata_class_ = cls.raw();
- cls = Class::New<MegamorphicCache>();
+ cls = Class::New<MegamorphicCache>(isolate);
megamorphic_cache_class_ = cls.raw();
- cls = Class::New<SubtypeTestCache>();
+ cls = Class::New<SubtypeTestCache>(isolate);
subtypetestcache_class_ = cls.raw();
- cls = Class::New<ApiError>();
+ cls = Class::New<ApiError>(isolate);
api_error_class_ = cls.raw();
- cls = Class::New<LanguageError>();
+ cls = Class::New<LanguageError>(isolate);
language_error_class_ = cls.raw();
- cls = Class::New<UnhandledException>();
+ cls = Class::New<UnhandledException>(isolate);
unhandled_exception_class_ = cls.raw();
- cls = Class::New<UnwindError>();
+ cls = Class::New<UnwindError>(isolate);
unwind_error_class_ = cls.raw();
ASSERT(class_class() != null_);
// Pre-allocate classes in the vm isolate so that we can for example create a
// symbol table and populate it with some frequently used strings as symbols.
- cls = Class::New<Array>();
+ cls = Class::New<Array>(isolate);
isolate->object_store()->set_array_class(cls);
cls.set_type_arguments_field_offset(Array::type_arguments_offset());
cls.set_num_type_arguments(1);
- cls = Class::New<Array>(kImmutableArrayCid);
+ cls = Class::New<Array>(kImmutableArrayCid, isolate);
isolate->object_store()->set_immutable_array_class(cls);
cls.set_type_arguments_field_offset(Array::type_arguments_offset());
cls.set_num_type_arguments(1);
- cls = Class::New<GrowableObjectArray>();
+ cls = Class::New<GrowableObjectArray>(isolate);
isolate->object_store()->set_growable_object_array_class(cls);
cls.set_type_arguments_field_offset(
GrowableObjectArray::type_arguments_offset());
cls.set_num_type_arguments(1);
- cls = Class::NewStringClass(kOneByteStringCid);
+ cls = Class::NewStringClass(kOneByteStringCid, isolate);
isolate->object_store()->set_one_byte_string_class(cls);
- cls = Class::NewStringClass(kTwoByteStringCid);
+ cls = Class::NewStringClass(kTwoByteStringCid, isolate);
isolate->object_store()->set_two_byte_string_class(cls);
- cls = Class::New<Mint>();
+ cls = Class::New<Mint>(isolate);
isolate->object_store()->set_mint_class(cls);
- cls = Class::New<Double>();
+ cls = Class::New<Double>(isolate);
isolate->object_store()->set_double_class(cls);
// Ensure that class kExternalTypedDataUint8ArrayCid is registered as we
// need it when reading in the token stream of bootstrap classes in the VM
// isolate.
- Class::NewExternalTypedDataClass(kExternalTypedDataUint8ArrayCid);
+ Class::NewExternalTypedDataClass(kExternalTypedDataUint8ArrayCid, isolate);
// Needed for object pools of VM isolate stubs.
- Class::NewTypedDataClass(kTypedDataInt8ArrayCid);
+ Class::NewTypedDataClass(kTypedDataInt8ArrayCid, isolate);
// Allocate and initialize the empty_array instance.
{
@@ -832,7 +833,7 @@
// as we do not have any VM isolate snapshot at this time.
*vm_isolate_snapshot_object_table_ = Object::empty_array().raw();
- cls = Class::New<Instance>(kDynamicCid);
+ cls = Class::New<Instance>(kDynamicCid, isolate);
cls.set_is_abstract();
cls.set_num_type_arguments(0);
cls.set_is_finalized();
@@ -840,14 +841,14 @@
cls.set_is_type_finalized();
dynamic_class_ = cls.raw();
- cls = Class::New<Instance>(kVoidCid);
+ cls = Class::New<Instance>(kVoidCid, isolate);
cls.set_num_type_arguments(0);
cls.set_is_finalized();
cls.set_is_declaration_loaded();
cls.set_is_type_finalized();
void_class_ = cls.raw();
- cls = Class::New<Type>();
+ cls = Class::New<Type>(isolate);
cls.set_is_finalized();
cls.set_is_declaration_loaded();
cls.set_is_type_finalized();
@@ -868,7 +869,7 @@
cls.SetFunctions(Object::empty_array());
// Allocate and initialize singleton true and false boolean objects.
- cls = Class::New<Bool>();
+ cls = Class::New<Bool>(isolate);
isolate->object_store()->set_bool_class(cls);
*bool_true_ = Bool::New(true);
*bool_false_ = Bool::New(false);
@@ -1398,7 +1399,7 @@
// All RawArray fields will be initialized to an empty array, therefore
// initialize array class first.
- cls = Class::New<Array>();
+ cls = Class::New<Array>(isolate);
object_store->set_array_class(cls);
// VM classes that are parameterized (Array, ImmutableArray,
@@ -1411,7 +1412,7 @@
// Set up the growable object array class (Has to be done after the array
// class is setup as one of its field is an array object).
- cls = Class::New<GrowableObjectArray>();
+ cls = Class::New<GrowableObjectArray>(isolate);
object_store->set_growable_object_array_class(cls);
cls.set_type_arguments_field_offset(
GrowableObjectArray::type_arguments_offset());
@@ -1430,19 +1431,20 @@
object_store->set_canonical_type_arguments(array);
// Setup type class early in the process.
- const Class& type_cls = Class::Handle(zone, Class::New<Type>());
- const Class& type_ref_cls = Class::Handle(zone, Class::New<TypeRef>());
+ const Class& type_cls = Class::Handle(zone, Class::New<Type>(isolate));
+ const Class& type_ref_cls =
+ Class::Handle(zone, Class::New<TypeRef>(isolate));
const Class& type_parameter_cls =
- Class::Handle(zone, Class::New<TypeParameter>());
+ Class::Handle(zone, Class::New<TypeParameter>(isolate));
const Class& library_prefix_cls =
- Class::Handle(zone, Class::New<LibraryPrefix>());
+ Class::Handle(zone, Class::New<LibraryPrefix>(isolate));
// Pre-allocate the OneByteString class needed by the symbol table.
- cls = Class::NewStringClass(kOneByteStringCid);
+ cls = Class::NewStringClass(kOneByteStringCid, isolate);
object_store->set_one_byte_string_class(cls);
// Pre-allocate the TwoByteString class needed by the symbol table.
- cls = Class::NewStringClass(kTwoByteStringCid);
+ cls = Class::NewStringClass(kTwoByteStringCid, isolate);
object_store->set_two_byte_string_class(cls);
// Setup the symbol table for the symbols created in the isolate.
@@ -1486,7 +1488,7 @@
RegisterPrivateClass(cls, Symbols::_GrowableList(), core_lib);
pending_classes.Add(cls);
- cls = Class::New<Array>(kImmutableArrayCid);
+ cls = Class::New<Array>(kImmutableArrayCid, isolate);
object_store->set_immutable_array_class(cls);
cls.set_type_arguments_field_offset(Array::type_arguments_offset());
cls.set_num_type_arguments(1);
@@ -1504,12 +1506,12 @@
RegisterPrivateClass(cls, Symbols::TwoByteString(), core_lib);
pending_classes.Add(cls);
- cls = Class::NewStringClass(kExternalOneByteStringCid);
+ cls = Class::NewStringClass(kExternalOneByteStringCid, isolate);
object_store->set_external_one_byte_string_class(cls);
RegisterPrivateClass(cls, Symbols::ExternalOneByteString(), core_lib);
pending_classes.Add(cls);
- cls = Class::NewStringClass(kExternalTwoByteStringCid);
+ cls = Class::NewStringClass(kExternalTwoByteStringCid, isolate);
object_store->set_external_two_byte_string_class(cls);
RegisterPrivateClass(cls, Symbols::ExternalTwoByteString(), core_lib);
pending_classes.Add(cls);
@@ -1527,29 +1529,30 @@
ASSERT(!isolate_lib.IsNull());
ASSERT(isolate_lib.raw() == Library::IsolateLibrary());
- cls = Class::New<Capability>();
+ cls = Class::New<Capability>(isolate);
RegisterPrivateClass(cls, Symbols::_CapabilityImpl(), isolate_lib);
pending_classes.Add(cls);
- cls = Class::New<ReceivePort>();
+ cls = Class::New<ReceivePort>(isolate);
RegisterPrivateClass(cls, Symbols::_RawReceivePortImpl(), isolate_lib);
pending_classes.Add(cls);
- cls = Class::New<SendPort>();
+ cls = Class::New<SendPort>(isolate);
RegisterPrivateClass(cls, Symbols::_SendPortImpl(), isolate_lib);
pending_classes.Add(cls);
- cls = Class::New<TransferableTypedData>();
+ cls = Class::New<TransferableTypedData>(isolate);
RegisterPrivateClass(cls, Symbols::_TransferableTypedDataImpl(),
isolate_lib);
pending_classes.Add(cls);
- const Class& stacktrace_cls = Class::Handle(zone, Class::New<StackTrace>());
+ const Class& stacktrace_cls =
+ Class::Handle(zone, Class::New<StackTrace>(isolate));
RegisterPrivateClass(stacktrace_cls, Symbols::_StackTrace(), core_lib);
pending_classes.Add(stacktrace_cls);
// Super type set below, after Object is allocated.
- cls = Class::New<RegExp>();
+ cls = Class::New<RegExp>(isolate);
RegisterPrivateClass(cls, Symbols::_RegExp(), core_lib);
pending_classes.Add(cls);
@@ -1559,7 +1562,7 @@
// The script and token index of these pre-allocated classes is set up in
// the parser when the corelib script is compiled (see
// Parser::ParseClassDefinition).
- cls = Class::New<Instance>(kInstanceCid);
+ cls = Class::New<Instance>(kInstanceCid, isolate);
object_store->set_object_class(cls);
cls.set_name(Symbols::Object());
cls.set_num_type_arguments(0);
@@ -1569,12 +1572,12 @@
type = Type::NewNonParameterizedType(cls);
object_store->set_object_type(type);
- cls = Class::New<Bool>();
+ cls = Class::New<Bool>(isolate);
object_store->set_bool_class(cls);
RegisterClass(cls, Symbols::Bool(), core_lib);
pending_classes.Add(cls);
- cls = Class::New<Instance>(kNullCid);
+ cls = Class::New<Instance>(kNullCid, isolate);
object_store->set_null_class(cls);
cls.set_num_type_arguments(0);
cls.set_is_prefinalized();
@@ -1596,33 +1599,33 @@
core_lib);
pending_classes.Add(type_parameter_cls);
- cls = Class::New<Integer>();
+ cls = Class::New<Integer>(isolate);
object_store->set_integer_implementation_class(cls);
RegisterPrivateClass(cls, Symbols::_IntegerImplementation(), core_lib);
pending_classes.Add(cls);
- cls = Class::New<Smi>();
+ cls = Class::New<Smi>(isolate);
object_store->set_smi_class(cls);
RegisterPrivateClass(cls, Symbols::_Smi(), core_lib);
pending_classes.Add(cls);
- cls = Class::New<Mint>();
+ cls = Class::New<Mint>(isolate);
object_store->set_mint_class(cls);
RegisterPrivateClass(cls, Symbols::_Mint(), core_lib);
pending_classes.Add(cls);
- cls = Class::New<Double>();
+ cls = Class::New<Double>(isolate);
object_store->set_double_class(cls);
RegisterPrivateClass(cls, Symbols::_Double(), core_lib);
pending_classes.Add(cls);
// Class that represents the Dart class _Closure and C++ class Closure.
- cls = Class::New<Closure>();
+ cls = Class::New<Closure>(isolate);
object_store->set_closure_class(cls);
RegisterPrivateClass(cls, Symbols::_Closure(), core_lib);
pending_classes.Add(cls);
- cls = Class::New<WeakProperty>();
+ cls = Class::New<WeakProperty>(isolate);
object_store->set_weak_property_class(cls);
RegisterPrivateClass(cls, Symbols::_WeakProperty(), core_lib);
@@ -1639,7 +1642,7 @@
ASSERT(!lib.IsNull());
ASSERT(lib.raw() == Library::MirrorsLibrary());
- cls = Class::New<MirrorReference>();
+ cls = Class::New<MirrorReference>(isolate);
RegisterPrivateClass(cls, Symbols::_MirrorReference(), lib);
#endif
@@ -1655,7 +1658,7 @@
object_store->set_bootstrap_library(ObjectStore::kCollection, lib);
ASSERT(!lib.IsNull());
ASSERT(lib.raw() == Library::CollectionLibrary());
- cls = Class::New<LinkedHashMap>();
+ cls = Class::New<LinkedHashMap>(isolate);
object_store->set_linked_hash_map_class(cls);
cls.set_type_arguments_field_offset(LinkedHashMap::type_arguments_offset());
cls.set_num_type_arguments(2);
@@ -1673,7 +1676,7 @@
object_store->set_bootstrap_library(ObjectStore::kDeveloper, lib);
ASSERT(!lib.IsNull());
ASSERT(lib.raw() == Library::DeveloperLibrary());
- cls = Class::New<UserTag>();
+ cls = Class::New<UserTag>(isolate);
RegisterPrivateClass(cls, Symbols::_UserTag(), lib);
pending_classes.Add(cls);
@@ -1694,66 +1697,69 @@
ASSERT(!lib.IsNull());
ASSERT(lib.raw() == Library::TypedDataLibrary());
#define REGISTER_TYPED_DATA_CLASS(clazz) \
- cls = Class::NewTypedDataClass(kTypedData##clazz##ArrayCid); \
+ cls = Class::NewTypedDataClass(kTypedData##clazz##ArrayCid, isolate); \
RegisterPrivateClass(cls, Symbols::_##clazz##List(), lib);
DART_CLASS_LIST_TYPED_DATA(REGISTER_TYPED_DATA_CLASS);
#undef REGISTER_TYPED_DATA_CLASS
#define REGISTER_TYPED_DATA_VIEW_CLASS(clazz) \
- cls = Class::NewTypedDataViewClass(kTypedData##clazz##ViewCid); \
+ cls = Class::NewTypedDataViewClass(kTypedData##clazz##ViewCid, isolate); \
RegisterPrivateClass(cls, Symbols::_##clazz##View(), lib); \
pending_classes.Add(cls);
CLASS_LIST_TYPED_DATA(REGISTER_TYPED_DATA_VIEW_CLASS);
- cls = Class::NewTypedDataViewClass(kByteDataViewCid);
+ cls = Class::NewTypedDataViewClass(kByteDataViewCid, isolate);
RegisterPrivateClass(cls, Symbols::_ByteDataView(), lib);
pending_classes.Add(cls);
#undef REGISTER_TYPED_DATA_VIEW_CLASS
#define REGISTER_EXT_TYPED_DATA_CLASS(clazz) \
- cls = Class::NewExternalTypedDataClass(kExternalTypedData##clazz##Cid); \
+ cls = Class::NewExternalTypedDataClass(kExternalTypedData##clazz##Cid, \
+ isolate); \
RegisterPrivateClass(cls, Symbols::_External##clazz(), lib);
- cls = Class::New<Instance>(kByteBufferCid);
+ cls =
+ Class::New<Instance>(kByteBufferCid, isolate, /*register_class=*/false);
cls.set_instance_size(0);
cls.set_next_field_offset(-kWordSize);
+ isolate->RegisterClass(cls);
RegisterPrivateClass(cls, Symbols::_ByteBuffer(), lib);
pending_classes.Add(cls);
CLASS_LIST_TYPED_DATA(REGISTER_EXT_TYPED_DATA_CLASS);
#undef REGISTER_EXT_TYPED_DATA_CLASS
// Register Float32x4, Int32x4, and Float64x2 in the object store.
- cls = Class::New<Float32x4>();
+ cls = Class::New<Float32x4>(isolate);
RegisterPrivateClass(cls, Symbols::_Float32x4(), lib);
pending_classes.Add(cls);
object_store->set_float32x4_class(cls);
- cls = Class::New<Instance>(kIllegalCid);
+ cls = Class::New<Instance>(kIllegalCid, isolate);
RegisterClass(cls, Symbols::Float32x4(), lib);
cls.set_num_type_arguments(0);
cls.set_is_prefinalized();
type = Type::NewNonParameterizedType(cls);
object_store->set_float32x4_type(type);
- cls = Class::New<Int32x4>();
+ cls = Class::New<Int32x4>(isolate);
RegisterPrivateClass(cls, Symbols::_Int32x4(), lib);
pending_classes.Add(cls);
object_store->set_int32x4_class(cls);
- cls = Class::New<Instance>(kIllegalCid);
+ cls = Class::New<Instance>(kIllegalCid, isolate);
RegisterClass(cls, Symbols::Int32x4(), lib);
cls.set_num_type_arguments(0);
cls.set_is_prefinalized();
type = Type::NewNonParameterizedType(cls);
object_store->set_int32x4_type(type);
- cls = Class::New<Float64x2>();
+ cls = Class::New<Float64x2>(isolate);
RegisterPrivateClass(cls, Symbols::_Float64x2(), lib);
pending_classes.Add(cls);
object_store->set_float64x2_class(cls);
- cls = Class::New<Instance>(kIllegalCid);
+ cls = Class::New<Instance>(kIllegalCid, isolate);
RegisterClass(cls, Symbols::Float64x2(), lib);
cls.set_num_type_arguments(0);
cls.set_is_prefinalized();
@@ -1767,7 +1773,7 @@
// Abstract class that represents the Dart class Type.
// Note that this class is implemented by Dart class _AbstractType.
- cls = Class::New<Instance>(kIllegalCid);
+ cls = Class::New<Instance>(kIllegalCid, isolate);
cls.set_num_type_arguments(0);
cls.set_is_prefinalized();
RegisterClass(cls, Symbols::Type(), core_lib);
@@ -1776,7 +1782,7 @@
object_store->set_type_type(type);
// Abstract class that represents the Dart class Function.
- cls = Class::New<Instance>(kIllegalCid);
+ cls = Class::New<Instance>(kIllegalCid, isolate);
cls.set_num_type_arguments(0);
cls.set_is_prefinalized();
RegisterClass(cls, Symbols::Function(), core_lib);
@@ -1784,13 +1790,13 @@
type = Type::NewNonParameterizedType(cls);
object_store->set_function_type(type);
- cls = Class::New<Number>();
+ cls = Class::New<Number>(isolate);
RegisterClass(cls, Symbols::Number(), core_lib);
pending_classes.Add(cls);
type = Type::NewNonParameterizedType(cls);
object_store->set_number_type(type);
- cls = Class::New<Instance>(kIllegalCid);
+ cls = Class::New<Instance>(kIllegalCid, isolate);
RegisterClass(cls, Symbols::Int(), core_lib);
cls.set_num_type_arguments(0);
cls.set_is_prefinalized();
@@ -1798,7 +1804,7 @@
type = Type::NewNonParameterizedType(cls);
object_store->set_int_type(type);
- cls = Class::New<Instance>(kIllegalCid);
+ cls = Class::New<Instance>(kIllegalCid, isolate);
RegisterClass(cls, Symbols::Double(), core_lib);
cls.set_num_type_arguments(0);
cls.set_is_prefinalized();
@@ -1807,7 +1813,7 @@
object_store->set_double_type(type);
name = Symbols::_String().raw();
- cls = Class::New<Instance>(kIllegalCid);
+ cls = Class::New<Instance>(kIllegalCid, isolate);
RegisterClass(cls, name, core_lib);
cls.set_num_type_arguments(0);
cls.set_is_prefinalized();
@@ -1883,7 +1889,7 @@
}
object_store->set_bootstrap_library(ObjectStore::kFfi, lib);
- cls = Class::New<Instance>(kFfiNativeTypeCid);
+ cls = Class::New<Instance>(kFfiNativeTypeCid, isolate);
cls.set_num_type_arguments(0);
cls.set_is_prefinalized();
pending_classes.Add(cls);
@@ -1891,7 +1897,7 @@
RegisterClass(cls, Symbols::FfiNativeType(), lib);
#define REGISTER_FFI_TYPE_MARKER(clazz) \
- cls = Class::New<Instance>(kFfi##clazz##Cid); \
+ cls = Class::New<Instance>(kFfi##clazz##Cid, isolate); \
cls.set_num_type_arguments(0); \
cls.set_is_prefinalized(); \
pending_classes.Add(cls); \
@@ -1899,24 +1905,32 @@
CLASS_LIST_FFI_TYPE_MARKER(REGISTER_FFI_TYPE_MARKER);
#undef REGISTER_FFI_TYPE_MARKER
- cls = Class::New<Instance>(kFfiNativeFunctionCid);
+ cls = Class::New<Instance>(kFfiNativeFunctionCid, isolate);
cls.set_type_arguments_field_offset(Pointer::type_arguments_offset());
cls.set_num_type_arguments(1);
cls.set_is_prefinalized();
pending_classes.Add(cls);
RegisterClass(cls, Symbols::FfiNativeFunction(), lib);
- cls = Class::NewPointerClass(kFfiPointerCid);
+ cls = Class::NewPointerClass(kFfiPointerCid, isolate);
object_store->set_ffi_pointer_class(cls);
pending_classes.Add(cls);
RegisterClass(cls, Symbols::FfiPointer(), lib);
- cls = Class::New<DynamicLibrary>(kFfiDynamicLibraryCid);
+ cls = Class::New<DynamicLibrary>(kFfiDynamicLibraryCid, isolate);
cls.set_instance_size(DynamicLibrary::InstanceSize());
cls.set_is_prefinalized();
pending_classes.Add(cls);
RegisterClass(cls, Symbols::FfiDynamicLibrary(), lib);
+ lib = Library::LookupLibrary(thread, Symbols::DartWasm());
+ if (lib.IsNull()) {
+ lib = Library::NewLibraryHelper(Symbols::DartWasm(), true);
+ lib.SetLoadRequested();
+ lib.Register(thread);
+ }
+ object_store->set_bootstrap_library(ObjectStore::kWasm, lib);
+
// Finish the initialization by compiling the bootstrap scripts containing
// the base interfaces and the implementation of the internal classes.
const Error& error = Error::Handle(
@@ -1959,112 +1973,117 @@
// stored in the object store. Yet we still need to create their Class
// object so that they get put into the class_table (as a side effect of
// Class::New()).
- cls = Class::New<Instance>(kInstanceCid);
+ cls = Class::New<Instance>(kInstanceCid, isolate);
object_store->set_object_class(cls);
- cls = Class::New<LibraryPrefix>();
- cls = Class::New<Type>();
- cls = Class::New<TypeRef>();
- cls = Class::New<TypeParameter>();
+ cls = Class::New<LibraryPrefix>(isolate);
+ cls = Class::New<Type>(isolate);
+ cls = Class::New<TypeRef>(isolate);
+ cls = Class::New<TypeParameter>(isolate);
- cls = Class::New<Array>();
+ cls = Class::New<Array>(isolate);
object_store->set_array_class(cls);
- cls = Class::New<Array>(kImmutableArrayCid);
+ cls = Class::New<Array>(kImmutableArrayCid, isolate);
object_store->set_immutable_array_class(cls);
- cls = Class::New<GrowableObjectArray>();
+ cls = Class::New<GrowableObjectArray>(isolate);
object_store->set_growable_object_array_class(cls);
- cls = Class::New<LinkedHashMap>();
+ cls = Class::New<LinkedHashMap>(isolate);
object_store->set_linked_hash_map_class(cls);
- cls = Class::New<Float32x4>();
+ cls = Class::New<Float32x4>(isolate);
object_store->set_float32x4_class(cls);
- cls = Class::New<Int32x4>();
+ cls = Class::New<Int32x4>(isolate);
object_store->set_int32x4_class(cls);
- cls = Class::New<Float64x2>();
+ cls = Class::New<Float64x2>(isolate);
object_store->set_float64x2_class(cls);
#define REGISTER_TYPED_DATA_CLASS(clazz) \
- cls = Class::NewTypedDataClass(kTypedData##clazz##Cid);
+ cls = Class::NewTypedDataClass(kTypedData##clazz##Cid, isolate);
CLASS_LIST_TYPED_DATA(REGISTER_TYPED_DATA_CLASS);
#undef REGISTER_TYPED_DATA_CLASS
#define REGISTER_TYPED_DATA_VIEW_CLASS(clazz) \
- cls = Class::NewTypedDataViewClass(kTypedData##clazz##ViewCid);
+ cls = Class::NewTypedDataViewClass(kTypedData##clazz##ViewCid, isolate);
CLASS_LIST_TYPED_DATA(REGISTER_TYPED_DATA_VIEW_CLASS);
#undef REGISTER_TYPED_DATA_VIEW_CLASS
- cls = Class::NewTypedDataViewClass(kByteDataViewCid);
+ cls = Class::NewTypedDataViewClass(kByteDataViewCid, isolate);
#define REGISTER_EXT_TYPED_DATA_CLASS(clazz) \
- cls = Class::NewExternalTypedDataClass(kExternalTypedData##clazz##Cid);
+ cls = Class::NewExternalTypedDataClass(kExternalTypedData##clazz##Cid, \
+ isolate);
CLASS_LIST_TYPED_DATA(REGISTER_EXT_TYPED_DATA_CLASS);
#undef REGISTER_EXT_TYPED_DATA_CLASS
- cls = Class::New<Instance>(kFfiNativeTypeCid);
+ cls = Class::New<Instance>(kFfiNativeTypeCid, isolate);
object_store->set_ffi_native_type_class(cls);
-#define REGISTER_FFI_CLASS(clazz) cls = Class::New<Instance>(kFfi##clazz##Cid);
+#define REGISTER_FFI_CLASS(clazz) \
+ cls = Class::New<Instance>(kFfi##clazz##Cid, isolate);
CLASS_LIST_FFI_TYPE_MARKER(REGISTER_FFI_CLASS);
#undef REGISTER_FFI_CLASS
- cls = Class::New<Instance>(kFfiNativeFunctionCid);
+ cls = Class::New<Instance>(kFfiNativeFunctionCid, isolate);
- cls = Class::NewPointerClass(kFfiPointerCid);
+ cls = Class::NewPointerClass(kFfiPointerCid, isolate);
object_store->set_ffi_pointer_class(cls);
- cls = Class::New<DynamicLibrary>(kFfiDynamicLibraryCid);
+ cls = Class::New<DynamicLibrary>(kFfiDynamicLibraryCid, isolate);
- cls = Class::New<Instance>(kByteBufferCid);
+ cls = Class::New<Instance>(kByteBufferCid, isolate,
+ /*register_isolate=*/false);
+ cls.set_instance_size_in_words(0);
+ isolate->RegisterClass(cls);
- cls = Class::New<Integer>();
+ cls = Class::New<Integer>(isolate);
object_store->set_integer_implementation_class(cls);
- cls = Class::New<Smi>();
+ cls = Class::New<Smi>(isolate);
object_store->set_smi_class(cls);
- cls = Class::New<Mint>();
+ cls = Class::New<Mint>(isolate);
object_store->set_mint_class(cls);
- cls = Class::New<Double>();
+ cls = Class::New<Double>(isolate);
object_store->set_double_class(cls);
- cls = Class::New<Closure>();
+ cls = Class::New<Closure>(isolate);
object_store->set_closure_class(cls);
- cls = Class::NewStringClass(kOneByteStringCid);
+ cls = Class::NewStringClass(kOneByteStringCid, isolate);
object_store->set_one_byte_string_class(cls);
- cls = Class::NewStringClass(kTwoByteStringCid);
+ cls = Class::NewStringClass(kTwoByteStringCid, isolate);
object_store->set_two_byte_string_class(cls);
- cls = Class::NewStringClass(kExternalOneByteStringCid);
+ cls = Class::NewStringClass(kExternalOneByteStringCid, isolate);
object_store->set_external_one_byte_string_class(cls);
- cls = Class::NewStringClass(kExternalTwoByteStringCid);
+ cls = Class::NewStringClass(kExternalTwoByteStringCid, isolate);
object_store->set_external_two_byte_string_class(cls);
- cls = Class::New<Bool>();
+ cls = Class::New<Bool>(isolate);
object_store->set_bool_class(cls);
- cls = Class::New<Instance>(kNullCid);
+ cls = Class::New<Instance>(kNullCid, isolate);
object_store->set_null_class(cls);
- cls = Class::New<Capability>();
- cls = Class::New<ReceivePort>();
- cls = Class::New<SendPort>();
- cls = Class::New<StackTrace>();
- cls = Class::New<RegExp>();
- cls = Class::New<Number>();
+ cls = Class::New<Capability>(isolate);
+ cls = Class::New<ReceivePort>(isolate);
+ cls = Class::New<SendPort>(isolate);
+ cls = Class::New<StackTrace>(isolate);
+ cls = Class::New<RegExp>(isolate);
+ cls = Class::New<Number>(isolate);
- cls = Class::New<WeakProperty>();
+ cls = Class::New<WeakProperty>(isolate);
object_store->set_weak_property_class(cls);
- cls = Class::New<MirrorReference>();
- cls = Class::New<UserTag>();
+ cls = Class::New<MirrorReference>(isolate);
+ cls = Class::New<UserTag>(isolate);
- cls = Class::New<TransferableTypedData>();
+ cls = Class::New<TransferableTypedData>(isolate);
}
return Error::null();
}
@@ -2312,7 +2331,7 @@
}
template <class FakeObject>
-RawClass* Class::New() {
+RawClass* Class::New(Isolate* isolate, bool register_class) {
ASSERT(Object::class_class() != Class::null());
Class& result = Class::Handle();
{
@@ -2348,7 +2367,9 @@
NOT_IN_PRECOMPILED(result.set_is_declared_in_bytecode(false));
NOT_IN_PRECOMPILED(result.set_binary_declaration_offset(0));
result.InitEmptyFields();
- Isolate::Current()->RegisterClass(result);
+ if (register_class) {
+ isolate->RegisterClass(result);
+ }
return result.raw();
}
@@ -2977,7 +2998,7 @@
// Initialize signature: receiver is a single fixed parameter.
const intptr_t kNumParameters = 1;
extractor.set_num_fixed_parameters(kNumParameters);
- extractor.SetNumOptionalParameters(0, 0);
+ extractor.SetNumOptionalParameters(0, false);
extractor.set_parameter_types(Object::extractor_parameter_types());
extractor.set_parameter_names(Object::extractor_parameter_names());
extractor.set_result_type(Object::dynamic_type());
@@ -3727,9 +3748,11 @@
}
template <class FakeInstance>
-RawClass* Class::New(intptr_t index) {
+RawClass* Class::New(intptr_t index, Isolate* isolate, bool register_class) {
Class& result = Class::Handle(NewCommon<FakeInstance>(index));
- Isolate::Current()->RegisterClass(result);
+ if (register_class) {
+ isolate->RegisterClass(result);
+ }
return result.raw();
}
@@ -3743,6 +3766,12 @@
result.set_name(name);
result.set_script(script);
result.set_token_pos(token_pos);
+
+ // The size gets initialized to 0. Once the class gets finalized the class
+ // finalizer will set the correct size.
+ ASSERT(!result.is_finalized() && !result.is_prefinalized());
+ result.set_instance_size_in_words(0);
+
if (register_class) {
Isolate::Current()->RegisterClass(result);
}
@@ -3750,7 +3779,7 @@
}
RawClass* Class::NewInstanceClass() {
- return Class::New<Instance>(kIllegalCid);
+ return Class::New<Instance>(kIllegalCid, Isolate::Current());
}
RawClass* Class::NewNativeWrapper(const Library& library,
@@ -3780,7 +3809,7 @@
}
}
-RawClass* Class::NewStringClass(intptr_t class_id) {
+RawClass* Class::NewStringClass(intptr_t class_id, Isolate* isolate) {
intptr_t instance_size;
if (class_id == kOneByteStringCid) {
instance_size = OneByteString::InstanceSize();
@@ -3792,51 +3821,62 @@
ASSERT(class_id == kExternalTwoByteStringCid);
instance_size = ExternalTwoByteString::InstanceSize();
}
- Class& result = Class::Handle(New<String>(class_id));
+ Class& result =
+ Class::Handle(New<String>(class_id, isolate, /*register_class=*/false));
result.set_instance_size(instance_size);
result.set_next_field_offset(String::NextFieldOffset());
result.set_is_prefinalized();
+ isolate->RegisterClass(result);
return result.raw();
}
-RawClass* Class::NewTypedDataClass(intptr_t class_id) {
+RawClass* Class::NewTypedDataClass(intptr_t class_id, Isolate* isolate) {
ASSERT(RawObject::IsTypedDataClassId(class_id));
intptr_t instance_size = TypedData::InstanceSize();
- Class& result = Class::Handle(New<TypedData>(class_id));
+ Class& result = Class::Handle(
+ New<TypedData>(class_id, isolate, /*register_class=*/false));
result.set_instance_size(instance_size);
result.set_next_field_offset(TypedData::NextFieldOffset());
result.set_is_prefinalized();
+ isolate->RegisterClass(result);
return result.raw();
}
-RawClass* Class::NewTypedDataViewClass(intptr_t class_id) {
+RawClass* Class::NewTypedDataViewClass(intptr_t class_id, Isolate* isolate) {
ASSERT(RawObject::IsTypedDataViewClassId(class_id));
const intptr_t instance_size = TypedDataView::InstanceSize();
- Class& result = Class::Handle(New<TypedDataView>(class_id));
+ Class& result = Class::Handle(
+ New<TypedDataView>(class_id, isolate, /*register_class=*/false));
result.set_instance_size(instance_size);
result.set_next_field_offset(TypedDataView::NextFieldOffset());
result.set_is_prefinalized();
+ isolate->RegisterClass(result);
return result.raw();
}
-RawClass* Class::NewExternalTypedDataClass(intptr_t class_id) {
+RawClass* Class::NewExternalTypedDataClass(intptr_t class_id,
+ Isolate* isolate) {
ASSERT(RawObject::IsExternalTypedDataClassId(class_id));
intptr_t instance_size = ExternalTypedData::InstanceSize();
- Class& result = Class::Handle(New<ExternalTypedData>(class_id));
+ Class& result = Class::Handle(
+ New<ExternalTypedData>(class_id, isolate, /*register_class=*/false));
result.set_instance_size(instance_size);
result.set_next_field_offset(ExternalTypedData::NextFieldOffset());
result.set_is_prefinalized();
+ isolate->RegisterClass(result);
return result.raw();
}
-RawClass* Class::NewPointerClass(intptr_t class_id) {
+RawClass* Class::NewPointerClass(intptr_t class_id, Isolate* isolate) {
ASSERT(RawObject::IsFfiPointerClassId(class_id));
intptr_t instance_size = Pointer::InstanceSize();
- Class& result = Class::Handle(New<Pointer>(class_id));
+ Class& result =
+ Class::Handle(New<Pointer>(class_id, isolate, /*register_class=*/false));
result.set_instance_size(instance_size);
result.set_type_arguments_field_offset(Pointer::type_arguments_offset());
result.set_next_field_offset(Pointer::NextFieldOffset());
result.set_is_prefinalized();
+ isolate->RegisterClass(result);
return result.raw();
}
@@ -6202,66 +6242,7 @@
}
const char* Function::KindToCString(RawFunction::Kind kind) {
- switch (kind) {
- case RawFunction::kRegularFunction:
- return "RegularFunction";
- break;
- case RawFunction::kClosureFunction:
- return "ClosureFunction";
- break;
- case RawFunction::kImplicitClosureFunction:
- return "ImplicitClosureFunction";
- break;
- case RawFunction::kSignatureFunction:
- return "SignatureFunction";
- break;
- case RawFunction::kGetterFunction:
- return "GetterFunction";
- break;
- case RawFunction::kSetterFunction:
- return "SetterFunction";
- break;
- case RawFunction::kConstructor:
- return "Constructor";
- break;
- case RawFunction::kImplicitGetter:
- return "ImplicitGetter";
- break;
- case RawFunction::kImplicitSetter:
- return "ImplicitSetter";
- break;
- case RawFunction::kImplicitStaticGetter:
- return "ImplicitStaticGetter";
- break;
- case RawFunction::kFieldInitializer:
- return "FieldInitializer";
- break;
- case RawFunction::kMethodExtractor:
- return "MethodExtractor";
- break;
- case RawFunction::kNoSuchMethodDispatcher:
- return "NoSuchMethodDispatcher";
- break;
- case RawFunction::kInvokeFieldDispatcher:
- return "InvokeFieldDispatcher";
- break;
- case RawFunction::kIrregexpFunction:
- return "IrregexpFunction";
- break;
- case RawFunction::kDynamicInvocationForwarder:
- return "DynamicInvocationForwarder";
- break;
- case RawFunction::kFfiTrampoline:
- return "FfiTrampoline";
- break;
- }
- // When you add a case to this switch, please also update the observatory.
- // - runtime/observatory/lib/src/models/objects/function.dart (FunctionKind)
- // - runtime/observatory/lib/src/elements/function_view.dart
- // (_functionKindToString)
- // - runtime/observatory/lib/src/service/object.dart (stringToFunctionKind)
- UNREACHABLE();
- return NULL;
+ return RawFunction::KindToCString(kind);
}
void Function::SetRedirectionType(const Type& type) const {
@@ -7362,6 +7343,13 @@
// in new space.
ASSERT(space == Heap::kOld);
}
+
+ // Force-optimized functions are not debuggable because they cannot
+ // deoptimize.
+ if (result.ForceOptimize()) {
+ result.set_is_debuggable(false);
+ }
+
return result.raw();
}
@@ -9978,60 +9966,6 @@
StoreNonPointer(&raw_ptr()->load_state_, RawLibrary::kLoaded);
}
-void Library::SetLoadError(const Instance& error) const {
- // Should not be already successfully loaded or just allocated.
- ASSERT(LoadInProgress() || LoadRequested() || LoadFailed());
- StoreNonPointer(&raw_ptr()->load_state_, RawLibrary::kLoadError);
- StorePointer(&raw_ptr()->load_error_, error.raw());
-}
-
-// Traits for looking up Libraries by url in a hash set.
-class LibraryUrlTraits {
- public:
- static const char* Name() { return "LibraryUrlTraits"; }
- static bool ReportStats() { return false; }
-
- // Called when growing the table.
- static bool IsMatch(const Object& a, const Object& b) {
- ASSERT(a.IsLibrary() && b.IsLibrary());
- // Library objects are always canonical.
- return a.raw() == b.raw();
- }
- static uword Hash(const Object& key) { return Library::Cast(key).UrlHash(); }
-};
-typedef UnorderedHashSet<LibraryUrlTraits> LibraryLoadErrorSet;
-
-RawInstance* Library::TransitiveLoadError() const {
- if (LoadError() != Instance::null()) {
- return LoadError();
- }
- Thread* thread = Thread::Current();
- Isolate* isolate = thread->isolate();
- Zone* zone = thread->zone();
- ObjectStore* object_store = isolate->object_store();
- LibraryLoadErrorSet set(object_store->library_load_error_table());
- bool present = false;
- if (set.GetOrNull(*this, &present) != Object::null()) {
- object_store->set_library_load_error_table(set.Release());
- return Instance::null();
- }
- // Ensure we don't repeatedly visit the same library again.
- set.Insert(*this);
- object_store->set_library_load_error_table(set.Release());
- intptr_t num_imp = num_imports();
- Library& lib = Library::Handle(zone);
- Instance& error = Instance::Handle(zone);
- for (intptr_t i = 0; i < num_imp; i++) {
- HANDLESCOPE(thread);
- lib = ImportLibraryAt(i);
- error = lib.TransitiveLoadError();
- if (!error.IsNull()) {
- break;
- }
- }
- return error.raw();
-}
-
static RawString* MakeClassMetaName(Thread* thread,
Zone* zone,
const Class& cls) {
@@ -10224,6 +10158,14 @@
!obj.IsLibrary() && !obj.IsTypeParameter()) {
UNREACHABLE();
}
+ if (obj.IsLibrary()) {
+ // Ensure top-level class is loaded as it may contain annotations of
+ // a library.
+ const auto& cls = Class::Handle(toplevel_class());
+ if (!cls.IsNull()) {
+ cls.EnsureDeclarationLoaded();
+ }
+ }
const String& metaname = String::Handle(MakeMetadataName(obj));
Field& field = Field::Handle(GetMetadataField(metaname));
if (field.IsNull()) {
@@ -10240,11 +10182,17 @@
metadata = kernel::EvaluateMetadata(
field, /* is_annotations_offset = */ obj.IsLibrary());
}
- if (metadata.IsArray()) {
- ASSERT(Array::Cast(metadata).raw() != Object::empty_array().raw());
- field.SetStaticValue(Array::Cast(metadata), true);
+ if (metadata.IsArray() || metadata.IsNull()) {
+ ASSERT(metadata.raw() != Object::empty_array().raw());
+ field.SetStaticValue(
+ metadata.IsNull() ? Object::null_array() : Array::Cast(metadata),
+ true);
}
}
+ if (metadata.IsNull()) {
+ // Metadata field exists in order to reference extended metadata.
+ return Object::empty_array().raw();
+ }
return metadata.raw();
#endif // defined(DART_PRECOMPILED_RUNTIME)
}
@@ -10254,9 +10202,7 @@
#if defined(DART_PRECOMPILED_RUNTIME)
return Object::empty_array().raw();
#else
- if (!obj.IsFunction()) {
- UNREACHABLE();
- }
+ RELEASE_ASSERT(obj.IsFunction() || obj.IsLibrary());
const String& metaname = String::Handle(MakeMetadataName(obj));
Field& field = Field::Handle(GetMetadataField(metaname));
if (field.IsNull()) {
@@ -11095,7 +11041,6 @@
result.StorePointer(&result.raw_ptr()->imports_, Object::empty_array().raw());
result.StorePointer(&result.raw_ptr()->exports_, Object::empty_array().raw());
result.StorePointer(&result.raw_ptr()->loaded_scripts_, Array::null());
- result.StorePointer(&result.raw_ptr()->load_error_, Instance::null());
result.set_native_entry_resolver(NULL);
result.set_native_entry_symbol_resolver(NULL);
result.set_is_in_fullsnapshot(false);
@@ -11726,6 +11671,10 @@
return Isolate::Current()->object_store()->_vmservice_library();
}
+RawLibrary* Library::WasmLibrary() {
+ return Isolate::Current()->object_store()->wasm_library();
+}
+
const char* Library::ToCString() const {
const String& name = String::Handle(url());
return OS::SCreate(Thread::Current()->zone(), "Library:'%s'",
@@ -11742,49 +11691,6 @@
return Library::null();
}
-RawInstance* LibraryPrefix::LoadError() const {
- Thread* thread = Thread::Current();
- Isolate* isolate = thread->isolate();
- Zone* zone = thread->zone();
- ObjectStore* object_store = isolate->object_store();
- GrowableObjectArray& libs =
- GrowableObjectArray::Handle(zone, object_store->libraries());
- ASSERT(!libs.IsNull());
- LibraryLoadErrorSet set(HashTables::New<LibraryLoadErrorSet>(libs.Length()));
- object_store->set_library_load_error_table(set.Release());
- Library& lib = Library::Handle(zone);
- Instance& error = Instance::Handle(zone);
- for (int32_t i = 0; i < num_imports(); i++) {
- lib = GetLibrary(i);
- ASSERT(!lib.IsNull());
- HANDLESCOPE(thread);
- error = lib.TransitiveLoadError();
- if (!error.IsNull()) {
- break;
- }
- }
- object_store->set_library_load_error_table(Object::empty_array());
- return error.raw();
-}
-
-bool LibraryPrefix::ContainsLibrary(const Library& library) const {
- int32_t num_current_imports = num_imports();
- if (num_current_imports > 0) {
- Library& lib = Library::Handle();
- const String& url = String::Handle(library.url());
- String& lib_url = String::Handle();
- for (int32_t i = 0; i < num_current_imports; i++) {
- lib = GetLibrary(i);
- ASSERT(!lib.IsNull());
- lib_url = lib.url();
- if (url.Equals(lib_url)) {
- return true;
- }
- }
- }
- return false;
-}
-
void LibraryPrefix::AddImport(const Namespace& import) const {
intptr_t num_current_imports = num_imports();
@@ -11805,9 +11711,6 @@
}
RawObject* LibraryPrefix::LookupObject(const String& name) const {
- if (!is_loaded() && !FLAG_load_deferred_eagerly) {
- return Object::null();
- }
Array& imports = Array::Handle(this->imports());
Object& obj = Object::Handle();
Namespace& import = Namespace::Handle();
@@ -11876,116 +11779,6 @@
return Class::null();
}
-void LibraryPrefix::set_is_loaded() const {
- StoreNonPointer(&raw_ptr()->is_loaded_, true);
-}
-
-bool LibraryPrefix::LoadLibrary() const {
- // Non-deferred prefixes are loaded.
- ASSERT(is_deferred_load() || is_loaded());
- if (is_loaded()) {
- return true; // Load request has already completed.
- }
- ASSERT(is_deferred_load());
- ASSERT(num_imports() == 1);
- if (Dart::vm_snapshot_kind() == Snapshot::kFullAOT) {
- // The library list was tree-shaken away.
- this->set_is_loaded();
- return true;
- }
- // This is a prefix for a deferred library. If the library is not loaded
- // yet and isn't being loaded, call the library tag handler to schedule
- // loading. Once all outstanding load requests have completed, the embedder
- // will call the core library to:
- // - invalidate dependent code of this prefix;
- // - mark this prefixes as loaded;
- // - complete the future associated with this prefix.
- const Library& deferred_lib = Library::Handle(GetLibrary(0));
- if (deferred_lib.Loaded()) {
- this->set_is_loaded();
- return true;
- } else if (deferred_lib.LoadNotStarted()) {
- Thread* thread = Thread::Current();
- Isolate* isolate = thread->isolate();
- Zone* zone = thread->zone();
- deferred_lib.SetLoadRequested();
- const GrowableObjectArray& pending_deferred_loads =
- GrowableObjectArray::Handle(
- isolate->object_store()->pending_deferred_loads());
- pending_deferred_loads.Add(deferred_lib);
- const String& lib_url = String::Handle(zone, deferred_lib.url());
- const Object& obj = Object::Handle(
- zone, isolate->CallTagHandler(
- Dart_kImportTag, Library::Handle(zone, importer()), lib_url));
- if (obj.IsError()) {
- Exceptions::PropagateError(Error::Cast(obj));
- }
- } else {
- // Another load request is in flight or previously failed.
- ASSERT(deferred_lib.LoadRequested() || deferred_lib.LoadFailed());
- }
- return false; // Load request not yet completed.
-}
-
-RawArray* LibraryPrefix::dependent_code() const {
- return raw_ptr()->dependent_code_;
-}
-
-void LibraryPrefix::set_dependent_code(const Array& array) const {
- StorePointer(&raw_ptr()->dependent_code_, array.raw());
-}
-
-class PrefixDependentArray : public WeakCodeReferences {
- public:
- explicit PrefixDependentArray(const LibraryPrefix& prefix)
- : WeakCodeReferences(Array::Handle(prefix.dependent_code())),
- prefix_(prefix) {}
-
- virtual void UpdateArrayTo(const Array& value) {
- prefix_.set_dependent_code(value);
- }
-
- virtual void ReportDeoptimization(const Code& code) {
- // This gets called when the code object is on the stack
- // while nuking code that depends on a prefix. We don't expect
- // this to happen, so make sure we die loudly if we find
- // ourselves here.
- UNIMPLEMENTED();
- }
-
- virtual void ReportSwitchingCode(const Code& code) {
- if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
- THR_Print("Prefix '%s': disabling %s code for %s function '%s'\n",
- String::Handle(prefix_.name()).ToCString(),
- code.is_optimized() ? "optimized" : "unoptimized",
- code.IsDisabled() ? "'patched'" : "'unpatched'",
- Function::Handle(code.function()).ToCString());
- }
- }
-
- private:
- const LibraryPrefix& prefix_;
- DISALLOW_COPY_AND_ASSIGN(PrefixDependentArray);
-};
-
-void LibraryPrefix::RegisterDependentCode(const Code& code) const {
- ASSERT(is_deferred_load());
- // In background compilation, a library can be loaded while we are compiling.
- // The generated code will be rejected in that case,
- ASSERT(!is_loaded() || Compiler::IsBackgroundCompilation());
- PrefixDependentArray a(*this);
- a.Register(code);
-}
-
-void LibraryPrefix::InvalidateDependentCode() const {
- PrefixDependentArray a(*this);
- if (FLAG_trace_deoptimization && a.HasCodes()) {
- THR_Print("Deopt for lazy load (prefix %s)\n", ToCString());
- }
- a.DisableCode();
- set_is_loaded();
-}
-
RawLibraryPrefix* LibraryPrefix::New() {
RawObject* raw = Object::Allocate(LibraryPrefix::kClassId,
LibraryPrefix::InstanceSize(), Heap::kOld);
@@ -12001,7 +11794,6 @@
result.set_num_imports(0);
result.set_importer(importer);
result.StoreNonPointer(&result.raw_ptr()->is_deferred_load_, deferred_load);
- result.StoreNonPointer(&result.raw_ptr()->is_loaded_, !deferred_load);
result.set_imports(Array::Handle(Array::New(kInitialSize)));
result.AddImport(import);
return result.raw();
@@ -12635,8 +12427,8 @@
result ^= raw;
result.SetSize(size);
result.SetHasSingleEntryPoint(has_single_entry_point);
- result.set_stats(nullptr);
result.set_unchecked_entrypoint_pc_offset(unchecked_entrypoint_pc_offset);
+ result.set_stats(nullptr);
}
return result.raw();
}
@@ -12839,6 +12631,8 @@
return "osr-entry ";
case RawPcDescriptors::kRewind:
return "rewind ";
+ case RawPcDescriptors::kBSSRelocation:
+ return "bss reloc ";
case RawPcDescriptors::kOther:
return "other ";
case RawPcDescriptors::kAnyKind:
@@ -12963,7 +12757,7 @@
int bit_remainder = bit_index & (kBitsPerByte - 1);
uint8_t byte_mask = 1U << bit_remainder;
uint8_t byte = raw_ptr()->data()[byte_index];
- return (byte & byte_mask);
+ return (byte & byte_mask) != 0;
}
void StackMap::SetBit(intptr_t bit_index, bool value) const {
@@ -13227,9 +13021,9 @@
ASSERT((handler_pc_offset == static_cast<uword>(kMaxUint32)) ||
(handler_pc_offset < static_cast<uword>(kMaxUint32)));
info->handler_pc_offset = handler_pc_offset;
- info->needs_stacktrace = needs_stacktrace;
- info->has_catch_all = has_catch_all;
- info->is_generated = is_generated;
+ info->needs_stacktrace = static_cast<int8_t>(needs_stacktrace);
+ info->has_catch_all = static_cast<int8_t>(has_catch_all);
+ info->is_generated = static_cast<int8_t>(is_generated);
}
void ExceptionHandlers::GetHandlerInfo(intptr_t try_index,
@@ -13251,17 +13045,17 @@
bool ExceptionHandlers::NeedsStackTrace(intptr_t try_index) const {
ASSERT((try_index >= 0) && (try_index < num_entries()));
- return raw_ptr()->data()[try_index].needs_stacktrace;
+ return raw_ptr()->data()[try_index].needs_stacktrace != 0;
}
bool ExceptionHandlers::IsGenerated(intptr_t try_index) const {
ASSERT((try_index >= 0) && (try_index < num_entries()));
- return raw_ptr()->data()[try_index].is_generated;
+ return raw_ptr()->data()[try_index].is_generated != 0;
}
bool ExceptionHandlers::HasCatchAll(intptr_t try_index) const {
ASSERT((try_index >= 0) && (try_index < num_entries()));
- return raw_ptr()->data()[try_index].has_catch_all;
+ return raw_ptr()->data()[try_index].has_catch_all != 0;
}
void ExceptionHandlers::SetHandledTypes(intptr_t try_index,
@@ -13348,7 +13142,7 @@
handled_types.IsNull() ? 0 : handled_types.Length();
len += Utils::SNPrint(NULL, 0, FORMAT1, i, info.handler_pc_offset,
num_types, info.outer_try_index,
- info.is_generated ? "(generated)" : "");
+ info.is_generated != 0 ? "(generated)" : "");
for (int k = 0; k < num_types; k++) {
type ^= handled_types.At(k);
ASSERT(!type.IsNull());
@@ -13367,7 +13161,7 @@
num_chars +=
Utils::SNPrint((buffer + num_chars), (len - num_chars), FORMAT1, i,
info.handler_pc_offset, num_types, info.outer_try_index,
- info.is_generated ? "(generated)" : "");
+ info.is_generated != 0 ? "(generated)" : "");
for (int k = 0; k < num_types; k++) {
type ^= handled_types.At(k);
num_chars += Utils::SNPrint((buffer + num_chars), (len - num_chars),
@@ -13592,6 +13386,29 @@
}
}
+const char* ICData::RebindRuleToCString(RebindRule r) {
+ switch (r) {
+#define RULE_CASE(Name) \
+ case RebindRule::k##Name: \
+ return #Name;
+ FOR_EACH_REBIND_RULE(RULE_CASE)
+#undef RULE_CASE
+ default:
+ return nullptr;
+ }
+}
+
+bool ICData::RebindRuleFromCString(const char* str, RebindRule* out) {
+#define RULE_CASE(Name) \
+ if (strcmp(str, #Name) == 0) { \
+ *out = RebindRule::k##Name; \
+ return true; \
+ }
+ FOR_EACH_REBIND_RULE(RULE_CASE)
+#undef RULE_CASE
+ return false;
+}
+
ICData::RebindRule ICData::rebind_rule() const {
return (ICData::RebindRule)RebindRuleBits::decode(raw_ptr()->state_bits_);
}
@@ -14333,59 +14150,6 @@
}
return false;
}
-
-// Returns true if all targets are the same.
-// TODO(srdjan): if targets are native use their C_function to compare.
-// TODO(rmacnak): this question should only be asked against a CallTargets,
-// not an ICData.
-bool ICData::HasOneTarget() const {
- ASSERT(!NumberOfChecksIs(0));
- const Function& first_target = Function::Handle(GetTargetAt(0));
- const intptr_t len = NumberOfChecks();
- for (intptr_t i = 1; i < len; i++) {
- if (IsUsedAt(i) && (GetTargetAt(i) != first_target.raw())) {
- return false;
- }
- }
- if (is_megamorphic()) {
- Thread* thread = Thread::Current();
- Zone* zone = thread->zone();
- const String& name = String::Handle(zone, target_name());
- const Array& descriptor = Array::Handle(zone, arguments_descriptor());
- const MegamorphicCache& cache = MegamorphicCache::Handle(
- zone, MegamorphicCacheTable::LookupClone(thread, name, descriptor));
- MegamorphicCacheEntries entries(Array::Handle(cache.buckets()));
- for (intptr_t i = 0; i < entries.Length(); i++) {
- const intptr_t id =
- Smi::Value(entries[i].Get<MegamorphicCache::kClassIdIndex>());
- if (id == kIllegalCid) {
- continue;
- }
- if (entries[i].Get<MegamorphicCache::kTargetFunctionIndex>() !=
- first_target.raw()) {
- return false;
- }
- }
- }
- return true;
-}
-
-void ICData::GetUsedCidsForTwoArgs(GrowableArray<intptr_t>* first,
- GrowableArray<intptr_t>* second) const {
- ASSERT(NumArgsTested() == 2);
- first->Clear();
- second->Clear();
- GrowableArray<intptr_t> class_ids;
- const intptr_t len = NumberOfChecks();
- for (intptr_t i = 0; i < len; i++) {
- if (GetCountAt(i) > 0) {
- GetClassIdsAt(i, &class_ids);
- ASSERT(class_ids.length() == 2);
- first->Add(class_ids[0]);
- second->Add(class_ids[1]);
- }
- }
-}
#endif
bool ICData::IsUsedAt(intptr_t i) const {
@@ -14517,6 +14281,9 @@
#if !defined(DART_PRECOMPILED_RUNTIME)
RawICData* ICData::NewFrom(const ICData& from, intptr_t num_args_tested) {
+ // See comment in [ICData::Clone] why we access the megamorphic bit first.
+ const bool is_megamorphic = from.is_megamorphic();
+
const ICData& result = ICData::Handle(ICData::New(
Function::Handle(from.Owner()), String::Handle(from.target_name()),
Array::Handle(from.arguments_descriptor()), from.deopt_id(),
@@ -14524,12 +14291,21 @@
AbstractType::Handle(from.receivers_static_type())));
// Copy deoptimization reasons.
result.SetDeoptReasons(from.DeoptReasons());
- result.set_is_megamorphic(from.is_megamorphic());
+ result.set_is_megamorphic(is_megamorphic);
return result.raw();
}
RawICData* ICData::Clone(const ICData& from) {
Zone* zone = Thread::Current()->zone();
+
+ // We have to check the megamorphic bit before accessing the entries of the
+ // ICData to ensure all writes to the entries have been flushed and are
+ // visible at this point.
+ //
+ // This will allow us to maintain the invariant that if the megamorphic bit is
+ // set, the number of entries in the ICData have reached the limit.
+ const bool is_megamorphic = from.is_megamorphic();
+
const ICData& result = ICData::Handle(
zone, ICData::NewDescriptor(
zone, Function::Handle(zone, from.Owner()),
@@ -14549,7 +14325,11 @@
result.set_entries(cloned_array);
// Copy deoptimization reasons.
result.SetDeoptReasons(from.DeoptReasons());
- result.set_is_megamorphic(from.is_megamorphic());
+ result.set_is_megamorphic(is_megamorphic);
+
+ RELEASE_ASSERT(!is_megamorphic ||
+ result.NumberOfChecks() >= FLAG_max_polymorphic_checks);
+
return result.raw();
}
#endif
@@ -15378,6 +15158,25 @@
reader.DumpSourcePositions(PayloadStart());
}
+bool Code::VerifyBSSRelocations() const {
+ const auto& descriptors = PcDescriptors::Handle(pc_descriptors());
+ const auto& insns = Instructions::Handle(instructions());
+ PcDescriptors::Iterator iterator(descriptors,
+ RawPcDescriptors::kBSSRelocation);
+ while (iterator.MoveNext()) {
+ const uword reloc = insns.PayloadStart() + iterator.PcOffset();
+ const word target = *reinterpret_cast<word*>(reloc);
+ // The relocation is in its original unpatched form -- the addend
+ // representing the target symbol itself.
+ if (target >= 0 &&
+ target <
+ BSS::RelocationIndex(BSS::Relocation::NumRelocations) * kWordSize) {
+ return false;
+ }
+ }
+ return true;
+}
+
void Bytecode::Disassemble(DisassemblyFormatter* formatter) const {
#if !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
#if !defined(DART_PRECOMPILED_RUNTIME)
@@ -15413,9 +15212,7 @@
result.set_pc_descriptors(Object::empty_descriptors());
result.set_instructions_binary_offset(instructions_offset);
result.set_source_positions_binary_offset(0);
-#if !defined(PRODUCT)
result.set_local_variables_binary_offset(0);
-#endif
}
return result.raw();
}
@@ -15973,37 +15770,6 @@
}
}
-RawMegamorphicCache* MegamorphicCache::Clone(const MegamorphicCache& from) {
- Thread* thread = Thread::Current();
- Zone* zone = thread->zone();
- MegamorphicCache& result = MegamorphicCache::Handle(zone);
- {
- RawObject* raw =
- Object::Allocate(MegamorphicCache::kClassId,
- MegamorphicCache::InstanceSize(), Heap::kNew);
- NoSafepointScope no_safepoint;
- result ^= raw;
- }
-
- SafepointMutexLocker ml(thread->isolate()->megamorphic_mutex());
- const Array& from_buckets = Array::Handle(zone, from.buckets());
- const intptr_t len = from_buckets.Length();
- const Array& cloned_buckets =
- Array::Handle(zone, Array::New(len, Heap::kNew));
- Object& obj = Object::Handle(zone);
- for (intptr_t i = 0; i < len; i++) {
- obj = from_buckets.At(i);
- cloned_buckets.SetAt(i, obj);
- }
- result.set_buckets(cloned_buckets);
- result.set_mask(from.mask());
- result.set_target_name(String::Handle(zone, from.target_name()));
- result.set_arguments_descriptor(
- Array::Handle(zone, from.arguments_descriptor()));
- result.set_filled_entry_count(from.filled_entry_count());
- return result.raw();
-}
-
void SubtypeTestCache::Init() {
cached_array_ = Array::New(kTestEntryLength, Heap::kOld);
}
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index bea9d0a..37aba42 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -78,48 +78,46 @@
using RawObjectType = Raw##object; \
Raw##object* raw() const { return reinterpret_cast<Raw##object*>(raw_); } \
bool Is##object() const { return true; } \
- static object& Handle(Zone* zone, Raw##object* raw_ptr) { \
- object* obj = reinterpret_cast<object*>(VMHandles::AllocateHandle(zone)); \
- initializeHandle(obj, raw_ptr); \
- return *obj; \
+ DART_NOINLINE static object& Handle() { \
+ return HandleImpl(Thread::Current()->zone(), object::null()); \
} \
- static object& Handle() { \
- return Handle(Thread::Current()->zone(), object::null()); \
+ DART_NOINLINE static object& Handle(Zone* zone) { \
+ return HandleImpl(zone, object::null()); \
} \
- static object& Handle(Zone* zone) { return Handle(zone, object::null()); } \
- static object& Handle(Raw##object* raw_ptr) { \
- return Handle(Thread::Current()->zone(), raw_ptr); \
+ DART_NOINLINE static object& Handle(Raw##object* raw_ptr) { \
+ return HandleImpl(Thread::Current()->zone(), raw_ptr); \
} \
- static object& CheckedHandle(Zone* zone, RawObject* raw_ptr) { \
- object* obj = reinterpret_cast<object*>(VMHandles::AllocateHandle(zone)); \
- initializeHandle(obj, raw_ptr); \
- if (!obj->Is##object()) { \
- FATAL2("Handle check failed: saw %s expected %s", obj->ToCString(), \
- #object); \
- } \
- return *obj; \
+ DART_NOINLINE static object& Handle(Zone* zone, Raw##object* raw_ptr) { \
+ return HandleImpl(zone, raw_ptr); \
} \
- static object& ZoneHandle(Zone* zone, Raw##object* raw_ptr) { \
- object* obj = \
- reinterpret_cast<object*>(VMHandles::AllocateZoneHandle(zone)); \
- initializeHandle(obj, raw_ptr); \
- return *obj; \
+ DART_NOINLINE static object& ZoneHandle() { \
+ return ZoneHandleImpl(Thread::Current()->zone(), object::null()); \
} \
- static object* ReadOnlyHandle() { \
+ DART_NOINLINE static object& ZoneHandle(Zone* zone) { \
+ return ZoneHandleImpl(zone, object::null()); \
+ } \
+ DART_NOINLINE static object& ZoneHandle(Raw##object* raw_ptr) { \
+ return ZoneHandleImpl(Thread::Current()->zone(), raw_ptr); \
+ } \
+ DART_NOINLINE static object& ZoneHandle(Zone* zone, Raw##object* raw_ptr) { \
+ return ZoneHandleImpl(zone, raw_ptr); \
+ } \
+ DART_NOINLINE static object* ReadOnlyHandle() { \
object* obj = reinterpret_cast<object*>(Dart::AllocateReadOnlyHandle()); \
initializeHandle(obj, object::null()); \
return obj; \
} \
- static object& ZoneHandle(Zone* zone) { \
- return ZoneHandle(zone, object::null()); \
+ DART_NOINLINE static object& CheckedHandle(Zone* zone, RawObject* raw_ptr) { \
+ object* obj = reinterpret_cast<object*>(VMHandles::AllocateHandle(zone)); \
+ initializeHandle(obj, raw_ptr); \
+ if (!obj->Is##object()) { \
+ FATAL2("Handle check failed: saw %s expected %s", obj->ToCString(), \
+ #object); \
+ } \
+ return *obj; \
} \
- static object& ZoneHandle() { \
- return ZoneHandle(Thread::Current()->zone(), object::null()); \
- } \
- static object& ZoneHandle(Raw##object* raw_ptr) { \
- return ZoneHandle(Thread::Current()->zone(), raw_ptr); \
- } \
- static object& CheckedZoneHandle(Zone* zone, RawObject* raw_ptr) { \
+ DART_NOINLINE static object& CheckedZoneHandle(Zone* zone, \
+ RawObject* raw_ptr) { \
object* obj = \
reinterpret_cast<object*>(VMHandles::AllocateZoneHandle(zone)); \
initializeHandle(obj, raw_ptr); \
@@ -129,7 +127,7 @@
} \
return *obj; \
} \
- static object& CheckedZoneHandle(RawObject* raw_ptr) { \
+ DART_NOINLINE static object& CheckedZoneHandle(RawObject* raw_ptr) { \
return CheckedZoneHandle(Thread::Current()->zone(), raw_ptr); \
} \
/* T::Cast cannot be applied to a null Object, because the object vtable */ \
@@ -150,6 +148,17 @@
static const ClassId kClassId = k##object##Cid; \
\
private: /* NOLINT */ \
+ static object& HandleImpl(Zone* zone, Raw##object* raw_ptr) { \
+ object* obj = reinterpret_cast<object*>(VMHandles::AllocateHandle(zone)); \
+ initializeHandle(obj, raw_ptr); \
+ return *obj; \
+ } \
+ static object& ZoneHandleImpl(Zone* zone, Raw##object* raw_ptr) { \
+ object* obj = \
+ reinterpret_cast<object*>(VMHandles::AllocateZoneHandle(zone)); \
+ initializeHandle(obj, raw_ptr); \
+ return *obj; \
+ } \
/* Initialize the handle based on the raw_ptr in the presence of null. */ \
static void initializeHandle(object* obj, RawObject* raw_ptr) { \
if (raw_ptr != Object::null()) { \
@@ -601,6 +610,29 @@
*const_cast<FieldType*>(addr) = value;
}
+ template <typename FieldType, typename ValueType, MemoryOrder order>
+ void StoreNonPointer(const FieldType* addr, ValueType value) const {
+ // Can't use Contains, as it uses tags_, which is set through this method.
+ ASSERT(reinterpret_cast<uword>(addr) >= RawObject::ToAddr(raw()));
+
+ if (order == MemoryOrder::kRelease) {
+ AtomicOperations::StoreRelease(const_cast<FieldType*>(addr), value);
+ } else {
+ ASSERT(order == MemoryOrder::kRelaxed);
+ StoreNonPointer<FieldType, ValueType>(addr, value);
+ }
+ }
+
+ template <typename FieldType, MemoryOrder order = MemoryOrder::kRelaxed>
+ FieldType LoadNonPointer(const FieldType* addr) const {
+ if (order == MemoryOrder::kAcquire) {
+ return AtomicOperations::LoadAcquire(const_cast<FieldType*>(addr));
+ } else {
+ ASSERT(order == MemoryOrder::kRelaxed);
+ return *const_cast<FieldType*>(addr);
+ }
+ }
+
// Provides non-const access to non-pointer fields within the object. Such
// access does not need a write barrier, but it is *not* GC-safe, since the
// object might move, hence must be fully contained within a NoSafepointScope.
@@ -1322,7 +1354,7 @@
// Allocate a class used for VM internal objects.
template <class FakeObject>
- static RawClass* New();
+ static RawClass* New(Isolate* isolate, bool register_class = true);
// Allocate instance classes.
static RawClass* New(const Library& lib,
@@ -1335,19 +1367,20 @@
int num_fields);
// Allocate the raw string classes.
- static RawClass* NewStringClass(intptr_t class_id);
+ static RawClass* NewStringClass(intptr_t class_id, Isolate* isolate);
// Allocate the raw TypedData classes.
- static RawClass* NewTypedDataClass(intptr_t class_id);
+ static RawClass* NewTypedDataClass(intptr_t class_id, Isolate* isolate);
// Allocate the raw TypedDataView/ByteDataView classes.
- static RawClass* NewTypedDataViewClass(intptr_t class_id);
+ static RawClass* NewTypedDataViewClass(intptr_t class_id, Isolate* isolate);
// Allocate the raw ExternalTypedData classes.
- static RawClass* NewExternalTypedDataClass(intptr_t class_id);
+ static RawClass* NewExternalTypedDataClass(intptr_t class_id,
+ Isolate* isolate);
// Allocate the raw Pointer classes.
- static RawClass* NewPointerClass(intptr_t class_id);
+ static RawClass* NewPointerClass(intptr_t class_id, Isolate* isolate);
// Register code that has used CHA for optimization.
// TODO(srdjan): Also register kind of CHA optimization (e.g.: leaf class,
@@ -1502,7 +1535,9 @@
// Allocate an instance class which has a VM implementation.
template <class FakeInstance>
- static RawClass* New(intptr_t id);
+ static RawClass* New(intptr_t id,
+ Isolate* isolate,
+ bool register_class = true);
// Helper that calls 'Class::New<Instance>(kIllegalCid)'.
static RawClass* NewInstanceClass();
@@ -1760,28 +1795,34 @@
// Call site classification that is helpful for hot-reload. Call sites with
// different `RebindRule` have to be rebound differently.
+#define FOR_EACH_REBIND_RULE(V) \
+ V(Instance) \
+ V(NoRebind) \
+ V(NSMDispatch) \
+ V(Optimized) \
+ V(Static) \
+ V(Super)
+
enum RebindRule {
- kInstance,
- kNoRebind,
- kNSMDispatch,
- kOptimized,
- kStatic,
- kSuper,
- kNumRebindRules,
+#define REBIND_ENUM_DEF(name) k##name,
+ FOR_EACH_REBIND_RULE(REBIND_ENUM_DEF)
+#undef REBIND_ENUM_DEF
+ kNumRebindRules,
};
+ static const char* RebindRuleToCString(RebindRule r);
+ static bool RebindRuleFromCString(const char* str, RebindRule* out);
RebindRule rebind_rule() const;
void set_rebind_rule(uint32_t rebind_rule) const;
- // This bit is set when a call site becomes megamorphic and starts using a
- // MegamorphicCache instead of ICData. It means that the entries in the
- // ICData are incomplete and the MegamorphicCache needs to also be consulted
- // to list the call site's observed receiver classes and targets.
- bool is_megamorphic() const {
- return MegamorphicBit::decode(raw_ptr()->state_bits_);
- }
void set_is_megamorphic(bool value) const {
- StoreNonPointer(&raw_ptr()->state_bits_,
- MegamorphicBit::update(value, raw_ptr()->state_bits_));
+ // We don't have concurrent RW access to [state_bits_].
+ const uint32_t updated_bits =
+ MegamorphicBit::update(value, raw_ptr()->state_bits_);
+
+ // Though we ensure that once the state bits are updated, all other previous
+ // writes to the IC are visible as well.
+ StoreNonPointer<uint32_t, uint32_t, MemoryOrder::kRelease>(
+ &raw_ptr()->state_bits_, updated_bits);
}
// The length of the array. This includes all sentinel entries including
@@ -1915,8 +1956,6 @@
RawUnlinkedCall* AsUnlinkedCall() const;
- // Consider only used entries.
- bool HasOneTarget() const;
bool HasReceiverClassId(intptr_t class_id) const;
// Note: passing non-null receiver_type enables exactness tracking for
@@ -1949,9 +1988,6 @@
bool IsUsedAt(intptr_t i) const;
- void GetUsedCidsForTwoArgs(GrowableArray<intptr_t>* first,
- GrowableArray<intptr_t>* second) const;
-
void PrintToJSONArray(const JSONArray& jsarray,
TokenPosition token_pos) const;
@@ -1995,6 +2031,20 @@
void set_entries(const Array& value) const;
void set_state_bits(uint32_t bits) const;
+ // This bit is set when a call site becomes megamorphic and starts using a
+ // MegamorphicCache instead of ICData. It means that the entries in the
+ // ICData are incomplete and the MegamorphicCache needs to also be consulted
+ // to list the call site's observed receiver classes and targets.
+ // In the compiler, this should only be read once by CallTargets to avoid the
+ // compiler seeing an unstable set of feedback.
+ bool is_megamorphic() const {
+ // Ensure any following load instructions do not get performed before this
+ // one.
+ const uint32_t bits = LoadNonPointer<uint32_t, MemoryOrder::kAcquire>(
+ &raw_ptr()->state_bits_);
+ return MegamorphicBit::decode(bits);
+ }
+
bool ValidateInterceptor(const Function& target) const;
enum {
@@ -2056,13 +2106,14 @@
static RawArray* cached_icdata_arrays_[kCachedICDataArrayCount];
FINAL_HEAP_OBJECT_IMPLEMENTATION(ICData, Object);
+ friend class CallSiteResetter;
+ friend class CallTargets;
friend class Class;
+ friend class Deserializer;
friend class ICDataTestTask;
friend class Interpreter;
- friend class SnapshotWriter;
friend class Serializer;
- friend class Deserializer;
- friend class CallSiteResetter;
+ friend class SnapshotWriter;
};
// Often used constants for number of free function type parameters.
@@ -3961,12 +4012,6 @@
void SetLoadInProgress() const;
bool Loaded() const { return raw_ptr()->load_state_ == RawLibrary::kLoaded; }
void SetLoaded() const;
- bool LoadFailed() const {
- return raw_ptr()->load_state_ == RawLibrary::kLoadError;
- }
- RawInstance* LoadError() const { return raw_ptr()->load_error_; }
- void SetLoadError(const Instance& error) const;
- RawInstance* TransitiveLoadError() const;
static intptr_t InstanceSize() {
return RoundedAllocationSize(sizeof(RawLibrary));
@@ -4240,6 +4285,7 @@
static RawLibrary* ProfilerLibrary();
static RawLibrary* TypedDataLibrary();
static RawLibrary* VMServiceLibrary();
+ static RawLibrary* WasmLibrary();
// Eagerly compile all classes and functions in the library.
static RawError* CompileAll(bool ignore_error = false);
@@ -5363,6 +5409,9 @@
void Disassemble(DisassemblyFormatter* formatter = NULL) const;
+ // Returns true if all BSS relocations in the code have been patched.
+ bool VerifyBSSRelocations() const;
+
class Comments : public ZoneAllocated {
public:
static Comments& New(intptr_t count);
@@ -5758,7 +5807,6 @@
return (source_positions_binary_offset() != 0);
}
-#if !defined(PRODUCT)
intptr_t local_variables_binary_offset() const {
return raw_ptr()->local_variables_binary_offset_;
}
@@ -5768,7 +5816,6 @@
bool HasLocalVariablesInfo() const {
return (local_variables_binary_offset() != 0);
}
-#endif // !defined(PRODUCT)
RawLocalVarDescriptors* var_descriptors() const {
#if defined(PRODUCT)
@@ -6460,27 +6507,12 @@
intptr_t num_imports() const { return raw_ptr()->num_imports_; }
RawLibrary* importer() const { return raw_ptr()->importer_; }
- RawInstance* LoadError() const;
-
- bool ContainsLibrary(const Library& library) const;
RawLibrary* GetLibrary(int index) const;
void AddImport(const Namespace& import) const;
RawObject* LookupObject(const String& name) const;
RawClass* LookupClass(const String& class_name) const;
bool is_deferred_load() const { return raw_ptr()->is_deferred_load_; }
- bool is_loaded() const { return raw_ptr()->is_loaded_; }
- bool LoadLibrary() const;
-
- // Return the list of code objects that were compiled when this
- // prefix was not yet loaded. These code objects will be invalidated
- // when the prefix is loaded.
- RawArray* dependent_code() const;
- void set_dependent_code(const Array& array) const;
-
- // Add the given code object to the list of dependent ones.
- void RegisterDependentCode(const Code& code) const;
- void InvalidateDependentCode() const;
static intptr_t InstanceSize() {
return RoundedAllocationSize(sizeof(RawLibraryPrefix));
@@ -6499,7 +6531,6 @@
void set_imports(const Array& value) const;
void set_num_imports(intptr_t value) const;
void set_importer(const Library& value) const;
- void set_is_loaded() const;
static RawLibraryPrefix* New();
@@ -6613,6 +6644,11 @@
// Return true if this vector contains a recursive type argument.
bool IsRecursive() const;
+ virtual RawInstance* CheckAndCanonicalize(Thread* thread,
+ const char** error_str) const {
+ return Canonicalize();
+ }
+
// Canonicalize only if instantiated, otherwise returns 'this'.
RawTypeArguments* Canonicalize(TrailPtr trail = NULL) const;
@@ -7341,8 +7377,8 @@
static intptr_t InstanceSize() { return 0; }
static RawSmi* New(intptr_t value) {
- RawSmi* raw_smi =
- reinterpret_cast<RawSmi*>((value << kSmiTagShift) | kSmiTag);
+ RawSmi* raw_smi = reinterpret_cast<RawSmi*>(
+ (static_cast<uintptr_t>(value) << kSmiTagShift) | kSmiTag);
ASSERT(ValueFromRawSmi(raw_smi) == value);
return raw_smi;
}
diff --git a/runtime/vm/object_graph.cc b/runtime/vm/object_graph.cc
index 26b607b..432a6a0 100644
--- a/runtime/vm/object_graph.cc
+++ b/runtime/vm/object_graph.cc
@@ -671,7 +671,8 @@
writer_->WriteUnsigned(kNullData);
} else if (cid == kBoolCid) {
writer_->WriteUnsigned(kBoolData);
- writer_->WriteUnsigned(static_cast<RawBool*>(obj)->ptr()->value_);
+ writer_->WriteUnsigned(
+ static_cast<uintptr_t>(static_cast<RawBool*>(obj)->ptr()->value_));
} else if (cid == kSmiCid) {
UNREACHABLE();
} else if (cid == kMintCid) {
diff --git a/runtime/vm/object_reload.cc b/runtime/vm/object_reload.cc
index 3268d3b..6857b57 100644
--- a/runtime/vm/object_reload.cc
+++ b/runtime/vm/object_reload.cc
@@ -665,34 +665,17 @@
}
};
-class UnimplementedDeferredLibrary : public ReasonForCancelling {
- public:
- UnimplementedDeferredLibrary(Zone* zone,
- const Library& from,
- const Library& to,
- const String& name)
- : ReasonForCancelling(zone), from_(from), to_(to), name_(name) {}
-
- private:
- const Library& from_;
- const Library& to_;
- const String& name_;
-
- RawString* ToString() {
- const String& lib_url = String::Handle(to_.url());
- from_.ToCString();
- return String::NewFormatted(
- "Reloading support for deferred loading has not yet been implemented:"
- " library '%s' has deferred import '%s'",
- lib_url.ToCString(), name_.ToCString());
- }
-};
-
// This is executed before iterating over the instances.
void Class::CheckReload(const Class& replacement,
IsolateReloadContext* context) const {
ASSERT(IsolateReloadContext::IsSameClass(*this, replacement));
+ if (!is_declaration_loaded()) {
+ // The old class hasn't been used in any meanfully way, so the VM is okay
+ // with any change.
+ return;
+ }
+
// Ensure is_enum_class etc have been set.
replacement.EnsureDeclarationLoaded();
@@ -816,20 +799,7 @@
void Library::CheckReload(const Library& replacement,
IsolateReloadContext* context) const {
- // TODO(26878): If the replacement library uses deferred loading,
- // reject it. We do not yet support reloading deferred libraries.
- LibraryPrefix& prefix = LibraryPrefix::Handle();
- LibraryPrefixIterator it(replacement);
- while (it.HasNext()) {
- prefix = it.GetNext();
- if (prefix.is_deferred_load()) {
- const String& prefix_name = String::Handle(prefix.name());
- context->AddReasonForCancelling(
- new (context->zone()) UnimplementedDeferredLibrary(
- context->zone(), *this, replacement, prefix_name));
- return;
- }
- }
+ // Currently no library properties will prevent a reload.
}
void CallSiteResetter::Reset(const ICData& ic) {
diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc
index c070103..1c12894 100644
--- a/runtime/vm/object_service.cc
+++ b/runtime/vm/object_service.cc
@@ -532,7 +532,7 @@
DictionaryIterator entries(*this);
Object& entry = Object::Handle();
LibraryPrefix& prefix = LibraryPrefix::Handle();
- String& prefixName = String::Handle();
+ String& prefix_name = String::Handle();
while (entries.HasNext()) {
entry = entries.GetNext();
if (entry.IsLibraryPrefix()) {
@@ -547,15 +547,62 @@
jsdep.AddProperty("isDeferred", prefix.is_deferred_load());
jsdep.AddProperty("isExport", false);
jsdep.AddProperty("isImport", true);
- prefixName = prefix.name();
- ASSERT(!prefixName.IsNull());
- jsdep.AddProperty("prefix", prefixName.ToCString());
+ prefix_name = prefix.name();
+ ASSERT(!prefix_name.IsNull());
+ jsdep.AddProperty("prefix", prefix_name.ToCString());
target = ns.library();
jsdep.AddProperty("target", target);
}
}
}
}
+
+ if (is_declared_in_bytecode()) {
+ // Make sure top level class (containing annotations) is fully loaded.
+ EnsureTopLevelClassIsFinalized();
+ Array& metadata = Array::Handle(GetExtendedMetadata(*this, 1));
+ if (metadata.Length() != 0) {
+ // Library has the only element in the extended metadata.
+ metadata ^= metadata.At(0);
+ if (!metadata.IsNull()) {
+ Thread* thread = Thread::Current();
+ auto& desc = Array::Handle();
+ auto& target_uri = String::Handle();
+ auto& is_export = Bool::Handle();
+ auto& is_deferred = Bool::Handle();
+ for (intptr_t i = 0, n = metadata.Length(); i < n; ++i) {
+ desc ^= metadata.At(i);
+ // Each dependency is represented as an array with the following
+ // layout:
+ // [0] = target library URI (String)
+ // [1] = is_export (bool)
+ // [2] = is_deferred (bool)
+ // [3] = prefix (String or null)
+ // ...
+ // The library dependencies are encoded by getLibraryAnnotations(),
+ // pkg/vm/lib/bytecode/gen_bytecode.dart.
+ target_uri ^= desc.At(0);
+ is_export ^= desc.At(1);
+ is_deferred ^= desc.At(2);
+ prefix_name ^= desc.At(3);
+
+ target = Library::LookupLibrary(thread, target_uri);
+ if (target.IsNull()) {
+ continue;
+ }
+
+ JSONObject jsdep(&jsarr);
+ jsdep.AddProperty("isDeferred", is_deferred.value());
+ jsdep.AddProperty("isExport", is_export.value());
+ jsdep.AddProperty("isImport", !is_export.value());
+ if (!prefix_name.IsNull()) {
+ jsdep.AddProperty("prefix", prefix_name.ToCString());
+ }
+ jsdep.AddProperty("target", target);
+ }
+ }
+ }
+ }
}
{
JSONArray jsarr(&jsobj, "variables");
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index 0237cc0..6dcf00a 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -80,8 +80,6 @@
ASSERT(this->out_of_memory() == Instance::null());
ASSERT(this->preallocated_stack_trace() == StackTrace::null());
- this->pending_deferred_loads_ = GrowableObjectArray::New();
-
this->closure_functions_ = GrowableObjectArray::New();
this->resume_capabilities_ = GrowableObjectArray::New();
this->exit_listeners_ = GrowableObjectArray::New();
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index f0ded97..77461f0 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -29,7 +29,8 @@
M(Mirrors, mirrors) \
M(Profiler, profiler) \
M(TypedData, typed_data) \
- M(VMService, _vmservice)
+ M(VMService, _vmservice) \
+ M(Wasm, wasm)
#define OBJECT_STORE_FIELD_LIST(R_, RW) \
RW(Class, object_class) \
@@ -101,12 +102,11 @@
RW(Library, root_library) \
RW(Library, typed_data_library) \
RW(Library, _vmservice_library) \
+ RW(Library, wasm_library) \
RW(GrowableObjectArray, libraries) \
RW(Array, libraries_map) \
RW(GrowableObjectArray, closure_functions) \
RW(GrowableObjectArray, pending_classes) \
- RW(GrowableObjectArray, pending_unevaluated_const_fields) \
- R_(GrowableObjectArray, pending_deferred_loads) \
R_(GrowableObjectArray, resume_capabilities) \
R_(GrowableObjectArray, exit_listeners) \
R_(GrowableObjectArray, error_listeners) \
@@ -126,7 +126,6 @@
RW(Function, complete_on_async_return) \
RW(Class, async_star_stream_controller) \
RW(ObjectPool, global_object_pool) \
- RW(Array, library_load_error_table) \
RW(Array, unique_dynamic_targets) \
RW(GrowableObjectArray, megamorphic_cache_table) \
RW(Code, build_method_extractor_code) \
@@ -199,10 +198,6 @@
}
}
- void clear_pending_deferred_loads() {
- pending_deferred_loads_ = GrowableObjectArray::New();
- }
-
void SetMegamorphicMissHandler(const Code& code, const Function& func) {
// Hold onto the code so it is traced and not detached from the function.
megamorphic_miss_code_ = code.raw();
@@ -242,7 +237,7 @@
RawObject** to_snapshot(Snapshot::Kind kind) {
switch (kind) {
case Snapshot::kFull:
- return reinterpret_cast<RawObject**>(&library_load_error_table_);
+ return reinterpret_cast<RawObject**>(&global_object_pool_);
case Snapshot::kFullJIT:
case Snapshot::kFullAOT:
return reinterpret_cast<RawObject**>(&megamorphic_miss_function_);
diff --git a/runtime/vm/os_linux.cc b/runtime/vm/os_linux.cc
index eecf7fd..9baba7e 100644
--- a/runtime/vm/os_linux.cc
+++ b/runtime/vm/os_linux.cc
@@ -599,7 +599,7 @@
va_end(measure_args);
char* buffer;
- if (zone) {
+ if (zone != nullptr) {
buffer = zone->Alloc<char>(len + 1);
} else {
buffer = reinterpret_cast<char*>(malloc(len + 1));
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 6abaac0..ae99c87 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -9,6 +9,7 @@
#include "lib/invocation_mirror.h"
#include "platform/utils.h"
+#include "vm/bit_vector.h"
#include "vm/bootstrap.h"
#include "vm/class_finalizer.h"
#include "vm/compiler/aot/precompiler.h"
@@ -58,7 +59,6 @@
expression_temp_var_(NULL),
entry_points_temp_var_(NULL),
finally_return_temp_var_(NULL),
- deferred_prefixes_(new ZoneGrowableArray<const LibraryPrefix*>()),
guarded_fields_(new ZoneGrowableArray<const Field*>()),
default_parameter_values_(NULL),
raw_type_arguments_var_(NULL),
@@ -184,20 +184,6 @@
regexp_compile_data_ = regexp_compile_data;
}
-void ParsedFunction::AddDeferredPrefix(const LibraryPrefix& prefix) {
- // 'deferred_prefixes_' are used to invalidate code, but no invalidation is
- // needed if --load_deferred_eagerly.
- ASSERT(!FLAG_load_deferred_eagerly);
- ASSERT(prefix.is_deferred_load());
- ASSERT(!prefix.is_loaded());
- for (intptr_t i = 0; i < deferred_prefixes_->length(); i++) {
- if ((*deferred_prefixes_)[i]->raw() == prefix.raw()) {
- return;
- }
- }
- deferred_prefixes_->Add(&LibraryPrefix::ZoneHandle(Z, prefix.raw()));
-}
-
void ParsedFunction::AllocateVariables() {
ASSERT(!function().IsIrregexpFunction());
LocalScope* scope = this->scope();
@@ -316,6 +302,33 @@
num_stack_locals_ = num_stack_locals;
}
+void ParsedFunction::SetCovariantParameters(
+ const BitVector* covariant_parameters) {
+ ASSERT(covariant_parameters_ == nullptr);
+ ASSERT(covariant_parameters->length() == function_.NumParameters());
+ covariant_parameters_ = covariant_parameters;
+}
+
+void ParsedFunction::SetGenericCovariantImplParameters(
+ const BitVector* generic_covariant_impl_parameters) {
+ ASSERT(generic_covariant_impl_parameters_ == nullptr);
+ ASSERT(generic_covariant_impl_parameters->length() ==
+ function_.NumParameters());
+ generic_covariant_impl_parameters_ = generic_covariant_impl_parameters;
+}
+
+bool ParsedFunction::IsCovariantParameter(intptr_t i) const {
+ ASSERT(covariant_parameters_ != nullptr);
+ ASSERT((i >= 0) && (i < function_.NumParameters()));
+ return covariant_parameters_->Contains(i);
+}
+
+bool ParsedFunction::IsGenericCovariantImplParameter(intptr_t i) const {
+ ASSERT(generic_covariant_impl_parameters_ != nullptr);
+ ASSERT((i >= 0) && (i < function_.NumParameters()));
+ return generic_covariant_impl_parameters_->Contains(i);
+}
+
} // namespace dart
#endif // DART_PRECOMPILED_RUNTIME
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index 2328080..f574ea6 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -30,6 +30,7 @@
} // namespace kernel
class ArgumentsDescriptor;
+class BitVector;
class Isolate;
class LocalScope;
class LocalVariable;
@@ -155,12 +156,6 @@
LocalVariable* EnsureExpressionTemp();
LocalVariable* EnsureEntryPointsTemp();
- bool HasDeferredPrefixes() const { return deferred_prefixes_->length() != 0; }
- ZoneGrowableArray<const LibraryPrefix*>* deferred_prefixes() const {
- return deferred_prefixes_;
- }
- void AddDeferredPrefix(const LibraryPrefix& prefix);
-
ZoneGrowableArray<const Field*>* guarded_fields() const {
return guarded_fields_;
}
@@ -226,6 +221,28 @@
return default_function_type_arguments_;
}
+ // Remembers the set of covariant parameters.
+ // [covariant_parameters] is a bitvector of function.NumParameters() length.
+ void SetCovariantParameters(const BitVector* covariant_parameters);
+
+ // Remembers the set of generic-covariant-impl parameters.
+ // [covariant_parameters] is a bitvector of function.NumParameters() length.
+ void SetGenericCovariantImplParameters(
+ const BitVector* generic_covariant_impl_parameters);
+
+ bool HasCovariantParametersInfo() const {
+ return covariant_parameters_ != nullptr;
+ }
+
+ // Returns true if i-th parameter is covariant.
+ // SetCovariantParameters should be called before using this method.
+ bool IsCovariantParameter(intptr_t i) const;
+
+ // Returns true if i-th parameter is generic-covariant-impl.
+ // SetGenericCovariantImplParameters should be called before using this
+ // method.
+ bool IsGenericCovariantImplParameter(intptr_t i) const;
+
private:
Thread* thread_;
const Function& function_;
@@ -240,7 +257,6 @@
LocalVariable* expression_temp_var_;
LocalVariable* entry_points_temp_var_;
LocalVariable* finally_return_temp_var_;
- ZoneGrowableArray<const LibraryPrefix*>* deferred_prefixes_;
ZoneGrowableArray<const Field*>* guarded_fields_;
ZoneGrowableArray<const Instance*>* default_parameter_values_;
@@ -256,6 +272,9 @@
TypeArguments& default_function_type_arguments_;
+ const BitVector* covariant_parameters_ = nullptr;
+ const BitVector* generic_covariant_impl_parameters_ = nullptr;
+
friend class Parser;
DISALLOW_COPY_AND_ASSIGN(ParsedFunction);
};
diff --git a/runtime/vm/pointer_tagging.h b/runtime/vm/pointer_tagging.h
index a4d6d9f..e4a59e6 100644
--- a/runtime/vm/pointer_tagging.h
+++ b/runtime/vm/pointer_tagging.h
@@ -5,6 +5,9 @@
#ifndef RUNTIME_VM_POINTER_TAGGING_H_
#define RUNTIME_VM_POINTER_TAGGING_H_
+#include "platform/assert.h"
+#include "platform/globals.h"
+
// This header defines constants associated with pointer tagging:
//
// * which bits determine whether or not this is a Smi value or a heap
diff --git a/runtime/vm/proccpuinfo.cc b/runtime/vm/proccpuinfo.cc
index 3dfb2cb..6278627 100644
--- a/runtime/vm/proccpuinfo.cc
+++ b/runtime/vm/proccpuinfo.cc
@@ -76,7 +76,7 @@
// Skip to the first colon followed by a space.
p = strchr(p + fieldlen, ':');
- if (p == NULL || !isspace(p[1])) {
+ if (p == NULL || (isspace(p[1]) == 0)) {
return NULL;
}
p += 2;
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index 52cbcf5..fee9e8e 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -1063,6 +1063,9 @@
// purposes as some samples may be collected when no thread exists.
if (thread != NULL) {
sample->set_thread_task(thread->task_kind());
+ sample->set_vm_tag(thread->vm_tag());
+ } else {
+ sample->set_vm_tag(VMTag::kEmbedderTagId);
}
return sample;
}
diff --git a/runtime/vm/profiler.h b/runtime/vm/profiler.h
index f0280fc..9c879ae 100644
--- a/runtime/vm/profiler.h
+++ b/runtime/vm/profiler.h
@@ -477,24 +477,56 @@
const char* Name() const {
if (code_.IsCode()) {
return Code::Cast(code_).Name();
- } else {
+ } else if (code_.IsBytecode()) {
return Bytecode::Cast(code_).Name();
+ } else {
+ return "";
}
}
const char* QualifiedName() const {
if (code_.IsCode()) {
return Code::Cast(code_).QualifiedName();
- } else {
+ } else if (code_.IsBytecode()) {
return Bytecode::Cast(code_).QualifiedName();
+ } else {
+ return "";
+ }
+ }
+
+ bool IsStubCode() const {
+ if (code_.IsCode()) {
+ return Code::Cast(code_).IsStubCode();
+ } else if (code_.IsBytecode()) {
+ return (Bytecode::Cast(code_).function() == Function::null());
+ } else {
+ return false;
+ }
+ }
+
+ bool IsAllocationStubCode() const {
+ if (code_.IsCode()) {
+ return Code::Cast(code_).IsAllocationStubCode();
+ } else {
+ return false;
+ }
+ }
+
+ bool IsTypeTestStubCode() const {
+ if (code_.IsCode()) {
+ return Code::Cast(code_).IsTypeTestStubCode();
+ } else {
+ return false;
}
}
RawObject* owner() const {
if (code_.IsCode()) {
return Code::Cast(code_).owner();
- } else {
+ } else if (code_.IsBytecode()) {
return Bytecode::Cast(code_).function();
+ } else {
+ return Object::null();
}
}
diff --git a/runtime/vm/profiler_service.cc b/runtime/vm/profiler_service.cc
index d3a1450..db033d0 100644
--- a/runtime/vm/profiler_service.cc
+++ b/runtime/vm/profiler_service.cc
@@ -225,16 +225,18 @@
}
void ProfileFunction::PrintToJSONObject(JSONObject* func) {
- func->AddProperty("type", "@Function");
+ func->AddProperty("type", "NativeFunction");
func->AddProperty("name", name());
func->AddProperty("_kind", KindToCString(kind()));
}
void ProfileFunction::PrintToJSONArray(JSONArray* functions) {
JSONObject obj(functions);
+ obj.AddProperty("type", "ProfileFunction");
obj.AddProperty("kind", KindToCString(kind()));
obj.AddProperty("inclusiveTicks", inclusive_ticks());
obj.AddProperty("exclusiveTicks", exclusive_ticks());
+ obj.AddProperty("resolvedUrl", ResolvedScriptUrl());
if (kind() == kDartFunction) {
ASSERT(!function_.IsNull());
obj.AddProperty("function", function_);
@@ -243,7 +245,7 @@
PrintToJSONObject(&func);
}
{
- JSONArray codes(&obj, "codes");
+ JSONArray codes(&obj, "_codes");
for (intptr_t i = 0; i < profile_codes_.length(); i++) {
intptr_t code_index = profile_codes_[i];
codes.AddValue(code_index);
@@ -865,335 +867,107 @@
}
}
-ProfileTrieNode::ProfileTrieNode(intptr_t table_index)
- : table_index_(table_index),
- count_(0),
- exclusive_allocations_(0),
- inclusive_allocations_(0),
- children_(0),
- parent_(NULL),
- frame_id_(-1) {
- ASSERT(table_index_ >= 0);
+void ProfileCodeInlinedFunctionsCache::Get(
+ uword pc,
+ const Code& code,
+ ProcessedSample* sample,
+ intptr_t frame_index,
+ // Outputs:
+ GrowableArray<const Function*>** inlined_functions,
+ GrowableArray<TokenPosition>** inlined_token_positions,
+ TokenPosition* token_position) {
+ const intptr_t offset = OffsetForPC(pc, code, sample, frame_index);
+ if (FindInCache(pc, offset, inlined_functions, inlined_token_positions,
+ token_position)) {
+ // Found in cache.
+ return;
+ }
+ Add(pc, code, sample, frame_index, inlined_functions, inlined_token_positions,
+ token_position);
}
-ProfileTrieNode::~ProfileTrieNode() {}
-
-void ProfileTrieNode::Tick(ProcessedSample* sample, bool exclusive) {
- count_++;
- IncrementAllocation(sample->native_allocation_size_bytes(), exclusive);
+bool ProfileCodeInlinedFunctionsCache::FindInCache(
+ uword pc,
+ intptr_t offset,
+ GrowableArray<const Function*>** inlined_functions,
+ GrowableArray<TokenPosition>** inlined_token_positions,
+ TokenPosition* token_position) {
+ // Simple linear scan.
+ for (intptr_t i = 0; i < kCacheSize; i++) {
+ intptr_t index = (last_hit_ + i) % kCacheSize;
+ if ((cache_[index].pc == pc) && (cache_[index].offset == offset)) {
+ // Hit.
+ if (cache_[index].inlined_functions.length() == 0) {
+ *inlined_functions = NULL;
+ *inlined_token_positions = NULL;
+ } else {
+ *inlined_functions = &cache_[index].inlined_functions;
+ *inlined_token_positions = &cache_[index].inlined_token_positions;
+ }
+ *token_position = cache_[index].token_position;
+ cache_hit_++;
+ last_hit_ = index;
+ return true;
+ }
+ }
+ cache_miss_++;
+ return false;
}
-void ProfileTrieNode::SortChildren() {
- children_.Sort(ProfileTrieNodeCompare);
- // Recurse.
- for (intptr_t i = 0; i < children_.length(); i++) {
- children_[i]->SortChildren();
+// Add to cache and fill in outputs.
+void ProfileCodeInlinedFunctionsCache::Add(
+ uword pc,
+ const Code& code,
+ ProcessedSample* sample,
+ intptr_t frame_index,
+ // Outputs:
+ GrowableArray<const Function*>** inlined_functions,
+ GrowableArray<TokenPosition>** inlined_token_positions,
+ TokenPosition* token_position) {
+ const intptr_t offset = OffsetForPC(pc, code, sample, frame_index);
+ CacheEntry* cache_entry = &cache_[NextFreeIndex()];
+ cache_entry->Reset();
+ cache_entry->pc = pc;
+ cache_entry->offset = offset;
+ code.GetInlinedFunctionsAtInstruction(
+ offset, &(cache_entry->inlined_functions),
+ &(cache_entry->inlined_token_positions));
+ if (cache_entry->inlined_functions.length() == 0) {
+ *inlined_functions = NULL;
+ *inlined_token_positions = NULL;
+ *token_position = cache_entry->token_position = TokenPosition();
+ return;
}
+
+ // Write outputs.
+ *inlined_functions = &(cache_entry->inlined_functions);
+ *inlined_token_positions = &(cache_entry->inlined_token_positions);
+ *token_position = cache_entry->token_position =
+ cache_entry->inlined_token_positions[0];
}
-intptr_t ProfileTrieNode::IndexOf(ProfileTrieNode* node) {
- for (intptr_t i = 0; i < children_.length(); i++) {
- if (children_[i] == node) {
- return i;
- }
+intptr_t ProfileCodeInlinedFunctionsCache::OffsetForPC(uword pc,
+ const Code& code,
+ ProcessedSample* sample,
+ intptr_t frame_index) {
+ intptr_t offset = pc - code.PayloadStart();
+ if (frame_index != 0) {
+ // The PC of frames below the top frame is a call's return address,
+ // which can belong to a different inlining interval than the call.
+ offset--;
+ } else if (sample->IsAllocationSample()) {
+ // Allocation samples skip the top frame, so the top frame's pc is
+ // also a call's return address.
+ offset--;
+ } else if (!sample->first_frame_executing()) {
+ // If the first frame wasn't executing code (i.e. we started to collect
+ // the stack trace at an exit frame), the top frame's pc is also a
+ // call's return address.
+ offset--;
}
- return -1;
+ return offset;
}
-class ProfileCodeTrieNode : public ProfileTrieNode {
- public:
- explicit ProfileCodeTrieNode(intptr_t table_index)
- : ProfileTrieNode(table_index) {}
-
- void PrintToJSONArray(JSONArray* array) const {
- ASSERT(array != NULL);
- // Write CodeRegion index.
- array->AddValue(table_index());
- // Write count.
- array->AddValue(count());
- // Write number of children.
- intptr_t child_count = NumChildren();
- array->AddValue(child_count);
- // Write inclusive allocations.
- array->AddValue64(inclusive_allocations_);
- // Write exclusive allocations.
- array->AddValue64(exclusive_allocations_);
- // Recurse.
- for (intptr_t i = 0; i < child_count; i++) {
- children_[i]->PrintToJSONArray(array);
- }
- }
-
- const char* ToCString(Profile* profile) const {
- return profile->GetCode(table_index())->name();
- }
-
- ProfileCodeTrieNode* GetChild(intptr_t child_table_index) {
- const intptr_t length = NumChildren();
- intptr_t i = 0;
- while (i < length) {
- ProfileCodeTrieNode* child =
- reinterpret_cast<ProfileCodeTrieNode*>(children_[i]);
- if (child->table_index() == child_table_index) {
- return child;
- }
- if (child->table_index() > child_table_index) {
- break;
- }
- i++;
- }
- ProfileCodeTrieNode* child = new ProfileCodeTrieNode(child_table_index);
- if (i < length) {
- // Insert at i.
- children_.InsertAt(i, reinterpret_cast<ProfileTrieNode*>(child));
- } else {
- // Add to end.
- children_.Add(reinterpret_cast<ProfileTrieNode*>(child));
- }
- return child;
- }
-};
-
-class ProfileFunctionTrieNodeCode {
- public:
- explicit ProfileFunctionTrieNodeCode(intptr_t index)
- : code_index_(index), ticks_(0) {}
-
- intptr_t index() const { return code_index_; }
-
- void Tick() { ticks_++; }
-
- intptr_t ticks() const { return ticks_; }
-
- private:
- intptr_t code_index_;
- intptr_t ticks_;
-};
-
-class ProfileFunctionTrieNode : public ProfileTrieNode {
- public:
- explicit ProfileFunctionTrieNode(intptr_t table_index)
- : ProfileTrieNode(table_index), code_objects_(1) {}
-
- void PrintToJSONArray(JSONArray* array) const {
- ASSERT(array != NULL);
- // Write CodeRegion index.
- array->AddValue(table_index());
- // Write count.
- array->AddValue(count());
- // Write inclusive allocations.
- array->AddValue64(inclusive_allocations_);
- // Write exclusive allocations.
- array->AddValue64(exclusive_allocations_);
- // Write number of code objects.
- intptr_t code_count = code_objects_.length();
- array->AddValue(code_count);
- // Write each code object index and ticks.
- for (intptr_t i = 0; i < code_count; i++) {
- array->AddValue(code_objects_[i].index());
- array->AddValue(code_objects_[i].ticks());
- }
- // Write number of children.
- intptr_t child_count = children_.length();
- array->AddValue(child_count);
- // Recurse.
- for (intptr_t i = 0; i < child_count; i++) {
- children_[i]->PrintToJSONArray(array);
- }
- }
-
- const char* ToCString(Profile* profile) const {
- ProfileFunction* f = profile->GetFunction(table_index());
- return f->Name();
- }
-
- ProfileFunctionTrieNode* GetChild(intptr_t child_table_index) {
- const intptr_t length = NumChildren();
- intptr_t i = 0;
- while (i < length) {
- ProfileFunctionTrieNode* child =
- reinterpret_cast<ProfileFunctionTrieNode*>(children_[i]);
- if (child->table_index() == child_table_index) {
- return child;
- }
- if (child->table_index() > child_table_index) {
- break;
- }
- i++;
- }
- ProfileFunctionTrieNode* child =
- new ProfileFunctionTrieNode(child_table_index);
- if (i < length) {
- // Insert at i.
- children_.InsertAt(i, reinterpret_cast<ProfileTrieNode*>(child));
- } else {
- // Add to end.
- children_.Add(reinterpret_cast<ProfileTrieNode*>(child));
- }
- return child;
- }
-
- void AddCodeObjectIndex(intptr_t index) {
- for (intptr_t i = 0; i < code_objects_.length(); i++) {
- ProfileFunctionTrieNodeCode& code_object = code_objects_[i];
- if (code_object.index() == index) {
- code_object.Tick();
- return;
- }
- }
- ProfileFunctionTrieNodeCode code_object(index);
- code_object.Tick();
- code_objects_.Add(code_object);
- }
-
- private:
- ZoneGrowableArray<ProfileFunctionTrieNodeCode> code_objects_;
-};
-
-class ProfileCodeInlinedFunctionsCache : public ValueObject {
- public:
- ProfileCodeInlinedFunctionsCache() : cache_cursor_(0), last_hit_(0) {
- for (intptr_t i = 0; i < kCacheSize; i++) {
- cache_[i].Reset();
- }
- cache_hit_ = 0;
- cache_miss_ = 0;
- }
-
- ~ProfileCodeInlinedFunctionsCache() {
- if (FLAG_trace_profiler) {
- intptr_t total = cache_hit_ + cache_miss_;
- OS::PrintErr("LOOKUPS: %" Pd " HITS: %" Pd " MISSES: %" Pd "\n", total,
- cache_hit_, cache_miss_);
- }
- }
-
- void Get(uword pc,
- const Code& code,
- ProcessedSample* sample,
- intptr_t frame_index,
- // Outputs:
- GrowableArray<const Function*>** inlined_functions,
- GrowableArray<TokenPosition>** inlined_token_positions,
- TokenPosition* token_position) {
- const intptr_t offset = OffsetForPC(pc, code, sample, frame_index);
- if (FindInCache(pc, offset, inlined_functions, inlined_token_positions,
- token_position)) {
- // Found in cache.
- return;
- }
- Add(pc, code, sample, frame_index, inlined_functions,
- inlined_token_positions, token_position);
- }
-
- private:
- bool FindInCache(uword pc,
- intptr_t offset,
- GrowableArray<const Function*>** inlined_functions,
- GrowableArray<TokenPosition>** inlined_token_positions,
- TokenPosition* token_position) {
- // Simple linear scan.
- for (intptr_t i = 0; i < kCacheSize; i++) {
- intptr_t index = (last_hit_ + i) % kCacheSize;
- if ((cache_[index].pc == pc) && (cache_[index].offset == offset)) {
- // Hit.
- if (cache_[index].inlined_functions.length() == 0) {
- *inlined_functions = NULL;
- *inlined_token_positions = NULL;
- } else {
- *inlined_functions = &cache_[index].inlined_functions;
- *inlined_token_positions = &cache_[index].inlined_token_positions;
- }
- *token_position = cache_[index].token_position;
- cache_hit_++;
- last_hit_ = index;
- return true;
- }
- }
- cache_miss_++;
- return false;
- }
-
- // Add to cache and fill in outputs.
- void Add(uword pc,
- const Code& code,
- ProcessedSample* sample,
- intptr_t frame_index,
- // Outputs:
- GrowableArray<const Function*>** inlined_functions,
- GrowableArray<TokenPosition>** inlined_token_positions,
- TokenPosition* token_position) {
- const intptr_t offset = OffsetForPC(pc, code, sample, frame_index);
- CacheEntry* cache_entry = &cache_[NextFreeIndex()];
- cache_entry->Reset();
- cache_entry->pc = pc;
- cache_entry->offset = offset;
- code.GetInlinedFunctionsAtInstruction(
- offset, &(cache_entry->inlined_functions),
- &(cache_entry->inlined_token_positions));
- if (cache_entry->inlined_functions.length() == 0) {
- *inlined_functions = NULL;
- *inlined_token_positions = NULL;
- *token_position = cache_entry->token_position = TokenPosition();
- return;
- }
-
- // Write outputs.
- *inlined_functions = &(cache_entry->inlined_functions);
- *inlined_token_positions = &(cache_entry->inlined_token_positions);
- *token_position = cache_entry->token_position =
- cache_entry->inlined_token_positions[0];
- }
-
- intptr_t NextFreeIndex() {
- cache_cursor_ = (cache_cursor_ + 1) % kCacheSize;
- return cache_cursor_;
- }
-
- intptr_t OffsetForPC(uword pc,
- const Code& code,
- ProcessedSample* sample,
- intptr_t frame_index) {
- intptr_t offset = pc - code.PayloadStart();
- if (frame_index != 0) {
- // The PC of frames below the top frame is a call's return address,
- // which can belong to a different inlining interval than the call.
- offset--;
- } else if (sample->IsAllocationSample()) {
- // Allocation samples skip the top frame, so the top frame's pc is
- // also a call's return address.
- offset--;
- } else if (!sample->first_frame_executing()) {
- // If the first frame wasn't executing code (i.e. we started to collect
- // the stack trace at an exit frame), the top frame's pc is also a
- // call's return address.
- offset--;
- }
- return offset;
- }
-
- struct CacheEntry {
- void Reset() {
- pc = 0;
- offset = 0;
- inlined_functions.Clear();
- inlined_token_positions.Clear();
- }
- uword pc;
- intptr_t offset;
- GrowableArray<const Function*> inlined_functions;
- GrowableArray<TokenPosition> inlined_token_positions;
- TokenPosition token_position;
- };
-
- static const intptr_t kCacheSize = 128;
- intptr_t cache_cursor_;
- intptr_t last_hit_;
- CacheEntry cache_[kCacheSize];
- intptr_t cache_miss_;
- intptr_t cache_hit_;
-};
-
class ProfileBuilder : public ValueObject {
public:
enum ProfileInfoKind {
@@ -1209,20 +983,15 @@
ProfileBuilder(Thread* thread,
SampleFilter* filter,
SampleBuffer* sample_buffer,
- Profile::TagOrder tag_order,
- intptr_t extra_tags,
Profile* profile)
: thread_(thread),
vm_isolate_(Dart::vm_isolate()),
filter_(filter),
sample_buffer_(sample_buffer),
- tag_order_(tag_order),
- extra_tags_(extra_tags),
profile_(profile),
deoptimized_code_(new DeoptimizedCodeSet(thread->isolate())),
null_code_(Code::null()),
null_function_(Function::ZoneHandle()),
- tick_functions_(false),
inclusive_tree_(false),
samples_(NULL),
info_kind_(kNone) {
@@ -1241,12 +1010,7 @@
BuildCodeTable();
FinalizeCodeIndexes();
BuildFunctionTable();
-
- BuildCodeTrie(Profile::kExclusiveCode);
- BuildCodeTrie(Profile::kInclusiveCode);
-
- BuildFunctionTrie(Profile::kExclusiveFunction);
- BuildFunctionTrie(Profile::kInclusiveFunction);
+ PopulateFunctionTicks();
}
private:
@@ -1256,11 +1020,6 @@
(sample->first_frame_executing() || sample->IsAllocationSample());
}
- static bool IsInclusiveTrie(Profile::TrieKind kind) {
- return (kind == Profile::kInclusiveFunction) ||
- (kind == Profile::kInclusiveCode);
- }
-
void Setup() {
profile_->live_code_ = new ProfileCodeTable();
profile_->dead_code_ = new ProfileCodeTable();
@@ -1413,202 +1172,27 @@
}
}
- void BuildCodeTrie(Profile::TrieKind kind) {
- ProfileCodeTrieNode* root =
- new ProfileCodeTrieNode(GetProfileCodeTagIndex(VMTag::kRootTagId));
- inclusive_tree_ = IsInclusiveTrie(kind);
- if (inclusive_tree_) {
- BuildInclusiveCodeTrie(root);
- } else {
- BuildExclusiveCodeTrie(root);
- }
- root->SortChildren();
- profile_->roots_[static_cast<intptr_t>(kind)] = root;
- }
-
- void BuildInclusiveCodeTrie(ProfileCodeTrieNode* root) {
- ScopeTimer sw("ProfileBuilder::BuildInclusiveCodeTrie",
- FLAG_trace_profiler);
+ void PopulateFunctionTicks() {
+ ScopeTimer sw("ProfileBuilder::PopulateFunctionTicks", FLAG_trace_profiler);
for (intptr_t sample_index = 0; sample_index < samples_->length();
sample_index++) {
ProcessedSample* sample = samples_->At(sample_index);
- // Tick the root.
- ProfileCodeTrieNode* current = root;
- current->Tick(sample);
-
- // VM & User tags.
- current =
- AppendTags(sample->vm_tag(), sample->user_tag(), current, sample);
-
- ResetKind();
-
- // Truncated tag.
- if (sample->truncated()) {
- current = AppendTruncatedTag(current, sample);
- }
-
- // Walk the sampled PCs.
- for (intptr_t frame_index = sample->length() - 1; frame_index >= 0;
- frame_index--) {
- ASSERT(sample->At(frame_index) != 0);
- intptr_t index =
- GetProfileCodeIndex(sample->At(frame_index), sample->timestamp());
- ASSERT(index >= 0);
- ProfileCode* profile_code =
- GetProfileCode(sample->At(frame_index), sample->timestamp());
- ASSERT(profile_code->code_table_index() == index);
- const AbstractCode code = profile_code->code();
- current = AppendKind(code, current, sample);
- current = current->GetChild(index);
- current->Tick(sample, (frame_index == 0));
- }
-
- if (!sample->first_frame_executing()) {
- current = AppendExitFrame(sample->vm_tag(), current, sample);
- }
-
- sample->set_timeline_code_trie(current);
- }
- }
-
- void BuildExclusiveCodeTrie(ProfileCodeTrieNode* root) {
- ScopeTimer sw("ProfileBuilder::BuildExclusiveCodeTrie",
- FLAG_trace_profiler);
- for (intptr_t sample_index = 0; sample_index < samples_->length();
- sample_index++) {
- ProcessedSample* sample = samples_->At(sample_index);
-
- // Tick the root.
- ProfileCodeTrieNode* current = root;
- current->Tick(sample);
- // VM & User tags.
- current =
- AppendTags(sample->vm_tag(), sample->user_tag(), current, sample);
-
- ResetKind();
-
- if (!sample->first_frame_executing()) {
- current = AppendExitFrame(sample->vm_tag(), current, sample);
- }
-
// Walk the sampled PCs.
for (intptr_t frame_index = 0; frame_index < sample->length();
frame_index++) {
ASSERT(sample->At(frame_index) != 0);
- intptr_t index =
- GetProfileCodeIndex(sample->At(frame_index), sample->timestamp());
- ASSERT(index >= 0);
- ProfileCode* profile_code =
- GetProfileCode(sample->At(frame_index), sample->timestamp());
- ASSERT(profile_code->code_table_index() == index);
- const AbstractCode code = profile_code->code();
- current = current->GetChild(index);
- if (ShouldTickNode(sample, frame_index)) {
- current->Tick(sample, (frame_index == 0));
- }
- current = AppendKind(code, current, sample);
+ ProcessFrame(sample_index, sample, frame_index);
}
- // Truncated tag.
if (sample->truncated()) {
- current = AppendTruncatedTag(current, sample);
- }
- }
- }
-
- void BuildFunctionTrie(Profile::TrieKind kind) {
- ProfileFunctionTrieNode* root = new ProfileFunctionTrieNode(
- GetProfileFunctionTagIndex(VMTag::kRootTagId));
- // We tick the functions while building the trie, but, we don't want to do
- // it for both tries, just the exclusive trie.
- inclusive_tree_ = IsInclusiveTrie(kind);
- tick_functions_ = !inclusive_tree_;
- if (inclusive_tree_) {
- BuildInclusiveFunctionTrie(root);
- } else {
- BuildExclusiveFunctionTrie(root);
- }
- root->SortChildren();
- profile_->roots_[static_cast<intptr_t>(kind)] = root;
- }
-
- void BuildInclusiveFunctionTrie(ProfileFunctionTrieNode* root) {
- ScopeTimer sw("ProfileBuilder::BuildInclusiveFunctionTrie",
- FLAG_trace_profiler);
- ASSERT(!tick_functions_);
- for (intptr_t sample_index = 0; sample_index < samples_->length();
- sample_index++) {
- ProcessedSample* sample = samples_->At(sample_index);
-
- // Tick the root.
- ProfileFunctionTrieNode* current = root;
- current->Tick(sample);
- // VM & User tags.
- current =
- AppendTags(sample->vm_tag(), sample->user_tag(), current, sample);
-
- // Truncated tag.
- if (sample->truncated()) {
- current = AppendTruncatedTag(current, sample);
- }
-
- // Walk the sampled PCs.
- for (intptr_t frame_index = sample->length() - 1; frame_index >= 0;
- frame_index--) {
- ASSERT(sample->At(frame_index) != 0);
- current = ProcessFrame(current, sample_index, sample, frame_index);
- }
-
- if (!sample->first_frame_executing()) {
- current = AppendExitFrame(sample->vm_tag(), current, sample);
- }
-
- sample->set_timeline_function_trie(current);
- }
- }
-
- void BuildExclusiveFunctionTrie(ProfileFunctionTrieNode* root) {
- ScopeTimer sw("ProfileBuilder::BuildExclusiveFunctionTrie",
- FLAG_trace_profiler);
- ASSERT(tick_functions_);
- for (intptr_t sample_index = 0; sample_index < samples_->length();
- sample_index++) {
- ProcessedSample* sample = samples_->At(sample_index);
-
- // Tick the root.
- ProfileFunctionTrieNode* current = root;
- current->Tick(sample);
- // VM & User tags.
- current =
- AppendTags(sample->vm_tag(), sample->user_tag(), current, sample);
-
- ResetKind();
-
- if (!sample->first_frame_executing()) {
- current = AppendExitFrame(sample->vm_tag(), current, sample);
- }
-
- // Walk the sampled PCs.
- for (intptr_t frame_index = 0; frame_index < sample->length();
- frame_index++) {
- ASSERT(sample->At(frame_index) != 0);
- current = ProcessFrame(current, sample_index, sample, frame_index);
- }
-
- TickExitFrameFunction(sample->vm_tag(), sample_index);
-
- // Truncated tag.
- if (sample->truncated()) {
- current = AppendTruncatedTag(current, sample);
InclusiveTickTruncatedTag(sample);
}
}
}
- ProfileFunctionTrieNode* ProcessFrame(ProfileFunctionTrieNode* current,
- intptr_t sample_index,
- ProcessedSample* sample,
- intptr_t frame_index) {
+ void ProcessFrame(intptr_t sample_index,
+ ProcessedSample* sample,
+ intptr_t frame_index) {
const uword pc = sample->At(frame_index);
ProfileCode* profile_code = GetProfileCode(pc, sample->timestamp());
ProfileFunction* function = profile_code->function();
@@ -1625,7 +1209,7 @@
inlined_functions_cache_.Get(pc, code, sample, frame_index,
&inlined_functions, &inlined_token_positions,
&token_position);
- if (FLAG_trace_profiler_verbose) {
+ if (FLAG_trace_profiler_verbose && (inlined_functions != NULL)) {
for (intptr_t i = 0; i < inlined_functions->length(); i++) {
const String& name =
String::Handle((*inlined_functions)[i]->QualifiedScrubbedName());
@@ -1643,16 +1227,9 @@
if (code.IsNull() || (inlined_functions == NULL) ||
(inlined_functions->length() <= 1)) {
- // No inlined functions.
- if (inclusive_tree_) {
- current = AppendKind(code, current, sample);
- }
- current = ProcessFunction(current, sample_index, sample, frame_index,
- function, token_position, code_index);
- if (!inclusive_tree_) {
- current = AppendKind(code, current, sample);
- }
- return current;
+ ProcessFunction(sample_index, sample, frame_index, function,
+ token_position, code_index);
+ return;
}
if (!code.is_optimized()) {
@@ -1668,99 +1245,56 @@
ASSERT(code.is_optimized());
- if (inclusive_tree_) {
- for (intptr_t i = 0; i < inlined_functions->length(); i++) {
- const Function* inlined_function = (*inlined_functions)[i];
- ASSERT(inlined_function != NULL);
- ASSERT(!inlined_function->IsNull());
- TokenPosition inlined_token_position = (*inlined_token_positions)[i];
- const bool inliner = i == 0;
- if (inliner) {
- current = AppendKind(code, current, sample);
- }
- current = ProcessInlinedFunction(current, sample_index, sample,
- frame_index, inlined_function,
- inlined_token_position, code_index);
- if (inliner) {
- current = AppendKind(kInlineStart, current, sample);
- }
- }
- current = AppendKind(kInlineFinish, current, sample);
- } else {
- // Append the inlined children.
- current = AppendKind(kInlineFinish, current, sample);
- for (intptr_t i = inlined_functions->length() - 1; i >= 0; i--) {
- const Function* inlined_function = (*inlined_functions)[i];
- ASSERT(inlined_function != NULL);
- ASSERT(!inlined_function->IsNull());
- TokenPosition inlined_token_position = (*inlined_token_positions)[i];
- const bool inliner = i == 0;
- if (inliner) {
- current = AppendKind(kInlineStart, current, sample);
- }
- current = ProcessInlinedFunction(current, sample_index, sample,
- frame_index + i, inlined_function,
- inlined_token_position, code_index);
- if (inliner) {
- current = AppendKind(code, current, sample);
- }
- }
+ // Append the inlined children.
+ for (intptr_t i = inlined_functions->length() - 1; i >= 0; i--) {
+ const Function* inlined_function = (*inlined_functions)[i];
+ ASSERT(inlined_function != NULL);
+ ASSERT(!inlined_function->IsNull());
+ TokenPosition inlined_token_position = (*inlined_token_positions)[i];
+ ProcessInlinedFunction(sample_index, sample, frame_index + i,
+ inlined_function, inlined_token_position,
+ code_index);
}
-
- return current;
}
- ProfileFunctionTrieNode* ProcessInlinedFunction(
- ProfileFunctionTrieNode* current,
- intptr_t sample_index,
- ProcessedSample* sample,
- intptr_t frame_index,
- const Function* inlined_function,
- TokenPosition inlined_token_position,
- intptr_t code_index) {
+ void ProcessInlinedFunction(intptr_t sample_index,
+ ProcessedSample* sample,
+ intptr_t frame_index,
+ const Function* inlined_function,
+ TokenPosition inlined_token_position,
+ intptr_t code_index) {
ProfileFunctionTable* function_table = profile_->functions_;
ProfileFunction* function = function_table->LookupOrAdd(*inlined_function);
ASSERT(function != NULL);
- return ProcessFunction(current, sample_index, sample, frame_index, function,
- inlined_token_position, code_index);
+ ProcessFunction(sample_index, sample, frame_index, function,
+ inlined_token_position, code_index);
}
bool ShouldTickNode(ProcessedSample* sample, intptr_t frame_index) {
if (frame_index != 0) {
return true;
}
- // Only tick the first frame's node, if we are executing OR
- // vm tags have been emitted.
- return IsExecutingFrame(sample, frame_index) || !FLAG_profile_vm ||
- vm_tags_emitted();
+ // Only tick the first frame's node, if we are executing
+ return IsExecutingFrame(sample, frame_index) || !FLAG_profile_vm;
}
- ProfileFunctionTrieNode* ProcessFunction(ProfileFunctionTrieNode* current,
- intptr_t sample_index,
- ProcessedSample* sample,
- intptr_t frame_index,
- ProfileFunction* function,
- TokenPosition token_position,
- intptr_t code_index) {
+ void ProcessFunction(intptr_t sample_index,
+ ProcessedSample* sample,
+ intptr_t frame_index,
+ ProfileFunction* function,
+ TokenPosition token_position,
+ intptr_t code_index) {
if (!function->is_visible()) {
- return current;
+ return;
}
- if (tick_functions_) {
- if (FLAG_trace_profiler_verbose) {
- THR_Print("S[%" Pd "]F[%" Pd "] %s %s 0x%" Px "\n", sample_index,
- frame_index, function->Name(), token_position.ToCString(),
- sample->At(frame_index));
- }
- function->Tick(IsExecutingFrame(sample, frame_index), sample_index,
- token_position);
+ if (FLAG_trace_profiler_verbose) {
+ THR_Print("S[%" Pd "]F[%" Pd "] %s %s 0x%" Px "\n", sample_index,
+ frame_index, function->Name(), token_position.ToCString(),
+ sample->At(frame_index));
}
+ function->Tick(IsExecutingFrame(sample, frame_index), sample_index,
+ token_position);
function->AddProfileCode(code_index);
- current = current->GetChild(function->table_index());
- if (ShouldTickNode(sample, frame_index)) {
- current->Tick(sample, (frame_index == 0));
- }
- current->AddCodeObjectIndex(code_index);
- return current;
}
// Tick the truncated tag's inclusive tick count.
@@ -1775,70 +1309,6 @@
function->IncInclusiveTicks();
}
- // Tag append functions are overloaded for |ProfileCodeTrieNode| and
- // |ProfileFunctionTrieNode| types.
-
- // ProfileCodeTrieNode
- ProfileCodeTrieNode* AppendUserTag(uword user_tag,
- ProfileCodeTrieNode* current,
- ProcessedSample* sample) {
- intptr_t user_tag_index = GetProfileCodeTagIndex(user_tag);
- if (user_tag_index >= 0) {
- current = current->GetChild(user_tag_index);
- current->Tick(sample);
- }
- return current;
- }
-
- ProfileCodeTrieNode* AppendTruncatedTag(ProfileCodeTrieNode* current,
- ProcessedSample* sample) {
- intptr_t truncated_tag_index =
- GetProfileCodeTagIndex(VMTag::kTruncatedTagId);
- ASSERT(truncated_tag_index >= 0);
- current = current->GetChild(truncated_tag_index);
- current->Tick(sample);
- return current;
- }
-
- ProfileCodeTrieNode* AppendVMTag(uword vm_tag,
- ProfileCodeTrieNode* current,
- ProcessedSample* sample) {
- if (VMTag::IsNativeEntryTag(vm_tag)) {
- // Insert a dummy kNativeTagId node.
- intptr_t tag_index = GetProfileCodeTagIndex(VMTag::kNativeTagId);
- current = current->GetChild(tag_index);
- // Give the tag a tick.
- current->Tick(sample);
- } else if (VMTag::IsRuntimeEntryTag(vm_tag)) {
- // Insert a dummy kRuntimeTagId node.
- intptr_t tag_index = GetProfileCodeTagIndex(VMTag::kRuntimeTagId);
- current = current->GetChild(tag_index);
- // Give the tag a tick.
- current->Tick(sample);
- } else {
- intptr_t tag_index = GetProfileCodeTagIndex(vm_tag);
- current = current->GetChild(tag_index);
- // Give the tag a tick.
- current->Tick(sample);
- }
- return current;
- }
-
- ProfileCodeTrieNode* AppendSpecificNativeRuntimeEntryVMTag(
- uword vm_tag,
- ProfileCodeTrieNode* current,
- ProcessedSample* sample) {
- // Only Native and Runtime entries have a second VM tag.
- if (!VMTag::IsNativeEntryTag(vm_tag) && !VMTag::IsRuntimeEntryTag(vm_tag)) {
- return current;
- }
- intptr_t tag_index = GetProfileCodeTagIndex(vm_tag);
- current = current->GetChild(tag_index);
- // Give the tag a tick.
- current->Tick(sample);
- return current;
- }
-
uword ProfileInfoKindToVMTag(ProfileInfoKind kind) {
switch (kind) {
case kNone:
@@ -1859,43 +1329,6 @@
}
}
- ProfileCodeTrieNode* AppendKind(ProfileInfoKind kind,
- ProfileCodeTrieNode* current,
- ProcessedSample* sample) {
- if (!TagsEnabled(ProfilerService::kCodeTransitionTagsBit)) {
- // Only emit if debug tags are requested.
- return current;
- }
- if (kind != info_kind_) {
- info_kind_ = kind;
- intptr_t tag_index = GetProfileCodeTagIndex(ProfileInfoKindToVMTag(kind));
- ASSERT(tag_index >= 0);
- current = current->GetChild(tag_index);
- current->Tick(sample);
- }
- return current;
- }
-
- ProfileCodeTrieNode* AppendKind(const AbstractCode code,
- ProfileCodeTrieNode* current,
- ProcessedSample* sample) {
- if (code.IsNull()) {
- return AppendKind(kNone, current, sample);
- } else if (code.is_optimized()) {
- return AppendKind(kOptimized, current, sample);
- } else {
- return AppendKind(kUnoptimized, current, sample);
- }
- }
-
- ProfileCodeTrieNode* AppendVMTags(uword vm_tag,
- ProfileCodeTrieNode* current,
- ProcessedSample* sample) {
- current = AppendVMTag(vm_tag, current, sample);
- current = AppendSpecificNativeRuntimeEntryVMTag(vm_tag, current, sample);
- return current;
- }
-
void TickExitFrame(uword vm_tag, intptr_t serial, ProcessedSample* sample) {
if (FLAG_profile_vm) {
return;
@@ -1924,204 +1357,6 @@
function->Tick(true, serial, TokenPosition::kNoSource);
}
- ProfileCodeTrieNode* AppendExitFrame(uword vm_tag,
- ProfileCodeTrieNode* current,
- ProcessedSample* sample) {
- if (FLAG_profile_vm) {
- return current;
- }
-
- if (!VMTag::IsExitFrameTag(vm_tag)) {
- return current;
- }
-
- if (VMTag::IsNativeEntryTag(vm_tag) || VMTag::IsRuntimeEntryTag(vm_tag)) {
- current = AppendSpecificNativeRuntimeEntryVMTag(vm_tag, current, sample);
- } else {
- intptr_t tag_index = GetProfileCodeTagIndex(vm_tag);
- current = current->GetChild(tag_index);
- // Give the tag a tick.
- current->Tick(sample);
- }
- return current;
- }
-
- ProfileCodeTrieNode* AppendTags(uword vm_tag,
- uword user_tag,
- ProfileCodeTrieNode* current,
- ProcessedSample* sample) {
- // None.
- if (tag_order() == Profile::kNoTags) {
- return current;
- }
- // User first.
- if ((tag_order() == Profile::kUserVM) || (tag_order() == Profile::kUser)) {
- current = AppendUserTag(user_tag, current, sample);
- // Only user.
- if (tag_order() == Profile::kUser) {
- return current;
- }
- return AppendVMTags(vm_tag, current, sample);
- }
- // VM first.
- ASSERT((tag_order() == Profile::kVMUser) || (tag_order() == Profile::kVM));
- current = AppendVMTags(vm_tag, current, sample);
- // Only VM.
- if (tag_order() == Profile::kVM) {
- return current;
- }
- return AppendUserTag(user_tag, current, sample);
- }
-
- // ProfileFunctionTrieNode
- void ResetKind() { info_kind_ = kNone; }
-
- ProfileFunctionTrieNode* AppendKind(ProfileInfoKind kind,
- ProfileFunctionTrieNode* current,
- ProcessedSample* sample) {
- if (!TagsEnabled(ProfilerService::kCodeTransitionTagsBit)) {
- // Only emit if debug tags are requested.
- return current;
- }
- if (kind != info_kind_) {
- info_kind_ = kind;
- intptr_t tag_index =
- GetProfileFunctionTagIndex(ProfileInfoKindToVMTag(kind));
- ASSERT(tag_index >= 0);
- current = current->GetChild(tag_index);
- current->Tick(sample);
- }
- return current;
- }
-
- ProfileFunctionTrieNode* AppendKind(const Code& code,
- ProfileFunctionTrieNode* current,
- ProcessedSample* sample) {
- if (code.IsNull()) {
- return AppendKind(kNone, current, sample);
- } else if (code.is_optimized()) {
- return AppendKind(kOptimized, current, sample);
- } else {
- return AppendKind(kUnoptimized, current, sample);
- }
- }
-
- ProfileFunctionTrieNode* AppendUserTag(uword user_tag,
- ProfileFunctionTrieNode* current,
- ProcessedSample* sample) {
- intptr_t user_tag_index = GetProfileFunctionTagIndex(user_tag);
- if (user_tag_index >= 0) {
- current = current->GetChild(user_tag_index);
- current->Tick(sample);
- }
- return current;
- }
-
- ProfileFunctionTrieNode* AppendTruncatedTag(ProfileFunctionTrieNode* current,
- ProcessedSample* sample) {
- intptr_t truncated_tag_index =
- GetProfileFunctionTagIndex(VMTag::kTruncatedTagId);
- ASSERT(truncated_tag_index >= 0);
- current = current->GetChild(truncated_tag_index);
- current->Tick(sample);
- return current;
- }
-
- ProfileFunctionTrieNode* AppendVMTag(uword vm_tag,
- ProfileFunctionTrieNode* current,
- ProcessedSample* sample) {
- if (VMTag::IsNativeEntryTag(vm_tag)) {
- // Insert a dummy kNativeTagId node.
- intptr_t tag_index = GetProfileFunctionTagIndex(VMTag::kNativeTagId);
- current = current->GetChild(tag_index);
- // Give the tag a tick.
- current->Tick(sample);
- } else if (VMTag::IsRuntimeEntryTag(vm_tag)) {
- // Insert a dummy kRuntimeTagId node.
- intptr_t tag_index = GetProfileFunctionTagIndex(VMTag::kRuntimeTagId);
- current = current->GetChild(tag_index);
- // Give the tag a tick.
- current->Tick(sample);
- } else {
- intptr_t tag_index = GetProfileFunctionTagIndex(vm_tag);
- current = current->GetChild(tag_index);
- // Give the tag a tick.
- current->Tick(sample);
- }
- return current;
- }
-
- ProfileFunctionTrieNode* AppendSpecificNativeRuntimeEntryVMTag(
- uword vm_tag,
- ProfileFunctionTrieNode* current,
- ProcessedSample* sample) {
- // Only Native and Runtime entries have a second VM tag.
- if (!VMTag::IsNativeEntryTag(vm_tag) && !VMTag::IsRuntimeEntryTag(vm_tag)) {
- return current;
- }
- intptr_t tag_index = GetProfileFunctionTagIndex(vm_tag);
- current = current->GetChild(tag_index);
- // Give the tag a tick.
- current->Tick(sample);
- return current;
- }
-
- ProfileFunctionTrieNode* AppendVMTags(uword vm_tag,
- ProfileFunctionTrieNode* current,
- ProcessedSample* sample) {
- current = AppendVMTag(vm_tag, current, sample);
- current = AppendSpecificNativeRuntimeEntryVMTag(vm_tag, current, sample);
- return current;
- }
-
- ProfileFunctionTrieNode* AppendExitFrame(uword vm_tag,
- ProfileFunctionTrieNode* current,
- ProcessedSample* sample) {
- if (FLAG_profile_vm) {
- return current;
- }
-
- if (!VMTag::IsExitFrameTag(vm_tag)) {
- return current;
- }
- if (VMTag::IsNativeEntryTag(vm_tag) || VMTag::IsRuntimeEntryTag(vm_tag)) {
- current = AppendSpecificNativeRuntimeEntryVMTag(vm_tag, current, sample);
- } else {
- intptr_t tag_index = GetProfileFunctionTagIndex(vm_tag);
- current = current->GetChild(tag_index);
- // Give the tag a tick.
- current->Tick(sample);
- }
- return current;
- }
-
- ProfileFunctionTrieNode* AppendTags(uword vm_tag,
- uword user_tag,
- ProfileFunctionTrieNode* current,
- ProcessedSample* sample) {
- // None.
- if (tag_order() == Profile::kNoTags) {
- return current;
- }
- // User first.
- if ((tag_order() == Profile::kUserVM) || (tag_order() == Profile::kUser)) {
- current = AppendUserTag(user_tag, current, sample);
- // Only user.
- if (tag_order() == Profile::kUser) {
- return current;
- }
- return AppendVMTags(vm_tag, current, sample);
- }
- // VM first.
- ASSERT((tag_order() == Profile::kVMUser) || (tag_order() == Profile::kVM));
- current = AppendVMTags(vm_tag, current, sample);
- // Only VM.
- if (tag_order() == Profile::kVM) {
- return current;
- }
- return AppendUserTag(user_tag, current, sample);
- }
-
intptr_t GetProfileCodeTagIndex(uword tag) {
ProfileCodeTable* tag_table = profile_->tag_code_;
intptr_t index = tag_table->FindCodeIndexForPC(tag);
@@ -2147,30 +1382,7 @@
}
ProfileCode* GetProfileCode(uword pc, int64_t timestamp) {
- ProfileCodeTable* live_table = profile_->live_code_;
- ProfileCodeTable* dead_table = profile_->dead_code_;
-
- intptr_t index = live_table->FindCodeIndexForPC(pc);
- ProfileCode* code = NULL;
- if (index < 0) {
- index = dead_table->FindCodeIndexForPC(pc);
- ASSERT(index >= 0);
- code = dead_table->At(index);
- } else {
- code = live_table->At(index);
- ASSERT(code != NULL);
- if (code->compile_timestamp() > timestamp) {
- // Code is newer than sample. Fall back to dead code table.
- index = dead_table->FindCodeIndexForPC(pc);
- ASSERT(index >= 0);
- code = dead_table->At(index);
- }
- }
-
- ASSERT(code != NULL);
- ASSERT(code->Contains(pc));
- ASSERT(code->compile_timestamp() <= timestamp);
- return code;
+ return profile_->GetCodeFromPC(pc, timestamp);
}
void RegisterProfileCodeTag(uword tag) {
@@ -2292,28 +1504,14 @@
return FindOrRegisterDeadProfileCode(pc);
}
- Profile::TagOrder tag_order() const { return tag_order_; }
-
- bool vm_tags_emitted() const {
- return (tag_order_ == Profile::kUserVM) ||
- (tag_order_ == Profile::kVMUser) || (tag_order_ == Profile::kVM);
- }
-
- bool TagsEnabled(intptr_t extra_tags_bits) const {
- return (extra_tags_ & extra_tags_bits) != 0;
- }
-
Thread* thread_;
Isolate* vm_isolate_;
SampleFilter* filter_;
SampleBuffer* sample_buffer_;
- Profile::TagOrder tag_order_;
- intptr_t extra_tags_;
Profile* profile_;
DeoptimizedCodeSet* deoptimized_code_;
const AbstractCode null_code_;
const Function& null_function_;
- bool tick_functions_;
bool inclusive_tree_;
ProfileCodeInlinedFunctionsCache inlined_functions_cache_;
ProcessedSampleBuffer* samples_;
@@ -2333,21 +1531,21 @@
min_time_(kMaxInt64),
max_time_(0) {
ASSERT(isolate_ != NULL);
- for (intptr_t i = 0; i < kNumTrieKinds; i++) {
- roots_[i] = NULL;
- }
}
void Profile::Build(Thread* thread,
SampleFilter* filter,
- SampleBuffer* sample_buffer,
- TagOrder tag_order,
- intptr_t extra_tags) {
- ProfileBuilder builder(thread, filter, sample_buffer, tag_order, extra_tags,
- this);
+ SampleBuffer* sample_buffer) {
+ ProfileBuilder builder(thread, filter, sample_buffer, this);
builder.Build();
}
+ProcessedSample* Profile::SampleAt(intptr_t index) {
+ ASSERT(index >= 0);
+ ASSERT(index < sample_count_);
+ return samples_->At(index);
+}
+
intptr_t Profile::NumFunctions() const {
return functions_->length();
}
@@ -2382,21 +1580,44 @@
return tag_code_->At(index);
}
-ProfileTrieNode* Profile::GetTrieRoot(TrieKind trie_kind) {
- return roots_[static_cast<intptr_t>(trie_kind)];
+ProfileCode* Profile::GetCodeFromPC(uword pc, int64_t timestamp) {
+ intptr_t index = live_code_->FindCodeIndexForPC(pc);
+ ProfileCode* code = NULL;
+ if (index < 0) {
+ index = dead_code_->FindCodeIndexForPC(pc);
+ ASSERT(index >= 0);
+ code = dead_code_->At(index);
+ } else {
+ code = live_code_->At(index);
+ ASSERT(code != NULL);
+ if (code->compile_timestamp() > timestamp) {
+ // Code is newer than sample. Fall back to dead code table.
+ index = dead_code_->FindCodeIndexForPC(pc);
+ ASSERT(index >= 0);
+ code = dead_code_->At(index);
+ }
+ }
+
+ ASSERT(code != NULL);
+ ASSERT(code->Contains(pc));
+ ASSERT(code->compile_timestamp() <= timestamp);
+ return code;
}
void Profile::PrintHeaderJSON(JSONObject* obj) {
+ intptr_t pid = OS::ProcessId();
+
obj->AddProperty("samplePeriod", static_cast<intptr_t>(FLAG_profile_period));
- obj->AddProperty("stackDepth", static_cast<intptr_t>(FLAG_max_profile_depth));
+ obj->AddProperty("maxStackDepth",
+ static_cast<intptr_t>(FLAG_max_profile_depth));
obj->AddProperty("sampleCount", sample_count());
- obj->AddProperty("timeSpan", MicrosecondsToSeconds(GetTimeSpan()));
+ obj->AddProperty("timespan", MicrosecondsToSeconds(GetTimeSpan()));
obj->AddPropertyTimeMicros("timeOriginMicros", min_time());
obj->AddPropertyTimeMicros("timeExtentMicros", GetTimeSpan());
-
+ obj->AddProperty64("pid", pid);
ProfilerCounters counters = Profiler::counters();
{
- JSONObject counts(obj, "counters");
+ JSONObject counts(obj, "_counters");
counts.AddProperty64("bail_out_unknown_task",
counters.bail_out_unknown_task);
counts.AddProperty64("bail_out_jump_to_exception_handler",
@@ -2418,154 +1639,144 @@
}
}
-static const intptr_t kRootFrameId = 0;
+void Profile::ProcessSampleFrameJSON(JSONArray* stack,
+ ProfileCodeInlinedFunctionsCache* cache_,
+ ProcessedSample* sample,
+ intptr_t frame_index) {
+ const uword pc = sample->At(frame_index);
+ ProfileCode* profile_code = GetCodeFromPC(pc, sample->timestamp());
+ ASSERT(profile_code != NULL);
+ ProfileFunction* function = profile_code->function();
+ ASSERT(function != NULL);
-void Profile::PrintTimelineFrameJSON(JSONObject* frames,
- ProfileTrieNode* current,
- ProfileTrieNode* parent,
- intptr_t* next_id,
- bool code_trie) {
- ASSERT(current->frame_id() == -1);
- const intptr_t id = *next_id;
- *next_id = id + 1;
- current->set_frame_id(id);
- ASSERT(current->frame_id() != -1);
-
- if (id != kRootFrameId) {
- // The samples from many isolates may be merged into a single timeline,
- // so prefix frames id with the isolate.
- intptr_t isolate_id = reinterpret_cast<intptr_t>(isolate_);
- const char* key =
- zone_->PrintToString("%" Pd "-%" Pd, isolate_id, current->frame_id());
- JSONObject frame(frames, key);
- frame.AddProperty("category", "Dart");
- if (code_trie) {
- ProfileCode* code = GetCode(current->table_index());
- frame.AddProperty("name", code->name());
- const char* resolved_script_url = NULL;
- if (code->function() != NULL) {
- resolved_script_url = code->function()->ResolvedScriptUrl();
- }
- frame.AddProperty("resolvedUrl", resolved_script_url);
- } else {
- ProfileFunction* func = GetFunction(current->table_index());
- frame.AddProperty("name", func->Name());
- frame.AddProperty("resolvedUrl", func->ResolvedScriptUrl());
- }
- if ((parent != NULL) && (parent->frame_id() != kRootFrameId)) {
- ASSERT(parent->frame_id() != -1);
- frame.AddPropertyF("parent", "%" Pd "-%" Pd, isolate_id,
- parent->frame_id());
- }
- }
-
- for (intptr_t i = 0; i < current->NumChildren(); i++) {
- ProfileTrieNode* child = current->At(i);
- PrintTimelineFrameJSON(frames, child, current, next_id, code_trie);
- }
-}
-
-void Profile::PrintTimelineJSON(JSONStream* stream, bool code_trie) {
- ScopeTimer sw("Profile::PrintTimelineJSON", FLAG_trace_profiler);
- JSONObject obj(stream);
- obj.AddProperty("type", "_CpuProfileTimeline");
- PrintHeaderJSON(&obj);
- {
- JSONObject frames(&obj, "stackFrames");
- ProfileTrieNode* root;
- if (code_trie) {
- root = GetTrieRoot(kInclusiveCode);
- } else {
- root = GetTrieRoot(kInclusiveFunction);
- }
- intptr_t next_id = kRootFrameId;
- PrintTimelineFrameJSON(&frames, root, NULL, &next_id, code_trie);
- }
- {
- JSONArray events(&obj, "traceEvents");
- intptr_t pid = OS::ProcessId();
- intptr_t isolate_id = reinterpret_cast<intptr_t>(isolate_);
- for (intptr_t sample_index = 0; sample_index < samples_->length();
- sample_index++) {
- ProcessedSample* sample = samples_->At(sample_index);
- ProfileTrieNode* trie;
- if (code_trie) {
- trie = sample->timeline_code_trie();
- } else {
- trie = sample->timeline_function_trie();
- }
- ASSERT(trie->frame_id() != -1);
-
- if (trie->frame_id() != kRootFrameId) {
- JSONObject event(&events);
- event.AddProperty("ph", "P"); // kind = sample event
- // Add a blank name to keep about:tracing happy.
- event.AddProperty("name", "");
- event.AddProperty64("pid", pid);
- event.AddProperty64("tid", OSThread::ThreadIdToIntPtr(sample->tid()));
- event.AddPropertyTimeMicros("ts", sample->timestamp());
- event.AddProperty("cat", "Dart");
- if (!Isolate::IsVMInternalIsolate(isolate_)) {
- JSONObject args(&event, "args");
- args.AddProperty("mode", "basic");
- }
- event.AddPropertyF("sf", "%" Pd "-%" Pd, isolate_id, trie->frame_id());
- }
- }
- }
-}
-
-void Profile::AddParentTriePointers(ProfileTrieNode* current,
- ProfileTrieNode* parent,
- bool code_trie) {
- if (current == NULL) {
- ProfileTrieNode* root;
- if (code_trie) {
- root = GetTrieRoot(kInclusiveCode);
- } else {
- root = GetTrieRoot(kInclusiveFunction);
- }
- AddParentTriePointers(root, NULL, code_trie);
+ // Don't show stubs in stack traces.
+ if (!function->is_visible() ||
+ (function->kind() == ProfileFunction::kStubFunction)) {
return;
}
- current->set_parent(parent);
- for (int i = 0; i < current->NumChildren(); i++) {
- AddParentTriePointers(current->At(i), current, code_trie);
- }
-}
+ GrowableArray<const Function*>* inlined_functions = NULL;
+ GrowableArray<TokenPosition>* inlined_token_positions = NULL;
+ TokenPosition token_position = TokenPosition::kNoSource;
+ Code& code = Code::ZoneHandle();
-void Profile::PrintBacktrace(ProfileTrieNode* node, TextBuffer* buf) {
- ProfileTrieNode* current = node;
- while (current != NULL) {
- buf->AddString(current->ToCString(this));
- buf->AddString("\n");
- current = current->parent();
+ if (profile_code->code().IsCode()) {
+ code ^= profile_code->code().raw();
+ cache_->Get(pc, code, sample, frame_index, &inlined_functions,
+ &inlined_token_positions, &token_position);
+ if (FLAG_trace_profiler_verbose && (inlined_functions != NULL)) {
+ for (intptr_t i = 0; i < inlined_functions->length(); i++) {
+ const String& name =
+ String::Handle((*inlined_functions)[i]->QualifiedScrubbedName());
+ THR_Print("InlinedFunction[%" Pd "] = {%s, %s}\n", i, name.ToCString(),
+ (*inlined_token_positions)[i].ToCString());
+ }
+ }
+ } else if (profile_code->code().IsBytecode()) {
+ // No inlining in bytecode.
+ const Bytecode& bc = Bytecode::CheckedHandle(Thread::Current()->zone(),
+ profile_code->code().raw());
+ token_position = bc.GetTokenIndexOfPC(pc);
}
-}
-void Profile::AddToTimeline(bool code_trie) {
- TimelineStream* stream = Timeline::GetProfilerStream();
- if (stream == NULL) {
+ if (code.IsNull() || (inlined_functions == NULL) ||
+ (inlined_functions->length() <= 1)) {
+ PrintFunctionFrameIndexJSON(stack, function);
return;
}
- AddParentTriePointers(NULL, NULL, code_trie);
+
+ if (!code.is_optimized()) {
+ OS::PrintErr("Code that should be optimized is not. Please file a bug\n");
+ OS::PrintErr("Code object: %s\n", code.ToCString());
+ OS::PrintErr("Inlined functions length: %" Pd "\n",
+ inlined_functions->length());
+ for (intptr_t i = 0; i < inlined_functions->length(); i++) {
+ OS::PrintErr("IF[%" Pd "] = %s\n", i,
+ (*inlined_functions)[i]->ToFullyQualifiedCString());
+ }
+ }
+
+ ASSERT(code.is_optimized());
+
+ for (intptr_t i = inlined_functions->length() - 1; i >= 0; i--) {
+ const Function* inlined_function = (*inlined_functions)[i];
+ ASSERT(inlined_function != NULL);
+ ASSERT(!inlined_function->IsNull());
+ ProcessInlinedFunctionFrameJSON(stack, inlined_function);
+ }
+}
+
+void Profile::ProcessInlinedFunctionFrameJSON(
+ JSONArray* stack,
+ const Function* inlined_function) {
+ ProfileFunction* function = functions_->LookupOrAdd(*inlined_function);
+ ASSERT(function != NULL);
+ PrintFunctionFrameIndexJSON(stack, function);
+}
+
+void Profile::PrintFunctionFrameIndexJSON(JSONArray* stack,
+ ProfileFunction* function) {
+ stack->AddValue64(function->table_index());
+}
+
+void Profile::PrintCodeFrameIndexJSON(JSONArray* stack,
+ ProcessedSample* sample,
+ intptr_t frame_index) {
+ ProfileCode* code =
+ GetCodeFromPC(sample->At(frame_index), sample->timestamp());
+ const AbstractCode codeObj = code->code();
+
+ // Ignore stub code objects.
+ if (codeObj.IsStubCode() || codeObj.IsAllocationStubCode() ||
+ codeObj.IsTypeTestStubCode()) {
+ return;
+ }
+ stack->AddValue64(code->code_table_index());
+}
+
+void Profile::PrintSamplesJSON(JSONObject* obj, bool code_samples) {
+ JSONArray samples(obj, "samples");
+ ProfileCodeInlinedFunctionsCache cache;
for (intptr_t sample_index = 0; sample_index < samples_->length();
sample_index++) {
- TextBuffer buf(256);
+ JSONObject sample_obj(&samples);
ProcessedSample* sample = samples_->At(sample_index);
- if (code_trie) {
- PrintBacktrace(sample->timeline_code_trie(), &buf);
- } else {
- PrintBacktrace(sample->timeline_function_trie(), &buf);
+ sample_obj.AddProperty64("tid", OSThread::ThreadIdToIntPtr(sample->tid()));
+ sample_obj.AddPropertyTimeMicros("timestamp", sample->timestamp());
+ sample_obj.AddProperty("vmTag", VMTag::TagName(sample->vm_tag()));
+ if (VMTag::IsNativeEntryTag(sample->vm_tag())) {
+ sample_obj.AddProperty("nativeEntryTag", true);
}
- TimelineEvent* event = stream->StartEvent();
- event->Instant("Dart CPU sample", sample->timestamp());
- event->set_owns_label(false);
- event->SetNumArguments(1);
- event->SetArgument(0, "backtrace", buf.Steal());
- event->Complete();
- event = NULL; // Complete() deletes the event.
+ if (VMTag::IsRuntimeEntryTag(sample->vm_tag())) {
+ sample_obj.AddProperty("runtimeEntryTag", true);
+ }
+ if (UserTags::IsUserTag(sample->user_tag())) {
+ sample_obj.AddProperty("userTag", UserTags::TagName(sample->user_tag()));
+ }
+ if (sample->truncated()) {
+ sample_obj.AddProperty("truncated", true);
+ }
+ if (sample->is_native_allocation_sample()) {
+ sample_obj.AddProperty64("_nativeAllocationSizeBytes",
+ sample->native_allocation_size_bytes());
+ }
+ {
+ JSONArray stack(&sample_obj, "stack");
+ // Walk the sampled PCs.
+ for (intptr_t frame_index = 0; frame_index < sample->length();
+ frame_index++) {
+ ASSERT(sample->At(frame_index) != 0);
+ ProcessSampleFrameJSON(&stack, &cache, sample, frame_index);
+ }
+ }
+ if (code_samples) {
+ JSONArray stack(&sample_obj, "_codeStack");
+ for (intptr_t frame_index = 0; frame_index < sample->length();
+ frame_index++) {
+ ASSERT(sample->At(frame_index) != 0);
+ PrintCodeFrameIndexJSON(&stack, sample, frame_index);
+ }
+ }
}
}
@@ -2573,13 +1784,13 @@
return (functions_ != NULL) ? functions_->Lookup(function) : NULL;
}
-void Profile::PrintProfileJSON(JSONStream* stream) {
+void Profile::PrintProfileJSON(JSONStream* stream, bool include_code_samples) {
ScopeTimer sw("Profile::PrintProfileJSON", FLAG_trace_profiler);
JSONObject obj(stream);
- obj.AddProperty("type", "_CpuProfile");
+ obj.AddProperty("type", "CpuSamples");
PrintHeaderJSON(&obj);
- {
- JSONArray codes(&obj, "codes");
+ if (include_code_samples) {
+ JSONArray codes(&obj, "_codes");
for (intptr_t i = 0; i < live_code_->length(); i++) {
ProfileCode* code = live_code_->At(i);
ASSERT(code != NULL);
@@ -2605,217 +1816,26 @@
function->PrintToJSONArray(&functions);
}
}
- {
- JSONArray code_trie(&obj, "exclusiveCodeTrie");
- ProfileTrieNode* root = roots_[static_cast<intptr_t>(kExclusiveCode)];
- ASSERT(root != NULL);
- root->PrintToJSONArray(&code_trie);
- }
- {
- JSONArray code_trie(&obj, "inclusiveCodeTrie");
- ProfileTrieNode* root = roots_[static_cast<intptr_t>(kInclusiveCode)];
- ASSERT(root != NULL);
- root->PrintToJSONArray(&code_trie);
- }
- {
- JSONArray function_trie(&obj, "exclusiveFunctionTrie");
- ProfileTrieNode* root = roots_[static_cast<intptr_t>(kExclusiveFunction)];
- ASSERT(root != NULL);
- root->PrintToJSONArray(&function_trie);
- }
- {
- JSONArray function_trie(&obj, "inclusiveFunctionTrie");
- ProfileTrieNode* root = roots_[static_cast<intptr_t>(kInclusiveFunction)];
- ASSERT(root != NULL);
- root->PrintToJSONArray(&function_trie);
- }
- {
- ProfilerCounters counters = Profiler::counters();
- JSONObject js_counters(&obj, "counters");
-#define ADD_PROFILER_COUNTER(name) \
- js_counters.AddProperty64("" #name, counters.name);
-PROFILER_COUNTERS(ADD_PROFILER_COUNTER)
-#undef ADD_PROFILER_COUNTER
- }
-}
-
-void ProfileTrieWalker::Reset(Profile::TrieKind trie_kind) {
- code_trie_ = Profile::IsCodeTrie(trie_kind);
- parent_ = NULL;
- current_ = profile_->GetTrieRoot(trie_kind);
- ASSERT(current_ != NULL);
-}
-
-const char* ProfileTrieWalker::CurrentName() {
- if (current_ == NULL) {
- return NULL;
- }
- if (code_trie_) {
- ProfileCode* code = profile_->GetCode(current_->table_index());
- return code->name();
- } else {
- ProfileFunction* func = profile_->GetFunction(current_->table_index());
- return func->Name();
- }
- UNREACHABLE();
- return NULL;
-}
-
-intptr_t ProfileTrieWalker::CurrentNodeTickCount() {
- if (current_ == NULL) {
- return -1;
- }
- return current_->count();
-}
-
-intptr_t ProfileTrieWalker::CurrentInclusiveTicks() {
- if (current_ == NULL) {
- return -1;
- }
- if (code_trie_) {
- ProfileCode* code = profile_->GetCode(current_->table_index());
- return code->inclusive_ticks();
- } else {
- ProfileFunction* func = profile_->GetFunction(current_->table_index());
- return func->inclusive_ticks();
- }
- UNREACHABLE();
- return -1;
-}
-
-intptr_t ProfileTrieWalker::CurrentExclusiveTicks() {
- if (current_ == NULL) {
- return -1;
- }
- if (code_trie_) {
- ProfileCode* code = profile_->GetCode(current_->table_index());
- return code->exclusive_ticks();
- } else {
- ProfileFunction* func = profile_->GetFunction(current_->table_index());
- return func->exclusive_ticks();
- }
- UNREACHABLE();
- return -1;
-}
-
-intptr_t ProfileTrieWalker::CurrentInclusiveAllocations() {
- if (current_ == NULL) {
- return -1;
- }
- return current_->inclusive_allocations();
-}
-
-intptr_t ProfileTrieWalker::CurrentExclusiveAllocations() {
- if (current_ == NULL) {
- return -1;
- }
- return current_->exclusive_allocations();
-}
-
-const char* ProfileTrieWalker::CurrentToken() {
- if (current_ == NULL) {
- return NULL;
- }
- if (code_trie_) {
- return NULL;
- }
- ProfileFunction* func = profile_->GetFunction(current_->table_index());
- const Function& function = *(func->function());
- if (function.IsNull()) {
- // No function.
- return NULL;
- }
- Zone* zone = Thread::Current()->zone();
- const Script& script = Script::Handle(zone, function.script());
- if (script.IsNull()) {
- // No script.
- return NULL;
- }
- ProfileFunctionSourcePosition pfsp(TokenPosition::kNoSource);
- if (!func->GetSinglePosition(&pfsp)) {
- // Not exactly one source position.
- return NULL;
- }
- TokenPosition token_pos = pfsp.token_pos();
- if (!token_pos.IsSourcePosition()) {
- // Not a location in a script.
- return NULL;
- }
- if (token_pos.IsSynthetic()) {
- token_pos = token_pos.FromSynthetic();
- }
-
- String& str = String::Handle(zone);
- if (script.kind() == RawScript::kKernelTag) {
- intptr_t line = 0, column = 0, token_len = 0;
- script.GetTokenLocation(token_pos, &line, &column, &token_len);
- str = script.GetSnippet(line, column, line, column + token_len);
- } else {
- UNREACHABLE();
- }
- return str.IsNull() ? NULL : str.ToCString();
-}
-
-bool ProfileTrieWalker::Down() {
- if ((current_ == NULL) || (current_->NumChildren() == 0)) {
- return false;
- }
- parent_ = current_;
- current_ = current_->At(0);
- return true;
-}
-
-bool ProfileTrieWalker::NextSibling() {
- if (parent_ == NULL) {
- return false;
- }
- intptr_t current_index = parent_->IndexOf(current_);
- if (current_index < 0) {
- return false;
- }
- current_index++;
- if (current_index >= parent_->NumChildren()) {
- return false;
- }
- current_ = parent_->At(current_index);
- return true;
-}
-
-intptr_t ProfileTrieWalker::SiblingCount() {
- ASSERT(parent_ != NULL);
- return parent_->NumChildren();
+ PrintSamplesJSON(&obj, include_code_samples);
}
void ProfilerService::PrintJSONImpl(Thread* thread,
JSONStream* stream,
- Profile::TagOrder tag_order,
- intptr_t extra_tags,
SampleFilter* filter,
SampleBuffer* sample_buffer,
- PrintKind kind,
- bool code_trie) {
+ bool include_code_samples) {
Isolate* isolate = thread->isolate();
// Disable thread interrupts while processing the buffer.
DisableThreadInterruptsScope dtis(thread);
- if (sample_buffer == NULL) {
- stream->PrintError(kFeatureDisabled, NULL);
- return;
- }
+ // We should bail out in service.cc if the profiler is disabled.
+ ASSERT(sample_buffer != NULL);
- {
- StackZone zone(thread);
- HANDLESCOPE(thread);
- Profile profile(isolate);
- profile.Build(thread, filter, sample_buffer, tag_order, extra_tags);
- if (kind == kAsTimeline) {
- profile.PrintTimelineJSON(stream, code_trie);
- } else if (kind == kAsProfile) {
- profile.PrintProfileJSON(stream);
- } else if (kind == kAsPlatformTimeline) {
- profile.AddToTimeline(code_trie);
- }
- }
+ StackZone zone(thread);
+ HANDLESCOPE(thread);
+ Profile profile(isolate);
+ profile.Build(thread, filter, sample_buffer);
+ profile.PrintProfileJSON(stream, include_code_samples);
}
class NoAllocationSampleFilter : public SampleFilter {
@@ -2833,17 +1853,15 @@
};
void ProfilerService::PrintJSON(JSONStream* stream,
- Profile::TagOrder tag_order,
- intptr_t extra_tags,
int64_t time_origin_micros,
- int64_t time_extent_micros) {
+ int64_t time_extent_micros,
+ bool include_code_samples) {
Thread* thread = Thread::Current();
Isolate* isolate = thread->isolate();
NoAllocationSampleFilter filter(isolate->main_port(), Thread::kMutatorTask,
time_origin_micros, time_extent_micros);
- bool code_trie = false; // Doesn't matter for kAsProfile.
- PrintJSONImpl(thread, stream, tag_order, extra_tags, &filter,
- Profiler::sample_buffer(), kAsProfile, code_trie);
+ PrintJSONImpl(thread, stream, &filter, Profiler::sample_buffer(),
+ include_code_samples);
}
class ClassAllocationSampleFilter : public SampleFilter {
@@ -2871,7 +1889,6 @@
};
void ProfilerService::PrintAllocationJSON(JSONStream* stream,
- Profile::TagOrder tag_order,
const Class& cls,
int64_t time_origin_micros,
int64_t time_extent_micros) {
@@ -2880,52 +1897,17 @@
ClassAllocationSampleFilter filter(isolate->main_port(), cls,
Thread::kMutatorTask, time_origin_micros,
time_extent_micros);
- bool code_trie = false; // Doesn't matter for kAsProfile.
- PrintJSONImpl(thread, stream, tag_order, kNoExtraTags, &filter,
- Profiler::sample_buffer(), kAsProfile, code_trie);
+ PrintJSONImpl(thread, stream, &filter, Profiler::sample_buffer(), true);
}
void ProfilerService::PrintNativeAllocationJSON(JSONStream* stream,
- Profile::TagOrder tag_order,
int64_t time_origin_micros,
- int64_t time_extent_micros) {
+ int64_t time_extent_micros,
+ bool include_code_samples) {
Thread* thread = Thread::Current();
NativeAllocationSampleFilter filter(time_origin_micros, time_extent_micros);
- bool code_trie = false; // Doesn't matter for kAsProfile.
- PrintJSONImpl(thread, stream, tag_order, kNoExtraTags, &filter,
- Profiler::allocation_sample_buffer(), kAsProfile, code_trie);
-}
-
-void ProfilerService::PrintTimelineJSON(JSONStream* stream,
- Profile::TagOrder tag_order,
- int64_t time_origin_micros,
- int64_t time_extent_micros,
- bool code_trie) {
- Thread* thread = Thread::Current();
- Isolate* isolate = thread->isolate();
- const intptr_t thread_task_mask = Thread::kMutatorTask |
- Thread::kCompilerTask |
- Thread::kSweeperTask | Thread::kMarkerTask;
- NoAllocationSampleFilter filter(isolate->main_port(), thread_task_mask,
- time_origin_micros, time_extent_micros);
- PrintJSONImpl(thread, stream, tag_order, kNoExtraTags, &filter,
- Profiler::sample_buffer(), kAsTimeline, code_trie);
-}
-
-void ProfilerService::AddToTimeline(Profile::TagOrder tag_order,
- int64_t time_origin_micros,
- int64_t time_extent_micros,
- bool code_trie) {
- JSONStream stream;
- Thread* thread = Thread::Current();
- Isolate* isolate = thread->isolate();
- const intptr_t thread_task_mask = Thread::kMutatorTask |
- Thread::kCompilerTask |
- Thread::kSweeperTask | Thread::kMarkerTask;
- NoAllocationSampleFilter filter(isolate->main_port(), thread_task_mask,
- time_origin_micros, time_extent_micros);
- PrintJSONImpl(thread, &stream, Profile::kNoTags, kNoExtraTags, &filter,
- Profiler::sample_buffer(), kAsPlatformTimeline, code_trie);
+ PrintJSONImpl(thread, stream, &filter, Profiler::allocation_sample_buffer(),
+ include_code_samples);
}
void ProfilerService::ClearSamples() {
diff --git a/runtime/vm/profiler_service.h b/runtime/vm/profiler_service.h
index 9328800..8460af8 100644
--- a/runtime/vm/profiler_service.h
+++ b/runtime/vm/profiler_service.h
@@ -53,6 +53,81 @@
DISALLOW_ALLOCATION();
};
+class ProfileCodeInlinedFunctionsCache : public ValueObject {
+ public:
+ ProfileCodeInlinedFunctionsCache() : cache_cursor_(0), last_hit_(0) {
+ for (intptr_t i = 0; i < kCacheSize; i++) {
+ cache_[i].Reset();
+ }
+ cache_hit_ = 0;
+ cache_miss_ = 0;
+ }
+
+ ~ProfileCodeInlinedFunctionsCache() {
+ if (FLAG_trace_profiler) {
+ intptr_t total = cache_hit_ + cache_miss_;
+ OS::PrintErr("LOOKUPS: %" Pd " HITS: %" Pd " MISSES: %" Pd "\n", total,
+ cache_hit_, cache_miss_);
+ }
+ }
+
+ void Get(uword pc,
+ const Code& code,
+ ProcessedSample* sample,
+ intptr_t frame_index,
+ // Outputs:
+ GrowableArray<const Function*>** inlined_functions,
+ GrowableArray<TokenPosition>** inlined_token_positions,
+ TokenPosition* token_position);
+
+ private:
+ bool FindInCache(uword pc,
+ intptr_t offset,
+ GrowableArray<const Function*>** inlined_functions,
+ GrowableArray<TokenPosition>** inlined_token_positions,
+ TokenPosition* token_position);
+
+ // Add to cache and fill in outputs.
+ void Add(uword pc,
+ const Code& code,
+ ProcessedSample* sample,
+ intptr_t frame_index,
+ // Outputs:
+ GrowableArray<const Function*>** inlined_functions,
+ GrowableArray<TokenPosition>** inlined_token_positions,
+ TokenPosition* token_position);
+
+ intptr_t NextFreeIndex() {
+ cache_cursor_ = (cache_cursor_ + 1) % kCacheSize;
+ return cache_cursor_;
+ }
+
+ intptr_t OffsetForPC(uword pc,
+ const Code& code,
+ ProcessedSample* sample,
+ intptr_t frame_index);
+ struct CacheEntry {
+ void Reset() {
+ pc = 0;
+ offset = 0;
+ inlined_functions.Clear();
+ inlined_token_positions.Clear();
+ }
+ uword pc;
+ intptr_t offset;
+ GrowableArray<const Function*> inlined_functions;
+ GrowableArray<TokenPosition> inlined_token_positions;
+ TokenPosition token_position;
+ };
+
+ static const intptr_t kCacheSize = 128;
+ intptr_t cache_cursor_;
+ intptr_t last_hit_;
+ CacheEntry cache_[kCacheSize];
+ intptr_t cache_miss_;
+ intptr_t cache_hit_;
+};
+
// Profile data related to a |Function|.
class ProfileFunction : public ZoneAllocated {
public:
@@ -213,6 +288,8 @@
ProfileFunction* function() const { return function_; }
+ intptr_t code_table_index() const { return code_table_index_; }
+
private:
void Tick(uword pc, bool exclusive, intptr_t serial);
void TickAddress(uword pc, bool exclusive);
@@ -225,7 +302,6 @@
void PrintTagCode(JSONObject* profile_code_obj);
void set_code_table_index(intptr_t index) { code_table_index_ = index; }
- intptr_t code_table_index() const { return code_table_index_; }
const Kind kind_;
uword start_;
@@ -285,137 +361,46 @@
ZoneGrowableArray<ProfileCode*> table_;
};
-// Stack traces are organized in a trie. This holds information about one node
-// in the trie. A node in a tree represents a stack frame and a path in the tree
-// represents a stack trace. Each unique stack trace appears in the tree once
-// and each node has a count indicating how many times this has been observed.
-// The index can be used to look up a |ProfileFunction| or |ProfileCode|.
-// A node can have zero or more children. Depending on the kind of trie the
-// children are callers or callees of the current node.
-class ProfileTrieNode : public ZoneAllocated {
- public:
- explicit ProfileTrieNode(intptr_t index);
- virtual ~ProfileTrieNode();
-
- virtual void PrintToJSONArray(JSONArray* array) const = 0;
-
- virtual const char* ToCString(Profile* profile) const = 0;
-
- // Index into function or code tables.
- intptr_t table_index() const { return table_index_; }
-
- intptr_t count() const { return count_; }
-
- void Tick(ProcessedSample* sample, bool exclusive = false);
-
- void IncrementAllocation(intptr_t allocation, bool exclusive) {
- ASSERT(allocation >= 0);
- if (exclusive) {
- exclusive_allocations_ += allocation;
- }
- inclusive_allocations_ += allocation;
- }
-
- intptr_t inclusive_allocations() const { return inclusive_allocations_; }
- intptr_t exclusive_allocations() const { return exclusive_allocations_; }
-
- intptr_t NumChildren() const { return children_.length(); }
-
- ProfileTrieNode* At(intptr_t i) { return children_.At(i); }
-
- ProfileTrieNode* parent() const { return parent_; }
- void set_parent(ProfileTrieNode* p) { parent_ = p; }
-
- intptr_t IndexOf(ProfileTrieNode* node);
-
- intptr_t frame_id() const { return frame_id_; }
- void set_frame_id(intptr_t id) {
- ASSERT(frame_id_ == -1);
- frame_id_ = id;
- }
-
- protected:
- void SortChildren();
-
- static int ProfileTrieNodeCompare(ProfileTrieNode* const* a,
- ProfileTrieNode* const* b) {
- ASSERT(a != NULL);
- ASSERT(b != NULL);
- return (*b)->count() - (*a)->count();
- }
-
- intptr_t table_index_;
- intptr_t count_;
- intptr_t exclusive_allocations_;
- intptr_t inclusive_allocations_;
- ZoneGrowableArray<ProfileTrieNode*> children_;
- ProfileTrieNode* parent_;
- intptr_t frame_id_;
-
- friend class ProfileBuilder;
-};
// The model for a profile. Most of the model is zone allocated, therefore
// a zone must be created that lives longer than this object.
class Profile : public ValueObject {
public:
- enum TagOrder { kNoTags, kUser, kUserVM, kVM, kVMUser };
-
- enum TrieKind {
- kExclusiveCode,
- kExclusiveFunction,
- kInclusiveCode,
- kInclusiveFunction,
- kNumTrieKinds,
- };
-
- static bool IsCodeTrie(TrieKind kind) {
- return (kind == kExclusiveCode) || (kind == kInclusiveCode);
- }
-
- static bool IsFunctionTrie(TrieKind kind) { return !IsCodeTrie(kind); }
-
explicit Profile(Isolate* isolate);
- // Build a filtered model using |filter| with the specified |tag_order|.
- void Build(Thread* thread,
- SampleFilter* filter,
- SampleBuffer* sample_buffer,
- TagOrder tag_order,
- intptr_t extra_tags = 0);
+ // Build a filtered model using |filter|.
+ void Build(Thread* thread, SampleFilter* filter, SampleBuffer* sample_buffer);
// After building:
int64_t min_time() const { return min_time_; }
int64_t max_time() const { return max_time_; }
int64_t GetTimeSpan() const { return max_time() - min_time(); }
intptr_t sample_count() const { return sample_count_; }
+ ProcessedSample* SampleAt(intptr_t index);
intptr_t NumFunctions() const;
ProfileFunction* GetFunction(intptr_t index);
ProfileCode* GetCode(intptr_t index);
- ProfileTrieNode* GetTrieRoot(TrieKind trie_kind);
+ ProfileCode* GetCodeFromPC(uword pc, int64_t timestamp);
- void PrintProfileJSON(JSONStream* stream);
- void PrintTimelineJSON(JSONStream* stream, bool code_trie);
-
- // Serializes sample backtraces into arguments on Instant events and adds them
- // directly to the timeline.
- void AddToTimeline(bool code_trie);
+ void PrintProfileJSON(JSONStream* stream, bool include_code_samples);
ProfileFunction* FindFunction(const Function& function);
private:
- void AddParentTriePointers(ProfileTrieNode* current,
- ProfileTrieNode* parent,
- bool code_trie);
- void PrintBacktrace(ProfileTrieNode* node, TextBuffer* buf);
void PrintHeaderJSON(JSONObject* obj);
- void PrintTimelineFrameJSON(JSONObject* frames,
- ProfileTrieNode* current,
- ProfileTrieNode* parent,
- intptr_t* next_id,
- bool code_trie);
+ void ProcessSampleFrameJSON(JSONArray* stack,
+ ProfileCodeInlinedFunctionsCache* cache,
+ ProcessedSample* sample,
+ intptr_t frame_index);
+ void ProcessInlinedFunctionFrameJSON(JSONArray* stack,
+ const Function* inlined_function);
+ void PrintFunctionFrameIndexJSON(JSONArray* stack, ProfileFunction* function);
+ void PrintCodeFrameIndexJSON(JSONArray* stack,
+ ProcessedSample* sample,
+ intptr_t frame_index);
+ void PrintSamplesJSON(JSONObject* obj, bool code_samples);
Isolate* isolate_;
Zone* zone_;
@@ -427,8 +412,6 @@
intptr_t dead_code_index_offset_;
intptr_t tag_code_index_offset_;
- ProfileTrieNode* roots_[kNumTrieKinds];
-
int64_t min_time_;
int64_t max_time_;
@@ -437,97 +420,31 @@
friend class ProfileBuilder;
};
-class ProfileTrieWalker : public ValueObject {
- public:
- explicit ProfileTrieWalker(Profile* profile)
- : profile_(profile), parent_(NULL), current_(NULL), code_trie_(false) {
- ASSERT(profile_ != NULL);
- }
-
- void Reset(Profile::TrieKind trie_kind);
-
- const char* CurrentName();
- // Return the current node's peer's inclusive tick count.
- intptr_t CurrentInclusiveTicks();
- // Return the current node's peer's exclusive tick count.
- intptr_t CurrentExclusiveTicks();
- // Return the current node's inclusive allocation count.
- intptr_t CurrentInclusiveAllocations();
- // Return the current node's exclusive allocation count.
- intptr_t CurrentExclusiveAllocations();
- // Return the current node's tick count.
- intptr_t CurrentNodeTickCount();
- // Return the number siblings (including yourself).
- intptr_t SiblingCount();
-
- // If the following conditions are met returns the current token:
- // 1) This is a function trie.
- // 2) There is only one token position for a given function.
- // Will return NULL otherwise.
- const char* CurrentToken();
-
- bool Down();
- bool NextSibling();
-
- private:
- Profile* profile_;
- ProfileTrieNode* parent_;
- ProfileTrieNode* current_;
- bool code_trie_;
-};
-
class ProfilerService : public AllStatic {
public:
- enum {
- kNoExtraTags = 0,
- kCodeTransitionTagsBit = (1 << 0),
- };
-
static void PrintJSON(JSONStream* stream,
- Profile::TagOrder tag_order,
- intptr_t extra_tags,
int64_t time_origin_micros,
- int64_t time_extent_micros);
+ int64_t time_extent_micros,
+ bool include_code_samples);
static void PrintAllocationJSON(JSONStream* stream,
- Profile::TagOrder tag_order,
const Class& cls,
int64_t time_origin_micros,
int64_t time_extent_micros);
static void PrintNativeAllocationJSON(JSONStream* stream,
- Profile::TagOrder tag_order,
int64_t time_origin_micros,
- int64_t time_extent_micros);
-
- static void PrintTimelineJSON(JSONStream* stream,
- Profile::TagOrder tag_order,
- int64_t time_origin_micros,
- int64_t time_extent_micros,
- bool code_trie);
-
- static void AddToTimeline(Profile::TagOrder tag_order,
- int64_t time_origin_micros,
- int64_t time_extent_micros,
- bool code_trie);
+ int64_t time_extent_micros,
+ bool include_code_samples);
static void ClearSamples();
private:
- enum PrintKind {
- kAsProfile,
- kAsTimeline,
- kAsPlatformTimeline,
- };
-
static void PrintJSONImpl(Thread* thread,
JSONStream* stream,
- Profile::TagOrder tag_order,
- intptr_t extra_tags,
SampleFilter* filter,
SampleBuffer* sample_buffer,
- PrintKind kind,
- bool code_trie);
+ bool include_code_samples);
};
} // namespace dart
diff --git a/runtime/vm/profiler_test.cc b/runtime/vm/profiler_test.cc
index 497954e..21566b5 100644
--- a/runtime/vm/profiler_test.cc
+++ b/runtime/vm/profiler_test.cc
@@ -229,6 +229,192 @@
}
}
+class ProfileStackWalker {
+ public:
+ explicit ProfileStackWalker(Profile* profile, bool as_func = false)
+ : profile_(profile),
+ as_functions_(as_func),
+ index_(0),
+ sample_(profile->SampleAt(0)) {
+ ClearInliningData();
+ }
+
+ bool Down() {
+ if (as_functions_) {
+ return UpdateFunctionIndex();
+ } else {
+ ++index_;
+ return (index_ < sample_->length());
+ }
+ }
+
+ const char* CurrentName() {
+ if (as_functions_) {
+ ProfileFunction* func = GetFunction();
+ EXPECT(func != NULL);
+ return func->Name();
+ } else {
+ ProfileCode* code = GetCode();
+ EXPECT(code != NULL);
+ return code->name();
+ }
+ }
+
+ const char* CurrentToken() {
+ if (!as_functions_) {
+ return NULL;
+ }
+ ProfileFunction* func = GetFunction();
+ const Function& function = *(func->function());
+ if (function.IsNull()) {
+ // No function.
+ return NULL;
+ }
+ Zone* zone = Thread::Current()->zone();
+ const Script& script = Script::Handle(zone, function.script());
+ if (script.IsNull()) {
+ // No script.
+ return NULL;
+ }
+ ProfileFunctionSourcePosition pfsp(TokenPosition::kNoSource);
+ if (!func->GetSinglePosition(&pfsp)) {
+ // Not exactly one source position.
+ return NULL;
+ }
+ TokenPosition token_pos = pfsp.token_pos();
+ if (!token_pos.IsSourcePosition()) {
+ // Not a location in a script.
+ return NULL;
+ }
+ if (token_pos.IsSynthetic()) {
+ token_pos = token_pos.FromSynthetic();
+ }
+
+ String& str = String::Handle(zone);
+ if (script.kind() == RawScript::kKernelTag) {
+ intptr_t line = 0, column = 0, token_len = 0;
+ script.GetTokenLocation(token_pos, &line, &column, &token_len);
+ str = script.GetSnippet(line, column, line, column + token_len);
+ } else {
+ UNREACHABLE();
+ }
+ return str.IsNull() ? NULL : str.ToCString();
+ }
+
+ intptr_t CurrentInclusiveTicks() {
+ if (as_functions_) {
+ ProfileFunction* func = GetFunction();
+ EXPECT(func != NULL);
+ return func->inclusive_ticks();
+ } else {
+ ProfileCode* code = GetCode();
+ ASSERT(code != NULL);
+ return code->inclusive_ticks();
+ }
+ }
+
+ intptr_t CurrentExclusiveTicks() {
+ if (as_functions_) {
+ ProfileFunction* func = GetFunction();
+ EXPECT(func != NULL);
+ return func->exclusive_ticks();
+ } else {
+ ProfileCode* code = GetCode();
+ ASSERT(code != NULL);
+ return code->exclusive_ticks();
+ }
+ }
+
+ const char* VMTagName() { return VMTag::TagName(sample_->vm_tag()); }
+
+ private:
+ ProfileCode* GetCode() {
+ uword pc = sample_->At(index_);
+ int64_t timestamp = sample_->timestamp();
+ return profile_->GetCodeFromPC(pc, timestamp);
+ }
+
+ static const intptr_t kInvalidInlinedIndex = -1;
+
+ bool UpdateFunctionIndex() {
+ if (inlined_index_ != kInvalidInlinedIndex) {
+ if (inlined_index_ - 1 >= 0) {
+ --inlined_index_;
+ return true;
+ }
+ ClearInliningData();
+ }
+ ++index_;
+ return (index_ < sample_->length());
+ }
+
+ void ClearInliningData() {
+ inlined_index_ = kInvalidInlinedIndex;
+ inlined_functions_ = NULL;
+ inlined_token_positions_ = NULL;
+ }
+
+ ProfileFunction* GetFunction() {
+ // Check to see if we're currently processing inlined functions. If so,
+ // return the next inlined function.
+ ProfileFunction* function = GetInlinedFunction();
+ if (function != NULL) {
+ return function;
+ }
+
+ const uword pc = sample_->At(index_);
+ ProfileCode* profile_code =
+ profile_->GetCodeFromPC(pc, sample_->timestamp());
+ ASSERT(profile_code != NULL);
+ function = profile_code->function();
+ ASSERT(function != NULL);
+
+ TokenPosition token_position = TokenPosition::kNoSource;
+ Code& code = Code::ZoneHandle();
+ if (profile_code->code().IsCode()) {
+ code ^= profile_code->code().raw();
+ inlined_functions_cache_.Get(pc, code, sample_, index_,
+ &inlined_functions_,
+ &inlined_token_positions_, &token_position);
+ } else if (profile_code->code().IsBytecode()) {
+ // No inlining in bytecode.
+ const Bytecode& bc = Bytecode::CheckedHandle(Thread::Current()->zone(),
+ profile_code->code().raw());
+ token_position = bc.GetTokenIndexOfPC(pc);
+ }
+
+ if (code.IsNull() || (inlined_functions_ == NULL) ||
+ (inlined_functions_->length() <= 1)) {
+ ClearInliningData();
+ // No inlined functions.
+ return function;
+ }
+
+ ASSERT(code.is_optimized());
+ inlined_index_ = inlined_functions_->length() - 1;
+ function = GetInlinedFunction();
+ ASSERT(function != NULL);
+ return function;
+ }
+
+ ProfileFunction* GetInlinedFunction() {
+ if ((inlined_index_ != kInvalidInlinedIndex) &&
+ (inlined_index_ < inlined_functions_->length())) {
+ return profile_->FindFunction(*(*inlined_functions_)[inlined_index_]);
+ }
+ return NULL;
+ }
+
+ Profile* profile_;
+ bool as_functions_;
+ intptr_t index_;
+ ProcessedSample* sample_;
+ ProfileCodeInlinedFunctionsCache inlined_functions_cache_;
+ GrowableArray<const Function*>* inlined_functions_;
+ GrowableArray<TokenPosition>* inlined_token_positions_;
+ intptr_t inlined_index_;
+};
+
ISOLATE_UNIT_TEST_CASE(Profiler_TrivialRecordAllocation) {
EnableProfiler();
DisableNativeProfileScope dnps;
@@ -269,17 +455,13 @@
AllocationFilter filter(isolate->main_port(), class_a.id(),
before_allocations_micros,
allocation_extent_micros);
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have 1 allocation sample.
EXPECT_EQ(1, profile.sample_count());
- ProfileTrieWalker walker(&profile);
+ ProfileStackWalker walker(&profile);
- // Exclusive code: B.boo -> main.
- walker.Reset(Profile::kExclusiveCode);
// Move down from the root.
- EXPECT(walker.Down());
- EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
- EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.VMTagName());
if (FLAG_enable_interpreter) {
EXPECT_STREQ("[Bytecode] B.boo", walker.CurrentName());
EXPECT(walker.Down());
@@ -293,56 +475,6 @@
EXPECT_STREQ("[Unoptimized] main", walker.CurrentName());
EXPECT(!walker.Down());
}
-
- // Inclusive code: main -> B.boo.
- walker.Reset(Profile::kInclusiveCode);
- // Move down from the root.
- EXPECT(walker.Down());
- if (FLAG_enable_interpreter) {
- EXPECT_STREQ("[Bytecode] main", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Bytecode] B.boo", walker.CurrentName());
- EXPECT(walker.Down());
- } else {
- EXPECT_STREQ("[Unoptimized] main", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Unoptimized] B.boo", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
- EXPECT(walker.Down());
- }
- EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
- EXPECT(!walker.Down());
-
- // Exclusive function: B.boo -> main.
- walker.Reset(Profile::kExclusiveFunction);
- // Move down from the root.
- EXPECT(walker.Down());
- EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
- EXPECT(walker.Down());
- if (!FLAG_enable_interpreter) {
- EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
- EXPECT(walker.Down());
- }
- EXPECT_STREQ("B.boo", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("main", walker.CurrentName());
- EXPECT(!walker.Down());
-
- // Inclusive function: main -> B.boo.
- walker.Reset(Profile::kInclusiveFunction);
- // Move down from the root.
- EXPECT(walker.Down());
- EXPECT_STREQ("main", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("B.boo", walker.CurrentName());
- EXPECT(walker.Down());
- if (!FLAG_enable_interpreter) {
- EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
- EXPECT(walker.Down());
- }
- EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
- EXPECT(!walker.Down());
}
// Query with a time filter where no allocations occurred.
@@ -354,7 +486,7 @@
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), class_a.id(),
Dart_TimelineGetMicros(), 16000);
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have no allocation samples because none occured within
// the specified time range.
EXPECT_EQ(0, profile.sample_count());
@@ -404,129 +536,31 @@
// Filter for the class in the time range.
NativeAllocationSampleFilter filter(before_allocations_micros,
allocation_extent_micros);
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have 1 allocation sample.
EXPECT_EQ(1, profile.sample_count());
- ProfileTrieWalker walker(&profile);
+ ProfileStackWalker walker(&profile)
- // Exclusive code: NativeAllocationSampleHelper -> main.
- walker.Reset(Profile::kExclusiveCode);
- // Move down from the root.
- EXPECT(walker.Down());
+ // Move down from the root.
+ EXPECT(walker.Down());
EXPECT_SUBSTRING("[Native]", walker.CurrentName());
- EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
- EXPECT_EQ(walker.CurrentExclusiveAllocations(), 1024);
+ EXPECT_EQ(walker.native_allocation_size_bytes(), 1024);
EXPECT(walker.Down());
EXPECT_STREQ("dart::Dart_TestProfiler_NativeAllocation()",
walker.CurrentName());
- EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
- EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
+ EXPECT_EQ(walker.native_allocation_size_bytes(), 1024);
EXPECT(walker.Down());
EXPECT_STREQ("dart::TestCase::Run()", walker.CurrentName());
- EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
- EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
+ EXPECT_EQ(walker.native_allocation_size_bytes(), 1024);
EXPECT(walker.Down());
EXPECT_STREQ("dart::TestCaseBase::RunTest()", walker.CurrentName());
- EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
- EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
+ EXPECT_EQ(walker.native_allocation_size_bytes(), 1024);
EXPECT(walker.Down());
EXPECT_STREQ("dart::TestCaseBase::RunAll()", walker.CurrentName());
- EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
- EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
+ EXPECT_EQ(walker.native_allocation_size_bytes(), 1024);
EXPECT(walker.Down());
EXPECT_STREQ("main", walker.CurrentName());
- EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
- EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
- EXPECT(!walker.Down());
-
- // Inclusive code: main -> NativeAllocationSampleHelper.
- walker.Reset(Profile::kInclusiveCode);
- // Move down from the root.
- EXPECT(walker.Down());
- EXPECT_STREQ("main", walker.CurrentName());
- EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
- EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
- EXPECT(walker.Down());
- EXPECT_STREQ("dart::TestCaseBase::RunAll()", walker.CurrentName());
- EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
- EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
- EXPECT(walker.Down());
- EXPECT_STREQ("dart::TestCaseBase::RunTest()", walker.CurrentName());
- EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
- EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
- EXPECT(walker.Down());
- EXPECT_STREQ("dart::TestCase::Run()", walker.CurrentName());
- EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
- EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
- EXPECT(walker.Down());
- EXPECT_STREQ("dart::Dart_TestProfiler_NativeAllocation()",
- walker.CurrentName());
- EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
- EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
- EXPECT(walker.Down());
- EXPECT_SUBSTRING("[Native]", walker.CurrentName());
- EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
- EXPECT_EQ(walker.CurrentExclusiveAllocations(), 1024);
- EXPECT(!walker.Down());
-
- // Exclusive function: NativeAllocationSampleHelper -> main.
- walker.Reset(Profile::kExclusiveFunction);
- // Move down from the root.
- EXPECT(walker.Down());
- EXPECT_SUBSTRING("[Native]", walker.CurrentName());
- EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
- EXPECT_EQ(walker.CurrentExclusiveAllocations(), 1024);
- EXPECT(walker.Down());
- EXPECT_STREQ("dart::Dart_TestProfiler_NativeAllocation()",
- walker.CurrentName());
- EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
- EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
- EXPECT(walker.Down());
- EXPECT_STREQ("dart::TestCase::Run()", walker.CurrentName());
- EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
- EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
- EXPECT(walker.Down());
- EXPECT_STREQ("dart::TestCaseBase::RunTest()", walker.CurrentName());
- EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
- EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
- EXPECT(walker.Down());
- EXPECT_STREQ("dart::TestCaseBase::RunAll()", walker.CurrentName());
- EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
- EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
- EXPECT(walker.Down());
- EXPECT_STREQ("main", walker.CurrentName());
- EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
- EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
- EXPECT(!walker.Down());
-
- // Inclusive function: main -> NativeAllocationSampleHelper.
- walker.Reset(Profile::kInclusiveFunction);
- // Move down from the root.
- EXPECT(walker.Down());
- EXPECT_STREQ("main", walker.CurrentName());
- EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
- EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
- EXPECT(walker.Down());
- EXPECT_STREQ("dart::TestCaseBase::RunAll()", walker.CurrentName());
- EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
- EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
- EXPECT(walker.Down());
- EXPECT_STREQ("dart::TestCaseBase::RunTest()", walker.CurrentName());
- EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
- EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
- EXPECT(walker.Down());
- EXPECT_STREQ("dart::TestCase::Run()", walker.CurrentName());
- EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
- EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
- EXPECT(walker.Down());
- EXPECT_STREQ("dart::Dart_TestProfiler_NativeAllocation()",
- walker.CurrentName());
- EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
- EXPECT_EQ(walker.CurrentExclusiveAllocations(), 0);
- EXPECT(walker.Down());
- EXPECT_SUBSTRING("[Native]", walker.CurrentName());
- EXPECT_EQ(walker.CurrentInclusiveAllocations(), 1024);
- EXPECT_EQ(walker.CurrentExclusiveAllocations(), 1024);
+ EXPECT_EQ(walker.native_allocation_size_bytes(), 1024);
EXPECT(!walker.Down());
}
@@ -546,7 +580,7 @@
// Filter for the class in the time range.
NativeAllocationSampleFilter filter(before_allocations_micros,
allocation_extent_micros);
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have 0 allocation samples since we freed the memory.
EXPECT_EQ(0, profile.sample_count());
}
@@ -559,7 +593,7 @@
HANDLESCOPE(thread);
Profile profile(isolate);
NativeAllocationSampleFilter filter(Dart_TimelineGetMicros(), 16000);
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have no allocation samples because none occured within
// the specified time range.
EXPECT_EQ(0, profile.sample_count());
@@ -606,7 +640,7 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), class_a.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have no allocation samples.
EXPECT_EQ(0, profile.sample_count());
}
@@ -623,17 +657,12 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), class_a.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have one allocation sample.
EXPECT_EQ(1, profile.sample_count());
- ProfileTrieWalker walker(&profile);
+ ProfileStackWalker walker(&profile);
- // Exclusive code: B.boo -> main.
- walker.Reset(Profile::kExclusiveCode);
- // Move down from the root.
- EXPECT(walker.Down());
- EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
- EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.VMTagName());
if (FLAG_enable_interpreter) {
EXPECT_STREQ("[Bytecode] B.boo", walker.CurrentName());
EXPECT(walker.Down());
@@ -647,56 +676,6 @@
EXPECT_STREQ("[Unoptimized] main", walker.CurrentName());
EXPECT(!walker.Down());
}
-
- // Inclusive code: main -> B.boo.
- walker.Reset(Profile::kInclusiveCode);
- // Move down from the root.
- EXPECT(walker.Down());
- if (FLAG_enable_interpreter) {
- EXPECT_STREQ("[Bytecode] main", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Bytecode] B.boo", walker.CurrentName());
- EXPECT(walker.Down());
- } else {
- EXPECT_STREQ("[Unoptimized] main", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Unoptimized] B.boo", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
- EXPECT(walker.Down());
- }
- EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
- EXPECT(!walker.Down());
-
- // Exclusive function: boo -> main.
- walker.Reset(Profile::kExclusiveFunction);
- // Move down from the root.
- EXPECT(walker.Down());
- EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
- EXPECT(walker.Down());
- if (!FLAG_enable_interpreter) {
- EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
- EXPECT(walker.Down());
- }
- EXPECT_STREQ("B.boo", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("main", walker.CurrentName());
- EXPECT(!walker.Down());
-
- // Inclusive function: main -> boo.
- walker.Reset(Profile::kInclusiveFunction);
- // Move down from the root.
- EXPECT(walker.Down());
- EXPECT_STREQ("main", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("B.boo", walker.CurrentName());
- EXPECT(walker.Down());
- if (!FLAG_enable_interpreter) {
- EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
- EXPECT(walker.Down());
- }
- EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
- EXPECT(!walker.Down());
}
// Turn off allocation tracing for A.
@@ -711,7 +690,7 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), class_a.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should still only have one allocation sample.
EXPECT_EQ(1, profile.sample_count());
}
@@ -749,7 +728,7 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), class_a.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have no allocation samples.
EXPECT_EQ(0, profile.sample_count());
}
@@ -769,24 +748,18 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), class_a.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have three allocation samples.
EXPECT_EQ(3, profile.sample_count());
- ProfileTrieWalker walker(&profile);
+ ProfileStackWalker walker(&profile);
- // Exclusive code: B.boo -> main.
- walker.Reset(Profile::kExclusiveCode);
// Move down from the root.
- EXPECT(walker.Down());
- EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
- EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.VMTagName());
if (FLAG_enable_interpreter) {
EXPECT_STREQ("[Bytecode] B.boo", walker.CurrentName());
- EXPECT_EQ(3, walker.CurrentNodeTickCount());
EXPECT_EQ(3, walker.CurrentInclusiveTicks());
EXPECT(walker.Down());
EXPECT_STREQ("[Bytecode] main", walker.CurrentName());
- EXPECT_EQ(3, walker.CurrentNodeTickCount());
EXPECT_EQ(3, walker.CurrentInclusiveTicks());
EXPECT_EQ(0, walker.CurrentExclusiveTicks());
EXPECT(!walker.Down());
@@ -795,49 +768,15 @@
EXPECT_EQ(3, walker.CurrentExclusiveTicks());
EXPECT(walker.Down());
EXPECT_STREQ("[Unoptimized] B.boo", walker.CurrentName());
- EXPECT_EQ(3, walker.CurrentNodeTickCount());
EXPECT_EQ(3, walker.CurrentInclusiveTicks());
EXPECT(walker.Down());
EXPECT_STREQ("[Unoptimized] main", walker.CurrentName());
- EXPECT_EQ(3, walker.CurrentNodeTickCount());
EXPECT_EQ(3, walker.CurrentInclusiveTicks());
EXPECT_EQ(0, walker.CurrentExclusiveTicks());
EXPECT(!walker.Down());
}
-
- // Inclusive code: main -> B.boo.
- walker.Reset(Profile::kInclusiveCode);
- // Move down from the root.
- EXPECT(walker.Down());
- if (FLAG_enable_interpreter) {
- EXPECT_STREQ("[Bytecode] main", walker.CurrentName());
- EXPECT_EQ(3, walker.CurrentNodeTickCount());
- EXPECT_EQ(3, walker.CurrentInclusiveTicks());
- EXPECT_EQ(0, walker.CurrentExclusiveTicks());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Bytecode] B.boo", walker.CurrentName());
- EXPECT_EQ(3, walker.CurrentNodeTickCount());
- EXPECT_EQ(3, walker.CurrentInclusiveTicks());
- EXPECT(walker.Down());
- } else {
- EXPECT_STREQ("[Unoptimized] main", walker.CurrentName());
- EXPECT_EQ(3, walker.CurrentNodeTickCount());
- EXPECT_EQ(3, walker.CurrentInclusiveTicks());
- EXPECT_EQ(0, walker.CurrentExclusiveTicks());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Unoptimized] B.boo", walker.CurrentName());
- EXPECT_EQ(3, walker.CurrentNodeTickCount());
- EXPECT_EQ(3, walker.CurrentInclusiveTicks());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
- EXPECT_EQ(3, walker.CurrentExclusiveTicks());
- EXPECT(walker.Down());
- }
- EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
- EXPECT(!walker.Down());
}
}
-
ISOLATE_UNIT_TEST_CASE(Profiler_FunctionTicks) {
EnableProfiler();
DisableNativeProfileScope dnps;
@@ -870,7 +809,7 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), class_a.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have no allocation samples.
EXPECT_EQ(0, profile.sample_count());
}
@@ -890,52 +829,25 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), class_a.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have three allocation samples.
EXPECT_EQ(3, profile.sample_count());
- ProfileTrieWalker walker(&profile);
+ ProfileStackWalker walker(&profile, true);
- // Exclusive function: B.boo -> main.
- walker.Reset(Profile::kExclusiveFunction);
- // Move down from the root.
- EXPECT(walker.Down());
- EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
- EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.VMTagName());
+
if (!FLAG_enable_interpreter) {
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT_EQ(3, walker.CurrentExclusiveTicks());
EXPECT(walker.Down());
}
EXPECT_STREQ("B.boo", walker.CurrentName());
- EXPECT_EQ(3, walker.CurrentNodeTickCount());
EXPECT_EQ(3, walker.CurrentInclusiveTicks());
EXPECT(walker.Down());
EXPECT_STREQ("main", walker.CurrentName());
- EXPECT_EQ(3, walker.CurrentNodeTickCount());
EXPECT_EQ(3, walker.CurrentInclusiveTicks());
EXPECT_EQ(0, walker.CurrentExclusiveTicks());
EXPECT(!walker.Down());
-
- // Inclusive function: main -> B.boo.
- walker.Reset(Profile::kInclusiveFunction);
- // Move down from the root.
- EXPECT(walker.Down());
- EXPECT_STREQ("main", walker.CurrentName());
- EXPECT_EQ(3, walker.CurrentNodeTickCount());
- EXPECT_EQ(3, walker.CurrentInclusiveTicks());
- EXPECT_EQ(0, walker.CurrentExclusiveTicks());
- EXPECT(walker.Down());
- EXPECT_STREQ("B.boo", walker.CurrentName());
- EXPECT_EQ(3, walker.CurrentNodeTickCount());
- EXPECT_EQ(3, walker.CurrentInclusiveTicks());
- EXPECT(walker.Down());
- if (!FLAG_enable_interpreter) {
- EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
- EXPECT_EQ(3, walker.CurrentExclusiveTicks());
- EXPECT(walker.Down());
- }
- EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
- EXPECT(!walker.Down());
}
}
@@ -965,7 +877,7 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), double_class.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have no allocation samples.
EXPECT_EQ(0, profile.sample_count());
}
@@ -978,21 +890,17 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), double_class.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have one allocation sample.
EXPECT_EQ(1, profile.sample_count());
- ProfileTrieWalker walker(&profile);
+ ProfileStackWalker walker(&profile);
- walker.Reset(Profile::kExclusiveCode);
- EXPECT(walker.Down());
if (FLAG_enable_interpreter) {
- EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
- EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.VMTagName());
EXPECT_STREQ("[Bytecode] foo", walker.CurrentName());
EXPECT(!walker.Down());
} else {
- EXPECT_STREQ("Double_add", walker.CurrentName());
- EXPECT(walker.Down());
+ EXPECT_STREQ("Double_add", walker.VMTagName());
EXPECT_STREQ("[Unoptimized] double._add", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("[Unoptimized] double.+", walker.CurrentName());
@@ -1010,7 +918,7 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), double_class.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should still only have one allocation sample.
EXPECT_EQ(1, profile.sample_count());
}
@@ -1037,7 +945,7 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), array_class.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have no allocation samples.
EXPECT_EQ(0, profile.sample_count());
}
@@ -1050,15 +958,12 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), array_class.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have one allocation sample.
EXPECT_EQ(1, profile.sample_count());
- ProfileTrieWalker walker(&profile);
+ ProfileStackWalker walker(&profile);
- walker.Reset(Profile::kExclusiveCode);
- EXPECT(walker.Down());
- EXPECT_STREQ("DRT_AllocateArray", walker.CurrentName());
- EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateArray", walker.VMTagName());
if (FLAG_enable_interpreter) {
EXPECT_STREQ("[Bytecode] new _List", walker.CurrentName());
EXPECT(walker.Down());
@@ -1082,7 +987,7 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), array_class.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should still only have one allocation sample.
EXPECT_EQ(1, profile.sample_count());
}
@@ -1104,7 +1009,7 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), array_class.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have no allocation samples, since empty
// growable lists use a shared backing.
EXPECT_EQ(0, profile.sample_count());
@@ -1134,7 +1039,7 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), context_class.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have no allocation samples.
EXPECT_EQ(0, profile.sample_count());
}
@@ -1147,15 +1052,12 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), context_class.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have one allocation sample.
EXPECT_EQ(1, profile.sample_count());
- ProfileTrieWalker walker(&profile);
+ ProfileStackWalker walker(&profile);
- walker.Reset(Profile::kExclusiveCode);
- EXPECT(walker.Down());
- EXPECT_STREQ("DRT_AllocateContext", walker.CurrentName());
- EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateContext", walker.VMTagName());
if (FLAG_enable_interpreter) {
EXPECT_STREQ("[Bytecode] foo", walker.CurrentName());
EXPECT(!walker.Down());
@@ -1175,7 +1077,7 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), context_class.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should still only have one allocation sample.
EXPECT_EQ(1, profile.sample_count());
}
@@ -1216,15 +1118,12 @@
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), closure_class.id());
filter.set_enable_vm_ticks(true);
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have one allocation sample.
EXPECT_EQ(1, profile.sample_count());
- ProfileTrieWalker walker(&profile);
+ ProfileStackWalker walker(&profile);
- walker.Reset(Profile::kExclusiveCode);
- EXPECT(walker.Down());
- EXPECT_SUBSTRING("DRT_AllocateObject", walker.CurrentName());
- EXPECT(walker.Down());
+ EXPECT_SUBSTRING("DRT_AllocateObject", walker.VMTagName());
if (!FLAG_enable_interpreter) {
EXPECT_STREQ("[Stub] Allocate _Closure", walker.CurrentName());
EXPECT(walker.Down());
@@ -1245,7 +1144,7 @@
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), closure_class.id());
filter.set_enable_vm_ticks(true);
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should still only have one allocation sample.
EXPECT_EQ(1, profile.sample_count());
}
@@ -1275,7 +1174,7 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), float32_list_class.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have no allocation samples.
EXPECT_EQ(0, profile.sample_count());
}
@@ -1288,15 +1187,12 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), float32_list_class.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have one allocation sample.
EXPECT_EQ(1, profile.sample_count());
- ProfileTrieWalker walker(&profile);
+ ProfileStackWalker walker(&profile);
- walker.Reset(Profile::kExclusiveCode);
- EXPECT(walker.Down());
- EXPECT_STREQ("TypedData_Float32Array_new", walker.CurrentName());
- EXPECT(walker.Down());
+ EXPECT_STREQ("TypedData_Float32Array_new", walker.VMTagName());
if (FLAG_enable_interpreter) {
EXPECT_STREQ("[Bytecode] new Float32List", walker.CurrentName());
EXPECT(walker.Down());
@@ -1318,7 +1214,7 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), float32_list_class.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should still only have one allocation sample.
EXPECT_EQ(1, profile.sample_count());
}
@@ -1331,7 +1227,7 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), float32_list_class.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should now have two allocation samples.
EXPECT_EQ(2, profile.sample_count());
}
@@ -1363,7 +1259,7 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), one_byte_string_class.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have no allocation samples.
EXPECT_EQ(0, profile.sample_count());
}
@@ -1376,15 +1272,12 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), one_byte_string_class.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should still only have one allocation sample.
EXPECT_EQ(1, profile.sample_count());
- ProfileTrieWalker walker(&profile);
+ ProfileStackWalker walker(&profile);
- walker.Reset(Profile::kExclusiveCode);
- EXPECT(walker.Down());
- EXPECT_STREQ("String_concat", walker.CurrentName());
- EXPECT(walker.Down());
+ EXPECT_STREQ("String_concat", walker.VMTagName());
if (FLAG_enable_interpreter) {
EXPECT_STREQ("[Bytecode] _StringBase.+", walker.CurrentName());
EXPECT(walker.Down());
@@ -1406,7 +1299,7 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), one_byte_string_class.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should still only have one allocation sample.
EXPECT_EQ(1, profile.sample_count());
}
@@ -1419,7 +1312,7 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), one_byte_string_class.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should now have two allocation samples.
EXPECT_EQ(2, profile.sample_count());
}
@@ -1451,7 +1344,7 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), one_byte_string_class.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have no allocation samples.
EXPECT_EQ(0, profile.sample_count());
}
@@ -1464,15 +1357,12 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), one_byte_string_class.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should still only have one allocation sample.
EXPECT_EQ(1, profile.sample_count());
- ProfileTrieWalker walker(&profile);
+ ProfileStackWalker walker(&profile);
- walker.Reset(Profile::kExclusiveCode);
- EXPECT(walker.Down());
- EXPECT_STREQ("OneByteString_allocate", walker.CurrentName());
- EXPECT(walker.Down());
+ EXPECT_STREQ("OneByteString_allocate", walker.VMTagName());
if (FLAG_enable_interpreter) {
EXPECT_STREQ("[Bytecode] _OneByteString._allocate", walker.CurrentName());
EXPECT(walker.Down());
@@ -1504,7 +1394,7 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), one_byte_string_class.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should still only have one allocation sample.
EXPECT_EQ(1, profile.sample_count());
}
@@ -1517,7 +1407,7 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), one_byte_string_class.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should now have two allocation samples.
EXPECT_EQ(2, profile.sample_count());
}
@@ -1574,7 +1464,7 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), class_a.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have no allocation samples.
EXPECT_EQ(0, profile.sample_count());
}
@@ -1592,215 +1482,48 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), class_a.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have 50,000 allocation samples.
EXPECT_EQ(50000, profile.sample_count());
- ProfileTrieWalker walker(&profile);
- // We have two code objects: mainA and B.boo.
- walker.Reset(Profile::kExclusiveCode);
- EXPECT(walker.Down());
- EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
- EXPECT_EQ(50000, walker.CurrentExclusiveTicks());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Optimized] B.boo", walker.CurrentName());
- EXPECT_EQ(1, walker.SiblingCount());
- EXPECT_EQ(50000, walker.CurrentNodeTickCount());
- EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Unoptimized] mainA", walker.CurrentName());
- EXPECT_EQ(1, walker.SiblingCount());
- EXPECT_EQ(50000, walker.CurrentNodeTickCount());
- EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
- EXPECT_EQ(0, walker.CurrentExclusiveTicks());
- EXPECT(!walker.Down());
- // We have two code objects: mainA and B.boo.
- walker.Reset(Profile::kInclusiveCode);
- EXPECT(walker.Down());
- EXPECT_STREQ("[Unoptimized] mainA", walker.CurrentName());
- EXPECT_EQ(1, walker.SiblingCount());
- EXPECT_EQ(50000, walker.CurrentNodeTickCount());
- EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
- EXPECT_EQ(0, walker.CurrentExclusiveTicks());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Optimized] B.boo", walker.CurrentName());
- EXPECT_EQ(1, walker.SiblingCount());
- EXPECT_EQ(50000, walker.CurrentNodeTickCount());
- EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
- EXPECT_EQ(50000, walker.CurrentExclusiveTicks());
- EXPECT(walker.Down());
- EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
- EXPECT(!walker.Down());
-
- // Inline expansion should show us the complete call chain:
- // mainA -> B.boo -> B.foo -> B.choo.
- walker.Reset(Profile::kExclusiveFunction);
- EXPECT(walker.Down());
- EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
- EXPECT_EQ(50000, walker.CurrentExclusiveTicks());
- EXPECT(walker.Down());
- EXPECT_STREQ("B.choo", walker.CurrentName());
- EXPECT_EQ(1, walker.SiblingCount());
- EXPECT_EQ(50000, walker.CurrentNodeTickCount());
- EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
- EXPECT(walker.Down());
- EXPECT_STREQ("B.foo", walker.CurrentName());
- EXPECT_EQ(1, walker.SiblingCount());
- EXPECT_EQ(50000, walker.CurrentNodeTickCount());
- EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
- EXPECT_EQ(0, walker.CurrentExclusiveTicks());
- EXPECT(walker.Down());
- EXPECT_STREQ("B.boo", walker.CurrentName());
- EXPECT_EQ(1, walker.SiblingCount());
- EXPECT_EQ(50000, walker.CurrentNodeTickCount());
- EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
- EXPECT_EQ(0, walker.CurrentExclusiveTicks());
- EXPECT(walker.Down());
- EXPECT_STREQ("mainA", walker.CurrentName());
- EXPECT_EQ(1, walker.SiblingCount());
- EXPECT_EQ(50000, walker.CurrentNodeTickCount());
- EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
- EXPECT_EQ(0, walker.CurrentExclusiveTicks());
- EXPECT(!walker.Down());
-
- // Inline expansion should show us the complete call chain:
- // mainA -> B.boo -> B.foo -> B.choo.
- walker.Reset(Profile::kInclusiveFunction);
- EXPECT(walker.Down());
- EXPECT_STREQ("mainA", walker.CurrentName());
- EXPECT_EQ(1, walker.SiblingCount());
- EXPECT_EQ(50000, walker.CurrentNodeTickCount());
- EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
- EXPECT_EQ(0, walker.CurrentExclusiveTicks());
- EXPECT(walker.Down());
- EXPECT_STREQ("B.boo", walker.CurrentName());
- EXPECT_EQ(1, walker.SiblingCount());
- EXPECT_EQ(50000, walker.CurrentNodeTickCount());
- EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
- EXPECT_EQ(0, walker.CurrentExclusiveTicks());
- EXPECT(walker.Down());
- EXPECT_STREQ("B.foo", walker.CurrentName());
- EXPECT_EQ(1, walker.SiblingCount());
- EXPECT_EQ(50000, walker.CurrentNodeTickCount());
- EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
- EXPECT_EQ(0, walker.CurrentExclusiveTicks());
- EXPECT(walker.Down());
- EXPECT_STREQ("B.choo", walker.CurrentName());
- EXPECT_EQ(1, walker.SiblingCount());
- EXPECT_EQ(50000, walker.CurrentNodeTickCount());
- EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
- EXPECT_EQ(50000, walker.CurrentExclusiveTicks());
- EXPECT(walker.Down());
- EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
- EXPECT(!walker.Down());
- }
-
- // Test code transition tags.
- {
- Thread* thread = Thread::Current();
- Isolate* isolate = thread->isolate();
- StackZone zone(thread);
- HANDLESCOPE(thread);
- Profile profile(isolate);
- AllocationFilter filter(isolate->main_port(), class_a.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags,
- ProfilerService::kCodeTransitionTagsBit);
- // We should have 50,000 allocation samples.
- EXPECT_EQ(50000, profile.sample_count());
- ProfileTrieWalker walker(&profile);
- // We have two code objects: mainA and B.boo.
- walker.Reset(Profile::kExclusiveCode);
- EXPECT(walker.Down());
- EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Unoptimized Code]", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Optimized] B.boo", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Optimized Code]", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Unoptimized] mainA", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Unoptimized Code]", walker.CurrentName());
- EXPECT(!walker.Down());
- // We have two code objects: mainA and B.boo.
- walker.Reset(Profile::kInclusiveCode);
- EXPECT(walker.Down());
- EXPECT_STREQ("[Unoptimized Code]", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Unoptimized] mainA", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Optimized Code]", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Optimized] B.boo", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Unoptimized Code]", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
- EXPECT(!walker.Down());
-
- // Inline expansion should show us the complete call chain:
- // mainA -> B.boo -> B.foo -> B.choo.
- walker.Reset(Profile::kExclusiveFunction);
- EXPECT(walker.Down());
- EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Unoptimized Code]", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Inline End]", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("B.choo", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("B.foo", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Inline Start]", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("B.boo", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Optimized Code]", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("mainA", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Unoptimized Code]", walker.CurrentName());
- EXPECT(!walker.Down());
-
- // Inline expansion should show us the complete call chain:
- // mainA -> B.boo -> B.foo -> B.choo.
- walker.Reset(Profile::kInclusiveFunction);
- EXPECT(walker.Down());
- EXPECT_STREQ("mainA", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Optimized Code]", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("B.boo", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Inline Start]", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("B.foo", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("B.choo", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Inline End]", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Unoptimized Code]", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
- EXPECT(!walker.Down());
+ {
+ ProfileStackWalker walker(&profile);
+ // We have two code objects: mainA and B.boo.
+ EXPECT_STREQ("DRT_AllocateObject", walker.VMTagName());
+ EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
+ EXPECT_EQ(50000, walker.CurrentExclusiveTicks());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("[Optimized] B.boo", walker.CurrentName());
+ EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("[Unoptimized] mainA", walker.CurrentName());
+ EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
+ EXPECT_EQ(0, walker.CurrentExclusiveTicks());
+ EXPECT(!walker.Down());
+ }
+ {
+ ProfileStackWalker walker(&profile, true);
+ // Inline expansion should show us the complete call chain:
+ // mainA -> B.boo -> B.foo -> B.choo.
+ EXPECT_STREQ("DRT_AllocateObject", walker.VMTagName());
+ EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
+ EXPECT_EQ(50000, walker.CurrentExclusiveTicks());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("B.choo", walker.CurrentName());
+ EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("B.foo", walker.CurrentName());
+ EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
+ EXPECT_EQ(0, walker.CurrentExclusiveTicks());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("B.boo", walker.CurrentName());
+ EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
+ EXPECT_EQ(0, walker.CurrentExclusiveTicks());
+ EXPECT(walker.Down());
+ EXPECT_STREQ("mainA", walker.CurrentName());
+ EXPECT_EQ(50000, walker.CurrentInclusiveTicks());
+ EXPECT_EQ(0, walker.CurrentExclusiveTicks());
+ EXPECT(!walker.Down());
+ }
}
}
@@ -1881,7 +1604,7 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), class_a.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have no allocation samples.
EXPECT_EQ(0, profile.sample_count());
}
@@ -1898,15 +1621,12 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), class_a.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
EXPECT_EQ(1, profile.sample_count());
- ProfileTrieWalker walker(&profile);
+ ProfileStackWalker walker(&profile, true);
// Inline expansion should show us the complete call chain:
- walker.Reset(Profile::kExclusiveFunction);
- EXPECT(walker.Down());
- EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
- EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.VMTagName());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("maybeAlloc", walker.CurrentName());
@@ -1916,22 +1636,6 @@
EXPECT_STREQ("a", walker.CurrentName());
EXPECT(walker.Down());
EXPECT_STREQ("mainAlloc", walker.CurrentName());
-
- // Inline expansion should show us the complete call chain:
- walker.Reset(Profile::kInclusiveFunction);
- EXPECT(walker.Down());
- EXPECT_STREQ("mainAlloc", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("a", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("right", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("maybeAlloc", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
- EXPECT(walker.Down());
- EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
- EXPECT(!walker.Down());
}
}
@@ -1989,16 +1693,12 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), class_a.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have 1 allocation sample.
EXPECT_EQ(1, profile.sample_count());
- ProfileTrieWalker walker(&profile);
+ ProfileStackWalker walker(&profile);
- walker.Reset(Profile::kExclusiveCode);
- // Move down from the root.
- EXPECT(walker.Down());
- EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
- EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.VMTagName());
if (FLAG_enable_interpreter) {
EXPECT_STREQ("[Bytecode] B.boo", walker.CurrentName());
EXPECT(walker.Down());
@@ -2127,29 +1827,22 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), class_a.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have one allocation samples.
EXPECT_EQ(1, profile.sample_count());
- ProfileTrieWalker walker(&profile);
+ ProfileStackWalker walker(&profile, true);
- // Exclusive function: B.boo -> main.
- walker.Reset(Profile::kExclusiveFunction);
- // Move down from the root.
- EXPECT(walker.Down());
- EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
- EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.VMTagName());
if (!FLAG_enable_interpreter) {
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT_EQ(1, walker.CurrentExclusiveTicks());
EXPECT(walker.Down());
}
EXPECT_STREQ("B.boo", walker.CurrentName());
- EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_STREQ("A", walker.CurrentToken());
EXPECT(walker.Down());
EXPECT_STREQ("main", walker.CurrentName());
- EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_EQ(0, walker.CurrentExclusiveTicks());
EXPECT_STREQ("boo", walker.CurrentToken());
@@ -2215,27 +1908,21 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), class_a.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have one allocation samples.
EXPECT_EQ(1, profile.sample_count());
- ProfileTrieWalker walker(&profile);
+ ProfileStackWalker walker(&profile, true);
- // Exclusive function: B.boo -> main.
- walker.Reset(Profile::kExclusiveFunction);
// Move down from the root.
- EXPECT(walker.Down());
- EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
- EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.VMTagName());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT_EQ(1, walker.CurrentExclusiveTicks());
EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
- EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_STREQ("A", walker.CurrentToken());
EXPECT(walker.Down());
EXPECT_STREQ("main", walker.CurrentName());
- EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_EQ(0, walker.CurrentExclusiveTicks());
EXPECT_STREQ("boo", walker.CurrentToken());
@@ -2295,47 +1982,37 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), class_a.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have one allocation samples.
EXPECT_EQ(1, profile.sample_count());
- ProfileTrieWalker walker(&profile);
+ ProfileStackWalker walker(&profile, true);
- // Exclusive function: B.boo -> main.
- walker.Reset(Profile::kExclusiveFunction);
- // Move down from the root.
- EXPECT(walker.Down());
- EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
- EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.VMTagName());
if (!FLAG_enable_interpreter) {
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT_EQ(1, walker.CurrentExclusiveTicks());
EXPECT(walker.Down());
}
EXPECT_STREQ("B.boo", walker.CurrentName());
- EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_STREQ("A", walker.CurrentToken());
EXPECT(walker.Down());
EXPECT_STREQ("B.oats", walker.CurrentName());
- EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_EQ(0, walker.CurrentExclusiveTicks());
EXPECT_STREQ("boo", walker.CurrentToken());
EXPECT(walker.Down());
EXPECT_STREQ("C.fox", walker.CurrentName());
- EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_EQ(0, walker.CurrentExclusiveTicks());
EXPECT_STREQ("oats", walker.CurrentToken());
EXPECT(walker.Down());
EXPECT_STREQ("C.bacon", walker.CurrentName());
- EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_EQ(0, walker.CurrentExclusiveTicks());
EXPECT_STREQ("fox", walker.CurrentToken());
EXPECT(walker.Down());
EXPECT_STREQ("main", walker.CurrentName());
- EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_EQ(0, walker.CurrentExclusiveTicks());
EXPECT_STREQ("bacon", walker.CurrentToken());
@@ -2414,45 +2091,35 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), class_a.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have one allocation samples.
EXPECT_EQ(1, profile.sample_count());
- ProfileTrieWalker walker(&profile);
+ ProfileStackWalker walker(&profile, true);
- // Exclusive function: B.boo -> main.
- walker.Reset(Profile::kExclusiveFunction);
- // Move down from the root.
- EXPECT(walker.Down());
- EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
- EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.VMTagName());
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT_EQ(1, walker.CurrentExclusiveTicks());
EXPECT(walker.Down());
EXPECT_STREQ("B.boo", walker.CurrentName());
- EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_STREQ("A", walker.CurrentToken());
EXPECT(walker.Down());
EXPECT_STREQ("B.oats", walker.CurrentName());
- EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_EQ(0, walker.CurrentExclusiveTicks());
EXPECT_STREQ("boo", walker.CurrentToken());
EXPECT(walker.Down());
EXPECT_STREQ("C.fox", walker.CurrentName());
- EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_EQ(0, walker.CurrentExclusiveTicks());
EXPECT_STREQ("oats", walker.CurrentToken());
EXPECT(walker.Down());
EXPECT_STREQ("C.bacon", walker.CurrentName());
- EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_EQ(0, walker.CurrentExclusiveTicks());
EXPECT_STREQ("fox", walker.CurrentToken());
EXPECT(walker.Down());
EXPECT_STREQ("main", walker.CurrentName());
- EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_EQ(0, walker.CurrentExclusiveTicks());
EXPECT_STREQ("bacon", walker.CurrentToken());
@@ -2515,53 +2182,42 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), class_a.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have one allocation samples.
EXPECT_EQ(1, profile.sample_count());
- ProfileTrieWalker walker(&profile);
+ ProfileStackWalker walker(&profile, true);
- // Exclusive function: B.boo -> main.
- walker.Reset(Profile::kExclusiveFunction);
- // Move down from the root.
- EXPECT(walker.Down());
- EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
- EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.VMTagName());
if (!FLAG_enable_interpreter) {
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT_EQ(1, walker.CurrentExclusiveTicks());
EXPECT(walker.Down());
}
EXPECT_STREQ("B.boo", walker.CurrentName());
- EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_STREQ("A", walker.CurrentToken());
EXPECT(walker.Down());
EXPECT_STREQ("B.oats", walker.CurrentName());
- EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_EQ(0, walker.CurrentExclusiveTicks());
EXPECT_STREQ("boo", walker.CurrentToken());
EXPECT(walker.Down());
EXPECT_STREQ("C.fox", walker.CurrentName());
- EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_EQ(0, walker.CurrentExclusiveTicks());
EXPECT_STREQ("oats", walker.CurrentToken());
EXPECT(walker.Down());
EXPECT_STREQ("C.+", walker.CurrentName());
- EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_EQ(0, walker.CurrentExclusiveTicks());
EXPECT_STREQ("fox", walker.CurrentToken());
EXPECT(walker.Down());
EXPECT_STREQ("C.bacon", walker.CurrentName());
- EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_EQ(0, walker.CurrentExclusiveTicks());
EXPECT_STREQ("+", walker.CurrentToken());
EXPECT(walker.Down());
EXPECT_STREQ("main", walker.CurrentName());
- EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_EQ(0, walker.CurrentExclusiveTicks());
EXPECT_STREQ("bacon", walker.CurrentToken());
@@ -2643,53 +2299,42 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate->main_port(), class_a.id());
- profile.Build(thread, &filter, Profiler::sample_buffer(), Profile::kNoTags);
+ profile.Build(thread, &filter, Profiler::sample_buffer());
// We should have one allocation samples.
EXPECT_EQ(1, profile.sample_count());
- ProfileTrieWalker walker(&profile);
+ ProfileStackWalker walker(&profile, true);
- // Exclusive function: B.boo -> main.
- walker.Reset(Profile::kExclusiveFunction);
- // Move down from the root.
- EXPECT(walker.Down());
- EXPECT_STREQ("DRT_AllocateObject", walker.CurrentName());
- EXPECT(walker.Down());
+ EXPECT_STREQ("DRT_AllocateObject", walker.VMTagName());
if (!FLAG_enable_interpreter) {
EXPECT_STREQ("[Stub] Allocate A", walker.CurrentName());
EXPECT_EQ(1, walker.CurrentExclusiveTicks());
EXPECT(walker.Down());
}
EXPECT_STREQ("B.boo", walker.CurrentName());
- EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_STREQ("A", walker.CurrentToken());
EXPECT(walker.Down());
EXPECT_STREQ("B.oats", walker.CurrentName());
- EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_EQ(0, walker.CurrentExclusiveTicks());
EXPECT_STREQ("boo", walker.CurrentToken());
EXPECT(walker.Down());
EXPECT_STREQ("C.fox", walker.CurrentName());
- EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_EQ(0, walker.CurrentExclusiveTicks());
EXPECT_STREQ("oats", walker.CurrentToken());
EXPECT(walker.Down());
EXPECT_STREQ("C.+", walker.CurrentName());
- EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_EQ(0, walker.CurrentExclusiveTicks());
EXPECT_STREQ("fox", walker.CurrentToken());
EXPECT(walker.Down());
EXPECT_STREQ("C.bacon", walker.CurrentName());
- EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_EQ(0, walker.CurrentExclusiveTicks());
EXPECT_STREQ("+", walker.CurrentToken());
EXPECT(walker.Down());
EXPECT_STREQ("main", walker.CurrentName());
- EXPECT_EQ(1, walker.CurrentNodeTickCount());
EXPECT_EQ(1, walker.CurrentInclusiveTicks());
EXPECT_EQ(0, walker.CurrentExclusiveTicks());
EXPECT_STREQ("bacon", walker.CurrentToken());
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index d937e14..1f2ccdb 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -637,4 +637,29 @@
}
END_LEAF_RUNTIME_ENTRY
+const char* RawPcDescriptors::KindToCString(Kind k) {
+ switch (k) {
+#define ENUM_CASE(name, init) \
+ case Kind::k##name: \
+ return #name;
+ FOR_EACH_RAW_PC_DESCRIPTOR(ENUM_CASE)
+#undef ENUM_CASE
+ default:
+ return nullptr;
+ }
+}
+
+bool RawPcDescriptors::KindFromCString(const char* cstr, Kind* out) {
+ ASSERT(cstr != nullptr && out != nullptr);
+#define ENUM_CASE(name, init) \
+ if (strcmp(#name, cstr) == 0) { \
+ *out = Kind::k##name; \
+ return true; \
+ }
+ FOR_EACH_RAW_PC_DESCRIPTOR(ENUM_CASE)
+#undef ENUM_CASE
+ return false;
+}
+#undef PREFIXED_NAME
+
} // namespace dart
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 7d9126c..fc8dfc7 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -65,6 +65,7 @@
enum class MemoryOrder {
kRelaxed,
kRelease,
+ kAcquire,
};
#define SNAPSHOT_WRITER_SUPPORT() \
@@ -689,7 +690,7 @@
friend class RawInstance;
friend class Scavenger;
friend class ScavengerVisitor;
- friend class ImageReader; // tags_ check
+ friend class ImageReader; // tags_ check
friend class ImageWriter;
friend class AssemblyImageWriter;
friend class BlobImageWriter;
@@ -716,9 +717,9 @@
class RawClass : public RawObject {
public:
enum ClassFinalizedState {
- kAllocated = 0, // Initial state.
- kPreFinalized, // VM classes: size precomputed, but no checks done.
- kFinalized, // Class parsed, finalized and ready for use.
+ kAllocated = 0, // Initial state.
+ kPreFinalized, // VM classes: size precomputed, but no checks done.
+ kFinalized, // Class parsed, finalized and ready for use.
};
enum ClassLoadingState {
// Class object is created, but it is not filled up.
@@ -750,13 +751,13 @@
RawTypeArguments* type_parameters_; // Array of TypeParameter.
RawAbstractType* super_type_;
RawFunction* signature_function_; // Associated function for typedef class.
- RawArray* constants_; // Canonicalized const instances of this class.
- RawType* declaration_type_; // Declaration type for this class.
+ RawArray* constants_; // Canonicalized const instances of this class.
+ RawType* declaration_type_; // Declaration type for this class.
RawArray* invocation_dispatcher_cache_; // Cache for dispatcher functions.
RawCode* allocation_stub_; // Stub code for allocation of instances.
RawGrowableObjectArray* direct_implementors_; // Array of Class.
- RawGrowableObjectArray* direct_subclasses_; // Array of Class.
- RawArray* dependent_code_; // CHA optimized codes.
+ RawGrowableObjectArray* direct_subclasses_; // Array of Class.
+ RawArray* dependent_code_; // CHA optimized codes.
VISIT_TO(RawObject*, dependent_code_);
RawObject** to_snapshot(Snapshot::Kind kind) {
switch (kind) {
@@ -837,33 +838,78 @@
class RawFunction : public RawObject {
public:
+ // When you add a new kind, please also update the observatory to account
+ // for the new string returned by KindToCString().
+ // - runtime/observatory/lib/src/models/objects/function.dart (FunctionKind)
+ // - runtime/observatory/lib/src/elements/function_view.dart
+ // (_functionKindToString)
+ // - runtime/observatory/lib/src/service/object.dart (stringToFunctionKind)
+#define FOR_EACH_RAW_FUNCTION_KIND(V) \
+ /* an ordinary or operator method */ \
+ V(RegularFunction) \
+ /* a user-declared closure function */ \
+ V(ClosureFunction) \
+ /* an implicit closure (i.e., tear-off) */ \
+ V(ImplicitClosureFunction) \
+ /* a signature only without actual code */ \
+ V(SignatureFunction) \
+ /* getter functions e.g: get foo() { .. } */ \
+ V(GetterFunction) \
+ /* setter functions e.g: set foo(..) { .. } */ \
+ V(SetterFunction) \
+ /* a generative (is_static=false) or factory (is_static=true) constructor */ \
+ V(Constructor) \
+ /* an implicit getter for instance fields */ \
+ V(ImplicitGetter) \
+ /* an implicit setter for instance fields */ \
+ V(ImplicitSetter) \
+ /* represents an implicit getter for static fields with initializers */ \
+ V(ImplicitStaticGetter) \
+ /* the initialization expression for a static or instance field */ \
+ V(FieldInitializer) \
+ /* return a closure on the receiver for tear-offs */ \
+ V(MethodExtractor) \
+ /* builds an Invocation and invokes noSuchMethod */ \
+ V(NoSuchMethodDispatcher) \
+ /* invokes a field as a closure (i.e., call-through-getter) */ \
+ V(InvokeFieldDispatcher) \
+ /* a generated irregexp matcher function. */ \
+ V(IrregexpFunction) \
+ /* a forwarder which performs type checks for arguments of a dynamic call */ \
+ /* (i.e., those checks omitted by the caller for interface calls). */ \
+ V(DynamicInvocationForwarder) \
+ V(FfiTrampoline)
+
enum Kind {
- kRegularFunction, // an ordinary or operator method
- kClosureFunction, // a user-declared closure function
- kImplicitClosureFunction, // an implicit closure (i.e., tear-off)
- kSignatureFunction, // a signature only without actual code
- kGetterFunction, // getter functions e.g: get foo() { .. }
- kSetterFunction, // setter functions e.g: set foo(..) { .. }
- kConstructor, // a generative (is_static=false) or
- // factory (is_static=true) constructor
- kImplicitGetter, // an implicit getter for instance fields
- kImplicitSetter, // an implicit setter for instance fields
- kImplicitStaticGetter, // represents an implicit getter for static
- // fields with initializers
- kFieldInitializer, // the initialization expression for a static
- // or instance field
- kMethodExtractor, // return a closure on the receiver for tear-offs
- kNoSuchMethodDispatcher, // builds an Invocation and invokes noSuchMethod
- kInvokeFieldDispatcher, // invokes a field as a closure (i.e.,
- // call-through-getter)
- kIrregexpFunction, // a generated irregexp matcher function.
- kDynamicInvocationForwarder, // a forwarder which performs type checks for
- // arguments of a dynamic call (i.e., those
- // checks omitted by the caller for interface
- // calls).
- kFfiTrampoline,
+#define KIND_DEFN(Name) k##Name,
+ FOR_EACH_RAW_FUNCTION_KIND(KIND_DEFN)
+#undef KIND_DEFN
};
+ static const char* KindToCString(Kind k) {
+ switch (k) {
+#define KIND_CASE(Name) \
+ case Kind::k##Name: \
+ return #Name;
+ FOR_EACH_RAW_FUNCTION_KIND(KIND_CASE)
+#undef KIND_CASE
+ default:
+ UNREACHABLE();
+ return nullptr;
+ }
+ }
+
+ static bool KindFromCString(const char* str, Kind* out) {
+#define KIND_CASE(Name) \
+ if (strcmp(str, #Name) == 0) { \
+ *out = Kind::k##Name; \
+ return true; \
+ }
+ FOR_EACH_RAW_FUNCTION_KIND(KIND_CASE)
+#undef KIND_CASE
+ return false;
+ }
+
enum AsyncModifier {
kNoModifier = 0x0,
kAsyncBit = 0x1,
@@ -881,7 +927,7 @@
RAW_HEAP_OBJECT_IMPLEMENTATION(Function);
- uword entry_point_; // Accessed from generated code.
+ uword entry_point_; // Accessed from generated code.
uword unchecked_entry_point_; // Accessed from generated code.
VISIT_FROM(RawObject*, name_);
@@ -924,11 +970,10 @@
NOT_IN_PRECOMPILED(TokenPosition token_pos_);
NOT_IN_PRECOMPILED(TokenPosition end_token_pos_);
- uint32_t kind_tag_; // See Function::KindTagBits.
+ uint32_t kind_tag_; // See Function::KindTagBits.
uint32_t packed_fields_;
- typedef BitField<uint32_t, bool, 0, 1>
- PackedHasNamedOptionalParameters;
+ typedef BitField<uint32_t, bool, 0, 1> PackedHasNamedOptionalParameters;
typedef BitField<uint32_t,
bool,
PackedHasNamedOptionalParameters::kNextBit,
@@ -1160,7 +1205,6 @@
kLoadRequested, // Compiler or script requested load of library.
kLoadInProgress, // Library is in the process of being loaded.
kLoaded, // Library is loaded.
- kLoadError, // Error occurred during load of the Library.
};
RAW_HEAP_OBJECT_IMPLEMENTATION(Library);
@@ -1175,12 +1219,11 @@
RawGrowableObjectArray* owned_scripts_;
RawArray* imports_; // List of Namespaces imported without prefix.
RawArray* exports_; // List of re-exported Namespaces.
- RawInstance* load_error_; // Error iff load_state_ == kLoadError.
RawExternalTypedData* kernel_data_;
RawObject** to_snapshot(Snapshot::Kind kind) {
switch (kind) {
case Snapshot::kFullAOT:
- return reinterpret_cast<RawObject**>(&ptr()->load_error_);
+ return reinterpret_cast<RawObject**>(&ptr()->exports_);
case Snapshot::kFull:
case Snapshot::kFullJIT:
return reinterpret_cast<RawObject**>(&ptr()->kernel_data_);
@@ -1258,7 +1301,7 @@
class RawCode : public RawObject {
RAW_HEAP_OBJECT_IMPLEMENTATION(Code);
- uword entry_point_; // Accessed from generated code.
+ uword entry_point_; // Accessed from generated code.
// In AOT this entry-point supports switchable calls. It checks the type of
// the receiver on entry to the function and calls a stub to patch up the
@@ -1294,7 +1337,7 @@
// type checks are necessary or this Code belongs to a stub). In this case
// 'unchecked_entry_point_' will refer to the same position as 'entry_point_'.
//
- uword unchecked_entry_point_; // Accessed from generated code.
+ uword unchecked_entry_point_; // Accessed from generated code.
uword monomorphic_unchecked_entry_point_; // Accessed from generated code.
VISIT_FROM(RawObject*, object_pool_);
@@ -1374,11 +1417,13 @@
VISIT_TO(RawObject*, var_descriptors_);
#endif
- RawObject** to_snapshot(Snapshot::Kind kind) { return to(); }
+ RawObject** to_snapshot(Snapshot::Kind kind) {
+ return reinterpret_cast<RawObject**>(&ptr()->pc_descriptors_);
+ }
int32_t instructions_binary_offset_;
int32_t source_positions_binary_offset_;
- NOT_IN_PRODUCT(int32_t local_variables_binary_offset_);
+ int32_t local_variables_binary_offset_;
static bool ContainsPC(RawObject* raw_obj, uword pc);
@@ -1451,18 +1496,39 @@
class RawPcDescriptors : public RawObject {
public:
+// The macro argument V is passed two arguments, the raw name of the enum value
+// and the initialization expression used within the enum definition. The uses
+// of enum values inside the initialization expression are hardcoded currently,
+// so the second argument is useless outside the enum definition and should be
+// dropped by other users of this macro.
+#define FOR_EACH_RAW_PC_DESCRIPTOR(V) \
+ /* Deoptimization continuation point. */ \
+ V(Deopt, 1) \
+ /* IC call. */ \
+ V(IcCall, kDeopt << 1) \
+ /* Call to a known target via stub. */ \
+ V(UnoptStaticCall, kIcCall << 1) \
+ /* Runtime call. */ \
+ V(RuntimeCall, kUnoptStaticCall << 1) \
+ /* OSR entry point in unopt. code. */ \
+ V(OsrEntry, kRuntimeCall << 1) \
+ /* Call rewind target address. */ \
+ V(Rewind, kOsrEntry << 1) \
+ /* Target-word-size relocation. */ \
+ V(BSSRelocation, kRewind << 1) \
+ V(Other, kBSSRelocation << 1) \
+ V(AnyKind, -1)
+
enum Kind {
- kDeopt = 1, // Deoptimization continuation point.
- kIcCall = kDeopt << 1, // IC call.
- kUnoptStaticCall = kIcCall << 1, // Call to a known target via stub.
- kRuntimeCall = kUnoptStaticCall << 1, // Runtime call.
- kOsrEntry = kRuntimeCall << 1, // OSR entry point in unopt. code.
- kRewind = kOsrEntry << 1, // Call rewind target address.
- kOther = kRewind << 1,
- kLastKind = kOther,
- kAnyKind = -1
+#define ENUM_DEF(name, init) k##name = init,
+ FOR_EACH_RAW_PC_DESCRIPTOR(ENUM_DEF)
+#undef ENUM_DEF
+ kLastKind = kOther,
};
+ static const char* KindToCString(Kind k);
+ static bool KindFromCString(const char* cstr, Kind* out);
+
class MergedKindTry {
public:
// Most of the time try_index will be small and merged field will fit into
@@ -1850,9 +1916,7 @@
RawString* name_; // Library prefix name.
RawLibrary* importer_; // Library which declares this prefix.
RawArray* imports_; // Libraries imported with this prefix.
- RawArray* dependent_code_; // Code that refers to deferred, unloaded
- // library prefix.
- VISIT_TO(RawObject*, dependent_code_)
+ VISIT_TO(RawObject*, imports_)
RawObject** to_snapshot(Snapshot::Kind kind) {
switch (kind) {
case Snapshot::kFull:
@@ -1870,7 +1934,6 @@
}
uint16_t num_imports_; // Number of library entries in libraries_.
bool is_deferred_load_;
- bool is_loaded_;
};
class RawTypeArguments : public RawInstance {
@@ -2077,10 +2140,6 @@
private:
friend class Library;
- friend class OneByteStringSerializationCluster;
- friend class TwoByteStringSerializationCluster;
- friend class OneByteStringDeserializationCluster;
- friend class TwoByteStringDeserializationCluster;
friend class RODataSerializationCluster;
friend class ImageWriter;
};
diff --git a/runtime/vm/raw_object_fields.cc b/runtime/vm/raw_object_fields.cc
index f90a01d..3dc239b 100644
--- a/runtime/vm/raw_object_fields.cc
+++ b/runtime/vm/raw_object_fields.cc
@@ -73,7 +73,6 @@
F(Library, owned_scripts_) \
F(Library, imports_) \
F(Library, exports_) \
- F(Library, load_error_) \
F(Library, kernel_data_) \
F(Library, resolved_names_) \
F(Library, exported_names_) \
@@ -138,7 +137,6 @@
F(LibraryPrefix, name_) \
F(LibraryPrefix, importer_) \
F(LibraryPrefix, imports_) \
- F(LibraryPrefix, dependent_code_) \
F(TypeArguments, instantiations_) \
F(TypeArguments, length_) \
F(TypeArguments, hash_) \
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index 22a7016..6773141 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -1311,6 +1311,7 @@
intptr_t length_in_bytes = len * element_size;
NoSafepointScope no_safepoint;
uint8_t* data = reinterpret_cast<uint8_t*>(result.DataAddr(0));
+ reader->Align(Zone::kAlignment);
reader->ReadBytes(data, length_in_bytes);
// If it is a canonical constant make it one.
@@ -1456,6 +1457,7 @@
writer->WriteTags(writer->GetObjectTags(this));
writer->Write<RawObject*>(ptr()->length_);
uint8_t* data = reinterpret_cast<uint8_t*>(ptr()->data());
+ writer->Align(Zone::kAlignment);
writer->WriteBytes(data, bytes);
}
}
diff --git a/runtime/vm/regexp.cc b/runtime/vm/regexp.cc
index 12796de..23efd9d 100644
--- a/runtime/vm/regexp.cc
+++ b/runtime/vm/regexp.cc
@@ -3556,7 +3556,7 @@
void DotPrinter::PrintNode(const char* label, RegExpNode* node) {
OS::PrintErr("digraph G {\n graph [label=\"");
- for (intptr_t i = 0; label[i]; i++) {
+ for (intptr_t i = 0; label[i] != '\0'; i++) {
switch (label[i]) {
case '\\':
OS::PrintErr("\\\\");
@@ -5286,7 +5286,7 @@
const Function& function = parsed_function->function();
const intptr_t specialization_cid = function.string_specialization_cid();
- const intptr_t is_sticky = function.is_sticky_specialization();
+ const bool is_sticky = function.is_sticky_specialization();
const bool is_one_byte = (specialization_cid == kOneByteStringCid ||
specialization_cid == kExternalOneByteStringCid);
RegExp& regexp = RegExp::Handle(zone, function.regexp());
diff --git a/runtime/vm/regexp_ast.h b/runtime/vm/regexp_ast.h
index 4fb64a3..6301d4d 100644
--- a/runtime/vm/regexp_ast.h
+++ b/runtime/vm/regexp_ast.h
@@ -204,10 +204,10 @@
// * : All characters
uint16_t standard_type() const { return set_.standard_set_type(); }
ZoneGrowableArray<CharacterRange>* ranges() { return set_.ranges(); }
- bool is_negated() const { return character_class_flags_ & NEGATED; }
+ bool is_negated() const { return (character_class_flags_ & NEGATED) != 0; }
RegExpFlags flags() const { return flags_; }
bool contains_split_surrogate() const {
- return character_class_flags_ & CONTAINS_SPLIT_SURROGATE;
+ return (character_class_flags_ & CONTAINS_SPLIT_SURROGATE) != 0;
}
private:
diff --git a/runtime/vm/regexp_parser.cc b/runtime/vm/regexp_parser.cc
index 40bf227..3f3bdf3 100644
--- a/runtime/vm/regexp_parser.cc
+++ b/runtime/vm/regexp_parser.cc
@@ -1506,7 +1506,7 @@
UErrorCode ec = U_ZERO_ERROR;
icu::UnicodeSet set;
set.applyIntPropertyValue(property, property_value, ec);
- bool success = ec == U_ZERO_ERROR && !set.isEmpty();
+ bool success = ec == U_ZERO_ERROR && (set.isEmpty() == 0);
if (success) {
set.removeAllStrings();
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index 1049692..3641e8a 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -1131,7 +1131,7 @@
if (Debugger::IsDebugging(thread, caller_function)) return;
#endif
- intptr_t num_checks = ic_data.NumberOfChecks();
+ const intptr_t num_checks = ic_data.NumberOfChecks();
// Monomorphic call.
if (FLAG_unopt_monomorphic_calls && (num_checks == 1)) {
@@ -1168,7 +1168,7 @@
const Array& descriptor =
Array::Handle(zone, ic_data.arguments_descriptor());
const MegamorphicCache& cache = MegamorphicCache::Handle(
- zone, MegamorphicCacheTable::LookupOriginal(thread, name, descriptor));
+ zone, MegamorphicCacheTable::Lookup(thread, name, descriptor));
ic_data.set_is_megamorphic(true);
CodePatcher::PatchInstanceCallAt(caller_frame->pc(), caller_code, cache,
StubCode::MegamorphicCall());
@@ -1795,8 +1795,7 @@
if (number_of_checks > FLAG_max_polymorphic_checks) {
// Switch to megamorphic call.
const MegamorphicCache& cache = MegamorphicCache::Handle(
- zone,
- MegamorphicCacheTable::LookupOriginal(thread, name, descriptor));
+ zone, MegamorphicCacheTable::Lookup(thread, name, descriptor));
DartFrameIterator iterator(thread,
StackFrameIterator::kNoCrossThreadIteration);
StackFrame* miss_function_frame = iterator.NextFrame();
@@ -2054,12 +2053,12 @@
}
}
}
- if ((FLAG_deoptimize_filter != NULL) || (FLAG_stacktrace_filter != NULL) ||
- FLAG_reload_every) {
+ if (FLAG_deoptimize_filter != nullptr || FLAG_stacktrace_filter != nullptr ||
+ (FLAG_reload_every != 0)) {
DartFrameIterator iterator(thread,
StackFrameIterator::kNoCrossThreadIteration);
StackFrame* frame = iterator.NextFrame();
- ASSERT(frame != NULL);
+ ASSERT(frame != nullptr);
Code& code = Code::Handle();
Function& function = Function::Handle();
if (frame->is_interpreted()) {
@@ -2071,21 +2070,22 @@
}
ASSERT(!function.IsNull());
const char* function_name = function.ToFullyQualifiedCString();
- ASSERT(function_name != NULL);
+ ASSERT(function_name != nullptr);
if (!code.IsNull()) {
if (!code.is_optimized() && FLAG_reload_every_optimized) {
// Don't do the reload if we aren't inside optimized code.
do_reload = false;
}
- if (code.is_optimized() && FLAG_deoptimize_filter != NULL &&
- strstr(function_name, FLAG_deoptimize_filter) != NULL) {
+ if (code.is_optimized() && FLAG_deoptimize_filter != nullptr &&
+ strstr(function_name, FLAG_deoptimize_filter) != nullptr &&
+ !function.ForceOptimize()) {
OS::PrintErr("*** Forcing deoptimization (%s)\n",
function.ToFullyQualifiedCString());
do_deopt = true;
}
}
- if (FLAG_stacktrace_filter != NULL &&
- strstr(function_name, FLAG_stacktrace_filter) != NULL) {
+ if (FLAG_stacktrace_filter != nullptr &&
+ strstr(function_name, FLAG_stacktrace_filter) != nullptr) {
OS::PrintErr("*** Computing stacktrace (%s)\n",
function.ToFullyQualifiedCString());
do_stacktrace = true;
@@ -2149,15 +2149,18 @@
intptr_t num_frames = stack->Length();
for (intptr_t i = 0; i < num_frames; i++) {
ActivationFrame* frame = stack->FrameAt(i);
-#ifndef DART_PRECOMPILED_RUNTIME
- if (!frame->IsInterpreted() && !frame->function().ForceOptimize()) {
- // Ensure that we have unoptimized code.
- frame->function().EnsureHasCompiledUnoptimizedCode();
- }
- const int num_vars = frame->NumLocalVariables();
-#else
+ int num_vars = 0;
// Variable locations and number are unknown when precompiling.
- const int num_vars = 0;
+#if !defined(DART_PRECOMPILED_RUNTIME)
+ // NumLocalVariables() can call EnsureHasUnoptimizedCode() for
+ // non-interpreted functions.
+ if (!frame->function().ForceOptimize()) {
+ if (!frame->IsInterpreted()) {
+ // Ensure that we have unoptimized code.
+ frame->function().EnsureHasCompiledUnoptimizedCode();
+ }
+ num_vars = frame->NumLocalVariables();
+ }
#endif
TokenPosition unused = TokenPosition::kNoSource;
for (intptr_t v = 0; v < num_vars; v++) {
@@ -2750,11 +2753,11 @@
THR_Print("== Deoptimizing code for '%s', %s, %s\n",
function.ToFullyQualifiedCString(),
deoptimizing_code ? "code & frame" : "frame",
- is_lazy_deopt ? "lazy-deopt" : "");
+ (is_lazy_deopt != 0u) ? "lazy-deopt" : "");
}
#if !defined(TARGET_ARCH_DBC)
- if (is_lazy_deopt) {
+ if (is_lazy_deopt != 0u) {
uword deopt_pc = isolate->FindPendingDeopt(caller_frame->fp());
if (FLAG_trace_deoptimization) {
THR_Print("Lazy deopt fp=%" Pp " pc=%" Pp "\n", caller_frame->fp(),
diff --git a/runtime/vm/scope_timer.h b/runtime/vm/scope_timer.h
index c910e34..0707980 100644
--- a/runtime/vm/scope_timer.h
+++ b/runtime/vm/scope_timer.h
@@ -5,8 +5,11 @@
#ifndef RUNTIME_VM_SCOPE_TIMER_H_
#define RUNTIME_VM_SCOPE_TIMER_H_
+#include "platform/allocation.h"
#include "platform/globals.h"
+#include "vm/os.h"
+
namespace dart {
// Simple utility class for timing a block of code.
diff --git a/runtime/vm/scopes.h b/runtime/vm/scopes.h
index 71ef849..69e8510 100644
--- a/runtime/vm/scopes.h
+++ b/runtime/vm/scopes.h
@@ -60,7 +60,7 @@
explicit VariableIndex(int value = kInvalidIndex) : value_(value) {}
- int operator==(const VariableIndex& other) { return value_ == other.value_; }
+ bool operator==(const VariableIndex& other) { return value_ == other.value_; }
bool IsValid() const { return value_ != kInvalidIndex; }
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index d212875..4ab9c57 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -146,7 +146,7 @@
return true;
}
}
- if (stream_listen_callback_) {
+ if (stream_listen_callback_ != nullptr) {
Thread* T = Thread::Current();
TransitionVMToNative transition(T);
return (*stream_listen_callback_)(stream_id);
@@ -165,7 +165,7 @@
return;
}
}
- if (stream_cancel_callback_) {
+ if (stream_cancel_callback_ != nullptr) {
Thread* T = Thread::Current();
TransitionVMToNative transition(T);
return (*stream_cancel_callback_)(stream_id);
@@ -2041,7 +2041,7 @@
Breakpoint* bpt = NULL;
if (GetIntegerId(rest, &bpt_id)) {
bpt = isolate->debugger()->GetBreakpointById(bpt_id);
- if (bpt) {
+ if (bpt != nullptr) {
*result = ObjectIdRing::kValid;
return bpt;
}
@@ -3828,100 +3828,30 @@
return true;
}
-static const char* const tags_enum_names[] = {
- "None", "UserVM", "UserOnly", "VMUser", "VMOnly", NULL,
-};
-
-static const Profile::TagOrder tags_enum_values[] = {
- Profile::kNoTags, Profile::kUserVM, Profile::kUser,
- Profile::kVMUser, Profile::kVM,
- Profile::kNoTags, // Default value.
-};
-
-static const MethodParameter* get_cpu_profile_params[] = {
+static const MethodParameter* get_cpu_samples_params[] = {
RUNNABLE_ISOLATE_PARAMETER,
- new EnumParameter("tags", true, tags_enum_names),
- new BoolParameter("_codeTransitionTags", false),
new Int64Parameter("timeOriginMicros", false),
new Int64Parameter("timeExtentMicros", false),
NULL,
};
-// TODO(johnmccutchan): Rename this to GetCpuSamples.
-static bool GetCpuProfile(Thread* thread, JSONStream* js) {
- if (CheckProfilerDisabled(thread, js)) {
- return true;
- }
-
- Profile::TagOrder tag_order =
- EnumMapper(js->LookupParam("tags"), tags_enum_names, tags_enum_values);
- intptr_t extra_tags = 0;
- if (BoolParameter::Parse(js->LookupParam("_codeTransitionTags"))) {
- extra_tags |= ProfilerService::kCodeTransitionTagsBit;
- }
+static bool GetCpuSamples(Thread* thread, JSONStream* js) {
int64_t time_origin_micros =
Int64Parameter::Parse(js->LookupParam("timeOriginMicros"));
int64_t time_extent_micros =
Int64Parameter::Parse(js->LookupParam("timeExtentMicros"));
- ProfilerService::PrintJSON(js, tag_order, extra_tags, time_origin_micros,
- time_extent_micros);
- return true;
-}
-
-static const MethodParameter* get_cpu_profile_timeline_params[] = {
- RUNNABLE_ISOLATE_PARAMETER,
- new EnumParameter("tags", true, tags_enum_names),
- new Int64Parameter("timeOriginMicros", false),
- new Int64Parameter("timeExtentMicros", false),
- NULL,
-};
-
-static bool GetCpuProfileTimeline(Thread* thread, JSONStream* js) {
+ const bool include_code_samples =
+ BoolParameter::Parse(js->LookupParam("_code"), false);
if (CheckProfilerDisabled(thread, js)) {
return true;
}
-
- Profile::TagOrder tag_order =
- EnumMapper(js->LookupParam("tags"), tags_enum_names, tags_enum_values);
- int64_t time_origin_micros =
- Int64Parameter::Parse(js->LookupParam("timeOriginMicros"));
- int64_t time_extent_micros =
- Int64Parameter::Parse(js->LookupParam("timeExtentMicros"));
- bool code_trie = BoolParameter::Parse(js->LookupParam("code"), false);
- ProfilerService::PrintTimelineJSON(js, tag_order, time_origin_micros,
- time_extent_micros, code_trie);
- return true;
-}
-
-static const MethodParameter* write_cpu_profile_timeline_params[] = {
- RUNNABLE_ISOLATE_PARAMETER,
- new EnumParameter("tags", true, tags_enum_names),
- new Int64Parameter("timeOriginMicros", false),
- new Int64Parameter("timeExtentMicros", false),
- NULL,
-};
-
-static bool WriteCpuProfileTimeline(Thread* thread, JSONStream* js) {
- if (CheckProfilerDisabled(thread, js)) {
- return true;
- }
-
- Profile::TagOrder tag_order =
- EnumMapper(js->LookupParam("tags"), tags_enum_names, tags_enum_values);
- int64_t time_origin_micros =
- Int64Parameter::Parse(js->LookupParam("timeOriginMicros"));
- int64_t time_extent_micros =
- Int64Parameter::Parse(js->LookupParam("timeExtentMicros"));
- bool code_trie = BoolParameter::Parse(js->LookupParam("code"), true);
- ProfilerService::AddToTimeline(tag_order, time_origin_micros,
- time_extent_micros, code_trie);
- PrintSuccess(js); // The "result" is a side-effect in the timeline.
+ ProfilerService::PrintJSON(js, time_origin_micros, time_extent_micros,
+ include_code_samples);
return true;
}
static const MethodParameter* get_allocation_samples_params[] = {
RUNNABLE_ISOLATE_PARAMETER,
- new EnumParameter("tags", true, tags_enum_names),
new IdParameter("classId", false),
new Int64Parameter("timeOriginMicros", false),
new Int64Parameter("timeExtentMicros", false),
@@ -3929,8 +3859,6 @@
};
static bool GetAllocationSamples(Thread* thread, JSONStream* js) {
- Profile::TagOrder tag_order =
- EnumMapper(js->LookupParam("tags"), tags_enum_names, tags_enum_values);
int64_t time_origin_micros =
Int64Parameter::Parse(js->LookupParam("timeOriginMicros"));
int64_t time_extent_micros =
@@ -3940,8 +3868,11 @@
GetPrefixedIntegerId(class_id, "classes/", &cid);
Isolate* isolate = thread->isolate();
if (IsValidClassId(isolate, cid)) {
+ if (CheckProfilerDisabled(thread, js)) {
+ return true;
+ }
const Class& cls = Class::Handle(GetClassForId(isolate, cid));
- ProfilerService::PrintAllocationJSON(js, tag_order, cls, time_origin_micros,
+ ProfilerService::PrintAllocationJSON(js, cls, time_origin_micros,
time_extent_micros);
} else {
PrintInvalidParamError(js, "classId");
@@ -3951,32 +3882,38 @@
static const MethodParameter* get_native_allocation_samples_params[] = {
NO_ISOLATE_PARAMETER,
- new EnumParameter("tags", true, tags_enum_names),
new Int64Parameter("timeOriginMicros", false),
new Int64Parameter("timeExtentMicros", false),
NULL,
};
static bool GetNativeAllocationSamples(Thread* thread, JSONStream* js) {
- Profile::TagOrder tag_order =
- EnumMapper(js->LookupParam("tags"), tags_enum_names, tags_enum_values);
int64_t time_origin_micros =
Int64Parameter::Parse(js->LookupParam("timeOriginMicros"));
int64_t time_extent_micros =
Int64Parameter::Parse(js->LookupParam("timeExtentMicros"));
+ bool include_code_samples =
+ BoolParameter::Parse(js->LookupParam("_code"), false);
#if defined(DEBUG)
Isolate::Current()->heap()->CollectAllGarbage();
#endif
- ProfilerService::PrintNativeAllocationJSON(js, tag_order, time_origin_micros,
- time_extent_micros);
+ if (CheckProfilerDisabled(thread, js)) {
+ return true;
+ }
+ ProfilerService::PrintNativeAllocationJSON(
+ js, time_origin_micros, time_extent_micros, include_code_samples);
return true;
}
-static const MethodParameter* clear_cpu_profile_params[] = {
- RUNNABLE_ISOLATE_PARAMETER, NULL,
+static const MethodParameter* clear_cpu_samples_params[] = {
+ RUNNABLE_ISOLATE_PARAMETER,
+ NULL,
};
-static bool ClearCpuProfile(Thread* thread, JSONStream* js) {
+static bool ClearCpuSamples(Thread* thread, JSONStream* js) {
+ if (CheckProfilerDisabled(thread, js)) {
+ return true;
+ }
ProfilerService::ClearSamples();
PrintSuccess(js);
return true;
@@ -4029,17 +3966,6 @@
return GetAllocationProfileImpl(thread, js, true);
}
-static const MethodParameter* collect_all_garbage_params[] = {
- RUNNABLE_ISOLATE_PARAMETER, NULL,
-};
-
-static bool CollectAllGarbage(Thread* thread, JSONStream* js) {
- Isolate* isolate = thread->isolate();
- isolate->heap()->CollectAllGarbage(Heap::kDebugging);
- PrintSuccess(js);
- return true;
-}
-
static const MethodParameter* get_heap_map_params[] = {
RUNNABLE_ISOLATE_PARAMETER, NULL,
};
@@ -4778,8 +4704,8 @@
add_breakpoint_at_activation_params },
{ "_buildExpressionEvaluationScope", BuildExpressionEvaluationScope,
build_expression_evaluation_scope_params },
- { "_clearCpuProfile", ClearCpuProfile,
- clear_cpu_profile_params },
+ { "clearCpuSamples", ClearCpuSamples,
+ clear_cpu_samples_params },
{ "clearVMTimeline", ClearVMTimeline,
clear_vm_timeline_params, },
{ "_compileExpression", CompileExpression, compile_expression_params },
@@ -4799,12 +4725,8 @@
get_native_allocation_samples_params },
{ "getClassList", GetClassList,
get_class_list_params },
- { "_getCpuProfile", GetCpuProfile,
- get_cpu_profile_params },
- { "_getCpuProfileTimeline", GetCpuProfileTimeline,
- get_cpu_profile_timeline_params },
- { "_writeCpuProfileTimeline", WriteCpuProfileTimeline,
- write_cpu_profile_timeline_params },
+ { "getCpuSamples", GetCpuSamples,
+ get_cpu_samples_params },
{ "getFlagList", GetFlagList,
get_flag_list_params },
{ "_getHeapMap", GetHeapMap,
@@ -4891,8 +4813,6 @@
set_vm_name_params },
{ "setVMTimelineFlags", SetVMTimelineFlags,
set_vm_timeline_flags_params },
- { "_collectAllGarbage", CollectAllGarbage,
- collect_all_garbage_params },
{ "_getDefaultClassesAliases", GetDefaultClassesAliases,
get_default_classes_aliases_params },
};
diff --git a/runtime/vm/service.h b/runtime/vm/service.h
index 453e872..d1ce7a7 100644
--- a/runtime/vm/service.h
+++ b/runtime/vm/service.h
@@ -15,7 +15,7 @@
namespace dart {
#define SERVICE_PROTOCOL_MAJOR_VERSION 3
-#define SERVICE_PROTOCOL_MINOR_VERSION 26
+#define SERVICE_PROTOCOL_MINOR_VERSION 27
class Array;
class EmbedderServiceHandler;
diff --git a/runtime/vm/service/service.md b/runtime/vm/service/service.md
index b0ae846..b91b660 100644
--- a/runtime/vm/service/service.md
+++ b/runtime/vm/service/service.md
@@ -1,8 +1,8 @@
-# Dart VM Service Protocol 3.26
+# Dart VM Service Protocol 3.27
> Please post feedback to the [observatory-discuss group][discuss-list]
-This document describes of _version 3.25_ of the Dart VM Service Protocol. This
+This document describes of _version 3.27_ of the Dart VM Service Protocol. This
protocol is used to communicate with a running Dart Virtual Machine.
To use the Service Protocol, start the VM with the *--observe* flag.
@@ -27,10 +27,12 @@
- [addBreakpoint](#addbreakpoint)
- [addBreakpointWithScriptUri](#addbreakpointwithscripturi)
- [addBreakpointAtEntry](#addbreakpointatentry)
+ - [clearCpuSamples](#clearcpusamples)
- [clearVMTimeline](#clearvmtimeline)
- [evaluate](#evaluate)
- [evaluateInFrame](#evaluateinframe)
- [getAllocationProfile](#getallocationprofile)
+ - [getCpuSamples](#getcpusamples)
- [getFlagList](#getflaglist)
- [getInstances](#getinstances)
- [getInboundReferences](#getinboundreferences)
@@ -73,6 +75,8 @@
- [CodeKind](#codekind)
- [Context](#context)
- [ContextElement](#contextelement)
+ - [CpuSamples](#cpusamples)
+ - [CpuSample](#cpusample)
- [Error](#error)
- [ErrorKind](#errorkind)
- [Event](#event)
@@ -94,6 +98,7 @@
- [MapAssociation](#mapassociation)
- [MemoryUsage](#memoryusage)
- [Message](#message)
+ - [NativeFunction](#nativefunction)
- [Null](#null)
- [Object](#object)
- [ReloadReport](#reloadreport)
@@ -509,6 +514,15 @@
Note that breakpoints are added and removed on a per-isolate basis.
+### clearCpuSamples
+
+```
+Success clearCpuSamples(string isolateId)
+```
+
+Clears all CPU profiling samples.
+
+See [Success](#success).
### clearVMTimeline
@@ -651,6 +665,22 @@
before collecting allocation information. There is no guarantee that a garbage
collection will be actually be performed.
+### getCpuSamples
+
+```
+CpuSamples getCpuSamples(string isolateId,
+ int timeOriginMicros,
+ int timeExtentMicros)
+```
+
+The _getCpuSamples_ RPC is used to retrieve samples collected by the CPU
+profiler. Only samples collected in the time range `[timeOriginMicros,
+timeOriginMicros + timeExtentMicros]` will be reported.
+
+If the profiler is disabled, an error response will be returned.
+
+See [CpuSamples](#cpusamples).
+
### getFlagList
```
@@ -1549,6 +1579,83 @@
}
```
+### CpuSamples
+
+```
+class CpuSamples extends Response {
+ // The sampling rate for the profiler in microseconds.
+ int samplePeriod;
+
+ // The maximum possible stack depth for samples.
+ int maxStackDepth;
+
+ // The number of samples returned.
+ int sampleCount;
+
+ // The timespan the set of returned samples covers, in microseconds.
+ int timeSpan;
+
+ // The start of the period of time in which the returned samples were
+ // collected.
+ int timeOriginMicros;
+
+ // The duration of time covered by the returned samples.
+ int timeExtentMicros;
+
+ // The process ID for the VM.
+ int pid;
+
+ // A list of functions seen in the relevant samples. These references can be
+ // looked up using the indicies provided in a `CpuSample` `stack` to determine
+ // which function was on the stack.
+ ProfileFunction[] functions;
+
+ // A list of samples collected in the range
+ // `[timeOriginMicros, timeOriginMicros + timeExtentMicros]`
+ CpuSample[] samples;
+}
+```
+
+See [getCpuSamples](#getcpusamples) and [CpuSample](#cpusample).
+
+### CpuSample
+
+```
+class CpuSample {
+ // The thread ID representing the thread on which this sample was collected.
+ int tid;
+
+ // The time this sample was collected in microseconds.
+ int timestamp;
+
+ // The name of VM tag set when this sample was collected. Omitted if the VM
+ // tag for the sample is not considered valid.
+ string vmTag [optional];
+
+ // The name of the User tag set when this sample was collected. Omitted if no
+ // User tag was set when this sample was collected.
+ string userTag [optional];
+
+ // Provided and set to true if the sample's stack was truncated. This can
+ // happen if the stack is deeper than the `stackDepth` in the `CpuSamples`
+ // response.
+ bool truncated [optional];
+
+ // The call stack at the time this sample was collected. The stack is to be
+ // interpreted as top to bottom. Each element in this array is a key into the
+ // `functions` array in `CpuSamples`.
+ //
+ // Example:
+ //
+ // `functions[stack[0]] = @Function(bar())`
+ // `functions[stack[1]] = @Function(foo())`
+ // `functions[stack[2]] = @Function(main())`
+ int[] stack;
+}
+```
+
+See [getCpuSamples](#getcpusamples) and [CpuSamples](#cpusamples).
+
### Error
```
@@ -2088,6 +2195,18 @@
// Provided for instance kinds:
// RegExp
@Instance pattern [optional];
+
+ // The function associated with a Closure instance.
+ //
+ // Provided for instance kinds:
+ // Closure
+ @Function closureFunction [optional];
+
+ // The context associated with a Closure instance.
+ //
+ // Provided for instance kinds:
+ // Closure
+ @Context closureContext [optional];
}
```
@@ -2239,18 +2358,6 @@
// Float64x2List
string bytes [optional];
- // The function associated with a Closure instance.
- //
- // Provided for instance kinds:
- // Closure
- @Function closureFunction [optional];
-
- // The context associated with a Closure instance.
- //
- // Provided for instance kinds:
- // Closure
- @Context closureContext [optional];
-
// The referent of a MirrorReference instance.
//
// Provided for instance kinds:
@@ -2690,6 +2797,17 @@
A _Message_ provides information about a pending isolate message and the
function that will be invoked to handle it.
+### NativeFunction
+
+```
+class NativeFunction {
+ // The name of the native function this object represents.
+ string name;
+}
+```
+
+A _NativeFunction_ object is used to represent native functions in profiler
+samples. See [CpuSamples](#cpusamples);
### Null
@@ -2764,6 +2882,33 @@
An _Object_ is a persistent object that is owned by some isolate.
+### ProfileFunction
+
+```
+class ProfileFunction {
+ // The kind of function this object represents.
+ string kind;
+
+ // The number of times function appeared on the stack during sampling events.
+ int inclusiveTicks;
+
+ // The number of times function appeared on the top of the stack during
+ // sampling events.
+ int exclusiveTicks;
+
+ // The resolved URL for the script containing function.
+ string resolvedUrl;
+
+ // The function captured during profiling.
+ (@Function|NativeFunction) function;
+}
+```
+
+A _ProfileFunction_ contains profiling information about a Dart or native
+function.
+
+See [CpuSamples](#cpusamples).
+
### ReloadReport
```
@@ -3323,5 +3468,6 @@
3.24 | Add `operatingSystem` property to `VM` object.
3.25 | Add 'getInboundReferences', 'getRetainingPath' RPCs, and 'InboundReferences', 'InboundReference', 'RetainingPath', and 'RetainingObject' objects.
3.26 | Add 'requestHeapSnapshot'.
+3.27 | Add 'clearCpuSamples', 'getCpuSamples' RPCs and 'CpuSamples', 'CpuSample' objects.
[discuss-list]: https://groups.google.com/a/dartlang.org/forum/#!forum/observatory-discuss
diff --git a/runtime/vm/service_isolate.cc b/runtime/vm/service_isolate.cc
index a0206b5..b01182b 100644
--- a/runtime/vm/service_isolate.cc
+++ b/runtime/vm/service_isolate.cc
@@ -81,6 +81,7 @@
Dart_Port ServiceIsolate::load_port_ = ILLEGAL_PORT;
Dart_Port ServiceIsolate::origin_ = ILLEGAL_PORT;
char* ServiceIsolate::server_address_ = NULL;
+char* ServiceIsolate::startup_failure_reason_ = nullptr;
void ServiceIsolate::RequestServerInfo(const SendPort& sp) {
const Array& message = Array::Handle(MakeServerControlMessage(
@@ -128,7 +129,7 @@
bool ServiceIsolate::IsServiceIsolate(const Isolate* isolate) {
MonitorLocker ml(monitor_);
- return isolate == isolate_;
+ return isolate != nullptr && isolate == isolate_;
}
bool ServiceIsolate::IsServiceIsolateDescendant(const Isolate* isolate) {
@@ -161,7 +162,8 @@
bool ServiceIsolate::SendServiceRpc(uint8_t* request_json,
intptr_t request_json_length,
- Dart_Port reply_port) {
+ Dart_Port reply_port,
+ char** error) {
// Keep in sync with "sdk/lib/vmservice/vmservice.dart:_handleNativeRpcCall".
Dart_CObject opcode;
opcode.type = Dart_CObject_kInt32;
@@ -190,7 +192,25 @@
request.value.as_array.length = ARRAY_SIZE(request_array);
ServiceIsolate::WaitForLoadPortInternal();
- return Dart_PostCObject(ServiceIsolate::Port(), &request);
+ Dart_Port service_port = ServiceIsolate::Port();
+
+ const bool success = Dart_PostCObject(service_port, &request);
+
+ if (!success && error != nullptr) {
+ if (service_port == ILLEGAL_PORT) {
+ if (startup_failure_reason_ != nullptr) {
+ *error = OS::SCreate(/*zone=*/nullptr,
+ "Service isolate failed to start up: %s.",
+ startup_failure_reason_);
+ } else {
+ *error = strdup("No service isolate port was found.");
+ }
+ } else {
+ *error = strdup("Was unable to post message to service isolate.");
+ }
+ }
+
+ return success;
}
bool ServiceIsolate::SendIsolateStartupMessage() {
@@ -318,10 +338,11 @@
ml.NotifyAll();
}
-void ServiceIsolate::InitializingFailed() {
+void ServiceIsolate::InitializingFailed(char* error) {
MonitorLocker ml(monitor_);
ASSERT(state_ == kStarting);
state_ = kStopped;
+ startup_failure_reason_ = error;
ml.NotifyAll();
}
@@ -350,10 +371,15 @@
": Isolate creation error: %s\n",
error);
}
+
+ char* formatted_error = OS::SCreate(
+ /*zone=*/nullptr, "Invoking the 'create_group' failed with: '%s'",
+ error);
+
free(error);
error = nullptr;
ServiceIsolate::SetServiceIsolate(NULL);
- ServiceIsolate::InitializingFailed();
+ ServiceIsolate::InitializingFailed(formatted_error);
return;
}
@@ -484,7 +510,8 @@
// that change this after Dart_Initialize returns.
create_group_callback_ = Isolate::CreateGroupCallback();
if (create_group_callback_ == NULL) {
- ServiceIsolate::InitializingFailed();
+ ServiceIsolate::InitializingFailed(
+ strdup("The 'create_group' callback was not provided"));
return;
}
bool task_started = Dart::thread_pool()->Run<RunServiceTask>();
@@ -547,6 +574,11 @@
free(server_address_);
server_address_ = NULL;
}
+
+ if (startup_failure_reason_ != nullptr) {
+ free(startup_failure_reason_);
+ startup_failure_reason_ = nullptr;
+ }
}
void ServiceIsolate::BootVmServiceLibrary() {
diff --git a/runtime/vm/service_isolate.h b/runtime/vm/service_isolate.h
index 25cef69..a3c1fdf 100644
--- a/runtime/vm/service_isolate.h
+++ b/runtime/vm/service_isolate.h
@@ -32,9 +32,14 @@
// Returns `true` if the request was sucessfully sent. If it was, the
// [reply_port] will receive a Dart_TypedData_kUint8 response json.
+ //
+ // If sending the rpc failed and [error] is not `nullptr` then [error] might
+ // be set to a string containting the reason for the failure. If so, the
+ // caller is responsible for free()ing the error.
static bool SendServiceRpc(uint8_t* request_json,
intptr_t request_json_length,
- Dart_Port reply_port);
+ Dart_Port reply_port,
+ char** error);
static void Run();
static bool SendIsolateStartupMessage();
@@ -66,7 +71,7 @@
static void SetLoadPort(Dart_Port port);
static void FinishedExiting();
static void FinishedInitializing();
- static void InitializingFailed();
+ static void InitializingFailed(char* error);
static void MaybeMakeServiceIsolate(Isolate* isolate);
static Dart_IsolateGroupCreateCallback create_group_callback() {
return create_group_callback_;
@@ -87,6 +92,10 @@
static Dart_Port origin_;
static char* server_address_;
+ // If starting the service-isolate failed, this error might provide the reason
+ // for the failure.
+ static char* startup_failure_reason_;
+
friend class Dart;
friend class Isolate;
friend class RunServiceTask;
diff --git a/runtime/vm/service_test.cc b/runtime/vm/service_test.cc
index 63ea6eb..7ba614a 100644
--- a/runtime/vm/service_test.cc
+++ b/runtime/vm/service_test.cc
@@ -718,25 +718,11 @@
}
Array& service_msg = Array::Handle();
- service_msg = Eval(lib, "[0, port, '0', '_getCpuProfile', [], []]");
- HandleIsolateMessage(isolate, service_msg);
- EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
- // Expect error (tags required).
- EXPECT_SUBSTRING("\"error\"", handler.msg());
-
- service_msg =
- Eval(lib, "[0, port, '0', '_getCpuProfile', ['tags'], ['None']]");
+ service_msg = Eval(lib, "[0, port, '0', 'getCpuSamples', [], []]");
HandleIsolateMessage(isolate, service_msg);
EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
// Expect profile
- EXPECT_SUBSTRING("\"type\":\"_CpuProfile\"", handler.msg());
-
- service_msg =
- Eval(lib, "[0, port, '0', '_getCpuProfile', ['tags'], ['Bogus']]");
- HandleIsolateMessage(isolate, service_msg);
- EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
- // Expect error.
- EXPECT_SUBSTRING("\"error\"", handler.msg());
+ EXPECT_SUBSTRING("\"type\":\"CpuSamples\"", handler.msg());
}
#endif // !defined(TARGET_ARCH_ARM64)
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index 65258de..7fbc4d5 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -636,7 +636,7 @@
const char* version = reinterpret_cast<const char*>(CurrentBufferAddress());
ASSERT(version != NULL);
- if (strncmp(version, expected_version, version_len)) {
+ if (strncmp(version, expected_version, version_len) != 0) {
const intptr_t kMessageBufferSize = 256;
char message_buffer[kMessageBufferSize];
char* actual_version = Utils::StrNDup(version, version_len);
@@ -660,7 +660,7 @@
ASSERT(features != NULL);
intptr_t buffer_len = Utils::StrNLen(features, PendingBytes());
if ((buffer_len != expected_len) ||
- strncmp(features, expected_features, expected_len)) {
+ (strncmp(features, expected_features, expected_len) != 0)) {
const intptr_t kMessageBufferSize = 256;
char message_buffer[kMessageBufferSize];
char* actual_features =
@@ -959,10 +959,13 @@
nodes_(),
first_unprocessed_object_id_(first_object_id) {
ASSERT(first_object_id > 0);
+ isolate()->set_forward_table_new(new WeakTable());
+ isolate()->set_forward_table_old(new WeakTable());
}
ForwardList::~ForwardList() {
- heap()->ResetObjectIdTable();
+ isolate()->set_forward_table_new(nullptr);
+ isolate()->set_forward_table_old(nullptr);
}
intptr_t ForwardList::AddObject(Zone* zone,
@@ -976,17 +979,33 @@
ASSERT(node != NULL);
nodes_.Add(node);
ASSERT(object_id != 0);
- heap()->SetObjectId(raw, object_id);
+ SetObjectId(raw, object_id);
return object_id;
}
intptr_t ForwardList::FindObject(RawObject* raw) {
NoSafepointScope no_safepoint;
- intptr_t id = heap()->GetObjectId(raw);
+ intptr_t id = GetObjectId(raw);
ASSERT(id == 0 || NodeForObjectId(id)->obj()->raw() == raw);
return (id == 0) ? static_cast<intptr_t>(kInvalidIndex) : id;
}
+void ForwardList::SetObjectId(RawObject* object, intptr_t id) {
+ if (object->IsNewObject()) {
+ isolate()->forward_table_new()->SetValue(object, id);
+ } else {
+ isolate()->forward_table_old()->SetValue(object, id);
+ }
+}
+
+intptr_t ForwardList::GetObjectId(RawObject* object) {
+ if (object->IsNewObject()) {
+ return isolate()->forward_table_new()->GetValue(object);
+ } else {
+ return isolate()->forward_table_old()->GetValue(object);
+ }
+}
+
bool SnapshotWriter::CheckAndWritePredefinedObject(RawObject* rawobj) {
// Check if object can be written in one of the following ways:
// - Smi: the Smi value is written as is (last bit is not tagged).
diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h
index 5f6c929..5c3b68e 100644
--- a/runtime/vm/snapshot.h
+++ b/runtime/vm/snapshot.h
@@ -196,9 +196,6 @@
const uint8_t* Addr() const { return reinterpret_cast<const uint8_t*>(this); }
const uint8_t* DataImage() const {
- if (!IncludesCode(kind())) {
- return NULL;
- }
uword offset = Utils::RoundUp(length(), OS::kMaxPreferredCodeAlignment);
return Addr() + offset;
}
@@ -255,6 +252,7 @@
return stream_.AddressOfCurrentPosition();
}
+ void Align(intptr_t value) { stream_.Align(value); }
void Advance(intptr_t value) { stream_.Advance(value); }
intptr_t PendingBytes() const { return stream_.PendingBytes(); }
@@ -517,6 +515,8 @@
Write<int8_t>(static_cast<int8_t>(flags));
}
+ void Align(intptr_t value) { stream_.Align(value); }
+
// Write out a buffer of bytes.
void WriteBytes(const uint8_t* addr, intptr_t len) {
stream_.WriteBytes(addr, len);
@@ -605,13 +605,16 @@
private:
intptr_t first_object_id() const { return first_object_id_; }
intptr_t next_object_id() const { return nodes_.length() + first_object_id_; }
- Heap* heap() const { return thread_->isolate()->heap(); }
+ Isolate* isolate() const { return thread_->isolate(); }
Thread* thread_;
const intptr_t first_object_id_;
GrowableArray<Node*> nodes_;
intptr_t first_unprocessed_object_id_;
+ void SetObjectId(RawObject* object, intptr_t id);
+ intptr_t GetObjectId(RawObject* object);
+
DISALLOW_COPY_AND_ASSIGN(ForwardList);
};
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index e05f475..3da6666 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -724,7 +724,8 @@
"}\n";
Dart_Handle result;
- uint8_t* isolate_snapshot_data_buffer;
+ uint8_t* isolate_snapshot_data_buffer = nullptr;
+ intptr_t isolate_snapshot_data_size = 0;
// Start an Isolate, load a script and create a full snapshot.
Timer timer1(true, "Snapshot_test");
@@ -749,17 +750,38 @@
OS::PrintErr("Without Snapshot: %" Pd64 "us\n", timer1.TotalElapsedTime());
// Write snapshot with object content.
- FullSnapshotWriter writer(Snapshot::kFull, NULL,
+ uint8_t* isolate_snapshot_text_buffer = nullptr;
+ BlobImageWriter image_writer(thread, &isolate_snapshot_text_buffer,
+ &malloc_allocator, 2 * MB /* initial_size */,
+ /*shared_objects=*/nullptr,
+ /*shared_instructions=*/nullptr,
+ /*reused_instructions=*/nullptr);
+ FullSnapshotWriter writer(Snapshot::kFull, nullptr,
&isolate_snapshot_data_buffer, &malloc_allocator,
- NULL, /*image_writer*/ nullptr);
+ nullptr, &image_writer);
writer.WriteFullSnapshot();
+ isolate_snapshot_data_size = writer.IsolateSnapshotSize();
+ free(isolate_snapshot_text_buffer);
}
+ // Malloc gives only 8 byte alignment, but we need
+ // OS::kMaxPreferredCodeAlignment. Rellocate to VirtualMemory to get page
+ // alignment.
+ std::unique_ptr<VirtualMemory> aligned_isolate_snapshot_data_buffer(
+ VirtualMemory::Allocate(
+ Utils::RoundUp(isolate_snapshot_data_size, VirtualMemory::PageSize()),
+ false, "snapshot_test"));
+ memmove(aligned_isolate_snapshot_data_buffer->address(),
+ isolate_snapshot_data_buffer, isolate_snapshot_data_size);
+ free(isolate_snapshot_data_buffer);
+ isolate_snapshot_data_buffer = nullptr;
+
// Now Create another isolate using the snapshot and execute a method
// from the script.
Timer timer2(true, "Snapshot_test");
timer2.Start();
- TestCase::CreateTestIsolateFromSnapshot(isolate_snapshot_data_buffer);
+ TestCase::CreateTestIsolateFromSnapshot(reinterpret_cast<uint8_t*>(
+ aligned_isolate_snapshot_data_buffer->address()));
{
Dart_EnterScope(); // Start a Dart API scope for invoking API functions.
timer2.Stop();
@@ -772,7 +794,6 @@
Dart_ExitScope();
}
Dart_ShutdownIsolate();
- free(isolate_snapshot_data_buffer);
}
// Helper function to call a top level Dart function and serialize the result.
diff --git a/runtime/vm/source_report.cc b/runtime/vm/source_report.cc
index 30bf604..59bc7a3 100644
--- a/runtime/vm/source_report.cc
+++ b/runtime/vm/source_report.cc
@@ -5,6 +5,7 @@
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
#include "vm/source_report.h"
+#include "vm/bit_vector.h"
#include "vm/compiler/jit/compiler.h"
#include "vm/isolate.h"
#include "vm/kernel_loader.h"
@@ -57,8 +58,7 @@
// Build the profile.
SampleFilter samplesForIsolate(thread_->isolate()->main_port(),
Thread::kMutatorTask, -1, -1);
- profile_.Build(thread, &samplesForIsolate, Profiler::sample_buffer(),
- Profile::kNoTags);
+ profile_.Build(thread, &samplesForIsolate, Profiler::sample_buffer());
}
}
@@ -330,11 +330,8 @@
const TokenPosition begin_pos = func.token_pos();
const TokenPosition end_pos = func.end_token_pos();
intptr_t func_length = (end_pos.Pos() - begin_pos.Pos()) + 1;
- GrowableArray<char> possible(func_length);
- possible.SetLength(func_length);
- for (int i = 0; i < func_length; i++) {
- possible[i] = false;
- }
+
+ BitVector possible(zone(), func_length);
if (code.IsNull()) {
const Bytecode& bytecode = Bytecode::Handle(func.bytecode());
@@ -354,7 +351,7 @@
// source position range.
if (bytecode.GetDebugCheckedOpcodeReturnAddress(
pc_offset, iter.PcOffset()) != 0) {
- possible[token_offset] = true;
+ possible.Add(token_offset);
}
pc_offset = kUwordMax;
}
@@ -373,7 +370,7 @@
}
if (pc_offset != kUwordMax && bytecode.GetDebugCheckedOpcodeReturnAddress(
pc_offset, bytecode.Size()) != 0) {
- possible[token_offset] = true;
+ possible.Add(token_offset);
}
} else {
const uint8_t kSafepointKind =
@@ -391,13 +388,13 @@
continue;
}
intptr_t token_offset = token_pos.Pos() - begin_pos.Pos();
- possible[token_offset] = true;
+ possible.Add(token_offset);
}
}
JSONArray bpts(jsobj, "possibleBreakpoints");
for (int i = 0; i < func_length; i++) {
- if (possible[i]) {
+ if (possible.Contains(i)) {
// Add the token position.
bpts.AddValue(begin_pos.Pos() + i);
}
diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc
index 0e61b72..2bdde95 100644
--- a/runtime/vm/stack_frame.cc
+++ b/runtime/vm/stack_frame.cc
@@ -515,8 +515,8 @@
ExceptionHandlerInfo* info = cache->Lookup(pc());
if (info != NULL) {
*handler_pc = start + info->handler_pc_offset;
- *needs_stacktrace = info->needs_stacktrace;
- *has_catch_all = info->has_catch_all;
+ *needs_stacktrace = (info->needs_stacktrace != 0);
+ *has_catch_all = (info->has_catch_all != 0);
return true;
}
@@ -544,8 +544,8 @@
ExceptionHandlerInfo handler_info;
handlers.GetHandlerInfo(try_index, &handler_info);
*handler_pc = start + handler_info.handler_pc_offset;
- *needs_stacktrace = handler_info.needs_stacktrace;
- *has_catch_all = handler_info.has_catch_all;
+ *needs_stacktrace = (handler_info.needs_stacktrace != 0);
+ *has_catch_all = (handler_info.has_catch_all != 0);
cache->Insert(pc(), handler_info);
return true;
}
diff --git a/runtime/vm/stack_frame.h b/runtime/vm/stack_frame.h
index fba676e..b36721d 100644
--- a/runtime/vm/stack_frame.h
+++ b/runtime/vm/stack_frame.h
@@ -56,7 +56,7 @@
return 0;
}
- uword IsMarkedForLazyDeopt() const {
+ bool IsMarkedForLazyDeopt() const {
ASSERT(!is_interpreted());
uword raw_pc =
*reinterpret_cast<uword*>(sp() + (kSavedPcSlotFromSp * kWordSize));
diff --git a/runtime/vm/stack_frame_arm.h b/runtime/vm/stack_frame_arm.h
index 6413989..c423a84 100644
--- a/runtime/vm/stack_frame_arm.h
+++ b/runtime/vm/stack_frame_arm.h
@@ -5,6 +5,10 @@
#ifndef RUNTIME_VM_STACK_FRAME_ARM_H_
#define RUNTIME_VM_STACK_FRAME_ARM_H_
+#if !defined(RUNTIME_VM_STACK_FRAME_H_)
+#error Do not include stack_frame_arm.h directly; use stack_frame.h instead.
+#endif
+
namespace dart {
/* ARM Dart Frame Layout
diff --git a/runtime/vm/stack_frame_arm64.h b/runtime/vm/stack_frame_arm64.h
index abaa49a..1558a22 100644
--- a/runtime/vm/stack_frame_arm64.h
+++ b/runtime/vm/stack_frame_arm64.h
@@ -5,6 +5,10 @@
#ifndef RUNTIME_VM_STACK_FRAME_ARM64_H_
#define RUNTIME_VM_STACK_FRAME_ARM64_H_
+#if !defined(RUNTIME_VM_STACK_FRAME_H_)
+#error Do not include stack_frame_arm64.h directly; use stack_frame.h instead.
+#endif
+
namespace dart {
/* ARM64 Dart Frame Layout
diff --git a/runtime/vm/stack_frame_dbc.h b/runtime/vm/stack_frame_dbc.h
index 42a1b79..616b012 100644
--- a/runtime/vm/stack_frame_dbc.h
+++ b/runtime/vm/stack_frame_dbc.h
@@ -5,6 +5,10 @@
#ifndef RUNTIME_VM_STACK_FRAME_DBC_H_
#define RUNTIME_VM_STACK_FRAME_DBC_H_
+#if !defined(RUNTIME_VM_STACK_FRAME_H_)
+#error Do not include stack_frame_dbc.h directly; use stack_frame.h instead.
+#endif
+
namespace dart {
/* DBC Frame Layout
diff --git a/runtime/vm/stack_frame_ia32.h b/runtime/vm/stack_frame_ia32.h
index 896fb05..c8221ee 100644
--- a/runtime/vm/stack_frame_ia32.h
+++ b/runtime/vm/stack_frame_ia32.h
@@ -5,6 +5,10 @@
#ifndef RUNTIME_VM_STACK_FRAME_IA32_H_
#define RUNTIME_VM_STACK_FRAME_IA32_H_
+#if !defined(RUNTIME_VM_STACK_FRAME_H_)
+#error Do not include stack_frame_ia32.h directly; use stack_frame.h instead.
+#endif
+
namespace dart {
/* IA32 Dart Frame Layout
diff --git a/runtime/vm/stack_frame_kbc.h b/runtime/vm/stack_frame_kbc.h
index 3418eaa..6af9a3a 100644
--- a/runtime/vm/stack_frame_kbc.h
+++ b/runtime/vm/stack_frame_kbc.h
@@ -5,6 +5,8 @@
#ifndef RUNTIME_VM_STACK_FRAME_KBC_H_
#define RUNTIME_VM_STACK_FRAME_KBC_H_
+#include "platform/globals.h"
+
namespace dart {
/* Kernel Bytecode Frame Layout
diff --git a/runtime/vm/stack_frame_test.cc b/runtime/vm/stack_frame_test.cc
index 76a31f8..15800b7 100644
--- a/runtime/vm/stack_frame_test.cc
+++ b/runtime/vm/stack_frame_test.cc
@@ -149,7 +149,7 @@
int num_entries = sizeof(BuiltinEntries) / sizeof(struct NativeEntries);
for (int i = 0; i < num_entries; i++) {
struct NativeEntries* entry = &(BuiltinEntries[i]);
- if (!strcmp(function_name, entry->name_) &&
+ if ((strcmp(function_name, entry->name_) == 0) &&
(entry->argument_count_ == argument_count)) {
return reinterpret_cast<Dart_NativeFunction>(entry->function_);
}
diff --git a/runtime/vm/stack_frame_x64.h b/runtime/vm/stack_frame_x64.h
index 1507960..dd01d67 100644
--- a/runtime/vm/stack_frame_x64.h
+++ b/runtime/vm/stack_frame_x64.h
@@ -5,6 +5,10 @@
#ifndef RUNTIME_VM_STACK_FRAME_X64_H_
#define RUNTIME_VM_STACK_FRAME_X64_H_
+#if !defined(RUNTIME_VM_STACK_FRAME_H_)
+#error Do not include stack_frame_x64.h directly; use stack_frame.h instead.
+#endif
+
#include "vm/constants_x64.h"
namespace dart {
diff --git a/runtime/vm/stack_trace.cc b/runtime/vm/stack_trace.cc
index b21b28e..17724a3 100644
--- a/runtime/vm/stack_trace.cc
+++ b/runtime/vm/stack_trace.cc
@@ -85,7 +85,6 @@
code_array.SetAt(array_offset, bytecode);
} else {
code = frame->LookupDartCode();
- function = code.function();
offset = Smi::New(frame->pc() - code.PayloadStart());
code_array.SetAt(array_offset, code);
}
diff --git a/runtime/vm/static_type_exactness_state.h b/runtime/vm/static_type_exactness_state.h
index 17e0089..a55f63a 100644
--- a/runtime/vm/static_type_exactness_state.h
+++ b/runtime/vm/static_type_exactness_state.h
@@ -6,6 +6,7 @@
#define RUNTIME_VM_STATIC_TYPE_EXACTNESS_STATE_H_
#include "platform/allocation.h"
+#include "platform/utils.h"
// This header defines the list of VM implementation classes and their ids.
//
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 04e827b..31bb9e7 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -72,6 +72,9 @@
V(DartExtensionScheme, "dart-ext:") \
V(DartFfi, "dart:ffi") \
V(DartFfiLibName, "ffi") \
+ V(DartWasm, "dart:wasm") \
+ V(DartWasmLibName, "wasm") \
+ V(DartLibraryWasm, "dart.library.wasm") \
V(DartIOLibName, "dart.io") \
V(DartInternal, "dart:_internal") \
V(DartIsVM, "dart.isVM") \
@@ -114,6 +117,7 @@
V(ExternalTwoByteString, "_ExternalTwoByteString") \
V(FactoryResult, "factory result") \
V(FallThroughError, "FallThroughError") \
+ V(FfiCallback, "_FfiCallback") \
V(FfiDouble, "Double") \
V(FfiDynamicLibrary, "DynamicLibrary") \
V(FfiFloat, "Float") \
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index 41a2afa..688e886 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -42,7 +42,7 @@
// There should be no top api scopes at this point.
ASSERT(api_top_scope() == NULL);
// Delete the resusable api scope if there is one.
- if (api_reusable_scope_) {
+ if (api_reusable_scope_ != nullptr) {
delete api_reusable_scope_;
api_reusable_scope_ = NULL;
}
@@ -941,7 +941,7 @@
}
const intptr_t kInitialCallbackIdsReserved = 1024;
-int32_t Thread::AllocateFfiCallbackId(uword* trampoline) {
+int32_t Thread::AllocateFfiCallbackId() {
Zone* Z = isolate()->current_zone();
if (ffi_callback_code_ == GrowableObjectArray::null()) {
ffi_callback_code_ = GrowableObjectArray::New(kInitialCallbackIdsReserved);
@@ -955,7 +955,7 @@
if (NativeCallbackTrampolines::Enabled()) {
auto* const tramps = isolate()->native_callback_trampolines();
ASSERT(tramps->next_callback_id() == id);
- *trampoline = tramps->AllocateTrampoline();
+ tramps->AllocateTrampoline();
}
#endif
@@ -964,7 +964,25 @@
void Thread::SetFfiCallbackCode(int32_t callback_id, const Code& code) {
Zone* Z = isolate()->current_zone();
+
+ /// In AOT the callback ID might have been allocated during compilation but
+ /// 'ffi_callback_code_' is initialized to empty again when the program
+ /// starts. Therefore we may need to initialize or expand it to accomodate
+ /// the callback ID.
+
+ if (ffi_callback_code_ == GrowableObjectArray::null()) {
+ ffi_callback_code_ = GrowableObjectArray::New(kInitialCallbackIdsReserved);
+ }
+
const auto& array = GrowableObjectArray::Handle(Z, ffi_callback_code_);
+
+ if (callback_id >= array.Length()) {
+ if (callback_id >= array.Capacity()) {
+ array.Grow(callback_id + 1);
+ }
+ array.SetLength(callback_id + 1);
+ }
+
array.SetAt(callback_id, code);
}
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 894197a..b1fa522 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -14,6 +14,7 @@
#include "platform/atomic.h"
#include "platform/safe_stack.h"
#include "vm/bitfield.h"
+#include "vm/compiler/runtime_api.h"
#include "vm/constants.h"
#include "vm/globals.h"
#include "vm/handles.h"
@@ -23,7 +24,6 @@
#include "vm/runtime_entry_list.h"
#include "vm/thread_stack_resource.h"
#include "vm/thread_state.h"
-
namespace dart {
class AbstractType;
@@ -786,7 +786,11 @@
}
}
- int32_t AllocateFfiCallbackId(uword* trampoline);
+ int32_t AllocateFfiCallbackId();
+
+ // Store 'code' for the native callback identified by 'callback_id'.
+ //
+ // Expands the callback code array as necessary to accomodate the callback ID.
void SetFfiCallbackCode(int32_t callback_id, const Code& code);
// Ensure that 'callback_id' refers to a valid callback in this isolate.
diff --git a/runtime/vm/timeline.cc b/runtime/vm/timeline.cc
index 8b9a644..bad38fd 100644
--- a/runtime/vm/timeline.cc
+++ b/runtime/vm/timeline.cc
@@ -737,10 +737,11 @@
: name_(name),
fuchsia_name_(fuchsia_name),
#if defined(HOST_OS_FUCHSIA)
- enabled_(true) { // For generated code.
+ enabled_(static_cast<uintptr_t>(true)) // For generated code.
#else
- enabled_(enabled) {
+ enabled_(static_cast<uintptr_t>(enabled))
#endif
+{
}
TimelineEvent* TimelineStream::StartEvent() {
diff --git a/runtime/vm/token.h b/runtime/vm/token.h
index ff8c682..844f9b9 100644
--- a/runtime/vm/token.h
+++ b/runtime/vm/token.h
@@ -259,6 +259,19 @@
return tok_str_[tok];
}
+ static bool FromStr(const char* str, Kind* out) {
+ ASSERT(str != nullptr && out != nullptr);
+#define TOK_CASE(t, s, p, a) \
+ if (strcmp(str, tok_str_[(t)]) == 0) { \
+ *out = (t); \
+ return true; \
+ }
+ DART_TOKEN_LIST(TOK_CASE)
+ DART_KEYWORD_LIST(TOK_CASE)
+#undef TOK_CASE
+ return false;
+ }
+
static int Precedence(Kind tok) {
ASSERT(tok < kNumTokens);
return precedence_[tok];
diff --git a/runtime/vm/vm_sources.gni b/runtime/vm/vm_sources.gni
index fcc057f..b692ab4 100644
--- a/runtime/vm/vm_sources.gni
+++ b/runtime/vm/vm_sources.gni
@@ -19,6 +19,8 @@
"bootstrap.h",
"bootstrap_natives.cc",
"bootstrap_natives.h",
+ "bss_relocs.cc",
+ "bss_relocs.h",
"class_finalizer.cc",
"class_finalizer.h",
"class_id.h",
diff --git a/runtime/vm/zone.h b/runtime/vm/zone.h
index 88e1ef9..6f11bf7 100644
--- a/runtime/vm/zone.h
+++ b/runtime/vm/zone.h
@@ -82,13 +82,13 @@
return false;
}
+ // All pointers returned from AllocateUnsafe() and New() have this alignment.
+ static const intptr_t kAlignment = kDoubleSize;
+
private:
Zone();
~Zone(); // Delete all memory associated with the zone.
- // All pointers returned from AllocateUnsafe() and New() have this alignment.
- static const intptr_t kAlignment = kDoubleSize;
-
// Default initial chunk size.
static const intptr_t kInitialChunkSize = 1 * KB;
@@ -119,6 +119,7 @@
void Free(ElementType* old_array, intptr_t len) {
#ifdef DEBUG
if (len > 0) {
+ ASSERT(old_array != nullptr);
memset(old_array, kZapUninitializedByte, len * sizeof(ElementType));
}
#endif
diff --git a/samples/samples.status b/samples/samples.status
index b5f2b33..257e3a5 100644
--- a/samples/samples.status
+++ b/samples/samples.status
@@ -17,9 +17,6 @@
[ $compiler == none && $runtime == vm && $system == fuchsia ]
*: Skip # Not yet triaged.
-[ !$preview_dart_2 && ($runtime == dart_precompiled || $runtime == vm) ]
-*: SkipByDesign # Deprecating all Dart1 modes of execution
-
[ $arch != x64 || $compiler != dartk || $system != linux || $hot_reload || $hot_reload_rollback ]
ffi/sqlite/test/sqlite_test: Skip # FFI not supported or libsqlite3.so not available.
diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn
index b689dd2..228fc3c 100644
--- a/sdk/BUILD.gn
+++ b/sdk/BUILD.gn
@@ -84,6 +84,7 @@
# ......math/
# ......mirrors/
# ......typed_data/
+# ......wasm/
# ......api_readme.md
# ....model/
# ......lexeme/
@@ -116,6 +117,10 @@
"../utils/dartanalyzer:generate_dartanalyzer_snapshot",
],
[
+ "dart2native",
+ "../utils/dart2native:generate_dart2native_snapshot",
+ ],
+ [
"dartdoc",
"../utils/dartdoc",
],
@@ -155,6 +160,10 @@
"../utils/dartanalyzer:generate_dartanalyzer_snapshot",
],
[
+ "dart2native",
+ "../utils/dart2native:generate_dart2native_snapshot",
+ ],
+ [
"dartdevc",
"../utils/dartdevc",
],
@@ -216,6 +225,7 @@
"profiler",
"svg",
"typed_data",
+ "wasm",
"web_audio",
"web_gl",
"web_sql",
@@ -249,22 +259,22 @@
copy_tree_specs = []
# This rule copies dartdoc templates to
-# bin/snapshots/resources/dartdoc/templates
+# bin/resources/dartdoc/templates
copy_tree_specs += [ {
target = "copy_dartdoc_templates"
visibility = [ ":copy_dartdoc_files" ]
source = "../third_party/pkg/dartdoc/lib/templates"
- dest = "$root_out_dir/dart-sdk/bin/snapshots/resources/dartdoc/templates"
+ dest = "$root_out_dir/dart-sdk/bin/resources/dartdoc/templates"
ignore_patterns = "{}"
} ]
# This rule copies dartdoc resources to
-# bin/snapshots/resources/dartdoc/resources
+# bin/resources/dartdoc/resources
copy_tree_specs += [ {
target = "copy_dartdoc_resources"
visibility = [ ":copy_dartdoc_files" ]
source = "../third_party/pkg/dartdoc/lib/resources"
- dest = "$root_out_dir/dart-sdk/bin/snapshots/resources/dartdoc/resources"
+ dest = "$root_out_dir/dart-sdk/bin/resources/dartdoc/resources"
ignore_patterns = "{}"
} ]
@@ -421,9 +431,6 @@
"$gen_snapshot_out/$gen_snapshot_stripped_binary",
]
}
- if (is_win) {
- sources += [ "$gen_snapshot_out/gen_snapshot.lib" ]
- }
outputs = [
"$root_out_dir/dart-sdk/bin/utils/{{source_file_part}}",
]
@@ -442,6 +449,23 @@
]
}
+copy("copy_dart2native") {
+ deps = [
+ ":copy_gen_kernel_snapshot",
+ ":copy_gen_snapshot",
+ ]
+ ext = ""
+ if (is_win) {
+ ext = ".bat"
+ }
+ sources = [
+ "bin/dart2native$ext",
+ ]
+ outputs = [
+ "$root_out_dir/dart-sdk/bin/{{source_file_part}}",
+ ]
+}
+
copy("copy_gen_kernel_snapshot") {
deps = [
"../utils/gen_kernel",
@@ -566,7 +590,7 @@
}
# This rule writes the .packages file for dartdoc resources.
-write_file("$root_out_dir/dart-sdk/bin/snapshots/resources/dartdoc/.packages",
+write_file("$root_out_dir/dart-sdk/bin/resources/dartdoc/.packages",
"dartdoc:.")
# This is the main rule for copying the files that dartdoc needs.
@@ -978,6 +1002,7 @@
":copy_analysis_summaries",
":copy_api_readme",
":copy_dart",
+ ":copy_dart2native",
":copy_dartdoc_files",
":copy_headers",
":copy_libraries_dart",
diff --git a/sdk/bin/dart2native b/sdk/bin/dart2native
new file mode 100755
index 0000000..29f29d7
--- /dev/null
+++ b/sdk/bin/dart2native
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+# Copyright (c) 2019, 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.
+
+# Run dart2native.dart.snapshot on the Dart VM
+
+function follow_links() {
+ file="$1"
+ while [ -h "$file" ]; do
+ # On Mac OS, readlink -f doesn't work.
+ file="$(readlink "$file")"
+ done
+ echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+SNAPSHOTS_DIR="${BIN_DIR}/snapshots"
+DART="$BIN_DIR/dart"
+
+exec "$DART" "${SNAPSHOTS_DIR}/dart2native.dart.snapshot" $*
diff --git a/sdk/bin/dart2native.bat b/sdk/bin/dart2native.bat
new file mode 100644
index 0000000..631dce8
--- /dev/null
+++ b/sdk/bin/dart2native.bat
@@ -0,0 +1,43 @@
+@echo off
+REM Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
+
+set DART=%BIN_DIR%\dart
+
+"%DART%" "%BIN_DIR%\snapshots\dart2native.dart.snapshot" %*
+
+endlocal
+
+exit /b %errorlevel%
+
+rem Follow the symbolic links (junctions points) using `dir to determine the
+rem canonical path. Output with a link looks something like this
+rem
+rem 01/03/2013 10:11 PM <JUNCTION> abc def
+rem [c:\dart_bleeding\dart-repo.9\dart\out\ReleaseIA32\dart-sdk]
+rem
+rem So in the output of 'dir /a:l "targetdir"' we are looking for a filename
+rem surrounded by right angle bracket and left square bracket. Once we get
+rem the filename, which is name of the link, we recursively follow that.
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+ ^| %SystemRoot%\System32\find.exe "> %~n1 [" 2^>nul`) do (
+ set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
diff --git a/sdk/bin/dartdoc b/sdk/bin/dartdoc
index d81a581..e9584c1 100755
--- a/sdk/bin/dartdoc
+++ b/sdk/bin/dartdoc
@@ -3,9 +3,6 @@
# 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.
-# Run dart_style/bin/format.dart on the Dart VM. This script assumes the Dart
-# SDK's directory structure.
-
function follow_links() {
file="$1"
while [ -h "$file" ]; do
@@ -26,4 +23,4 @@
# We are running the snapshot in the built SDK.
DART="$BIN_DIR/dart"
-exec "$DART" "--packages=$BIN_DIR/snapshots/resources/dartdoc/.packages" "$SNAPSHOT" "$@"
+exec "$DART" "--packages=$BIN_DIR/resources/dartdoc/.packages" "$SNAPSHOT" "$@"
diff --git a/sdk/bin/dartdoc.bat b/sdk/bin/dartdoc.bat
index 8c2c900..876eb0e 100644
--- a/sdk/bin/dartdoc.bat
+++ b/sdk/bin/dartdoc.bat
@@ -14,7 +14,7 @@
set DART=%BIN_DIR%\dart
set SNAPSHOT=%BIN_DIR%\snapshots\dartdoc.dart.snapshot
-"%DART%" "--packages=%BIN_DIR%/snapshots/resources/dartdoc/.packages" "%SNAPSHOT%" %*
+"%DART%" "--packages=%BIN_DIR%/resources/dartdoc/.packages" "%SNAPSHOT%" %*
endlocal
diff --git a/sdk/lib/_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart b/sdk/lib/_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart
index f769673..91d6847 100644
--- a/sdk/lib/_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart
+++ b/sdk/lib/_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart
@@ -541,9 +541,7 @@
return value;
}
-// The allowInterop method is a no-op in Dart Dev Compiler.
-// TODO(jacobr): tag methods so we can throw if a Dart method is passed to
-// JavaScript using the new interop without calling allowInterop.
+Expando<Function> _interopExpando = Expando<Function>();
/// Returns a wrapper around function [f] that can be called from JavaScript
/// using the package:js Dart-JavaScript interop.
@@ -556,7 +554,20 @@
/// JavaScript. We may remove the need to call this method completely in the
/// future if Dart2Js is refactored so that its function calling conventions
/// are more compatible with JavaScript.
-F allowInterop<F extends Function>(F f) => f;
+F allowInterop<F extends Function>(F f) {
+ var ret = _interopExpando[f];
+ if (ret == null) {
+ ret = JS(
+ '',
+ 'function (...args) {'
+ ' return #(#, args);'
+ '}',
+ dart.dcall,
+ f);
+ _interopExpando[f] = ret;
+ }
+ return ret;
+}
Expando<Function> _interopCaptureThisExpando = Expando<Function>();
@@ -571,13 +582,12 @@
if (ret == null) {
ret = JS(
'',
- 'function(/*...arguments*/) {'
+ 'function(...arguments) {'
' let args = [this];'
- ' for (let arg of arguments) {'
- ' args.push(arg);'
- ' }'
- ' return #(...args);'
+ ' args.push.apply(args, arguments);'
+ ' return #(#, args);'
'}',
+ dart.dcall,
f);
_interopCaptureThisExpando[f] = ret;
}
diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
index bbde1a6..3175eeb 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
@@ -334,11 +334,16 @@
})()''');
class FunctionType extends AbstractFunctionType {
- final returnType;
+ final Type returnType;
List args;
List optionals;
+ // Named arguments native JS Object of the form { namedArgName: namedArgType }
final named;
// TODO(vsm): This is just parameter metadata for now.
+ // Suspected but not confirmed: Only used by mirrors for pageloader2 support.
+ // The metadata is represented as a list of JS arrays, one for each argument
+ // that contains the annotations for that argument or an empty array if there
+ // are no annotations.
List metadata = [];
String _stringValue;
@@ -380,6 +385,11 @@
return _memoizeArray(_fnTypeTypeMap, keys, create);
}
+ /// Returns the function arguments.
+ ///
+ /// If an argument is provided with annotations (encoded as a JS array where
+ /// the first element is the argument, and the rest are annotations) the
+ /// annotations are extracted and saved in [metadata].
List _process(List array) {
var result = [];
for (var i = 0; JS<bool>('!', '# < #.length', i, array); ++i) {
@@ -398,7 +408,8 @@
FunctionType(this.returnType, this.args, this.optionals, this.named) {
this.args = _process(this.args);
this.optionals = _process(this.optionals);
- // TODO(vsm): Add named arguments.
+ // TODO(vsm): Named arguments were never used by pageloader2 so they were
+ // never processed here.
}
toString() => name;
diff --git a/sdk/lib/_internal/js_runtime/lib/js_names.dart b/sdk/lib/_internal/js_runtime/lib/js_names.dart
index 06b633a..cb4aa0e 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_names.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_names.dart
@@ -82,7 +82,7 @@
}
/// Implements the inverse of [_LazyMangledNamesMap]. As it would be too
-/// expensive to seach the mangled names map for a value that corresponds to
+/// expensive to search the mangled names map for a value that corresponds to
/// the lookup key on each invocation, we compute the full mapping in demand
/// and cache it. The cache is invalidated when the underlying [_jsMangledNames]
/// object changes its length. This condition is sufficient as the name mapping
diff --git a/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart b/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
index cfd6fa6..ba141fa 100644
--- a/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
+++ b/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
@@ -134,6 +134,8 @@
categories: "Client",
maturity: Maturity.WEB_STABLE,
platforms: DART2JS_PLATFORM),
+ "wasm": const LibraryInfo("wasm/wasm.dart",
+ categories: "Server", maturity: Maturity.EXPERIMENTAL),
"web_audio": const LibraryInfo("web_audio/dart2js/web_audio_dart2js.dart",
categories: "Client",
maturity: Maturity.WEB_STABLE,
diff --git a/sdk/lib/developer/timeline.dart b/sdk/lib/developer/timeline.dart
index dce5b7e..02f9c98 100644
--- a/sdk/lib/developer/timeline.dart
+++ b/sdk/lib/developer/timeline.dart
@@ -194,14 +194,12 @@
if (!_hasTimeline) return;
ArgumentError.checkNotNull(name, 'name');
var block = new _AsyncBlock._(name, _taskId);
- if (arguments != null) {
- block._arguments = arguments;
- }
_stack.add(block);
- block._start();
+ block._start(arguments);
}
/// Emit an instant event for this task.
+ /// Optionally takes a [Map] of [arguments].
void instant(String name, {Map arguments}) {
if (!_hasTimeline) return;
ArgumentError.checkNotNull(name, 'name');
@@ -214,7 +212,8 @@
}
/// Finish the last synchronous operation that was started.
- void finish() {
+ /// Optionally takes a [Map] of [arguments].
+ void finish({Map arguments}) {
if (!_hasTimeline) {
return;
}
@@ -223,7 +222,7 @@
}
// Pop top item off of stack.
var block = _stack.removeLast();
- block._finish();
+ block._finish(arguments);
}
/// Retrieve the [TimelineTask]'s task id. Will throw an exception if the
@@ -254,22 +253,18 @@
/// The asynchronous task id.
final int _taskId;
- /// An (optional) set of arguments which will be serialized to JSON and
- /// associated with this block.
- Map _arguments;
-
_AsyncBlock._(this.name, this._taskId);
// Emit the start event.
- void _start() {
- _reportTaskEvent(
- _getTraceClock(), _taskId, 'b', category, name, _argumentsAsJson(null));
+ void _start(Map arguments) {
+ _reportTaskEvent(_getTraceClock(), _taskId, 'b', category, name,
+ _argumentsAsJson(arguments));
}
// Emit the finish event.
- void _finish() {
+ void _finish(Map arguments) {
_reportTaskEvent(_getTraceClock(), _taskId, 'e', category, name,
- _argumentsAsJson(_arguments));
+ _argumentsAsJson(arguments));
}
}
diff --git a/sdk/lib/ffi/ffi.dart b/sdk/lib/ffi/ffi.dart
index 85837e1..a975a13 100644
--- a/sdk/lib/ffi/ffi.dart
+++ b/sdk/lib/ffi/ffi.dart
@@ -2,8 +2,16 @@
// 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
-/// {@category VM}
-/// {@nodoc}
+/**
+ * Foreign Function Interface for interoperability with the C programming language.
+ *
+ * **NOTE**: Dart:FFI is in technical preview. The overall feature is incomplete,
+ * may contain issues, and breaking API changes are still expected.
+ *
+ * For further details, please see: https://dart.dev/server/c-interop
+ *
+ * {@category VM}
+ */
library dart.ffi;
import 'dart:typed_data' show TypedData;
@@ -50,7 +58,8 @@
/// Does not accept dynamic invocations -- where the type of the receiver is
/// [dynamic].
external static Pointer<NativeFunction<T>> fromFunction<T extends Function>(
- @DartRepresentationOf("T") Function f, Object exceptionalReturn);
+ @DartRepresentationOf("T") Function f,
+ [Object exceptionalReturn]);
/// Store a Dart value into this location.
///
diff --git a/sdk/lib/ffi/native_type.dart b/sdk/lib/ffi/native_type.dart
index bd88b28..aa30e63 100644
--- a/sdk/lib/ffi/native_type.dart
+++ b/sdk/lib/ffi/native_type.dart
@@ -121,13 +121,11 @@
/// [Void] is not constructible in the Dart code and serves purely as marker in
/// type signatures.
@unsized
-class Void extends NativeType {
- const Void();
-}
+abstract class Void extends NativeType {}
/// Represents a function type in C.
///
/// [NativeFunction] is not constructible in the Dart code and serves purely as
/// marker in type signatures.
@unsized
-class NativeFunction<T extends Function> extends NativeType {}
+abstract class NativeFunction<T extends Function> extends NativeType {}
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 0736e06..303ec9e 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -28281,11 +28281,12 @@
*
* See also:
*
- * * <https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#innerhtml-on-templates>
+ * * <https://w3c.github.io/DOM-Parsing/#the-innerhtml-mixin>
*/
void setInnerHtml(String html,
{NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
text = null;
+ content.nodes.clear();
var fragment = createFragment(html,
validator: validator, treeSanitizer: treeSanitizer);
diff --git a/sdk/lib/html/html_common/conversions.dart b/sdk/lib/html/html_common/conversions.dart
index a563c05..4c31efb 100644
--- a/sdk/lib/html/html_common/conversions.dart
+++ b/sdk/lib/html/html_common/conversions.dart
@@ -255,7 +255,7 @@
}
// Assume anything else is already a valid Dart object, either by having
- // already been processed, or e.g. a clonable native class.
+ // already been processed, or e.g. a cloneable native class.
return e;
}
diff --git a/sdk/lib/io/secure_socket.dart b/sdk/lib/io/secure_socket.dart
index d7c7ff7..a4751ef 100644
--- a/sdk/lib/io/secure_socket.dart
+++ b/sdk/lib/io/secure_socket.dart
@@ -92,6 +92,11 @@
* the [socket] will be used. The [host] can be either a [String] or
* an [InternetAddress].
*
+ * [supportedProtocols] is an optional list of protocols (in decreasing
+ * order of preference) to use during the ALPN protocol negotiation with the
+ * server. Example values are "http/1.1" or "h2". The selected protocol
+ * can be obtained via [SecureSocket.selectedProtocol].
+ *
* Calling this function will _not_ cause a DNS host lookup. If the
* [host] passed is a [String] the [InternetAddress] for the
* resulting [SecureSocket] will have the passed in [host] as its
@@ -104,14 +109,16 @@
static Future<SecureSocket> secure(Socket socket,
{host,
SecurityContext context,
- bool onBadCertificate(X509Certificate certificate)}) {
+ bool onBadCertificate(X509Certificate certificate),
+ @Since("2.6") List<String> supportedProtocols}) {
return ((socket as dynamic /*_Socket*/)._detachRaw() as Future)
.then<RawSecureSocket>((detachedRaw) {
return RawSecureSocket.secure(detachedRaw[0] as RawSocket,
subscription: detachedRaw[1] as StreamSubscription<RawSocketEvent>,
host: host,
context: context,
- onBadCertificate: onBadCertificate);
+ onBadCertificate: onBadCertificate,
+ supportedProtocols: supportedProtocols);
}).then<SecureSocket>((raw) => new SecureSocket._(raw));
}
@@ -272,6 +279,11 @@
* the [socket] will be used. The [host] can be either a [String] or
* an [InternetAddress].
*
+ * [supportedProtocols] is an optional list of protocols (in decreasing
+ * order of preference) to use during the ALPN protocol negotiation with the
+ * server. Example values are "http/1.1" or "h2". The selected protocol
+ * can be obtained via [SecureSocket.selectedProtocol].
+ *
* Calling this function will _not_ cause a DNS host lookup. If the
* [host] passed is a [String] the [InternetAddress] for the
* resulting [SecureSocket] will have this passed in [host] as its
diff --git a/sdk/lib/libraries.json b/sdk/lib/libraries.json
index 4bf7129..663991f 100644
--- a/sdk/lib/libraries.json
+++ b/sdk/lib/libraries.json
@@ -71,6 +71,12 @@
],
"uri": "ffi/ffi.dart"
},
+ "wasm": {
+ "patches": [
+ "../../runtime/lib/wasm_patch.dart"
+ ],
+ "uri": "wasm/wasm.dart"
+ },
"typed_data": {
"patches": "../../runtime/lib/typed_data_patch.dart",
"uri": "typed_data/typed_data.dart"
@@ -481,4 +487,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/sdk/lib/libraries.yaml b/sdk/lib/libraries.yaml
index 01144b8..f33a42b 100644
--- a/sdk/lib/libraries.yaml
+++ b/sdk/lib/libraries.yaml
@@ -94,6 +94,11 @@
- "../../runtime/lib/ffi_dynamic_library_patch.dart"
- "../../runtime/lib/ffi_native_type_patch.dart"
+ wasm:
+ uri: "wasm/wasm.dart"
+ patches:
+ - "../../runtime/lib/wasm_patch.dart"
+
_http:
uri: "_http/http.dart"
diff --git a/sdk/lib/wasm/wasm.dart b/sdk/lib/wasm/wasm.dart
new file mode 100644
index 0000000..edf0887
--- /dev/null
+++ b/sdk/lib/wasm/wasm.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2019, 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.
+
+/// {@category VM}
+/// {@nodoc}
+library dart.wasm;
+
+int callWasm(String name, int arg) {
+ return _callWasm(name, arg);
+}
+
+external int _callWasm(String name, int arg);
diff --git a/sdk/lib/wasm/wasm_sources.gni b/sdk/lib/wasm/wasm_sources.gni
new file mode 100644
index 0000000..dcd359a
--- /dev/null
+++ b/sdk/lib/wasm/wasm_sources.gni
@@ -0,0 +1,7 @@
+# Copyright (c) 2019, 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.
+
+wasm_sdk_sources = [
+ "wasm.dart",
+]
diff --git a/tests/co19_2/co19_2-analyzer.status b/tests/co19_2/co19_2-analyzer.status
deleted file mode 100644
index 8841e40..0000000
--- a/tests/co19_2/co19_2-analyzer.status
+++ /dev/null
@@ -1,206 +0,0 @@
-# !Copyright (c) 2018, 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.
-
-[ $compiler == dart2analyzer ]
-Language/Classes/Abstract_Instance_Members/override_default_value_t01: MissingCompileTimeError # https://github.com/dart-lang/co19/issues/234
-Language/Classes/Abstract_Instance_Members/override_default_value_t02: MissingCompileTimeError # https://github.com/dart-lang/co19/issues/234
-Language/Classes/Abstract_Instance_Members/override_default_value_t03: MissingCompileTimeError # https://github.com/dart-lang/co19/issues/234
-Language/Classes/Abstract_Instance_Members/override_default_value_t04: MissingCompileTimeError # https://github.com/dart-lang/co19/issues/234
-Language/Classes/Abstract_Instance_Members/override_default_value_t05: MissingCompileTimeError # https://github.com/dart-lang/co19/issues/234
-Language/Classes/Getters/type_object_t01: CompileTimeError # Issue 33995
-Language/Classes/Getters/type_object_t02: CompileTimeError # Issue 33995
-Language/Classes/Instance_Methods/Operators/allowed_names_t01: CompileTimeError # triple shift
-Language/Classes/Instance_Methods/Operators/allowed_names_t23: CompileTimeError # triple shift
-Language/Classes/Instance_Methods/Operators/arity_1_t19: CompileTimeError # triple shift
-Language/Classes/Instance_Methods/override_different_default_values_t01: MissingCompileTimeError # https://github.com/dart-lang/co19/issues/234
-Language/Classes/Instance_Methods/override_different_default_values_t02: MissingCompileTimeError # https://github.com/dart-lang/co19/issues/234
-Language/Classes/Static_Methods/same_name_method_and_setter_t01: CompileTimeError # Invalid test, see #33237
-Language/Classes/method_definition_t06: MissingCompileTimeError # Please triage this failure
-Language/Enums/syntax_t08: CompileTimeError # Issue 33995
-Language/Enums/syntax_t09: CompileTimeError # Issue 33995
-Language/Errors_and_Warnings/static_warning_t01: CompileTimeError # issue #34319
-Language/Expressions/Assignment/Compound_Assignment/expression_assignment_t12: CompileTimeError # triple shift
-Language/Expressions/Assignment/Compound_Assignment/indexed_expression_assignment_t12: CompileTimeError # triple shift
-Language/Expressions/Assignment/Compound_Assignment/null_aware_compound_assignment_static_t12: CompileTimeError # triple shift
-Language/Expressions/Assignment/Compound_Assignment/null_aware_compound_assignment_t12: CompileTimeError # triple shift
-Language/Expressions/Assignment/Compound_Assignment/setter_assignment_t12: CompileTimeError # triple shift
-Language/Expressions/Assignment/Compound_Assignment/variable_assignment_t12: CompileTimeError # triple shift
-Language/Expressions/Bitwise_Expressions/syntax_t01: CompileTimeError # triple shift
-Language/Expressions/Constants/bitwise_operators_t01: CompileTimeError # triple shift
-Language/Expressions/Constants/constant_list_t02: MissingCompileTimeError # Please triage this failure
-Language/Expressions/Constants/constant_map_t02: MissingCompileTimeError # Please triage this failure
-Language/Expressions/Equality/syntax_t01: CompileTimeError # triple shift
-Language/Expressions/Function_Invocation/Unqualified_Invocation/function_expr_invocation_t05: CompileTimeError # Please triage this failure
-Language/Expressions/Function_Invocation/async_cleanup_t01: CompileTimeError # Issue 33995
-Language/Expressions/Function_Invocation/async_cleanup_t02: CompileTimeError # Issue 33995
-Language/Expressions/Function_Invocation/async_cleanup_t03: CompileTimeError # Issue 33995
-Language/Expressions/Function_Invocation/async_cleanup_t04: CompileTimeError # Issue 33995
-Language/Expressions/Function_Invocation/async_cleanup_t05: CompileTimeError # Issue 33995
-Language/Expressions/Function_Invocation/async_cleanup_t06: CompileTimeError # Issue 33995
-Language/Expressions/Function_Invocation/async_cleanup_t07: CompileTimeError # Issue 33995
-Language/Expressions/Function_Invocation/async_cleanup_t08: CompileTimeError # Issue 33995
-Language/Expressions/Identifier_Reference/evaluation_library_or_getter_t01: StaticWarning # Please triage this failure
-Language/Expressions/Instance_Creation/Const/arguments_t03: MissingCompileTimeError # Please triage this failure
-Language/Expressions/Instance_Creation/Const/parameterized_type_t01: CompileTimeError # Please triage this failure
-Language/Expressions/Instance_Creation/Const/parameterized_type_t02: CompileTimeError # Please triage this failure
-Language/Expressions/Instance_Creation/New/syntax_t04: MissingCompileTimeError # Please triage this failure
-Language/Expressions/Lists/constant_list_t01: CompileTimeError # Please triage this failure
-Language/Expressions/Lists/syntax_t01: CompileTimeError # triple shift
-Language/Expressions/Maps/constant_map_t02: MissingCompileTimeError # Please triage this failure
-Language/Expressions/Maps/constant_map_type_t01: CompileTimeError # Please triage this failure
-Language/Expressions/Maps/syntax_t01: CompileTimeError # triple shift
-Language/Expressions/Relational_Expressions/syntax_t01: CompileTimeError # triple shift
-Language/Expressions/Shift/allowed_characters_t02: CompileTimeError # triple shift
-Language/Expressions/Shift/integer_t03: CompileTimeError # triple shift
-Language/Expressions/Shift/syntax_t01: CompileTimeError # triple shift
-Language/Expressions/Shift/syntax_t15: CompileTimeError # triple shift
-Language/Expressions/Strings/String_Interpolation/syntax_t01: CompileTimeError # triple shift
-Language/Expressions/Symbols/syntax_t02: CompileTimeError # triple shift
-Language/Expressions/parentheses_t01: CompileTimeError # triple shift
-Language/Functions/generator_return_type_t02: MissingCompileTimeError # Issue 32192
-Language/Functions/generator_return_type_t06: MissingCompileTimeError # Issue 32192
-Language/Functions/syntax_t03: CompileTimeError # triple shift
-Language/Generics/scope_t03: CompileTimeError # Please triage this failure
-Language/Generics/syntax_t02: CompileTimeError # Please triage this failure
-Language/Generics/syntax_t03: Crash # Issue 29388
-Language/Generics/syntax_t04: CompileTimeError # Bad test
-Language/Libraries_and_Scripts/Exports/implicit_hide_t01: MissingStaticWarning # Issue #34302
-Language/Libraries_and_Scripts/Imports/implicit_hide_t01: MissingStaticWarning # Issue #34302
-Language/Libraries_and_Scripts/Imports/implicit_hide_t02: MissingStaticWarning # Issue #34302
-Language/Libraries_and_Scripts/Parts/compilation_t01: MissingCompileTimeError, Pass # Please triage this failure
-Language/Libraries_and_Scripts/Parts/compilation_t04: Pass, CompileTimeError, MissingCompileTimeError # Please triage this failure
-Language/Libraries_and_Scripts/Parts/compilation_t15: CompileTimeError, Pass # Please triage this failure
-Language/Mixins/Mixin_Application/static_warning_t02: CompileTimeError # Issue 26409
-Language/Mixins/Mixin_Application/syntax_t11: CompileTimeError # Issue 26409
-Language/Mixins/Mixin_Application/syntax_t12: CompileTimeError # Issue 26409
-Language/Mixins/Mixin_Application/syntax_t13: CompileTimeError # Issue 26409
-Language/Mixins/Mixin_Application/syntax_t14: CompileTimeError # Issue 26409
-Language/Mixins/Mixin_Application/syntax_t22: CompileTimeError # Issue 26409
-Language/Mixins/Mixin_Application/syntax_t23: CompileTimeError # Issue 26409
-Language/Mixins/Mixin_Application/syntax_t24: CompileTimeError # Issue 26409
-Language/Mixins/Mixin_Application/syntax_t25: CompileTimeError # Issue 26409
-Language/Mixins/declaring_constructor_t05: MissingCompileTimeError # Issue 24767
-Language/Mixins/declaring_constructor_t06: MissingCompileTimeError # Issue 24767
-Language/Reference/Operator_Precedence/precedence_01_assignment_t14: CompileTimeError # triple shift
-Language/Reference/Operator_Precedence/precedence_12_Shift_t04: CompileTimeError # triple shift
-Language/Reference/Operator_Precedence/precedence_t05: CompileTimeError # triple shift
-Language/Statements/Continue/async_loops_t01: CompileTimeError # Issue 33995
-Language/Statements/Continue/async_loops_t02: CompileTimeError # Issue 33995
-Language/Statements/Continue/async_loops_t03: CompileTimeError # Issue 33995
-Language/Statements/Continue/async_loops_t04: CompileTimeError # Issue 33995
-Language/Statements/Continue/async_loops_t05: CompileTimeError # Issue 33995
-Language/Statements/Continue/async_loops_t06: CompileTimeError # Issue 33995
-Language/Statements/Continue/async_loops_t07: CompileTimeError # Issue 33995
-Language/Statements/Continue/async_loops_t08: CompileTimeError # Issue 33995
-Language/Statements/Continue/async_loops_t09: CompileTimeError # Issue 33995
-Language/Statements/Continue/async_loops_t10: CompileTimeError # Issue 33995
-Language/Statements/Continue/control_transfer_t08: CompileTimeError # Issue 33995
-Language/Statements/Continue/control_transfer_t09: CompileTimeError # Issue 33995
-Language/Statements/Expression_Statements/syntax_t06: CompileTimeError # triple shift
-Language/Statements/Return/many_return_statements_t01: CompileTimeError # co19 issue 157
-Language/Statements/Return/many_return_statements_t02: CompileTimeError # issue #34319
-Language/Statements/Return/no_expression_function_t01: CompileTimeError # issue #34319
-Language/Statements/Return/no_expression_function_t02: CompileTimeError # issue #34319
-Language/Statements/Return/no_expression_function_t03: CompileTimeError # issue #34319
-Language/Statements/Return/no_expression_function_t04: CompileTimeError # issue #34319
-Language/Statements/Return/no_expression_function_t05: CompileTimeError # issue #34319
-Language/Statements/Return/no_expression_function_t07: CompileTimeError # issue #34319
-Language/Statements/Return/no_expression_function_t08: CompileTimeError # issue #34319
-Language/Statements/Return/no_expression_function_t09: CompileTimeError # issue #34319
-Language/Statements/Return/no_expression_function_t10: CompileTimeError # issue #34319
-Language/Statements/Return/no_expression_function_t11: CompileTimeError # issue #34319
-Language/Statements/Return/no_expression_function_t16: CompileTimeError # issue #34319
-Language/Statements/Return/no_expression_not_function_t01: CompileTimeError # issue #34319
-Language/Types/Interface_Types/subtype_t30: CompileTimeError # Please triage this failure
-LanguageFeatures/Constant_update2018/CastOperator_A01_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/CastOperator_A02_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/CastOperator_A02_t02: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/CastOperator_A03_t01/none: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/CastOperator_A03_t02/none: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/NewOperators_A01_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/NewOperators_A01_t02: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/NewOperators_A02_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/NewOperators_A02_t02: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/NewOperators_A02_t04: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/NewOperators_A02_t05: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/NewOperators_A02_t07: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/NewOperators_A02_t08: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/ShortCircuitOperators_A01_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/ShortCircuitOperators_A01_t02: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/ShortCircuitOperators_A02_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/ShortCircuitOperators_A03_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/ShortCircuitOperators_A03_t03: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/ShortCircuitOperators_A03_t05: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/ShortCircuitOperators_A04_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/ShortCircuitOperators_A04_t02: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/TypeTestOperator_A01_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/TypeTestOperator_A01_t02: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/TypeTestOperator_A02_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/TypeTestOperator_A02_t02: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/TypeTestOperator_A03_t03/none: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Constant_update2018/TypeTestOperator_A03_t04/none: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Instantiate-to-bound/class/dynamic/class_FutureOr_l1_t02: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/dynamic/class_FutureOr_l1_t04: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/dynamic/class_l1_t04: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/dynamic/class_l2_t03: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/dynamic/class_l2_t04: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/dynamic/class_l3_t02: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/static/class_FutureOr_l1_t01/01: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/static/class_FutureOr_l1_t01/02: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/static/class_FutureOr_l1_t01/03: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/static/class_FutureOr_l1_t01/04: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/static/class_FutureOr_l1_t02/none: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/static/class_FutureOr_l1_t04/none: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/static/class_l1_t04/none: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/static/class_l2_t03/none: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/static/class_l2_t04/none: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/static/class_l2_t08/none: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/static/class_l3_t02/none: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/class/static/class_l4_t01/none: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t02/none: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t04/01: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t04/02: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t04/03: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t04/04: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t04/05: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t04/06: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t04/07: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t07/none: CompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t09/01: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t09/02: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t09/03: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t09/04: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t09/05: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t09/06: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l1_t09/07: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/Instantiate-to-bound/typedef/static/typedef_l2_t01/none: CompileTimeError # Please triage this failure
-LanguageFeatures/Set-literals/constant_set_literals_A02_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Set-literals/constant_set_literals_A03_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Set-literals/constant_set_literals_A04_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Set-literals/exact_types_of_literals_A01_t03: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Set-literals/non_constant_set_literals_A01_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Set-literals/non_constant_set_literals_A02_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Set-literals/semantics_A04_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Set-literals/set_literals_A01_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Set-literals/set_literals_A02_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Set-literals/set_literals_A04_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Set-literals/syntax_compatibility_A01_t01: CompileTimeError # This feature is not implemented yet
-LanguageFeatures/Simple-bounds/static/typedef_l2_t02/none: CompileTimeError # Please triage this failure
-LanguageFeatures/Super-bounded-types/static_analysis_A01_t02: CompileTimeError # Issue 32903
-LanguageFeatures/Super-bounded-types/static_analysis_A01_t05: CompileTimeError # Issue 32903
-LanguageFeatures/Super-bounded-types/static_analysis_A01_t08: CompileTimeError # Issue 32903
-LanguageFeatures/Super-mixins/covariance_t03: MissingCompileTimeError # Issue 35111
-LanguageFeatures/Super-mixins/covariance_t06: MissingCompileTimeError # Issue 35111
-LanguageFeatures/Super-mixins/covariance_t07: MissingCompileTimeError # Issue 35111
-LanguageFeatures/regression/33597_t01: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/regression/33701_t02: CompileTimeError # Please triage this failure
-LanguageFeatures/regression/34635_t01: CompileTimeError # Please triage this failure
-LanguageFeatures/regression/34635_t02: CompileTimeError # Please triage this failure
-LanguageFeatures/regression/34635_t03: CompileTimeError # Please triage this failure
-LibTest/async/Future/Future_A01_t01: CompileTimeError # Please triage this failure
-
-[ $compiler == dart2analyzer && $system != macos && $system != windows ]
-LanguageFeatures/regression/33585_t01: MissingCompileTimeError # Please triage this failure
-LanguageFeatures/regression/33585_t02: MissingCompileTimeError # Please triage this failure
-
diff --git a/tests/co19_2/co19_2-kernel.status b/tests/co19_2/co19_2-kernel.status
index 7bd5ada..e6024bc 100644
--- a/tests/co19_2/co19_2-kernel.status
+++ b/tests/co19_2/co19_2-kernel.status
@@ -18,29 +18,15 @@
LanguageFeatures/Constant-update-2018/NewOperators_A01_t06/none: Crash
[ $runtime == vm ]
-LibTest/collection/ListBase/ListBase_class_A01_t02: Pass, Slow # Does many calls
-LibTest/collection/ListMixin/ListMixin_class_A01_t02: Pass, Slow # Does many calls
-LibTest/core/List/List_class_A01_t02: Pass, Slow # Does many calls
-LibTest/io/FileSystemCreateEvent/isDirectory_A01_t06: Pass, RuntimeError # https://github.com/dart-lang/co19/issues/186
+LibTest/collection/ListBase/ListBase_class_A01_t02: Slow # Does many calls
+LibTest/collection/ListMixin/ListMixin_class_A01_t02: Slow # Does many calls
+LibTest/core/List/List_class_A01_t02: Slow # Does many calls
LibTest/io/RawDatagramSocket/*: Skip # RawDatagramSocket are flacky. Skip them all until rewritten
-LibTest/io/RawDatagramSocket/any_A01_t02: Pass, Fail # Issue https://github.com/dart-lang/co19/issues/170
-LibTest/io/RawDatagramSocket/any_A01_t03: Pass, Fail # Issue https://github.com/dart-lang/co19/issues/170
-LibTest/io/RawDatagramSocket/asBroadcastStream_A01_t02: Pass, Fail # Issue https://github.com/dart-lang/co19/issues/170
-LibTest/io/RawDatagramSocket/distinct_A01_t05: Pass, Fail # Issue https://github.com/dart-lang/co19/issues/170
-LibTest/io/RawDatagramSocket/lastWhere_A01_t02: Pass, Fail # Issue https://github.com/dart-lang/co19/issues/170
-LibTest/io/RawDatagramSocket/listen_A02_t02: Pass, Fail # Issue https://github.com/dart-lang/co19/issues/170
-LibTest/io/RawDatagramSocket/receive_A01_t01: Pass, Fail # Issue https://github.com/dart-lang/co19/issues/170
-LibTest/io/RawDatagramSocket/timeout_A02_t01: Pass, Fail # Issue https://github.com/dart-lang/co19/issues/170
-LibTest/io/RawDatagramSocket/timeout_A06_t01: Pass, Fail # Next roll might fix it (see https://github.com/dart-lang/co19/commit/8b2e2be5bc3bb9fec41efec8ac6fc777e231d915)
-LibTest/io/RawDatagramSocket/where_A01_t01: Pass, Fail # Issue https://github.com/dart-lang/co19/issues/170
[ $fasta ]
Language/Classes/Instance_Methods/Operators/allowed_names_t01: Skip # triple-shift flag
Language/Classes/Instance_Methods/Operators/allowed_names_t23: Skip # triple-shift flag
Language/Classes/Instance_Methods/Operators/arity_1_t19: Skip # triple-shift flag
-Language/Classes/Superclasses/wrong_superclass_t08: MissingCompileTimeError # Issue 30273
-Language/Classes/Superinterfaces/wrong_type_t05: MissingCompileTimeError # Issue 30273
-Language/Classes/method_definition_t06: MissingCompileTimeError # Legal
Language/Enums/restrictions_t10: Crash
Language/Expressions/Assignment/Compound_Assignment/expression_assignment_t12: Skip # triple-shift flag
Language/Expressions/Assignment/Compound_Assignment/indexed_expression_assignment_t12: Skip # triple-shift flag
@@ -52,13 +38,8 @@
Language/Expressions/Constants/bitwise_operators_t01: Skip # triple-shift flag
Language/Expressions/Constants/bitwise_operators_t07: Skip # triple-shift flag
Language/Expressions/Constants/bitwise_operators_t08: Skip # triple-shift flag
-Language/Expressions/Constants/constant_list_t02: MissingCompileTimeError # Legal because of implicit const
-Language/Expressions/Constants/constant_map_t02: MissingCompileTimeError # Legal because of implicit const
Language/Expressions/Equality/syntax_t01: Skip # triple-shift flag
-Language/Expressions/Instance_Creation/Const/arguments_t03: MissingCompileTimeError # Legal because of implicit const
-Language/Expressions/Instance_Creation/New/syntax_t04: MissingCompileTimeError # Legal because of implicit new
Language/Expressions/Lists/syntax_t01: Skip # triple-shift flag
-Language/Expressions/Maps/key_value_equals_operator_t01: MissingCompileTimeError # Issue 32557
Language/Expressions/Maps/syntax_t01: Skip # triple-shift flag
Language/Expressions/Relational_Expressions/syntax_t01: Skip # triple-shift experiment flag
Language/Expressions/Shift/allowed_characters_t02: Skip # triple-shift flag
@@ -89,7 +70,6 @@
Language/Expressions/Symbols/syntax_t02: Skip # triple-shift experiment flag
Language/Expressions/parentheses_t01: Skip # triple-shift experiment flag
Language/Functions/syntax_t03: Skip # triple-shift experiment flag
-Language/Libraries_and_Scripts/Imports/library_name_t01: MissingCompileTimeError # Expects an error, but this is a warning in Dart 2
Language/Mixins/Mixin_Application/abstract_t09: Crash
Language/Mixins/Mixin_Application/abstract_t10: Crash
Language/Mixins/Mixin_Application/abstract_t11: Crash
@@ -103,7 +83,6 @@
Language/Mixins/Mixin_Application/initializers_t06: Crash
Language/Mixins/Mixin_Application/interfaces_t06: Crash
Language/Mixins/Mixin_Application/interfaces_t07: Crash
-Language/Mixins/Mixin_Application/static_warning_t01: MissingCompileTimeError # Mixin super equirement
Language/Mixins/Mixin_Application/superclass_t03: Crash
Language/Mixins/Mixin_Application/superclass_t04: Crash
Language/Mixins/Mixin_Application/superinterfaces_t10: Crash
@@ -114,13 +93,10 @@
Language/Mixins/Mixin_Application/warning_t04: Crash
Language/Mixins/Mixin_Application/wrong_mixin_type_t09: Crash
Language/Mixins/Mixin_Composition/order_t02: Crash
-Language/Mixins/declaring_constructor_t05: MissingCompileTimeError # Mixin constructor
-Language/Mixins/declaring_constructor_t06: MissingCompileTimeError # Mixin constructor
Language/Mixins/declaring_constructor_t11: Crash
Language/Reference/Operator_Precedence/precedence_01_assignment_t14: Skip # triple-shift experimental flag
Language/Reference/Operator_Precedence/precedence_12_Shift_t04: Skip # triple-shift experimental flag
Language/Reference/Operator_Precedence/precedence_t05: Skip # triple-shift experimental flag
-Language/Statements/Continue/label_t07: MissingCompileTimeError # Issue 34206
Language/Statements/Expression_Statements/syntax_t06: Skip # triple-shift experimental flag
LanguageFeatures/Constant-update-2018/NewOperators_A01_t01: Crash
LanguageFeatures/Constant-update-2018/NewOperators_A01_t02: Crash
@@ -199,9 +175,6 @@
LanguageFeatures/Instantiate-to-bound/class/static/class_typedef_l2_t08/02: Crash
LanguageFeatures/Instantiate-to-bound/class/static/class_typedef_l2_t08/none: Crash
LanguageFeatures/Set-literals/disambiguating_A02_t03: Crash
-LanguageFeatures/Super-mixins/covariance_t03: MissingCompileTimeError # Issue 35111
-LanguageFeatures/Super-mixins/covariance_t06: MissingCompileTimeError # Issue 35111
-LanguageFeatures/Super-mixins/covariance_t07: MissingCompileTimeError # Issue 35111
LanguageFeatures/regression/34803_t01: Crash
LanguageFeatures/regression/34803_t02: Crash
@@ -214,19 +187,8 @@
LanguageFeatures/Subtyping/static/generated/function_type_function_arguments_binding_A04_t02: Crash
[ $arch == simdbc64 && ($compiler == dartk || $compiler == dartkb) ]
-LibTest/collection/ListBase/ListBase_class_A01_t02: Timeout, Pass # https://github.com/dart-lang/sdk/issues/35316 as well?
-LibTest/collection/ListMixin/ListMixin_class_A01_t02: Timeout, Pass # https://github.com/dart-lang/sdk/issues/35316 as well?
LibTest/isolate/Isolate/removeErrorListener_A02_t01: Crash
-[ $compiler != dart2js && $runtime != vm && $fasta ]
-Language/Classes/Constructors/Constant_Constructors/invalid_constant_initializer_t02: MissingCompileTimeError # Issue 34192
-Language/Expressions/Instance_Creation/Const/exception_t01: MissingCompileTimeError # Issue 31936
-Language/Metadata/compilation_t03: MissingCompileTimeError # Issue 34205
-
-[ $compiler != dart2js && $fasta ]
-Language/Statements/Switch/equal_operator_t01: MissingCompileTimeError # Issue 32557
-Language/Statements/Switch/equal_operator_t02: MissingCompileTimeError # Issue 32557
-
[ $runtime == vm && $system == linux && ($compiler == dartk || $compiler == dartkb) ]
LibTest/isolate/Isolate/spawn_A06_t03: Crash
@@ -238,9 +200,6 @@
LibTest/core/List/List_class_A01_t02: Slow
LibTest/core/List/List_class_A01_t03: Slow
-[ $runtime != vm && $fasta ]
-Language/Classes/Constructors/Constant_Constructors/potentially_constant_expression_t01: MissingCompileTimeError # Issue 34192
-
[ $runtime != vm && ($compiler == dartk || $compiler == dartkb) ]
Language/Classes/Constructors/Constant_Constructors/potentially_constant_expression_t01: Crash
diff --git a/tests/compiler/dart2js/dart2js.status b/tests/compiler/dart2js/dart2js.status
index 17a3670..9afaf8b 100644
--- a/tests/compiler/dart2js/dart2js.status
+++ b/tests/compiler/dart2js/dart2js.status
@@ -2,71 +2,71 @@
# 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.
-analyses/analyze_test: Slow, Pass
-analyses/api_dynamic_test: Slow, Pass
-analyses/dart2js_dynamic_test: Slow, Pass
-closure/closure_test: Pass, Slow
+analyses/analyze_test: Slow
+analyses/api_dynamic_test: Slow
+analyses/dart2js_dynamic_test: Slow
+closure/closure_test: Slow
codegen/gvn_dynamic_field_get_test: Fail # Issue 18519
codegen/list_tracer_length_test: Fail # Issue 33051
-codegen/load_elimination_test: Pass, Slow
+codegen/load_elimination_test: Slow
codegen/logical_expression_test: Fail # Issue 17027
-codegen/model_test: Pass, Slow
+codegen/model_test: Slow
codegen/side_effect_tdiv_regression_test: Fail # Issue 33050
codegen/simple_function_subtype_test: Fail # simple_function_subtype_test is temporarily(?) disabled due to new method for building function type tests.
-deferred_loading/deferred_loading_test: Slow, Pass
-end_to_end/dump_info_test: Slow, Pass
+deferred_loading/deferred_loading_test: Slow
+end_to_end/dump_info_test: Slow
end_to_end/generate_code_with_compile_time_errors_test: RuntimeError # not supported yet with the new FE.
end_to_end/show_package_warnings_test: RuntimeError # missing errors from the FE
-equivalence/id_equivalence1_test: Pass, Slow
-equivalence/id_equivalence2_test: Pass, Slow
-impact/impact_test: Pass, Slow
-inference/inference0_test: Slow, Pass
-inference/inference1_test: Slow, Pass
-inference/inference2_test: Slow, Pass
-inference/inference3_test: Slow, Pass
+equivalence/id_equivalence1_test: Slow
+equivalence/id_equivalence2_test: Slow
+impact/impact_test: Slow
+inference/inference0_test: Slow
+inference/inference1_test: Slow
+inference/inference2_test: Slow
+inference/inference3_test: Slow
inference/simple_inferrer_const_closure2_test: Fail # Issue 16507
inference/simple_inferrer_const_closure_test: Fail # Issue 16507
inference/simple_inferrer_global_field_closure_test: Fail # Issue 16507
inference/swarm_test: Slow, Pass, Fail #
-inlining/inlining_test: Slow, Pass
-model/native_test: Pass, Slow
-model/no_such_method_enabled_test: Pass, Slow
-model/subtype_test: Pass, Slow
-modular/*: Slow, Pass
+inlining/inlining_test: Slow
+model/native_test: Slow
+model/no_such_method_enabled_test: Slow
+model/subtype_test: Slow
+modular/*: Slow
packages/*: Skip # Skip packages folder
-rti/rti_emission_test: Pass, Slow
-rti/rti_need0_test: Pass, Slow
-rti/rti_need1_test: Pass, Slow
-serialization/serialization_test: Pass, Slow
+rti/rti_emission_test: Slow
+rti/rti_need0_test: Slow
+rti/rti_need1_test: Slow
+serialization/serialization_test: Slow
sourcemaps/d2js_validity_test: RuntimeError # Issue 33072
sourcemaps/deferred_d2js_validity_test: RuntimeError # Issue 33072
-sourcemaps/source_mapping_invokes_test: Pass, Slow
-sourcemaps/source_mapping_operators_test: Pass, Slow
-sourcemaps/source_mapping_test: Pass, Slow
-sourcemaps/stacktrace_test: Pass, Slow
+sourcemaps/source_mapping_invokes_test: Slow
+sourcemaps/source_mapping_operators_test: Slow
+sourcemaps/source_mapping_test: Slow
+sourcemaps/stacktrace_test: Slow
[ $mode == debug ]
-deferred/load_graph_segmentation_test: Pass, Slow
-deferred/load_mapping_test: Pass, Slow
-end_to_end/dart2js_batch_test: Pass, Slow
-end_to_end/exit_code_test: Pass, Slow
-end_to_end/in_user_code_test: Pass, Slow
-end_to_end/show_package_warnings_test: Pass, Slow
+deferred/load_graph_segmentation_test: Slow
+deferred/load_mapping_test: Slow
+end_to_end/dart2js_batch_test: Slow
+end_to_end/exit_code_test: Slow
+end_to_end/in_user_code_test: Slow
+end_to_end/show_package_warnings_test: Slow
[ $checked ]
-codegen/value_range_kernel_test: Pass, Slow
-codegen/value_range_test: Pass, Slow
-end_to_end/exit_code_test: Pass, Slow
-end_to_end/output_type_test: Pass, Slow
-end_to_end/uri_retention_test: Pass, Slow
-jsinterop/declaration_test: Slow, Pass
-jsinterop/interop_anonymous_unreachable_test: Pass, Slow
-jsinterop/world_test: Pass, Slow
-sourcemaps/stacktrace_test: Pass, Slow
+codegen/value_range_kernel_test: Slow
+codegen/value_range_test: Slow
+end_to_end/exit_code_test: Slow
+end_to_end/output_type_test: Slow
+end_to_end/uri_retention_test: Slow
+jsinterop/declaration_test: Slow
+jsinterop/interop_anonymous_unreachable_test: Slow
+jsinterop/world_test: Slow
+sourcemaps/stacktrace_test: Slow
[ !$checked ]
end_to_end/exit_code_test: Skip # This tests requires checked mode.
-jsinterop/declaration_test: Slow, Pass
+jsinterop/declaration_test: Slow
[ $runtime == chrome || $runtime == ff || $runtime == firefox || $runtime == safari || $jscl ]
*: Skip # dart2js uses #import('dart:io'); and it is not self-hosted (yet).
diff --git a/tests/compiler/dart2js/end_to_end/no_platform_test.dart b/tests/compiler/dart2js/end_to_end/no_platform_test.dart
index c6c11da..968507b 100644
--- a/tests/compiler/dart2js/end_to_end/no_platform_test.dart
+++ b/tests/compiler/dart2js/end_to_end/no_platform_test.dart
@@ -36,7 +36,6 @@
asyncTest(() async {
await runTest(const {});
- await runTest(const {fe.ExperimentalFlag.constantUpdate2018: true});
- await runTest(const {fe.ExperimentalFlag.spreadCollections: true});
+ await runTest(const {fe.ExperimentalFlag.extensionMethods: true});
});
}
diff --git a/tests/compiler/dart2js/equivalence/id_equivalence_helper.dart b/tests/compiler/dart2js/equivalence/id_equivalence_helper.dart
index 54eeeac..4455bf5 100644
--- a/tests/compiler/dart2js/equivalence/id_equivalence_helper.dart
+++ b/tests/compiler/dart2js/equivalence/id_equivalence_helper.dart
@@ -429,7 +429,6 @@
if (setUpFunction != null) setUpFunction();
- print('name="${name}"');
if (skip.contains(name)) {
print('--skipped ------------------------------------------------------');
} else {
diff --git a/tests/compiler/dart2js/impact/data/jsinterop_setter1.dart b/tests/compiler/dart2js/impact/data/jsinterop_setter1.dart
new file mode 100644
index 0000000..eab4fd4
--- /dev/null
+++ b/tests/compiler/dart2js/impact/data/jsinterop_setter1.dart
@@ -0,0 +1,51 @@
+// Copyright (c) 2019, 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.
+
+@JS()
+library main;
+
+import 'dart:html' show File;
+
+import 'package:js/js.dart';
+
+/*member: foo=:
+ type=[
+ inst:JSBool,
+ native:ApplicationCacheErrorEvent,
+ native:DomError,
+ native:DomException,
+ native:ErrorEvent,
+ native:MediaError,
+ native:NavigatorUserMediaError,
+ native:OverconstrainedError,
+ native:PositionError,
+ native:SensorErrorEvent,
+ native:SpeechRecognitionError,
+ native:SqlError,
+ param:Function]
+ */
+@JS()
+external set foo(Function f);
+
+/*member: _doStuff:
+ dynamic=[File.==,File.name],
+ static=[defineProperty(3),print(1)],
+ type=[inst:JSBool,inst:JSNull,inst:JSString,param:File,param:String]
+*/
+void _doStuff(String name, File file) {
+ if (file == null) {
+ print('OK');
+ }
+ print(file.name);
+}
+
+/*member: main:
+ static=[
+ _doStuff,
+ allowInterop<Function>(1),
+ set:foo]
+*/
+void main() {
+ foo = allowInterop(_doStuff);
+}
diff --git a/tests/compiler/dart2js/impact/data/jsinterop_setter2.dart b/tests/compiler/dart2js/impact/data/jsinterop_setter2.dart
new file mode 100644
index 0000000..0dbb322
--- /dev/null
+++ b/tests/compiler/dart2js/impact/data/jsinterop_setter2.dart
@@ -0,0 +1,64 @@
+// Copyright (c) 2019, 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.
+
+@JS()
+library main;
+
+import 'dart:html' show File;
+
+import 'package:js/js.dart';
+
+/*member: foo=:
+ static=[
+ checkSubtype(4),
+ getRuntimeTypeArgument(3),
+ getRuntimeTypeArgumentIntercepted(4),
+ getRuntimeTypeInfo(1),
+ getTypeArgumentByIndex(2),
+ setRuntimeTypeInfo(2)],
+ type=[
+ inst:JSArray<dynamic>,
+ inst:JSBool,
+ inst:JSExtendableArray<dynamic>,
+ inst:JSFixedArray<dynamic>,
+ inst:JSMutableArray<dynamic>,
+ inst:JSUnmodifiableArray<dynamic>,
+ native:ApplicationCacheErrorEvent,
+ native:DomError,
+ native:DomException,
+ native:ErrorEvent,
+ native:File,
+ native:MediaError,
+ native:NavigatorUserMediaError,
+ native:OverconstrainedError,
+ native:PositionError,
+ native:SensorErrorEvent,
+ native:SpeechRecognitionError,
+ native:SqlError,
+ param:void Function(String,File)]
+*/
+@JS()
+external set foo(void Function(String, File) f);
+
+/*member: _doStuff:
+ dynamic=[File.==,File.name],
+ static=[defineProperty(3),print(1)],
+ type=[inst:JSBool,inst:JSNull,inst:JSString,param:File,param:String]
+*/
+void _doStuff(String name, File file) {
+ if (file == null) {
+ print('OK');
+ }
+ print(file.name);
+}
+
+/*member: main:
+ static=[
+ _doStuff,
+ allowInterop<void Function(String,File)>(1),
+ set:foo]
+*/
+void main() {
+ foo = allowInterop(_doStuff);
+}
diff --git a/tests/compiler/dart2js/model/cfe_constant_evaluation_test.dart b/tests/compiler/dart2js/model/cfe_constant_evaluation_test.dart
index 5dabc0f..180375b 100644
--- a/tests/compiler/dart2js/model/cfe_constant_evaluation_test.dart
+++ b/tests/compiler/dart2js/model/cfe_constant_evaluation_test.dart
@@ -600,7 +600,9 @@
(ir.LocatedMessage message, List<ir.LocatedMessage> context) {
// TODO(johnniwinther): Assert that `message.uri != null`. Currently
// all unevaluated constants have no uri.
- errors.add(message.code.name);
+ // The actual message is a "constant errors starts here" message,
+ // the "real error message" is the first in the context.
+ errors.add(context.first.code.name);
reportLocatedMessage(elementMap.reporter, message, context);
}, environment: environment, supportReevaluationForTesting: true);
ir.Constant evaluatedConstant = evaluator.evaluate(initializer);
diff --git a/tests/compiler/dart2js_extra/37576_test.dart b/tests/compiler/dart2js_extra/37576_test.dart
new file mode 100644
index 0000000..b243963
--- /dev/null
+++ b/tests/compiler/dart2js_extra/37576_test.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2019, 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:js/js.dart';
+
+@JS('jsFun')
+external set jsFun(Function fun);
+
+void main() {
+ jsFun = allowInterop(dartFun);
+}
+
+void dartFun() {}
diff --git a/tests/compiler/dart2js_extra/dart2js_extra.status b/tests/compiler/dart2js_extra/dart2js_extra.status
index b1acb29..efc2aea 100644
--- a/tests/compiler/dart2js_extra/dart2js_extra.status
+++ b/tests/compiler/dart2js_extra/dart2js_extra.status
@@ -3,16 +3,8 @@
# BSD-style license that can be found in the LICENSE file.
[ $compiler == dart2js ]
-23264_test: RuntimeError
-bound_closure_interceptor_type_test: RuntimeError
bounds_check4a_test: RuntimeError # Issue 32741
bounds_check4b_test: RuntimeError # Issue 32741
-class_test: Fail
-closure_capture2_test: RuntimeError
-constant_javascript_semantics4_test: Fail, OK
-constant_javascript_semantics_test/03: CompileTimeError
-constant_javascript_semantics_test/04: CompileTimeError
-constant_javascript_semantics_test/none: CompileTimeError
generic_class_is_test: Fail # Issue 32004
jsinterop_test/01: MissingCompileTimeError # Issue 34174
jsinterop_test/02: MissingCompileTimeError # Issue 34174
@@ -52,17 +44,6 @@
non_jsinterop_test/52: MissingCompileTimeError # Issue 34345
non_jsinterop_test/53: MissingCompileTimeError # Issue 34345
non_jsinterop_test/54: MissingCompileTimeError # Issue 34345
-private_symbol_literal_test/01: MissingCompileTimeError
-private_symbol_literal_test/02: MissingCompileTimeError
-private_symbol_literal_test/03: MissingCompileTimeError
-private_symbol_literal_test/04: MissingCompileTimeError
-private_symbol_literal_test/05: MissingCompileTimeError
-private_symbol_literal_test/06: MissingCompileTimeError
-regress/4562_test/none: CompileTimeError
-round_constant_folding_test: CompileTimeError
-statements_test: Fail
-type_constant_switch_test/01: MissingCompileTimeError
-typed_locals_test: Pass, Fail
[ $compiler != dart2js ]
dummy_compiler_test: SkipByDesign # Issue 30773. Test should be migrated as a unit test of dart2js, is only intended to test self-hosting.
@@ -100,11 +81,6 @@
[ $compiler == dart2js && $runtime == none ]
*: Fail, Pass # TODO(ahe): Triage these tests.
-[ $compiler == dart2js && $checked ]
-dummy_compiler_test: Crash
-local_signature_test: Crash
-minus_zero_test/01: MissingCompileTimeError
-
[ $compiler == dart2js && $csp ]
deferred_custom_loader_test: SkipByDesign # Issue 25683
deferred_fail_and_retry_test: SkipByDesign # Uses eval to simulate failed loading.
@@ -118,9 +94,7 @@
closure_capture2_test: Pass # Passes for the wrong reason
code_motion_exception_test: Skip # Requires unminified operator names.
deferred/reflect_multiple_annotations_test: Crash # NoSuchMethodError: The getter 'closureClassEntity' was called on null.
-deferred/reflect_multiple_annotations_test: Fail
deferred/reflect_multiple_default_arg_test: Crash # NoSuchMethodError: The getter 'closureClassEntity' was called on null.
-deferred/reflect_multiple_default_arg_test: Fail
mirrors_used_warning_test/minif: Fail, OK # Tests warning that minified code will be broken.
runtime_type_test: Fail, OK # Tests extected output of Type.toString().
to_string_test: Fail # Issue 7179.
diff --git a/tests/compiler/dart2js_native/dart2js_native.status b/tests/compiler/dart2js_native/dart2js_native.status
index 0d9594f..ad3e21a 100644
--- a/tests/compiler/dart2js_native/dart2js_native.status
+++ b/tests/compiler/dart2js_native/dart2js_native.status
@@ -3,20 +3,14 @@
# BSD-style license that can be found in the LICENSE file.
[ $compiler == dart2js ]
-bound_closure_super_test: RuntimeError
fake_thing_test: RuntimeError # Issue 13010
field_type2_test: CompileTimeError # Issue 33762
field_type_test: CompileTimeError # Issue 33762
native_exceptions1_frog_test: CompileTimeError # Issue 33762
-native_library_same_name_used_frog_test: CompileTimeError
native_mixin_with_plain_test: CompileTimeError # Issue 33762
native_window1_frog_test: CompileTimeError # Issue 33762
native_window2_frog_test: CompileTimeError # Issue 33762
subclassing_constructor_1_test: CompileTimeError # Issue 33762
-subclassing_constructor_1_test: RuntimeError
-subclassing_super_call_test: RuntimeError
-subclassing_super_field_1_test: RuntimeError
-subclassing_super_field_2_test: RuntimeError
[ $browser ]
*: Skip
diff --git a/tests/corelib_2/corelib_2.status b/tests/corelib_2/corelib_2.status
index 4d9dd1d..04290fc 100644
--- a/tests/corelib_2/corelib_2.status
+++ b/tests/corelib_2/corelib_2.status
@@ -163,9 +163,6 @@
symbol_test/none: RuntimeError # Issues 11669 and 31936 - throwing const constructors.
unicode_test: RuntimeError # Issue 18061: German double S.
-[ !$preview_dart_2 && ($runtime == dart_precompiled || $runtime == vm) ]
-*: SkipByDesign # Deprecating all Dart1 modes of execution
-
[ ($arch == simdbc || $arch == simdbc64) && ($hot_reload || $hot_reload_rollback) ]
uri_parse_test: SkipSlow
diff --git a/tests/corelib_2/unsigned_shift_test.dart b/tests/corelib_2/unsigned_shift_test.dart
index 09687f8..457bc7c 100644
--- a/tests/corelib_2/unsigned_shift_test.dart
+++ b/tests/corelib_2/unsigned_shift_test.dart
@@ -44,7 +44,7 @@
}
}
-void testNonDoublesShift() {
+void testNonDoubleShifts() {
double n = 0.0;
n >>> 1; //# 01: compile-time error
for (dynamic number in [0.0, 1.0, 2.4, -2.4, double.infinity, double.nan]) {
@@ -60,25 +60,25 @@
// >>> is a constant operation on integers.
const c1 = 2 >>> 1;
const c2 = (1 >>> 0) >>> 0;
- // >> is a potentially constant operation independent of type.
+ // >>> is a potentially constant operation independent of type.
// The type must still type-check.
const c3 = false ? 1 : c >>> c;
- const c4 = true || c >>> c;
// It's an error if it doesn't type-check.
- const c5 = true || "string" >>> 1; //# 02: compile-time error
+ const c4 = true || c >>> c; //# 02: compile-time error
+ const c5 = true || "string" >>> 1; //# 03: compile-time error
// Or if the shift isn't on integers and it is evaluated.
- const c6 = c >>> c; //# 03: compile-time error
+ const c6 = c >>> c; //# 04: compile-time error
// Or if shifting throws
- const c7 = 1 >>> -1; //# 04: compile-time error
- const c8 = 1 >>> 65; //# 05: compile-time error
+ const c7 = 1 >>> -1; //# 05: compile-time error
+ const c8 = 1 >>> 65; //# 06: compile-time error
- Expect.notNull(c1 + c2 + c3 + c4); // Avoid "unused variable" warnings.
+ Expect.isNotNull(c1 + c2 + c3); // Avoid "unused variable" warnings.
}
-const bool isJSBitOps => (-1 | 0) > 0;
+const bool isJSBitOps = (-1 | 0) > 0;
const String jsFlag = isJSBitOps ? " (JS)" : "";
void testShift(int value, int shift) {
@@ -94,7 +94,7 @@
return;
}
var expected;
- if (isJsBitOps) {
+ if (isJSBitOps) {
// TODO: Check that this is the desired behavior for JS >>>.
expected = value.toUnsigned(32) >> shift;
} else if (value < 0) {
diff --git a/tests/ffi/ffi.status b/tests/ffi/ffi.status
index 7652349..46f4755 100644
--- a/tests/ffi/ffi.status
+++ b/tests/ffi/ffi.status
@@ -2,33 +2,32 @@
# 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.
-[ $arch == simdbc ]
-*: Skip # FFI not yet supported on SimDBC32: dartbug.com/36809
+[ $arch == simdbc || $arch == simdbc64 ]
+*: Skip # SIMDBC will be deleted soon.
-[ $arch == simdbc64 ]
-function_callbacks_test: Skip # Issue 37140
-regress_37511_callbacks_test: Skip # Issue 37140
+# Issue 37295, not yet supported in blobs snapshots at present.
+[ $compiler == dartkp && $system == windows ]
+function_callbacks_test: Skip
+regress_37511_callbacks_test: Skip
+stacktrace_regress_37910_test: Skip
+
+[ $compiler != dartkp || $system != windows ]
+function_callbacks_unsupported_test: SkipByDesign # See above
[ $builder_tag == asan ]
data_not_asan_test: SkipByDesign # This test tries to allocate too much memory on purpose.
-# These tests trigger and catch an abort (intentionally) and terminate the VM
-# before it can generate a snapshot.
-[ $compiler == app_jitk ]
+# These tests trigger and catch an abort (intentionally) and terminate the VM.
+# They're incompatible with ASAN because not all memory is freed when aborting and
+# with AppJit because the abort the VM before it can generate a snapshot.
+[ $compiler == app_jitk || $builder_tag == asan ]
function_callbacks_test/01: Skip
function_callbacks_test/02: Skip
function_callbacks_test/03: Skip
-[ $runtime == dart_precompiled ]
-function_callbacks_test: Skip # Issue dartbug.com/37295
-regress_37511_callbacks_test: Skip # Issue dartbug.com/37295
-
[ $arch == arm && $system != android ]
*: Skip # "hardfp" calling convention is not yet supported (iOS is also supported but not tested): dartbug.com/36309
-[ $arch == simdbc64 && $system != linux && $system != macos ]
-*: Skip # DBC is only supported on MacOS and Linux for testing
-
[ $runtime != dart_precompiled && $runtime != vm ]
*: SkipByDesign # FFI is a VM-only feature. (This test suite is part of the default set.)
diff --git a/tests/ffi/function_callbacks_test.dart b/tests/ffi/function_callbacks_test.dart
index 4377938..1c5eca5 100644
--- a/tests/ffi/function_callbacks_test.dart
+++ b/tests/ffi/function_callbacks_test.dart
@@ -5,7 +5,9 @@
// Dart test program for testing dart:ffi function pointers with callbacks.
//
// VMOptions=--enable-testing-pragmas
+// VMOptions=--enable-testing-pragmas --stacktrace-every=100
// VMOptions=--enable-testing-pragmas --write-protect-code --no-dual-map-code
+// VMOptions=--enable-testing-pragmas --write-protect-code --no-dual-map-code --stacktrace-every=100
// SharedObjects=ffi_test_functions
library FfiTest;
@@ -190,26 +192,26 @@
Test("ManyInts", Pointer.fromFunction<ManyIntsType>(manyInts, 0)),
Test("ManyDoubles", Pointer.fromFunction<ManyDoublesType>(manyDoubles, 0.0)),
Test("ManyArgs", Pointer.fromFunction<ManyArgsType>(manyArgs, 0.0)),
- Test("Store", Pointer.fromFunction<StoreType>(store, null)),
- Test("NullPointers", Pointer.fromFunction<NullPointersType>(nullPointers, null)),
+ Test("Store", Pointer.fromFunction<StoreType>(store)),
+ Test("NullPointers", Pointer.fromFunction<NullPointersType>(nullPointers)),
Test("ReturnNull", Pointer.fromFunction<ReturnNullType>(returnNull, 42)),
- Test("ReturnVoid", Pointer.fromFunction<ReturnVoid>(returnVoid, null)),
+ Test("ReturnVoid", Pointer.fromFunction<ReturnVoid>(returnVoid)),
Test("ThrowExceptionDouble",
Pointer.fromFunction<ThrowExceptionDouble>(throwExceptionDouble, 42.0)),
Test(
"ThrowExceptionPointer",
Pointer.fromFunction<ThrowExceptionPointer>(
- throwExceptionPointer, Pointer<Void>.fromAddress(42))),
+ throwExceptionPointer)),
Test("ThrowException", Pointer.fromFunction<ThrowExceptionInt>(throwExceptionInt, 42)),
- Test("GC", Pointer.fromFunction<ReturnVoid>(testGC, null)),
- Test("UnprotectCode", Pointer.fromFunction<WaitForHelper>(waitForHelper, null)),
+ Test("GC", Pointer.fromFunction<ReturnVoid>(testGC)),
+ Test("UnprotectCode", Pointer.fromFunction<WaitForHelper>(waitForHelper)),
];
testCallbackWrongThread() =>
- Test("CallbackWrongThread", Pointer.fromFunction<ReturnVoid>(returnVoid, null)).run();
+ Test("CallbackWrongThread", Pointer.fromFunction<ReturnVoid>(returnVoid)).run();
testCallbackOutsideIsolate() =>
- Test("CallbackOutsideIsolate", Pointer.fromFunction<ReturnVoid>(returnVoid, null))
+ Test("CallbackOutsideIsolate", Pointer.fromFunction<ReturnVoid>(returnVoid))
.run();
isolateHelper(int callbackPointer) {
@@ -221,22 +223,25 @@
}
testCallbackWrongIsolate() async {
- final int callbackPointer = Pointer.fromFunction<ReturnVoid>(returnVoid, null).address;
+ final int callbackPointer = Pointer.fromFunction<ReturnVoid>(returnVoid).address;
final ReceivePort exitPort = ReceivePort();
await Isolate.spawn(isolateHelper, callbackPointer,
errorsAreFatal: true, onExit: exitPort.sendPort);
await exitPort.first;
}
+const double zeroPointZero = 0.0;
+
// Correct type of exceptionalReturn argument to Pointer.fromFunction.
double testExceptionalReturn() {
Pointer.fromFunction<Double Function()>(testExceptionalReturn, 0.0);
- Expect.throwsArgumentError(() => Pointer.fromFunction<Void Function()>(returnVoid, 0));
- Pointer.fromFunction<Void Function()>(returnVoid, null);
- Expect.throwsArgumentError(() => Pointer.fromFunction<Double Function()>(returnVoid, null));
+ Pointer.fromFunction<Double Function()>(testExceptionalReturn, zeroPointZero);
+ Pointer.fromFunction<Double Function()>(returnVoid, null); //# 59: compile-time error
+ Pointer.fromFunction<Void Function()>(returnVoid, 0); //# 60: compile-time error
Pointer.fromFunction<Double Function()>(testExceptionalReturn, "abc"); //# 61: compile-time error
Pointer.fromFunction<Double Function()>(testExceptionalReturn, 0); //# 62: compile-time error
+ Pointer.fromFunction<Double Function()>(testExceptionalReturn); //# 63: compile-time error
}
void main() async {
@@ -261,11 +266,1014 @@
// trampolines. The use of distinct exceptional return values forces separate
// trampolines.
final List<Pointer> pointers = [];
- for (int i = 0; i < 1000; ++i) {
- pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, i));
- }
+
+ // All the parameters of 'fromFunction' are forced to be constant so that we
+ // only need to generate one trampoline per 'fromFunction' call-site.
+ //
+ // As a consequence, to force the creation of 1000 trampolines (and prevent
+ // any possible caching), we need literally 1000 call-sites.
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 0));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 1));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 2));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 3));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 4));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 5));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 6));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 7));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 8));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 9));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 10));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 11));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 12));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 13));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 14));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 15));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 16));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 17));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 18));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 19));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 20));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 21));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 22));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 23));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 24));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 25));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 26));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 27));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 28));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 29));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 30));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 31));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 32));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 33));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 34));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 35));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 36));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 37));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 38));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 39));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 40));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 41));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 42));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 43));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 44));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 45));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 46));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 47));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 48));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 49));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 50));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 51));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 52));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 53));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 54));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 55));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 56));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 57));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 58));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 59));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 60));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 61));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 62));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 63));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 64));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 65));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 66));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 67));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 68));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 69));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 70));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 71));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 72));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 73));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 74));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 75));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 76));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 77));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 78));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 79));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 80));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 81));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 82));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 83));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 84));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 85));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 86));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 87));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 88));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 89));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 90));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 91));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 92));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 93));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 94));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 95));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 96));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 97));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 98));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 99));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 100));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 101));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 102));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 103));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 104));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 105));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 106));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 107));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 108));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 109));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 110));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 111));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 112));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 113));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 114));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 115));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 116));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 117));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 118));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 119));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 120));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 121));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 122));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 123));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 124));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 125));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 126));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 127));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 128));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 129));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 130));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 131));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 132));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 133));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 134));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 135));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 136));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 137));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 138));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 139));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 140));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 141));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 142));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 143));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 144));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 145));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 146));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 147));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 148));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 149));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 150));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 151));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 152));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 153));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 154));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 155));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 156));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 157));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 158));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 159));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 160));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 161));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 162));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 163));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 164));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 165));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 166));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 167));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 168));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 169));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 170));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 171));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 172));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 173));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 174));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 175));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 176));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 177));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 178));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 179));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 180));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 181));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 182));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 183));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 184));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 185));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 186));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 187));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 188));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 189));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 190));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 191));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 192));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 193));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 194));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 195));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 196));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 197));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 198));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 199));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 200));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 201));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 202));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 203));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 204));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 205));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 206));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 207));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 208));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 209));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 210));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 211));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 212));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 213));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 214));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 215));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 216));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 217));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 218));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 219));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 220));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 221));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 222));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 223));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 224));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 225));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 226));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 227));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 228));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 229));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 230));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 231));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 232));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 233));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 234));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 235));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 236));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 237));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 238));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 239));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 240));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 241));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 242));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 243));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 244));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 245));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 246));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 247));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 248));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 249));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 250));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 251));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 252));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 253));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 254));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 255));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 256));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 257));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 258));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 259));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 260));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 261));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 262));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 263));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 264));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 265));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 266));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 267));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 268));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 269));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 270));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 271));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 272));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 273));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 274));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 275));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 276));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 277));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 278));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 279));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 280));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 281));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 282));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 283));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 284));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 285));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 286));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 287));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 288));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 289));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 290));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 291));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 292));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 293));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 294));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 295));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 296));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 297));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 298));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 299));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 300));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 301));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 302));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 303));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 304));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 305));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 306));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 307));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 308));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 309));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 310));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 311));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 312));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 313));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 314));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 315));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 316));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 317));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 318));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 319));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 320));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 321));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 322));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 323));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 324));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 325));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 326));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 327));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 328));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 329));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 330));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 331));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 332));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 333));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 334));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 335));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 336));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 337));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 338));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 339));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 340));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 341));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 342));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 343));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 344));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 345));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 346));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 347));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 348));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 349));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 350));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 351));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 352));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 353));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 354));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 355));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 356));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 357));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 358));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 359));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 360));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 361));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 362));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 363));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 364));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 365));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 366));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 367));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 368));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 369));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 370));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 371));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 372));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 373));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 374));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 375));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 376));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 377));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 378));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 379));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 380));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 381));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 382));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 383));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 384));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 385));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 386));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 387));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 388));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 389));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 390));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 391));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 392));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 393));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 394));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 395));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 396));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 397));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 398));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 399));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 400));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 401));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 402));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 403));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 404));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 405));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 406));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 407));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 408));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 409));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 410));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 411));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 412));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 413));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 414));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 415));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 416));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 417));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 418));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 419));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 420));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 421));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 422));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 423));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 424));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 425));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 426));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 427));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 428));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 429));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 430));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 431));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 432));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 433));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 434));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 435));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 436));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 437));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 438));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 439));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 440));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 441));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 442));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 443));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 444));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 445));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 446));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 447));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 448));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 449));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 450));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 451));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 452));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 453));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 454));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 455));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 456));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 457));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 458));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 459));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 460));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 461));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 462));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 463));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 464));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 465));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 466));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 467));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 468));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 469));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 470));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 471));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 472));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 473));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 474));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 475));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 476));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 477));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 478));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 479));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 480));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 481));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 482));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 483));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 484));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 485));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 486));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 487));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 488));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 489));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 490));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 491));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 492));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 493));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 494));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 495));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 496));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 497));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 498));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 499));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 500));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 501));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 502));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 503));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 504));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 505));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 506));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 507));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 508));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 509));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 510));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 511));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 512));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 513));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 514));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 515));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 516));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 517));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 518));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 519));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 520));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 521));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 522));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 523));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 524));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 525));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 526));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 527));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 528));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 529));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 530));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 531));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 532));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 533));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 534));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 535));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 536));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 537));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 538));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 539));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 540));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 541));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 542));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 543));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 544));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 545));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 546));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 547));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 548));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 549));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 550));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 551));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 552));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 553));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 554));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 555));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 556));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 557));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 558));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 559));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 560));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 561));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 562));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 563));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 564));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 565));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 566));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 567));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 568));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 569));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 570));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 571));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 572));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 573));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 574));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 575));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 576));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 577));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 578));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 579));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 580));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 581));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 582));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 583));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 584));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 585));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 586));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 587));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 588));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 589));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 590));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 591));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 592));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 593));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 594));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 595));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 596));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 597));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 598));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 599));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 600));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 601));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 602));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 603));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 604));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 605));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 606));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 607));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 608));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 609));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 610));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 611));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 612));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 613));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 614));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 615));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 616));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 617));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 618));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 619));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 620));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 621));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 622));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 623));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 624));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 625));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 626));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 627));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 628));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 629));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 630));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 631));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 632));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 633));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 634));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 635));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 636));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 637));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 638));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 639));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 640));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 641));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 642));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 643));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 644));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 645));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 646));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 647));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 648));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 649));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 650));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 651));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 652));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 653));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 654));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 655));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 656));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 657));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 658));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 659));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 660));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 661));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 662));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 663));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 664));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 665));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 666));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 667));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 668));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 669));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 670));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 671));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 672));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 673));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 674));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 675));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 676));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 677));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 678));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 679));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 680));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 681));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 682));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 683));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 684));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 685));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 686));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 687));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 688));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 689));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 690));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 691));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 692));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 693));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 694));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 695));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 696));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 697));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 698));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 699));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 700));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 701));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 702));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 703));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 704));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 705));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 706));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 707));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 708));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 709));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 710));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 711));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 712));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 713));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 714));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 715));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 716));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 717));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 718));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 719));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 720));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 721));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 722));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 723));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 724));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 725));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 726));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 727));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 728));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 729));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 730));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 731));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 732));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 733));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 734));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 735));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 736));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 737));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 738));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 739));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 740));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 741));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 742));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 743));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 744));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 745));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 746));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 747));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 748));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 749));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 750));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 751));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 752));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 753));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 754));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 755));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 756));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 757));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 758));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 759));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 760));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 761));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 762));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 763));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 764));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 765));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 766));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 767));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 768));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 769));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 770));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 771));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 772));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 773));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 774));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 775));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 776));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 777));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 778));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 779));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 780));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 781));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 782));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 783));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 784));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 785));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 786));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 787));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 788));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 789));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 790));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 791));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 792));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 793));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 794));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 795));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 796));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 797));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 798));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 799));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 800));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 801));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 802));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 803));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 804));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 805));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 806));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 807));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 808));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 809));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 810));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 811));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 812));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 813));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 814));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 815));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 816));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 817));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 818));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 819));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 820));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 821));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 822));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 823));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 824));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 825));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 826));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 827));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 828));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 829));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 830));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 831));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 832));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 833));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 834));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 835));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 836));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 837));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 838));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 839));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 840));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 841));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 842));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 843));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 844));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 845));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 846));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 847));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 848));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 849));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 850));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 851));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 852));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 853));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 854));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 855));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 856));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 857));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 858));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 859));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 860));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 861));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 862));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 863));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 864));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 865));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 866));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 867));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 868));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 869));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 870));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 871));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 872));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 873));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 874));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 875));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 876));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 877));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 878));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 879));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 880));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 881));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 882));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 883));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 884));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 885));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 886));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 887));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 888));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 889));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 890));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 891));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 892));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 893));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 894));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 895));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 896));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 897));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 898));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 899));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 900));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 901));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 902));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 903));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 904));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 905));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 906));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 907));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 908));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 909));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 910));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 911));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 912));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 913));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 914));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 915));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 916));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 917));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 918));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 919));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 920));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 921));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 922));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 923));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 924));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 925));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 926));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 927));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 928));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 929));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 930));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 931));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 932));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 933));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 934));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 935));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 936));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 937));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 938));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 939));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 940));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 941));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 942));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 943));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 944));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 945));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 946));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 947));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 948));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 949));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 950));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 951));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 952));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 953));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 954));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 955));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 956));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 957));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 958));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 959));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 960));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 961));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 962));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 963));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 964));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 965));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 966));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 967));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 968));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 969));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 970));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 971));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 972));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 973));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 974));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 975));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 976));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 977));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 978));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 979));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 980));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 981));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 982));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 983));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 984));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 985));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 986));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 987));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 988));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 989));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 990));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 991));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 992));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 993));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 994));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 995));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 996));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 997));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 998));
+ pointers.add(Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 999));
for (final pointer in pointers) {
Test("SimpleAddition", pointer).run();
}
-}
\ No newline at end of file
+}
diff --git a/tests/ffi/function_callbacks_unsupported_test.dart b/tests/ffi/function_callbacks_unsupported_test.dart
new file mode 100644
index 0000000..5ac1b5d
--- /dev/null
+++ b/tests/ffi/function_callbacks_unsupported_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// Dart test program for testing that FFI callbacks report an appropriate
+// runtime error for unsupported snapshot formats.
+
+import 'dart:ffi';
+
+import 'package:expect/expect.dart';
+
+bool checkError(UnsupportedError err) {
+ return "$err".contains("callbacks are not yet supported in blobs");
+}
+
+void main() {
+ Expect.throws<UnsupportedError>(
+ () => Pointer.fromFunction<Void Function()>(main), checkError);
+}
diff --git a/tests/ffi/function_gc_test.dart b/tests/ffi/function_gc_test.dart
index b212b32..ed56e34 100644
--- a/tests/ffi/function_gc_test.dart
+++ b/tests/ffi/function_gc_test.dart
@@ -6,6 +6,8 @@
// VMOptions=--deterministic --optimization-counter-threshold=-1 --enable-testing-pragmas
// VMOptions=--deterministic --optimization-counter-threshold=500 --enable-testing-pragmas --no-dual-map-code --write-protect-code
// VMOptions=--deterministic --optimization-counter-threshold=-1 --enable-testing-pragmas --no-dual-map-code --write-protect-code
+// VMOptions=--enable-testing-pragmas --no-dual-map-code --write-protect-code
+// VMOptions=--enable-testing-pragmas --no-dual-map-code --write-protect-code --stacktrace-every=100
//
// Dart test program for stress-testing boxing and GC in return paths from FFI
// trampolines.
diff --git a/tests/ffi/function_test.dart b/tests/ffi/function_test.dart
index 68529bd..b4e6d7c 100644
--- a/tests/ffi/function_test.dart
+++ b/tests/ffi/function_test.dart
@@ -7,8 +7,10 @@
// VMOptions=
// VMOptions=--deterministic --optimization-counter-threshold=10
// VMOptions=--use-slow-path
+// VMOptions=--use-slow-path --stacktrace-every=100
// VMOptions=--write-protect-code --no-dual-map-code
// VMOptions=--write-protect-code --no-dual-map-code --use-slow-path
+// VMOptions=--write-protect-code --no-dual-map-code --stacktrace-every=100
// SharedObjects=ffi_test_functions
library FfiTest;
diff --git a/tests/ffi/stacktrace_regress_37910_test.dart b/tests/ffi/stacktrace_regress_37910_test.dart
new file mode 100644
index 0000000..0a76648
--- /dev/null
+++ b/tests/ffi/stacktrace_regress_37910_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2019, 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.
+//
+// VMOptions=--stacktrace_every=100
+
+import 'dart:ffi' as ffi;
+
+typedef fooFfi1Type = ffi.Int32 Function();
+int fooFfi1() {
+ int a = 0;
+ for (int i = 0; i < 1000; ++i) {
+ a += i;
+ }
+ return a;
+}
+
+int Function() foo1 = ffi.Pointer.fromFunction<fooFfi1Type>(fooFfi1, 0)
+ .cast<ffi.NativeFunction<fooFfi1Type>>()
+ .asFunction();
+
+main() {
+ foo1();
+}
diff --git a/tests/ffi/static_checks_test.dart b/tests/ffi/static_checks_test.dart
index 0a24b6d..22d5256 100644
--- a/tests/ffi/static_checks_test.dart
+++ b/tests/ffi/static_checks_test.dart
@@ -36,6 +36,7 @@
testFromFunctionTypeMismatch();
testFromFunctionClosure();
testFromFunctionTearOff();
+ testFromFunctionAbstract();
testLookupFunctionGeneric();
testLookupFunctionGeneric2();
testLookupFunctionWrongNativeFunctionSignature();
@@ -248,6 +249,10 @@
p = ffi.fromFunction(fld); //# 75: compile-time error
}
+void testFromFunctionAbstract() {
+ ffi.Pointer.fromFunction<Function>(testFromFunctionAbstract); //# 76: compile-time error
+}
+
void testLookupFunctionGeneric() {
Function generic<T extends Function>() {
ffi.DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
diff --git a/tests/kernel/kernel.status b/tests/kernel/kernel.status
index 53968e2..00f926c 100644
--- a/tests/kernel/kernel.status
+++ b/tests/kernel/kernel.status
@@ -8,9 +8,3 @@
[ !$fasta ]
unsorted/loop_test: Skip # This test uses optional new/const.
-
-[ $builder_tag == obfuscated && $runtime == dart_precompiled ]
-unsorted/symbol_literal_test: RuntimeError # Issue 34911
-
-[ !$preview_dart_2 && ($runtime == dart_precompiled || $runtime == vm) ]
-*: SkipByDesign # Deprecating all Dart1 modes of execution
diff --git a/tests/language_2/compile_time_constant_static5_test.dart b/tests/language_2/compile_time_constant_static5_test.dart
index 48eb09b..c1666e8 100644
--- a/tests/language_2/compile_time_constant_static5_test.dart
+++ b/tests/language_2/compile_time_constant_static5_test.dart
@@ -40,7 +40,7 @@
// Will be instantiated with U=A and V=B.
class Test3<U extends A, V extends B> {
- final U x = const A(); //# 11: ok
+ final U x = const A(); //# 11: compile-time error
final U x = const B(); //# 12: compile-time error
final V x = const A(); //# 13: compile-time error
final V x = const C(); //# 14: compile-time error
@@ -50,7 +50,7 @@
// Will be instantiated with U=A and V=B.
class Test4<U extends A, V extends A> {
- final U x = const A(); //# 16: ok
+ final U x = const A(); //# 16: compile-time error
final U x = const B(); //# 17: compile-time error
final V x = const A(); //# 18: compile-time error
final V x = const C(); //# 19: compile-time error
@@ -60,9 +60,9 @@
// Will be instantiated with U=dynamic and V=dynamic.
class Test5<U extends A, V extends B> {
- final U x = const A(); //# 21: ok
+ final U x = const A(); //# 21: compile-time error
final U x = const B(); //# 22: compile-time error
- final V x = const A(); //# 23: ok
+ final V x = const A(); //# 23: compile-time error
final V x = const C(); //# 24: compile-time error
final V x = const C.d(); //# 25: compile-time error
const Test5();
diff --git a/tests/language_2/config_import_corelib_general.dart b/tests/language_2/config_import_corelib_general.dart
index 04d3b5c..295f09a 100644
--- a/tests/language_2/config_import_corelib_general.dart
+++ b/tests/language_2/config_import_corelib_general.dart
@@ -4,7 +4,11 @@
class Classy {
String get name => "classy general";
+ String httpSpecific() => throw UnimplementedError();
+ String ioSpecific() => throw UnimplementedError();
}
bool general() => true;
+bool httpSpecific() => false;
+bool ioSpecific() => false;
final String name = "general";
diff --git a/tests/language_2/config_import_corelib_http.dart b/tests/language_2/config_import_corelib_http.dart
index 292e091..857e391 100644
--- a/tests/language_2/config_import_corelib_http.dart
+++ b/tests/language_2/config_import_corelib_http.dart
@@ -7,8 +7,10 @@
class Classy {
String get name => "classy http";
String httpSpecific() => "classy http";
+ String ioSpecific() => throw UnimplementedError();
}
bool general() => true;
bool httpSpecific() => true;
+bool ioSpecific() => false;
final String name = "http";
diff --git a/tests/language_2/config_import_corelib_io.dart b/tests/language_2/config_import_corelib_io.dart
index d5b594a..5e1543d 100644
--- a/tests/language_2/config_import_corelib_io.dart
+++ b/tests/language_2/config_import_corelib_io.dart
@@ -6,9 +6,11 @@
class Classy {
String get name => "classy io";
+ String httpSpecific() => throw UnimplementedError();
String ioSpecific() => "classy io";
}
bool general() => true;
+bool httpSpecific() => false;
bool ioSpecific() => true;
final String name = "io";
diff --git a/tests/language_2/config_import_corelib_test.dart b/tests/language_2/config_import_corelib_test.dart
index 1428bd5..9267d50 100644
--- a/tests/language_2/config_import_corelib_test.dart
+++ b/tests/language_2/config_import_corelib_test.dart
@@ -26,23 +26,15 @@
Expect.isTrue(lib.ioSpecific());
Expect.equals("classy io", cy.ioSpecific());
- Expect.throws(() {
- lib.httpSpecific();
- });
- Expect.throws(() {
- cy.httpSpecific();
- });
+ Expect.isFalse(lib.httpSpecific());
+ Expect.throws(cy.httpSpecific);
} else if (http) {
Expect.isTrue(lib.general());
Expect.equals("http", lib.name);
Expect.equals("classy http", cy.name);
- Expect.throws(() {
- lib.ioSpecific();
- });
- Expect.throws(() {
- cy.ioSpecific();
- });
+ Expect.isFalse(lib.ioSpecific());
+ Expect.throws(cy.ioSpecific);
Expect.isTrue(lib.httpSpecific());
Expect.equals("classy http", cy.httpSpecific());
@@ -51,18 +43,10 @@
Expect.equals("general", lib.name);
Expect.equals("classy general", cy.name);
- Expect.throws(() {
- lib.ioSpecific();
- });
- Expect.throws(() {
- cy.ioSpecific();
- });
+ Expect.isFalse(lib.ioSpecific());
+ Expect.throws(cy.ioSpecific);
- Expect.throws(() {
- lib.httpSpecific();
- });
- Expect.throws(() {
- cy.httpSpecific();
- });
+ Expect.isFalse(lib.httpSpecific());
+ Expect.throws(cy.httpSpecific);
}
}
diff --git a/tests/language_2/deferred_load_library_wrong_args_test.dart b/tests/language_2/deferred_load_library_wrong_args_test.dart
index 9055eae..1cd2ded 100644
--- a/tests/language_2/deferred_load_library_wrong_args_test.dart
+++ b/tests/language_2/deferred_load_library_wrong_args_test.dart
@@ -2,7 +2,11 @@
void main() {
// Loadlibrary should be called without arguments.
- lib.loadLibrary(
- 10 //# 01: runtime error
- );
+ lib.loadLibrary(10);
+//^
+// [analyzer] unspecified
+// [cfe] 'loadLibrary' takes no arguments.
+ // ^
+ // [analyzer] unspecified
+ // [cfe] Too many positional arguments: 0 allowed, but 1 found.
}
diff --git a/tests/language_2/extension_methods/static_extension_getter_setter_conflicts_test.dart b/tests/language_2/extension_methods/static_extension_getter_setter_conflicts_test.dart
new file mode 100644
index 0000000..402ff2d
--- /dev/null
+++ b/tests/language_2/extension_methods/static_extension_getter_setter_conflicts_test.dart
@@ -0,0 +1,162 @@
+// Copyright (c) 2019, 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.
+
+// SharedOptions=--enable-experiment=extension-methods
+
+// Tests interactions between getters and setters where there is a conflict.
+
+// Conflicting class declarations.
+
+class C0 {
+ int get m1 => 0;
+ void set m2(int x) {}
+}
+
+extension E0 on C0 {
+ void set m1(int x) {}
+ int get m2 => 0;
+}
+
+void test0() {
+ C0 c0 = C0();
+ c0.m1;
+ c0.m1 = 0;
+ // ^^^^^^
+ // [analyzer] unspecified
+ // [cfe] unspecified
+ E0(c0).m1 = 0;
+ E0(c0).m1;
+ // ^^
+ // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_EXTENSION_GETTER
+ // [cfe] unspecified
+
+ c0.m1 += 0;
+ // ^^^^^^
+ // [analyzer] unspecified
+ // [cfe] unspecified
+
+ c0.m2 = 0;
+ c0.m2;
+ // ^^
+ // [analyzer] unspecified
+ // [cfe] unspecified
+ c0.m2 += 0;
+ // ^^^^^^^
+ // [analyzer] unspecified
+ // [cfe] unspecified
+ E0(c0).m2;
+}
+
+// Conflicting extensions.
+
+class C1<T> {
+}
+
+extension E1A<T> on C1<T> {
+ int get m1 => 0;
+ void set m2(int x) {}
+}
+
+extension E1B on C1<Object> {
+ void set m1(int x) {}
+ int get m2 => 0;
+}
+
+void test1() {
+ C1<int> c1a = C1<Null>(); // E1A is more specific.
+ c1a.m1;
+
+ c1a.m1 = 0;
+ // ^^^^^^
+ // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_EXTENSION_SETTER
+ // [cfe] unspecified
+
+ c1a.m2;
+ // ^^
+ // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_EXTENSION_GETTER
+ // [cfe] unspecified
+
+ c1a.m2 = 0;
+
+ C1<Object> c1b = C1<Null>(); // Neither extension is more specific.
+
+ c1b.m1;
+ // ^^
+ // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+ // [cfe] unspecified
+
+ c1b.m1 = 0;
+ // ^^^^^^
+ // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+ // [cfe] unspecified
+
+ c1b.m2;
+ // ^^
+ // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+ // [cfe] unspecified
+
+ c1b.m2 = 0;
+ // ^^^^^^
+ // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+ // [cfe] unspecified
+}
+
+// Getter on the extension itself.
+class C2 {
+ int get m1 => 0;
+ void set m2(int x) {}
+ int get mc => 0;
+}
+
+extension E2 on C2 {
+ void set m1(int x) {}
+ int get m2 => 0;
+ String get me => "";
+
+ void test2() {
+ // Using `this.member` means using the `on` type.
+
+ this.m1;
+ this.m1 = 0;
+ // ^^^^^^
+ // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_EXTENSION_SETTER
+ // [cfe] unspecified
+
+ this.m2 = 0;
+ this.m2;
+ // ^^
+ // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_EXTENSION_GETTER
+ // [cfe] unspecified
+
+ // Check that `this.mc` refers to `C2.mc`.
+ this.mc.toRadixString(16);
+ // Check that `this.me` refers to `E2.me`.
+ this.me.substring(0);
+
+ // An unqualified identifier is matched against the extension (by basename).
+
+ m1 = 0;
+ 1 + m1;
+ // ^^
+ // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_EXTENSION_GETTER
+ // [cfe] unspecified
+
+ 1 + m2;
+ if (true) m2 = 0; // for the indent!
+ // ^^^^^^
+ // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_EXTENSION_SETTER
+ // [cfe] unspecified
+
+ // Check that `mc` refers to `C2.me`.
+ mc.toRadixString(16);
+ // Check that `me` refers to `E2.me`.
+ me.substring(0);
+ }
+}
+
+main() {
+ test0();
+ test1();
+ C2().test2();
+}
diff --git a/tests/language_2/extension_methods/static_extension_internal_basename_shadowing_error_test.dart b/tests/language_2/extension_methods/static_extension_internal_basename_shadowing_error_test.dart
new file mode 100644
index 0000000..855cf6d
--- /dev/null
+++ b/tests/language_2/extension_methods/static_extension_internal_basename_shadowing_error_test.dart
@@ -0,0 +1,529 @@
+// Copyright (c) 2019, 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.
+
+// SharedOptions=--enable-experiment=extension-methods
+
+///////////////////////////////////////////////////////////////////////
+// The following tests check that setters or getters in an extension
+// correctly shadow members with the same basename in the surrounding
+// scope.
+///////////////////////////////////////////////////////////////////////
+
+int get topLevelGetter => -1;
+void set topLevelSetter(int _) {}
+int topLevelField = -3;
+int topLevelMethod(int x) => -4;
+
+// Check that an instance getter in an extension shadows top level
+// members with the same basename.
+extension E1 on A1 {
+ int get topLevelSetter => 1;
+ int get topLevelField => 2;
+ int get topLevelMethod => 3;
+ void test() {
+ // The instance getter shadows the global setter
+ topLevelSetter = topLevelSetter + 1;
+// ^^
+// [cfe] unspecified
+// ^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+ topLevelSetter++;
+// ^^
+// [cfe] unspecified
+// ^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+ topLevelSetter = 0;
+// ^^
+// [cfe] unspecified
+// ^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+
+ // The instance getter shadows the global field setter
+ topLevelField = topLevelField + 1;
+// ^^
+// [cfe] unspecified
+// ^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+ topLevelField++;
+// ^^
+// [cfe] unspecified
+// ^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+ topLevelField = 0;
+// ^^
+// [cfe] unspecified
+// ^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+
+ // The instance getter shadows the global method
+ topLevelMethod(4);
+// ^^
+// [cfe] unspecified
+// ^^^^^^^^^^^^^^
+// [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION
+ }
+}
+
+class A1 {}
+
+// Check that an instance setter in an extension shadows top level
+// members with the same basename.
+extension E2 on A2 {
+ void set topLevelGetter(int _) {}
+ void set topLevelField(int _) {}
+ void set topLevelMethod(int _) {}
+ void test() {
+ // The instance setter shadows the global getter
+ topLevelGetter = topLevelGetter + 1;
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+ topLevelGetter++;
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+ topLevelGetter;
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+ topLevelGetter = 3;
+
+ // The instance setter shadows the global field getter
+ topLevelField = topLevelField + 1;
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+ topLevelField++;
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+ topLevelField;
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+ // The instance setter shadows the global method
+ topLevelMethod(4);
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+ }
+}
+
+class A2 {}
+
+// Check that a static getter in an extension shadows top level
+// members with the same basename.
+extension E3 on A3 {
+ static int get topLevelSetter => 1;
+ static int get topLevelField => 2;
+ static int get topLevelMethod => 3;
+ void test() {
+ // The static getter shadows the global setter
+ topLevelSetter = topLevelSetter + 1;
+// ^^
+// [cfe] unspecified
+// ^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+ topLevelSetter++;
+// ^^
+// [cfe] unspecified
+// ^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+ topLevelSetter = 0;
+// ^^
+// [cfe] unspecified
+// ^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+
+ // The static getter shadows the global field setter
+ topLevelField = topLevelField + 1;
+// ^^
+// [cfe] unspecified
+// ^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+ topLevelField++;
+// ^^
+// [cfe] unspecified
+// ^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+ topLevelField = 0;
+// ^^
+// [cfe] unspecified
+// ^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+
+ // The static getter shadows the global method
+ topLevelMethod(4);
+// ^^
+// [cfe] unspecified
+// ^^^^^^^^^^^^^^
+// [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION
+ }
+}
+
+class A3 {}
+
+// Check that a static setter in an extension shadows top level
+// members with the same basename.
+extension E4 on A4 {
+ static void set topLevelGetter(int _) {}
+ static void set topLevelField(int _) {}
+ static void set topLevelMethod(int _) {}
+ void test() {
+ // The static setter shadows the global getter
+ topLevelGetter = topLevelGetter + 1;
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+ topLevelGetter++;
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+ topLevelGetter;
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+ // The static setter shadows the global field getter
+ topLevelField = topLevelField + 1;
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+ topLevelField++;
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+ topLevelField;
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+ // The static setter shadows the global method
+ topLevelMethod(4);
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+ }
+}
+
+class A4 {}
+
+// Define extensions on A6.
+extension E5 on A6 {
+ void set extensionSetter(int _) {};
+ int extensionMethod(int x) => -3;
+}
+
+// Check that an instance getter in an extension shadows extension
+// members with the same basename from a different extension.
+extension E6 on A6 {
+ int get extensionSetter => 1;
+ int get extensionMethod => 3;
+ void test() {
+ // The instance getter shadows the other extension's setter
+ extensionSetter = extensionSetter + 1;
+// ^^
+// [cfe] unspecified
+// ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+ extensionSetter++;
+// ^^
+// [cfe] unspecified
+// ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+ extensionSetter = 0;
+// ^^
+// [cfe] unspecified
+// ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+
+ // The instance getter shadows the other extensions method
+ extensionMethod(4);
+// ^^
+// [cfe] unspecified
+// ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION
+ }
+}
+
+class A6 {}
+
+// Check that an instance getter in a class shadows extension
+// members with the same basename from extension E5.
+class A7 extends A6 {
+ int get extensionSetter => 1;
+ int get extensionMethod => 3;
+ void test() {
+ // The instance getter shadows the other extension's setter
+ extensionSetter = extensionSetter + 1;
+// ^^
+// [cfe] unspecified
+// ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+ extensionSetter++;
+// ^^
+// [cfe] unspecified
+// ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+ extensionSetter = 0;
+// ^^
+// [cfe] unspecified
+// ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+
+ // The instance getter shadows the other extensions method
+ extensionMethod(4);
+// ^^
+// [cfe] unspecified
+// ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION
+ }
+}
+
+// Define extensions on A8.
+extension E7 on A8 {
+ int get extensionGetter => -1;
+ int extensionMethod(int x) => -3;
+}
+
+// Check that an instance setter in an extension shadows extension
+// members with the same basename from a different extension.
+extension E8 on A8 {
+ void set extensionGetter(int _) {}
+ void set extensionMethod(int _) {}
+ void test() {
+ // The instance setter shadows the other extension's getter
+ extensionGetter = extensionGetter + 1;
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+ extensionGetter++;
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+ extensionGetter;
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+ // The instance setter shadows the other extension's method.
+ extensionMethod(4);
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+ }
+}
+
+class A8 {}
+
+// Check that an instance setter in a class shadows extension
+// members with the same basename from extension E7.
+class A9 extends A8 {
+ void set extensionGetter(int _) {}
+ void set extensionMethod(int _) {}
+ void test() {
+ // The instance setter shadows the other extension's getter
+ extensionGetter = extensionGetter + 1;
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+ extensionGetter++;
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+ extensionGetter;
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+ // The instance setter shadows the other extension's method.
+ extensionMethod(4);
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+ }
+}
+
+// Define extensions on A10.
+extension E9 on A10 {
+ void set extensionSetter(int _) {}
+ void set extensionFieldSetter(int _) {}
+ int extensionMethod(int x) => -3;
+}
+
+// Check that a static getter in an extension shadows extension
+// members with the same basename from a different extension.
+extension E10 on A10 {
+ static int get extensionSetter => 1;
+ static final int extensionFieldSetter = 2;
+ static int get extensionMethod => 3;
+ void test() {
+ // The static getter shadows the other extension's setter
+ extensionSetter = extensionSetter + 1;
+// ^^
+// [cfe] unspecified
+// ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+ extensionSetter++;
+// ^^
+// [cfe] unspecified
+// ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+ extensionSetter = 0;
+// ^^
+// [cfe] unspecified
+// ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+
+ // The static field shadows the other extension's setter
+ extensionFieldSetter = extensionFieldSetter + 1;
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+ extensionFieldSetter++;
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+ extensionFieldSetter = 0;
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+ // The static getter shadows the other extensions method
+ extensionMethod(4);
+// ^^
+// [cfe] unspecified
+// ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION
+ }
+}
+
+class A10 {}
+
+// Check that a static getter in a class shadows extension
+// members with the same basename from extension E9.
+class A11 extends A10 {
+ static int get extensionSetter => 1;
+ static final int extensionFieldSetter = 2;
+ static int get extensionMethod => 3;
+ void test() {
+ // The static getter shadows the other extension's setter
+ extensionSetter = extensionSetter + 1;
+// ^^
+// [cfe] unspecified
+// ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+ extensionSetter++;
+// ^^
+// [cfe] unspecified
+// ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+ extensionSetter = 0;
+// ^^
+// [cfe] unspecified
+// ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+
+ // The static field shadows the other extension's setter
+ extensionFieldSetter = extensionFieldSetter + 1;
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+ extensionFieldSetter++;
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+ extensionFieldSetter = 0;
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+ // The static getter shadows the other extensions method
+ extensionMethod(4);
+// ^^
+// [cfe] unspecified
+// ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION
+ }
+}
+
+// Define extensions on A12.
+extension E11 on A12 {
+ int get extensionGetter => -1;
+ int extensionMethod(int x) => -3;
+}
+
+// Check that a static setter in an extension shadows extension
+// members with the same basename from a different extension.
+extension E12 on A12 {
+ static void set extensionGetter(int _) {}
+ static void set extensionMethod(int _) {}
+ void test() {
+ // The static setter shadows the other extension's getter
+ extensionGetter = extensionGetter + 1;
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+ extensionGetter++;
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+ extensionGetter;
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+ // The static setter shadows the other extension's method.
+ extensionMethod(4);
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+ }
+}
+
+class A12 {}
+
+// Check that a static setter in a class shadows extension
+// members with the same basename from extension E11.
+class A13 extends A12 {
+ static void set extensionGetter(int _) {}
+ static void set extensionMethod(int _) {}
+ void test() {
+ // The static setter shadows the other extension's getter
+ extensionGetter = extensionGetter + 1;
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+ extensionGetter++;
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+ extensionGetter;
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+ // The static setter shadows the other extension's method.
+ extensionMethod(4);
+// ^^
+// [analyzer] unspecified
+// [cfe] unspecified
+ }
+}
+
+void main() {
+ A1().test();
+ A2().test();
+ A3().test();
+ A4().test();
+ A6().test();
+ A7().test();
+ A8().test();
+ A9().test();
+ A10().test();
+ A11().test();
+ A12().test();
+ A13().test();
+}
diff --git a/tests/language_2/extension_methods/static_extension_internal_basename_shadowing_test.dart b/tests/language_2/extension_methods/static_extension_internal_basename_shadowing_test.dart
new file mode 100644
index 0000000..519451a
--- /dev/null
+++ b/tests/language_2/extension_methods/static_extension_internal_basename_shadowing_test.dart
@@ -0,0 +1,276 @@
+// Copyright (c) 2019, 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.
+
+// SharedOptions=--enable-experiment=extension-methods
+
+import "package:expect/expect.dart";
+
+///////////////////////////////////////////////////////////////////////
+// The following tests check that setters or getters in an extension
+// correctly shadow members with the same basename in the surrounding
+// scope.
+///////////////////////////////////////////////////////////////////////
+
+String get topLevelGetter => "-1";
+void set topLevelSetter(String _) {}
+String topLevelField = "-3";
+String topLevelMethod(String x) => "-4";
+
+// Location that extension setters write to.
+int _storeTo = null;
+// Check that the most recent setter call set the value
+// of _storeTo.
+void checkSetter(int x) {
+ int written = _storeTo;
+ _storeTo = null;
+ Expect.equals(written, x);
+}
+
+// Check that an instance getter in an extension shadows top level
+// members with the same basename.
+extension E1 on A1 {
+ int get topLevelSetter => 1;
+ int get topLevelField => 2;
+ int get topLevelMethod => 3;
+ void test() {
+ // Reading the local getters is valid
+ Expect.equals(topLevelSetter + 1, 2);
+ Expect.equals(topLevelField + 1, 3);
+ Expect.equals(topLevelMethod + 1, 4);
+ }
+}
+
+class A1 {}
+
+// Check that an instance setter in an extension shadows top level
+// members with the same basename.
+extension E2 on A2 {
+ void set topLevelGetter(int x) {
+ _storeTo = x;
+ }
+
+ void set topLevelField(int x) {
+ _storeTo = x;
+ }
+
+ void set topLevelMethod(int x) {
+ _storeTo = x;
+ }
+
+ void test() {
+ checkSetter(topLevelGetter = 42);
+ checkSetter(topLevelField = 42);
+ checkSetter(topLevelMethod = 42);
+ }
+}
+
+class A2 {}
+
+// Check that a static getter in an extension shadows top level
+// members with the same basename.
+extension E3 on A3 {
+ static int get topLevelSetter => 1;
+ static int get topLevelField => 2;
+ static int get topLevelMethod => 3;
+ void test() {
+ // Reading the local getters is valid
+ Expect.equals(topLevelSetter + 1, 2);
+ Expect.equals(topLevelField + 1, 3);
+ Expect.equals(topLevelMethod + 1, 4);
+ }
+}
+
+class A3 {}
+
+// Check that a static setter in an extension shadows top level
+// members with the same basename.
+extension E4 on A4 {
+ static void set topLevelGetter(int x) {
+ _storeTo = x;
+ }
+
+ static void set topLevelField(int x) {
+ _storeTo = x;
+ }
+
+ static void set topLevelMethod(int x) {
+ _storeTo = x;
+ }
+
+ void test() {
+ checkSetter(topLevelGetter = 42);
+ checkSetter(topLevelField = 42);
+ checkSetter(topLevelMethod = 42);
+ }
+}
+
+class A4 {}
+
+// Define extensions on A6.
+extension E5 on A6 {
+ void set extensionSetter(int x) {}
+ int extensionMethod(int x) => -3;
+}
+
+// Check that an instance getter in an extension shadows extension
+// members with the same basename from a different extension.
+extension E6 on A6 {
+ int get extensionSetter => 1;
+ int get extensionMethod => 3;
+ void test() {
+ // Reading the local getters is valid
+ Expect.equals(extensionSetter + 1, 2);
+ Expect.equals(extensionMethod + 1, 4);
+ }
+}
+
+class A6 {}
+
+// Check that an instance getter in a class shadows extension
+// members with the same basename from extension E5.
+class A7 extends A6 {
+ int get extensionSetter => 1;
+ int get extensionMethod => 3;
+ void test() {
+ // Reading the local getters is valid
+ Expect.equals(extensionSetter + 1, 2);
+ Expect.equals(extensionMethod + 1, 4);
+ }
+}
+
+// Define extensions on A8.
+extension E7 on A8 {
+ int get extensionGetter => -1;
+ int extensionMethod(int x) => -3;
+}
+
+// Check that an instance setter in an extension shadows extension
+// members with the same basename from a different extension.
+extension E8 on A8 {
+ void set extensionGetter(int x) {
+ _storeTo = x;
+ }
+
+ void set extensionMethod(int x) {
+ _storeTo = x;
+ }
+
+ void test() {
+ checkSetter(extensionGetter = 42);
+ checkSetter(extensionMethod = 42);
+ }
+}
+
+class A8 {}
+
+// Check that an instance setter in a class shadows extension
+// members with the same basename from extension E7.
+class A9 extends A8 {
+ void set extensionGetter(int x) {
+ _storeTo = x;
+ }
+
+ void set extensionMethod(int x) {
+ _storeTo = x;
+ }
+
+ void test() {
+ checkSetter(extensionGetter = 42);
+ checkSetter(extensionMethod = 42);
+ }
+}
+
+// Define extensions on A10.
+extension E9 on A10 {
+ void set extensionSetter(int x) {}
+ void set extensionFieldSetter(int x) {}
+ int extensionMethod(int x) => -3;
+}
+
+// Check that a static getter in an extension shadows extension
+// members with the same basename from a different extension.
+extension E10 on A10 {
+ static int get extensionSetter => 1;
+ static final int extensionFieldSetter = 2;
+ static int get extensionMethod => 3;
+ void test() {
+ // Reading the local getters is valid
+ Expect.equals(extensionSetter + 1, 2);
+ Expect.equals(extensionFieldSetter + 1, 3);
+ Expect.equals(extensionMethod + 1, 4);
+ }
+}
+
+class A10 {}
+
+// Check that a static getter in a class shadows extension
+// members with the same basename from extension E9.
+class A11 extends A10 {
+ static int get extensionSetter => 1;
+ static final int extensionFieldSetter = 2;
+ static int get extensionMethod => 3;
+ void test() {
+ // Reading the local getters is valid
+ Expect.equals(extensionSetter + 1, 2);
+ Expect.equals(extensionFieldSetter + 1, 3);
+ Expect.equals(extensionMethod + 1, 4);
+ }
+}
+
+// Define extensions on A12.
+extension E11 on A12 {
+ int get extensionGetter => -1;
+ int extensionMethod(int x) => -3;
+}
+
+// Check that a static setter in an extension shadows extension
+// members with the same basename from a different extension.
+extension E12 on A12 {
+ static void set extensionGetter(int x) {
+ _storeTo = x;
+ }
+
+ static void set extensionMethod(int x) {
+ _storeTo = x;
+ }
+
+ void test() {
+ checkSetter(extensionGetter = 42);
+ checkSetter(extensionMethod = 42);
+ }
+}
+
+class A12 {}
+
+// Check that a static setter in a class shadows extension
+// members with the same basename from extension E11.
+class A13 extends A12 {
+ static void set extensionGetter(int x) {
+ _storeTo = x;
+ }
+
+ static void set extensionMethod(int x) {
+ _storeTo = x;
+ }
+
+ void test() {
+ checkSetter(extensionGetter = 42);
+ checkSetter(extensionMethod = 42);
+ }
+}
+
+void main() {
+ A1().test();
+ A2().test();
+ A3().test();
+ A4().test();
+ A6().test();
+ A7().test();
+ A8().test();
+ A9().test();
+ A10().test();
+ A11().test();
+ A12().test();
+ A13().test();
+}
diff --git a/tests/language_2/extension_methods/static_extension_resolution_failures_test.dart b/tests/language_2/extension_methods/static_extension_resolution_failures_test.dart
index f7c38dc..0a70b9b 100644
--- a/tests/language_2/extension_methods/static_extension_resolution_failures_test.dart
+++ b/tests/language_2/extension_methods/static_extension_resolution_failures_test.dart
@@ -22,41 +22,58 @@
Expect.equals("EA.v2", a.v2);
Expect.equals("EB1.v2", b1.v2);
Expect.equals("EB2.v2", b2.v2);
- c // Cannot determine which of EB1 and EB2's v2 is more specific
- .v2 //# 01: compile-time error
- ;
+ // Cannot determine which of EB1 and EB2's v2 is more specific
+ c.v2;
+ //^^
+ // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+ // [cfe] The getter 'v2' isn't defined for the class 'C'.
Expect.equals("EA.v3", a.v3);
Expect.equals("EA.v3", b1.v3);
Expect.equals("EA.v3", b2.v3);
Expect.equals("EA.v3", c.v3);
-
Iterable<num> i_num = <int>[];
Iterable<int> ii = <int>[];
List<num> ln = <int>[];
List<int> li = <int>[];
- i_num // No `i_num` extension declared.
- .i_num //# 02: compile-time error
- ;
+ // No `i_num` extension declared.
+ i_num.i_num;
+ // ^^^^^
+ // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
+ // [cfe] The getter 'i_num' isn't defined for the class 'Iterable<num>'.
Expect.equals("Iterable<int>.i_num", ii.i_num);
Expect.equals("List<num>.i_num", ln.i_num);
- li // Both apply, neither is more specific.
- .i_num //# 03: compile-time error
- ;
+ // Both apply, neither is more specific.
+ li.i_num;
+ // ^^^^^
+ // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+ // [cfe] The getter 'i_num' isn't defined for the class 'List<int>'.
- c // no most specific because both are equally specific.
- .cs //# 04: compile-time error
- ;
+ // no most specific because both are equally specific.
+ c.cs;
+ //^^
+ // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+ // [cfe] The getter 'cs' isn't defined for the class 'C'.
+
+ // Both EIT.e1 and ELO.e1 apply, but their instantiated on
+ // types are incomparable, and hence this is an error.
+ ln.e1();
+ // ^
+ // [analyzer] unspecified
+ // [cfe] The method 'e1' isn't defined for the class 'List<num>'.
}
// Diamond class hierarchy.
class A {}
+
class B1 implements A {}
+
class B2 implements A {}
+
class C implements B1, B2 {}
extension EA on A {
@@ -97,3 +114,11 @@
extension C2 on C {
String get cs => "C2.cs";
}
+
+extension EIT<T> on Iterable<T> {
+ String e1() => "Iterable<T>.e1";
+}
+
+extension ELO on List<Object> {
+ String e1() => "List<Object>.e1";
+}
diff --git a/tests/language_2/extension_methods/static_extension_resolution_test.dart b/tests/language_2/extension_methods/static_extension_resolution_test.dart
index e766025..42bddbc 100644
--- a/tests/language_2/extension_methods/static_extension_resolution_test.dart
+++ b/tests/language_2/extension_methods/static_extension_resolution_test.dart
@@ -210,16 +210,16 @@
// Applicable methods.
Expect.equals("SubTarget<T>.e1", s1.e1());
- Expect.equals("SubTarget<Object>.e2", s1.e2());
- Expect.equals("Target<T>.e3", s1.e3());
- Expect.equals("Target<Object>.e4", s1.e4());
+ Expect.equals("T.e2", s1.e2());
+ Expect.equals("T.e3", s1.e3());
+ Expect.equals("T.e4", s1.e4());
Expect.equals("T.e5", s1.e5());
Expect.equals("Object.e6", s1.e6());
Expect.equals("Target<T>.e1", t1.e1());
Expect.equals("Target<T>.e2", t1.e2());
Expect.equals("Target<T>.e3", t1.e3());
- Expect.equals("Target<Object>.e4", t1.e4());
+ Expect.equals("T.e4", t1.e4());
Expect.equals("T.e5", t1.e5());
Expect.equals("Object.e6", t1.e6());
diff --git a/tests/language_2/f_bounded_quantification2_test.dart b/tests/language_2/f_bounded_quantification2_test.dart
index 23d78b6..b55977b 100644
--- a/tests/language_2/f_bounded_quantification2_test.dart
+++ b/tests/language_2/f_bounded_quantification2_test.dart
@@ -4,9 +4,9 @@
// Test for F-Bounded Quantification. Regression test for issue 9291.
-class Entities<T extends ConceptEntity<T>> implements EntitiesApi {}
+class Entities<T extends ConceptEntity<T>> implements EntitiesApi<T> {}
-class ConceptEntity<T extends ConceptEntity<T>> implements EntityApi {}
+class ConceptEntity<T extends ConceptEntity<T>> implements EntityApi<T> {}
abstract class EntityApi<T extends EntityApi<T>> {}
diff --git a/tests/language_2/f_bounded_quantification4_test.dart b/tests/language_2/f_bounded_quantification4_test.dart
index d48a31d..c3f7dec 100644
--- a/tests/language_2/f_bounded_quantification4_test.dart
+++ b/tests/language_2/f_bounded_quantification4_test.dart
@@ -8,8 +8,10 @@
class A<T extends B<T>> {}
-class B<T> extends A {}
+class B<T extends B<T>> extends A<T> {}
+
+class Foo<T extends B<T>> extends B<Foo<T>> {}
main() {
- Expect.equals("B<B<dynamic>>", new B<B>().runtimeType.toString());
+ Expect.equals("Foo<Foo<B<dynamic>>>", new Foo<Foo>().runtimeType.toString());
}
diff --git a/tests/language_2/generic_no_such_method_dispatcher_test.dart b/tests/language_2/generic_no_such_method_dispatcher_test.dart
index 6ade491..336e7b9 100644
--- a/tests/language_2/generic_no_such_method_dispatcher_test.dart
+++ b/tests/language_2/generic_no_such_method_dispatcher_test.dart
@@ -41,13 +41,13 @@
}
main() {
- var a = new A();
+ dynamic a = new A();
for (var i = 0; i < 20; ++i) Expect.equals(123, a.foo<int, A>());
Expect.throws(() => (a.foo)());
Expect.throws(() => (a.foo)<int, A>());
Expect.equals("123", (a.foo).toString());
- var b = new B();
+ dynamic b = new B();
for (var i = 0; i < 20; ++i) {
Expect.equals(2, b.bar<int, A>(1));
Expect.equals(2, b.bar(1));
@@ -63,7 +63,7 @@
}
// Test type, named, and positional arguments.
- var c = new C([int, A], [100], {"n1": 101, "n2": 102});
+ dynamic c = new C([int, A], [100], {"n1": 101, "n2": 102});
for (var i = 0; i < 20; ++i) {
Expect.equals(123, c.bar<int, A>(100, n1: 101, n2: 102));
Expect.equals(123, c.bar<int, A>(100, n2: 102, n1: 101));
diff --git a/tests/language_2/issue31596_covariant_declaration_test.dart b/tests/language_2/issue31596_covariant_declaration_test.dart
new file mode 100644
index 0000000..20defe2
--- /dev/null
+++ b/tests/language_2/issue31596_covariant_declaration_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class I0 {}
+
+class A {}
+
+class B extends A implements I0 {}
+
+class C {
+ void f(B x) {}
+}
+
+abstract class I {
+ void f(covariant A x);
+}
+
+class D extends C implements I {}
+// ^
+// [analyzer] COMPILE_TIME_ERROR.INVALID_OVERRIDE
+// [cfe] unspecified
+
+main() {}
diff --git a/tests/language_2/issue31596_implement_covariant_test.dart b/tests/language_2/issue31596_implement_covariant_test.dart
deleted file mode 100644
index 901308c..0000000
--- a/tests/language_2/issue31596_implement_covariant_test.dart
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2018, 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";
-
-class A {}
-
-class B extends A {}
-
-class B2 extends A {}
-
-class C {
- void f(covariant B x) {}
-}
-
-abstract class I {
- void f(A x);
-}
-
-// This class does not require a forwarding stub; the interface of D.f is (A) ->
-// void and the implementation has signature (covariant B) -> void. The
-// implementation satisfies the interface thanks to the presence of the
-// "covariant" keyword.
-class D extends C implements I {}
-
-main() {
- var d = new D();
- I i = d;
- A a = new A();
- B b = new B();
- B2 b2Null = null;
-
- // The following two lines are statically ok because the type B2 is assignable
- // to the type A. There should be no runtime error because the actual value
- // at runtime is `null`, which may be assigned to A.
- d.f(b2Null);
- i.f(b2Null);
-
- void Function(Object) g = d.f; // Ok; D.f reified as (Object) -> void
- Expect.throwsTypeError(() {
- d.f(a);
- });
- Expect.throwsTypeError(() {
- i.f(a);
- });
-}
diff --git a/tests/language_2/issue31596_override_test.dart b/tests/language_2/issue31596_override_test.dart
index 5fd37d8..592ae44 100644
--- a/tests/language_2/issue31596_override_test.dart
+++ b/tests/language_2/issue31596_override_test.dart
@@ -14,31 +14,25 @@
void f(B x) {}
}
-abstract class I1 {
- void f(covariant A x);
+abstract class I1<X> {
+ void f(X x);
}
// This class contains a forwarding stub for f to allow it to satisfy the
-// interface I, while still ensuring that the x argument is type checked before
-// C.f is executed.
-//
-// For purposes of override checking, the forwarding stub is ignored.
-class D extends C implements I1 {}
+// interface I<B>, while still ensuring that the x argument is type checked
+// before C.f is executed.
+class D extends C implements I1<B> {}
class Test extends D {
- // Valid override - A assignable to A and B
void f(A x) {} //# 01: ok
void f(covariant A x) {} //# 02: ok
- // Valid override - B assignable to A and B
void f(B x) {} //# 03: ok
void f(covariant B x) {} //# 04: ok
- // Invalid override - I0 not assignable to A
- void f(I0 x) {} //# 05: compile-time error
- void f(covariant I0 x) {} //# 06: compile-time error
+ void f(I0 x) {} //# 05: ok
+ void f(covariant I0 x) {} //# 06: ok
- // Invalid override - B2 not assignable to B
void f(B2 x) {} //# 07: compile-time error
void f(covariant B2 x) {} //# 08: compile-time error
}
diff --git a/tests/language_2/issue31596_super_test.dart b/tests/language_2/issue31596_super_test.dart
index 875e4f3..86b7807 100644
--- a/tests/language_2/issue31596_super_test.dart
+++ b/tests/language_2/issue31596_super_test.dart
@@ -16,17 +16,17 @@
void f(B x) {}
}
-abstract class I {
- void f(covariant A x);
+abstract class I<X> {
+ void f(X x);
}
// This class contains a forwarding stub for f to allow it to satisfy the
-// interface I, while still ensuring that the x argument is type checked before
-// C.f is executed.
+// interface I<B>, while still ensuring that the x argument is type checked
+// before C.f is executed.
//
// Super calls in a derived class resolve directly to C.f, and are type checked
// accordingly at compile time.
-class D extends C implements I {}
+class D extends C implements I<B> {}
class E extends D {
void test() {
@@ -34,24 +34,26 @@
B2 b2 = null;
// ok since I0 is assignable to B
+ // TODO: Downcast from I0 to B will be a compile-time error with NNBD.
super.f(i0); //# 01: ok
// not ok since B2 is not assignable to B
super.f(b2); //# 02: compile-time error
- var superF = super.f; // Inferred type: (B) -> void
+ var superF = super.f; // Inferred static type: void Function(B)
// ok since I0 is assignable to B
+ // TODO: Downcast from I0 to B will be a compile-time error with NNBD.
superF(i0); //# 03: ok
// not ok since B2 is not assignable to B
superF(b2); //# 04: compile-time error
- // Should pass since superF's runtime type is (B) -> void
+ // Should pass since superF's runtime type is void Function(Object)
Expect.isTrue(superF is void Function(B)); //# 05: ok
- Expect.isTrue(superF is! void Function(I0)); //# 05: continued
- Expect.isTrue(superF is! void Function(A)); //# 05: continued
- Expect.isTrue(superF is! void Function(Object)); //# 05: continued
+ Expect.isTrue(superF is void Function(I0)); //# 05: continued
+ Expect.isTrue(superF is void Function(A)); //# 05: continued
+ Expect.isTrue(superF is void Function(Object)); //# 05: continued
}
}
diff --git a/tests/language_2/issue31596_tearoff_test.dart b/tests/language_2/issue31596_tearoff_test.dart
index 4feba46..035a7c7 100644
--- a/tests/language_2/issue31596_tearoff_test.dart
+++ b/tests/language_2/issue31596_tearoff_test.dart
@@ -8,41 +8,41 @@
class B extends A {}
-class B2 extends A {}
-
class C {
void f(B x) {}
}
-abstract class I {
- void f(covariant A x);
+abstract class I<X> {
+ void f(X x);
}
// This class contains a forwarding stub for f to allow it to satisfy the
-// interface I, while still ensuring that the x argument is type checked before
-// C.f is executed.
+// interface I<B>, while still ensuring that the x argument is type checked
+// before C.f is executed.
//
// For purposes of static type checking, the interface of the class D is
-// considered to contain a method f with signature (A) -> void. For purposes of
+// considered to contain a method f with signature (B) -> void. For purposes of
// runtime behavior, a tearoff of D.f is considered to have the reified runtime
// type (Object) -> void.
-class D extends C implements I {}
+class D extends C implements I<B> {}
main() {
var d = new D();
- B2 b2Null = null;
- B2 b2 = new B2();
+ A aNull = null;
+ A a = new A();
- // Since the compile-time type of D.f is (A) -> void, it is assignable to (B2)
+ // Since the compile-time type of D.f is (B) -> void, it is assignable to (A)
// -> void. Since the runtime type is (Object) -> void, the assignment is
// allowed at runtime as well.
- void Function(B2) g = d.f;
+ // TODO: Implicit downcast from void Function(B) to void Function(A) will be a
+ // compile-time error with NNBD. Consider using `d.f as dynamic`.
+ void Function(A) g = d.f;
// However, the tear-off performs a runtime check of its argument, so it
// accepts a value of `null`, but it does not accept a value whose runtime
- // type is B2.
- g(b2Null);
+ // type is A.
+ g(aNull);
Expect.throwsTypeError(() {
- g(b2);
+ g(a);
});
}
diff --git a/tests/language_2/issue31596_test.dart b/tests/language_2/issue31596_test.dart
index 0309256..4edb2ce 100644
--- a/tests/language_2/issue31596_test.dart
+++ b/tests/language_2/issue31596_test.dart
@@ -14,33 +14,37 @@
void f(B x, B y) {}
}
-abstract class I {
- void f(covariant A x, B y);
+abstract class I<X> {
+ void f(X x, B y);
}
// This class contains a forwarding stub for f to allow it to satisfy the
-// interface I, while still ensuring that the x argument is type checked before
-// C.f is executed.
+// interface I<B>, while still ensuring that the x argument is type checked
+// before C.f is executed.
//
// For purposes of static type checking, the interface of the class D is
-// considered to contain a method f with signature (A, B) -> void. For purposes
+// considered to contain a method f with signature (B, B) -> void. For purposes
// of runtime behavior, a tearoff of D.f is considered to have the reified
// runtime type (Object, B) -> void.
-class D extends C implements I {}
+class D extends C implements I<B> {}
main() {
var d = new D();
- I i = d;
+ I<A> i = d;
A a = new A();
B b = new B();
B2 b2 = null;
- d.f(b2, b); // Ok since B2 assignable to A
+ d.f(b2, b); //# 01: compile-time error
i.f(b2, b); // Ok since B2 assignable to A
+ // TODO: Downcast will be a compile-time error with NNBD. Consider using
+ // `d.f as dynamic`.
void Function(Object, B) g = d.f; // Ok; D.f reified as (Object, B) -> void
Expect.throwsTypeError(() {
+ // TODO: Downcast will be a compile-time error with NNBD.
d.f(a, b);
});
Expect.throwsTypeError(() {
+ // TODO: Downcast will be a compile-time error with NNBD.
i.f(a, b);
});
}
diff --git a/tests/language_2/language_2.status b/tests/language_2/language_2.status
index 157f47f..d03e859 100644
--- a/tests/language_2/language_2.status
+++ b/tests/language_2/language_2.status
@@ -53,13 +53,6 @@
partial_instantiation_static_bounds_check_test/02: MissingCompileTimeError # Issue 34327
partial_instantiation_static_bounds_check_test/03: MissingCompileTimeError # Issue 34327
-[ $compiler != compare_analyzer_cfe && $compiler != dart2js && $compiler != spec_parser && !$fasta ]
-compile_time_constant_static5_test/11: CompileTimeError # Issue 30546
-compile_time_constant_static5_test/16: CompileTimeError # Issue 30546
-compile_time_constant_static5_test/21: CompileTimeError # Issue 30546
-compile_time_constant_static5_test/23: CompileTimeError # Issue 30546
-type_promotion_more_specific_test/04: CompileTimeError # Issue 30906.
-
[ $compiler != compare_analyzer_cfe && $compiler != spec_parser ]
mixin_constructor_forwarding/const_constructor_test/none: CompileTimeError # Issue 32223
mixin_constructor_forwarding/const_constructor_with_field_test/none: CompileTimeError # Issue 32223
@@ -72,46 +65,7 @@
[ $compiler != dartk && $compiler != dartkb && $compiler != dartkp && $mode == debug && $runtime == vm ]
built_in_identifier_type_annotation_test/set: Crash # Not supported by legacy VM front-end.
-[ !$preview_dart_2 && ($runtime == dart_precompiled || $runtime == vm) ]
-*: SkipByDesign # Deprecating all Dart1 modes of execution
-
[ $hot_reload || $hot_reload_rollback ]
-cha_deopt1_test: Crash # Requires deferred libraries
-cha_deopt2_test: Crash # Requires deferred libraries
-cha_deopt3_test: Crash # Requires deferred libraries
-conditional_import_string_test: Crash # Requires deferred libraries
-conditional_import_test: Crash # Requires deferred libraries
-deferred_call_empty_before_load_test: Crash # Requires deferred libraries
-deferred_closurize_load_library_test: Crash # Requires deferred libraries
-deferred_constant_list_test: Crash # Requires deferred libraries
-deferred_constraints_constants_test: Crash # Requires deferred libraries
-deferred_constraints_type_annotation_test: Crash # Requires deferred libraries
-deferred_function_type_test: Crash # Requires deferred libraries
-deferred_global_test: Crash # Requires deferred libraries
-deferred_import_core_test: Crash # Requires deferred libraries
-deferred_inheritance_constraints_test: Crash # Requires deferred libraries
-deferred_inlined_test: Crash # Requires deferred libraries
-deferred_load_constants_test: Crash # Requires deferred libraries
-deferred_load_inval_code_test: Crash # Requires deferred libraries
-deferred_load_library_wrong_args_test: Crash # Requires deferred libraries
-deferred_mixin_test: Crash # Requires deferred libraries
-deferred_no_such_method_test: Crash # Requires deferred libraries
-deferred_not_loaded_check_test: Crash # Requires deferred libraries
-deferred_only_constant_test: Crash # Requires deferred libraries
-deferred_optimized_test: Crash # Requires deferred libraries
-deferred_redirecting_factory_test: Crash # Requires deferred libraries
-deferred_regression_22995_test: Crash # Requires deferred libraries
-deferred_regression_28678_test: Crash # Requires deferred libraries
-deferred_shadow_load_library_test: Crash # Requires deferred libraries
-deferred_shared_and_unshared_classes_test: Crash # Requires deferred libraries
-deferred_static_seperate_test: Crash # Requires deferred libraries
-deferred_super_dependency_test: Pass, Crash # Requires deferred libraries
-deferred_type_dependency_test: Crash # Requires deferred libraries
-issue_1751477_test: Crash # Requires deferred libraries
issue_22780_test/01: Pass, Crash # Issue 29094
-regress_22443_test: Crash # Requires deferred libraries
-regress_23408_test: Crash # Requires deferred libraries
-regress_28278_test: Crash # Requires deferred libraries
static_closure_identical_test: Pass, Fail # Closure identity
vm/optimized_stacktrace_test: Slow
-vm/regress_27201_test: Pass, Crash # Requires deferred libraries
diff --git a/tests/language_2/language_2_analyzer.status b/tests/language_2/language_2_analyzer.status
index 73d9383..bb945c5 100644
--- a/tests/language_2/language_2_analyzer.status
+++ b/tests/language_2/language_2_analyzer.status
@@ -5,90 +5,9 @@
# Sections in this file should contain "$compiler == dart2analyzer".
[ $compiler == dart2analyzer ]
-accessor_conflict_export2_test: CompileTimeError # Issue 25626
-accessor_conflict_export_test: CompileTimeError # Issue 25626
-accessor_conflict_import2_test: CompileTimeError # Issue 25626
-accessor_conflict_import_prefixed2_test: CompileTimeError # Issue 25626
-accessor_conflict_import_prefixed_test: CompileTimeError # Issue 25626
-accessor_conflict_import_test: CompileTimeError # Issue 25626
-cascaded_forwarding_stubs_test: CompileTimeError # Issue 34329
-config_import_corelib_test: CompileTimeError, StaticWarning, OK # failing-by-design: Will never pass, see Issue #34332
-const_cast2_test/01: CompileTimeError # failing-by-design: Not a const expression, see Issue #34334
-const_cast2_test/none: CompileTimeError # failing-by-design: Not a const expression, see Issue #34334
-covariant_subtyping_with_mixin_test: CompileTimeError # Issue 34329
-dynamic_prefix_core_test/01: MissingCompileTimeError # failing-by-design: #34339
-enum_syntax_test/05: Fail # Issue 34341
-enum_syntax_test/06: Fail # Issue 34341
-f_bounded_quantification2_test: CompileTimeError # Issue 34583
-f_bounded_quantification4_test: CompileTimeError # Issue 34583
-forwarding_stub_tearoff_test: CompileTimeError # Issue 34329
-generic_local_functions_test: CompileTimeError # Issue 28515
-generic_methods_generic_function_parameter_test: CompileTimeError # Issue 28515
-generic_methods_generic_function_result_test/none: CompileTimeError # Issue #30207
generic_no_such_method_dispatcher_simple_test: Skip # failing-by-design: This test is just for kernel
-generic_no_such_method_dispatcher_test: CompileTimeError # failing-by-design: This test needs to be updated for Dart 2, see Issue #34366
-generic_tearoff_test: CompileTimeError # failing-by-design: Analysis of generic function typed parameters is not yet supported
-getter_setter_in_lib_test: Fail # Issue 23286
-getters_setters2_test/01: CompileTimeError # failing-by-design: Test needs refactoring, see Issue #34365
-getters_setters_type_test/01: CompileTimeError # failing-by-design: Test needs refactoring, see Issue #34365
-hidden_import_test/01: MissingStaticWarning # failing-by-design: invalid test, see Issue #34302
-hidden_import_test/02: MissingStaticWarning # failing-by-design: invalid test, see Issue #34302
-implements_futureor_test/01: MissingCompileTimeError # Issue #33745
-implicit_creation/implicit_const_context_constructor_generic_named_test: CompileTimeError # Issue #34367
-implicit_creation/implicit_const_context_constructor_generic_test: CompileTimeError # Issue #34367
-implicit_creation/implicit_const_context_prefix_constructor_generic_named_test: CompileTimeError # Issue #34367
-implicit_creation/implicit_const_context_prefix_constructor_generic_test: CompileTimeError # Issue #34367
-index_assign_operator_infer_return_type_test: CompileTimeError # failing-by-design: outdated against the spec, see Issue #34368
-initializing_formal_final_test: MissingCompileTimeError # Issue #34369
-interface_test/00: MissingCompileTimeError # Issue #34370
-invalid_returns/async_invalid_return_00_test/none: CompileTimeError # issue #34319
-invalid_returns/async_invalid_return_01_test/none: CompileTimeError # issue #34319
-invalid_returns/async_invalid_return_02_test/none: CompileTimeError # issue #34319
-invalid_returns/async_invalid_return_03_test/none: CompileTimeError # issue #34319
-invalid_returns/async_invalid_return_04_test/none: CompileTimeError # issue #34319
-invalid_returns/sync_invalid_return_00_test/none: CompileTimeError # issue #34319
-invalid_returns/sync_invalid_return_01_test/none: CompileTimeError # issue #34319
-invalid_returns/sync_invalid_return_02_test/none: CompileTimeError # issue #34319
-invalid_returns/sync_invalid_return_03_test/none: CompileTimeError # issue #34319
-invalid_returns/sync_invalid_return_04_test/none: CompileTimeError # issue #34319
-invalid_returns/sync_invalid_return_05_test/none: CompileTimeError # issue #34319
-issue31596_implement_covariant_test: CompileTimeError # Issue #31596
-issue31596_override_test/01: CompileTimeError # Issue #31596
-issue31596_override_test/02: CompileTimeError # Issue #31596
-issue31596_override_test/03: CompileTimeError # Issue #31596
-issue31596_override_test/04: CompileTimeError # Issue #31596
-issue31596_override_test/none: CompileTimeError # Issue #31596
-issue31596_super_test/01: CompileTimeError # Issue #31596
-issue31596_super_test/03: CompileTimeError # Issue #31596
-issue31596_super_test/05: CompileTimeError # Issue #31596
-issue31596_super_test/none: CompileTimeError # Issue #31596
-issue31596_tearoff_test: CompileTimeError # Issue #31596
-issue31596_test: CompileTimeError # Issue #31596
-issue34498_test: MissingCompileTimeError # Issue 34500
large_class_declaration_test: Slow
-malformed2_test: Pass, MissingCompileTimeError # Flaky: issue 31056.
-nested_generic_closure_test: CompileTimeError # Issue #28515
-no_main_test/01: Fail # failing-by-design, the analyzer has no restriction that a library include a main function.
-part_of_multiple_libs_test/01: MissingCompileTimeError # Issue 33227
-part_refers_to_core_library_test/01: MissingCompileTimeError # Issue 29709
-prefix_shadow_test/01: MissingCompileTimeError # Issue 33005
regress_23408_test: Skip # don't care about the static warning.
-regress_29025_test: CompileTimeError # Issue 29081
-regress_29405_test: CompileTimeError # Issue 29421
-regress_29784_test/02: MissingCompileTimeError # Issue 29784
-regress_33479_test/01: Crash # Issue #33479
-setter3_test/01: CompileTimeError # Invalid test, see https://github.com/dart-lang/sdk/issues/33837
-setter3_test/02: CompileTimeError # Invalid test, see https://github.com/dart-lang/sdk/issues/33837
-super_setter_test: CompileTimeError # Invalid test, see https://github.com/dart-lang/sdk/issues/33837
-type_variable_static_context_negative_test: Fail # Issue 12161
vm/debug_break_enabled_vm_test: Skip
vm/debug_break_vm_test/*: Skip
-vm/reflect_core_vm_test: CompileTimeError # Issue 33994
vm/regress_27201_test: SkipByDesign # Loads bad library, so will always crash.
-vm/regression_32912_test/01: MissingCompileTimeError # Issue 32912
-vm/regression_32912_test/02: MissingCompileTimeError # Issue 32912
-vm/regression_32912_test/03: MissingCompileTimeError # Issue 32912
-void/return_future_future_or_void_async_error1_test/none: CompileTimeError # issue #34319
-void/return_future_or_future_or_void_sync_error2_test/none: CompileTimeError # issue #34319
-void/return_future_or_void_sync_error4_test/none: CompileTimeError # issue #34319
-void/void_type_usage_test/final_local_for_in2: MissingCompileTimeError # issue 35508
diff --git a/tests/language_2/language_2_dart2js.status b/tests/language_2/language_2_dart2js.status
index c60a962..2478e07 100644
--- a/tests/language_2/language_2_dart2js.status
+++ b/tests/language_2/language_2_dart2js.status
@@ -5,86 +5,38 @@
[ $compiler == dart2js ]
arithmetic_int64_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-async_await_test/02: RuntimeError
-async_await_test/03: RuntimeError
-async_await_test/none: RuntimeError
-async_star/async_star_await_for_test: RuntimeError
-async_star/async_star_cancel_test: RuntimeError
async_star_cancel_while_paused_test: RuntimeError # Issue 22853
-async_star_test/02: RuntimeError
bit_operations_test: RuntimeError, OK # non JS number semantics
-bit_operations_test: RuntimeError
bit_operations_test/03: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
bit_operations_test/04: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
bit_operations_test/none: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-call_method_as_cast_test/06: RuntimeError
-call_method_implicit_tear_off_implements_function_test/05: RuntimeError
-call_method_implicit_tear_off_implements_function_test/06: RuntimeError
-call_method_is_check_test/06: RuntimeError
call_method_must_not_be_field_test/03: RuntimeError # Issue 32155
call_method_must_not_be_getter_test/03: RuntimeError # Issue 32155
canonical_const2_test: RuntimeError, OK # non JS number semantics
closure_type_arguments_test: Crash # Issue 34272
-compile_time_constant_static5_test/11: CompileTimeError
-compile_time_constant_static5_test/16: CompileTimeError
-compile_time_constant_static5_test/21: CompileTimeError
-compile_time_constant_static5_test/23: CompileTimeError
config_import_corelib_test: CompileTimeError # we need a special platform.dill file for categories=all. Once we fix that, all dart:* are supported when using '--categories=all' so this will become a RuntimeError, OK.
config_import_test: RuntimeError # Test flag is not passed to the compiler.
const_constructor3_test/04: MissingCompileTimeError # OK - Subtype check uses JS number semantics.
-const_constructor_nonconst_param_test/01: MissingCompileTimeError
const_dynamic_type_literal_test/03: Pass # but it shouldn't until we fix issue 17207
-const_evaluation_test/01: RuntimeError
-const_map2_test/00: MissingCompileTimeError
-const_map3_test/00: MissingCompileTimeError
const_switch_test/02: RuntimeError, OK # constant identity based on JS constants
const_switch_test/04: RuntimeError, OK # constant identity based on JS constants
-constructor_named_arguments_test/none: RuntimeError
covariant_subtyping_test: Crash # Unsupported operation: Unsupported type parameter type node E.
-ct_const_test: RuntimeError
-deferred_load_library_wrong_args_test/01: CompileTimeError
deferred_not_loaded_check_test: RuntimeError # Test out of date. Issue 31933
-deferred_redirecting_factory_test: RuntimeError
deopt_inlined_function_lazy_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
deopt_smi_op_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
double_identical_test: RuntimeError # Negative and positive zero are distinct, but not in dart2js; bug #11551.
double_int_to_string_test: RuntimeError, OK # non JS number semantics
-dynamic_prefix_core_test/none: CompileTimeError
-enum_mirror_test: RuntimeError
-example_constructor_test: RuntimeError
expect_test: RuntimeError, OK # Issue 13080
external_test/10: CompileTimeError # External non-js-interop function are treated as compile-time errors.
-external_test/10: MissingRuntimeError
external_test/13: CompileTimeError # External non-js-interop function are treated as compile-time errors.
-external_test/13: MissingRuntimeError
external_test/20: CompileTimeError # External non-js-interop function are treated as compile-time errors.
-external_test/20: MissingRuntimeError
-external_test/21: CompileTimeError
-external_test/24: CompileTimeError
-flatten_test/05: MissingRuntimeError
-flatten_test/08: MissingRuntimeError
-flatten_test/09: MissingRuntimeError
-flatten_test/12: MissingRuntimeError
full_stacktrace1_test: RuntimeError # Issue 12698
full_stacktrace2_test: RuntimeError # Issue 12698
full_stacktrace3_test: RuntimeError # Issue 12698
-function_propagation_test: RuntimeError
-function_subtype_inline2_test: RuntimeError
-generic_function_bounds_test: RuntimeError
-generic_function_dcall_test/01: RuntimeError
-generic_is_check_test: RuntimeError
-generic_methods_bounds_test/02: MissingRuntimeError
-generic_no_such_method_dispatcher_simple_test: CompileTimeError
-generic_no_such_method_dispatcher_test: CompileTimeError
-generic_tearoff_test: CompileTimeError
guess_cid_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
identical_closure2_test: RuntimeError # non JS number semantics
identical_closure2_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-if_null_precedence_test/none: RuntimeError
infinity_test: RuntimeError # non JS number semantics - Issue 4984
-instance_creation_in_function_annotation_test: RuntimeError
-instantiate_tearoff_of_call_test: CompileTimeError
-instantiate_tearoff_of_call_test: RuntimeError
int2_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
int64_literal_test/01: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
int64_literal_test/02: RuntimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
@@ -99,71 +51,19 @@
int64_literal_test/19: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
int64_literal_test/none: RuntimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
integer_division_by_zero_test: RuntimeError # Issue 8301
-internal_library_test/02: Crash
-invocation_mirror_invoke_on2_test: RuntimeError
-invocation_mirror_invoke_on_test: RuntimeError
-issue21079_test: RuntimeError
issue23244_test: RuntimeError # Isolates - enum canonicalization - Issue 23244
-issue31596_super_test/01: CompileTimeError
-issue31596_super_test/03: CompileTimeError
left_shift_test: RuntimeError # non JS number semantics
library_env_test/has_io_support: RuntimeError, OK # dart2js doesn't support io when compiling on --categories=Client
-library_env_test/has_mirror_support: RuntimeError
library_env_test/has_mirror_support: Fail # mirrors not supported on web
-library_env_test/has_no_html_support: RuntimeError, OK
library_env_test/has_no_mirror_support: Pass # fails for the wrong reason.
-local_function2_test/none: RuntimeError
-local_function3_test/none: RuntimeError
-local_function_test/none: RuntimeError
-minify_closure_variable_collision_test: CompileTimeError
mint_arithmetic_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
mint_arithmetic_test: RuntimeError # non JS number semantics
mint_compares_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
mint_identical_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-mixin_illegal_super_use_test/01: MissingCompileTimeError
-mixin_illegal_super_use_test/04: MissingCompileTimeError
-mixin_illegal_super_use_test/07: MissingCompileTimeError
-mixin_illegal_super_use_test/10: MissingCompileTimeError
-mixin_illegal_super_use_test/11: MissingCompileTimeError
-mixin_illegal_superclass_test/01: MissingCompileTimeError
-mixin_illegal_superclass_test/02: MissingCompileTimeError
-mixin_illegal_superclass_test/03: MissingCompileTimeError
-mixin_illegal_superclass_test/04: MissingCompileTimeError
-mixin_illegal_superclass_test/05: MissingCompileTimeError
-mixin_illegal_superclass_test/06: MissingCompileTimeError
-mixin_illegal_superclass_test/07: MissingCompileTimeError
-mixin_illegal_superclass_test/08: MissingCompileTimeError
-mixin_illegal_superclass_test/09: MissingCompileTimeError
-mixin_illegal_superclass_test/10: MissingCompileTimeError
-mixin_illegal_superclass_test/11: MissingCompileTimeError
-mixin_illegal_superclass_test/12: MissingCompileTimeError
-mixin_illegal_superclass_test/13: MissingCompileTimeError
-mixin_illegal_superclass_test/14: MissingCompileTimeError
-mixin_illegal_superclass_test/15: MissingCompileTimeError
-mixin_illegal_superclass_test/16: MissingCompileTimeError
-mixin_illegal_superclass_test/17: MissingCompileTimeError
-mixin_illegal_superclass_test/18: MissingCompileTimeError
-mixin_illegal_superclass_test/19: MissingCompileTimeError
-mixin_illegal_superclass_test/20: MissingCompileTimeError
-mixin_illegal_superclass_test/21: MissingCompileTimeError
-mixin_illegal_superclass_test/22: MissingCompileTimeError
-mixin_illegal_superclass_test/23: MissingCompileTimeError
-mixin_illegal_superclass_test/24: MissingCompileTimeError
-mixin_illegal_superclass_test/25: MissingCompileTimeError
-mixin_illegal_superclass_test/26: MissingCompileTimeError
-mixin_illegal_superclass_test/27: MissingCompileTimeError
-mixin_illegal_superclass_test/28: MissingCompileTimeError
-mixin_illegal_superclass_test/29: MissingCompileTimeError
-mixin_illegal_superclass_test/30: MissingCompileTimeError
mixin_method_override_test/G5: Skip # Issue 34354
mock_writable_final_field_test: RuntimeError # Issue 30847
modulo_test: RuntimeError # non JS number semantics
-named_parameters_default_eq_test/none: RuntimeError
nan_identical_test: RuntimeError # Issue 11551
-no_main_test/01: CompileTimeError
-no_such_method_mock_test: RuntimeError
-null_no_such_method_test: CompileTimeError
-number_identity2_test: RuntimeError
number_identity_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
numbers_test: RuntimeError, OK # non JS number semantics
partial_instantiation_eager_bounds_check_test: RuntimeError # Issue #34295
@@ -171,28 +71,13 @@
partial_tearoff_instantiation_test/06: Pass # for the wrong reason.
partial_tearoff_instantiation_test/07: Pass # for the wrong reason.
partial_tearoff_instantiation_test/08: Pass # for the wrong reason.
-private_method_tearoff_test: RuntimeError
-redirecting_factory_reflection_test: RuntimeError
-regress_23408_test: CompileTimeError
regress_24283_test: RuntimeError, OK # non JS number semantics
-regress_28255_test: RuntimeError
-regress_29025_test: CompileTimeError
-regress_29405_test: CompileTimeError
-regress_30339_test: CompileTimeError
-setter_no_getter_test/01: CompileTimeError
stacktrace_demangle_ctors_test: RuntimeError # Issue 12698
stacktrace_rethrow_error_test/none: RuntimeError # Issue 12698
stacktrace_rethrow_error_test/withtraceparameter: RuntimeError # Issue 12698
stacktrace_rethrow_nonerror_test: RuntimeError # Issue 12698
-super_bound_closure_test/none: CompileTimeError
-super_call4_test/01: MissingCompileTimeError
-super_test: RuntimeError
-tearoff_dynamic_test: RuntimeError
truncdiv_zero_test: RuntimeError # non JS number semantics - Issue 15246
type_constants_test/none: RuntimeError # Issue 35052
-type_error_test: RuntimeError
-type_literal_canonicalization_test: RuntimeError
-type_promotion_more_specific_test/04: CompileTimeError
vm/*: SkipByDesign # Tests for the VM.
[ $compiler != dart2js ]
@@ -201,10 +86,6 @@
[ $builder_tag == dart2js_production && $compiler == dart2js ]
control_flow_collections/for_non_bool_condition_test: Crash # Issue 36442
-[ $compiler == dart2js && $runtime == chrome ]
-field_override_optimization_test: RuntimeError
-stacktrace_test: RuntimeError
-
[ $compiler == dart2js && $runtime == chrome && $system == macos ]
await_future_test: Pass, Timeout # Issue 26735
@@ -214,14 +95,8 @@
[ $compiler == dart2js && $runtime == d8 ]
conditional_import_string_test: SkipByDesign # No XHR in d8
conditional_import_test: SkipByDesign # No XHR in d8
-implicit_creation/implicit_new_constructor_generic_test: Pass
-stacktrace_test: RuntimeError
-
-[ $compiler == dart2js && $runtime == d8 && !$checked ]
-field_override_optimization_test: RuntimeError
[ $compiler == dart2js && $runtime == ff ]
-field_override_optimization_test: RuntimeError
round_test: Pass, Fail, OK # Fixed in ff 35. Common JavaScript engine Math.round bug.
[ $compiler == dart2js && $runtime == jsshell ]
@@ -229,21 +104,15 @@
async_star_await_pauses_test: RuntimeError # Need triage
async_star_no_cancel2_test: RuntimeError # Need triage
async_star_no_cancel_test: RuntimeError # Need triage
-async_star_test/02: RuntimeError
await_for_test: Skip # Jsshell does not provide periodic timers, Issue 7728
-field_override_optimization_test: RuntimeError
regress_23996_test: RuntimeError # Jsshell does not provide non-zero timers, Issue 7728
[ $compiler == dart2js && $runtime != none && $checked ]
-assert_with_message_test: RuntimeError
syncstar_covariant_type_test: RuntimeError # dart2js misplaces check in Iterator, not Iterable.
syncstar_dcall_type_test: RuntimeError # dart2js misplaces check in Iterator, not Iterable.
[ $compiler == dart2js && $runtime == safari ]
-async_throw_in_catch_test/none: Pass, RuntimeError
-field_override_optimization_test: RuntimeError
round_test: Fail, OK # Common JavaScript engine Math.round bug.
-stacktrace_test: RuntimeError
[ $compiler == dart2js && $system == windows ]
canonicalization_hashing_memoize_array_test: Skip # Issue 37631
@@ -253,299 +122,62 @@
string_literals_test: Pass, RuntimeError # Failures on dart2js-win7-chrome-4-4-be and dart2js-win7-ie11ff-4-4-be
[ $compiler == dart2js && $checked ]
-assign_instance_method_test: RuntimeError
-async_await_foreign_test: RuntimeError
-async_star_cancel_while_paused_test: RuntimeError
-async_star_pause_test: RuntimeError
-async_star_regression_23116_test: RuntimeError
-async_star_test/02: RuntimeError
-await_test: RuntimeError
-bit_operations_test/03: RuntimeError
-bit_operations_test/04: RuntimeError
-bit_operations_test/none: RuntimeError
canonical_const2_test: RuntimeError, OK # non JS number semantics
-checked_method_error_order_test: RuntimeError
-class_cycle_test/02: MissingCompileTimeError
-class_cycle_test/03: MissingCompileTimeError
-conditional_method_invocation_test/05: MissingCompileTimeError
-conditional_method_invocation_test/06: MissingCompileTimeError
-conditional_method_invocation_test/07: MissingCompileTimeError
-conditional_method_invocation_test/08: MissingCompileTimeError
-conditional_method_invocation_test/12: MissingCompileTimeError
-conditional_method_invocation_test/13: MissingCompileTimeError
-conditional_method_invocation_test/18: MissingCompileTimeError
-conditional_method_invocation_test/19: MissingCompileTimeError
-conditional_property_access_test/04: MissingCompileTimeError
-conditional_property_access_test/05: MissingCompileTimeError
-conditional_property_access_test/06: MissingCompileTimeError
-conditional_property_access_test/10: MissingCompileTimeError
-conditional_property_access_test/11: MissingCompileTimeError
-conditional_property_access_test/16: MissingCompileTimeError
-conditional_property_access_test/17: MissingCompileTimeError
-conditional_property_assignment_test/04: MissingCompileTimeError
-conditional_property_assignment_test/05: MissingCompileTimeError
-conditional_property_assignment_test/06: MissingCompileTimeError
-conditional_property_assignment_test/10: MissingCompileTimeError
-conditional_property_assignment_test/11: MissingCompileTimeError
-conditional_property_assignment_test/12: MissingCompileTimeError
-conditional_property_assignment_test/13: MissingCompileTimeError
-conditional_property_assignment_test/27: MissingCompileTimeError
-conditional_property_assignment_test/28: MissingCompileTimeError
-conditional_property_assignment_test/32: MissingCompileTimeError
-conditional_property_assignment_test/33: MissingCompileTimeError
-conditional_property_assignment_test/34: MissingCompileTimeError
-conditional_property_assignment_test/35: MissingCompileTimeError
-conditional_property_increment_decrement_test/04: MissingCompileTimeError
-conditional_property_increment_decrement_test/08: MissingCompileTimeError
-conditional_property_increment_decrement_test/12: MissingCompileTimeError
-conditional_property_increment_decrement_test/16: MissingCompileTimeError
-conditional_property_increment_decrement_test/21: MissingCompileTimeError
-conditional_property_increment_decrement_test/22: MissingCompileTimeError
-conditional_property_increment_decrement_test/27: MissingCompileTimeError
-conditional_property_increment_decrement_test/28: MissingCompileTimeError
-conditional_property_increment_decrement_test/33: MissingCompileTimeError
-conditional_property_increment_decrement_test/34: MissingCompileTimeError
-conditional_property_increment_decrement_test/39: MissingCompileTimeError
-conditional_property_increment_decrement_test/40: MissingCompileTimeError
-config_import_test: RuntimeError
-const_constructor2_test/05: MissingCompileTimeError
-const_constructor2_test/06: MissingCompileTimeError
-const_constructor2_test/13: MissingCompileTimeError
-const_constructor2_test/14: MissingCompileTimeError
-const_constructor2_test/15: MissingCompileTimeError
-const_constructor2_test/16: MissingCompileTimeError
-const_constructor2_test/17: MissingCompileTimeError
-const_constructor2_test/18: MissingCompileTimeError
-const_constructor2_test/20: MissingCompileTimeError
-const_constructor2_test/22: MissingCompileTimeError
-const_constructor2_test/24: MissingCompileTimeError
-const_error_multiply_initialized_test/02: MissingCompileTimeError
-const_error_multiply_initialized_test/04: MissingCompileTimeError
-const_evaluation_test/01: RuntimeError
-const_init2_test/02: MissingCompileTimeError
-const_map2_test/00: MissingCompileTimeError
-const_map3_test/00: MissingCompileTimeError
const_switch_test/02: RuntimeError, OK # constant identity based on JS constants
const_switch_test/04: RuntimeError, OK # constant identity based on JS constants
-const_types_test/01: MissingCompileTimeError
-const_types_test/02: MissingCompileTimeError
-const_types_test/03: MissingCompileTimeError
-const_types_test/04: MissingCompileTimeError
-const_types_test/05: MissingCompileTimeError
-const_types_test/06: MissingCompileTimeError
-const_types_test/13: MissingCompileTimeError
-const_types_test/34: MissingCompileTimeError
-const_types_test/35: MissingCompileTimeError
-const_types_test/39: MissingCompileTimeError
-const_types_test/40: MissingCompileTimeError
-constructor_duplicate_final_test/01: MissingCompileTimeError
-constructor_duplicate_final_test/02: MissingCompileTimeError
-constructor_named_arguments_test/01: MissingCompileTimeError
-constructor_named_arguments_test/none: RuntimeError
-covariant_override/runtime_check_test: RuntimeError
-covariant_subtyping_test: CompileTimeError
-covariant_subtyping_test: RuntimeError
-deferred_constraints_type_annotation_test/as_operation: MissingCompileTimeError
-deferred_constraints_type_annotation_test/catch_check: MissingCompileTimeError
-deferred_constraints_type_annotation_test/is_check: MissingCompileTimeError
-deferred_constraints_type_annotation_test/new_before_load: MissingCompileTimeError
-deferred_constraints_type_annotation_test/new_generic2: MissingCompileTimeError
-deferred_constraints_type_annotation_test/new_generic3: MissingCompileTimeError
-deferred_constraints_type_annotation_test/type_annotation1: MissingCompileTimeError
-deferred_constraints_type_annotation_test/type_annotation_generic1: MissingCompileTimeError
-deferred_constraints_type_annotation_test/type_annotation_generic2: MissingCompileTimeError
-deferred_constraints_type_annotation_test/type_annotation_generic3: MissingCompileTimeError
-deferred_constraints_type_annotation_test/type_annotation_generic4: MissingCompileTimeError
-deferred_constraints_type_annotation_test/type_annotation_null: MissingCompileTimeError
-deferred_constraints_type_annotation_test/type_annotation_top_level: MissingCompileTimeError
-deferred_load_library_wrong_args_test/01: MissingRuntimeError
deferred_not_loaded_check_test: RuntimeError # Test out of date. Issue 31933
-deferred_redirecting_factory_test: RuntimeError
double_int_to_string_test: RuntimeError, OK # non JS number semantics
-dynamic_prefix_core_test/none: RuntimeError
-enum_mirror_test: RuntimeError
expect_test: RuntimeError, OK # Issue 13080
-external_test/10: MissingRuntimeError
-external_test/13: MissingRuntimeError
-external_test/20: MissingRuntimeError
-factory_redirection_test/07: MissingCompileTimeError
-final_attempt_reinitialization_test/01: MissingCompileTimeError
-final_attempt_reinitialization_test/02: MissingCompileTimeError
full_stacktrace1_test: RuntimeError # Issue 12698
full_stacktrace2_test: RuntimeError # Issue 12698
full_stacktrace3_test: RuntimeError # Issue 12698
generalized_void_syntax_test: CompileTimeError # Issue #30176.
generic_function_dcall_test/01: Crash # Unsupported operation: Unsupported type parameter type node T.
generic_tearoff_test: Crash # Unsupported operation: Unsupported type parameter type node T.
-generic_typedef_test: RuntimeError
identical_closure2_test: RuntimeError # non JS number semantics
-implicit_downcast_during_assert_initializer_test: RuntimeError
infinity_test: RuntimeError # non JS number semantics - Issue 4984
-instance_creation_in_function_annotation_test: RuntimeError
-instanceof2_test: RuntimeError
-instanceof4_test/01: RuntimeError
-instanceof4_test/none: RuntimeError
integer_division_by_zero_test: RuntimeError # Issue 8301
invocation_mirror2_test: RuntimeError # mirrors not supported
-issue21079_test: RuntimeError
-issue23244_test: RuntimeError
left_shift_test: RuntimeError # non JS number semantics
-library_env_test/has_mirror_support: RuntimeError
-list_literal1_test/01: MissingCompileTimeError
-list_literal4_test/00: MissingCompileTimeError
-list_literal4_test/01: MissingCompileTimeError
-list_literal4_test/03: MissingCompileTimeError
-list_literal4_test/04: MissingCompileTimeError
-list_literal4_test/05: MissingCompileTimeError
-list_literal_syntax_test/01: MissingCompileTimeError
-list_literal_syntax_test/02: MissingCompileTimeError
-list_literal_syntax_test/03: MissingCompileTimeError
-malformed2_test/00: MissingCompileTimeError
-map_literal1_test/01: MissingCompileTimeError
-map_literal8_test: RuntimeError
mint_arithmetic_test: RuntimeError # non JS number semantics
-mixin_illegal_super_use_test/01: MissingCompileTimeError
-mixin_illegal_super_use_test/02: MissingCompileTimeError
-mixin_illegal_super_use_test/03: MissingCompileTimeError
-mixin_illegal_super_use_test/04: MissingCompileTimeError
-mixin_illegal_super_use_test/05: MissingCompileTimeError
-mixin_illegal_super_use_test/06: MissingCompileTimeError
-mixin_illegal_super_use_test/07: MissingCompileTimeError
-mixin_illegal_super_use_test/08: MissingCompileTimeError
-mixin_illegal_super_use_test/09: MissingCompileTimeError
-mixin_illegal_super_use_test/10: MissingCompileTimeError
-mixin_illegal_super_use_test/11: MissingCompileTimeError
-mixin_illegal_superclass_test/01: MissingCompileTimeError
-mixin_illegal_superclass_test/02: MissingCompileTimeError
-mixin_illegal_superclass_test/03: MissingCompileTimeError
-mixin_illegal_superclass_test/04: MissingCompileTimeError
-mixin_illegal_superclass_test/05: MissingCompileTimeError
-mixin_illegal_superclass_test/06: MissingCompileTimeError
-mixin_illegal_superclass_test/07: MissingCompileTimeError
-mixin_illegal_superclass_test/08: MissingCompileTimeError
-mixin_illegal_superclass_test/09: MissingCompileTimeError
-mixin_illegal_superclass_test/10: MissingCompileTimeError
-mixin_illegal_superclass_test/11: MissingCompileTimeError
-mixin_illegal_superclass_test/12: MissingCompileTimeError
-mixin_illegal_superclass_test/13: MissingCompileTimeError
-mixin_illegal_superclass_test/14: MissingCompileTimeError
-mixin_illegal_superclass_test/15: MissingCompileTimeError
-mixin_illegal_superclass_test/16: MissingCompileTimeError
-mixin_illegal_superclass_test/17: MissingCompileTimeError
-mixin_illegal_superclass_test/18: MissingCompileTimeError
-mixin_illegal_superclass_test/19: MissingCompileTimeError
-mixin_illegal_superclass_test/20: MissingCompileTimeError
-mixin_illegal_superclass_test/21: MissingCompileTimeError
-mixin_illegal_superclass_test/22: MissingCompileTimeError
-mixin_illegal_superclass_test/23: MissingCompileTimeError
-mixin_illegal_superclass_test/24: MissingCompileTimeError
-mixin_illegal_superclass_test/25: MissingCompileTimeError
-mixin_illegal_superclass_test/26: MissingCompileTimeError
-mixin_illegal_superclass_test/27: MissingCompileTimeError
-mixin_illegal_superclass_test/28: MissingCompileTimeError
-mixin_illegal_superclass_test/29: MissingCompileTimeError
-mixin_illegal_superclass_test/30: MissingCompileTimeError
-mixin_issue10216_2_test: RuntimeError
-mixin_mixin4_test: RuntimeError
-mixin_mixin5_test: RuntimeError
-mixin_mixin7_test: RuntimeError
-mixin_mixin_bound2_test: RuntimeError
-mixin_mixin_bound_test: RuntimeError
-mixin_mixin_test: RuntimeError
-mixin_type_parameters_super_test: RuntimeError
mock_writable_final_field_test: RuntimeError # Issue 30847
modulo_test: RuntimeError # non JS number semantics
nan_identical_test: RuntimeError # Issue 11551
-no_main_test/01: CompileTimeError
-not_enough_positional_arguments_test/00: MissingCompileTimeError
-not_enough_positional_arguments_test/01: MissingCompileTimeError
-not_enough_positional_arguments_test/02: MissingCompileTimeError
-not_enough_positional_arguments_test/03: MissingCompileTimeError
-not_enough_positional_arguments_test/05: MissingCompileTimeError
-not_enough_positional_arguments_test/06: MissingCompileTimeError
-not_enough_positional_arguments_test/07: MissingCompileTimeError
-number_identity2_test: RuntimeError
numbers_test: RuntimeError, OK # non JS number semantics
-positional_parameters_type_test/01: MissingCompileTimeError
-positional_parameters_type_test/02: MissingCompileTimeError
-private_super_constructor_test/01: MissingCompileTimeError
-redirecting_factory_long_test: RuntimeError
-redirecting_factory_reflection_test: RuntimeError
-regress_20394_test/01: MissingCompileTimeError
regress_27617_test/1: Crash # Assertion failure: Unexpected constructor j:constructor(Foo._) in ConstructorDataImpl._getConstructorConstant
-regress_28217_test/01: MissingCompileTimeError
-regress_28217_test/none: MissingCompileTimeError
-regress_28255_test: RuntimeError
-regress_28341_test: RuntimeError
-regress_29405_test: RuntimeError
-regress_30339_test: RuntimeError # Issue 26429
regress_31057_test: Crash # Unsupported operation: Unsupported type parameter type node B.
stacktrace_demangle_ctors_test: RuntimeError # Issue 12698
stacktrace_rethrow_error_test/none: RuntimeError # Issue 12698
stacktrace_rethrow_error_test/withtraceparameter: RuntimeError # Issue 12698
stacktrace_rethrow_nonerror_test: RuntimeError # Issue 12698
stacktrace_test: RuntimeError # Issue 12698
-symbol_literal_test/01: MissingCompileTimeError
-tearoff_dynamic_test: RuntimeError
truncdiv_zero_test: RuntimeError # non JS number semantics - Issue 15246
-type_check_const_function_typedef2_test: MissingCompileTimeError
-type_literal_canonicalization_test: RuntimeError
type_parameter_test/06: Crash # Internal Error: Unexpected type variable in static context.
type_parameter_test/09: Crash # Internal Error: Unexpected type variable in static context.
type_variable_scope_test/03: Crash # Internal Error: Unexpected type variable in static context.
-[ $compiler == dart2js && $checked && $minified ]
-inline_super_field_test: Crash
-typedef_is_test: Crash
-
-[ $compiler == dart2js && !$checked ]
-bool_check_test: RuntimeError
-bool_condition_check_test: RuntimeError
-issue31596_super_test/05: RuntimeError
-
[ $compiler == dart2js && $host_checked ]
async_return_types_test/nestedFuture: Crash # 'file:*/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart': Failed assertion: line 208 pos 18: '!(_useKernel && _strongMode && !_disableRtiOptimization) ||
async_star_cancel_while_paused_test: Crash # 'file:*/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart': Failed assertion: line 208 pos 18: '!(_useKernel && _strongMode && !_disableRtiOptimization) ||
await_not_started_immediately_test: Crash # Assertion failure: Runtime type information not available for type_variable_local(bindCallback.R) in (local(_RootZone.bindCallback#)) for j:closure_call(_RootZone_bindCallback_closure.call).
-class_literal_static_test/01: MissingCompileTimeError
-class_literal_static_test/03: MissingCompileTimeError
-class_literal_static_test/07: MissingCompileTimeError
closure_self_reference_test: Crash # 'file:*/pkg/compiler/lib/src/ssa/nodes.dart': Failed assertion: line 641 pos 12: 'isClosed()': is not true.
-config_import_corelib_test: CompileTimeError
-covariant_subtyping_test: RuntimeError
issue23244_test: Crash # 'file:*/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart': Failed assertion: line 208 pos 18: '!(_useKernel && _strongMode && !_disableRtiOptimization) ||
-library_env_test/has_no_html_support: RuntimeError
-map_literal3_test/03: MissingCompileTimeError
partial_tearoff_instantiation_test/05: Crash # Assertion failure: kind=special,memberName=instantiate,callStructure:CallStructure(arity=0, types=1)
partial_tearoff_instantiation_test/06: Crash # Assertion failure: kind=special,memberName=instantiate,callStructure:CallStructure(arity=0, types=1)
partial_tearoff_instantiation_test/07: Crash # Assertion failure: kind=special,memberName=instantiate,callStructure:CallStructure(arity=0, types=1)
partial_tearoff_instantiation_test/08: Crash # Assertion failure: kind=special,memberName=instantiate,callStructure:CallStructure(arity=0, types=1)
-regress_13462_1_test: RuntimeError
-regress_18535_test: RuntimeError
-type_literal_prefix_call_test/00: MissingCompileTimeError
-type_promotion_logical_and_test/01: MissingCompileTimeError
[ $compiler == dart2js && $minified ]
async_return_types_test/nestedFuture: Crash # Interpolated value #1 is not an Expression or List of Expressions: [VariableUse(f), Instance of 'LiteralNull', null]
async_star_cancel_while_paused_test: Crash # Interpolated value #1 is not an Expression or List of Expressions: [VariableUse(f), Instance of 'LiteralNull', null]
await_not_started_immediately_test: Crash # Assertion failure: Runtime type information not available for type_variable_local(bindCallback.R) in (local(_RootZone.bindCallback#)) for j:closure_call(_RootZone_bindCallback_closure.call).
-call_with_no_such_method_test: RuntimeError
-class_literal_static_test/01: MissingCompileTimeError
-class_literal_static_test/03: MissingCompileTimeError
-class_literal_static_test/07: MissingCompileTimeError
-config_import_corelib_test: CompileTimeError
-covariant_subtyping_test: RuntimeError
cyclic_type2_test: RuntimeError # Issue 31054
cyclic_type_test/0*: RuntimeError # Issue 31054
f_bounded_quantification4_test: RuntimeError # Issue 31054
f_bounded_quantification5_test: RuntimeError # Issue 31054
generic_closure_test/01: RuntimeError # Uses runtimeType.toString()
invocation_mirror2_test: RuntimeError # mirrors not supported
-invocation_mirror_test: RuntimeError
issue23244_test: Crash # Interpolated value #1 is not an Expression or List of Expressions: [VariableUse(f), Instance of 'LiteralNull', null]
-library_env_test/has_no_html_support: RuntimeError
-many_overridden_no_such_method_test: RuntimeError
-map_literal3_test/03: MissingCompileTimeError
mixin_generic_test: RuntimeError # Issue 12605
mixin_mixin2_test: RuntimeError # Issue 31054
mixin_mixin3_test: RuntimeError # Issue 31054
@@ -555,15 +187,7 @@
mixin_mixin_bound2_test: RuntimeError # Issue 31054
mixin_mixin_bound_test: RuntimeError # Issue 31054
mixin_mixin_type_arguments_test: RuntimeError # Issue 31054
-no_such_method_native_test: RuntimeError
-no_such_method_test: RuntimeError
-overridden_no_such_method_test: RuntimeError
-recursive_generic_test: RuntimeError
-regress_13462_1_test: RuntimeError
-regress_18535_test: RuntimeError
regress_21795_test: RuntimeError # Issue 12605
runtime_type_function_test: RuntimeError # Uses runtimeType.toString()
stack_trace_test: RuntimeError, OK # Stack trace not preserved in minified code.
symbol_conflict_test: RuntimeError # Issue 23857
-type_literal_prefix_call_test/00: MissingCompileTimeError
-type_promotion_logical_and_test/01: MissingCompileTimeError
diff --git a/tests/language_2/language_2_dartdevc.status b/tests/language_2/language_2_dartdevc.status
index eb9a51e..9afe4d1 100644
--- a/tests/language_2/language_2_dartdevc.status
+++ b/tests/language_2/language_2_dartdevc.status
@@ -4,386 +4,20 @@
# Sections in this file should contain "$compiler == dartdevc" or dartdevk.
[ $compiler == dartdevc ]
-accessor_conflict_export2_test: CompileTimeError # Issue 25626
-accessor_conflict_export_test: CompileTimeError # Issue 25626
-accessor_conflict_import2_test: CompileTimeError # Issue 25626
-accessor_conflict_import_prefixed2_test: CompileTimeError # Issue 25626
-accessor_conflict_import_prefixed_test: CompileTimeError # Issue 25626
-accessor_conflict_import_test: CompileTimeError # Issue 25626
-assertion_test: RuntimeError # Issue 30326; Expect.equals(expected: <1>, actual: <0>) fails.
-async_star/async_star_await_for_test: RuntimeError
-async_star/async_star_cancel_test: RuntimeError
-async_star/async_star_test: RuntimeError
-async_star_test/01: RuntimeError
-async_star_test/03: RuntimeError
-async_star_test/04: RuntimeError
-async_star_test/05: RuntimeError
-async_star_test/none: RuntimeError
-await_future_test: Pass, Timeout # Issue 29920
-bit_operations_test: RuntimeError # No bigints on web.
-built_in_identifier_prefix_test: CompileTimeError
-built_in_identifier_type_annotation_test/dynamic-funarg: RuntimeError # Issue 28816
-built_in_identifier_type_annotation_test/dynamic-funret: RuntimeError # Issue 28816
-built_in_identifier_type_annotation_test/dynamic-list: RuntimeError # Issue 28816
-cascaded_forwarding_stubs_generic_test: RuntimeError
-cascaded_forwarding_stubs_test: CompileTimeError
-const_cast2_test/01: CompileTimeError
-const_cast2_test/none: CompileTimeError
-const_constructor3_test/04: MissingCompileTimeError # Side-effect of working around issue 33441 for int-to-double
const_double_in_int_op_test/dd6: Skip # Triple shift
const_double_in_int_op_test/di6: Skip # Triple shift
const_double_in_int_op_test/id6: Skip # Triple shift
const_double_in_int_op_test/ii6: Skip # Triple shift
-covariant_override/tear_off_type_test: RuntimeError # Issue 28395
-covariant_subtyping_with_mixin_test: CompileTimeError # Issue 34329
-deferred_load_library_wrong_args_test/01: MissingRuntimeError, RuntimeError # Issue 29920
-double_identical_test: RuntimeError # Negative and positive zero are distinct, but not in ddc
-dynamic_prefix_core_test/01: MissingCompileTimeError
-enum_syntax_test/05: MissingCompileTimeError
-enum_syntax_test/06: MissingCompileTimeError
-execute_finally6_test: RuntimeError # Issue 29920
-expect_test: RuntimeError # Issue 29920
-export_private_test/01: MissingCompileTimeError # Issue 29920
extension_methods/*: SkipByDesign # Analyzer DDC is expected to be turned down before releasing extension methods.
-f_bounded_quantification2_test: CompileTimeError # Issue 34583
-f_bounded_quantification3_test: RuntimeError # Issue 29920
-f_bounded_quantification4_test: CompileTimeError # Issue 34583
-field_wierd_name_test: Crash
-for_test/01: MissingCompileTimeError
-forwarding_stub_tearoff_generic_test: RuntimeError
-forwarding_stub_tearoff_test: CompileTimeError
-function_propagation_test: RuntimeError
-generic_local_functions_test: CompileTimeError
-generic_methods_generic_function_parameter_test: CompileTimeError
-generic_methods_generic_function_result_test/none: CompileTimeError # Issue #30208
generic_no_such_method_dispatcher_simple_test: Skip # This test is just for kernel.
-generic_no_such_method_dispatcher_test: CompileTimeError
-getter_closure_execution_order_test: RuntimeError # Issue 29920
-getter_setter_in_lib_test: CompileTimeError
-getters_setters2_test/01: CompileTimeError
-getters_setters_type_test/01: CompileTimeError
-implements_futureor_test/01: MissingCompileTimeError
-implicit_creation/implicit_const_context_constructor_generic_named_test: CompileTimeError
-implicit_creation/implicit_const_context_constructor_generic_test: CompileTimeError
-implicit_creation/implicit_const_context_prefix_constructor_generic_named_test: CompileTimeError
-implicit_creation/implicit_const_context_prefix_constructor_generic_test: CompileTimeError
-implicit_downcast_during_compound_assignment_test: RuntimeError
-implicit_downcast_during_indexed_compound_assignment_test: RuntimeError
-implicit_downcast_during_indexed_if_null_assignment_test: RuntimeError
-import_private_test/01: MissingCompileTimeError # Issue 29920
-index_assign_operator_infer_return_type_test: CompileTimeError
-initializing_formal_final_test: MissingCompileTimeError
-instantiate_tearoff_after_contravariance_check_test: RuntimeError
-instantiate_tearoff_of_call_test: RuntimeError
-interface_test/00: MissingCompileTimeError
-internal_library_test/01: MissingCompileTimeError # Issue 29920
-invalid_returns/async_invalid_return_00_test/none: CompileTimeError # issue #34319
-invalid_returns/async_invalid_return_01_test/none: CompileTimeError # issue #34319
-invalid_returns/async_invalid_return_02_test/none: CompileTimeError # issue #34319
-invalid_returns/async_invalid_return_03_test/none: CompileTimeError # issue #34319
-invalid_returns/async_invalid_return_04_test/none: CompileTimeError # issue #34319
-invalid_returns/sync_invalid_return_00_test/none: CompileTimeError # issue #34319
-invalid_returns/sync_invalid_return_01_test/none: CompileTimeError # issue #34319
-invalid_returns/sync_invalid_return_02_test/none: CompileTimeError # issue #34319
-invalid_returns/sync_invalid_return_03_test/none: CompileTimeError # issue #34319
-invalid_returns/sync_invalid_return_04_test/none: CompileTimeError # issue #34319
-invalid_returns/sync_invalid_return_05_test/none: CompileTimeError # issue #34319
-issue31596_implement_covariant_test: CompileTimeError # Issue #31596
-issue31596_override_test/01: CompileTimeError
-issue31596_override_test/02: CompileTimeError
-issue31596_override_test/03: CompileTimeError
-issue31596_override_test/04: CompileTimeError
-issue31596_override_test/none: CompileTimeError
-issue31596_super_test/01: CompileTimeError
-issue31596_super_test/03: CompileTimeError
-issue31596_super_test/05: CompileTimeError
-issue31596_super_test/none: CompileTimeError
-issue31596_tearoff_test: CompileTimeError
-issue31596_test: CompileTimeError
-issue34498_test: MissingCompileTimeError # Issue 34500
-label_test: RuntimeError
-labeled_variable_declaration_test: RuntimeError
-large_class_declaration_test: Slow, Pass
-left_shift_test: RuntimeError # Ints and doubles are unified.
-mixin_declaration/mixin_declaration_factory_test/02: Crash
-mixin_method_override_test/01: MissingCompileTimeError
-mixin_super_2_test: CompileTimeError # Issue 34806
-mixin_super_use_test: CompileTimeError # Issue 34806
-nested_generic_closure_test: CompileTimeError
+large_class_declaration_test: Slow
nnbd/*: Skip
-override_inheritance_field_test/42: CompileTimeError
-part_of_multiple_libs_test/01: MissingCompileTimeError
-part_refers_to_core_library_test/01: Crash
-prefix_shadow_test/01: MissingCompileTimeError # Issue 33005
-private_method_tearoff_test: RuntimeError
-regress_22976_test: CompileTimeError # Issue 31935, test is not legal in Dart 2.
-regress_23408_test: CompileTimeError
-regress_24283_test: RuntimeError # Intended to fail, requires 64-bit numbers.
-regress_27617_test/1: MissingCompileTimeError
-regress_29025_test: CompileTimeError # Issue 29081
-regress_29405_test: CompileTimeError # Issue 29421
-regress_29784_test/02: Crash # assert initializers not implemented
-regress_29784_test/02: MissingCompileTimeError
-regress_30339_test: CompileTimeError # As expected. Should we make this a multi test?
-regress_33479_test/01: Crash # Issue #33479
-setter3_test/01: CompileTimeError # Invalid test, see https://github.com/dart-lang/sdk/issues/33837
-setter3_test/02: CompileTimeError # Invalid test, see https://github.com/dart-lang/sdk/issues/33837
-stacktrace_test: RuntimeError # Issue 29920
-super_bound_closure_test/none: CompileTimeError
-super_call4_test/01: MissingCompileTimeError
-super_operator_index5_test: RuntimeError # 33470
-super_operator_index7_test: RuntimeError # 33470
-super_operator_index8_test: RuntimeError # 33470
-super_setter_test: CompileTimeError # Invalid test, see https://github.com/dart-lang/sdk/issues/33837
-syntax_test/60: MissingCompileTimeError
-syntax_test/61: MissingCompileTimeError
-truncdiv_test: RuntimeError # Issue 29920
-try_catch_on_syntax_test/10: MissingCompileTimeError
-try_catch_on_syntax_test/11: MissingCompileTimeError
-type_inference_inconsistent_inheritance_test: MissingCompileTimeError
-void/return_future_future_or_void_async_error1_test/none: CompileTimeError # issue #34319
-void/return_future_or_future_or_void_sync_error2_test/none: CompileTimeError # issue #34319
-void/return_future_or_void_sync_error4_test/none: CompileTimeError # issue #34319
-void/void_type_usage_test/final_local_for_in2: MissingCompileTimeError
-
-[ $compiler == dartdevk ]
-async_star/async_star_cancel_test: RuntimeError
-async_star/async_star_test: RuntimeError
-built_in_identifier_type_annotation_test/dynamic-funarg: RuntimeError # Issue 30450, test name contains hyphen
-built_in_identifier_type_annotation_test/dynamic-funret: RuntimeError # Issue 30450, test name contains hyphen
-built_in_identifier_type_annotation_test/dynamic-list: RuntimeError # Issue 30450, test name contains hyphen
-call_method_as_cast_test/06: RuntimeError # Kernel allows classes to subtype `Function` so DDK elides the explicit cast.
-call_method_implicit_tear_off_implements_function_test/05: RuntimeError # Kernel is missing the implicit `call` tearoff for assignment `Function`
-call_method_implicit_tear_off_implements_function_test/06: RuntimeError # Kernel is missing the implicit `call` tearoff for assignment `Function`
-call_method_must_not_be_field_test/06: RuntimeError # Kernel does not distinguish `d()` from `d.call()`
-call_method_must_not_be_getter_test/06: RuntimeError # Kernel does not distinguish `d()` from `d.call()`
-compile_time_constant_c_test/02: MissingCompileTimeError
-compile_time_constant_k_test/01: MissingCompileTimeError
-compile_time_constant_k_test/02: MissingCompileTimeError
-compile_time_constant_k_test/03: MissingCompileTimeError
-compile_time_constant_o_test/01: MissingCompileTimeError
-compile_time_constant_o_test/02: MissingCompileTimeError
-compile_time_constant_static4_test/02: MissingCompileTimeError
-compile_time_constant_static4_test/03: MissingCompileTimeError
-compile_time_constant_static5_test/11: CompileTimeError # Issue 31537
-compile_time_constant_static5_test/16: CompileTimeError # Issue 31537
-compile_time_constant_static5_test/21: CompileTimeError # Issue 31537
-compile_time_constant_static5_test/23: CompileTimeError # Issue 31537
-config_import_test: RuntimeError
-const_cast1_test/02: MissingCompileTimeError
-const_constructor3_test/04: MissingCompileTimeError
-const_constructor_nonconst_param_test/01: MissingCompileTimeError
-const_dynamic_type_literal_test/02: MissingCompileTimeError
-const_map2_test/00: MissingCompileTimeError
-const_map3_test/00: MissingCompileTimeError
-const_optional_args_test/01: MissingCompileTimeError
-const_syntax_test/05: MissingCompileTimeError
-constants_test/05: MissingCompileTimeError
-covariant_subtyping_test: RuntimeError
-deferred_load_library_wrong_args_test/01: CompileTimeError
-double_identical_test: RuntimeError # Negative and positive zero are distinct, but not in ddk
-dynamic_prefix_core_test/none: CompileTimeError
-external_test/21: CompileTimeError
-external_test/24: CompileTimeError
-function_propagation_test: RuntimeError
-generic_function_bounds_test: RuntimeError
-generic_no_such_method_dispatcher_simple_test: CompileTimeError # Warning: Superclass has no method named 'foo'.
-generic_no_such_method_dispatcher_test: CompileTimeError # Issue 31533
-identical_const_test/01: MissingCompileTimeError
-identical_const_test/02: MissingCompileTimeError
-identical_const_test/03: MissingCompileTimeError
-identical_const_test/04: MissingCompileTimeError
-implicit_creation/implicit_const_not_default_values_test/e.*: MissingCompileTimeError
-implicit_creation/implicit_const_not_default_values_test/e12: Pass
-implicit_creation/implicit_const_not_default_values_test/e15: Pass
-implicit_creation/implicit_const_not_default_values_test/e18: Pass
-implicit_creation/implicit_const_not_default_values_test/e21: Pass
-implicit_creation/implicit_const_not_default_values_test/e24: Pass
-implicit_creation/implicit_const_not_default_values_test/e27: Pass
-implicit_creation/implicit_const_not_default_values_test/e3: Pass
-implicit_creation/implicit_const_not_default_values_test/e30: Pass
-implicit_creation/implicit_const_not_default_values_test/e6: Pass
-implicit_creation/implicit_const_not_default_values_test/e9: Pass
-instantiate_tearoff_of_call_test: CompileTimeError
-issue31596_super_test/01: CompileTimeError
-issue31596_super_test/03: CompileTimeError
-issue31596_super_test/05: RuntimeError
-map_literal3_test/01: MissingCompileTimeError
-map_literal3_test/02: MissingCompileTimeError
-map_literal3_test/03: MissingCompileTimeError
-mixin_declaration/mixin_declaration_subtype_test: RuntimeError
-mixin_illegal_super_use_test/01: MissingCompileTimeError
-mixin_illegal_super_use_test/04: MissingCompileTimeError
-mixin_illegal_super_use_test/07: MissingCompileTimeError
-mixin_illegal_super_use_test/10: MissingCompileTimeError
-mixin_illegal_super_use_test/11: MissingCompileTimeError
-mixin_illegal_superclass_test/01: MissingCompileTimeError
-mixin_illegal_superclass_test/02: MissingCompileTimeError
-mixin_illegal_superclass_test/03: MissingCompileTimeError
-mixin_illegal_superclass_test/04: MissingCompileTimeError
-mixin_illegal_superclass_test/05: MissingCompileTimeError
-mixin_illegal_superclass_test/06: MissingCompileTimeError
-mixin_illegal_superclass_test/07: MissingCompileTimeError
-mixin_illegal_superclass_test/08: MissingCompileTimeError
-mixin_illegal_superclass_test/09: MissingCompileTimeError
-mixin_illegal_superclass_test/10: MissingCompileTimeError
-mixin_illegal_superclass_test/11: MissingCompileTimeError
-mixin_illegal_superclass_test/12: MissingCompileTimeError
-mixin_illegal_superclass_test/13: MissingCompileTimeError
-mixin_illegal_superclass_test/14: MissingCompileTimeError
-mixin_illegal_superclass_test/15: MissingCompileTimeError
-mixin_illegal_superclass_test/16: MissingCompileTimeError
-mixin_illegal_superclass_test/17: MissingCompileTimeError
-mixin_illegal_superclass_test/18: MissingCompileTimeError
-mixin_illegal_superclass_test/19: MissingCompileTimeError
-mixin_illegal_superclass_test/20: MissingCompileTimeError
-mixin_illegal_superclass_test/21: MissingCompileTimeError
-mixin_illegal_superclass_test/22: MissingCompileTimeError
-mixin_illegal_superclass_test/23: MissingCompileTimeError
-mixin_illegal_superclass_test/24: MissingCompileTimeError
-mixin_illegal_superclass_test/25: MissingCompileTimeError
-mixin_illegal_superclass_test/26: MissingCompileTimeError
-mixin_illegal_superclass_test/27: MissingCompileTimeError
-mixin_illegal_superclass_test/28: MissingCompileTimeError
-mixin_illegal_superclass_test/29: MissingCompileTimeError
-mixin_illegal_superclass_test/30: MissingCompileTimeError
-mixin_super_2_test: RuntimeError # Issue 34807
-mixin_super_use_test: RuntimeError # Issue 34808
-multiline_newline_test/04: MissingCompileTimeError
-multiline_newline_test/04r: MissingCompileTimeError
-multiline_newline_test/05: MissingCompileTimeError
-multiline_newline_test/05r: MissingCompileTimeError
-multiline_newline_test/06: MissingCompileTimeError
-multiline_newline_test/06r: MissingCompileTimeError
-no_such_method_mock_test: RuntimeError # Issue 31426 - Kernel does not introduce nSM for implemented fields.
-null_no_such_method_test: CompileTimeError # Issue 31533
-redirecting_factory_reflection_test: RuntimeError # UnimplementedError: node <InvalidExpression> `invalid-expression`
-regress_23408_test: CompileTimeError # Issue 31533
-regress_24283_test: RuntimeError # Expect.equals(expected: <-1>, actual: <4294967295>) fails.
-regress_29025_test: CompileTimeError
-regress_29405_test: CompileTimeError # Issue 31402 Error: A value of type '#lib2::Foo' can't be assigned to a variable of type '(#lib2::Foo) → void'.
-regress_30339_test: CompileTimeError
-regress_30339_test: RuntimeError # Uncaught Expect.isTrue(false) fails.
-setter_no_getter_test/01: CompileTimeError
-super_bound_closure_test/none: CompileTimeError # Issue 31533
-super_call4_test/01: MissingCompileTimeError
-switch_bad_case_test/01: MissingCompileTimeError
-switch_bad_case_test/02: MissingCompileTimeError
-switch_case_test/00: MissingCompileTimeError
-switch_case_test/01: MissingCompileTimeError
-switch_case_test/02: MissingCompileTimeError
-syncstar_yield_test/capturing: RuntimeError
-syncstar_yield_test/copyParameters: RuntimeError # Expect.equals(expected: <2>, actual: <3>) fails.
-try_catch_test/01: MissingCompileTimeError
-type_promotion_logical_and_test/01: MissingCompileTimeError
-type_promotion_more_specific_test/04: CompileTimeError # Issue 31533
-
-[ $compiler == dartdevk && $checked ]
-assertion_initializer_const_error2_test/*: MissingCompileTimeError
-assertion_initializer_const_error2_test/none: Pass
-implicit_creation/implicit_new_constructor_generic_test: Pass
[ $compiler == dartdevk && !$checked ]
assertion_initializer_const_error2_test/*: SkipByDesign # DDC does not support non-checked mode.
[ $compiler == dartdevc || $compiler == dartdevk ]
-arithmetic_int64_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-async_covariant_type_test: RuntimeError # Check too late
-async_star/async_star_await_for_test: RuntimeError
-async_star_cancel_while_paused_test: RuntimeError # Issue 29920; Uncaught Expect.listEquals(list length, expected: <4>, actual: <3>) fails: Next element <*3>
-async_star_pause_test: RuntimeError # Uncaught Expect.listEquals(at index 2, expected: <0+>, actual: <0!>) fails
-async_star_test/02: RuntimeError
-asyncstar_covariant_type_test: RuntimeError # Check too late
asyncstar_throw_in_catch_test: Skip # Times out. Issue 29920
-bit_operations_test: RuntimeError # No bigints on web.; Expect.equals(expected: <-25>, actual: <4294967271>) fails.
-bit_operations_test/01: MissingCompileTimeError
-bit_operations_test/02: MissingCompileTimeError
-bit_operations_test/03: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-bit_operations_test/04: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-bit_operations_test/none: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-built_in_identifier_prefix_test: CompileTimeError
-canonical_const2_test: RuntimeError # Ints and doubles are unified.; Expect.isFalse(true) fails.
-closure_call_wrong_argument_count_negative_test: Fail
-compile_time_constant_d_test: RuntimeError # Issue 30876; Expect.isTrue(false) fails.
-compile_time_constant_e_test: RuntimeError # Issue 30876; Expect.identical(expected: <A 3 499 99 100>, actual: <A 3 499 99 100>) fails.
-config_import_corelib_test: CompileTimeError
-const_evaluation_test/01: RuntimeError # dart:mirrors not supported in DDC
-const_list_test: RuntimeError # Expect.equals(expected: <false>, actual: <true>) fails.
-const_switch_test/02: RuntimeError # Issue 29920; Expect.equals(expected: <0>, actual: <0.0>) fails.
-const_switch_test/04: RuntimeError # Ints and doubles are unified.; Expect.equals(expected: <1>, actual: <1.0>) fails.
-ct_const_test: RuntimeError # Issue 2992; RangeError: Maximum call stack size exceeded
-cyclic_type2_test: RuntimeError # Issue 29920; Uncaught ReferenceError: V is not defined
-cyclic_type_test/02: RuntimeError # Issue 29920; Uncaught RangeError: Maximum call stack size exceeded
-cyclic_type_test/03: RuntimeError # Issue 29920; Uncaught ReferenceError: U is not defined
-cyclic_type_test/04: RuntimeError # Issue 29920; Uncaught ReferenceError: U is not defined
-deferred_call_empty_before_load_test: RuntimeError # Issue 27777; Expect.throws fails: Did not throw
-deferred_load_constants_test/none: RuntimeError # Issue 27394; Expect.throws fails: Did not throw
-deferred_not_loaded_check_test: RuntimeError # Issue 27777; Expect.throws fails: Did not throw
-deferred_redirecting_factory_test: RuntimeError # Issue 27777; Uncaught Expect.throws fails: Did not throw
-deferred_static_seperate_test: RuntimeError # Issue 27777; Expect.throws fails: Did not throw
-deopt_inlined_function_lazy_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-deopt_smi_op_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-double_int_to_string_test: RuntimeError # Issue 29920; Expect.equals(expected: <0.0>, actual: <0>) fails.
-double_to_string_as_fixed2_test/none: RuntimeError # Issue 29920; Expect.throws(ArgumentError) fails: Did not throw
-example_constructor_test: RuntimeError # Expect.equals(expected: <0 1 2 3 4 5 6 >, actual: <0 3 4 1 2 5 6 >) fails.
-exception_test: RuntimeError # DDC doesn't implement NullThrownError?; Expect.isTrue(false) fails.
-expect_test: RuntimeError # Issue 29920; Expect.identical did not fail
-f_bounded_quantification3_test: RuntimeError # Issue 29920; Uncaught Error: type arguments should not be null: (F1, F2) => {
-flatten_test/05: MissingRuntimeError # Issue 29920
-flatten_test/08: MissingRuntimeError # Issue 29920
-flatten_test/09: MissingRuntimeError # Issue 29920
-flatten_test/12: MissingRuntimeError # Issue 29920
-for_variable_capture_test: RuntimeError # Issue 29920; Expect.equals(expected: <1>, actual: <0>) fails.
-function_subtype_inline2_test: RuntimeError # Expect.fail('Missing type error: 'new C.c1(m2)'.')
-generic_instanceof2_test: RuntimeError # Issue 29920; ReferenceError: FooOfK$String is not defined
-generic_is_check_test: RuntimeError # Issue 29920; Expect.isTrue(false) fails.
-generic_tearoff_test: CompileTimeError
-guess_cid_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-identical_closure2_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-identical_closure2_test: RuntimeError # Issue 29920; Expect.isFalse(true) fails.
-infinite_switch_label_test: RuntimeError # Issue 29920; NoSuchMethodError: method not found: '<Unexpected Null Value>'
-infinity_test: RuntimeError # Issue 29920; Expect.isFalse(true) fails.
-instance_creation_in_function_annotation_test: RuntimeError # Issue 29920; UnimplementedError: JsClosureMirror.function unimplemented
-int2_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
int64_literal_test/*: Skip # This is testing Dart 2.0 int64 semantics.
-integer_division_by_zero_test: RuntimeError # Issue 29920; Expect.throws: Unexpected 'Unsupported operation: Infinity'
-internal_library_test/02: Crash
-invocation_mirror_invoke_on2_test: RuntimeError # UnimplementedError: JsInstanceMirror.delegate unimplemented
-invocation_mirror_invoke_on_test: RuntimeError # UnimplementedError: JsInstanceMirror.delegate unimplemented
-invocation_mirror_test: RuntimeError # Type 'NativeJavaScriptObject' is not a subtype of type 'int' in strong mode
-issue23244_test: RuntimeError # Issue 29920; Uncaught Unsupported operation: only top-level functions can be spawned.
-least_upper_bound_expansive_test/none: RuntimeError # 30908; Uncaught RangeError: Maximum call stack size exceeded
-left_shift_test: RuntimeError # Ints and doubles are unified.; Expect.equals(expected: <1>, actual: <-4294967295>) fails.
-library_env_test/has_io_support: RuntimeError, OK # Intended to fail, bool.fromEnvironment("dart.library.async") is false
-library_env_test/has_mirror_support: RuntimeError, OK # Intended to fail, bool.fromEnvironment("dart.library.async") is false
-library_env_test/has_no_html_support: RuntimeError, OK # Intended to fail, bool.fromEnvironment("dart.library.async") is false
-local_function2_test/none: RuntimeError # ReferenceError: TToNull is not defined
-local_function3_test/none: RuntimeError # Expect.equals(expected: <true>, actual: <false>) fails.
-local_function_test/none: RuntimeError # Expect.equals(expected: <true>, actual: <false>) fails.
-mint_arithmetic_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-mint_arithmetic_test: RuntimeError # Issue 29920; Expect.equals(expected: <4294967297>, actual: <1>) fails.
-mint_compares_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-mint_identical_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-modulo_test: RuntimeError # Ints and doubles are unified.; Expect.throws fails: Did not throw
-named_parameters_default_eq_test/none: RuntimeError # Expect.isTrue(false) fails.
-nan_identical_test: RuntimeError # Issue 29920; Unsupported operation: Uint64 accessor not supported by dart2js.
-nested_switch_label_test: RuntimeError # Issue 29920; UnimplementedError: node <ShadowContinueSwitchStatement> see https://github.com/dart-lang/sdk/issues/29352 `continue #L1;
-null_test/mirrors: RuntimeError # Uses mirrors.; ReferenceError: GenericOfT is not defined
-number_identity2_test: RuntimeError # Issue 29920; Expect.isTrue(false) fails.
-number_identity_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-numbers_test: RuntimeError # Issue 29920; Expect.equals(expected: <false>, actual: <true>) fails.
-regress_16640_test: RuntimeError # Issue 29920; Uncaught Error: type arguments should not be null: E => {
-regress_22443_test: RuntimeError # Uncaught Expect.isTrue(false) fails.
-stack_overflow_stacktrace_test: RuntimeError # Issue 29920; RangeError: Maximum call stack size exceeded
-stack_overflow_test: RuntimeError # Issue 29920; RangeError: Maximum call stack size exceeded
-stacktrace_demangle_ctors_test: RuntimeError # Issue 31089; Expect.isTrue(false) fails.
-stacktrace_test: RuntimeError # Issue 29920; Expect.isTrue(false) fails.
-string_literals_test: RuntimeError # Expect.equals(expected: <\x00\x0A\x0D\x7F\xFF\u{FFFF}\u{D800}\u{DC00}\u{DBFF}\u{DFFF}>, actual: <\x00\x0A\x0D\x7F\xFF\u{FFFF}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}>) fails.
-super_test: RuntimeError # Expect.equals(expected: <0>, actual: <2>) fails.
superinterface_variance/*: Skip # Issue dart-lang/language#113
-switch_label2_test: RuntimeError # Issue 29920; UnimplementedError: node <ShadowContinueSwitchStatement> see https://github.com/dart-lang/sdk/issues/29352 `continue #L1;
-switch_label_test: RuntimeError # Issue 29920; UnimplementedError: node <ShadowContinueSwitchStatement> see https://github.com/dart-lang/sdk/issues/29352 `continue #L1;
-switch_try_catch_test: RuntimeError # Issue 29920; Expect.throws: Unexpected 'UnimplementedError: node <ShadowContinueSwitchStatement> see https://github.com/dart-lang/sdk/issues/29352 `continue #L1;
-syncstar_covariant_type_test: RuntimeError # Check too late
-truncdiv_test: RuntimeError # Issue 29920; Expect.throws fails: Did not throw
vm/*: SkipByDesign # VM only tests.; VM only tests.
diff --git a/tests/language_2/language_2_kernel.status b/tests/language_2/language_2_kernel.status
index ee72f59..0f1d7ea 100644
--- a/tests/language_2/language_2_kernel.status
+++ b/tests/language_2/language_2_kernel.status
@@ -5,187 +5,22 @@
[ $compiler == app_jitk ]
no_main_test/01: Crash
-type_alias_equality_test/03: RuntimeError # Issue 32783
-type_alias_equality_test/04: RuntimeError # Issue 32783
-vm/bool_check_stack_traces_test/02: RuntimeError # Issue 33584
vm/regress_27671_test: SkipByDesign # Relies on string comparison of exception message which may return '<optimized out>'
web_int_literals_test/*: SkipByDesign # Test applies only to JavaScript targets
[ $compiler == dartkp ]
-generic_no_such_method_dispatcher_test: RuntimeError # Issue 31424
web_int_literals_test/*: SkipByDesign # Test applies only to JavaScript targets
[ $compiler == fasta ]
async_await_syntax_test/e5: Crash # Assertion error: continuation.dart: Failed assertion: 'node.expression == null || node.expression is NullLiteral': is not true.
async_await_syntax_test/e6: Crash # Assertion error: continuation.dart: Failed assertion: 'node.expression == null || node.expression is NullLiteral': is not true.
-constructor5_test: CompileTimeError # Verification error
-constructor6_test: CompileTimeError # Verification error
web_int_literals_test/*: SkipByDesign # Test applies only to JavaScript targets
[ $fasta ]
-async_return_types_test/nestedFuture: MissingCompileTimeError # Issue 33068
-const_cast2_test/01: CompileTimeError # Issue 32517
-const_cast2_test/none: CompileTimeError # Issue 32517
-constants_2018/potential_const_dynamic_test/sh3: CompileTimeError # New test introduced in https://dart-review.googlesource.com/c/sdk/+/97510
-constants_2018/potential_const_type_test/sh3: CompileTimeError # New test introduced in https://dart-review.googlesource.com/c/sdk/+/97510
-deferred_inheritance_constraints_test/extends: MissingCompileTimeError # Fasta/KernelVM bug: Deferred loading kernel issue 30273.
-deferred_inheritance_constraints_test/implements: MissingCompileTimeError # Fasta/KernelVM bug: Deferred loading kernel issue 30273.
-deferred_inheritance_constraints_test/mixin: MissingCompileTimeError # Fasta/KernelVM bug: Deferred loading kernel issue 30273.
-f_bounded_quantification2_test: CompileTimeError # Issue 34583
-f_bounded_quantification4_test: CompileTimeError # Issue 34583
-issue31596_super_test/02: MissingCompileTimeError # Issue 31596
-issue31596_super_test/04: MissingCompileTimeError # Issue 31596
nnbd/*: Skip
-regress_22976_test/*: CompileTimeError # Issue 31935
-set_literals/invalid_set_literal_test/08: MissingCompileTimeError # Requires constant evaluation
-set_literals/invalid_set_literal_test/09: MissingCompileTimeError # Requires constant evaluation
-set_literals/invalid_set_literal_test/10: MissingCompileTimeError # Requires constant evaluation
-set_literals/invalid_set_literal_test/29: MissingCompileTimeError # Requires constant evaluation
-set_literals/invalid_set_literal_test/30: MissingCompileTimeError # Requires constant evaluation
-set_literals/invalid_set_literal_test/31: MissingCompileTimeError # Requires constant evaluation
-set_literals/invalid_set_literal_test/32: MissingCompileTimeError # Requires constant evaluation
-set_literals/invalid_set_literal_test/33: MissingCompileTimeError # Requires constant evaluation
-set_literals/invalid_set_literal_test/34: MissingCompileTimeError # Requires constant evaluation
-superinterface_variance/abstract_class_error_test/01: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/02: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/04: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/05: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/06: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/07: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/08: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/10: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/11: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/12: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/13: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/14: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/16: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/17: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/18: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/19: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/20: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/22: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/23: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/24: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/26: MissingCompileTimeError # Issue dart-lang/language#113
superinterface_variance/abstract_class_error_test/27: Crash # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/29: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/30: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/31: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/32: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/34: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/35: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_class_error_test/36: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/01: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/02: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/04: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/05: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/06: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/07: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/08: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/10: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/11: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/12: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/13: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/14: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/16: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/17: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/18: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/19: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/20: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/22: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/23: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/24: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/25: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/26: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/28: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/29: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/30: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/31: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/32: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/34: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/35: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/abstract_mixin_application_error_test/36: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/01: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/02: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/04: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/05: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/06: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/07: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/08: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/10: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/11: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/12: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/13: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/14: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/16: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/17: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/18: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/19: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/20: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/22: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/23: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/24: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/26: MissingCompileTimeError # Issue dart-lang/language#113
superinterface_variance/concrete_class_error_test/27: Crash # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/29: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/30: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/31: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/32: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/34: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/35: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_class_error_test/36: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/01: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/02: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/04: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/05: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/06: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/07: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/08: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/10: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/11: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/12: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/13: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/14: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/16: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/17: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/18: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/19: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/20: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/22: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/23: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/24: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/25: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/26: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/28: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/29: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/30: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/31: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/32: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/34: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/35: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/concrete_mixin_application_error_test/36: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/covariance_test: CompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/01: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/02: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/04: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/05: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/06: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/13: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/14: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/16: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/17: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/18: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/19: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/20: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/22: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/23: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/24: MissingCompileTimeError # Issue dart-lang/language#113
superinterface_variance/mixin_error_test/27: Crash # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/31: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/32: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/34: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/35: MissingCompileTimeError # Issue dart-lang/language#113
-superinterface_variance/mixin_error_test/36: MissingCompileTimeError # Issue dart-lang/language#113
superinterface_variance/mixin_error_test/37: Crash # Issue dart-lang/language#113
superinterface_variance/mixin_error_test/38: Crash # Issue dart-lang/language#113
superinterface_variance/mixin_error_test/40: Crash # Issue dart-lang/language#113
@@ -196,32 +31,16 @@
superinterface_variance/mixin_error_test/46: Crash # Issue dart-lang/language#113
superinterface_variance/mixin_error_test/47: Crash # Issue dart-lang/language#113
superinterface_variance/mixin_error_test/48: Crash # Issue dart-lang/language#113
-syntax_test/28: MissingCompileTimeError # Issue 29763 - low priority
-syntax_test/29: MissingCompileTimeError # Issue 29763 - low priority
-syntax_test/30: MissingCompileTimeError # Issue 29763 - low priority
-syntax_test/31: MissingCompileTimeError # Issue 29763 - low priority
-syntax_test/32: MissingCompileTimeError # Issue 29763 - low priority
-syntax_test/33: MissingCompileTimeError # Issue 29763 - low priority
-syntax_test/60: MissingCompileTimeError # Issue 30470
-syntax_test/61: MissingCompileTimeError # Issue 30470
-type_constants_test/04: MissingCompileTimeError # Issue 32557
-vm/debug_break_enabled_vm_test/01: CompileTimeError # KernelVM bug: Bad test using extended break syntax.
-vm/debug_break_enabled_vm_test/none: CompileTimeError # KernelVM bug: Bad test using extended break syntax.
-vm/regress_27201_test: CompileTimeError # Fasta/KernelVM bug: Deferred loading kernel issue 30273.
[ $builder_tag == obfuscated && $compiler == dartkp ]
generic_function_dcall_test/01: SkipByDesign # Prints type names
-invocation_mirror_test: RuntimeError # Issue 34911
many_named_arguments_test: SkipByDesign # Checks names of arguments
mixin_generic_test: SkipByDesign # Prints type names
mixin_mixin3_test: SkipByDesign # Prints type names
mixin_mixin5_test: SkipByDesign # Prints type names
mixin_mixin6_test: SkipByDesign # Prints type names
mixin_mixin_bound2_test: SkipByDesign # Prints type names
-no_such_method_native_test: RuntimeError # Compares symbol #foobar with string "foobar" in noSuchMethod
-recursive_generic_test: RuntimeError # Compares a (dynamic) toString call to 'C<D>'
symbol_literal_test/02: SkipByDesign # We don't obfuscate const Symbol constructor
-tearoff_dynamic_test: RuntimeError # Compares call to "foo" (noSuchMethod) with string "foo"
type_literal_test: SkipByDesign # Uses lots of strings with type names in them
vm/bool_check_stack_traces_test: SkipByDesign # Looks for filenames in stacktrace output
vm/no_such_args_error_message_vm_test: SkipByDesign # Looks for function name in error message
@@ -229,56 +48,9 @@
vm/no_such_method_error_message_vm_test: SkipByDesign # Looks for unobfuscated name in error message
vm/regress_28325_test: SkipByDesign # Looks for filename in stack trace
-# The precompilation and bytecode configurations use a kernel2kernel constants evaluator
-# which is is more correct than fasta/vm in JIT mode (i.e. it catches more
-# compile-time errors).
-[ $compiler != dart2analyzer && $compiler != dart2js && $compiler != dartkb && $compiler != dartkp && $fasta ]
-compile_time_constant_o_test/01: MissingCompileTimeError # Issue 32983
-compile_time_constant_o_test/02: MissingCompileTimeError # Issue 32983
-const_dynamic_type_literal_test/02: MissingCompileTimeError # Issue 32983
-identical_const_test/01: MissingCompileTimeError # Issue 32983
-identical_const_test/02: MissingCompileTimeError # Issue 32983
-identical_const_test/03: MissingCompileTimeError # Issue 32983
-identical_const_test/04: MissingCompileTimeError # Issue 32983
-
-[ $compiler != dart2analyzer && $compiler != dart2js && $fasta ]
-switch_bad_case_test/01: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-switch_bad_case_test/02: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-switch_case_test/00: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-switch_case_test/01: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-switch_case_test/02: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-
-[ $compiler != dart2analyzer && $fasta ]
-const_map2_test/00: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-const_map3_test/00: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-
-[ $compiler != dart2js && $compiler != dartdevk && $fasta ]
-const_native_factory_test: MissingCompileTimeError # Issue 29763
-
-[ $compiler != dart2js && $fasta ]
-type_constants_test/01: MissingCompileTimeError # Issue 32557
-
[ $compiler == dartk && $mode == debug && ($hot_reload || $hot_reload_rollback) ]
inference_enum_list_test: Skip # Issue 35885
-[ $compiler == dartk && $runtime == vm && !$checked ]
-assertion_initializer_const_error2_test/cc01: MissingCompileTimeError # Not reporting failed assert() at compile time.
-assertion_initializer_const_error2_test/cc02: MissingCompileTimeError # Not reporting failed assert() at compile time.
-assertion_initializer_const_error2_test/cc03: MissingCompileTimeError # Not reporting failed assert() at compile time.
-assertion_initializer_const_error2_test/cc04: MissingCompileTimeError # Not reporting failed assert() at compile time.
-assertion_initializer_const_error2_test/cc05: MissingCompileTimeError # Not reporting failed assert() at compile time.
-assertion_initializer_const_error2_test/cc06: MissingCompileTimeError # Not reporting failed assert() at compile time.
-assertion_initializer_const_error2_test/cc07: MissingCompileTimeError # Not reporting failed assert() at compile time.
-assertion_initializer_const_error2_test/cc08: MissingCompileTimeError # Not reporting failed assert() at compile time.
-assertion_initializer_const_error2_test/cc09: MissingCompileTimeError # Not reporting failed assert() at compile time.
-assertion_initializer_const_error2_test/cc10: MissingCompileTimeError # Not reporting failed assert() at compile time.
-
-[ $compiler == dartkb && $runtime == vm ]
-async_star_test/03: Pass, RuntimeError # Please triage
-async_star_test/04: Pass, RuntimeError # Please triage
-vm/causal_async_exception_stack2_test: RuntimeError # Please triage
-vm/causal_async_exception_stack_test: RuntimeError # Please triage
-
[ $compiler == dartkp && $mode == debug && $runtime == dart_precompiled ]
external_test/13: Crash
vm/precompiled_static_initializer_test: Slow
@@ -286,73 +58,28 @@
# ==== dartkp + dart_precompiled status lines ====
[ $compiler == dartkp && $runtime == dart_precompiled ]
assert_with_type_test_or_cast_test: Crash
-async_star_test/02: RuntimeError, CompileTimeError # Issue 31402 (Invocation arguments)
-call_method_must_not_be_field_test/03: RuntimeError # Issue 32265
-call_method_must_not_be_getter_test/03: RuntimeError # Issue 32265
-compile_time_constant_static5_test/11: CompileTimeError # Issue 31537
-compile_time_constant_static5_test/16: CompileTimeError # Issue 31537
-compile_time_constant_static5_test/21: CompileTimeError # Issue 31537
-compile_time_constant_static5_test/23: CompileTimeError # Issue 31402 (Field declaration)
-conditional_import_string_test: CompileTimeError # KernelVM bug: Deferred loading kernel issue 30273.
-conditional_import_test: CompileTimeError # KernelVM bug: Deferred loading kernel issue 30273.
-config_import_corelib_test: CompileTimeError # Issue 31533
-config_import_test: RuntimeError # KernelVM bug: Configurable imports.
const_evaluation_test: SkipByDesign
ct_const2_test: Skip # Incompatible flag: --compile_all
-cyclic_type_test/02: Fail, OK # Non-contractive types are not supported in the vm.
-deferred_call_empty_before_load_test: RuntimeError # Fasta/KernelVM bug: Deferred loading kernel issue 30273.
-deferred_load_constants_test/none: RuntimeError # KernelVM bug: Deferred loading kernel issue 30273.
-deferred_load_library_wrong_args_test/01: Pass # Passes by mistake. KernelVM bug: Deferred loading kernel issue 30273.
-deferred_not_loaded_check_test: RuntimeError # Fasta/KernelVM bug: Deferred loading kernel issue 30273.
-deferred_redirecting_factory_test: CompileTimeError, Fail, Crash # Issue 23408, KernelVM bug: Deferred loading kernel issue 30273.
-deferred_static_seperate_test: RuntimeError # KernelVM bug: Deferred loading kernel issue 30273.
+deferred_redirecting_factory_test: Crash # Issue 23408, KernelVM bug: Deferred loading kernel issue 30273.
deopt_inlined_function_lazy_test: Skip # Incompatible flag: --deoptimize-alot
enum_mirror_test: SkipByDesign
export_ambiguous_main_test: Skip # Issue 29895 Fail Issue 14763
export_double_same_main_test: Skip # Issue 29895 Crash Issue 29895
-external_test/10: MissingRuntimeError # KernelVM bug: Unbound external.
-external_test/13: MissingRuntimeError # KernelVM bug: Unbound external.
-external_test/20: MissingRuntimeError # KernelVM bug: Unbound external.
field_increment_bailout_test: SkipByDesign
generic_methods_recursive_bound_test/03: Crash
-generic_no_such_method_dispatcher_simple_test: CompileTimeError # Issue 31533
-generic_no_such_method_dispatcher_test: CompileTimeError # Issue 31533
hello_dart_test: Skip # Incompatible flag: --compile_all
implicit_closure_test: Skip # Incompatible flag: --use_slow_path
-implicit_downcast_during_assignment_test: Pass # Correctly passes.
-implicit_downcast_during_combiner_test: Pass # Correctly passes.
-implicit_downcast_during_compound_assignment_test: Pass # Correctly passes.
-implicit_downcast_during_conditional_expression_test: Pass # Correctly passes.
-implicit_downcast_during_do_test: Pass # Correctly passes.
-implicit_downcast_during_for_condition_test: Pass # Correctly passes.
-implicit_downcast_during_for_initializer_expression_test: Pass # Correctly passes.
-implicit_downcast_during_for_initializer_var_test: Pass # Correctly passes.
-implicit_downcast_during_if_null_assignment_test: Pass # Correctly passes.
-implicit_downcast_during_if_statement_test: Pass # Correctly passes.
-implicit_downcast_during_list_literal_test: Pass # Correctly passes.
-implicit_downcast_during_logical_expression_test: Pass # Correctly passes.
-implicit_downcast_during_map_literal_test: Pass # Correctly passes.
-implicit_downcast_during_not_test: Pass # Correctly passes.
-implicit_downcast_during_return_async_test: Pass # Correctly passes.
-implicit_downcast_during_return_test: Pass # Correctly passes.
-implicit_downcast_during_variable_declaration_test: Pass # Correctly passes.
-implicit_downcast_during_while_statement_test: Pass # Correctly passes.
-implicit_downcast_during_yield_star_test: Pass # Correctly passes.
-implicit_downcast_during_yield_test: Pass # Correctly passes.
instance_creation_in_function_annotation_test: SkipByDesign
invocation_mirror2_test: SkipByDesign
invocation_mirror_invoke_on2_test: SkipByDesign
invocation_mirror_invoke_on_test: SkipByDesign
issue21079_test: SkipByDesign
-library_env_test/has_html_support: RuntimeError # KernelVM bug: Configurable imports.
-library_env_test/has_no_io_support: RuntimeError # KernelVM bug: Configurable imports.
main_not_a_function_test: Skip
many_overridden_no_such_method_test: SkipByDesign
mixin_illegal_super_use_test: Skip # Issues 24478 and 23773
mixin_illegal_superclass_test: Skip # Issues 24478 and 23773
no_main_test/01: Skip
no_such_method_test: SkipByDesign
-null_no_such_method_test: CompileTimeError # Issue 31533
null_test/mirrors: Skip # Uses mirrors.
null_test/none: SkipByDesign
overridden_no_such_method_test: SkipByDesign
@@ -360,47 +87,15 @@
regress_13462_0_test: SkipByDesign
regress_13462_1_test: SkipByDesign
regress_18535_test: SkipByDesign
-regress_22443_test: RuntimeError # KernelVM bug: Deferred loading kernel issue 30273.
-regress_23408_test: CompileTimeError # KernelVM bug: Deferred loading kernel issue 30273.
regress_28255_test: SkipByDesign
-regress_29025_test: CompileTimeError # Issue 31402 (Variable declaration)
-regress_29405_test: CompileTimeError # Issue 31402 (Invocation arguments)
-regress_30339_test: CompileTimeError # Issue 31402 (Variable declaration)
-setter_no_getter_test/01: Pass, CompileTimeError # Issue 31533 (started passing after switching to batch-mode)
-string_interpolation_and_buffer_test: RuntimeError # Issue 31402 (Return and yield statements)
-super_bound_closure_test/none: CompileTimeError # Issue 31533
-type_alias_equality_test/03: RuntimeError # Issue 32783
-type_alias_equality_test/04: RuntimeError # Issue 32783
-type_promotion_more_specific_test/04: CompileTimeError # Issue 31533
-vm/bool_check_stack_traces_test/01: RuntimeError # Issue 33584
-vm/bool_check_stack_traces_test/02: RuntimeError # Issue 33584
vm/causal_async_exception_stack2_test: SkipByDesign
vm/causal_async_exception_stack_test: SkipByDesign
vm/closure_memory_retention_test: Skip # KernelVM bug: Hits OOM
vm/reflect_core_vm_test: SkipByDesign
vm/regress_27671_test: Skip # Unsupported
vm/regress_29145_test: Skip # Issue 29145
-vm/type_cast_vm_test: RuntimeError # Expects line and column numbers
-vm/type_vm_test: RuntimeError, Pass # Expects line and column numbers
[ $compiler == dartkp && $runtime == dart_precompiled && $checked ]
-assert_initializer_test/31: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/32: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/33: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/34: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/35: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/36: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/37: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/38: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/41: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/42: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/43: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/44: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/45: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/46: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/47: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/48: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/none: RuntimeError # KernelVM bug: Constant evaluation.
assertion_initializer_const_error2_test/cc01: Crash
assertion_initializer_const_error2_test/cc02: Crash
assertion_initializer_const_error2_test/cc03: Crash
@@ -412,17 +107,6 @@
assertion_initializer_const_error2_test/cc09: Crash
assertion_initializer_const_error2_test/cc10: Crash
assertion_initializer_const_error2_test/cc11: Crash
-generic_functions_test: Pass # Issue 25869
-generic_local_functions_test: Pass # Issue 25869
-generic_methods_function_type_test: Pass # Issue 25869
-generic_methods_generic_function_parameter_test: Pass # Issue 25869
-generic_methods_new_test: Pass # Issue 25869
-generic_methods_test: Pass # Issue 25869
-known_identifier_usage_error_test/none: RuntimeError # Issue 28814
-regress_22728_test: Fail # Dartk Issue 28498
-
-[ $compiler == dartkp && $runtime == dart_precompiled && !$checked ]
-type_error_test: RuntimeError # Issue 31402 (Variable declaration)
[ $compiler == dartkp && $system == windows ]
disassemble_test: Slow
@@ -436,115 +120,28 @@
[ $mode == debug && ($compiler == dartk || $compiler == dartkb) && ($hot_reload || $hot_reload_rollback) ]
enum_duplicate_test/02: Crash # Issue 34606
-enum_duplicate_test/none: Pass, Crash # Issue 34606
-enum_private_test/01: Pass, Crash # Issue 34606
+enum_duplicate_test/none: Crash # Issue 34606
+enum_private_test/01: Crash # Issue 34606
enum_test: Crash # Issue 34606
[ $mode == product && $runtime == vm && ($compiler == dartk || $compiler == dartkb) ]
vm/causal_async_exception_stack2_test: SkipByDesign
vm/causal_async_exception_stack_test: SkipByDesign
-[ $runtime == vm && $checked && ($compiler == dartk || $compiler == dartkb) ]
-assert_initializer_test/31: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/32: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/33: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/34: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/35: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/36: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/37: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/38: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/41: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/42: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/43: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/44: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/45: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/46: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/47: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/48: MissingCompileTimeError # KernelVM bug: Constant evaluation.
-assert_initializer_test/none: RuntimeError # KernelVM bug: Constant evaluation.
-
-[ $runtime == vm && !$checked && ($compiler == dartk || $compiler == dartkb) ]
-type_error_test: RuntimeError # Issue 31402 (Variable declaration)
-
# ===== dartk + vm status lines =====
[ $runtime == vm && ($compiler == dartk || $compiler == dartkb) ]
-arithmetic2_test: RuntimeError # Throws CastError instead of TypeError
-async_star_test/02: RuntimeError # Issue 31402 (Invocation arguments)
-call_method_must_not_be_field_test/03: RuntimeError # Issue 32265
-call_method_must_not_be_getter_test/03: RuntimeError # Issue 32265
-compile_time_constant_o_test/01: RuntimeError # KernelVM bug: Constant map duplicated key.
-compile_time_constant_o_test/02: RuntimeError # KernelVM bug: Constant map duplicated key.
-compile_time_constant_static5_test/11: CompileTimeError # Issue 31537
-compile_time_constant_static5_test/16: CompileTimeError # Issue 31537
-compile_time_constant_static5_test/21: CompileTimeError # Issue 31537
-compile_time_constant_static5_test/23: CompileTimeError # Issue 31402 (Field declaration)
-conditional_import_string_test: CompileTimeError # KernelVM bug: Deferred loading kernel issue 30273.
-conditional_import_test: CompileTimeError # KernelVM bug: Deferred loading kernel issue 30273.
-config_import_corelib_test: CompileTimeError # Issue 31533
-config_import_test: RuntimeError # KernelVM bug: Configurable imports.
-const_dynamic_type_literal_test/02: RuntimeError # KernelVM bug: Constant map duplicated key.
-const_nested_test: RuntimeError # KernelVM bug: Constant evaluation.
-ct_const2_test: Pass, Crash # Flaky
-deferred_call_empty_before_load_test: RuntimeError # KernelVM bug: Deferred loading kernel issue 30273.
-deferred_load_constants_test/none: RuntimeError # KernelVM bug: Deferred loading kernel issue 30273.
-deferred_load_library_wrong_args_test/01: Pass # Passes by mistake. KernelVM bug: Deferred loading kernel issue 30273.
-deferred_not_loaded_check_test: RuntimeError # Fasta/KernelVM bug: Deferred loading kernel issue 30273.
-deferred_redirecting_factory_test: RuntimeError # KernelVM bug: Deferred loading kernel issue 30273.
-deferred_static_seperate_test: RuntimeError # KernelVM bug: Deferred loading kernel issue 30273.
-disassemble_test: Pass, Slow, Crash # dartbug.com/34971
-external_test/10: MissingRuntimeError # KernelVM bug: Unbound external.
-external_test/13: MissingRuntimeError # KernelVM bug: Unbound external.
-external_test/20: MissingRuntimeError # KernelVM bug: Unbound external.
-generic_no_such_method_dispatcher_simple_test: CompileTimeError # Issue 31533
-generic_no_such_method_dispatcher_test: CompileTimeError # Issue 31533
-library_env_test/has_html_support: RuntimeError # KernelVM bug: Configurable imports.
-library_env_test/has_no_io_support: RuntimeError # KernelVM bug: Configurable imports.
+ct_const2_test: Crash # Flaky
+disassemble_test: Slow, Crash # dartbug.com/34971
mixin_illegal_super_use_test: Skip # Issues 24478 and 23773
mixin_illegal_superclass_test: Skip # Issues 24478 and 23773
no_main_test/01: Skip
-no_such_method_mock_test: RuntimeError # Issue 31426
-null_no_such_method_test: CompileTimeError # Issue 31533
-regress_22443_test: RuntimeError # KernelVM bug: Deferred loading kernel issue 30273.
-regress_23408_test: RuntimeError, CompileTimeError # KernelVM bug: Deferred loading kernel issue 30273.
-regress_29025_test: CompileTimeError # Issue 31402 (Variable declaration)
-regress_29405_test: CompileTimeError # Issue 31402 (Invocation arguments)
-regress_30339_test: CompileTimeError # Issue 31402 (Variable declaration)
-string_interpolation_and_buffer_test: RuntimeError # Issue 31402 (Return and yield statements)
-super_bound_closure_test/none: CompileTimeError # Issue 31533
-type_promotion_more_specific_test/04: CompileTimeError # Issue 31533
-vm/bool_check_stack_traces_test/02: RuntimeError # Issue 33584
vm/closure_memory_retention_test: Skip # KernelVM bug: Hits OOM
vm/regress_29145_test: Skip # Issue 29145
web_int_literals_test/*: SkipByDesign # Test applies only to JavaScript targets
-[ $checked && ($compiler == dartk || $compiler == dartkb) ]
-assertion_initializer_const_error2_test/cc01: Pass # Works in --checked mode but not in --strong mode.
-assertion_initializer_const_error2_test/cc02: Pass # Works in --checked mode but not in --strong mode.
-assertion_initializer_const_error2_test/cc03: Pass # Works in --checked mode but not in --strong mode.
-assertion_initializer_const_error2_test/cc04: Pass # Works in --checked mode but not in --strong mode.
-assertion_initializer_const_error2_test/cc05: Pass # Works in --checked mode but not in --strong mode.
-assertion_initializer_const_error2_test/cc06: Pass # Works in --checked mode but not in --strong mode.
-assertion_initializer_const_error2_test/cc07: Pass # Works in --checked mode but not in --strong mode.
-assertion_initializer_const_error2_test/cc08: Pass # Works in --checked mode but not in --strong mode.
-assertion_initializer_const_error2_test/cc09: Pass # Works in --checked mode but not in --strong mode.
-assertion_initializer_const_error2_test/cc10: Pass # Works in --checked mode but not in --strong mode.
-
[ $hot_reload_rollback && ($compiler == dartk || $compiler == dartkb) ]
symbol_conflict_test: Slow
-# Enabling of dartk for sim{arm,arm64,dbc64} revealed these test failures, which
-# are to be triaged. Isolate tests are skipped on purpose due to the usage of
-# batch mode.
-[ ($arch == simarm || $arch == simarm64 || $arch == simdbc64) && ($compiler == dartk || $compiler == dartkb) ]
-least_upper_bound_expansive_test/none: RuntimeError # Please triage.
-
-[ ($compiler == app_jitk || $compiler == dartk || $compiler == dartkb || $compiler == dartkp) && ($runtime == dart_precompiled || $runtime == vm) ]
-type_alias_equality_test/04: RuntimeError # Issue 32783
-
-[ ($compiler == app_jitk || $compiler == dartk || $compiler == dartkp) && ($runtime == dart_precompiled || $runtime == vm) ]
-covariant_subtyping_with_mixin_test: RuntimeError # Issue 34321
-type_alias_equality_test/03: RuntimeError # Issue 32783
-
[ ($compiler == dartk || $compiler == dartkb) && ($hot_reload || $hot_reload_rollback) ]
async_star_test/01: Skip # Timeout
async_star_test/02: Skip # Timeout
@@ -554,14 +151,3 @@
async_star_test/none: Skip # Timeout
type_constants_test/none: Skip # Deferred libraries and hot reload.
-[ $compiler == dartk || $compiler == dartkb || $compiler == dartkp ]
-generic_function_bounds_test: RuntimeError # Issue 32076
-
-[ $compiler == dartkb || $compiler == dartkp ]
-set_literals/invalid_set_literal_test/29: Pass # Gen_kernel does does constant
-set_literals/invalid_set_literal_test/30: Pass # evalutation, so these tests
-set_literals/invalid_set_literal_test/31: Pass # throw the expected errors. The
-set_literals/invalid_set_literal_test/32: Pass # $fasta block marks these as
-set_literals/invalid_set_literal_test/33: Pass # MissingCompileTimeError, so we
-set_literals/invalid_set_literal_test/34: Pass # need to override them to Pass.
-vm/reflect_core_vm_test: CompileTimeError # Test uses Symbol("_...") which is a compile-time error.
diff --git a/tests/language_2/nnbd/resolution/question_dot_index_produces_nullable_type_test.dart b/tests/language_2/nnbd/resolution/question_dot_index_produces_nullable_type_test.dart
new file mode 100644
index 0000000..aac6c33
--- /dev/null
+++ b/tests/language_2/nnbd/resolution/question_dot_index_produces_nullable_type_test.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2019, 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.
+
+// SharedOptions=--enable-experiment=non-nullable
+
+void main() {}
+
+void f1(NotGeneric x) {
+ x[0] + 1; //# 01: ok
+ x[0] = 1; //# 02: ok
+ useNonNullable(x[0] = 1); //# 03: ok
+ x[0] += 1; //# 04: ok
+ useNonNullable(x[0] += 1); //# 05: ok
+}
+
+void f2(NotGeneric? x) {
+ x?.[0] + 1; //# 06: compile-time error
+ x?.[0] = 1; //# 07: ok
+ useNonNullable(x?.[0] = 1); //# 08: compile-time error
+ x?.[0] += 1; //# 09: ok
+ useNonNullable(x?.[0] += 1); //# 10: compile-time error
+}
+
+void f3<T extends num>(Generic<T>? x) {
+ x?.[0] + 1; //# 11: compile-time error
+}
+
+void f4<T extends num>(Generic<T?> x) {
+ x[0] + 1; //# 12: compile-time error
+}
+
+class NotGeneric {
+ int operator[](int index) => throw 'unreachable';
+ void operator[]=(int index, int value) => throw 'unreachable';
+}
+
+class Generic<T> {
+ T operator[](int index) => throw 'unreachable';
+ void operator[]=(int index, T value) => throw 'unreachable';
+}
+
+void useNonNullable(int a) {}
diff --git a/tests/language_2/regress_22976_test.dart b/tests/language_2/regress_22976_test.dart
index d64ef30..7b54b5d 100644
--- a/tests/language_2/regress_22976_test.dart
+++ b/tests/language_2/regress_22976_test.dart
@@ -9,10 +9,16 @@
class B<T> implements A<T> {}
class C<S, T> implements B<S>, A<T> {}
+// [error line 11, column 1, length 38]
+// [analyzer] COMPILE_TIME_ERROR.CONFLICTING_GENERIC_INTERFACES
+// ^
+// [cfe] 'C' can't implement both 'A<S>' and 'A<T>'
main() {
C<int, String> c1 = new C<int, String>();
C<String, int> c2 = new C<String, int>();
- A<int> a0 = c1; //# 01: ok
- A<int> a1 = c2; //# 02: ok
+ A<int> a0 = c1;
+ A<int> a1 = c2;
+ // ^
+ // [cfe] A value of type 'C<String, int>' can't be assigned to a variable of type 'A<int>'.
}
diff --git a/tests/language_2/regress_23408_test.dart b/tests/language_2/regress_23408_test.dart
index 4372b54..5abf41d 100644
--- a/tests/language_2/regress_23408_test.dart
+++ b/tests/language_2/regress_23408_test.dart
@@ -2,33 +2,20 @@
// 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.
-// This test has been modified: it is now ok to use deferred types as long as
-// they aren't instantiated.
-
library regress_23408_test;
import 'package:expect/expect.dart';
import 'regress_23408_lib.dart' deferred as lib;
-class A<T> extends C {
- get t => T;
-}
-
class C {
var v = 55;
C();
factory C.c() = lib.K;
- factory C.l() = A<lib.K>;
}
void main() {
- var a = new C.l();
- Expect.equals(lib.K, a.t);
- Expect.throws(() => new C.c());
lib.loadLibrary().then((_) {
- var b = new C.l();
- Expect.equals(lib.K, b.t);
var z = new C.c();
Expect.equals(55, z.v);
});
diff --git a/tests/language_2/regress_23408a_test.dart b/tests/language_2/regress_23408a_test.dart
new file mode 100644
index 0000000..32d3579
--- /dev/null
+++ b/tests/language_2/regress_23408a_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2019, 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.
+
+library regress_23408a_test;
+
+import 'package:expect/expect.dart';
+
+import 'regress_23408_lib.dart' deferred as lib;
+
+class A<T> extends C {
+ get t => T;
+}
+
+class C {
+ C();
+ factory C.l() = A<lib.K>;
+ // ^^^^^
+ // [analyzer] STATIC_WARNING.TYPE_ANNOTATION_DEFERRED_CLASS
+ // [cfe] unspecified
+ get t => null;
+}
+
+void main() async {
+ await lib.loadLibrary();
+ Expect.equals(lib.K, C.l().t);
+}
diff --git a/tests/language_2/regress_29025_test.dart b/tests/language_2/regress_29025_test.dart
index c68f17a..867d738 100644
--- a/tests/language_2/regress_29025_test.dart
+++ b/tests/language_2/regress_29025_test.dart
@@ -2,29 +2,27 @@
// 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.
-typedef T F<T>(T t);
+abstract class F<T> {
+ T foo(T t);
+}
class B<T extends F<T>> {}
class C<T extends F<C<T>>> {}
-class D extends B<D> {
+class D extends B<D> implements F<D> {
D foo(D x) => x;
- D call(D x) => x;
- D bar(D x) => x;
}
-class E extends C<E> {
+class E extends C<E> implements F<C<E>> {
C<E> foo(C<E> x) => x;
- C<E> call(C<E> x) => x;
- C<E> bar(C<E> x) => x;
}
main() {
- F<D> fd = new D();
- var d = fd(fd);
+ D fd = D();
+ var d = fd.foo(fd);
print(d);
- F<E> fe = new E();
- var e = fe(fe);
+ E fe = E();
+ var e = fe.foo(fe);
print(e);
}
diff --git a/tests/language_2/regress_29405_test.dart b/tests/language_2/regress_29405_test.dart
deleted file mode 100644
index 4907716..0000000
--- a/tests/language_2/regress_29405_test.dart
+++ /dev/null
@@ -1,12 +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.
-
-class Foo {
- void call(void callback(Foo foo)) {}
-}
-
-main() {
- Foo foo = new Foo();
- foo(foo);
-}
diff --git a/tests/language_2/regress_30339_test.dart b/tests/language_2/regress_30339_test.dart
index 59ef53f..c3a6861 100644
--- a/tests/language_2/regress_30339_test.dart
+++ b/tests/language_2/regress_30339_test.dart
@@ -7,7 +7,7 @@
isCheckedMode() {
try {
- var i = 1;
+ dynamic i = 1;
String s = i;
return false;
} on TypeError {
@@ -15,7 +15,7 @@
}
}
-var x = 'a';
+dynamic x = 'a';
Future<int> foo() async {
return x;
diff --git a/tests/language_2/super_bound_closure_test.dart b/tests/language_2/super_bound_closure_test.dart
index 55efcf0..554b0e2 100644
--- a/tests/language_2/super_bound_closure_test.dart
+++ b/tests/language_2/super_bound_closure_test.dart
@@ -72,7 +72,8 @@
fooIntercept27() => confuse(super.lastWhere)(0);
fooIntercept28() => confuse(super.lastWhere)(3, orElse: 77);
- bar([var optional]) => -1; // //# 01: compile-time error
+ // Warning: overrides should not change default parameter values.
+ bar([var optional]) => -1; // //# 01: static type warning
bar2({namedOptional}) => -1; // //# 01: continued
bar3(x, [var optional]) => -1; // //# 01: continued
bar4(x, {namedOptional}) => -1; //# 01: continued
@@ -101,7 +102,7 @@
main() {
var list = [new A(), new B(), [], "foo"];
var a = list[confuse(0)];
- var b = list[confuse(1)];
+ dynamic b = list[confuse(1)];
var ignored = list[confuse(2)];
var ignored2 = list[confuse(3)];
diff --git a/tests/language_2/type_promotion_more_specific_test.dart b/tests/language_2/type_promotion_more_specific_test.dart
index 314d7c0..03f40a7 100644
--- a/tests/language_2/type_promotion_more_specific_test.dart
+++ b/tests/language_2/type_promotion_more_specific_test.dart
@@ -54,8 +54,8 @@
x = b.b; //# 03: ok
}
if (x is A) {
- // No promotion: x has type dynamic.
- y = x.b; //# 04: ok
+ // Promotion A << dynamic.
+ y = x.b; //# 04: compile-time error
}
}
diff --git a/tests/language_2/vm/clamp_37868_test.dart b/tests/language_2/vm/clamp_37868_test.dart
index 181f895..a6d7f21 100755
--- a/tests/language_2/vm/clamp_37868_test.dart
+++ b/tests/language_2/vm/clamp_37868_test.dart
@@ -13,8 +13,15 @@
@pragma("vm:never-inline")
foo(List<int> x) => Uint8ClampedList.fromList(x);
+@pragma("vm:never-inline")
+bar(List<int> x) => Uint8List.fromList(x);
+
+@pragma("vm:never-inline")
+baz(List<int> x) => Int8List.fromList(x);
+
main() {
- var x = [
+ // Proper values.
+ final List<int> x = [
9223372036854775807,
-9223372036854775808,
9223372032559808513,
@@ -25,10 +32,34 @@
-2147483648,
255,
-255,
+ 11,
+ -11,
+ 0,
+ -1,
];
- var y = foo(x);
- for (int i = 0; i < y.length; i += 2) {
- Expect.equals(255, y[i]);
- Expect.equals(0, y[i + 1]);
+ Expect.listEquals(
+ [255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 11, 0, 0, 0], foo(x));
+ Expect.listEquals(
+ [255, 0, 1, 255, 0, 0, 255, 0, 255, 1, 11, 245, 0, 255], bar(x));
+ Expect.listEquals([-1, 0, 1, -1, 0, 0, -1, 0, -1, 1, 11, -11, 0, -1], baz(x));
+
+ // Hidden null.
+ final List<int> a = [1, null, 2];
+ int num_exceptions = 0;
+ try {
+ foo(a);
+ } on NoSuchMethodError catch (e) {
+ num_exceptions++;
}
+ try {
+ bar(a);
+ } on NoSuchMethodError catch (e) {
+ num_exceptions++;
+ }
+ try {
+ baz(a);
+ } on NoSuchMethodError catch (e) {
+ num_exceptions++;
+ }
+ Expect.equals(3, num_exceptions);
}
diff --git a/tests/language_2/vm/div_mod_test.dart b/tests/language_2/vm/div_mod_test.dart
new file mode 100755
index 0000000..92fab4f
--- /dev/null
+++ b/tests/language_2/vm/div_mod_test.dart
@@ -0,0 +1,302 @@
+// Copyright (c) 2019, 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.
+
+// VMOptions=--deterministic
+
+// Unit tests on DIV and MOV operations by various constants.
+
+import "package:expect/expect.dart";
+
+import 'dart:core';
+
+int kMin = 0x8000000000000000;
+int kMax = 0x7fffffffffffffff;
+
+// The basic DIV operation.
+int divme(int x, int c) {
+ return x ~/ c;
+}
+
+// The basic MOD operation.
+int modme(int x, int c) {
+ return x % c;
+}
+
+//
+// Test several "hidden" DIV constants.
+//
+
+@pragma("vm:never-inline")
+int div0(int x) {
+ return divme(x, 0);
+}
+
+@pragma("vm:never-inline")
+int div1(int x) {
+ return divme(x, 1);
+}
+
+@pragma("vm:never-inline")
+int divm1(int x) {
+ return divme(x, -1);
+}
+
+@pragma("vm:never-inline")
+int div2(int x) {
+ return divme(x, 2);
+}
+
+@pragma("vm:never-inline")
+int divm2(int x) {
+ return divme(x, -2);
+}
+
+@pragma("vm:never-inline")
+int div37(int x) {
+ return divme(x, 37);
+}
+
+@pragma("vm:never-inline")
+int div131(int x) {
+ return divme(x, 131);
+}
+
+@pragma("vm:never-inline")
+int divm333(int x) {
+ return divme(x, -333);
+}
+
+@pragma("vm:never-inline")
+int divmin(int x) {
+ return divme(x, kMin);
+}
+
+@pragma("vm:never-inline")
+int divmax(int x) {
+ return divme(x, kMax);
+}
+
+//
+// Test several "hidden" MOD constants.
+//
+
+@pragma("vm:never-inline")
+int mod0(int x) {
+ return modme(x, 0);
+}
+
+@pragma("vm:never-inline")
+int mod1(int x) {
+ return modme(x, 1);
+}
+
+@pragma("vm:never-inline")
+int modm1(int x) {
+ return modme(x, -1);
+}
+
+@pragma("vm:never-inline")
+int mod2(int x) {
+ return modme(x, 2);
+}
+
+@pragma("vm:never-inline")
+int modm2(int x) {
+ return modme(x, -2);
+}
+
+@pragma("vm:never-inline")
+int mod37(int x) {
+ return modme(x, 37);
+}
+
+@pragma("vm:never-inline")
+int mod131(int x) {
+ return modme(x, 131);
+}
+
+@pragma("vm:never-inline")
+int modm333(int x) {
+ return modme(x, -333);
+}
+
+@pragma("vm:never-inline")
+int modmin(int x) {
+ return modme(x, kMin);
+}
+
+@pragma("vm:never-inline")
+int modmax(int x) {
+ return modme(x, kMax);
+}
+
+main() {
+ // Exceptional case DIV.
+ for (int i = -1; i <= 1; i++) {
+ bool threw = false;
+ try {
+ div0(i);
+ } on IntegerDivisionByZeroException catch (e) {
+ threw = true;
+ }
+ Expect.isTrue(threw);
+ }
+
+ // Exceptional case MOD.
+ for (int i = -1; i <= 1; i++) {
+ bool threw = false;
+ try {
+ mod0(i);
+ } on IntegerDivisionByZeroException catch (e) {
+ threw = true;
+ }
+ Expect.isTrue(threw);
+ }
+
+ // DIV by +/- 1.
+ Expect.equals(kMin, div1(kMin));
+ Expect.equals(kMin, divm1(kMin));
+ for (int i = -999; i <= 999; i++) {
+ Expect.equals(i, div1(i));
+ Expect.equals(-i, divm1(i));
+ }
+ Expect.equals(kMax, div1(kMax));
+ Expect.equals(-kMax, divm1(kMax));
+
+ // MOD by +/- 1.
+ Expect.equals(0, mod1(kMin));
+ Expect.equals(0, modm1(kMin));
+ for (int i = -999; i <= 999; i++) {
+ Expect.equals(0, mod1(i));
+ Expect.equals(0, modm1(i));
+ }
+ Expect.equals(0, mod1(kMax));
+ Expect.equals(0, modm1(kMax));
+
+ // DIV by +/- 2.
+ Expect.equals(-4611686018427387904, div2(kMin));
+ Expect.equals(-4611686018427387903, div2(kMin + 1));
+ Expect.equals(-4611686018427387903, div2(kMin + 2));
+ Expect.equals(4611686018427387904, divm2(kMin));
+ Expect.equals(4611686018427387903, divm2(kMin + 1));
+ Expect.equals(4611686018427387903, divm2(kMin + 2));
+ for (int i = -999; i <= 999; i++) {
+ int e = (i + ((i < 0) ? 1 : 0)) >> 1;
+ Expect.equals(e, div2(i));
+ Expect.equals(-e, divm2(i));
+ }
+ Expect.equals(4611686018427387903, div2(kMax));
+ Expect.equals(4611686018427387903, div2(kMax - 1));
+ Expect.equals(4611686018427387902, div2(kMax - 2));
+ Expect.equals(-4611686018427387903, divm2(kMax));
+ Expect.equals(-4611686018427387903, divm2(kMax - 1));
+ Expect.equals(-4611686018427387902, divm2(kMax - 2));
+
+ // MOD by +/- 2.
+ Expect.equals(0, mod2(kMin));
+ Expect.equals(1, mod2(kMin + 1));
+ Expect.equals(0, mod2(kMin + 2));
+ Expect.equals(0, modm2(kMin));
+ Expect.equals(1, modm2(kMin + 1));
+ Expect.equals(0, modm2(kMin + 2));
+ for (int i = -999; i <= 999; i++) {
+ Expect.equals(i & 1, mod2(i));
+ Expect.equals(i & 1, modm2(i));
+ }
+ Expect.equals(1, mod2(kMax));
+ Expect.equals(0, mod2(kMax - 1));
+ Expect.equals(1, mod2(kMax - 2));
+ Expect.equals(1, modm2(kMax));
+ Expect.equals(0, modm2(kMax - 1));
+ Expect.equals(1, modm2(kMax - 2));
+
+ // DIV/MOD by 37.
+ Expect.equals(-249280325320399346, div37(kMin));
+ Expect.equals(31, mod37(kMin));
+ for (int i = -999; i <= 999; i++) {
+ Expect.equals(i, div37(37 * i));
+ Expect.equals(i, div37(37 * i + ((i >= 0) ? 36 : -36)));
+ Expect.equals(0, mod37(37 * i));
+ Expect.equals(1, mod37(37 * i + 1));
+ Expect.equals(36, mod37(37 * i + 36));
+ }
+ for (int i = 1; i < 37; i++) {
+ Expect.equals(0, div37(i));
+ Expect.equals(i, mod37(i));
+ Expect.equals(0, div37(-i));
+ Expect.equals(37 - i, mod37(-i));
+ }
+ Expect.equals(249280325320399346, div37(kMax));
+ Expect.equals(5, mod37(kMax));
+
+ // DIV/MOD by 131.
+ Expect.equals(-70407420128662410, div131(kMin));
+ Expect.equals(33, mod131(kMin));
+ for (int i = -999; i <= 999; i++) {
+ Expect.equals(i, div131(131 * i));
+ Expect.equals(i, div131(131 * i + ((i >= 0) ? 130 : -130)));
+ Expect.equals(0, mod131(131 * i));
+ Expect.equals(1, mod131(131 * i + 1));
+ Expect.equals(130, mod131(131 * i + 130));
+ }
+ for (int i = 1; i < 131; i++) {
+ Expect.equals(0, div131(i));
+ Expect.equals(i, mod131(i));
+ Expect.equals(0, div131(-i));
+ Expect.equals(131 - i, mod131(-i));
+ }
+ Expect.equals(70407420128662410, div131(kMax));
+ Expect.equals(97, mod131(kMax));
+
+ // DIV/MOD by -333.
+ Expect.equals(27697813924488816, divm333(kMin));
+ Expect.equals(253, modm333(kMin));
+ for (int i = -999; i <= 999; i++) {
+ Expect.equals(i, divm333(-333 * i));
+ Expect.equals(i, divm333(-333 * i + ((i < 0) ? 130 : -130)));
+ Expect.equals(0, modm333(-333 * i));
+ Expect.equals(1, modm333(-333 * i + 1));
+ Expect.equals(130, modm333(-333 * i + 130));
+ }
+ Expect.equals(-27697813924488816, divm333(kMax));
+ Expect.equals(79, modm333(kMax));
+
+ // DIV/MOD by Min.
+ Expect.equals(1, divmin(kMin));
+ Expect.equals(0, modmin(kMin));
+ for (int i = -999; i <= 999; i++) {
+ Expect.equals(0, divmin(i));
+ Expect.equals(i >= 0 ? i : 1 + kMax + i, modmin(i));
+ }
+ Expect.equals(0, divmin(kMax));
+ Expect.equals(kMax, modmin(kMax));
+
+ // DIV/MOD by Max.
+ Expect.equals(-1, divmax(kMin));
+ Expect.equals(kMax - 1, modmax(kMin));
+ for (int i = -999; i <= 999; i++) {
+ Expect.equals(0, divmax(i));
+ Expect.equals(i >= 0 ? i : kMax + i, modmax(i));
+ }
+ Expect.equals(1, divmax(kMax));
+ Expect.equals(0, modmax(kMax));
+
+ // Exceptional null value MOD.
+ bool threwDiv = false;
+ try {
+ div2(null);
+ } on NoSuchMethodError catch (e) {
+ threwDiv = true;
+ }
+ Expect.isTrue(threwDiv);
+
+ // Exceptional null value MOD.
+ bool threwMod = false;
+ try {
+ mod2(null);
+ } on NoSuchMethodError catch (e) {
+ threwMod = true;
+ }
+ Expect.isTrue(threwMod);
+}
diff --git a/tests/language_2/vm/regress_37984_test.dart b/tests/language_2/vm/regress_37984_test.dart
new file mode 100644
index 0000000..2e7cd6f
--- /dev/null
+++ b/tests/language_2/vm/regress_37984_test.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2019, 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';
+
+main() async {
+ await for (var x in func(3)) {
+ print(x);
+ }
+}
+
+Stream<int> func(int i) async* {
+ int currentState = 0;
+ try {
+ print('outer try');
+ } finally {
+ try {
+ print('inner try');
+ } finally {
+ yield currentState + 1;
+ }
+ yield currentState + 1;
+ print('finally');
+ }
+}
diff --git a/tests/language_2/vm/regression_37821_test.dart b/tests/language_2/vm/regression_37821_test.dart
new file mode 100755
index 0000000..fd7ef2d
--- /dev/null
+++ b/tests/language_2/vm/regression_37821_test.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2019, 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.
+
+// VMOptions=--deterministic
+
+import "package:expect/expect.dart";
+
+import 'dart:typed_data';
+
+// Found by DartFuzzing: inconsistent view of unboxing
+// https://github.com/dart-lang/sdk/issues/37821
+
+double var5 = 0.5521203015696288;
+
+class X0 {
+ double fld0_1 = 0.44794902547497595;
+ void run() {
+ for (int loc1 = 0; loc1 < 11; loc1++) {
+ var5 = fld0_1;
+ }
+ fld0_1 -= 20;
+ }
+}
+
+class X1 extends X0 {
+ void run() {
+ super.run();
+ }
+}
+
+@pragma("vm:never-inline")
+void checkMe(double value) {
+ Expect.approxEquals(0.44794902547497595, value);
+}
+
+main() {
+ Expect.approxEquals(0.5521203015696288, var5);
+ new X1().run();
+ checkMe(var5);
+}
diff --git a/tests/language_2/vm/regression_38147_test.dart b/tests/language_2/vm/regression_38147_test.dart
new file mode 100755
index 0000000..0f3450a
--- /dev/null
+++ b/tests/language_2/vm/regression_38147_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2019, 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.
+
+// VMOptions=--deterministic --optimization_counter_threshold=10
+
+import "package:expect/expect.dart";
+
+import 'dart:typed_data';
+
+// Found by DartFuzzing: truncating shift
+// https://github.com/dart-lang/sdk/issues/38147
+
+int bar(int x, int y) {
+ return (x << y) & 0xffff;
+}
+
+@pragma("vm:never-inline")
+int foo() {
+ return bar(-61, 12);
+}
+
+main() {
+ for (int i = 0; i < 20; i++) {
+ Expect.equals(12288, foo());
+ }
+}
diff --git a/tests/lib_2/lib_2.status b/tests/lib_2/lib_2.status
index 0d9adbc..097b176 100644
--- a/tests/lib_2/lib_2.status
+++ b/tests/lib_2/lib_2.status
@@ -117,9 +117,6 @@
[ $runtime != dart_precompiled && ($runtime != vm || $compiler != dartk && $compiler != none) ]
isolate/vm_rehash_test: SkipByDesign
-[ !$preview_dart_2 && ($runtime == dart_precompiled || $runtime == vm) ]
-*: SkipByDesign # Deprecating all Dart1 modes of execution
-
[ $arch == simarm || $arch == simarmv5te || $arch == simarmv6 ]
convert/utf85_test: Skip # Pass, Slow Issue 12644.
diff --git a/tests/lib_2/lib_2_analyzer.status b/tests/lib_2/lib_2_analyzer.status
index 85a2a1d..113c571 100644
--- a/tests/lib_2/lib_2_analyzer.status
+++ b/tests/lib_2/lib_2_analyzer.status
@@ -3,8 +3,4 @@
# BSD-style license that can be found in the LICENSE file.
[ $compiler == dart2analyzer ]
-html/element_types_keygen_test: CompileTimeError # Chrome 57 keygen removed
html/js_function_getter_trust_types_test: Skip # dart2js specific flags.
-html/js_typed_interop_default_arg_test/default_value: MissingCompileTimeError # Issue #25759
-mirrors/deferred_type_test: CompileTimeError, OK # Deliberately refers to a deferred type in a declaration.
-mirrors/repeated_private_anon_mixin_app_test: CompileTimeError, OK # Intentional library name conflict.
diff --git a/tests/lib_2/lib_2_dart2js.status b/tests/lib_2/lib_2_dart2js.status
index b96429f..e1c07ea 100644
--- a/tests/lib_2/lib_2_dart2js.status
+++ b/tests/lib_2/lib_2_dart2js.status
@@ -3,10 +3,6 @@
# BSD-style license that can be found in the LICENSE file.
[ $compiler == dart2js ]
-async/future_or_type_test: RuntimeError
-async/slow_consumer2_test: RuntimeError
-async/stream_distinct_test: RuntimeError
-collection/list_test: RuntimeError
convert/chunked_conversion_utf88_test: Slow
convert/utf85_test: Slow
developer/timeline_test: Skip # Not supported
@@ -19,7 +15,6 @@
html/custom/mirrors_2_test: Skip # mirrors not supported, delete this test.
html/custom/mirrors_test: Skip # mirrors not supported, delete this test.
html/custom_elements_test: Slow # Issue 26789
-html/element_classes_test: RuntimeError
html/isolates_test: SkipByDesign
html/mirrors_js_typed_interop_test: Skip # mirrors not supported, delete this test.
html/worker_api_test: SkipByDesign
@@ -38,28 +33,10 @@
convert/streamed_conversion_json_utf8_encode_test: SkipSlow # Times out. Issue 22050
convert/streamed_conversion_utf8_decode_test: SkipSlow # Times out. Issue 22050
html/element_types_keygen_test: RuntimeError # Issue 29055
-html/file_sample_test: Pass, RuntimeError
-html/fileapi_entry_test: Pass, RuntimeError
-html/interactive_media_test: RuntimeError
html/media_stream_test: RuntimeError # Please triage.
html/speechrecognition_test: RuntimeError # Please triage.
[ $compiler == dart2js && $runtime == chrome && $csp ]
-html/canvas_pixel_array_type_alias_test: RuntimeError
-html/js_browser_test: RuntimeError
-html/js_caching_test: RuntimeError
-html/js_context_test: RuntimeError
-html/js_dart_functions_test: RuntimeError
-html/js_dart_js_test: RuntimeError
-html/js_identity_test: RuntimeError
-html/js_jsarray_test: RuntimeError
-html/js_jsfunc_callmethod_test: RuntimeError
-html/js_jsify_test: RuntimeError
-html/js_jsobject_test: RuntimeError
-html/js_methods_test: RuntimeError
-html/js_transferrables_test: RuntimeError
-html/js_typed_interop_lazy_test/none: RuntimeError
-html/js_typed_interop_rename_static_test: RuntimeError
html/worker_test/functional: RuntimeError # Issue 32261
[ $compiler == dart2js && $runtime == chromeOnAndroid ]
@@ -80,275 +57,35 @@
typed_data/setRange_3_test: RuntimeError # TODO(dart2js-team): Please triage this failure.
[ $compiler == dart2js && $runtime == d8 ]
-async/dart2js_uncaught_error_test: RuntimeError
-html/async_test: RuntimeError
-html/audiobuffersourcenode_test: RuntimeError
-html/audiocontext_test: RuntimeError
-html/audioelement_test: RuntimeError
-html/b_element_test: RuntimeError
-html/blob_constructor_test: RuntimeError
-html/cache_test: RuntimeError
-html/callback_list_test: RuntimeError
-html/callbacks_test: RuntimeError
-html/canvas_pixel_array_type_alias_test: RuntimeError
-html/canvas_test: RuntimeError
-html/canvasrenderingcontext2d_test: RuntimeError
-html/cdata_test: RuntimeError
-html/client_rect_test: RuntimeError
-html/cross_domain_iframe_test: RuntimeError
-html/crypto_test: RuntimeError
-html/css_rule_list_test: RuntimeError
-html/css_test: RuntimeError
-html/cssstyledeclaration_test: RuntimeError
-html/custom/attribute_changed_callback_test: RuntimeError
-html/custom/constructor_calls_created_synchronously_test: RuntimeError
-html/custom/created_callback_test: RuntimeError
-html/custom/document_register_basic_test: RuntimeError
-html/custom/document_register_template_test: RuntimeError
-html/custom/document_register_type_extensions_test: RuntimeError
-html/custom/element_upgrade_test: RuntimeError
-html/custom/entered_left_view_test: RuntimeError
-html/custom/js_custom_test: RuntimeError
-html/custom_element_method_clash_test: RuntimeError
-html/custom_element_name_clash_test: RuntimeError
-html/custom_elements_23127_test: RuntimeError
-html/custom_elements_test: RuntimeError
-html/custom_tags_test: RuntimeError
-html/dart_object_local_storage_test: RuntimeError
-html/datalistelement_test: RuntimeError
-html/document_test: RuntimeError
-html/documentfragment_test: RuntimeError
-html/dom_constructors_test: RuntimeError
-html/domparser_test: RuntimeError
-html/element_add_test: RuntimeError
-html/element_animate_test: RuntimeError
-html/element_classes_svg_test: RuntimeError
-html/element_constructor_1_test: RuntimeError
-html/element_dimensions_test: RuntimeError
-html/element_offset_test: RuntimeError
-html/element_test: RuntimeError
-html/element_types_constructors1_test: RuntimeError
-html/element_types_constructors2_test: RuntimeError
-html/element_types_constructors3_test: RuntimeError
-html/element_types_constructors4_test: RuntimeError
-html/element_types_constructors5_test: RuntimeError
-html/element_types_constructors6_test: RuntimeError
-html/element_types_content_test: RuntimeError
-html/element_types_datalist_test: RuntimeError
-html/element_types_details_test: RuntimeError
-html/element_types_embed_test: RuntimeError
-html/element_types_keygen_test: RuntimeError
-html/element_types_meter_test: RuntimeError
-html/element_types_object_test: RuntimeError
-html/element_types_output_test: RuntimeError
-html/element_types_progress_test: RuntimeError
-html/element_types_shadow_test: RuntimeError
-html/element_types_template_test: RuntimeError
-html/element_types_track_test: RuntimeError
html/event_callback_test: Skip # Browser test
-html/event_customevent_test: RuntimeError
-html/event_test: RuntimeError
-html/events_test: RuntimeError
-html/exceptions_test: RuntimeError
-html/file_sample_test: RuntimeError
-html/fileapi_directory_reader_test: RuntimeError
-html/fileapi_directory_test: RuntimeError
-html/fileapi_entry_test: RuntimeError
-html/fileapi_file_entry_test: RuntimeError
-html/fileapi_file_test: RuntimeError
-html/fileapi_supported_test: RuntimeError
-html/fileapi_supported_throws_test: RuntimeError
-html/filereader_test: RuntimeError
-html/filteredelementlist_test: RuntimeError
-html/fontface_loaded_test: RuntimeError
-html/fontface_test: RuntimeError
-html/form_data_test: RuntimeError
-html/form_element_test: RuntimeError
-html/gamepad_test: RuntimeError
-html/geolocation_test: RuntimeError
-html/hidden_dom_1_test: RuntimeError
-html/hidden_dom_2_test: RuntimeError
-html/history_hash_change_test: RuntimeError
-html/history_history_test: RuntimeError
-html/history_test: RuntimeError
-html/html_mock_test: RuntimeError
-html/htmlcollection_test: RuntimeError
-html/htmlelement_test: RuntimeError
-html/htmloptionscollection_test: RuntimeError
-html/indexeddb_1_test: RuntimeError
-html/indexeddb_2_test: RuntimeError
-html/indexeddb_4_test: RuntimeError
-html/input_element_attributes_test: RuntimeError
-html/input_element_constructor_test: RuntimeError
-html/input_element_date_test: RuntimeError
-html/input_element_datetime_test: RuntimeError
-html/input_element_email_test: RuntimeError
-html/input_element_month_test: RuntimeError
-html/input_element_number_test: RuntimeError
-html/input_element_range_test: RuntimeError
-html/input_element_search_test: RuntimeError
-html/input_element_tel_test: RuntimeError
-html/input_element_time_test: RuntimeError
-html/input_element_url_test: RuntimeError
-html/input_element_week_test: RuntimeError
-html/instance_of_test: RuntimeError
-html/interactive_media_test: RuntimeError
-html/interactive_test: RuntimeError
-html/isolates_test: RuntimeError
-html/js_array_test: RuntimeError
-html/js_array_test: CompileTimeError
-html/js_browser_test: RuntimeError
-html/js_caching_test: RuntimeError
-html/js_context_test: RuntimeError
-html/js_dart_functions_test: RuntimeError
-html/js_dart_js_test: RuntimeError
-html/js_dart_to_string_test: RuntimeError
-html/js_dispatch_property_test: CompileTimeError
-html/js_dispatch_property_test: RuntimeError
-html/js_extend_class_test: RuntimeError
-html/js_function_getter_test: RuntimeError
-html/js_function_getter_trust_types_test: RuntimeError
-html/js_identity_test: RuntimeError
-html/js_interop_1_test: RuntimeError
-html/js_interop_constructor_name_div_test: RuntimeError
-html/js_interop_constructor_name_error1_test: RuntimeError
-html/js_interop_constructor_name_error2_test: RuntimeError
-html/js_interop_constructor_name_method_test: RuntimeError
-html/js_javascript_function_test: RuntimeError
-html/js_jsarray_test: RuntimeError
-html/js_jsfunc_callmethod_test: RuntimeError
-html/js_jsify_test: RuntimeError
-html/js_jsobject_test: RuntimeError
-html/js_methods_test: RuntimeError
-html/js_transferrables_test: RuntimeError
-html/js_typed_interop_bind_this_test: RuntimeError
-html/js_typed_interop_callable_object_test: RuntimeError
-html/js_typed_interop_default_arg_test/explicit_argument: CompileTimeError
-html/js_typed_interop_default_arg_test/none: RuntimeError
-html/js_typed_interop_dynamic_test: RuntimeError
-html/js_typed_interop_lazy_test/01: RuntimeError
-html/js_typed_interop_lazy_test/none: RuntimeError
-html/js_typed_interop_rename_static_test: RuntimeError
-html/js_typed_interop_test: CompileTimeError
-html/js_typed_interop_type1_test/01: RuntimeError
-html/js_typed_interop_type1_test/none: RuntimeError
-html/js_typed_interop_type3_test/01: RuntimeError
-html/js_typed_interop_type3_test/02: RuntimeError
-html/js_typed_interop_type3_test/none: RuntimeError
-html/js_typed_interop_type_test: RuntimeError
-html/js_typed_interop_window_property_test: RuntimeError
-html/js_util_test: RuntimeError
-html/keyboard_event_test: RuntimeError
-html/localstorage_test: RuntimeError
-html/location_test: RuntimeError
-html/media_stream_test: RuntimeError
-html/mediasource_test: RuntimeError
-html/message_channel_test: RuntimeError
-html/messageevent_test: RuntimeError
-html/mirrors_js_typed_interop_test: RuntimeError
-html/mouse_event_test: RuntimeError
-html/mutationobserver_test: RuntimeError
-html/native_gc_test: RuntimeError
-html/navigator_test: RuntimeError
-html/node_test: RuntimeError
-html/node_validator_important_if_you_suppress_make_the_bug_critical_test: RuntimeError
-html/notification_permission_test: RuntimeError
-html/notification_test: RuntimeError
-html/performance_api_test: RuntimeError
-html/postmessage_structured_test: RuntimeError
-html/private_extension_member_test: RuntimeError
-html/query_test: RuntimeError
-html/queryall_test: RuntimeError
-html/range_test: RuntimeError
-html/request_animation_frame_test: RuntimeError
-html/rtc_test: RuntimeError
-html/selectelement_test: RuntimeError
-html/serialized_script_value_test: RuntimeError
-html/shadow_dom_test: RuntimeError
-html/shadowroot_test: RuntimeError
-html/speechrecognition_test: RuntimeError
-html/storage_promise_test: RuntimeError
-html/storage_test: RuntimeError
-html/streams_test: RuntimeError
-html/svg_test: RuntimeError
-html/svgelement_test: RuntimeError
-html/table_test: RuntimeError
-html/text_event_test: RuntimeError
-html/touchevent_test: RuntimeError
-html/track_element_constructor_test: RuntimeError
-html/transferables_test: RuntimeError
-html/transition_event_test: RuntimeError
-html/trusted_html_tree_sanitizer_test: RuntimeError
-html/typed_arrays_1_test: RuntimeError
-html/typed_arrays_2_test: RuntimeError
-html/typed_arrays_3_test: RuntimeError
-html/typed_arrays_4_test: RuntimeError
-html/typed_arrays_5_test: RuntimeError
-html/typed_arrays_arraybuffer_test: RuntimeError
-html/typed_arrays_dataview_test: RuntimeError
-html/typed_arrays_range_checks_test: RuntimeError
-html/typed_arrays_simd_test: RuntimeError
-html/typing_test: RuntimeError
-html/unknownelement_test: RuntimeError
-html/uri_test: RuntimeError
-html/url_test: RuntimeError
-html/webgl_1_test: RuntimeError
-html/webgl_extensions_test: RuntimeError
-html/websocket_test: RuntimeError
-html/websql_test: RuntimeError
-html/wheelevent_test: RuntimeError
-html/window_eq_test: RuntimeError
-html/window_mangling_test: RuntimeError
-html/window_nosuchmethod_test: RuntimeError
-html/window_test: RuntimeError
-html/worker_api_test: RuntimeError
-html/worker_test: RuntimeError
-html/xhr_cross_origin_test: RuntimeError
-html/xhr_test: RuntimeError
-html/xsltprocessor_test: RuntimeError
-js/null_test: RuntimeError
-js/prototype_access_test: RuntimeError
-
-[ $compiler == dart2js && $runtime == d8 && $minified ]
-collection/list_test: RuntimeError
[ $compiler == dart2js && $runtime != d8 ]
html/html_mock_test: RuntimeError # Issue 31038
-html/input_element_attributes_test: RuntimeError
-html/js_extend_class_test: RuntimeError
[ $compiler == dart2js && $runtime == ff ]
async/slow_consumer2_test: SkipSlow # Times out. Issue 22050
convert/streamed_conversion_json_utf8_decode_test: SkipSlow # Times out. Issue 22050
convert/streamed_conversion_json_utf8_encode_test: SkipSlow # Times out. Issue 22050
convert/streamed_conversion_utf8_decode_test: SkipSlow # Times out. Issue 22050
-convert/utf85_test: Pass, Slow, Timeout
+convert/utf85_test: Slow
html/callback_list_test: SkipByDesign # FileSystem not supported in FireFox.
html/custom/attribute_changed_callback_test: Skip # Times out
-html/custom/constructor_calls_created_synchronously_test: Pass, Timeout
html/custom/created_callback_test: Skip # Times out
html/custom/document_register_basic_test: Skip # Times out, or unittest times out
html/dart_object_local_storage_test: Skip # sessionStorage NS_ERROR_DOM_NOT_SUPPORTED_ERR
html/element_animate_test/timing_dict: RuntimeError # Issue 26730
html/element_types_content_test: Pass, RuntimeError # Issues 28983, 29922
-html/element_types_keygen_test: Fail
html/element_types_keygen_test: RuntimeError # Issue 29922
html/element_types_shadow_test: Pass, RuntimeError # Issues 28983, 29922
html/file_sample_test: Skip # FileSystem not supported on FireFox.
html/fileapi_supported_test: Skip # FileSystem not supported on FireFox.
html/fileapi_supported_throws_test: Skip # FileSystem not supported on FireFox.
html/fontface_test: Fail # Fontface not supported on ff
-html/gamepad_test: RuntimeError
html/history_test/history: Skip # Issue 22050
-html/input_element_datetime_test: Fail
-html/input_element_month_test: Fail
-html/input_element_week_test: Fail
html/interactive_media_test: RuntimeError # Not supported in FF
-html/media_stream_test: Fail
html/messageevent_test: Pass, RuntimeError # Issue 28983
html/request_animation_frame_test: Skip # Async test hangs.
html/serialized_script_value_test: Pass, RuntimeError # Issue 28983
-html/shadow_dom_test: Fail
html/speechrecognition_test: RuntimeError # Please triage.
html/text_event_test: Fail # Issue 17893
html/webgl_1_test: Pass, Fail # Issue 8219
@@ -366,8 +103,6 @@
html/element_types_shadow_test: RuntimeError # Issue 29922
html/element_types_template_test: RuntimeError # Issue 29922
html/element_types_track_test: RuntimeError # Issue 29922
-math/math2_test: RuntimeError
-math/math_test: RuntimeError
[ $compiler == dart2js && $runtime == jsshell ]
async/catch_errors12_test: Fail # Timer interface not supported: Issue 7728.
@@ -388,7 +123,6 @@
async/periodic_timer4_test: Fail # Timer interface not supported: Issue 7728.
async/run_zoned7_test: RuntimeError # Timer interface not supported: Issue 7728.
async/run_zoned8_test: Fail # Timer interface not supported: Issue 7728.
-async/schedule_microtask3_test: RuntimeError
async/schedule_microtask_test: Fail # Preamble file does not correctly implement scheduleImmediate.
async/slow_consumer2_test: RuntimeError # Timer interface not supported; Issue 7728.
async/slow_consumer3_test: RuntimeError # Timer interface not supported; Issue 7728.
@@ -418,22 +152,9 @@
async/zone_create_timer2_test: RuntimeError # Timer interface not supported: Issue 7728.
async/zone_empty_description2_test: RuntimeError # Timer interface not supported: Issue 7728.
-[ $compiler == dart2js && $runtime != jsshell ]
-async/timer_not_available_test: RuntimeError
-
[ $compiler == dart2js && $runtime == safari ]
-html/audiobuffersourcenode_test: RuntimeError
-html/audiobuffersourcenode_test: Pass, RuntimeError
html/callback_list_test: SkipByDesign # FileSystem not supported in Safari.
-html/canvasrenderingcontext2d_test/arc: Pass, RuntimeError
-html/canvasrenderingcontext2d_test/drawImage_canvas_element: Pass, RuntimeError
-html/canvasrenderingcontext2d_test/drawImage_image_element: Pass, RuntimeError
-html/canvasrenderingcontext2d_test/fillText: Pass, RuntimeError
html/css_test/functional/functional: RuntimeError # Issue 32576
-html/custom/attribute_changed_callback_test: RuntimeError, Timeout
-html/custom/constructor_calls_created_synchronously_test: Pass, Timeout
-html/custom/created_callback_test: Pass, Timeout
-html/custom/document_register_basic_test: Pass, Timeout
html/element_types_content_test: RuntimeError # Issue 29922
html/element_types_datalist_test: RuntimeError # Issue 29922
html/element_types_shadow_test: RuntimeError # Issue 29922
@@ -442,22 +163,12 @@
html/interactive_media_test: SkipSlow
html/notification_test: Pass, RuntimeError # Safari doesn't let us access the fields of the Notification to verify them.
html/storage_promise_test: RuntimeError # Not supported on Safari
-html/xhr_test: RuntimeError
[ $compiler == dart2js && $system == linux ]
html/interactive_geolocation_test: Skip # Requires allowing geo location.
-[ $compiler == dart2js && $system == windows ]
-html/xhr_test: RuntimeError
-
[ $compiler == dart2js && $browser ]
-html/custom/created_callback_test: RuntimeError
-html/element_classes_svg_test: RuntimeError
-html/js_array_test: RuntimeError
-html/js_typed_interop_lazy_test/01: RuntimeError
html/notification_permission_test: Timeout, Pass # Issue 32002
-html/private_extension_member_test: RuntimeError
-html/typed_arrays_range_checks_test: RuntimeError
js/null_test: RuntimeError # Issue 30652
[ $compiler == dart2js && $browser && $csp ]
@@ -465,13 +176,9 @@
html/custom/js_custom_test: Fail # Issue 14643
[ $compiler == dart2js && $checked ]
-async/stream_listen_zone_test: RuntimeError
convert/utf85_test: Pass, Slow # Issue 12029.
html/js_function_getter_trust_types_test: Skip # --trust-type-annotations incompatible with --checked
-[ $compiler == dart2js && $csp && $minified ]
-collection/list_test: RuntimeError
-
[ $compiler == dart2js && $csp && ($runtime == chrome || $runtime == chromeOnAndroid || $runtime == ff || $runtime == safari) ]
html/event_customevent_test: SkipByDesign
html/js_array_test: SkipByDesign
@@ -492,14 +199,9 @@
html/postmessage_structured_test: SkipByDesign
[ $compiler == dart2js && !$csp && $minified ]
-html/async_test: RuntimeError
html/audiobuffersourcenode_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
html/audiocontext_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/audioelement_test: RuntimeError
-html/b_element_test: RuntimeError
-html/blob_constructor_test: RuntimeError
html/cache_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/callbacks_test: RuntimeError
html/custom_element_method_clash_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
html/custom_element_name_clash_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
html/custom_elements_23127_test: Crash # Assertion failure: Cannot find value local(B2T.created#a) in (type_variable_local(B2T.T), local(C2T.created#a), local(C2T.created#b), local(C2T.created#c), BoxLocal(_box_0)) for j:constructor(C2T.created).
@@ -516,18 +218,6 @@
html/element_dimensions_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
html/element_offset_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
html/element_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/element_test/_ElementList: RuntimeError
-html/element_test/attributes: RuntimeError
-html/element_test/children: RuntimeError
-html/element_test/click: RuntimeError
-html/element_test/constructors: RuntimeError
-html/element_test/eventDelegation: RuntimeError
-html/element_test/eventListening: RuntimeError
-html/element_test/functional: RuntimeError
-html/element_test/matches: RuntimeError
-html/element_test/position: RuntimeError
-html/element_test/queryAll: RuntimeError
-html/element_types_constructors1_test: RuntimeError
html/element_types_constructors2_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
html/element_types_constructors3_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
html/element_types_constructors4_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
@@ -544,191 +234,57 @@
html/element_types_shadow_test: RuntimeError # Issue 29922
html/element_types_template_test: RuntimeError # Issue 29922
html/element_types_track_test: RuntimeError # Issue 29922
-html/event_test: RuntimeError
-html/exceptions_test: RuntimeError
-html/fileapi_supported_test: RuntimeError
-html/filereader_test: RuntimeError
-html/filteredelementlist_test: RuntimeError
-html/fontface_test: RuntimeError
html/form_data_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/form_data_test/functional: RuntimeError
-html/form_data_test/supported: RuntimeError
-html/form_element_test: RuntimeError
-html/gamepad_test: RuntimeError
-html/geolocation_test: RuntimeError
-html/hidden_dom_1_test: RuntimeError
-html/hidden_dom_2_test: RuntimeError
html/history_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/history_test/history: RuntimeError
-html/history_test/supported_HashChangeEvent: RuntimeError
-html/history_test/supported_state: RuntimeError
-html/htmlcollection_test: RuntimeError
-html/htmlelement_test: RuntimeError
-html/htmloptionscollection_test: RuntimeError
html/indexeddb_1_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/indexeddb_1_test/dynamic: RuntimeError
-html/indexeddb_1_test/supported: RuntimeError
-html/indexeddb_1_test/typed: RuntimeError
-html/input_element_constructor_test: RuntimeError
-html/input_element_date_test: RuntimeError
-html/input_element_datetime_test: RuntimeError
-html/input_element_email_test: RuntimeError
-html/input_element_month_test: RuntimeError
-html/input_element_number_test: RuntimeError
-html/input_element_range_test: RuntimeError
-html/input_element_search_test: RuntimeError
-html/input_element_tel_test: RuntimeError
-html/input_element_time_test: RuntimeError
-html/input_element_url_test: RuntimeError
-html/input_element_week_test: RuntimeError
-html/instance_of_test: RuntimeError
-html/isolates_test: RuntimeError
-html/js_dispatch_property_test: RuntimeError
-html/js_javascript_function_test: RuntimeError
html/keyboard_event_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/localstorage_test: RuntimeError
-html/location_test: RuntimeError
html/mediasource_test: RuntimeError, Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/mouse_event_test: RuntimeError
html/mutationobserver_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/native_gc_test: RuntimeError
-html/navigator_test: RuntimeError
html/node_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
html/node_validator_important_if_you_suppress_make_the_bug_critical_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
html/notification_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
html/performance_api_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/query_test: RuntimeError
-html/queryall_test: RuntimeError
html/range_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
html/request_animation_frame_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
html/rtc_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/selectelement_test: RuntimeError
html/shadow_dom_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/shadowroot_test: RuntimeError
-html/storage_test: RuntimeError
-html/streams_test: RuntimeError
html/svg_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
html/svgelement_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/table_test: RuntimeError
-html/text_event_test: RuntimeError
-html/track_element_constructor_test: RuntimeError
-html/transferables_test: RuntimeError
html/transition_event_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
html/trusted_html_tree_sanitizer_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
html/typed_arrays_1_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/typed_arrays_2_test: RuntimeError
-html/typed_arrays_3_test: RuntimeError
-html/typed_arrays_4_test: RuntimeError
-html/typed_arrays_5_test: RuntimeError
-html/typed_arrays_arraybuffer_test: RuntimeError
-html/typed_arrays_dataview_test: RuntimeError
-html/typed_arrays_range_checks_test: RuntimeError
-html/typed_arrays_simd_test: RuntimeError
-html/typing_test: RuntimeError
-html/unknownelement_test: RuntimeError
-html/uri_test: RuntimeError
-html/url_test: RuntimeError
html/webgl_extensions_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
html/websocket_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
html/websql_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/wheelevent_test: RuntimeError
-html/window_eq_test: RuntimeError
-html/window_mangling_test: RuntimeError
-html/window_nosuchmethod_test: RuntimeError
[ $compiler == dart2js && $host_checked ]
html/custom/mirrors_2_test: Crash # 'file:*/pkg/compiler/lib/src/common_elements.dart': Failed assertion: line 405 pos 12: 'element.name == '=='': is not true.
html/custom/mirrors_test: Crash # 'file:*/pkg/compiler/lib/src/common_elements.dart': Failed assertion: line 405 pos 12: 'element.name == '=='': is not true.
html/indexeddb_3_test: Crash # 'file:*/pkg/compiler/lib/src/common_elements.dart': Failed assertion: line 405 pos 12: 'element.name == '=='': is not true.
html/indexeddb_5_test: Crash # 'file:*/pkg/compiler/lib/src/common_elements.dart': Failed assertion: line 405 pos 12: 'element.name == '=='': is not true.
-html/js_array_test: CompileTimeError
-html/js_dispatch_property_test: CompileTimeError
html/js_function_getter_test/call getter as function: Crash # FileSystemException(uri=file:///usr/local/google/home/efortuna/dart2/sdk/sdk/lib/_internal/dart2js_platform.dill; message=Error reading 'sdk/lib/_internal/dart2js_platform.dill' (No such file or directory))
-html/js_function_getter_trust_types_test: CompileTimeError
-html/js_typed_interop_default_arg_test/explicit_argument: CompileTimeError
html/js_typed_interop_side_cast_exp_test: Crash # 'file:*/pkg/compiler/lib/src/common_elements.dart': Failed assertion: line 405 pos 12: 'element.name == '=='': is not true.
-html/js_typed_interop_test: CompileTimeError
[ $compiler == dart2js && $ie ]
html/fontface_loaded_test: RuntimeError # FontFace polyfill?
html/fontface_test: Fail # Fontface not supported on ie
-html/interactive_media_test: RuntimeError
[ $compiler == dart2js && $minified ]
-html/audiobuffersourcenode_test/functional: RuntimeError
-html/audiobuffersourcenode_test/supported: RuntimeError
-html/audiocontext_test/supported: RuntimeError
-html/cache_test/ApplicationCache: RuntimeError
-html/cache_test/supported: RuntimeError
html/canvas_pixel_array_type_alias_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/canvas_pixel_array_type_alias_test/basic: RuntimeError
-html/canvas_pixel_array_type_alias_test/typed_data: RuntimeError
-html/canvas_pixel_array_type_alias_test/types1: RuntimeError
-html/canvas_pixel_array_type_alias_test/types2: RuntimeError
html/canvas_pixel_array_type_alias_test/types2_runtimeTypeName: Fail, OK # Issue 12605
html/custom/mirrors_2_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
html/custom/mirrors_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
html/custom_elements_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
html/element_classes_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/element_offset_test/offset: RuntimeError
-html/element_test/ElementList: RuntimeError
-html/element_types_constructors2_test/constructors: RuntimeError
-html/element_types_constructors3_test/constructors: RuntimeError
-html/element_types_constructors4_test/constructors: RuntimeError
-html/element_types_constructors5_test/constructors: RuntimeError
-html/element_types_constructors6_test/constructors: RuntimeError
-html/element_types_constructors6_test/ul: RuntimeError
html/element_types_keygen_test: RuntimeError # Issue 29922
-html/event_customevent_test: RuntimeError
-html/file_sample_test: RuntimeError
-html/fileapi_entry_test: RuntimeError
-html/indexeddb_1_test/functional: RuntimeError
-html/indexeddb_2_test: RuntimeError
-html/indexeddb_3_test: RuntimeError
-html/indexeddb_4_test: RuntimeError
-html/indexeddb_5_test: RuntimeError
-html/js_array_test: RuntimeError
-html/js_browser_test: RuntimeError
-html/js_caching_test: RuntimeError
-html/js_context_test: RuntimeError
-html/js_dart_functions_tests: RuntimeError
-html/js_dart_js_test: RuntimeError
-html/js_dart_to_string_test: RuntimeError
-html/js_function_getter_test: CompileTimeError
-html/js_function_getter_test/call getter as function: RuntimeError
html/js_function_getter_trust_types_test: Crash # NoSuchMethodError: Class 'InterfaceType' has no instance getter 'isObject'.
-html/js_function_getter_trust_types_test: CompileTimeError
-html/js_identity_test: RuntimeError
-html/js_interop_1_test: RuntimeError
-html/js_interop_constructor_name_div_test: RuntimeError
-html/js_interop_constructor_name_method_test: RuntimeError
-html/js_jsarray_test: RuntimeError
-html/js_jsfunc_callmethod_test: RuntimeError
-html/js_jsify_test: RuntimeError
-html/js_jsobject_test: RuntimeError
-html/js_transferrables_test: RuntimeError
html/js_typed_interop_bind_this_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/js_typed_interop_callable_object_test: CompileTimeError
-html/js_typed_interop_default_arg_test/explicit_argument: CompileTimeError
-html/js_typed_interop_default_arg_test/none: CompileTimeError
html/js_typed_interop_side_cast_exp_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/js_typed_interop_test: CompileTimeError
-html/js_typed_interop_type1_test/01: RuntimeError
-html/js_typed_interop_type1_test/none: RuntimeError
-html/js_typed_interop_type3_test/01: RuntimeError
-html/js_typed_interop_type3_test/02: RuntimeError
-html/js_typed_interop_type3_test/none: RuntimeError
-html/js_typed_interop_type_test: RuntimeError
html/js_typed_interop_window_property_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
html/js_util_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
html/media_stream_test: RuntimeError, Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/mirrors_js_typed_interop_test: RuntimeError
html/postmessage_structured_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
html/speechrecognition_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
-html/trusted_html_tree_sanitizer_test/not_create_document_fragment: RuntimeError
-html/trusted_html_tree_sanitizer_test/untrusted: RuntimeError
-html/typed_arrays_1_test/arrays: RuntimeError
-html/typed_arrays_1_test/supported: RuntimeError
html/webgl_1_test: Crash # NoSuchMethodError: Class 'JMethod' has no instance getter 'implementation'.
[ $compiler == dart2js && ($runtime == chrome || $runtime == ff) ]
diff --git a/tests/lib_2/lib_2_dartdevc.status b/tests/lib_2/lib_2_dartdevc.status
index dd4bbaa..b3c2a53 100644
--- a/tests/lib_2/lib_2_dartdevc.status
+++ b/tests/lib_2/lib_2_dartdevc.status
@@ -3,48 +3,28 @@
# BSD-style license that can be found in the LICENSE file.
[ $compiler == dartdevc ]
-html/element_types_keygen_test: CompileTimeError # Chrome 57 keygen removed
-html/mediasource_test: RuntimeError # Issue 29922
-html/xhr_test: Pass, Slow
-
-[ $compiler == dartdevk ]
-async/slow_consumer_test: CompileTimeError
+html/xhr_test: Slow
[ $runtime == chrome && ($compiler == dartdevc || $compiler == dartdevk) ]
-html/element_animate_test/timing_dict: RuntimeError # Issue 29922
-html/element_types_keygen_test: CompileTimeError # Issue 29055
html/js_dispatch_property_test: Skip # Timeout Issue 31030
[ $system == linux && ($compiler == dartdevc || $compiler == dartdevk) ]
html/interactive_geolocation_test: Skip # Requires allowing geo location.
[ $system == macos && ($compiler == dartdevc || $compiler == dartdevk) ]
-html/client_rect_test: Pass, RuntimeError # Issue 31019
-html/css_test: Pass, RuntimeError # Issue 31019
-html/fileapi_entry_test: Pass, RuntimeError # Issue 31019
html/interactive_media_test: Skip # Requires interactive camera, microphone permissions.
[ $system == windows && ($compiler == dartdevc || $compiler == dartdevk) ]
html/xhr_test: Skip # Times out. Issue 21527
[ $compiler == dartdevc || $compiler == dartdevk ]
-async/future_or_bad_type_test/implements: RuntimeError # Issue 29922
-async/future_or_bad_type_test/none: RuntimeError # Issue 29922
-async/future_test: RuntimeError # Issue 29922
-async/slow_consumer_test: Pass, Timeout # Issue 29922
-async/stream_distinct_test: RuntimeError # Issue 29922
-async/timer_not_available_test: RuntimeError
-convert/base64_test/01: Fail, OK # Uses bit-wise operations to detect invalid values. Some large invalid values accepted by DDC/dart2js.
-convert/chunked_conversion_utf88_test: Slow, Pass
-convert/json_utf8_chunk_test: Slow, Pass
-convert/streamed_conversion_json_utf8_encode_test: Pass, Timeout # Issue 29922
-convert/streamed_conversion_utf8_decode_test: Slow, Pass, Timeout # Issue 29922
-convert/utf85_test: Slow, Pass
-html/async_test: RuntimeError # Issue 29922
+convert/chunked_conversion_utf88_test: Slow
+convert/json_utf8_chunk_test: Slow
+convert/streamed_conversion_utf8_decode_test: Slow # Issue 29922
+convert/utf85_test: Slow
html/callback_list_test: Skip # Test requires user interaction to accept permissions.
html/custom/attribute_changed_callback_test: Skip # Issue 31577
html/custom/constructor_calls_created_synchronously_test: Skip # Issue 31577
-html/custom/created_callback_test: RuntimeError
html/custom/created_callback_test: Skip # Issue 31577
html/custom/document_register_basic_test: Skip # Issue 31577
html/custom/document_register_template_test: Skip # Issue 31577
@@ -58,45 +38,12 @@
html/custom/document_register_type_extensions_test/single-parameter createElement: Skip # Issue 31577
html/custom/element_upgrade_test: Skip # Issue 31577
html/custom/entered_left_view_test: Skip # Issue 31577
-html/custom/js_custom_test: Crash # Issue 29922
html/custom/mirrors_2_test: Skip # Issue 31577
-html/custom/mirrors_test: Crash # Issue 29922
-html/custom/regress_194523002_test: Crash # Issue 29922
html/custom_element_method_clash_test: Skip # Issue 29922
html/custom_element_name_clash_test: Skip # Issue 29922
html/custom_elements_23127_test: Skip # Issue 29922
html/custom_elements_test: Skip # Issue 29922
-html/element_classes_test: RuntimeError # Issue 29922
-html/isolates_test: RuntimeError # Issue 29922
-html/js_typed_interop_default_arg_test/default_value: MissingCompileTimeError # Issue 29922
-html/js_typed_interop_side_cast_exp_test/01: RuntimeError # Requires --experimental-trust-js-interop-type-annotations flag.
-html/js_typed_interop_type3_test/*: RuntimeError # Issue 30947
-html/js_typed_interop_type_test: RuntimeError # Issue 30947
-html/js_util_test: RuntimeError # Issue 29922
-html/media_stream_test: RuntimeError # Issue 29922
html/notification_permission_test: Skip # Issue 32002
-html/transition_event_test: Pass, RuntimeError, Timeout # Issue 29922, this test seems flaky
-html/webgl_extensions_test: RuntimeError # Issue 31017
-html/worker_api_test: RuntimeError # Issue 29922
isolate/*: SkipByDesign # No support for dart:isolate in dart4web (http://dartbug.com/30538)
-js/null_test: RuntimeError # Issue 30652
-math/double_pow_test: RuntimeError # Issue 29922
-math/double_pow_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-math/random_big_test: RuntimeError # Issue 29922
mirrors/*: SkipByDesign # Mirrors not supported on web in Dart 2.0.
-mirrors/private_types_test: RuntimeError # Issue 29922
-mirrors/reflect_runtime_type_test: RuntimeError # Issue 29922
-mirrors/reflect_uninstantiated_class_test: RuntimeError # Issue 29922
-mirrors/reflected_type_function_type_test: RuntimeError # Issue 29922
-mirrors/reflected_type_special_types_test: RuntimeError # Issue 29922
-mirrors/reflected_type_typedefs_test: RuntimeError # Issue 29922
-mirrors/reflected_type_typevars_test: RuntimeError # Issue 29922
-mirrors/regress_14304_test: RuntimeError # Issue 29922
profiler/metrics_num_test: Skip # Because of an int / double type test.
-typed_data/int32x4_arithmetic_test/int64: RuntimeError # Issue 29922
-typed_data/int32x4_arithmetic_test/int64: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-typed_data/int32x4_arithmetic_test/none: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-typed_data/int64_list_load_store_test: RuntimeError # Issue 29922
-typed_data/int64_list_load_store_test: CompileTimeError, OK # Error if web int literal cannot be represented exactly, see http://dartbug.com/33351
-typed_data/typed_data_hierarchy_int64_test: RuntimeError # Issue 29922
-typed_data/unmodifiable_typed_data_test: RuntimeError # Issue 10275
diff --git a/tests/lib_2/lib_2_kernel.status b/tests/lib_2/lib_2_kernel.status
index 531e3d4..23463b5 100644
--- a/tests/lib_2/lib_2_kernel.status
+++ b/tests/lib_2/lib_2_kernel.status
@@ -4,53 +4,31 @@
# Sections in this file should contain "$compiler == dartk" or
# "$compiler == dartkp".
-convert/streamed_conversion_json_utf8_decode_test: Pass, Slow # Uses --verify_before_gc --verify_after_gc --old_gen_growth_rate=1 flags
+convert/streamed_conversion_json_utf8_decode_test: Slow # Uses --verify_before_gc --verify_after_gc --old_gen_growth_rate=1 flags
isolate/ping_pause_test: Skip # Issue https://dartbug.com/37787
-[ $builder_tag == asan ]
-isolate/non_fatal_exception_in_timer_callback_test: Pass, Fail # Issue 34724
-mirrors/dynamic_load_test: Fail # Issue 32187
-
[ $compiler == dartkb ]
-convert/streamed_conversion_json_utf8_decode_test: Pass, Timeout # Please triage.
-isolate/isolate_complex_messages_test: Pass, Crash # runtime/vm/object.cc: 17395: error: expected: type_arguments.IsNull() || type_arguments.IsCanonical()
-isolate/mandel_isolate_test: Pass, Timeout # Please triage.
-isolate/spawn_uri_exported_main_test: Pass, RuntimeError # Please triage: Expect.fail('Isolate was not spawned successfully.')
-mirrors/library_uri_io_test: RuntimeError # Platform.script points to dill file.
+isolate/isolate_complex_messages_test: Crash # runtime/vm/object.cc: 17395: error: expected: type_arguments.IsNull() || type_arguments.IsCanonical()
[ $compiler == fasta ]
html/*: Skip # TODO(ahe): Make dart:html available.
js/*: Skip # TODO(ahe): Make dart:js available.
-[ $fasta ]
-async/future_or_type_test: CompileTimeError # Issue 34626
-mirrors/generic_f_bounded_mixin_application_test: CompileTimeError # Issue 34613
-mirrors/redirecting_factory_test/01: CompileTimeError # Issue 34714
-mirrors/redirecting_factory_test/none: CompileTimeError # Issue 34714
-
[ $arch == simdbc64 && $hot_reload_rollback ]
convert/streamed_conversion_json_utf8_decode_test: SkipSlow # Uses --verify_before_gc --verify_after_gc --old_gen_growth_rate=1 flags
-[ $arch == x64 && $builder_tag == asan && $compiler == dartk ]
-mirrors/dynamic_load_test: Fail # Memory leak (issue 34724)
-
[ $arch == x64 && $mode == debug && $runtime == vm && ($compiler == dartk || $compiler == dartkb) ]
mirrors/invocation_fuzz_test: Skip # Because it times out, issue 29439.
[ $arch == x64 && ($hot_reload || $hot_reload_rollback) ]
-convert/base64_test/01: Pass, Crash # http://dartbug.com/35948
-isolate/int32_length_overflow_test: Timeout # Issue 35733
-
-[ $builder_tag == obfuscated && $compiler == dartkp ]
-collection/list_test: RuntimeError # Issue 34911
+convert/base64_test/01: Crash # http://dartbug.com/35948
[ $builder_tag == optimization_counter_threshold && ($compiler == dartk || $compiler == dartkb) ]
-isolate/unresolved_ports_test: CompileTimeError, Pass, Timeout # Fails to compile on opt counter builder (#31838)
-mirrors/invocation_fuzz_test/emptyarray: Pass, Crash, RuntimeError # Flaky on vm-kernel-optcounter-threshold-linux-release-x64, bug #31838
-mirrors/invocation_fuzz_test/false: Pass, Crash, RuntimeError # Flaky on vm-kernel-optcounter-threshold-linux-release-x64, bug #31838
-mirrors/invocation_fuzz_test/none: Pass, Crash, RuntimeError # Flaky on vm-kernel-optcounter-threshold-linux-release-x64, bug #31838
-mirrors/invocation_fuzz_test/smi: Crash, RuntimeError, Fail, Pass # Crashes on opt counter builder (#31838)
-mirrors/invocation_fuzz_test/string: Pass, Crash, RuntimeError # Flaky on vm-kernel-optcounter-threshold-linux-release-x64, bug #31838
+mirrors/invocation_fuzz_test/emptyarray: Crash # Flaky on vm-kernel-optcounter-threshold-linux-release-x64, bug #31838
+mirrors/invocation_fuzz_test/false: Crash # Flaky on vm-kernel-optcounter-threshold-linux-release-x64, bug #31838
+mirrors/invocation_fuzz_test/none: Crash # Flaky on vm-kernel-optcounter-threshold-linux-release-x64, bug #31838
+mirrors/invocation_fuzz_test/smi: Crash # Crashes on opt counter builder (#31838)
+mirrors/invocation_fuzz_test/string: Crash # Flaky on vm-kernel-optcounter-threshold-linux-release-x64, bug #31838
[ $compiler == app_jitk && ($mode == product || $mode == release) ]
isolate/spawn_uri_nested_vm_test: Skip # Timeout, Issue 33385
@@ -60,7 +38,6 @@
# ===== dartkp + dart_precompiled status lines =====
[ $compiler == dartkp && $runtime == dart_precompiled ]
-async/slow_consumer2_test: RuntimeError # Issue 31402 (Invocation arguments)
html/*: SkipByDesign # dart:html not supported on VM.
isolate/deferred_in_isolate2_test: Skip # Times out. Deferred loading kernel issue 28335.
isolate/deferred_in_isolate_test: Skip # Times out. Deferred loading kernel issue 28335.
@@ -73,69 +50,24 @@
[ $mode == debug && $hot_reload_rollback && ($compiler == dartk || $compiler == dartkb) ]
isolate/message3_test/constList_identical: Skip # Timeout
-[ $runtime == vm && $checked && ($compiler == dartk || $compiler == dartkb) ]
-mirrors/redirecting_factory_different_type_test/none: RuntimeError # Issue 28424
-
# ===== dartk + vm status lines =====
[ $runtime == vm && ($compiler == dartk || $compiler == dartkb) ]
-async/slow_consumer2_test: CompileTimeError # Issue 31402 (Invocation arguments)
html/*: SkipByDesign # dart:html not supported on VM.
isolate/deferred_in_isolate2_test: Skip # Times out. Deferred loading kernel issue 28335.
isolate/deferred_in_isolate_test: Skip # Times out. Deferred loading kernel issue 28335.
isolate/issue_21398_parent_isolate2_test/01: Skip # Times out. Deferred loading kernel issue 28335.
isolate/static_function_test: Skip # Times out. Issue 31855. CompileTimeError. Issue 31402
-mirrors/class_declarations_test/01: RuntimeError # Issue 31402 (Invocation arguments)
-mirrors/class_declarations_test/none: RuntimeError # Issue 31402 (Invocation arguments)
-mirrors/constructor_private_name_test: RuntimeError # Issue 33345 - Incorrect qualified symbol literal from kernel reader
-mirrors/constructors_test: CompileTimeError # Issue 31402 (Invocation arguments)
-mirrors/dart2js_mirrors_test: RuntimeError # 31916
-mirrors/enum_test: RuntimeError # Issue 31402 (Invocation arguments)
mirrors/invocation_fuzz_test: Crash
-mirrors/library_declarations_test/none: RuntimeError # Issue 31402 (Invocation arguments)
-mirrors/library_exports_hidden_test: RuntimeError # Issue 33098
-mirrors/library_exports_shown_test: RuntimeError # Issue 33098
-mirrors/library_import_deferred_loading_test: RuntimeError # Issue 33098
-mirrors/library_imports_deferred_test: RuntimeError # Issue 33098
-mirrors/library_imports_hidden_test: RuntimeError # Issue 33098
-mirrors/library_imports_metadata_test: RuntimeError # Issue 33098
-mirrors/library_imports_prefixed_show_hide_test: RuntimeError # Issue 33098
-mirrors/library_imports_prefixed_test: RuntimeError # Issue 33098
-mirrors/library_imports_shown_test: RuntimeError # Issue 33098
mirrors/metadata_allowed_values_test/16: Skip # Flaky, crashes.
-mirrors/method_mirror_source_line_ending_test: RuntimeError # Issue 33478
-mirrors/method_mirror_source_test: RuntimeError # Issue 33041
-mirrors/mirrors_nsm_mismatch_test: CompileTimeError # Issue 31533
-mirrors/mirrors_nsm_test/dart2js: CompileTimeError # Issue 31533
-mirrors/mirrors_nsm_test/none: CompileTimeError # Issue 31533
mirrors/mirrors_used*: SkipByDesign # Invalid tests. MirrorsUsed does not have a specification, and dart:mirrors is not required to hide declarations that are not covered by any MirrorsUsed annotation.
-mirrors/mixin_application_test: RuntimeError # Issue 31402 (Invocation arguments)
-mirrors/mixin_members_test: CompileTimeError # Issue 31402 (Invocation arguments)
mirrors/native_class_test: SkipByDesign # Imports dart:html
-mirrors/operator_test: CompileTimeError # Issue 31402 (Invocation arguments)
-mirrors/other_declarations_location_test: RuntimeError # Issue 33325 (no source positions for type parameters).
-mirrors/parameter_of_mixin_app_constructor_test: RuntimeError # Issue 31402 (Invocation arguments)
-mirrors/private_symbol_test: RuntimeError # Issue 33326 - CFE/kernel invalid typedef substitution
-mirrors/private_types_test: RuntimeError # Issue 33326 - CFE/kernel invalid typedef substitution
-mirrors/repeated_private_anon_mixin_app_test: RuntimeError # Mangled mixin application class name
-mirrors/static_members_easier_test: RuntimeError # Issue 31402 (Invocation arguments)
-mirrors/static_members_test: RuntimeError # Issue 31402 (Invocation arguments)
-mirrors/symbol_validation_test/01: RuntimeError # Issue 31537
-mirrors/symbol_validation_test/none: RuntimeError # Issue 31537
-mirrors/typedef_deferred_library_test: CompileTimeError # Deferred loading kernel issue 28335.
[ $hot_reload_rollback && ($compiler == dartk || $compiler == dartkb) ]
isolate/illegal_msg_function_test: Skip # Timeout
isolate/pause_test: Skip # Timeout
-# Enabling of dartk for sim{arm,arm64,dbc64} revealed these test failures, which
-# are to be triaged. Isolate tests are skipped on purpose due to the usage of
-# batch mode.
-[ ($arch == simarm || $arch == simarm64 || $arch == simdbc64) && ($compiler == dartk || $compiler == dartkb) ]
-mirrors/library_uri_io_test: RuntimeError # Please triage.
-
[ ($compiler == dartk || $compiler == dartkb) && ($hot_reload || $hot_reload_rollback) ]
-isolate/mandel_isolate_test: Pass, Timeout, RuntimeError # Test can time out which results in runtime error
-isolate/message4_test: Pass, Timeout, Crash # Timeout and sporadic crash (issue 33824)
+isolate/message4_test: Crash # Timeout and sporadic crash (issue 33824)
mirrors/dynamic_load_test: Crash
mirrors/library_uri_io_test: Skip # Timeout
mirrors/library_uri_package_test: Skip # Timeout
@@ -144,8 +76,5 @@
html/*: SkipByDesign
js/*: SkipByDesign
-[ $compiler == dartk || $compiler == dartkb ]
-async/slow_consumer2_test: RuntimeError # Issue 31402 (Invocation arguments)
-
[ $hot_reload || $hot_reload_rollback ]
isolate/issue_6610_test: Skip # Sources are looked up on every reload request.
diff --git a/tests/lib_2/lib_2_vm.status b/tests/lib_2/lib_2_vm.status
index 869e7c8..305c371 100644
--- a/tests/lib_2/lib_2_vm.status
+++ b/tests/lib_2/lib_2_vm.status
@@ -79,9 +79,6 @@
mirrors/library_uri_io_test: RuntimeError
mirrors/library_uri_package_test: RuntimeError
-[ $runtime == vm && $no_preview_dart_2 ]
-async/async_no_await_zones_test: RuntimeError # not supported in Dart 1 mode.
-
[ $runtime == vm && ($arch == simarm || $arch == simarmv5te || $arch == simarmv6) ]
convert/utf85_test: Skip # Pass, Slow Issue 12644.
diff --git a/tests/lib_2/mirrors/regress_38035_test.dart b/tests/lib_2/mirrors/regress_38035_test.dart
new file mode 100644
index 0000000..4e6c25a
--- /dev/null
+++ b/tests/lib_2/mirrors/regress_38035_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2019, 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.
+
+// Regression test for https://github.com/dart-lang/sdk/issues/38035.
+//
+// Verifies that static tear-off has correct information about argument types.
+
+import 'package:expect/expect.dart';
+import 'dart:mirrors';
+
+class A {
+ static bool _defaultCheck([dynamic e]) => true;
+}
+
+main() {
+ Expect.equals('([dynamic]) -> dart.core.bool',
+ MirrorSystem.getName(reflect(A._defaultCheck).type.simpleName));
+}
diff --git a/tests/modular/extension_methods/def.dart b/tests/modular/extension_methods/def.dart
new file mode 100644
index 0000000..665da3d8
--- /dev/null
+++ b/tests/modular/extension_methods/def.dart
@@ -0,0 +1,55 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Class {
+ int field;
+
+ Class(this.field);
+}
+
+extension Extension on Class {
+ int method() => this.field;
+
+ int get property => this.field;
+
+ void set property(int value) {
+ this.field = value;
+ }
+
+ int _privateMethod() => this.field;
+
+ static int staticField = 87;
+
+ static int staticMethod() => staticField;
+
+ static int get staticProperty => staticField;
+
+ static void set staticProperty(int value) {
+ staticField = value;
+ }
+}
+
+extension /*UnnamedExtension*/ on Class {
+ int method() => this.field + 1;
+}
+
+extension _PrivateExtension on Class {
+ int method() => this.field + 2;
+}
+
+class GenericClass<T> {
+ T field;
+
+ GenericClass(this.field);
+}
+
+extension GenericExtension<T> on GenericClass<T> {
+ T method() => this.field;
+
+ T get property => this.field;
+
+ void set property(T value) {
+ this.field = value;
+ }
+}
\ No newline at end of file
diff --git a/tests/modular/extension_methods/main.dart b/tests/modular/extension_methods/main.dart
new file mode 100644
index 0000000..760cc85
--- /dev/null
+++ b/tests/modular/extension_methods/main.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+import 'def.dart';
+
+main() {
+ testExplicitAccess(new Class(42));
+ testImplicitAccess(new Class(87));
+ testStaticAccess();
+ testExplicitGenericAccess(new GenericClass<String>('foo'), 'bar');
+ testImplicitGenericAccess(new GenericClass<String>('baz'), 'boz');
+}
+
+testExplicitAccess(Class c) {
+ Expect.equals(c.field, Extension(c).method());
+ Expect.equals(c.field, Extension(c).property);
+ Expect.equals(123, Extension(c).property = 123);
+ var f = Extension(c).method;
+ Expect.equals(c.field, f());
+}
+
+testImplicitAccess(Class c) {
+ Expect.equals(c.field, c.method());
+ Expect.equals(c.field, c.property);
+ Expect.equals(123, c.property = 123);
+ var f = c.method;
+ Expect.equals(c.field, f());
+}
+
+testStaticAccess() {
+ Expect.equals(Extension.staticField, Extension.staticMethod());
+ Expect.equals(Extension.staticField, Extension.staticProperty);
+ Expect.equals(123, Extension.staticProperty = 123);
+}
+
+testExplicitGenericAccess<T>(GenericClass<T> c, T value) {
+ Expect.equals(c.field, GenericExtension<T>(c).method());
+ Expect.equals(c.field, GenericExtension<T>(c).property);
+ Expect.equals(value, GenericExtension<T>(c).property = value);
+ var f = GenericExtension<T>(c).method;
+ Expect.equals(c.field, f());
+}
+
+testImplicitGenericAccess<T>(GenericClass<T> c, T value) {
+ Expect.equals(c.field, c.method());
+ Expect.equals(c.field, c.property);
+ Expect.equals(value, c.property = value);
+ var f = c.method;
+ Expect.equals(c.field, f());
+}
diff --git a/tests/modular/extension_methods/modules.yaml b/tests/modular/extension_methods/modules.yaml
new file mode 100644
index 0000000..854c44f
--- /dev/null
+++ b/tests/modular/extension_methods/modules.yaml
@@ -0,0 +1,8 @@
+# Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+#
+dependencies:
+ main: [def, expect]
+flags:
+ - extension-methods
\ No newline at end of file
diff --git a/tests/standalone_2/fragmentation_typed_data_test.dart b/tests/standalone_2/fragmentation_typed_data_test.dart
index 470aaad..0d00fb2 100644
--- a/tests/standalone_2/fragmentation_typed_data_test.dart
+++ b/tests/standalone_2/fragmentation_typed_data_test.dart
@@ -13,12 +13,17 @@
// VMOptions=--concurrent_mark --use_compactor
// VMOptions=--concurrent_mark --use_compactor --force_evacuation
+import 'dart:io';
import 'dart:typed_data';
main() {
+ // We have less memory available on the Android testing devices, and if we
+ // allocate to much the kernel may summarily terminate us.
+ final double factor = Platform.isAndroid ? 0.5 : 1.0;
+
final List<List> arrays = [];
// Fill up heap with alternate large-small items.
- for (int i = 0; i < 500000; i++) {
+ for (int i = 0; i < 500000 * factor; i++) {
arrays.add(new Uint32List(260));
arrays.add(new Uint32List(1));
}
@@ -27,7 +32,7 @@
arrays[i] = null;
}
// Allocate a lot of large items which don't fit in the gaps created above.
- for (int i = 0; i < 600000; i++) {
+ for (int i = 0; i < 600000 * factor; i++) {
arrays.add(new Uint32List(300));
}
}
diff --git a/tests/standalone_2/io/file_system_watcher_test.dart b/tests/standalone_2/io/file_system_watcher_test.dart
index 492379a..14eb5f9 100644
--- a/tests/standalone_2/io/file_system_watcher_test.dart
+++ b/tests/standalone_2/io/file_system_watcher_test.dart
@@ -141,8 +141,7 @@
var watcher = dir.watch(events: 0);
asyncStart();
- var sub;
- sub = watcher.listen((event) {
+ watcher.listen((event) {
if (event is FileSystemDeleteEvent) {
Expect.isTrue(event.path == dir.path);
}
@@ -298,9 +297,8 @@
var watcher = dir2.watch();
asyncStart();
- var sub;
bool gotDelete = false;
- sub = watcher.listen((event) {
+ watcher.listen((event) {
if (event is FileSystemDeleteEvent) {
Expect.isTrue(event.path.endsWith('dir'));
gotDelete = true;
@@ -319,42 +317,56 @@
// happens in a very short period of time the modifying event will be missed before the
// stream listen has been set up and the watcher will hang forever.
// Bug: https://github.com/dart-lang/sdk/issues/37233
+ // Bug: https://github.com/dart-lang/sdk/issues/37909
asyncStart();
ReceivePort receivePort = ReceivePort();
- await Isolate.spawn(modifyFiles, receivePort.sendPort);
+ Completer<bool> exiting = Completer<bool>();
- await for (var object in receivePort) {
- if (object == 'end') {
- receivePort.close();
- break;
+ Directory dir;
+ Completer<bool> modificationEventReceived = Completer<bool>();
+
+ StreamSubscription receiverSubscription;
+ SendPort workerSendPort;
+ receiverSubscription = receivePort.listen((object) async {
+ if (object == 'modification_started') {
+ var watcher = dir.watch();
+ var subscription;
+ // Wait for event and check the type
+ subscription = watcher.listen((data) async {
+ if (data is FileSystemModifyEvent) {
+ Expect.isTrue(data.path.endsWith('file'));
+ await subscription.cancel();
+ modificationEventReceived.complete(true);
+ }
+ });
+ return;
}
- var sendPort = object[0];
- var path = object[1];
- var dir = new Directory(path);
+ if (object == 'end') {
+ await receiverSubscription.cancel();
+ exiting.complete(true);
+ return;
+ }
+ // init event
+ workerSendPort = object[0];
+ dir = new Directory(object[1]);
+ });
- sendPort.send('start');
- // Delay some time to ensure that watcher is created when modification is running consistently.
- await Future.delayed(Duration(milliseconds: 10));
- var watcher = dir.watch();
- var subscription;
+ Completer<bool> workerExitedCompleter = Completer();
+ RawReceivePort exitReceivePort = RawReceivePort((object) { workerExitedCompleter.complete(true); });
+ RawReceivePort errorReceivePort = RawReceivePort((object) { print('worker errored: $object'); });
+ await Isolate.spawn(modifyFiles, receivePort.sendPort, onExit: exitReceivePort.sendPort, onError: errorReceivePort.sendPort);
- // Wait for event and check the type
- subscription = watcher.listen((data) {
- if (data is FileSystemModifyEvent) {
- Expect.isTrue(data.path.endsWith('file'));
- subscription.cancel();
- }
- });
+ await modificationEventReceived.future;
+ workerSendPort.send('end');
- // Create a file to signal modifier isolate to stop modification and clean up temp directory.
- var file = new File(join(dir.path, 'EventReceived'));
- file.createSync();
- sendPort.send('end');
- }
+ await exiting.future;
+ await workerExitedCompleter.future;
+ exitReceivePort.close();
+ errorReceivePort.close();
asyncEnd();
}
-void modifyFiles(SendPort sendPort) {
+void modifyFiles(SendPort sendPort) async {
// Send sendPort back to listen for modification signal.
ReceivePort receivePort = ReceivePort();
var dir = Directory.systemTemp.createTempSync('dart_file_system_watcher');
@@ -362,25 +374,30 @@
// Create file within the directory and keep modifying.
var file = new File(join(dir.path, 'file'));
file.createSync();
+ bool done = false;
var subscription;
- sendPort.send([receivePort.sendPort, dir.path]);
- subscription = receivePort.listen((data) {
- if (data == 'end') {
- // Clean up the directory and files
- dir.deleteSync(recursive: true);
- sendPort.send('end');
- subscription.cancel();
- } else {
- // This signal file is created once watcher isolate receives the event.
- var signal = new File(join(dir.path, 'EventReceived'));
- while (!signal.existsSync()) {
- // Start modifying the file continuously before watcher start watching.
- for (int i = 0; i < 100; i++) {
- file.writeAsStringSync('a');
- }
- }
+ subscription = receivePort.listen((object) async {
+ if (object == 'end') {
+ await subscription.cancel();
+ done = true;
}
});
+ sendPort.send([receivePort.sendPort, dir.path]);
+ bool notificationSent = false;
+ while(!done) {
+ // Start modifying the file continuously before watcher start watching.
+ for (int i = 0; i < 100; i++) {
+ file.writeAsStringSync('a');
+ }
+ if (!notificationSent) {
+ sendPort.send('modification_started');
+ notificationSent = true;
+ }
+ await Future.delayed(Duration());
+ }
+ // Clean up the directory and files
+ dir.deleteSync(recursive: true);
+ sendPort.send('end');
}
void main() {
diff --git a/tests/standalone_2/io/http_linklocal_ipv6_test.dart b/tests/standalone_2/io/http_linklocal_ipv6_test.dart
new file mode 100644
index 0000000..ea4e54d
--- /dev/null
+++ b/tests/standalone_2/io/http_linklocal_ipv6_test.dart
@@ -0,0 +1,55 @@
+// Copyright (c) 2019, 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:async_helper/async_helper.dart';
+import 'package:expect/expect.dart';
+
+void main() {
+ // A virtual tun/tap interface should be created with following instrutctions:
+ // Create an interface with name [tap0],
+ // sudo ip tuntap add name [tap0] mode tap
+ // Assign an ipv6 address [fe80:1::1],
+ // sudo ip -6 addr add dev [tap0] [fe80:1::1] scope link nodad
+ // Check for virtual interface with ipv6 set,
+ // ip address show
+ asyncStart();
+ try {
+ // Make sure the address here is the same as what it shows in "ip address show"
+ var ipv6 = 'fe80:1::10%tap0';
+ HttpServer.bind(ipv6, 0).then((server) {
+ server.listen((request) {
+ var timer = new Timer.periodic(const Duration(milliseconds: 0), (_) {
+ request.response
+ .write('data:${new DateTime.now().millisecondsSinceEpoch}\n\n');
+ });
+ request.response.done.whenComplete(() {
+ timer.cancel();
+ }).catchError((_) {});
+ });
+
+ var client = new HttpClient();
+ client
+ .getUrl(Uri.parse("http://[${ipv6}]:${server.port}"))
+ .then((request) => request.close())
+ .then((response) {
+ print(
+ 'reponse: status code: ${response.statusCode}, reason: ${response.reasonPhrase}');
+ int bytes = 0;
+ response.listen((data) {
+ bytes += data.length;
+ if (bytes > 100) {
+ client.close(force: true);
+ }
+ }, onError: (error) {
+ server.close();
+ });
+ });
+ asyncEnd();
+ });
+ } catch (e) {
+ Expect.fail('SocketException: $e');
+ asyncEnd();
+ }
+}
diff --git a/tests/standalone_2/standalone_2.status b/tests/standalone_2/standalone_2.status
index 6754a30..7f28264 100644
--- a/tests/standalone_2/standalone_2.status
+++ b/tests/standalone_2/standalone_2.status
@@ -5,6 +5,7 @@
# Tests using the multitest feature where failure is expected should *also* be
# listed in tests/lib/analyzer/analyze_tests.status without the "standalone"
# prefix.
+io/http_linklocal_ipv6_test: SkipByDesign # This needs manual test.
io/non_utf8_directory_test: Skip # Issue 33519. Temp files causing bots to go purple.
io/non_utf8_file_test: Skip # Issue 33519. Temp files causing bots to go purple.
io/non_utf8_link_test: Skip # Issue 33519. Temp files causing bots to go purple.
@@ -93,9 +94,6 @@
io/socket_connect_stream_data_close_cancel_test: Pass, Timeout # Issue 27453
io/socket_many_connections_test: Skip # This test fails with "Too many open files" on the Mac OS buildbot. This is expected as MacOS by default runs with a very low number of allowed open files ('ulimit -n' says something like 256).
-[ !$preview_dart_2 && ($runtime == dart_precompiled || $runtime == vm) ]
-*: SkipByDesign # Deprecating all Dart1 modes of execution
-
[ $arch == arm || $arch == arm64 || $runtime != vm || $mode == debug && $system == windows ]
fragmentation_test: Skip
diff --git a/tests/standalone_2/standalone_2_analyzer.status b/tests/standalone_2/standalone_2_analyzer.status
index df9b617..fa699b4 100644
--- a/tests/standalone_2/standalone_2_analyzer.status
+++ b/tests/standalone_2/standalone_2_analyzer.status
@@ -5,11 +5,4 @@
[ $compiler == dart2analyzer ]
deferred_transitive_import_error_test: Skip # Contains intentional errors.
io/process_exit_negative_test: Skip
-package/scenarios/invalid/invalid_package_name_test: Crash, OK # Analyzer exits on invalid package config
-package/scenarios/invalid/invalid_utf8_test: Crash, OK # Analyzer exits on invalid package config
-package/scenarios/invalid/non_existent_packages_file_test: Crash, OK # Analyzer exits on invalid package config
-package/scenarios/invalid/same_package_twice_test: Crash, OK # Analyzer exits on invalid package config
-[ $compiler == dart2analyzer && $system == windows ]
-package/scenarios/empty_packages_file/empty_packages_file_option_test: Crash, Pass # Issue 28645
-package/scenarios/packages_file_strange_formatting/empty_package_dir_test: Crash # Issue 28645
diff --git a/tests/standalone_2/standalone_2_kernel.status b/tests/standalone_2/standalone_2_kernel.status
index dc7698b..93f0fda 100644
--- a/tests/standalone_2/standalone_2_kernel.status
+++ b/tests/standalone_2/standalone_2_kernel.status
@@ -4,42 +4,21 @@
# Sections in this file should contain "$compiler == dartk" or
# "$compiler == dartkp".
-fragmentation_test: Pass, Slow # GC heavy
-io/process_sync_test: Pass, Slow # Spawns synchronously subprocesses in sequence.
-
-[ $builder_tag == asan ]
-io/file_test: Fail # Issue 34724
-io/http_server_response_test: Fail # Issue 34724
-io/process_sync_test: Pass, Fail # https://github.com/dart-lang/sdk/issues/34724
-io/signals_test: Fail # Issue 34724
-io/test_extension_fail_test: Fail # Issue 32187
+fragmentation_test: Slow # GC heavy
+io/process_sync_test: Slow # Spawns synchronously subprocesses in sequence.
[ $compiler == dartkb ]
-io/dart_std_io_pipe_test: Pass, Timeout # Please triage
-io/platform_test: RuntimeError # Platform.script points to dill file.
no_lazy_dispatchers_test: SkipByDesign # KBC interpreter doesn't support --no_lazy_dispatchers
-[ $compiler == dartkp ]
-io/arguments_test: Fail # Test harness passes runtime arguments to the compiler
-
[ $system == android ]
entrypoints_verification_test: Skip # Requires shared objects which the test script doesn't "adb push".
[ $arch == ia32 && $builder_tag == optimization_counter_threshold ]
io/file_lock_test: SkipSlow # Timeout
-[ $arch == ia32 && $compiler == dartk ]
-io/dart_std_io_pipe_test: Timeout, Pass # Issue 34723
-
[ $arch == simarm64 && ($compiler == dartk || $compiler == dartkb) ]
io/http_bind_test: Slow
-[ $arch == x64 && $builder_tag == asan && $compiler == dartk ]
-io/file_test: Fail # Memory leak (issue 34724)
-io/http_server_response_test: Fail # Memory leak (issue 34724)
-io/signals_test: Pass, RuntimeError # Issue 34734
-io/test_extension_fail_test: Fail # Memory leak (issue 34724)
-
[ $builder_tag == optimization_counter_threshold && ($compiler == dartk || $compiler == dartkb) ]
map_insert_remove_oom_test: Skip # Heap limit too low.
@@ -66,7 +45,6 @@
io/raw_datagram_socket_test: Skip # Flaky.
io/raw_secure_server_closing_test: Skip # Flaky
io/raw_socket_test: Crash
-io/secure_builtin_roots_test: Timeout, Pass # Times out on bots.
io/secure_multiple_client_server_test: Skip # Flaky.
io/secure_server_closing_test: Skip # Flaky.
io/secure_server_socket_test: Skip # Flaky.
@@ -77,7 +55,6 @@
io/web_socket_test: Skip # Flaky.
map_insert_remove_oom_test: Skip # Heap limit too low.
no_support_debugger_test: Skip # kernel-service snapshot not compatible with flag disabled
-regress_29350_test/none: Pass # Issue 31537
[ $mode == debug && $runtime == vm && ($compiler == dartk || $compiler == dartkb) ]
io/file_lock_test: Slow
@@ -93,14 +70,10 @@
[ $runtime == vm && ($compiler == dartk || $compiler == dartkb) ]
no_support_debugger_test: Skip # kernel-service snapshot not compatible with flag disabled
-regress_29350_test/none: Pass # Issue 31537
[ $system == windows && ($compiler == dartk || $compiler == dartkb) ]
-io/compile_all_test: Pass, Fail # Possibly related to issue 32373
io/dart_std_io_pipe_test: Slow
io/secure_builtin_roots_test: Skip # Issues 32137 and 32138.
-io/test_extension_fail_test: RuntimeError, Pass # Issue 32137.
-io/test_extension_test: RuntimeError, Pass # Issue 32137.
io/wait_for_event_isolate_test: Skip # Issues 32137 and 32138.
map_insert_remove_oom_test: Skip # Heap limit too low.
@@ -116,12 +89,8 @@
# are to be triaged. Isolate tests are skipped on purpose due to the usage of
# batch mode.
[ ($arch == simarm || $arch == simarm64 || $arch == simdbc64) && ($compiler == dartk || $compiler == dartkb) ]
-io/directory_list_sync_test: Timeout, Pass # Please triage.
-io/file_blocking_lock_test: Pass, Crash # Please triage.
+io/file_blocking_lock_test: Crash # Please triage.
io/file_lock_test: Slow
-io/platform_test: RuntimeError # Platform.script points to dill file.
-io/test_extension_fail_test: RuntimeError # Platform.script points to dill file.
-io/test_extension_test: RuntimeError # Platform.script points to dill file.
map_insert_remove_oom_test: Skip # Heap limit too low.
[ ($compiler == dartk || $compiler == dartkb) && ($hot_reload || $hot_reload_rollback) ]
@@ -129,7 +98,6 @@
io/http_advanced_test: Skip # Timeout
io/http_auth_digest_test: Crash
io/http_auth_test: Skip # Timeout
-io/http_basic_test: Pass, Timeout # Issue 28046
io/http_proxy_advanced_test: Skip # Timeout
io/http_read_test: Skip # Timeout
io/pipe_server_test: Skip # Timeout
diff --git a/tools/VERSION b/tools/VERSION
index b56200c..e822ddc 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -31,9 +31,9 @@
#
CHANNEL dev
MAJOR 2
-MINOR 5
+MINOR 6
PATCH 0
-PRERELEASE 5
+PRERELEASE 0
PRERELEASE_PATCH 0
-ABI_VERSION 11
-OLDEST_SUPPORTED_ABI_VERSION 11
+ABI_VERSION 14
+OLDEST_SUPPORTED_ABI_VERSION 13
diff --git a/tools/bots/bot_utils.py b/tools/bots/bot_utils.py
index fc840f3..f3543ce 100755
--- a/tools/bots/bot_utils.py
+++ b/tools/bots/bot_utils.py
@@ -142,6 +142,10 @@
# Functions for querying gs:// directories
+ def base_directory(self, revision):
+ return '%s/channels/%s/%s/%s' % (self.bucket, self.channel,
+ self.release_type, revision)
+
def sdk_directory(self, revision):
return self._variant_directory('sdk', revision)
@@ -164,8 +168,7 @@
return self._variant_directory('misc', revision)
def _variant_directory(self, name, revision):
- return '%s/channels/%s/%s/%s/%s' % (self.bucket, self.channel,
- self.release_type, revision, name)
+ return '%s/%s' % (self.base_directory(revision), name)
# Functions for quering filenames
diff --git a/tools/bots/results.dart b/tools/bots/results.dart
index c42d828..1383b3b 100644
--- a/tools/bots/results.dart
+++ b/tools/bots/results.dart
@@ -131,10 +131,14 @@
}
Map<String, Map<String, dynamic>> createResultsMap(
- List<Map<String, dynamic>> results) =>
- new Map<String, Map<String, dynamic>>.fromIterable(results,
- key: (dynamic result) =>
- "${result["configuration"]}:${result["name"]}");
+ List<Map<String, dynamic>> results) {
+ Map<String, Map<String, dynamic>> result = {};
+ for (Map<String, dynamic> map in results) {
+ var key = "${map["configuration"]}:${map["name"]}";
+ result.putIfAbsent(key, () => map);
+ }
+ return result;
+}
Map<String, Map<String, dynamic>> parseResultsMap(String contents) =>
createResultsMap(parseResults(contents));
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index 650f810..64de89d 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -596,7 +596,8 @@
},
{
"builders": [
- "vm-kernel-precomp-android-release-arm"
+ "vm-kernel-precomp-android-release-arm",
+ "vm-kernel-precomp-android-release-arm64"
],
"meta": {
"description": "This configuration is used by the vm precomp builders on Android."
@@ -1054,7 +1055,8 @@
"--enable-asserts",
"pkg/dev_compiler/bin/dartdevc.dart",
"-k",
- "-o=out/ReleaseX64/dartdevk.js",
+ "-o",
+ "out/ReleaseX64/dartdevk.js",
"pkg/dev_compiler/bin/dartdevc.dart"
]
}
@@ -1091,18 +1093,6 @@
"lib_2",
"dartdevc_native"
]
- },
- {
- "name": "ddc kernel modular tests",
- "script": "out/ReleaseX64/dart-sdk/bin/dart",
- "testRunner": true,
- "arguments": [
- "pkg/dev_compiler/test/modular_suite.dart",
- "--configuration-name",
- "dartdevk-${system}-release",
- "--verbose",
- "--use-sdk"
- ]
}
]
},
@@ -1120,18 +1110,6 @@
"arguments": ["dart2js_bot", "dartdevc_test"]
},
{
- "name": "ddc tests",
- "arguments": [
- "-ndartdevc-checked-mac-release-chrome",
- "language_2",
- "corelib_2",
- "lib_2",
- "dartdevc_native"
- ],
- "shards": 1,
- "fileset": "dart2js"
- },
- {
"name": "ddc kernel tests",
"arguments": [
"-ndartdevk-checked-mac-release-chrome",
@@ -1154,14 +1132,6 @@
]
},
{
- "name": "ddc sourcemap tests",
- "script": "xcodebuild/ReleaseX64/dart",
- "arguments": [
- "pkg/dev_compiler/test/sourcemap/sourcemaps_ddc_suite.dart",
- "-rnone"
- ]
- },
- {
"name": "ddk sourcemap tests",
"script": "xcodebuild/ReleaseX64/dart",
"arguments": [
@@ -1170,14 +1140,6 @@
]
},
{
- "name": "ddc sourcemap stacktrace tests",
- "script": "xcodebuild/ReleaseX64/dart",
- "arguments": [
- "pkg/dev_compiler/test/sourcemap/stacktrace_ddc_suite.dart",
- "-rnone"
- ]
- },
- {
"name": "ddk sourcemap stacktrace tests",
"script": "xcodebuild/ReleaseX64/dart",
"arguments": [
@@ -1194,23 +1156,14 @@
]
},
{
- "name": "ddc self host test",
- "script": "xcodebuild/ReleaseX64/dart-sdk/bin/dart",
- "arguments": [
- "--enable-asserts",
- "pkg/dev_compiler/bin/dartdevc.dart",
- "-o=xcodebuild/ReleaseX64/dartdevc.js",
- "pkg/dev_compiler/bin/dartdevc.dart"
- ]
- },
- {
"name": "ddk self host test",
"script": "xcodebuild/ReleaseX64/dart-sdk/bin/dart",
"arguments": [
"--enable-asserts",
"pkg/dev_compiler/bin/dartdevc.dart",
"-k",
- "-o=xcodebuild/ReleaseX64/dartdevk.js",
+ "-o",
+ "xcodebuild/ReleaseX64/dartdevk.js",
"pkg/dev_compiler/bin/dartdevc.dart"
]
}
@@ -1857,7 +1810,11 @@
"script": "tools/build.py",
"arguments": ["create_sdk"]
},
-
+ {
+ "name": "analyze runtime/tools/dartfuzz",
+ "script": "out/ReleaseX64/dart-sdk/bin/dartanalyzer",
+ "arguments": ["--fatal-warnings", "runtime/tools/dartfuzz"]
+ },
{
"name": "analyze pkg/analysis_server",
"script": "out/ReleaseX64/dart-sdk/bin/dartanalyzer",
diff --git a/tools/dom/templates/html/impl/impl_HTMLTemplateElement.darttemplate b/tools/dom/templates/html/impl/impl_HTMLTemplateElement.darttemplate
index f37da96..7fb61fe 100644
--- a/tools/dom/templates/html/impl/impl_HTMLTemplateElement.darttemplate
+++ b/tools/dom/templates/html/impl/impl_HTMLTemplateElement.darttemplate
@@ -14,11 +14,12 @@
*
* See also:
*
- * * <https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#innerhtml-on-templates>
+ * * <https://w3c.github.io/DOM-Parsing/#the-innerhtml-mixin>
*/
void setInnerHtml(String html,
{NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
text = null;
+ content.nodes.clear();
var fragment = createFragment(
html, validator: validator, treeSanitizer: treeSanitizer);
diff --git a/tools/promote.py b/tools/promote.py
index cf31291..c9b820b 100644
--- a/tools/promote.py
+++ b/tools/promote.py
@@ -4,7 +4,7 @@
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
-# Dart Editor promote tools.
+# Dart SDK promote tools.
import imp
import optparse
@@ -27,8 +27,8 @@
promote - Will promote builds from raw/signed locations to release
locations.
- Example: Promote revision r29962 on dev channel:
- python editor/build/promote.py promote --channel=dev --revision=29962
+ Example: Promote version 2.5.0 on the stable channel:
+ python editor/build/promote.py promote --channel=stable --version=2.5.0
"""
result = optparse.OptionParser(usage=usage)
@@ -36,9 +36,15 @@
group = optparse.OptionGroup(result, 'Promote',
'options used to promote code')
group.add_option(
- '--revision', help='The svn revision to promote', action='store')
+ '--revision',
+ '--version',
+ help='The version to promote',
+ action='store')
group.add_option(
- '--channel', type='string', help='Channel to promote.', default=None)
+ '--channel',
+ type='string',
+ help='The channel to promote.',
+ default=None)
group.add_option(
"--dry", help='Dry run', default=False, action="store_true")
result.add_option_group(group)
@@ -131,11 +137,20 @@
Gsutil(['-m', 'rm', '-R', '-f', gs_path])
wait_for_delete_to_be_consistent_with_list(gs_path)
- # Copy sdk directory.
- from_loc = raw_namer.sdk_directory(revision)
+ # Copy the signed sdk directory.
+ from_loc = signed_namer.sdk_directory(revision)
to_loc = release_namer.sdk_directory(to_revision)
remove_gs_directory(to_loc)
- Gsutil(['-m', 'cp', '-a', 'public-read', '-R', from_loc, to_loc])
+ has_signed = exists(from_loc)
+ if has_signed:
+ Gsutil(['-m', 'cp', '-a', 'public-read', '-R', from_loc, to_loc])
+ # Because gsutil copies differently to existing directories, we need
+ # to use the base directory for the next recursive copy.
+ to_loc = release_namer.base_directory(to_revision)
+
+ # Copy the unsigned sdk directory without clobbering signed files.
+ from_loc = raw_namer.sdk_directory(revision)
+ Gsutil(['-m', 'cp', '-n', '-a', 'public-read', '-R', from_loc, to_loc])
# Copy api-docs zipfile.
from_loc = raw_namer.apidocs_zipfilepath(revision)
@@ -162,7 +177,7 @@
command = [sys.executable, gsutilTool] + cmd
if DRY_RUN:
print "DRY runnning: %s" % command
- return
+ return (None, None, 0)
return bot_utils.run(command, throw_on_error=throw_on_error)
diff --git a/utils/bazel/kernel_worker.dart b/utils/bazel/kernel_worker.dart
index a0e5af3..d18212b 100644
--- a/utils/bazel/kernel_worker.dart
+++ b/utils/bazel/kernel_worker.dart
@@ -272,6 +272,12 @@
// TODO(sigmund): add support for experiments with the incremental compiler.
state = await fe.initializeIncrementalCompiler(
previousState,
+ {
+ "target=$targetName",
+ "trackWidgetCreation=$trackWidgetCreation",
+ "multiRootScheme=${fileSystem.markerScheme}",
+ "multiRootRoots=${fileSystem.roots}",
+ },
_toUri(parsedArgs['dart-sdk-summary']),
_toUri(parsedArgs['packages-file']),
_toUri(parsedArgs['libraries-file']),
diff --git a/utils/dart2native/BUILD.gn b/utils/dart2native/BUILD.gn
new file mode 100644
index 0000000..47712d1
--- /dev/null
+++ b/utils/dart2native/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright (c) 2019, 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("../application_snapshot.gni")
+
+group("dart2native") {
+ deps = [
+ ":generate_dart2native_snapshot",
+ ]
+}
+
+application_snapshot("generate_dart2native_snapshot") {
+ main_dart = "../../pkg/dart2native/bin/dart2native.dart"
+ training_args = [
+ "--help",
+ ]
+ name = "dart2native"
+}