Version 2.14.0-9.0.dev
Merge commit 'b802aadf7150af606b8cc5ba87d7a8b39c102292' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index ef7591c..5bd7c51 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -11,7 +11,7 @@
"constraint, update this by running tools/generate_package_config.dart."
],
"configVersion": 2,
- "generated": "2021-04-13T13:32:11.977579",
+ "generated": "2021-04-16T13:34:20.183158",
"generator": "tools/generate_package_config.dart",
"packages": [
{
@@ -749,7 +749,7 @@
"name": "vm_snapshot_analysis",
"rootUri": "../pkg/vm_snapshot_analysis",
"packageUri": "lib/",
- "languageVersion": "2.8"
+ "languageVersion": "2.12"
},
{
"name": "wasm",
diff --git a/.gn b/.gn
index fc54abe..a9e618f 100644
--- a/.gn
+++ b/.gn
@@ -12,3 +12,6 @@
# GN build files are placed when they can not be placed directly
# in the source tree, e.g. for third party source trees.
secondary_source = "//build/secondary/"
+
+# Override the default script executable to always be python3.
+script_executable = "python3"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1a4558d..2b563cd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -152,7 +152,14 @@
[#44211]: https://github.com/dart-lang/sdk/issues/44211
-## 2.12.3 - 2021-04-12
+## 2.12.4 - 2021-04-15
+
+This is a patch release that fixes a Dart VM compiler crashes when compiling
+initializers containing async closures (issue [#45306][]).
+
+[#45306]: https://github.com/dart-lang/sdk/issues/45306
+
+## 2.12.3 - 2021-04-14
This is a patch release that fixes a vulnerability in `dart:html` related to
DOM clobbering. Thanks again to **Vincenzo di Cicco** for finding and reporting
diff --git a/DEPS b/DEPS
index 5c44d05..9f97b1f 100644
--- a/DEPS
+++ b/DEPS
@@ -73,7 +73,7 @@
# Revisions of /third_party/* dependencies.
"args_rev": "d8fea36c10ef96797be02e3d132d572445cd86f4",
- "async_rev": "376d418b1b535030fbe3369938d2ffdbb0340a77",
+ "async_rev": "376c0fe95fa6fe7a5a6c41ef7b4585085c826f89",
"bazel_worker_rev": "0885637b037979afbf5bcd05fd748b309fd669c0",
"benchmark_harness_rev": "c546dbd9f639f75cd2f75de8df2eb9f8ea15e8e7",
"boolean_selector_rev": "665e6921ab246569420376f827bff4585dff0b14",
@@ -268,8 +268,8 @@
Var("dart_root") + "/third_party/gsutil": {
"packages": [{
- "package": "infra/gsutil",
- "version": "version:4.34",
+ "package": "infra/3pp/tools/gsutil",
+ "version": "version:4.58",
}],
"dep_type": "cipd",
},
@@ -672,59 +672,56 @@
# Pull Debian sysroot for i386 Linux
'name': 'sysroot_i386',
'pattern': '.',
- 'action': ['python', 'sdk/build/linux/sysroot_scripts/install-sysroot.py',
+ 'action': ['python3', 'sdk/build/linux/sysroot_scripts/install-sysroot.py',
'--arch', 'i386'],
},
{
# Pull Debian sysroot for amd64 Linux
'name': 'sysroot_amd64',
'pattern': '.',
- 'action': ['python', 'sdk/build/linux/sysroot_scripts/install-sysroot.py',
+ 'action': ['python3', 'sdk/build/linux/sysroot_scripts/install-sysroot.py',
'--arch', 'amd64'],
},
{
# Pull Debian sysroot for arm Linux
'name': 'sysroot_amd64',
'pattern': '.',
- 'action': ['python', 'sdk/build/linux/sysroot_scripts/install-sysroot.py',
+ 'action': ['python3', 'sdk/build/linux/sysroot_scripts/install-sysroot.py',
'--arch', 'arm'],
},
{
# Pull Debian jessie sysroot for arm64 Linux
'name': 'sysroot_amd64',
'pattern': '.',
- 'action': ['python', 'sdk/build/linux/sysroot_scripts/install-sysroot.py',
+ 'action': ['python3', 'sdk/build/linux/sysroot_scripts/install-sysroot.py',
'--arch', 'arm64'],
},
{
'name': 'buildtools',
'pattern': '.',
- 'action': ['python', 'sdk/tools/buildtools/update.py'],
+ 'action': ['python3', 'sdk/tools/buildtools/update.py'],
},
{
# Update the Windows toolchain if necessary.
'name': 'win_toolchain',
'pattern': '.',
- 'action': ['python', 'sdk/build/vs_toolchain.py', 'update'],
+ 'action': ['python3', 'sdk/build/vs_toolchain.py', 'update'],
+ 'condition': 'checkout_win'
+ },
+ {
+ "name": "7zip",
+ "pattern": ".",
+ "action": [
+ "download_from_google_storage",
+ "--no_auth",
+ "--no_resume",
+ "--bucket",
+ "dart-dependencies",
+ "--platform=win32",
+ "--extract",
+ "-s",
+ Var('dart_root') + "/third_party/7zip.tar.gz.sha1",
+ ],
+ 'condition': 'checkout_win'
},
]
-
-hooks_os = {
- "win": [
- {
- "name": "7zip",
- "pattern": ".",
- "action": [
- "download_from_google_storage",
- "--no_auth",
- "--no_resume",
- "--bucket",
- "dart-dependencies",
- "--platform=win32",
- "--extract",
- "-s",
- Var('dart_root') + "/third_party/7zip.tar.gz.sha1",
- ],
- },
- ]
-}
diff --git a/benchmarks/Richards/dart/Richards.dart b/benchmarks/Richards/dart/Richards.dart
new file mode 100644
index 0000000..f930651
--- /dev/null
+++ b/benchmarks/Richards/dart/Richards.dart
@@ -0,0 +1,446 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Ported by the Dart team to Dart.
+
+// This is a Dart implementation of the Richards benchmark from:
+//
+// http://www.cl.cam.ac.uk/~mr10/Bench.html
+//
+// The benchmark was originally implemented in BCPL by
+// Martin Richards.
+
+import 'package:benchmark_harness/benchmark_harness.dart';
+
+void main() {
+ const Richards().report();
+}
+
+/// Richards imulates the task dispatcher of an operating system.
+class Richards extends BenchmarkBase {
+ const Richards() : super('Richards');
+
+ @override
+ void run() {
+ final Scheduler scheduler = Scheduler();
+ scheduler.addIdleTask(ID_IDLE, 0, null, COUNT);
+
+ Packet queue = Packet(null, ID_WORKER, KIND_WORK);
+ queue = Packet(queue, ID_WORKER, KIND_WORK);
+ scheduler.addWorkerTask(ID_WORKER, 1000, queue);
+
+ queue = Packet(null, ID_DEVICE_A, KIND_DEVICE);
+ queue = Packet(queue, ID_DEVICE_A, KIND_DEVICE);
+ queue = Packet(queue, ID_DEVICE_A, KIND_DEVICE);
+ scheduler.addHandlerTask(ID_HANDLER_A, 2000, queue);
+
+ queue = Packet(null, ID_DEVICE_B, KIND_DEVICE);
+ queue = Packet(queue, ID_DEVICE_B, KIND_DEVICE);
+ queue = Packet(queue, ID_DEVICE_B, KIND_DEVICE);
+ scheduler.addHandlerTask(ID_HANDLER_B, 3000, queue);
+
+ scheduler.addDeviceTask(ID_DEVICE_A, 4000, null);
+
+ scheduler.addDeviceTask(ID_DEVICE_B, 5000, null);
+
+ scheduler.schedule();
+
+ if (scheduler.queueCount != EXPECTED_QUEUE_COUNT ||
+ scheduler.holdCount != EXPECTED_HOLD_COUNT) {
+ print('Error during execution: queueCount = ${scheduler.queueCount}'
+ ', holdCount = ${scheduler.holdCount}.');
+ }
+ if (EXPECTED_QUEUE_COUNT != scheduler.queueCount) {
+ throw 'bad scheduler queue-count';
+ }
+ if (EXPECTED_HOLD_COUNT != scheduler.holdCount) {
+ throw 'bad scheduler hold-count';
+ }
+ }
+
+ static const int DATA_SIZE = 4;
+ static const int COUNT = 1000;
+
+ /// These two constants specify how many times a packet is queued and
+ /// how many times a task is put on hold in a correct run of richards.
+ /// They don't have any meaning a such but are characteristic of a
+ /// correct run so if the actual queue or hold count is different from
+ /// the expected there must be a bug in the implementation.
+ static const int EXPECTED_QUEUE_COUNT = 2322;
+ static const int EXPECTED_HOLD_COUNT = 928;
+
+ static const int ID_IDLE = 0;
+ static const int ID_WORKER = 1;
+ static const int ID_HANDLER_A = 2;
+ static const int ID_HANDLER_B = 3;
+ static const int ID_DEVICE_A = 4;
+ static const int ID_DEVICE_B = 5;
+ static const int NUMBER_OF_IDS = 6;
+
+ static const int KIND_DEVICE = 0;
+ static const int KIND_WORK = 1;
+}
+
+/// A scheduler can be used to schedule a set of tasks based on their relative
+/// priorities. Scheduling is done by maintaining a list of task control blocks
+/// which holds tasks and the data queue they are processing.
+class Scheduler {
+ int queueCount = 0;
+ int holdCount = 0;
+ TaskControlBlock? currentTcb;
+ int currentId = Richards.ID_IDLE;
+ TaskControlBlock? list;
+ final List<TaskControlBlock?> blocks =
+ List<TaskControlBlock?>.filled(Richards.NUMBER_OF_IDS, null);
+
+ /// Add an idle task to this scheduler.
+ void addIdleTask(int id, int priority, Packet? queue, int count) {
+ addRunningTask(id, priority, queue, IdleTask(this, 1, count));
+ }
+
+ /// Add a work task to this scheduler.
+ void addWorkerTask(int id, int priority, Packet? queue) {
+ addTask(id, priority, queue, WorkerTask(this, Richards.ID_HANDLER_A, 0));
+ }
+
+ /// Add a handler task to this scheduler.
+ void addHandlerTask(int id, int priority, Packet? queue) {
+ addTask(id, priority, queue, HandlerTask(this));
+ }
+
+ /// Add a handler task to this scheduler.
+ void addDeviceTask(int id, int priority, Packet? queue) {
+ addTask(id, priority, queue, DeviceTask(this));
+ }
+
+ /// Add the specified task and mark it as running.
+ void addRunningTask(int id, int priority, Packet? queue, Task task) {
+ addTask(id, priority, queue, task);
+ currentTcb!.setRunning();
+ }
+
+ /// Add the specified task to this scheduler.
+ void addTask(int id, int priority, Packet? queue, Task task) {
+ currentTcb = TaskControlBlock(list, id, priority, queue, task);
+ list = currentTcb;
+ blocks[id] = currentTcb;
+ }
+
+ /// Execute the tasks managed by this scheduler.
+ void schedule() {
+ currentTcb = list;
+ while (currentTcb != null) {
+ if (currentTcb!.isHeldOrSuspended()) {
+ currentTcb = currentTcb!.link;
+ } else {
+ currentId = currentTcb!.id;
+ currentTcb = currentTcb!.run();
+ }
+ }
+ }
+
+ /// Release a task that is currently blocked and return the next block to run.
+ TaskControlBlock? release(int id) {
+ final TaskControlBlock? tcb = blocks[id];
+ if (tcb == null) return tcb;
+ tcb.markAsNotHeld();
+ if (tcb.priority > currentTcb!.priority) return tcb;
+ return currentTcb;
+ }
+
+ /// Block the currently executing task and return the next task control block
+ /// to run. The blocked task will not be made runnable until it is explicitly
+ /// released, even if new work is added to it.
+ TaskControlBlock? holdCurrent() {
+ holdCount++;
+ currentTcb!.markAsHeld();
+ return currentTcb!.link;
+ }
+
+ /// Suspend the currently executing task and return the next task
+ /// control block to run.
+ /// If new work is added to the suspended task it will be made runnable.
+ TaskControlBlock suspendCurrent() {
+ currentTcb!.markAsSuspended();
+ return currentTcb!;
+ }
+
+ /// Add the specified packet to the end of the worklist used by the task
+ /// associated with the packet and make the task runnable if it is currently
+ /// suspended.
+ TaskControlBlock? queue(Packet packet) {
+ final TaskControlBlock? t = blocks[packet.id];
+ if (t == null) return t;
+ queueCount++;
+ packet.link = null;
+ packet.id = currentId;
+ return t.checkPriorityAdd(currentTcb!, packet);
+ }
+}
+
+/// A task control block manages a task and the queue of work packages
+/// associated with it.
+class TaskControlBlock {
+ TaskControlBlock? link;
+ int id; // The id of this block.
+ int priority; // The priority of this block.
+ Packet? queue; // The queue of packages to be processed by the task.
+ Task task;
+ int state;
+
+ TaskControlBlock(this.link, this.id, this.priority, this.queue, this.task)
+ : state = queue == null ? STATE_SUSPENDED : STATE_SUSPENDED_RUNNABLE;
+
+ /// The task is running and is currently scheduled.
+ static const int STATE_RUNNING = 0;
+
+ /// The task has packets left to process.
+ static const int STATE_RUNNABLE = 1;
+
+ /// The task is not currently running. The task is not blocked as such and may
+ /// be started by the scheduler.
+ static const int STATE_SUSPENDED = 2;
+
+ /// The task is blocked and cannot be run until it is explicitly released.
+ static const int STATE_HELD = 4;
+
+ static const int STATE_SUSPENDED_RUNNABLE = STATE_SUSPENDED | STATE_RUNNABLE;
+ static const int STATE_NOT_HELD = ~STATE_HELD;
+
+ void setRunning() {
+ state = STATE_RUNNING;
+ }
+
+ void markAsNotHeld() {
+ state = state & STATE_NOT_HELD;
+ }
+
+ void markAsHeld() {
+ state = state | STATE_HELD;
+ }
+
+ bool isHeldOrSuspended() {
+ return (state & STATE_HELD) != 0 || (state == STATE_SUSPENDED);
+ }
+
+ void markAsSuspended() {
+ state = state | STATE_SUSPENDED;
+ }
+
+ void markAsRunnable() {
+ state = state | STATE_RUNNABLE;
+ }
+
+ /// Runs this task, if it is ready to be run, and returns the next
+ /// task to run.
+ TaskControlBlock? run() {
+ Packet? packet;
+ if (state == STATE_SUSPENDED_RUNNABLE) {
+ packet = queue;
+ queue = packet!.link;
+ state = queue == null ? STATE_RUNNING : STATE_RUNNABLE;
+ } else {
+ packet = null;
+ }
+ return task.run(packet);
+ }
+
+ /// Adds a packet to the worklist of this block's task, marks this as
+ /// runnable if necessary, and returns the next runnable object to run
+ /// (the one with the highest priority).
+ TaskControlBlock checkPriorityAdd(TaskControlBlock task, Packet packet) {
+ if (queue == null) {
+ queue = packet;
+ markAsRunnable();
+ if (priority > task.priority) return this;
+ } else {
+ queue = packet.addTo(queue);
+ }
+ return task;
+ }
+
+ @override
+ String toString() => 'tcb { $task@$state }';
+}
+
+/// Abstract task that manipulates work packets.
+abstract class Task {
+ Scheduler scheduler; // The scheduler that manages this task.
+
+ Task(this.scheduler);
+
+ TaskControlBlock? run(Packet? packet);
+}
+
+/// An idle task doesn't do any work itself but cycles control between the two
+/// device tasks.
+class IdleTask extends Task {
+ int v1; // A seed value that controls how the device tasks are scheduled.
+ int count; // The number of times this task should be scheduled.
+
+ IdleTask(Scheduler scheduler, this.v1, this.count) : super(scheduler);
+
+ @override
+ TaskControlBlock? run(Packet? packet) {
+ count--;
+ if (count == 0) return scheduler.holdCurrent();
+ if ((v1 & 1) == 0) {
+ v1 = v1 >> 1;
+ return scheduler.release(Richards.ID_DEVICE_A);
+ }
+ v1 = (v1 >> 1) ^ 0xD008;
+ return scheduler.release(Richards.ID_DEVICE_B);
+ }
+
+ @override
+ String toString() => 'IdleTask';
+}
+
+/// A task that suspends itself after each time it has been run to simulate
+/// waiting for data from an external device.
+class DeviceTask extends Task {
+ Packet? v1;
+
+ DeviceTask(Scheduler scheduler) : super(scheduler);
+
+ @override
+ TaskControlBlock? run(Packet? packet) {
+ if (packet == null) {
+ if (v1 == null) return scheduler.suspendCurrent();
+ final Packet v = v1!;
+ v1 = null;
+ return scheduler.queue(v);
+ }
+ v1 = packet;
+ return scheduler.holdCurrent();
+ }
+
+ @override
+ String toString() => 'DeviceTask';
+}
+
+/// A task that manipulates work packets.
+class WorkerTask extends Task {
+ int v1; // A seed used to specify how work packets are manipulated.
+ int v2; // Another seed used to specify how work packets are manipulated.
+
+ WorkerTask(Scheduler scheduler, this.v1, this.v2) : super(scheduler);
+
+ @override
+ TaskControlBlock? run(Packet? packet) {
+ if (packet == null) {
+ return scheduler.suspendCurrent();
+ }
+ if (v1 == Richards.ID_HANDLER_A) {
+ v1 = Richards.ID_HANDLER_B;
+ } else {
+ v1 = Richards.ID_HANDLER_A;
+ }
+ packet.id = v1;
+ packet.a1 = 0;
+ for (int i = 0; i < Richards.DATA_SIZE; i++) {
+ v2++;
+ if (v2 > 26) v2 = 1;
+ packet.a2[i] = v2;
+ }
+ return scheduler.queue(packet);
+ }
+
+ @override
+ String toString() => 'WorkerTask';
+}
+
+/// A task that manipulates work packets and then suspends itself.
+class HandlerTask extends Task {
+ Packet? v1;
+ Packet? v2;
+
+ HandlerTask(Scheduler scheduler) : super(scheduler);
+
+ @override
+ TaskControlBlock? run(Packet? packet) {
+ if (packet != null) {
+ if (packet.kind == Richards.KIND_WORK) {
+ v1 = packet.addTo(v1);
+ } else {
+ v2 = packet.addTo(v2);
+ }
+ }
+ if (v1 != null) {
+ final int count = v1!.a1;
+ if (count < Richards.DATA_SIZE) {
+ if (v2 != null) {
+ final Packet v = v2!;
+ v2 = v.link;
+ v.a1 = v1!.a2[count];
+ v1!.a1 = count + 1;
+ return scheduler.queue(v);
+ }
+ } else {
+ final Packet v = v1!;
+ v1 = v.link;
+ return scheduler.queue(v);
+ }
+ }
+ return scheduler.suspendCurrent();
+ }
+
+ @override
+ String toString() => 'HandlerTask';
+}
+
+/// A simple package of data that is manipulated by the tasks. The exact layout
+/// of the payload data carried by a packet is not importaint, and neither is
+/// the nature of the work performed on packets by the tasks. Besides carrying
+/// data, packets form linked lists and are hence used both as data and
+/// worklists.
+class Packet {
+ Packet? link; // The tail of the linked list of packets.
+ int id; // An ID for this packet.
+ int kind; // The type of this packet.
+ int a1 = 0;
+
+ List<int> a2 = List<int>.filled(Richards.DATA_SIZE, 0);
+
+ Packet(this.link, this.id, this.kind);
+
+ /// Add this packet to the end of a worklist, and return the worklist.
+ Packet addTo(Packet? queue) {
+ link = null;
+ if (queue == null) return this;
+ Packet? peek;
+ Packet next = queue;
+ while ((peek = next.link) != null) {
+ next = peek!;
+ }
+ next.link = this;
+ return queue;
+ }
+
+ @override
+ String toString() => 'Packet';
+}
diff --git a/benchmarks/Richards/dart2/Richards.dart b/benchmarks/Richards/dart2/Richards.dart
new file mode 100644
index 0000000..f479a32
--- /dev/null
+++ b/benchmarks/Richards/dart2/Richards.dart
@@ -0,0 +1,449 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Ported by the Dart team to Dart.
+
+// This is a Dart implementation of the Richards benchmark from:
+//
+// http://www.cl.cam.ac.uk/~mr10/Bench.html
+//
+// The benchmark was originally implemented in BCPL by
+// Martin Richards.
+
+// @dart=2.9
+
+import 'package:benchmark_harness/benchmark_harness.dart';
+
+void main() {
+ const Richards().report();
+}
+
+/// Richards imulates the task dispatcher of an operating system.
+class Richards extends BenchmarkBase {
+ const Richards() : super('Richards');
+
+ @override
+ void run() {
+ final Scheduler scheduler = Scheduler();
+ scheduler.addIdleTask(ID_IDLE, 0, null, COUNT);
+
+ Packet queue = Packet(null, ID_WORKER, KIND_WORK);
+ queue = Packet(queue, ID_WORKER, KIND_WORK);
+ scheduler.addWorkerTask(ID_WORKER, 1000, queue);
+
+ queue = Packet(null, ID_DEVICE_A, KIND_DEVICE);
+ queue = Packet(queue, ID_DEVICE_A, KIND_DEVICE);
+ queue = Packet(queue, ID_DEVICE_A, KIND_DEVICE);
+ scheduler.addHandlerTask(ID_HANDLER_A, 2000, queue);
+
+ queue = Packet(null, ID_DEVICE_B, KIND_DEVICE);
+ queue = Packet(queue, ID_DEVICE_B, KIND_DEVICE);
+ queue = Packet(queue, ID_DEVICE_B, KIND_DEVICE);
+ scheduler.addHandlerTask(ID_HANDLER_B, 3000, queue);
+
+ scheduler.addDeviceTask(ID_DEVICE_A, 4000, null);
+
+ scheduler.addDeviceTask(ID_DEVICE_B, 5000, null);
+
+ scheduler.schedule();
+
+ if (scheduler.queueCount != EXPECTED_QUEUE_COUNT ||
+ scheduler.holdCount != EXPECTED_HOLD_COUNT) {
+ print('Error during execution: queueCount = ${scheduler.queueCount}'
+ ', holdCount = ${scheduler.holdCount}.');
+ }
+ if (EXPECTED_QUEUE_COUNT != scheduler.queueCount) {
+ throw 'bad scheduler queue-count';
+ }
+ if (EXPECTED_HOLD_COUNT != scheduler.holdCount) {
+ throw 'bad scheduler hold-count';
+ }
+ }
+
+ static const int DATA_SIZE = 4;
+ static const int COUNT = 1000;
+
+ /// These two constants specify how many times a packet is queued and
+ /// how many times a task is put on hold in a correct run of richards.
+ /// They don't have any meaning a such but are characteristic of a
+ /// correct run so if the actual queue or hold count is different from
+ /// the expected there must be a bug in the implementation.
+ static const int EXPECTED_QUEUE_COUNT = 2322;
+ static const int EXPECTED_HOLD_COUNT = 928;
+
+ static const int ID_IDLE = 0;
+ static const int ID_WORKER = 1;
+ static const int ID_HANDLER_A = 2;
+ static const int ID_HANDLER_B = 3;
+ static const int ID_DEVICE_A = 4;
+ static const int ID_DEVICE_B = 5;
+ static const int NUMBER_OF_IDS = 6;
+
+ static const int KIND_DEVICE = 0;
+ static const int KIND_WORK = 1;
+}
+
+/// A scheduler can be used to schedule a set of tasks based on their relative
+/// priorities. Scheduling is done by maintaining a list of task control blocks
+/// which holds tasks and the data queue they are processing.
+class Scheduler {
+ int queueCount = 0;
+ int holdCount = 0;
+ TaskControlBlock currentTcb;
+ int currentId;
+ TaskControlBlock list;
+ List<TaskControlBlock> blocks =
+ List<TaskControlBlock>(Richards.NUMBER_OF_IDS);
+
+ /// Add an idle task to this scheduler.
+ void addIdleTask(int id, int priority, Packet queue, int count) {
+ addRunningTask(id, priority, queue, IdleTask(this, 1, count));
+ }
+
+ /// Add a work task to this scheduler.
+ void addWorkerTask(int id, int priority, Packet queue) {
+ addTask(id, priority, queue, WorkerTask(this, Richards.ID_HANDLER_A, 0));
+ }
+
+ /// Add a handler task to this scheduler.
+ void addHandlerTask(int id, int priority, Packet queue) {
+ addTask(id, priority, queue, HandlerTask(this));
+ }
+
+ /// Add a handler task to this scheduler.
+ void addDeviceTask(int id, int priority, Packet queue) {
+ addTask(id, priority, queue, DeviceTask(this));
+ }
+
+ /// Add the specified task and mark it as running.
+ void addRunningTask(int id, int priority, Packet queue, Task task) {
+ addTask(id, priority, queue, task);
+ currentTcb.setRunning();
+ }
+
+ /// Add the specified task to this scheduler.
+ void addTask(int id, int priority, Packet queue, Task task) {
+ currentTcb = TaskControlBlock(list, id, priority, queue, task);
+ list = currentTcb;
+ blocks[id] = currentTcb;
+ }
+
+ /// Execute the tasks managed by this scheduler.
+ void schedule() {
+ currentTcb = list;
+ while (currentTcb != null) {
+ if (currentTcb.isHeldOrSuspended()) {
+ currentTcb = currentTcb.link;
+ } else {
+ currentId = currentTcb.id;
+ currentTcb = currentTcb.run();
+ }
+ }
+ }
+
+ /// Release a task that is currently blocked and return the next block to run.
+ TaskControlBlock release(int id) {
+ final TaskControlBlock tcb = blocks[id];
+ if (tcb == null) return tcb;
+ tcb.markAsNotHeld();
+ if (tcb.priority > currentTcb.priority) return tcb;
+ return currentTcb;
+ }
+
+ /// Block the currently executing task and return the next task control block
+ /// to run. The blocked task will not be made runnable until it is explicitly
+ /// released, even if new work is added to it.
+ TaskControlBlock holdCurrent() {
+ holdCount++;
+ currentTcb.markAsHeld();
+ return currentTcb.link;
+ }
+
+ /// Suspend the currently executing task and return the next task
+ /// control block to run.
+ /// If new work is added to the suspended task it will be made runnable.
+ TaskControlBlock suspendCurrent() {
+ currentTcb.markAsSuspended();
+ return currentTcb;
+ }
+
+ /// Add the specified packet to the end of the worklist used by the task
+ /// associated with the packet and make the task runnable if it is currently
+ /// suspended.
+ TaskControlBlock queue(Packet packet) {
+ final TaskControlBlock t = blocks[packet.id];
+ if (t == null) return t;
+ queueCount++;
+ packet.link = null;
+ packet.id = currentId;
+ return t.checkPriorityAdd(currentTcb, packet);
+ }
+}
+
+/// A task control block manages a task and the queue of work packages
+/// associated with it.
+class TaskControlBlock {
+ TaskControlBlock link;
+ int id; // The id of this block.
+ int priority; // The priority of this block.
+ Packet queue; // The queue of packages to be processed by the task.
+ Task task;
+ int state;
+
+ TaskControlBlock(this.link, this.id, this.priority, this.queue, this.task) {
+ state = queue == null ? STATE_SUSPENDED : STATE_SUSPENDED_RUNNABLE;
+ }
+
+ /// The task is running and is currently scheduled.
+ static const int STATE_RUNNING = 0;
+
+ /// The task has packets left to process.
+ static const int STATE_RUNNABLE = 1;
+
+ /// The task is not currently running. The task is not blocked as such and may
+ /// be started by the scheduler.
+ static const int STATE_SUSPENDED = 2;
+
+ /// The task is blocked and cannot be run until it is explicitly released.
+ static const int STATE_HELD = 4;
+
+ static const int STATE_SUSPENDED_RUNNABLE = STATE_SUSPENDED | STATE_RUNNABLE;
+ static const int STATE_NOT_HELD = ~STATE_HELD;
+
+ void setRunning() {
+ state = STATE_RUNNING;
+ }
+
+ void markAsNotHeld() {
+ state = state & STATE_NOT_HELD;
+ }
+
+ void markAsHeld() {
+ state = state | STATE_HELD;
+ }
+
+ bool isHeldOrSuspended() {
+ return (state & STATE_HELD) != 0 || (state == STATE_SUSPENDED);
+ }
+
+ void markAsSuspended() {
+ state = state | STATE_SUSPENDED;
+ }
+
+ void markAsRunnable() {
+ state = state | STATE_RUNNABLE;
+ }
+
+ /// Runs this task, if it is ready to be run, and returns the next
+ /// task to run.
+ TaskControlBlock run() {
+ Packet packet;
+ if (state == STATE_SUSPENDED_RUNNABLE) {
+ packet = queue;
+ queue = packet.link;
+ state = queue == null ? STATE_RUNNING : STATE_RUNNABLE;
+ } else {
+ packet = null;
+ }
+ return task.run(packet);
+ }
+
+ /// Adds a packet to the worklist of this block's task, marks this as
+ /// runnable if necessary, and returns the next runnable object to run
+ /// (the one with the highest priority).
+ TaskControlBlock checkPriorityAdd(TaskControlBlock task, Packet packet) {
+ if (queue == null) {
+ queue = packet;
+ markAsRunnable();
+ if (priority > task.priority) return this;
+ } else {
+ queue = packet.addTo(queue);
+ }
+ return task;
+ }
+
+ @override
+ String toString() => 'tcb { $task@$state }';
+}
+
+/// Abstract task that manipulates work packets.
+abstract class Task {
+ Scheduler scheduler; // The scheduler that manages this task.
+
+ Task(this.scheduler);
+
+ TaskControlBlock run(Packet packet);
+}
+
+/// An idle task doesn't do any work itself but cycles control between the two
+/// device tasks.
+class IdleTask extends Task {
+ int v1; // A seed value that controls how the device tasks are scheduled.
+ int count; // The number of times this task should be scheduled.
+
+ IdleTask(Scheduler scheduler, this.v1, this.count) : super(scheduler);
+
+ @override
+ TaskControlBlock run(Packet packet) {
+ count--;
+ if (count == 0) return scheduler.holdCurrent();
+ if ((v1 & 1) == 0) {
+ v1 = v1 >> 1;
+ return scheduler.release(Richards.ID_DEVICE_A);
+ }
+ v1 = (v1 >> 1) ^ 0xD008;
+ return scheduler.release(Richards.ID_DEVICE_B);
+ }
+
+ @override
+ String toString() => 'IdleTask';
+}
+
+/// A task that suspends itself after each time it has been run to simulate
+/// waiting for data from an external device.
+class DeviceTask extends Task {
+ Packet v1;
+
+ DeviceTask(Scheduler scheduler) : super(scheduler);
+
+ @override
+ TaskControlBlock run(Packet packet) {
+ if (packet == null) {
+ if (v1 == null) return scheduler.suspendCurrent();
+ final Packet v = v1;
+ v1 = null;
+ return scheduler.queue(v);
+ }
+ v1 = packet;
+ return scheduler.holdCurrent();
+ }
+
+ @override
+ String toString() => 'DeviceTask';
+}
+
+/// A task that manipulates work packets.
+class WorkerTask extends Task {
+ int v1; // A seed used to specify how work packets are manipulated.
+ int v2; // Another seed used to specify how work packets are manipulated.
+
+ WorkerTask(Scheduler scheduler, this.v1, this.v2) : super(scheduler);
+
+ @override
+ TaskControlBlock run(Packet packet) {
+ if (packet == null) {
+ return scheduler.suspendCurrent();
+ }
+ if (v1 == Richards.ID_HANDLER_A) {
+ v1 = Richards.ID_HANDLER_B;
+ } else {
+ v1 = Richards.ID_HANDLER_A;
+ }
+ packet.id = v1;
+ packet.a1 = 0;
+ for (int i = 0; i < Richards.DATA_SIZE; i++) {
+ v2++;
+ if (v2 > 26) v2 = 1;
+ packet.a2[i] = v2;
+ }
+ return scheduler.queue(packet);
+ }
+
+ @override
+ String toString() => 'WorkerTask';
+}
+
+/// A task that manipulates work packets and then suspends itself.
+class HandlerTask extends Task {
+ Packet v1;
+ Packet v2;
+
+ HandlerTask(Scheduler scheduler) : super(scheduler);
+
+ @override
+ TaskControlBlock run(Packet packet) {
+ if (packet != null) {
+ if (packet.kind == Richards.KIND_WORK) {
+ v1 = packet.addTo(v1);
+ } else {
+ v2 = packet.addTo(v2);
+ }
+ }
+ if (v1 != null) {
+ final int count = v1.a1;
+ Packet v;
+ if (count < Richards.DATA_SIZE) {
+ if (v2 != null) {
+ v = v2;
+ v2 = v2.link;
+ v.a1 = v1.a2[count];
+ v1.a1 = count + 1;
+ return scheduler.queue(v);
+ }
+ } else {
+ v = v1;
+ v1 = v1.link;
+ return scheduler.queue(v);
+ }
+ }
+ return scheduler.suspendCurrent();
+ }
+
+ @override
+ String toString() => 'HandlerTask';
+}
+
+/// A simple package of data that is manipulated by the tasks. The exact layout
+/// of the payload data carried by a packet is not importaint, and neither is
+/// the nature of the work performed on packets by the tasks. Besides carrying
+/// data, packets form linked lists and are hence used both as data and
+/// worklists.
+class Packet {
+ Packet link; // The tail of the linked list of packets.
+ int id; // An ID for this packet.
+ int kind; // The type of this packet.
+ int a1 = 0;
+
+ List<int> a2 = List(Richards.DATA_SIZE);
+
+ Packet(this.link, this.id, this.kind);
+
+ /// Add this packet to the end of a worklist, and return the worklist.
+ Packet addTo(Packet queue) {
+ link = null;
+ if (queue == null) return this;
+ Packet peek, next = queue;
+ while ((peek = next.link) != null) {
+ next = peek;
+ }
+ next.link = this;
+ return queue;
+ }
+
+ @override
+ String toString() => 'Packet';
+}
diff --git a/benchmarks/Richards/javascript/Richards.js b/benchmarks/Richards/javascript/Richards.js
new file mode 100644
index 0000000..8a71f99
--- /dev/null
+++ b/benchmarks/Richards/javascript/Richards.js
@@ -0,0 +1,536 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+// This is a JavaScript implementation of the Richards
+// benchmark from:
+//
+// http://www.cl.cam.ac.uk/~mr10/Bench.html
+//
+// The benchmark was originally implemented in BCPL by
+// Martin Richards.
+
+
+/**
+ * The Richards benchmark simulates the task dispatcher of an
+ * operating system.
+ **/
+function runRichards() {
+ var scheduler = new Scheduler();
+ scheduler.addIdleTask(ID_IDLE, 0, null, COUNT);
+
+ var queue = new Packet(null, ID_WORKER, KIND_WORK);
+ queue = new Packet(queue, ID_WORKER, KIND_WORK);
+ scheduler.addWorkerTask(ID_WORKER, 1000, queue);
+
+ queue = new Packet(null, ID_DEVICE_A, KIND_DEVICE);
+ queue = new Packet(queue, ID_DEVICE_A, KIND_DEVICE);
+ queue = new Packet(queue, ID_DEVICE_A, KIND_DEVICE);
+ scheduler.addHandlerTask(ID_HANDLER_A, 2000, queue);
+
+ queue = new Packet(null, ID_DEVICE_B, KIND_DEVICE);
+ queue = new Packet(queue, ID_DEVICE_B, KIND_DEVICE);
+ queue = new Packet(queue, ID_DEVICE_B, KIND_DEVICE);
+ scheduler.addHandlerTask(ID_HANDLER_B, 3000, queue);
+
+ scheduler.addDeviceTask(ID_DEVICE_A, 4000, null);
+
+ scheduler.addDeviceTask(ID_DEVICE_B, 5000, null);
+
+ scheduler.schedule();
+
+ if (scheduler.queueCount != EXPECTED_QUEUE_COUNT ||
+ scheduler.holdCount != EXPECTED_HOLD_COUNT) {
+ var msg =
+ "Error during execution: queueCount = " + scheduler.queueCount +
+ ", holdCount = " + scheduler.holdCount + ".";
+ throw new Error(msg);
+ }
+}
+
+var COUNT = 1000;
+
+/**
+ * These two constants specify how many times a packet is queued and
+ * how many times a task is put on hold in a correct run of richards.
+ * They don't have any meaning a such but are characteristic of a
+ * correct run so if the actual queue or hold count is different from
+ * the expected there must be a bug in the implementation.
+ **/
+var EXPECTED_QUEUE_COUNT = 2322;
+var EXPECTED_HOLD_COUNT = 928;
+
+
+/**
+ * A scheduler can be used to schedule a set of tasks based on their relative
+ * priorities. Scheduling is done by maintaining a list of task control blocks
+ * which holds tasks and the data queue they are processing.
+ * @constructor
+ */
+function Scheduler() {
+ this.queueCount = 0;
+ this.holdCount = 0;
+ this.blocks = new Array(NUMBER_OF_IDS);
+ this.list = null;
+ this.currentTcb = null;
+ this.currentId = null;
+}
+
+var ID_IDLE = 0;
+var ID_WORKER = 1;
+var ID_HANDLER_A = 2;
+var ID_HANDLER_B = 3;
+var ID_DEVICE_A = 4;
+var ID_DEVICE_B = 5;
+var NUMBER_OF_IDS = 6;
+
+var KIND_DEVICE = 0;
+var KIND_WORK = 1;
+
+/**
+ * Add an idle task to this scheduler.
+ * @param {int} id the identity of the task
+ * @param {int} priority the task's priority
+ * @param {Packet} queue the queue of work to be processed by the task
+ * @param {int} count the number of times to schedule the task
+ */
+Scheduler.prototype.addIdleTask = function (id, priority, queue, count) {
+ this.addRunningTask(id, priority, queue, new IdleTask(this, 1, count));
+};
+
+/**
+ * Add a work task to this scheduler.
+ * @param {int} id the identity of the task
+ * @param {int} priority the task's priority
+ * @param {Packet} queue the queue of work to be processed by the task
+ */
+Scheduler.prototype.addWorkerTask = function (id, priority, queue) {
+ this.addTask(id, priority, queue, new WorkerTask(this, ID_HANDLER_A, 0));
+};
+
+/**
+ * Add a handler task to this scheduler.
+ * @param {int} id the identity of the task
+ * @param {int} priority the task's priority
+ * @param {Packet} queue the queue of work to be processed by the task
+ */
+Scheduler.prototype.addHandlerTask = function (id, priority, queue) {
+ this.addTask(id, priority, queue, new HandlerTask(this));
+};
+
+/**
+ * Add a handler task to this scheduler.
+ * @param {int} id the identity of the task
+ * @param {int} priority the task's priority
+ * @param {Packet} queue the queue of work to be processed by the task
+ */
+Scheduler.prototype.addDeviceTask = function (id, priority, queue) {
+ this.addTask(id, priority, queue, new DeviceTask(this))
+};
+
+/**
+ * Add the specified task and mark it as running.
+ * @param {int} id the identity of the task
+ * @param {int} priority the task's priority
+ * @param {Packet} queue the queue of work to be processed by the task
+ * @param {Task} task the task to add
+ */
+Scheduler.prototype.addRunningTask = function (id, priority, queue, task) {
+ this.addTask(id, priority, queue, task);
+ this.currentTcb.setRunning();
+};
+
+/**
+ * Add the specified task to this scheduler.
+ * @param {int} id the identity of the task
+ * @param {int} priority the task's priority
+ * @param {Packet} queue the queue of work to be processed by the task
+ * @param {Task} task the task to add
+ */
+Scheduler.prototype.addTask = function (id, priority, queue, task) {
+ this.currentTcb = new TaskControlBlock(this.list, id, priority, queue, task);
+ this.list = this.currentTcb;
+ this.blocks[id] = this.currentTcb;
+};
+
+/**
+ * Execute the tasks managed by this scheduler.
+ */
+Scheduler.prototype.schedule = function () {
+ this.currentTcb = this.list;
+ while (this.currentTcb != null) {
+ if (this.currentTcb.isHeldOrSuspended()) {
+ this.currentTcb = this.currentTcb.link;
+ } else {
+ this.currentId = this.currentTcb.id;
+ this.currentTcb = this.currentTcb.run();
+ }
+ }
+};
+
+/**
+ * Release a task that is currently blocked and return the next block to run.
+ * @param {int} id the id of the task to suspend
+ */
+Scheduler.prototype.release = function (id) {
+ var tcb = this.blocks[id];
+ if (tcb == null) return tcb;
+ tcb.markAsNotHeld();
+ if (tcb.priority > this.currentTcb.priority) {
+ return tcb;
+ } else {
+ return this.currentTcb;
+ }
+};
+
+/**
+ * Block the currently executing task and return the next task control block
+ * to run. The blocked task will not be made runnable until it is explicitly
+ * released, even if new work is added to it.
+ */
+Scheduler.prototype.holdCurrent = function () {
+ this.holdCount++;
+ this.currentTcb.markAsHeld();
+ return this.currentTcb.link;
+};
+
+/**
+ * Suspend the currently executing task and return the next task control block
+ * to run. If new work is added to the suspended task it will be made runnable.
+ */
+Scheduler.prototype.suspendCurrent = function () {
+ this.currentTcb.markAsSuspended();
+ return this.currentTcb;
+};
+
+/**
+ * Add the specified packet to the end of the worklist used by the task
+ * associated with the packet and make the task runnable if it is currently
+ * suspended.
+ * @param {Packet} packet the packet to add
+ */
+Scheduler.prototype.queue = function (packet) {
+ var t = this.blocks[packet.id];
+ if (t == null) return t;
+ this.queueCount++;
+ packet.link = null;
+ packet.id = this.currentId;
+ return t.checkPriorityAdd(this.currentTcb, packet);
+};
+
+/**
+ * A task control block manages a task and the queue of work packages associated
+ * with it.
+ * @param {TaskControlBlock} link the preceding block in the linked block list
+ * @param {int} id the id of this block
+ * @param {int} priority the priority of this block
+ * @param {Packet} queue the queue of packages to be processed by the task
+ * @param {Task} task the task
+ * @constructor
+ */
+function TaskControlBlock(link, id, priority, queue, task) {
+ this.link = link;
+ this.id = id;
+ this.priority = priority;
+ this.queue = queue;
+ this.task = task;
+ if (queue == null) {
+ this.state = STATE_SUSPENDED;
+ } else {
+ this.state = STATE_SUSPENDED_RUNNABLE;
+ }
+}
+
+/**
+ * The task is running and is currently scheduled.
+ */
+var STATE_RUNNING = 0;
+
+/**
+ * The task has packets left to process.
+ */
+var STATE_RUNNABLE = 1;
+
+/**
+ * The task is not currently running. The task is not blocked as such and may
+* be started by the scheduler.
+ */
+var STATE_SUSPENDED = 2;
+
+/**
+ * The task is blocked and cannot be run until it is explicitly released.
+ */
+var STATE_HELD = 4;
+
+var STATE_SUSPENDED_RUNNABLE = STATE_SUSPENDED | STATE_RUNNABLE;
+var STATE_NOT_HELD = ~STATE_HELD;
+
+TaskControlBlock.prototype.setRunning = function () {
+ this.state = STATE_RUNNING;
+};
+
+TaskControlBlock.prototype.markAsNotHeld = function () {
+ this.state = this.state & STATE_NOT_HELD;
+};
+
+TaskControlBlock.prototype.markAsHeld = function () {
+ this.state = this.state | STATE_HELD;
+};
+
+TaskControlBlock.prototype.isHeldOrSuspended = function () {
+ return (this.state & STATE_HELD) != 0 || (this.state == STATE_SUSPENDED);
+};
+
+TaskControlBlock.prototype.markAsSuspended = function () {
+ this.state = this.state | STATE_SUSPENDED;
+};
+
+TaskControlBlock.prototype.markAsRunnable = function () {
+ this.state = this.state | STATE_RUNNABLE;
+};
+
+/**
+ * Runs this task, if it is ready to be run, and returns the next task to run.
+ */
+TaskControlBlock.prototype.run = function () {
+ var packet;
+ if (this.state == STATE_SUSPENDED_RUNNABLE) {
+ packet = this.queue;
+ this.queue = packet.link;
+ if (this.queue == null) {
+ this.state = STATE_RUNNING;
+ } else {
+ this.state = STATE_RUNNABLE;
+ }
+ } else {
+ packet = null;
+ }
+ return this.task.run(packet);
+};
+
+/**
+ * Adds a packet to the worklist of this block's task, marks this as runnable if
+ * necessary, and returns the next runnable object to run (the one
+ * with the highest priority).
+ */
+TaskControlBlock.prototype.checkPriorityAdd = function (task, packet) {
+ if (this.queue == null) {
+ this.queue = packet;
+ this.markAsRunnable();
+ if (this.priority > task.priority) return this;
+ } else {
+ this.queue = packet.addTo(this.queue);
+ }
+ return task;
+};
+
+TaskControlBlock.prototype.toString = function () {
+ return "tcb { " + this.task + "@" + this.state + " }";
+};
+
+/**
+ * An idle task doesn't do any work itself but cycles control between the two
+ * device tasks.
+ * @param {Scheduler} scheduler the scheduler that manages this task
+ * @param {int} v1 a seed value that controls how the device tasks are scheduled
+ * @param {int} count the number of times this task should be scheduled
+ * @constructor
+ */
+function IdleTask(scheduler, v1, count) {
+ this.scheduler = scheduler;
+ this.v1 = v1;
+ this.count = count;
+}
+
+IdleTask.prototype.run = function (packet) {
+ this.count--;
+ if (this.count == 0) return this.scheduler.holdCurrent();
+ if ((this.v1 & 1) == 0) {
+ this.v1 = this.v1 >> 1;
+ return this.scheduler.release(ID_DEVICE_A);
+ } else {
+ this.v1 = (this.v1 >> 1) ^ 0xD008;
+ return this.scheduler.release(ID_DEVICE_B);
+ }
+};
+
+IdleTask.prototype.toString = function () {
+ return "IdleTask"
+};
+
+/**
+ * A task that suspends itself after each time it has been run to simulate
+ * waiting for data from an external device.
+ * @param {Scheduler} scheduler the scheduler that manages this task
+ * @constructor
+ */
+function DeviceTask(scheduler) {
+ this.scheduler = scheduler;
+ this.v1 = null;
+}
+
+DeviceTask.prototype.run = function (packet) {
+ if (packet == null) {
+ if (this.v1 == null) return this.scheduler.suspendCurrent();
+ var v = this.v1;
+ this.v1 = null;
+ return this.scheduler.queue(v);
+ } else {
+ this.v1 = packet;
+ return this.scheduler.holdCurrent();
+ }
+};
+
+DeviceTask.prototype.toString = function () {
+ return "DeviceTask";
+};
+
+/**
+ * A task that manipulates work packets.
+ * @param {Scheduler} scheduler the scheduler that manages this task
+ * @param {int} v1 a seed used to specify how work packets are manipulated
+ * @param {int} v2 another seed used to specify how work packets are manipulated
+ * @constructor
+ */
+function WorkerTask(scheduler, v1, v2) {
+ this.scheduler = scheduler;
+ this.v1 = v1;
+ this.v2 = v2;
+}
+
+WorkerTask.prototype.run = function (packet) {
+ if (packet == null) {
+ return this.scheduler.suspendCurrent();
+ } else {
+ if (this.v1 == ID_HANDLER_A) {
+ this.v1 = ID_HANDLER_B;
+ } else {
+ this.v1 = ID_HANDLER_A;
+ }
+ packet.id = this.v1;
+ packet.a1 = 0;
+ for (var i = 0; i < DATA_SIZE; i++) {
+ this.v2++;
+ if (this.v2 > 26) this.v2 = 1;
+ packet.a2[i] = this.v2;
+ }
+ return this.scheduler.queue(packet);
+ }
+};
+
+WorkerTask.prototype.toString = function () {
+ return "WorkerTask";
+};
+
+/**
+ * A task that manipulates work packets and then suspends itself.
+ * @param {Scheduler} scheduler the scheduler that manages this task
+ * @constructor
+ */
+function HandlerTask(scheduler) {
+ this.scheduler = scheduler;
+ this.v1 = null;
+ this.v2 = null;
+}
+
+HandlerTask.prototype.run = function (packet) {
+ if (packet != null) {
+ if (packet.kind == KIND_WORK) {
+ this.v1 = packet.addTo(this.v1);
+ } else {
+ this.v2 = packet.addTo(this.v2);
+ }
+ }
+ if (this.v1 != null) {
+ var count = this.v1.a1;
+ var v;
+ if (count < DATA_SIZE) {
+ if (this.v2 != null) {
+ v = this.v2;
+ this.v2 = this.v2.link;
+ v.a1 = this.v1.a2[count];
+ this.v1.a1 = count + 1;
+ return this.scheduler.queue(v);
+ }
+ } else {
+ v = this.v1;
+ this.v1 = this.v1.link;
+ return this.scheduler.queue(v);
+ }
+ }
+ return this.scheduler.suspendCurrent();
+};
+
+HandlerTask.prototype.toString = function () {
+ return "HandlerTask";
+};
+
+/* --- *
+ * P a c k e t
+ * --- */
+
+var DATA_SIZE = 4;
+
+/**
+ * A simple package of data that is manipulated by the tasks. The exact layout
+ * of the payload data carried by a packet is not importaint, and neither is the
+ * nature of the work performed on packets by the tasks.
+ *
+ * Besides carrying data, packets form linked lists and are hence used both as
+ * data and worklists.
+ * @param {Packet} link the tail of the linked list of packets
+ * @param {int} id an ID for this packet
+ * @param {int} kind the type of this packet
+ * @constructor
+ */
+function Packet(link, id, kind) {
+ this.link = link;
+ this.id = id;
+ this.kind = kind;
+ this.a1 = 0;
+ this.a2 = new Array(DATA_SIZE);
+}
+
+/**
+ * Add this packet to the end of a worklist, and return the worklist.
+ * @param {Packet} queue the worklist to add this packet to
+ */
+Packet.prototype.addTo = function (queue) {
+ this.link = null;
+ if (queue == null) return this;
+ var peek, next = queue;
+ while ((peek = next.link) != null)
+ next = peek;
+ next.link = this;
+ return queue;
+};
+
+Packet.prototype.toString = function () {
+ return "Packet";
+};
+
+Benchmark.report("Richards", runRichards);
diff --git a/build/config/linux/pkg-config.py b/build/config/linux/pkg-config.py
index 70cc608..a7334f7 100644
--- a/build/config/linux/pkg-config.py
+++ b/build/config/linux/pkg-config.py
@@ -34,7 +34,7 @@
# success. This allows us to "kind of emulate" a Linux build from other
# platforms.
if sys.platform.find("linux") == -1:
- print "[[],[],[],[],[]]"
+ print("[[],[],[],[],[]]")
sys.exit(0)
@@ -50,7 +50,7 @@
# Compute the library path name based on the architecture.
arch = options.arch
if sysroot and not arch:
- print "You must specify an architecture via -a if using a sysroot."
+ print("You must specify an architecture via -a if using a sysroot.")
sys.exit(1)
if arch == 'x64':
libpath = 'lib64'
@@ -138,9 +138,9 @@
[options.pkg_config, "--atleast-version=" + options.atleast_version] +
args,
env=os.environ):
- print "true"
+ print("true")
else:
- print "false"
+ print("false")
sys.exit(0)
if options.libdir:
@@ -148,7 +148,7 @@
libdir = subprocess.check_output(
[options.pkg_config, "--variable=libdir"] + args, env=os.environ)
except:
- print "Error from pkg-config."
+ print("Error from pkg-config.")
sys.exit(1)
sys.stdout.write(libdir.strip())
sys.exit(0)
@@ -163,7 +163,7 @@
# to happen in practice.
all_flags = flag_string.strip().split(' ')
except:
- print "Could not run pkg-config."
+ print("Could not run pkg-config.")
sys.exit(1)
sysroot = options.sysroot
@@ -199,4 +199,4 @@
# Output a GN array, the first one is the cflags, the second are the libs. The
# JSON formatter prints GN compatible lists when everything is a list of
# strings.
-print json.dumps([includes, cflags, libs, lib_dirs, ldflags])
+print(json.dumps([includes, cflags, libs, lib_dirs, ldflags]))
diff --git a/build/config/linux/sysroot_ld_path.py b/build/config/linux/sysroot_ld_path.py
index 53b094d..a62381f 100644
--- a/build/config/linux/sysroot_ld_path.py
+++ b/build/config/linux/sysroot_ld_path.py
@@ -12,9 +12,10 @@
import sys
if len(sys.argv) != 3:
- print "Need two arguments"
+ print("Need two arguments")
sys.exit(1)
-result = subprocess.check_output([sys.argv[1], sys.argv[2]]).strip()
+result = subprocess.check_output([sys.argv[1], sys.argv[2]],
+ universal_newlines=True).strip()
-print '"' + result + '"'
+print('"' + result + '"')
diff --git a/build/config/mac/mac_app.py b/build/config/mac/mac_app.py
index 8245967..3eec8c6 100644
--- a/build/config/mac/mac_app.py
+++ b/build/config/mac/mac_app.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
diff --git a/build/detect_host_arch.py b/build/detect_host_arch.py
index 1b179cb..5d939b7 100755
--- a/build/detect_host_arch.py
+++ b/build/detect_host_arch.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
@@ -48,4 +48,4 @@
if __name__ == '__main__':
- print DoMain([])
+ print(DoMain([]))
diff --git a/build/gn_run_binary.py b/build/gn_run_binary.py
index 0c2287d..9b3c32d 100755
--- a/build/gn_run_binary.py
+++ b/build/gn_run_binary.py
@@ -1,11 +1,11 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Helper script for GN to run an arbitrary binary. See compiled_action.gni.
Run with:
- python gn_run_binary.py <invoker> <binary_name> [args ...]
+ python3 gn_run_binary.py <invoker> <binary_name> [args ...]
Where <invoker> is either "compiled_action" or "exec_script". If it is
"compiled_action" the script has a non-zero exit code on a failure. If it is
@@ -25,10 +25,14 @@
return 0
except subprocess.CalledProcessError as e:
return ("Command failed: " + ' '.join(command) + "\n" + "output: " +
- e.output)
+ _decode(e.output))
except OSError as e:
return ("Command failed: " + ' '.join(command) + "\n" + "output: " +
- e.strerror)
+ _decode(e.strerror))
+
+
+def _decode(bytes):
+ return bytes.decode("utf-8")
def main(argv):
diff --git a/build/linux/sysroot_scripts/install-sysroot.py b/build/linux/sysroot_scripts/install-sysroot.py
index cbe8fff..5e2fffe 100755
--- a/build/linux/sysroot_scripts/install-sysroot.py
+++ b/build/linux/sysroot_scripts/install-sysroot.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright (c) 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
@@ -17,14 +17,12 @@
import hashlib
import json
-import platform
import optparse
import os
-import re
import shutil
import subprocess
import sys
-import urllib2
+from urllib.request import urlopen
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.dirname(os.path.dirname(SCRIPT_DIR)))
@@ -87,7 +85,7 @@
return 0
if not options.arch:
- print 'You much specify either --arch or --running-as-hook'
+ print('You much specify either --arch or --running-as-hook')
return 1
InstallDefaultSysrootForArch(options.arch)
@@ -134,18 +132,18 @@
if s.read() == url:
return
- print 'Installing Debian %s %s root image: %s' % \
- (target_platform, target_arch, sysroot)
+ print('Installing Debian %s %s root image: %s' % \
+ (target_platform, target_arch, sysroot))
if os.path.isdir(sysroot):
shutil.rmtree(sysroot)
os.mkdir(sysroot)
tarball = os.path.join(sysroot, tarball_filename)
- print 'Downloading %s' % url
+ print('Downloading %s' % url)
sys.stdout.flush()
sys.stderr.flush()
for _ in range(3):
try:
- response = urllib2.urlopen(url)
+ response = urlopen(url)
with open(tarball, "wb") as f:
f.write(response.read())
break
diff --git a/build/mac/change_mach_o_flags.py b/build/mac/change_mach_o_flags.py
index 427117c..4155dc6 100755
--- a/build/mac/change_mach_o_flags.py
+++ b/build/mac/change_mach_o_flags.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright (c) 2011 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
diff --git a/build/mac/find_sdk.py b/build/mac/find_sdk.py
index 01d0673..d2bf424 100755
--- a/build/mac/find_sdk.py
+++ b/build/mac/find_sdk.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
@@ -6,7 +6,7 @@
given minimum sdk version to standard output.
Usage:
- python find_sdk.py 10.6 # Ignores SDKs < 10.6
+ python3 find_sdk.py 10.6 # Ignores SDKs < 10.6
"""
import os
@@ -54,7 +54,7 @@
def parse_version(version_str):
"""'10.6' => [10, 6]"""
- return map(int, re.findall(r'(\d+)', version_str))
+ return list(map(int, re.findall(r'(\d+)', version_str)))
def main():
@@ -90,11 +90,12 @@
job = subprocess.Popen(['xcode-select', '-print-path'],
stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT)
+ stderr=subprocess.STDOUT,
+ universal_newlines=True)
out, err = job.communicate()
if job.returncode != 0:
- print >> sys.stderr, out
- print >> sys.stderr, err
+ print(out, file=sys.stderr)
+ print(err, file=sys.stderr)
raise Exception((
'Error %d running xcode-select, you might have to run '
'|sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer| '
@@ -119,27 +120,26 @@
best_sdk = sorted(sdks, key=parse_version)[0]
if options.verify and best_sdk != min_sdk_version and not options.sdk_path:
- print >> sys.stderr, ''
- print >> sys.stderr, ' vvvvvvv'
- print >> sys.stderr, ''
- print >> sys.stderr, \
- 'This build requires the %s SDK, but it was not found on your system.' \
- % min_sdk_version
- print >> sys.stderr, \
- 'Either install it, or explicitly set mac_sdk in your GYP_DEFINES.'
- print >> sys.stderr, ''
- print >> sys.stderr, ' ^^^^^^^'
- print >> sys.stderr, ''
+ print('''
+ vvvvvvv
+
+This build requires the %s SDK, but it was not found on your system.
+
+Either install it, or explicitly set mac_sdk in your GYP_DEFINES.
+
+ ^^^^^^^'
+''' % min_sdk_version,
+ file=sys.stderr)
return min_sdk_version
if options.print_sdk_path:
sdk_path = subprocess.check_output(
- ['xcodebuild', '-version', '-sdk', 'macosx' + best_sdk,
- 'Path']).strip()
+ ['xcodebuild', '-version', '-sdk', 'macosx' + best_sdk, 'Path'],
+ universal_newlines=True).strip()
if options.create_symlink_at:
- print CreateSymlinkForSDKAt(sdk_path, options.create_symlink_at)
+ print(CreateSymlinkForSDKAt(sdk_path, options.create_symlink_at))
else:
- print sdk_path
+ print(sdk_path)
return best_sdk
@@ -147,4 +147,4 @@
if __name__ == '__main__':
if sys.platform != 'darwin':
raise Exception("This script only runs on Mac")
- print main()
+ print(main())
diff --git a/build/mac/strip_save_dsym b/build/mac/strip_save_dsym
index c9cf226..0b0bc7b 100755
--- a/build/mac/strip_save_dsym
+++ b/build/mac/strip_save_dsym
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright (c) 2011 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
diff --git a/build/mac/tweak_info_plist.py b/build/mac/tweak_info_plist.py
index b2a0f0c..988a1b3 100755
--- a/build/mac/tweak_info_plist.py
+++ b/build/mac/tweak_info_plist.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
@@ -68,7 +68,8 @@
if version:
match = re.match('\d+\.\d+\.(\d+\.\d+)$', version)
if not match:
- print >> sys.stderr, 'Invalid version string specified: "%s"' % version
+ print('Invalid version string specified: "%s"' % version,
+ file=sys.stderr)
return False
full_version = match.group(0)
@@ -129,7 +130,8 @@
if scm_revision != None:
plist['SCMRevision'] = scm_revision
elif add_keys:
- print >> sys.stderr, 'Could not determine SCM revision. This may be OK.'
+ print('Could not determine SCM revision. This may be OK.',
+ file=sys.stderr)
return True
@@ -162,9 +164,9 @@
components_len = len(components)
combinations = 1 << components_len
tag_suffixes = []
- for combination in xrange(0, combinations):
+ for combination in range(0, combinations):
tag_suffix = ''
- for component_index in xrange(0, components_len):
+ for component_index in range(0, components_len):
if combination & (1 << component_index):
tag_suffix += '-' + components[component_index]
tag_suffixes.append(tag_suffix)
@@ -248,7 +250,7 @@
(options, args) = parser.parse_args(argv)
if len(args) > 0:
- print >> sys.stderr, parser.get_usage()
+ print(parser.get_usage(), file=sys.stderr)
return 1
# Read the plist into its parsed format.
@@ -263,7 +265,7 @@
# Add Breakpad if configured to do so.
if options.use_breakpad:
if options.branding is None:
- print >> sys.stderr, 'Use of Breakpad requires branding.'
+ print('Use of Breakpad requires branding.', file=sys.stderr)
return 1
_AddBreakpadKeys(plist, options.branding)
if options.breakpad_uploads:
@@ -282,7 +284,7 @@
# Only add Keystone in Release builds.
if options.use_keystone and env['CONFIGURATION'] == 'Release':
if options.bundle_identifier is None:
- print >> sys.stderr, 'Use of Keystone requires the bundle id.'
+ print('Use of Keystone requires the bundle id.', file=sys.stderr)
return 1
_AddKeystoneKeys(plist, options.bundle_identifier)
else:
diff --git a/build/rust/run.py b/build/rust/run.py
index 6bdbea1..3041cf9 100755
--- a/build/rust/run.py
+++ b/build/rust/run.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# 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
@@ -15,9 +15,9 @@
bindir = os.path.dirname(cmd[0]);
env = os.environ
if 'PATH' in env:
- env['PATH'] += os.pathsep + bindir
+ env['PATH'] += os.pathsep + bindir
else:
- env['PATH'] = bindir
+ env['PATH'] = bindir
out = ''
err = ''
proc = subprocess.Popen(
@@ -29,7 +29,7 @@
err += stderr
proc.poll()
if proc.returncode == 0:
- return 0
+ return 0
print(out)
print(err)
return proc.returncode
diff --git a/build/toolchain/get_concurrent_links.py b/build/toolchain/get_concurrent_links.py
index 45e3ff5..a322526 100644
--- a/build/toolchain/get_concurrent_links.py
+++ b/build/toolchain/get_concurrent_links.py
@@ -36,7 +36,7 @@
stat = MEMORYSTATUSEX(dwLength=ctypes.sizeof(MEMORYSTATUSEX))
ctypes.windll.kernel32.GlobalMemoryStatusEx(ctypes.byref(stat))
- mem_limit = max(1, stat.ullTotalPhys / (4 * (2**30))) # total / 4GB
+ mem_limit = max(1, stat.ullTotalPhys // (4 * (2**30))) # total / 4GB
hard_cap = max(1, int(os.getenv('GYP_LINK_CONCURRENCY_MAX', 2**32)))
return min(mem_limit, hard_cap)
elif sys.platform.startswith('linux'):
@@ -48,7 +48,7 @@
if not match:
continue
# Allow 8Gb per link on Linux because Gold is quite memory hungry
- return max(1, int(match.group(1)) / (8 * (2**20)))
+ return max(1, int(match.group(1)) // (8 * (2**20)))
return 1
elif sys.platform == 'darwin':
try:
@@ -56,7 +56,7 @@
subprocess.check_output(['sysctl', '-n', 'hw.memsize']))
# A static library debug build of Chromium's unit_tests takes ~2.7GB, so
# 4GB per ld process allows for some more bloat.
- return max(1, avail_bytes / (4 * (2**30))) # total / 4GB
+ return max(1, avail_bytes // (4 * (2**30))) # total / 4GB
except Exception:
return 1
else:
@@ -64,4 +64,4 @@
return 1
-print GetDefaultConcurrentLinks()
+print(GetDefaultConcurrentLinks())
diff --git a/build/toolchain/win/BUILD.gn b/build/toolchain/win/BUILD.gn
index 16518a6..478e39c 100644
--- a/build/toolchain/win/BUILD.gn
+++ b/build/toolchain/win/BUILD.gn
@@ -26,7 +26,9 @@
visual_studio_path,
windows_sdk_path,
visual_studio_runtime_dirs,
+ "win",
current_cpu,
+ "environment." + current_cpu,
],
"scope")
diff --git a/build/toolchain/win/setup_toolchain.py b/build/toolchain/win/setup_toolchain.py
index fde043b..ee3d8ee 100644
--- a/build/toolchain/win/setup_toolchain.py
+++ b/build/toolchain/win/setup_toolchain.py
@@ -10,7 +10,8 @@
# win tool. The script assumes that the root build directory is the current dir
# and the files will be written to the current directory.
-import errno
+from __future__ import print_function
+
import json
import os
import re
@@ -22,20 +23,25 @@
SCRIPT_DIR = os.path.dirname(__file__)
-
def _ExtractImportantEnvironment(output_of_set):
"""Extracts environment variables required for the toolchain to run from
a textual dump output by the cmd.exe 'set' command."""
envvars_to_save = (
+ 'cipd_cache_dir', # needed by vpython
+ 'homedrive', # needed by vpython
+ 'homepath', # needed by vpython
'goma_.*', # TODO(scottmg): This is ugly, but needed for goma.
'include',
'lib',
'libpath',
+ 'luci_context', # needed by vpython
'path',
'pathext',
'systemroot',
'temp',
'tmp',
+ 'userprofile', # needed by vpython
+ 'vpython_virtualenv_root' # needed by vpython
)
env = {}
# This occasionally happens and leads to misleading SYSTEMROOT error messages
@@ -52,7 +58,7 @@
# path when ninja is run later, python will still be found.
setting = os.path.dirname(
sys.executable) + os.pathsep + setting
- env[var.upper()] = setting.lower()
+ env[var.upper()] = setting
break
if sys.platform in ('win32', 'cygwin'):
for required in ('SYSTEMROOT', 'TEMP', 'TMP'):
@@ -63,7 +69,7 @@
def _DetectVisualStudioPath():
- """Return path to the GYP_MSVS_VERSION of Visual Studio.
+ """Return path to the installed Visual Studio.
"""
# Use the code in build/vs_toolchain.py to avoid duplicating code.
@@ -77,31 +83,36 @@
"""Given a bat command, runs it and returns env vars set by it."""
args = args[:]
args.extend(('&&', 'set'))
- popen = subprocess.Popen(
- args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ popen = subprocess.Popen(args,
+ shell=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
variables, _ = popen.communicate()
if popen.returncode != 0:
raise Exception('"%s" failed with error %d' % (args, popen.returncode))
- return variables
+ return variables.decode(errors='ignore')
-def _LoadToolchainEnv(cpu, sdk_dir):
+def _LoadToolchainEnv(cpu, toolchain_root, sdk_dir, target_store):
"""Returns a dictionary with environment variables that must be set while
running binaries from the toolchain (e.g. INCLUDE and PATH for cl.exe)."""
# Check if we are running in the SDK command line environment and use
# the setup script from the SDK if so. |cpu| should be either
- # 'x86' or 'x64'.
- assert cpu in ('x86', 'x64')
+ # 'x86' or 'x64' or 'arm' or 'arm64'.
+ assert cpu in ('x86', 'x64', 'arm', 'arm64')
if bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', 1))) and sdk_dir:
# Load environment from json file.
- env = os.path.normpath(
- os.path.join(sdk_dir, 'bin/SetEnv.%s.json' % cpu))
+ env = os.path.normpath(os.path.join(sdk_dir,
+ 'bin/SetEnv.%s.json' % cpu))
env = json.load(open(env))['env']
+ if env['VSINSTALLDIR'] == [["..", "..\\"]]:
+ # Old-style paths were relative to the win_sdk\bin directory.
+ json_relative_dir = os.path.join(sdk_dir, 'bin')
+ else:
+ # New-style paths are relative to the toolchain directory.
+ json_relative_dir = toolchain_root
for k in env:
- entries = [
- os.path.join(*([os.path.join(sdk_dir, 'bin')] + e))
- for e in env[k]
- ]
+ entries = [os.path.join(*([json_relative_dir] + e)) for e in env[k]]
# clang-cl wants INCLUDE to be ;-separated even on non-Windows,
# lld-link wants LIB to be ;-separated even on non-Windows. Path gets :.
# The separator for INCLUDE here must match the one used in main() below.
@@ -122,8 +133,11 @@
# Check that the json file contained the same environment as the .cmd file.
if sys.platform in ('win32', 'cygwin'):
script = os.path.normpath(os.path.join(sdk_dir, 'Bin/SetEnv.cmd'))
- assert _ExtractImportantEnvironment(variables) == \
- _ExtractImportantEnvironment(_LoadEnvFromBat([script, '/' + cpu]))
+ arg = '/' + cpu
+ json_env = _ExtractImportantEnvironment(variables)
+ cmd_env = _ExtractImportantEnvironment(
+ _LoadEnvFromBat([script, arg]))
+ assert _LowercaseDict(json_env) == _LowercaseDict(cmd_env)
else:
if 'GYP_MSVS_OVERRIDE_PATH' not in os.environ:
os.environ['GYP_MSVS_OVERRIDE_PATH'] = _DetectVisualStudioPath()
@@ -134,9 +148,16 @@
if not os.path.exists(script_path):
# vcvarsall.bat for VS 2017 fails if run after running vcvarsall.bat from
# VS 2013 or VS 2015. Fix this by clearing the vsinstalldir environment
- # variable.
+ # variable. Since vcvarsall.bat appends to the INCLUDE, LIB, and LIBPATH
+ # environment variables we need to clear those to avoid getting double
+ # entries when vcvarsall.bat has been run before gn gen. vcvarsall.bat
+ # also adds to PATH, but there is no clean way of clearing that and it
+ # doesn't seem to cause problems.
if 'VSINSTALLDIR' in os.environ:
del os.environ['VSINSTALLDIR']
+ del os.environ['INCLUDE']
+ del os.environ['LIB']
+ del os.environ['LIBPATH']
other_path = os.path.normpath(
os.path.join(os.environ['GYP_MSVS_OVERRIDE_PATH'],
'VC/Auxiliary/Build/vcvarsall.bat'))
@@ -145,9 +166,21 @@
'%s is missing - make sure VC++ tools are installed.' %
script_path)
script_path = other_path
- # Chromium requires the 10.0.14393.0 SDK or higher - previous versions don't
- # have all of the required declarations.
- args = [script_path, 'amd64_x86' if cpu == 'x86' else 'amd64']
+ cpu_arg = "amd64"
+ if (cpu != 'x64'):
+ # x64 is default target CPU thus any other CPU requires a target set
+ cpu_arg += '_' + cpu
+ args = [
+ script_path,
+ cpu_arg,
+ ]
+ # Store target must come before any SDK version declaration
+ if (target_store):
+ args.append('store')
+ # Explicitly specifying the SDK version to build with to avoid accidentally
+ # building with a new and untested SDK. This should stay in sync with the
+ # packaged toolchain in build/vs_toolchain.py.
+ args.append('10.0.19041.0')
variables = _LoadEnvFromBat(args)
return _ExtractImportantEnvironment(variables)
@@ -158,68 +191,137 @@
CreateProcess documentation for more details."""
block = ''
nul = '\0'
- for key, value in envvar_dict.iteritems():
+ for key, value in envvar_dict.items():
block += key + '=' + value + nul
block += nul
return block
+def _LowercaseDict(d):
+ """Returns a copy of `d` with both key and values lowercased.
+
+ Args:
+ d: dict to lowercase (e.g. {'A': 'BcD'}).
+
+ Returns:
+ A dict with both keys and values lowercased (e.g.: {'a': 'bcd'}).
+ """
+ return {k.lower(): d[k].lower() for k in d}
+
+
+def FindFileInEnvList(env, env_name, separator, file_name, optional=False):
+ parts = env[env_name].split(separator)
+ for path in parts:
+ if os.path.exists(os.path.join(path, file_name)):
+ return os.path.realpath(path)
+ assert optional, "%s is not found in %s:\n%s\nCheck if it is installed." % (
+ file_name, env_name, '\n'.join(parts))
+ return ''
+
+
def main():
- if len(sys.argv) != 5:
+ if len(sys.argv) != 7:
print('Usage setup_toolchain.py '
'<visual studio path> <win sdk path> '
- '<runtime dirs> <target_cpu> <include prefix>')
+ '<runtime dirs> <target_os> <target_cpu> '
+ '<environment block name|none>')
sys.exit(2)
+ # toolchain_root and win_sdk_path are only read if the hermetic Windows
+ # toolchain is set, that is if DEPOT_TOOLS_WIN_TOOLCHAIN is not set to 0.
+ # With the hermetic Windows toolchain, the visual studio path in argv[1]
+ # is the root of the Windows toolchain directory.
+ toolchain_root = sys.argv[1]
win_sdk_path = sys.argv[2]
- runtime_dirs = sys.argv[3]
- target_cpu = sys.argv[4]
- cpus = ('x86', 'x64')
+ runtime_dirs = sys.argv[3]
+ target_os = sys.argv[4]
+ target_cpu = sys.argv[5]
+ environment_block_name = sys.argv[6]
+ if (environment_block_name == 'none'):
+ environment_block_name = ''
+
+ if (target_os == 'winuwp'):
+ target_store = True
+ else:
+ target_store = False
+
+ cpus = ('x86', 'x64', 'arm', 'arm64')
assert target_cpu in cpus
vc_bin_dir = ''
+ vc_lib_path = ''
+ vc_lib_atlmfc_path = ''
+ vc_lib_um_path = ''
include = ''
+ lib = ''
# TODO(scottmg|goma): Do we need an equivalent of
# ninja_use_custom_environment_files?
- for cpu in cpus:
- # Extract environment variables for subprocesses.
- env = _LoadToolchainEnv(cpu, win_sdk_path)
- env['PATH'] = runtime_dirs + os.pathsep + env['PATH']
+ def relflag(
+ s): # Make s relative to builddir when cwd and sdk on same drive.
+ try:
+ return os.path.relpath(s)
+ except ValueError:
+ return s
+ def q(s): # Quote s if it contains spaces or other weird characters.
+ return s if re.match(r'^[a-zA-Z0-9._/\\:-]*$', s) else '"' + s + '"'
+
+ for cpu in cpus:
if cpu == target_cpu:
- for path in env['PATH'].split(os.pathsep):
- if os.path.exists(os.path.join(path, 'cl.exe')):
- vc_bin_dir = os.path.realpath(path)
- break
+ # Extract environment variables for subprocesses.
+ env = _LoadToolchainEnv(cpu, toolchain_root, win_sdk_path,
+ target_store)
+ env['PATH'] = runtime_dirs + os.pathsep + env['PATH']
+
+ vc_bin_dir = FindFileInEnvList(env, 'PATH', os.pathsep, 'cl.exe')
+ vc_lib_path = FindFileInEnvList(env, 'LIB', ';', 'msvcrt.lib')
+ vc_lib_atlmfc_path = FindFileInEnvList(env,
+ 'LIB',
+ ';',
+ 'atls.lib',
+ optional=True)
+ vc_lib_um_path = FindFileInEnvList(env, 'LIB', ';', 'user32.lib')
+
# The separator for INCLUDE here must match the one used in
# _LoadToolchainEnv() above.
include = [
p.replace('"', r'\"') for p in env['INCLUDE'].split(';') if p
]
- include_I = ' '.join(['"/I' + i + '"' for i in include])
- include_imsvc = ' '.join(['"-imsvc' + i + '"' for i in include])
+ include = list(map(relflag, include))
- env_block = _FormatAsEnvironmentBlock(env)
- with open('environment.' + cpu, 'wb') as f:
- f.write(env_block)
+ lib = [p.replace('"', r'\"') for p in env['LIB'].split(';') if p]
+ lib = list(map(relflag, lib))
- # Create a store app version of the environment.
- if 'LIB' in env:
- env['LIB'] = env['LIB'].replace(r'\VC\LIB', r'\VC\LIB\STORE')
- if 'LIBPATH' in env:
- env['LIBPATH'] = env['LIBPATH'].replace(r'\VC\LIB',
- r'\VC\LIB\STORE')
- env_block = _FormatAsEnvironmentBlock(env)
- with open('environment.winrt_' + cpu, 'wb') as f:
- f.write(env_block)
+ include_I = ' '.join([q('/I' + i) for i in include])
+ include_imsvc = ' '.join([q('-imsvc' + i) for i in include])
+ libpath_flags = ' '.join([q('-libpath:' + i) for i in lib])
- assert vc_bin_dir
- print 'vc_bin_dir = ' + gn_helpers.ToGNString(vc_bin_dir)
+ if (environment_block_name != ''):
+ env_block = _FormatAsEnvironmentBlock(env)
+ with open(environment_block_name, 'w') as f:
+ f.write(env_block)
+
+ print('vc_bin_dir = ' + gn_helpers.ToGNString(vc_bin_dir))
assert include_I
- print 'include_flags_I = ' + gn_helpers.ToGNString(include_I)
+ print('include_flags_I = ' + gn_helpers.ToGNString(include_I))
assert include_imsvc
- print 'include_flags_imsvc = ' + gn_helpers.ToGNString(include_imsvc)
+ if bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN',
+ 1))) and win_sdk_path:
+ print('include_flags_imsvc = ' +
+ gn_helpers.ToGNString(q('/winsysroot' + relflag(toolchain_root))))
+ else:
+ print('include_flags_imsvc = ' + gn_helpers.ToGNString(include_imsvc))
+ print('vc_lib_path = ' + gn_helpers.ToGNString(vc_lib_path))
+ # Possible atlmfc library path gets introduced in the future for store thus
+ # output result if a result exists.
+ if (vc_lib_atlmfc_path != ''):
+ print('vc_lib_atlmfc_path = ' +
+ gn_helpers.ToGNString(vc_lib_atlmfc_path))
+ print('vc_lib_um_path = ' + gn_helpers.ToGNString(vc_lib_um_path))
+ print('paths = ' + gn_helpers.ToGNString(env['PATH']))
+ assert libpath_flags
+ print('libpath_flags = ' + gn_helpers.ToGNString(libpath_flags))
if __name__ == '__main__':
diff --git a/build/toolchain/win/tool_wrapper.py b/build/toolchain/win/tool_wrapper.py
index fbe9248..b094b2bf 100644
--- a/build/toolchain/win/tool_wrapper.py
+++ b/build/toolchain/win/tool_wrapper.py
@@ -12,7 +12,6 @@
import shutil
import subprocess
import stat
-import string
import sys
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
@@ -137,19 +136,19 @@
# Popen(['/bin/sh', '-c', args[0], args[1], ...])"
# For that reason, since going through the shell doesn't seem necessary on
# non-Windows don't do that there.
- link = subprocess.Popen(
- args,
- shell=sys.platform == 'win32',
- env=env,
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT)
+ link = subprocess.Popen(args,
+ shell=sys.platform == 'win32',
+ env=env,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ universal_newlines=True)
# Read output one line at a time as it shows up to avoid OOM failures when
# GBs of output is produced.
for line in link.stdout:
if (not line.startswith(' Creating library ') and
not line.startswith('Generating code') and
not line.startswith('Finished generating code')):
- print line,
+ print(line)
return link.wait()
def ExecMidlWrapper(self, arch, outdir, tlb, h, dlldata, iid, proxy, idl,
@@ -162,12 +161,12 @@
iid, '/proxy', proxy, idl
]
env = self._GetEnv(arch)
- popen = subprocess.Popen(
- args,
- shell=True,
- env=env,
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT)
+ popen = subprocess.Popen(args,
+ shell=True,
+ env=env,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ universal_newlines=True)
out, _ = popen.communicate()
# Filter junk out of stdout, and write filtered versions. Output we want
# to filter is pairs of lines that look like this:
@@ -179,18 +178,18 @@
os.path.basename(x) for x in lines if x.startswith(prefixes))
for line in lines:
if not line.startswith(prefixes) and line not in processing:
- print line
+ print(line)
return popen.returncode
def ExecAsmWrapper(self, arch, *args):
"""Filter logo banner from invocations of asm.exe."""
env = self._GetEnv(arch)
- popen = subprocess.Popen(
- args,
- shell=True,
- env=env,
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT)
+ popen = subprocess.Popen(args,
+ shell=True,
+ env=env,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ universal_newlines=True)
out, _ = popen.communicate()
for line in out.splitlines():
# Split to avoid triggering license checks:
@@ -198,26 +197,26 @@
') Microsoft Corporation') and
not line.startswith('Microsoft (R) Macro Assembler') and
not line.startswith(' Assembling: ') and line):
- print line
+ print(line)
return popen.returncode
def ExecRcWrapper(self, arch, *args):
"""Filter logo banner from invocations of rc.exe. Older versions of RC
don't support the /nologo flag."""
env = self._GetEnv(arch)
- popen = subprocess.Popen(
- args,
- shell=True,
- env=env,
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT)
+ popen = subprocess.Popen(args,
+ shell=True,
+ env=env,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ universal_newlines=True)
out, _ = popen.communicate()
for line in out.splitlines():
if (not line.startswith(
'Microsoft (R) Windows (R) Resource Compiler') and
not line.startswith('Copy' + 'right (C' +
') Microsoft Corporation') and line):
- print line
+ print(line)
return popen.returncode
def ExecActionWrapper(self, arch, rspfile, *dirname):
diff --git a/build/vs_toolchain.py b/build/vs_toolchain.py
index 11376198..6c9f2d3 100644
--- a/build/vs_toolchain.py
+++ b/build/vs_toolchain.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
@@ -27,18 +27,44 @@
from gn_helpers import ToGNString
+# VS 2019 16.61 with 10.0.19041 SDK, and 10.0.17134 version of
+# d3dcompiler_47.dll, with ARM64 libraries and UWP support.
+# See go/chromium-msvc-toolchain for instructions about how to update the
+# toolchain.
+#
+# When updating the toolchain, consider the following areas impacted by the
+# toolchain version:
+#
+# * //base/win/windows_version.cc NTDDI preprocessor check
+# Triggers a compiler error if the available SDK is older than the minimum.
+# * //build/config/win/BUILD.gn NTDDI_VERSION value
+# Affects the availability of APIs in the toolchain headers.
+# * //docs/windows_build_instructions.md mentions of VS or Windows SDK.
+# Keeps the document consistent with the toolchain version.
+TOOLCHAIN_HASH = '20d5f2553f'
+
script_dir = os.path.dirname(os.path.realpath(__file__))
-chrome_src = os.path.abspath(os.path.join(script_dir, os.pardir))
-SRC_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-sys.path.insert(0, os.path.join(chrome_src, 'tools'))
+dart_src = os.path.abspath(os.path.join(script_dir, os.pardir))
+sys.path.insert(0, os.path.join(dart_src, 'tools'))
json_data_file = os.path.join(script_dir, 'win_toolchain.json')
# VS versions are listed in descending order of priority (highest first).
MSVS_VERSIONS = collections.OrderedDict([
- ('2017', '15.0'),
('2019', '16.0'),
+ ('2017', '15.0'),
])
+# List of preferred VC toolset version based on MSVS
+MSVC_TOOLSET_VERSION = {
+ '2019': 'VC142',
+ '2017': 'VC141',
+}
+
+
+def _HostIsWindows():
+ """Returns True if running on a Windows host (including under cygwin)."""
+ return sys.platform in ('win32', 'cygwin')
+
def SetEnvironmentAndGetRuntimeDllDirs():
"""Sets up os.environ to use the depot_tools VS toolchain with gyp, and
@@ -54,24 +80,22 @@
bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1')))
# When running on a non-Windows host, only do this if the SDK has explicitly
# been downloaded before (in which case json_data_file will exist).
- if ((sys.platform in ('win32', 'cygwin') or os.path.exists(json_data_file))
- and depot_tools_win_toolchain):
+ if ((_HostIsWindows() or os.path.exists(json_data_file)) and
+ depot_tools_win_toolchain):
if ShouldUpdateToolchain():
if len(sys.argv) > 1 and sys.argv[1] == 'update':
update_result = Update()
else:
update_result = Update(no_download=True)
if update_result != 0:
- raise Exception(
- 'Failed to update, error code %d.' % update_result)
+ raise Exception('Failed to update, error code %d.' %
+ update_result)
with open(json_data_file, 'r') as tempf:
toolchain_data = json.load(tempf)
toolchain = toolchain_data['path']
version = toolchain_data['version']
win_sdk = toolchain_data.get('win_sdk')
- if not win_sdk:
- win_sdk = toolchain_data['win8sdk']
wdk = toolchain_data['wdk']
# TODO(scottmg): The order unfortunately matters in these. They should be
# split into separate keys for x64/x86/arm64. (See CopyDlls call below).
@@ -84,7 +108,6 @@
vs_runtime_dll_dirs.append('Arm64Unused')
os.environ['GYP_MSVS_OVERRIDE_PATH'] = toolchain
- os.environ['GYP_MSVS_VERSION'] = version
os.environ['WINDOWSSDKDIR'] = win_sdk
os.environ['WDK_DIR'] = wdk
@@ -94,8 +117,6 @@
elif sys.platform == 'win32' and not depot_tools_win_toolchain:
if not 'GYP_MSVS_OVERRIDE_PATH' in os.environ:
os.environ['GYP_MSVS_OVERRIDE_PATH'] = DetectVisualStudioPath()
- if not 'GYP_MSVS_VERSION' in os.environ:
- os.environ['GYP_MSVS_VERSION'] = GetVisualStudioVersion()
# When using an installed toolchain these files aren't needed in the output
# directory in order to run binaries locally, but they are needed in order
@@ -146,12 +167,7 @@
def GetVisualStudioVersion():
"""Return best available version of Visual Studio.
"""
-
- env_version = os.environ.get('GYP_MSVS_VERSION')
- if env_version:
- return env_version
-
- supported_versions = MSVS_VERSIONS.keys()
+ supported_versions = list(MSVS_VERSIONS.keys())
# VS installed in depot_tools for Googlers
if bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1'))):
@@ -162,13 +178,23 @@
'{} ({})'.format(v, k) for k, v in MSVS_VERSIONS.items())
available_versions = []
for version in supported_versions:
- for path in (
- os.environ.get('vs%s_install' % version),
- os.path.expandvars('%ProgramFiles(x86)%' +
- '/Microsoft Visual Studio/%s' % version)):
- if path and os.path.exists(path):
- available_versions.append(version)
- break
+ # Checking vs%s_install environment variables.
+ # For example, vs2019_install could have the value
+ # "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community".
+ # Only vs2017_install and vs2019_install are supported.
+ path = os.environ.get('vs%s_install' % version)
+ if path and os.path.exists(path):
+ available_versions.append(version)
+ break
+ # Detecting VS under possible paths.
+ path = os.path.expandvars('%ProgramFiles(x86)%' +
+ '/Microsoft Visual Studio/%s' % version)
+ if path and any(
+ os.path.exists(os.path.join(path, edition))
+ for edition in ('Enterprise', 'Professional', 'Community',
+ 'Preview', 'BuildTools')):
+ available_versions.append(version)
+ break
if not available_versions:
raise Exception('No supported Visual Studio can be found.'
@@ -177,7 +203,7 @@
def DetectVisualStudioPath():
- """Return path to the GYP_MSVS_VERSION of Visual Studio.
+ """Return path to the installed Visual Studio.
"""
# Note that this code is used from
@@ -188,25 +214,26 @@
# the registry. For details see:
# https://blogs.msdn.microsoft.com/heaths/2016/09/15/changes-to-visual-studio-15-setup/
# For now we use a hardcoded default with an environment variable override.
- for path in (
- os.environ.get('vs%s_install' % version_as_year),
- os.path.expandvars(
- '%ProgramFiles(x86)%' +
- '/Microsoft Visual Studio/%s/Enterprise' % version_as_year),
- os.path.expandvars(
- '%ProgramFiles(x86)%' +
- '/Microsoft Visual Studio/%s/Professional' % version_as_year),
- os.path.expandvars(
- '%ProgramFiles(x86)%' +
- '/Microsoft Visual Studio/%s/Community' % version_as_year),
- os.path.expandvars(
- '%ProgramFiles(x86)%' +
- '/Microsoft Visual Studio/%s/Preview' % version_as_year)):
+ for path in (os.environ.get('vs%s_install' % version_as_year),
+ os.path.expandvars('%ProgramFiles(x86)%' +
+ '/Microsoft Visual Studio/%s/Enterprise' %
+ version_as_year),
+ os.path.expandvars('%ProgramFiles(x86)%' +
+ '/Microsoft Visual Studio/%s/Professional' %
+ version_as_year),
+ os.path.expandvars('%ProgramFiles(x86)%' +
+ '/Microsoft Visual Studio/%s/Community' %
+ version_as_year),
+ os.path.expandvars('%ProgramFiles(x86)%' +
+ '/Microsoft Visual Studio/%s/Preview' %
+ version_as_year),
+ os.path.expandvars('%ProgramFiles(x86)%' +
+ '/Microsoft Visual Studio/%s/BuildTools' %
+ version_as_year)):
if path and os.path.exists(path):
return path
- raise Exception('Visual Studio Version %s (from GYP_MSVS_VERSION)'
- ' not found.' % version_as_year)
+ raise Exception('Visual Studio Version %s not found.' % version_as_year)
def _CopyRuntimeImpl(target, source, verbose=True):
@@ -251,21 +278,28 @@
list_of_str_versions.sort(key=to_number_sequence, reverse=True)
-def _CopyUCRTRuntime(target_dir, source_dir, target_cpu, dll_pattern, suffix):
+def _CopyUCRTRuntime(target_dir, source_dir, target_cpu, suffix):
"""Copy both the msvcp and vccorlib runtime DLLs, only if the target doesn't
exist, but the target directory does exist."""
if target_cpu == 'arm64':
# Windows ARM64 VCRuntime is located at {toolchain_root}/VC/Redist/MSVC/
- # {x.y.z}/[debug_nonredist/]arm64/Microsoft.VC141.CRT/.
+ # {x.y.z}/[debug_nonredist/]arm64/Microsoft.VC14x.CRT/.
+ # Select VC toolset directory based on Visual Studio version
vc_redist_root = FindVCRedistRoot()
if suffix.startswith('.'):
- source_dir = os.path.join(vc_redist_root, 'arm64',
- 'Microsoft.VC141.CRT')
+ vc_toolset_dir = 'Microsoft.{}.CRT' \
+ .format(MSVC_TOOLSET_VERSION[GetVisualStudioVersion()])
+ source_dir = os.path.join(vc_redist_root, 'arm64', vc_toolset_dir)
else:
+ vc_toolset_dir = 'Microsoft.{}.DebugCRT' \
+ .format(MSVC_TOOLSET_VERSION[GetVisualStudioVersion()])
source_dir = os.path.join(vc_redist_root, 'debug_nonredist',
- 'arm64', 'Microsoft.VC141.DebugCRT')
- for file_part in ('msvcp', 'vccorlib', 'vcruntime'):
- dll = dll_pattern % file_part
+ 'arm64', vc_toolset_dir)
+ file_parts = ('msvcp140', 'vccorlib140', 'vcruntime140')
+ if target_cpu == 'x64' and GetVisualStudioVersion() != '2017':
+ file_parts = file_parts + ('vcruntime140_1',)
+ for file_part in file_parts:
+ dll = file_part + suffix
target = os.path.join(target_dir, dll)
source = os.path.join(source_dir, dll)
_CopyRuntimeImpl(target, source)
@@ -301,22 +335,19 @@
if not suffix.startswith('.'):
# ucrtbased.dll is located at {win_sdk_dir}/bin/{a.b.c.d}/{target_cpu}/
# ucrt/.
- sdk_redist_root = os.path.join(win_sdk_dir, 'bin')
- sdk_bin_sub_dirs = os.listdir(sdk_redist_root)
+ sdk_bin_root = os.path.join(win_sdk_dir, 'bin')
+ sdk_bin_sub_dirs = glob.glob(os.path.join(sdk_bin_root, '10.*'))
# Select the most recent SDK if there are multiple versions installed.
_SortByHighestVersionNumberFirst(sdk_bin_sub_dirs)
for directory in sdk_bin_sub_dirs:
- sdk_redist_root_version = os.path.join(sdk_redist_root,
- directory)
+ sdk_redist_root_version = os.path.join(sdk_bin_root, directory)
if not os.path.isdir(sdk_redist_root_version):
continue
- if re.match(r'10\.\d+\.\d+\.\d+', directory):
- source_dir = os.path.join(sdk_redist_root_version,
- target_cpu, 'ucrt')
- break
- _CopyRuntimeImpl(
- os.path.join(target_dir, 'ucrtbase' + suffix),
- os.path.join(source_dir, 'ucrtbase' + suffix))
+ source_dir = os.path.join(sdk_redist_root_version, target_cpu,
+ 'ucrt')
+ break
+ _CopyRuntimeImpl(os.path.join(target_dir, 'ucrtbase' + suffix),
+ os.path.join(source_dir, 'ucrtbase' + suffix))
def FindVCComponentRoot(component):
@@ -330,14 +361,13 @@
assert ('GYP_MSVS_OVERRIDE_PATH' in os.environ)
vc_component_msvc_root = os.path.join(os.environ['GYP_MSVS_OVERRIDE_PATH'],
'VC', component, 'MSVC')
- vc_component_msvc_contents = os.listdir(vc_component_msvc_root)
+ vc_component_msvc_contents = glob.glob(
+ os.path.join(vc_component_msvc_root, '14.*'))
# Select the most recent toolchain if there are several.
_SortByHighestVersionNumberFirst(vc_component_msvc_contents)
for directory in vc_component_msvc_contents:
- if not os.path.isdir(os.path.join(vc_component_msvc_root, directory)):
- continue
- if re.match(r'14\.\d+\.\d+', directory):
- return os.path.join(vc_component_msvc_root, directory)
+ if os.path.isdir(directory):
+ return directory
raise Exception('Unable to find the VC %s directory.' % component)
@@ -355,8 +385,7 @@
directory does exist. Handles VS 2015, 2017 and 2019."""
suffix = 'd.dll' if debug else '.dll'
# VS 2015, 2017 and 2019 use the same CRT DLLs.
- _CopyUCRTRuntime(target_dir, source_dir, target_cpu, '%s140' + suffix,
- suffix)
+ _CopyUCRTRuntime(target_dir, source_dir, target_cpu, suffix)
def CopyDlls(target_dir, configuration, target_cpu):
@@ -407,6 +436,10 @@
# List of debug files that should be copied, the first element of the tuple is
# the name of the file and the second indicates if it's optional.
debug_files = [('dbghelp.dll', False), ('dbgcore.dll', True)]
+ # The UCRT is not a redistributable component on arm64.
+ if target_cpu != 'arm64':
+ debug_files.extend([('api-ms-win-downlevel-kernel32-l2-1-0.dll', False),
+ ('api-ms-win-eventing-provider-l1-1-0.dll', False)])
for debug_file, is_optional in debug_files:
full_path = os.path.join(win_sdk_dir, 'Debuggers', target_cpu,
debug_file)
@@ -414,11 +447,11 @@
if is_optional:
continue
else:
- # TODO(crbug.com/773476): remove version requirement.
raise Exception(
- '%s not found in "%s"\r\nYou must install the '
- '"Debugging Tools for Windows" feature from the Windows'
- ' 10 SDK.' % (debug_file, full_path))
+ '%s not found in "%s"\r\nYou must install'
+ 'Windows 10 SDK version 10.0.19041.0 including the '
+ '"Debugging Tools for Windows" feature.' %
+ (debug_file, full_path))
target_path = os.path.join(target_dir, debug_file)
_CopyRuntimeImpl(target_path, full_path)
@@ -426,17 +459,10 @@
def _GetDesiredVsToolchainHashes():
"""Load a list of SHA1s corresponding to the toolchains that we want installed
to build with."""
- env_version = GetVisualStudioVersion()
- if env_version == '2017':
- # VS 2017 Update 9 (15.9.12) with 10.0.18362 SDK, 10.0.17763 version of
- # Debuggers, and 10.0.17134 version of d3dcompiler_47.dll, with ARM64
- # libraries.
- toolchain_hash = '418b3076791776573a815eb298c8aa590307af63'
- # Third parties that do not have access to the canonical toolchain can map
- # canonical toolchain version to their own toolchain versions.
- toolchain_hash_mapping_key = 'GYP_MSVS_HASH_%s' % toolchain_hash
- return [os.environ.get(toolchain_hash_mapping_key, toolchain_hash)]
- raise Exception('Unsupported VS version %s' % env_version)
+ # Third parties that do not have access to the canonical toolchain can map
+ # canonical toolchain version to their own toolchain versions.
+ toolchain_hash_mapping_key = 'GYP_MSVS_HASH_%s' % TOOLCHAIN_HASH
+ return [os.environ.get(toolchain_hash_mapping_key, TOOLCHAIN_HASH)]
def ShouldUpdateToolchain():
@@ -467,8 +493,7 @@
depot_tools_win_toolchain = \
bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1')))
- if ((sys.platform in ('win32', 'cygwin') or force) and
- depot_tools_win_toolchain):
+ if (_HostIsWindows() or force) and depot_tools_win_toolchain:
import find_depot_tools
depot_tools_path = find_depot_tools.add_depot_tools_to_path()
@@ -500,11 +525,9 @@
toolchain_dir
])
- # Necessary so that get_toolchain_if_necessary.py will put the VS toolkit
- # in the correct directory.
- os.environ['GYP_MSVS_VERSION'] = GetVisualStudioVersion()
get_toolchain_args = [
- sys.executable,
+ # TODO(athom): use sys.executable (python3).
+ 'python',
os.path.join(depot_tools_path, 'win_toolchain',
'get_toolchain_if_necessary.py'),
'--output-json',
diff --git a/build/win/importlibs/create_importlib_win.py b/build/win/importlibs/create_importlib_win.py
index 401b6e8..b23a7c0 100755
--- a/build/win/importlibs/create_importlib_win.py
+++ b/build/win/importlibs/create_importlib_win.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
diff --git a/build/win/importlibs/filter_export_list.py b/build/win/importlibs/filter_export_list.py
index 23fe362..b1fc122 100755
--- a/build/win/importlibs/filter_export_list.py
+++ b/build/win/importlibs/filter_export_list.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
@@ -79,7 +79,7 @@
found_exports = set(master_mapping.values()) - set(found_exports)
# Sort the found exports for tidy output.
- print '\n'.join(sorted(found_exports))
+ print('\n'.join(sorted(found_exports)))
return 0
diff --git a/build/win/reorder-imports.py b/build/win/reorder-imports.py
index f96a9ec..45c4c9a 100755
--- a/build/win/reorder-imports.py
+++ b/build/win/reorder-imports.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
diff --git a/build/win/use_ansi_codes.py b/build/win/use_ansi_codes.py
index b24ae24..c453c7b 100755
--- a/build/win/use_ansi_codes.py
+++ b/build/win/use_ansi_codes.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright (c) 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
@@ -7,4 +7,4 @@
import os
# Add more terminals here as needed.
-print 'ANSICON' in os.environ
+print('ANSICON' in os.environ)
diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
index bfa4d8d..f75600c 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -1261,28 +1261,6 @@
r"""A constant constructor can't call a non-constant super constructor.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Template<Message Function(String stringOKEmpty)>
- templateConstEvalBadState =
- const Template<Message Function(String stringOKEmpty)>(
- messageTemplate: r"""Bad state: '#stringOKEmpty'""",
- withArguments: _withArgumentsConstEvalBadState);
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Code<Message Function(String stringOKEmpty)> codeConstEvalBadState =
- const Code<Message Function(String stringOKEmpty)>(
- "ConstEvalBadState",
-);
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-Message _withArgumentsConstEvalBadState(String stringOKEmpty) {
- // ignore: unnecessary_null_comparison
- if (stringOKEmpty == null || stringOKEmpty.isEmpty) stringOKEmpty = '(empty)';
- return new Message(codeConstEvalBadState,
- message: """Bad state: '${stringOKEmpty}'""",
- arguments: {'stringOKEmpty': stringOKEmpty});
-}
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeConstEvalCircularity = messageConstEvalCircularity;
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -1561,6 +1539,29 @@
message: r"""Couldn't evaluate constant expression.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<Message Function(String stringOKEmpty)>
+ templateConstEvalUnhandledCoreException =
+ const Template<Message Function(String stringOKEmpty)>(
+ messageTemplate: r"""Unhandled core exception: #stringOKEmpty""",
+ withArguments: _withArgumentsConstEvalUnhandledCoreException);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String stringOKEmpty)>
+ codeConstEvalUnhandledCoreException =
+ const Code<Message Function(String stringOKEmpty)>(
+ "ConstEvalUnhandledCoreException",
+);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsConstEvalUnhandledCoreException(String stringOKEmpty) {
+ // ignore: unnecessary_null_comparison
+ if (stringOKEmpty == null || stringOKEmpty.isEmpty) stringOKEmpty = '(empty)';
+ return new Message(codeConstEvalUnhandledCoreException,
+ message: """Unhandled core exception: ${stringOKEmpty}""",
+ arguments: {'stringOKEmpty': stringOKEmpty});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<
Message Function(
String string,
@@ -3735,26 +3736,30 @@
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<
- Message Function(String name)> templateFfiEmptyStruct = const Template<
- Message Function(String name)>(
+ Message Function(
+ String string,
+ String
+ name)> templateFfiEmptyStruct = const Template<
+ Message Function(String string, String name)>(
messageTemplate:
- r"""Struct '#name' is empty. Empty structs are undefined behavior.""",
+ r"""#string '#name' is empty. Empty structs and unions are undefined behavior.""",
withArguments: _withArgumentsFfiEmptyStruct);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Code<Message Function(String name)> codeFfiEmptyStruct =
- const Code<Message Function(String name)>(
+const Code<Message Function(String string, String name)> codeFfiEmptyStruct =
+ const Code<Message Function(String string, String name)>(
"FfiEmptyStruct",
);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-Message _withArgumentsFfiEmptyStruct(String name) {
+Message _withArgumentsFfiEmptyStruct(String string, String name) {
+ if (string.isEmpty) throw 'No string provided';
if (name.isEmpty) throw 'No name provided';
name = demangleMixinApplicationName(name);
return new Message(codeFfiEmptyStruct,
message:
- """Struct '${name}' is empty. Empty structs are undefined behavior.""",
- arguments: {'name': name});
+ """${string} '${name}' is empty. Empty structs and unions are undefined behavior.""",
+ arguments: {'string': string, 'name': name});
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3802,7 +3807,7 @@
Message Function(String name)> templateFfiFieldAnnotation = const Template<
Message Function(String name)>(
messageTemplate:
- r"""Field '#name' requires exactly one annotation to declare its native 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 and Unions cannot have regular Dart fields.""",
withArguments: _withArgumentsFfiFieldAnnotation);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3817,33 +3822,36 @@
name = demangleMixinApplicationName(name);
return new Message(codeFfiFieldAnnotation,
message:
- """Field '${name}' requires exactly one annotation to declare its native 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 and Unions cannot have regular Dart fields.""",
arguments: {'name': name});
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Template<Message Function(String name, List<String> _names)>
- templateFfiFieldCyclic =
- const Template<Message Function(String name, List<String> _names)>(
- messageTemplate: r"""Struct '#name' contains itself. Cycle elements:
+const Template<
+ Message Function(String string, String name, List<String> _names)>
+ templateFfiFieldCyclic = const Template<
+ Message Function(String string, String name, List<String> _names)>(
+ messageTemplate: r"""#string '#name' contains itself. Cycle elements:
#names""", withArguments: _withArgumentsFfiFieldCyclic);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Code<Message Function(String name, List<String> _names)>
- codeFfiFieldCyclic =
- const Code<Message Function(String name, List<String> _names)>(
+const Code<Message Function(String string, String name, List<String> _names)>
+ codeFfiFieldCyclic = const Code<
+ Message Function(String string, String name, List<String> _names)>(
"FfiFieldCyclic",
);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-Message _withArgumentsFfiFieldCyclic(String name, List<String> _names) {
+Message _withArgumentsFfiFieldCyclic(
+ String string, String name, List<String> _names) {
+ if (string.isEmpty) throw 'No string provided';
if (name.isEmpty) throw 'No name provided';
name = demangleMixinApplicationName(name);
if (_names.isEmpty) throw 'No names provided';
String names = itemizeNames(_names);
return new Message(codeFfiFieldCyclic,
- message: """Struct '${name}' contains itself. Cycle elements:
-${names}""", arguments: {'name': name, 'names': _names});
+ message: """${string} '${name}' contains itself. Cycle elements:
+${names}""", arguments: {'string': string, 'name': name, 'names': _names});
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3904,7 +3912,7 @@
Message Function(String name)> templateFfiFieldNull = const Template<
Message Function(String name)>(
messageTemplate:
- r"""Field '#name' cannot have type 'Null', it must be `int`, `double`, `Pointer`, or a subtype of `Struct`.""",
+ r"""Field '#name' cannot have type 'Null', it must be `int`, `double`, `Pointer`, or a subtype of `Struct` or `Union`.""",
withArguments: _withArgumentsFfiFieldNull);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3919,7 +3927,7 @@
name = demangleMixinApplicationName(name);
return new Message(codeFfiFieldNull,
message:
- """Field '${name}' cannot have type 'Null', it must be `int`, `double`, `Pointer`, or a subtype of `Struct`.""",
+ """Field '${name}' cannot have type 'Null', it must be `int`, `double`, `Pointer`, or a subtype of `Struct` or `Union`.""",
arguments: {'name': name});
}
@@ -4058,24 +4066,26 @@
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Template<Message Function(String name)> templateFfiStructGeneric =
- const Template<Message Function(String name)>(
- messageTemplate: r"""Struct '#name' should not be generic.""",
+const Template<Message Function(String string, String name)>
+ templateFfiStructGeneric =
+ const Template<Message Function(String string, String name)>(
+ messageTemplate: r"""#string '#name' should not be generic.""",
withArguments: _withArgumentsFfiStructGeneric);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Code<Message Function(String name)> codeFfiStructGeneric =
- const Code<Message Function(String name)>(
+const Code<Message Function(String string, String name)> codeFfiStructGeneric =
+ const Code<Message Function(String string, String name)>(
"FfiStructGeneric",
);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-Message _withArgumentsFfiStructGeneric(String name) {
+Message _withArgumentsFfiStructGeneric(String string, String name) {
+ if (string.isEmpty) throw 'No string provided';
if (name.isEmpty) throw 'No name provided';
name = demangleMixinApplicationName(name);
return new Message(codeFfiStructGeneric,
- message: """Struct '${name}' should not be generic.""",
- arguments: {'name': name});
+ message: """${string} '${name}' should not be generic.""",
+ arguments: {'string': string, 'name': name});
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/argument_type_not_assignable_nullability_error.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/argument_type_not_assignable_nullability_error.dart
index a5c894b..3421716 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/argument_type_not_assignable_nullability_error.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/argument_type_not_assignable_nullability_error.dart
@@ -13,9 +13,8 @@
required_unnamed(C1 c) {
if (c.bad == null) return;
- c.f(
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C1.bad, type: int?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C1.bad, type: int?))*/ bad);
+ c.f(c.
+ /*notPromoted(propertyNotPromoted(target: member:C1.bad, type: int?))*/ bad);
}
class C2 {
@@ -25,9 +24,8 @@
optional_unnamed(C2 c) {
if (c.bad == null) return;
- c.f(
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C2.bad, type: int?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C2.bad, type: int?))*/ bad);
+ c.f(c.
+ /*notPromoted(propertyNotPromoted(target: member:C2.bad, type: int?))*/ bad);
}
class C3 {
@@ -38,8 +36,8 @@
required_named(C3 c) {
if (c.bad == null) return;
c.f(
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C3.bad, type: int?))*/ i:
- c. /*cfe.notPromoted(propertyNotPromoted(target: member:C3.bad, type: int?))*/ bad);
+ i: c.
+ /*notPromoted(propertyNotPromoted(target: member:C3.bad, type: int?))*/ bad);
}
class C4 {
@@ -50,8 +48,8 @@
optional_named(C4 c) {
if (c.bad == null) return;
c.f(
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C4.bad, type: int?))*/ i:
- c. /*cfe.notPromoted(propertyNotPromoted(target: member:C4.bad, type: int?))*/ bad);
+ i: c.
+ /*notPromoted(propertyNotPromoted(target: member:C4.bad, type: int?))*/ bad);
}
class C5 {
@@ -61,9 +59,8 @@
type_inferred(C5 c) {
if (c.bad == null) return;
- c.f(
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C5.bad, type: List<int>?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C5.bad, type: List<int>?))*/ bad);
+ c.f(c.
+ /*notPromoted(propertyNotPromoted(target: member:C5.bad, type: List<int>?))*/ bad);
}
class C6 {
@@ -73,9 +70,8 @@
C6? constructor_with_implicit_new(C6 c) {
if (c.bad == null) return null;
- return C6(
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C6.bad, type: int?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C6.bad, type: int?))*/ bad);
+ return C6(c.
+ /*notPromoted(propertyNotPromoted(target: member:C6.bad, type: int?))*/ bad);
}
class C7 {
@@ -85,9 +81,8 @@
C7? constructor_with_explicit_new(C7 c) {
if (c.bad == null) return null;
- return new C7(
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C7.bad, type: int?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C7.bad, type: int?))*/ bad);
+ return new C7(c.
+ /*notPromoted(propertyNotPromoted(target: member:C7.bad, type: int?))*/ bad);
}
class C8 {
@@ -97,8 +92,8 @@
userDefinableBinaryOpRhs(C8 c) {
if (c.bad == null) return;
1 +
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C8.bad, type: int?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C8.bad, type: int?))*/ bad;
+ c.
+ /*notPromoted(propertyNotPromoted(target: member:C8.bad, type: int?))*/ bad;
}
class C9 {
@@ -140,13 +135,12 @@
andOperand(C11 c, bool b) {
if (c.bad == null) return;
- c.f(
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C11.bad, type: bool?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C11.bad, type: bool?))*/ bad &&
- b);
+ c.f(c.
+ /*notPromoted(propertyNotPromoted(target: member:C11.bad, type: bool?))*/ bad &&
+ b);
c.f(b &&
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C11.bad, type: bool?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C11.bad, type: bool?))*/ bad);
+ c.
+ /*notPromoted(propertyNotPromoted(target: member:C11.bad, type: bool?))*/ bad);
}
class C12 {
@@ -156,13 +150,12 @@
orOperand(C12 c, bool b) {
if (c.bad == null) return;
- c.f(
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C12.bad, type: bool?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C12.bad, type: bool?))*/ bad ||
- b);
+ c.f(c.
+ /*notPromoted(propertyNotPromoted(target: member:C12.bad, type: bool?))*/ bad ||
+ b);
c.f(b ||
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C12.bad, type: bool?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C12.bad, type: bool?))*/ bad);
+ c.
+ /*notPromoted(propertyNotPromoted(target: member:C12.bad, type: bool?))*/ bad);
}
class C13 {
@@ -171,18 +164,16 @@
assertStatementCondition(C13 c) {
if (c.bad == null) return;
- assert(
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C13.bad, type: bool?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C13.bad, type: bool?))*/ bad);
+ assert(c.
+ /*notPromoted(propertyNotPromoted(target: member:C13.bad, type: bool?))*/ bad);
}
class C14 {
bool? bad;
C14.assertInitializerCondition(C14 c)
: bad = c.bad!,
- assert(
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C14.bad, type: bool?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C14.bad, type: bool?))*/ bad);
+ assert(c.
+ /*notPromoted(propertyNotPromoted(target: member:C14.bad, type: bool?))*/ bad);
}
class C15 {
@@ -192,9 +183,8 @@
notOperand(C15 c) {
if (c.bad == null) return;
- c.f(!
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C15.bad, type: bool?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C15.bad, type: bool?))*/ bad);
+ c.f(!c.
+ /*notPromoted(propertyNotPromoted(target: member:C15.bad, type: bool?))*/ bad);
}
class C16 {
@@ -205,24 +195,24 @@
forLoopCondition(C16 c) {
if (c.bad == null) return;
for (;
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C16.bad, type: bool?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C16.bad, type: bool?))*/ bad;) {}
+ c.
+ /*notPromoted(propertyNotPromoted(target: member:C16.bad, type: bool?))*/ bad;) {}
[
for (;
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C16.bad, type: bool?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C16.bad, type: bool?))*/ bad;)
+ c.
+ /*notPromoted(propertyNotPromoted(target: member:C16.bad, type: bool?))*/ bad;)
null
];
({
for (;
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C16.bad, type: bool?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C16.bad, type: bool?))*/ bad;)
+ c.
+ /*notPromoted(propertyNotPromoted(target: member:C16.bad, type: bool?))*/ bad;)
null
});
({
for (;
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C16.bad, type: bool?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C16.bad, type: bool?))*/ bad;)
+ c.
+ /*notPromoted(propertyNotPromoted(target: member:C16.bad, type: bool?))*/ bad;)
null: null
});
}
@@ -234,11 +224,10 @@
conditionalExpressionCondition(C17 c) {
if (c.bad == null) return;
- c.f(
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C17.bad, type: bool?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C17.bad, type: bool?))*/ bad
- ? 1
- : 2);
+ c.f(c.
+ /*notPromoted(propertyNotPromoted(target: member:C17.bad, type: bool?))*/ bad
+ ? 1
+ : 2);
}
class C18 {
@@ -247,9 +236,8 @@
doLoopCondition(C18 c) {
if (c.bad == null) return;
- do {} while (
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C18.bad, type: bool?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C18.bad, type: bool?))*/ bad);
+ do {} while (c.
+ /*notPromoted(propertyNotPromoted(target: member:C18.bad, type: bool?))*/ bad);
}
class C19 {
@@ -258,25 +246,21 @@
ifCondition(C19 c) {
if (c.bad == null) return;
- if (
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C19.bad, type: bool?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C19.bad, type: bool?))*/ bad) {}
+ if (c.
+ /*notPromoted(propertyNotPromoted(target: member:C19.bad, type: bool?))*/ bad) {}
[
- if (
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C19.bad, type: bool?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C19.bad, type: bool?))*/ bad)
+ if (c.
+ /*notPromoted(propertyNotPromoted(target: member:C19.bad, type: bool?))*/ bad)
null
];
({
- if (
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C19.bad, type: bool?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C19.bad, type: bool?))*/ bad)
+ if (c.
+ /*notPromoted(propertyNotPromoted(target: member:C19.bad, type: bool?))*/ bad)
null
});
({
- if (
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C19.bad, type: bool?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C19.bad, type: bool?))*/ bad)
+ if (c.
+ /*notPromoted(propertyNotPromoted(target: member:C19.bad, type: bool?))*/ bad)
null: null
});
}
@@ -287,8 +271,8 @@
whileCondition(C20 c) {
if (c.bad == null) return;
- while (/*analyzer.notPromoted(propertyNotPromoted(target: member:C20.bad, type: bool?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C20.bad, type: bool?))*/ bad) {}
+ while (c.
+ /*notPromoted(propertyNotPromoted(target: member:C20.bad, type: bool?))*/ bad) {}
}
class C21 {
@@ -297,9 +281,8 @@
assignmentRhs(C21 c, int i) {
if (c.bad == null) return;
- i =
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C21.bad, type: int?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C21.bad, type: int?))*/ bad;
+ i = c.
+ /*notPromoted(propertyNotPromoted(target: member:C21.bad, type: int?))*/ bad;
}
class C22 {
@@ -308,9 +291,8 @@
variableInitializer(C22 c) {
if (c.bad == null) return;
- int i =
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C22.bad, type: int?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C22.bad, type: int?))*/ bad;
+ int i = c.
+ /*notPromoted(propertyNotPromoted(target: member:C22.bad, type: int?))*/ bad;
}
class C23 {
@@ -319,9 +301,8 @@
final int y;
C23.constructorInitializer(C23 c)
: x = c.bad!,
- y =
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C23.bad, type: int?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C23.bad, type: int?))*/ bad;
+ y = c.
+ /*notPromoted(propertyNotPromoted(target: member:C23.bad, type: int?))*/ bad;
}
class C24 {
@@ -330,28 +311,24 @@
forVariableInitializer(C24 c) {
if (c.bad == null) return;
- for (int i =
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C24.bad, type: int?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C24.bad, type: int?))*/ bad;
+ for (int i = c.
+ /*notPromoted(propertyNotPromoted(target: member:C24.bad, type: int?))*/ bad;
false;) {}
[
- for (int i =
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C24.bad, type: int?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C24.bad, type: int?))*/ bad;
+ for (int i = c.
+ /*notPromoted(propertyNotPromoted(target: member:C24.bad, type: int?))*/ bad;
false;)
null
];
({
- for (int i =
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C24.bad, type: int?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C24.bad, type: int?))*/ bad;
+ for (int i = c.
+ /*notPromoted(propertyNotPromoted(target: member:C24.bad, type: int?))*/ bad;
false;)
null
});
({
- for (int i =
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C24.bad, type: int?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C24.bad, type: int?))*/ bad;
+ for (int i = c.
+ /*notPromoted(propertyNotPromoted(target: member:C24.bad, type: int?))*/ bad;
false;)
null: null
});
@@ -363,28 +340,24 @@
forAssignmentInitializer(C25 c, int i) {
if (c.bad == null) return;
- for (i =
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C25.bad, type: int?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C25.bad, type: int?))*/ bad;
+ for (i = c.
+ /*notPromoted(propertyNotPromoted(target: member:C25.bad, type: int?))*/ bad;
false;) {}
[
- for (i =
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C25.bad, type: int?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C25.bad, type: int?))*/ bad;
+ for (i = c.
+ /*notPromoted(propertyNotPromoted(target: member:C25.bad, type: int?))*/ bad;
false;)
null
];
({
- for (i =
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C25.bad, type: int?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C25.bad, type: int?))*/ bad;
+ for (i = c.
+ /*notPromoted(propertyNotPromoted(target: member:C25.bad, type: int?))*/ bad;
false;)
null
});
({
- for (i =
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C25.bad, type: int?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C25.bad, type: int?))*/ bad;
+ for (i = c.
+ /*notPromoted(propertyNotPromoted(target: member:C25.bad, type: int?))*/ bad;
false;)
null: null
});
@@ -397,9 +370,8 @@
compoundAssignmentRhs(C26 c) {
num n = 0;
if (c.bad == null) return;
- n +=
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C26.bad, type: int?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C26.bad, type: int?))*/ bad;
+ n += c.
+ /*notPromoted(propertyNotPromoted(target: member:C26.bad, type: int?))*/ bad;
}
class C27 {
@@ -408,9 +380,8 @@
indexGet(C27 c, List<int> values) {
if (c.bad == null) return;
- values[
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C27.bad, type: int?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C27.bad, type: int?))*/ bad];
+ values[c.
+ /*notPromoted(propertyNotPromoted(target: member:C27.bad, type: int?))*/ bad];
}
class C28 {
@@ -419,9 +390,8 @@
indexSet(C28 c, List<int> values) {
if (c.bad == null) return;
- values[
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C28.bad, type: int?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C28.bad, type: int?))*/ bad] = 0;
+ values[c.
+ /*notPromoted(propertyNotPromoted(target: member:C28.bad, type: int?))*/ bad] = 0;
}
class C29 {
@@ -430,9 +400,8 @@
indexSetCompound(C29 c, List<int> values) {
if (c.bad == null) return;
- values[
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C29.bad, type: int?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C29.bad, type: int?))*/ bad] += 1;
+ values[c.
+ /*notPromoted(propertyNotPromoted(target: member:C29.bad, type: int?))*/ bad] += 1;
}
class C30 {
@@ -441,9 +410,8 @@
indexSetIfNull(C30 c, List<int?> values) {
if (c.bad == null) return;
- values[
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C30.bad, type: int?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C30.bad, type: int?))*/ bad] ??= 1;
+ values[c.
+ /*notPromoted(propertyNotPromoted(target: member:C30.bad, type: int?))*/ bad] ??= 1;
}
class C31 {
@@ -452,12 +420,10 @@
indexSetPreIncDec(C31 c, List<int> values) {
if (c.bad == null) return;
- ++values[
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C31.bad, type: int?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C31.bad, type: int?))*/ bad];
- --values[
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C31.bad, type: int?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C31.bad, type: int?))*/ bad];
+ ++values[c.
+ /*notPromoted(propertyNotPromoted(target: member:C31.bad, type: int?))*/ bad];
+ --values[c.
+ /*notPromoted(propertyNotPromoted(target: member:C31.bad, type: int?))*/ bad];
}
class C32 {
@@ -466,10 +432,23 @@
indexSetPostIncDec(C32 c, List<int> values) {
if (c.bad == null) return;
- values[
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C32.bad, type: int?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C32.bad, type: int?))*/ bad]++;
- values[
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C32.bad, type: int?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C32.bad, type: int?))*/ bad]--;
+ values[c.
+ /*notPromoted(propertyNotPromoted(target: member:C32.bad, type: int?))*/ bad]++;
+ values[c.
+ /*notPromoted(propertyNotPromoted(target: member:C32.bad, type: int?))*/ bad]--;
+}
+
+extension E33 on int {
+ void f() {}
+}
+
+class C33 {
+ int? bad;
+}
+
+test(C33 c) {
+ if (c.bad == null) return;
+ E33(c.
+ /*notPromoted(propertyNotPromoted(target: member:C33.bad, type: int?))*/ bad)
+ .f();
}
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/for_in_loop_type_not_iterable_nullability_error.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/for_in_loop_type_not_iterable_nullability_error.dart
index 5bbde08..a893bc5 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/for_in_loop_type_not_iterable_nullability_error.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/for_in_loop_type_not_iterable_nullability_error.dart
@@ -13,17 +13,15 @@
forStatement(C1 c) {
if (c.bad == null) return;
- for (var x
- in /*analyzer.notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ bad) {}
+ for (var x in c.
+ /*notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ bad) {}
}
forElementInList(C1 c) {
if (c.bad == null) return;
[
- for (var x
- in /*analyzer.notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ bad)
+ for (var x in c.
+ /*notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ bad)
null
];
}
@@ -31,9 +29,8 @@
forElementInSet(C1 c) {
if (c.bad == null) return;
<dynamic>{
- for (var x
- in /*analyzer.notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ bad)
+ for (var x in c.
+ /*notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ bad)
null
};
}
@@ -41,9 +38,8 @@
forElementInMap(C1 c) {
if (c.bad == null) return;
<dynamic, dynamic>{
- for (var x
- in /*analyzer.notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ bad)
+ for (var x in c.
+ /*notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ bad)
null: null
};
}
@@ -51,9 +47,8 @@
forElementInAmbiguousSet_resolvableDuringParsing(C1 c) {
if (c.bad == null) return;
({
- for (var x
- in /*analyzer.notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ bad)
+ for (var x in c.
+ /*notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ bad)
null
});
}
@@ -61,9 +56,8 @@
forElementInAmbiguousMap_resolvableDuringParsing(C1 c) {
if (c.bad == null) return;
({
- for (var x
- in /*analyzer.notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ bad)
+ for (var x in c.
+ /*notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ bad)
null: null
});
}
@@ -71,9 +65,8 @@
forElementInAmbiguousSet_notResolvableDuringParsing(C1 c, List list) {
if (c.bad == null) return;
({
- for (var x
- in /*analyzer.notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ bad)
+ for (var x in c.
+ /*notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ bad)
...list
});
}
@@ -81,9 +74,8 @@
forElementInAmbiguousMap_notResolvableDuringParsing(C1 c, Map map) {
if (c.bad == null) return;
({
- for (var x
- in /*analyzer.notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ bad)
+ for (var x in c.
+ /*notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ bad)
...map
});
}
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/invalid_assignment_error_nullability_error.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/invalid_assignment_error_nullability_error.dart
index a0f0388..95c3b97 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/invalid_assignment_error_nullability_error.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/invalid_assignment_error_nullability_error.dart
@@ -13,6 +13,6 @@
test(C1 c) sync* {
if (c.bad == null) return;
- yield* /*analyzer.notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ bad;
+ yield* c.
+ /*notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ bad;
}
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_spread_error.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_spread_error.dart
index 6d05759..ece5484 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_spread_error.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_spread_error.dart
@@ -16,56 +16,56 @@
list_from_list_question(C c) {
if (c.listQuestion == null) return;
return [
- ... /*analyzer.notPromoted(propertyNotPromoted(target: member:C.listQuestion, type: List<int>?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C.listQuestion, type: List<int>?))*/ listQuestion
+ ...c.
+ /*notPromoted(propertyNotPromoted(target: member:C.listQuestion, type: List<int>?))*/ listQuestion
];
}
list_from_set_question(C c) {
if (c.setQuestion == null) return;
return [
- ... /*analyzer.notPromoted(propertyNotPromoted(target: member:C.setQuestion, type: Set<int>?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C.setQuestion, type: Set<int>?))*/ setQuestion
+ ...c.
+ /*notPromoted(propertyNotPromoted(target: member:C.setQuestion, type: Set<int>?))*/ setQuestion
];
}
list_from_map_question(C c) {
if (c.mapQuestion == null) return;
return [
- ... /*analyzer.notPromoted(propertyNotPromoted(target: member:C.mapQuestion, type: Map<int, int>?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C.mapQuestion, type: Map<int, int>?))*/ mapQuestion
+ ...c.
+ /*notPromoted(propertyNotPromoted(target: member:C.mapQuestion, type: Map<int, int>?))*/ mapQuestion
];
}
list_from_object_question(C c) {
if (c.objectQuestion is! List<int>) return;
return [
- ... /*analyzer.notPromoted(propertyNotPromoted(target: member:C.objectQuestion, type: Object?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C.objectQuestion, type: Object?))*/ objectQuestion
+ ...c.
+ /*notPromoted(propertyNotPromoted(target: member:C.objectQuestion, type: Object?))*/ objectQuestion
];
}
set_from_list_question(C c) {
if (c.listQuestion == null) return;
return {
- ... /*analyzer.notPromoted(propertyNotPromoted(target: member:C.listQuestion, type: List<int>?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C.listQuestion, type: List<int>?))*/ listQuestion
+ ...c.
+ /*notPromoted(propertyNotPromoted(target: member:C.listQuestion, type: List<int>?))*/ listQuestion
};
}
set_from_set_question(C c) {
if (c.setQuestion == null) return;
return {
- ... /*analyzer.notPromoted(propertyNotPromoted(target: member:C.setQuestion, type: Set<int>?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C.setQuestion, type: Set<int>?))*/ setQuestion
+ ...c.
+ /*notPromoted(propertyNotPromoted(target: member:C.setQuestion, type: Set<int>?))*/ setQuestion
};
}
set_from_map_question(C c) {
if (c.mapQuestion == null) return;
return {
- ... /*analyzer.notPromoted(propertyNotPromoted(target: member:C.mapQuestion, type: Map<int, int>?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C.mapQuestion, type: Map<int, int>?))*/ mapQuestion
+ ...c.
+ /*notPromoted(propertyNotPromoted(target: member:C.mapQuestion, type: Map<int, int>?))*/ mapQuestion
};
}
@@ -73,8 +73,8 @@
if (c.objectQuestion is! Set<int>) return;
return {
null,
- ... /*analyzer.notPromoted(propertyNotPromoted(target: member:C.objectQuestion, type: Object?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C.objectQuestion, type: Object?))*/ objectQuestion
+ ...c.
+ /*notPromoted(propertyNotPromoted(target: member:C.objectQuestion, type: Object?))*/ objectQuestion
};
}
@@ -82,40 +82,40 @@
if (c.objectQuestion is! Set<int>) return;
return {
...<int>{},
- ... /*analyzer.notPromoted(propertyNotPromoted(target: member:C.objectQuestion, type: Object?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C.objectQuestion, type: Object?))*/ objectQuestion
+ ...c.
+ /*notPromoted(propertyNotPromoted(target: member:C.objectQuestion, type: Object?))*/ objectQuestion
};
}
set_from_object_question_type_disambiguate_by_literal_args(C c) {
if (c.objectQuestion is! Set<int>) return;
return <int>{
- ... /*analyzer.notPromoted(propertyNotPromoted(target: member:C.objectQuestion, type: Object?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C.objectQuestion, type: Object?))*/ objectQuestion
+ ...c.
+ /*notPromoted(propertyNotPromoted(target: member:C.objectQuestion, type: Object?))*/ objectQuestion
};
}
map_from_list_question(C c) {
if (c.listQuestion == null) return;
return {
- ... /*analyzer.notPromoted(propertyNotPromoted(target: member:C.listQuestion, type: List<int>?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C.listQuestion, type: List<int>?))*/ listQuestion
+ ...c.
+ /*notPromoted(propertyNotPromoted(target: member:C.listQuestion, type: List<int>?))*/ listQuestion
};
}
map_from_set_question(C c) {
if (c.setQuestion == null) return;
return {
- ... /*analyzer.notPromoted(propertyNotPromoted(target: member:C.setQuestion, type: Set<int>?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C.setQuestion, type: Set<int>?))*/ setQuestion
+ ...c.
+ /*notPromoted(propertyNotPromoted(target: member:C.setQuestion, type: Set<int>?))*/ setQuestion
};
}
map_from_map_question(C c) {
if (c.mapQuestion == null) return;
return {
- ... /*analyzer.notPromoted(propertyNotPromoted(target: member:C.mapQuestion, type: Map<int, int>?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C.mapQuestion, type: Map<int, int>?))*/ mapQuestion
+ ...c.
+ /*notPromoted(propertyNotPromoted(target: member:C.mapQuestion, type: Map<int, int>?))*/ mapQuestion
};
}
@@ -123,8 +123,8 @@
if (c.objectQuestion is! Map<int, int>) return;
return {
null: null,
- ... /*analyzer.notPromoted(propertyNotPromoted(target: member:C.objectQuestion, type: Object?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C.objectQuestion, type: Object?))*/ objectQuestion
+ ...c.
+ /*notPromoted(propertyNotPromoted(target: member:C.objectQuestion, type: Object?))*/ objectQuestion
};
}
@@ -132,8 +132,8 @@
if (c.objectQuestion is! Map<int, int>) return;
return {
...<int, int>{},
- ... /*analyzer.notPromoted(propertyNotPromoted(target: member:C.objectQuestion, type: Object?))*/ c
- . /*cfe.notPromoted(propertyNotPromoted(target: member:C.objectQuestion, type: Object?))*/ objectQuestion
+ ...c.
+ /*notPromoted(propertyNotPromoted(target: member:C.objectQuestion, type: Object?))*/ objectQuestion
};
}
@@ -144,8 +144,7 @@
// the other.
if (c.setQuestion == null) return;
return <int, int>{
- ...
- /*analyzer.notPromoted(propertyNotPromoted(target: member:C.setQuestion, type: Set<int>?))*/ c
- .setQuestion
+ ...c.
+ /*analyzer.notPromoted(propertyNotPromoted(target: member:C.setQuestion, type: Set<int>?))*/ setQuestion
};
}
diff --git a/pkg/_fe_analyzer_shared/test/inference/inferred_type_arguments/data/constructor_invocation.dart b/pkg/_fe_analyzer_shared/test/inference/inferred_type_arguments/data/constructor_invocation.dart
index 4575c37..79d2844 100644
--- a/pkg/_fe_analyzer_shared/test/inference/inferred_type_arguments/data/constructor_invocation.dart
+++ b/pkg/_fe_analyzer_shared/test/inference/inferred_type_arguments/data/constructor_invocation.dart
@@ -68,7 +68,7 @@
MultipleArgs/*<dynamic,dynamic,dynamic>*/(dyn, dyn, dyn);
MultipleArgs/*<int,String,bool>*/(0, true, "");
MultipleArgs<int, bool, String>(0, true, "");
- var multipleArgs1 = MultipleArgs();
+ var multipleArgs1 = MultipleArgs /*analyzer.<dynamic,dynamic,dynamic>*/ ();
var multipleArgs2 = MultipleArgs/*<int,String,bool>*/(0, true, "");
MultipleArgs multipleArgs3 =
MultipleArgs/*<dynamic,dynamic,dynamic>*/(0, true, "");
diff --git a/pkg/_fe_analyzer_shared/test/inference/inferred_type_arguments/data/marker.options b/pkg/_fe_analyzer_shared/test/inference/inferred_type_arguments/data/marker.options
index b0f2c56..9384923 100644
--- a/pkg/_fe_analyzer_shared/test/inference/inferred_type_arguments/data/marker.options
+++ b/pkg/_fe_analyzer_shared/test/inference/inferred_type_arguments/data/marker.options
@@ -1 +1,2 @@
cfe=pkg/front_end/test/id_tests/inferred_type_arguments_test.dart
+analyzer=pkg/analyzer/test/id_tests/inferred_type_arguments_test.dart
diff --git a/pkg/_fe_analyzer_shared/test/inference/inferred_type_arguments/data/static_invocation.dart b/pkg/_fe_analyzer_shared/test/inference/inferred_type_arguments/data/static_invocation.dart
index 70932b3..b9254ec 100644
--- a/pkg/_fe_analyzer_shared/test/inference/inferred_type_arguments/data/static_invocation.dart
+++ b/pkg/_fe_analyzer_shared/test/inference/inferred_type_arguments/data/static_invocation.dart
@@ -73,7 +73,7 @@
int extendsNumReturnArg6 = extendsNumReturnArg/*<int>*/("");
int extendsNumReturnArg7 = extendsNumReturnArg<num>(0);
- multipleArgs();
+ multipleArgs /*analyzer.<dynamic,dynamic,dynamic>*/ ();
multipleArgs/*<int,String,bool>*/(0, true, "");
multipleArgs<int, bool, String>(0, true, "");
}
diff --git a/pkg/_fe_analyzer_shared/test/inference/inferred_variable_types/data/marker.options b/pkg/_fe_analyzer_shared/test/inference/inferred_variable_types/data/marker.options
index 5669a4b..f732667 100644
--- a/pkg/_fe_analyzer_shared/test/inference/inferred_variable_types/data/marker.options
+++ b/pkg/_fe_analyzer_shared/test/inference/inferred_variable_types/data/marker.options
@@ -1 +1,2 @@
-cfe=pkg/front_end/test/id_tests/inferred_variable_types_test.dart
\ No newline at end of file
+cfe=pkg/front_end/test/id_tests/inferred_variable_types_test.dart
+analyzer=pkg/analyzer/test/id_tests/inferred_variable_types_test.dart
diff --git a/pkg/analysis_server/lib/lsp_protocol/protocol_custom_generated.dart b/pkg/analysis_server/lib/lsp_protocol/protocol_custom_generated.dart
index 4695a19..fd739c7 100644
--- a/pkg/analysis_server/lib/lsp_protocol/protocol_custom_generated.dart
+++ b/pkg/analysis_server/lib/lsp_protocol/protocol_custom_generated.dart
@@ -178,6 +178,10 @@
if (DartCompletionItemResolutionInfo.canParse(json, nullLspJsonReporter)) {
return DartCompletionItemResolutionInfo.fromJson(json);
}
+ if (PubPackageCompletionItemResolutionInfo.canParse(
+ json, nullLspJsonReporter)) {
+ return PubPackageCompletionItemResolutionInfo.fromJson(json);
+ }
final file = json['file'];
final offset = json['offset'];
return CompletionItemResolutionInfo(file: file, offset: offset);
@@ -1185,6 +1189,121 @@
String toString() => jsonEncoder.convert(toJson());
}
+class PubPackageCompletionItemResolutionInfo
+ implements CompletionItemResolutionInfo, ToJsonable {
+ static const jsonHandler = LspJsonHandler(
+ PubPackageCompletionItemResolutionInfo.canParse,
+ PubPackageCompletionItemResolutionInfo.fromJson);
+
+ PubPackageCompletionItemResolutionInfo(
+ {required this.packageName, required this.file, required this.offset});
+ static PubPackageCompletionItemResolutionInfo fromJson(
+ Map<String, dynamic> json) {
+ final packageName = json['packageName'];
+ final file = json['file'];
+ final offset = json['offset'];
+ return PubPackageCompletionItemResolutionInfo(
+ packageName: packageName, file: file, offset: offset);
+ }
+
+ final String file;
+ final num offset;
+ final String packageName;
+
+ Map<String, dynamic> toJson() {
+ var __result = <String, dynamic>{};
+ __result['packageName'] = packageName;
+ __result['file'] = file;
+ __result['offset'] = offset;
+ return __result;
+ }
+
+ static bool canParse(Object obj, LspJsonReporter reporter) {
+ if (obj is Map<String, dynamic>) {
+ reporter.push('packageName');
+ try {
+ if (!obj.containsKey('packageName')) {
+ reporter.reportError('must not be undefined');
+ return false;
+ }
+ if (obj['packageName'] == null) {
+ reporter.reportError('must not be null');
+ return false;
+ }
+ if (!(obj['packageName'] is String)) {
+ reporter.reportError('must be of type String');
+ return false;
+ }
+ } finally {
+ reporter.pop();
+ }
+ reporter.push('file');
+ try {
+ if (!obj.containsKey('file')) {
+ reporter.reportError('must not be undefined');
+ return false;
+ }
+ if (obj['file'] == null) {
+ reporter.reportError('must not be null');
+ return false;
+ }
+ if (!(obj['file'] is String)) {
+ reporter.reportError('must be of type String');
+ return false;
+ }
+ } finally {
+ reporter.pop();
+ }
+ reporter.push('offset');
+ try {
+ if (!obj.containsKey('offset')) {
+ reporter.reportError('must not be undefined');
+ return false;
+ }
+ if (obj['offset'] == null) {
+ reporter.reportError('must not be null');
+ return false;
+ }
+ if (!(obj['offset'] is num)) {
+ reporter.reportError('must be of type num');
+ return false;
+ }
+ } finally {
+ reporter.pop();
+ }
+ return true;
+ } else {
+ reporter.reportError(
+ 'must be of type PubPackageCompletionItemResolutionInfo');
+ return false;
+ }
+ }
+
+ @override
+ bool operator ==(Object other) {
+ if (other is PubPackageCompletionItemResolutionInfo &&
+ other.runtimeType == PubPackageCompletionItemResolutionInfo) {
+ return packageName == other.packageName &&
+ file == other.file &&
+ offset == other.offset &&
+ true;
+ }
+ return false;
+ }
+
+ @override
+ int get hashCode {
+ var hash = 0;
+ hash = JenkinsSmiHash.combine(hash, packageName.hashCode);
+ hash = JenkinsSmiHash.combine(hash, file.hashCode);
+ hash = JenkinsSmiHash.combine(hash, offset.hashCode);
+ return JenkinsSmiHash.finish(hash);
+ }
+
+ @override
+ String toString() => jsonEncoder.convert(toJson());
+}
+
class PublishClosingLabelsParams implements ToJsonable {
static const jsonHandler = LspJsonHandler(
PublishClosingLabelsParams.canParse, PublishClosingLabelsParams.fromJson);
diff --git a/pkg/analysis_server/lib/src/analysis_server_abstract.dart b/pkg/analysis_server/lib/src/analysis_server_abstract.dart
index 3288d8b..109b9c7 100644
--- a/pkg/analysis_server/lib/src/analysis_server_abstract.dart
+++ b/pkg/analysis_server/lib/src/analysis_server_abstract.dart
@@ -288,12 +288,13 @@
return null;
}
- var unitElementResult = await driver.getUnitElement(file);
- if (unitElementResult == null) {
+ var unitElementResult = await driver.getUnitElement2(file);
+ if (unitElementResult is! UnitElementResult) {
return null;
}
- var element = findElementByNameOffset(unitElementResult.element, offset);
+ var element = findElementByNameOffset(
+ (unitElementResult as UnitElementResult).element, offset);
if (element != null) {
return element;
}
@@ -361,7 +362,8 @@
}
return driver
- .getResult(path, sendCachedToStream: sendCachedToStream)
+ .getResult2(path, sendCachedToStream: sendCachedToStream)
+ .then((value) => value is ResolvedUnitResult ? value : null)
.catchError((e, st) {
instrumentationService.logException(e, st);
return null;
diff --git a/pkg/analysis_server/lib/src/domain_analysis.dart b/pkg/analysis_server/lib/src/domain_analysis.dart
index 0cec373..c557341 100644
--- a/pkg/analysis_server/lib/src/domain_analysis.dart
+++ b/pkg/analysis_server/lib/src/domain_analysis.dart
@@ -61,7 +61,7 @@
// Prepare the resolved units.
var result = await server.getResolvedUnit(file);
- if (result.state != ResultState.VALID) {
+ if (result == null) {
server.sendResponse(Response.fileNotAnalyzed(request, file));
return;
}
diff --git a/pkg/analysis_server/lib/src/domains/execution/completion.dart b/pkg/analysis_server/lib/src/domains/execution/completion.dart
index 825dce0..97ab5bf 100644
--- a/pkg/analysis_server/lib/src/domains/execution/completion.dart
+++ b/pkg/analysis_server/lib/src/domains/execution/completion.dart
@@ -7,6 +7,7 @@
import 'package:analysis_server/src/services/completion/completion_core.dart';
import 'package:analysis_server/src/services/completion/completion_performance.dart';
import 'package:analysis_server/src/services/completion/dart/completion_manager.dart';
+import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/file_system/overlay_file_system.dart';
import 'package:analyzer/src/dart/analysis/driver.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
@@ -25,7 +26,11 @@
this.code, this.offset, this.contextPath, this.contextOffset);
Future<RuntimeCompletionResult> compute() async {
- var contextResult = await analysisDriver.getResult(contextPath);
+ var contextResult = await analysisDriver.getResult2(contextPath);
+ if (contextResult is! ResolvedUnitResult) {
+ return RuntimeCompletionResult([], []);
+ }
+
var session = contextResult.session;
const codeMarker = '__code_\_';
@@ -59,8 +64,11 @@
// Update the context file content to include the code being completed.
// Then resolve it, and restore the file to its initial state.
var targetResult = await _withContextFileContent(targetCode, () async {
- return await analysisDriver.getResult(contextPath);
+ return await analysisDriver.getResult2(contextPath);
});
+ if (targetResult is! ResolvedUnitResult) {
+ return RuntimeCompletionResult([], []);
+ }
var contributor = DartCompletionManager(
// dartdocDirectiveInfo: server.getDartdocDirectiveInfoFor(targetResult)
diff --git a/pkg/analysis_server/lib/src/edit/edit_domain.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart
index f93c1ad..fec4a3f 100644
--- a/pkg/analysis_server/lib/src/edit/edit_domain.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart
@@ -859,8 +859,8 @@
}
// try RENAME
{
- var renameRefactoring =
- RenameRefactoring(refactoringWorkspace, resolvedUnit, element);
+ var renameRefactoring = RenameRefactoring.create(
+ refactoringWorkspace, resolvedUnit, element);
if (renameRefactoring != null) {
kinds.add(RefactoringKind.RENAME);
}
@@ -1197,7 +1197,7 @@
RenameRefactoring.getElementToRename(node, element);
// do create the refactoring
- refactoring = RenameRefactoring(
+ refactoring = RenameRefactoring.create(
refactoringWorkspace, resolvedUnit, renameElement.element);
feedback = RenameFeedback(
renameElement.offset, renameElement.length, 'kind', 'oldName');
diff --git a/pkg/analysis_server/lib/src/lsp/constants.dart b/pkg/analysis_server/lib/src/lsp/constants.dart
index 952a5c5..4afc13e 100644
--- a/pkg/analysis_server/lib/src/lsp/constants.dart
+++ b/pkg/analysis_server/lib/src/lsp/constants.dart
@@ -24,25 +24,17 @@
/// Set the characters that will cause the editor to automatically
/// trigger completion.
-/// TODO(dantup): There are several characters that we want to conditionally
-/// allow to trigger completion, but they can only be added when the completion
-/// provider is able to handle them in context:
-///
-/// { trigger if being typed in a string immediately after a $
-/// ' trigger if the opening quote for an import/export
-/// " trigger if the opening quote for an import/export
-/// / trigger if as part of a path in an import/export
-/// \ trigger if as part of a path in an import/export
-/// : don't trigger when typing case expressions (`case x:`)
-///
-/// Additionally, we need to prefix `filterText` on completion items
-/// with spaces for those that can follow whitespace (eg. `foo` in
-/// `myArg: foo`) to ensure they're not filtered away when the user
-/// types space.
-///
-/// See https://github.com/Dart-Code/Dart-Code/blob/68d1cd271e88a785570257d487adbdec17abd6a3/src/providers/dart_completion_item_provider.ts#L36-L64
-/// for the VS Code implementation of this.
-const dartCompletionTriggerCharacters = ['.', '=', '(', r'$'];
+const dartCompletionTriggerCharacters = [
+ '.',
+ '=',
+ '(',
+ r'$',
+ '"',
+ "'",
+ '{',
+ '/',
+ ':'
+];
/// Characters that refresh signature help only if it's already open on the client.
const dartSignatureHelpRetriggerCharacters = <String>[','];
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
index 13a5890..4f68075 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
@@ -6,6 +6,7 @@
import 'dart:math' as math;
+import 'package:analysis_server/lsp_protocol/protocol_custom_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/protocol/protocol_generated.dart';
@@ -24,11 +25,13 @@
import 'package:analysis_server/src/services/completion/yaml/pubspec_generator.dart';
import 'package:analysis_server/src/services/completion/yaml/yaml_completion_generator.dart';
import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/dart/ast/ast.dart' as ast;
import 'package:analyzer/source/line_info.dart';
import 'package:analyzer/src/services/available_declarations.dart';
import 'package:analyzer/src/util/file_paths.dart' as file_paths;
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
+import 'package:analyzer_plugin/src/utilities/completion/completion_target.dart';
class CompletionHandler
extends MessageHandler<CompletionParams, List<CompletionItem>>
@@ -51,6 +54,7 @@
final includeSuggestionSets =
suggestFromUnimportedLibraries && server.clientCapabilities.applyEdit;
+ final triggerCharacter = params.context?.triggerCharacter;
final pos = params.position;
final path = pathOfDoc(params.textDocument);
final unit = await path.mapResult(requireResolvedUnit);
@@ -75,6 +79,7 @@
includeSuggestionSets,
unit.result,
offset,
+ triggerCharacter,
token,
);
} else if (fileExtension == '.yaml') {
@@ -189,6 +194,7 @@
bool includeSuggestionSets,
ResolvedUnitResult unit,
int offset,
+ String triggerCharacter,
CancellationToken token,
) async {
final performance = CompletionPerformance();
@@ -204,6 +210,13 @@
final dartCompletionRequest = await DartCompletionRequestImpl.from(
perf, completionRequest, directiveInfo);
+ if (triggerCharacter != null) {
+ if (!_triggerCharacterValid(
+ offset, triggerCharacter, dartCompletionRequest.target)) {
+ return success([]);
+ }
+ }
+
Set<ElementKind> includedElementKinds;
Set<String> includedElementNames;
List<IncludedSuggestionRelevanceTag> includedSuggestionRelevanceTags;
@@ -410,6 +423,17 @@
suggestions.replacementLength,
includeCommitCharacters: false,
completeFunctionCalls: false,
+ // Add on any completion-kind-specific resolution data that will be
+ // used during resolve() calls to provide additional information.
+ resolutionData: item.kind == CompletionSuggestionKind.PACKAGE_NAME
+ ? PubPackageCompletionItemResolutionInfo(
+ file: path,
+ offset: offset,
+ // The completion for package names may contain a trailing
+ // ': ' for convenience, so if it's there, trim it off.
+ packageName: item.completion.split(':').first,
+ )
+ : null,
),
)
.toList();
@@ -444,4 +468,37 @@
);
});
}
+
+ /// Checks whether the given [triggerCharacter] is valid for [target].
+ ///
+ /// Some trigger characters are only valid in certain locations, for example
+ /// a single quote ' is valid to trigger completion after typing an import
+ /// statement, but not when terminating a string. The client has no context
+ /// and sends the requests unconditionally.
+ bool _triggerCharacterValid(
+ int offset, String triggerCharacter, CompletionTarget target) {
+ final node = target.containingNode;
+
+ switch (triggerCharacter) {
+ // For quotes, it's only valid if we're right after the opening quote of a
+ // directive.
+ case '"':
+ case "'":
+ return node is ast.SimpleStringLiteral &&
+ node.parent is ast.Directive &&
+ offset == node.contentsOffset;
+ // Braces only for starting interpolated expressions.
+ case '{':
+ return node is ast.InterpolationExpression &&
+ node.expression.offset == offset;
+ // Slashes only as path separators in directives.
+ case '/':
+ return node is ast.SimpleStringLiteral &&
+ node.parent is ast.Directive &&
+ offset >= node.contentsOffset &&
+ offset <= node.contentsEnd;
+ }
+
+ return true; // Any other trigger character can be handled always.
+ }
}
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart
index 95e8259..c183d33 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart
@@ -42,6 +42,8 @@
if (resolutionInfo is DartCompletionItemResolutionInfo) {
return resolveDartCompletion(item, resolutionInfo, token);
+ } else if (resolutionInfo is PubPackageCompletionItemResolutionInfo) {
+ return resolvePubPackageCompletion(item, resolutionInfo, token);
} else {
return success(item);
}
@@ -215,4 +217,40 @@
null,
);
}
+
+ Future<ErrorOr<CompletionItem>> resolvePubPackageCompletion(
+ CompletionItem item,
+ PubPackageCompletionItemResolutionInfo data,
+ CancellationToken token,
+ ) async {
+ // Fetch details for this package. This may come from the cache or trigger
+ // a real web request to the Pub API.
+ final packageDetails =
+ await server.pubPackageService.packageDetails(data.packageName);
+
+ if (token.isCancellationRequested) {
+ return cancelled();
+ }
+
+ return success(CompletionItem(
+ label: item.label,
+ kind: item.kind,
+ tags: item.tags,
+ detail: item.detail,
+ documentation: packageDetails?.description != null
+ ? Either2<String, MarkupContent>.t1(packageDetails.description)
+ : null,
+ deprecated: item.deprecated,
+ preselect: item.preselect,
+ sortText: item.sortText,
+ filterText: item.filterText,
+ insertText: item.insertText,
+ insertTextFormat: item.insertTextFormat,
+ textEdit: item.textEdit,
+ additionalTextEdits: item.additionalTextEdits,
+ commitCharacters: item.commitCharacters,
+ command: item.command,
+ data: item.data,
+ ));
+ }
}
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_rename.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_rename.dart
index 20f59c0..caa7c78 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_rename.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_rename.dart
@@ -43,7 +43,7 @@
final refactorDetails =
RenameRefactoring.getElementToRename(node, element);
- final refactoring = RenameRefactoring(
+ final refactoring = RenameRefactoring.create(
server.refactoringWorkspace, unit.result, refactorDetails.element);
if (refactoring == null) {
return success(null);
@@ -116,7 +116,7 @@
final refactorDetails =
RenameRefactoring.getElementToRename(node, element);
- final refactoring = RenameRefactoring(
+ final refactoring = RenameRefactoring.create(
server.refactoringWorkspace, unit.result, refactorDetails.element);
if (refactoring == null) {
return success(null);
diff --git a/pkg/analysis_server/lib/src/lsp/server_capabilities_computer.dart b/pkg/analysis_server/lib/src/lsp/server_capabilities_computer.dart
index 72b8dbc..ad0241d 100644
--- a/pkg/analysis_server/lib/src/lsp/server_capabilities_computer.dart
+++ b/pkg/analysis_server/lib/src/lsp/server_capabilities_computer.dart
@@ -124,8 +124,8 @@
final LspAnalysisServer _server;
- /// Map from method name to current registration data.
- Map<String, Registration> currentRegistrations = {};
+ /// List of current registrations.
+ Set<Registration> currentRegistrations = {};
var _lastRegistrationId = 0;
ServerCapabilitiesComputer(this._server);
@@ -306,8 +306,10 @@
// Completion is supported for some synchronised files that we don't _fully_
// support (eg. YAML). If these gain support for things like hover, we may
// wish to move them to fullySupprtedTypes but add an exclusion for formatting.
- final completionSupportedTypes = {
- ...fullySupportedTypes,
+ final completionSupportedTypesExcludingDart = {
+ // Dart is excluded here at it's registered separately with trigger/commit
+ // characters.
+ ...pluginTypes,
pubspecFile,
analysisOptionsFile,
fixDataFile,
@@ -349,11 +351,13 @@
syncKind: TextDocumentSyncKind.Incremental,
documentSelector: synchronisedTypes),
);
+ // Trigger and commit characters are specific to Dart, so register them
+ // separately to the others.
register(
dynamicRegistrations.completion,
Method.textDocument_completion,
CompletionRegistrationOptions(
- documentSelector: completionSupportedTypes,
+ documentSelector: [dartFiles],
triggerCharacters: dartCompletionTriggerCharacters,
allCommitCharacters:
previewCommitCharacters ? dartCompletionCommitCharacters : null,
@@ -361,6 +365,14 @@
),
);
register(
+ dynamicRegistrations.completion,
+ Method.textDocument_completion,
+ CompletionRegistrationOptions(
+ documentSelector: completionSupportedTypesExcludingDart,
+ resolveProvider: true,
+ ),
+ );
+ register(
dynamicRegistrations.hover,
Method.textDocument_hover,
TextDocumentRegistrationOptions(documentSelector: fullySupportedTypes),
@@ -464,51 +476,52 @@
await _applyRegistrations(registrations);
}
- Future<void> _applyRegistrations(List<Registration> registrations) async {
- final newRegistrationsByMethod = {
- for (final registration in registrations)
- registration.method: registration
- };
+ Future<void> _applyRegistrations(List<Registration> newRegistrations) async {
+ // Compute a diff of old and new registrations to send the unregister or
+ // another register request. We compare registrations by their methods and
+ // the hashcode of their registration options to allow for multiple
+ // registrations of a single method.
- final additionalRegistrations = List.of(registrations);
- final removedRegistrations = <Unregistration>[];
+ String _registrationHash(Registration registration) =>
+ '${registration.method}${registration.registerOptions.hashCode}';
- // compute a diff of old and new registrations to send the unregister or
- // another register request. We assume that we'll only ever have one
- // registration per LSP method name.
- for (final entry in currentRegistrations.entries) {
- final method = entry.key;
- final registration = entry.value;
+ final newRegistrationsMap = Map.fromEntries(
+ newRegistrations.map((r) => MapEntry(r, _registrationHash(r))));
+ final newRegistrationsJsons = newRegistrationsMap.values.toSet();
+ final currentRegistrationsMap = Map.fromEntries(
+ currentRegistrations.map((r) => MapEntry(r, _registrationHash(r))));
+ final currentRegistrationJsons = currentRegistrationsMap.values.toSet();
- final newRegistrationForMethod = newRegistrationsByMethod[method];
- final entryRemovedOrChanged = newRegistrationForMethod?.registerOptions !=
- registration.registerOptions;
+ final registrationsToAdd = newRegistrationsMap.entries
+ .where((entry) => !currentRegistrationJsons.contains(entry.value))
+ .map((entry) => entry.key)
+ .toList();
- if (entryRemovedOrChanged) {
- removedRegistrations.add(
- Unregistration(id: registration.id, method: registration.method));
- } else {
- // Replace the registration in our new set with the original registration
- // so that we retain the original ID sent to the client (otherwise we
- // will try to unregister using an ID the client was never sent).
- newRegistrationsByMethod[method] = registration;
- additionalRegistrations.remove(newRegistrationForMethod);
- }
- }
+ final registrationsToRemove = currentRegistrationsMap.entries
+ .where((entry) => !newRegistrationsJsons.contains(entry.value))
+ .map((entry) => entry.key)
+ .toList();
- currentRegistrations = newRegistrationsByMethod;
+ // Update the current list before we start sending requests since we
+ // go async.
+ currentRegistrations
+ ..removeAll(registrationsToRemove)
+ ..addAll(registrationsToAdd);
- if (removedRegistrations.isNotEmpty) {
+ if (registrationsToRemove.isNotEmpty) {
+ final unregistrations = registrationsToRemove
+ .map((r) => Unregistration(id: r.id, method: r.method))
+ .toList();
await _server.sendRequest(Method.client_unregisterCapability,
- UnregistrationParams(unregisterations: removedRegistrations));
+ UnregistrationParams(unregisterations: unregistrations));
}
// Only send the registration request if we have at least one (since
// otherwise we don't know that the client supports registerCapability).
- if (additionalRegistrations.isNotEmpty) {
+ if (registrationsToAdd.isNotEmpty) {
final registrationResponse = await _server.sendRequest(
Method.client_registerCapability,
- RegistrationParams(registrations: additionalRegistrations),
+ RegistrationParams(registrations: registrationsToAdd),
);
if (registrationResponse.error != null) {
diff --git a/pkg/analysis_server/lib/src/search/element_references.dart b/pkg/analysis_server/lib/src/search/element_references.dart
index e2bf228..f843776 100644
--- a/pkg/analysis_server/lib/src/search/element_references.dart
+++ b/pkg/analysis_server/lib/src/search/element_references.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:analysis_server/src/protocol_server.dart'
show SearchResult, newSearchResult_fromMatch;
import 'package:analysis_server/src/services/search/hierarchy.dart';
diff --git a/pkg/analysis_server/lib/src/search/type_hierarchy.dart b/pkg/analysis_server/lib/src/search/type_hierarchy.dart
index 90c3866b..422be2e 100644
--- a/pkg/analysis_server/lib/src/search/type_hierarchy.dart
+++ b/pkg/analysis_server/lib/src/search/type_hierarchy.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'dart:collection';
import 'package:analysis_server/src/protocol_server.dart'
@@ -18,23 +16,23 @@
final SearchEngine _searchEngine;
final Element _pivotElement;
- LibraryElement _pivotLibrary;
- ElementKind _pivotKind;
- String _pivotName;
- bool _pivotFieldFinal;
- ClassElement _pivotClass;
+ final LibraryElement _pivotLibrary;
+ final ElementKind _pivotKind;
+ final String? _pivotName;
+ late bool _pivotFieldFinal;
+ ClassElement? _pivotClass;
final List<TypeHierarchyItem> _items = <TypeHierarchyItem>[];
final List<ClassElement> _itemClassElements = <ClassElement>[];
final Map<Element, TypeHierarchyItem> _elementItemMap =
HashMap<Element, TypeHierarchyItem>();
- TypeHierarchyComputer(this._searchEngine, this._pivotElement) {
- _pivotLibrary = _pivotElement.library;
- _pivotKind = _pivotElement.kind;
- _pivotName = _pivotElement.name;
+ TypeHierarchyComputer(this._searchEngine, this._pivotElement)
+ : _pivotLibrary = _pivotElement.library!,
+ _pivotKind = _pivotElement.kind,
+ _pivotName = _pivotElement.name {
// try to find enclosing ClassElement
- var element = _pivotElement;
+ Element? element = _pivotElement;
if (_pivotElement is FieldElement) {
_pivotFieldFinal = (_pivotElement as FieldElement).isFinal;
element = _pivotElement.enclosingElement;
@@ -48,19 +46,21 @@
}
/// Returns the computed type hierarchy, maybe `null`.
- Future<List<TypeHierarchyItem>> compute() async {
- if (_pivotClass != null) {
- _createSuperItem(_pivotClass, null);
- await _createSubclasses(_items[0], 0, _pivotClass);
+ Future<List<TypeHierarchyItem>?> compute() async {
+ var pivotClass = _pivotClass;
+ if (pivotClass != null) {
+ _createSuperItem(pivotClass, null);
+ await _createSubclasses(_items[0], 0, pivotClass);
return _items;
}
return null;
}
/// Returns the computed super type only type hierarchy, maybe `null`.
- List<TypeHierarchyItem> computeSuper() {
- if (_pivotClass != null) {
- _createSuperItem(_pivotClass, null);
+ List<TypeHierarchyItem>? computeSuper() {
+ var pivotClass = _pivotClass;
+ if (pivotClass != null) {
+ _createSuperItem(pivotClass, null);
return _items;
}
return null;
@@ -103,16 +103,17 @@
}
int _createSuperItem(
- ClassElement classElement, List<DartType> typeArguments) {
+ ClassElement classElement, List<DartType>? typeArguments) {
// check for recursion
- var item = _elementItemMap[classElement];
- if (item != null) {
- return _items.indexOf(item);
+ var cachedItem = _elementItemMap[classElement];
+ if (cachedItem != null) {
+ return _items.indexOf(cachedItem);
}
// create an empty item now
+ TypeHierarchyItem item;
int itemId;
{
- String displayName;
+ String? displayName;
if (typeArguments != null && typeArguments.isNotEmpty) {
var typeArgumentsStr = typeArguments
.map((type) => type.getDisplayString(withNullability: false))
@@ -153,19 +154,23 @@
return itemId;
}
- ExecutableElement _findMemberElement(ClassElement clazz) {
- ExecutableElement result;
+ ExecutableElement? _findMemberElement(ClassElement clazz) {
+ var pivotName = _pivotName;
+ if (pivotName == null) {
+ return null;
+ }
+ ExecutableElement? result;
// try to find in the class itself
if (_pivotKind == ElementKind.METHOD) {
- result = clazz.getMethod(_pivotName);
+ result = clazz.getMethod(pivotName);
} else if (_pivotKind == ElementKind.GETTER) {
- result = clazz.getGetter(_pivotName);
+ result = clazz.getGetter(pivotName);
} else if (_pivotKind == ElementKind.SETTER) {
- result = clazz.getSetter(_pivotName);
+ result = clazz.getSetter(pivotName);
} else if (_pivotKind == ElementKind.FIELD) {
- result = clazz.getGetter(_pivotName);
+ result = clazz.getGetter(pivotName);
if (result == null && !_pivotFieldFinal) {
- result = clazz.getSetter(_pivotName);
+ result = clazz.getSetter(pivotName);
}
}
if (result != null && result.isAccessibleIn(_pivotLibrary)) {
@@ -175,15 +180,15 @@
for (var mixin in clazz.mixins.reversed) {
var mixinElement = mixin.element;
if (_pivotKind == ElementKind.METHOD) {
- result = mixinElement.lookUpMethod(_pivotName, _pivotLibrary);
+ result = mixinElement.lookUpMethod(pivotName, _pivotLibrary);
} else if (_pivotKind == ElementKind.GETTER) {
- result = mixinElement.lookUpGetter(_pivotName, _pivotLibrary);
+ result = mixinElement.lookUpGetter(pivotName, _pivotLibrary);
} else if (_pivotKind == ElementKind.SETTER) {
- result = mixinElement.lookUpSetter(_pivotName, _pivotLibrary);
+ result = mixinElement.lookUpSetter(pivotName, _pivotLibrary);
} else if (_pivotKind == ElementKind.FIELD) {
- result = mixinElement.lookUpGetter(_pivotName, _pivotLibrary);
+ result = mixinElement.lookUpGetter(pivotName, _pivotLibrary);
if (result == null && !_pivotFieldFinal) {
- result = mixinElement.lookUpSetter(_pivotName, _pivotLibrary);
+ result = mixinElement.lookUpSetter(pivotName, _pivotLibrary);
}
}
if (result == _pivotElement) {
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 7c20027..66989f9 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
@@ -368,8 +368,8 @@
var entity = target.entity;
if (entity is Token) {
- var prev = entity.previous!;
- if (prev.end == offset && prev.isKeywordOrIdentifier) {
+ var prev = entity.previous;
+ if (prev != null && prev.end == offset && prev.isKeywordOrIdentifier) {
return prev.lexeme;
}
}
diff --git a/pkg/analysis_server/lib/src/services/completion/yaml/pubspec_generator.dart b/pkg/analysis_server/lib/src/services/completion/yaml/pubspec_generator.dart
index a1e73c3..724bb6f 100644
--- a/pkg/analysis_server/lib/src/services/completion/yaml/pubspec_generator.dart
+++ b/pkg/analysis_server/lib/src/services/completion/yaml/pubspec_generator.dart
@@ -9,10 +9,13 @@
import 'package:analyzer/file_system/file_system.dart';
/// An object that represents the location of a package name.
-class PubPackageNameProducer extends Producer {
+class PubPackageNameProducer extends KeyValueProducer {
const PubPackageNameProducer();
@override
+ Producer producerForKey(String key) => PubPackageVersionProducer(key);
+
+ @override
Iterable<CompletionSuggestion> suggestions(
YamlCompletionRequest request) sync* {
final cachedPackages = request.pubPackageService?.cachedPackages;
@@ -24,6 +27,32 @@
}
}
+/// An object that represents the location of the version number for a pub
+/// package.
+class PubPackageVersionProducer extends Producer {
+ final String package;
+
+ const PubPackageVersionProducer(this.package);
+
+ @override
+ Iterable<CompletionSuggestion> suggestions(
+ YamlCompletionRequest request) sync* {
+ // TOOD(dantup): Consider supporting async completion requests so this
+ // could call packageDetails() (with a short timeout, and pub retries
+ // disabled). A user that explicitly invokes completion in the location
+ // of a version may be prepared to wait a short period for a web request
+ // to get completion versions (this is also the only way for non-LSP
+ // clients to get them, since there are no resolve calls).
+ //
+ // Supporting this will require making the completion async further up.
+ final details = request.pubPackageService?.cachedPackageDetails(package);
+ final version = details?.latestVersion;
+ if (version != null) {
+ yield identifier('^$version');
+ }
+ }
+}
+
/// A completion generator that can produce completion suggestions for pubspec
/// files.
class PubspecGenerator extends YamlCompletionGenerator {
diff --git a/pkg/analysis_server/lib/src/services/completion/yaml/yaml_completion_generator.dart b/pkg/analysis_server/lib/src/services/completion/yaml/yaml_completion_generator.dart
index 724475f..618ba40 100644
--- a/pkg/analysis_server/lib/src/services/completion/yaml/yaml_completion_generator.dart
+++ b/pkg/analysis_server/lib/src/services/completion/yaml/yaml_completion_generator.dart
@@ -127,9 +127,15 @@
for (var i = 0; i < path.length - 1; i++) {
var node = path[i];
if (node is YamlMap && producer is KeyValueProducer) {
+ // Value producers are based on keys, so try to locate the key for the
+ // value that was next in the path.
var key = node.keyAtValue(path[i + 1]);
if (key is YamlScalar) {
producer = producer.producerForKey(key.value);
+ // Otherwise, if the item next in the path was a key itself, use the
+ // current producer to provide completion for the key.
+ } else if (node.nodes.containsKey(path[i + 1])) {
+ return producer;
} else {
return null;
}
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/create_method.dart b/pkg/analysis_server/lib/src/services/correction/dart/create_method.dart
index a697fff..a76ce2a 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/create_method.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/create_method.dart
@@ -5,6 +5,7 @@
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analysis_server/src/services/correction/util.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_plugin/protocol/protocol_common.dart' show Position;
@@ -147,7 +148,10 @@
// use different utils
var targetPath = targetClassElement.source.fullName;
var targetResolveResult =
- await resolvedResult.session.getResolvedUnit(targetPath);
+ await resolvedResult.session.getResolvedUnit2(targetPath);
+ if (targetResolveResult is! ResolvedUnitResult) {
+ return;
+ }
utils = CorrectionUtils(targetResolveResult);
}
if (targetElement == null || targetNode == null) {
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/wrap_in_text.dart b/pkg/analysis_server/lib/src/services/correction/dart/wrap_in_text.dart
index 49fb849..53c87c90 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/wrap_in_text.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/wrap_in_text.dart
@@ -48,15 +48,17 @@
static WrapInText newInstance() => WrapInText();
static _Context? _extractContextInformation(AstNode node) {
- if (node is NamedExpression) {
- var expression = node.expression;
- if (expression.typeOrThrow.isDartCoreString) {
- var parameterElement = node.name.label.staticElement;
- if (parameterElement is ParameterElement) {
- return _Context(
- stringExpression: expression,
- parameterElement: parameterElement,
- );
+ if (node is Expression) {
+ var parent = node.parent;
+ if (parent is NamedExpression) {
+ if (node.typeOrThrow.isDartCoreString) {
+ var parameterElement = parent.name.label.staticElement;
+ if (parameterElement is ParameterElement) {
+ return _Context(
+ stringExpression: node,
+ parameterElement: parameterElement,
+ );
+ }
}
}
}
diff --git a/pkg/analysis_server/lib/src/services/correction/util.dart b/pkg/analysis_server/lib/src/services/correction/util.dart
index 2f4bec9..c77cc97 100644
--- a/pkg/analysis_server/lib/src/services/correction/util.dart
+++ b/pkg/analysis_server/lib/src/services/correction/util.dart
@@ -35,7 +35,12 @@
Future<void> addLibraryImports(AnalysisSession session, SourceChange change,
LibraryElement targetLibrary, Set<Source> libraries) async {
var libraryPath = targetLibrary.source.fullName;
- var resolveResult = await session.getResolvedUnit(libraryPath);
+
+ var resolveResult = await session.getResolvedUnit2(libraryPath);
+ if (resolveResult is! ResolvedUnitResult) {
+ return;
+ }
+
var libUtils = CorrectionUtils(resolveResult);
var eol = libUtils.endOfLine;
// Prepare information about existing imports.
diff --git a/pkg/analysis_server/lib/src/services/pub/pub_api.dart b/pkg/analysis_server/lib/src/services/pub/pub_api.dart
index e52dc50..d89d165 100644
--- a/pkg/analysis_server/lib/src/services/pub/pub_api.dart
+++ b/pkg/analysis_server/lib/src/services/pub/pub_api.dart
@@ -17,6 +17,7 @@
/// Failed requests will automatically be retried.
class PubApi {
static const packageNameListPath = '/api/package-name-completion-data';
+ static const packageInfoPath = '/api/packages';
/// Maximum number of retries if requests fail.
static const maxFailedRequests = 5;
@@ -66,6 +67,28 @@
httpClient.close();
}
+ /// Fetches package details from the Pub API.
+ ///
+ /// Failed requests will be retried a number of times. If no successful response
+ /// is received, will return null.
+ Future<PubApiPackageDetails?> packageInfo(String packageName) async {
+ final json = await _getJson('$_pubHostedUrl$packageInfoPath/$packageName');
+ if (json == null) {
+ return null;
+ }
+
+ final latest = json['latest'] as Map<String, Object?>?;
+ if (latest == null) {
+ return null;
+ }
+
+ final pubspec = latest['pubspec'] as Map<String, Object?>?;
+ final description =
+ pubspec != null ? pubspec['description'] as String? : null;
+ final version = latest['version'] as String?;
+ return PubApiPackageDetails(packageName, description, version);
+ }
+
/// Calls a pub API and decodes the resulting JSON.
///
/// Automatically retries the request for specific types of failures after
@@ -132,6 +155,14 @@
PubApiPackage(this.packageName);
}
+class PubApiPackageDetails {
+ final String packageName;
+ final String? description;
+ final String? latestVersion;
+
+ PubApiPackageDetails(this.packageName, this.description, this.latestVersion);
+}
+
/// A wrapper over a package:http Client that does not pass on calls to [close].
///
/// This is used to prevent the server closing a client that may be provided to
diff --git a/pkg/analysis_server/lib/src/services/pub/pub_package_service.dart b/pkg/analysis_server/lib/src/services/pub/pub_package_service.dart
index e958542..815711f 100644
--- a/pkg/analysis_server/lib/src/services/pub/pub_package_service.dart
+++ b/pkg/analysis_server/lib/src/services/pub/pub_package_service.dart
@@ -14,8 +14,15 @@
/// Information about Pub packages that can be converted to/from JSON and
/// cached to disk.
class PackageDetailsCache {
- static const cacheVersion = 2;
+ static const cacheVersion = 3;
static const maxCacheAge = Duration(hours: 18);
+ static const maxPackageDetailsRequestsInFlight = 5;
+
+ /// Requests to write the cache from fetching packge details will be debounced
+ /// by this duration to prevent many writes while the user may be cursoring
+ /// though completion requests that will trigger fetching descriptions/versions.
+ static const _writeCacheDebounceDuration = Duration(seconds: 3);
+
final Map<String, PubPackage> packages;
DateTime lastUpdatedUtc;
@@ -71,7 +78,7 @@
if (nameJson is! String) {
return null;
}
- packages.add(PubPackage.fromJson(nameJson));
+ packages.add(PubPackage.fromJson(packageJson));
}
final packageMap = Map.fromEntries(
@@ -96,8 +103,18 @@
/// Information about a single Pub package.
class PubPackage {
String packageName;
+ String? description;
+ String? latestVersion;
- PubPackage.fromJson(this.packageName);
+ PubPackage.fromDetails(PubApiPackageDetails package)
+ : packageName = package.packageName,
+ description = package.description,
+ latestVersion = package.latestVersion;
+
+ PubPackage.fromJson(Map<String, Object?> json)
+ : packageName = json['packageName'] as String,
+ description = json['description'] as String?,
+ latestVersion = json['latestVersion'] as String?;
PubPackage.fromName(PubApiPackage package)
: packageName = package.packageName;
@@ -105,6 +122,8 @@
Map<String, Object> toJson() {
return {
'packageName': packageName,
+ if (description != null) 'description': description!,
+ if (latestVersion != null) 'latestVersion': latestVersion!,
};
}
}
@@ -115,7 +134,8 @@
class PubPackageService {
final InstrumentationService _instrumentationService;
final PubApi _api;
- Timer? _nextRequestTimer;
+ Timer? _nextPackageNameListRequestTimer;
+ Timer? _nextWriteDiskCacheTimer;
/// [ResourceProvider] used for caching. This should generally be a
/// [PhysicalResourceProvider] outside of tests.
@@ -126,6 +146,8 @@
@visibleForTesting
PackageDetailsCache? packageCache;
+ int _packageDetailsRequestsInFlight = 0;
+
PubPackageService(
this._instrumentationService, this.cacheResourceProvider, this._api);
@@ -133,7 +155,7 @@
List<PubPackage> get cachedPackages =>
packageCache?.packages.values.toList() ?? [];
- bool get isRunning => _nextRequestTimer != null;
+ bool get isRunning => _nextPackageNameListRequestTimer != null;
@visibleForTesting
File get packageCacheFile {
@@ -153,10 +175,48 @@
}
// If there is no queued request, initialize one when the current cache expires.
- _nextRequestTimer ??=
+ _nextPackageNameListRequestTimer ??=
Timer(packageCache.cacheTimeRemaining, _fetchFromServer);
}
+ /// Gets the cached package details for package [packageName].
+ ///
+ /// Returns null if no package details are cached.
+ PubPackage? cachedPackageDetails(String packageName) =>
+ packageCache?.packages[packageName];
+
+ /// Gets package details for package [packageName].
+ ///
+ /// If the package details are not cached, will call the Pub API and cache
+ /// the result. Results are cached for the same period as the main package
+ /// list cache - that is, when the package list cache expires, all cached
+ /// package details will go with it.
+ Future<PubPackage?> packageDetails(String packageName) async {
+ var packageData = packageCache?.packages[packageName];
+ // If we don't have the version for this package, we don't have its full details.
+ if (packageData?.latestVersion == null &&
+ // Limit the number of package details requests that can be in-flight at
+ // once since an editor may send many of these requests as the user
+ // cursors through the results (a good editor will cancel the resolve
+ // requests, but we may have already started the requests synchronously
+ // before handling a cancellation).
+ _packageDetailsRequestsInFlight <=
+ PackageDetailsCache.maxPackageDetailsRequestsInFlight) {
+ _packageDetailsRequestsInFlight++;
+ try {
+ final details = await _api.packageInfo(packageName);
+ if (details != null) {
+ packageData = PubPackage.fromDetails(details);
+ packageCache?.packages[packageName] = packageData;
+ _writeDiskCacheDebounced();
+ }
+ } finally {
+ _packageDetailsRequestsInFlight--;
+ }
+ }
+ return packageData;
+ }
+
@visibleForTesting
PackageDetailsCache? readDiskCache() {
final file = packageCacheFile;
@@ -175,10 +235,14 @@
}
}
- void shutdown() => _nextRequestTimer?.cancel();
+ void shutdown() => _nextPackageNameListRequestTimer?.cancel();
@visibleForTesting
- void writeDiskCache(PackageDetailsCache cache) {
+ void writeDiskCache([PackageDetailsCache? cache]) {
+ cache ??= packageCache;
+ if (cache == null) {
+ return;
+ }
final file = packageCacheFile;
file.writeAsStringSync(jsonEncode(cache.toJson()));
}
@@ -194,12 +258,21 @@
final packageCache = PackageDetailsCache.fromApiResults(packages);
this.packageCache = packageCache;
- writeDiskCache(packageCache);
+ writeDiskCache();
} catch (e) {
_instrumentationService.logError('Failed to fetch packages from Pub: $e');
} finally {
- _nextRequestTimer =
+ _nextPackageNameListRequestTimer =
Timer(PackageDetailsCache.maxCacheAge, _fetchFromServer);
}
}
+
+ /// Writes the package cache to disk after
+ /// [PackageDetailsCache._writeCacheDebounceDuration] has elapsed, restarting
+ /// the timer each time this method is called.
+ void _writeDiskCacheDebounced() {
+ _nextWriteDiskCacheTimer?.cancel();
+ _nextWriteDiskCacheTimer =
+ Timer(PackageDetailsCache._writeCacheDebounceDuration, writeDiskCache);
+ }
}
diff --git a/pkg/analysis_server/lib/src/services/refactoring/convert_getter_to_method.dart b/pkg/analysis_server/lib/src/services/refactoring/convert_getter_to_method.dart
index b2f9f13..565b9a8 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/convert_getter_to_method.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/convert_getter_to_method.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:analysis_server/src/protocol_server.dart' hide Element;
import 'package:analysis_server/src/services/correction/status.dart';
import 'package:analysis_server/src/services/refactoring/refactoring.dart';
@@ -24,7 +22,7 @@
final AnalysisSession session;
final PropertyAccessorElement element;
- SourceChange change;
+ late SourceChange change;
ConvertGetterToMethodRefactoringImpl(
this.searchEngine, this.session, this.element);
@@ -53,13 +51,13 @@
await _updateElementReferences(element);
}
// method
- if (element.enclosingElement is ClassElement) {
- FieldElement field = element.variable;
+ var field = element.variable;
+ if (field is FieldElement && field.enclosingElement is ClassElement) {
var elements = await getHierarchyMembers(searchEngine, field);
await Future.forEach(elements, (ClassMemberElement member) async {
if (member is FieldElement) {
var getter = member.getter;
- if (!getter.isSynthetic) {
+ if (getter != null && !getter.isSynthetic) {
await _updateElementDeclaration(getter);
return _updateElementReferences(getter);
}
@@ -81,11 +79,11 @@
Future<void> _updateElementDeclaration(
PropertyAccessorElement element) async {
// prepare "get" keyword
- Token getKeyword;
+ Token? getKeyword;
{
var sessionHelper = AnalysisSessionHelper(session);
var result = await sessionHelper.getElementDeclaration(element);
- var declaration = result.node;
+ var declaration = result?.node;
if (declaration is MethodDeclaration) {
getKeyword = declaration.propertyKeyword;
} else if (declaration is FunctionDeclaration) {
diff --git a/pkg/analysis_server/lib/src/services/refactoring/convert_method_to_getter.dart b/pkg/analysis_server/lib/src/services/refactoring/convert_method_to_getter.dart
index 7fb6210..95ce6f0 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/convert_method_to_getter.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/convert_method_to_getter.dart
@@ -2,14 +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.
-// @dart = 2.9
-
import 'package:analysis_server/src/protocol_server.dart' hide Element;
import 'package:analysis_server/src/services/correction/status.dart';
import 'package:analysis_server/src/services/refactoring/refactoring.dart';
import 'package:analysis_server/src/services/refactoring/refactoring_internal.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/element/element.dart';
import 'package:analyzer/src/dart/analysis/session_helper.dart';
@@ -23,10 +22,11 @@
final AnalysisSessionHelper sessionHelper;
final ExecutableElement element;
- SourceChange change;
+ late SourceChange change;
- ConvertMethodToGetterRefactoringImpl(this.searchEngine, this.element)
- : sessionHelper = AnalysisSessionHelper(element.session);
+ ConvertMethodToGetterRefactoringImpl(
+ this.searchEngine, AnalysisSession session, this.element)
+ : sessionHelper = AnalysisSessionHelper(session);
@override
String get refactoringName => 'Convert Method To Getter';
@@ -50,7 +50,7 @@
'Only class methods or top-level functions can be converted to getters.');
}
// returns a value
- if (element.returnType != null && element.returnType.isVoid) {
+ if (element.returnType.isVoid) {
return RefactoringStatus.fatal(
'Cannot convert ${element.kind.displayName} returning void.');
}
@@ -67,14 +67,14 @@
Future<SourceChange> createChange() async {
change = SourceChange(refactoringName);
// FunctionElement
+ final element = this.element;
if (element is FunctionElement) {
await _updateElementDeclaration(element);
await _updateElementReferences(element);
}
// MethodElement
if (element is MethodElement) {
- MethodElement method = element;
- var elements = await getHierarchyMembers(searchEngine, method);
+ var elements = await getHierarchyMembers(searchEngine, element);
await Future.forEach(elements, (Element element) async {
await _updateElementDeclaration(element);
return _updateElementReferences(element);
@@ -86,10 +86,10 @@
Future<void> _updateElementDeclaration(Element element) async {
// prepare parameters
- FormalParameterList parameters;
+ FormalParameterList? parameters;
{
var result = await sessionHelper.getElementDeclaration(element);
- var declaration = result.node;
+ var declaration = result?.node;
if (declaration is MethodDeclaration) {
parameters = declaration.parameters;
} else if (declaration is FunctionDeclaration) {
@@ -98,6 +98,9 @@
return;
}
}
+ if (parameters == null) {
+ return;
+ }
// insert "get "
{
var edit = SourceEdit(element.nameOffset, 0, 'get ');
@@ -117,13 +120,13 @@
var refElement = reference.element;
var refRange = reference.range;
// prepare invocation
- MethodInvocation invocation;
+ MethodInvocation? invocation;
{
var resolvedUnit =
await sessionHelper.getResolvedUnitByElement(refElement);
- var refUnit = resolvedUnit.unit;
+ var refUnit = resolvedUnit?.unit;
var refNode = NodeLocator(refRange.offset).searchWithin(refUnit);
- invocation = refNode.thisOrAncestorOfType<MethodInvocation>();
+ invocation = refNode?.thisOrAncestorOfType<MethodInvocation>();
}
// we need invocation
if (invocation != null) {
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 e6ffa45..16ca48b 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'dart:collection';
import 'package:analysis_server/src/protocol_server.dart' hide Element;
@@ -34,10 +32,10 @@
final ResolvedUnitResult resolveResult;
final int selectionOffset;
final int selectionLength;
- SourceRange selectionRange;
- CorrectionUtils utils;
+ late SourceRange selectionRange;
+ late CorrectionUtils utils;
- String name;
+ late String name;
bool extractAll = true;
@override
final List<int> coveringExpressionOffsets = <int>[];
@@ -50,9 +48,9 @@
@override
final List<int> lengths = <int>[];
- FunctionBody coveringFunctionBody;
- Expression singleExpression;
- String stringLiteralPart;
+ FunctionBody? coveringFunctionBody;
+ Expression? singleExpression;
+ String? stringLiteralPart;
final List<SourceRange> occurrences = <SourceRange>[];
final Map<Element, int> elementIds = <Element, int>{};
Set<String> excludedVariableNames = <String>{};
@@ -63,14 +61,14 @@
utils = CorrectionUtils(resolveResult);
}
- String get file => resolveResult.path;
+ String get file => resolveResult.path!;
@override
String get refactoringName => 'Extract Local Variable';
- CompilationUnit get unit => resolveResult.unit;
+ CompilationUnit get unit => resolveResult.unit!;
- CompilationUnitElement get unitElement => unit.declaredElement;
+ CompilationUnitElement get unitElement => unit.declaredElement!;
String get _declarationKeyword {
if (_isPartOfConstantExpression(singleExpression)) {
@@ -132,7 +130,9 @@
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 (singleExpression?.parent is ExpressionStatement &&
+ var singleExpression = this.singleExpression;
+ if (singleExpression != null &&
+ singleExpression.parent is ExpressionStatement &&
occurrences.length == 1) {
var keyword = _declarationKeyword;
var declarationSource = '$keyword $name = ';
@@ -173,7 +173,7 @@
addPosition(edit.offset + nameOffsetInDeclarationCode);
occurrencesShift = edit.replacement.length;
} else if (target is ExpressionFunctionBody) {
- var prefix = utils.getNodePrefix(target.parent);
+ var prefix = utils.getNodePrefix(target.parent!);
var indent = utils.getIndent(1);
var expr = target.expression;
{
@@ -231,7 +231,7 @@
return RefactoringStatus.fatal(
'The selection offset must be greater than zero.');
}
- if (selectionOffset + selectionLength >= resolveResult.content.length) {
+ if (selectionOffset + selectionLength >= resolveResult.content!.length) {
return RefactoringStatus.fatal(
'The selection end offset must be less then the length of the file.');
}
@@ -300,9 +300,7 @@
if (node is MethodInvocation) {
var invocation = node;
var element = invocation.methodName.staticElement;
- if (element is ExecutableElement &&
- element.returnType != null &&
- element.returnType.isVoid) {
+ if (element is ExecutableElement && element.returnType.isVoid) {
if (singleExpression == null) {
return RefactoringStatus.fatal(
'Cannot extract the void expression.',
@@ -338,7 +336,7 @@
}
// single node selected
if (singleExpression != null) {
- selectionRange = range.node(singleExpression);
+ selectionRange = range.node(singleExpression!);
return RefactoringStatus();
}
// invalid selection
@@ -348,7 +346,7 @@
/// Return an unique identifier for the given [Element], or `null` if
/// [element] is `null`.
- int _encodeElement(Element element) {
+ int? _encodeElement(Element? element) {
if (element == null) {
return null;
}
@@ -367,10 +365,6 @@
/// there are multiple variables with the same name are declared in the
/// function we are searching occurrences in.
String _encodeExpressionTokens(Expression expr, List<Token> tokens) {
- // no expression, i.e. a part of a string
- if (expr == null) {
- return tokens.join(_TOKEN_SEPARATOR);
- }
// prepare Token -> LocalElement map
Map<Token, Element> map = HashMap<Token, Element>(
equals: (Token a, Token b) => a.lexeme == b.lexeme,
@@ -395,7 +389,7 @@
/// Return the [AstNode] to defined the variable before.
/// It should be accessible by all the given [occurrences].
- AstNode _findDeclarationTarget(List<SourceRange> occurrences) {
+ AstNode? _findDeclarationTarget(List<SourceRange> occurrences) {
var nodes = _findNodes(occurrences);
var commonParent = getNearestCommonAncestor(nodes);
// Block
@@ -405,14 +399,18 @@
return firstParents[commonIndex + 1];
}
// ExpressionFunctionBody
- AstNode expressionBody = _getEnclosingExpressionBody(commonParent);
+ var expressionBody = _getEnclosingExpressionBody(commonParent);
if (expressionBody != null) {
return expressionBody;
}
// single Statement
- AstNode target = commonParent.thisOrAncestorOfType<Statement>();
- while (target.parent is! Block) {
- target = target.parent;
+ AstNode? target = commonParent?.thisOrAncestorOfType<Statement>();
+ while (target != null) {
+ var parent = target.parent;
+ if (parent is Block) {
+ break;
+ }
+ target = parent;
}
return target;
}
@@ -421,7 +419,7 @@
List<AstNode> _findNodes(List<SourceRange> ranges) {
var nodes = <AstNode>[];
for (var range in ranges) {
- var node = NodeLocator(range.offset).searchWithin(unit);
+ var node = NodeLocator(range.offset).searchWithin(unit)!;
nodes.add(node);
}
return nodes;
@@ -429,7 +427,7 @@
/// Returns the [ExpressionFunctionBody] that encloses [node], or `null`
/// if [node] is not enclosed with an [ExpressionFunctionBody].
- ExpressionFunctionBody _getEnclosingExpressionBody(AstNode node) {
+ ExpressionFunctionBody? _getEnclosingExpressionBody(AstNode? node) {
while (node != null) {
if (node is Statement) {
return null;
@@ -447,7 +445,10 @@
return analysisOptions.isLintEnabled(name);
}
- bool _isPartOfConstantExpression(AstNode node) {
+ bool _isPartOfConstantExpression(AstNode? node) {
+ if (node == null) {
+ return false;
+ }
if (node is TypedLiteral) {
return node.isConst;
}
@@ -468,6 +469,8 @@
void _prepareNames() {
names.clear();
+ final stringLiteralPart = this.stringLiteralPart;
+ final singleExpression = this.singleExpression;
if (stringLiteralPart != null) {
names.addAll(getVariableNameSuggestionsForText(
stringLiteralPart, excludedVariableNames));
@@ -486,13 +489,14 @@
elementIds.clear();
// prepare selection
- String selectionSource;
+ String? selectionSource;
+ var singleExpression = this.singleExpression;
if (singleExpression != null) {
var tokens = TokenUtils.getNodeTokens(singleExpression);
selectionSource = _encodeExpressionTokens(singleExpression, tokens);
}
// visit function
- coveringFunctionBody.accept(_OccurrencesVisitor(
+ coveringFunctionBody!.accept(_OccurrencesVisitor(
this, occurrences, selectionSource, unit.featureSet));
}
@@ -509,7 +513,7 @@
class _OccurrencesVisitor extends GeneralizingAstVisitor<void> {
final ExtractLocalRefactoringImpl ref;
final List<SourceRange> occurrences;
- final String selectionSource;
+ final String? selectionSource;
final FeatureSet featureSet;
_OccurrencesVisitor(
@@ -533,12 +537,13 @@
@override
void visitStringLiteral(StringLiteral node) {
- if (ref.stringLiteralPart != null) {
- var length = ref.stringLiteralPart.length;
+ var stringLiteralPart = ref.stringLiteralPart;
+ if (stringLiteralPart != null) {
+ var length = stringLiteralPart.length;
var value = ref.utils.getNodeText(node);
var lastIndex = 0;
while (true) {
- var index = value.indexOf(ref.stringLiteralPart, lastIndex);
+ var index = value.indexOf(stringLiteralPart, lastIndex);
if (index == -1) {
break;
}
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 d9c1a15..a2c9a19 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
@@ -2,8 +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.
-// @dart = 2.9
-
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';
@@ -17,6 +15,7 @@
import 'package:analysis_server/src/services/refactoring/rename_unit_member.dart';
import 'package:analysis_server/src/services/refactoring/visible_ranges_computer.dart';
import 'package:analysis_server/src/services/search/search_engine.dart';
+import 'package:analysis_server/src/utilities/extensions/ast.dart';
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/ast/ast.dart';
@@ -34,7 +33,7 @@
const String _TOKEN_SEPARATOR = '\uFFFF';
-Element _getLocalElement(SimpleIdentifier node) {
+Element? _getLocalElement(SimpleIdentifier node) {
var element = node.writeOrReadElement;
if (element is LocalVariableElement ||
element is ParameterElement ||
@@ -72,14 +71,14 @@
final ResolvedUnitResult resolveResult;
final int selectionOffset;
final int selectionLength;
- SourceRange selectionRange;
- CorrectionUtils utils;
+ late SourceRange selectionRange;
+ late CorrectionUtils utils;
final Set<Source> librariesToImport = <Source>{};
@override
String returnType = '';
- String variableType;
- String name;
+ String? variableType;
+ late String name;
bool extractAll = true;
@override
bool canCreateGetter = false;
@@ -92,7 +91,7 @@
final List<int> lengths = <int>[];
/// The map of local elements to their visibility ranges.
- Map<LocalElement, SourceRange> _visibleRangeMap;
+ late Map<LocalElement, SourceRange> _visibleRangeMap;
/// The map of local names to their visibility ranges.
final Map<String, List<SourceRange>> _localNames =
@@ -108,12 +107,12 @@
final Map<String, List<SourceRange>> _parameterReferencesMap =
<String, List<SourceRange>>{};
bool _hasAwait = false;
- DartType _returnType;
- String _returnVariableName;
- AstNode _parentMember;
- Expression _selectionExpression;
- FunctionExpression _selectionFunctionExpression;
- List<Statement> _selectionStatements;
+ DartType? _returnType;
+ String? _returnVariableName;
+ AstNode? _parentMember;
+ Expression? _selectionExpression;
+ FunctionExpression? _selectionFunctionExpression;
+ List<Statement>? _selectionStatements;
final List<_Occurrence> _occurrences = [];
bool _staticContext = false;
@@ -250,7 +249,7 @@
occurrence._parameterOldToOccurrenceName[_returnVariableName];
// may be declare variable
if (!_parametersMap.containsKey(_returnVariableName)) {
- if (variableType.isEmpty) {
+ if (variableType!.isEmpty) {
sb.write('var ');
} else {
sb.write(variableType);
@@ -298,12 +297,12 @@
// add replace edit
var edit = newSourceEdit_range(range, invocationSource);
doSourceChange_addElementEdit(
- change, resolveResult.unit.declaredElement, edit);
+ change, resolveResult.unit!.declaredElement!, edit);
}
// add method declaration
{
// prepare environment
- var prefix = utils.getNodePrefix(_parentMember);
+ var prefix = utils.getNodePrefix(_parentMember!);
var eol = utils.endOfLine;
// prepare annotations
var annotations = '';
@@ -314,14 +313,15 @@
}
}
// prepare declaration source
- String declarationSource;
+ String? declarationSource;
{
var returnExpressionSource = _getMethodBodySource();
// closure
- if (_selectionFunctionExpression != null) {
+ final selectionFunctionExpression = _selectionFunctionExpression;
+ if (selectionFunctionExpression != null) {
var returnTypeCode = _getExpectedClosureReturnTypeCode();
declarationSource = '$returnTypeCode$name$returnExpressionSource';
- if (_selectionFunctionExpression.body is ExpressionFunctionBody) {
+ if (selectionFunctionExpression.body is ExpressionFunctionBody) {
declarationSource += ';';
}
}
@@ -375,10 +375,10 @@
}
// insert declaration
if (declarationSource != null) {
- var offset = _parentMember.end;
+ var offset = _parentMember!.end;
var edit = SourceEdit(offset, 0, '$eol$eol$prefix$declarationSource');
doSourceChange_addElementEdit(
- change, resolveResult.unit.declaredElement, edit);
+ change, resolveResult.unit!.declaredElement!, edit);
}
}
// done
@@ -427,15 +427,15 @@
/// elements.
Future<RefactoringStatus> _checkPossibleConflicts() async {
var result = RefactoringStatus();
- var parent = _parentMember.parent;
+ var parent = _parentMember!.parent;
// top-level function
if (parent is CompilationUnit) {
- var libraryElement = parent.declaredElement.library;
+ var libraryElement = parent.declaredElement!.library;
return validateCreateFunction(searchEngine, libraryElement, name);
}
// method of class
if (parent is ClassDeclaration) {
- var classElement = parent.declaredElement;
+ var classElement = parent.declaredElement!;
return validateCreateMethod(searchEngine,
AnalysisSessionHelper(resolveResult.session), classElement, name);
}
@@ -450,7 +450,7 @@
return RefactoringStatus.fatal(
'The selection offset must be greater than zero.');
}
- if (selectionOffset + selectionLength >= resolveResult.content.length) {
+ if (selectionOffset + selectionLength >= resolveResult.content!.length) {
return RefactoringStatus.fatal(
'The selection end offset must be less then the length of the file.');
}
@@ -557,7 +557,7 @@
/// If the [selectionRange] is associated with a [FunctionExpression], return
/// this [FunctionExpression].
- FunctionExpression _findFunctionExpression() {
+ FunctionExpression? _findFunctionExpression() {
if (selectionRange.length != 0) {
return null;
}
@@ -567,21 +567,25 @@
// Check for the parameter list of a FunctionExpression.
{
var function = node?.thisOrAncestorOfType<FunctionExpression>();
- if (function != null &&
- function.parameters != null &&
- range.node(function.parameters).contains(offset)) {
- return function;
+ if (function != null) {
+ var parameters = function.parameters;
+ if (parameters != null && range.node(parameters).contains(offset)) {
+ return function;
+ }
}
}
// Check for the name of the named argument with the closure expression.
- if (node is SimpleIdentifier &&
- node.parent is Label &&
- node.parent.parent is NamedExpression) {
- NamedExpression namedExpression = node.parent.parent;
- var expression = namedExpression.expression;
- if (expression is FunctionExpression) {
- return expression;
+ if (node is SimpleIdentifier) {
+ var label = node.parent;
+ if (label is Label) {
+ var namedExpression = label.parent;
+ if (namedExpression is NamedExpression) {
+ var expression = namedExpression.expression;
+ if (expression is FunctionExpression) {
+ return expression;
+ }
+ }
}
}
@@ -593,7 +597,7 @@
/// function type has the return type specified, return this return type's
/// code. Otherwise return the empty string.
String _getExpectedClosureReturnTypeCode() {
- Expression argument = _selectionFunctionExpression;
+ Expression argument = _selectionFunctionExpression!;
if (argument.parent is NamedExpression) {
argument = argument.parent as NamedExpression;
}
@@ -629,19 +633,21 @@
// apply replacements
source = SourceEdit.applySequence(source, replaceEdits);
// change indentation
- if (_selectionFunctionExpression != null) {
- AstNode baseNode =
- _selectionFunctionExpression.thisOrAncestorOfType<Statement>();
+ final selectionFunctionExpression = _selectionFunctionExpression;
+ if (selectionFunctionExpression != null) {
+ var baseNode =
+ selectionFunctionExpression.thisOrAncestorOfType<Statement>();
if (baseNode != null) {
var baseIndent = utils.getNodePrefix(baseNode);
- var targetIndent = utils.getNodePrefix(_parentMember);
+ var targetIndent = utils.getNodePrefix(_parentMember!);
source = utils.replaceSourceIndent(source, baseIndent, targetIndent);
source = source.trim();
}
}
- if (_selectionStatements != null) {
- var selectionIndent = utils.getNodePrefix(_selectionStatements[0]);
- var targetIndent = utils.getNodePrefix(_parentMember) + ' ';
+ final selectionStatements = _selectionStatements;
+ if (selectionStatements != null) {
+ var selectionIndent = utils.getNodePrefix(selectionStatements[0]);
+ var targetIndent = utils.getNodePrefix(_parentMember!) + ' ';
source = utils.replaceSourceIndent(source, selectionIndent, targetIndent);
}
// done
@@ -652,25 +658,25 @@
var originalSource = utils.getText(range.offset, range.length);
var pattern = _SourcePattern();
var replaceEdits = <SourceEdit>[];
- resolveResult.unit
+ resolveResult.unit!
.accept(_GetSourcePatternVisitor(range, pattern, replaceEdits));
replaceEdits = replaceEdits.reversed.toList();
var source = SourceEdit.applySequence(originalSource, replaceEdits);
pattern.normalizedSource =
- _getNormalizedSource(source, resolveResult.unit.featureSet);
+ _getNormalizedSource(source, resolveResult.unit!.featureSet);
return pattern;
}
String _getTypeCode(DartType type) {
- return utils.getTypeSource(type, librariesToImport);
+ return utils.getTypeSource(type, librariesToImport)!;
}
void _initializeHasAwait() {
var visitor = _HasAwaitVisitor();
if (_selectionExpression != null) {
- _selectionExpression.accept(visitor);
+ _selectionExpression!.accept(visitor);
} else if (_selectionStatements != null) {
- _selectionStatements.forEach((statement) {
+ _selectionStatements!.forEach((statement) {
statement.accept(visitor);
});
}
@@ -685,7 +691,7 @@
var patternToSelectionName =
_inverseMap(selectionPattern.originalToPatternNames);
// prepare an enclosing parent - class or unit
- var enclosingMemberParent = _parentMember.parent;
+ var enclosingMemberParent = _parentMember!.parent!;
// visit nodes which will able to access extracted method
enclosingMemberParent.accept(_InitializeOccurrencesVisitor(
this, selectionPattern, patternToSelectionName));
@@ -700,28 +706,30 @@
var result = RefactoringStatus();
var assignedUsedVariables = <VariableElement>[];
- var unit = resolveResult.unit;
+ var unit = resolveResult.unit!;
_visibleRangeMap = VisibleRangesComputer.forNode(unit);
unit.accept(
_InitializeParametersVisitor(this, assignedUsedVariables),
);
// single expression
- if (_selectionExpression != null) {
- _returnType = _selectionExpression.staticType;
+ final selectionExpression = _selectionExpression;
+ if (selectionExpression != null) {
+ _returnType = selectionExpression.typeOrThrow;
}
// verify that none or all execution flows end with a "return"
- if (_selectionStatements != null) {
- var hasReturn = _selectionStatements.any(_mayEndWithReturnStatement);
- if (hasReturn && !ExitDetector.exits(_selectionStatements.last)) {
+ final selectionStatements = _selectionStatements;
+ if (selectionStatements != null) {
+ var hasReturn = selectionStatements.any(_mayEndWithReturnStatement);
+ if (hasReturn && !ExitDetector.exits(selectionStatements.last)) {
result.addError(ERROR_EXITS);
}
}
// maybe ends with "return" statement
- if (_selectionStatements != null) {
+ if (selectionStatements != null) {
var typeSystem = resolveResult.typeSystem;
var returnTypeComputer = _ReturnTypeComputer(typeSystem);
- _selectionStatements.forEach((statement) {
+ selectionStatements.forEach((statement) {
statement.accept(returnTypeComputer);
});
_returnType = returnTypeComputer.returnType;
@@ -758,10 +766,11 @@
Future<void> _initializeReturnType() async {
var typeProvider = resolveResult.typeProvider;
+ final returnTypeObj = _returnType;
if (_selectionFunctionExpression != null) {
variableType = '';
returnType = '';
- } else if (_returnType == null) {
+ } else if (returnTypeObj == null) {
variableType = null;
if (_hasAwait) {
var futureVoid = typeProvider.futureType(typeProvider.voidType);
@@ -769,7 +778,7 @@
} else {
returnType = 'void';
}
- } else if (_returnType.isDynamic) {
+ } else if (returnTypeObj.isDynamic) {
variableType = '';
if (_hasAwait) {
returnType = _getTypeCode(typeProvider.futureDynamicType);
@@ -777,13 +786,13 @@
returnType = '';
}
} else {
- variableType = _getTypeCode(_returnType);
+ variableType = _getTypeCode(returnTypeObj);
if (_hasAwait) {
- if (_returnType.element != typeProvider.futureElement) {
- returnType = _getTypeCode(typeProvider.futureType(_returnType));
+ if (returnTypeObj.element != typeProvider.futureElement) {
+ returnType = _getTypeCode(typeProvider.futureType(returnTypeObj));
}
} else {
- returnType = variableType;
+ returnType = variableType!;
}
}
}
@@ -805,7 +814,7 @@
var name = parameter.name;
var parameterRanges = _parameterReferencesMap[id];
var otherRanges = _localNames[name];
- for (var parameterRange in parameterRanges) {
+ for (var parameterRange in parameterRanges!) {
if (otherRanges != null) {
for (var otherRange in otherRanges) {
if (parameterRange.intersects(otherRange)) {
@@ -823,7 +832,7 @@
/// Checks if [element] is referenced after [selectionRange].
bool _isUsedAfterSelection(Element element) {
var visitor = _IsUsedAfterSelectionVisitor(this, element);
- _parentMember.accept(visitor);
+ _parentMember!.accept(visitor);
return visitor.result;
}
@@ -831,15 +840,16 @@
/// proposed as names of the extracted method.
void _prepareExcludedNames() {
_excludedNames.clear();
- var localElements = getDefinedLocalElements(_parentMember);
- _excludedNames.addAll(localElements.map((e) => e.name));
+ var localElements = getDefinedLocalElements(_parentMember!);
+ _excludedNames.addAll(localElements.map((e) => e.name!));
}
void _prepareNames() {
names.clear();
- if (_selectionExpression != null) {
+ final selectionExpression = _selectionExpression;
+ if (selectionExpression != null) {
names.addAll(getVariableNameSuggestionsForExpression(
- _selectionExpression.staticType, _selectionExpression, _excludedNames,
+ selectionExpression.typeOrThrow, selectionExpression, _excludedNames,
isMethod: true));
}
}
@@ -854,7 +864,7 @@
}
/// Checks if the given [expression] is reasonable to extract as a getter.
- static bool _isExpressionForGetter(Expression expression) {
+ static bool _isExpressionForGetter(Expression? expression) {
if (expression is BinaryExpression) {
return _isExpressionForGetter(expression.leftOperand) &&
_isExpressionForGetter(expression.rightOperand);
@@ -906,18 +916,17 @@
}
@override
- Object visitAssignmentExpression(AssignmentExpression node) {
+ void visitAssignmentExpression(AssignmentExpression node) {
super.visitAssignmentExpression(node);
var lhs = node.leftHandSide;
if (_isFirstSelectedNode(lhs)) {
invalidSelection('Cannot extract the left-hand side of an assignment.',
newLocation_fromNode(lhs));
}
- return null;
}
@override
- Object visitConstructorInitializer(ConstructorInitializer node) {
+ void visitConstructorInitializer(ConstructorInitializer node) {
super.visitConstructorInitializer(node);
if (_isFirstSelectedNode(node)) {
invalidSelection(
@@ -925,17 +934,15 @@
'Select expression part of initializer.',
newLocation_fromNode(node));
}
- return null;
}
@override
- Object visitForParts(ForParts node) {
+ void visitForParts(ForParts node) {
node.visitChildren(this);
- return null;
}
@override
- Object visitForStatement(ForStatement node) {
+ void visitForStatement(ForStatement node) {
super.visitForStatement(node);
var forLoopParts = node.forLoopParts;
if (forLoopParts is ForParts) {
@@ -947,20 +954,18 @@
invalidSelection("Cannot extract increment part of a 'for' statement.");
}
}
- return null;
}
@override
- Object visitGenericFunctionType(GenericFunctionType node) {
+ void visitGenericFunctionType(GenericFunctionType node) {
super.visitGenericFunctionType(node);
if (_isFirstSelectedNode(node)) {
invalidSelection('Cannot extract a single type reference.');
}
- return null;
}
@override
- Object visitSimpleIdentifier(SimpleIdentifier node) {
+ void visitSimpleIdentifier(SimpleIdentifier node) {
super.visitSimpleIdentifier(node);
if (_isFirstSelectedNode(node)) {
// name of declaration
@@ -978,20 +983,18 @@
invalidSelection('Can not extract name part of a property access.');
}
}
- return null;
}
@override
- Object visitTypeName(TypeName node) {
+ void visitTypeName(TypeName node) {
super.visitTypeName(node);
if (_isFirstSelectedNode(node)) {
invalidSelection('Cannot extract a single type reference.');
}
- return null;
}
@override
- Object visitVariableDeclaration(VariableDeclaration node) {
+ void visitVariableDeclaration(VariableDeclaration node) {
super.visitVariableDeclaration(node);
if (_isFirstSelectedNode(node)) {
invalidSelection(
@@ -999,17 +1002,15 @@
'Select whole declaration statement.',
newLocation_fromNode(node));
}
- return null;
}
void _checkParent(AstNode node) {
- var firstParent = firstSelectedNode.parent;
- do {
- node = node.parent;
- if (identical(node, firstParent)) {
+ var firstParent = firstSelectedNode!.parent;
+ for (var parent in node.withParents) {
+ if (identical(parent, firstParent)) {
return;
}
- } while (node != null);
+ }
invalidSelection(
'Not all selected statements are enclosed by the same parent statement.');
}
@@ -1056,7 +1057,7 @@
if (element is FunctionElement) {
return element.type;
}
- throw StateError('Unknown element type: ${element?.runtimeType}');
+ throw StateError('Unknown element type: ${element.runtimeType}');
}
}
@@ -1163,7 +1164,7 @@
// prepare mapping of parameter names to the occurrence variables
nodePattern.originalToPatternNames
.forEach((String originalName, String patternName) {
- var selectionName = patternToSelectionName[patternName];
+ var selectionName = patternToSelectionName[patternName]!;
occurrence._parameterOldToOccurrenceName[selectionName] = originalName;
});
// update static
@@ -1179,7 +1180,7 @@
void _visitStatements(List<Statement> statements) {
var beginStatementIndex = 0;
- var selectionCount = ref._selectionStatements.length;
+ var selectionCount = ref._selectionStatements!.length;
while (beginStatementIndex + selectionCount <= statements.length) {
var nodeRange = range.startEnd(statements[beginStatementIndex],
statements[beginStatementIndex + selectionCount - 1]);
@@ -1219,11 +1220,14 @@
// add parameter
var parameter = ref._parametersMap[name];
if (parameter == null) {
- var parameterType = node.writeOrReadType;
+ var parameterType = node.writeOrReadType!;
var parametersBuffer = StringBuffer();
var parameterTypeCode = ref.utils.getTypeSource(
parameterType, ref.librariesToImport,
parametersBuffer: parametersBuffer);
+ if (parameterTypeCode == null) {
+ return;
+ }
var parametersCode =
parametersBuffer.isNotEmpty ? parametersBuffer.toString() : null;
parameter = RefactoringMethodParameter(
@@ -1237,7 +1241,8 @@
}
// remember, if assigned and used after selection
if (isLeftHandOfAssignment(node) && ref._isUsedAfterSelection(element)) {
- if (!assignedUsedVariables.contains(element)) {
+ if (element is VariableElement &&
+ !assignedUsedVariables.contains(element)) {
assignedUsedVariables.add(element);
}
}
@@ -1246,8 +1251,11 @@
if (element is LocalElement) {
// declared local elements
if (node.inDeclarationContext()) {
- ref._localNames.putIfAbsent(name, () => <SourceRange>[]);
- ref._localNames[name].add(ref._visibleRangeMap[element]);
+ var range = ref._visibleRangeMap[element];
+ if (range != null) {
+ var ranges = ref._localNames.putIfAbsent(name, () => <SourceRange>[]);
+ ranges.add(range);
+ }
}
} else {
// unqualified non-local names
@@ -1291,7 +1299,7 @@
class _ReturnTypeComputer extends RecursiveAstVisitor<void> {
final TypeSystem typeSystem;
- DartType returnType;
+ DartType? returnType;
_ReturnTypeComputer(this.typeSystem);
@@ -1306,18 +1314,22 @@
return;
}
// prepare type
- var type = expression.staticType;
+ var type = expression.typeOrThrow;
if (type.isBottom) {
return;
}
// combine types
+ returnType = _combine(returnType, type);
+ }
+
+ DartType _combine(DartType? returnType, DartType type) {
if (returnType == null) {
- returnType = type;
+ return type;
} else {
if (returnType is InterfaceType && type is InterfaceType) {
- returnType = InterfaceType.getSmartLeastUpperBound(returnType, type);
+ return InterfaceType.getSmartLeastUpperBound(returnType, type);
} else {
- returnType = typeSystem.leastUpperBound(returnType, type);
+ return typeSystem.leastUpperBound(returnType, type);
}
}
}
@@ -1328,7 +1340,7 @@
/// pattern to the original variable names.
class _SourcePattern {
final List<DartType> parameterTypes = <DartType>[];
- String normalizedSource;
+ late String normalizedSource;
final Map<String, String> originalToPatternNames = {};
bool isCompatible(_SourcePattern other) {
diff --git a/pkg/analysis_server/lib/src/services/refactoring/extract_widget.dart b/pkg/analysis_server/lib/src/services/refactoring/extract_widget.dart
index f7f67c7..36304e9 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_widget.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_widget.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:analysis_server/src/protocol_server.dart' hide Element;
import 'package:analysis_server/src/services/correction/status.dart';
import 'package:analysis_server/src/services/correction/util.dart';
@@ -38,37 +36,37 @@
final int offset;
final int length;
- CorrectionUtils utils;
+ late CorrectionUtils utils;
- ClassElement classBuildContext;
- ClassElement classKey;
- ClassElement classStatelessWidget;
- ClassElement classWidget;
- PropertyAccessorElement accessorRequired;
+ ClassElement? classBuildContext;
+ ClassElement? classKey;
+ ClassElement? classStatelessWidget;
+ ClassElement? classWidget;
+ PropertyAccessorElement? accessorRequired;
@override
- String name;
+ late String name;
/// If [offset] is in a class, the node of this class, `null` otherwise.
- ClassDeclaration _enclosingClassNode;
+ ClassDeclaration? _enclosingClassNode;
/// If [offset] is in a class, the element of this class, `null` otherwise.
- ClassElement _enclosingClassElement;
+ ClassElement? _enclosingClassElement;
/// The [CompilationUnitMember] that encloses the [offset].
- CompilationUnitMember _enclosingUnitMember;
+ CompilationUnitMember? _enclosingUnitMember;
/// The widget creation expression to extract.
- InstanceCreationExpression _expression;
+ InstanceCreationExpression? _expression;
/// The statements covered by [offset] and [length] to extract.
- List<Statement> _statements;
+ List<Statement>? _statements;
/// The [SourceRange] that covers [_statements].
- SourceRange _statementsRange;
+ SourceRange? _statementsRange;
/// The method returning widget to extract.
- MethodDeclaration _method;
+ MethodDeclaration? _method;
/// The parameters for the new widget class - referenced fields of the
/// [_enclosingClassElement], local variables referenced by [_expression],
@@ -87,7 +85,7 @@
}
FeatureSet get _featureSet {
- return resolveResult.unit.featureSet;
+ return resolveResult.unit!.featureSet;
}
Flutter get _flutter => Flutter.instance;
@@ -110,7 +108,7 @@
return result;
}
- var astNode = _expression ?? _method ?? _statements.first;
+ var astNode = _expression ?? _method ?? _statements!.first;
_enclosingUnitMember = astNode.thisOrAncestorMatching((n) {
return n is CompilationUnitMember && n.parent is CompilationUnit;
});
@@ -146,13 +144,15 @@
Future<SourceChange> createChange() async {
var builder =
ChangeBuilder(session: sessionHelper.session, eol: utils.endOfLine);
- await builder.addDartFileEdit(resolveResult.path, (builder) {
- if (_expression != null) {
- builder.addReplacement(range.node(_expression), (builder) {
+ await builder.addDartFileEdit(resolveResult.path!, (builder) {
+ final expression = _expression;
+ final statements = _statements;
+ if (expression != null) {
+ builder.addReplacement(range.node(expression), (builder) {
_writeWidgetInstantiation(builder);
});
- } else if (_statements != null) {
- builder.addReplacement(_statementsRange, (builder) {
+ } else if (statements != null) {
+ builder.addReplacement(_statementsRange!, (builder) {
builder.write('return ');
_writeWidgetInstantiation(builder);
builder.write(';');
@@ -179,7 +179,7 @@
// Treat single ReturnStatement as its expression.
if (node is ReturnStatement) {
- node = (node as ReturnStatement).expression;
+ node = node.expression;
}
// Find the enclosing class.
@@ -224,7 +224,7 @@
}
if (node is MethodDeclaration) {
var returnType = node.returnType?.type;
- if (_flutter.isWidgetType(returnType) && node.body != null) {
+ if (_flutter.isWidgetType(returnType)) {
_method = node;
return RefactoringStatus();
}
@@ -240,7 +240,7 @@
Future<RefactoringStatus> _initializeClasses() async {
var result = RefactoringStatus();
- Future<ClassElement> getClass(String name) async {
+ Future<ClassElement?> getClass(String name) async {
var element = await sessionHelper.getClass(_flutter.widgetsUri, name);
if (element == null) {
result.addFatalError(
@@ -250,7 +250,8 @@
return element;
}
- Future<PropertyAccessorElement> getAccessor(String uri, String name) async {
+ Future<PropertyAccessorElement?> getAccessor(
+ String uri, String name) async {
var element = await sessionHelper.getTopLevelPropertyAccessor(uri, name);
if (element == null) {
result.addFatalError("Unable to find 'required' in $uri");
@@ -271,40 +272,48 @@
/// Prepare referenced local variables and fields, that should be turned
/// into the widget class fields and constructor parameters.
Future<RefactoringStatus> _initializeParameters() async {
- _ParametersCollector collector;
- if (_expression != null) {
- var localRange = range.node(_expression);
+ _ParametersCollector? collector;
+
+ final expression = _expression;
+ if (expression != null) {
+ var localRange = range.node(expression);
collector = _ParametersCollector(_enclosingClassElement, localRange);
- _expression.accept(collector);
+ expression.accept(collector);
}
- if (_statements != null) {
+
+ final statements = _statements;
+ if (statements != null) {
collector =
- _ParametersCollector(_enclosingClassElement, _statementsRange);
- for (var statement in _statements) {
+ _ParametersCollector(_enclosingClassElement, _statementsRange!);
+ for (var statement in statements) {
statement.accept(collector);
}
}
- if (_method != null) {
- var localRange = range.node(_method);
+
+ final method = _method;
+ if (method != null) {
+ var localRange = range.node(method);
collector = _ParametersCollector(_enclosingClassElement, localRange);
- _method.body.accept(collector);
+ method.body.accept(collector);
}
_parameters
..clear()
- ..addAll(collector.parameters);
+ ..addAll(collector!.parameters);
// We added fields, now add the method parameters.
- if (_method != null) {
- for (var parameter in _method.parameters.parameters) {
- if (parameter is DefaultFormalParameter) {
- DefaultFormalParameter defaultFormalParameter = parameter;
- parameter = defaultFormalParameter.parameter;
- }
- if (parameter is NormalFormalParameter) {
- _parameters.add(_Parameter(
- parameter.identifier.name, parameter.declaredElement.type,
- isMethodParameter: true));
+ if (method != null) {
+ var parameterList = method.parameters;
+ if (parameterList != null) {
+ for (var parameter in parameterList.parameters) {
+ if (parameter is DefaultFormalParameter) {
+ parameter = parameter.parameter;
+ }
+ if (parameter is NormalFormalParameter) {
+ _parameters.add(_Parameter(
+ parameter.identifier!.name, parameter.declaredElement!.type,
+ isMethodParameter: true));
+ }
}
}
}
@@ -349,7 +358,7 @@
/// Remove the [_method] declaration.
void _removeMethodDeclaration(DartFileEditBuilder builder) {
- var methodRange = range.node(_method);
+ var methodRange = range.node(_method!);
var linesRange =
utils.getLinesRange(methodRange, skipLeadingEmptyLines: true);
builder.addDeletion(linesRange);
@@ -363,8 +372,8 @@
/// Replace invocations of the [_method] with instantiations of the new
/// widget class.
void _replaceInvocationsWithInstantiations(DartFileEditBuilder builder) {
- var collector = _MethodInvocationsCollector(_method.declaredElement);
- _enclosingClassNode.accept(collector);
+ var collector = _MethodInvocationsCollector(_method!.declaredElement!);
+ _enclosingClassNode!.accept(collector);
for (var invocation in collector.invocations) {
List<Expression> arguments = invocation.argumentList.arguments;
builder.addReplacement(range.node(invocation), (builder) {
@@ -382,7 +391,7 @@
if (parameter.isMethodParameter) {
var argument = arguments[argumentIndex++];
if (argument is NamedExpression) {
- argument = (argument as NamedExpression).expression;
+ argument = argument.expression;
}
builder.write(utils.getNodeText(argument));
} else {
@@ -396,12 +405,12 @@
/// Write declaration of the new widget class.
void _writeWidgetDeclaration(DartFileEditBuilder builder) {
- builder.addInsertion(_enclosingUnitMember.end, (builder) {
+ builder.addInsertion(_enclosingUnitMember!.end, (builder) {
builder.writeln();
builder.writeln();
builder.writeClassDeclaration(
name,
- superclass: classStatelessWidget.instantiate(
+ superclass: classStatelessWidget!.instantiate(
typeArguments: const [],
nullabilitySuffix: NullabilitySuffix.none,
),
@@ -418,7 +427,7 @@
builder.write(' ');
builder.writeParameter(
'key',
- type: classKey.instantiate(
+ type: classKey!.instantiate(
typeArguments: const [],
nullabilitySuffix: _isNonNullable
? NullabilitySuffix.question
@@ -434,7 +443,7 @@
builder.write('required');
} else {
builder.write('@');
- builder.writeReference(accessorRequired);
+ builder.writeReference(accessorRequired!);
}
builder.write(' ');
if (parameter.constructorName != parameter.name) {
@@ -481,25 +490,26 @@
builder.write(' ');
builder.writeFunctionDeclaration(
'build',
- returnType: classWidget.instantiate(
+ returnType: classWidget!.instantiate(
typeArguments: const [],
nullabilitySuffix: NullabilitySuffix.none,
),
parameterWriter: () {
builder.writeParameter(
'context',
- type: classBuildContext.instantiate(
+ type: classBuildContext!.instantiate(
typeArguments: const [],
nullabilitySuffix: NullabilitySuffix.none,
),
);
},
bodyWriter: () {
- if (_expression != null) {
- var indentOld = utils.getLinePrefix(_expression.offset);
+ final expression = _expression;
+ if (expression != null) {
+ var indentOld = utils.getLinePrefix(expression.offset);
var indentNew = ' ';
- var code = utils.getNodeText(_expression);
+ var code = utils.getNodeText(expression);
code = _replaceIndent(code, indentOld, indentNew);
builder.writeln('{');
@@ -510,10 +520,10 @@
builder.writeln(' }');
} else if (_statements != null) {
- var indentOld = utils.getLinePrefix(_statementsRange.offset);
+ var indentOld = utils.getLinePrefix(_statementsRange!.offset);
var indentNew = ' ';
- var code = utils.getRangeText(_statementsRange);
+ var code = utils.getRangeText(_statementsRange!);
code = _replaceIndent(code, indentOld, indentNew);
builder.writeln('{');
@@ -524,7 +534,7 @@
builder.writeln(' }');
} else {
- var code = utils.getNodeText(_method.body);
+ var code = utils.getNodeText(_method!.body);
builder.writeln(code);
}
},
@@ -552,14 +562,14 @@
}
class _MethodInvocationsCollector extends RecursiveAstVisitor<void> {
- final MethodElement methodElement;
+ final ExecutableElement methodElement;
final List<MethodInvocation> invocations = [];
_MethodInvocationsCollector(this.methodElement);
@override
void visitMethodInvocation(MethodInvocation node) {
- if (node.methodName?.staticElement == methodElement) {
+ if (node.methodName.staticElement == methodElement) {
invocations.add(node);
} else {
super.visitMethodInvocation(node);
@@ -579,20 +589,20 @@
/// If the [name] is private, the public name to use in the new widget
/// constructor. If the [name] is already public, then the [name].
- String constructorName;
+ late String constructorName;
_Parameter(this.name, this.type, {this.isMethodParameter = false});
}
class _ParametersCollector extends RecursiveAstVisitor<void> {
- final ClassElement enclosingClass;
+ final ClassElement? enclosingClass;
final SourceRange expressionRange;
final RefactoringStatus status = RefactoringStatus();
final Set<Element> uniqueElements = <Element>{};
final List<_Parameter> parameters = [];
- List<ClassElement> enclosingClasses;
+ List<ClassElement>? enclosingClasses;
_ParametersCollector(this.enclosingClass, this.expressionRange);
@@ -604,7 +614,7 @@
}
var elementName = element.displayName;
- DartType type;
+ DartType? type;
if (element is MethodElement) {
if (_isMemberOfEnclosingClass(element)) {
status.addError(
@@ -638,8 +648,9 @@
/// Return `true` if the given [element] is a member of the [enclosingClass]
/// or one of its supertypes, interfaces, or mixins.
bool _isMemberOfEnclosingClass(Element element) {
+ final enclosingClass = this.enclosingClass;
if (enclosingClass != null) {
- enclosingClasses ??= <ClassElement>[]
+ final enclosingClasses = this.enclosingClasses ??= <ClassElement>[]
..add(enclosingClass)
..addAll(enclosingClass.allSupertypes.map((t) => t.element));
return enclosingClasses.contains(element.enclosingElement);
diff --git a/pkg/analysis_server/lib/src/services/refactoring/inline_local.dart b/pkg/analysis_server/lib/src/services/refactoring/inline_local.dart
index bbfccb9..12afe4d 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/inline_local.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/inline_local.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:analysis_server/src/protocol_server.dart' hide Element;
import 'package:analysis_server/src/services/correction/status.dart';
import 'package:analysis_server/src/services/correction/util.dart';
@@ -25,34 +23,24 @@
final SearchEngine searchEngine;
final ResolvedUnitResult resolveResult;
final int offset;
- CorrectionUtils utils;
+ final CorrectionUtils utils;
- Element _variableElement;
- VariableDeclaration _variableNode;
- List<SearchMatch> _references;
+ _InitialState? _initialState;
- InlineLocalRefactoringImpl(
- this.searchEngine, this.resolveResult, this.offset) {
- utils = CorrectionUtils(resolveResult);
- }
+ InlineLocalRefactoringImpl(this.searchEngine, this.resolveResult, this.offset)
+ : utils = CorrectionUtils(resolveResult);
@override
String get refactoringName => 'Inline Local Variable';
@override
int get referenceCount {
- if (_references == null) {
- return 0;
- }
- return _references.length;
+ return _initialState?.references.length ?? 0;
}
@override
- String get variableName {
- if (_variableElement == null) {
- return null;
- }
- return _variableElement.name;
+ String? get variableName {
+ return _initialState?.element.name;
}
@override
@@ -63,78 +51,93 @@
@override
Future<RefactoringStatus> checkInitialConditions() async {
- var result = RefactoringStatus();
// prepare variable
- {
- var offsetNode = NodeLocator(offset).searchWithin(resolveResult.unit);
- if (offsetNode is SimpleIdentifier) {
- var element = offsetNode.staticElement;
- if (element is LocalVariableElement) {
- _variableElement = element;
- var declarationResult =
- await AnalysisSessionHelper(resolveResult.session)
- .getElementDeclaration(element);
- _variableNode = declarationResult.node;
- }
- }
+ var offsetNode = NodeLocator(offset).searchWithin(resolveResult.unit);
+ if (offsetNode is! SimpleIdentifier) {
+ return _noLocalVariableStatus();
+ }
+
+ var element = offsetNode.staticElement;
+ if (element is! LocalVariableElement) {
+ return _noLocalVariableStatus();
+ }
+
+ var helper = AnalysisSessionHelper(resolveResult.session);
+ var declarationResult = await helper.getElementDeclaration(element);
+ var node = declarationResult?.node;
+ if (node is! VariableDeclaration) {
+ return _noLocalVariableStatus();
}
// validate node declaration
- if (!_isVariableDeclaredInStatement()) {
- result = RefactoringStatus.fatal(
- 'Local variable declaration or reference must be selected '
- 'to activate this refactoring.');
- return Future<RefactoringStatus>.value(result);
+ var declarationStatement = _declarationStatement(node);
+ if (declarationStatement == null) {
+ return _noLocalVariableStatus();
}
// should have initializer at declaration
- if (_variableNode.initializer == null) {
+ var initializer = node.initializer;
+ if (initializer == null) {
var message = format(
- "Local variable '{0}' is not initialized at declaration.",
- _variableElement.displayName);
- result =
- RefactoringStatus.fatal(message, newLocation_fromNode(_variableNode));
- return Future<RefactoringStatus>.value(result);
+ "Local variable '{0}' is not initialized at declaration.",
+ element.displayName,
+ );
+ return RefactoringStatus.fatal(
+ message,
+ newLocation_fromNode(node),
+ );
}
// prepare references
- _references = await searchEngine.searchReferences(_variableElement);
+ var references = await searchEngine.searchReferences(element);
// should not have assignments
- for (var reference in _references) {
+ for (var reference in references) {
if (reference.kind != MatchKind.READ) {
- var message = format("Local variable '{0}' is assigned more than once.",
- [_variableElement.displayName]);
+ var message = format(
+ "Local variable '{0}' is assigned more than once.",
+ [element.displayName],
+ );
return RefactoringStatus.fatal(
- message, newLocation_fromMatch(reference));
+ message,
+ newLocation_fromMatch(reference),
+ );
}
}
// done
- return result;
+ _initialState = _InitialState(
+ element: element,
+ node: node,
+ initializer: initializer,
+ declarationStatement: declarationStatement,
+ references: references,
+ );
+ return RefactoringStatus();
}
@override
Future<SourceChange> createChange() {
var change = SourceChange(refactoringName);
+ var unitElement = resolveResult.unit!.declaredElement!;
+ var state = _initialState!;
// remove declaration
{
- Statement declarationStatement =
- _variableNode.thisOrAncestorOfType<VariableDeclarationStatement>();
- var range = utils.getLinesRangeStatements([declarationStatement]);
- doSourceChange_addElementEdit(change, resolveResult.unit.declaredElement,
- newSourceEdit_range(range, ''));
+ var range = utils.getLinesRangeStatements([(state.declarationStatement)]);
+ doSourceChange_addElementEdit(
+ change, unitElement, newSourceEdit_range(range, ''));
}
// prepare initializer
- var initializer = _variableNode.initializer;
+ var initializer = state.initializer;
var initializerCode = utils.getNodeText(initializer);
// replace references
- for (var reference in _references) {
+ for (var reference in state.references) {
var editRange = reference.sourceRange;
// prepare context
var offset = editRange.offset;
- var node = utils.findNode(offset);
+ var node = utils.findNode(offset)!;
var parent = node.parent;
// prepare code
String codeForReference;
if (parent is InterpolationExpression) {
- StringInterpolation target = parent.parent;
- if (initializer is SingleStringLiteral &&
+ var target = parent.parent;
+ if (target is StringInterpolation &&
+ initializer is SingleStringLiteral &&
!initializer.isRaw &&
initializer.isSingleQuoted == target.isSingleQuoted &&
(!initializer.isMultiline || target.isMultiline)) {
@@ -154,26 +157,34 @@
codeForReference = initializerCode;
}
// do replace
- doSourceChange_addElementEdit(change, resolveResult.unit.declaredElement,
+ doSourceChange_addElementEdit(change, unitElement,
newSourceEdit_range(editRange, codeForReference));
}
// done
return Future.value(change);
}
- bool _isVariableDeclaredInStatement() {
- if (_variableNode == null) {
- return false;
- }
- var parent = _variableNode.parent;
- if (parent is VariableDeclarationList) {
- parent = parent.parent;
- if (parent is VariableDeclarationStatement) {
- parent = parent.parent;
- return parent is Block || parent is SwitchCase;
+ RefactoringStatus _noLocalVariableStatus() {
+ return RefactoringStatus.fatal(
+ 'Local variable declaration or reference must be selected '
+ 'to activate this refactoring.',
+ );
+ }
+
+ static VariableDeclarationStatement? _declarationStatement(
+ VariableDeclaration declaration,
+ ) {
+ var declarationList = declaration.parent;
+ if (declarationList is VariableDeclarationList) {
+ var statement = declarationList.parent;
+ if (statement is VariableDeclarationStatement) {
+ var parent = statement.parent;
+ if (parent is Block || parent is SwitchCase) {
+ return statement;
+ }
}
}
- return false;
+ return null;
}
static bool _shouldBeExpressionInterpolation(
@@ -204,3 +215,19 @@
return false;
}
}
+
+class _InitialState {
+ final LocalVariableElement element;
+ final VariableDeclaration node;
+ final Expression initializer;
+ final VariableDeclarationStatement declarationStatement;
+ final List<SearchMatch> references;
+
+ _InitialState({
+ required this.element,
+ required this.node,
+ required this.initializer,
+ required this.declarationStatement,
+ required this.references,
+ });
+}
diff --git a/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart b/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart
index 0b6f4a2..47362ca 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:analysis_server/src/protocol_server.dart' hide Element;
import 'package:analysis_server/src/services/correction/status.dart';
import 'package:analysis_server/src/services/correction/util.dart';
@@ -47,14 +45,14 @@
_SourcePart part,
CorrectionUtils utils,
AstNode contextNode,
- Expression targetExpression,
+ Expression? targetExpression,
List<Expression> arguments) {
// prepare edits to replace parameters with arguments
var edits = <SourceEdit>[];
part._parameters.forEach(
(ParameterElement parameter, List<_ParameterOccurrence> occurrences) {
// prepare argument
- Expression argument;
+ Expression? argument;
for (var arg in arguments) {
if (arg.staticParameterElement == parameter) {
argument = arg;
@@ -62,11 +60,11 @@
}
}
if (argument is NamedExpression) {
- argument = (argument as NamedExpression).expression;
+ argument = argument.expression;
}
// prepare argument properties
Precedence argumentPrecedence;
- String argumentSource;
+ String? argumentSource;
if (argument != null) {
argumentPrecedence = getExpressionPrecedence(argument);
argumentSource = utils.getNodeText(argument);
@@ -149,7 +147,7 @@
// local variables and functions
{
var localsRange = _getLocalsConflictingRange(node);
- var enclosingExecutable = getEnclosingExecutableNode(node);
+ var enclosingExecutable = getEnclosingExecutableNode(node)!;
var visibleRangeMap = VisibleRangesComputer.forNode(enclosingExecutable);
visibleRangeMap.forEach((element, elementRange) {
if (elementRange.intersects(localsRange)) {
@@ -183,23 +181,23 @@
final ResolvedUnitResult resolveResult;
final int offset;
final AnalysisSessionHelper sessionHelper;
- CorrectionUtils utils;
- SourceChange change;
+ late CorrectionUtils utils;
+ late SourceChange change;
@override
bool isDeclaration = false;
bool deleteSource = false;
bool inlineAll = true;
- ExecutableElement _methodElement;
- CompilationUnit _methodUnit;
- CorrectionUtils _methodUtils;
- AstNode _methodNode;
- FormalParameterList _methodParameters;
- FunctionBody _methodBody;
- Expression _methodExpression;
- _SourcePart _methodExpressionPart;
- _SourcePart _methodStatementsPart;
+ ExecutableElement? _methodElement;
+ late CompilationUnit _methodUnit;
+ late CorrectionUtils _methodUtils;
+ late AstNode _methodNode;
+ FormalParameterList? _methodParameters;
+ FunctionBody? _methodBody;
+ Expression? _methodExpression;
+ _SourcePart? _methodExpressionPart;
+ _SourcePart? _methodStatementsPart;
final List<_ReferenceProcessor> _referenceProcessors = [];
final Set<Element> _alreadyMadeAsync = <Element>{};
@@ -210,11 +208,8 @@
}
@override
- String get className {
- if (_methodElement == null) {
- return null;
- }
- var classElement = _methodElement.enclosingElement;
+ String? get className {
+ var classElement = _methodElement?.enclosingElement;
if (classElement is ClassElement) {
return classElement.displayName;
}
@@ -222,11 +217,8 @@
}
@override
- String get methodName {
- if (_methodElement == null) {
- return null;
- }
- return _methodElement.displayName;
+ String? get methodName {
+ return _methodElement?.displayName;
}
@override
@@ -256,7 +248,7 @@
var linesRange =
_methodUtils.getLinesRange(methodRange, skipLeadingEmptyLines: true);
doSourceChange_addElementEdit(
- change, _methodElement, newSourceEdit_range(linesRange, ''));
+ change, _methodElement!, newSourceEdit_range(linesRange, ''));
}
// done
return Future.value(result);
@@ -271,19 +263,19 @@
return Future<RefactoringStatus>.value(result);
}
// maybe operator
- if (_methodElement.isOperator) {
+ if (_methodElement!.isOperator) {
result = RefactoringStatus.fatal('Cannot inline operator.');
return Future<RefactoringStatus>.value(result);
}
// maybe [a]sync*
- if (_methodElement.isGenerator) {
+ if (_methodElement!.isGenerator) {
result = RefactoringStatus.fatal('Cannot inline a generator.');
return Future<RefactoringStatus>.value(result);
}
// analyze method body
result.addStatus(_prepareMethodParts());
// process references
- var references = await searchEngine.searchReferences(_methodElement);
+ var references = await searchEngine.searchReferences(_methodElement!);
_referenceProcessors.clear();
for (var reference in references) {
var processor = _ReferenceProcessor(this, reference);
@@ -303,7 +295,7 @@
var prefix = getLinePrefix(source);
var result = _SourcePart(range.offset, source, prefix);
// remember parameters and variables occurrences
- _methodUnit.accept(_VariablesVisitor(_methodElement, range, result));
+ _methodUnit.accept(_VariablesVisitor(_methodElement!, range, result));
// done
return result;
}
@@ -319,11 +311,10 @@
var fatalStatus = RefactoringStatus.fatal(
'Method declaration or reference must be selected to activate this refactoring.');
// prepare selected SimpleIdentifier
- var node = NodeLocator(offset).searchWithin(resolveResult.unit);
- if (node is! SimpleIdentifier) {
+ var identifier = NodeLocator(offset).searchWithin(resolveResult.unit);
+ if (identifier is! SimpleIdentifier) {
return fatalStatus;
}
- var identifier = node as SimpleIdentifier;
// prepare selected ExecutableElement
var element = identifier.writeOrReadElement;
if (element is! ExecutableElement) {
@@ -332,14 +323,14 @@
if (element.isSynthetic) {
return fatalStatus;
}
- _methodElement = element as ExecutableElement;
+ _methodElement = element;
- var declaration = await sessionHelper.getElementDeclaration(_methodElement);
- var methodNode = declaration.node;
+ var declaration = await sessionHelper.getElementDeclaration(element);
+ var methodNode = declaration!.node;
_methodNode = methodNode;
- var resolvedUnit = declaration.resolvedUnit;
- _methodUnit = resolvedUnit.unit;
+ var resolvedUnit = declaration.resolvedUnit!;
+ _methodUnit = resolvedUnit.unit!;
_methodUtils = CorrectionUtils(resolvedUnit);
if (methodNode is MethodDeclaration) {
@@ -353,7 +344,7 @@
}
isDeclaration = resolveResult.uri == element.source.uri &&
- node.offset == element.nameOffset;
+ identifier.offset == element.nameOffset;
deleteSource = isDeclaration;
inlineAll = deleteSource;
return RefactoringStatus();
@@ -366,7 +357,7 @@
if (_methodBody is ExpressionFunctionBody) {
var body = _methodBody as ExpressionFunctionBody;
_methodExpression = body.expression;
- var methodExpressionRange = range.node(_methodExpression);
+ var methodExpressionRange = range.node(_methodExpression!);
_methodExpressionPart = _createSourcePart(methodExpressionRange);
} else if (_methodBody is BlockFunctionBody) {
var body = (_methodBody as BlockFunctionBody).block;
@@ -377,7 +368,7 @@
if (lastStatement is ReturnStatement) {
_methodExpression = lastStatement.expression;
if (_methodExpression != null) {
- var methodExpressionRange = range.node(_methodExpression);
+ var methodExpressionRange = range.node(_methodExpression!);
_methodExpressionPart = _createSourcePart(methodExpressionRange);
}
// exclude "return" statement from statements
@@ -411,11 +402,11 @@
final InlineMethodRefactoringImpl ref;
final SearchMatch reference;
- Element refElement;
- CorrectionUtils _refUtils;
- SimpleIdentifier _node;
- SourceRange _refLineRange;
- String _refPrefix;
+ late Element refElement;
+ late CorrectionUtils _refUtils;
+ late SimpleIdentifier _node;
+ SourceRange? _refLineRange;
+ late String _refPrefix;
_ReferenceProcessor(this.ref, this.reference);
@@ -424,10 +415,11 @@
// prepare CorrectionUtils
var result = await ref.sessionHelper.getResolvedUnitByElement(refElement);
- _refUtils = CorrectionUtils(result);
+ _refUtils = CorrectionUtils(result!);
// prepare node and environment
- _node = _refUtils.findNode(reference.sourceRange.offset);
+ _node =
+ _refUtils.findNode(reference.sourceRange.offset) as SimpleIdentifier;
var refStatement = _node.thisOrAncestorOfType<Statement>();
if (refStatement != null) {
_refLineRange = _refUtils.getLinesRangeStatements([refStatement]);
@@ -454,7 +446,7 @@
}
// analyze point of invocation
var parent = usage.parent;
- var parent2 = parent.parent;
+ var parent2 = parent?.parent;
// OK, if statement in block
if (parent is Statement) {
return parent2 is Block;
@@ -484,7 +476,7 @@
}
void _inlineMethodInvocation(RefactoringStatus status, Expression usage,
- bool cascaded, Expression target, List<Expression> arguments) {
+ bool cascaded, Expression? target, List<Expression> arguments) {
// we don't support cascade
if (cascaded) {
status.addError(
@@ -496,20 +488,20 @@
if (ref._methodStatementsPart != null) {
// prepare statements source for invocation
var source = _getMethodSourceForInvocation(status,
- ref._methodStatementsPart, _refUtils, usage, target, arguments);
+ ref._methodStatementsPart!, _refUtils, usage, target, arguments);
source = _refUtils.replaceSourceIndent(
- source, ref._methodStatementsPart._prefix, _refPrefix);
+ source, ref._methodStatementsPart!._prefix, _refPrefix);
// do insert
var edit =
- newSourceEdit_range(SourceRange(_refLineRange.offset, 0), source);
+ newSourceEdit_range(SourceRange(_refLineRange!.offset, 0), source);
_addRefEdit(edit);
}
// replace invocation with return expression
if (ref._methodExpressionPart != null) {
// prepare expression source for invocation
var source = _getMethodSourceForInvocation(status,
- ref._methodExpressionPart, _refUtils, usage, target, arguments);
- if (getExpressionPrecedence(ref._methodExpression) <
+ ref._methodExpressionPart!, _refUtils, usage, target, arguments);
+ if (getExpressionPrecedence(ref._methodExpression!) <
getExpressionParentPrecedence(usage)) {
source = '($source)';
}
@@ -518,7 +510,7 @@
var edit = newSourceEdit_range(methodUsageRange, source);
_addRefEdit(edit);
} else {
- var edit = newSourceEdit_range(_refLineRange, '');
+ var edit = newSourceEdit_range(_refLineRange!, '');
_addRefEdit(edit);
}
return;
@@ -527,7 +519,7 @@
String source;
{
source = ref._methodUtils.getRangeText(range.startEnd(
- ref._methodParameters.leftParenthesis, ref._methodNode));
+ ref._methodParameters!.leftParenthesis, ref._methodNode));
var methodPrefix = ref._methodUtils.getLinePrefix(ref._methodNode.offset);
source = _refUtils.replaceSourceIndent(source, methodPrefix, _refPrefix);
source = source.trim();
@@ -545,7 +537,7 @@
}
// If the element being inlined is async, ensure that the function
// body that encloses the method is also async.
- if (ref._methodElement.isAsynchronous) {
+ if (ref._methodElement!.isAsynchronous) {
var body = _node.thisOrAncestorOfType<FunctionBody>();
if (body != null) {
if (body.isSynchronous) {
@@ -587,7 +579,7 @@
// PropertyAccessorElement
if (ref._methodElement is PropertyAccessorElement) {
Expression usage = _node;
- Expression target;
+ Expression? target;
var cascade = false;
if (nodeParent is PrefixedIdentifier) {
var propertyAccess = nodeParent;
@@ -604,7 +596,7 @@
// prepare arguments
var arguments = <Expression>[];
if (_node.inSetterContext()) {
- var assignment = _node.thisOrAncestorOfType<AssignmentExpression>();
+ var assignment = _node.thisOrAncestorOfType<AssignmentExpression>()!;
arguments.add(assignment.rightHandSide);
}
// inline body
@@ -615,13 +607,13 @@
String source;
{
source = ref._methodUtils.getRangeText(range.startEnd(
- ref._methodParameters.leftParenthesis, ref._methodNode));
+ ref._methodParameters!.leftParenthesis, ref._methodNode));
var methodPrefix =
ref._methodUtils.getLinePrefix(ref._methodNode.offset);
source =
_refUtils.replaceSourceIndent(source, methodPrefix, _refPrefix);
source = source.trim();
- source = removeEnd(source, ';');
+ source = removeEnd(source, ';')!;
}
// do insert
var edit = newSourceEdit_range(range.node(_node), source);
@@ -700,15 +692,13 @@
void addParameterOccurrence(ParameterElement parameter,
SourceRange identifierRange, Precedence precedence) {
- if (parameter != null) {
- var occurrences = _parameters[parameter];
- if (occurrences == null) {
- occurrences = [];
- _parameters[parameter] = occurrences;
- }
- identifierRange = range.offsetBy(identifierRange, -_base);
- occurrences.add(_ParameterOccurrence(precedence, identifierRange));
+ var occurrences = _parameters[parameter];
+ if (occurrences == null) {
+ occurrences = [];
+ _parameters[parameter] = occurrences;
}
+ identifierRange = range.offsetBy(identifierRange, -_base);
+ occurrences.add(_ParameterOccurrence(precedence, identifierRange));
}
void addVariable(VariableElement element, SourceRange identifierRange) {
@@ -733,8 +723,6 @@
/// The [_SourcePart] to record reference into.
final _SourcePart result;
- int offset;
-
_VariablesVisitor(this.methodElement, this.bodyRange, this.result);
@override
@@ -766,23 +754,28 @@
void _addMemberQualifier(SimpleIdentifier node) {
// should be unqualified
- AstNode qualifier = getNodeQualifier(node);
+ var qualifier = getNodeQualifier(node);
if (qualifier != null) {
return;
}
// should be a method or field reference
var element = node.writeOrReadElement;
- if (!(element is MethodElement || element is PropertyAccessorElement)) {
+ if (element is ExecutableElement) {
+ if (element is MethodElement || element is PropertyAccessorElement) {
+ // OK
+ } else {
+ return;
+ }
+ } else {
return;
}
if (element.enclosingElement is! ClassElement) {
return;
}
// record the implicit static or instance reference
- ExecutableElement member = element;
var offset = node.offset;
- if (member.isStatic) {
- var className = member.enclosingElement.displayName;
+ if (element.isStatic) {
+ var className = element.enclosingElement.displayName;
result.addImplicitClassNameOffset(className, offset);
} else {
result.addImplicitThisOffset(offset);
@@ -807,7 +800,7 @@
}
void _addVariable(SimpleIdentifier node) {
- VariableElement variableElement = getLocalVariableElement(node);
+ var variableElement = getLocalVariableElement(node);
if (variableElement != null) {
var nodeRange = range.node(node);
result.addVariable(variableElement, nodeRange);
diff --git a/pkg/analysis_server/lib/src/services/refactoring/move_file.dart b/pkg/analysis_server/lib/src/services/refactoring/move_file.dart
index 93a7520..397af5c 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/move_file.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/move_file.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'dart:core';
import 'package:analysis_server/src/protocol_server.dart' hide Element;
@@ -17,6 +15,7 @@
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
import 'package:analyzer_plugin/utilities/range_factory.dart';
+import 'package:collection/collection.dart';
import 'package:path/path.dart' as pathos;
/// [MoveFileRefactoring] implementation.
@@ -26,10 +25,10 @@
final pathos.Context pathContext;
final RefactoringWorkspace refactoringWorkspace;
final ResolvedUnitResult resolvedUnit;
- AnalysisDriver driver;
+ late AnalysisDriver driver;
- String oldFile;
- String newFile;
+ late String oldFile;
+ late String newFile;
final packagePrefixedStringPattern = RegExp(r'''^r?['"]+package:''');
@@ -43,7 +42,7 @@
@override
Future<RefactoringStatus> checkFinalConditions() async {
for (var driver in refactoringWorkspace.drivers) {
- var rootPath = driver.analysisContext.contextRoot.root.path;
+ var rootPath = driver.analysisContext!.contextRoot.root.path;
if (pathContext.equals(rootPath, oldFile)) {
return RefactoringStatus.fatal(
'Renaming an analysis root is not supported ($oldFile)');
@@ -72,13 +71,12 @@
@override
Future<SourceChange> createChange() async {
var changeBuilder = ChangeBuilder(session: resolvedUnit.session);
- var element = resolvedUnit.unit.declaredElement;
+ var element = resolvedUnit.unit!.declaredElement;
if (element == null) {
return changeBuilder.sourceChange;
}
var libraryElement = element.library;
- var libraryPath = libraryElement.source.fullName;
final oldDir = pathContext.dirname(oldFile);
final newDir = pathContext.dirname(newFile);
@@ -88,34 +86,33 @@
// Handle part-of directives in this library
var libraryResult = await driver.currentSession
.getResolvedLibraryByElement(libraryElement);
- ResolvedUnitResult definingUnitResult;
- for (var result in libraryResult.units) {
+ var definingUnitResult = libraryResult.units!.first;
+ for (var result in libraryResult.units!) {
if (result.isPart) {
- var partOfs = result.unit.directives
+ var partOfs = result.unit!.directives
.whereType<PartOfDirective>()
- .where(
- (po) => po.uri != null && _isRelativeUri(po.uri.stringValue));
+ .map((e) => e.uri)
+ .whereNotNull()
+ .where((uri) => _isRelativeUri(uri.stringValue));
if (partOfs.isNotEmpty) {
await changeBuilder.addDartFileEdit(
- result.unit.declaredElement.source.fullName, (builder) {
- partOfs.forEach((po) {
+ result.unit!.declaredElement!.source.fullName, (builder) {
+ partOfs.forEach((uri) {
var newLocation =
pathContext.join(newDir, pathos.basename(newFile));
var newUri = _getRelativeUri(newLocation, oldDir);
builder.addSimpleReplacement(
- SourceRange(po.uri.offset, po.uri.length), "'$newUri'");
+ SourceRange(uri.offset, uri.length), "'$newUri'");
});
});
}
}
- if (result.path == libraryPath) {
- definingUnitResult = result;
- }
}
if (newDir != oldDir) {
- await changeBuilder.addDartFileEdit(definingUnitResult.path, (builder) {
- for (var directive in definingUnitResult.unit.directives) {
+ await changeBuilder.addDartFileEdit(definingUnitResult.path!,
+ (builder) {
+ for (var directive in definingUnitResult.unit!.directives) {
if (directive is UriBasedDirective) {
_updateUriReference(builder, directive, oldDir, newDir);
}
@@ -124,17 +121,19 @@
}
} else if (newDir != oldDir) {
// Otherwise, we need to update any relative part-of references.
- var partOfs = resolvedUnit.unit.directives
+ var partOfs = resolvedUnit.unit!.directives
.whereType<PartOfDirective>()
- .where((po) => po.uri != null && _isRelativeUri(po.uri.stringValue));
+ .map((e) => e.uri)
+ .whereNotNull()
+ .where((uri) => _isRelativeUri(uri.stringValue));
if (partOfs.isNotEmpty) {
await changeBuilder.addDartFileEdit(element.source.fullName, (builder) {
- partOfs.forEach((po) {
- var oldLocation = pathContext.join(oldDir, po.uri.stringValue);
+ partOfs.forEach((uri) {
+ var oldLocation = pathContext.join(oldDir, uri.stringValue);
var newUri = _getRelativeUri(oldLocation, newDir);
builder.addSimpleReplacement(
- SourceRange(po.uri.offset, po.uri.length), "'$newUri'");
+ SourceRange(uri.offset, uri.length), "'$newUri'");
});
});
}
@@ -178,7 +177,7 @@
}
bool _isPackageReference(SourceReference reference) {
- var source = reference.element.source;
+ var source = reference.element.source!;
var quotedImportUri = source.contents.data.substring(reference.range.offset,
reference.range.offset + reference.range.length);
return packagePrefixedStringPattern.hasMatch(quotedImportUri);
@@ -189,7 +188,10 @@
/// The following URI's are not relative:
/// `/absolute/path/file.dart`
/// `dart:math`
- bool _isRelativeUri(String path) {
+ bool _isRelativeUri(String? path) {
+ if (path == null) {
+ return false;
+ }
// absolute URI
if (Uri.parse(path).isAbsolute) {
return false;
diff --git a/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart b/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart
index fbd4d3b..31e5302 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:analysis_server/src/services/correction/status.dart';
import 'package:analysis_server/src/services/refactoring/convert_getter_to_method.dart';
import 'package:analysis_server/src/services/refactoring/convert_method_to_getter.dart';
@@ -48,7 +46,7 @@
/// [element] and all the corresponding hierarchy elements.
factory ConvertMethodToGetterRefactoring(SearchEngine searchEngine,
AnalysisSession session, ExecutableElement element) {
- return ConvertMethodToGetterRefactoringImpl(searchEngine, element);
+ return ConvertMethodToGetterRefactoringImpl(searchEngine, session, element);
}
}
@@ -211,7 +209,7 @@
int get referenceCount;
/// Returns the name of the variable being inlined.
- String get variableName;
+ String? get variableName;
}
/// [Refactoring] to inline an [ExecutableElement].
@@ -224,7 +222,7 @@
/// The name of the class enclosing the method being inlined.
/// If not a class member is being inlined, then `null`.
- String get className;
+ String? get className;
/// True if the method being inlined should be removed.
/// It is an error if this field is `true` and [inlineAll] is `false`.
@@ -239,7 +237,7 @@
bool get isDeclaration;
/// The name of the method (or function) being inlined.
- String get methodName;
+ String? get methodName;
}
/// [Refactoring] to move/rename a file.
@@ -300,65 +298,26 @@
/// Whether the [element] is defined in a file that is in a context root.
bool containsElement(Element element) {
- return containsFile(element.source.fullName);
+ return containsFile(element.source!.fullName);
}
/// Whether the file with the given [path] is in a context root.
bool containsFile(String path) {
return drivers.any((driver) {
- return driver.analysisContext.contextRoot.isAnalyzed(path);
+ return driver.analysisContext!.contextRoot.isAnalyzed(path);
});
}
/// Returns the drivers that have [path] in a context root.
Iterable<AnalysisDriver> driversContaining(String path) {
return drivers.where((driver) {
- return driver.analysisContext.contextRoot.isAnalyzed(path);
+ return driver.analysisContext!.contextRoot.isAnalyzed(path);
});
}
}
/// Abstract [Refactoring] for renaming some [Element].
abstract class RenameRefactoring implements Refactoring {
- /// Returns a new [RenameRefactoring] instance for renaming [element],
- /// maybe `null` if there is no support for renaming [Element]s of the given
- /// type.
- factory RenameRefactoring(RefactoringWorkspace workspace,
- ResolvedUnitResult resolvedUnit, Element element) {
- var session = resolvedUnit.session;
- if (element == null) {
- return null;
- }
- if (element is PropertyAccessorElement) {
- element = (element as PropertyAccessorElement).variable;
- }
- if (element.enclosingElement is CompilationUnitElement) {
- return RenameUnitMemberRefactoringImpl(workspace, resolvedUnit, element);
- }
- if (element is ConstructorElement) {
- return RenameConstructorRefactoringImpl(workspace, session, element);
- }
- if (element is ImportElement) {
- return RenameImportRefactoringImpl(workspace, session, element);
- }
- if (element is LabelElement) {
- return RenameLabelRefactoringImpl(workspace, element);
- }
- if (element is LibraryElement) {
- return RenameLibraryRefactoringImpl(workspace, element);
- }
- if (element is LocalElement) {
- return RenameLocalRefactoringImpl(workspace, element);
- }
- if (element.enclosingElement is ClassElement) {
- return RenameClassMemberRefactoringImpl(workspace, session, element);
- }
- if (element.enclosingElement is ExtensionElement) {
- return RenameExtensionMemberRefactoringImpl(workspace, session, element);
- }
- return null;
- }
-
/// Returns the human-readable description of the kind of element being
/// renamed (such as “class” or “function type alias”).
String get elementKindName;
@@ -378,10 +337,52 @@
/// this level of checking.
RefactoringStatus checkNewName();
+ /// Returns a new [RenameRefactoring] instance for renaming [element],
+ /// maybe `null` if there is no support for renaming [Element]s of the given
+ /// type.
+ static RenameRefactoring? create(RefactoringWorkspace workspace,
+ ResolvedUnitResult resolvedUnit, Element? element) {
+ var session = resolvedUnit.session;
+ if (element == null) {
+ return null;
+ }
+ if (element is PropertyAccessorElement) {
+ element = element.variable;
+ }
+ var enclosingElement = element.enclosingElement;
+ if (enclosingElement is CompilationUnitElement) {
+ return RenameUnitMemberRefactoringImpl(workspace, resolvedUnit, element);
+ }
+ if (element is ConstructorElement) {
+ return RenameConstructorRefactoringImpl(workspace, session, element);
+ }
+ if (element is ImportElement) {
+ return RenameImportRefactoringImpl(workspace, session, element);
+ }
+ if (element is LabelElement) {
+ return RenameLabelRefactoringImpl(workspace, element);
+ }
+ if (element is LibraryElement) {
+ return RenameLibraryRefactoringImpl(workspace, element);
+ }
+ if (element is LocalElement) {
+ return RenameLocalRefactoringImpl(workspace, session, element);
+ }
+ if (enclosingElement is ClassElement) {
+ return RenameClassMemberRefactoringImpl(
+ workspace, session, enclosingElement, element);
+ }
+ if (enclosingElement is ExtensionElement) {
+ return RenameExtensionMemberRefactoringImpl(
+ workspace, session, enclosingElement, element);
+ }
+ return null;
+ }
+
/// Given a node/element, finds the best element to rename (for example
/// the class when on the `new` keyword).
- static RenameRefactoringElement getElementToRename(
- AstNode node, Element element) {
+ static RenameRefactoringElement? getElementToRename(
+ AstNode node, Element? element) {
var offset = node.offset;
var length = node.length;
@@ -390,14 +391,15 @@
}
if (element is FieldFormalParameterElement) {
- element = (element as FieldFormalParameterElement).field;
+ element = element.field;
}
// Use the prefix offset/length when renaming an import directive.
if (node is ImportDirective && element is ImportElement) {
- if (node.prefix != null) {
- offset = node.prefix.offset;
- length = node.prefix.length;
+ var prefix = node.prefix;
+ if (prefix != null) {
+ offset = prefix.offset;
+ length = prefix.length;
} else {
// -1 means the name does not exist yet.
offset = -1;
@@ -414,6 +416,10 @@
length = typeIdentifier.length;
}
+ if (element == null) {
+ return null;
+ }
+
return RenameRefactoringElement(element, offset, length);
}
}
diff --git a/pkg/analysis_server/lib/src/services/refactoring/refactoring_internal.dart b/pkg/analysis_server/lib/src/services/refactoring/refactoring_internal.dart
index dd05a9b..d34c39e 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/refactoring_internal.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/refactoring_internal.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'dart:collection';
import 'package:analysis_server/src/protocol_server.dart' hide Element;
@@ -89,13 +87,13 @@
}
/// Adds the [SourceEdit] to replace this reference.
- void addEdit(SourceChange change, String newText, {String id}) {
+ void addEdit(SourceChange change, String newText, {String? id}) {
var edit = createEdit(newText, id: id);
doSourceChange_addSourceEdit(change, unitSource, edit);
}
/// Returns the [SourceEdit] to replace this reference.
- SourceEdit createEdit(String newText, {String id}) {
+ SourceEdit createEdit(String newText, {String? id}) {
return newSourceEdit_range(range, newText, id: id);
}
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename.dart b/pkg/analysis_server/lib/src/services/refactoring/rename.dart
index 35d547b..4f2271f 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:analysis_server/src/protocol_server.dart' hide Element;
import 'package:analysis_server/src/services/correction/status.dart';
import 'package:analysis_server/src/services/correction/util.dart';
@@ -23,7 +21,7 @@
RenameProcessor(this.workspace, this.change, this.newName);
/// Add the edit that updates the [element] declaration.
- void addDeclarationEdit(Element element) {
+ void addDeclarationEdit(Element? element) {
if (element != null && workspace.containsElement(element)) {
var edit = newSourceEdit_range(range.elementName(element), newName);
doSourceChange_addElementEdit(change, element, edit);
@@ -60,9 +58,9 @@
final String elementKindName;
@override
final String oldName;
- SourceChange change;
+ late SourceChange change;
- String newName;
+ late String newName;
RenameRefactoringImpl(this.workspace, Element element)
: searchEngine = workspace.searchEngine,
@@ -75,7 +73,7 @@
@override
Future<RefactoringStatus> checkInitialConditions() {
var result = RefactoringStatus();
- if (element.source.isInSystemLibrary) {
+ if (element.source!.isInSystemLibrary) {
var message = format(
"The {0} '{1}' is defined in the SDK, so cannot be renamed.",
getElementKindName(element),
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
index eb2ab3c..422d944 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:analysis_server/src/protocol_server.dart'
hide Element, ElementKind;
import 'package:analysis_server/src/services/correction/status.dart';
@@ -30,7 +28,7 @@
AnalysisSessionHelper sessionHelper,
ClassElement classElement,
String name) {
- return _ClassMemberValidator.forCreate(
+ return _CreateClassMemberValidator(
searchEngine, sessionHelper, classElement, name)
.validate();
}
@@ -38,11 +36,12 @@
/// A [Refactoring] for renaming class member [Element]s.
class RenameClassMemberRefactoringImpl extends RenameRefactoringImpl {
final AnalysisSessionHelper sessionHelper;
+ final ClassElement classElement;
- _ClassMemberValidator _validator;
+ late _RenameClassMemberValidator _validator;
- RenameClassMemberRefactoringImpl(
- RefactoringWorkspace workspace, AnalysisSession session, Element element)
+ RenameClassMemberRefactoringImpl(RefactoringWorkspace workspace,
+ AnalysisSession session, this.classElement, Element element)
: sessionHelper = AnalysisSessionHelper(session),
super(workspace, element);
@@ -59,8 +58,8 @@
@override
Future<RefactoringStatus> checkFinalConditions() {
- _validator = _ClassMemberValidator.forRename(
- searchEngine, sessionHelper, element, newName);
+ _validator = _RenameClassMemberValidator(
+ searchEngine, sessionHelper, classElement, element, newName);
return _validator.validate();
}
@@ -126,37 +125,27 @@
}
}
-/// Helper to check if the created or renamed [Element] will cause any
-/// conflicts.
-class _ClassMemberValidator {
+/// The base class for the create and rename validators.
+class _BaseClassMemberValidator {
final SearchEngine searchEngine;
final AnalysisSessionHelper sessionHelper;
- final LibraryElement library;
- final Element element;
final ClassElement elementClass;
final ElementKind elementKind;
final String name;
- final bool isRename;
final RefactoringStatus result = RefactoringStatus();
- Set<Element> elements = <Element>{};
- List<SearchMatch> references = <SearchMatch>[];
- _ClassMemberValidator.forCreate(
- this.searchEngine, this.sessionHelper, this.elementClass, this.name)
- : isRename = false,
- library = null,
- element = null,
- elementKind = ElementKind.METHOD;
+ _BaseClassMemberValidator(
+ this.searchEngine,
+ this.sessionHelper,
+ this.elementClass,
+ this.elementKind,
+ this.name,
+ );
- _ClassMemberValidator.forRename(
- this.searchEngine, this.sessionHelper, this.element, this.name)
- : isRename = true,
- library = element.library,
- elementClass = element.enclosingElement,
- elementKind = element.kind;
+ LibraryElement get library => elementClass.library;
- Future<RefactoringStatus> validate() async {
+ void _checkClassAlreadyDeclares() {
// check if there is a member with "newName" in the same ClassElement
for (var newNameMember in getChildren(elementClass, name)) {
result.addError(
@@ -167,47 +156,13 @@
name),
newLocation_fromElement(newNameMember));
}
- // do chained computations
- var superClasses = getSuperClasses(elementClass);
- await _prepareReferences();
- var subClasses = await searchEngine.searchAllSubtypes(elementClass);
- // check shadowing of class names
- if (element != null) {
- for (var element in elements) {
- ClassElement clazz = element.enclosingElement;
- if (clazz.name == name) {
- result.addError(
- format(
- "Renamed {0} has the same name as the declaring class '{1}'.",
- elementKind.displayName,
- name),
- newLocation_fromElement(element));
- }
- }
- } else {
- if (elementClass.name == name) {
- result.addError(
- format(
- "Created {0} has the same name as the declaring class '{1}'.",
- elementKind.displayName,
- name),
- newLocation_fromElement(elementClass));
- }
- }
- // usage of the renamed Element is shadowed by a local element
- {
- var conflict = await _getShadowingLocalElement();
- if (conflict != null) {
- var 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));
- }
- }
+ }
+
+ Future<void> _checkHierarchy({
+ required bool isRename,
+ required Set<ClassElement> superClasses,
+ required Set<ClassElement> subClasses,
+ }) async {
// check shadowing in the hierarchy
var declarations = await searchEngine.searchMemberDeclarations(name);
for (var declaration in declarations) {
@@ -236,25 +191,152 @@
newLocation_fromElement(nameElement));
}
}
- // visibility
- if (isRename) {
- _validateWillBeInvisible();
+ }
+}
+
+/// Helper to check if the created element will cause any conflicts.
+class _CreateClassMemberValidator extends _BaseClassMemberValidator {
+ _CreateClassMemberValidator(
+ SearchEngine searchEngine,
+ AnalysisSessionHelper sessionHelper,
+ ClassElement elementClass,
+ String name)
+ : super(
+ searchEngine,
+ sessionHelper,
+ elementClass,
+ ElementKind.METHOD,
+ name,
+ );
+
+ Future<RefactoringStatus> validate() async {
+ _checkClassAlreadyDeclares();
+ // do chained computations
+ var superClasses = getSuperClasses(elementClass);
+ var subClasses = await searchEngine.searchAllSubtypes(elementClass);
+ // check shadowing of class names
+ if (elementClass.name == name) {
+ result.addError(
+ format("Created {0} has the same name as the declaring class '{1}'.",
+ elementKind.displayName, name),
+ newLocation_fromElement(elementClass));
}
+ // check shadowing in the hierarchy
+ await _checkHierarchy(
+ isRename: false,
+ superClasses: superClasses,
+ subClasses: subClasses,
+ );
+ // done
+ return result;
+ }
+}
+
+class _LocalElementsCollector extends GeneralizingAstVisitor<void> {
+ final String name;
+ final List<LocalElement> elements = [];
+
+ _LocalElementsCollector(this.name);
+
+ @override
+ void visitSimpleIdentifier(SimpleIdentifier node) {
+ var 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);
+}
+
+/// Helper to check if the renamed [element] will cause any conflicts.
+class _RenameClassMemberValidator extends _BaseClassMemberValidator {
+ final Element element;
+
+ Set<Element> elements = <Element>{};
+ List<SearchMatch> references = <SearchMatch>[];
+
+ _RenameClassMemberValidator(
+ SearchEngine searchEngine,
+ AnalysisSessionHelper sessionHelper,
+ ClassElement elementClass,
+ this.element,
+ String name,
+ ) : super(searchEngine, sessionHelper, elementClass, element.kind, name);
+
+ Future<RefactoringStatus> validate() async {
+ _checkClassAlreadyDeclares();
+ // do chained computations
+ var superClasses = getSuperClasses(elementClass);
+ await _prepareReferences();
+ var subClasses = await searchEngine.searchAllSubtypes(elementClass);
+ // check shadowing of class names
+ for (var element in elements) {
+ var enclosingElement = element.enclosingElement;
+ if (enclosingElement is ClassElement && enclosingElement.name == name) {
+ result.addError(
+ format(
+ "Renamed {0} has the same name as the declaring class '{1}'.",
+ elementKind.displayName,
+ name,
+ ),
+ newLocation_fromElement(element),
+ );
+ }
+ }
+ // usage of the renamed Element is shadowed by a local element
+ {
+ var conflict = await _getShadowingLocalElement();
+ if (conflict != null) {
+ var 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));
+ }
+ }
+ // check shadowing in the hierarchy
+ await _checkHierarchy(
+ isRename: true,
+ superClasses: superClasses,
+ subClasses: subClasses,
+ );
+ // visibility
+ _validateWillBeInvisible();
// done
return result;
}
- Future<_MatchShadowedByLocal> _getShadowingLocalElement() async {
+ Future<_MatchShadowedByLocal?> _getShadowingLocalElement() async {
var localElementMap = <CompilationUnitElement, List<LocalElement>>{};
var visibleRangeMap = <LocalElement, SourceRange>{};
Future<List<LocalElement>> getLocalElements(Element element) async {
var unitElement = element.thisOrAncestorOfType<CompilationUnitElement>();
+ if (unitElement == null) {
+ return const [];
+ }
+
var localElements = localElementMap[unitElement];
if (localElements == null) {
var result = await sessionHelper.getResolvedUnitByElement(element);
+ if (result == null) {
+ return const [];
+ }
+
var unit = result.unit;
+ if (unit == null) {
+ return const [];
+ }
var collector = _LocalElementsCollector(name);
unit.accept(collector);
@@ -287,6 +369,7 @@
/// Fills [elements] with [Element]s to rename.
Future _prepareElements() async {
+ final element = this.element;
if (element is ClassMemberElement) {
elements = await getHierarchyMembers(searchEngine, element);
} else {
@@ -296,9 +379,6 @@
/// Fills [references] with all references to [elements].
Future _prepareReferences() async {
- if (!isRename) {
- return Future.value();
- }
await _prepareElements();
await Future.forEach(elements, (Element element) async {
var elementReferences = await searchEngine.searchReferences(element);
@@ -313,7 +393,7 @@
}
for (var reference in references) {
var refElement = reference.element;
- var refLibrary = refElement.library;
+ var refLibrary = refElement.library!;
if (refLibrary != library) {
var message = format("Renamed {0} will be invisible in '{1}'.",
getElementKindName(element), getElementQualifiedName(refLibrary));
@@ -322,25 +402,3 @@
}
}
}
-
-class _LocalElementsCollector extends GeneralizingAstVisitor<void> {
- final String name;
- final List<LocalElement> elements = [];
-
- _LocalElementsCollector(this.name);
-
- @override
- void visitSimpleIdentifier(SimpleIdentifier node) {
- var 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/refactoring/rename_constructor.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_constructor.dart
index 3d6edf8..dd17e71 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_constructor.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_constructor.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:analysis_server/src/protocol_server.dart' hide Element;
import 'package:analysis_server/src/services/correction/status.dart';
import 'package:analysis_server/src/services/correction/util.dart';
@@ -48,9 +46,7 @@
RefactoringStatus checkNewName() {
var result = super.checkNewName();
result.addStatus(validateConstructorName(newName));
- if (newName != null) {
- _analyzePossibleConflicts(result);
- }
+ _analyzePossibleConflicts(result);
return result;
}
@@ -90,10 +86,11 @@
SourceReference _createDeclarationReference() {
SourceRange sourceRange;
var offset = element.periodOffset;
+ var nameEnd = element.nameEnd!;
if (offset != null) {
- sourceRange = range.startOffsetEndOffset(offset, element.nameEnd);
+ sourceRange = range.startOffsetEndOffset(offset, nameEnd);
} else {
- sourceRange = SourceRange(element.nameEnd, 0);
+ sourceRange = SourceRange(nameEnd, 0);
}
return SourceReference(SearchMatchImpl(
element.source.fullName,
@@ -112,17 +109,35 @@
var result = await AnalysisSessionHelper(session)
.getElementDeclaration(classElement);
- ClassDeclaration classNode = result.node;
- var utils = CorrectionUtils(result.resolvedUnit);
+ if (result == null) {
+ return;
+ }
+
+ var classNode = result.node;
+ if (classNode is! ClassDeclaration) {
+ return;
+ }
+
+ var resolvedUnit = result.resolvedUnit;
+ if (resolvedUnit == null) {
+ return;
+ }
+
+ var utils = CorrectionUtils(resolvedUnit);
var location = utils.prepareNewConstructorLocation(classNode);
+ if (location == null) {
+ return;
+ }
+
+ var header = '${classElement.name}.$newName();';
doSourceChange_addElementEdit(
- change,
- classElement,
- SourceEdit(
- location.offset,
- 0,
- location.prefix +
- '${classElement.name}.$newName();' +
- location.suffix));
+ change,
+ classElement,
+ SourceEdit(
+ location.offset,
+ 0,
+ location.prefix + header + location.suffix,
+ ),
+ );
}
}
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
index 2665ac7..5367235 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_extension_member.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_extension_member.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:analysis_server/src/protocol_server.dart'
hide Element, ElementKind;
import 'package:analysis_server/src/services/correction/status.dart';
@@ -25,11 +23,12 @@
/// A [Refactoring] for renaming extension member [Element]s.
class RenameExtensionMemberRefactoringImpl extends RenameRefactoringImpl {
final AnalysisSessionHelper sessionHelper;
+ final ExtensionElement extensionElement;
- _ExtensionMemberValidator _validator;
+ late _ExtensionMemberValidator _validator;
- RenameExtensionMemberRefactoringImpl(
- RefactoringWorkspace workspace, AnalysisSession session, Element element)
+ RenameExtensionMemberRefactoringImpl(RefactoringWorkspace workspace,
+ AnalysisSession session, this.extensionElement, Element element)
: sessionHelper = AnalysisSessionHelper(session),
super(workspace, element);
@@ -47,7 +46,7 @@
@override
Future<RefactoringStatus> checkFinalConditions() {
_validator = _ExtensionMemberValidator.forRename(
- searchEngine, sessionHelper, element, newName);
+ searchEngine, sessionHelper, extensionElement, element, newName);
return _validator.validate();
}
@@ -105,11 +104,10 @@
final RefactoringStatus result = RefactoringStatus();
final List<SearchMatch> references = <SearchMatch>[];
- _ExtensionMemberValidator.forRename(
- this.searchEngine, this.sessionHelper, this.element, this.name)
+ _ExtensionMemberValidator.forRename(this.searchEngine, this.sessionHelper,
+ this.elementExtension, this.element, this.name)
: isRename = true,
- library = element.library,
- elementExtension = element.enclosingElement,
+ library = elementExtension.library,
elementKind = element.kind;
Future<RefactoringStatus> validate() async {
@@ -148,17 +146,28 @@
return result;
}
- Future<_MatchShadowedByLocal> _getShadowingLocalElement() async {
+ Future<_MatchShadowedByLocal?> _getShadowingLocalElement() async {
var localElementMap = <CompilationUnitElement, List<LocalElement>>{};
var visibleRangeMap = <LocalElement, SourceRange>{};
Future<List<LocalElement>> getLocalElements(Element element) async {
var unitElement = element.thisOrAncestorOfType<CompilationUnitElement>();
+ if (unitElement == null) {
+ return const [];
+ }
+
var localElements = localElementMap[unitElement];
if (localElements == null) {
var result = await sessionHelper.getResolvedUnitByElement(element);
+ if (result == null) {
+ return const [];
+ }
+
var unit = result.unit;
+ if (unit == null) {
+ return const [];
+ }
var collector = _LocalElementsCollector(name);
unit.accept(collector);
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart
index 04eeea2..5de4b4b 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:analysis_server/src/protocol_server.dart';
import 'package:analysis_server/src/services/correction/status.dart';
import 'package:analysis_server/src/services/refactoring/naming_conventions.dart';
@@ -53,6 +51,11 @@
var prefix = element.prefix;
SourceEdit edit;
if (newName.isEmpty) {
+ // We should not get `prefix == null` because we check in
+ // `checkNewName` that the new name is different.
+ if (prefix == null) {
+ return;
+ }
var node = _findNode();
var uriEnd = node.uri.end;
var prefixEnd = element.prefixOffset + prefix.nameLength;
@@ -69,9 +72,7 @@
edit = newSourceEdit_range(SourceRange(offset, length), newName);
}
}
- if (edit != null) {
- doSourceChange_addElementEdit(change, element, edit);
- }
+ doSourceChange_addElementEdit(change, element, edit);
}
// update references
var matches = await searchEngine.searchReferences(element);
@@ -108,8 +109,8 @@
/// If the given [reference] is before an interpolated [SimpleIdentifier] in
/// an [InterpolationExpression] without surrounding curly brackets, return
/// it. Otherwise return `null`.
- SimpleIdentifier _getInterpolationIdentifier(SourceReference reference) {
- var source = reference.element.source;
+ SimpleIdentifier? _getInterpolationIdentifier(SourceReference reference) {
+ var source = reference.element.source!;
var unit = session.getParsedUnit(source.fullName).unit;
var nodeLocator = NodeLocator(reference.range.offset);
var node = nodeLocator.searchWithin(unit);
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_label.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_label.dart
index 86873b0..d32922a 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_label.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_label.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:analysis_server/src/services/correction/status.dart';
import 'package:analysis_server/src/services/refactoring/naming_conventions.dart';
import 'package:analysis_server/src/services/refactoring/refactoring.dart';
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_library.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_library.dart
index 1338bbc..68b8849 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_library.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_library.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:analysis_server/src/services/correction/status.dart';
import 'package:analysis_server/src/services/refactoring/naming_conventions.dart';
import 'package:analysis_server/src/services/refactoring/refactoring.dart';
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_local.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_local.dart
index 04fa336..eb2745e 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_local.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_local.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:analysis_server/src/protocol_server.dart'
hide Element, ElementKind;
import 'package:analysis_server/src/services/correction/status.dart';
@@ -13,6 +11,7 @@
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: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';
@@ -25,9 +24,9 @@
List<LocalElement> elements = [];
- RenameLocalRefactoringImpl(
- RefactoringWorkspace workspace, LocalElement element)
- : sessionHelper = AnalysisSessionHelper(element.session),
+ RenameLocalRefactoringImpl(RefactoringWorkspace workspace,
+ AnalysisSession session, LocalElement element)
+ : sessionHelper = AnalysisSessionHelper(session),
super(workspace, element);
@override
@@ -50,8 +49,8 @@
await _prepareElements();
for (var element in elements) {
var resolvedUnit = await sessionHelper.getResolvedUnitByElement(element);
- var unit = resolvedUnit.unit;
- unit.accept(
+ var unit = resolvedUnit?.unit;
+ unit?.accept(
_ConflictValidatorVisitor(
result,
newName,
@@ -94,7 +93,7 @@
/// Fills [elements] with [Element]s to rename.
Future _prepareElements() async {
- Element element = this.element;
+ var element = this.element;
if (element is ParameterElement && element.isNamed) {
elements = await getHierarchyNamedParameters(searchEngine, element);
} else {
@@ -141,7 +140,7 @@
nodeElement = getSyntheticAccessorVariable(nodeElement);
var nodeKind = nodeElement.kind.displayName;
var nodeName = getElementQualifiedName(nodeElement);
- var nameElementSourceName = nodeElement.source.shortName;
+ var nameElementSourceName = nodeElement.source!.shortName;
var refKind = target.kind.displayName;
var message = 'Usage of $nodeKind "$nodeName" declared in '
'"$nameElementSourceName" will be shadowed by renamed $refKind.';
@@ -150,7 +149,7 @@
}
}
- SourceRange _getVisibleRange(LocalElement element) {
+ SourceRange? _getVisibleRange(LocalElement element) {
return visibleRangeMap[element];
}
@@ -167,6 +166,7 @@
}
static bool _isNamedExpressionName(SimpleIdentifier node) {
- return node.parent is Label && node.parent.parent is NamedExpression;
+ var parent = node.parent;
+ return parent is Label && parent.parent is NamedExpression;
}
}
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_unit_member.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_unit_member.dart
index 2afbf50..113f8d8 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_unit_member.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_unit_member.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:analysis_server/src/protocol_server.dart'
show newLocation_fromElement, newLocation_fromMatch;
import 'package:analysis_server/src/services/correction/status.dart';
@@ -23,7 +21,7 @@
/// will cause any conflicts.
Future<RefactoringStatus> validateCreateFunction(
SearchEngine searchEngine, LibraryElement library, String name) {
- return _RenameUnitMemberValidator.forCreate(
+ return _CreateUnitMemberValidator(
searchEngine, library, ElementKind.FUNCTION, name)
.validate();
}
@@ -32,8 +30,7 @@
/// will cause any conflicts.
Future<RefactoringStatus> validateRenameTopLevel(
SearchEngine searchEngine, Element element, String name) {
- return _RenameUnitMemberValidator.forRename(searchEngine, element, name)
- .validate();
+ return _RenameUnitMemberValidator(searchEngine, element, name).validate();
}
/// A [Refactoring] for renaming compilation unit member [Element]s.
@@ -42,10 +39,10 @@
/// If the [element] is a Flutter `StatefulWidget` declaration, this is the
/// corresponding `State` declaration.
- ClassElement _flutterWidgetState;
+ ClassElement? _flutterWidgetState;
/// If [_flutterWidgetState] is set, this is the new name of it.
- String _flutterWidgetStateNewName;
+ String? _flutterWidgetStateNewName;
RenameUnitMemberRefactoringImpl(
RefactoringWorkspace workspace, this.resolvedUnit, Element element)
@@ -68,13 +65,15 @@
@override
Future<RefactoringStatus> checkFinalConditions() async {
var status = await validateRenameTopLevel(searchEngine, element, newName);
- if (_flutterWidgetState != null) {
+ final flutterWidgetState = _flutterWidgetState;
+ final flutterWidgetStateNewName = _flutterWidgetStateNewName;
+ if (flutterWidgetState != null && flutterWidgetStateNewName != null) {
_updateFlutterWidgetStateName();
status.addStatus(
await validateRenameTopLevel(
searchEngine,
- _flutterWidgetState,
- _flutterWidgetStateNewName,
+ flutterWidgetState,
+ flutterWidgetStateNewName,
),
);
}
@@ -130,74 +129,55 @@
}
// If a StatefulWidget is being renamed, rename also its State.
- if (_flutterWidgetState != null) {
+ final flutterWidgetState = _flutterWidgetState;
+ if (flutterWidgetState != null) {
_updateFlutterWidgetStateName();
await RenameProcessor(
workspace,
change,
- _flutterWidgetStateNewName,
- ).renameElement(_flutterWidgetState);
+ _flutterWidgetStateNewName!,
+ ).renameElement(flutterWidgetState);
}
}
void _findFlutterStateClass() {
if (Flutter.instance.isStatefulWidgetDeclaration(element)) {
var oldStateName = oldName + 'State';
- _flutterWidgetState = element.library.getType(oldStateName) ??
- element.library.getType('_' + oldStateName);
+ var library = element.library!;
+ _flutterWidgetState =
+ library.getType(oldStateName) ?? library.getType('_' + oldStateName);
}
}
void _updateFlutterWidgetStateName() {
- if (_flutterWidgetState != null) {
- _flutterWidgetStateNewName = newName + 'State';
+ final flutterWidgetState = _flutterWidgetState;
+ if (flutterWidgetState != null) {
+ var flutterWidgetStateNewName = newName + 'State';
// If the State was private, ensure that it stays private.
- if (_flutterWidgetState.name.startsWith('_') &&
- !_flutterWidgetStateNewName.startsWith('_')) {
- _flutterWidgetStateNewName = '_' + _flutterWidgetStateNewName;
+ if (flutterWidgetState.name.startsWith('_') &&
+ !flutterWidgetStateNewName.startsWith('_')) {
+ flutterWidgetStateNewName = '_' + flutterWidgetStateNewName;
}
+ _flutterWidgetStateNewName = flutterWidgetStateNewName;
}
}
}
-/// Helper to check if the created or renamed [Element] will cause any
-/// conflicts.
-class _RenameUnitMemberValidator {
+/// The base class for the create and rename validators.
+class _BaseUnitMemberValidator {
final SearchEngine searchEngine;
- LibraryElement library;
- Element element;
- ElementKind elementKind;
+ final LibraryElement library;
+ final ElementKind elementKind;
final String name;
- final bool isRename;
- List<SearchMatch> references = <SearchMatch>[];
final RefactoringStatus result = RefactoringStatus();
- _RenameUnitMemberValidator.forCreate(
- this.searchEngine, this.library, this.elementKind, this.name)
- : isRename = false;
-
- _RenameUnitMemberValidator.forRename(
- this.searchEngine, this.element, this.name)
- : isRename = true {
- library = element.library;
- elementKind = element.kind;
- }
-
- Future<RefactoringStatus> validate() async {
- _validateWillConflict();
- if (isRename) {
- references = await searchEngine.searchReferences(element);
- _validateWillBeInvisible();
- _validateWillBeShadowed();
- }
- await _validateWillShadow();
- return result;
- }
+ _BaseUnitMemberValidator(
+ this.searchEngine, this.library, this.elementKind, this.name);
/// Returns `true` if [element] is visible at the given [SearchMatch].
bool _isVisibleAt(Element element, SearchMatch at) {
- var atLibrary = at.element.library;
+ var atLibrary = at.element.library!;
// may be the same library
if (library == atLibrary) {
return true;
@@ -217,6 +197,90 @@
return false;
}
+ /// Validates if an element with the [name] will conflict with another
+ /// top-level [Element] in the same library.
+ void _validateWillConflict() {
+ visitLibraryTopLevelElements(library, (element) {
+ if (hasDisplayName(element, name)) {
+ var message = format("Library already declares {0} with name '{1}'.",
+ getElementKindName(element), name);
+ result.addError(message, newLocation_fromElement(element));
+ }
+ });
+ }
+
+ /// Validates if renamed [element] will shadow any [Element] named [name].
+ Future _validateWillShadow(Element? element) async {
+ var declarations = await searchEngine.searchMemberDeclarations(name);
+ for (var declaration in declarations) {
+ var member = declaration.element;
+ var declaringClass = member.enclosingElement as ClassElement;
+ var memberReferences = await searchEngine.searchReferences(member);
+ for (var memberReference in memberReferences) {
+ var refElement = memberReference.element;
+ // cannot be shadowed if qualified
+ if (memberReference.isQualified) {
+ continue;
+ }
+ // cannot be shadowed if declared in the same class as reference
+ var refClass = refElement.thisOrAncestorOfType<ClassElement>();
+ if (refClass == declaringClass) {
+ continue;
+ }
+ // ignore if not visible
+ if (element != null && !_isVisibleAt(element, memberReference)) {
+ continue;
+ }
+ // OK, reference will be shadowed be the element being renamed
+ var message = format(
+ element != null
+ ? "Renamed {0} will shadow {1} '{2}'."
+ : "Created {0} will shadow {1} '{2}'.",
+ elementKind.displayName,
+ getElementKindName(member),
+ getElementQualifiedName(member));
+ result.addError(message, newLocation_fromMatch(memberReference));
+ }
+ }
+ }
+}
+
+/// Helper to check if the created element will cause any conflicts.
+class _CreateUnitMemberValidator extends _BaseUnitMemberValidator {
+ _CreateUnitMemberValidator(
+ SearchEngine searchEngine,
+ LibraryElement library,
+ ElementKind elementKind,
+ String name,
+ ) : super(searchEngine, library, elementKind, name);
+
+ Future<RefactoringStatus> validate() async {
+ _validateWillConflict();
+ await _validateWillShadow(null);
+ return result;
+ }
+}
+
+/// Helper to check if the renamed element will cause any conflicts.
+class _RenameUnitMemberValidator extends _BaseUnitMemberValidator {
+ final Element element;
+ List<SearchMatch> references = <SearchMatch>[];
+
+ _RenameUnitMemberValidator(
+ SearchEngine searchEngine,
+ this.element,
+ String name,
+ ) : super(searchEngine, element.library!, element.kind, name);
+
+ Future<RefactoringStatus> validate() async {
+ _validateWillConflict();
+ references = await searchEngine.searchReferences(element);
+ _validateWillBeInvisible();
+ _validateWillBeShadowed();
+ await _validateWillShadow(element);
+ return result;
+ }
+
/// Validates if any usage of [element] renamed to [name] will be invisible.
void _validateWillBeInvisible() {
if (!Identifier.isPrivateName(name)) {
@@ -224,7 +288,7 @@
}
for (var reference in references) {
var refElement = reference.element;
- var refLibrary = refElement.library;
+ var refLibrary = refElement.library!;
if (refLibrary != library) {
var message = format("Renamed {0} will be invisible in '{1}'.",
getElementKindName(element), getElementQualifiedName(refLibrary));
@@ -253,51 +317,4 @@
}
}
}
-
- /// Validates if [element] renamed to [name] will conflict with another
- /// top-level [Element] in the same library.
- void _validateWillConflict() {
- visitLibraryTopLevelElements(library, (element) {
- if (hasDisplayName(element, name)) {
- var message = format("Library already declares {0} with name '{1}'.",
- getElementKindName(element), name);
- result.addError(message, newLocation_fromElement(element));
- }
- });
- }
-
- /// Validates if renamed [element] will shadow any [Element] named [name].
- Future _validateWillShadow() async {
- var declarations = await searchEngine.searchMemberDeclarations(name);
- for (var declaration in declarations) {
- var member = declaration.element;
- ClassElement declaringClass = member.enclosingElement;
- var memberReferences = await searchEngine.searchReferences(member);
- for (var memberReference in memberReferences) {
- var refElement = memberReference.element;
- // cannot be shadowed if qualified
- if (memberReference.isQualified) {
- continue;
- }
- // cannot be shadowed if declared in the same class as reference
- var refClass = refElement.thisOrAncestorOfType<ClassElement>();
- if (refClass == declaringClass) {
- continue;
- }
- // ignore if not visible
- if (!_isVisibleAt(element, memberReference)) {
- continue;
- }
- // OK, reference will be shadowed be the element being renamed
- var message = format(
- isRename
- ? "Renamed {0} will shadow {1} '{2}'."
- : "Created {0} will shadow {1} '{2}'.",
- elementKind.displayName,
- getElementKindName(member),
- getElementQualifiedName(member));
- result.addError(message, newLocation_fromMatch(memberReference));
- }
- }
- }
}
diff --git a/pkg/analysis_server/lib/src/status/diagnostics.dart b/pkg/analysis_server/lib/src/status/diagnostics.dart
index bfb39c7..86da984 100644
--- a/pkg/analysis_server/lib/src/status/diagnostics.dart
+++ b/pkg/analysis_server/lib/src/status/diagnostics.dart
@@ -24,6 +24,7 @@
import 'package:analysis_server/src/status/pages.dart';
import 'package:analysis_server/src/utilities/profiling.dart';
import 'package:analyzer/dart/analysis/context_root.dart';
+import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/src/context/source.dart';
import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:analyzer/src/dartdoc/dartdoc_directive_info.dart';
@@ -242,17 +243,16 @@
raw: true);
return;
}
- var result = await driver.getResult(filePath);
- if (result == null) {
+ var result = await driver.getResult2(filePath);
+ if (result is ResolvedUnitResult) {
+ var writer = AstWriter(buf);
+ result.unit.accept(writer);
+ } else {
p(
'An AST could not be produced for the file '
'<code>${escape(filePath)}</code>.',
raw: true);
- return;
}
-
- var writer = AstWriter(buf);
- result.unit.accept(writer);
}
@override
@@ -829,17 +829,16 @@
raw: true);
return;
}
- var result = await driver.getResult(filePath);
- if (result == null) {
+ var result = await driver.getResult2(filePath);
+ if (result is ResolvedUnitResult) {
+ var writer = ElementWriter(buf);
+ result.unit.declaredElement.accept(writer);
+ } else {
p(
'An element model could not be produced for the file '
'<code>${escape(filePath)}</code>.',
raw: true);
- return;
}
-
- var writer = ElementWriter(buf);
- result.unit.declaredElement.accept(writer);
}
@override
diff --git a/pkg/analysis_server/lib/src/status/pages.dart b/pkg/analysis_server/lib/src/status/pages.dart
index 61f4704..e626e02 100644
--- a/pkg/analysis_server/lib/src/status/pages.dart
+++ b/pkg/analysis_server/lib/src/status/pages.dart
@@ -118,7 +118,7 @@
buf.writeln('</pre>');
}
- void prettyJson(Map<String, dynamic> data) {
+ void prettyJson(Object? data) {
const jsonEncoder = JsonEncoder.withIndent(' ');
pre(() {
buf.write(jsonEncoder.convert(data));
diff --git a/pkg/analysis_server/lib/src/utilities/extensions/yaml.dart b/pkg/analysis_server/lib/src/utilities/extensions/yaml.dart
index dfe4983..474b711 100644
--- a/pkg/analysis_server/lib/src/utilities/extensions/yaml.dart
+++ b/pkg/analysis_server/lib/src/utilities/extensions/yaml.dart
@@ -23,16 +23,22 @@
}
}
} else if (node is YamlMap) {
- for (var entry in node.nodes.entries) {
+ var entries = node.nodes.entries.toList();
+ for (var i = 0; i < entries.length; i++) {
+ var entry = entries[i];
+ var nextEntryOffset = i + 1 < entries.length
+ ? (entries[i + 1].key as YamlNode).span.start.offset
+ : null;
if ((entry.key as YamlNode).containsOffset(offset)) {
return entry.key;
}
var value = entry.value;
if (value.containsOffset(offset) ||
- (value is YamlScalar && value.value == null)) {
- // TODO(brianwilkerson) Testing for a null value probably gets
- // confused when there are multiple null values or when there is a
- // null value before the node that actually contains the offset.
+ (value is YamlScalar &&
+ value.value == null &&
+ // To match a null, we need to be the last node, or the offset
+ // needs to be before the next key.
+ (nextEntryOffset == null || offset < nextEntryOffset))) {
return entry.value;
}
}
diff --git a/pkg/analysis_server/lib/src/utilities/flutter.dart b/pkg/analysis_server/lib/src/utilities/flutter.dart
index adaef36..cb513a3 100644
--- a/pkg/analysis_server/lib/src/utilities/flutter.dart
+++ b/pkg/analysis_server/lib/src/utilities/flutter.dart
@@ -266,7 +266,7 @@
/// Return the instance creation expression that surrounds the given
/// [node], if any, else null. The [node] may be the instance creation
/// expression itself or the identifier that names the constructor.
- InstanceCreationExpression? identifyNewExpression(AstNode node) {
+ InstanceCreationExpression? identifyNewExpression(AstNode? node) {
InstanceCreationExpression? newExpr;
if (node is SimpleIdentifier) {
var parent = node.parent;
diff --git a/pkg/analysis_server/test/abstract_context.dart b/pkg/analysis_server/test/abstract_context.dart
index eeb1471..b2db401 100644
--- a/pkg/analysis_server/test/abstract_context.dart
+++ b/pkg/analysis_server/test/abstract_context.dart
@@ -90,7 +90,7 @@
var analysisContext = contextFor(testPackageRootPath);
var files = analysisContext.contextRoot.analyzedFiles().toList();
for (var path in files) {
- await analysisContext.currentSession.getResolvedUnit(path);
+ await analysisContext.currentSession.getResolvedUnit2(path);
}
}
@@ -171,7 +171,8 @@
Future<ResolvedUnitResult> resolveFile(String path) async {
path = convertPath(path);
- return contextFor(path).currentSession.getResolvedUnit(path);
+ var session = contextFor(path).currentSession;
+ return await session.getResolvedUnit2(path) as ResolvedUnitResult;
}
@mustCallSuper
diff --git a/pkg/analysis_server/test/abstract_single_unit.dart b/pkg/analysis_server/test/abstract_single_unit.dart
index a889acf..e479d9c 100644
--- a/pkg/analysis_server/test/abstract_single_unit.dart
+++ b/pkg/analysis_server/test/abstract_single_unit.dart
@@ -70,7 +70,7 @@
}
Future<void> resolveTestFile() async {
- var result = await session.getResolvedUnit(testFile);
+ var result = await session.getResolvedUnit2(testFile) as ResolvedUnitResult;
testAnalysisResult = result;
testCode = result.content!;
testUnit = result.unit!;
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index e31fc32..8da9476 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -485,7 +485,7 @@
expect(suggestions, isEmpty);
}
- Future<void> test_inComment_endOfFile() async {
+ Future<void> test_inComment_endOfFile_withNewline() async {
addTestFile('''
// text ^
''');
@@ -493,6 +493,12 @@
expect(suggestions, isEmpty);
}
+ Future<void> test_inComment_endOfFile_withoutNewline() async {
+ addTestFile('// text ^');
+ await getSuggestions();
+ expect(suggestions, isEmpty);
+ }
+
Future<void> test_inComment_endOfLine_beforeNode() async {
addTestFile('''
main(aaa, bbb) {
diff --git a/pkg/analysis_server/test/edit/refactoring_test.dart b/pkg/analysis_server/test/edit/refactoring_test.dart
index 24d8e02..9baa5b3 100644
--- a/pkg/analysis_server/test/edit/refactoring_test.dart
+++ b/pkg/analysis_server/test/edit/refactoring_test.dart
@@ -2127,7 +2127,7 @@
print(otherName);
}
''');
- server.getAnalysisDriver(testFile).getResult(testFile);
+ server.getAnalysisDriver(testFile).getResult2(testFile);
// send the second request, with the same kind, file and offset
await waitForTasksFinished();
result = await getRefactoringResult(() {
diff --git a/pkg/analysis_server/test/lsp/completion.dart b/pkg/analysis_server/test/lsp/completion.dart
index 2e1e1e2..7d8dd01 100644
--- a/pkg/analysis_server/test/lsp/completion.dart
+++ b/pkg/analysis_server/test/lsp/completion.dart
@@ -13,7 +13,7 @@
int sortTextSorter(CompletionItem item1, CompletionItem item2) =>
(item1.sortText ?? item1.label).compareTo(item2.sortText ?? item2.label);
- Future<void> verifyCompletions(
+ Future<String> verifyCompletions(
Uri fileUri,
String content, {
List<String> expectCompletions,
@@ -22,6 +22,7 @@
String expectedContent,
String expectedContentIfInserting,
bool verifyInsertReplaceRanges = false,
+ bool openCloseFile = true,
}) async {
// If verifyInsertReplaceRanges is true, we need both expected contents.
assert(verifyInsertReplaceRanges == false ||
@@ -38,9 +39,13 @@
await initialize(textDocumentCapabilities: textDocCapabilities);
}
- await openFile(fileUri, withoutMarkers(content));
+ if (openCloseFile) {
+ await openFile(fileUri, withoutMarkers(content));
+ }
final res = await getCompletion(fileUri, positionFromMarker(content));
- await closeFile(fileUri);
+ if (openCloseFile) {
+ await closeFile(fileUri);
+ }
// Sort the completions by sortText and filter to those we expect, so the ordering
// can be compared.
@@ -60,14 +65,16 @@
item = await resolveCompletion(item);
}
+ String updatedContent;
if (verifyInsertReplaceRanges &&
expectedContent != expectedContentIfInserting) {
// Replacing.
- final replaced = applyTextEdits(
+ updatedContent = applyTextEdits(
withoutMarkers(content),
[textEditForReplace(item.textEdit)],
);
- expect(withCaret(replaced, insertFormat), equals(expectedContent));
+ expect(
+ withCaret(updatedContent, insertFormat), equals(expectedContent));
// Inserting.
final inserted = applyTextEdits(
@@ -77,13 +84,19 @@
expect(withCaret(inserted, insertFormat),
equals(expectedContentIfInserting));
} else {
- final updated = applyTextEdits(
+ updatedContent = applyTextEdits(
withoutMarkers(content),
[toTextEdit(item.textEdit)],
);
- expect(withCaret(updated, insertFormat), equals(expectedContent));
+ if (expectedContent != null) {
+ expect(
+ withCaret(updatedContent, insertFormat), equals(expectedContent));
+ }
}
+ return updatedContent;
}
+
+ return null;
}
/// Replaces the LSP snippet placeholder '${0:}' with '^' for easier verifying
diff --git a/pkg/analysis_server/test/lsp/completion_dart_test.dart b/pkg/analysis_server/test/lsp/completion_dart_test.dart
index 07e00ed..faacf84 100644
--- a/pkg/analysis_server/test/lsp/completion_dart_test.dart
+++ b/pkg/analysis_server/test/lsp/completion_dart_test.dart
@@ -44,6 +44,42 @@
);
}
+ Future<void> test_comment() async {
+ final content = '''
+ // foo ^
+ main() {}
+ ''';
+
+ await initialize();
+ await openFile(mainFileUri, withoutMarkers(content));
+ final res = await getCompletion(mainFileUri, positionFromMarker(content));
+ expect(res, isEmpty);
+ }
+
+ Future<void> test_comment_endOfFile_withNewline() async {
+ // Checks for a previous bug where invoking completion inside a comment
+ // at the end of a file would return results.
+ final content = '''
+ // foo ^
+ ''';
+
+ await initialize();
+ await openFile(mainFileUri, withoutMarkers(content));
+ final res = await getCompletion(mainFileUri, positionFromMarker(content));
+ expect(res, isEmpty);
+ }
+
+ Future<void> test_comment_endOfFile_withoutNewline() async {
+ // Checks for a previous bug where invoking completion inside a comment
+ // at the very end of a file with no trailing newline would return results.
+ final content = '// foo ^';
+
+ await initialize();
+ await openFile(mainFileUri, withoutMarkers(content));
+ final res = await getCompletion(mainFileUri, positionFromMarker(content));
+ expect(res, isEmpty);
+ }
+
Future<void> test_commitCharacter_completionItem() async {
await provideConfig(
() => initialize(
@@ -89,7 +125,7 @@
);
Registration registration(Method method) =>
- registrationFor(registrations, method);
+ registrationForDart(registrations, method);
// By default, there should be no commit characters.
var reg = registration(Method.textDocument_completion);
@@ -344,6 +380,81 @@
);
}
+ Future<void> test_completionTrigger_brace_block() async {
+ // Brace should not trigger completion if a normal code block.
+ final content = r'''
+ main () {^}
+ ''';
+ await _checkResultsForTriggerCharacters(content, ['{'], isEmpty);
+ }
+
+ Future<void>
+ test_completionTrigger_brace_interpolatedStringExpression() async {
+ // Brace should trigger completion if at the start of an interpolated expression
+ final content = r'''
+ var a = '${^';
+ ''';
+ await _checkResultsForTriggerCharacters(content, [r'{'], isNotEmpty);
+ }
+
+ Future<void> test_completionTrigger_brace_rawString() async {
+ // Brace should not trigger completion if in a raw string.
+ final content = r'''
+ var a = r'${^';
+ ''';
+ await _checkResultsForTriggerCharacters(content, [r'{'], isEmpty);
+ }
+
+ Future<void> test_completionTrigger_brace_string() async {
+ // Brace should not trigger completion if not at the start of an interpolated
+ // expression.
+ final content = r'''
+ var a = '{^';
+ ''';
+ await _checkResultsForTriggerCharacters(content, [r'{'], isEmpty);
+ }
+
+ Future<void> test_completionTrigger_quotes_endingString() async {
+ // Completion triggered by a quote ending a string should not return results.
+ final content = "foo(''^);";
+ await _checkResultsForTriggerCharacters(content, ["'", '"'], isEmpty);
+ }
+
+ Future<void> test_completionTrigger_quotes_startingImport() async {
+ // Completion triggered by a quote for import should return results.
+ final content = "import '^'";
+ await _checkResultsForTriggerCharacters(content, ["'", '"'], isNotEmpty);
+ }
+
+ Future<void> test_completionTrigger_quotes_startingString() async {
+ // Completion triggered by a quote for normal string should not return results.
+ final content = "foo('^');";
+ await _checkResultsForTriggerCharacters(content, ["'", '"'], isEmpty);
+ }
+
+ Future<void> test_completionTrigger_quotes_terminatingImport() async {
+ // Completion triggered by a quote ending an import should not return results.
+ final content = "import ''^";
+ await _checkResultsForTriggerCharacters(content, ["'", '"'], isEmpty);
+ }
+
+ Future<void> test_completionTrigger_slash_directivePath() async {
+ // Slashes should trigger completion when typing in directive paths, eg.
+ // after typing 'package:foo/' completion should give the next folder segments.
+ final content = r'''
+ import 'package:test/^';
+ ''';
+ await _checkResultsForTriggerCharacters(content, [r'/'], isNotEmpty);
+ }
+
+ Future<void> test_completionTrigger_slash_divide() async {
+ // Slashes should not trigger completion when typing in a normal expression.
+ final content = r'''
+ var a = 1 /^
+ ''';
+ await _checkResultsForTriggerCharacters(content, [r'/'], isEmpty);
+ }
+
Future<void> test_completionTriggerKinds_invalidParams() async {
await initialize();
@@ -898,11 +1009,12 @@
);
}
- Future<void> test_nonDartFile() async {
- newFile(pubspecFilePath, content: simplePubspecContent);
+ Future<void> test_nonAnalyzedFile() async {
+ final readmeFilePath = convertPath(join(projectFolderPath, 'README.md'));
+ newFile(readmeFilePath, content: '');
await initialize();
- final res = await getCompletion(pubspecFileUri, startOfDocPos);
+ final res = await getCompletion(Uri.file(readmeFilePath), startOfDocPos);
expect(res, isEmpty);
}
@@ -1761,6 +1873,21 @@
);
expect(updated, contains('a.abcdefghij'));
}
+
+ Future<void> _checkResultsForTriggerCharacters(String content,
+ List<String> triggerCharacters, Matcher expectedResults) async {
+ await initialize();
+ await openFile(mainFileUri, withoutMarkers(content));
+
+ for (final triggerCharacter in triggerCharacters) {
+ final context = CompletionContext(
+ triggerKind: CompletionTriggerKind.TriggerCharacter,
+ triggerCharacter: triggerCharacter);
+ final res = await getCompletion(mainFileUri, positionFromMarker(content),
+ context: context);
+ expect(res, expectedResults);
+ }
+ }
}
@reflectiveTest
diff --git a/pkg/analysis_server/test/lsp/completion_yaml_test.dart b/pkg/analysis_server/test/lsp/completion_yaml_test.dart
index a00dce5..878d367 100644
--- a/pkg/analysis_server/test/lsp/completion_yaml_test.dart
+++ b/pkg/analysis_server/test/lsp/completion_yaml_test.dart
@@ -7,6 +7,7 @@
import 'package:analysis_server/src/services/pub/pub_api.dart';
import 'package:http/http.dart';
import 'package:linter/src/rules.dart';
+import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'completion.dart';
@@ -192,10 +193,14 @@
@reflectiveTest
class PubspecCompletionTest extends AbstractLspAnalysisServerTest
with CompletionTestMixin {
+ /// Sample package name list JSON in the same format as the API:
+ /// https://pub.dev/api/package-name-completion-data
static const samplePackageList = '''
{ "packages": ["one", "two", "three"] }
''';
+ /// Sample package details JSON in the same format as the API:
+ /// https://pub.dev/api/packages/devtools
static const samplePackageDetails = '''
{
"name":"package",
@@ -297,6 +302,41 @@
);
}
+ Future<void> test_package_description() async {
+ httpClient.sendHandler = (BaseRequest request) async {
+ if (request.url.path.startsWith(PubApi.packageNameListPath)) {
+ return Response(samplePackageList, 200);
+ } else if (request.url.path.startsWith(PubApi.packageInfoPath)) {
+ return Response(samplePackageDetails, 200);
+ } else {
+ throw UnimplementedError();
+ }
+ };
+
+ final content = '''
+name: foo
+version: 1.0.0
+
+dependencies:
+ ^''';
+
+ await initialize();
+ await openFile(pubspecFileUri, withoutMarkers(content));
+ await pumpEventQueue();
+
+ // Descriptions are included in the documentation field that is only added
+ // when completions are resolved.
+ final completion = await getResolvedCompletion(
+ pubspecFileUri,
+ positionFromMarker(content),
+ 'one: ',
+ );
+ expect(
+ completion.documentation.valueEquals('Description of package'),
+ isTrue,
+ );
+ }
+
Future<void> test_package_names() async {
httpClient.sendHandler = (BaseRequest request) async {
if (request.url.toString().endsWith(PubApi.packageNameListPath)) {
@@ -329,6 +369,57 @@
);
}
+ Future<void> test_package_version() async {
+ httpClient.sendHandler = (BaseRequest request) async {
+ if (request.url.path.startsWith(PubApi.packageNameListPath)) {
+ return Response(samplePackageList, 200);
+ } else if (request.url.path.startsWith(PubApi.packageInfoPath)) {
+ return Response(samplePackageDetails, 200);
+ } else {
+ throw UnimplementedError();
+ }
+ };
+
+ final content = '''
+name: foo
+version: 1.0.0
+
+dependencies:
+ ^''';
+
+ final expected = '''
+name: foo
+version: 1.0.0
+
+dependencies:
+ one: ^1.2.3''';
+
+ await initialize();
+ await openFile(pubspecFileUri, withoutMarkers(content));
+
+ // Versions are currently only available if we've previously resolved on the
+ // package name, so first complete/resolve that.
+ final newContent = await verifyCompletions(
+ pubspecFileUri,
+ content,
+ expectCompletions: ['one: '],
+ resolve: true,
+ applyEditsFor: 'one: ',
+ openCloseFile: false,
+ );
+ await replaceFile(222, pubspecFileUri, newContent);
+
+ await verifyCompletions(
+ pubspecFileUri,
+ newContent.replaceFirst(
+ 'one: ', 'one: ^'), // Insert caret at new location
+ expectCompletions: ['^1.2.3'],
+ applyEditsFor: '^1.2.3',
+ expectedContent: expected,
+ openCloseFile: false,
+ );
+ }
+
Future<void> test_topLevel() async {
final content = '''
version: 1.0.0
diff --git a/pkg/analysis_server/test/lsp/initialization_test.dart b/pkg/analysis_server/test/lsp/initialization_test.dart
index fc6b1fc..93ecc62 100644
--- a/pkg/analysis_server/test/lsp/initialization_test.dart
+++ b/pkg/analysis_server/test/lsp/initialization_test.dart
@@ -31,6 +31,45 @@
registrationFor(registrations, method)?.registerOptions);
}
+ Future<void> test_completionRegistrations_triggerCharacters() async {
+ final registrations = <Registration>[];
+ final initResponse = await monitorDynamicRegistrations(
+ registrations,
+ () => initialize(
+ // Support dynamic registration for everything we support.
+ textDocumentCapabilities:
+ withAllSupportedTextDocumentDynamicRegistrations(
+ emptyTextDocumentClientCapabilities),
+ workspaceCapabilities: withAllSupportedWorkspaceDynamicRegistrations(
+ emptyWorkspaceClientCapabilities),
+ ),
+ );
+
+ final initResult = InitializeResult.fromJson(initResponse.result);
+ expect(initResult.capabilities, isNotNull);
+
+ // Check Dart-only registration.
+ final dartRegistration =
+ registrationForDart(registrations, Method.textDocument_completion);
+ final dartOptions = CompletionRegistrationOptions.fromJson(
+ dartRegistration.registerOptions);
+ expect(dartOptions.documentSelector, hasLength(1));
+ expect(dartOptions.documentSelector[0].language, dartLanguageId);
+ expect(dartOptions.triggerCharacters, isNotEmpty);
+
+ // Check non-Dart registration.
+ final nonDartRegistration = registrations.singleWhere((r) =>
+ r.method == Method.textDocument_completion.toJson() &&
+ r != dartRegistration);
+ final nonDartOptions = CompletionRegistrationOptions.fromJson(
+ nonDartRegistration.registerOptions);
+ final otherLanguages = nonDartOptions.documentSelector
+ .map((selector) => selector.language)
+ .toList();
+ expect(otherLanguages, isNot(contains('dart')));
+ expect(nonDartOptions.triggerCharacters, isNull);
+ }
+
Future<void> test_dynamicRegistration_containsAppropriateSettings() async {
// Basic check that the server responds with the capabilities we'd expect,
// for ex including analysis_options.yaml in text synchronization but not
@@ -192,11 +231,22 @@
// Ensure all expected dynamic registrations.
for (final expectedRegistration in ClientDynamicRegistrations.supported) {
+ // We have two completion registrations (to handle different trigger
+ // characters), so exclude that here and check it manually below.
+ if (expectedRegistration == Method.textDocument_completion) {
+ continue;
+ }
+
final registration =
registrationOptionsFor(registrations, expectedRegistration);
expect(registration, isNotNull,
reason: 'Missing dynamic registration for $expectedRegistration');
}
+
+ // Check the were two completion registrations.
+ final completionRegistrations = registrations
+ .where((reg) => reg.method == Method.textDocument_completion.toJson());
+ expect(completionRegistrations, hasLength(2));
}
Future<void> test_dynamicRegistration_unregistersOutdatedAfterChange() async {
diff --git a/pkg/analysis_server/test/lsp/server_abstract.dart b/pkg/analysis_server/test/lsp/server_abstract.dart
index b99c4fe..8091172 100644
--- a/pkg/analysis_server/test/lsp/server_abstract.dart
+++ b/pkg/analysis_server/test/lsp/server_abstract.dart
@@ -118,6 +118,21 @@
orElse: () => null);
}
+ /// Finds the registration for a given LSP method with Dart in its
+ /// documentSelector.
+ Registration registrationForDart(
+ List<Registration> registrations,
+ Method method,
+ ) {
+ return registrations.singleWhere(
+ (r) =>
+ r.method == method.toJson() &&
+ TextDocumentRegistrationOptions.fromJson(r.registerOptions)
+ .documentSelector
+ .any((selector) => selector.language == dartLanguageId),
+ orElse: () => null);
+ }
+
void resetContextBuildCounter() {
_previousContextBuilds = server.contextBuilds;
}
diff --git a/pkg/analysis_server/test/mocks_lsp.dart b/pkg/analysis_server/test/mocks_lsp.dart
index 868b648..fdb402e 100644
--- a/pkg/analysis_server/test/mocks_lsp.dart
+++ b/pkg/analysis_server/test/mocks_lsp.dart
@@ -124,7 +124,7 @@
Future<lsp.ResponseMessage> sendRequestToServer(lsp.RequestMessage request) {
// No further requests should be sent after the connection is closed.
if (_closed.isCompleted) {
- throw Exception('sendLspRequest after connection closed');
+ throw Exception('${request.method} request sent after connection closed');
}
request = _convertJson(request, lsp.RequestMessage.fromJson);
diff --git a/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart b/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
index c92a7b2..0a651c2 100644
--- a/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
+++ b/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
@@ -536,7 +536,7 @@
DartCompletionRequest request);
Future computeSuggestions({int times = 200}) async {
- result = await session.getResolvedUnit(testFile);
+ result = await session.getResolvedUnit2(testFile) as ResolvedUnitResult;
var baseRequest = CompletionRequestImpl(
result, completionOffset, CompletionPerformance());
diff --git a/pkg/analysis_server/test/services/completion/dart/completion_manager_test.dart b/pkg/analysis_server/test/services/completion/dart/completion_manager_test.dart
index 0f6f5e7..4dd13ee 100644
--- a/pkg/analysis_server/test/services/completion/dart/completion_manager_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/completion_manager_test.dart
@@ -9,6 +9,7 @@
import 'package:analysis_server/src/services/completion/completion_performance.dart';
import 'package:analysis_server/src/services/completion/dart/completion_manager.dart';
import 'package:analysis_server/src/services/completion/dart/imported_reference_contributor.dart';
+import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/dartdoc/dartdoc_directive_info.dart';
import 'package:test/test.dart';
@@ -49,7 +50,7 @@
// Build the request
var baseRequest = CompletionRequestImpl(
- await session.getResolvedUnit(testFile),
+ await session.getResolvedUnit2(testFile) as ResolvedUnitResult,
completionOffset,
CompletionPerformance());
await baseRequest.performance.runRequestOperation((performance) async {
diff --git a/pkg/analysis_server/test/services/correction/organize_directives_test.dart b/pkg/analysis_server/test/services/correction/organize_directives_test.dart
index 56a370b..a147a80 100644
--- a/pkg/analysis_server/test/services/correction/organize_directives_test.dart
+++ b/pkg/analysis_server/test/services/correction/organize_directives_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/organize_imports.dart';
+import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart'
hide AnalysisError;
@@ -581,7 +582,7 @@
Future<void> _computeUnitAndErrors(String code) async {
addTestSource(code);
- var result = await session.getResolvedUnit(testFile);
+ var result = await session.getResolvedUnit2(testFile) as ResolvedUnitResult;
testUnit = result.unit!;
testErrors = result.errors;
}
diff --git a/pkg/analysis_server/test/services/refactoring/abstract_refactoring.dart b/pkg/analysis_server/test/services/refactoring/abstract_refactoring.dart
index 7e982701..1ab4b27 100644
--- a/pkg/analysis_server/test/services/refactoring/abstract_refactoring.dart
+++ b/pkg/analysis_server/test/services/refactoring/abstract_refactoring.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:analysis_server/src/services/correction/status.dart';
import 'package:analysis_server/src/services/refactoring/refactoring.dart';
import 'package:analysis_server/src/services/search/search_engine.dart';
@@ -34,9 +32,9 @@
/// The base class for all [Refactoring] tests.
abstract class RefactoringTest extends AbstractSingleUnitTest
with WithNonFunctionTypeAliasesMixin {
- SearchEngine searchEngine;
+ late SearchEngine searchEngine;
- SourceChange refactoringChange;
+ late SourceChange refactoringChange;
Refactoring get refactoring;
@@ -48,7 +46,9 @@
}
// prepare FileEdit
var fileEdit = refactoringChange.getFileEdit(convertPath(path));
- expect(fileEdit, isNotNull, reason: 'No file edit for $path');
+ if (fileEdit == null) {
+ fail('No file edit for $path');
+ }
// validate resulting code
var file = getFile(path);
var ini = file.readAsStringSync();
@@ -79,26 +79,28 @@
/// Asserts that [status] has expected severity and message.
void assertRefactoringStatus(
- RefactoringStatus status, RefactoringProblemSeverity expectedSeverity,
- {String expectedMessage,
- SourceRange expectedContextRange,
- String expectedContextSearch}) {
+ RefactoringStatus status, RefactoringProblemSeverity? expectedSeverity,
+ {String? expectedMessage,
+ SourceRange? expectedContextRange,
+ String? expectedContextSearch}) {
expect(status.severity, expectedSeverity, reason: status.toString());
if (expectedSeverity != null) {
- var problem = status.problem;
+ var problem = status.problem!;
expect(problem.severity, expectedSeverity);
if (expectedMessage != null) {
expect(problem.message, expectedMessage);
}
if (expectedContextRange != null) {
- expect(problem.location.offset, expectedContextRange.offset);
- expect(problem.location.length, expectedContextRange.length);
+ var location = problem.location!;
+ expect(location.offset, expectedContextRange.offset);
+ expect(location.length, expectedContextRange.length);
}
if (expectedContextSearch != null) {
+ var location = problem.location!;
var expectedOffset = findOffset(expectedContextSearch);
var expectedLength = findIdentifierLength(expectedContextSearch);
- expect(problem.location.offset, expectedOffset);
- expect(problem.location.length, expectedLength);
+ expect(location.offset, expectedOffset);
+ expect(location.length, expectedLength);
}
}
}
@@ -125,7 +127,9 @@
}
// prepare FileEdit
var fileEdit = refactoringChange.getFileEdit(testFile);
- expect(fileEdit, isNotNull);
+ if (fileEdit == null) {
+ fail('No file edit for $testFile');
+ }
// validate resulting code
var actualCode = SourceEdit.applySequence(testCode, fileEdit.edits);
expect(actualCode, expectedCode);
diff --git a/pkg/analysis_server/test/services/refactoring/abstract_rename.dart b/pkg/analysis_server/test/services/refactoring/abstract_rename.dart
index 1437541..26676b3 100644
--- a/pkg/analysis_server/test/services/refactoring/abstract_rename.dart
+++ b/pkg/analysis_server/test/services/refactoring/abstract_rename.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:analysis_server/src/services/correction/namespace.dart';
import 'package:analysis_server/src/services/refactoring/refactoring.dart';
import 'package:analyzer/dart/ast/ast.dart';
@@ -19,7 +17,7 @@
/// The base class for all [RenameRefactoring] tests.
class RenameRefactoringTest extends RefactoringTest {
@override
- RenameRefactoring refactoring;
+ late RenameRefactoring refactoring;
/// Asserts that [refactoring] has potential edits in [testFile] at offset
/// of the given [searches].
@@ -52,13 +50,17 @@
/// Creates a new [RenameRefactoring] in [refactoring] for [element].
/// Fails if no [RenameRefactoring] can be created.
- void createRenameRefactoringForElement(Element element) {
+ void createRenameRefactoringForElement(Element? element) {
var workspace = RefactoringWorkspace(
[driverFor(testFile)],
searchEngine,
);
- refactoring = RenameRefactoring(workspace, testAnalysisResult, element);
- expect(refactoring, isNotNull, reason: "No refactoring for '$element'.");
+ var refactoring =
+ RenameRefactoring.create(workspace, testAnalysisResult, element);
+ if (refactoring == null) {
+ fail("No refactoring for '$element'.");
+ }
+ this.refactoring = refactoring;
}
/// Returns the [Edit] with the given [id], maybe `null`.
@@ -70,6 +72,6 @@
}
}
}
- return null;
+ fail('No edit with id: $id');
}
}
diff --git a/pkg/analysis_server/test/services/refactoring/convert_getter_to_method_test.dart b/pkg/analysis_server/test/services/refactoring/convert_getter_to_method_test.dart
index ff2de57..b8cc8eb 100644
--- a/pkg/analysis_server/test/services/refactoring/convert_getter_to_method_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/convert_getter_to_method_test.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:analysis_server/src/services/refactoring/refactoring.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart' hide ElementKind;
@@ -20,7 +18,7 @@
@reflectiveTest
class ConvertGetterToMethodTest extends RefactoringTest {
@override
- ConvertGetterToMethodRefactoring refactoring;
+ late ConvertGetterToMethodRefactoring refactoring;
Future<void> test_change_function() async {
await indexTestUnit('''
@@ -149,7 +147,7 @@
assertTestChangeResult(expectedCode);
}
- void _createRefactoringForElement(ExecutableElement element) {
+ void _createRefactoringForElement(PropertyAccessorElement element) {
refactoring = ConvertGetterToMethodRefactoring(
searchEngine, testAnalysisResult.session, element);
}
diff --git a/pkg/analysis_server/test/services/refactoring/convert_method_to_getter_test.dart b/pkg/analysis_server/test/services/refactoring/convert_method_to_getter_test.dart
index d7434390..c95f9e0 100644
--- a/pkg/analysis_server/test/services/refactoring/convert_method_to_getter_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/convert_method_to_getter_test.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:analysis_server/src/services/refactoring/refactoring.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart'
@@ -21,7 +19,7 @@
@reflectiveTest
class ConvertMethodToGetterTest extends RefactoringTest {
@override
- ConvertMethodToGetterRefactoring refactoring;
+ late ConvertMethodToGetterRefactoring refactoring;
Future<void> test_change_function() async {
await indexTestUnit('''
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 215745e..bbe2a84 100644
--- a/pkg/analysis_server/test/services/refactoring/extract_local_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/extract_local_test.dart
@@ -2,13 +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.
-// @dart = 2.9
-
import 'dart:convert';
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';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -24,7 +21,7 @@
@reflectiveTest
class ExtractLocalTest extends RefactoringTest {
@override
- ExtractLocalRefactoringImpl refactoring;
+ late ExtractLocalRefactoringImpl refactoring;
Future<void> test_checkFinalConditions_sameVariable_after() async {
await indexTestUnit('''
@@ -196,11 +193,6 @@
''');
_createRefactoringForString('1 + 2');
expect(refactoring.refactoringName, 'Extract Local Variable');
- // null
- refactoring.name = null;
- assertRefactoringStatus(
- refactoring.checkName(), RefactoringProblemSeverity.FATAL,
- expectedMessage: 'Variable name must not be null.');
// empty
refactoring.name = '';
assertRefactoringStatus(
@@ -1365,8 +1357,11 @@
'Expression must be selected to activate this refactoring.');
}
- void _assertSingleLinkedEditGroup(
- {int length, List<int> offsets, List<String> names}) {
+ void _assertSingleLinkedEditGroup({
+ required int length,
+ required List<int> offsets,
+ required List<String> names,
+ }) {
var positions =
offsets.map((offset) => {'file': testFile, 'offset': offset});
var suggestions = names.map((name) => {'value': name, 'kind': 'VARIABLE'});
@@ -1394,7 +1389,8 @@
}
void _createRefactoring(int offset, int length) {
- refactoring = ExtractLocalRefactoring(testAnalysisResult, offset, length);
+ refactoring =
+ ExtractLocalRefactoringImpl(testAnalysisResult, offset, length);
refactoring.name = 'res';
}
diff --git a/pkg/analysis_server/test/services/refactoring/extract_method_test.dart b/pkg/analysis_server/test/services/refactoring/extract_method_test.dart
index 06b2131..fec1997 100644
--- a/pkg/analysis_server/test/services/refactoring/extract_method_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/extract_method_test.dart
@@ -2,10 +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.
-// @dart = 2.9
-
import 'package:analysis_server/src/services/refactoring/extract_method.dart';
-import 'package:analysis_server/src/services/refactoring/refactoring.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -21,7 +18,7 @@
@reflectiveTest
class ExtractMethodTest extends RefactoringTest {
@override
- ExtractMethodRefactoringImpl refactoring;
+ late ExtractMethodRefactoringImpl refactoring;
Future<void> test_bad_assignmentLeftHandSide() async {
await indexTestUnit('''
@@ -791,11 +788,6 @@
}
''');
_createRefactoringForString('1 + 2');
- // null
- refactoring.name = null;
- assertRefactoringStatus(
- refactoring.checkName(), RefactoringProblemSeverity.FATAL,
- expectedMessage: 'Method name must not be null.');
// empty
refactoring.name = '';
assertRefactoringStatus(
@@ -2919,7 +2911,7 @@
}
void _createRefactoring(int offset, int length) {
- refactoring = ExtractMethodRefactoring(
+ refactoring = ExtractMethodRefactoringImpl(
searchEngine, testAnalysisResult, offset, length);
refactoring.name = 'res';
}
diff --git a/pkg/analysis_server/test/services/refactoring/extract_widget_test.dart b/pkg/analysis_server/test/services/refactoring/extract_widget_test.dart
index 8ceaf78..6106c93 100644
--- a/pkg/analysis_server/test/services/refactoring/extract_widget_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/extract_widget_test.dart
@@ -2,10 +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.
-// @dart = 2.9
-
import 'package:analysis_server/src/services/refactoring/extract_widget.dart';
-import 'package:analysis_server/src/services/refactoring/refactoring.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -21,7 +18,7 @@
@reflectiveTest
class ExtractWidgetTest extends RefactoringTest {
@override
- ExtractWidgetRefactoringImpl refactoring;
+ late ExtractWidgetRefactoringImpl refactoring;
@override
void setUp() {
@@ -55,12 +52,6 @@
''');
_createRefactoringForStringOffset('new Text');
- // null
- refactoring.name = null;
- assertRefactoringStatus(
- refactoring.checkName(), RefactoringProblemSeverity.FATAL,
- expectedMessage: 'Class name must not be null.');
-
// empty
refactoring.name = '';
assertRefactoringStatus(
@@ -1232,7 +1223,7 @@
}
void _createRefactoring(int offset, int length) {
- refactoring = ExtractWidgetRefactoring(
+ refactoring = ExtractWidgetRefactoringImpl(
searchEngine, testAnalysisResult, offset, length);
refactoring.name = 'Test';
}
diff --git a/pkg/analysis_server/test/services/refactoring/inline_local_test.dart b/pkg/analysis_server/test/services/refactoring/inline_local_test.dart
index 80920b8..1285872 100644
--- a/pkg/analysis_server/test/services/refactoring/inline_local_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/inline_local_test.dart
@@ -2,11 +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.
-// @dart = 2.9
-
import 'package:analysis_server/src/services/correction/status.dart';
import 'package:analysis_server/src/services/refactoring/inline_local.dart';
-import 'package:analysis_server/src/services/refactoring/refactoring.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart' hide Element;
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -22,7 +19,7 @@
@reflectiveTest
class InlineLocalTest extends RefactoringTest {
@override
- InlineLocalRefactoringImpl refactoring;
+ late InlineLocalRefactoringImpl refactoring;
Future<void> test_access() async {
await indexTestUnit('''
@@ -639,7 +636,7 @@
void _createRefactoring(String search) {
var offset = findOffset(search);
- refactoring = InlineLocalRefactoring(
+ refactoring = InlineLocalRefactoringImpl(
searchEngine,
testAnalysisResult,
offset,
diff --git a/pkg/analysis_server/test/services/refactoring/inline_method_test.dart b/pkg/analysis_server/test/services/refactoring/inline_method_test.dart
index 204df5c..281b5f0 100644
--- a/pkg/analysis_server/test/services/refactoring/inline_method_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/inline_method_test.dart
@@ -2,10 +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.
-// @dart = 2.9
-
import 'package:analysis_server/src/services/refactoring/inline_method.dart';
-import 'package:analysis_server/src/services/refactoring/refactoring.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart' hide Element;
import 'package:test/test.dart';
@@ -22,9 +19,9 @@
@reflectiveTest
class InlineMethodTest extends RefactoringTest {
@override
- InlineMethodRefactoringImpl refactoring;
- bool deleteSource;
- bool inlineAll;
+ late InlineMethodRefactoringImpl refactoring;
+ bool? deleteSource;
+ bool? inlineAll;
Future<void> test_access_FunctionElement() async {
await indexTestUnit(r'''
@@ -1763,9 +1760,11 @@
var status = await refactoring.checkInitialConditions();
assertRefactoringStatusOK(status);
// configure
+ var deleteSource = this.deleteSource;
if (deleteSource != null) {
refactoring.deleteSource = deleteSource;
}
+ var inlineAll = this.inlineAll;
if (inlineAll != null) {
refactoring.inlineAll = inlineAll;
}
@@ -1780,7 +1779,7 @@
void _createRefactoring(String search) {
var offset = findOffset(search);
- refactoring = InlineMethodRefactoring(
+ refactoring = InlineMethodRefactoringImpl(
searchEngine,
testAnalysisResult,
offset,
diff --git a/pkg/analysis_server/test/services/refactoring/move_file_test.dart b/pkg/analysis_server/test/services/refactoring/move_file_test.dart
index 8d8fa21..ad4b7ef 100644
--- a/pkg/analysis_server/test/services/refactoring/move_file_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/move_file_test.dart
@@ -2,10 +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.
-// @dart = 2.9
-
import 'package:analysis_server/src/protocol_server.dart';
import 'package:analysis_server/src/services/refactoring/refactoring.dart';
+import 'package:analyzer/dart/analysis/results.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -20,7 +19,7 @@
@reflectiveTest
class MoveFileTest extends RefactoringTest {
@override
- MoveFileRefactoring refactoring;
+ late MoveFileRefactoring refactoring;
Future<void> test_file_containing_imports_exports_parts() async {
var pathA = convertPath('/home/test/000/1111/a.dart');
@@ -67,7 +66,8 @@
// Since the file being refactored isn't the test source, we set the
// testAnalysisResult manually here, the path is referenced through the
// referenced File object to run on Windows:
- testAnalysisResult = await session.getResolvedUnit(file.path);
+ testAnalysisResult =
+ await session.getResolvedUnit2(file.path) as ResolvedUnitResult;
_createRefactoring('/home/test/lib/222/new_name.dart', oldFile: file.path);
await _assertSuccessfulRefactoring();
@@ -89,7 +89,8 @@
// Since the file being refactored isn't the test source, we set the
// testAnalysisResult manually here, the path is referenced through the
// referenced File object to run on Windows:
- testAnalysisResult = await session.getResolvedUnit(file.path);
+ testAnalysisResult =
+ await session.getResolvedUnit2(file.path) as ResolvedUnitResult;
_createRefactoring('/home/test0/test1/test3/lib/111/name.dart',
oldFile: file.path);
@@ -112,7 +113,8 @@
// Since the file being refactored isn't the test source, we set the
// testAnalysisResult manually here, the path is referenced through the
// referenced File object to run on Windows:
- testAnalysisResult = await session.getResolvedUnit(file.path);
+ testAnalysisResult =
+ await session.getResolvedUnit2(file.path) as ResolvedUnitResult;
_createRefactoring('/home/test0/test1/test2/test3/lib/111/name.dart',
oldFile: file.path);
@@ -135,7 +137,8 @@
// Since the file being refactored isn't the test source, we set the
// testAnalysisResult manually here, the path is referenced through the
// referenced File object to run on Windows:
- testAnalysisResult = await session.getResolvedUnit(file.path);
+ testAnalysisResult =
+ await session.getResolvedUnit2(file.path) as ResolvedUnitResult;
_createRefactoring('/home/test0/test1/lib/111/name.dart',
oldFile: file.path);
@@ -156,7 +159,8 @@
// Since the file being refactored isn't the test source, we set the
// testAnalysisResult manually here, the path is referenced through the
// referenced File object to run on Windows:
- testAnalysisResult = await session.getResolvedUnit(file.path);
+ testAnalysisResult =
+ await session.getResolvedUnit2(file.path) as ResolvedUnitResult;
_createRefactoring('/home/test/lib/222/new_name.dart', oldFile: file.path);
await _assertSuccessfulRefactoring();
@@ -176,7 +180,8 @@
// Since the file being refactored isn't the test source, we set the
// testAnalysisResult manually here, the path is referenced through the
// referenced File object to run on Windows:
- testAnalysisResult = await session.getResolvedUnit(file.path);
+ testAnalysisResult =
+ await session.getResolvedUnit2(file.path) as ResolvedUnitResult;
_createRefactoring('/home/test/lib/new_name.dart', oldFile: file.path);
await _assertSuccessfulRefactoring();
@@ -492,7 +497,7 @@
}
Future _assertFailedRefactoring(RefactoringProblemSeverity expectedSeverity,
- {String expectedMessage}) async {
+ {String? expectedMessage}) async {
var status = await refactoring.checkAllConditions();
assertRefactoringStatus(status, expectedSeverity,
expectedMessage: expectedMessage);
@@ -504,7 +509,7 @@
refactoringChange = await refactoring.createChange();
}
- void _createRefactoring(String newFile, {String oldFile}) {
+ void _createRefactoring(String newFile, {String? oldFile}) {
var refactoringWorkspace =
RefactoringWorkspace([driverFor(testFile)], searchEngine);
// Allow passing an oldName for when we don't want to rename testSource,
diff --git a/pkg/analysis_server/test/services/refactoring/naming_conventions_test.dart b/pkg/analysis_server/test/services/refactoring/naming_conventions_test.dart
index 810ec9b..8441368 100644
--- a/pkg/analysis_server/test/services/refactoring/naming_conventions_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/naming_conventions_test.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:analysis_server/src/services/correction/status.dart';
import 'package:analysis_server/src/services/refactoring/naming_conventions.dart';
import 'package:analysis_server/src/services/refactoring/refactoring.dart';
@@ -22,7 +20,7 @@
@reflectiveTest
class NamingConventionsTest extends RefactoringTest {
@override
- Refactoring get refactoring => null;
+ Refactoring get refactoring => throw UnimplementedError();
void test_validateClassName_doesNotStartWithLowerCase() {
assertRefactoringStatus(
@@ -60,12 +58,6 @@
expectedMessage: 'Class name should start with an uppercase letter.');
}
- void test_validateClassName_null() {
- assertRefactoringStatus(
- validateClassName(null), RefactoringProblemSeverity.FATAL,
- expectedMessage: 'Class name must not be null.');
- }
-
void test_validateClassName_OK() {
assertRefactoringStatusOK(validateClassName('NewName'));
}
@@ -177,12 +169,6 @@
'Field name must begin with a lowercase letter or underscore.');
}
- void test_validateFieldName_null() {
- assertRefactoringStatus(
- validateFieldName(null), RefactoringProblemSeverity.FATAL,
- expectedMessage: 'Field name must not be null.');
- }
-
void test_validateFieldName_OK() {
assertRefactoringStatusOK(validateFieldName('newName'));
}
@@ -242,12 +228,6 @@
'Function name must begin with a lowercase letter or underscore.');
}
- void test_validateFunctionName_null() {
- assertRefactoringStatus(
- validateFunctionName(null), RefactoringProblemSeverity.FATAL,
- expectedMessage: 'Function name must not be null.');
- }
-
void test_validateFunctionName_OK() {
assertRefactoringStatusOK(validateFunctionName('newName'));
}
@@ -375,12 +355,6 @@
'Label name must begin with a lowercase letter or underscore.');
}
- void test_validateLabelName_null() {
- assertRefactoringStatus(
- validateLabelName(null), RefactoringProblemSeverity.FATAL,
- expectedMessage: 'Label name must not be null.');
- }
-
void test_validateLabelName_OK() {
assertRefactoringStatusOK(validateLabelName('newName'));
}
@@ -517,12 +491,6 @@
'Method name must begin with a lowercase letter or underscore.');
}
- void test_validateMethodName_null() {
- assertRefactoringStatus(
- validateMethodName(null), RefactoringProblemSeverity.FATAL,
- expectedMessage: 'Method name must not be null.');
- }
-
void test_validateMethodName_OK() {
assertRefactoringStatusOK(validateMethodName('newName'));
}
@@ -587,12 +555,6 @@
'Parameter name must begin with a lowercase letter or underscore.');
}
- void test_validateParameterName_null() {
- assertRefactoringStatus(
- validateParameterName(null), RefactoringProblemSeverity.FATAL,
- expectedMessage: 'Parameter name must not be null.');
- }
-
void test_validateParameterName_OK() {
assertRefactoringStatusOK(validateParameterName('newName'));
}
@@ -653,12 +615,6 @@
'Type alias name should start with an uppercase letter.');
}
- void test_validateTypeAliasName_null() {
- assertRefactoringStatus(
- validateTypeAliasName(null), RefactoringProblemSeverity.FATAL,
- expectedMessage: 'Type alias name must not be null.');
- }
-
void test_validateTypeAliasName_OK() {
assertRefactoringStatusOK(validateTypeAliasName('NewName'));
}
@@ -722,12 +678,6 @@
'Variable name must begin with a lowercase letter or underscore.');
}
- void test_validateVariableName_null() {
- assertRefactoringStatus(
- validateVariableName(null), RefactoringProblemSeverity.FATAL,
- expectedMessage: 'Variable name must not be null.');
- }
-
void test_validateVariableName_OK() {
assertRefactoringStatusOK(validateVariableName('newName'));
}
diff --git a/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart b/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart
index 47a6c12..74a2fee 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:test/test.dart';
@@ -441,11 +439,6 @@
}
''');
createRenameRefactoringAtString('test = 0;');
- // null
- refactoring.newName = null;
- assertRefactoringStatus(
- refactoring.checkNewName(), RefactoringProblemSeverity.FATAL,
- expectedMessage: 'Field name must not be null.');
// OK
refactoring.newName = 'newName';
assertRefactoringStatusOK(refactoring.checkNewName());
@@ -458,11 +451,6 @@
}
''');
createRenameRefactoringAtString('test() {}');
- // null
- refactoring.newName = null;
- assertRefactoringStatus(
- refactoring.checkNewName(), RefactoringProblemSeverity.FATAL,
- expectedMessage: 'Method name must not be null.');
// empty
refactoring.newName = '';
assertRefactoringStatus(
diff --git a/pkg/analysis_server/test/services/refactoring/rename_constructor_test.dart b/pkg/analysis_server/test/services/refactoring/rename_constructor_test.dart
index 2cb9270..97c6102 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_constructor_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_constructor_test.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:analysis_server/src/services/refactoring/refactoring.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:test/test.dart';
@@ -42,11 +40,6 @@
''');
createRenameRefactoringAtString('test() {}');
expect(refactoring.oldName, 'test');
- // null
- refactoring.newName = null;
- assertRefactoringStatus(
- refactoring.checkNewName(), RefactoringProblemSeverity.FATAL,
- expectedMessage: 'Constructor name must not be null.');
// same
refactoring.newName = 'test';
assertRefactoringStatus(
@@ -239,7 +232,8 @@
Future<void> test_newInstance_nullElement() async {
await indexTestUnit('');
var workspace = RefactoringWorkspace([driverFor(testFile)], searchEngine);
- var refactoring = RenameRefactoring(workspace, testAnalysisResult, null);
+ var refactoring =
+ RenameRefactoring.create(workspace, testAnalysisResult, null);
expect(refactoring, isNull);
}
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
index 36f2bc3..b7e3770 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_extension_member_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_extension_member_test.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -139,12 +137,12 @@
}
''');
createRenameRefactoringAtString('test =>');
- // null
- refactoring.newName = null;
+ // empty
+ refactoring.newName = '';
assertRefactoringStatus(
refactoring.checkNewName(),
RefactoringProblemSeverity.FATAL,
- expectedMessage: 'Field name must not be null.',
+ expectedMessage: 'Field name must not be empty.',
);
// OK
@@ -160,14 +158,6 @@
''');
createRenameRefactoringAtString('test() {}');
- // null
- refactoring.newName = null;
- assertRefactoringStatus(
- refactoring.checkNewName(),
- RefactoringProblemSeverity.FATAL,
- expectedMessage: 'Method name must not be null.',
- );
-
// empty
refactoring.newName = '';
assertRefactoringStatus(
diff --git a/pkg/analysis_server/test/services/refactoring/rename_import_test.dart b/pkg/analysis_server/test/services/refactoring/rename_import_test.dart
index 0e90484..998fc74 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_import_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_import_test.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -22,11 +20,6 @@
await indexTestUnit("import 'dart:async' as test;");
_createRefactoring("import 'dart:");
expect(refactoring.oldName, 'test');
- // null
- refactoring.newName = null;
- assertRefactoringStatus(
- refactoring.checkNewName(), RefactoringProblemSeverity.FATAL,
- expectedMessage: 'Import prefix name must not be null.');
// same
refactoring.newName = 'test';
assertRefactoringStatus(
@@ -41,6 +34,22 @@
assertRefactoringStatusOK(refactoring.checkNewName());
}
+ Future<void> test_checkNewName_sameName_empty() async {
+ await indexTestUnit('''
+import 'dart:math';
+void f(Random r) {}
+''');
+
+ _createRefactoring("import 'dart:math");
+
+ refactoring.newName = '';
+ assertRefactoringStatus(
+ refactoring.checkNewName(),
+ RefactoringProblemSeverity.FATAL,
+ expectedMessage: 'The new name must be different than the current name.',
+ );
+ }
+
Future<void> test_createChange_add() async {
await indexTestUnit('''
import 'dart:async';
diff --git a/pkg/analysis_server/test/services/refactoring/rename_label_test.dart b/pkg/analysis_server/test/services/refactoring/rename_label_test.dart
index 98f5cb9..3c824f2 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_label_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_label_test.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -28,11 +26,6 @@
}
''');
createRenameRefactoringAtString('test:');
- // null
- refactoring.newName = null;
- assertRefactoringStatus(
- refactoring.checkNewName(), RefactoringProblemSeverity.FATAL,
- expectedMessage: 'Label name must not be null.');
// empty
refactoring.newName = '';
assertRefactoringStatus(
diff --git a/pkg/analysis_server/test/services/refactoring/rename_library_test.dart b/pkg/analysis_server/test/services/refactoring/rename_library_test.dart
index 3b22091..2f37e06 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_library_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_library_test.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -23,11 +21,6 @@
library my.app;
''');
_createRenameRefactoring();
- // null
- refactoring.newName = null;
- assertRefactoringStatus(
- refactoring.checkNewName(), RefactoringProblemSeverity.FATAL,
- expectedMessage: 'Library name must not be null.');
// empty
refactoring.newName = '';
assertRefactoringStatus(
diff --git a/pkg/analysis_server/test/services/refactoring/rename_local_test.dart b/pkg/analysis_server/test/services/refactoring/rename_local_test.dart
index c620f97..c0ea209 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_local_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_local_test.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -242,11 +240,11 @@
}
''');
createRenameRefactoringAtString('test() => 0;');
- // null
- refactoring.newName = null;
+ // empty
+ refactoring.newName = '';
assertRefactoringStatus(
refactoring.checkNewName(), RefactoringProblemSeverity.FATAL,
- expectedMessage: 'Function name must not be null.');
+ expectedMessage: 'Function name must not be empty.');
// OK
refactoring.newName = 'newName';
assertRefactoringStatusOK(refactoring.checkNewName());
@@ -259,11 +257,6 @@
}
''');
createRenameRefactoringAtString('test = 0;');
- // null
- refactoring.newName = null;
- assertRefactoringStatus(
- refactoring.checkNewName(), RefactoringProblemSeverity.FATAL,
- expectedMessage: 'Variable name must not be null.');
// empty
refactoring.newName = '';
assertRefactoringStatus(
@@ -280,11 +273,11 @@
}
''');
createRenameRefactoringAtString('test) {');
- // null
- refactoring.newName = null;
+ // empty
+ refactoring.newName = '';
assertRefactoringStatus(
refactoring.checkNewName(), RefactoringProblemSeverity.FATAL,
- expectedMessage: 'Parameter name must not be null.');
+ expectedMessage: 'Parameter name must not be empty.');
// OK
refactoring.newName = 'newName';
assertRefactoringStatusOK(refactoring.checkNewName());
diff --git a/pkg/analysis_server/test/services/refactoring/rename_unit_member_test.dart b/pkg/analysis_server/test/services/refactoring/rename_unit_member_test.dart
index 84b916e..a3dcbb8 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_unit_member_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_unit_member_test.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -267,11 +265,6 @@
class Test {}
''');
createRenameRefactoringAtString('Test {}');
- // null
- refactoring.newName = null;
- assertRefactoringStatus(
- refactoring.checkNewName(), RefactoringProblemSeverity.FATAL,
- expectedMessage: 'Class name must not be null.');
// empty
refactoring.newName = '';
assertRefactoringStatus(
@@ -293,11 +286,6 @@
test() {}
''');
createRenameRefactoringAtString('test() {}');
- // null
- refactoring.newName = null;
- assertRefactoringStatus(
- refactoring.checkNewName(), RefactoringProblemSeverity.FATAL,
- expectedMessage: 'Function name must not be null.');
// empty
refactoring.newName = '';
assertRefactoringStatus(
@@ -313,11 +301,6 @@
var test;
''');
createRenameRefactoringAtString('test;');
- // null
- refactoring.newName = null;
- assertRefactoringStatus(
- refactoring.checkNewName(), RefactoringProblemSeverity.FATAL,
- expectedMessage: 'Variable name must not be null.');
// empty
refactoring.newName = '';
assertRefactoringStatus(
@@ -333,11 +316,11 @@
typedef Test = void Function();
''');
createRenameRefactoringAtString('Test =');
- // null
- refactoring.newName = null;
+ // empty
+ refactoring.newName = '';
assertRefactoringStatus(
refactoring.checkNewName(), RefactoringProblemSeverity.FATAL,
- expectedMessage: 'Type alias name must not be null.');
+ expectedMessage: 'Type alias name must not be empty.');
// OK
refactoring.newName = 'NewName';
assertRefactoringStatusOK(refactoring.checkNewName());
@@ -348,11 +331,11 @@
typedef Test = List<int>;
''');
createRenameRefactoringAtString('Test =');
- // null
- refactoring.newName = null;
+ // empty
+ refactoring.newName = '';
assertRefactoringStatus(
refactoring.checkNewName(), RefactoringProblemSeverity.FATAL,
- expectedMessage: 'Type alias name must not be null.');
+ expectedMessage: 'Type alias name must not be empty.');
// OK
refactoring.newName = 'NewName';
assertRefactoringStatusOK(refactoring.checkNewName());
@@ -363,11 +346,11 @@
typedef Test();
''');
createRenameRefactoringAtString('Test();');
- // null
- refactoring.newName = null;
+ // empty
+ refactoring.newName = '';
assertRefactoringStatus(
refactoring.checkNewName(), RefactoringProblemSeverity.FATAL,
- expectedMessage: 'Type alias name must not be null.');
+ expectedMessage: 'Type alias name must not be empty.');
// OK
refactoring.newName = 'NewName';
assertRefactoringStatusOK(refactoring.checkNewName());
diff --git a/pkg/analysis_server/test/services/refactoring/test_all.dart b/pkg/analysis_server/test/services/refactoring/test_all.dart
index 9dc8a8e..d48e879 100644
--- a/pkg/analysis_server/test/services/refactoring/test_all.dart
+++ b/pkg/analysis_server/test/services/refactoring/test_all.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'convert_getter_to_method_test.dart' as convert_getter_to_method_test;
diff --git a/pkg/analysis_server/test/services/search/search_engine_test.dart b/pkg/analysis_server/test/services/search/search_engine_test.dart
index 664c8fd..a352332 100644
--- a/pkg/analysis_server/test/services/search/search_engine_test.dart
+++ b/pkg/analysis_server/test/services/search/search_engine_test.dart
@@ -427,7 +427,7 @@
var contextRoot = driver.analysisContext!.contextRoot;
for (var file in contextRoot.analyzedFiles()) {
if (file.endsWith('.dart')) {
- await driver.getUnitElement(file);
+ await driver.getUnitElement2(file);
}
}
}
diff --git a/pkg/analysis_server/test/src/cider/completion_test.dart b/pkg/analysis_server/test/src/cider/completion_test.dart
index 5e15e31..d96e72b 100644
--- a/pkg/analysis_server/test/src/cider/completion_test.dart
+++ b/pkg/analysis_server/test/src/cider/completion_test.dart
@@ -500,8 +500,7 @@
''');
_assertHasClass(text: 'int');
- // TODO(scheglov) would be nice to have it
- _assertNoClass(text: 'A');
+ _assertHasClass(text: 'A');
}
Future<void> test_limitedResolution_inPart_partOfUri() async {
diff --git a/pkg/analysis_server/test/src/computer/closing_labels_computer_test.dart b/pkg/analysis_server/test/src/computer/closing_labels_computer_test.dart
index c79006b..eff0c79 100644
--- a/pkg/analysis_server/test/src/computer/closing_labels_computer_test.dart
+++ b/pkg/analysis_server/test/src/computer/closing_labels_computer_test.dart
@@ -4,6 +4,7 @@
import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analysis_server/src/computer/computer_closingLabels.dart';
+import 'package:analyzer/dart/analysis/results.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -396,7 +397,8 @@
Future<List<ClosingLabel>> _computeElements(String sourceContent) async {
newFile(sourcePath, content: sourceContent);
- var result = await session.getResolvedUnit(sourcePath);
+ var result =
+ await session.getResolvedUnit2(sourcePath) as ResolvedUnitResult;
var computer = DartUnitClosingLabelsComputer(result.lineInfo, result.unit!);
return computer.compute();
}
diff --git a/pkg/analysis_server/test/src/computer/folding_computer_test.dart b/pkg/analysis_server/test/src/computer/folding_computer_test.dart
index 2ef0286..94372c5 100644
--- a/pkg/analysis_server/test/src/computer/folding_computer_test.dart
+++ b/pkg/analysis_server/test/src/computer/folding_computer_test.dart
@@ -4,6 +4,7 @@
import 'package:analysis_server/src/computer/computer_folding.dart';
import 'package:analysis_server/src/protocol_server.dart';
+import 'package:analyzer/dart/analysis/results.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -555,7 +556,8 @@
Future<List<FoldingRegion>> _computeRegions(String sourceContent) async {
newFile(sourcePath, content: sourceContent);
- var result = await session.getResolvedUnit(sourcePath);
+ var result =
+ await session.getResolvedUnit2(sourcePath) as ResolvedUnitResult;
var computer = DartUnitFoldingComputer(result.lineInfo, result.unit!);
return 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 08682eb..2012268 100644
--- a/pkg/analysis_server/test/src/computer/highlights_computer_test.dart
+++ b/pkg/analysis_server/test/src/computer/highlights_computer_test.dart
@@ -4,6 +4,7 @@
import 'package:analysis_server/src/computer/computer_highlights.dart';
import 'package:analysis_server/src/protocol_server.dart';
+import 'package:analyzer/dart/analysis/results.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -112,7 +113,8 @@
}) async {
this.content = content;
newFile(sourcePath, content: content);
- var result = await session.getResolvedUnit(sourcePath);
+ var result =
+ await session.getResolvedUnit2(sourcePath) as ResolvedUnitResult;
if (hasErrors) {
expect(result.errors, isNotEmpty);
diff --git a/pkg/analysis_server/test/src/computer/import_elements_computer_test.dart b/pkg/analysis_server/test/src/computer/import_elements_computer_test.dart
index 19bb89e..ebdde35 100644
--- a/pkg/analysis_server/test/src/computer/import_elements_computer_test.dart
+++ b/pkg/analysis_server/test/src/computer/import_elements_computer_test.dart
@@ -4,6 +4,7 @@
import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analysis_server/src/computer/import_elements_computer.dart';
+import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/src/test_utilities/package_config_file_builder.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:test/test.dart';
@@ -49,7 +50,7 @@
Future<void> createBuilder(String content) async {
originalContent = content;
newFile(path, content: content);
- var result = await session.getResolvedUnit(path);
+ var result = await session.getResolvedUnit2(path) as ResolvedUnitResult;
computer = ImportElementsComputer(resourceProvider, result);
}
diff --git a/pkg/analysis_server/test/src/computer/imported_elements_computer_test.dart b/pkg/analysis_server/test/src/computer/imported_elements_computer_test.dart
index 9f55abb..7057898 100644
--- a/pkg/analysis_server/test/src/computer/imported_elements_computer_test.dart
+++ b/pkg/analysis_server/test/src/computer/imported_elements_computer_test.dart
@@ -6,6 +6,7 @@
import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analysis_server/src/computer/imported_elements_computer.dart';
+import 'package:analyzer/dart/analysis/results.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -471,7 +472,8 @@
Future<void> _computeElements(String content, String selection) async {
// TODO(brianwilkerson) Automatically extract the selection from the content.
newFile(sourcePath, content: content);
- var result = await session.getResolvedUnit(sourcePath);
+ var result =
+ await session.getResolvedUnit2(sourcePath) as ResolvedUnitResult;
var computer = ImportedElementsComputer(
result.unit, content.indexOf(selection), selection.length);
importedElements = computer.compute();
diff --git a/pkg/analysis_server/test/src/computer/outline_computer_test.dart b/pkg/analysis_server/test/src/computer/outline_computer_test.dart
index 08abb6d..da4b72a 100644
--- a/pkg/analysis_server/test/src/computer/outline_computer_test.dart
+++ b/pkg/analysis_server/test/src/computer/outline_computer_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/computer/computer_outline.dart';
+import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -30,7 +31,8 @@
Future<Outline> _computeOutline(String code) async {
testCode = code;
newFile(testPath, content: code);
- var resolveResult = await session.getResolvedUnit(testPath);
+ var resolveResult =
+ await session.getResolvedUnit2(testPath) as ResolvedUnitResult;
return DartUnitOutlineComputer(
resolveResult,
withBasicFlutter: true,
diff --git a/pkg/analysis_server/test/src/flutter/flutter_outline_computer_test.dart b/pkg/analysis_server/test/src/flutter/flutter_outline_computer_test.dart
index cad89c1..1cd6ba2 100644
--- a/pkg/analysis_server/test/src/flutter/flutter_outline_computer_test.dart
+++ b/pkg/analysis_server/test/src/flutter/flutter_outline_computer_test.dart
@@ -516,7 +516,8 @@
Future<FlutterOutline> _computeOutline(String code) async {
testCode = code;
newFile(testPath, content: code);
- resolveResult = await session.getResolvedUnit(testPath);
+ resolveResult =
+ await session.getResolvedUnit2(testPath) as ResolvedUnitResult;
computer = FlutterOutlineComputer(resolveResult);
return computer.compute();
}
diff --git a/pkg/analysis_server/test/src/services/completion/yaml/pubspec_generator_test.dart b/pkg/analysis_server/test/src/services/completion/yaml/pubspec_generator_test.dart
index 3df9b93..4f4923f 100644
--- a/pkg/analysis_server/test/src/services/completion/yaml/pubspec_generator_test.dart
+++ b/pkg/analysis_server/test/src/services/completion/yaml/pubspec_generator_test.dart
@@ -50,6 +50,17 @@
assertSuggestion('name: ');
}
+ void test_emptyPreviousSibling() {
+ // Ensure handling of nulls does not pick up nulls from previous siblings
+ getCompletions('''
+flutter:
+ assets:
+ fonts:
+ ^
+''');
+ assertSuggestion('family: ');
+ }
+
void test_environment() {
getCompletions('''
environment:
@@ -279,6 +290,8 @@
}
void test_packageName() async {
+ /// Sample package name list JSON in the same format as the API:
+ /// https://pub.dev/api/package-name-completion-data
const samplePackageList = '''
{ "packages": ["one", "two", "three"] }
''';
diff --git a/pkg/analysis_server/test/stress/completion/completion_runner.dart b/pkg/analysis_server/test/stress/completion/completion_runner.dart
index 4a5cf3b..542d8fe 100644
--- a/pkg/analysis_server/test/stress/completion/completion_runner.dart
+++ b/pkg/analysis_server/test/stress/completion/completion_runner.dart
@@ -7,6 +7,7 @@
import 'package:analysis_server/src/services/completion/dart/completion_manager.dart';
import 'package:analysis_server/src/utilities/null_string_sink.dart';
import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
+import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/file_system/overlay_file_system.dart';
@@ -79,7 +80,8 @@
}
fileCount++;
output.write('.');
- var result = await context.currentSession.getResolvedUnit(path);
+ var result = await context.currentSession.getResolvedUnit2(path)
+ as ResolvedUnitResult;
var content = result.content!;
var lineInfo = result.lineInfo;
var identifiers = _identifiersIn(result.unit!);
@@ -92,7 +94,8 @@
content.substring(identifier.end);
resourceProvider.setOverlay(path,
content: modifiedContent, modificationStamp: stamp++);
- result = await context.currentSession.getResolvedUnit(path);
+ result = await context.currentSession.getResolvedUnit2(path)
+ as ResolvedUnitResult;
}
timer.start();
diff --git a/pkg/analysis_server/test/tool/lsp_spec/dart_test.dart b/pkg/analysis_server/test/tool/lsp_spec/dart_test.dart
index ea05eed..7ead849 100644
--- a/pkg/analysis_server/test/tool/lsp_spec/dart_test.dart
+++ b/pkg/analysis_server/test/tool/lsp_spec/dart_test.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:test/test.dart';
import '../../../tool/lsp_spec/typescript_parser.dart' as ast;
diff --git a/pkg/analysis_server/test/tool/lsp_spec/generated_classes_test.dart b/pkg/analysis_server/test/tool/lsp_spec/generated_classes_test.dart
index 3b034df..a506de9 100644
--- a/pkg/analysis_server/test/tool/lsp_spec/generated_classes_test.dart
+++ b/pkg/analysis_server/test/tool/lsp_spec/generated_classes_test.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:test/test.dart';
diff --git a/pkg/analysis_server/test/tool/lsp_spec/json_test.dart b/pkg/analysis_server/test/tool/lsp_spec/json_test.dart
index e0b9720..add3ab4 100644
--- a/pkg/analysis_server/test/tool/lsp_spec/json_test.dart
+++ b/pkg/analysis_server/test/tool/lsp_spec/json_test.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'dart:convert';
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
@@ -389,6 +387,10 @@
});
test('objects with lists can round-trip through to json and back', () {
+ final workspaceFolders = [
+ WorkspaceFolder(uri: '!uri1', name: '!name1'),
+ WorkspaceFolder(uri: '!uri2', name: '!name2'),
+ ];
final obj = InitializeParams(
processId: 1,
clientInfo:
@@ -396,21 +398,17 @@
rootPath: '!root',
capabilities: ClientCapabilities(),
trace: 'off',
- workspaceFolders: [
- WorkspaceFolder(uri: '!uri1', name: '!name1'),
- WorkspaceFolder(uri: '!uri2', name: '!name2'),
- ],
+ workspaceFolders: workspaceFolders,
);
final json = jsonEncode(obj);
final restoredObj = InitializeParams.fromJson(jsonDecode(json));
+ final restoredWorkspaceFolders = restoredObj.workspaceFolders!;
- expect(
- restoredObj.workspaceFolders, hasLength(obj.workspaceFolders.length));
- for (var i = 0; i < obj.workspaceFolders.length; i++) {
- expect(restoredObj.workspaceFolders[i].name,
- equals(obj.workspaceFolders[i].name));
- expect(restoredObj.workspaceFolders[i].uri,
- equals(obj.workspaceFolders[i].uri));
+ expect(restoredWorkspaceFolders, hasLength(workspaceFolders.length));
+ for (var i = 0; i < workspaceFolders.length; i++) {
+ expect(
+ restoredWorkspaceFolders[i].name, equals(workspaceFolders[i].name));
+ expect(restoredWorkspaceFolders[i].uri, equals(workspaceFolders[i].uri));
}
});
@@ -444,7 +442,7 @@
expect(restoredObj.documentChanges, equals(obj.documentChanges));
expect(restoredObj.changes, equals(obj.changes));
- expect(restoredObj.changes.keys, equals(obj.changes.keys));
- expect(restoredObj.changes.values, equals(obj.changes.values));
+ expect(restoredObj.changes!.keys, equals(obj.changes!.keys));
+ expect(restoredObj.changes!.values, equals(obj.changes!.values));
});
}
diff --git a/pkg/analysis_server/test/tool/lsp_spec/matchers.dart b/pkg/analysis_server/test/tool/lsp_spec/matchers.dart
index 8fa3f4f..a424ae1 100644
--- a/pkg/analysis_server/test/tool/lsp_spec/matchers.dart
+++ b/pkg/analysis_server/test/tool/lsp_spec/matchers.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:matcher/matcher.dart';
@@ -11,7 +9,7 @@
Matcher isArrayOf(Matcher matcher) => ArrayTypeMatcher(wrapMatcher(matcher));
-Matcher isLiteralOf(Matcher typeMatcher, Object value) =>
+Matcher isLiteralOf(Matcher typeMatcher, String value) =>
LiteralTypeMatcher(typeMatcher, value);
Matcher isMapOf(Matcher indexMatcher, Matcher valueMatcher) =>
diff --git a/pkg/analysis_server/test/tool/lsp_spec/test_all.dart b/pkg/analysis_server/test/tool/lsp_spec/test_all.dart
index 0b98b69..07a4247 100644
--- a/pkg/analysis_server/test/tool/lsp_spec/test_all.dart
+++ b/pkg/analysis_server/test/tool/lsp_spec/test_all.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'dart_test.dart' as dart_test;
diff --git a/pkg/analysis_server/test/tool/lsp_spec/typescript_test.dart b/pkg/analysis_server/test/tool/lsp_spec/typescript_test.dart
index 3c69370..2fbe495 100644
--- a/pkg/analysis_server/test/tool/lsp_spec/typescript_test.dart
+++ b/pkg/analysis_server/test/tool/lsp_spec/typescript_test.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:test/test.dart';
import '../../../tool/lsp_spec/typescript_parser.dart';
@@ -26,13 +24,13 @@
final output = parseString(input);
expect(output, hasLength(1));
expect(output[0], const TypeMatcher<Interface>());
- final Interface interface = output[0];
+ final interface = output[0] as Interface;
expect(interface.name, equals('SomeOptions'));
expect(interface.commentText, equals('Some options.'));
expect(interface.baseTypes, hasLength(0));
expect(interface.members, hasLength(1));
expect(interface.members[0], const TypeMatcher<Field>());
- final Field field = interface.members[0];
+ final field = interface.members[0] as Field;
expect(field.name, equals('options'));
expect(field.commentText, equals('''Options used by something.'''));
expect(field.allowsNull, isFalse);
@@ -54,11 +52,11 @@
// Check there was a full fabricarted interface for this type.
expect(output[0], const TypeMatcher<Interface>());
- Interface interface = output[0];
+ var interface = output[0] as Interface;
expect(interface.name, equals('CapabilitiesTextDoc'));
expect(interface.members, hasLength(1));
expect(interface.members[0], const TypeMatcher<Field>());
- Field field = interface.members[0];
+ var field = interface.members[0] as Field;
expect(field.name, equals('deprecated'));
expect(field.allowsNull, isFalse);
expect(field.allowsUndefined, isTrue);
@@ -66,11 +64,11 @@
expect(field.allowsUndefined, isTrue);
expect(output[1], const TypeMatcher<Interface>());
- interface = output[1];
+ interface = output[1] as Interface;
expect(interface.name, equals('Capabilities'));
expect(interface.members, hasLength(1));
expect(interface.members[0], const TypeMatcher<Field>());
- field = interface.members[0];
+ field = interface.members[0] as Field;
expect(field.name, equals('textDoc'));
expect(field.allowsNull, isFalse);
expect(field.type, isSimpleType('CapabilitiesTextDoc'));
@@ -92,11 +90,11 @@
final output = parseString(input);
expect(output, hasLength(1));
expect(output[0], const TypeMatcher<Interface>());
- final Interface interface = output[0];
+ final interface = output[0] as Interface;
expect(interface.members, hasLength(2));
[0, 1].forEach((i) {
expect(interface.members[i], const TypeMatcher<Field>());
- final Field field = interface.members[i];
+ final field = interface.members[i] as Field;
expect(field.name, equals('options$i'));
expect(field.commentText, equals('''Options$i used by something.'''));
});
@@ -111,9 +109,9 @@
final output = parseString(input);
expect(output, hasLength(1));
expect(output[0], const TypeMatcher<Interface>());
- final Interface interface = output[0];
+ final interface = output[0] as Interface;
expect(interface.members, hasLength(1));
- final Field field = interface.members.first;
+ final field = interface.members.first as Field;
expect(field, const TypeMatcher<Field>());
expect(field.name, equals('data'));
expect(field.allowsUndefined, isTrue);
@@ -133,16 +131,16 @@
final output = parseString(input);
expect(output, hasLength(1));
expect(output[0], const TypeMatcher<Interface>());
- final Interface interface = output[0];
+ final interface = output[0] as Interface;
expect(interface.members, hasLength(1));
- final Field field = interface.members.first;
+ final field = interface.members.first as Field;
expect(field, const TypeMatcher<Field>());
expect(field.name, equals('params'));
expect(field.commentText, equals('''The method's params.'''));
expect(field.allowsUndefined, isTrue);
expect(field.allowsNull, isFalse);
expect(field.type, const TypeMatcher<UnionType>());
- UnionType union = field.type;
+ final union = field.type as UnionType;
expect(union.types, hasLength(2));
expect(union.types[0], isArrayOf(isSimpleType('any')));
expect(union.types[1], isSimpleType('string'));
@@ -157,9 +155,9 @@
final output = parseString(input);
expect(output, hasLength(1));
expect(output[0], const TypeMatcher<Interface>());
- final Interface interface = output[0];
+ final interface = output[0] as Interface;
expect(interface.members, hasLength(1));
- final Field field = interface.members.first;
+ final field = interface.members.first as Field;
expect(field, const TypeMatcher<Field>());
expect(field.name, equals('changes'));
expect(field.type,
@@ -176,13 +174,13 @@
}
''';
final output = parseString(input);
- final Interface interface = output[0];
+ final interface = output[0] as Interface;
expect(interface.members, hasLength(4));
interface.members.forEach((m) => expect(m, const TypeMatcher<Field>()));
- final Field canBeBoth = interface.members[0],
- canBeNeither = interface.members[1],
- canBeNull = interface.members[2],
- canBeUndefined = interface.members[3];
+ final canBeBoth = interface.members[0] as Field,
+ canBeNeither = interface.members[1] as Field,
+ canBeNull = interface.members[2] as Field,
+ canBeUndefined = interface.members[3] as Field;
expect(canBeNeither.allowsNull, isFalse);
expect(canBeNeither.allowsUndefined, isFalse);
expect(canBeNull.allowsNull, isTrue);
@@ -216,7 +214,7 @@
}
''';
final output = parseString(input);
- final Interface interface = output[0];
+ final interface = output[0] as Interface;
expect(interface.commentText, equals('''
Describes the what this class in lots of words that wrap onto multiple lines that will need re-wrapping to format nicely when converted into Dart.
@@ -239,7 +237,7 @@
final output = parseString(input);
expect(output, hasLength(1));
expect(output[0], const TypeMatcher<TypeAlias>());
- final TypeAlias typeAlias = output[0];
+ final typeAlias = output[0] as TypeAlias;
expect(typeAlias.name, equals('DocumentSelector'));
expect(typeAlias.baseType, isArrayOf(isSimpleType('DocumentFilter')));
});
@@ -254,24 +252,24 @@
// Results should be the two inline interfaces followed by the type alias.
expect(output[0], const TypeMatcher<InlineInterface>());
- final InlineInterface interface1 = output[0];
+ final interface1 = output[0] as InlineInterface;
expect(interface1.name, equals('NameOrLength1'));
expect(interface1.members, hasLength(1));
expect(interface1.members[0].name, equals('name'));
expect(output[1], const TypeMatcher<InlineInterface>());
- final InlineInterface interface2 = output[1];
+ final interface2 = output[1] as InlineInterface;
expect(interface2.name, equals('NameOrLength2'));
expect(interface2.members, hasLength(1));
expect(interface2.members[0].name, equals('length'));
expect(output[2], const TypeMatcher<TypeAlias>());
- final TypeAlias typeAlias = output[2];
+ final typeAlias = output[2] as TypeAlias;
expect(typeAlias.name, equals('NameOrLength'));
expect(typeAlias.baseType, const TypeMatcher<UnionType>());
// The type alias should be a union of the two types above.
- UnionType union = typeAlias.baseType;
+ final union = typeAlias.baseType as UnionType;
expect(union.types, hasLength(2));
expect(union.types[0], isSimpleType(interface1.name));
expect(union.types[1], isSimpleType(interface2.name));
@@ -299,12 +297,12 @@
final output = parseString(input);
expect(output, hasLength(1));
expect(output[0], const TypeMatcher<Namespace>());
- final Namespace namespace = output[0];
+ final namespace = output[0] as Namespace;
expect(namespace.members, hasLength(3));
namespace.members.forEach((m) => expect(m, const TypeMatcher<Const>()));
- final Const create = namespace.members[0],
- delete = namespace.members[1],
- rename = namespace.members[2];
+ final create = namespace.members[0] as Const,
+ delete = namespace.members[1] as Const,
+ rename = namespace.members[2] as Const;
expect(create.name, equals('Create'));
expect(create.type, isSimpleType('ResourceOperationKind'));
expect(create.commentText,
@@ -346,13 +344,13 @@
final output = parseString(input);
expect(output, hasLength(1));
expect(output[0], const TypeMatcher<Interface>());
- final Interface interface = output[0];
+ final interface = output[0] as Interface;
expect(interface.members, hasLength(1));
- final Field field = interface.members.first;
+ final field = interface.members.first as Field;
expect(field, const TypeMatcher<Field>());
expect(field.name, equals('label'));
expect(field.type, const TypeMatcher<UnionType>());
- UnionType union = field.type;
+ final union = field.type as UnionType;
expect(union.types, hasLength(2));
expect(union.types[0], isSimpleType('string'));
expect(union.types[1], isArrayOf(isSimpleType('number')));
@@ -367,9 +365,9 @@
final output = parseString(input);
expect(output, hasLength(1));
expect(output[0], const TypeMatcher<Interface>());
- final Interface interface = output[0];
+ final interface = output[0] as Interface;
expect(interface.members, hasLength(1));
- final Field field = interface.members.first;
+ final field = interface.members.first as Field;
expect(field, const TypeMatcher<Field>());
expect(field.name, equals('label'));
expect(field.type, isSimpleType('object'));
@@ -384,7 +382,7 @@
''';
final output = parseString(input);
expect(output, hasLength(1));
- expect(output[0].commentNode.token.lexeme, equals('''// This is line 1
+ expect(output[0].commentNode!.token.lexeme, equals('''// This is line 1
// This is line 2'''));
});
@@ -397,11 +395,11 @@
final output = parseString(input);
expect(output, hasLength(1));
expect(output[0], const TypeMatcher<Interface>());
- final Interface interface = output[0];
+ final interface = output[0] as Interface;
expect(interface.name, equals('MyType'));
expect(interface.members, hasLength(1));
expect(interface.members[0], const TypeMatcher<Field>());
- final Field field = interface.members[0];
+ final field = interface.members[0] as Field;
expect(field.name, equals('kind'));
expect(field.allowsNull, isFalse);
expect(field.allowsUndefined, isFalse);
@@ -417,16 +415,16 @@
final output = parseString(input);
expect(output, hasLength(1));
expect(output[0], const TypeMatcher<Interface>());
- final Interface interface = output[0];
+ final interface = output[0] as Interface;
expect(interface.name, equals('MyType'));
expect(interface.members, hasLength(1));
expect(interface.members[0], const TypeMatcher<Field>());
- final Field field = interface.members[0];
+ final field = interface.members[0] as Field;
expect(field.name, equals('kind'));
expect(field.allowsNull, isFalse);
expect(field.allowsUndefined, isFalse);
expect(field.type, const TypeMatcher<LiteralUnionType>());
- LiteralUnionType union = field.type;
+ final union = field.type as LiteralUnionType;
expect(union.types, hasLength(2));
expect(union.types[0], isLiteralOf(isSimpleType('string'), "'one'"));
expect(union.types[1], isLiteralOf(isSimpleType('string'), "'two'"));
diff --git a/pkg/analysis_server/test/tool/test_all.dart b/pkg/analysis_server/test/tool/test_all.dart
index 4852a64..8d2910e 100644
--- a/pkg/analysis_server/test/tool/test_all.dart
+++ b/pkg/analysis_server/test/tool/test_all.dart
@@ -2,8 +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.
-// @dart = 2.9
-
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'completion_metrics/test_all.dart' as completion_metrics;
diff --git a/pkg/analysis_server/tool/code_completion/code_metrics.dart b/pkg/analysis_server/tool/code_completion/code_metrics.dart
index 27585c6..5ff17b9 100644
--- a/pkg/analysis_server/tool/code_completion/code_metrics.dart
+++ b/pkg/analysis_server/tool/code_completion/code_metrics.dart
@@ -1394,11 +1394,11 @@
if (file_paths.isDart(pathContext, filePath)) {
try {
var resolvedUnitResult =
- await context.currentSession.getResolvedUnit(filePath);
+ await context.currentSession.getResolvedUnit2(filePath);
//
// Check for errors that cause the file to be skipped.
//
- if (resolvedUnitResult.state != ResultState.VALID) {
+ if (resolvedUnitResult is! ResolvedUnitResult) {
print('File $filePath skipped because it could not be analyzed.');
print('');
continue;
diff --git a/pkg/analysis_server/tool/code_completion/completion_metrics.dart b/pkg/analysis_server/tool/code_completion/completion_metrics.dart
index f9c0503..31237c3 100644
--- a/pkg/analysis_server/tool/code_completion/completion_metrics.dart
+++ b/pkg/analysis_server/tool/code_completion/completion_metrics.dart
@@ -1114,8 +1114,8 @@
for (var filePath in context.contextRoot.analyzedFiles()) {
if (file_paths.isDart(pathContext, filePath)) {
try {
- _resolvedUnitResult =
- await context.currentSession.getResolvedUnit(filePath);
+ _resolvedUnitResult = await context.currentSession
+ .getResolvedUnit2(filePath) as ResolvedUnitResult;
var analysisError = getFirstErrorOrNull(_resolvedUnitResult);
if (analysisError != null) {
@@ -1144,8 +1144,8 @@
content: overlayContents,
modificationStamp: overlayModificationStamp++);
context.driver.changeFile(filePath);
- resolvedUnitResult =
- await context.currentSession.getResolvedUnit(filePath);
+ resolvedUnitResult = await context.currentSession
+ .getResolvedUnit2(filePath) as ResolvedUnitResult;
}
// As this point the completion suggestions are computed,
diff --git a/pkg/analysis_server/tool/code_completion/flutter_metrics.dart b/pkg/analysis_server/tool/code_completion/flutter_metrics.dart
index 9942472..ee267a5 100644
--- a/pkg/analysis_server/tool/code_completion/flutter_metrics.dart
+++ b/pkg/analysis_server/tool/code_completion/flutter_metrics.dart
@@ -207,11 +207,11 @@
if (file_paths.isDart(pathContext, filePath)) {
try {
var resolvedUnitResult =
- await context.currentSession.getResolvedUnit(filePath);
+ await context.currentSession.getResolvedUnit2(filePath);
//
// Check for errors that cause the file to be skipped.
//
- if (resolvedUnitResult.state != ResultState.VALID) {
+ if (resolvedUnitResult is! ResolvedUnitResult) {
print('');
print('File $filePath skipped because it could not be analyzed.');
continue;
diff --git a/pkg/analysis_server/tool/code_completion/implicit_type_declarations.dart b/pkg/analysis_server/tool/code_completion/implicit_type_declarations.dart
index baa7300..6b0b3c1 100644
--- a/pkg/analysis_server/tool/code_completion/implicit_type_declarations.dart
+++ b/pkg/analysis_server/tool/code_completion/implicit_type_declarations.dart
@@ -184,11 +184,11 @@
if (file_paths.isDart(pathContext, filePath)) {
try {
var resolvedUnitResult =
- await context.currentSession.getResolvedUnit(filePath);
+ await context.currentSession.getResolvedUnit2(filePath);
//
// Check for errors that cause the file to be skipped.
//
- if (resolvedUnitResult.state != ResultState.VALID) {
+ if (resolvedUnitResult is! ResolvedUnitResult) {
print('File $filePath skipped because it could not be analyzed.');
if (verbose) {
print('');
diff --git a/pkg/analysis_server/tool/code_completion/relevance_metrics.dart b/pkg/analysis_server/tool/code_completion/relevance_metrics.dart
index 47717d2..0975c8a 100644
--- a/pkg/analysis_server/tool/code_completion/relevance_metrics.dart
+++ b/pkg/analysis_server/tool/code_completion/relevance_metrics.dart
@@ -1940,11 +1940,11 @@
if (file_paths.isDart(pathContext, filePath)) {
try {
var resolvedUnitResult =
- await context.currentSession.getResolvedUnit(filePath);
+ await context.currentSession.getResolvedUnit2(filePath);
//
// Check for errors that cause the file to be skipped.
//
- if (resolvedUnitResult.state != ResultState.VALID) {
+ if (resolvedUnitResult is! ResolvedUnitResult) {
print('File $filePath skipped because it could not be analyzed.');
if (verbose) {
print('');
diff --git a/pkg/analysis_server/tool/code_completion/relevance_table_generator.dart b/pkg/analysis_server/tool/code_completion/relevance_table_generator.dart
index e5848fa..52b219e 100644
--- a/pkg/analysis_server/tool/code_completion/relevance_table_generator.dart
+++ b/pkg/analysis_server/tool/code_completion/relevance_table_generator.dart
@@ -1459,11 +1459,11 @@
if (file_paths.isDart(pathContext, filePath)) {
try {
var resolvedUnitResult =
- await context.currentSession.getResolvedUnit(filePath);
+ await context.currentSession.getResolvedUnit2(filePath);
//
// Check for errors that cause the file to be skipped.
//
- if (resolvedUnitResult.state != ResultState.VALID) {
+ if (resolvedUnitResult is! ResolvedUnitResult) {
print('File $filePath skipped because it could not be analyzed.');
if (verbose) {
print('');
diff --git a/pkg/analysis_server/tool/lsp_spec/generate_all.dart b/pkg/analysis_server/tool/lsp_spec/generate_all.dart
index e6bd416..1cd4b7b 100644
--- a/pkg/analysis_server/tool/lsp_spec/generate_all.dart
+++ b/pkg/analysis_server/tool/lsp_spec/generate_all.dart
@@ -271,6 +271,13 @@
],
baseType: 'CompletionItemResolutionInfo',
),
+ interface(
+ 'PubPackageCompletionItemResolutionInfo',
+ [
+ field('packageName', type: 'string'),
+ ],
+ baseType: 'CompletionItemResolutionInfo',
+ ),
// Custom types for experimental SnippetTextEdits
// https://github.com/rust-analyzer/rust-analyzer/blob/b35559a2460e7f0b2b79a7029db0c5d4e0acdb44/docs/dev/lsp-extensions.md#snippet-textedit
interface(
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index d692e51..aed9fad 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 1.5.0-dev
+* Deprecated `AnalysisSession.getUnitElement()`.
+ Use `AnalysisSession.getUnitElement2()` instead.
+* Deprecated `AnalysisSession.getResolvedUnit()`.
+ Use `AnalysisSession.getResolvedUnit2()` instead.
+
## 1.4.0
* Deprecated `TypeProvider.nonSubtypableClasses`.
Use `TypeProvider.isNonSubtypableClass` instead.
diff --git a/pkg/analyzer/doc/tutorial/ast.md b/pkg/analyzer/doc/tutorial/ast.md
index e39a89b..2adab31 100644
--- a/pkg/analyzer/doc/tutorial/ast.md
+++ b/pkg/analyzer/doc/tutorial/ast.md
@@ -65,8 +65,10 @@
```dart
void processFile(AnalysisSession session, String path) async {
- ResolvedUnitResult result = await session.getResolvedUnit(path);
- CompilationUnit unit = result.unit;
+ var result = await session.getResolvedUnit2(path);
+ if (result is ResolvedUnitResult) {
+ CompilationUnit unit = result.unit;
+ }
}
```
diff --git a/pkg/analyzer/doc/tutorial/element.md b/pkg/analyzer/doc/tutorial/element.md
index 5464d12..b0169e4 100644
--- a/pkg/analyzer/doc/tutorial/element.md
+++ b/pkg/analyzer/doc/tutorial/element.md
@@ -46,8 +46,10 @@
```dart
void analyzeSingleFile(AnalysisSession session, String path) async {
- UnitElementResult result = await session.getUnitElement(path);
- CompilationUnitElement element = result.element;
+ var result = await session.getUnitElement2(path);
+ if (result is UnitElementResult) {
+ CompilationUnitElement element = result.element;
+ }
}
```
diff --git a/pkg/analyzer/lib/dart/analysis/results.dart b/pkg/analyzer/lib/dart/analysis/results.dart
index 4a17594..ca07131 100644
--- a/pkg/analyzer/lib/dart/analysis/results.dart
+++ b/pkg/analyzer/lib/dart/analysis/results.dart
@@ -81,6 +81,29 @@
LineInfo get lineInfo;
}
+/// The type of [InvalidResult] returned when the given file path is invalid,
+/// for example is not absolute and normalized.
+///
+/// Clients may not extend, implement or mix-in this class.
+class InvalidPathResult
+ implements InvalidResult, SomeResolvedUnitResult, SomeUnitElementResult {}
+
+/// The base class for any invalid result.
+///
+/// Clients may not extend, implement or mix-in this class.
+abstract class InvalidResult {}
+
+/// The type of [InvalidResult] returned when the given file path does not
+/// represent the corresponding URI.
+///
+/// This usually happens in Bazel workspaces, when a URI is resolved to
+/// a generated file, but there is also a writable file to which this URI
+/// would be resolved, if there were no generated file.
+///
+/// Clients may not extend, implement or mix-in this class.
+class NotPathOfUriResult
+ implements InvalidResult, SomeResolvedUnitResult, SomeUnitElementResult {}
+
/// The result of building parsed AST(s) for the whole library.
///
/// Clients may not extend, implement or mix-in this class.
@@ -152,10 +175,14 @@
/// include both syntactic and semantic errors.
///
/// Clients may not extend, implement or mix-in this class.
-abstract class ResolvedUnitResult implements AnalysisResultWithErrors {
+abstract class ResolvedUnitResult
+ implements SomeResolvedUnitResult, AnalysisResultWithErrors {
/// The content of the file that was scanned, parsed and resolved.
String? get content;
+ /// Return `true` if the file exists.
+ bool get exists;
+
/// The element representing the library containing the compilation [unit].
LibraryElement get libraryElement;
@@ -192,10 +219,28 @@
VALID
}
+/// The result of building a resolved AST for a single file. The errors returned
+/// include both syntactic and semantic errors.
+///
+/// Clients may not extend, implement or mix-in this class.
+///
+/// There are existing implementations of this class.
+/// [ResolvedUnitResult] represents a valid result.
+abstract class SomeResolvedUnitResult {}
+
/// The result of building the element model for a single file.
///
/// Clients may not extend, implement or mix-in this class.
-abstract class UnitElementResult implements AnalysisResult {
+///
+/// There are existing implementations of this class.
+/// [UnitElementResult] represents a valid result.
+abstract class SomeUnitElementResult {}
+
+/// The result of building the element model for a single file.
+///
+/// Clients may not extend, implement or mix-in this class.
+abstract class UnitElementResult
+ implements SomeUnitElementResult, AnalysisResult {
/// The element of the file.
CompilationUnitElement get element;
diff --git a/pkg/analyzer/lib/dart/analysis/session.dart b/pkg/analyzer/lib/dart/analysis/session.dart
index 9fe33e3..ff10b22 100644
--- a/pkg/analyzer/lib/dart/analysis/session.dart
+++ b/pkg/analyzer/lib/dart/analysis/session.dart
@@ -80,8 +80,13 @@
/// Return a future that will complete with information about the results of
/// resolving the file with the given absolute, normalized [path].
+ @Deprecated('Use getResolvedUnit2() instead')
Future<ResolvedUnitResult> getResolvedUnit(String path);
+ /// Return a future that will complete with information about the results of
+ /// resolving the file with the given absolute, normalized [path].
+ Future<SomeResolvedUnitResult> getResolvedUnit2(String path);
+
/// Return a future that will complete with the source kind of the file with
/// the given absolute, normalized [path]. If the path does not represent a
/// file or if the kind of the file cannot be determined, then the future will
@@ -93,12 +98,18 @@
/// Return a future that will complete with information about the results of
/// building the element model for the file with the given absolute,
/// normalized [path].
+ @Deprecated('Use getUnitElement2() instead')
Future<UnitElementResult> getUnitElement(String path);
+ /// Return a future that will complete with information about the results of
+ /// building the element model for the file with the given absolute,
+ /// normalized [path].
+ Future<SomeUnitElementResult> getUnitElement2(String path);
+
/// Return a future that will complete with the signature for the file with
/// the given absolute, normalized [path], or `null` if the file cannot be
/// analyzed. This is the same signature returned in the result from
- /// [getUnitElement].
+ /// [getUnitElement2].
///
/// The signature is based on the APIs of the files of the library (including
/// the file itself), and the transitive closure of files imported and
diff --git a/pkg/analyzer/lib/dart/analysis/utilities.dart b/pkg/analyzer/lib/dart/analysis/utilities.dart
index 801d224..50e0677 100644
--- a/pkg/analyzer/lib/dart/analysis/utilities.dart
+++ b/pkg/analyzer/lib/dart/analysis/utilities.dart
@@ -113,6 +113,7 @@
/// create one or more contexts and use those contexts to resolve the files.
///
/// TODO(migration): should not be nullable
+@Deprecated('Use resolveFile2() instead')
Future<ResolvedUnitResult?> resolveFile(
{required String path, ResourceProvider? resourceProvider}) async {
AnalysisContext context =
@@ -120,6 +121,20 @@
return await context.currentSession.getResolvedUnit(path);
}
+/// Return the result of resolving the file at the given [path].
+///
+/// If a [resourceProvider] is given, it will be used to access the file system.
+///
+/// Note that if more than one file is going to be resolved then this function
+/// is inefficient. Clients should instead use [AnalysisContextCollection] to
+/// create one or more contexts and use those contexts to resolve the files.
+Future<SomeResolvedUnitResult> resolveFile2(
+ {required String path, ResourceProvider? resourceProvider}) async {
+ AnalysisContext context =
+ _createAnalysisContext(path: path, resourceProvider: resourceProvider);
+ return await context.currentSession.getResolvedUnit2(path);
+}
+
/// Return a newly create analysis context in which the file at the given [path]
/// can be analyzed.
///
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index 6024381..ca35727 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -151,7 +151,7 @@
final _priorityFiles = <String>{};
/// The mapping from the files for which analysis was requested using
- /// [getResult] to the [Completer]s to report the result.
+ /// [getResult2] to the [Completer]s to report the result.
final _requestedFiles = <String, List<Completer<ResolvedUnitResult>>>{};
/// The mapping from the files for which analysis was requested using
@@ -193,18 +193,18 @@
final _unitElementSignatureParts = <String, List<Completer<String>>>{};
/// The mapping from the files for which the unit element was requested using
- /// [getUnitElement] to the [Completer]s to report the result.
+ /// [getUnitElement2] to the [Completer]s to report the result.
final _unitElementRequestedFiles =
<String, List<Completer<UnitElementResult>>>{};
/// The mapping from the files for which the unit element was requested using
- /// [getUnitElement], and which were found to be parts without known libraries,
- /// to the [Completer]s to report the result.
+ /// [getUnitElement2], and which were found to be parts without known
+ /// libraries, to the [Completer]s to report the result.
final _unitElementRequestedParts =
<String, List<Completer<UnitElementResult>>>{};
/// The mapping from the files for which analysis was requested using
- /// [getResult], and which were found to be parts without known libraries,
+ /// [getResult2], and which were found to be parts without known libraries,
/// to the [Completer]s to report the result.
final _requestedParts = <String, List<Completer<ResolvedUnitResult>>>{};
@@ -360,7 +360,7 @@
/// client does not change the state of the files.
///
/// Results might be produced even for files that have never been added
- /// using [addFile], for example when [getResult] was called for a file.
+ /// using [addFile], for example when [getResult2] was called for a file.
Stream<ResolvedUnitResult> get results => _onResults;
/// Return the search support for the driver.
@@ -465,7 +465,7 @@
/// transitions to "idle".
///
/// Invocation of this method will not prevent a [Future] returned from
- /// [getResult] from completing with a result, but the result is not
+ /// [getResult2] from completing with a result, but the result is not
/// guaranteed to be consistent with the new current file state after this
/// [changeFile] invocation.
void changeFile(String path) {
@@ -632,7 +632,12 @@
throw ArgumentError('$uri is not a library.');
}
- var unitResult = await getUnitElement(file.path);
+ var unitResult = await getUnitElement2(file.path);
+ // TODO(scheglov) this method should also return a result hierarchy
+ if (unitResult is! UnitElementResult) {
+ throw ArgumentError('$uri has no valid result.');
+ }
+
return unitResult.element.library;
},
(externalLibrary) async {
@@ -789,12 +794,46 @@
/// it, which is consistent with the current file state (including new states
/// of the files previously reported using [changeFile]), prior to the next
/// time the analysis state transitions to "idle".
+ @Deprecated('Use getResult2() instead')
Future<ResolvedUnitResult> getResult(String path,
- {bool sendCachedToStream = false}) {
+ {bool sendCachedToStream = false}) async {
_throwIfNotAbsolutePath(path);
+
+ var result = await getResult2(path, sendCachedToStream: sendCachedToStream);
+ if (result is NotPathOfUriResult) {
+ return NotValidResolvedUnitResultImpl(ResultState.NOT_FILE_OF_URI);
+ }
+
+ return result as ResolvedUnitResult;
+ }
+
+ /// Return a [Future] that completes with a [SomeResolvedUnitResult] for the
+ /// Dart file with the given [path].
+ ///
+ /// The [path] must be absolute and normalized.
+ ///
+ /// The [path] can be any file - explicitly or implicitly analyzed, or neither.
+ ///
+ /// If the driver has the cached analysis result for the file, it is returned.
+ /// If [sendCachedToStream] is `true`, then the result is also reported into
+ /// the [results] stream, just as if it were freshly computed.
+ ///
+ /// Otherwise causes the analysis state to transition to "analyzing" (if it is
+ /// not in that state already), the driver will produce the analysis result for
+ /// it, which is consistent with the current file state (including new states
+ /// of the files previously reported using [changeFile]), prior to the next
+ /// time the analysis state transitions to "idle".
+ Future<SomeResolvedUnitResult> getResult2(String path,
+ {bool sendCachedToStream = false}) {
+ if (!_isAbsolutePath(path)) {
+ return Future.value(
+ InvalidPathResult(),
+ );
+ }
+
if (!_fsState.hasUri(path)) {
return Future.value(
- NotValidResolvedUnitResultImpl(ResultState.NOT_FILE_OF_URI),
+ NotPathOfUriResult(),
);
}
@@ -834,13 +873,35 @@
/// Return a [Future] that completes with the [UnitElementResult] for the
/// file with the given [path].
- Future<UnitElementResult> getUnitElement(String path) {
+ @Deprecated('Use getUnitElement2() instead')
+ Future<UnitElementResult> getUnitElement(String path) async {
_throwIfNotAbsolutePath(path);
- if (!_fsState.hasUri(path)) {
+ var result = await getUnitElement2(path);
+
+ if (result is NotPathOfUriResult) {
return Future.value(
NotValidUnitElementResultImpl(ResultState.NOT_FILE_OF_URI),
);
}
+
+ return result as UnitElementResult;
+ }
+
+ /// Return a [Future] that completes with the [SomeUnitElementResult]
+ /// for the file with the given [path].
+ Future<SomeUnitElementResult> getUnitElement2(String path) {
+ if (!_isAbsolutePath(path)) {
+ return Future.value(
+ InvalidPathResult(),
+ );
+ }
+
+ if (!_fsState.hasUri(path)) {
+ return Future.value(
+ NotPathOfUriResult(),
+ );
+ }
+
var completer = Completer<UnitElementResult>();
_unitElementRequestedFiles
.putIfAbsent(path, () => <Completer<UnitElementResult>>[])
@@ -1656,6 +1717,10 @@
);
}
+ bool _isAbsolutePath(String path) {
+ return _resourceProvider.pathContext.isAbsolute(path);
+ }
+
/// We detected that one of the required `dart` libraries is missing.
/// Return the empty analysis result with the error.
AnalysisResult _newMissingDartLibraryResult(
@@ -1773,7 +1838,7 @@
/// The driver supports only absolute paths, this method is used to validate
/// any input paths to prevent errors later.
void _throwIfNotAbsolutePath(String path) {
- if (!_resourceProvider.pathContext.isAbsolute(path)) {
+ if (!_isAbsolutePath(path)) {
throw ArgumentError('Only absolute paths are supported: $path');
}
}
diff --git a/pkg/analyzer/lib/src/dart/analysis/results.dart b/pkg/analyzer/lib/src/dart/analysis/results.dart
index c2e5b28..2ddf619 100644
--- a/pkg/analyzer/lib/src/dart/analysis/results.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/results.dart
@@ -133,6 +133,11 @@
}
@override
+ bool get exists {
+ throw StateError('This result is not valid');
+ }
+
+ @override
LibraryElement get libraryElement {
throw StateError('This result is not valid');
}
@@ -331,7 +336,7 @@
class ResolvedUnitResultImpl extends FileResultImpl
implements ResolvedUnitResult {
- /// Return `true` if the file exists.
+ @override
final bool exists;
@override
diff --git a/pkg/analyzer/lib/src/dart/analysis/search.dart b/pkg/analyzer/lib/src/dart/analysis/search.dart
index 9e3c4b0..c460b9e 100644
--- a/pkg/analyzer/lib/src/dart/analysis/search.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/search.dart
@@ -54,8 +54,8 @@
List<String> files = await _driver.getFilesDefiningClassMemberName(name);
for (String file in files) {
if (searchedFiles.add(file, this)) {
- var unitResult = await _driver.getUnitElement(file);
- if (unitResult.state == ResultState.VALID) {
+ var unitResult = await _driver.getUnitElement2(file);
+ if (unitResult is UnitElementResult) {
unitResult.element.types.forEach(addElements);
unitResult.element.mixins.forEach(addElements);
}
@@ -174,8 +174,8 @@
List<FileState> knownFiles = _driver.fsState.knownFiles.toList();
for (FileState file in knownFiles) {
- var unitResult = await _driver.getUnitElement(file.path);
- if (unitResult.state == ResultState.VALID) {
+ var unitResult = await _driver.getUnitElement2(file.path);
+ if (unitResult is UnitElementResult) {
CompilationUnitElement unitElement = unitResult.element;
unitElement.accessors.forEach(addElement);
unitElement.enums.forEach(addElement);
@@ -283,8 +283,8 @@
}
Future<CompilationUnitElement?> _getUnitElement(String file) async {
- var result = await _driver.getUnitElement(file);
- return result.state == ResultState.VALID ? result.element : null;
+ var result = await _driver.getUnitElement2(file);
+ return result is UnitElementResult ? result.element : null;
}
Future<List<SearchResult>> _searchReferences(
@@ -378,11 +378,12 @@
LibraryElement libraryElement = element.library;
for (CompilationUnitElement unitElement in libraryElement.units) {
String unitPath = unitElement.source.fullName;
- ResolvedUnitResult unitResult = await _driver.getResult(unitPath);
- _ImportElementReferencesVisitor visitor =
- _ImportElementReferencesVisitor(element, unitElement);
- unitResult.unit!.accept(visitor);
- results.addAll(visitor.results);
+ var unitResult = await _driver.getResult2(unitPath);
+ if (unitResult is ResolvedUnitResult) {
+ var visitor = _ImportElementReferencesVisitor(element, unitElement);
+ unitResult.unit!.accept(visitor);
+ results.addAll(visitor.results);
+ }
}
return results;
}
@@ -397,17 +398,22 @@
List<SearchResult> results = <SearchResult>[];
for (CompilationUnitElement unitElement in element.units) {
String unitPath = unitElement.source.fullName;
- ResolvedUnitResult unitResult = await _driver.getResult(unitPath);
- CompilationUnit unit = unitResult.unit!;
- for (Directive directive in unit.directives) {
- if (directive is PartOfDirective && directive.element == element) {
- results.add(SearchResult._(
- unit.declaredElement!,
- SearchResultKind.REFERENCE,
- directive.libraryName!.offset,
- directive.libraryName!.length,
- true,
- false));
+ var unitResult = await _driver.getResult2(unitPath);
+ if (unitResult is ResolvedUnitResult) {
+ CompilationUnit unit = unitResult.unit!;
+ for (Directive directive in unit.directives) {
+ if (directive is PartOfDirective && directive.element == element) {
+ results.add(
+ SearchResult._(
+ unit.declaredElement!,
+ SearchResultKind.REFERENCE,
+ directive.libraryName!.offset,
+ directive.libraryName!.length,
+ true,
+ false,
+ ),
+ );
+ }
}
}
}
@@ -422,7 +428,10 @@
}
// Prepare the unit.
- ResolvedUnitResult unitResult = await _driver.getResult(path);
+ var unitResult = await _driver.getResult2(path);
+ if (unitResult is! ResolvedUnitResult) {
+ return const <SearchResult>[];
+ }
var unit = unitResult.unit;
if (unit == null) {
return const <SearchResult>[];
@@ -475,11 +484,12 @@
LibraryElement libraryElement = element.library;
for (CompilationUnitElement unitElement in libraryElement.units) {
String unitPath = unitElement.source.fullName;
- ResolvedUnitResult unitResult = await _driver.getResult(unitPath);
- _LocalReferencesVisitor visitor =
- _LocalReferencesVisitor(element, unitElement);
- unitResult.unit!.accept(visitor);
- results.addAll(visitor.results);
+ var unitResult = await _driver.getResult2(unitPath);
+ if (unitResult is ResolvedUnitResult) {
+ var visitor = _LocalReferencesVisitor(element, unitElement);
+ unitResult.unit!.accept(visitor);
+ results.addAll(visitor.results);
+ }
}
return results;
}
diff --git a/pkg/analyzer/lib/src/dart/analysis/session.dart b/pkg/analyzer/lib/src/dart/analysis/session.dart
index 7153b15..9af60f9 100644
--- a/pkg/analyzer/lib/src/dart/analysis/session.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/session.dart
@@ -114,6 +114,7 @@
return _driver.getResolvedLibraryByUri(element.source.uri);
}
+ @Deprecated('Use getResolvedUnit2() instead')
@override
Future<ResolvedUnitResult> getResolvedUnit(String path) {
_checkConsistency();
@@ -121,11 +122,18 @@
}
@override
+ Future<SomeResolvedUnitResult> getResolvedUnit2(String path) {
+ _checkConsistency();
+ return _driver.getResult2(path);
+ }
+
+ @override
Future<SourceKind?> getSourceKind(String path) {
_checkConsistency();
return _driver.getSourceKind(path);
}
+ @Deprecated('Use getUnitElement2() instead')
@override
Future<UnitElementResult> getUnitElement(String path) {
_checkConsistency();
@@ -133,6 +141,12 @@
}
@override
+ Future<SomeUnitElementResult> getUnitElement2(String path) {
+ _checkConsistency();
+ return _driver.getUnitElement2(path);
+ }
+
+ @override
Future<String> getUnitElementSignature(String path) {
_checkConsistency();
return _driver.getUnitElementSignature(path);
diff --git a/pkg/analyzer/lib/src/dart/micro/analysis_context.dart b/pkg/analyzer/lib/src/dart/micro/analysis_context.dart
index 5e45d1e7..df022bf 100644
--- a/pkg/analyzer/lib/src/dart/micro/analysis_context.dart
+++ b/pkg/analyzer/lib/src/dart/micro/analysis_context.dart
@@ -208,7 +208,7 @@
}
@override
- Future<ResolvedUnitResult> getResolvedUnit(String path) async {
+ Future<SomeResolvedUnitResult> getResolvedUnit2(String path) async {
return analysisContext.fileResolver.resolve(path: path);
}
diff --git a/pkg/analyzer/lib/src/dart/micro/library_graph.dart b/pkg/analyzer/lib/src/dart/micro/library_graph.dart
index f4cce34..2c10c45 100644
--- a/pkg/analyzer/lib/src/dart/micro/library_graph.dart
+++ b/pkg/analyzer/lib/src/dart/micro/library_graph.dart
@@ -28,6 +28,7 @@
import 'package:analyzer/src/summary/idl.dart';
import 'package:analyzer/src/summary/link.dart' as graph
show DependencyWalker, Node;
+import 'package:analyzer/src/util/file_paths.dart' as file_paths;
import 'package:analyzer/src/util/performance/operation_performance.dart';
import 'package:analyzer/src/workspace/workspace.dart';
import 'package:collection/collection.dart';
@@ -211,6 +212,7 @@
}
void refresh({
+ FileState? containingLibrary,
required OperationPerformanceImpl performance,
}) {
_fsState.testView.refreshedFiles.add(path);
@@ -282,6 +284,7 @@
}
for (var uri in unlinked2.parts) {
var file = _fileForRelativeUri(
+ containingLibrary: this,
relativeUri: uri,
performance: performance,
);
@@ -290,15 +293,24 @@
}
}
if (unlinked2.hasPartOfDirective) {
- var uri = unlinked2.partOfUri;
- if (uri.isNotEmpty) {
- partOfLibrary = _fileForRelativeUri(
- relativeUri: uri,
- performance: performance,
- );
- if (partOfLibrary != null) {
- directReferencedFiles.add(partOfLibrary!);
+ if (containingLibrary == null) {
+ _fsState.testView.partsDiscoveredLibraries.add(path);
+ var libraryName = unlinked2.partOfName;
+ var libraryUri = unlinked2.partOfUri;
+ partOfLibrary = null;
+ if (libraryName.isNotEmpty) {
+ _findPartOfNameLibrary(performance: performance);
+ } else if (libraryUri.isNotEmpty) {
+ partOfLibrary = _fileForRelativeUri(
+ relativeUri: libraryUri,
+ performance: performance,
+ );
}
+ } else {
+ partOfLibrary = containingLibrary;
+ }
+ if (partOfLibrary != null) {
+ directReferencedFiles.add(partOfLibrary!);
}
}
libraryFiles.add(this);
@@ -318,6 +330,7 @@
}
FileState? _fileForRelativeUri({
+ FileState? containingLibrary,
required String relativeUri,
required OperationPerformanceImpl performance,
}) {
@@ -333,6 +346,7 @@
}
var file = _fsState.getFileForUri(
+ containingLibrary: containingLibrary,
uri: absoluteUri,
performance: performance,
);
@@ -344,6 +358,35 @@
return file;
}
+ /// This file has a `part of some.library;` directive. Because it does not
+ /// specify the URI of the library, we don't know the library for sure.
+ /// But usually the library is one of the sibling files.
+ void _findPartOfNameLibrary({
+ required OperationPerformanceImpl performance,
+ }) {
+ var resourceProvider = _fsState._resourceProvider;
+ var pathContext = resourceProvider.pathContext;
+
+ var children = <Resource>[];
+ try {
+ var parent = resourceProvider.getFile(path).parent2;
+ children = parent.getChildren();
+ } catch (_) {}
+
+ for (var siblingFile in children) {
+ if (file_paths.isDart(pathContext, siblingFile.path)) {
+ var childState = _fsState.getFileForPath(
+ path: siblingFile.path,
+ performance: performance,
+ );
+ if (childState.partedFiles.contains(this)) {
+ partOfLibrary = childState;
+ break;
+ }
+ }
+ }
+ }
+
void _prefetchDirectReferences(UnlinkedUnit2 unlinkedUnit2) {
if (_fsState.prefetchFiles == null) {
return;
@@ -388,6 +431,7 @@
var hasLibraryDirective = false;
var hasPartOfDirective = false;
var partOfUriStr = '';
+ var partOfName = '';
for (var directive in unit.directives) {
if (directive is ExportDirective) {
var builder = _serializeNamespaceDirective(directive);
@@ -405,8 +449,12 @@
parts.add(uriStr ?? '');
} else if (directive is PartOfDirective) {
hasPartOfDirective = true;
- if (directive.uri != null) {
- partOfUriStr = directive.uri!.stringValue!;
+ var libraryName = directive.libraryName;
+ var uriStr = directive.uri?.stringValue;
+ if (libraryName != null) {
+ partOfName = libraryName.components.map((e) => e.name).join('.');
+ } else if (uriStr != null) {
+ partOfUriStr = uriStr;
}
}
}
@@ -424,6 +472,7 @@
parts: parts,
hasLibraryDirective: hasLibraryDirective,
hasPartOfDirective: hasPartOfDirective,
+ partOfName: partOfName,
partOfUri: partOfUriStr,
lineStarts: unit.lineInfo!.lineStarts,
);
@@ -583,6 +632,7 @@
}
FileState? getFileForUri({
+ FileState? containingLibrary,
required Uri uri,
required OperationPerformanceImpl performance,
}) {
@@ -605,6 +655,7 @@
_uriToFile[uri] = file;
file.refresh(
+ containingLibrary: containingLibrary,
performance: performance,
);
}
@@ -646,6 +697,7 @@
class FileSystemStateTestView {
final List<String> refreshedFiles = [];
+ final List<String> partsDiscoveredLibraries = [];
Set<String> removedPaths = {};
}
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 93cc5b6..c5013b7 100644
--- a/pkg/analyzer/lib/src/dart/resolver/extension_member_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/extension_member_resolver.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:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart';
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/syntactic_entity.dart';
@@ -119,7 +120,8 @@
}
/// Perform upward inference for the override.
- void resolveOverride(ExtensionOverride node) {
+ void resolveOverride(ExtensionOverride node,
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList) {
var nodeImpl = node as ExtensionOverrideImpl;
var element = node.staticElement!;
var typeParameters = element.typeParameters;
@@ -173,10 +175,14 @@
_errorReporter.reportErrorForNode(
CompileTimeErrorCode.USE_OF_VOID_RESULT, receiverExpression);
} else if (!_typeSystem.isAssignableTo(receiverType, node.extendedType!)) {
+ var whyNotPromoted =
+ whyNotPromotedList.isEmpty ? null : whyNotPromotedList[0];
_errorReporter.reportErrorForNode(
CompileTimeErrorCode.EXTENSION_OVERRIDE_ARGUMENT_NOT_ASSIGNABLE,
receiverExpression,
[receiverType, node.extendedType],
+ _resolver.computeWhyNotPromotedMessages(
+ receiverExpression, whyNotPromoted?.call()),
);
}
}
diff --git a/pkg/analyzer/lib/src/error/unused_local_elements_verifier.dart b/pkg/analyzer/lib/src/error/unused_local_elements_verifier.dart
index c8b4452..45c9c66 100644
--- a/pkg/analyzer/lib/src/error/unused_local_elements_verifier.dart
+++ b/pkg/analyzer/lib/src/error/unused_local_elements_verifier.dart
@@ -687,6 +687,11 @@
}
void addMember(Element? element) {
+ // Store un-parameterized members.
+ if (element is ExecutableMember) {
+ element = element.declaration;
+ }
+
if (element != null) {
members.add(element);
}
diff --git a/pkg/analyzer/lib/src/generated/error_detection_helpers.dart b/pkg/analyzer/lib/src/generated/error_detection_helpers.dart
index ce69393..b53515f 100644
--- a/pkg/analyzer/lib/src/generated/error_detection_helpers.dart
+++ b/pkg/analyzer/lib/src/generated/error_detection_helpers.dart
@@ -56,7 +56,7 @@
{bool promoteParameterToNullable = false,
Map<DartType, NonPromotionReason> Function()? whyNotPromoted}) {
_checkForArgumentTypeNotAssignableForArgument2(
- argument: argument,
+ argument: argument is NamedExpression ? argument.expression : argument,
parameter: argument.staticParameterElement,
promoteParameterToNullable: promoteParameterToNullable,
whyNotPromoted: whyNotPromoted,
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index b878793..a6f3800 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -1456,7 +1456,7 @@
whyNotPromotedList: whyNotPromotedList);
node.accept(elementResolver);
- node.accept(typeAnalyzer);
+ extensionResolver.resolveOverride(node, whyNotPromotedList);
}
@override
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index ead332f..54b29b2 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -128,7 +128,8 @@
@override
void visitExtensionOverride(ExtensionOverride node) {
- _resolver.extensionResolver.resolveOverride(node);
+ assert(false,
+ 'Resolver should call extensionResolver.resolveOverride directly');
}
/// The Dart Language Specification, 12.9: <blockquote>The static type of a function literal of the
diff --git a/pkg/analyzer/lib/src/lint/project.dart b/pkg/analyzer/lib/src/lint/project.dart
index ff937d9..c98e7bd 100644
--- a/pkg/analyzer/lib/src/lint/project.dart
+++ b/pkg/analyzer/lib/src/lint/project.dart
@@ -134,16 +134,18 @@
for (Source source in sources!) {
String path = source.uri.path;
if (path.startsWith(libDir) && !path.startsWith(libSrcDir)) {
- ResolvedUnitResult result = await driver.getResult(source.fullName);
- LibraryElement library = result.libraryElement;
+ var result = await driver.getResult2(source.fullName);
+ if (result is ResolvedUnitResult) {
+ LibraryElement library = result.libraryElement;
- NamespaceBuilder namespaceBuilder = NamespaceBuilder();
- Namespace exports =
- namespaceBuilder.createExportNamespaceForLibrary(library);
- Namespace public =
- namespaceBuilder.createPublicNamespaceForLibrary(library);
- elements.addAll(exports.definedNames.values);
- elements.addAll(public.definedNames.values);
+ NamespaceBuilder namespaceBuilder = NamespaceBuilder();
+ Namespace exports =
+ namespaceBuilder.createExportNamespaceForLibrary(library);
+ Namespace public =
+ namespaceBuilder.createPublicNamespaceForLibrary(library);
+ elements.addAll(exports.definedNames.values);
+ elements.addAll(public.definedNames.values);
+ }
}
}
}
diff --git a/pkg/analyzer/lib/src/summary/format.dart b/pkg/analyzer/lib/src/summary/format.dart
index c98c9d6..edf1d2f 100644
--- a/pkg/analyzer/lib/src/summary/format.dart
+++ b/pkg/analyzer/lib/src/summary/format.dart
@@ -4444,6 +4444,7 @@
bool? _hasPartOfDirective;
List<UnlinkedNamespaceDirectiveBuilder>? _imports;
List<int>? _lineStarts;
+ String? _partOfName;
String? _partOfUri;
List<String>? _parts;
@@ -4501,9 +4502,17 @@
}
@override
+ String get partOfName => _partOfName ??= '';
+
+ /// The library name of the `part of my.name;` directive.
+ set partOfName(String value) {
+ this._partOfName = value;
+ }
+
+ @override
String get partOfUri => _partOfUri ??= '';
- /// URI of the `part of` directive.
+ /// URI of the `part of 'uri';` directive.
set partOfUri(String value) {
this._partOfUri = value;
}
@@ -4523,6 +4532,7 @@
bool? hasPartOfDirective,
List<UnlinkedNamespaceDirectiveBuilder>? imports,
List<int>? lineStarts,
+ String? partOfName,
String? partOfUri,
List<String>? parts})
: _apiSignature = apiSignature,
@@ -4531,6 +4541,7 @@
_hasPartOfDirective = hasPartOfDirective,
_imports = imports,
_lineStarts = lineStarts,
+ _partOfName = partOfName,
_partOfUri = partOfUri,
_parts = parts;
@@ -4582,6 +4593,7 @@
}
signatureSink.addBool(this._hasLibraryDirective == true);
signatureSink.addString(this._partOfUri ?? '');
+ signatureSink.addString(this._partOfName ?? '');
}
List<int> toBuffer() {
@@ -4594,6 +4606,7 @@
fb.Offset? offset_exports;
fb.Offset? offset_imports;
fb.Offset? offset_lineStarts;
+ fb.Offset? offset_partOfName;
fb.Offset? offset_partOfUri;
fb.Offset? offset_parts;
var apiSignature = _apiSignature;
@@ -4614,6 +4627,10 @@
if (!(lineStarts == null || lineStarts.isEmpty)) {
offset_lineStarts = fbBuilder.writeListUint32(lineStarts);
}
+ var partOfName = _partOfName;
+ if (partOfName != null) {
+ offset_partOfName = fbBuilder.writeString(partOfName);
+ }
var partOfUri = _partOfUri;
if (partOfUri != null) {
offset_partOfUri = fbBuilder.writeString(partOfUri);
@@ -4638,6 +4655,9 @@
if (offset_lineStarts != null) {
fbBuilder.addOffset(5, offset_lineStarts);
}
+ if (offset_partOfName != null) {
+ fbBuilder.addOffset(8, offset_partOfName);
+ }
if (offset_partOfUri != null) {
fbBuilder.addOffset(7, offset_partOfUri);
}
@@ -4675,6 +4695,7 @@
bool? _hasPartOfDirective;
List<idl.UnlinkedNamespaceDirective>? _imports;
List<int>? _lineStarts;
+ String? _partOfName;
String? _partOfUri;
List<String>? _parts;
@@ -4717,6 +4738,12 @@
}
@override
+ String get partOfName {
+ return _partOfName ??=
+ const fb.StringReader().vTableGet(_bc, _bcOffset, 8, '');
+ }
+
+ @override
String get partOfUri {
return _partOfUri ??=
const fb.StringReader().vTableGet(_bc, _bcOffset, 7, '');
@@ -4759,6 +4786,10 @@
if (local_lineStarts.isNotEmpty) {
_result["lineStarts"] = local_lineStarts;
}
+ var local_partOfName = partOfName;
+ if (local_partOfName != '') {
+ _result["partOfName"] = local_partOfName;
+ }
var local_partOfUri = partOfUri;
if (local_partOfUri != '') {
_result["partOfUri"] = local_partOfUri;
@@ -4778,6 +4809,7 @@
"hasPartOfDirective": hasPartOfDirective,
"imports": imports,
"lineStarts": lineStarts,
+ "partOfName": partOfName,
"partOfUri": partOfUri,
"parts": parts,
};
diff --git a/pkg/analyzer/lib/src/summary/format.fbs b/pkg/analyzer/lib/src/summary/format.fbs
index bdce0bf..43b6eb4 100644
--- a/pkg/analyzer/lib/src/summary/format.fbs
+++ b/pkg/analyzer/lib/src/summary/format.fbs
@@ -498,7 +498,10 @@
/// Offsets of the first character of each line in the source code.
lineStarts:[uint] (id: 5);
- /// URI of the `part of` directive.
+ /// The library name of the `part of my.name;` directive.
+ partOfName:string (id: 8);
+
+ /// URI of the `part of 'uri';` directive.
partOfUri:string (id: 7);
/// URIs of `part` directives.
diff --git a/pkg/analyzer/lib/src/summary/idl.dart b/pkg/analyzer/lib/src/summary/idl.dart
index d66803a..58625f0 100644
--- a/pkg/analyzer/lib/src/summary/idl.dart
+++ b/pkg/analyzer/lib/src/summary/idl.dart
@@ -666,7 +666,11 @@
@Id(5)
List<int> get lineStarts;
- /// URI of the `part of` directive.
+ /// The library name of the `part of my.name;` directive.
+ @Id(8)
+ String get partOfName;
+
+ /// URI of the `part of 'uri';` directive.
@Id(7)
String get partOfUri;
diff --git a/pkg/analyzer/lib/src/util/ast_data_extractor.dart b/pkg/analyzer/lib/src/util/ast_data_extractor.dart
index 4ae6f75..18dec74 100644
--- a/pkg/analyzer/lib/src/util/ast_data_extractor.dart
+++ b/pkg/analyzer/lib/src/util/ast_data_extractor.dart
@@ -59,6 +59,12 @@
registerValue(uri, _nodeOffset(node), id, value, node);
}
+ void computeForFormalParameter(FormalParameter node, NodeId? id) {
+ if (id == null) return;
+ T? value = computeNodeValue(id, node);
+ registerValue(uri, _nodeOffset(node), id, value, node);
+ }
+
void computeForLibrary(LibraryElement library, Id? id) {
if (id == null) return;
T? value = computeElementValue(id, library);
@@ -77,6 +83,12 @@
registerValue(uri, _nodeOffset(node), id, value, node);
}
+ void computeForVariableDeclaration(VariableDeclaration node, NodeId? id) {
+ if (id == null) return;
+ T? value = computeNodeValue(id, node);
+ registerValue(uri, _nodeOffset(node), id, value, node);
+ }
+
/// Implement this to compute the data corresponding to [node].
///
/// If `null` is returned, [node] has no associated data.
@@ -145,6 +157,12 @@
}
@override
+ void visitFormalParameter(FormalParameter node) {
+ computeForFormalParameter(node, computeDefaultNodeId(node));
+ super.visitFormalParameter(node);
+ }
+
+ @override
void visitFunctionDeclaration(FunctionDeclaration node) {
if (node.parent is CompilationUnit) {
computeForMember(node, createMemberId(node));
@@ -174,6 +192,8 @@
computeForMember(node, createMemberId(node));
} else if (node.parent!.parent is FieldDeclaration) {
computeForMember(node, createMemberId(node));
+ } else {
+ computeForVariableDeclaration(node, computeDefaultNodeId(node));
}
super.visitVariableDeclaration(node);
}
@@ -184,6 +204,12 @@
offset = node.question.offset;
} else if (node is BinaryExpression) {
offset = node.operator.offset;
+ } else if (node is InstanceCreationExpression) {
+ offset = node.argumentList.leftParenthesis.offset;
+ } else if (node is InvocationExpression) {
+ offset = node.argumentList.leftParenthesis.offset;
+ } else if (node is PrefixedIdentifier) {
+ offset = node.identifier.offset;
} else {
offset = node.offset;
}
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 10eb85c..ae88729 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,10 +1,10 @@
name: analyzer
-version: 1.4.0
+version: 1.5.0-dev
description: This package provides a library that performs static analysis of Dart code.
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/analyzer
environment:
- sdk: '>=2.12.0-0 <3.0.0'
+ sdk: '>=2.12.0 <3.0.0'
dependencies:
_fe_analyzer_shared: ^20.0.0
@@ -29,5 +29,4 @@
linter: any
matcher: ^0.12.10
test: ^1.16.0
- test_api: ^0.2.19
test_reflective_loader: ^0.2.0
diff --git a/pkg/analyzer/test/id_tests/inferred_type_arguments_test.dart b/pkg/analyzer/test/id_tests/inferred_type_arguments_test.dart
new file mode 100644
index 0000000..224d689
--- /dev/null
+++ b/pkg/analyzer/test/id_tests/inferred_type_arguments_test.dart
@@ -0,0 +1,110 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:_fe_analyzer_shared/src/testing/id.dart' show ActualData, Id;
+import 'package:_fe_analyzer_shared/src/testing/id_testing.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/analysis/testing_data.dart';
+import 'package:analyzer/src/util/ast_data_extractor.dart';
+
+import '../util/id_testing_helper.dart';
+
+main(List<String> args) async {
+ Directory dataDir = Directory.fromUri(
+ Platform.script.resolve('../../../_fe_analyzer_shared/test/inference/'
+ 'inferred_type_arguments/data'));
+ return runTests<List<DartType>>(dataDir,
+ args: args,
+ createUriForFileName: createUriForFileName,
+ onFailure: onFailure,
+ runTest: runTestFor(
+ const _InferredTypeArgumentsDataComputer(), [analyzerNnbdConfig]));
+}
+
+class _InferredTypeArgumentsDataComputer extends DataComputer<List<DartType>> {
+ const _InferredTypeArgumentsDataComputer();
+
+ @override
+ DataInterpreter<List<DartType>> get dataValidator =>
+ const _InferredTypeArgumentsDataInterpreter();
+
+ @override
+ bool get supportsErrors => true;
+
+ @override
+ void computeUnitData(TestingData testingData, CompilationUnit unit,
+ Map<Id, ActualData<List<DartType>>> actualMap) {
+ _InferredTypeArgumentsDataExtractor(
+ unit.declaredElement!.source.uri, actualMap)
+ .run(unit);
+ }
+}
+
+class _InferredTypeArgumentsDataExtractor
+ extends AstDataExtractor<List<DartType>> {
+ _InferredTypeArgumentsDataExtractor(
+ Uri uri, Map<Id, ActualData<List<DartType>>> actualMap)
+ : super(uri, actualMap);
+
+ @override
+ List<DartType>? computeNodeValue(Id id, AstNode node) {
+ TypeArgumentList? typeArguments;
+ List<DartType> typeArgumentTypes;
+ if (node is InstanceCreationExpression) {
+ typeArguments = node.constructorName.type.typeArguments;
+ typeArgumentTypes =
+ (node.constructorName.type.type as InterfaceType).typeArguments;
+ } else if (node is InvocationExpression) {
+ typeArguments = node.typeArguments;
+ typeArgumentTypes = node.typeArgumentTypes!;
+ } else if (node is TypedLiteral) {
+ typeArguments = node.typeArguments;
+ typeArgumentTypes = (node.staticType as InterfaceType).typeArguments;
+ } else {
+ return null;
+ }
+ if (typeArguments == null && typeArgumentTypes.isNotEmpty) {
+ return typeArgumentTypes;
+ }
+ return null;
+ }
+}
+
+class _InferredTypeArgumentsDataInterpreter
+ implements DataInterpreter<List<DartType>> {
+ const _InferredTypeArgumentsDataInterpreter();
+
+ @override
+ String getText(List<DartType> actualData, [String? indentation]) {
+ StringBuffer sb = StringBuffer();
+ if (actualData.isNotEmpty) {
+ sb.write('<');
+ for (int i = 0; i < actualData.length; i++) {
+ if (i > 0) {
+ sb.write(',');
+ }
+ sb.write(actualData[i].getDisplayString(withNullability: true));
+ }
+ sb.write('>');
+ }
+ return sb.toString();
+ }
+
+ @override
+ String? isAsExpected(List<DartType> actualData, String? expectedData) {
+ var actualDataText = getText(actualData);
+ if (actualDataText == expectedData) {
+ return null;
+ } else {
+ return 'Expected $expectedData, got $actualDataText';
+ }
+ }
+
+ @override
+ bool isEmpty(List<DartType>? actualData) =>
+ actualData == null || actualData.isEmpty;
+}
diff --git a/pkg/analyzer/test/id_tests/inferred_variable_types_test.dart b/pkg/analyzer/test/id_tests/inferred_variable_types_test.dart
new file mode 100644
index 0000000..7f312ca
--- /dev/null
+++ b/pkg/analyzer/test/id_tests/inferred_variable_types_test.dart
@@ -0,0 +1,101 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:_fe_analyzer_shared/src/testing/id.dart' show ActualData, Id;
+import 'package:_fe_analyzer_shared/src/testing/id_testing.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/analysis/testing_data.dart';
+import 'package:analyzer/src/util/ast_data_extractor.dart';
+
+import '../util/id_testing_helper.dart';
+
+main(List<String> args) async {
+ Directory dataDir = Directory.fromUri(
+ Platform.script.resolve('../../../_fe_analyzer_shared/test/inference/'
+ 'inferred_variable_types/data'));
+ return runTests<DartType>(dataDir,
+ args: args,
+ createUriForFileName: createUriForFileName,
+ onFailure: onFailure,
+ runTest: runTestFor(
+ const _InferredVariableTypesDataComputer(), [analyzerNnbdConfig]));
+}
+
+class _InferredVariableTypesDataComputer extends DataComputer<DartType> {
+ const _InferredVariableTypesDataComputer();
+
+ @override
+ DataInterpreter<DartType> get dataValidator =>
+ const _InferredVariableTypesDataInterpreter();
+
+ @override
+ bool get supportsErrors => true;
+
+ @override
+ void computeUnitData(TestingData testingData, CompilationUnit unit,
+ Map<Id, ActualData<DartType>> actualMap) {
+ _InferredVariableTypesDataExtractor(
+ unit.declaredElement!.source.uri, actualMap)
+ .run(unit);
+ }
+}
+
+class _InferredVariableTypesDataExtractor extends AstDataExtractor<DartType> {
+ _InferredVariableTypesDataExtractor(
+ Uri uri, Map<Id, ActualData<DartType>> actualMap)
+ : super(uri, actualMap);
+
+ @override
+ DartType? computeNodeValue(Id id, AstNode node) {
+ if (node is VariableDeclaration) {
+ var element = node.declaredElement!;
+ if (element.hasImplicitType) {
+ return element.type;
+ }
+ } else if (node is FormalParameter) {
+ var element = node.declaredElement!;
+ if (element.hasImplicitType) {
+ return element.type;
+ }
+ } else if (node is FunctionDeclarationStatement) {
+ var element = node.functionDeclaration.declaredElement!;
+ if (element.hasImplicitReturnType) {
+ return element.returnType;
+ }
+ } else if (node is FunctionExpression &&
+ node.parent is! FunctionDeclaration) {
+ var element = node.declaredElement!;
+ if (element.hasImplicitReturnType) {
+ return element.returnType;
+ }
+ }
+ return null;
+ }
+}
+
+class _InferredVariableTypesDataInterpreter
+ implements DataInterpreter<DartType> {
+ const _InferredVariableTypesDataInterpreter();
+
+ @override
+ String getText(DartType actualData, [String? indentation]) {
+ return actualData.getDisplayString(withNullability: true);
+ }
+
+ @override
+ String? isAsExpected(DartType actualData, String? expectedData) {
+ var actualDataText = getText(actualData);
+ if (actualDataText == expectedData) {
+ return null;
+ } else {
+ return 'Expected $expectedData, got $actualDataText';
+ }
+ }
+
+ @override
+ bool isEmpty(DartType? actualData) => actualData == null;
+}
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
index 9ddda1e..fd84578 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
@@ -194,7 +194,7 @@
driver1.priorityFiles = [a];
driver2.priorityFiles = [a];
- ResolvedUnitResult result = await driver2.getResult(b);
+ var result = await driver2.getResult2(b) as ResolvedUnitResult;
expect(result.path, b);
await scheduler.status.firstWhere((status) => status.isIdle);
@@ -443,9 +443,9 @@
part of 'lib.dart';
''');
- ResolvedUnitResult libResult = await driver.getResult(lib);
- ResolvedUnitResult partResult1 = await driver.getResult(part1);
- ResolvedUnitResult partResult2 = await driver.getResult(part2);
+ ResolvedUnitResult libResult = await driver.getResultValid(lib);
+ ResolvedUnitResult partResult1 = await driver.getResultValid(part1);
+ ResolvedUnitResult partResult2 = await driver.getResultValid(part2);
CompilationUnit libUnit = libResult.unit!;
CompilationUnit partUnit1 = partResult1.unit!;
@@ -490,7 +490,7 @@
driver.addFile(lib);
- ResolvedUnitResult libResult = await driver.getResult(lib);
+ ResolvedUnitResult libResult = await driver.getResultValid(lib);
List<AnalysisError> errors = libResult.errors;
expect(errors, hasLength(1));
expect(errors[0].errorCode, CompileTimeErrorCode.PART_OF_UNNAMED_LIBRARY);
@@ -509,7 +509,7 @@
driver.addFile(lib);
- ResolvedUnitResult libResult = await driver.getResult(lib);
+ ResolvedUnitResult libResult = await driver.getResultValid(lib);
List<AnalysisError> errors = libResult.errors;
expect(errors, hasLength(1));
expect(errors[0].errorCode, CompileTimeErrorCode.PART_OF_DIFFERENT_LIBRARY);
@@ -528,7 +528,7 @@
driver.addFile(lib);
- ResolvedUnitResult libResult = await driver.getResult(lib);
+ ResolvedUnitResult libResult = await driver.getResultValid(lib);
List<AnalysisError> errors = libResult.errors;
expect(errors, hasLength(1));
expect(errors[0].errorCode, CompileTimeErrorCode.PART_OF_DIFFERENT_LIBRARY);
@@ -547,7 +547,7 @@
driver.addFile(lib);
- ResolvedUnitResult libResult = await driver.getResult(lib);
+ ResolvedUnitResult libResult = await driver.getResultValid(lib);
List<AnalysisError> errors = libResult.errors;
expect(errors, hasLength(1));
expect(errors[0].errorCode, CompileTimeErrorCode.PART_OF_NON_PART);
@@ -559,7 +559,7 @@
driver.priorityFiles = [a];
- ResolvedUnitResult result1 = await driver.getResult(a);
+ ResolvedUnitResult result1 = await driver.getResultValid(a);
expect(driver.test.priorityResults, containsPair(a, result1));
await waitForIdleWithoutExceptions();
@@ -567,15 +567,14 @@
// Get the (cached) result, not reported to the stream.
{
- ResolvedUnitResult result2 = await driver.getResult(a);
+ ResolvedUnitResult result2 = await driver.getResultValid(a);
expect(result2, same(result1));
expect(allResults, isEmpty);
}
// Get the (cached) result, reported to the stream.
{
- ResolvedUnitResult result2 =
- await driver.getResult(a, sendCachedToStream: true);
+ var result2 = await driver.getResult2(a, sendCachedToStream: true);
expect(result2, same(result1));
expect(allResults, hasLength(1));
@@ -591,21 +590,21 @@
driver.priorityFiles = [a];
- ResolvedUnitResult result1 = await driver.getResult(a);
+ ResolvedUnitResult result1 = await driver.getResultValid(a);
expect(driver.test.priorityResults, containsPair(a, result1));
// Change a file.
// The cache is flushed.
driver.changeFile(a);
expect(driver.test.priorityResults, isEmpty);
- ResolvedUnitResult result2 = await driver.getResult(a);
+ ResolvedUnitResult result2 = await driver.getResultValid(a);
expect(driver.test.priorityResults, containsPair(a, result2));
// Add a file.
// The cache is flushed.
driver.addFile(b);
expect(driver.test.priorityResults, isEmpty);
- ResolvedUnitResult result3 = await driver.getResult(a);
+ ResolvedUnitResult result3 = await driver.getResultValid(a);
expect(driver.test.priorityResults, containsPair(a, result3));
// Remove a file.
@@ -622,7 +621,7 @@
driver.priorityFiles = [a];
- ResolvedUnitResult result1 = await driver.getResult(a);
+ ResolvedUnitResult result1 = await driver.getResultValid(a);
expect(driver.test.priorityResults, hasLength(1));
expect(driver.test.priorityResults, containsPair(a, result1));
@@ -633,7 +632,7 @@
expect(driver.test.priorityResults, containsPair(a, result1));
// Get the result for "b".
- ResolvedUnitResult result2 = await driver.getResult(b);
+ ResolvedUnitResult result2 = await driver.getResultValid(b);
expect(driver.test.priorityResults, hasLength(2));
expect(driver.test.priorityResults, containsPair(a, result1));
expect(driver.test.priorityResults, containsPair(b, result2));
@@ -649,11 +648,11 @@
var a = convertPath('/test/bin/a.dart');
newFile(a, content: 'var a = 1;');
- ResolvedUnitResult result1 = await driver.getResult(a);
+ ResolvedUnitResult result1 = await driver.getResultValid(a);
expect(driver.test.priorityResults, isEmpty);
// The file is not priority, so its result is not cached.
- ResolvedUnitResult result2 = await driver.getResult(a);
+ ResolvedUnitResult result2 = await driver.getResultValid(a);
expect(result2, isNot(same(result1)));
}
@@ -823,7 +822,7 @@
@A(5)
class C {}
''');
- var result = await driver.getResult(testFile);
+ var result = await driver.getResultValid(testFile);
var atD = AstFinder.getClass(result.unit!, 'C').metadata[0];
var atDI = atD.elementAnnotation as ElementAnnotationImpl;
var value = atDI.evaluationResult!.value;
@@ -840,7 +839,7 @@
final value;
}
''');
- var result = await driver.getResult(testFile);
+ var result = await driver.getResultValid(testFile);
var atD = AstFinder.getClass(result.unit!, 'C').metadata[0];
var atDI = atD.elementAnnotation as ElementAnnotationImpl;
var value = atDI.evaluationResult!.value!;
@@ -856,7 +855,7 @@
const x = 1;
@x class C {}
''');
- var result = await driver.getResult(testFile);
+ var result = await driver.getResultValid(testFile);
Annotation at_x = AstFinder.getClass(result.unit!, 'C').metadata[0];
expect(at_x.elementAnnotation!.computeConstantValue()!.toIntValue(), 1);
}
@@ -866,7 +865,7 @@
const x = y + 1;
const y = x + 1;
''');
- var result = await driver.getResult(testFile);
+ var result = await driver.getResultValid(testFile);
var x = AstFinder.getTopLevelVariableElement(result.unit!, 'x')
as TopLevelVariableElementImpl;
_expectCircularityError(x.evaluationResult!);
@@ -877,7 +876,7 @@
const x = y + 1;
const y = 1;
''');
- var result = await driver.getResult(testFile);
+ var result = await driver.getResultValid(testFile);
var x = AstFinder.getTopLevelVariableElement(result.unit!, 'x');
var y = AstFinder.getTopLevelVariableElement(result.unit!, 'y');
expect(x.computeConstantValue()!.toIntValue(), 2);
@@ -894,7 +893,7 @@
class B {}
''');
- var result = await driver.getResult(testFile);
+ var result = await driver.getResultValid(testFile);
var x = AstFinder.getTopLevelVariableElement(result.unit!, 'x');
expect(x.computeConstantValue(), isNotNull);
}
@@ -919,7 +918,7 @@
const c = C.WARNING;
const d = D.WARNING;
''');
- ResolvedUnitResult result = await driver.getResult(b);
+ ResolvedUnitResult result = await driver.getResultValid(b);
expect(result.errors, isEmpty);
}
@@ -948,7 +947,7 @@
const C();
}
''');
- ResolvedUnitResult result = await driver.getResult(b);
+ ResolvedUnitResult result = await driver.getResultValid(b);
expect(result.errors, isEmpty);
}
@@ -960,7 +959,7 @@
}
const x = const Derived();
''');
- var result = await driver.getResult(testFile);
+ var result = await driver.getResultValid(testFile);
var x = AstFinder.getTopLevelVariableElement(result.unit!, 'x');
expect(x.computeConstantValue(), isNotNull);
}
@@ -969,7 +968,7 @@
addTestFile('''
const x = 1;
''');
- var result = await driver.getResult(testFile);
+ var result = await driver.getResultValid(testFile);
var x = AstFinder.getTopLevelVariableElement(result.unit!, 'x');
expect(x.computeConstantValue()!.toIntValue(), 1);
}
@@ -978,14 +977,14 @@
var a = convertPath('/a.dart');
newFile(a, content: 'var V = 1;');
- await driver.getResult(a);
+ await driver.getResultValid(a);
var session1 = driver.currentSession;
expect(session1, isNotNull);
modifyFile(a, 'var V = 2;');
driver.changeFile(a);
- await driver.getResult(a);
+ await driver.getResultValid(a);
var session2 = driver.currentSession;
expect(session2, isNotNull);
@@ -1046,7 +1045,7 @@
export 'foo.dart';
''');
- ResolvedUnitResult result = await driver.getResult(testFile);
+ ResolvedUnitResult result = await driver.getResultValid(testFile);
List<AnalysisError> errors = result.errors;
expect(errors, hasLength(1));
expect(errors[0].errorCode, CompileTimeErrorCode.URI_DOES_NOT_EXIST);
@@ -1057,7 +1056,7 @@
import 'foo.dart';
''');
- ResolvedUnitResult result = await driver.getResult(testFile);
+ ResolvedUnitResult result = await driver.getResultValid(testFile);
List<AnalysisError> errors = result.errors;
expect(errors, hasLength(1));
expect(errors[0].errorCode, CompileTimeErrorCode.URI_DOES_NOT_EXIST);
@@ -1071,7 +1070,7 @@
}
''', priority: true);
- ResolvedUnitResult result = await driver.getResult(testFile);
+ ResolvedUnitResult result = await driver.getResultValid(testFile);
List<AnalysisError> errors = result.errors;
expect(errors, hasLength(1));
expect(errors[0].errorCode, CompileTimeErrorCode.URI_DOES_NOT_EXIST);
@@ -1083,12 +1082,13 @@
part 'foo.dart';
''');
- ResolvedUnitResult result = await driver.getResult(testFile);
+ ResolvedUnitResult result = await driver.getResultValid(testFile);
List<AnalysisError> errors = result.errors;
expect(errors, hasLength(1));
expect(errors[0].errorCode, CompileTimeErrorCode.URI_DOES_NOT_EXIST);
}
+ @deprecated
test_generatedFile() async {
Uri uri = Uri.parse('package:aaa/foo.dart');
String templatePath = convertPath('/aaa/lib/foo.dart');
@@ -1127,11 +1127,82 @@
expect(allExceptions, isEmpty);
expect(allResults, isEmpty);
- var elementResult = await driver.getUnitElement(templatePath);
- expect(elementResult.state, ResultState.NOT_FILE_OF_URI);
+ {
+ var elementResult = await driver.getUnitElement(templatePath);
+ expect(elementResult.state, ResultState.NOT_FILE_OF_URI);
+ expect(allExceptions, isEmpty);
+ expect(allResults, isEmpty);
+ }
+
+ {
+ var elementResult = await driver.getUnitElement2(templatePath);
+ expect(elementResult, isA<NotPathOfUriResult>());
+ expect(allExceptions, isEmpty);
+ expect(allResults, isEmpty);
+ }
+
+ driver.priorityFiles = [templatePath];
+ driver.changeFile(templatePath);
+ await waitForIdleWithoutExceptions();
expect(allExceptions, isEmpty);
expect(allResults, isEmpty);
+ expect(driver.knownFiles, isNot(contains(templatePath)));
+ }
+
+ test_generatedFile2() async {
+ Uri uri = Uri.parse('package:aaa/foo.dart');
+ String templatePath = convertPath('/aaa/lib/foo.dart');
+ String generatedPath = convertPath('/generated/aaa/lib/foo.dart');
+
+ newFile(templatePath, content: r'''
+a() {}
+b() {}
+''');
+
+ newFile(generatedPath, content: r'''
+aaa() {}
+bbb() {}
+''');
+
+ Source generatedSource = _SourceMock(generatedPath, uri);
+
+ generatedUriResolver.resolveAbsoluteFunction = (uri) => generatedSource;
+ generatedUriResolver.restoreAbsoluteFunction = (Source source) {
+ String path = source.fullName;
+ if (path == templatePath || path == generatedPath) {
+ return uri;
+ } else {
+ return null;
+ }
+ };
+
+ driver.addFile(templatePath);
+
+ await waitForIdleWithoutExceptions();
+ expect(allExceptions, isEmpty);
+ expect(allResults, isEmpty);
+
+ var result = await driver.getResult2(templatePath);
+ expect(result, isA<NotPathOfUriResult>());
+ expect(allExceptions, isEmpty);
+ expect(allResults, isEmpty);
+
+ {
+ // ignore: deprecated_member_use_from_same_package
+ var elementResult = await driver.getUnitElement(templatePath);
+ expect(elementResult.state, ResultState.NOT_FILE_OF_URI);
+ expect(allExceptions, isEmpty);
+ expect(allResults, isEmpty);
+ }
+
+ {
+ var elementResult = await driver.getUnitElement2(templatePath);
+ expect(elementResult, isA<NotPathOfUriResult>());
+ expect(allExceptions, isEmpty);
+ expect(allResults, isEmpty);
+ }
+
driver.priorityFiles = [templatePath];
driver.changeFile(templatePath);
await waitForIdleWithoutExceptions();
@@ -1148,7 +1219,7 @@
expect(driver.getCachedResult(a), isNull);
driver.priorityFiles = [a];
- ResolvedUnitResult result = await driver.getResult(a);
+ ResolvedUnitResult result = await driver.getResultValid(a);
expect(driver.getCachedResult(a), same(result));
}
@@ -1285,7 +1356,7 @@
// Ensure that [a.dart] library cycle is loaded.
// So, `a.dart` is in the library context.
- await driver.getResult(a);
+ await driver.getResultValid(a);
// Update the file, changing its API signature.
// Note that we don't call `changeFile`.
@@ -1299,14 +1370,14 @@
expect(driver.getFileSync(a).lineInfo.lineCount, 1);
// We have not read `a.dart`, so `A` is still not declared.
- expect((await driver.getResult(b)).errors, isNotEmpty);
+ expect((await driver.getResultValid(b)).errors, isNotEmpty);
// Notify the driver that the file was changed.
driver.changeFile(a);
// So, `class A {}` is declared now.
expect(driver.getFileSync(a).lineInfo.lineCount, 2);
- expect((await driver.getResult(b)).errors, isEmpty);
+ expect((await driver.getResultValid(b)).errors, isEmpty);
}
test_getFileSync_library() async {
@@ -1395,7 +1466,7 @@
String content = 'int f() => 42;';
addTestFile(content, priority: true);
- ResolvedUnitResult result = await driver.getResult(testFile);
+ ResolvedUnitResult result = await driver.getResultValid(testFile);
expect(result.path, testFile);
expect(result.uri.toString(), 'package:test/test.dart');
expect(result.state, ResultState.VALID);
@@ -1412,6 +1483,11 @@
expect(allResults, [result]);
}
+ test_getResult2_notAbsolutePath() async {
+ var result = await driver.getResult2('not_absolute.dart');
+ expect(result, isA<InvalidPathResult>());
+ }
+
test_getResult_constants_defaultParameterValue_localFunction() async {
var a = convertPath('/test/bin/a.dart');
var b = convertPath('/test/bin/b.dart');
@@ -1427,14 +1503,14 @@
driver.addFile(b);
await waitForIdleWithoutExceptions();
- ResolvedUnitResult result = await driver.getResult(b);
+ ResolvedUnitResult result = await driver.getResultValid(b);
expect(result.errors, isEmpty);
}
test_getResult_doesNotExist() async {
var a = convertPath('/test/lib/a.dart');
- ResolvedUnitResult result = await driver.getResult(a);
+ ResolvedUnitResult result = await driver.getResultValid(a);
expect(result.path, a);
expect(result.uri.toString(), 'package:test/a.dart');
expect(result.state, ResultState.NOT_A_FILE);
@@ -1445,7 +1521,7 @@
String content = 'main() { int vv; }';
addTestFile(content, priority: true);
- ResolvedUnitResult result = await driver.getResult(testFile);
+ ResolvedUnitResult result = await driver.getResultValid(testFile);
expect(result.path, testFile);
expect(result.errors, hasLength(1));
{
@@ -1468,7 +1544,7 @@
class B {}
''');
- ResolvedUnitResult result = await driver.getResult(testFile);
+ ResolvedUnitResult result = await driver.getResultValid(testFile);
expect(result.path, testFile);
}
@@ -1480,7 +1556,7 @@
''';
addTestFile(content, priority: true);
- var result = await driver.getResult(testFile);
+ var result = await driver.getResultValid(testFile);
expect(result.errors, isEmpty);
}
@@ -1499,7 +1575,7 @@
// No errors in b.dart
{
- ResolvedUnitResult result = await driver.getResult(b);
+ ResolvedUnitResult result = await driver.getResultValid(b);
expect(result.errors, isEmpty);
}
@@ -1509,7 +1585,7 @@
// The unresolved URI error must be reported.
{
- ResolvedUnitResult result = await driver.getResult(b);
+ ResolvedUnitResult result = await driver.getResultValid(b);
expect(
result.errors,
contains(predicate((AnalysisError e) =>
@@ -1522,7 +1598,7 @@
// No errors in b.dart again.
{
- ResolvedUnitResult result = await driver.getResult(b);
+ ResolvedUnitResult result = await driver.getResultValid(b);
expect(result.errors, isEmpty);
}
}
@@ -1535,7 +1611,7 @@
''', priority: true);
await waitForIdleWithoutExceptions();
- ResolvedUnitResult result = await driver.getResult(testFile);
+ ResolvedUnitResult result = await driver.getResultValid(testFile);
_assertClassFieldType(result.unit!, 'C', 'f', 'int');
}
@@ -1550,7 +1626,7 @@
''', priority: true);
await waitForIdleWithoutExceptions();
- ResolvedUnitResult result = await driver.getResult(testFile);
+ ResolvedUnitResult result = await driver.getResultValid(testFile);
_assertClassMethodReturnType(result.unit!, 'A', 'm', 'int');
_assertClassMethodReturnType(result.unit!, 'B', 'm', 'int');
}
@@ -1563,7 +1639,7 @@
class C {}
''', priority: true);
- ResolvedUnitResult result = await driver.getResult(testFile);
+ ResolvedUnitResult result = await driver.getResultValid(testFile);
ClassDeclaration c = result.unit!.declarations[1] as ClassDeclaration;
Annotation a = c.metadata[0];
expect(a.name.name, 'fff');
@@ -1590,7 +1666,7 @@
''';
addTestFile(content);
- ResolvedUnitResult result = await driver.getResult(testFile);
+ ResolvedUnitResult result = await driver.getResultValid(testFile);
expect(result.path, testFile);
}
@@ -1602,7 +1678,7 @@
''';
addTestFile(content, priority: true);
- ResolvedUnitResult result = await driver.getResult(testFile);
+ ResolvedUnitResult result = await driver.getResultValid(testFile);
expect(result.path, testFile);
// Has only exports for valid URIs.
List<ExportElement> imports = result.libraryElement.exports;
@@ -1619,7 +1695,7 @@
''';
addTestFile(content, priority: true);
- ResolvedUnitResult result = await driver.getResult(testFile);
+ ResolvedUnitResult result = await driver.getResultValid(testFile);
expect(result.path, testFile);
// Has only imports for valid URIs.
List<ImportElement> imports = result.libraryElement.imports;
@@ -1640,7 +1716,7 @@
part '';
''';
addTestFile(content);
- await driver.getResult(testFile);
+ await driver.getResultValid(testFile);
}
test_getResult_languageVersion() async {
@@ -1650,7 +1726,7 @@
class A{}
''');
- var result = await driver.getResult(path);
+ var result = await driver.getResultValid(path);
var languageVersion = result.unit!.languageVersionToken!;
expect(languageVersion.major, 2);
expect(languageVersion.minor, 7);
@@ -1687,7 +1763,7 @@
// package:my_pkg/c.dart's import is erroneous, causing y's reference to z
// to be unresolved (and therefore have type dynamic).
{
- ResolvedUnitResult result = await driver.getResult(a);
+ ResolvedUnitResult result = await driver.getResultValid(a);
expect(result.errors, isEmpty);
}
@@ -1697,7 +1773,7 @@
// successfully imports file:///my_pkg/test/d.dart, causing y to have an
// inferred type of String.
{
- ResolvedUnitResult result = await driver.getResult(b);
+ ResolvedUnitResult result = await driver.getResultValid(b);
List<AnalysisError> errors = result.errors;
expect(errors, hasLength(1));
expect(errors[0].errorCode, CompileTimeErrorCode.INVALID_ASSIGNMENT);
@@ -1711,7 +1787,7 @@
var V;
''';
addTestFile(content);
- await driver.getResult(testFile);
+ await driver.getResultValid(testFile);
}
test_getResult_nameConflict_local_typeInference() async {
@@ -1725,9 +1801,10 @@
}
''';
addTestFile(content);
- await driver.getResult(testFile);
+ await driver.getResultValid(testFile);
}
+ @deprecated
test_getResult_notAbsolutePath() async {
expect(() async {
await driver.getResult('not_absolute.dart');
@@ -1738,7 +1815,7 @@
var path = convertPath('/test/lib/test.txt');
newFile(path, content: 'class A {}');
- ResolvedUnitResult result = await driver.getResult(path);
+ ResolvedUnitResult result = await driver.getResultValid(path);
expect(result, isNotNull);
expect(result.unit!.declaredElement!.types.map((e) => e.name), ['A']);
}
@@ -1750,7 +1827,7 @@
''';
addTestFile(content);
// Should not throw exceptions.
- await driver.getResult(testFile);
+ await driver.getResultValid(testFile);
}
test_getResult_sameFile_twoUris() async {
@@ -1772,14 +1849,14 @@
await waitForIdleWithoutExceptions();
{
- ResolvedUnitResult result = await driver.getResult(b);
+ ResolvedUnitResult result = await driver.getResultValid(b);
expect(_getImportSource(result.unit!, 0).uri.toString(),
'package:test/a.dart');
_assertTopLevelVarType(result.unit!, 'VB', 'A<int>');
}
{
- ResolvedUnitResult result = await driver.getResult(c);
+ ResolvedUnitResult result = await driver.getResultValid(c);
expect(
_getImportSource(result.unit!, 0).uri,
toUri('/test/lib/a.dart'),
@@ -1806,7 +1883,7 @@
await waitForIdleWithoutExceptions();
{
- ResolvedUnitResult result = await driver.getResult(a);
+ ResolvedUnitResult result = await driver.getResultValid(a);
_assertTopLevelVarType(result.unit!, 'A1', 'int');
_assertTopLevelVarType(result.unit!, 'A2', 'int');
}
@@ -1826,7 +1903,7 @@
driver.changeFile(a);
{
- ResolvedUnitResult result = await driver.getResult(a);
+ ResolvedUnitResult result = await driver.getResultValid(a);
_assertTopLevelVarType(result.unit!, 'A1', 'double');
_assertTopLevelVarType(result.unit!, 'A2', 'double');
}
@@ -1835,7 +1912,7 @@
test_getResult_thenRemove() async {
addTestFile('main() {}', priority: true);
- var resultFuture = driver.getResult(testFile);
+ var resultFuture = driver.getResultValid(testFile);
driver.removeFile(testFile);
var result = await resultFuture;
@@ -1847,8 +1924,8 @@
String content = 'main() {}';
addTestFile(content, priority: true);
- var future1 = driver.getResult(testFile);
- var future2 = driver.getResult(testFile);
+ var future1 = driver.getResultValid(testFile);
+ var future2 = driver.getResultValid(testFile);
// Both futures complete, with the same result.
ResolvedUnitResult result1 = await future1;
@@ -1871,7 +1948,7 @@
// Ensure that [a.dart] library cycle is loaded.
// So, `a.dart` is in the library context.
- await driver.getResult(a);
+ await driver.getResultValid(a);
// Update the file, changing its API signature.
// Note that we don't call `changeFile`.
@@ -1885,14 +1962,14 @@
expect(await driver.getSourceKind(a), SourceKind.PART);
// We have not read `a.dart`, so `A` is still not declared.
- expect((await driver.getResult(b)).errors, isNotEmpty);
+ expect((await driver.getResultValid(b)).errors, isNotEmpty);
// Notify the driver that the file was changed.
driver.changeFile(a);
// So, `class A {}` is declared now.
expect(await driver.getSourceKind(a), SourceKind.LIBRARY);
- expect((await driver.getResult(b)).errors, isEmpty);
+ expect((await driver.getResultValid(b)).errors, isEmpty);
}
test_getSourceKind_changeFile() async {
@@ -1937,6 +2014,7 @@
expect(await driver.getSourceKind(path), SourceKind.PART);
}
+ @deprecated
test_getUnitElement() async {
String content = r'''
foo(int p) {}
@@ -1953,6 +2031,49 @@
unorderedEquals(['foo', 'main']));
}
+ test_getUnitElement2() async {
+ String content = r'''
+foo(int p) {}
+main() {
+ foo(42);
+}
+''';
+ addTestFile(content);
+
+ var unitResult = await driver.getUnitElement2(testFile);
+ unitResult as UnitElementResult;
+ CompilationUnitElement unitElement = unitResult.element;
+ expect(unitElement.source.fullName, testFile);
+ expect(unitElement.functions.map((c) => c.name),
+ unorderedEquals(['foo', 'main']));
+ }
+
+ test_getUnitElement2_doesNotExist_afterResynthesized() async {
+ var a = convertPath('/test/lib/a.dart');
+ var b = convertPath('/test/lib/b.dart');
+
+ newFile(a, content: r'''
+import 'package:test/b.dart';
+''');
+
+ await driver.getResolvedLibrary(a);
+ await driver.getUnitElement2(b);
+ }
+
+ test_getUnitElement2_notAbsolutePath() async {
+ var result = await driver.getUnitElement2('not_absolute.dart');
+ expect(result, isA<InvalidPathResult>());
+ }
+
+ test_getUnitElement2_notDart() async {
+ var path = convertPath('/test.txt');
+ newFile(path, content: 'class A {}');
+ var unitResult = await driver.getUnitElement2(path);
+ unitResult as UnitElementResult;
+ expect(unitResult.element.types.map((e) => e.name), ['A']);
+ }
+
+ @deprecated
test_getUnitElement_doesNotExist_afterResynthesized() async {
var a = convertPath('/test/lib/a.dart');
var b = convertPath('/test/lib/b.dart');
@@ -1965,12 +2086,14 @@
await driver.getUnitElement(b);
}
+ @deprecated
test_getUnitElement_notAbsolutePath() async {
expect(() async {
await driver.getUnitElement('not_absolute.dart');
}, throwsArgumentError);
}
+ @deprecated
test_getUnitElement_notDart() async {
var path = convertPath('/test.txt');
newFile(path, content: 'class A {}');
@@ -1978,6 +2101,7 @@
expect(unitResult.element.types.map((e) => e.name), ['A']);
}
+ @deprecated
test_getUnitElementSignature() async {
var a = convertPath('/test/lib/a.dart');
@@ -1998,6 +2122,27 @@
expect(signature2, isNot(signature));
}
+ test_getUnitElementSignature2() async {
+ var a = convertPath('/test/lib/a.dart');
+
+ newFile(a, content: 'foo() {}');
+
+ String signature = await driver.getUnitElementSignature(a);
+ expect(signature, isNotNull);
+
+ var unitResult = await driver.getUnitElement2(a);
+ unitResult as UnitElementResult;
+ expect(unitResult.path, a);
+ expect(unitResult.signature, signature);
+
+ modifyFile(a, 'bar() {}');
+ driver.changeFile(a);
+
+ String signature2 = await driver.getUnitElementSignature(a);
+ expect(signature2, isNotNull);
+ expect(signature2, isNot(signature));
+ }
+
test_hasFilesToAnalyze() async {
// No files yet, nothing to analyze.
expect(driver.hasFilesToAnalyze, isFalse);
@@ -2011,7 +2156,7 @@
expect(driver.hasFilesToAnalyze, isFalse);
// Ask to analyze the file, so there is a file to analyze.
- var future = driver.getResult(testFile);
+ var future = driver.getResultValid(testFile);
expect(driver.hasFilesToAnalyze, isTrue);
// Once analysis is done, there is nothing to analyze.
@@ -2048,7 +2193,7 @@
driver.addFile(a);
driver.addFile(b);
- await driver.getResult(b);
+ await driver.getResultValid(b);
// Modify the library, but don't notify the driver.
// The driver should use the previous library content and elements.
@@ -2060,7 +2205,7 @@
}
''');
- var result = await driver.getResult(b);
+ var result = await driver.getResultValid(b);
var c = _getTopLevelVar(result.unit!, 'c');
var typeC = c.declaredElement!.type as InterfaceType;
// The class C has an old field 'foo', not the new 'bar'.
@@ -2082,7 +2227,7 @@
driver.addFile(a);
driver.addFile(b);
- ResolvedUnitResult result = await driver.getResult(a);
+ ResolvedUnitResult result = await driver.getResultValid(a);
expect(result.errors, isEmpty);
_assertTopLevelVarType(result.unit!, 'b', 'B');
}
@@ -2107,10 +2252,10 @@
''');
// This ensures that `a.dart` linked library is cached.
- await driver.getResult(a);
+ await driver.getResultValid(a);
// Should not fail because of considering `b.dart` part as `a.dart` library.
- await driver.getResult(c);
+ await driver.getResultValid(c);
}
test_instantiateToBounds_invalid() async {
@@ -2245,7 +2390,7 @@
// Ensure that [a.dart] library cycle is loaded.
// So, `a.dart` is in the library context.
- await driver.getResult(a);
+ await driver.getResultValid(a);
// Update the file, changing its API signature.
// Note that we don't call `changeFile`.
@@ -2263,7 +2408,7 @@
// We have not read `a.dart`, so `A` is still not declared.
{
- var bResult = await driver.getResult(b);
+ var bResult = await driver.getResultValid(b);
expect(bResult.errors, isNotEmpty);
}
@@ -2276,7 +2421,7 @@
expect(parseResult.unit.declarations, hasLength(1));
}
{
- var bResult = await driver.getResult(b);
+ var bResult = await driver.getResultValid(b);
expect(bResult.errors, isEmpty);
}
}
@@ -2309,7 +2454,7 @@
// Ensure that [a.dart] library cycle is loaded.
// So, `a.dart` is in the library context.
- await driver.getResult(a);
+ await driver.getResultValid(a);
// Update the file, changing its API signature.
// Note that we don't call `changeFile`.
@@ -2327,7 +2472,7 @@
// We have not read `a.dart`, so `A` is still not declared.
{
- var bResult = await driver.getResult(b);
+ var bResult = await driver.getResultValid(b);
expect(bResult.errors, isNotEmpty);
}
@@ -2340,7 +2485,7 @@
expect(parseResult.unit.declarations, hasLength(1));
}
{
- var bResult = await driver.getResult(b);
+ var bResult = await driver.getResultValid(b);
expect(bResult.errors, isEmpty);
}
}
@@ -2519,14 +2664,14 @@
// Process a.dart so that we know that it's a library for c.dart later.
{
- ResolvedUnitResult result = await driver.getResult(a);
+ ResolvedUnitResult result = await driver.getResultValid(a);
expect(result.errors, isEmpty);
_assertTopLevelVarType(result.unit!, 'c', 'C');
}
// Now c.dart can be resolved without errors in the context of a.dart
{
- ResolvedUnitResult result = await driver.getResult(c);
+ ResolvedUnitResult result = await driver.getResultValid(c);
expect(result.errors, isEmpty);
_assertTopLevelVarType(result.unit!, 'a', 'A');
_assertTopLevelVarType(result.unit!, 'b', 'B');
@@ -2558,7 +2703,7 @@
// b.dart will be analyzed after a.dart is analyzed.
// So, A and B references are resolved.
- ResolvedUnitResult result = await driver.getResult(c);
+ ResolvedUnitResult result = await driver.getResultValid(c);
expect(result.errors, isEmpty);
_assertTopLevelVarType(result.unit!, 'a', 'A');
_assertTopLevelVarType(result.unit!, 'b', 'B');
@@ -2574,7 +2719,7 @@
driver.addFile(a);
// Analyze the library without the part.
- await driver.getResult(a);
+ await driver.getResultValid(a);
// Create the part file.
// This should invalidate library file state (specifically the library
@@ -2586,7 +2731,7 @@
driver.changeFile(b);
// This should not crash.
- var result = await driver.getResult(b);
+ var result = await driver.getResultValid(b);
expect(result.errors, isEmpty);
}
@@ -2603,11 +2748,114 @@
// There is no library which c.dart is a part of, so it has unresolved
// A and B references.
- ResolvedUnitResult result = await driver.getResult(c);
+ ResolvedUnitResult result = await driver.getResultValid(c);
expect(result.errors, isNotEmpty);
expect(result.unit!, isNotNull);
}
+ test_part_getUnitElement2_afterLibrary() async {
+ var a = convertPath('/test/lib/a.dart');
+ var b = convertPath('/test/lib/b.dart');
+ var c = convertPath('/test/lib/c.dart');
+ newFile(a, content: r'''
+library a;
+import 'b.dart';
+part 'c.dart';
+class A {}
+var c = new C();
+''');
+ newFile(b, content: 'class B {}');
+ newFile(c, content: r'''
+part of a;
+class C {}
+var a = new A();
+var b = new B();
+''');
+
+ driver.addFile(a);
+ driver.addFile(b);
+ driver.addFile(c);
+
+ // Process a.dart so that we know that it's a library for c.dart later.
+ await driver.getResultValid(a);
+
+ // c.dart is resolve in the context of a.dart, knows 'A' and 'B'.
+ {
+ var result = await driver.getUnitElement2(c);
+ result as UnitElementResult;
+ var partUnit = result.element;
+
+ assertType(partUnit.topLevelVariables[0].type, 'A');
+ assertType(partUnit.topLevelVariables[1].type, 'B');
+
+ var libraryUnit = partUnit.library.definingCompilationUnit;
+ assertType(libraryUnit.topLevelVariables[0].type, 'C');
+ }
+ }
+
+ test_part_getUnitElement2_beforeLibrary() async {
+ var a = convertPath('/test/lib/a.dart');
+ var b = convertPath('/test/lib/b.dart');
+ var c = convertPath('/test/lib/c.dart');
+ newFile(a, content: r'''
+library a;
+import 'b.dart';
+part 'c.dart';
+class A {}
+var c = new C();
+''');
+ newFile(b, content: 'class B {}');
+ newFile(c, content: r'''
+part of a;
+class C {}
+var a = new A();
+var b = new B();
+''');
+
+ driver.addFile(a);
+ driver.addFile(b);
+ driver.addFile(c);
+
+ // c.dart is resolve in the context of a.dart, knows 'A' and 'B'.
+ {
+ var result = await driver.getUnitElement2(c);
+ result as UnitElementResult;
+ var partUnit = result.element;
+
+ assertType(partUnit.topLevelVariables[0].type, 'A');
+ assertType(partUnit.topLevelVariables[1].type, 'B');
+
+ var libraryUnit = partUnit.library.definingCompilationUnit;
+ assertType(libraryUnit.topLevelVariables[0].type, 'C');
+ }
+ }
+
+ test_part_getUnitElement2_noLibrary() async {
+ var c = convertPath('/test/lib/c.dart');
+ newFile(c, content: r'''
+part of a;
+var a = new A();
+var b = new B();
+''');
+
+ driver.addFile(c);
+
+ // We don't know the library of c.dart, but we should get a result.
+ // The types "A" and "B" are unresolved.
+ {
+ var result = await driver.getUnitElement2(c);
+ result as UnitElementResult;
+ var partUnit = result.element;
+
+ expect(partUnit.topLevelVariables[0].name, 'a');
+ assertType(partUnit.topLevelVariables[0].type, 'dynamic');
+
+ expect(partUnit.topLevelVariables[1].name, 'b');
+ assertType(partUnit.topLevelVariables[1].type, 'dynamic');
+ }
+ }
+
+ @deprecated
test_part_getUnitElement_afterLibrary() async {
var a = convertPath('/test/lib/a.dart');
var b = convertPath('/test/lib/b.dart');
@@ -2632,7 +2880,7 @@
driver.addFile(c);
// Process a.dart so that we know that it's a library for c.dart later.
- await driver.getResult(a);
+ await driver.getResultValid(a);
// c.dart is resolve in the context of a.dart, knows 'A' and 'B'.
{
@@ -2647,6 +2895,7 @@
}
}
+ @deprecated
test_part_getUnitElement_beforeLibrary() async {
var a = convertPath('/test/lib/a.dart');
var b = convertPath('/test/lib/b.dart');
@@ -2683,6 +2932,7 @@
}
}
+ @deprecated
test_part_getUnitElement_noLibrary() async {
var c = convertPath('/test/lib/c.dart');
newFile(c, content: r'''
@@ -2734,7 +2984,7 @@
String signatureBefore = await driver.getUnitElementSignature(c);
// Process a.dart so that we know that it's a library for c.dart later.
- await driver.getResult(a);
+ await driver.getResultValid(a);
// The before and after signatures must be the same.
String signatureAfter = await driver.getUnitElementSignature(c);
@@ -3356,3 +3606,9 @@
throw StateError('Unexpected invocation of ${invocation.memberName}');
}
}
+
+extension on AnalysisDriver {
+ Future<ResolvedUnitResult> getResultValid(String path) async {
+ return await getResult2(path) as ResolvedUnitResult;
+ }
+}
diff --git a/pkg/analyzer/test/src/dart/analysis/search_test.dart b/pkg/analyzer/test/src/dart/analysis/search_test.dart
index 10ac334..210b9b9 100644
--- a/pkg/analyzer/test/src/dart/analysis/search_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/search_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/analysis/results.dart';
import 'package:analyzer/dart/ast/ast.dart' hide Declaration;
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/dart/analysis/driver.dart';
@@ -376,7 +377,8 @@
''');
var element = findElement.unnamedConstructor('A');
- CompilationUnit otherUnit = (await driver.getResult(other)).unit!;
+ var otherUnitResult = await driver.getResult2(other) as ResolvedUnitResult;
+ CompilationUnit otherUnit = otherUnitResult.unit!;
Element main = otherUnit.declaredElement!.functions[0];
var expected = [
ExpectedResult(main, SearchResultKind.REFERENCE,
diff --git a/pkg/analyzer/test/src/dart/analysis/session_test.dart b/pkg/analyzer/test/src/dart/analysis/session_test.dart
index f1235ca..7812b9d 100644
--- a/pkg/analyzer/test/src/dart/analysis/session_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/session_test.dart
@@ -51,6 +51,32 @@
expect(result.uri.toString(), 'package:dart.my/a.dart');
}
+ void test_getResolvedUnit2_notFileOfUri() async {
+ var relPath = 'dart/my/lib/a.dart';
+ newFile('$workspaceRootPath/bazel-bin/$relPath');
+
+ var path = convertPath('$workspaceRootPath/$relPath');
+ var session = contextFor(path).currentSession;
+ var result = await session.getResolvedUnit2(path);
+ expect(result, isA<NotPathOfUriResult>());
+ }
+
+ void test_getResolvedUnit2_valid() async {
+ var file = newFile(
+ '$workspaceRootPath/dart/my/lib/a.dart',
+ content: 'class A {}',
+ );
+
+ var session = contextFor(file.path).currentSession;
+ var result =
+ await session.getResolvedUnit2(file.path) as ResolvedUnitResult;
+ expect(result.state, ResultState.VALID);
+ expect(result.path, file.path);
+ expect(result.errors, isEmpty);
+ expect(result.uri.toString(), 'package:dart.my/a.dart');
+ }
+
+ @deprecated
void test_getResolvedUnit_notFileOfUri() async {
var relPath = 'dart/my/lib/a.dart';
newFile('$workspaceRootPath/bazel-bin/$relPath');
@@ -62,6 +88,7 @@
expect(() => result.errors, throwsStateError);
}
+ @deprecated
void test_getResolvedUnit_valid() async {
var file = newFile(
'$workspaceRootPath/dart/my/lib/a.dart',
@@ -76,6 +103,32 @@
expect(result.uri.toString(), 'package:dart.my/a.dart');
}
+ void test_getUnitElement2_notPathOfUri() async {
+ var relPath = 'dart/my/lib/a.dart';
+ newFile('$workspaceRootPath/bazel-bin/$relPath');
+
+ var path = convertPath('$workspaceRootPath/$relPath');
+ var session = contextFor(path).currentSession;
+ var result = await session.getUnitElement2(path);
+ expect(result, isA<NotPathOfUriResult>());
+ }
+
+ void test_getUnitElement2_valid() async {
+ var file = newFile(
+ '$workspaceRootPath/dart/my/lib/a.dart',
+ content: 'class A {}',
+ );
+
+ var session = contextFor(file.path).currentSession;
+ var result = await session.getUnitElement2(file.path);
+ result as UnitElementResult;
+ expect(result.state, ResultState.VALID);
+ expect(result.path, file.path);
+ expect(result.element.types, hasLength(1));
+ expect(result.uri.toString(), 'package:dart.my/a.dart');
+ }
+
+ @deprecated
void test_getUnitElement_notFileOfUri() async {
var relPath = 'dart/my/lib/a.dart';
newFile('$workspaceRootPath/bazel-bin/$relPath');
@@ -87,6 +140,7 @@
expect(() => result.element, throwsStateError);
}
+ @deprecated
void test_getUnitElement_valid() async {
var file = newFile(
'$workspaceRootPath/dart/my/lib/a.dart',
@@ -200,6 +254,7 @@
expect(node.length, 10);
}
+ @deprecated
test_getParsedLibrary_getElementDeclaration_notThisLibrary() async {
newFile(testPath, content: '');
@@ -214,6 +269,21 @@
}, throwsArgumentError);
}
+ test_getParsedLibrary_getElementDeclaration_notThisLibrary2() async {
+ newFile(testPath, content: '');
+
+ var resolvedUnit =
+ await session.getResolvedUnit2(testPath) as ResolvedUnitResult;
+ var typeProvider = resolvedUnit.typeProvider;
+ var intClass = typeProvider.intType.element;
+
+ var parsedLibrary = session.getParsedLibrary(testPath);
+
+ expect(() {
+ parsedLibrary.getElementDeclaration(intClass);
+ }, throwsArgumentError);
+ }
+
test_getParsedLibrary_getElementDeclaration_synthetic() async {
newFile(testPath, content: r'''
int foo = 0;
@@ -221,6 +291,32 @@
var parsedLibrary = session.getParsedLibrary(testPath);
+ var unitResult = await session.getUnitElement2(testPath);
+ var unitElement = (unitResult as UnitElementResult).element;
+ var fooElement = unitElement.topLevelVariables[0];
+ expect(fooElement.name, 'foo');
+
+ // We can get the variable element declaration.
+ var fooDeclaration = parsedLibrary.getElementDeclaration(fooElement)!;
+ var fooNode = fooDeclaration.node as VariableDeclaration;
+ expect(fooNode.name.name, 'foo');
+ expect(fooNode.offset, 4);
+ expect(fooNode.length, 7);
+ expect(fooNode.name.staticElement, isNull);
+
+ // Synthetic elements don't have nodes.
+ expect(parsedLibrary.getElementDeclaration(fooElement.getter!), isNull);
+ expect(parsedLibrary.getElementDeclaration(fooElement.setter!), isNull);
+ }
+
+ @deprecated
+ test_getParsedLibrary_getElementDeclaration_synthetic_deprecated() async {
+ newFile(testPath, content: r'''
+int foo = 0;
+''');
+
+ var parsedLibrary = session.getParsedLibrary(testPath);
+
var unitElement = (await session.getUnitElement(testPath)).element;
var fooElement = unitElement.topLevelVariables[0];
expect(fooElement.name, 'foo');
@@ -525,6 +621,7 @@
}, throwsArgumentError);
}
+ @deprecated
test_getResolvedUnit() async {
newFile(testPath, content: r'''
class A {}
@@ -540,6 +637,22 @@
expect(unitResult.libraryElement, isNotNull);
}
+ test_getResolvedUnit2() async {
+ newFile(testPath, content: r'''
+class A {}
+class B {}
+''');
+
+ var unitResult =
+ await session.getResolvedUnit2(testPath) as ResolvedUnitResult;
+ expect(unitResult.session, session);
+ expect(unitResult.path, testPath);
+ expect(unitResult.uri, Uri.parse('package:test/test.dart'));
+ expect(unitResult.unit!.declarations, hasLength(2));
+ expect(unitResult.typeProvider, isNotNull);
+ expect(unitResult.libraryElement, isNotNull);
+ }
+
test_getSourceKind() async {
newFile(testPath, content: 'class C {}');
@@ -554,6 +667,7 @@
expect(kind, SourceKind.PART);
}
+ @deprecated
test_getUnitElement() async {
newFile(testPath, content: r'''
class A {}
@@ -570,6 +684,23 @@
expect(unitResult.signature, signature);
}
+ test_getUnitElement2() async {
+ newFile(testPath, content: r'''
+class A {}
+class B {}
+''');
+
+ var unitResult = await session.getUnitElement2(testPath);
+ unitResult as UnitElementResult;
+ expect(unitResult.session, session);
+ expect(unitResult.path, testPath);
+ expect(unitResult.uri, Uri.parse('package:test/test.dart'));
+ expect(unitResult.element.types, hasLength(2));
+
+ var signature = await session.getUnitElementSignature(testPath);
+ expect(unitResult.signature, signature);
+ }
+
test_resourceProvider() async {
expect(session.resourceProvider, resourceProvider);
}
diff --git a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
index aa6dfb3..e82b7ca 100644
--- a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
+++ b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
@@ -628,7 +628,49 @@
_assertRemovedPaths(isEmpty);
}
- test_resolve_part_of() async {
+ test_resolve_libraryWithPart_noLibraryDiscovery() async {
+ var partPath = '/workspace/dart/test/lib/a.dart';
+ newFile(partPath, content: r'''
+part of 'test.dart';
+
+class A {}
+''');
+
+ await assertNoErrorsInCode(r'''
+part 'a.dart';
+
+void f(A a) {}
+''');
+
+ // We started resolution from the library, and then followed to the part.
+ // So, the part knows its library, there is no need to discover it.
+ _assertDiscoveredLibraryForParts([]);
+ }
+
+ test_resolve_part_of_name() async {
+ newFile('/workspace/dart/test/lib/a.dart', content: r'''
+library my.lib;
+
+part 'test.dart';
+
+class A {
+ int m;
+}
+''');
+
+ await assertNoErrorsInCode(r'''
+part of my.lib;
+
+void func() {
+ var a = A();
+ print(a.m);
+}
+''');
+
+ _assertDiscoveredLibraryForParts([result.path!]);
+ }
+
+ test_resolve_part_of_uri() async {
newFile('/workspace/dart/test/lib/a.dart', content: r'''
part 'test.dart';
@@ -645,6 +687,8 @@
print(a.m);
}
''');
+
+ _assertDiscoveredLibraryForParts([result.path!]);
}
test_resolveFile_cache() async {
@@ -790,6 +834,10 @@
]);
}
+ void _assertDiscoveredLibraryForParts(List<String> expected) {
+ expect(fileResolver.fsState!.testView.partsDiscoveredLibraries, expected);
+ }
+
void _assertRemovedPaths(Matcher matcher) {
expect(fileResolver.fsState!.testView.removedPaths, matcher);
}
diff --git a/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart b/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart
index 2b7598a..64e9563 100644
--- a/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart
+++ b/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart
@@ -189,7 +189,7 @@
Future<ResolvedUnitResult> resolveFile(String path) async {
var analysisContext = contextFor(pathForContextSelection ?? path);
var session = analysisContext.currentSession;
- return await session.getResolvedUnit(path);
+ return await session.getResolvedUnit2(path) as ResolvedUnitResult;
}
@mustCallSuper
diff --git a/pkg/analyzer/test/src/diagnostics/ambiguous_import_test.dart b/pkg/analyzer/test/src/diagnostics/ambiguous_import_test.dart
index dd7b71f..81c91fd 100644
--- a/pkg/analyzer/test/src/diagnostics/ambiguous_import_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/ambiguous_import_test.dart
@@ -5,7 +5,7 @@
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:matcher/src/core_matchers.dart';
-import 'package:test_api/src/frontend/expect.dart';
+import 'package:test/test.dart' show expect;
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../../generated/test_support.dart';
diff --git a/pkg/analyzer/test/src/diagnostics/argument_type_not_assignable_test.dart b/pkg/analyzer/test/src/diagnostics/argument_type_not_assignable_test.dart
index 096fcdc..e177d5e 100644
--- a/pkg/analyzer/test/src/diagnostics/argument_type_not_assignable_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/argument_type_not_assignable_test.dart
@@ -398,7 +398,7 @@
main() {
f(p: 42);
}''', [
- error(CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 35, 5),
+ error(CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 38, 2),
]);
}
diff --git a/pkg/analyzer/test/src/diagnostics/const_eval_throws_exception_test.dart b/pkg/analyzer/test/src/diagnostics/const_eval_throws_exception_test.dart
index b71deef..926a7b6 100644
--- a/pkg/analyzer/test/src/diagnostics/const_eval_throws_exception_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/const_eval_throws_exception_test.dart
@@ -238,7 +238,7 @@
error(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, 9, 29),
error(CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 36, 1),
error(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, 49, 48),
- error(CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 81, 15),
+ error(CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 95, 1),
]);
}
@@ -250,7 +250,7 @@
var b = const bool.fromEnvironment('x', defaultValue: 1);
''', [
error(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, 8, 48),
- error(CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 40, 15),
+ error(CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 54, 1),
]);
}
diff --git a/pkg/analyzer/test/src/diagnostics/unused_element_test.dart b/pkg/analyzer/test/src/diagnostics/unused_element_test.dart
index c3ca7ec..105d62b 100644
--- a/pkg/analyzer/test/src/diagnostics/unused_element_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/unused_element_test.dart
@@ -712,6 +712,78 @@
''');
}
+ test_method_isUsed_privateExtension_generic_binaryOperator() async {
+ await assertNoErrorsInCode(r'''
+class A<T> {}
+extension _A<T> on A<T> {
+ int operator -(int other) => other;
+}
+void f(A<int> a) {
+ a - 3;
+}
+''');
+ }
+
+ test_method_isUsed_privateExtension_generic_indexEqOperator() async {
+ await assertNoErrorsInCode(r'''
+class A<T> {}
+extension _A<T> on A<T> {
+ void operator []=(int index, T value) {
+}}
+void f(A<int> a) {
+ a[0] = 1;
+}
+''');
+ }
+
+ test_method_isUsed_privateExtension_generic_indexOperator() async {
+ await assertNoErrorsInCode(r'''
+class A<T> {}
+extension _A<T> on A<T> {
+ A<T> operator [](int index) => throw 0;
+}
+void f(A<int> a) {
+ a[0];
+}
+''');
+ }
+
+ test_method_isUsed_privateExtension_generic_method() async {
+ await assertNoErrorsInCode(r'''
+class A<T> {}
+extension _A<T> on A<T> {
+ A<T> foo() => throw 0;
+}
+void f(A<int> a) {
+ a.foo();
+}
+''');
+ }
+
+ test_method_isUsed_privateExtension_generic_postfixOperator() async {
+ await assertNoErrorsInCode(r'''
+class A<T> {}
+extension _A<T> on A<T> {
+ A<T> operator -(int i) => throw 0;
+}
+void f(A<int> a) {
+ a--;
+}
+''');
+ }
+
+ test_method_isUsed_privateExtension_generic_prefixOperator() async {
+ await assertNoErrorsInCode(r'''
+class A<T> {}
+extension _A<T> on A<T> {
+ T operator ~() => throw 0;
+}
+void f(A<int> a) {
+ ~a;
+}
+''');
+ }
+
test_method_isUsed_privateExtension_indexEqOperator() async {
await assertNoErrorsInCode(r'''
extension _A on bool {
diff --git a/pkg/analyzer/test/src/summary/top_level_inference_test.dart b/pkg/analyzer/test/src/summary/top_level_inference_test.dart
index 25b90f1..5675f3f 100644
--- a/pkg/analyzer/test/src/summary/top_level_inference_test.dart
+++ b/pkg/analyzer/test/src/summary/top_level_inference_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/analysis/results.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -2745,7 +2746,8 @@
var path = convertPath(testFilePath);
var analysisSession = contextFor(path).currentSession;
- var result = await analysisSession.getUnitElement(path);
+ var result = await analysisSession.getUnitElement2(path);
+ result as UnitElementResult;
return result.element.library;
}
}
diff --git a/pkg/analyzer/test/src/task/strong/checker_test.dart b/pkg/analyzer/test/src/task/strong/checker_test.dart
index d7bc492..6a5a5cc 100644
--- a/pkg/analyzer/test/src/task/strong/checker_test.dart
+++ b/pkg/analyzer/test/src/task/strong/checker_test.dart
@@ -2292,10 +2292,10 @@
error(CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER, 254, 1),
error(CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER, 271, 1),
error(CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER, 327, 1),
- error(CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 345, 4),
- error(CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 351, 4),
+ error(CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 348, 1),
+ error(CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 354, 1),
error(CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER, 357, 1),
- error(CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 374, 4),
+ error(CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 377, 1),
]);
}
diff --git a/pkg/analyzer/test/util/id_testing_helper.dart b/pkg/analyzer/test/util/id_testing_helper.dart
index 19c16a4..e8c4e79 100644
--- a/pkg/analyzer/test/util/id_testing_helper.dart
+++ b/pkg/analyzer/test/util/id_testing_helper.dart
@@ -173,7 +173,7 @@
var results = <Uri, ResolvedUnitResult>{};
for (var testUri in testUris) {
var path = resourceProvider.convertPath(testUri.path);
- var result = await driver.getResult(path);
+ var result = await driver.getResult2(path) as ResolvedUnitResult;
var errors =
result.errors.where((e) => e.severity == Severity.error).toList();
if (errors.isNotEmpty) {
diff --git a/pkg/analyzer/tool/fasta_migration_progress.sh b/pkg/analyzer/tool/fasta_migration_progress.sh
index 042e0db..ec3d9eb 100644
--- a/pkg/analyzer/tool/fasta_migration_progress.sh
+++ b/pkg/analyzer/tool/fasta_migration_progress.sh
@@ -44,7 +44,7 @@
echo " Log file: $logfile"
# TODO: delete by default and stop logging the location of the file.
# delete=1
- python tools/test.py -m release --checked --use-sdk \
+ python3 tools/test.py -m release --checked --use-sdk \
--vm-options="-DuseFastaParser=true" \
--print_passing_stdout \
pkg/analy > $logfile
diff --git a/pkg/analyzer_cli/lib/src/analyzer_impl.dart b/pkg/analyzer_cli/lib/src/analyzer_impl.dart
index 1486580..a3e1fd9 100644
--- a/pkg/analyzer_cli/lib/src/analyzer_impl.dart
+++ b/pkg/analyzer_cli/lib/src/analyzer_impl.dart
@@ -206,7 +206,8 @@
Future<LibraryElement> _resolveLibrary() async {
var libraryPath = libraryFile.path;
analysisDriver.priorityFiles = [libraryPath];
- var elementResult = await analysisDriver.getUnitElement(libraryPath);
+ var elementResult =
+ await analysisDriver.getUnitElement2(libraryPath) as UnitElementResult;
return elementResult.element.library;
}
diff --git a/pkg/analyzer_plugin/lib/plugin/plugin.dart b/pkg/analyzer_plugin/lib/plugin/plugin.dart
index 0a5fa70..14ede54 100644
--- a/pkg/analyzer_plugin/lib/plugin/plugin.dart
+++ b/pkg/analyzer_plugin/lib/plugin/plugin.dart
@@ -161,9 +161,8 @@
throw RequestFailure(
RequestErrorFactory.pluginError('Failed to analyze $path', null));
}
- var result = await driver.getResult(path);
- var state = result.state;
- if (state != ResultState.VALID) {
+ var result = await driver.getResult2(path);
+ if (result is! ResolvedUnitResult) {
// Return an error from the request.
throw RequestFailure(
RequestErrorFactory.pluginError('Failed to analyze $path', null));
diff --git a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_core.dart b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_core.dart
index eb1cded..8341d33 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_core.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_core.dart
@@ -193,14 +193,13 @@
}
var session = workspace.getSession(path);
- var result = await session?.getResolvedUnit(path);
- var state = result?.state ?? ResultState.INVALID_FILE_TYPE;
- if (state == ResultState.INVALID_FILE_TYPE) {
+ var result = await session?.getResolvedUnit2(path);
+ if (result is! ResolvedUnitResult) {
throw AnalysisException('Cannot analyze "$path"');
}
- var timeStamp = state == ResultState.VALID ? 0 : -1;
+ var timeStamp = result.exists ? 0 : -1;
- var declaredUnit = result!.unit?.declaredElement;
+ var declaredUnit = result.unit?.declaredElement;
var libraryUnit = declaredUnit?.library.definingCompilationUnit;
DartFileEditBuilderImpl? libraryEditBuilder;
diff --git a/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart b/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart
index 4781140..3c3d9c4 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart
@@ -506,7 +506,10 @@
if (token == null) {
return null;
}
- if (offset >= token.offset) {
+ // Usually if the offset is greater than the token it can't be in the comment
+ // but for EOF this is not the case - the offset at EOF could still be inside
+ // the comment if EOF is on the same line as the comment.
+ if (token.type != TokenType.EOF && offset >= token.offset) {
return null;
}
token = token.precedingComments;
diff --git a/pkg/analyzer_plugin/pubspec.yaml b/pkg/analyzer_plugin/pubspec.yaml
index 083c022..06f98e5 100644
--- a/pkg/analyzer_plugin/pubspec.yaml
+++ b/pkg/analyzer_plugin/pubspec.yaml
@@ -8,7 +8,7 @@
sdk: '>=2.12.0 <3.0.0'
dependencies:
- analyzer: ^1.4.0
+ analyzer: ^1.5.0
collection: ^1.15.0
dart_style: ^2.0.0
pub_semver: ^2.0.0
diff --git a/pkg/analyzer_plugin/test/support/abstract_context.dart b/pkg/analyzer_plugin/test/support/abstract_context.dart
index e0776c3..6bd18116 100644
--- a/pkg/analyzer_plugin/test/support/abstract_context.dart
+++ b/pkg/analyzer_plugin/test/support/abstract_context.dart
@@ -97,7 +97,8 @@
}
Future<ResolvedUnitResult> resolveFile(String path) async {
- return contextFor(path).currentSession.getResolvedUnit(path);
+ var session = contextFor(path).currentSession;
+ return await session.getResolvedUnit2(path) as ResolvedUnitResult;
}
void setUp() {
diff --git a/pkg/compiler/lib/src/common/codegen.dart b/pkg/compiler/lib/src/common/codegen.dart
index a17ef22..9ea7506 100644
--- a/pkg/compiler/lib/src/common/codegen.dart
+++ b/pkg/compiler/lib/src/common/codegen.dart
@@ -551,9 +551,6 @@
case ModularNameKind.operatorIs:
name.value = namer.operatorIs(name.data);
break;
- case ModularNameKind.operatorIsType:
- name.value = namer.operatorIsType(name.data);
- break;
case ModularNameKind.instanceMethod:
name.value = namer.instanceMethodName(name.data);
break;
@@ -626,7 +623,6 @@
staticClosure,
methodProperty,
operatorIs,
- operatorIsType,
instanceMethod,
instanceField,
invocation,
@@ -674,9 +670,6 @@
case ModularNameKind.globalPropertyNameForMember:
data = source.readMember();
break;
- case ModularNameKind.operatorIsType:
- data = source.readDartType();
- break;
case ModularNameKind.invocation:
data = Selector.readFromDataSource(source);
break;
@@ -720,9 +713,6 @@
case ModularNameKind.globalPropertyNameForMember:
sink.writeMember(data);
break;
- case ModularNameKind.operatorIsType:
- sink.writeDartType(data);
- break;
case ModularNameKind.invocation:
Selector selector = data;
selector.writeToDataSink(sink);
@@ -1247,6 +1237,11 @@
}
@override
+ void visitDeferredStatement(js.DeferredStatement node) {
+ throw new UnsupportedError('JsNodeSerializer.visitDeferredStatement');
+ }
+
+ @override
void visitDeferredNumber(js.DeferredNumber node) {
throw new UnsupportedError('JsNodeSerializer.visitDeferredNumber');
}
diff --git a/pkg/compiler/lib/src/ir/scope_visitor.dart b/pkg/compiler/lib/src/ir/scope_visitor.dart
index 3004f39..abaff07 100644
--- a/pkg/compiler/lib/src/ir/scope_visitor.dart
+++ b/pkg/compiler/lib/src/ir/scope_visitor.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:kernel/ast.dart' as ir;
+import 'package:kernel/core_types.dart' as ir;
import 'package:kernel/type_environment.dart' as ir;
import '../ir/constants.dart';
@@ -18,6 +19,9 @@
final Dart2jsConstantEvaluator _constantEvaluator;
ir.StaticTypeContext _staticTypeContext;
+ ir.TypeEnvironment get _typeEnvironment => _constantEvaluator.typeEnvironment;
+ ir.CoreTypes get _coreTypes => _typeEnvironment.coreTypes;
+
final ClosureScopeModel _model = new ClosureScopeModel();
/// A map of each visited call node with the associated information about what
@@ -87,8 +91,7 @@
initializerComplexity: const EvaluationComplexity.lazy());
}
- _staticTypeContext =
- new ir.StaticTypeContext(node, _constantEvaluator.typeEnvironment);
+ _staticTypeContext = new ir.StaticTypeContext(node, _typeEnvironment);
if (node is ir.Constructor) {
_hasThisLocal = true;
} else if (node is ir.Procedure && node.kind == ir.ProcedureKind.Factory) {
@@ -958,9 +961,7 @@
}
EvaluationComplexity complexity = visitArguments(node.arguments);
- if (complexity.isConstant &&
- node.target ==
- _staticTypeContext.typeEnvironment.coreTypes.identicalProcedure) {
+ if (complexity.isConstant && node.target == _coreTypes.identicalProcedure) {
return _evaluateImplicitConstant(node);
}
return node.isConst
@@ -982,6 +983,14 @@
@override
EvaluationComplexity visitConstructorInvocation(
ir.ConstructorInvocation node) {
+ // TODO(45681): Investigate if other initializers should be made eager.
+
+ // Lazily invoking the `_Cell` constructor pessimizes certain uses of late
+ // variables, so we ensure it gets called eagerly.
+ if (node.target == _coreTypes.cellConstructor) {
+ return EvaluationComplexity.eager();
+ }
+
if (node.arguments.types.isNotEmpty) {
visitNodesInContext(node.arguments.types,
new VariableUse.constructorTypeArgument(node.target));
diff --git a/pkg/compiler/lib/src/js/rewrite_async.dart b/pkg/compiler/lib/src/js/rewrite_async.dart
index 53e156a..ab8d742 100644
--- a/pkg/compiler/lib/src/js/rewrite_async.dart
+++ b/pkg/compiler/lib/src/js/rewrite_async.dart
@@ -1265,6 +1265,9 @@
js.Expression visitDeferredExpression(js.DeferredExpression node) => node;
@override
+ visitDeferredStatement(js.DeferredStatement node) => unsupported(node);
+
+ @override
js.Expression visitDeferredNumber(js.DeferredNumber node) => node;
@override
@@ -2677,6 +2680,11 @@
}
@override
+ bool visitDeferredStatement(js.DeferredStatement node) {
+ return unsupported(node);
+ }
+
+ @override
bool visitDeferredNumber(js.DeferredNumber node) {
return false;
}
diff --git a/pkg/compiler/lib/src/js/size_estimator.dart b/pkg/compiler/lib/src/js/size_estimator.dart
index e8ec19f..e2b8a9b 100644
--- a/pkg/compiler/lib/src/js/size_estimator.dart
+++ b/pkg/compiler/lib/src/js/size_estimator.dart
@@ -830,6 +830,16 @@
}
}
+ @override
+ visitDeferredStatement(DeferredStatement node) {
+ if (node.isFinalized) {
+ // Continue printing with the statement value.
+ node.statement.accept(this);
+ } else {
+ sizeEstimate(node);
+ }
+ }
+
outputNumberWithRequiredWhitespace(String number) {
int charCode = number.codeUnitAt(0);
if (charCode == charCodes.$MINUS) {
diff --git a/pkg/compiler/lib/src/js_backend/namer.dart b/pkg/compiler/lib/src/js_backend/namer.dart
index 82b1481..71a11cf 100644
--- a/pkg/compiler/lib/src/js_backend/namer.dart
+++ b/pkg/compiler/lib/src/js_backend/namer.dart
@@ -436,7 +436,6 @@
static const String _callPrefixDollar = r'call$';
static final jsAst.Name _literalDollar = new StringBackedName(r'$');
- static final jsAst.Name _literalUnderscore = new StringBackedName('_');
static final jsAst.Name literalPlus = new StringBackedName('+');
static final jsAst.Name _literalDynamic = new StringBackedName("dynamic");
@@ -1507,20 +1506,6 @@
}
@override
- jsAst.Name operatorIsType(DartType type) {
- if (type is FunctionType) {
- // TODO(erikcorry): Reduce from $isx to ix when we are minifying.
- return new CompoundName([
- new StringBackedName(fixedNames.operatorIsPrefix),
- _literalUnderscore,
- getFunctionTypeName(type)
- ]);
- }
- InterfaceType interfaceType = type;
- return operatorIs(interfaceType.element);
- }
-
- @override
jsAst.Name operatorIs(ClassEntity element) {
// TODO(erikcorry): Reduce from $isx to ix when we are minifying.
return new CompoundName([
@@ -2413,9 +2398,6 @@
/// [element].
jsAst.Name operatorIs(ClassEntity element);
- /// Return the name of the `isX` property for classes that implement [type].
- jsAst.Name operatorIsType(DartType type);
-
/// Returns the name of the lazy initializer for the static field [element].
jsAst.Name lazyInitializerName(FieldEntity element);
@@ -2660,14 +2642,6 @@
}
@override
- jsAst.Name operatorIsType(DartType type) {
- jsAst.Name name =
- new ModularName(ModularNameKind.operatorIsType, data: type);
- _registry.registerModularName(name);
- return name;
- }
-
- @override
jsAst.Name instanceMethodName(FunctionEntity method) {
jsAst.Name name =
new ModularName(ModularNameKind.instanceMethod, data: method);
diff --git a/pkg/compiler/lib/src/kernel/dart2js_target.dart b/pkg/compiler/lib/src/kernel/dart2js_target.dart
index d0b3617..96cd1ad 100644
--- a/pkg/compiler/lib/src/kernel/dart2js_target.dart
+++ b/pkg/compiler/lib/src/kernel/dart2js_target.dart
@@ -62,8 +62,6 @@
/// Late lowerings which the frontend performs for dart2js.
const List<int> _allEnabledLateLowerings = [
- LateLowering.initializedNonFinalStaticField,
- LateLowering.initializedFinalStaticField,
LateLowering.uninitializedNonFinalInstanceField,
LateLowering.uninitializedFinalInstanceField,
LateLowering.initializedNonFinalInstanceField,
diff --git a/pkg/compiler/lib/src/kernel/transformations/late_lowering.dart b/pkg/compiler/lib/src/kernel/transformations/late_lowering.dart
index eacb5ae..ebac6bb 100644
--- a/pkg/compiler/lib/src/kernel/transformations/late_lowering.dart
+++ b/pkg/compiler/lib/src/kernel/transformations/late_lowering.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:kernel/ast.dart';
-import 'package:kernel/library_index.dart';
+import 'package:kernel/core_types.dart';
import 'package:kernel/type_algebra.dart';
bool _shouldLowerVariable(VariableDeclaration node) => node.isLate;
@@ -15,7 +15,7 @@
_shouldLowerVariable(node) && node.initializer != null;
bool _shouldLowerField(Field node) =>
- node.initializer == null && node.isStatic && node.isLate;
+ node.isLate && node.isStatic && node.initializer == null;
class _Reader {
final Procedure _procedure;
@@ -28,53 +28,24 @@
}
class LateLowering {
- final Class _cellClass;
- final Constructor _cellConstructor;
-
- final Class _initializedCellClass;
- final Constructor _initializedCellConstructor;
+ final CoreTypes _coreTypes;
final _Reader _readLocal;
final _Reader _readField;
final _Reader _readInitialized;
final _Reader _readInitializedFinal;
- final Procedure _setValue;
- final Procedure _setFinalLocalValue;
- final Procedure _setFinalFieldValue;
- final Procedure _setInitializedValue;
- final Procedure _setInitializedFinalValue;
-
// TODO(fishythefish): Remove cells when exiting their scope.
final Map<VariableDeclaration, VariableDeclaration> _variableCells = {};
final Map<Field, Field> _fieldCells = {};
Member _contextMember;
- LateLowering(LibraryIndex index)
- : _cellClass = index.getClass('dart:_late_helper', '_Cell'),
- _cellConstructor = index.getMember('dart:_late_helper', '_Cell', ''),
- _initializedCellClass =
- index.getClass('dart:_late_helper', '_InitializedCell'),
- _initializedCellConstructor =
- index.getMember('dart:_late_helper', '_InitializedCell', ''),
- _readLocal =
- _Reader(index.getMember('dart:_late_helper', '_Cell', 'readLocal')),
- _readField =
- _Reader(index.getMember('dart:_late_helper', '_Cell', 'readField')),
- _readInitialized = _Reader(
- index.getMember('dart:_late_helper', '_InitializedCell', 'read')),
- _readInitializedFinal = _Reader(index.getMember(
- 'dart:_late_helper', '_InitializedCell', 'readFinal')),
- _setValue = index.getMember('dart:_late_helper', '_Cell', 'set:value'),
- _setFinalLocalValue = index.getMember(
- 'dart:_late_helper', '_Cell', 'set:finalLocalValue'),
- _setFinalFieldValue = index.getMember(
- 'dart:_late_helper', '_Cell', 'set:finalFieldValue'),
- _setInitializedValue = index.getMember(
- 'dart:_late_helper', '_InitializedCell', 'set:value'),
- _setInitializedFinalValue = index.getMember(
- 'dart:_late_helper', '_InitializedCell', 'set:finalValue');
+ LateLowering(this._coreTypes)
+ : _readLocal = _Reader(_coreTypes.cellReadLocal),
+ _readField = _Reader(_coreTypes.cellReadField),
+ _readInitialized = _Reader(_coreTypes.initializedCellRead),
+ _readInitializedFinal = _Reader(_coreTypes.initializedCellReadFinal);
void transformAdditionalExports(Library node) {
List<Reference> additionalExports = node.additionalExports;
@@ -89,13 +60,13 @@
}
ConstructorInvocation _callCellConstructor(int fileOffset) =>
- ConstructorInvocation(
- _cellConstructor, Arguments.empty()..fileOffset = fileOffset)
+ ConstructorInvocation(_coreTypes.cellConstructor,
+ Arguments.empty()..fileOffset = fileOffset)
..fileOffset = fileOffset;
ConstructorInvocation _callInitializedCellConstructor(
Expression initializer, int fileOffset) =>
- ConstructorInvocation(_initializedCellConstructor,
+ ConstructorInvocation(_coreTypes.initializedCellConstructor,
Arguments([initializer])..fileOffset = fileOffset)
..fileOffset = fileOffset;
@@ -127,8 +98,8 @@
int fileOffset = variable.fileOffset;
return VariableDeclaration(variable.name,
initializer: _callCellConstructor(fileOffset),
- type: InterfaceType(
- _cellClass, _contextMember.enclosingLibrary.nonNullable),
+ type: InterfaceType(_coreTypes.cellClass,
+ _contextMember.enclosingLibrary.nonNullable),
isFinal: true)
..fileOffset = fileOffset;
});
@@ -152,7 +123,7 @@
initializer: _callInitializedCellConstructor(
_initializerClosure(variable.initializer, variable.type),
fileOffset),
- type: InterfaceType(_initializedCellClass,
+ type: InterfaceType(_coreTypes.initializedCellClass,
_contextMember.enclosingLibrary.nonNullable),
isFinal: true)
..fileOffset = fileOffset;
@@ -207,8 +178,12 @@
int fileOffset = node.fileOffset;
VariableGet cell = _variableCellAccess(variable, fileOffset);
Procedure setter = variable.initializer == null
- ? (variable.isFinal ? _setFinalLocalValue : _setValue)
- : (variable.isFinal ? _setInitializedFinalValue : _setInitializedValue);
+ ? (variable.isFinal
+ ? _coreTypes.cellFinalLocalValueSetter
+ : _coreTypes.cellValueSetter)
+ : (variable.isFinal
+ ? _coreTypes.initializedCellFinalValueSetter
+ : _coreTypes.initializedCellValueSetter);
return _callSetter(setter, cell, node.value, fileOffset);
}
@@ -219,7 +194,8 @@
field.getterReference.canonicalName?.unbind();
field.setterReference?.canonicalName?.unbind();
return Field.immutable(field.name,
- type: InterfaceType(_cellClass, field.enclosingLibrary.nonNullable),
+ type: InterfaceType(
+ _coreTypes.cellClass, field.enclosingLibrary.nonNullable),
initializer: _callCellConstructor(fileOffset),
isFinal: true,
isStatic: true,
@@ -260,7 +236,9 @@
if (target is Field && _shouldLowerField(target)) {
int fileOffset = node.fileOffset;
StaticGet cell = _fieldCellAccess(target, fileOffset);
- Procedure setter = target.isFinal ? _setFinalFieldValue : _setValue;
+ Procedure setter = target.isFinal
+ ? _coreTypes.cellFinalFieldValueSetter
+ : _coreTypes.cellValueSetter;
return _callSetter(setter, cell, node.value, fileOffset);
} else {
return node;
diff --git a/pkg/compiler/lib/src/kernel/transformations/lowering.dart b/pkg/compiler/lib/src/kernel/transformations/lowering.dart
index ccc4d7e..3885486 100644
--- a/pkg/compiler/lib/src/kernel/transformations/lowering.dart
+++ b/pkg/compiler/lib/src/kernel/transformations/lowering.dart
@@ -33,7 +33,7 @@
_Lowering(CoreTypes coreTypes, ClassHierarchy hierarchy)
: factorySpecializer = FactorySpecializer(coreTypes, hierarchy),
- _lateLowering = LateLowering(coreTypes.index);
+ _lateLowering = LateLowering(coreTypes);
void transformAdditionalExports(Library node) {
_lateLowering.transformAdditionalExports(node);
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index a729f53..0051870 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -48,7 +48,6 @@
import '../universe/feature.dart';
import '../universe/member_usage.dart' show MemberAccess;
import '../universe/selector.dart';
-import '../universe/side_effects.dart' show SideEffects;
import '../universe/target_checks.dart' show TargetChecks;
import '../universe/use.dart' show ConstantUse, StaticUse, TypeUse;
import '../world.dart';
@@ -4168,10 +4167,6 @@
_handleForeignDartClosureToJs(invocation, 'DART_CLOSURE_TO_JS');
} else if (name == 'RAW_DART_FUNCTION_REF') {
_handleForeignRawFunctionRef(invocation, 'RAW_DART_FUNCTION_REF');
- } else if (name == 'JS_SET_STATIC_STATE') {
- _handleForeignJsSetStaticState(invocation);
- } else if (name == 'JS_GET_STATIC_STATE') {
- _handleForeignJsGetStaticState(invocation);
} else if (name == 'JS_GET_NAME') {
_handleForeignJsGetName(invocation);
} else if (name == 'JS_EMBEDDED_GLOBAL') {
@@ -4499,37 +4494,6 @@
return;
}
- void _handleForeignJsSetStaticState(ir.StaticInvocation invocation) {
- if (_unexpectedForeignArguments(invocation,
- minPositional: 1, maxPositional: 1)) {
- // Result expected on stack.
- stack.add(graph.addConstantNull(closedWorld));
- return;
- }
-
- List<HInstruction> inputs = _visitPositionalArguments(invocation.arguments);
-
- String isolateName = _namer.staticStateHolder;
- SideEffects sideEffects = new SideEffects.empty();
- sideEffects.setAllSideEffects();
- push(new HForeignCode(js.js.parseForeignJS("$isolateName = #"),
- _abstractValueDomain.dynamicType, inputs,
- nativeBehavior: NativeBehavior.CHANGES_OTHER, effects: sideEffects));
- }
-
- void _handleForeignJsGetStaticState(ir.StaticInvocation invocation) {
- if (_unexpectedForeignArguments(invocation,
- minPositional: 0, maxPositional: 0)) {
- // Result expected on stack.
- stack.add(graph.addConstantNull(closedWorld));
- return;
- }
-
- push(new HForeignCode(js.js.parseForeignJS(_namer.staticStateHolder),
- _abstractValueDomain.dynamicType, <HInstruction>[],
- nativeBehavior: NativeBehavior.DEPENDS_OTHER));
- }
-
void _handleForeignJsGetName(ir.StaticInvocation invocation) {
if (_unexpectedForeignArguments(invocation,
minPositional: 1, maxPositional: 1)) {
diff --git a/pkg/compiler/test/inference/data/foreign.dart b/pkg/compiler/test/inference/data/foreign.dart
index e0b7078..7ae6e76 100644
--- a/pkg/compiler/test/inference/data/foreign.dart
+++ b/pkg/compiler/test/inference/data/foreign.dart
@@ -23,8 +23,6 @@
jsEmbeddedGlobal_getTypeFromName();
jsStringConcat();
-
- jsGetStaticState();
}
/*member: jsCallEmpty:[null|subclass=Object]*/
@@ -46,6 +44,3 @@
/*member: jsStringConcat:[exact=JSString]*/
jsStringConcat() => JS_STRING_CONCAT('a', 'b');
-
-/*member: jsGetStaticState:[null|subclass=Object]*/
-jsGetStaticState() => JS_GET_STATIC_STATE();
diff --git a/pkg/compiler/test/inference/side_effects/foreign.dart b/pkg/compiler/test/inference/side_effects/foreign.dart
index 9884d38..68ff097 100644
--- a/pkg/compiler/test/inference/side_effects/foreign.dart
+++ b/pkg/compiler/test/inference/side_effects/foreign.dart
@@ -34,9 +34,6 @@
/*member: jsStringConcat:SideEffects(reads nothing; writes nothing)*/
jsStringConcat() => JS_STRING_CONCAT('a', 'b');
-/*member: jsGetStaticState:SideEffects(reads nothing; writes anything)*/
-jsGetStaticState() => JS_GET_STATIC_STATE();
-
/*member: main:SideEffects(reads anything; writes anything)*/
main() {
jsCallInt();
@@ -47,6 +44,4 @@
jsEmbeddedGlobal_getTypeFromName();
jsStringConcat();
-
- jsGetStaticState();
}
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 88ec1fb..a01a3b9 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -5109,6 +5109,7 @@
// If we know that the left type uses identity for equality, we can
// sometimes emit better code, either `===` or `==`.
var isEnum = leftType is InterfaceType && leftType.classNode.isEnum;
+
var usesIdentity = _typeRep.isPrimitive(leftType) ||
isEnum ||
_isNull(left) ||
diff --git a/pkg/dev_compiler/lib/src/kernel/native_types.dart b/pkg/dev_compiler/lib/src/kernel/native_types.dart
index dd7bdc8..5a81641 100644
--- a/pkg/dev_compiler/lib/src/kernel/native_types.dart
+++ b/pkg/dev_compiler/lib/src/kernel/native_types.dart
@@ -49,6 +49,8 @@
_addExtensionType(coreTypes.doubleClass, true);
_addExtensionType(coreTypes.boolClass, true);
_addExtensionType(coreTypes.stringClass, true);
+ // Allow `Function.==` to be recognized as a symbolized member.
+ _addExtensionType(coreTypes.functionClass, false);
var sdk = coreTypes.index;
_addExtensionTypes(sdk.getLibrary('dart:_interceptors'));
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 8d2d698..c528f5f 100644
--- a/pkg/front_end/lib/src/fasta/builder/class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
@@ -705,7 +705,7 @@
Set<ClassBuilder> implemented = new Set<ClassBuilder>();
for (TypeBuilder type in interfaceBuilders) {
if (type is NamedTypeBuilder) {
- int charOffset = -1; // TODO(ahe): Get offset from type.
+ int charOffset = type.charOffset;
TypeDeclarationBuilder typeDeclaration = type.declaration;
TypeDeclarationBuilder decl;
TypeAliasBuilder aliasBuilder; // Non-null if a type alias is used.
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 f6cceab..5d38a56 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
@@ -52,7 +52,6 @@
messageNonAgnosticConstant,
messageNotAConstantExpression,
noLength,
- templateConstEvalBadState,
templateConstEvalCaseImplementsEqual,
templateConstEvalDeferredLibrary,
templateConstEvalDuplicateElement,
@@ -71,6 +70,7 @@
templateConstEvalInvalidSymbolName,
templateConstEvalKeyImplementsEqual,
templateConstEvalNonConstantVariableGet,
+ templateConstEvalUnhandledCoreException,
templateConstEvalUnhandledException,
templateConstEvalZeroDivisor;
@@ -1012,8 +1012,9 @@
if (value is Constant) {
message = templateConstEvalUnhandledException.withArguments(
value, isNonNullableByDefault);
- } else if (value is StateError) {
- message = templateConstEvalBadState.withArguments(value.message);
+ } else if (value is Error) {
+ message = templateConstEvalUnhandledCoreException
+ .withArguments(value.toString());
}
assert(message != null);
@@ -3604,6 +3605,7 @@
Constant result;
if (node.expression != null) {
result = evaluate(node.expression);
+ if (result is AbortConstant) return new AbortStatus(result);
}
return new ReturnStatus(result);
}
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 6e79f8f..a20b83a 100644
--- a/pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart
@@ -29,6 +29,7 @@
import '../fasta_codes.dart'
show
LocatedMessage,
+ Message,
templateBoundIssueViaCycleNonSimplicity,
templateBoundIssueViaLoopNonSimplicity,
templateBoundIssueViaRawTypeWithNonSimpleBounds,
@@ -664,8 +665,9 @@
/// [TypeDeclarationBuilder] for the type variable from [variables] that has raw
/// generic types with inbound references in its bound. The second element of
/// the triplet is the error message. The third element is the context.
-List<Object> getInboundReferenceIssues(List<TypeVariableBuilder> variables) {
- List<Object> issues = <Object>[];
+List<NonSimplicityIssue> getInboundReferenceIssues(
+ List<TypeVariableBuilder> variables) {
+ List<NonSimplicityIssue> issues = <NonSimplicityIssue>[];
for (TypeVariableBuilder variable in variables) {
if (variable.bound != null) {
List<Object> rawTypesAndMutualDependencies =
@@ -678,23 +680,25 @@
TypeVariableBuilder dependent = variablesAndDependencies[j];
List<NamedTypeBuilder> dependencies = variablesAndDependencies[j + 1];
for (NamedTypeBuilder dependency in dependencies) {
- issues.add(variable);
- issues.add(templateBoundIssueViaRawTypeWithNonSimpleBounds
- .withArguments(type.declaration.name));
- issues.add(<LocatedMessage>[
- templateNonSimpleBoundViaVariable
- .withArguments(dependency.declaration.name)
- .withLocation(dependent.fileUri, dependent.charOffset,
- dependent.name.length)
- ]);
+ issues.add(new NonSimplicityIssue(
+ variable,
+ templateBoundIssueViaRawTypeWithNonSimpleBounds
+ .withArguments(type.declaration.name),
+ <LocatedMessage>[
+ templateNonSimpleBoundViaVariable
+ .withArguments(dependency.declaration.name)
+ .withLocation(dependent.fileUri, dependent.charOffset,
+ dependent.name.length)
+ ]));
}
}
if (variablesAndDependencies.length == 0) {
// The inbound references are in a compiled declaration in a .dill.
- issues.add(variable);
- issues.add(templateBoundIssueViaRawTypeWithNonSimpleBounds
- .withArguments(type.declaration.name));
- issues.add(const <LocatedMessage>[]);
+ issues.add(new NonSimplicityIssue(
+ variable,
+ templateBoundIssueViaRawTypeWithNonSimpleBounds
+ .withArguments(type.declaration.name),
+ const <LocatedMessage>[]));
}
}
}
@@ -708,12 +712,13 @@
/// [TypeDeclarationBuilder] for the type variable from [variables] that has raw
/// generic types with inbound references in its bound. The second element of
/// the triplet is the error message. The third element is the context.
-List<Object> getInboundReferenceIssuesInType(TypeBuilder typeBuilder) {
+List<NonSimplicityIssue> getInboundReferenceIssuesInType(
+ TypeBuilder typeBuilder) {
List<FunctionTypeBuilder> genericFunctionTypeBuilders =
<FunctionTypeBuilder>[];
findUnaliasedGenericFunctionTypes(typeBuilder,
result: genericFunctionTypeBuilders);
- List<Object> issues = <Object>[];
+ List<NonSimplicityIssue> issues = <NonSimplicityIssue>[];
for (FunctionTypeBuilder genericFunctionTypeBuilder
in genericFunctionTypeBuilders) {
List<TypeVariableBuilder> typeVariables =
@@ -725,32 +730,34 @@
/// Finds raw type paths starting from those in [start] and ending with [end].
///
-/// Returns list of found paths. Each path is represented as a list of
-/// alternating builders of the raw generic types from the path and builders of
-/// type variables of the immediately preceding types that contain the reference
-/// to the next raw generic type in the path. The list ends with the type
-/// builder for [end].
+/// Returns list of found paths consisting of [RawTypeCycleElement]s. The list
+/// ends with the type builder for [end].
///
/// The reason for putting the type variables into the paths as well as for
/// using type for [start], and not the corresponding type declaration,
/// is better error reporting.
-List<List<Object>> findRawTypePathsToDeclaration(
+List<List<RawTypeCycleElement>> findRawTypePathsToDeclaration(
TypeBuilder start, TypeDeclarationBuilder end,
[Set<TypeDeclarationBuilder> visited]) {
visited ??= new Set<TypeDeclarationBuilder>.identity();
- List<List<Object>> paths = <List<Object>>[];
+ List<List<RawTypeCycleElement>> paths = <List<RawTypeCycleElement>>[];
if (start is NamedTypeBuilder) {
TypeDeclarationBuilder declaration = start.declaration;
if (start.arguments == null) {
if (start.declaration == end) {
- paths.add(<Object>[start]);
+ paths.add(<RawTypeCycleElement>[new RawTypeCycleElement(start, null)]);
} else if (visited.add(start.declaration)) {
if (declaration is ClassBuilder && declaration.typeVariables != null) {
for (TypeVariableBuilder variable in declaration.typeVariables) {
if (variable.bound != null) {
- for (List<Object> path in findRawTypePathsToDeclaration(
- variable.bound, end, visited)) {
- paths.add(<Object>[start, variable]..addAll(path));
+ for (List<RawTypeCycleElement> path
+ in findRawTypePathsToDeclaration(
+ variable.bound, end, visited)) {
+ if (path.isNotEmpty) {
+ paths.add(<RawTypeCycleElement>[
+ new RawTypeCycleElement(start, null)
+ ]..addAll(path..first.typeVariable = variable));
+ }
}
}
}
@@ -758,10 +765,14 @@
if (declaration.typeVariables != null) {
for (TypeVariableBuilder variable in declaration.typeVariables) {
if (variable.bound != null) {
- for (List<Object> dependencyPath
+ for (List<RawTypeCycleElement> dependencyPath
in findRawTypePathsToDeclaration(
variable.bound, end, visited)) {
- paths.add(<Object>[start, variable]..addAll(dependencyPath));
+ if (dependencyPath.isNotEmpty) {
+ paths.add(<RawTypeCycleElement>[
+ new RawTypeCycleElement(start, null)
+ ]..addAll(dependencyPath..first.typeVariable = variable));
+ }
}
}
}
@@ -771,11 +782,14 @@
if (type.typeVariables != null) {
for (TypeVariableBuilder variable in type.typeVariables) {
if (variable.bound != null) {
- for (List<Object> dependencyPath
+ for (List<RawTypeCycleElement> dependencyPath
in findRawTypePathsToDeclaration(
variable.bound, end, visited)) {
- paths
- .add(<Object>[start, variable]..addAll(dependencyPath));
+ if (dependencyPath.isNotEmpty) {
+ paths.add(<RawTypeCycleElement>[
+ new RawTypeCycleElement(start, null)
+ ]..addAll(dependencyPath..first.typeVariable = variable));
+ }
}
}
}
@@ -814,22 +828,24 @@
/// Finds raw generic type cycles ending and starting with [declaration].
///
-/// Returns list of found cycles. Each cycle is represented as a list of
-/// alternating raw generic types from the cycle and type variables of the
-/// immediately preceding type that reference the next type in the cycle. The
+/// Returns list of found cycles consisting of [RawTypeCycleElement]s. The
/// cycle starts with a type variable from [declaration] and ends with a type
/// that has [declaration] as its declaration.
///
/// The reason for putting the type variables into the cycles is better error
/// reporting.
-List<List<Object>> findRawTypeCycles(TypeDeclarationBuilder declaration) {
- List<List<Object>> cycles = <List<Object>>[];
+List<List<RawTypeCycleElement>> findRawTypeCycles(
+ TypeDeclarationBuilder declaration) {
+ List<List<RawTypeCycleElement>> cycles = <List<RawTypeCycleElement>>[];
if (declaration is ClassBuilder && declaration.typeVariables != null) {
for (TypeVariableBuilder variable in declaration.typeVariables) {
if (variable.bound != null) {
- for (List<Object> path
+ for (List<RawTypeCycleElement> path
in findRawTypePathsToDeclaration(variable.bound, declaration)) {
- cycles.add(<Object>[variable]..addAll(path));
+ if (path.isNotEmpty) {
+ path.first.typeVariable = variable;
+ cycles.add(path);
+ }
}
}
}
@@ -837,9 +853,12 @@
if (declaration.typeVariables != null) {
for (TypeVariableBuilder variable in declaration.typeVariables) {
if (variable.bound != null) {
- for (List<Object> dependencyPath
+ for (List<RawTypeCycleElement> dependencyPath
in findRawTypePathsToDeclaration(variable.bound, declaration)) {
- cycles.add(<Object>[variable]..addAll(dependencyPath));
+ if (dependencyPath.isNotEmpty) {
+ dependencyPath.first.typeVariable = variable;
+ cycles.add(dependencyPath);
+ }
}
}
}
@@ -849,9 +868,12 @@
if (type.typeVariables != null) {
for (TypeVariableBuilder variable in type.typeVariables) {
if (variable.bound != null) {
- for (List<Object> dependencyPath
+ for (List<RawTypeCycleElement> dependencyPath
in findRawTypePathsToDeclaration(variable.bound, declaration)) {
- cycles.add(<Object>[variable]..addAll(dependencyPath));
+ if (dependencyPath.isNotEmpty) {
+ dependencyPath.first.typeVariable = variable;
+ cycles.add(dependencyPath);
+ }
}
}
}
@@ -870,34 +892,35 @@
/// [TypeDeclarationBuilder] for the type variable from [variables] that has raw
/// generic types with inbound references in its bound. The second element of
/// the triplet is the error message. The third element is the context.
-List<Object> convertRawTypeCyclesIntoIssues(
- TypeDeclarationBuilder declaration, List<List<Object>> cycles) {
- List<Object> issues = <Object>[];
- for (List<Object> cycle in cycles) {
- if (cycle.length == 2) {
+List<NonSimplicityIssue> convertRawTypeCyclesIntoIssues(
+ TypeDeclarationBuilder declaration,
+ List<List<RawTypeCycleElement>> cycles) {
+ List<NonSimplicityIssue> issues = <NonSimplicityIssue>[];
+ for (List<RawTypeCycleElement> cycle in cycles) {
+ if (cycle.length == 1) {
// Loop.
- TypeVariableBuilder variable = cycle[0];
- NamedTypeBuilder type = cycle[1];
- issues.add(variable);
- issues.add(templateBoundIssueViaLoopNonSimplicity
- .withArguments(type.declaration.name));
- issues.add(null); // Context.
- } else {
+ issues.add(new NonSimplicityIssue(
+ cycle.single.typeVariable,
+ templateBoundIssueViaLoopNonSimplicity
+ .withArguments(cycle.single.type.declaration.name),
+ null));
+ } else if (cycle.isNotEmpty) {
+ assert(cycle.length > 1);
List<LocatedMessage> context = <LocatedMessage>[];
- for (int i = 0; i < cycle.length; i += 2) {
- TypeVariableBuilder variable = cycle[i];
- NamedTypeBuilder type = cycle[i + 1];
+ for (RawTypeCycleElement cycleElement in cycle) {
context.add(templateNonSimpleBoundViaReference
- .withArguments(type.declaration.name)
+ .withArguments(cycleElement.type.declaration.name)
.withLocation(
- variable.fileUri, variable.charOffset, variable.name.length));
+ cycleElement.typeVariable.fileUri,
+ cycleElement.typeVariable.charOffset,
+ cycleElement.typeVariable.name.length));
}
- NamedTypeBuilder firstEncounteredType = cycle[1];
- issues.add(declaration);
- issues.add(templateBoundIssueViaCycleNonSimplicity.withArguments(
- declaration.name, firstEncounteredType.declaration.name));
- issues.add(context);
+ issues.add(new NonSimplicityIssue(
+ declaration,
+ templateBoundIssueViaCycleNonSimplicity.withArguments(
+ declaration.name, cycle.first.type.declaration.name),
+ context));
}
}
return issues;
@@ -912,9 +935,9 @@
/// first element in the triplet is the type declaration that has the issue.
/// The second element in the triplet is the error message. The third element
/// in the triplet is the context.
-List<Object> getNonSimplicityIssuesForTypeVariables(
+List<NonSimplicityIssue> getNonSimplicityIssuesForTypeVariables(
List<TypeVariableBuilder> variables) {
- if (variables == null) return <Object>[];
+ if (variables == null) return <NonSimplicityIssue>[];
return getInboundReferenceIssues(variables);
}
@@ -928,31 +951,31 @@
/// first element in the triplet is the type declaration that has the issue.
/// The second element in the triplet is the error message. The third element
/// in the triplet is the context.
-List<Object> getNonSimplicityIssuesForDeclaration(
+List<NonSimplicityIssue> getNonSimplicityIssuesForDeclaration(
TypeDeclarationBuilder declaration,
{bool performErrorRecovery: true}) {
- List<Object> issues = <Object>[];
+ List<NonSimplicityIssue> issues = <NonSimplicityIssue>[];
if (declaration is ClassBuilder && declaration.typeVariables != null) {
issues.addAll(getInboundReferenceIssues(declaration.typeVariables));
} else if (declaration is TypeAliasBuilder &&
declaration.typeVariables != null) {
issues.addAll(getInboundReferenceIssues(declaration.typeVariables));
}
- List<List<Object>> cyclesToReport = <List<Object>>[];
- for (List<Object> cycle in findRawTypeCycles(declaration)) {
+ List<List<RawTypeCycleElement>> cyclesToReport =
+ <List<RawTypeCycleElement>>[];
+ for (List<RawTypeCycleElement> cycle in findRawTypeCycles(declaration)) {
// To avoid reporting the same error for each element of the cycle, we only
// do so if it comes the first in the lexicographical order. Note that
// one-element cycles shouldn't be checked, as they are loops.
- if (cycle.length == 2) {
+ if (cycle.length == 1) {
cyclesToReport.add(cycle);
} else {
String declarationPathAndName =
"${declaration.fileUri}:${declaration.name}";
String lexMinPathAndName = null;
- for (int i = 1; i < cycle.length; i += 2) {
- NamedTypeBuilder type = cycle[i];
- String pathAndName =
- "${type.declaration.fileUri}:${type.declaration.name}";
+ for (RawTypeCycleElement cycleElement in cycle) {
+ String pathAndName = "${cycleElement.type.declaration.fileUri}:"
+ "${cycleElement.type.declaration.name}";
if (lexMinPathAndName == null ||
lexMinPathAndName.compareTo(pathAndName) > 0) {
lexMinPathAndName = pathAndName;
@@ -963,7 +986,7 @@
}
}
}
- List<Object> rawTypeCyclesAsIssues =
+ List<NonSimplicityIssue> rawTypeCyclesAsIssues =
convertRawTypeCyclesIntoIssues(declaration, cyclesToReport);
issues.addAll(rawTypeCyclesAsIssues);
@@ -978,10 +1001,11 @@
///
/// The [cycles] are expected to be in the format specified for the return value
/// of [findRawTypeCycles].
-void breakCycles(List<List<Object>> cycles) {
- for (List<Object> cycle in cycles) {
- TypeVariableBuilder variable = cycle[0];
- variable.bound = null;
+void breakCycles(List<List<RawTypeCycleElement>> cycles) {
+ for (List<RawTypeCycleElement> cycle in cycles) {
+ if (cycle.isNotEmpty) {
+ cycle.first.typeVariable.bound = null;
+ }
}
}
@@ -1123,3 +1147,60 @@
return anyTypeVariables(node.typeArguments);
}
}
+
+/// A representation of a found non-simplicity issue in bounds
+///
+/// The following are the examples of generic declarations with non-simple
+/// bounds:
+///
+/// // `A` has a non-simple bound.
+/// class A<X extends A<X>> {}
+///
+/// // Error: A type with non-simple bounds is used raw in another bound.
+/// class B<Y extends A> {}
+///
+/// // Error: Checking if a type has non-simple bounds leads back to the type,
+/// // so the process is infinite. In that case, the type is deemed as having
+/// // non-simple bounds.
+/// class C<U extends D> {} // `C` has a non-simple bound.
+/// class D<V extends C> {} // `D` has a non-simple bound.
+///
+/// See section 15.3.1 Auxiliary Concepts for Instantiation to Bound.
+class NonSimplicityIssue {
+ /// The generic declaration that has a non-simplicity issue.
+ final TypeDeclarationBuilder declaration;
+
+ /// The non-simplicity error message.
+ final Message message;
+
+ /// The context for the error message, containing the locations of all of the
+ /// elements from the cycle.
+ final List<LocatedMessage> context;
+
+ NonSimplicityIssue(this.declaration, this.message, this.context);
+}
+
+/// Represents an element of a non-simple raw type cycle
+///
+/// Such cycles appear when the process of checking if a type has a non-simple
+/// bound leads back to that type. The cycle that goes through other types and
+/// type variables in-between them is recorded for better error reporting. An
+/// example of such cycle is the following:
+///
+/// // Error: Checking if a type has non-simple bounds leads back to the type,
+/// // so the process is infinite. In that case, the type is deemed as having
+/// // non-simple bounds.
+/// class C<U extends D> {} // `C` has a non-simple bound.
+/// class D<V extends C> {} // `D` has a non-simple bound.
+///
+/// See section 15.3.1 Auxiliary Concepts for Instantiation to Bound.
+class RawTypeCycleElement {
+ /// The type that is on a non-simple raw type cycle.
+ final TypeBuilder type;
+
+ /// The type variable that connects [type] to the next element in the
+ /// non-simple raw type cycle.
+ TypeVariableBuilder typeVariable;
+
+ RawTypeCycleElement(this.type, this.typeVariable);
+}
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 94ed0ca..aca996f 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
@@ -93,6 +93,7 @@
import '../kernel/type_algorithms.dart'
show
+ NonSimplicityIssue,
calculateBounds,
computeTypeVariableBuilderVariance,
findGenericFunctionTypes,
@@ -3078,24 +3079,20 @@
return variables.length;
}
- void reportIssues(List<Object> issues) {
- for (int i = 0; i < issues.length; i += 3) {
- TypeDeclarationBuilder declaration = issues[i];
- Message message = issues[i + 1];
- List<LocatedMessage> context = issues[i + 2];
-
- addProblem(message, declaration.charOffset, declaration.name.length,
- declaration.fileUri,
- context: context);
+ void reportIssues(List<NonSimplicityIssue> issues) {
+ for (NonSimplicityIssue issue in issues) {
+ addProblem(issue.message, issue.declaration.charOffset,
+ issue.declaration.name.length, issue.declaration.fileUri,
+ context: issue.context);
}
}
for (Builder declaration in libraryDeclaration.members.values) {
if (declaration is ClassBuilder) {
{
- List<Object> issues = getNonSimplicityIssuesForDeclaration(
- declaration,
- performErrorRecovery: true);
+ List<NonSimplicityIssue> issues =
+ getNonSimplicityIssuesForDeclaration(declaration,
+ performErrorRecovery: true);
reportIssues(issues);
count += computeDefaultTypesForVariables(declaration.typeVariables,
inErrorRecovery: issues.isNotEmpty);
@@ -3417,7 +3414,11 @@
DartType superBoundedAttempt,
DartType superBoundedAttemptInverted}) {
List<LocatedMessage> context;
- if (typeParameter != null && typeParameter.fileOffset != -1) {
+ // Skip reporting location for function-type type parameters as it's a
+ // limitation of Kernel.
+ if (typeParameter != null &&
+ typeParameter.fileOffset != -1 &&
+ typeParameter.parent != null) {
// It looks like when parameters come from patch files, they don't
// have a reportable location.
(context ??= <LocatedMessage>[]).add(
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart b/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart
index bdf54c8..5e8e77f 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart
@@ -10,10 +10,13 @@
import 'package:kernel/core_types.dart' show CoreTypes;
-import 'package:kernel/type_algebra.dart' show Substitution;
+import 'package:kernel/type_algebra.dart'
+ show FreshTypeParameters, Substitution, getFreshTypeParameters, substitute;
import 'package:kernel/type_environment.dart';
+import 'package:kernel/src/bounds_checks.dart' show calculateBounds;
+
import 'package:kernel/src/hierarchy_based_type_environment.dart'
show HierarchyBasedTypeEnvironment;
@@ -357,6 +360,42 @@
preferUpwardsInference: !typeParam.isLegacyCovariant);
}
}
+
+ if (!downwardsInferPhase) {
+ assert(typeParametersToInfer.length == inferredTypes.length);
+ FreshTypeParameters freshTypeParameters =
+ getFreshTypeParameters(typeParametersToInfer);
+ List<TypeParameter> helperTypeParameters =
+ freshTypeParameters.freshTypeParameters;
+
+ Map<TypeParameter, DartType> inferredSubstitution =
+ <TypeParameter, DartType>{};
+ for (int i = 0; i < helperTypeParameters.length; ++i) {
+ if (inferredTypes[i] is UnknownType) {
+ inferredSubstitution[helperTypeParameters[i]] =
+ new TypeParameterType.forAlphaRenaming(
+ helperTypeParameters[i], helperTypeParameters[i]);
+ } else {
+ assert(isKnown(inferredTypes[i]));
+ inferredSubstitution[helperTypeParameters[i]] = inferredTypes[i];
+ }
+ }
+ for (int i = 0; i < helperTypeParameters.length; ++i) {
+ if (inferredTypes[i] is UnknownType) {
+ helperTypeParameters[i].bound =
+ substitute(helperTypeParameters[i].bound, inferredSubstitution);
+ } else {
+ helperTypeParameters[i].bound = inferredTypes[i];
+ }
+ }
+ List<DartType> instantiatedTypes = calculateBounds(
+ helperTypeParameters, coreTypes.objectClass, clientLibrary);
+ for (int i = 0; i < instantiatedTypes.length; ++i) {
+ if (inferredTypes[i] is UnknownType) {
+ inferredTypes[i] = instantiatedTypes[i];
+ }
+ }
+ }
}
@override
@@ -423,7 +462,9 @@
/// of constraints.
///
/// If [grounded] is `true`, then the returned type is guaranteed to be a
- /// known type (i.e. it will not contain any instances of `?`).
+ /// known type (i.e. it will not contain any instances of `?`) if it is
+ /// constrained at all. The returned type for unconstrained variables is
+ /// [UnknownType].
///
/// If [isContravariant] is `true`, then we are solving for a contravariant
/// type parameter which means we choose the upper bound rather than the
@@ -449,7 +490,7 @@
? greatestClosure(constraint.upper, topType, bottomType)
: constraint.upper;
} else {
- return grounded ? const DynamicType() : const UnknownType();
+ return const UnknownType();
}
} else {
// Prefer the known bound, if any.
@@ -467,7 +508,7 @@
? leastClosure(constraint.lower, topType, bottomType)
: constraint.lower;
} else {
- return grounded ? bottomType : const UnknownType();
+ return const UnknownType();
}
}
}
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index 99253fc..d15884e 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -92,8 +92,6 @@
ConstConstructorLateFinalFieldWarning/example: Fail
ConstConstructorNonFinalField/example: Fail
ConstConstructorRedirectionToNonConst/analyzerCode: Fail # The analyzer doesn't report this error.
-ConstEvalBadState/analyzerCode: Fail
-ConstEvalBadState/example: Fail
ConstEvalCaseImplementsEqual/analyzerCode: Fail
ConstEvalCaseImplementsEqual/example: Fail
ConstEvalCircularity/example: Fail
@@ -139,6 +137,8 @@
ConstEvalTruncateError/example: Fail
ConstEvalUnevaluated/analyzerCode: Fail
ConstEvalUnevaluated/example: Fail
+ConstEvalUnhandledCoreException/analyzerCode: Fail
+ConstEvalUnhandledCoreException/example: Fail
ConstEvalUnhandledException/analyzerCode: Fail
ConstEvalUnhandledException/example: Fail
ConstEvalZeroDivisor/example: Fail
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 6b392cf..dafcd5f 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -106,9 +106,6 @@
ConstEvalStartingPoint:
template: "Constant evaluation error:"
-ConstEvalBadState:
- template: "Bad state: '#stringOKEmpty'"
-
ConstEvalContext:
template: "While analyzing:"
@@ -225,6 +222,9 @@
ConstEvalUnevaluated:
template: "Couldn't evaluate constant expression."
+ConstEvalUnhandledCoreException:
+ template: "Unhandled core exception: #stringOKEmpty"
+
ConstEvalUnhandledException:
template: "Unhandled exception: #constant"
@@ -4366,7 +4366,7 @@
FfiEmptyStruct:
# Used by dart:ffi
- template: "Struct '#name' is empty. Empty structs are undefined behavior."
+ template: "#string '#name' is empty. Empty structs and unions are undefined behavior."
external: test/ffi_test.dart
FfiTypeInvalid:
@@ -4376,12 +4376,12 @@
FfiFieldNull:
# Used by dart:ffi
- template: "Field '#name' cannot have type 'Null', it must be `int`, `double`, `Pointer`, or a subtype of `Struct`."
+ template: "Field '#name' cannot have type 'Null', it must be `int`, `double`, `Pointer`, or a subtype of `Struct` or `Union`."
external: test/ffi_test.dart
FfiFieldAnnotation:
# Used by dart:ffi
- template: "Field '#name' requires exactly one annotation to declare its native 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 and Unions cannot have regular Dart fields."
external: test/ffi_test.dart
FfiFieldNoAnnotation:
@@ -4392,7 +4392,7 @@
FfiFieldCyclic:
# Used by dart:ffi
template: |
- Struct '#name' contains itself. Cycle elements:
+ #string '#name' contains itself. Cycle elements:
#names
external: test/ffi_test.dart
@@ -4439,7 +4439,7 @@
FfiStructGeneric:
# Used by dart:ffi
- template: "Struct '#name' should not be generic."
+ template: "#string '#name' should not be generic."
external: test/ffi_test.dart
FfiDartTypeMismatch:
diff --git a/pkg/front_end/test/fasta/type_inference/type_schema_environment_nnbd_test.dart b/pkg/front_end/test/fasta/type_inference/type_schema_environment_nnbd_test.dart
index 67cfacc..a1448b7 100644
--- a/pkg/front_end/test/fasta/type_inference/type_schema_environment_nnbd_test.dart
+++ b/pkg/front_end/test/fasta/type_inference/type_schema_environment_nnbd_test.dart
@@ -1403,8 +1403,10 @@
// Solve(? <: T <: ?) => ?
checkConstraintSolving("", "UNKNOWN", grounded: false);
- // Solve(? <: T <: ?, grounded) => dynamic
- checkConstraintSolving("", "dynamic", grounded: true);
+ // Solve(? <: T <: ?, grounded) => ?
+ // Fully unconstrained variables are inferred via instantiate-to-bounds
+ // rather than constraint solving.
+ checkConstraintSolving("", "UNKNOWN", grounded: true);
// Solve(A <: T <: ?) => A
checkConstraintSolving(":> A<dynamic>*", "A<dynamic>*", grounded: false);
diff --git a/pkg/front_end/test/fasta/type_inference/type_schema_environment_test.dart b/pkg/front_end/test/fasta/type_inference/type_schema_environment_test.dart
index ba48bb9..027bac2 100644
--- a/pkg/front_end/test/fasta/type_inference/type_schema_environment_test.dart
+++ b/pkg/front_end/test/fasta/type_inference/type_schema_environment_test.dart
@@ -493,8 +493,10 @@
// Solve(? <: T <: ?) => ?
checkConstraintSolving("", "UNKNOWN", grounded: false);
- // Solve(? <: T <: ?, grounded) => dynamic
- checkConstraintSolving("", "dynamic", grounded: true);
+ // Solve(? <: T <: ?, grounded) => ?
+ // Fully unconstrained variables are inferred via instantiate-to-bounds
+ // rather than constraint solving.
+ checkConstraintSolving("", "UNKNOWN", grounded: true);
// Solve(A <: T <: ?) => A
checkConstraintSolving(":> A*", "A*", grounded: false);
diff --git a/pkg/front_end/test/language_versioning/language_versioning_up_to_date_git_test.dart b/pkg/front_end/test/language_versioning/language_versioning_up_to_date_git_test.dart
index 16a442b..d79b1fd 100644
--- a/pkg/front_end/test/language_versioning/language_versioning_up_to_date_git_test.dart
+++ b/pkg/front_end/test/language_versioning/language_versioning_up_to_date_git_test.dart
@@ -18,7 +18,7 @@
main(List<String> args) async {
ProcessResult result = await Process.run(
- "python", ["tools/make_version.py", "--no_git", "-q"],
+ "python3", ["tools/make_version.py", "--no_git", "-q"],
workingDirectory: repoDir);
String stdout = result.stdout.toString();
diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt
index 912054f..f6a69db 100644
--- a/pkg/front_end/test/spell_checking_list_common.txt
+++ b/pkg/front_end/test/spell_checking_list_common.txt
@@ -415,6 +415,7 @@
causes
causing
caveats
+cell
certain
chain
chained
@@ -561,6 +562,7 @@
computing
concatenated
concatenation
+concepts
conclude
conclusion
concrete
@@ -587,6 +589,7 @@
connect
connected
connection
+connects
consequence
consequently
conservative
@@ -1723,6 +1726,7 @@
like
likely
limit
+limitation
limited
line
linear
@@ -3181,6 +3185,7 @@
uninitialized
union
unioned
+unions
unique
unit
unite
diff --git a/pkg/front_end/test/spell_checking_list_messages.txt b/pkg/front_end/test/spell_checking_list_messages.txt
index be9adce..4d51529 100644
--- a/pkg/front_end/test/spell_checking_list_messages.txt
+++ b/pkg/front_end/test/spell_checking_list_messages.txt
@@ -19,6 +19,7 @@
compilercontext.runincontext
compilesdk
constructor(s)
+core
count.#count
d
dart.dev
diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt
index 17ee5f0..2a418f9 100644
--- a/pkg/front_end/test/spell_checking_list_tests.txt
+++ b/pkg/front_end/test/spell_checking_list_tests.txt
@@ -135,6 +135,7 @@
class5c
class5d
cloneable
+cm
cmd
cmp
cnn
diff --git a/pkg/front_end/testcases/const_functions/const_functions_list_error.dart.strong.expect b/pkg/front_end/testcases/const_functions/const_functions_list_error.dart.strong.expect
index 4024724..8f1cc49 100644
--- a/pkg/front_end/testcases/const_functions/const_functions_list_error.dart.strong.expect
+++ b/pkg/front_end/testcases/const_functions/const_functions_list_error.dart.strong.expect
@@ -11,28 +11,28 @@
// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:9:24: Error: Constant evaluation error:
// const firstException = firstExceptionFn();
// ^
-// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:12:12: Context: Bad state: 'No element'
+// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:12:12: Context: Unhandled core exception: Bad state: No element
// return x.first;
// ^
//
// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:15:23: Error: Constant evaluation error:
// const lastException = lastExceptionFn();
// ^
-// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:18:12: Context: Bad state: 'No element'
+// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:18:12: Context: Unhandled core exception: Bad state: No element
// return x.last;
// ^
//
// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:21:25: Error: Constant evaluation error:
// const singleException = singleExceptionFn();
// ^
-// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:24:12: Context: Bad state: 'No element'
+// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:24:12: Context: Unhandled core exception: Bad state: No element
// return x.single;
// ^
//
// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:27:30: Error: Constant evaluation error:
// const singleExceptionMulti = singleExceptionMultiFn();
// ^
-// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:30:12: Context: Bad state: 'Too many elements'
+// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:30:12: Context: Unhandled core exception: Bad state: Too many elements
// return x.single;
// ^
//
@@ -41,10 +41,10 @@
import "package:expect/expect.dart";
-static const field core::int firstException = invalid-expression "Bad state: 'No element'";
-static const field core::int lastException = invalid-expression "Bad state: 'No element'";
-static const field core::int singleException = invalid-expression "Bad state: 'No element'";
-static const field core::int singleExceptionMulti = invalid-expression "Bad state: 'Too many elements'";
+static const field core::int firstException = invalid-expression "Unhandled core exception: Bad state: No element";
+static const field core::int lastException = invalid-expression "Unhandled core exception: Bad state: No element";
+static const field core::int singleException = invalid-expression "Unhandled core exception: Bad state: No element";
+static const field core::int singleExceptionMulti = invalid-expression "Unhandled core exception: Bad state: Too many elements";
static const field core::int invalidProperty = invalid-expression "pkg/front_end/testcases/const_functions/const_functions_list_error.dart:36:12: Error: The getter 'invalidProperty' isn't defined for the class 'List<int>'.
- 'List' is from 'dart:core'.
Try correcting the name to the name of an existing getter, or defining a getter or field named 'invalidProperty'.
diff --git a/pkg/front_end/testcases/const_functions/const_functions_list_error.dart.strong.transformed.expect b/pkg/front_end/testcases/const_functions/const_functions_list_error.dart.strong.transformed.expect
index 6cf44d0..8ec1037 100644
--- a/pkg/front_end/testcases/const_functions/const_functions_list_error.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/const_functions/const_functions_list_error.dart.strong.transformed.expect
@@ -11,28 +11,28 @@
// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:9:24: Error: Constant evaluation error:
// const firstException = firstExceptionFn();
// ^
-// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:12:12: Context: Bad state: 'No element'
+// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:12:12: Context: Unhandled core exception: Bad state: No element
// return x.first;
// ^
//
// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:15:23: Error: Constant evaluation error:
// const lastException = lastExceptionFn();
// ^
-// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:18:12: Context: Bad state: 'No element'
+// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:18:12: Context: Unhandled core exception: Bad state: No element
// return x.last;
// ^
//
// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:21:25: Error: Constant evaluation error:
// const singleException = singleExceptionFn();
// ^
-// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:24:12: Context: Bad state: 'No element'
+// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:24:12: Context: Unhandled core exception: Bad state: No element
// return x.single;
// ^
//
// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:27:30: Error: Constant evaluation error:
// const singleExceptionMulti = singleExceptionMultiFn();
// ^
-// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:30:12: Context: Bad state: 'Too many elements'
+// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:30:12: Context: Unhandled core exception: Bad state: Too many elements
// return x.single;
// ^
//
@@ -41,10 +41,10 @@
import "package:expect/expect.dart";
-static const field core::int firstException = invalid-expression "Bad state: 'No element'";
-static const field core::int lastException = invalid-expression "Bad state: 'No element'";
-static const field core::int singleException = invalid-expression "Bad state: 'No element'";
-static const field core::int singleExceptionMulti = invalid-expression "Bad state: 'Too many elements'";
+static const field core::int firstException = invalid-expression "Unhandled core exception: Bad state: No element";
+static const field core::int lastException = invalid-expression "Unhandled core exception: Bad state: No element";
+static const field core::int singleException = invalid-expression "Unhandled core exception: Bad state: No element";
+static const field core::int singleExceptionMulti = invalid-expression "Unhandled core exception: Bad state: Too many elements";
static const field core::int invalidProperty = invalid-expression "pkg/front_end/testcases/const_functions/const_functions_list_error.dart:36:12: Error: The getter 'invalidProperty' isn't defined for the class 'List<int>'.
- 'List' is from 'dart:core'.
Try correcting the name to the name of an existing getter, or defining a getter or field named 'invalidProperty'.
diff --git a/pkg/front_end/testcases/const_functions/const_functions_list_error.dart.weak.expect b/pkg/front_end/testcases/const_functions/const_functions_list_error.dart.weak.expect
index fea30ee..6d2f2a4 100644
--- a/pkg/front_end/testcases/const_functions/const_functions_list_error.dart.weak.expect
+++ b/pkg/front_end/testcases/const_functions/const_functions_list_error.dart.weak.expect
@@ -11,28 +11,28 @@
// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:9:24: Error: Constant evaluation error:
// const firstException = firstExceptionFn();
// ^
-// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:12:12: Context: Bad state: 'No element'
+// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:12:12: Context: Unhandled core exception: Bad state: No element
// return x.first;
// ^
//
// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:15:23: Error: Constant evaluation error:
// const lastException = lastExceptionFn();
// ^
-// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:18:12: Context: Bad state: 'No element'
+// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:18:12: Context: Unhandled core exception: Bad state: No element
// return x.last;
// ^
//
// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:21:25: Error: Constant evaluation error:
// const singleException = singleExceptionFn();
// ^
-// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:24:12: Context: Bad state: 'No element'
+// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:24:12: Context: Unhandled core exception: Bad state: No element
// return x.single;
// ^
//
// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:27:30: Error: Constant evaluation error:
// const singleExceptionMulti = singleExceptionMultiFn();
// ^
-// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:30:12: Context: Bad state: 'Too many elements'
+// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:30:12: Context: Unhandled core exception: Bad state: Too many elements
// return x.single;
// ^
//
@@ -41,10 +41,10 @@
import "package:expect/expect.dart";
-static const field core::int firstException = invalid-expression "Bad state: 'No element'";
-static const field core::int lastException = invalid-expression "Bad state: 'No element'";
-static const field core::int singleException = invalid-expression "Bad state: 'No element'";
-static const field core::int singleExceptionMulti = invalid-expression "Bad state: 'Too many elements'";
+static const field core::int firstException = invalid-expression "Unhandled core exception: Bad state: No element";
+static const field core::int lastException = invalid-expression "Unhandled core exception: Bad state: No element";
+static const field core::int singleException = invalid-expression "Unhandled core exception: Bad state: No element";
+static const field core::int singleExceptionMulti = invalid-expression "Unhandled core exception: Bad state: Too many elements";
static const field core::int invalidProperty = invalid-expression "pkg/front_end/testcases/const_functions/const_functions_list_error.dart:36:12: Error: The getter 'invalidProperty' isn't defined for the class 'List<int>'.
- 'List' is from 'dart:core'.
Try correcting the name to the name of an existing getter, or defining a getter or field named 'invalidProperty'.
diff --git a/pkg/front_end/testcases/const_functions/const_functions_list_error.dart.weak.transformed.expect b/pkg/front_end/testcases/const_functions/const_functions_list_error.dart.weak.transformed.expect
index 95805b6..54d1e2b 100644
--- a/pkg/front_end/testcases/const_functions/const_functions_list_error.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/const_functions/const_functions_list_error.dart.weak.transformed.expect
@@ -11,28 +11,28 @@
// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:9:24: Error: Constant evaluation error:
// const firstException = firstExceptionFn();
// ^
-// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:12:12: Context: Bad state: 'No element'
+// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:12:12: Context: Unhandled core exception: Bad state: No element
// return x.first;
// ^
//
// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:15:23: Error: Constant evaluation error:
// const lastException = lastExceptionFn();
// ^
-// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:18:12: Context: Bad state: 'No element'
+// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:18:12: Context: Unhandled core exception: Bad state: No element
// return x.last;
// ^
//
// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:21:25: Error: Constant evaluation error:
// const singleException = singleExceptionFn();
// ^
-// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:24:12: Context: Bad state: 'No element'
+// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:24:12: Context: Unhandled core exception: Bad state: No element
// return x.single;
// ^
//
// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:27:30: Error: Constant evaluation error:
// const singleExceptionMulti = singleExceptionMultiFn();
// ^
-// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:30:12: Context: Bad state: 'Too many elements'
+// pkg/front_end/testcases/const_functions/const_functions_list_error.dart:30:12: Context: Unhandled core exception: Bad state: Too many elements
// return x.single;
// ^
//
@@ -41,10 +41,10 @@
import "package:expect/expect.dart";
-static const field core::int firstException = invalid-expression "Bad state: 'No element'";
-static const field core::int lastException = invalid-expression "Bad state: 'No element'";
-static const field core::int singleException = invalid-expression "Bad state: 'No element'";
-static const field core::int singleExceptionMulti = invalid-expression "Bad state: 'Too many elements'";
+static const field core::int firstException = invalid-expression "Unhandled core exception: Bad state: No element";
+static const field core::int lastException = invalid-expression "Unhandled core exception: Bad state: No element";
+static const field core::int singleException = invalid-expression "Unhandled core exception: Bad state: No element";
+static const field core::int singleExceptionMulti = invalid-expression "Unhandled core exception: Bad state: Too many elements";
static const field core::int invalidProperty = invalid-expression "pkg/front_end/testcases/const_functions/const_functions_list_error.dart:36:12: Error: The getter 'invalidProperty' isn't defined for the class 'List<int>'.
- 'List' is from 'dart:core'.
Try correcting the name to the name of an existing getter, or defining a getter or field named 'invalidProperty'.
diff --git a/pkg/front_end/testcases/const_functions/const_functions_return.dart b/pkg/front_end/testcases/const_functions/const_functions_return.dart
index 6a2eb8d..661c217 100644
--- a/pkg/front_end/testcases/const_functions/const_functions_return.dart
+++ b/pkg/front_end/testcases/const_functions/const_functions_return.dart
@@ -22,9 +22,19 @@
return null;
}
+const var5 = fn5();
+int fn5() {
+ try {
+ return throw 1;
+ } on int {
+ return 2;
+ }
+}
+
void main() {
Expect.equals((var1 as dynamic), null);
Expect.equals((var2 as dynamic), null);
Expect.equals(var3, null);
Expect.equals(var4, null);
+ Expect.equals(var5, 2);
}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_return.dart.strong.expect b/pkg/front_end/testcases/const_functions/const_functions_return.dart.strong.expect
index 3253656..4ea38f7 100644
--- a/pkg/front_end/testcases/const_functions/const_functions_return.dart.strong.expect
+++ b/pkg/front_end/testcases/const_functions/const_functions_return.dart.strong.expect
@@ -9,6 +9,7 @@
static const field void var2 = #C1;
static const field core::int? var3 = #C1;
static const field core::int? var4 = #C1;
+static const field core::int var5 = #C2;
static method fn() → void {}
static method fn2() → void {
return;
@@ -18,13 +19,23 @@
static method fn4() → core::int? {
return null;
}
+static method fn5() → core::int {
+ try {
+ return throw 1;
+ }
+ on core::int catch(no-exception-var) {
+ return 2;
+ }
+}
static method main() → void {
exp::Expect::equals((#C1) as{ForNonNullableByDefault} dynamic, null);
exp::Expect::equals((#C1) as{ForNonNullableByDefault} dynamic, null);
exp::Expect::equals(#C1, null);
exp::Expect::equals(#C1, null);
+ exp::Expect::equals(#C2, 2);
}
constants {
#C1 = null
+ #C2 = 2
}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_return.dart.strong.transformed.expect b/pkg/front_end/testcases/const_functions/const_functions_return.dart.strong.transformed.expect
index 59de3d1..16743c6 100644
--- a/pkg/front_end/testcases/const_functions/const_functions_return.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/const_functions/const_functions_return.dart.strong.transformed.expect
@@ -9,6 +9,7 @@
static const field void var2 = #C1;
static const field core::int? var3 = #C1;
static const field core::int? var4 = #C1;
+static const field core::int var5 = #C2;
static method fn() → void {}
static method fn2() → void {
return;
@@ -18,18 +19,28 @@
static method fn4() → core::int? {
return null;
}
+static method fn5() → core::int {
+ try {
+ return throw 1;
+ }
+ on core::int catch(no-exception-var) {
+ return 2;
+ }
+}
static method main() → void {
exp::Expect::equals((#C1) as{ForNonNullableByDefault} dynamic, null);
exp::Expect::equals((#C1) as{ForNonNullableByDefault} dynamic, null);
exp::Expect::equals(#C1, null);
exp::Expect::equals(#C1, null);
+ exp::Expect::equals(#C2, 2);
}
constants {
#C1 = null
+ #C2 = 2
}
Extra constant evaluation status:
-Evaluated: AsExpression @ org-dartlang-testcase:///const_functions_return.dart:26:23 -> NullConstant(null)
-Evaluated: AsExpression @ org-dartlang-testcase:///const_functions_return.dart:27:23 -> NullConstant(null)
-Extra constant evaluation: evaluated: 6, effectively constant: 2
+Evaluated: AsExpression @ org-dartlang-testcase:///const_functions_return.dart:35:23 -> NullConstant(null)
+Evaluated: AsExpression @ org-dartlang-testcase:///const_functions_return.dart:36:23 -> NullConstant(null)
+Extra constant evaluation: evaluated: 8, effectively constant: 2
diff --git a/pkg/front_end/testcases/const_functions/const_functions_return.dart.textual_outline.expect b/pkg/front_end/testcases/const_functions/const_functions_return.dart.textual_outline.expect
index cf82ba3..4232e88 100644
--- a/pkg/front_end/testcases/const_functions/const_functions_return.dart.textual_outline.expect
+++ b/pkg/front_end/testcases/const_functions/const_functions_return.dart.textual_outline.expect
@@ -8,4 +8,6 @@
int? fn3() => null;
const var4 = fn4();
int? fn4() {}
+const var5 = fn5();
+int fn5() {}
void main() {}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_return.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/const_functions/const_functions_return.dart.textual_outline_modelled.expect
index 06ba06e..2800612 100644
--- a/pkg/front_end/testcases/const_functions/const_functions_return.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/const_functions/const_functions_return.dart.textual_outline_modelled.expect
@@ -4,8 +4,10 @@
const var2 = fn2();
const var3 = fn3();
const var4 = fn4();
+const var5 = fn5();
int? fn3() => null;
int? fn4() {}
+int fn5() {}
void fn() {}
void fn2() {}
void main() {}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_return.dart.weak.expect b/pkg/front_end/testcases/const_functions/const_functions_return.dart.weak.expect
index 3253656..4ea38f7 100644
--- a/pkg/front_end/testcases/const_functions/const_functions_return.dart.weak.expect
+++ b/pkg/front_end/testcases/const_functions/const_functions_return.dart.weak.expect
@@ -9,6 +9,7 @@
static const field void var2 = #C1;
static const field core::int? var3 = #C1;
static const field core::int? var4 = #C1;
+static const field core::int var5 = #C2;
static method fn() → void {}
static method fn2() → void {
return;
@@ -18,13 +19,23 @@
static method fn4() → core::int? {
return null;
}
+static method fn5() → core::int {
+ try {
+ return throw 1;
+ }
+ on core::int catch(no-exception-var) {
+ return 2;
+ }
+}
static method main() → void {
exp::Expect::equals((#C1) as{ForNonNullableByDefault} dynamic, null);
exp::Expect::equals((#C1) as{ForNonNullableByDefault} dynamic, null);
exp::Expect::equals(#C1, null);
exp::Expect::equals(#C1, null);
+ exp::Expect::equals(#C2, 2);
}
constants {
#C1 = null
+ #C2 = 2
}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_return.dart.weak.outline.expect b/pkg/front_end/testcases/const_functions/const_functions_return.dart.weak.outline.expect
index 1587dfd..913960f 100644
--- a/pkg/front_end/testcases/const_functions/const_functions_return.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/const_functions/const_functions_return.dart.weak.outline.expect
@@ -8,6 +8,7 @@
static const field void var2 = self::fn2();
static const field core::int? var3 = self::fn3();
static const field core::int? var4 = self::fn4();
+static const field core::int var5 = self::fn5();
static method fn() → void
;
static method fn2() → void
@@ -16,5 +17,7 @@
;
static method fn4() → core::int?
;
+static method fn5() → core::int
+ ;
static method main() → void
;
diff --git a/pkg/front_end/testcases/const_functions/const_functions_return.dart.weak.transformed.expect b/pkg/front_end/testcases/const_functions/const_functions_return.dart.weak.transformed.expect
index 59de3d1..16743c6 100644
--- a/pkg/front_end/testcases/const_functions/const_functions_return.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/const_functions/const_functions_return.dart.weak.transformed.expect
@@ -9,6 +9,7 @@
static const field void var2 = #C1;
static const field core::int? var3 = #C1;
static const field core::int? var4 = #C1;
+static const field core::int var5 = #C2;
static method fn() → void {}
static method fn2() → void {
return;
@@ -18,18 +19,28 @@
static method fn4() → core::int? {
return null;
}
+static method fn5() → core::int {
+ try {
+ return throw 1;
+ }
+ on core::int catch(no-exception-var) {
+ return 2;
+ }
+}
static method main() → void {
exp::Expect::equals((#C1) as{ForNonNullableByDefault} dynamic, null);
exp::Expect::equals((#C1) as{ForNonNullableByDefault} dynamic, null);
exp::Expect::equals(#C1, null);
exp::Expect::equals(#C1, null);
+ exp::Expect::equals(#C2, 2);
}
constants {
#C1 = null
+ #C2 = 2
}
Extra constant evaluation status:
-Evaluated: AsExpression @ org-dartlang-testcase:///const_functions_return.dart:26:23 -> NullConstant(null)
-Evaluated: AsExpression @ org-dartlang-testcase:///const_functions_return.dart:27:23 -> NullConstant(null)
-Extra constant evaluation: evaluated: 6, effectively constant: 2
+Evaluated: AsExpression @ org-dartlang-testcase:///const_functions_return.dart:35:23 -> NullConstant(null)
+Evaluated: AsExpression @ org-dartlang-testcase:///const_functions_return.dart:36:23 -> NullConstant(null)
+Extra constant evaluation: evaluated: 8, effectively constant: 2
diff --git a/pkg/front_end/testcases/dart2js/late_statics.dart.strong.expect b/pkg/front_end/testcases/dart2js/late_statics.dart.strong.expect
index 0a73391..766e7f1 100644
--- a/pkg/front_end/testcases/dart2js/late_statics.dart.strong.expect
+++ b/pkg/front_end/testcases/dart2js/late_statics.dart.strong.expect
@@ -1,7 +1,6 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
-import "dart:_internal" as _in;
import "late_statics_lib.dart" as lat;
additionalExports = (lat::a,
lat::a,
@@ -17,17 +16,11 @@
class Statics extends core::Object {
late static field core::int a;
late static final [setter] field core::int b;
- static field core::int? _#c = null;
- static field core::int? _#d = null;
+ late static field core::int c = 1.{core::int::unary-}(){() → core::int};
+ late static final field core::int d = 1.{core::int::unary-}(){() → core::int};
synthetic constructor •() → self::Statics
: super core::Object::•()
;
- static get c() → core::int
- return let final core::int? #t1 = self::Statics::_#c in #t1 == null ?{core::int} self::Statics::_#c = 1.{core::int::unary-}(){() → core::int} : #t1{core::int};
- static set c(core::int #t2) → void
- self::Statics::_#c = #t2;
- static get d() → core::int
- return let final core::int? #t3 = self::Statics::_#d in #t3 == null ?{core::int} let final core::int #t4 = 1.{core::int::unary-}(){() → core::int} in self::Statics::_#d == null ?{core::int} self::Statics::_#d = #t4 : throw new _in::LateError::fieldADI("d") : #t3{core::int};
}
static method main() → void {
self::testUninitializedNonFinalStaticField();
@@ -79,15 +72,8 @@
library /*isNonNullableByDefault*/;
import self as lat;
import "dart:core" as core;
-import "dart:_internal" as _in;
late static field core::int a;
late static final [setter] field core::int b;
-static field core::int? _#c = null;
-static field core::int? _#d = null;
-static get c() → core::int
- return let final core::int? #t5 = lat::_#c in #t5 == null ?{core::int} lat::_#c = 1.{core::int::unary-}(){() → core::int} : #t5{core::int};
-static set c(core::int #t6) → void
- lat::_#c = #t6;
-static get d() → core::int
- return let final core::int? #t7 = lat::_#d in #t7 == null ?{core::int} let final core::int #t8 = 1.{core::int::unary-}(){() → core::int} in lat::_#d == null ?{core::int} lat::_#d = #t8 : throw new _in::LateError::fieldADI("d") : #t7{core::int};
+late static field core::int c = 1.{core::int::unary-}(){() → core::int};
+late static final field core::int d = 1.{core::int::unary-}(){() → core::int};
diff --git a/pkg/front_end/testcases/dart2js/late_statics.dart.strong.transformed.expect b/pkg/front_end/testcases/dart2js/late_statics.dart.strong.transformed.expect
index f251c18..30448db 100644
--- a/pkg/front_end/testcases/dart2js/late_statics.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/dart2js/late_statics.dart.strong.transformed.expect
@@ -1,7 +1,6 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
-import "dart:_internal" as _in;
import "dart:_late_helper" as _la;
import "late_statics_lib.dart" as lat;
additionalExports = (lat::c,
@@ -16,17 +15,11 @@
class Statics extends core::Object {
static final field _la::_Cell a = new _la::_Cell::•();
static final field _la::_Cell b = new _la::_Cell::•();
- static field core::int? _#c = null;
- static field core::int? _#d = null;
+ late static field core::int c = 1.{core::int::unary-}(){() → core::int};
+ late static final field core::int d = 1.{core::int::unary-}(){() → core::int};
synthetic constructor •() → self::Statics
: super core::Object::•()
;
- static get c() → core::int
- return let final core::int? #t1 = self::Statics::_#c in #t1 == null ?{core::int} self::Statics::_#c = 1.{core::int::unary-}(){() → core::int} : #t1{core::int};
- static set c(core::int #t2) → void
- self::Statics::_#c = #t2;
- static get d() → core::int
- return let final core::int? #t3 = self::Statics::_#d in #t3 == null ?{core::int} let final core::int #t4 = 1.{core::int::unary-}(){() → core::int} in self::Statics::_#d == null ?{core::int} self::Statics::_#d = #t4 : throw new _in::LateError::fieldADI("d") : #t3{core::int};
}
static method main() → void {
self::testUninitializedNonFinalStaticField();
@@ -77,27 +70,18 @@
library /*isNonNullableByDefault*/;
import self as lat;
-import "dart:core" as core;
-import "dart:_internal" as _in;
import "dart:_late_helper" as _la;
+import "dart:core" as core;
static final field _la::_Cell a = new _la::_Cell::•();
static final field _la::_Cell b = new _la::_Cell::•();
-static field core::int? _#c = null;
-static field core::int? _#d = null;
-static get c() → core::int
- return let final core::int? #t5 = lat::_#c in #t5 == null ?{core::int} lat::_#c = 1.{core::int::unary-}(){() → core::int} : #t5{core::int};
-static set c(core::int #t6) → void
- lat::_#c = #t6;
-static get d() → core::int
- return let final core::int? #t7 = lat::_#d in #t7 == null ?{core::int} let final core::int #t8 = 1.{core::int::unary-}(){() → core::int} in lat::_#d == null ?{core::int} lat::_#d = #t8 : throw new _in::LateError::fieldADI("d") : #t7{core::int};
+late static field core::int c = 1.{core::int::unary-}(){() → core::int};
+late static final field core::int d = 1.{core::int::unary-}(){() → core::int};
Extra constant evaluation status:
Evaluated: InstanceInvocation @ org-dartlang-testcase:///late_statics.dart:22:23 -> DoubleConstant(-1.0)
Evaluated: InstanceInvocation @ org-dartlang-testcase:///late_statics.dart:23:29 -> DoubleConstant(-1.0)
-Evaluated: VariableGet @ org-dartlang-testcase:///late_statics.dart:23:25 -> DoubleConstant(-1.0)
Evaluated: InstanceInvocation @ org-dartlang-testcase:///late_statics_lib.dart:7:14 -> DoubleConstant(-1.0)
Evaluated: InstanceInvocation @ org-dartlang-testcase:///late_statics_lib.dart:8:20 -> DoubleConstant(-1.0)
-Evaluated: VariableGet @ org-dartlang-testcase:///late_statics_lib.dart:8:16 -> DoubleConstant(-1.0)
-Extra constant evaluation: evaluated: 108, effectively constant: 6
+Extra constant evaluation: evaluated: 62, effectively constant: 4
diff --git a/pkg/front_end/testcases/dart2js/late_statics.dart.weak.expect b/pkg/front_end/testcases/dart2js/late_statics.dart.weak.expect
index c53c058..766e7f1 100644
--- a/pkg/front_end/testcases/dart2js/late_statics.dart.weak.expect
+++ b/pkg/front_end/testcases/dart2js/late_statics.dart.weak.expect
@@ -1,7 +1,6 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
-import "dart:_internal" as _in;
import "late_statics_lib.dart" as lat;
additionalExports = (lat::a,
lat::a,
@@ -17,17 +16,11 @@
class Statics extends core::Object {
late static field core::int a;
late static final [setter] field core::int b;
- static field core::int? _#c = _in::createSentinel<core::int>();
- static field core::int? _#d = _in::createSentinel<core::int>();
+ late static field core::int c = 1.{core::int::unary-}(){() → core::int};
+ late static final field core::int d = 1.{core::int::unary-}(){() → core::int};
synthetic constructor •() → self::Statics
: super core::Object::•()
;
- static get c() → core::int
- return let final core::int? #t1 = self::Statics::_#c in _in::isSentinel(#t1) ?{core::int} self::Statics::_#c = 1.{core::int::unary-}(){() → core::int} : #t1{core::int};
- static set c(core::int #t2) → void
- self::Statics::_#c = #t2;
- static get d() → core::int
- return let final core::int #t3 = self::Statics::_#d in _in::isSentinel(#t3) ?{core::int} let final core::int #t4 = 1.{core::int::unary-}(){() → core::int} in _in::isSentinel(self::Statics::_#d) ?{core::int} self::Statics::_#d = #t4 : throw new _in::LateError::fieldADI("d") : #t3;
}
static method main() → void {
self::testUninitializedNonFinalStaticField();
@@ -79,15 +72,8 @@
library /*isNonNullableByDefault*/;
import self as lat;
import "dart:core" as core;
-import "dart:_internal" as _in;
late static field core::int a;
late static final [setter] field core::int b;
-static field core::int? _#c = _in::createSentinel<core::int>();
-static field core::int? _#d = _in::createSentinel<core::int>();
-static get c() → core::int
- return let final core::int? #t5 = lat::_#c in _in::isSentinel(#t5) ?{core::int} lat::_#c = 1.{core::int::unary-}(){() → core::int} : #t5{core::int};
-static set c(core::int #t6) → void
- lat::_#c = #t6;
-static get d() → core::int
- return let final core::int #t7 = lat::_#d in _in::isSentinel(#t7) ?{core::int} let final core::int #t8 = 1.{core::int::unary-}(){() → core::int} in _in::isSentinel(lat::_#d) ?{core::int} lat::_#d = #t8 : throw new _in::LateError::fieldADI("d") : #t7;
+late static field core::int c = 1.{core::int::unary-}(){() → core::int};
+late static final field core::int d = 1.{core::int::unary-}(){() → core::int};
diff --git a/pkg/front_end/testcases/dart2js/late_statics.dart.weak.outline.expect b/pkg/front_end/testcases/dart2js/late_statics.dart.weak.outline.expect
index 21ef816..76913dc 100644
--- a/pkg/front_end/testcases/dart2js/late_statics.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/dart2js/late_statics.dart.weak.outline.expect
@@ -16,13 +16,10 @@
class Statics extends core::Object {
late static field core::int a;
late static final [setter] field core::int b;
- static field core::int? _#c;
- static field core::int? _#d;
+ late static field core::int c;
+ late static final field core::int d;
synthetic constructor •() → self::Statics
;
- static get c() → core::int;
- static set c(core::int #t1) → void;
- static get d() → core::int;
}
static method main() → void
;
@@ -49,8 +46,5 @@
late static field core::int a;
late static final [setter] field core::int b;
-static field core::int? _#c;
-static field core::int? _#d;
-static get c() → core::int;
-static set c(core::int #t2) → void;
-static get d() → core::int;
+late static field core::int c;
+late static final field core::int d;
diff --git a/pkg/front_end/testcases/dart2js/late_statics.dart.weak.transformed.expect b/pkg/front_end/testcases/dart2js/late_statics.dart.weak.transformed.expect
index 3806163..30448db 100644
--- a/pkg/front_end/testcases/dart2js/late_statics.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/dart2js/late_statics.dart.weak.transformed.expect
@@ -1,7 +1,6 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
-import "dart:_internal" as _in;
import "dart:_late_helper" as _la;
import "late_statics_lib.dart" as lat;
additionalExports = (lat::c,
@@ -16,17 +15,11 @@
class Statics extends core::Object {
static final field _la::_Cell a = new _la::_Cell::•();
static final field _la::_Cell b = new _la::_Cell::•();
- static field core::int? _#c = _in::createSentinel<core::int>();
- static field core::int? _#d = _in::createSentinel<core::int>();
+ late static field core::int c = 1.{core::int::unary-}(){() → core::int};
+ late static final field core::int d = 1.{core::int::unary-}(){() → core::int};
synthetic constructor •() → self::Statics
: super core::Object::•()
;
- static get c() → core::int
- return let final core::int? #t1 = self::Statics::_#c in _in::isSentinel(#t1) ?{core::int} self::Statics::_#c = 1.{core::int::unary-}(){() → core::int} : #t1{core::int};
- static set c(core::int #t2) → void
- self::Statics::_#c = #t2;
- static get d() → core::int
- return let final core::int #t3 = self::Statics::_#d in _in::isSentinel(#t3) ?{core::int} let final core::int #t4 = 1.{core::int::unary-}(){() → core::int} in _in::isSentinel(self::Statics::_#d) ?{core::int} self::Statics::_#d = #t4 : throw new _in::LateError::fieldADI("d") : #t3;
}
static method main() → void {
self::testUninitializedNonFinalStaticField();
@@ -77,27 +70,18 @@
library /*isNonNullableByDefault*/;
import self as lat;
-import "dart:core" as core;
-import "dart:_internal" as _in;
import "dart:_late_helper" as _la;
+import "dart:core" as core;
static final field _la::_Cell a = new _la::_Cell::•();
static final field _la::_Cell b = new _la::_Cell::•();
-static field core::int? _#c = _in::createSentinel<core::int>();
-static field core::int? _#d = _in::createSentinel<core::int>();
-static get c() → core::int
- return let final core::int? #t5 = lat::_#c in _in::isSentinel(#t5) ?{core::int} lat::_#c = 1.{core::int::unary-}(){() → core::int} : #t5{core::int};
-static set c(core::int #t6) → void
- lat::_#c = #t6;
-static get d() → core::int
- return let final core::int #t7 = lat::_#d in _in::isSentinel(#t7) ?{core::int} let final core::int #t8 = 1.{core::int::unary-}(){() → core::int} in _in::isSentinel(lat::_#d) ?{core::int} lat::_#d = #t8 : throw new _in::LateError::fieldADI("d") : #t7;
+late static field core::int c = 1.{core::int::unary-}(){() → core::int};
+late static final field core::int d = 1.{core::int::unary-}(){() → core::int};
Extra constant evaluation status:
Evaluated: InstanceInvocation @ org-dartlang-testcase:///late_statics.dart:22:23 -> DoubleConstant(-1.0)
Evaluated: InstanceInvocation @ org-dartlang-testcase:///late_statics.dart:23:29 -> DoubleConstant(-1.0)
-Evaluated: VariableGet @ org-dartlang-testcase:///late_statics.dart:23:25 -> DoubleConstant(-1.0)
Evaluated: InstanceInvocation @ org-dartlang-testcase:///late_statics_lib.dart:7:14 -> DoubleConstant(-1.0)
Evaluated: InstanceInvocation @ org-dartlang-testcase:///late_statics_lib.dart:8:20 -> DoubleConstant(-1.0)
-Evaluated: VariableGet @ org-dartlang-testcase:///late_statics_lib.dart:8:16 -> DoubleConstant(-1.0)
-Extra constant evaluation: evaluated: 112, effectively constant: 6
+Extra constant evaluation: evaluated: 62, effectively constant: 4
diff --git a/pkg/front_end/testcases/general/issue45598.dart b/pkg/front_end/testcases/general/issue45598.dart
new file mode 100644
index 0000000..ad18575
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45598.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// @dart=2.9
+
+foo(Function<X extends Z, Y, Z>({Map<Y, Z> m}) bar, Map<String, String> m) {
+ bar(m: m);
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/general/issue45598.dart.textual_outline.expect b/pkg/front_end/testcases/general/issue45598.dart.textual_outline.expect
new file mode 100644
index 0000000..734e138
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45598.dart.textual_outline.expect
@@ -0,0 +1,3 @@
+// @dart = 2.9
+foo(Function<X extends Z, Y, Z>({Map<Y, Z> m}) bar, Map<String, String> m) {}
+main() {}
diff --git a/pkg/front_end/testcases/general/issue45598.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/issue45598.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..734e138
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45598.dart.textual_outline_modelled.expect
@@ -0,0 +1,3 @@
+// @dart = 2.9
+foo(Function<X extends Z, Y, Z>({Map<Y, Z> m}) bar, Map<String, String> m) {}
+main() {}
diff --git a/pkg/front_end/testcases/general/issue45598.dart.weak.expect b/pkg/front_end/testcases/general/issue45598.dart.weak.expect
new file mode 100644
index 0000000..fc68d7b
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45598.dart.weak.expect
@@ -0,0 +1,8 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo(<X extends Z* = dynamic, Y extends core::Object* = dynamic, Z extends core::Object* = dynamic>({m: core::Map<Y*, Z*>*}) →* dynamic bar, core::Map<core::String*, core::String*>* m) → dynamic {
+ bar.call<core::String*, core::String*, core::String*>(m: m);
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/general/issue45598.dart.weak.outline.expect b/pkg/front_end/testcases/general/issue45598.dart.weak.outline.expect
new file mode 100644
index 0000000..829a44c
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45598.dart.weak.outline.expect
@@ -0,0 +1,8 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo(<X extends Z* = dynamic, Y extends core::Object* = dynamic, Z extends core::Object* = dynamic>({m: core::Map<Y*, Z*>*}) →* dynamic bar, core::Map<core::String*, core::String*>* m) → dynamic
+ ;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/general/issue45598.dart.weak.transformed.expect b/pkg/front_end/testcases/general/issue45598.dart.weak.transformed.expect
new file mode 100644
index 0000000..fc68d7b
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45598.dart.weak.transformed.expect
@@ -0,0 +1,8 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo(<X extends Z* = dynamic, Y extends core::Object* = dynamic, Z extends core::Object* = dynamic>({m: core::Map<Y*, Z*>*}) →* dynamic bar, core::Map<core::String*, core::String*>* m) → dynamic {
+ bar.call<core::String*, core::String*, core::String*>(m: m);
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/general/issue45598_2.dart b/pkg/front_end/testcases/general/issue45598_2.dart
new file mode 100644
index 0000000..61a731e
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45598_2.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// @dart=2.9
+
+foo(Map<String, String> m) {
+ void bar<X extends Z, Y, Z>({Map<Y, Z> m}) {}
+ bar(m: m);
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/general/issue45598_2.dart.textual_outline.expect b/pkg/front_end/testcases/general/issue45598_2.dart.textual_outline.expect
new file mode 100644
index 0000000..983b1d0
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45598_2.dart.textual_outline.expect
@@ -0,0 +1,3 @@
+// @dart = 2.9
+foo(Map<String, String> m) {}
+main() {}
diff --git a/pkg/front_end/testcases/general/issue45598_2.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/issue45598_2.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..983b1d0
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45598_2.dart.textual_outline_modelled.expect
@@ -0,0 +1,3 @@
+// @dart = 2.9
+foo(Map<String, String> m) {}
+main() {}
diff --git a/pkg/front_end/testcases/general/issue45598_2.dart.weak.expect b/pkg/front_end/testcases/general/issue45598_2.dart.weak.expect
new file mode 100644
index 0000000..d8d1fd0
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45598_2.dart.weak.expect
@@ -0,0 +1,13 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo(core::Map<core::String*, core::String*>* m) → dynamic {
+ function bar<X extends Z* = dynamic, Y extends core::Object* = dynamic, Z extends core::Object* = dynamic>({core::Map<Y*, Z*>* m = #C1}) → void {}
+ bar.call<core::String*, core::String*, core::String*>(m: m);
+}
+static method main() → dynamic {}
+
+constants {
+ #C1 = null
+}
diff --git a/pkg/front_end/testcases/general/issue45598_2.dart.weak.outline.expect b/pkg/front_end/testcases/general/issue45598_2.dart.weak.outline.expect
new file mode 100644
index 0000000..9efffa9a
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45598_2.dart.weak.outline.expect
@@ -0,0 +1,8 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo(core::Map<core::String*, core::String*>* m) → dynamic
+ ;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/general/issue45598_2.dart.weak.transformed.expect b/pkg/front_end/testcases/general/issue45598_2.dart.weak.transformed.expect
new file mode 100644
index 0000000..d8d1fd0
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45598_2.dart.weak.transformed.expect
@@ -0,0 +1,13 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo(core::Map<core::String*, core::String*>* m) → dynamic {
+ function bar<X extends Z* = dynamic, Y extends core::Object* = dynamic, Z extends core::Object* = dynamic>({core::Map<Y*, Z*>* m = #C1}) → void {}
+ bar.call<core::String*, core::String*, core::String*>(m: m);
+}
+static method main() → dynamic {}
+
+constants {
+ #C1 = null
+}
diff --git a/pkg/front_end/testcases/general/issue45660.dart b/pkg/front_end/testcases/general/issue45660.dart
new file mode 100644
index 0000000..9850a81
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45660.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// @dart=2.9
+
+T Function<T extends num>(T) extendsNumReturnArg = <S extends num>(S s) => s;
+
+functionInvocations() {
+ extendsNumReturnArg/*<Null>*/(null);
+ extendsNumReturnArg/*<String>*/("");
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/general/issue45660.dart.textual_outline.expect b/pkg/front_end/testcases/general/issue45660.dart.textual_outline.expect
new file mode 100644
index 0000000..377eb18
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45660.dart.textual_outline.expect
@@ -0,0 +1,4 @@
+// @dart = 2.9
+T Function<T extends num>(T) extendsNumReturnArg = <S extends num>(S s) => s;
+functionInvocations() {}
+main() {}
diff --git a/pkg/front_end/testcases/general/issue45660.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/issue45660.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..377eb18
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45660.dart.textual_outline_modelled.expect
@@ -0,0 +1,4 @@
+// @dart = 2.9
+T Function<T extends num>(T) extendsNumReturnArg = <S extends num>(S s) => s;
+functionInvocations() {}
+main() {}
diff --git a/pkg/front_end/testcases/general/issue45660.dart.weak.expect b/pkg/front_end/testcases/general/issue45660.dart.weak.expect
new file mode 100644
index 0000000..cd197e9
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45660.dart.weak.expect
@@ -0,0 +1,18 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/issue45660.dart:11:22: Error: Inferred type argument 'String' doesn't conform to the bound 'num' of the type variable 'T' on 'call'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// extendsNumReturnArg/*<String>*/("");
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+static field <T extends core::num* = dynamic>(T*) →* T* extendsNumReturnArg = <S extends core::num* = core::num*>(S* s) → S* => s;
+static method functionInvocations() → dynamic {
+ self::extendsNumReturnArg.call<Null>(null);
+ self::extendsNumReturnArg.call<core::String*>("");
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/general/issue45660.dart.weak.outline.expect b/pkg/front_end/testcases/general/issue45660.dart.weak.outline.expect
new file mode 100644
index 0000000..db6f621
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45660.dart.weak.outline.expect
@@ -0,0 +1,9 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static field <T extends core::num* = dynamic>(T*) →* T* extendsNumReturnArg;
+static method functionInvocations() → dynamic
+ ;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/general/issue45660.dart.weak.transformed.expect b/pkg/front_end/testcases/general/issue45660.dart.weak.transformed.expect
new file mode 100644
index 0000000..cd197e9
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45660.dart.weak.transformed.expect
@@ -0,0 +1,18 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/issue45660.dart:11:22: Error: Inferred type argument 'String' doesn't conform to the bound 'num' of the type variable 'T' on 'call'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// extendsNumReturnArg/*<String>*/("");
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+static field <T extends core::num* = dynamic>(T*) →* T* extendsNumReturnArg = <S extends core::num* = core::num*>(S* s) → S* => s;
+static method functionInvocations() → dynamic {
+ self::extendsNumReturnArg.call<Null>(null);
+ self::extendsNumReturnArg.call<core::String*>("");
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.expect
index d997209..b92f5af 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.expect
@@ -25,4 +25,4 @@
Constructor coverage from constants:
org-dartlang-testcase:///ffi_struct_inline_array.dart:
-- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:134:9)
+- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:135:9)
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.transformed.expect
index 49368b2..8b2f96c 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.transformed.expect
@@ -48,4 +48,4 @@
Constructor coverage from constants:
org-dartlang-testcase:///ffi_struct_inline_array.dart:
-- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:134:9)
+- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:135:9)
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.expect
index f04b75d..792f6e0 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.expect
@@ -25,4 +25,4 @@
Constructor coverage from constants:
org-dartlang-testcase:///ffi_struct_inline_array.dart:
-- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:134:9)
+- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:135:9)
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.transformed.expect
index 0164237..4d17ccf 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.transformed.expect
@@ -48,4 +48,4 @@
Constructor coverage from constants:
org-dartlang-testcase:///ffi_struct_inline_array.dart:
-- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:134:9)
+- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:135:9)
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.expect
index 391f4bc..b4d5461 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.expect
@@ -33,4 +33,4 @@
Constructor coverage from constants:
org-dartlang-testcase:///ffi_struct_inline_array_multi_dimensional.dart:
-- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:134:9)
+- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:135:9)
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.transformed.expect
index 6b9936f..5b4a08c 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.strong.transformed.expect
@@ -80,4 +80,4 @@
Constructor coverage from constants:
org-dartlang-testcase:///ffi_struct_inline_array_multi_dimensional.dart:
-- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:134:9)
+- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:135:9)
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.expect
index 32510af..03a5224 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.expect
@@ -33,4 +33,4 @@
Constructor coverage from constants:
org-dartlang-testcase:///ffi_struct_inline_array_multi_dimensional.dart:
-- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:134:9)
+- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:135:9)
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.transformed.expect
index cff35ac..e502690 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array_multi_dimensional.dart.weak.transformed.expect
@@ -80,4 +80,4 @@
Constructor coverage from constants:
org-dartlang-testcase:///ffi_struct_inline_array_multi_dimensional.dart:
-- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:134:9)
+- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:135:9)
diff --git a/pkg/front_end/testcases/nnbd/issue45598.dart b/pkg/front_end/testcases/nnbd/issue45598.dart
new file mode 100644
index 0000000..8c8267e
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+foo(Function<X extends Z, Y, Z>({Map<Y, Z> m}) bar, Map<String, String> m) {
+ bar(m: m);
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue45598.dart.strong.expect b/pkg/front_end/testcases/nnbd/issue45598.dart.strong.expect
new file mode 100644
index 0000000..a1055bf
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598.dart.strong.expect
@@ -0,0 +1,8 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method foo(<X extends Z% = dynamic, Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>({m: core::Map<Y%, Z%>}) → dynamic bar, core::Map<core::String, core::String> m) → dynamic {
+ bar.call<core::String, core::String, core::String>(m: m);
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue45598.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/issue45598.dart.strong.transformed.expect
new file mode 100644
index 0000000..a1055bf
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598.dart.strong.transformed.expect
@@ -0,0 +1,8 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method foo(<X extends Z% = dynamic, Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>({m: core::Map<Y%, Z%>}) → dynamic bar, core::Map<core::String, core::String> m) → dynamic {
+ bar.call<core::String, core::String, core::String>(m: m);
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue45598.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd/issue45598.dart.textual_outline.expect
new file mode 100644
index 0000000..50b6ae2
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598.dart.textual_outline.expect
@@ -0,0 +1,2 @@
+foo(Function<X extends Z, Y, Z>({Map<Y, Z> m}) bar, Map<String, String> m) {}
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue45598.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/issue45598.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..50b6ae2
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598.dart.textual_outline_modelled.expect
@@ -0,0 +1,2 @@
+foo(Function<X extends Z, Y, Z>({Map<Y, Z> m}) bar, Map<String, String> m) {}
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue45598.dart.weak.expect b/pkg/front_end/testcases/nnbd/issue45598.dart.weak.expect
new file mode 100644
index 0000000..a1055bf
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598.dart.weak.expect
@@ -0,0 +1,8 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method foo(<X extends Z% = dynamic, Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>({m: core::Map<Y%, Z%>}) → dynamic bar, core::Map<core::String, core::String> m) → dynamic {
+ bar.call<core::String, core::String, core::String>(m: m);
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue45598.dart.weak.outline.expect b/pkg/front_end/testcases/nnbd/issue45598.dart.weak.outline.expect
new file mode 100644
index 0000000..9ad166e
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598.dart.weak.outline.expect
@@ -0,0 +1,8 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method foo(<X extends Z% = dynamic, Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>({m: core::Map<Y%, Z%>}) → dynamic bar, core::Map<core::String, core::String> m) → dynamic
+ ;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/nnbd/issue45598.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/issue45598.dart.weak.transformed.expect
new file mode 100644
index 0000000..a1055bf
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598.dart.weak.transformed.expect
@@ -0,0 +1,8 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method foo(<X extends Z% = dynamic, Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>({m: core::Map<Y%, Z%>}) → dynamic bar, core::Map<core::String, core::String> m) → dynamic {
+ bar.call<core::String, core::String, core::String>(m: m);
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue45598_2.dart b/pkg/front_end/testcases/nnbd/issue45598_2.dart
new file mode 100644
index 0000000..49350a9
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598_2.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+foo(Map<String, String> m) {
+ void bar<X extends Z, Y, Z>({required Map<Y, Z> m}) {}
+ bar(m: m);
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue45598_2.dart.strong.expect b/pkg/front_end/testcases/nnbd/issue45598_2.dart.strong.expect
new file mode 100644
index 0000000..9c145d3
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598_2.dart.strong.expect
@@ -0,0 +1,13 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method foo(core::Map<core::String, core::String> m) → dynamic {
+ function bar<X extends Z% = dynamic, Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>({required core::Map<Y%, Z%> m = #C1}) → void {}
+ bar.call<core::String, core::String, core::String>(m: m);
+}
+static method main() → dynamic {}
+
+constants {
+ #C1 = null
+}
diff --git a/pkg/front_end/testcases/nnbd/issue45598_2.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/issue45598_2.dart.strong.transformed.expect
new file mode 100644
index 0000000..9c145d3
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598_2.dart.strong.transformed.expect
@@ -0,0 +1,13 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method foo(core::Map<core::String, core::String> m) → dynamic {
+ function bar<X extends Z% = dynamic, Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>({required core::Map<Y%, Z%> m = #C1}) → void {}
+ bar.call<core::String, core::String, core::String>(m: m);
+}
+static method main() → dynamic {}
+
+constants {
+ #C1 = null
+}
diff --git a/pkg/front_end/testcases/nnbd/issue45598_2.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd/issue45598_2.dart.textual_outline.expect
new file mode 100644
index 0000000..853274f
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598_2.dart.textual_outline.expect
@@ -0,0 +1,2 @@
+foo(Map<String, String> m) {}
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue45598_2.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/issue45598_2.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..853274f
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598_2.dart.textual_outline_modelled.expect
@@ -0,0 +1,2 @@
+foo(Map<String, String> m) {}
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue45598_2.dart.weak.expect b/pkg/front_end/testcases/nnbd/issue45598_2.dart.weak.expect
new file mode 100644
index 0000000..9c145d3
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598_2.dart.weak.expect
@@ -0,0 +1,13 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method foo(core::Map<core::String, core::String> m) → dynamic {
+ function bar<X extends Z% = dynamic, Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>({required core::Map<Y%, Z%> m = #C1}) → void {}
+ bar.call<core::String, core::String, core::String>(m: m);
+}
+static method main() → dynamic {}
+
+constants {
+ #C1 = null
+}
diff --git a/pkg/front_end/testcases/nnbd/issue45598_2.dart.weak.outline.expect b/pkg/front_end/testcases/nnbd/issue45598_2.dart.weak.outline.expect
new file mode 100644
index 0000000..1e7263b
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598_2.dart.weak.outline.expect
@@ -0,0 +1,8 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method foo(core::Map<core::String, core::String> m) → dynamic
+ ;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/nnbd/issue45598_2.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/issue45598_2.dart.weak.transformed.expect
new file mode 100644
index 0000000..9c145d3
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598_2.dart.weak.transformed.expect
@@ -0,0 +1,13 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method foo(core::Map<core::String, core::String> m) → dynamic {
+ function bar<X extends Z% = dynamic, Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>({required core::Map<Y%, Z%> m = #C1}) → void {}
+ bar.call<core::String, core::String, core::String>(m: m);
+}
+static method main() → dynamic {}
+
+constants {
+ #C1 = null
+}
diff --git a/pkg/front_end/testcases/nnbd_mixed/mock_http_headers.dart.weak.outline.expect b/pkg/front_end/testcases/nnbd_mixed/mock_http_headers.dart.weak.outline.expect
index e3bc4c3..e9f1bbe 100644
--- a/pkg/front_end/testcases/nnbd_mixed/mock_http_headers.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/nnbd_mixed/mock_http_headers.dart.weak.outline.expect
@@ -170,8 +170,8 @@
Evaluated: SymbolLiteral @ org-dartlang-testcase:///mock_http_headers.dart:13:7 -> SymbolConstant(#noFolding)
Evaluated: ListLiteral @ org-dartlang-testcase:///mock_http_headers.dart:13:7 -> ListConstant(const <Type*>[])
Evaluated: MapLiteral @ org-dartlang-testcase:///mock_http_headers.dart:13:7 -> InstanceConstant(const _ImmutableMap<Symbol*, dynamic>{_ImmutableMap._kvPairs: const <dynamic>[]})
-Evaluated: SymbolLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:761:8 -> SymbolConstant(#clear)
-Evaluated: ListLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:761:8 -> ListConstant(const <Type*>[])
-Evaluated: ListLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:761:8 -> ListConstant(const <dynamic>[])
-Evaluated: MapLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:761:8 -> InstanceConstant(const _ImmutableMap<Symbol*, dynamic>{_ImmutableMap._kvPairs: const <dynamic>[]})
+Evaluated: SymbolLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:762:8 -> SymbolConstant(#clear)
+Evaluated: ListLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:762:8 -> ListConstant(const <Type*>[])
+Evaluated: ListLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:762:8 -> ListConstant(const <dynamic>[])
+Evaluated: MapLiteral @ org-dartlang-sdk:///sdk/lib/_http/http.dart:762:8 -> InstanceConstant(const _ImmutableMap<Symbol*, dynamic>{_ImmutableMap._kvPairs: const <dynamic>[]})
Extra constant evaluation: evaluated: 268, effectively constant: 91
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart b/pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart
new file mode 100644
index 0000000..ae2b59d
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'issue45626.dart' as self;
+
+class C {}
+typedef CAlias = C;
+
+class D implements C, C {}
+class D2 implements C, CAlias {}
+class D3 implements CAlias, C {}
+class D4 implements C, self.C {}
+class D5 implements self.C, C {}
+
+mixin CM on C, C {}
+mixin CM2 on C, CAlias {}
+mixin CM3 on CAlias, C {}
+mixin CM4 on self.C, C {}
+mixin CM5 on C, self.C {}
+
+main() {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart.strong.expect b/pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart.strong.expect
new file mode 100644
index 0000000..84c660a
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart.strong.expect
@@ -0,0 +1,126 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:10:23: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// class D implements C, C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:11:24: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// class D2 implements C, CAlias {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:12:29: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// class D3 implements CAlias, C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:13:24: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// class D4 implements C, self.C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:14:29: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// class D5 implements self.C, C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:16:16: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// mixin CM on C, C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:17:17: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// mixin CM2 on C, CAlias {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:18:22: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// mixin CM3 on CAlias, C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:19:22: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// mixin CM4 on self.C, C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:20:17: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// mixin CM5 on C, self.C {}
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///issue45626.dart" as self;
+
+typedef CAlias = self::C;
+class C extends core::Object {
+ synthetic constructor •() → self::C
+ : super core::Object::•()
+ ;
+}
+class D extends core::Object implements self::C, self::C {
+ synthetic constructor •() → self::D
+ : super core::Object::•()
+ ;
+}
+class D2 extends core::Object implements self::C, self::C {
+ synthetic constructor •() → self::D2
+ : super core::Object::•()
+ ;
+}
+class D3 extends core::Object implements self::C, self::C {
+ synthetic constructor •() → self::D3
+ : super core::Object::•()
+ ;
+}
+class D4 extends core::Object implements self::C, self::C {
+ synthetic constructor •() → self::D4
+ : super core::Object::•()
+ ;
+}
+class D5 extends core::Object implements self::C, self::C {
+ synthetic constructor •() → self::D5
+ : super core::Object::•()
+ ;
+}
+abstract class _CM&C&C extends core::Object implements self::C, self::C /*isAnonymousMixin*/ {
+ synthetic constructor •() → self::_CM&C&C
+ : super core::Object::•()
+ ;
+}
+abstract class CM extends self::_CM&C&C /*isMixinDeclaration*/ {
+}
+abstract class _CM2&C&CAlias extends core::Object implements self::C, self::C /*isAnonymousMixin*/ {
+ synthetic constructor •() → self::_CM2&C&CAlias
+ : super core::Object::•()
+ ;
+}
+abstract class CM2 extends self::_CM2&C&CAlias /*isMixinDeclaration*/ {
+}
+abstract class _CM3&CAlias&C extends core::Object implements self::C, self::C /*isAnonymousMixin*/ {
+ synthetic constructor •() → self::_CM3&CAlias&C
+ : super core::Object::•()
+ ;
+}
+abstract class CM3 extends self::_CM3&CAlias&C /*isMixinDeclaration*/ {
+}
+abstract class _CM4&C&C extends core::Object implements self::C, self::C /*isAnonymousMixin*/ {
+ synthetic constructor •() → self::_CM4&C&C
+ : super core::Object::•()
+ ;
+}
+abstract class CM4 extends self::_CM4&C&C /*isMixinDeclaration*/ {
+}
+abstract class _CM5&C&C extends core::Object implements self::C, self::C /*isAnonymousMixin*/ {
+ synthetic constructor •() → self::_CM5&C&C
+ : super core::Object::•()
+ ;
+}
+abstract class CM5 extends self::_CM5&C&C /*isMixinDeclaration*/ {
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart.strong.transformed.expect b/pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart.strong.transformed.expect
new file mode 100644
index 0000000..84c660a
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart.strong.transformed.expect
@@ -0,0 +1,126 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:10:23: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// class D implements C, C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:11:24: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// class D2 implements C, CAlias {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:12:29: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// class D3 implements CAlias, C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:13:24: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// class D4 implements C, self.C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:14:29: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// class D5 implements self.C, C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:16:16: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// mixin CM on C, C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:17:17: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// mixin CM2 on C, CAlias {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:18:22: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// mixin CM3 on CAlias, C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:19:22: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// mixin CM4 on self.C, C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:20:17: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// mixin CM5 on C, self.C {}
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///issue45626.dart" as self;
+
+typedef CAlias = self::C;
+class C extends core::Object {
+ synthetic constructor •() → self::C
+ : super core::Object::•()
+ ;
+}
+class D extends core::Object implements self::C, self::C {
+ synthetic constructor •() → self::D
+ : super core::Object::•()
+ ;
+}
+class D2 extends core::Object implements self::C, self::C {
+ synthetic constructor •() → self::D2
+ : super core::Object::•()
+ ;
+}
+class D3 extends core::Object implements self::C, self::C {
+ synthetic constructor •() → self::D3
+ : super core::Object::•()
+ ;
+}
+class D4 extends core::Object implements self::C, self::C {
+ synthetic constructor •() → self::D4
+ : super core::Object::•()
+ ;
+}
+class D5 extends core::Object implements self::C, self::C {
+ synthetic constructor •() → self::D5
+ : super core::Object::•()
+ ;
+}
+abstract class _CM&C&C extends core::Object implements self::C, self::C /*isAnonymousMixin*/ {
+ synthetic constructor •() → self::_CM&C&C
+ : super core::Object::•()
+ ;
+}
+abstract class CM extends self::_CM&C&C /*isMixinDeclaration*/ {
+}
+abstract class _CM2&C&CAlias extends core::Object implements self::C, self::C /*isAnonymousMixin*/ {
+ synthetic constructor •() → self::_CM2&C&CAlias
+ : super core::Object::•()
+ ;
+}
+abstract class CM2 extends self::_CM2&C&CAlias /*isMixinDeclaration*/ {
+}
+abstract class _CM3&CAlias&C extends core::Object implements self::C, self::C /*isAnonymousMixin*/ {
+ synthetic constructor •() → self::_CM3&CAlias&C
+ : super core::Object::•()
+ ;
+}
+abstract class CM3 extends self::_CM3&CAlias&C /*isMixinDeclaration*/ {
+}
+abstract class _CM4&C&C extends core::Object implements self::C, self::C /*isAnonymousMixin*/ {
+ synthetic constructor •() → self::_CM4&C&C
+ : super core::Object::•()
+ ;
+}
+abstract class CM4 extends self::_CM4&C&C /*isMixinDeclaration*/ {
+}
+abstract class _CM5&C&C extends core::Object implements self::C, self::C /*isAnonymousMixin*/ {
+ synthetic constructor •() → self::_CM5&C&C
+ : super core::Object::•()
+ ;
+}
+abstract class CM5 extends self::_CM5&C&C /*isMixinDeclaration*/ {
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart.textual_outline.expect b/pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart.textual_outline.expect
new file mode 100644
index 0000000..9083f89
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart.textual_outline.expect
@@ -0,0 +1,22 @@
+import 'issue45626.dart' as self;
+
+class C {}
+
+typedef CAlias = C;
+
+class D implements C, C {}
+
+class D2 implements C, CAlias {}
+
+class D3 implements CAlias, C {}
+
+class D4 implements C, self.C {}
+
+class D5 implements self.C, C {}
+
+mixin CM on C, C {}
+mixin CM2 on C, CAlias {}
+mixin CM3 on CAlias, C {}
+mixin CM4 on self.C, C {}
+mixin CM5 on C, self.C {}
+main() {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..2c192dd
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart.textual_outline_modelled.expect
@@ -0,0 +1,21 @@
+import 'issue45626.dart' as self;
+
+class C {}
+
+class D implements C, C {}
+
+class D2 implements C, CAlias {}
+
+class D3 implements CAlias, C {}
+
+class D4 implements C, self.C {}
+
+class D5 implements self.C, C {}
+
+main() {}
+mixin CM on C, C {}
+mixin CM2 on C, CAlias {}
+mixin CM3 on CAlias, C {}
+mixin CM4 on self.C, C {}
+mixin CM5 on C, self.C {}
+typedef CAlias = C;
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart.weak.expect b/pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart.weak.expect
new file mode 100644
index 0000000..84c660a
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart.weak.expect
@@ -0,0 +1,126 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:10:23: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// class D implements C, C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:11:24: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// class D2 implements C, CAlias {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:12:29: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// class D3 implements CAlias, C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:13:24: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// class D4 implements C, self.C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:14:29: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// class D5 implements self.C, C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:16:16: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// mixin CM on C, C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:17:17: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// mixin CM2 on C, CAlias {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:18:22: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// mixin CM3 on CAlias, C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:19:22: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// mixin CM4 on self.C, C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:20:17: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// mixin CM5 on C, self.C {}
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///issue45626.dart" as self;
+
+typedef CAlias = self::C;
+class C extends core::Object {
+ synthetic constructor •() → self::C
+ : super core::Object::•()
+ ;
+}
+class D extends core::Object implements self::C, self::C {
+ synthetic constructor •() → self::D
+ : super core::Object::•()
+ ;
+}
+class D2 extends core::Object implements self::C, self::C {
+ synthetic constructor •() → self::D2
+ : super core::Object::•()
+ ;
+}
+class D3 extends core::Object implements self::C, self::C {
+ synthetic constructor •() → self::D3
+ : super core::Object::•()
+ ;
+}
+class D4 extends core::Object implements self::C, self::C {
+ synthetic constructor •() → self::D4
+ : super core::Object::•()
+ ;
+}
+class D5 extends core::Object implements self::C, self::C {
+ synthetic constructor •() → self::D5
+ : super core::Object::•()
+ ;
+}
+abstract class _CM&C&C extends core::Object implements self::C, self::C /*isAnonymousMixin*/ {
+ synthetic constructor •() → self::_CM&C&C
+ : super core::Object::•()
+ ;
+}
+abstract class CM extends self::_CM&C&C /*isMixinDeclaration*/ {
+}
+abstract class _CM2&C&CAlias extends core::Object implements self::C, self::C /*isAnonymousMixin*/ {
+ synthetic constructor •() → self::_CM2&C&CAlias
+ : super core::Object::•()
+ ;
+}
+abstract class CM2 extends self::_CM2&C&CAlias /*isMixinDeclaration*/ {
+}
+abstract class _CM3&CAlias&C extends core::Object implements self::C, self::C /*isAnonymousMixin*/ {
+ synthetic constructor •() → self::_CM3&CAlias&C
+ : super core::Object::•()
+ ;
+}
+abstract class CM3 extends self::_CM3&CAlias&C /*isMixinDeclaration*/ {
+}
+abstract class _CM4&C&C extends core::Object implements self::C, self::C /*isAnonymousMixin*/ {
+ synthetic constructor •() → self::_CM4&C&C
+ : super core::Object::•()
+ ;
+}
+abstract class CM4 extends self::_CM4&C&C /*isMixinDeclaration*/ {
+}
+abstract class _CM5&C&C extends core::Object implements self::C, self::C /*isAnonymousMixin*/ {
+ synthetic constructor •() → self::_CM5&C&C
+ : super core::Object::•()
+ ;
+}
+abstract class CM5 extends self::_CM5&C&C /*isMixinDeclaration*/ {
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart.weak.outline.expect b/pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart.weak.outline.expect
new file mode 100644
index 0000000..d12c6e1
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart.weak.outline.expect
@@ -0,0 +1,116 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:10:23: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// class D implements C, C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:11:24: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// class D2 implements C, CAlias {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:12:29: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// class D3 implements CAlias, C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:13:24: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// class D4 implements C, self.C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:14:29: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// class D5 implements self.C, C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:16:16: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// mixin CM on C, C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:17:17: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// mixin CM2 on C, CAlias {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:18:22: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// mixin CM3 on CAlias, C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:19:22: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// mixin CM4 on self.C, C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:20:17: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// mixin CM5 on C, self.C {}
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///issue45626.dart" as self;
+
+typedef CAlias = self::C;
+class C extends core::Object {
+ synthetic constructor •() → self::C
+ ;
+}
+class D extends core::Object implements self::C, self::C {
+ synthetic constructor •() → self::D
+ ;
+}
+class D2 extends core::Object implements self::C, self::C {
+ synthetic constructor •() → self::D2
+ ;
+}
+class D3 extends core::Object implements self::C, self::C {
+ synthetic constructor •() → self::D3
+ ;
+}
+class D4 extends core::Object implements self::C, self::C {
+ synthetic constructor •() → self::D4
+ ;
+}
+class D5 extends core::Object implements self::C, self::C {
+ synthetic constructor •() → self::D5
+ ;
+}
+abstract class _CM&C&C extends core::Object implements self::C, self::C /*isAnonymousMixin*/ {
+ synthetic constructor •() → self::_CM&C&C
+ ;
+}
+abstract class CM extends self::_CM&C&C /*isMixinDeclaration*/ {
+}
+abstract class _CM2&C&CAlias extends core::Object implements self::C, self::C /*isAnonymousMixin*/ {
+ synthetic constructor •() → self::_CM2&C&CAlias
+ ;
+}
+abstract class CM2 extends self::_CM2&C&CAlias /*isMixinDeclaration*/ {
+}
+abstract class _CM3&CAlias&C extends core::Object implements self::C, self::C /*isAnonymousMixin*/ {
+ synthetic constructor •() → self::_CM3&CAlias&C
+ ;
+}
+abstract class CM3 extends self::_CM3&CAlias&C /*isMixinDeclaration*/ {
+}
+abstract class _CM4&C&C extends core::Object implements self::C, self::C /*isAnonymousMixin*/ {
+ synthetic constructor •() → self::_CM4&C&C
+ ;
+}
+abstract class CM4 extends self::_CM4&C&C /*isMixinDeclaration*/ {
+}
+abstract class _CM5&C&C extends core::Object implements self::C, self::C /*isAnonymousMixin*/ {
+ synthetic constructor •() → self::_CM5&C&C
+ ;
+}
+abstract class CM5 extends self::_CM5&C&C /*isMixinDeclaration*/ {
+}
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart.weak.transformed.expect b/pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart.weak.transformed.expect
new file mode 100644
index 0000000..84c660a
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart.weak.transformed.expect
@@ -0,0 +1,126 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:10:23: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// class D implements C, C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:11:24: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// class D2 implements C, CAlias {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:12:29: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// class D3 implements CAlias, C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:13:24: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// class D4 implements C, self.C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:14:29: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// class D5 implements self.C, C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:16:16: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// mixin CM on C, C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:17:17: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// mixin CM2 on C, CAlias {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:18:22: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// mixin CM3 on CAlias, C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:19:22: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// mixin CM4 on self.C, C {}
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45626.dart:20:17: Error: 'C' can only be implemented once.
+// Try removing 1 of the occurrences.
+// mixin CM5 on C, self.C {}
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///issue45626.dart" as self;
+
+typedef CAlias = self::C;
+class C extends core::Object {
+ synthetic constructor •() → self::C
+ : super core::Object::•()
+ ;
+}
+class D extends core::Object implements self::C, self::C {
+ synthetic constructor •() → self::D
+ : super core::Object::•()
+ ;
+}
+class D2 extends core::Object implements self::C, self::C {
+ synthetic constructor •() → self::D2
+ : super core::Object::•()
+ ;
+}
+class D3 extends core::Object implements self::C, self::C {
+ synthetic constructor •() → self::D3
+ : super core::Object::•()
+ ;
+}
+class D4 extends core::Object implements self::C, self::C {
+ synthetic constructor •() → self::D4
+ : super core::Object::•()
+ ;
+}
+class D5 extends core::Object implements self::C, self::C {
+ synthetic constructor •() → self::D5
+ : super core::Object::•()
+ ;
+}
+abstract class _CM&C&C extends core::Object implements self::C, self::C /*isAnonymousMixin*/ {
+ synthetic constructor •() → self::_CM&C&C
+ : super core::Object::•()
+ ;
+}
+abstract class CM extends self::_CM&C&C /*isMixinDeclaration*/ {
+}
+abstract class _CM2&C&CAlias extends core::Object implements self::C, self::C /*isAnonymousMixin*/ {
+ synthetic constructor •() → self::_CM2&C&CAlias
+ : super core::Object::•()
+ ;
+}
+abstract class CM2 extends self::_CM2&C&CAlias /*isMixinDeclaration*/ {
+}
+abstract class _CM3&CAlias&C extends core::Object implements self::C, self::C /*isAnonymousMixin*/ {
+ synthetic constructor •() → self::_CM3&CAlias&C
+ : super core::Object::•()
+ ;
+}
+abstract class CM3 extends self::_CM3&CAlias&C /*isMixinDeclaration*/ {
+}
+abstract class _CM4&C&C extends core::Object implements self::C, self::C /*isAnonymousMixin*/ {
+ synthetic constructor •() → self::_CM4&C&C
+ : super core::Object::•()
+ ;
+}
+abstract class CM4 extends self::_CM4&C&C /*isMixinDeclaration*/ {
+}
+abstract class _CM5&C&C extends core::Object implements self::C, self::C /*isAnonymousMixin*/ {
+ synthetic constructor •() → self::_CM5&C&C
+ : super core::Object::•()
+ ;
+}
+abstract class CM5 extends self::_CM5&C&C /*isMixinDeclaration*/ {
+}
+static method main() → dynamic {}
diff --git a/pkg/js_ast/lib/src/equivalence_visitor.dart b/pkg/js_ast/lib/src/equivalence_visitor.dart
index d06f50f..191b1e0 100644
--- a/pkg/js_ast/lib/src/equivalence_visitor.dart
+++ b/pkg/js_ast/lib/src/equivalence_visitor.dart
@@ -209,6 +209,13 @@
}
@override
+ bool visitDeferredStatement(DeferredStatement node, Node arg) {
+ if (arg is! DeferredStatement) return failAt(node, arg);
+ DeferredStatement other = arg;
+ return testNodes(node.statement, other.statement);
+ }
+
+ @override
bool visitFun(Fun node, Node arg) {
if (arg is! Fun) return failAt(node, arg);
Fun other = arg;
diff --git a/pkg/js_ast/lib/src/nodes.dart b/pkg/js_ast/lib/src/nodes.dart
index b9cc51f..2868346 100644
--- a/pkg/js_ast/lib/src/nodes.dart
+++ b/pkg/js_ast/lib/src/nodes.dart
@@ -49,6 +49,7 @@
T visitNamedFunction(NamedFunction node);
T visitFun(Fun node);
+ T visitDeferredStatement(DeferredStatement node);
T visitDeferredExpression(DeferredExpression node);
T visitDeferredNumber(DeferredNumber node);
T visitDeferredString(DeferredString node);
@@ -152,6 +153,7 @@
T visitToken(DeferredToken node) => visitExpression(node);
+ T visitDeferredStatement(DeferredStatement node) => visitStatement(node);
T visitDeferredExpression(DeferredExpression node) => visitExpression(node);
T visitDeferredNumber(DeferredNumber node) => visitToken(node);
T visitDeferredString(DeferredString node) => visitToken(node);
@@ -243,6 +245,7 @@
R visitNamedFunction(NamedFunction node, A arg);
R visitFun(Fun node, A arg);
+ R visitDeferredStatement(DeferredStatement node, A arg);
R visitDeferredExpression(DeferredExpression node, A arg);
R visitDeferredNumber(DeferredNumber node, A arg);
R visitDeferredString(DeferredString node, A arg);
@@ -355,6 +358,8 @@
R visitToken(DeferredToken node, A arg) => visitExpression(node, arg);
+ R visitDeferredStatement(DeferredStatement node, A arg) =>
+ visitStatement(node, arg);
R visitDeferredExpression(DeferredExpression node, A arg) =>
visitExpression(node, arg);
R visitDeferredNumber(DeferredNumber node, A arg) => visitToken(node, arg);
@@ -477,6 +482,25 @@
Statement toStatement() => this;
}
+/// Interface for a deferred [Statement] value. An implementation has to provide
+/// a value via the [statement] getter the latest when the ast is printed.
+abstract class DeferredStatement extends Statement {
+ T accept<T>(NodeVisitor<T> visitor) => visitor.visitDeferredStatement(this);
+
+ R accept1<R, A>(NodeVisitor1<R, A> visitor, A arg) =>
+ visitor.visitDeferredStatement(this, arg);
+
+ void visitChildren<T>(NodeVisitor<T> visitor) {
+ statement.accept(visitor);
+ }
+
+ void visitChildren1<R, A>(NodeVisitor1<R, A> visitor, A arg) {
+ statement.accept1(visitor, arg);
+ }
+
+ Statement get statement;
+}
+
class Block extends Statement {
final List<Statement> statements;
diff --git a/pkg/js_ast/lib/src/printer.dart b/pkg/js_ast/lib/src/printer.dart
index 0d04a21..d851cb8 100644
--- a/pkg/js_ast/lib/src/printer.dart
+++ b/pkg/js_ast/lib/src/printer.dart
@@ -299,12 +299,17 @@
return false;
}
+ /// Elide Blocks and DeferredStatements with Blocks as children.
void blockOutWithoutBraces(Node node) {
if (node is Block) {
startNode(node);
Block block = node;
block.statements.forEach(blockOutWithoutBraces);
endNode(node);
+ } else if (node is DeferredStatement) {
+ startNode(node);
+ blockOutWithoutBraces(node.statement);
+ endNode(node);
} else {
visit(node);
}
@@ -1101,6 +1106,13 @@
node.value.accept(this);
}
+ @override
+ visitDeferredStatement(DeferredStatement node) {
+ startNode(node);
+ visit(node.statement);
+ endNode(node);
+ }
+
outputNumberWithRequiredWhitespace(String number) {
int charCode = number.codeUnitAt(0);
if (charCode == charCodes.$MINUS && lastCharCode == charCodes.$MINUS) {
@@ -1414,6 +1426,10 @@
bool visitBlock(Block node) => false;
bool visitExpressionStatement(ExpressionStatement node) => false;
bool visitEmptyStatement(EmptyStatement node) => false;
+ bool visitDeferredStatement(DeferredStatement node) {
+ return node.statement.accept(this);
+ }
+
bool visitIf(If node) {
if (!node.hasElse) return true;
return node.otherwise.accept(this);
diff --git a/pkg/js_ast/lib/src/template.dart b/pkg/js_ast/lib/src/template.dart
index 3cfc133..5aa45ba 100644
--- a/pkg/js_ast/lib/src/template.dart
+++ b/pkg/js_ast/lib/src/template.dart
@@ -661,6 +661,8 @@
Instantiator visitDeferredExpression(DeferredExpression node) => same(node);
+ Instantiator visitDeferredStatement(DeferredStatement node) => same(node);
+
Instantiator visitDeferredNumber(DeferredNumber node) => same(node);
Instantiator visitDeferredString(DeferredString node) => (arguments) => node;
diff --git a/pkg/js_ast/test/deferred_statement_test.dart b/pkg/js_ast/test/deferred_statement_test.dart
new file mode 100644
index 0000000..9628cdf
--- /dev/null
+++ b/pkg/js_ast/test/deferred_statement_test.dart
@@ -0,0 +1,50 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+import 'package:js_ast/js_ast.dart';
+
+class _DeferredStatement extends DeferredStatement {
+ final Statement statement;
+
+ _DeferredStatement(this.statement);
+}
+
+main() {
+ // Defering a statement should not change how it prints.
+ var undeferredStatement = js.statement('var x = 3');
+ var deferredStatement = _DeferredStatement(undeferredStatement);
+ Expect.equals(DebugPrint(undeferredStatement), DebugPrint(deferredStatement));
+
+ // Printing a non-finalized DeferredStatement throws.
+ Expect.throws(() => DebugPrint(_DeferredStatement(null)));
+
+ // DeferredStatement with empty Block puts braces.
+ Expect.equals(DebugPrint(_DeferredStatement(Block.empty())), '{\n}\n');
+
+ // DeferredStatement in block with nested block gets elided.
+ Expect.equals(
+ DebugPrint(Block([_DeferredStatement(Block.empty())])), '{\n}\n');
+ Expect.equals(
+ DebugPrint(Block([
+ _DeferredStatement(
+ _DeferredStatement(_DeferredStatement(Block.empty())))
+ ])),
+ '{\n}\n');
+
+ // Nested Blocks in DeferredStatements are elided.
+ Expect.equals(
+ DebugPrint(Block([
+ _DeferredStatement(Block([
+ _DeferredStatement(Block.empty()),
+ Block.empty(),
+ Block([_DeferredStatement(Block.empty()), Block.empty()]),
+ _DeferredStatement(_DeferredStatement(Block.empty()))
+ ]))
+ ])),
+ '{\n}\n');
+
+ // DeferredStatement with empty Statement prints semicolon and a newline.
+ Expect.equals(DebugPrint(_DeferredStatement(EmptyStatement())), ';\n');
+}
diff --git a/pkg/kernel/lib/core_types.dart b/pkg/kernel/lib/core_types.dart
index 98160cf..63ad64c 100644
--- a/pkg/kernel/lib/core_types.dart
+++ b/pkg/kernel/lib/core_types.dart
@@ -306,6 +306,67 @@
late final Procedure isSentinelMethod =
index.getTopLevelMember('dart:_internal', 'isSentinel') as Procedure;
+ late final Constructor
+ lateInitializationFieldAssignedDuringInitializationConstructor =
+ index.getMember('dart:_internal', 'LateError', 'fieldADI') as Constructor;
+
+ late final Constructor
+ lateInitializationLocalAssignedDuringInitializationConstructor =
+ index.getMember('dart:_internal', 'LateError', 'localADI') as Constructor;
+
+ late final Constructor lateInitializationFieldNotInitializedConstructor =
+ index.getMember('dart:_internal', 'LateError', 'fieldNI') as Constructor;
+
+ late final Constructor lateInitializationLocalNotInitializedConstructor =
+ index.getMember('dart:_internal', 'LateError', 'localNI') as Constructor;
+
+ late final Constructor lateInitializationFieldAlreadyInitializedConstructor =
+ index.getMember('dart:_internal', 'LateError', 'fieldAI') as Constructor;
+
+ late final Constructor lateInitializationLocalAlreadyInitializedConstructor =
+ index.getMember('dart:_internal', 'LateError', 'localAI') as Constructor;
+
+ late final Constructor reachabilityErrorConstructor =
+ index.getMember('dart:_internal', 'ReachabilityError', '') as Constructor;
+
+ late final Class cellClass = index.getClass('dart:_late_helper', '_Cell');
+
+ late final Constructor cellConstructor =
+ index.getMember('dart:_late_helper', '_Cell', '') as Constructor;
+
+ late final Class initializedCellClass =
+ index.getClass('dart:_late_helper', '_InitializedCell');
+
+ late final Constructor initializedCellConstructor = index.getMember(
+ 'dart:_late_helper', '_InitializedCell', '') as Constructor;
+
+ late final Procedure cellReadLocal =
+ index.getMember('dart:_late_helper', '_Cell', 'readLocal') as Procedure;
+
+ late final Procedure cellReadField =
+ index.getMember('dart:_late_helper', '_Cell', 'readField') as Procedure;
+
+ late final Procedure initializedCellRead = index.getMember(
+ 'dart:_late_helper', '_InitializedCell', 'read') as Procedure;
+
+ late final Procedure initializedCellReadFinal = index.getMember(
+ 'dart:_late_helper', '_InitializedCell', 'readFinal') as Procedure;
+
+ late final Procedure cellValueSetter =
+ index.getMember('dart:_late_helper', '_Cell', 'set:value') as Procedure;
+
+ late final Procedure cellFinalLocalValueSetter = index.getMember(
+ 'dart:_late_helper', '_Cell', 'set:finalLocalValue') as Procedure;
+
+ late final Procedure cellFinalFieldValueSetter = index.getMember(
+ 'dart:_late_helper', '_Cell', 'set:finalFieldValue') as Procedure;
+
+ late final Procedure initializedCellValueSetter = index.getMember(
+ 'dart:_late_helper', '_InitializedCell', 'set:value') as Procedure;
+
+ late final Procedure initializedCellFinalValueSetter = index.getMember(
+ 'dart:_late_helper', '_InitializedCell', 'set:finalValue') as Procedure;
+
InterfaceType get objectLegacyRawType {
return _objectLegacyRawType ??= _legacyRawTypes[objectClass] ??=
new InterfaceType(objectClass, Nullability.legacy, const <DartType>[]);
@@ -1028,29 +1089,6 @@
return result;
}
- late final Constructor
- lateInitializationFieldAssignedDuringInitializationConstructor =
- index.getMember('dart:_internal', 'LateError', 'fieldADI') as Constructor;
-
- late final Constructor
- lateInitializationLocalAssignedDuringInitializationConstructor =
- index.getMember('dart:_internal', 'LateError', 'localADI') as Constructor;
-
- late final Constructor lateInitializationFieldNotInitializedConstructor =
- index.getMember('dart:_internal', 'LateError', 'fieldNI') as Constructor;
-
- late final Constructor lateInitializationLocalNotInitializedConstructor =
- index.getMember('dart:_internal', 'LateError', 'localNI') as Constructor;
-
- late final Constructor lateInitializationFieldAlreadyInitializedConstructor =
- index.getMember('dart:_internal', 'LateError', 'fieldAI') as Constructor;
-
- late final Constructor lateInitializationLocalAlreadyInitializedConstructor =
- index.getMember('dart:_internal', 'LateError', 'localAI') as Constructor;
-
- late final Constructor reachabilityErrorConstructor =
- index.getMember('dart:_internal', 'ReachabilityError', '') as Constructor;
-
InterfaceType bottomInterfaceType(Class klass, Nullability nullability) {
InterfaceType? result = _bottomInterfaceTypes[klass];
if (result == null) {
diff --git a/pkg/kernel/lib/src/bounds_checks.dart b/pkg/kernel/lib/src/bounds_checks.dart
index a0d9fb8..17b0a06 100644
--- a/pkg/kernel/lib/src/bounds_checks.dart
+++ b/pkg/kernel/lib/src/bounds_checks.dart
@@ -165,13 +165,18 @@
new List<DartType>.filled(typeParameters.length, dummyDartType);
for (int i = 0; i < typeParameters.length; i++) {
DartType? bound = typeParameters[i].bound;
+ bool isContravariant = typeParameters[i].variance == Variance.contravariant;
if (bound == null) {
- bound = const DynamicType();
+ bound = isNonNullableByDefault && isContravariant
+ ? const NeverType.nonNullable()
+ : const DynamicType();
} else if (bound is InterfaceType && bound.classNode == objectClass) {
DartType defaultType = typeParameters[i].defaultType!;
if (!(defaultType is InterfaceType &&
defaultType.classNode == objectClass)) {
- bound = const DynamicType();
+ bound = isNonNullableByDefault && isContravariant
+ ? const NeverType.nonNullable()
+ : const DynamicType();
}
}
bounds[i] = bound;
@@ -193,8 +198,10 @@
Substitution substitution =
Substitution.fromUpperAndLowerBounds(upperBounds, lowerBounds);
for (int typeParameterIndex in component) {
- bounds[typeParameterIndex] =
- substitution.substituteType(bounds[typeParameterIndex]);
+ bounds[typeParameterIndex] = substitution.substituteType(
+ bounds[typeParameterIndex],
+ contravariant: typeParameters[typeParameterIndex].variance ==
+ Variance.contravariant);
}
}
@@ -206,7 +213,8 @@
Substitution substitution =
Substitution.fromUpperAndLowerBounds(upperBounds, lowerBounds);
for (int j = 0; j < typeParameters.length; j++) {
- bounds[j] = substitution.substituteType(bounds[j]);
+ bounds[j] = substitution.substituteType(bounds[j],
+ contravariant: typeParameters[j].variance == Variance.contravariant);
}
}
diff --git a/pkg/nnbd_migration/lib/migration_cli.dart b/pkg/nnbd_migration/lib/migration_cli.dart
index 9298730..0590138 100644
--- a/pkg/nnbd_migration/lib/migration_cli.dart
+++ b/pkg/nnbd_migration/lib/migration_cli.dart
@@ -950,7 +950,7 @@
_dartFixListener.reset();
_fixCodeProcessor.prepareToRerun();
var analysisResult = await _fixCodeProcessor.runFirstPhase();
- if (analysisResult.hasErrors) {
+ if (analysisResult.hasErrors && !options.ignoreErrors) {
_logErrors(analysisResult);
return MigrationState(
_fixCodeProcessor._task.migration,
@@ -1088,11 +1088,10 @@
}
for (var path in pathsToProcess.difference(pathsProcessed)) {
- var result = await driver.getResolvedUnit(path);
- if (result == null || result.unit == null) {
- continue;
+ var result = await driver.getResolvedUnit2(path);
+ if (result is ResolvedUnitResult) {
+ await process(result);
}
- await process(result);
}
}
diff --git a/pkg/nnbd_migration/lib/src/edge_builder.dart b/pkg/nnbd_migration/lib/src/edge_builder.dart
index d64b16b..316b4b2 100644
--- a/pkg/nnbd_migration/lib/src/edge_builder.dart
+++ b/pkg/nnbd_migration/lib/src/edge_builder.dart
@@ -2043,8 +2043,7 @@
'(${expression.toSource()}) offset=${expression.offset}');
}
var origin = _makeEdgeOrigin(sourceType, expression);
- var hard = _postDominatedLocals.isReferenceInScope(expression) ||
- expression.unParenthesized is AsExpression;
+ var hard = _shouldUseHardEdge(expression);
var edge = _graph.makeNonNullable(sourceType.node, origin,
hard: hard, guards: _guards);
if (origin is ExpressionChecksOrigin) {
@@ -2407,8 +2406,7 @@
FixReasonTarget.root,
source: destinationType,
destination: _createNonNullableType(compoundOperatorInfo),
- hard: _postDominatedLocals
- .isReferenceInScope(assignmentExpression.leftHandSide));
+ hard: _shouldUseHardEdge(assignmentExpression.leftHandSide));
DecoratedType compoundOperatorType = getOrComputeElementType(
compoundOperatorInfo, compoundOperatorMethod,
targetType: destinationType,
@@ -2417,7 +2415,7 @@
_checkAssignment(edgeOrigin, FixReasonTarget.root,
source: sourceType,
destination: compoundOperatorType.positionalParameters[0],
- hard: _postDominatedLocals.isReferenceInScope(expression),
+ hard: _shouldUseHardEdge(expression),
sourceIsFunctionLiteral: expression is FunctionExpression);
sourceType = _fixNumericTypes(
compoundOperatorType.returnType, compoundOperatorInfo.staticType);
@@ -2452,13 +2450,8 @@
return methodInvocationType.withNode(newNode);
};
} else {
- var unwrappedExpression = expression.unParenthesized;
- var hard = (questionAssignNode == null &&
- _postDominatedLocals.isReferenceInScope(expression)) ||
- // An edge from a cast should be hard, so that the cast type
- // annotation is appropriately made nullable according to the
- // destination type.
- unwrappedExpression is AsExpression;
+ var hard = _shouldUseHardEdge(expression,
+ isConditionallyExecuted: questionAssignNode != null);
_checkAssignment(edgeOrigin, FixReasonTarget.root,
source: sourceType,
destination: destinationType,
@@ -3266,6 +3259,37 @@
return node;
}
+ /// Determines whether uses of [expression] should cause hard edges to be
+ /// created in the nullability graph.
+ ///
+ /// If [isConditionallyExecuted] is `true`, that indicates that [expression]
+ /// appears in a context where it might not get executed (e.g. on the RHS of
+ /// a `??=`).
+ bool _shouldUseHardEdge(Expression expression,
+ {bool isConditionallyExecuted = false}) {
+ expression = expression.unParenthesized;
+ if (expression is ListLiteral || expression is SetOrMapLiteral) {
+ // List, set, and map literals have either explicit or implicit type
+ // arguments. If supplying a nullable type for one of these type
+ // arguments would lead to an error (e.g. `f(<int?>[])` where `f` requires
+ // a `List<int>`), then we should use a hard edge, to ensure that the
+ // migrated type argument will be non-nullable.
+ return true;
+ } else if (expression is AsExpression) {
+ // "as" expressions have an explicit type. If making this type nullable
+ // would lead to an error (e.g. `f(x as int?)` where `f` requires an
+ // `int`),then we should use a hard edge, to ensure that the migrated type
+ // will be non-nullable.
+ return true;
+ }
+ // For other expressions, we should use a hard edge only if (a) the
+ // expression is unconditionally executed, and (b) the expression is a
+ // reference to a local variable or parameter and it post-dominates the
+ // declaration of that local variable or parameter.
+ return !isConditionallyExecuted &&
+ _postDominatedLocals.isReferenceInScope(expression);
+ }
+
DecoratedType _thisOrSuper(Expression node) {
if (_currentClassOrExtension == null) {
return null;
@@ -3439,7 +3463,8 @@
_checkAssignment_recursion(origin, edgeTarget,
source: source,
destination: destination,
- sourceIsFunctionLiteral: sourceIsFunctionLiteral);
+ sourceIsFunctionLiteral: sourceIsFunctionLiteral,
+ hard: hard);
}
/// Does the recursive part of [_checkAssignment], visiting all of the types
@@ -3449,7 +3474,8 @@
void _checkAssignment_recursion(EdgeOrigin origin, FixReasonTarget edgeTarget,
{@required DecoratedType source,
@required DecoratedType destination,
- bool sourceIsFunctionLiteral = false}) {
+ bool sourceIsFunctionLiteral = false,
+ bool hard = false}) {
var sourceType = source.type;
var destinationType = destination.type;
assert(_typeSystem.isSubtypeOf(sourceType, destinationType));
@@ -3554,7 +3580,7 @@
_checkAssignment(origin, edgeTarget.typeArgument(i),
source: rewrittenSource.typeArguments[i],
destination: destination.typeArguments[i],
- hard: false,
+ hard: hard,
checkable: false);
}
} else if (sourceType is FunctionType && destinationType is FunctionType) {
diff --git a/pkg/nnbd_migration/lib/src/nullability_node.dart b/pkg/nnbd_migration/lib/src/nullability_node.dart
index 85fa200..668b8ad 100644
--- a/pkg/nnbd_migration/lib/src/nullability_node.dart
+++ b/pkg/nnbd_migration/lib/src/nullability_node.dart
@@ -141,7 +141,9 @@
@override
bool get isHard =>
- _kind == _NullabilityEdgeKind.hard || _kind == _NullabilityEdgeKind.union;
+ _kind == _NullabilityEdgeKind.hard ||
+ _kind == _NullabilityEdgeKind.union ||
+ _kind == _NullabilityEdgeKind.uncheckableHard;
@override
bool get isSatisfied {
@@ -177,6 +179,9 @@
case _NullabilityEdgeKind.uncheckable:
json['kind'] = 'uncheckable';
break;
+ case _NullabilityEdgeKind.uncheckableHard:
+ json['kind'] = 'uncheckableHard';
+ break;
case _NullabilityEdgeKind.hard:
json['kind'] = 'hard';
break;
@@ -205,6 +210,9 @@
case _NullabilityEdgeKind.uncheckable:
edgeDecorations.add('uncheckable');
break;
+ case _NullabilityEdgeKind.uncheckableHard:
+ edgeDecorations.add('uncheckableHard');
+ break;
case _NullabilityEdgeKind.hard:
edgeDecorations.add('hard');
break;
@@ -228,6 +236,8 @@
switch (kind) {
case 'uncheckable':
return _NullabilityEdgeKind.uncheckable;
+ case 'uncheckableHard':
+ return _NullabilityEdgeKind.uncheckableHard;
case 'hard':
return _NullabilityEdgeKind.hard;
case 'union':
@@ -295,7 +305,9 @@
List<NullabilityNode> guards = const []}) {
var upstreamNodes = [sourceNode, ...guards];
var kind = hard
- ? _NullabilityEdgeKind.hard
+ ? checkable
+ ? _NullabilityEdgeKind.hard
+ : _NullabilityEdgeKind.uncheckableHard
: checkable
? _NullabilityEdgeKind.soft
: _NullabilityEdgeKind.uncheckable;
@@ -1297,6 +1309,11 @@
/// nullability.
union,
+ /// Uncheckable hard edge. Propagates nullability downstream and
+ /// non-nullability upstream. May not be overridden by suggestions that the
+ /// user intends non-nullability.
+ uncheckableHard,
+
/// Dummy edge. Indicates that two edges are connected in a way that should
/// not propagate (non-)nullability in either direction.
dummy,
diff --git a/pkg/nnbd_migration/test/abstract_single_unit.dart b/pkg/nnbd_migration/test/abstract_single_unit.dart
index 2e1ea9b..1edbb80 100644
--- a/pkg/nnbd_migration/test/abstract_single_unit.dart
+++ b/pkg/nnbd_migration/test/abstract_single_unit.dart
@@ -37,7 +37,8 @@
Future<void> resolveTestUnit(String code) async {
addTestSource(code, testUri);
- testAnalysisResult = await session.getResolvedUnit(testFile);
+ testAnalysisResult =
+ await session.getResolvedUnit2(testFile) as ResolvedUnitResult;
testUnit = testAnalysisResult.unit;
if (verifyNoTestUnitErrors) {
expect(testAnalysisResult.errors.where((AnalysisError error) {
diff --git a/pkg/nnbd_migration/test/api_test.dart b/pkg/nnbd_migration/test/api_test.dart
index c069791..7f5df1c 100644
--- a/pkg/nnbd_migration/test/api_test.dart
+++ b/pkg/nnbd_migration/test/api_test.dart
@@ -714,6 +714,102 @@
await _checkSingleFileChanges(content, expected, warnOnWeakCode: true);
}
+ Future<void> test_collection_literal_typed_list() async {
+ var content = '''
+void f(int/*?*/ x, int/*?*/ y) {
+ g(<int>[x, y]);
+}
+g(List<int/*!*/>/*!*/ z) {}
+''';
+ var expected = '''
+void f(int? x, int? y) {
+ g(<int>[x!, y!]);
+}
+g(List<int> z) {}
+''';
+ await _checkSingleFileChanges(content, expected);
+ }
+
+ Future<void> test_collection_literal_typed_map() async {
+ var content = '''
+void f(int/*?*/ x, int/*?*/ y) {
+ g(<int, int>{x: y});
+}
+g(Map<int/*!*/, int/*!*/>/*!*/ z) {}
+''';
+ var expected = '''
+void f(int? x, int? y) {
+ g(<int, int>{x!: y!});
+}
+g(Map<int, int> z) {}
+''';
+ await _checkSingleFileChanges(content, expected);
+ }
+
+ Future<void> test_collection_literal_typed_set() async {
+ var content = '''
+void f(int/*?*/ x, int/*?*/ y) {
+ g(<int>{x, y});
+}
+g(Set<int/*!*/>/*!*/ z) {}
+''';
+ var expected = '''
+void f(int? x, int? y) {
+ g(<int>{x!, y!});
+}
+g(Set<int> z) {}
+''';
+ await _checkSingleFileChanges(content, expected);
+ }
+
+ Future<void> test_collection_literal_untyped_list() async {
+ var content = '''
+void f(int/*?*/ x, int/*?*/ y) {
+ g([x, y]);
+}
+g(List<int/*!*/>/*!*/ z) {}
+''';
+ var expected = '''
+void f(int? x, int? y) {
+ g([x!, y!]);
+}
+g(List<int> z) {}
+''';
+ await _checkSingleFileChanges(content, expected);
+ }
+
+ Future<void> test_collection_literal_untyped_map() async {
+ var content = '''
+void f(int/*?*/ x, int/*?*/ y) {
+ g({x: y});
+}
+g(Map<int/*!*/, int/*!*/>/*!*/ z) {}
+''';
+ var expected = '''
+void f(int? x, int? y) {
+ g({x!: y!});
+}
+g(Map<int, int> z) {}
+''';
+ await _checkSingleFileChanges(content, expected);
+ }
+
+ Future<void> test_collection_literal_untyped_set() async {
+ var content = '''
+void f(int/*?*/ x, int/*?*/ y) {
+ g({x, y});
+}
+g(Set<int/*!*/>/*!*/ z) {}
+''';
+ var expected = '''
+void f(int? x, int? y) {
+ g({x!, y!});
+}
+g(Set<int> z) {}
+''';
+ await _checkSingleFileChanges(content, expected);
+ }
+
Future<void> test_comment_bang_implies_non_null_intent() async {
var content = '''
void f(int/*!*/ i) {}
@@ -1577,15 +1673,9 @@
}
g({List<int/*!*/>/*!*/ named}) {}
''';
- // Note: this test is to ensure that we don't produce
- // `g((named: <int?>[x, y]) as List<int>)` (which would be a parse error).
- // The migration we produce (`g(named: <int?>[x, y])`) still isn't great,
- // because it's a type mismatch, but it's better.
- //
- // TODO(paulberry): a better migration would be `g(named: <int>[x!, y!])`.
var expected = '''
void f(int? x, int? y) {
- g(named: <int?>[x, y]);
+ g(named: <int>[x!, y!]);
}
g({required List<int> named}) {}
''';
diff --git a/pkg/nnbd_migration/test/edge_builder_test.dart b/pkg/nnbd_migration/test/edge_builder_test.dart
index e50b091..0771b0e 100644
--- a/pkg/nnbd_migration/test/edge_builder_test.dart
+++ b/pkg/nnbd_migration/test/edge_builder_test.dart
@@ -220,7 +220,7 @@
assign(t1, t2, hard: true);
assertEdge(t1.node, t2.node, hard: true);
assertEdge(t1.typeArguments[0].node, t2.typeArguments[0].node,
- hard: false, checkable: false);
+ hard: true, checkable: false);
}
void test_future_or_int_to_future_int() {
@@ -320,7 +320,7 @@
assign(t1, t2, hard: true);
assertEdge(t1.node, t2.node, hard: true);
assertEdge(t1.typeArguments[0].node, t2.typeArguments[0].node,
- hard: false, checkable: false);
+ hard: true, checkable: false);
}
void test_generic_to_generic_upcast() {
@@ -712,7 +712,7 @@
hard: true);
assertEdge(decoratedTypeAnnotation('bool>;').node,
decoratedTypeAnnotation('bool> f').node,
- hard: false, checkable: false);
+ hard: true, checkable: false);
assertNoEdge(anyNode, decoratedTypeAnnotation('bool>;').node);
assertNoEdge(anyNode, decoratedTypeAnnotation('int> a').node);
// int> a should be connected to the bound of T in A<T>, but nothing else.
@@ -803,7 +803,7 @@
// the return type `FutureOr<List<int?>>`.
assertEdge(decoratedTypeAnnotation('int>> x').node,
decoratedTypeAnnotation('int>> f').node,
- hard: false, checkable: false);
+ hard: true, checkable: false);
assertNoEdge(decoratedTypeAnnotation('int>> x').node,
decoratedTypeAnnotation('List<int>> f').node);
assertNoEdge(decoratedTypeAnnotation('int>> x').node,
@@ -831,7 +831,7 @@
substitutionNode(
decoratedTypeAnnotation('int> x').node, inSet(pointsToNever)),
decoratedTypeAnnotation('int> f').node,
- hard: false,
+ hard: true,
checkable: false);
assertNoEdge(decoratedTypeAnnotation('int> x').node,
decoratedTypeAnnotation('FutureOr<int>').node);
@@ -1237,7 +1237,7 @@
assertEdge(
substitutionNode(listInt.typeArguments[0].node, inSet(pointsToNever)),
iterableInt.typeArguments[0].node,
- hard: false,
+ hard: true,
checkable: false);
}
@@ -2032,7 +2032,7 @@
hard: true);
assertEdge(decoratedTypeAnnotation('int>/*2*/').node,
constructorParameterType.typeArguments[0].node,
- hard: false, checkable: false);
+ hard: true, checkable: false);
assertUnion(constructorParameterType.node,
decoratedTypeAnnotation('MyList<int>/*1*/').node);
assertUnion(constructorParameterType.typeArguments[0].node,
@@ -3507,7 +3507,7 @@
assertNoUpstreamNullability(decoratedTypeAnnotation('List<int/*1*/>').node);
assertEdge(decoratedTypeAnnotation('int/*2*/').node,
decoratedTypeAnnotation('int/*1*/').node,
- hard: false, checkable: false);
+ hard: true, checkable: false);
}
Future<void>
@@ -3847,7 +3847,7 @@
decoratedTypeAnnotation('String> j').node,
substitutionNode(decoratedTypeAnnotation('String> d').node,
decoratedTypeAnnotation('V>>').node),
- hard: false,
+ hard: true,
checkable: false);
assertEdge(
decoratedTypeAnnotation('List<String> j').node,
@@ -4293,7 +4293,7 @@
decoratedTypeAnnotation('int> x').node,
substitutionNode(
inferredTypeArgument, decoratedTypeAnnotation('T> x').node),
- hard: false,
+ hard: true,
checkable: false);
}
@@ -4636,7 +4636,7 @@
var typeArgForReturnType = decoratedTypeAnnotation('String> ').node;
assertNoUpstreamNullability(typeArgForLiteral);
assertEdge(typeArgForLiteral, typeArgForReturnType,
- hard: false, checkable: false);
+ hard: true, checkable: false);
}
Future<void> test_listLiteral_typeArgument_nullableElement() async {
@@ -5118,7 +5118,7 @@
assertEdge(decoratedTypeAnnotation('int/*3*/').node,
decoratedTypeAnnotation('int/*1*/').node,
- hard: false, checkable: false);
+ hard: true, checkable: false);
assertNullCheck(
checkExpression('c/*check*/'),
assertEdge(decoratedTypeAnnotation('C<int/*3*/>/*4*/').node,
@@ -7129,7 +7129,7 @@
decoratedTypeAnnotation('int g').node,
// TODO(40621): This should be a checkable edge.
assertEdge(anyNode, decoratedTypeAnnotation('int>').node,
- hard: false, checkable: false)
+ hard: true, checkable: false)
.sourceNode,
hard: false,
// TODO(40621): This should be a checkable edge.
@@ -7188,7 +7188,7 @@
''');
var lubNodeMatcher = anyNode;
assertEdge(lubNodeMatcher, decoratedTypeAnnotation('Object').node,
- hard: false, checkable: false);
+ hard: true, checkable: false);
var lubNode = lubNodeMatcher.matchingNode as NullabilityNodeForLUB;
expect(lubNode.left, same(decoratedTypeAnnotation('int> x').node));
expect(lubNode.right, same(decoratedTypeAnnotation('FutureOr<int>').node));
@@ -7201,7 +7201,7 @@
''');
assertEdge(decoratedTypeAnnotation('List<int>').node,
decoratedTypeAnnotation('Object').node,
- hard: false, checkable: false);
+ hard: true, checkable: false);
}
Future<void> test_return_from_async_null() async {
@@ -7298,11 +7298,11 @@
var mapNode = decoratedTypeAnnotation('Map').node;
assertNoUpstreamNullability(mapNode);
- var keyEdge = assertEdge(anyNode, keyNode, hard: false, checkable: false);
+ var keyEdge = assertEdge(anyNode, keyNode, hard: true, checkable: false);
assertNoUpstreamNullability(keyEdge.sourceNode);
expect(keyEdge.sourceNode.displayName, 'map key type (test.dart:2:10)');
var valueEdge =
- assertEdge(anyNode, valueNode, hard: false, checkable: false);
+ assertEdge(anyNode, valueNode, hard: true, checkable: false);
assertNoUpstreamNullability(valueEdge.sourceNode);
expect(valueEdge.sourceNode.displayName, 'map value type (test.dart:2:10)');
}
@@ -7319,10 +7319,10 @@
assertNoUpstreamNullability(mapNode);
assertEdge(inSet(alwaysPlus),
- assertEdge(anyNode, keyNode, hard: false, checkable: false).sourceNode,
+ assertEdge(anyNode, keyNode, hard: true, checkable: false).sourceNode,
hard: false);
assertNoUpstreamNullability(
- assertEdge(anyNode, valueNode, hard: false, checkable: false)
+ assertEdge(anyNode, valueNode, hard: true, checkable: false)
.sourceNode);
}
@@ -7339,12 +7339,10 @@
assertNoUpstreamNullability(mapNode);
assertEdge(inSet(alwaysPlus),
- assertEdge(anyNode, keyNode, hard: false, checkable: false).sourceNode,
+ assertEdge(anyNode, keyNode, hard: true, checkable: false).sourceNode,
hard: false);
- assertEdge(
- inSet(alwaysPlus),
- assertEdge(anyNode, valueNode, hard: false, checkable: false)
- .sourceNode,
+ assertEdge(inSet(alwaysPlus),
+ assertEdge(anyNode, valueNode, hard: true, checkable: false).sourceNode,
hard: false);
}
@@ -7360,11 +7358,9 @@
assertNoUpstreamNullability(mapNode);
assertNoUpstreamNullability(
- assertEdge(anyNode, keyNode, hard: false, checkable: false).sourceNode);
- assertEdge(
- inSet(alwaysPlus),
- assertEdge(anyNode, valueNode, hard: false, checkable: false)
- .sourceNode,
+ assertEdge(anyNode, keyNode, hard: true, checkable: false).sourceNode);
+ assertEdge(inSet(alwaysPlus),
+ assertEdge(anyNode, valueNode, hard: true, checkable: false).sourceNode,
hard: false);
}
@@ -7380,13 +7376,13 @@
var keyForLiteral = decoratedTypeAnnotation('String, int>{').node;
var keyForReturnType = decoratedTypeAnnotation('String, int> ').node;
assertNoUpstreamNullability(keyForLiteral);
- assertEdge(keyForLiteral, keyForReturnType, hard: false, checkable: false);
+ assertEdge(keyForLiteral, keyForReturnType, hard: true, checkable: false);
var valueForLiteral = decoratedTypeAnnotation('int>{').node;
var valueForReturnType = decoratedTypeAnnotation('int> ').node;
assertNoUpstreamNullability(valueForLiteral);
assertEdge(valueForLiteral, valueForReturnType,
- hard: false, checkable: false);
+ hard: true, checkable: false);
}
Future<void> test_setOrMapLiteral_map_typeArguments_nullableKey() async {
@@ -7438,7 +7434,7 @@
var setNode = decoratedTypeAnnotation('Set').node;
assertNoUpstreamNullability(setNode);
- var edge = assertEdge(anyNode, valueNode, hard: false, checkable: false);
+ var edge = assertEdge(anyNode, valueNode, hard: true, checkable: false);
assertNoUpstreamNullability(edge.sourceNode);
expect(edge.sourceNode.displayName, 'set element type (test.dart:2:10)');
}
@@ -7453,10 +7449,8 @@
var setNode = decoratedTypeAnnotation('Set').node;
assertNoUpstreamNullability(setNode);
- assertEdge(
- inSet(alwaysPlus),
- assertEdge(anyNode, valueNode, hard: false, checkable: false)
- .sourceNode,
+ assertEdge(inSet(alwaysPlus),
+ assertEdge(anyNode, valueNode, hard: true, checkable: false).sourceNode,
hard: false);
}
@@ -7472,7 +7466,7 @@
var typeArgForReturnType = decoratedTypeAnnotation('String> ').node;
assertNoUpstreamNullability(typeArgForLiteral);
assertEdge(typeArgForLiteral, typeArgForReturnType,
- hard: false, checkable: false);
+ hard: true, checkable: false);
}
Future<void> test_setOrMapLiteral_set_typeArgument_nullableElement() async {
@@ -7737,7 +7731,7 @@
assertEdge(
substitutionNode(decoratedTypeAnnotation('int> ints').node, anyNode),
decoratedTypeAnnotation('int>[').node,
- hard: false,
+ hard: true,
checkable: false);
}
@@ -7763,7 +7757,7 @@
assertEdge(
substitutionNode(decoratedTypeAnnotation('int> ints').node, anyNode),
decoratedTypeAnnotation('int>[').node,
- hard: false,
+ hard: true,
checkable: false);
}
@@ -7778,10 +7772,10 @@
hard: true);
assertEdge(decoratedTypeAnnotation('String, int> map').node,
decoratedTypeAnnotation('String, int>{').node,
- hard: false, checkable: false);
+ hard: true, checkable: false);
assertEdge(decoratedTypeAnnotation('int> map').node,
decoratedTypeAnnotation('int>{').node,
- hard: false, checkable: false);
+ hard: true, checkable: false);
}
Future<void> test_spread_element_set() async {
@@ -7795,7 +7789,7 @@
assertEdge(
substitutionNode(decoratedTypeAnnotation('int> ints').node, anyNode),
decoratedTypeAnnotation('int>{').node,
- hard: false,
+ hard: true,
checkable: false);
}
@@ -7813,7 +7807,7 @@
substitutionNode(decoratedTypeAnnotation('int> ints').node,
decoratedTypeAnnotation('R> {}').node),
decoratedTypeAnnotation('int>[').node,
- hard: false,
+ hard: true,
checkable: false);
}
diff --git a/pkg/nnbd_migration/test/front_end/info_builder_test.dart b/pkg/nnbd_migration/test/front_end/info_builder_test.dart
index 45292fd..625672b 100644
--- a/pkg/nnbd_migration/test/front_end/info_builder_test.dart
+++ b/pkg/nnbd_migration/test/front_end/info_builder_test.dart
@@ -25,7 +25,7 @@
@reflectiveTest
class BuildEnclosingMemberDescriptionTest extends AbstractAnalysisTest {
Future<ResolvedUnitResult> resolveTestFile() async {
- return await session.getResolvedUnit(testFile);
+ return await session.getResolvedUnit2(testFile) as ResolvedUnitResult;
}
Future<void> test_classConstructor_named() async {
diff --git a/pkg/nnbd_migration/test/front_end/nnbd_migration_test_base.dart b/pkg/nnbd_migration/test/front_end/nnbd_migration_test_base.dart
index 2622ed5..f9d7b6e 100644
--- a/pkg/nnbd_migration/test/front_end/nnbd_migration_test_base.dart
+++ b/pkg/nnbd_migration/test/front_end/nnbd_migration_test_base.dart
@@ -241,7 +241,8 @@
Future<void> _forEachPath(
void Function(ResolvedUnitResult) callback) async {
for (var testPath in testPaths) {
- var result = await driver.currentSession.getResolvedUnit(testPath);
+ var result = await driver.currentSession.getResolvedUnit2(testPath)
+ as ResolvedUnitResult;
callback(result);
}
}
diff --git a/pkg/nnbd_migration/test/instrumentation_test.dart b/pkg/nnbd_migration/test/instrumentation_test.dart
index 6e8cd37..605f928 100644
--- a/pkg/nnbd_migration/test/instrumentation_test.dart
+++ b/pkg/nnbd_migration/test/instrumentation_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/analysis/results.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/generated/source.dart';
@@ -147,7 +148,8 @@
instrumentation: _InstrumentationClient(this),
removeViaComments: removeViaComments,
warnOnWeakCode: warnOnWeakCode);
- var result = await session.getResolvedUnit(sourcePath);
+ var result =
+ await session.getResolvedUnit2(sourcePath) as ResolvedUnitResult;
source = result.unit.declaredElement.source;
findNode = FindNode(content, result.unit);
migration.prepareInput(result);
diff --git a/pkg/nnbd_migration/test/migration_cli_test.dart b/pkg/nnbd_migration/test/migration_cli_test.dart
index 5758e9a..36a85b2 100644
--- a/pkg/nnbd_migration/test/migration_cli_test.dart
+++ b/pkg/nnbd_migration/test/migration_cli_test.dart
@@ -1272,6 +1272,32 @@
});
}
+ test_lifecycle_preview_rerun_with_ignore_errors() async {
+ var origSourceText = 'void f(int i) {}';
+ var projectContents = simpleProject(sourceText: origSourceText);
+ var projectDir = createProjectDir(projectContents);
+ var cli = _createCli();
+ await runWithPreviewServer(cli, ['--ignore-errors', projectDir],
+ (url) async {
+ await assertPreviewServerResponsive(url);
+ var uri = Uri.parse(url);
+ var testPath =
+ resourceProvider.pathContext.join(projectDir, 'lib', 'test.dart');
+ resourceProvider.getFile(testPath).writeAsStringSync('void f(int? i) {}');
+ // We haven't rerun, so getting the file details from the server should
+ // still yield the original source text, with informational space.
+ expect(await getSourceFromServer(uri, testPath), 'void f(int i) {}');
+ var response = await httpPost(uri.replace(path: 'rerun-migration'),
+ headers: {'Content-Type': 'application/json; charset=UTF-8'});
+ assertHttpSuccess(response);
+ var body = jsonDecode(response.body);
+ expect(body['success'], isTrue);
+ expect(body['errors'], isNull);
+ // Now that we've rerun, the server should yield the new source text
+ expect(await getSourceFromServer(uri, testPath), 'void f(int? i) {}');
+ });
+ }
+
test_lifecycle_preview_rerun_with_new_analysis_errors() async {
var origSourceText = 'void f(int i) {}';
var projectContents = simpleProject(sourceText: origSourceText);
diff --git a/pkg/nnbd_migration/tool/trial_migration.dart b/pkg/nnbd_migration/tool/trial_migration.dart
index 2d0769d..4c14791 100644
--- a/pkg/nnbd_migration/tool/trial_migration.dart
+++ b/pkg/nnbd_migration/tool/trial_migration.dart
@@ -10,6 +10,7 @@
import 'dart:io';
+import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/diagnostic/diagnostic.dart';
import 'package:analyzer/src/dart/analysis/analysis_context_collection.dart';
@@ -68,7 +69,8 @@
var migration =
NullabilityMigration(listener, getLineInfo, permissive: true);
for (var file in localFiles) {
- var resolvedUnit = await session.getResolvedUnit(file);
+ var resolvedUnit =
+ await session.getResolvedUnit2(file) as ResolvedUnitResult;
if (!resolvedUnit.errors.any((e) => e.severity == Severity.error)) {
migration.prepareInput(resolvedUnit);
} else {
@@ -76,13 +78,15 @@
}
}
for (var file in localFiles) {
- var resolvedUnit = await session.getResolvedUnit(file);
+ var resolvedUnit =
+ await session.getResolvedUnit2(file) as ResolvedUnitResult;
if (!resolvedUnit.errors.any((e) => e.severity == Severity.error)) {
migration.processInput(resolvedUnit);
}
}
for (var file in localFiles) {
- var resolvedUnit = await session.getResolvedUnit(file);
+ var resolvedUnit =
+ await session.getResolvedUnit2(file) as ResolvedUnitResult;
if (!resolvedUnit.errors.any((e) => e.severity == Severity.error)) {
migration.finalizeInput(resolvedUnit);
}
diff --git a/pkg/test_runner/lib/bot_results.dart b/pkg/test_runner/lib/bot_results.dart
index b5032f6..8f68b04 100644
--- a/pkg/test_runner/lib/bot_results.dart
+++ b/pkg/test_runner/lib/bot_results.dart
@@ -71,7 +71,7 @@
Future<String> runGsutil(List<String> arguments) async {
return gsutilPool.withResource(() async {
var processResult = await Process.run(
- "python", [gsutilPy]..addAll(arguments),
+ "python3", [gsutilPy]..addAll(arguments),
runInShell: Platform.isWindows);
var stderr = processResult.stderr as String;
if (processResult.exitCode != 0) {
@@ -79,14 +79,14 @@
stderr.contains("One or more URLs matched no objects")) {
return null;
}
- var error = "Failed to run: python $gsutilPy $arguments\n"
+ var error = "Failed to run: python3 $gsutilPy $arguments\n"
"exitCode: ${processResult.exitCode}\n"
"stdout:\n${processResult.stdout}\n"
"stderr:\n${processResult.stderr}";
if (processResult.exitCode == 1 &&
stderr.contains("401 Anonymous caller")) {
error =
- "\n\nYou need to authenticate by running:\npython $gsutilPy config\n";
+ "\n\nYou need to authenticate by running:\npython3 $gsutilPy config\n";
}
throw Exception(error);
}
diff --git a/pkg/test_runner/lib/src/build_configurations.dart b/pkg/test_runner/lib/src/build_configurations.dart
index 6179997..b6c8aa8b 100644
--- a/pkg/test_runner/lib/src/build_configurations.dart
+++ b/pkg/test_runner/lib/src/build_configurations.dart
@@ -49,8 +49,8 @@
...osFlags,
...buildTargets
];
- print('Running command: python ${command.join(' ')}');
- final process = await Process.start('python', command);
+ print('Running command: python3 ${command.join(' ')}');
+ final process = await Process.start('python3', command);
stdout.nonBlocking.addStream(process.stdout);
stderr.nonBlocking.addStream(process.stderr);
final exitCode = await process.exitCode;
diff --git a/pkg/test_runner/lib/src/status_reporter.dart b/pkg/test_runner/lib/src/status_reporter.dart
index 36e0414..e795d96 100644
--- a/pkg/test_runner/lib/src/status_reporter.dart
+++ b/pkg/test_runner/lib/src/status_reporter.dart
@@ -77,9 +77,9 @@
'runtime'
];
- print('Running: python ${args.join(" ")}');
+ print('Running: python3 ${args.join(" ")}');
- var result = Process.runSync('python', args);
+ var result = Process.runSync('python3', args);
if (result.exitCode != 0) {
print('ERROR');
@@ -149,7 +149,7 @@
'--report-in-json',
'--use-sdk'
];
- var result = Process.runSync('python', args);
+ var result = Process.runSync('python3', args);
if (result.exitCode != 0) {
print(result.stdout);
print(result.stderr);
diff --git a/pkg/test_runner/lib/src/test_progress.dart b/pkg/test_runner/lib/src/test_progress.dart
index 850c492..a089688 100644
--- a/pkg/test_runner/lib/src/test_progress.dart
+++ b/pkg/test_runner/lib/src/test_progress.dart
@@ -622,7 +622,7 @@
if (Platform.isFuchsia) {
arguments = [Platform.executable, Platform.script.path];
} else {
- arguments = ['python', 'tools/test.py'];
+ arguments = ['python3', 'tools/test.py'];
}
arguments.addAll(test.configuration.reproducingArguments);
arguments.add(test.displayName);
diff --git a/pkg/test_runner/lib/test_runner.dart b/pkg/test_runner/lib/test_runner.dart
index 33f93ba..59fcb9f 100644
--- a/pkg/test_runner/lib/test_runner.dart
+++ b/pkg/test_runner/lib/test_runner.dart
@@ -482,7 +482,7 @@
print("Running tests");
print("".padLeft(80, "="));
await runProcessInheritStdio(
- "python",
+ "python3",
[
"tools/test.py",
"--named-configuration=${configurationsToRun.join(",")}",
@@ -607,7 +607,7 @@
];
await runProcessInheritStdio(
- "python", ["tools/test.py", ...deflakeArguments],
+ "python3", ["tools/test.py", ...deflakeArguments],
runInShell: Platform.isWindows);
deflakingResultsPaths.add("${deflakeDirectory.path}/results.json");
}
diff --git a/pkg/vm/lib/transformations/ffi.dart b/pkg/vm/lib/transformations/ffi.dart
index bd70fef..b6c00a8 100644
--- a/pkg/vm/lib/transformations/ffi.dart
+++ b/pkg/vm/lib/transformations/ffi.dart
@@ -231,6 +231,7 @@
final Class pointerClass;
final Class compoundClass;
final Class structClass;
+ final Class unionClass;
final Class ffiStructLayoutClass;
final Field ffiStructLayoutTypesField;
final Field ffiStructLayoutPackingField;
@@ -247,7 +248,10 @@
final Procedure addressGetter;
final Procedure structPointerRef;
final Procedure structPointerElemAt;
+ final Procedure unionPointerRef;
+ final Procedure unionPointerElemAt;
final Procedure structArrayElemAt;
+ final Procedure unionArrayElemAt;
final Procedure arrayArrayElemAt;
final Procedure arrayArrayAssignAt;
final Procedure asFunctionMethod;
@@ -264,6 +268,7 @@
final Field arrayNestedDimensionsFirst;
final Field arrayNestedDimensionsRest;
final Constructor structFromTypedDataBase;
+ final Constructor unionFromTypedDataBase;
final Constructor arrayConstructor;
final Procedure fromAddressInternal;
final Procedure libraryLookupMethod;
@@ -333,6 +338,7 @@
pointerClass = index.getClass('dart:ffi', 'Pointer'),
compoundClass = index.getClass('dart:ffi', '_Compound'),
structClass = index.getClass('dart:ffi', 'Struct'),
+ unionClass = index.getClass('dart:ffi', 'Union'),
ffiStructLayoutClass = index.getClass('dart:ffi', '_FfiStructLayout'),
ffiStructLayoutTypesField =
index.getMember('dart:ffi', '_FfiStructLayout', 'fieldTypes'),
@@ -369,6 +375,8 @@
index.getMember('dart:ffi', 'Array', '_nestedDimensionsRest'),
structFromTypedDataBase =
index.getMember('dart:ffi', 'Struct', '_fromTypedDataBase'),
+ unionFromTypedDataBase =
+ index.getMember('dart:ffi', 'Union', '_fromTypedDataBase'),
arrayConstructor = index.getMember('dart:ffi', 'Array', '_'),
fromAddressInternal =
index.getTopLevelMember('dart:ffi', '_fromAddress'),
@@ -376,7 +384,11 @@
index.getMember('dart:ffi', 'StructPointer', 'get:ref'),
structPointerElemAt =
index.getMember('dart:ffi', 'StructPointer', '[]'),
+ unionPointerRef =
+ index.getMember('dart:ffi', 'UnionPointer', 'get:ref'),
+ unionPointerElemAt = index.getMember('dart:ffi', 'UnionPointer', '[]'),
structArrayElemAt = index.getMember('dart:ffi', 'StructArray', '[]'),
+ unionArrayElemAt = index.getMember('dart:ffi', 'UnionArray', '[]'),
arrayArrayElemAt = index.getMember('dart:ffi', 'ArrayArray', '[]'),
arrayArrayAssignAt = index.getMember('dart:ffi', 'ArrayArray', '[]='),
asFunctionMethod =
@@ -478,7 +490,7 @@
return nativeType;
}
if (hierarchy.isSubclassOf(nativeClass, compoundClass)) {
- if (nativeClass == structClass) {
+ if (nativeClass == structClass || nativeClass == unionClass) {
return null;
}
return allowCompounds ? nativeType : null;
@@ -749,11 +761,13 @@
return false;
}
if (type is InterfaceType) {
- if (type.classNode == structClass) {
+ if (type.classNode == structClass || type.classNode == unionClass) {
return false;
}
}
- return env.isSubtypeOf(type, InterfaceType(structClass, Nullability.legacy),
+ return env.isSubtypeOf(
+ type,
+ InterfaceType(compoundClass, Nullability.legacy),
SubtypeCheckMode.ignoringNullabilities);
}
}
diff --git a/pkg/vm/lib/transformations/ffi_definitions.dart b/pkg/vm/lib/transformations/ffi_definitions.dart
index 732a676..6dc8a46 100644
--- a/pkg/vm/lib/transformations/ffi_definitions.dart
+++ b/pkg/vm/lib/transformations/ffi_definitions.dart
@@ -146,8 +146,8 @@
if (report) {
component.forEach((Class e) {
diagnosticReporter.report(
- templateFfiFieldCyclic.withArguments(
- e.name, component.map((e) => e.name).toList()),
+ templateFfiFieldCyclic.withArguments(e.superclass.name, e.name,
+ component.map((e) => e.name).toList()),
e.fileOffset,
e.name.length,
e.fileUri);
@@ -175,7 +175,8 @@
visitClass(Class node) {
if (!hierarchy.isSubclassOf(node, compoundClass) ||
node == compoundClass ||
- node == structClass) {
+ node == structClass ||
+ node == unionClass) {
return node;
}
@@ -203,39 +204,41 @@
int _checkCompoundClass(Class node) {
if (node.typeParameters.length > 0) {
diagnosticReporter.report(
- templateFfiStructGeneric.withArguments(node.name),
+ templateFfiStructGeneric.withArguments(
+ node.superclass.name, node.name),
node.fileOffset,
1,
node.location.file);
}
- if (node.superclass != structClass) {
- // Not a struct, but extends a struct. The error will be emitted by
- // _FfiUseSiteTransformer.
+ if (node.superclass != structClass && node.superclass != unionClass) {
+ // Not a struct or union, but extends a struct or union.
+ // The error will be emitted by _FfiUseSiteTransformer.
return null;
}
- final packingAnnotations = _getPackedAnnotations(node);
- if (packingAnnotations.length > 1) {
- diagnosticReporter.report(
- templateFfiPackedAnnotation.withArguments(node.name),
- node.fileOffset,
- node.name.length,
- node.location.file);
- }
- if (packingAnnotations.isNotEmpty) {
- final packing = packingAnnotations.first;
- if (!(packing == 1 ||
- packing == 2 ||
- packing == 4 ||
- packing == 8 ||
- packing == 16)) {
- diagnosticReporter.report(messageFfiPackedAnnotationAlignment,
- node.fileOffset, node.name.length, node.location.file);
+ if (node.superclass == structClass) {
+ final packingAnnotations = _getPackedAnnotations(node);
+ if (packingAnnotations.length > 1) {
+ diagnosticReporter.report(
+ templateFfiPackedAnnotation.withArguments(node.name),
+ node.fileOffset,
+ node.name.length,
+ node.location.file);
}
- return packing;
+ if (packingAnnotations.isNotEmpty) {
+ final packing = packingAnnotations.first;
+ if (!(packing == 1 ||
+ packing == 2 ||
+ packing == 4 ||
+ packing == 8 ||
+ packing == 16)) {
+ diagnosticReporter.report(messageFfiPackedAnnotationAlignment,
+ node.fileOffset, node.name.length, node.location.file);
+ }
+ return packing;
+ }
}
-
return null;
}
@@ -440,7 +443,10 @@
name: name,
initializers: [
SuperInitializer(
- structFromTypedDataBase, Arguments([VariableGet(typedDataBase)]))
+ node.superclass == structClass
+ ? structFromTypedDataBase
+ : unionFromTypedDataBase,
+ Arguments([VariableGet(typedDataBase)]))
],
fileUri: node.fileUri,
reference: referenceFrom?.reference)
@@ -511,12 +517,17 @@
_annoteCompoundWithFields(node, types, packing);
if (types.isEmpty) {
- diagnosticReporter.report(templateFfiEmptyStruct.withArguments(node.name),
- node.fileOffset, node.name.length, node.location.file);
+ diagnosticReporter.report(
+ templateFfiEmptyStruct.withArguments(node.superclass.name, node.name),
+ node.fileOffset,
+ node.name.length,
+ node.location.file);
emptyCompounds.add(node);
}
- final compoundType = StructNativeTypeCfe(node, types, packing: packing);
+ final compoundType = node.superclass == structClass
+ ? StructNativeTypeCfe(node, types, packing: packing)
+ : UnionNativeTypeCfe(node, types);
compoundCache[node] = compoundType;
final compoundLayout = compoundType.layout;
@@ -1090,6 +1101,34 @@
}
}
+class UnionNativeTypeCfe extends CompoundNativeTypeCfe {
+ factory UnionNativeTypeCfe(Class clazz, List<NativeTypeCfe> members) {
+ final layout = Map.fromEntries(
+ Abi.values.map((abi) => MapEntry(abi, _calculateLayout(members, abi))));
+ return UnionNativeTypeCfe._(clazz, members, layout);
+ }
+
+ UnionNativeTypeCfe._(
+ Class clazz, List<NativeTypeCfe> members, Map<Abi, CompoundLayout> layout)
+ : super._(clazz, members, layout);
+
+ // Keep consistent with runtime/vm/compiler/ffi/native_type.cc
+ // NativeUnionType::FromNativeTypes.
+ static CompoundLayout _calculateLayout(List<NativeTypeCfe> types, Abi abi) {
+ int unionSize = 1;
+ int unionAlignment = 1;
+ for (int i = 0; i < types.length; i++) {
+ final int size = types[i].size[abi];
+ int alignment = types[i].alignment[abi];
+ unionSize = math.max(unionSize, size);
+ unionAlignment = math.max(unionAlignment, alignment);
+ }
+ final int size = _alignOffset(unionSize, unionAlignment);
+ return CompoundLayout(
+ size, unionAlignment, List.filled(Abi.values.length, 0));
+ }
+}
+
class ArrayNativeTypeCfe implements NativeTypeCfe {
final NativeTypeCfe elementType;
final int length;
diff --git a/pkg/vm/lib/transformations/ffi_use_sites.dart b/pkg/vm/lib/transformations/ffi_use_sites.dart
index 44d56f1..a4383ed 100644
--- a/pkg/vm/lib/transformations/ffi_use_sites.dart
+++ b/pkg/vm/lib/transformations/ffi_use_sites.dart
@@ -176,13 +176,16 @@
final Member target = node.target;
try {
- if (target == structPointerRef || target == structPointerElemAt) {
+ if (target == structPointerRef ||
+ target == structPointerElemAt ||
+ target == unionPointerRef ||
+ target == unionPointerElemAt) {
final DartType nativeType = node.arguments.types[0];
_ensureNativeTypeValid(nativeType, node, allowCompounds: true);
return _replaceRef(node);
- } else if (target == structArrayElemAt) {
+ } else if (target == structArrayElemAt || target == unionArrayElemAt) {
final DartType nativeType = node.arguments.types[0];
_ensureNativeTypeValid(nativeType, node, allowCompounds: true);
@@ -228,7 +231,8 @@
final returnType = dartType.returnType;
if (returnType is InterfaceType) {
final clazz = returnType.classNode;
- if (clazz.superclass == structClass) {
+ if (clazz.superclass == structClass ||
+ clazz.superclass == unionClass) {
return _invokeCompoundConstructor(replacement, clazz);
}
}
@@ -256,7 +260,8 @@
final returnType = dartType.returnType;
if (returnType is InterfaceType) {
final clazz = returnType.classNode;
- if (clazz.superclass == structClass) {
+ if (clazz.superclass == structClass ||
+ clazz.superclass == unionClass) {
return _invokeCompoundConstructor(replacement, clazz);
}
}
@@ -286,7 +291,8 @@
if (expectedReturn == NativeType.kVoid ||
expectedReturn == NativeType.kPointer ||
expectedReturn == NativeType.kHandle ||
- expectedReturnClass.superclass == structClass) {
+ expectedReturnClass.superclass == structClass ||
+ expectedReturnClass.superclass == unionClass) {
if (node.arguments.positional.length > 1) {
diagnosticReporter.report(
templateFfiExpectedNoExceptionalReturn.withArguments(
@@ -351,7 +357,8 @@
final compoundClasses = funcType.positionalParameters
.whereType<InterfaceType>()
.map((t) => t.classNode)
- .where((c) => c.superclass == structClass)
+ .where((c) =>
+ c.superclass == structClass || c.superclass == unionClass)
.toList();
return _invokeCompoundConstructors(replacement, compoundClasses);
} else if (target == allocateMethod) {
@@ -778,7 +785,8 @@
if (hierarchy.isSubclassOf(nativeClass, compoundClass)) {
if (emptyCompounds.contains(nativeClass)) {
diagnosticReporter.report(
- templateFfiEmptyStruct.withArguments(nativeClass.name),
+ templateFfiEmptyStruct.withArguments(
+ nativeClass.superclass.name, nativeClass.name),
node.fileOffset,
1,
node.location.file);
@@ -830,13 +838,14 @@
klass == compoundClass ||
klass == opaqueClass ||
klass == structClass ||
+ klass == unionClass ||
nativeTypesClasses.contains(klass)) {
return null;
}
// The Opaque and Struct classes can be extended, but subclasses
// cannot be (nor implemented).
- final onlyDirectExtendsClasses = [opaqueClass, structClass];
+ final onlyDirectExtendsClasses = [opaqueClass, structClass, unionClass];
final superClass = klass.superclass;
for (final onlyDirectExtendsClass in onlyDirectExtendsClasses) {
if (hierarchy.isSubtypeOf(klass, onlyDirectExtendsClass)) {
diff --git a/pkg/vm_snapshot_analysis/lib/ascii_table.dart b/pkg/vm_snapshot_analysis/lib/ascii_table.dart
index a0e5404..3721814 100644
--- a/pkg/vm_snapshot_analysis/lib/ascii_table.dart
+++ b/pkg/vm_snapshot_analysis/lib/ascii_table.dart
@@ -16,7 +16,7 @@
/// Note: there is a border on the left and right of each column
/// plus whitespace around it.
static int totalWidth(List<int> widths) =>
- widths.fold(0, (sum, width) => sum + width + 3) + 1;
+ widths.fold<int>(0, (sum, width) => sum + width + 3) + 1;
}
enum Separator {
@@ -91,7 +91,7 @@
final String value;
final AlignmentDirection direction;
- Text({this.value, this.direction});
+ Text({required this.value, required this.direction});
Text.left(String value)
: this(value: value, direction: AlignmentDirection.Left);
Text.right(String value)
@@ -113,7 +113,6 @@
final diff = width - value.length;
return ' ' * (diff ~/ 2) + value + (' ' * (diff - diff ~/ 2));
}
- return null; // Make analyzer happy.
}
int get length => value.length;
@@ -126,7 +125,7 @@
final List<Row> rows = <Row>[];
- AsciiTable({List<dynamic> header, this.maxWidth = unlimitedWidth}) {
+ AsciiTable({List<dynamic>? header, this.maxWidth = unlimitedWidth}) {
if (header != null) {
addSeparator();
addRow(header);
diff --git a/pkg/vm_snapshot_analysis/lib/instruction_sizes.dart b/pkg/vm_snapshot_analysis/lib/instruction_sizes.dart
index 635f8dd..a1db07f 100644
--- a/pkg/vm_snapshot_analysis/lib/instruction_sizes.dart
+++ b/pkg/vm_snapshot_analysis/lib/instruction_sizes.dart
@@ -40,16 +40,20 @@
/// If this instructions object originated from a function then [libraryUri]
/// will contain uri of the library of that function.
- final String libraryUri;
+ final String? libraryUri;
/// If this instructions object originated from a function then [className]
/// would contain name of the class owning that function.
- final String className;
+ final String? className;
/// Size of the instructions object in bytes.
final int size;
- SymbolInfo({String name, this.libraryUri, this.className, this.size})
+ SymbolInfo(
+ {required String name,
+ this.libraryUri,
+ this.className,
+ required this.size})
: name = Name(name);
static SymbolInfo _fromJson(Map<String, dynamic> map) {
@@ -74,37 +78,41 @@
final program = ProgramInfo();
for (var sym in symbols) {
final scrubbed = sym.name.scrubbed;
- if (sym.libraryUri == null) {
+ final libraryUri = sym.libraryUri;
+
+ // Handle stubs specially.
+ if (libraryUri == null) {
assert(sym.name.isStub);
final node = program.makeNode(
name: scrubbed, parent: program.stubs, type: NodeType.functionNode);
assert(node.size == null || sym.name.isTypeTestingStub);
node.size = (node.size ?? 0) + sym.size;
- } else {
- // Split the name into components (names of individual functions).
- final path = sym.name.components;
-
- var node = program.root;
- final package = packageOf(sym.libraryUri);
- if (package != sym.libraryUri) {
- node = program.makeNode(
- name: package, parent: node, type: NodeType.packageNode);
- }
- node = program.makeNode(
- name: sym.libraryUri, parent: node, type: NodeType.libraryNode);
- node = program.makeNode(
- name: sym.className, parent: node, type: NodeType.classNode);
- node = program.makeNode(
- name: path.first, parent: node, type: NodeType.functionNode);
- for (var name in path.skip(1)) {
- if (collapseAnonymousClosures) {
- name = Name.collapse(name);
- }
- node = program.makeNode(
- name: name, parent: node, type: NodeType.functionNode);
- }
- node.size = (node.size ?? 0) + sym.size;
+ continue;
}
+
+ // Split the name into components (names of individual functions).
+ final path = sym.name.components;
+
+ var node = program.root;
+ final package = packageOf(libraryUri);
+ if (package != libraryUri) {
+ node = program.makeNode(
+ name: package, parent: node, type: NodeType.packageNode);
+ }
+ node = program.makeNode(
+ name: libraryUri, parent: node, type: NodeType.libraryNode);
+ node = program.makeNode(
+ name: sym.className!, parent: node, type: NodeType.classNode);
+ node = program.makeNode(
+ name: path.first, parent: node, type: NodeType.functionNode);
+ for (var name in path.skip(1)) {
+ if (collapseAnonymousClosures) {
+ name = Name.collapse(name);
+ }
+ node = program.makeNode(
+ name: name, parent: node, type: NodeType.functionNode);
+ }
+ node.size = (node.size ?? 0) + sym.size;
}
return program;
diff --git a/pkg/vm_snapshot_analysis/lib/name.dart b/pkg/vm_snapshot_analysis/lib/name.dart
index 3b17bd1..5d4e569 100644
--- a/pkg/vm_snapshot_analysis/lib/name.dart
+++ b/pkg/vm_snapshot_analysis/lib/name.dart
@@ -15,9 +15,6 @@
/// Raw textual representation of the name as it occurred in the output
/// of the AOT compiler.
final String raw;
- String _scrubbed;
-
- Name(this.raw);
/// Pretty version of the name, with some of the irrelevant information
/// removed from it.
@@ -26,16 +23,18 @@
/// so we are not removing any details that are used for disambiguation.
/// The only exception are type testing stubs, these refer to type names
/// and types names are not bound to be unique between compilations.
- String get scrubbed => _scrubbed ??=
+ late final String scrubbed =
raw.replaceAll(isStub ? _stubScrubbingRe : _scrubbingRe, '');
+ Name(this.raw);
+
/// Returns true if this name refers to a stub.
bool get isStub => raw.startsWith('[Stub] ');
/// Returns true if this name refers to an allocation stub.
bool get isAllocationStub => raw.startsWith('[Stub] Allocate ');
- /// Returns ture if this name refers to a type testing stub.
+ /// Returns true if this name refers to a type testing stub.
bool get isTypeTestingStub => raw.startsWith('[Stub] Type Test ');
/// Split this name into individual '.' separated components (e.g. names of
diff --git a/pkg/vm_snapshot_analysis/lib/precompiler_trace.dart b/pkg/vm_snapshot_analysis/lib/precompiler_trace.dart
index 54d86fe..3c9843c 100644
--- a/pkg/vm_snapshot_analysis/lib/precompiler_trace.dart
+++ b/pkg/vm_snapshot_analysis/lib/precompiler_trace.dart
@@ -11,7 +11,8 @@
/// Build [CallGraph] based on the trace written by `--trace-precompiler-to`
/// flag.
-CallGraph loadTrace(Object inputJson) => _TraceReader(inputJson).readTrace();
+CallGraph loadTrace(Object inputJson) =>
+ _TraceReader(inputJson as Map<String, dynamic>).readTrace();
/// [CallGraphNode] represents a node of the call-graph. It can either be:
///
@@ -39,7 +40,7 @@
/// Dominator of this node.
///
/// Computed by [CallGraph.computeDominators].
- CallGraphNode dominator;
+ late CallGraphNode dominator;
/// Nodes dominated by this node.
///
@@ -99,13 +100,13 @@
// Mapping from [ProgramInfoNode] to a corresponding [CallGraphNode] (if any)
// via [ProgramInfoNode.id].
- final List<CallGraphNode> _graphNodeByEntityId;
+ final List<CallGraphNode?> _graphNodeByEntityId;
CallGraph._(this.program, this.nodes, this._graphNodeByEntityId);
CallGraphNode get root => nodes.first;
- CallGraphNode lookup(ProgramInfoNode node) => _graphNodeByEntityId[node.id];
+ CallGraphNode lookup(ProgramInfoNode node) => _graphNodeByEntityId[node.id]!;
Iterable<CallGraphNode> get dynamicCalls =>
nodes.where((n) => n.isDynamicCallNode);
@@ -113,7 +114,7 @@
/// Compute a collapsed version of the call-graph, where
CallGraph collapse(NodeType type, {bool dropCallNodes = false}) {
final graphNodesByData = <Object, CallGraphNode>{};
- final graphNodeByEntityId = <CallGraphNode>[];
+ final graphNodeByEntityId = <CallGraphNode?>[];
ProgramInfoNode collapsed(ProgramInfoNode nn) {
// Root always collapses onto itself.
@@ -127,7 +128,7 @@
// hitting the root node.
var n = nn;
while (n.parent != program.root && n.type != type) {
- n = n.parent;
+ n = n.parent!;
}
return n;
}
@@ -186,14 +187,14 @@
///
/// See README.md for description of the format.
class _TraceReader {
- final List<Object> trace;
- final List<Object> strings;
- final List<Object> entities;
+ final List<dynamic> trace;
+ final List<String> strings;
+ final List<dynamic> entities;
final program = ProgramInfo();
/// Mapping between entity ids and corresponding [ProgramInfoNode] nodes.
- final entityById = List<ProgramInfoNode>.filled(1024, null, growable: true);
+ final entityById = List<ProgramInfoNode?>.filled(1024, null, growable: true);
/// Mapping between functions (represented as [ProgramInfoNode]s) and
/// their selector ids.
@@ -203,21 +204,22 @@
final dynamicFunctions = Set<ProgramInfoNode>();
_TraceReader(Map<String, dynamic> data)
- : strings = data['strings'],
+ : strings = (data['strings'] as List<dynamic>).cast<String>(),
entities = data['entities'],
trace = data['trace'];
/// Read all trace events and construct the call graph based on them.
CallGraph readTrace() {
var pos = 0; // Position in the [trace] array.
- CallGraphNode currentNode;
+ late CallGraphNode currentNode;
+ int maxId = 0;
final nodes = <CallGraphNode>[];
- final nodeByEntityId = <CallGraphNode>[];
+ final nodeByEntityId = <CallGraphNode?>[];
final callNodesBySelector = <dynamic, CallGraphNode>{};
final allocated = Set<ProgramInfoNode>();
- Object next() => trace[pos++];
+ T next<T>() => trace[pos++] as T;
CallGraphNode makeNode({dynamic data}) {
final n = CallGraphNode(nodes.length, data: data);
@@ -232,6 +234,9 @@
if (nodeByEntityId.length <= n.id) {
nodeByEntityId.length = n.id * 2 + 1;
}
+ if (n.id > maxId) {
+ maxId = n.id;
+ }
return nodeByEntityId[n.id] ??= makeNode(data: n);
}
@@ -363,10 +368,13 @@
/// Read the entity at the given [index] in [entities].
ProgramInfoNode readEntityAt(int index) {
final type = entities[index];
+ final idx0 = entities[index + 1] as int;
+ final idx1 = entities[index + 2] as int;
+ final idx2 = entities[index + 3] as int;
switch (type) {
case 'C': // Class: 'C', <library-uri-idx>, <name-idx>, 0
- final libraryUri = strings[entities[index + 1]];
- final className = strings[entities[index + 2]];
+ final libraryUri = strings[idx0];
+ final className = strings[idx1];
return program.makeNode(
name: className,
@@ -375,9 +383,9 @@
case 'S':
case 'F': // Function: 'F'|'S', <class-idx>, <name-idx>, <selector-id>
- final classNode = getEntityAt(entities[index + 1]);
- final functionName = strings[entities[index + 2]];
- final int selectorId = entities[index + 3];
+ final classNode = getEntityAt(idx0);
+ final functionName = strings[idx1];
+ final int selectorId = idx2;
final path = Name(functionName).rawComponents;
if (path.last == 'FfiTrampoline') {
@@ -398,8 +406,8 @@
return node;
case 'V': // Field: 'V', <class-idx>, <name-idx>, 0
- final classNode = getEntityAt(entities[index + 1]);
- final fieldName = strings[entities[index + 2]];
+ final classNode = getEntityAt(idx0);
+ final fieldName = strings[idx1];
return program.makeNode(
name: fieldName, parent: classNode, type: NodeType.other);
diff --git a/pkg/vm_snapshot_analysis/lib/program_info.dart b/pkg/vm_snapshot_analysis/lib/program_info.dart
index e243048..cca2bca 100644
--- a/pkg/vm_snapshot_analysis/lib/program_info.dart
+++ b/pkg/vm_snapshot_analysis/lib/program_info.dart
@@ -5,8 +5,6 @@
/// Classes for representing information about the program structure.
library vm_snapshot_analysis.program_info;
-import 'package:meta/meta.dart';
-
import 'package:vm_snapshot_analysis/v8_profile.dart';
/// Represents information about compiled program.
@@ -22,7 +20,7 @@
/// V8 snapshot profile if this [ProgramInfo] object was created from an
/// output of `--write-v8-snapshot-profile-to=...` flag.
- SnapshotInfo snapshotInfo;
+ SnapshotInfo? snapshotInfo;
ProgramInfo._(this.root, this.stubs, this.unknown);
@@ -45,24 +43,22 @@
}
ProgramInfoNode makeNode(
- {@required String name,
- @required ProgramInfoNode parent,
- @required NodeType type}) {
- return parent.children.putIfAbsent(name, () {
- final node = ProgramInfoNode._(
- id: _nextId++, name: name, parent: parent ?? root, type: type);
- node.parent.children[name] = node;
- return node;
- });
+ {required String name,
+ required ProgramInfoNode parent,
+ required NodeType type}) {
+ return parent.children.putIfAbsent(
+ name,
+ () => ProgramInfoNode._(
+ id: _nextId++, name: name, parent: parent, type: type));
}
/// Recursively visit all function nodes, which have [FunctionInfo.info]
/// populated.
void visit(
- void Function(
- String pkg, String lib, String cls, String fun, ProgramInfoNode n)
+ void Function(String? pkg, String lib, String? cls, String? fun,
+ ProgramInfoNode n)
callback) {
- final context = List<String>.filled(NodeType.values.length, null);
+ final context = List<String?>.filled(NodeType.values.length, null);
void recurse(ProgramInfoNode node) {
final prevContext = context[node._type];
@@ -72,11 +68,11 @@
context[node._type] = node.name;
}
- final String pkg = context[NodeType.packageNode.index];
- final String lib = context[NodeType.libraryNode.index];
- final String cls = context[NodeType.classNode.index];
- final String mem = context[NodeType.functionNode.index];
- callback(pkg, lib, cls, mem, node);
+ final pkg = context[NodeType.packageNode.index];
+ final lib = context[NodeType.libraryNode.index];
+ final cls = context[NodeType.classNode.index];
+ final mem = context[NodeType.functionNode.index];
+ callback(pkg, lib!, cls, mem, node);
for (var child in node.children.values) {
recurse(child);
@@ -96,12 +92,14 @@
Map<String, dynamic> toJson() => root.toJson();
/// Lookup a node in the program given a path to it.
- ProgramInfoNode lookup(List<String> path) {
+ ProgramInfoNode? lookup(List<String> path) {
var n = root;
for (var p in path) {
- if ((n = n.children[p]) == null) {
- break;
+ final next = n.children[p];
+ if (next == null) {
+ return null;
}
+ n = next;
}
return n;
}
@@ -121,12 +119,12 @@
NodeType.classNode: 'class',
NodeType.functionNode: 'function',
NodeType.other: 'other',
- }[type];
+ }[type]!;
class ProgramInfoNode {
final int id;
final String name;
- final ProgramInfoNode parent;
+ final ProgramInfoNode? parent;
final Map<String, ProgramInfoNode> children = {};
final int _type;
@@ -151,13 +149,13 @@
/// Assuming that both `C.f` and `C.g` are included into AOT snapshot
/// and string `"something"` does not occur anywhere else in the program
/// then the size of `"something"` is going to be attributed to `C`.
- int size;
+ int? size;
ProgramInfoNode._(
- {@required this.id,
- @required this.name,
- @required this.parent,
- @required NodeType type})
+ {required this.id,
+ required this.name,
+ required this.parent,
+ required NodeType type})
: _type = type.index;
NodeType get type => NodeType.values[_type];
@@ -175,9 +173,10 @@
var prefix = '';
// Do not include root name or package name (library uri already contains
// package name).
- if (parent?.parent != null && parent?.type != NodeType.packageNode) {
- prefix = parent.qualifiedName;
- if (parent.type != NodeType.libraryNode) {
+ final p = parent;
+ if (p != null && p.parent != null && p.type != NodeType.packageNode) {
+ prefix = p.qualifiedName;
+ if (p.type != NodeType.libraryNode) {
prefix += '.';
} else {
prefix += '::';
@@ -198,7 +197,7 @@
var n = this;
while (n.parent != null) {
result.add(n.name);
- n = n.parent;
+ n = n.parent!;
}
return result.reversed.toList();
}
@@ -215,24 +214,24 @@
final programDiff = ProgramInfo();
var path = <Object>[];
- void recurse(ProgramInfoNode oldNode, ProgramInfoNode newNode) {
+ void recurse(ProgramInfoNode? oldNode, ProgramInfoNode? newNode) {
if (oldNode?.size != newNode?.size) {
var diffNode = programDiff.root;
for (var i = 0; i < path.length; i += 2) {
- final name = path[i];
- final type = path[i + 1];
+ final name = path[i] as String;
+ final type = path[i + 1] as NodeType;
diffNode =
programDiff.makeNode(name: name, parent: diffNode, type: type);
}
- diffNode.size ??= 0;
- diffNode.size += (newNode?.size ?? 0) - (oldNode?.size ?? 0);
+ diffNode.size =
+ (diffNode.size ?? 0) + (newNode?.size ?? 0) - (oldNode?.size ?? 0);
}
for (var key in _allKeys(newNode?.children, oldNode?.children)) {
final newChildNode = newNode != null ? newNode.children[key] : null;
final oldChildNode = oldNode != null ? oldNode.children[key] : null;
path.add(key);
- path.add(oldChildNode?.type ?? newChildNode?.type);
+ path.add((oldChildNode?.type ?? newChildNode?.type)!);
recurse(oldChildNode, newChildNode);
path.removeLast();
path.removeLast();
@@ -244,7 +243,7 @@
return programDiff;
}
-Iterable<T> _allKeys<T>(Map<T, dynamic> a, Map<T, dynamic> b) {
+Iterable<T> _allKeys<T>(Map<T, dynamic>? a, Map<T, dynamic>? b) {
return <T>{...?a?.keys, ...?b?.keys};
}
@@ -267,14 +266,14 @@
Histogram._(this.bucketInfo, this.buckets)
: bySize = buckets.keys.toList(growable: false)
- ..sort((a, b) => buckets[b] - buckets[a]),
+ ..sort((a, b) => buckets[b]! - buckets[a]!),
totalSize = buckets.values.fold(0, (sum, size) => sum + size);
static Histogram fromIterable<T>(
Iterable<T> entries, {
- @required int Function(T) sizeOf,
- @required String Function(T) bucketFor,
- @required BucketInfo bucketInfo,
+ required int Function(T) sizeOf,
+ required String Function(T) bucketFor,
+ required BucketInfo bucketInfo,
}) {
final buckets = <String, int>{};
@@ -290,20 +289,26 @@
/// Rebuckets the histogram given the new bucketing rule.
Histogram map(String Function(String) bucketFor) {
return Histogram.fromIterable(buckets.keys,
- sizeOf: (key) => buckets[key],
+ sizeOf: (key) => buckets[key]!,
bucketFor: bucketFor,
bucketInfo: bucketInfo);
}
}
/// Construct the histogram of specific [type] given a [ProgramInfo].
+///
+/// [filter] glob can be provided to skip some of the nodes in the [info]:
+/// a string is created which contains library name, class name and function
+/// name for the given node and if this string does not match the [filter]
+/// glob then this node is ignored.
Histogram computeHistogram(ProgramInfo info, HistogramType type,
- {String filter}) {
- bool Function(String, String, String) matchesFilter;
+ {String? filter}) {
+ bool Function(String, String?, String?) matchesFilter;
if (filter != null) {
final re = RegExp(filter.replaceAll('*', '.*'), caseSensitive: false);
- matchesFilter = (lib, cls, fun) => re.hasMatch("${lib}::${cls}.${fun}");
+ matchesFilter =
+ (lib, cls, fun) => re.hasMatch("${lib}::${cls ?? ''}.${fun ?? ''}");
} else {
matchesFilter = (_, __, ___) => true;
}
@@ -318,10 +323,12 @@
});
}
+ final snapshotInfo = info.snapshotInfo!;
+
return Histogram.fromIterable<Node>(
- info.snapshotInfo.snapshot.nodes.where((n) =>
+ snapshotInfo.snapshot.nodes.where((n) =>
filter == null ||
- filteredNodes.contains(info.snapshotInfo.ownerOf(n).id)),
+ filteredNodes.contains(snapshotInfo.ownerOf(n).id)),
sizeOf: (n) {
return n.selfSize;
},
@@ -329,17 +336,18 @@
bucketInfo: const BucketInfo(nameComponents: ['Type']));
} else {
final buckets = <String, int>{};
- final bucketing = Bucketing._forType[type];
+ final bucketing = Bucketing._forType[type]!;
info.visit((pkg, lib, cls, fun, node) {
- if (node.size == null || node.size == 0) {
+ final sz = node.size;
+ if (sz == null || sz == 0) {
return;
}
if (!matchesFilter(lib, cls, fun)) {
return;
}
final bucket = bucketing.bucketFor(pkg, lib, cls, fun);
- buckets[bucket] = (buckets[bucket] ?? 0) + node.size;
+ buckets[bucket] = (buckets[bucket] ?? 0) + sz;
});
return Histogram._(bucketing, buckets);
@@ -363,15 +371,15 @@
/// one returned by [nameComponents]).
List<String> namesFromBucket(String bucket) => [bucket];
- const BucketInfo({@required this.nameComponents});
+ const BucketInfo({required this.nameComponents});
}
abstract class Bucketing extends BucketInfo {
/// Constructs the bucket name from the given library name [lib], class name
/// [cls] and function name [fun].
- String bucketFor(String pkg, String lib, String cls, String fun);
+ String bucketFor(String? pkg, String lib, String? cls, String? fun);
- const Bucketing({@required List<String> nameComponents})
+ const Bucketing({required List<String> nameComponents})
: super(nameComponents: nameComponents);
static const _forType = {
@@ -387,11 +395,11 @@
class _BucketBySymbol extends Bucketing {
@override
- String bucketFor(String pkg, String lib, String cls, String fun) {
+ String bucketFor(String? pkg, String lib, String? cls, String? fun) {
if (fun == null) {
return '@other${_nameSeparator}';
}
- return '$lib${_nameSeparator}${cls}${cls != '' ? '.' : ''}${fun}';
+ return '$lib${_nameSeparator}${cls ?? ''}${cls != '' && cls != null ? '.' : ''}${fun}';
}
@override
@@ -402,7 +410,7 @@
class _BucketByClass extends Bucketing {
@override
- String bucketFor(String pkg, String lib, String cls, String fun) {
+ String bucketFor(String? pkg, String lib, String? cls, String? fun) {
if (cls == null) {
return '@other${_nameSeparator}';
}
@@ -417,14 +425,14 @@
class _BucketByLibrary extends Bucketing {
@override
- String bucketFor(String pkg, String lib, String cls, String fun) => '$lib';
+ String bucketFor(String? pkg, String lib, String? cls, String? fun) => '$lib';
const _BucketByLibrary() : super(nameComponents: const ['Library']);
}
class _BucketByPackage extends Bucketing {
@override
- String bucketFor(String pkg, String lib, String cls, String fun) =>
+ String bucketFor(String? pkg, String lib, String? cls, String? fun) =>
pkg ?? lib;
const _BucketByPackage() : super(nameComponents: const ['Package']);
diff --git a/pkg/vm_snapshot_analysis/lib/src/commands/compare.dart b/pkg/vm_snapshot_analysis/lib/src/commands/compare.dart
index 4a9442e..bb2bdaf 100644
--- a/pkg/vm_snapshot_analysis/lib/src/commands/compare.dart
+++ b/pkg/vm_snapshot_analysis/lib/src/commands/compare.dart
@@ -64,23 +64,25 @@
@override
Future<void> run() async {
- if (argResults.rest.length != 2) {
+ final args = argResults!;
+
+ if (args.rest.length != 2) {
usageException('Need to provide path to old.json and new.json reports.');
}
- final columnWidth = argResults['column-width'];
+ final columnWidth = args['column-width'];
final maxWidth = int.tryParse(columnWidth);
if (maxWidth == null) {
usageException(
'Specified column width (${columnWidth}) is not an integer');
}
- final oldJsonPath = _checkExists(argResults.rest[0]);
- final newJsonPath = _checkExists(argResults.rest[1]);
+ final oldJsonPath = _checkExists(args.rest[0]);
+ final newJsonPath = _checkExists(args.rest[1]);
printComparison(oldJsonPath, newJsonPath,
maxWidth: maxWidth,
- granularity: _parseHistogramType(argResults['by']),
- collapseAnonymousClosures: argResults['collapse-anonymous-closures']);
+ granularity: _parseHistogramType(args['by']),
+ collapseAnonymousClosures: args['collapse-anonymous-closures']);
}
HistogramType _parseHistogramType(String value) {
@@ -93,8 +95,9 @@
return HistogramType.byLibrary;
case 'package':
return HistogramType.byPackage;
+ default:
+ usageException('Unrecognized histogram type $value');
}
- return null;
}
File _checkExists(String path) {
@@ -136,10 +139,10 @@
printHistogram(diff, histogram,
sizeHeader: 'Diff (Bytes)',
prefix: histogram.bySize
- .where((k) => histogram.buckets[k] > 0)
+ .where((k) => histogram.buckets[k]! > 0)
.take(numLargerSymbolsToReport),
suffix: histogram.bySize.reversed
- .where((k) => histogram.buckets[k] < 0)
+ .where((k) => histogram.buckets[k]! < 0)
.take(numSmallerSymbolsToReport)
.toList()
.reversed,
@@ -159,7 +162,7 @@
final newTypeHistogram =
computeHistogram(newSizes, HistogramType.byNodeType);
- final diffTypeHistogram = Histogram.fromIterable(
+ final diffTypeHistogram = Histogram.fromIterable<String>(
Set<String>()
..addAll(oldTypeHistogram.buckets.keys)
..addAll(newTypeHistogram.buckets.keys),
diff --git a/pkg/vm_snapshot_analysis/lib/src/commands/explain.dart b/pkg/vm_snapshot_analysis/lib/src/commands/explain.dart
index 33c1418..e81833f 100644
--- a/pkg/vm_snapshot_analysis/lib/src/commands/explain.dart
+++ b/pkg/vm_snapshot_analysis/lib/src/commands/explain.dart
@@ -53,13 +53,15 @@
@override
Future<void> run() async {
- final sizesJson = File(argResults.rest[0]);
+ final args = argResults!;
+
+ final sizesJson = File(args.rest[0]);
if (!sizesJson.existsSync()) {
usageException('Size profile ${sizesJson.path} does not exist!');
}
final sizesJsonRaw = await loadJsonFromFile(sizesJson);
- final traceJson = File(argResults.rest[1]);
+ final traceJson = File(args.rest[1]);
if (!traceJson.existsSync()) {
usageException('Size profile ${traceJson.path} does not exist!');
}
@@ -103,7 +105,7 @@
}, bucketInfo: BucketInfo(nameComponents: ['Selector']));
printHistogram(programInfo, histogram,
- prefix: histogram.bySize.where((key) => histogram.buckets[key] > 0));
+ prefix: histogram.bySize.where((key) => histogram.buckets[key]! > 0));
// For top 10 dynamic selectors print the functions which contain these
// dynamic calls.
diff --git a/pkg/vm_snapshot_analysis/lib/src/commands/summary.dart b/pkg/vm_snapshot_analysis/lib/src/commands/summary.dart
index 13854d2..90b87b9 100644
--- a/pkg/vm_snapshot_analysis/lib/src/commands/summary.dart
+++ b/pkg/vm_snapshot_analysis/lib/src/commands/summary.dart
@@ -12,7 +12,6 @@
import 'dart:math' as math;
import 'package:args/command_runner.dart';
-import 'package:meta/meta.dart';
import 'package:vm_snapshot_analysis/ascii_table.dart';
import 'package:vm_snapshot_analysis/precompiler_trace.dart';
@@ -95,18 +94,20 @@
@override
Future<void> run() async {
- if (argResults.rest.length != 1) {
+ final args = argResults!;
+
+ if (args.rest.length != 1) {
usageException('Need to specify input JSON.');
}
- final input = File(argResults.rest[0]);
+ final input = File(args.rest[0]);
if (!input.existsSync()) {
usageException('Input file ${input.path} does not exist!');
}
- final granularity = _parseHistogramType(argResults['by']);
+ final granularity = _parseHistogramType(args['by']);
- final traceJson = argResults['precompiler-trace'];
+ final traceJson = args['precompiler-trace'];
if (traceJson != null) {
if (!File(traceJson).existsSync()) {
usageException('Trace ${traceJson} does not exist!');
@@ -119,21 +120,21 @@
}
}
- final columnWidth = argResults['column-width'];
+ final columnWidth = args['column-width'];
final maxWidth = int.tryParse(columnWidth);
if (maxWidth == null) {
usageException(
'Specified column width (${columnWidth}) is not an integer');
}
- final depsStartDepthStr = argResults['deps-start-depth'];
+ final depsStartDepthStr = args['deps-start-depth'];
final depsStartDepth = int.tryParse(depsStartDepthStr);
if (depsStartDepth == null) {
usageException('Specified depsStartDepth (${depsStartDepthStr})'
' is not an integer');
}
- final depsDisplayDepthStr = argResults['deps-display-depth'];
+ final depsDisplayDepthStr = args['deps-display-depth'];
final depsDisplayDepth = int.tryParse(depsDisplayDepthStr);
if (depsDisplayDepth == null) {
usageException('Specified depsDisplayDepth (${depsStartDepthStr})'
@@ -143,14 +144,14 @@
await outputSummary(input,
maxWidth: maxWidth,
granularity: granularity,
- collapseAnonymousClosures: argResults['collapse-anonymous-closures'],
- filter: argResults['where'],
+ collapseAnonymousClosures: args['collapse-anonymous-closures'],
+ filter: args['where'],
traceJson: traceJson != null ? File(traceJson) : null,
depsStartDepth: depsStartDepth,
depsDisplayDepth: depsDisplayDepth);
}
- static HistogramType _parseHistogramType(String value) {
+ HistogramType _parseHistogramType(String value) {
switch (value) {
case 'method':
return HistogramType.bySymbol;
@@ -160,17 +161,18 @@
return HistogramType.byLibrary;
case 'package':
return HistogramType.byPackage;
+ default:
+ usageException('Unrecognized histogram type $value');
}
- return null;
}
}
-void outputSummary(File input,
+Future<void> outputSummary(File input,
{int maxWidth = 0,
bool collapseAnonymousClosures = false,
HistogramType granularity = HistogramType.bySymbol,
- String filter,
- File traceJson,
+ String? filter,
+ File? traceJson,
int depsStartDepth = 2,
int depsDisplayDepth = 4,
int topToReport = 30}) async {
@@ -182,7 +184,7 @@
// If precompiler trace is provided, collapse entries based on the dependency
// graph (dominator tree) extracted from the trace.
- void Function() printDependencyTrees;
+ void Function()? printDependencyTrees;
if (traceJson != null &&
(granularity == HistogramType.byLibrary ||
granularity == HistogramType.byPackage)) {
@@ -235,8 +237,8 @@
var totalCount = 1;
for (var n in node.dominated) {
computeTotalsRecursively(n);
- totalSize += totalSizes[n.data.name];
- totalCount += totalCounts[n.data.name];
+ totalSize += totalSizes[n.data.name]!;
+ totalCount += totalCounts[n.data.name]!;
}
totalSizes[node.data.name] = totalSize;
totalCounts[node.data.name] = totalCount;
@@ -255,7 +257,7 @@
final collapsedEntries = histogram.bySize
.take(topToReport)
.map((k) => collapsed[k])
- .where((n) => n != null);
+ .whereType<CallGraphNode>();
if (collapsedEntries.isNotEmpty) {
print('\bDependency trees:');
for (var n in collapsedEntries) {
@@ -302,9 +304,9 @@
void _printDominatedNodes(CallGraphNode node,
{int displayDepth = 4,
int maxChildrenToPrint = 10,
- List<bool> isLastPerLevel,
- @required Map<String, int> totalSizes,
- @required Map<String, int> totalCounts}) {
+ List<bool>? isLastPerLevel,
+ required Map<String, int> totalSizes,
+ required Map<String, int> totalCounts}) {
isLastPerLevel ??= [];
// Subtract one to account for the parent node that is printed before the
@@ -315,8 +317,8 @@
final sizes = node.dominated.map((n) => totalSizes[n.data.name]).toList();
final order = List.generate(node.dominated.length, (i) => i)
- ..sort((a, b) => sizes[b] - sizes[a]);
- final lastIndex = order.lastIndexWhere((i) => sizes[i] > 0);
+ ..sort((a, b) => sizes[b]! - sizes[a]!);
+ final lastIndex = order.lastIndexWhere((i) => sizes[i]! > 0);
for (var j = 0, n = math.min(maxChildrenToPrint - 1, lastIndex);
j <= n;
@@ -339,7 +341,7 @@
if (maxChildrenToPrint < lastIndex) {
isLastPerLevel.add(true);
print(
- '${_treeLines(isLastPerLevel)} ... (+${totalCounts[node.data.name] - 1} deps)');
+ '${_treeLines(isLastPerLevel)} ... (+${totalCounts[node.data.name]! - 1} deps)');
isLastPerLevel.removeLast();
}
}
diff --git a/pkg/vm_snapshot_analysis/lib/src/commands/treemap.dart b/pkg/vm_snapshot_analysis/lib/src/commands/treemap.dart
index 059d353..2de0694 100644
--- a/pkg/vm_snapshot_analysis/lib/src/commands/treemap.dart
+++ b/pkg/vm_snapshot_analysis/lib/src/commands/treemap.dart
@@ -56,24 +56,27 @@
@override
Future<void> run() async {
- if (argResults.rest.length != 2) {
+ final args = argResults!;
+
+ if (args.rest.length != 2) {
usageException('Need to specify input JSON and output directory.');
}
- final input = File(argResults.rest[0]);
- final outputDir = Directory(argResults.rest[1]);
+ final input = File(args.rest[0]);
+ final outputDir = Directory(args.rest[1]);
if (!input.existsSync()) {
usageException('Input file ${input.path} does not exist!');
}
- if (outputDir.existsSync() && !argResults['force']) {
+ if (outputDir.existsSync() && !args['force']) {
usageException(
'Output directory ${outputDir.path} already exists, specify --force to ignore.');
}
await generateTreeMap(input, outputDir,
- format: _formatFromString[argResults['format']]);
+ format: _formatFromString[args['format']] ??
+ (throw 'Unrecognized format ${args['format']}'));
}
// Note: the first key in this map is the default format.
@@ -95,8 +98,8 @@
// Create output directory and copy all auxiliary files from binary_size tool.
await outputDir.create(recursive: true);
- final assetsUri = await Isolate.resolvePackageUri(
- Uri.parse('package:vm_snapshot_analysis/src/assets'));
+ final assetsUri = (await Isolate.resolvePackageUri(
+ Uri.parse('package:vm_snapshot_analysis/src/assets')))!;
final assetsDir = assetsUri.toFilePath();
final d3SrcDir = p.join(assetsDir, 'd3', 'src');
@@ -114,7 +117,7 @@
final dataJsPath = p.join(outputDir.path, 'data.js');
final sink = File(dataJsPath).openWrite();
sink.write('var tree_data=');
- await sink.addStream(Stream<Object>.fromIterable([tree])
+ await sink.addStream(Stream<Object?>.fromIterable([tree])
.transform(json.encoder.fuse(utf8.encoder)));
await sink.close();
diff --git a/pkg/vm_snapshot_analysis/lib/src/commands/utils.dart b/pkg/vm_snapshot_analysis/lib/src/commands/utils.dart
index f6a5bbe..c73dab8 100644
--- a/pkg/vm_snapshot_analysis/lib/src/commands/utils.dart
+++ b/pkg/vm_snapshot_analysis/lib/src/commands/utils.dart
@@ -6,9 +6,9 @@
import 'dart:io';
Future<Object> loadJsonFromFile(File input) async {
- return await input
+ return (await input
.openRead()
.transform(utf8.decoder)
.transform(json.decoder)
- .first;
+ .first)!;
}
diff --git a/pkg/vm_snapshot_analysis/lib/src/dominators.dart b/pkg/vm_snapshot_analysis/lib/src/dominators.dart
index 5e9078f..92504f3 100644
--- a/pkg/vm_snapshot_analysis/lib/src/dominators.dart
+++ b/pkg/vm_snapshot_analysis/lib/src/dominators.dart
@@ -13,16 +13,16 @@
/// native compiler (see runtime/vm/compiler/backend/flow_graph.cc).
@pragma('vm:prefer-inline')
List<int> computeDominators({
- int size,
- int root,
- Iterable<int> succ(int n),
- Iterable<int> predOf(int n),
- void handleEdge(int from, int to),
+ required int size,
+ required int root,
+ required Iterable<int> Function(int) succ,
+ required Iterable<int> Function(int) predOf,
+ required void handleEdge(int from, int to),
}) {
// Compute preorder numbering for the graph using DFS.
final parent = List<int>.filled(size, -1);
- final preorder = List<int>.filled(size, null);
- final preorderNumber = List<int>.filled(size, null);
+ final preorder = List<int>.filled(size, -1);
+ final preorderNumber = List<int>.filled(size, -1);
var N = 0;
void dfs() {
@@ -32,7 +32,7 @@
final p = s.p;
final n = s.n;
handleEdge(s.n, s.p);
- if (preorderNumber[n] == null) {
+ if (preorderNumber[n] == -1) {
preorderNumber[n] = N;
preorder[preorderNumber[n]] = n;
parent[preorderNumber[n]] = p;
@@ -122,5 +122,5 @@
class _DfsState {
final int p;
final int n;
- _DfsState({this.p, this.n});
+ _DfsState({required this.p, required this.n});
}
diff --git a/pkg/vm_snapshot_analysis/lib/treemap.dart b/pkg/vm_snapshot_analysis/lib/treemap.dart
index c0535e7..2d6da72 100644
--- a/pkg/vm_snapshot_analysis/lib/treemap.dart
+++ b/pkg/vm_snapshot_analysis/lib/treemap.dart
@@ -82,10 +82,11 @@
final root = {'n': '', 'children': {}, 'k': kindPath, 'maxDepth': 0};
if (v8_profile.Snapshot.isV8HeapSnapshot(inputJson)) {
- _treemapFromSnapshot(root, v8_profile.Snapshot.fromJson(inputJson),
+ _treemapFromSnapshot(
+ root, v8_profile.Snapshot.fromJson(inputJson as Map<String, dynamic>),
format: format);
} else {
- final symbols = instruction_sizes.fromJson(inputJson);
+ final symbols = instruction_sizes.fromJson(inputJson as List<dynamic>);
for (var symbol in symbols) {
_addSymbol(root, _treePath(symbol), symbol.name.scrubbed, symbol.size);
}
@@ -163,20 +164,22 @@
return;
}
+ final snapshotInfo = info.snapshotInfo!;
+
final ownerPathCache =
- List<String>.filled(info.snapshotInfo.infoNodes.length, null);
+ List<String?>.filled(snapshotInfo.infoNodes.length, null);
ownerPathCache[info.root.id] = info.root.name;
String ownerPath(ProgramInfoNode n) {
- return ownerPathCache[n.id] ??=
- ((n.parent != info.root) ? '${ownerPath(n.parent)}/${n.name}' : n.name);
+ return ownerPathCache[n.id] ??= ((n.parent != info.root)
+ ? '${ownerPath(n.parent!)}/${n.name}'
+ : n.name);
}
- final nameFormatter = _nameFormatters[format];
-
+ final nameFormatter = _nameFormatters[format]!;
for (var node in snap.nodes) {
if (node.selfSize > 0) {
- final owner = info.snapshotInfo.ownerOf(node);
+ final owner = snapshotInfo.ownerOf(node);
final name = nameFormatter(node);
final path = ownerPath(owner);
@@ -227,7 +230,7 @@
}
/// Add the given symbol to the tree.
-void _addSymbol(Map<String, dynamic> root, String path, String name, int size,
+void _addSymbol(Map<String, dynamic> root, String path, String name, int? size,
{String symbolType = symbolTypeGlobalText}) {
if (size == null || size == 0) {
return;
diff --git a/pkg/vm_snapshot_analysis/lib/utils.dart b/pkg/vm_snapshot_analysis/lib/utils.dart
index abf3eb3..40ef457 100644
--- a/pkg/vm_snapshot_analysis/lib/utils.dart
+++ b/pkg/vm_snapshot_analysis/lib/utils.dart
@@ -13,10 +13,11 @@
ProgramInfo loadProgramInfoFromJson(Object json,
{bool collapseAnonymousClosures = false}) {
if (v8_profile.Snapshot.isV8HeapSnapshot(json)) {
- return v8_profile.toProgramInfo(v8_profile.Snapshot.fromJson(json),
+ return v8_profile.toProgramInfo(
+ v8_profile.Snapshot.fromJson(json as Map<String, dynamic>),
collapseAnonymousClosures: collapseAnonymousClosures);
} else {
- return instruction_sizes.loadProgramInfo(json,
+ return instruction_sizes.loadProgramInfo(json as List<dynamic>,
collapseAnonymousClosures: collapseAnonymousClosures);
}
}
@@ -62,7 +63,7 @@
final visibleRows = [prefix, suffix].expand((l) => l).toList();
final visibleSize =
- visibleRows.fold(0, (sum, key) => sum + histogram.buckets[key]);
+ visibleRows.fold<int>(0, (sum, key) => sum + histogram.buckets[key]!);
final numRestRows = histogram.length - (suffix.length + prefix.length);
final hiddenRows = Set<String>.from(histogram.bySize)
.difference(Set<String>.from(visibleRows));
@@ -71,7 +72,7 @@
if (prefix.isNotEmpty) {
for (var key in prefix) {
- final size = histogram.buckets[key];
+ final size = histogram.buckets[key]!;
table.addRow([
...histogram.bucketInfo.namesFromBucket(key),
size.toString(),
@@ -99,7 +100,7 @@
table.addRow([
...histogram.bucketInfo.namesFromBucket(key),
histogram.buckets[key].toString(),
- formatPercent(histogram.buckets[key], histogram.totalSize),
+ formatPercent(histogram.buckets[key]!, histogram.totalSize),
]);
}
table.addSeparator(Separator.Line);
diff --git a/pkg/vm_snapshot_analysis/lib/v8_profile.dart b/pkg/vm_snapshot_analysis/lib/v8_profile.dart
index cbbe717..7dde867 100644
--- a/pkg/vm_snapshot_analysis/lib/v8_profile.dart
+++ b/pkg/vm_snapshot_analysis/lib/v8_profile.dart
@@ -6,7 +6,7 @@
/// produced by `--write-v8-snapshot-profile-to` VM flag.
library vm_snapshot_analysis.v8_profile;
-import 'package:meta/meta.dart';
+import 'package:collection/collection.dart';
import 'package:vm_snapshot_analysis/src/dominators.dart' as dominators;
import 'package:vm_snapshot_analysis/name.dart';
@@ -35,7 +35,7 @@
/// for the given node index.
final List<int> _edgesStartIndexForNode;
- List<int> _dominators;
+ late final List<int> _dominators = _computeDominators(this);
final List strings;
@@ -53,7 +53,6 @@
/// Return dominator node for the given node [n].
Node dominatorOf(Node n) {
- _dominators ??= _computeDominators(this);
return nodeAt(_dominators[n.index]);
}
@@ -67,7 +66,7 @@
// Extract meta information first.
final meta = Meta._fromJson(m['snapshot']['meta']);
- final nodes = m['nodes'];
+ final nodes = (m['nodes'] as List<dynamic>).cast<int>();
// Build an array of starting indexes of edges for each node.
final edgesStartIndexForNode = <int>[0];
@@ -130,18 +129,18 @@
final List<String> edgeTypes;
Meta._(
- {this.nodeTypeIndex,
- this.nodeNameIndex,
- this.nodeIdIndex,
- this.nodeSelfSizeIndex,
- this.nodeEdgeCountIndex,
- this.nodeFieldCount,
- this.edgeTypeIndex,
- this.edgeNameOrIndexIndex,
- this.edgeToNodeIndex,
- this.edgeFieldCount,
- this.nodeTypes,
- this.edgeTypes});
+ {required this.nodeTypeIndex,
+ required this.nodeNameIndex,
+ required this.nodeIdIndex,
+ required this.nodeSelfSizeIndex,
+ required this.nodeEdgeCountIndex,
+ required this.nodeFieldCount,
+ required this.edgeTypeIndex,
+ required this.edgeNameOrIndexIndex,
+ required this.edgeToNodeIndex,
+ required this.edgeFieldCount,
+ required this.nodeTypes,
+ required this.edgeTypes});
factory Meta._fromJson(Map<String, dynamic> m) {
final nodeFields = m['node_fields'];
@@ -171,7 +170,7 @@
/// Index of this [Edge] within the [snapshot].
final int index;
- Edge._({this.snapshot, this.index});
+ Edge._({required this.snapshot, required this.index});
String get type => snapshot
.meta.edgeTypes[snapshot._edges[_offset + snapshot.meta.edgeTypeIndex]];
@@ -212,7 +211,7 @@
/// Index of this [Node] within the [snapshot].
final int index;
- Node._({this.snapshot, this.index});
+ Node._({required this.snapshot, required this.index});
int get edgeCount =>
snapshot._nodes[_offset + snapshot.meta.nodeEdgeCountIndex];
@@ -248,10 +247,8 @@
}
/// Returns the target of an outgoing edge with the given name (if any).
- Node operator [](String edgeName) => this
- .edges
- .firstWhere((e) => e.name == edgeName, orElse: () => null)
- ?.target;
+ Node? operator [](String edgeName) =>
+ this.edges.firstWhereOrNull((e) => e.name == edgeName)?.target;
@override
bool operator ==(Object other) {
@@ -317,7 +314,7 @@
/// See [findCommonAncestor] method.
final Map<int, int> commonAncestorCache = {};
- _ProgramInfoBuilder({this.collapseAnonymousClosures});
+ _ProgramInfoBuilder({required this.collapseAnonymousClosures});
/// Recover [ProgramInfo] structure from the snapshot profile.
///
@@ -372,7 +369,7 @@
return program;
}
- ProgramInfoNode getInfoNodeFor(Node node) {
+ ProgramInfoNode? getInfoNodeFor(Node node) {
var info = infoNodeByIndex[node.index];
if (info == null) {
info = createInfoNodeFor(node);
@@ -390,7 +387,7 @@
switch (node.type) {
case 'Code':
// Freeze ownership of the Instructions object.
- final instructions = node['<instructions>'];
+ final instructions = node['<instructions>']!;
nodesWithFrozenOwner.add(instructions.index);
ownerOf[instructions.index] =
findCommonAncestor(ownerOf[instructions.index], info.id);
@@ -403,7 +400,7 @@
if (e.target.type == 'Script') {
nodesWithFrozenOwner.add(e.target.index);
ownerOf[e.target.index] =
- findCommonAncestor(ownerOf[e.target.index], info.id);
+ findCommonAncestor(ownerOf[e.target.index]!, info.id);
}
}
}
@@ -414,13 +411,13 @@
return info;
}
- ProgramInfoNode createInfoNodeFor(Node node) {
+ ProgramInfoNode? createInfoNodeFor(Node node) {
switch (node.type) {
case 'Code':
- var owner = node['owner_'];
+ final owner = node['owner_']!;
if (owner.type != 'Type') {
final ownerNode =
- owner.type == 'Null' ? program.stubs : getInfoNodeFor(owner);
+ owner.type == 'Null' ? program.stubs : getInfoNodeFor(owner)!;
if (owner.type == 'Function') {
// For normal functions we just attribute Code object and all
// objects dominated by it to the function itself.
@@ -436,29 +433,29 @@
case 'Function':
if (node.name != '<anonymous signature>') {
- var owner = node['owner_'];
+ var owner = node['owner_']!;
// Artificial nodes may not have a data_ field.
var data = node['data_'];
- if (data?.type == 'ClosureData') {
- owner = data['parent_function_'];
+ if (data != null && data.type == 'ClosureData') {
+ owner = data['parent_function_']!;
}
return makeInfoNode(node.index,
name: node.name,
- parent: getInfoNodeFor(owner),
+ parent: getInfoNodeFor(owner)!,
type: NodeType.functionNode);
}
break;
case 'PatchClass':
- return getInfoNodeFor(node['patched_class_']);
+ return getInfoNodeFor(node['patched_class_']!);
case 'Class':
// Default to root node. Some builtin classes (void, dynamic) don't have
// any information about their library written out.
var ownerNode = program.root;
if (node['library_'] != null) {
- ownerNode = getInfoNodeFor(node['library_']) ?? ownerNode;
+ ownerNode = getInfoNodeFor(node['library_']!) ?? ownerNode;
}
return makeInfoNode(node.index,
@@ -477,20 +474,16 @@
case 'Field':
return makeInfoNode(node.index,
name: node.name,
- parent: getInfoNodeFor(node['owner_']),
+ parent: getInfoNodeFor(node['owner_']!)!,
type: NodeType.other);
}
return null;
}
- ProgramInfoNode makeInfoNode(int index,
- {@required ProgramInfoNode parent,
- @required String name,
- @required NodeType type}) {
- assert(parent != null,
- 'Trying to create node of type ${type} with ${name} and no parent.');
- assert(name != null);
-
+ ProgramInfoNode makeInfoNode(int? index,
+ {required ProgramInfoNode parent,
+ required String name,
+ required NodeType type}) {
name = Name(name).scrubbed;
if (collapseAnonymousClosures) {
name = Name.collapse(name);
@@ -527,10 +520,10 @@
}
/// Returns id of a common ancestor between [ProgramInfoNode] with [idA] and
- /// [idB].
- int findCommonAncestor(int idA, int idB) {
+ /// [idB]. At least either [idA] or [idB] are expected to be not null.
+ int findCommonAncestor(int? idA, int? idB) {
if (idA == null) {
- return idB;
+ return idB!;
}
if (idB == null) {
return idA;
@@ -558,9 +551,8 @@
static List<ProgramInfoNode> pathToRoot(ProgramInfoNode node) {
final path = <ProgramInfoNode>[];
- while (node != null) {
- path.add(node);
- node = node.parent;
+ for (ProgramInfoNode? n = node; n != null; n = n.parent) {
+ path.add(n);
}
return path;
}
@@ -609,14 +601,15 @@
/// The code for dominator tree computation is taken verbatim from the
/// native compiler (see runtime/vm/compiler/backend/flow_graph.cc).
List<int> _computeDominators(Snapshot snap) {
- final predecessors = List<Object>.filled(snap.nodeCount, null);
+ final predecessors = List<Object?>.filled(snap.nodeCount, null);
void addPred(int n, int p) {
- if (predecessors[n] == null) {
+ final pred = predecessors[n];
+ if (pred == null) {
predecessors[n] = p;
- } else if (predecessors[n] is int) {
- predecessors[n] = <int>[predecessors[n], p];
+ } else if (pred is int) {
+ predecessors[n] = <int>[pred, p];
} else {
- (predecessors[n] as List<int>).add(p);
+ (pred as List<int>).add(p);
}
}
diff --git a/pkg/vm_snapshot_analysis/pubspec.yaml b/pkg/vm_snapshot_analysis/pubspec.yaml
index 5b75e91..3a37d38 100644
--- a/pkg/vm_snapshot_analysis/pubspec.yaml
+++ b/pkg/vm_snapshot_analysis/pubspec.yaml
@@ -5,7 +5,7 @@
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/vm_snapshot_analysis
environment:
- sdk: '>=2.8.0 <3.0.0'
+ sdk: '>=2.12.0 <3.0.0'
executables:
snapshot_analysis: analyse
@@ -13,7 +13,7 @@
dependencies:
args: ^2.0.0
path: ^1.8.0
- meta: ^1.3.0
+ collection: ^1.15.0
dev_dependencies:
pedantic: ^1.11.0
diff --git a/pkg/vm_snapshot_analysis/test/instruction_sizes_test.dart b/pkg/vm_snapshot_analysis/test/instruction_sizes_test.dart
index 5347acc..16b2504 100644
--- a/pkg/vm_snapshot_analysis/test/instruction_sizes_test.dart
+++ b/pkg/vm_snapshot_analysis/test/instruction_sizes_test.dart
@@ -5,6 +5,8 @@
import 'dart:io';
import 'package:test/test.dart';
+import 'package:collection/collection.dart';
+
import 'package:vm_snapshot_analysis/instruction_sizes.dart'
as instruction_sizes;
import 'package:vm_snapshot_analysis/program_info.dart';
@@ -242,7 +244,7 @@
test('basic-parsing', () async {
await withSymbolSizes(testSource, (sizesJson) async {
final json = await loadJson(File(sizesJson));
- final symbols = instruction_sizes.fromJson(json);
+ final symbols = instruction_sizes.fromJson(json as List<dynamic>);
expect(symbols, isNotNull,
reason: 'Sizes file was successfully parsed');
expect(symbols.length, greaterThan(0),
@@ -254,7 +256,7 @@
final symbolScrubbedNames = <String, Map<String, Set<String>>>{};
Set<String> getSetOfNames(Map<String, Map<String, Set<String>>> map,
- String libraryUri, String className) {
+ String? libraryUri, String? className) {
return map
.putIfAbsent(libraryUri ?? '', () => {})
.putIfAbsent(className ?? '', () => {});
@@ -280,10 +282,12 @@
expect(inputDartSymbolNames, isNotNull,
reason: 'Symbols from input.dart are included into sizes output');
+ inputDartSymbolNames!; // Checked above. Promote the variable type.
+
expect(inputDartSymbolNames[''], isNotNull,
reason: 'Should include top-level members from input.dart');
expect(inputDartSymbolNames[''], contains('makeSomeClosures'));
- final closures = inputDartSymbolNames[''].where(
+ final closures = inputDartSymbolNames['']!.where(
(name) => name.startsWith('makeSomeClosures.<anonymous closure'));
expect(closures.length, 3,
reason: 'There are three closures inside makeSomeClosure');
@@ -311,7 +315,7 @@
expect(inputDartSymbolNames['D'], contains('[tear-off] tornOff'));
// Check that output does not contain '[unknown stub]'
- expect(symbolRawNames[''][''], isNot(contains('[unknown stub]')),
+ expect(symbolRawNames['']![''], isNot(contains('[unknown stub]')),
reason: 'All stubs must be named');
});
});
@@ -324,19 +328,18 @@
expect(info.root.children, contains('dart:typed_data'));
expect(info.root.children, contains('package:input'));
- final inputLib = info.root.children['package:input']
- .children['package:input/input.dart'];
- expect(inputLib, isNotNull);
+ final inputLib = info.root.children['package:input']!
+ .children['package:input/input.dart']!;
expect(inputLib.children, contains('')); // Top-level class.
expect(inputLib.children, contains('A'));
expect(inputLib.children, contains('B'));
expect(inputLib.children, contains('C'));
expect(inputLib.children, contains('D'));
- final topLevel = inputLib.children[''];
+ final topLevel = inputLib.children['']!;
expect(topLevel.children, contains('makeSomeClosures'));
expect(
- topLevel.children['makeSomeClosures'].children.length, equals(3));
+ topLevel.children['makeSomeClosures']!.children.length, equals(3));
for (var name in [
'[tear-off] tornOff',
@@ -344,8 +347,8 @@
'Allocate A',
'[tear-off-extractor] get:tornOff'
]) {
- expect(inputLib.children['A'].children, contains(name));
- expect(inputLib.children['A'].children[name].children, isEmpty);
+ expect(inputLib.children['A']!.children, contains(name));
+ expect(inputLib.children['A']!.children[name]!.children, isEmpty);
}
for (var name in [
@@ -354,13 +357,13 @@
'Allocate B',
'[tear-off-extractor] get:tornOff'
]) {
- expect(inputLib.children['B'].children, contains(name));
- expect(inputLib.children['B'].children[name].children, isEmpty);
+ expect(inputLib.children['B']!.children, contains(name));
+ expect(inputLib.children['B']!.children[name]!.children, isEmpty);
}
for (var name in ['tornOff{body}', 'tornOff', '[tear-off] tornOff']) {
- expect(inputLib.children['C'].children, contains(name));
- expect(inputLib.children['C'].children[name].children, isEmpty);
+ expect(inputLib.children['C']!.children, contains(name));
+ expect(inputLib.children['C']!.children[name]!.children, isEmpty);
}
for (var name in [
@@ -369,8 +372,8 @@
'tornOff',
'[tear-off] tornOff'
]) {
- expect(inputLib.children['D'].children, contains(name));
- expect(inputLib.children['D'].children[name].children, isEmpty);
+ expect(inputLib.children['D']!.children, contains(name));
+ expect(inputLib.children['D']!.children[name]!.children, isEmpty);
}
});
});
@@ -435,6 +438,64 @@
});
});
+ test('histograms-filter', () async {
+ await withSymbolSizes(testSource, (sizesJson) async {
+ final json = await loadJson(File(sizesJson));
+ final info = loadProgramInfoFromJson(json);
+
+ {
+ final h = computeHistogram(info, HistogramType.bySymbol,
+ filter: 'A.tornOff');
+ expect(
+ h.buckets,
+ contains(h.bucketFor('package:input', 'package:input/input.dart',
+ 'A', 'tornOff')));
+ expect(
+ h.buckets,
+ isNot(contains(h.bucketFor('package:input',
+ 'package:input/input.dart', 'B', 'tornOff'))));
+ }
+
+ {
+ final h = computeHistogram(info, HistogramType.bySymbol,
+ filter: '::A*tornOff');
+ expect(
+ h.buckets,
+ contains(h.bucketFor('package:input', 'package:input/input.dart',
+ 'A', 'tornOff')));
+ expect(
+ h.buckets,
+ isNot(contains(h.bucketFor('package:input',
+ 'package:input/input.dart', 'B', 'tornOff'))));
+ }
+
+ {
+ final h = computeHistogram(info, HistogramType.bySymbol,
+ filter: 'input.dart*tornOff');
+ expect(
+ h.buckets,
+ contains(h.bucketFor('package:input', 'package:input/input.dart',
+ 'A', 'tornOff')));
+ expect(
+ h.buckets,
+ contains(h.bucketFor('package:input', 'package:input/input.dart',
+ 'B', 'tornOff')));
+ }
+
+ {
+ final h =
+ computeHistogram(info, HistogramType.byPackage, filter: 'A');
+ expect(
+ h.buckets,
+ contains(h.bucketFor(
+ 'package:input',
+ 'package:input/does-not-matter.dart',
+ 'does-not-matter',
+ 'does-not-matter')));
+ }
+ });
+ });
+
test('diff', () async {
await withSymbolSizes(testSource, (sizesJson) async {
await withSymbolSizes(testSourceModified, (modifiedSizesJson) async {
@@ -534,18 +595,17 @@
expect(info.root.children, contains('dart:typed_data'));
expect(info.root.children, contains('package:input'));
- final inputLib = info.root.children['package:input']
- .children['package:input/input.dart'];
- expect(inputLib, isNotNull);
+ final inputLib = info.root.children['package:input']!
+ .children['package:input/input.dart']!;
expect(inputLib.children, contains('::')); // Top-level class.
expect(inputLib.children, contains('A'));
expect(inputLib.children, contains('B'));
expect(inputLib.children, contains('C'));
- final topLevel = inputLib.children['::'];
+ final topLevel = inputLib.children['::']!;
expect(topLevel.children, contains('makeSomeClosures'));
expect(
- topLevel.children['makeSomeClosures'].children.values
+ topLevel.children['makeSomeClosures']!.children.values
.where((child) => child.type == NodeType.functionNode)
.length,
equals(3));
@@ -555,9 +615,9 @@
'Allocate A',
'[tear-off-extractor] get:tornOff'
]) {
- expect(inputLib.children['A'].children, contains(name));
+ expect(inputLib.children['A']!.children, contains(name));
}
- expect(inputLib.children['A'].children['tornOff'].children,
+ expect(inputLib.children['A']!.children['tornOff']!.children,
contains('[tear-off] tornOff'));
for (var name in [
@@ -565,35 +625,35 @@
'Allocate B',
'[tear-off-extractor] get:tornOff'
]) {
- expect(inputLib.children['B'].children, contains(name));
+ expect(inputLib.children['B']!.children, contains(name));
}
- expect(inputLib.children['B'].children['tornOff'].children,
+ expect(inputLib.children['B']!.children['tornOff']!.children,
contains('[tear-off] tornOff'));
- final classC = inputLib.children['C'];
+ final classC = inputLib.children['C']!;
expect(classC.children, contains('tornOff'));
for (var name in ['tornOff{body}', '[tear-off] tornOff']) {
- expect(classC.children['tornOff'].children, contains(name));
+ expect(classC.children['tornOff']!.children, contains(name));
}
// Verify that [ProgramInfoNode] owns its corresponding snapshot [Node].
- final classesOwnedByC = info.snapshotInfo.snapshot.nodes
- .where((n) => info.snapshotInfo.ownerOf(n) == classC)
+ final classesOwnedByC = info.snapshotInfo!.snapshot.nodes
+ .where((n) => info.snapshotInfo!.ownerOf(n) == classC)
.where((n) => n.type == 'Class')
.map((n) => n.name);
expect(classesOwnedByC, equals(['C']));
- final classD = inputLib.children['D'];
+ final classD = inputLib.children['D']!;
expect(classD.children, contains('tornOff'));
for (var name in ['tornOff{body}', '[tear-off] tornOff']) {
- expect(classD.children['tornOff'].children, contains(name));
+ expect(classD.children['tornOff']!.children, contains(name));
}
- expect(classD.children['tornOff'].children['tornOff{body}'].children,
+ expect(classD.children['tornOff']!.children['tornOff{body}']!.children,
contains('tornOff{body depth 2}'));
// Verify that [ProgramInfoNode] owns its corresponding snapshot [Node].
- final classesOwnedByD = info.snapshotInfo.snapshot.nodes
- .where((n) => info.snapshotInfo.ownerOf(n) == classD)
+ final classesOwnedByD = info.snapshotInfo!.snapshot.nodes
+ .where((n) => info.snapshotInfo!.ownerOf(n) == classD)
.where((n) => n.type == 'Class')
.map((n) => n.name);
expect(classesOwnedByD, equals(['D']));
@@ -616,20 +676,20 @@
'::',
'makeSomeClosures'
]);
- final codeNode = fromProfile.snapshotInfo.snapshot.nodes.firstWhere(
+ final codeNode = fromProfile.snapshotInfo!.snapshot.nodes.firstWhere(
(n) =>
n.type == 'Code' &&
- fromProfile.snapshotInfo.ownerOf(n) == functionNode &&
+ fromProfile.snapshotInfo!.ownerOf(n) == functionNode &&
n.name.contains('makeSomeClosures'));
expect(codeNode['<instructions>'], isNotNull);
- final instructionsSize = codeNode['<instructions>'].selfSize;
+ final instructionsSize = codeNode['<instructions>']!.selfSize;
final symbolSize = fromSymbolSizes.lookup([
'package:input',
'package:input/input.dart',
'',
'makeSomeClosures'
- ]).size;
- expect(instructionsSize - symbolSize, equals(0));
+ ])!.size;
+ expect(instructionsSize - symbolSize!, equals(0));
});
});
});
@@ -786,9 +846,10 @@
String nameOf(Map<String, dynamic> node) => node['n'];
- Map<String, dynamic> findChild(Map<String, dynamic> node, String name) {
+ Map<String, dynamic>? findChild(
+ Map<String, dynamic> node, String name) {
return childrenOf(node)
- .firstWhere((child) => nameOf(child) == name, orElse: () => null);
+ .firstWhereOrNull((child) => nameOf(child) == name);
}
Set<String> childrenNames(Map<String, dynamic> node) {
@@ -802,7 +863,7 @@
// for some reason.
expect(findChild(treemap, 'package:input/input.dart'), isNotNull);
} else {
- expect(childrenNames(findChild(treemap, 'package:input')),
+ expect(childrenNames(findChild(treemap, 'package:input')!),
equals({'main.dart', 'input.dart'}));
}
});
@@ -813,7 +874,7 @@
// Note: computing dominators also verifies that we don't have
// unreachable nodes in the snapshot.
final infoJson = await loadJson(File(profileJson));
- final snapshot = Snapshot.fromJson(infoJson);
+ final snapshot = Snapshot.fromJson(infoJson as Map<String, dynamic>);
for (var n in snapshot.nodes.skip(1)) {
expect(snapshot.dominatorOf(n), isNotNull);
}
@@ -839,7 +900,7 @@
// simply ignore entry point library (main.dart).
// Additionally this function removes all nodes with the size below
// the given threshold.
-Map<String, dynamic> diffToJson(ProgramInfo diff,
+Map<String, dynamic>? diffToJson(ProgramInfo diff,
{bool keepOnlyInputPackage = false}) {
final diffJson = diff.toJson();
diffJson.removeWhere((key, _) =>
@@ -847,7 +908,7 @@
// Rebuild the diff JSON discarding all nodes with size below threshold.
const smallChangeThreshold = 16;
- Map<String, dynamic> discardSmallChanges(Map<String, dynamic> map) {
+ Map<String, dynamic>? discardSmallChanges(Map<String, dynamic> map) {
final result = <String, dynamic>{};
// First recursively process all children (skipping #type and #size keys).
diff --git a/pkg/vm_snapshot_analysis/test/precompiler_trace_test.dart b/pkg/vm_snapshot_analysis/test/precompiler_trace_test.dart
index 2392171..f00e977 100644
--- a/pkg/vm_snapshot_analysis/test/precompiler_trace_test.dart
+++ b/pkg/vm_snapshot_analysis/test/precompiler_trace_test.dart
@@ -75,7 +75,7 @@
callGraph.computeDominators();
final main = callGraph.program
- .lookup(['package:input', 'package:input/input.dart', '', 'main']);
+ .lookup(['package:input', 'package:input/input.dart', '', 'main'])!;
final mainNode = callGraph.lookup(main);
final retainedClasses = mainNode.dominated
diff --git a/pkg/vm_snapshot_analysis/test/utils.dart b/pkg/vm_snapshot_analysis/test/utils.dart
index 830ca06..1163ae7 100644
--- a/pkg/vm_snapshot_analysis/test/utils.dart
+++ b/pkg/vm_snapshot_analysis/test/utils.dart
@@ -24,7 +24,7 @@
final String outputBinary;
final String sizesJson;
- AotSnapshot({this.outputBinary, this.sizesJson});
+ AotSnapshot({required this.outputBinary, required this.sizesJson});
}
Future withFlag(
@@ -33,7 +33,7 @@
}
Future withFlagImpl(
- Map<String, String> source, String flag, Future Function(AotSnapshot) f) {
+ Map<String, String> source, String? flag, Future Function(AotSnapshot) f) {
return withTempDir((dir) async {
final snapshot = AotSnapshot(
outputBinary: path.join(dir, 'output.exe'),
@@ -90,7 +90,8 @@
});
}
-const keepTempKey = 'KEEP_TEMPORARY_DIRECTORIES';
+late final shouldKeepTemporaryDirectories =
+ Platform.environment['KEEP_TEMPORARY_DIRECTORIES']?.isNotEmpty == true;
Future withTempDir(Future Function(String dir) f) async {
final tempDir =
@@ -98,17 +99,16 @@
try {
await f(tempDir.path);
} finally {
- if (!Platform.environment.containsKey(keepTempKey) ||
- Platform.environment[keepTempKey].isEmpty) {
+ if (shouldKeepTemporaryDirectories) {
tempDir.deleteSync(recursive: true);
}
}
}
Future<Object> loadJson(File input) async {
- return await input
+ return (await input
.openRead()
.transform(utf8.decoder)
.transform(json.decoder)
- .first;
+ .first)!;
}
diff --git a/runtime/bin/ffi_test/ffi_test_functions_generated.cc b/runtime/bin/ffi_test/ffi_test_functions_generated.cc
index 6d3a2cf..8a23e24 100644
--- a/runtime/bin/ffi_test/ffi_test_functions_generated.cc
+++ b/runtime/bin/ffi_test/ffi_test_functions_generated.cc
@@ -518,7 +518,33 @@
Struct5BytesPackedMixed a0[3];
};
-// Used for testing structs by value.
+union Union4BytesMixed {
+ uint32_t a0;
+ float a1;
+};
+
+union Union8BytesNestedFloat {
+ double a0;
+ Struct8BytesHomogeneousFloat a1;
+};
+
+union Union9BytesNestedInt {
+ Struct8BytesInt a0;
+ Struct9BytesHomogeneousUint8 a1;
+};
+
+union Union16BytesNestedInlineArrayFloat {
+ float a0[4];
+ Struct16BytesHomogeneousFloat a1;
+};
+
+union Union16BytesNestedFloat {
+ Struct8BytesHomogeneousFloat a0;
+ Struct12BytesHomogeneousFloat a1;
+ Struct16BytesHomogeneousFloat a2;
+};
+
+// Used for testing structs and unions by value.
// Smallest struct with data.
// 10 struct arguments will exhaust available registers.
DART_EXPORT int64_t PassStruct1ByteIntx10(Struct1ByteInt a0,
@@ -559,7 +585,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Not a multiple of word size, not a power of two.
// 10 struct arguments will exhaust available registers.
DART_EXPORT int64_t
@@ -635,7 +661,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Not a multiple of word size, not a power of two.
// With alignment rules taken into account size is 4 bytes.
// 10 struct arguments will exhaust available registers.
@@ -691,7 +717,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Exactly word size on 32-bit architectures.
// 10 struct arguments will exhaust available registers.
DART_EXPORT int64_t
@@ -742,7 +768,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Sub word size on 64 bit architectures.
// 10 struct arguments will exhaust available registers.
DART_EXPORT int64_t
@@ -874,7 +900,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Sub word size on 64 bit architectures.
// With alignment rules taken into account size is 8 bytes.
// 10 struct arguments will exhaust available registers.
@@ -942,7 +968,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Exactly word size struct on 64bit architectures.
// 10 struct arguments will exhaust available registers.
DART_EXPORT int64_t PassStruct8BytesIntx10(Struct8BytesInt a0,
@@ -1005,7 +1031,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Arguments passed in FP registers as long as they fit.
// 10 struct arguments will exhaust available registers.
DART_EXPORT float PassStruct8BytesHomogeneousFloatx10(
@@ -1056,7 +1082,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// On x64, arguments go in int registers because it is not only float.
// 10 struct arguments will exhaust available registers.
DART_EXPORT float PassStruct8BytesMixedx10(Struct8BytesMixed a0,
@@ -1119,7 +1145,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Argument is a single byte over a multiple of word size.
// 10 struct arguments will exhaust available registers.
// Struct only has 1-byte aligned fields to test struct alignment itself.
@@ -1284,7 +1310,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Argument is a single byte over a multiple of word size.
// With alignment rules taken into account size is 12 or 16 bytes.
// 10 struct arguments will exhaust available registers.
@@ -1341,7 +1367,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Arguments in FPU registers on arm hardfp and arm64.
// Struct arguments will exhaust available registers, and leave some empty.
// The last argument is to test whether arguments are backfilled.
@@ -1387,7 +1413,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// On Linux x64 argument is transferred on stack because it is over 16 bytes.
// Arguments in FPU registers on arm hardfp and arm64.
// 5 struct arguments will exhaust available registers.
@@ -1434,7 +1460,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// On x64, arguments are split over FP and int registers.
// On x64, it will exhaust the integer registers with the 6th argument.
// The rest goes on the stack.
@@ -1486,7 +1512,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// On x64, arguments are split over FP and int registers.
// On x64, it will exhaust the integer registers with the 6th argument.
// The rest goes on the stack.
@@ -1564,7 +1590,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Arguments are passed as pointer to copy on arm64.
// Tests that the memory allocated for copies are rounded up to word size.
DART_EXPORT int64_t PassStruct17BytesIntx10(Struct17BytesInt a0,
@@ -1630,7 +1656,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// The minimum alignment of this struct is only 1 byte based on its fields.
// Test that the memory backing these structs is extended to the right size.
//
@@ -1943,7 +1969,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Argument too big to go into integer registers on arm64.
// The arguments are passed as pointers to copies.
// The amount of arguments exhausts the number of integer registers, such that
@@ -2034,7 +2060,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Argument too big to go into FPU registers in hardfp and arm64.
DART_EXPORT float PassStruct20BytesHomogeneousFloat(
Struct20BytesHomogeneousFloat a0) {
@@ -2056,7 +2082,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Arguments in FPU registers on arm64.
// 5 struct arguments will exhaust available registers.
DART_EXPORT double PassStruct32BytesHomogeneousDoublex5(
@@ -2102,7 +2128,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Argument too big to go into FPU registers in arm64.
DART_EXPORT double PassStruct40BytesHomogeneousDouble(
Struct40BytesHomogeneousDouble a0) {
@@ -2124,7 +2150,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test 1kb struct.
DART_EXPORT uint64_t
PassStruct1024BytesHomogeneousUint64(Struct1024BytesHomogeneousUint64 a0) {
@@ -2304,7 +2330,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Tests the alignment of structs in FPU registers and backfilling.
DART_EXPORT float PassFloatStruct16BytesHomogeneousFloatFloatStruct1(
float a0,
@@ -2354,7 +2380,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Tests the alignment of structs in FPU registers and backfilling.
DART_EXPORT double PassFloatStruct32BytesHomogeneousDoubleFloatStruct(
float a0,
@@ -2404,7 +2430,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Tests the alignment of structs in integers registers and on the stack.
// Arm32 aligns this struct at 8.
// Also, arm32 allocates the second struct partially in registers, partially
@@ -2449,7 +2475,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// On Linux x64, it will exhaust xmm registers first, after 6 doubles and 2
// structs. The rest of the structs will go on the stack.
// The int will be backfilled into the int register.
@@ -2494,7 +2520,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// On Linux x64, it will exhaust int registers first.
// The rest of the structs will go on the stack.
// The double will be backfilled into the xmm register.
@@ -2535,7 +2561,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// On various architectures, first struct is allocated on stack.
// Check that the other two arguments are allocated on registers.
DART_EXPORT double PassStruct40BytesHomogeneousDoubleStruct4BytesHomo(
@@ -2565,7 +2591,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test alignment and padding of 16 byte int within struct.
DART_EXPORT double PassInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int(
int32_t a0,
@@ -2690,7 +2716,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test alignment and padding of 16 byte int within struct.
DART_EXPORT int64_t PassStructAlignmentInt16(StructAlignmentInt16 a0) {
std::cout << "PassStructAlignmentInt16"
@@ -2709,7 +2735,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test alignment and padding of 32 byte int within struct.
DART_EXPORT int64_t PassStructAlignmentInt32(StructAlignmentInt32 a0) {
std::cout << "PassStructAlignmentInt32"
@@ -2728,7 +2754,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test alignment and padding of 64 byte int within struct.
DART_EXPORT int64_t PassStructAlignmentInt64(StructAlignmentInt64 a0) {
std::cout << "PassStructAlignmentInt64"
@@ -2747,7 +2773,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Simple nested struct. No alignment gaps on any architectures.
// 10 arguments exhaust registers on all platforms.
DART_EXPORT int64_t PassStruct8BytesNestedIntx10(Struct8BytesNestedInt a0,
@@ -2825,7 +2851,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Simple nested struct. No alignment gaps on any architectures.
// 10 arguments exhaust fpu registers on all platforms.
DART_EXPORT float PassStruct8BytesNestedFloatx10(Struct8BytesNestedFloat a0,
@@ -2877,7 +2903,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Simple nested struct. No alignment gaps on any architectures.
// 10 arguments exhaust fpu registers on all platforms.
// The nesting is irregular, testing homogenous float rules on arm and arm64,
@@ -2930,7 +2956,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Simple nested struct. No alignment gaps on any architectures.
// 10 arguments exhaust all registers on all platforms.
DART_EXPORT double PassStruct8BytesNestedMixedx10(Struct8BytesNestedMixed a0,
@@ -2995,7 +3021,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Deeper nested struct to test recursive member access.
DART_EXPORT int64_t PassStruct16BytesNestedIntx2(Struct16BytesNestedInt a0,
Struct16BytesNestedInt a1) {
@@ -3033,7 +3059,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Even deeper nested struct to test recursive member access.
DART_EXPORT int64_t PassStruct32BytesNestedIntx2(Struct32BytesNestedInt a0,
Struct32BytesNestedInt a1) {
@@ -3096,7 +3122,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test alignment and padding of nested struct with 16 byte int.
DART_EXPORT int64_t PassStructNestedIntStructAlignmentInt16(
StructNestedIntStructAlignmentInt16 a0) {
@@ -3121,7 +3147,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test alignment and padding of nested struct with 32 byte int.
DART_EXPORT int64_t PassStructNestedIntStructAlignmentInt32(
StructNestedIntStructAlignmentInt32 a0) {
@@ -3146,7 +3172,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test alignment and padding of nested struct with 64 byte int.
DART_EXPORT int64_t PassStructNestedIntStructAlignmentInt64(
StructNestedIntStructAlignmentInt64 a0) {
@@ -3171,7 +3197,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return big irregular struct as smoke test.
DART_EXPORT double PassStructNestedIrregularEvenBiggerx4(
StructNestedIrregularEvenBigger a0,
@@ -3380,7 +3406,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Simple struct with inline array.
DART_EXPORT int32_t
PassStruct8BytesInlineArrayIntx4(Struct8BytesInlineArrayInt a0,
@@ -3453,7 +3479,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Irregular struct with inline array.
DART_EXPORT int32_t
PassStructInlineArrayIrregularx4(StructInlineArrayIrregular a0,
@@ -3503,7 +3529,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Regular larger struct with inline array.
DART_EXPORT int32_t
PassStructInlineArray100Bytes(StructInlineArray100Bytes a0) {
@@ -3686,7 +3712,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Arguments in FPU registers on arm hardfp and arm64.
// 5 struct arguments will exhaust available registers.
DART_EXPORT float PassStructStruct16BytesHomogeneousFloat2x5(
@@ -3734,7 +3760,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Arguments in FPU registers on arm64.
// 5 struct arguments will exhaust available registers.
DART_EXPORT double PassStructStruct32BytesHomogeneousDouble2x5(
@@ -3782,7 +3808,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// On x64, arguments are split over FP and int registers.
// On x64, it will exhaust the integer registers with the 6th argument.
// The rest goes on the stack.
@@ -3892,7 +3918,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test multi dimensional inline array struct as argument.
DART_EXPORT uint32_t PassUint8Struct32BytesInlineArrayMultiDimensionalI(
uint8_t a0,
@@ -4017,7 +4043,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test struct in multi dimensional inline array.
DART_EXPORT uint32_t PassUint8Struct4BytesInlineArrayMultiDimensionalIn(
uint8_t a0,
@@ -4046,7 +4072,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Small struct with mis-aligned member.
DART_EXPORT int64_t PassStruct3BytesPackedIntx10(Struct3BytesPackedInt a0,
Struct3BytesPackedInt a1,
@@ -4099,7 +4125,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Struct with mis-aligned member.
DART_EXPORT int64_t PassStruct8BytesPackedIntx10(Struct8BytesPackedInt a0,
Struct8BytesPackedInt a1,
@@ -4202,7 +4228,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Struct with mis-aligned member.
// Tests backfilling of CPU and FPU registers.
DART_EXPORT double PassStruct9BytesPackedMixedx10DoubleInt32(
@@ -4262,7 +4288,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// This packed struct happens to have only aligned members.
DART_EXPORT double PassStruct5BytesPackedMixed(Struct5BytesPackedMixed a0) {
std::cout << "PassStruct5BytesPackedMixed"
@@ -4279,7 +4305,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Check alignment of packed struct in non-packed struct.
DART_EXPORT double PassStructNestedAlignmentStruct5BytesPackedMixed(
StructNestedAlignmentStruct5BytesPackedMixed a0) {
@@ -4299,7 +4325,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Check alignment of packed struct array in non-packed struct.
DART_EXPORT double PassStruct6BytesInlineArrayInt(
Struct6BytesInlineArrayInt a0) {
@@ -4321,7 +4347,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Check alignment of packed struct array in non-packed struct.
DART_EXPORT double PassStruct15BytesInlineArrayMixed(
Struct15BytesInlineArrayMixed a0) {
@@ -4346,7 +4372,377 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
+// Check placement of mixed integer/float union.
+DART_EXPORT double PassUnion4BytesMixedx10(Union4BytesMixed a0,
+ Union4BytesMixed a1,
+ Union4BytesMixed a2,
+ Union4BytesMixed a3,
+ Union4BytesMixed a4,
+ Union4BytesMixed a5,
+ Union4BytesMixed a6,
+ Union4BytesMixed a7,
+ Union4BytesMixed a8,
+ Union4BytesMixed a9) {
+ std::cout << "PassUnion4BytesMixedx10"
+ << "((" << a0.a0 << ", " << a0.a1 << "), (" << a1.a0 << ", "
+ << a1.a1 << "), (" << a2.a0 << ", " << a2.a1 << "), (" << a3.a0
+ << ", " << a3.a1 << "), (" << a4.a0 << ", " << a4.a1 << "), ("
+ << a5.a0 << ", " << a5.a1 << "), (" << a6.a0 << ", " << a6.a1
+ << "), (" << a7.a0 << ", " << a7.a1 << "), (" << a8.a0 << ", "
+ << a8.a1 << "), (" << a9.a0 << ", " << a9.a1 << "))"
+ << "\n";
+
+ double result = 0;
+
+ result += a0.a0;
+ result += a1.a0;
+ result += a2.a0;
+ result += a3.a0;
+ result += a4.a0;
+ result += a5.a0;
+ result += a6.a0;
+ result += a7.a0;
+ result += a8.a0;
+ result += a9.a0;
+
+ std::cout << "result = " << result << "\n";
+
+ return result;
+}
+
+// Used for testing structs and unions by value.
+// Check placement of mixed floats union.
+DART_EXPORT double PassUnion8BytesNestedFloatx10(Union8BytesNestedFloat a0,
+ Union8BytesNestedFloat a1,
+ Union8BytesNestedFloat a2,
+ Union8BytesNestedFloat a3,
+ Union8BytesNestedFloat a4,
+ Union8BytesNestedFloat a5,
+ Union8BytesNestedFloat a6,
+ Union8BytesNestedFloat a7,
+ Union8BytesNestedFloat a8,
+ Union8BytesNestedFloat a9) {
+ std::cout << "PassUnion8BytesNestedFloatx10"
+ << "((" << a0.a0 << ", (" << a0.a1.a0 << ", " << a0.a1.a1 << ")), ("
+ << a1.a0 << ", (" << a1.a1.a0 << ", " << a1.a1.a1 << ")), ("
+ << a2.a0 << ", (" << a2.a1.a0 << ", " << a2.a1.a1 << ")), ("
+ << a3.a0 << ", (" << a3.a1.a0 << ", " << a3.a1.a1 << ")), ("
+ << a4.a0 << ", (" << a4.a1.a0 << ", " << a4.a1.a1 << ")), ("
+ << a5.a0 << ", (" << a5.a1.a0 << ", " << a5.a1.a1 << ")), ("
+ << a6.a0 << ", (" << a6.a1.a0 << ", " << a6.a1.a1 << ")), ("
+ << a7.a0 << ", (" << a7.a1.a0 << ", " << a7.a1.a1 << ")), ("
+ << a8.a0 << ", (" << a8.a1.a0 << ", " << a8.a1.a1 << ")), ("
+ << a9.a0 << ", (" << a9.a1.a0 << ", " << a9.a1.a1 << ")))"
+ << "\n";
+
+ double result = 0;
+
+ result += a0.a0;
+ result += a1.a0;
+ result += a2.a0;
+ result += a3.a0;
+ result += a4.a0;
+ result += a5.a0;
+ result += a6.a0;
+ result += a7.a0;
+ result += a8.a0;
+ result += a9.a0;
+
+ std::cout << "result = " << result << "\n";
+
+ return result;
+}
+
+// Used for testing structs and unions by value.
+// Mixed-size union argument.
+DART_EXPORT double PassUnion9BytesNestedIntx10(Union9BytesNestedInt a0,
+ Union9BytesNestedInt a1,
+ Union9BytesNestedInt a2,
+ Union9BytesNestedInt a3,
+ Union9BytesNestedInt a4,
+ Union9BytesNestedInt a5,
+ Union9BytesNestedInt a6,
+ Union9BytesNestedInt a7,
+ Union9BytesNestedInt a8,
+ Union9BytesNestedInt a9) {
+ std::cout << "PassUnion9BytesNestedIntx10"
+ << "(((" << a0.a0.a0 << ", " << a0.a0.a1 << ", " << a0.a0.a2
+ << "), (" << static_cast<int>(a0.a1.a0) << ", "
+ << static_cast<int>(a0.a1.a1) << ", " << static_cast<int>(a0.a1.a2)
+ << ", " << static_cast<int>(a0.a1.a3) << ", "
+ << static_cast<int>(a0.a1.a4) << ", " << static_cast<int>(a0.a1.a5)
+ << ", " << static_cast<int>(a0.a1.a6) << ", "
+ << static_cast<int>(a0.a1.a7) << ", " << static_cast<int>(a0.a1.a8)
+ << ")), ((" << a1.a0.a0 << ", " << a1.a0.a1 << ", " << a1.a0.a2
+ << "), (" << static_cast<int>(a1.a1.a0) << ", "
+ << static_cast<int>(a1.a1.a1) << ", " << static_cast<int>(a1.a1.a2)
+ << ", " << static_cast<int>(a1.a1.a3) << ", "
+ << static_cast<int>(a1.a1.a4) << ", " << static_cast<int>(a1.a1.a5)
+ << ", " << static_cast<int>(a1.a1.a6) << ", "
+ << static_cast<int>(a1.a1.a7) << ", " << static_cast<int>(a1.a1.a8)
+ << ")), ((" << a2.a0.a0 << ", " << a2.a0.a1 << ", " << a2.a0.a2
+ << "), (" << static_cast<int>(a2.a1.a0) << ", "
+ << static_cast<int>(a2.a1.a1) << ", " << static_cast<int>(a2.a1.a2)
+ << ", " << static_cast<int>(a2.a1.a3) << ", "
+ << static_cast<int>(a2.a1.a4) << ", " << static_cast<int>(a2.a1.a5)
+ << ", " << static_cast<int>(a2.a1.a6) << ", "
+ << static_cast<int>(a2.a1.a7) << ", " << static_cast<int>(a2.a1.a8)
+ << ")), ((" << a3.a0.a0 << ", " << a3.a0.a1 << ", " << a3.a0.a2
+ << "), (" << static_cast<int>(a3.a1.a0) << ", "
+ << static_cast<int>(a3.a1.a1) << ", " << static_cast<int>(a3.a1.a2)
+ << ", " << static_cast<int>(a3.a1.a3) << ", "
+ << static_cast<int>(a3.a1.a4) << ", " << static_cast<int>(a3.a1.a5)
+ << ", " << static_cast<int>(a3.a1.a6) << ", "
+ << static_cast<int>(a3.a1.a7) << ", " << static_cast<int>(a3.a1.a8)
+ << ")), ((" << a4.a0.a0 << ", " << a4.a0.a1 << ", " << a4.a0.a2
+ << "), (" << static_cast<int>(a4.a1.a0) << ", "
+ << static_cast<int>(a4.a1.a1) << ", " << static_cast<int>(a4.a1.a2)
+ << ", " << static_cast<int>(a4.a1.a3) << ", "
+ << static_cast<int>(a4.a1.a4) << ", " << static_cast<int>(a4.a1.a5)
+ << ", " << static_cast<int>(a4.a1.a6) << ", "
+ << static_cast<int>(a4.a1.a7) << ", " << static_cast<int>(a4.a1.a8)
+ << ")), ((" << a5.a0.a0 << ", " << a5.a0.a1 << ", " << a5.a0.a2
+ << "), (" << static_cast<int>(a5.a1.a0) << ", "
+ << static_cast<int>(a5.a1.a1) << ", " << static_cast<int>(a5.a1.a2)
+ << ", " << static_cast<int>(a5.a1.a3) << ", "
+ << static_cast<int>(a5.a1.a4) << ", " << static_cast<int>(a5.a1.a5)
+ << ", " << static_cast<int>(a5.a1.a6) << ", "
+ << static_cast<int>(a5.a1.a7) << ", " << static_cast<int>(a5.a1.a8)
+ << ")), ((" << a6.a0.a0 << ", " << a6.a0.a1 << ", " << a6.a0.a2
+ << "), (" << static_cast<int>(a6.a1.a0) << ", "
+ << static_cast<int>(a6.a1.a1) << ", " << static_cast<int>(a6.a1.a2)
+ << ", " << static_cast<int>(a6.a1.a3) << ", "
+ << static_cast<int>(a6.a1.a4) << ", " << static_cast<int>(a6.a1.a5)
+ << ", " << static_cast<int>(a6.a1.a6) << ", "
+ << static_cast<int>(a6.a1.a7) << ", " << static_cast<int>(a6.a1.a8)
+ << ")), ((" << a7.a0.a0 << ", " << a7.a0.a1 << ", " << a7.a0.a2
+ << "), (" << static_cast<int>(a7.a1.a0) << ", "
+ << static_cast<int>(a7.a1.a1) << ", " << static_cast<int>(a7.a1.a2)
+ << ", " << static_cast<int>(a7.a1.a3) << ", "
+ << static_cast<int>(a7.a1.a4) << ", " << static_cast<int>(a7.a1.a5)
+ << ", " << static_cast<int>(a7.a1.a6) << ", "
+ << static_cast<int>(a7.a1.a7) << ", " << static_cast<int>(a7.a1.a8)
+ << ")), ((" << a8.a0.a0 << ", " << a8.a0.a1 << ", " << a8.a0.a2
+ << "), (" << static_cast<int>(a8.a1.a0) << ", "
+ << static_cast<int>(a8.a1.a1) << ", " << static_cast<int>(a8.a1.a2)
+ << ", " << static_cast<int>(a8.a1.a3) << ", "
+ << static_cast<int>(a8.a1.a4) << ", " << static_cast<int>(a8.a1.a5)
+ << ", " << static_cast<int>(a8.a1.a6) << ", "
+ << static_cast<int>(a8.a1.a7) << ", " << static_cast<int>(a8.a1.a8)
+ << ")), ((" << a9.a0.a0 << ", " << a9.a0.a1 << ", " << a9.a0.a2
+ << "), (" << static_cast<int>(a9.a1.a0) << ", "
+ << static_cast<int>(a9.a1.a1) << ", " << static_cast<int>(a9.a1.a2)
+ << ", " << static_cast<int>(a9.a1.a3) << ", "
+ << static_cast<int>(a9.a1.a4) << ", " << static_cast<int>(a9.a1.a5)
+ << ", " << static_cast<int>(a9.a1.a6) << ", "
+ << static_cast<int>(a9.a1.a7) << ", " << static_cast<int>(a9.a1.a8)
+ << ")))"
+ << "\n";
+
+ double result = 0;
+
+ result += a0.a0.a0;
+ result += a0.a0.a1;
+ result += a0.a0.a2;
+ result += a1.a0.a0;
+ result += a1.a0.a1;
+ result += a1.a0.a2;
+ result += a2.a0.a0;
+ result += a2.a0.a1;
+ result += a2.a0.a2;
+ result += a3.a0.a0;
+ result += a3.a0.a1;
+ result += a3.a0.a2;
+ result += a4.a0.a0;
+ result += a4.a0.a1;
+ result += a4.a0.a2;
+ result += a5.a0.a0;
+ result += a5.a0.a1;
+ result += a5.a0.a2;
+ result += a6.a0.a0;
+ result += a6.a0.a1;
+ result += a6.a0.a2;
+ result += a7.a0.a0;
+ result += a7.a0.a1;
+ result += a7.a0.a2;
+ result += a8.a0.a0;
+ result += a8.a0.a1;
+ result += a8.a0.a2;
+ result += a9.a0.a0;
+ result += a9.a0.a1;
+ result += a9.a0.a2;
+
+ std::cout << "result = " << result << "\n";
+
+ return result;
+}
+
+// Used for testing structs and unions by value.
+// Union with homogenous floats.
+DART_EXPORT double PassUnion16BytesNestedInlineArrayFloatx10(
+ Union16BytesNestedInlineArrayFloat a0,
+ Union16BytesNestedInlineArrayFloat a1,
+ Union16BytesNestedInlineArrayFloat a2,
+ Union16BytesNestedInlineArrayFloat a3,
+ Union16BytesNestedInlineArrayFloat a4,
+ Union16BytesNestedInlineArrayFloat a5,
+ Union16BytesNestedInlineArrayFloat a6,
+ Union16BytesNestedInlineArrayFloat a7,
+ Union16BytesNestedInlineArrayFloat a8,
+ Union16BytesNestedInlineArrayFloat a9) {
+ std::cout << "PassUnion16BytesNestedInlineArrayFloatx10"
+ << "(([" << a0.a0[0] << ", " << a0.a0[1] << ", " << a0.a0[2] << ", "
+ << a0.a0[3] << "], (" << a0.a1.a0 << ", " << a0.a1.a1 << ", "
+ << a0.a1.a2 << ", " << a0.a1.a3 << ")), ([" << a1.a0[0] << ", "
+ << a1.a0[1] << ", " << a1.a0[2] << ", " << a1.a0[3] << "], ("
+ << a1.a1.a0 << ", " << a1.a1.a1 << ", " << a1.a1.a2 << ", "
+ << a1.a1.a3 << ")), ([" << a2.a0[0] << ", " << a2.a0[1] << ", "
+ << a2.a0[2] << ", " << a2.a0[3] << "], (" << a2.a1.a0 << ", "
+ << a2.a1.a1 << ", " << a2.a1.a2 << ", " << a2.a1.a3 << ")), (["
+ << a3.a0[0] << ", " << a3.a0[1] << ", " << a3.a0[2] << ", "
+ << a3.a0[3] << "], (" << a3.a1.a0 << ", " << a3.a1.a1 << ", "
+ << a3.a1.a2 << ", " << a3.a1.a3 << ")), ([" << a4.a0[0] << ", "
+ << a4.a0[1] << ", " << a4.a0[2] << ", " << a4.a0[3] << "], ("
+ << a4.a1.a0 << ", " << a4.a1.a1 << ", " << a4.a1.a2 << ", "
+ << a4.a1.a3 << ")), ([" << a5.a0[0] << ", " << a5.a0[1] << ", "
+ << a5.a0[2] << ", " << a5.a0[3] << "], (" << a5.a1.a0 << ", "
+ << a5.a1.a1 << ", " << a5.a1.a2 << ", " << a5.a1.a3 << ")), (["
+ << a6.a0[0] << ", " << a6.a0[1] << ", " << a6.a0[2] << ", "
+ << a6.a0[3] << "], (" << a6.a1.a0 << ", " << a6.a1.a1 << ", "
+ << a6.a1.a2 << ", " << a6.a1.a3 << ")), ([" << a7.a0[0] << ", "
+ << a7.a0[1] << ", " << a7.a0[2] << ", " << a7.a0[3] << "], ("
+ << a7.a1.a0 << ", " << a7.a1.a1 << ", " << a7.a1.a2 << ", "
+ << a7.a1.a3 << ")), ([" << a8.a0[0] << ", " << a8.a0[1] << ", "
+ << a8.a0[2] << ", " << a8.a0[3] << "], (" << a8.a1.a0 << ", "
+ << a8.a1.a1 << ", " << a8.a1.a2 << ", " << a8.a1.a3 << ")), (["
+ << a9.a0[0] << ", " << a9.a0[1] << ", " << a9.a0[2] << ", "
+ << a9.a0[3] << "], (" << a9.a1.a0 << ", " << a9.a1.a1 << ", "
+ << a9.a1.a2 << ", " << a9.a1.a3 << ")))"
+ << "\n";
+
+ double result = 0;
+
+ result += a0.a0[0];
+ result += a0.a0[1];
+ result += a0.a0[2];
+ result += a0.a0[3];
+ result += a1.a0[0];
+ result += a1.a0[1];
+ result += a1.a0[2];
+ result += a1.a0[3];
+ result += a2.a0[0];
+ result += a2.a0[1];
+ result += a2.a0[2];
+ result += a2.a0[3];
+ result += a3.a0[0];
+ result += a3.a0[1];
+ result += a3.a0[2];
+ result += a3.a0[3];
+ result += a4.a0[0];
+ result += a4.a0[1];
+ result += a4.a0[2];
+ result += a4.a0[3];
+ result += a5.a0[0];
+ result += a5.a0[1];
+ result += a5.a0[2];
+ result += a5.a0[3];
+ result += a6.a0[0];
+ result += a6.a0[1];
+ result += a6.a0[2];
+ result += a6.a0[3];
+ result += a7.a0[0];
+ result += a7.a0[1];
+ result += a7.a0[2];
+ result += a7.a0[3];
+ result += a8.a0[0];
+ result += a8.a0[1];
+ result += a8.a0[2];
+ result += a8.a0[3];
+ result += a9.a0[0];
+ result += a9.a0[1];
+ result += a9.a0[2];
+ result += a9.a0[3];
+
+ std::cout << "result = " << result << "\n";
+
+ return result;
+}
+
+// Used for testing structs and unions by value.
+// Union with homogenous floats.
+DART_EXPORT double PassUnion16BytesNestedFloatx10(Union16BytesNestedFloat a0,
+ Union16BytesNestedFloat a1,
+ Union16BytesNestedFloat a2,
+ Union16BytesNestedFloat a3,
+ Union16BytesNestedFloat a4,
+ Union16BytesNestedFloat a5,
+ Union16BytesNestedFloat a6,
+ Union16BytesNestedFloat a7,
+ Union16BytesNestedFloat a8,
+ Union16BytesNestedFloat a9) {
+ std::cout << "PassUnion16BytesNestedFloatx10"
+ << "(((" << a0.a0.a0 << ", " << a0.a0.a1 << "), (" << a0.a1.a0
+ << ", " << a0.a1.a1 << ", " << a0.a1.a2 << "), (" << a0.a2.a0
+ << ", " << a0.a2.a1 << ", " << a0.a2.a2 << ", " << a0.a2.a3
+ << ")), ((" << a1.a0.a0 << ", " << a1.a0.a1 << "), (" << a1.a1.a0
+ << ", " << a1.a1.a1 << ", " << a1.a1.a2 << "), (" << a1.a2.a0
+ << ", " << a1.a2.a1 << ", " << a1.a2.a2 << ", " << a1.a2.a3
+ << ")), ((" << a2.a0.a0 << ", " << a2.a0.a1 << "), (" << a2.a1.a0
+ << ", " << a2.a1.a1 << ", " << a2.a1.a2 << "), (" << a2.a2.a0
+ << ", " << a2.a2.a1 << ", " << a2.a2.a2 << ", " << a2.a2.a3
+ << ")), ((" << a3.a0.a0 << ", " << a3.a0.a1 << "), (" << a3.a1.a0
+ << ", " << a3.a1.a1 << ", " << a3.a1.a2 << "), (" << a3.a2.a0
+ << ", " << a3.a2.a1 << ", " << a3.a2.a2 << ", " << a3.a2.a3
+ << ")), ((" << a4.a0.a0 << ", " << a4.a0.a1 << "), (" << a4.a1.a0
+ << ", " << a4.a1.a1 << ", " << a4.a1.a2 << "), (" << a4.a2.a0
+ << ", " << a4.a2.a1 << ", " << a4.a2.a2 << ", " << a4.a2.a3
+ << ")), ((" << a5.a0.a0 << ", " << a5.a0.a1 << "), (" << a5.a1.a0
+ << ", " << a5.a1.a1 << ", " << a5.a1.a2 << "), (" << a5.a2.a0
+ << ", " << a5.a2.a1 << ", " << a5.a2.a2 << ", " << a5.a2.a3
+ << ")), ((" << a6.a0.a0 << ", " << a6.a0.a1 << "), (" << a6.a1.a0
+ << ", " << a6.a1.a1 << ", " << a6.a1.a2 << "), (" << a6.a2.a0
+ << ", " << a6.a2.a1 << ", " << a6.a2.a2 << ", " << a6.a2.a3
+ << ")), ((" << a7.a0.a0 << ", " << a7.a0.a1 << "), (" << a7.a1.a0
+ << ", " << a7.a1.a1 << ", " << a7.a1.a2 << "), (" << a7.a2.a0
+ << ", " << a7.a2.a1 << ", " << a7.a2.a2 << ", " << a7.a2.a3
+ << ")), ((" << a8.a0.a0 << ", " << a8.a0.a1 << "), (" << a8.a1.a0
+ << ", " << a8.a1.a1 << ", " << a8.a1.a2 << "), (" << a8.a2.a0
+ << ", " << a8.a2.a1 << ", " << a8.a2.a2 << ", " << a8.a2.a3
+ << ")), ((" << a9.a0.a0 << ", " << a9.a0.a1 << "), (" << a9.a1.a0
+ << ", " << a9.a1.a1 << ", " << a9.a1.a2 << "), (" << a9.a2.a0
+ << ", " << a9.a2.a1 << ", " << a9.a2.a2 << ", " << a9.a2.a3 << ")))"
+ << "\n";
+
+ double result = 0;
+
+ result += a0.a0.a0;
+ result += a0.a0.a1;
+ result += a1.a0.a0;
+ result += a1.a0.a1;
+ result += a2.a0.a0;
+ result += a2.a0.a1;
+ result += a3.a0.a0;
+ result += a3.a0.a1;
+ result += a4.a0.a0;
+ result += a4.a0.a1;
+ result += a5.a0.a0;
+ result += a5.a0.a1;
+ result += a6.a0.a0;
+ result += a6.a0.a1;
+ result += a7.a0.a0;
+ result += a7.a0.a1;
+ result += a8.a0.a0;
+ result += a8.a0.a1;
+ result += a9.a0.a0;
+ result += a9.a0.a1;
+
+ std::cout << "result = " << result << "\n";
+
+ return result;
+}
+
+// Used for testing structs and unions by value.
// Smallest struct with data.
DART_EXPORT Struct1ByteInt ReturnStruct1ByteInt(int8_t a0) {
std::cout << "ReturnStruct1ByteInt"
@@ -4364,7 +4760,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Smaller than word size return value on all architectures.
DART_EXPORT Struct3BytesHomogeneousUint8
ReturnStruct3BytesHomogeneousUint8(uint8_t a0, uint8_t a1, uint8_t a2) {
@@ -4388,7 +4784,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Smaller than word size return value on all architectures.
// With alignment rules taken into account size is 4 bytes.
DART_EXPORT Struct3BytesInt2ByteAligned
@@ -4409,7 +4805,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Word size return value on 32 bit architectures..
DART_EXPORT Struct4BytesHomogeneousInt16
ReturnStruct4BytesHomogeneousInt16(int16_t a0, int16_t a1) {
@@ -4429,7 +4825,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Non-wordsize return value.
DART_EXPORT Struct7BytesHomogeneousUint8
ReturnStruct7BytesHomogeneousUint8(uint8_t a0,
@@ -4469,7 +4865,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Non-wordsize return value.
// With alignment rules taken into account size is 8 bytes.
DART_EXPORT Struct7BytesInt4ByteAligned
@@ -4492,7 +4888,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return value in integer registers on many architectures.
DART_EXPORT Struct8BytesInt ReturnStruct8BytesInt(int16_t a0,
int16_t a1,
@@ -4514,7 +4910,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return value in FP registers on many architectures.
DART_EXPORT Struct8BytesHomogeneousFloat
ReturnStruct8BytesHomogeneousFloat(float a0, float a1) {
@@ -4534,7 +4930,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return value split over FP and integer register in x64.
DART_EXPORT Struct8BytesMixed ReturnStruct8BytesMixed(float a0,
int16_t a1,
@@ -4556,7 +4952,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// The minimum alignment of this struct is only 1 byte based on its fields.
// Test that the memory backing these structs is the right size and that
// dart:ffi trampolines do not write outside this size.
@@ -4605,7 +5001,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return value in two integer registers on x64.
// With alignment rules taken into account size is 12 or 16 bytes.
DART_EXPORT Struct9BytesInt4Or8ByteAligned
@@ -4626,7 +5022,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return value in FPU registers, but does not use all registers on arm hardfp
// and arm64.
DART_EXPORT Struct12BytesHomogeneousFloat
@@ -4648,7 +5044,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return value in FPU registers on arm hardfp and arm64.
DART_EXPORT Struct16BytesHomogeneousFloat
ReturnStruct16BytesHomogeneousFloat(float a0, float a1, float a2, float a3) {
@@ -4671,7 +5067,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return value split over FP and integer register in x64.
DART_EXPORT Struct16BytesMixed ReturnStruct16BytesMixed(double a0, int64_t a1) {
std::cout << "ReturnStruct16BytesMixed"
@@ -4690,7 +5086,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return value split over FP and integer register in x64.
// The integer register contains half float half int.
DART_EXPORT Struct16BytesMixed2 ReturnStruct16BytesMixed2(float a0,
@@ -4716,7 +5112,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Rerturn value returned in preallocated space passed by pointer on most ABIs.
// Is non word size on purpose, to test that structs are rounded up to word size
// on all ABIs.
@@ -4741,7 +5137,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// The minimum alignment of this struct is only 1 byte based on its fields.
// Test that the memory backing these structs is the right size and that
// dart:ffi trampolines do not write outside this size.
@@ -4825,7 +5221,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return value too big to go in cpu registers on arm64.
DART_EXPORT Struct20BytesHomogeneousInt32
ReturnStruct20BytesHomogeneousInt32(int32_t a0,
@@ -4854,7 +5250,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return value too big to go in FPU registers on x64, arm hardfp and arm64.
DART_EXPORT Struct20BytesHomogeneousFloat
ReturnStruct20BytesHomogeneousFloat(float a0,
@@ -4883,7 +5279,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return value in FPU registers on arm64.
DART_EXPORT Struct32BytesHomogeneousDouble
ReturnStruct32BytesHomogeneousDouble(double a0,
@@ -4909,7 +5305,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return value too big to go in FPU registers on arm64.
DART_EXPORT Struct40BytesHomogeneousDouble
ReturnStruct40BytesHomogeneousDouble(double a0,
@@ -4938,7 +5334,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test 1kb struct.
DART_EXPORT Struct1024BytesHomogeneousUint64
ReturnStruct1024BytesHomogeneousUint64(uint64_t a0,
@@ -5282,7 +5678,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Small struct with mis-aligned member.
DART_EXPORT Struct3BytesPackedInt ReturnStruct3BytesPackedInt(int8_t a0,
int16_t a1) {
@@ -5302,7 +5698,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Struct with mis-aligned member.
DART_EXPORT Struct8BytesPackedInt ReturnStruct8BytesPackedInt(uint8_t a0,
uint32_t a1,
@@ -5333,7 +5729,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Struct with mis-aligned member.
// Tests backfilling of CPU and FPU registers.
DART_EXPORT Struct9BytesPackedMixed ReturnStruct9BytesPackedMixed(uint8_t a0,
@@ -5354,7 +5750,97 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
+// Returning a mixed integer/float union.
+DART_EXPORT Union4BytesMixed ReturnUnion4BytesMixed(uint32_t a0) {
+ std::cout << "ReturnUnion4BytesMixed"
+ << "(" << a0 << ")"
+ << "\n";
+
+ Union4BytesMixed result;
+
+ result.a0 = a0;
+
+ std::cout << "result = "
+ << "(" << result.a0 << ", " << result.a1 << ")"
+ << "\n";
+
+ return result;
+}
+
+// Used for testing structs and unions by value.
+// Returning a floating point only union.
+DART_EXPORT Union8BytesNestedFloat ReturnUnion8BytesNestedFloat(double a0) {
+ std::cout << "ReturnUnion8BytesNestedFloat"
+ << "(" << a0 << ")"
+ << "\n";
+
+ Union8BytesNestedFloat result;
+
+ result.a0 = a0;
+
+ std::cout << "result = "
+ << "(" << result.a0 << ", (" << result.a1.a0 << ", " << result.a1.a1
+ << "))"
+ << "\n";
+
+ return result;
+}
+
+// Used for testing structs and unions by value.
+// Returning a mixed-size union.
+DART_EXPORT Union9BytesNestedInt
+ReturnUnion9BytesNestedInt(Struct8BytesInt a0) {
+ std::cout << "ReturnUnion9BytesNestedInt"
+ << "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << "))"
+ << "\n";
+
+ Union9BytesNestedInt result;
+
+ result.a0.a0 = a0.a0;
+ result.a0.a1 = a0.a1;
+ result.a0.a2 = a0.a2;
+
+ std::cout << "result = "
+ << "((" << result.a0.a0 << ", " << result.a0.a1 << ", "
+ << result.a0.a2 << "), (" << static_cast<int>(result.a1.a0) << ", "
+ << static_cast<int>(result.a1.a1) << ", "
+ << static_cast<int>(result.a1.a2) << ", "
+ << static_cast<int>(result.a1.a3) << ", "
+ << static_cast<int>(result.a1.a4) << ", "
+ << static_cast<int>(result.a1.a5) << ", "
+ << static_cast<int>(result.a1.a6) << ", "
+ << static_cast<int>(result.a1.a7) << ", "
+ << static_cast<int>(result.a1.a8) << "))"
+ << "\n";
+
+ return result;
+}
+
+// Used for testing structs and unions by value.
+// Returning union with homogenous floats.
+DART_EXPORT Union16BytesNestedFloat
+ReturnUnion16BytesNestedFloat(Struct8BytesHomogeneousFloat a0) {
+ std::cout << "ReturnUnion16BytesNestedFloat"
+ << "((" << a0.a0 << ", " << a0.a1 << "))"
+ << "\n";
+
+ Union16BytesNestedFloat result;
+
+ result.a0.a0 = a0.a0;
+ result.a0.a1 = a0.a1;
+
+ std::cout << "result = "
+ << "((" << result.a0.a0 << ", " << result.a0.a1 << "), ("
+ << result.a1.a0 << ", " << result.a1.a1 << ", " << result.a1.a2
+ << "), (" << result.a2.a0 << ", " << result.a2.a1 << ", "
+ << result.a2.a2 << ", " << result.a2.a3 << "))"
+ << "\n";
+
+ return result;
+}
+
+// Used for testing structs and unions by value.
// Test that a struct passed in as argument can be returned.
// Especially for ffi callbacks.
// Struct is passed in int registers in most ABIs.
@@ -5373,7 +5859,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test that a struct passed in as argument can be returned.
// Especially for ffi callbacks.
// Struct is passed on stack on all ABIs.
@@ -5402,7 +5888,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test that a struct passed in as argument can be returned.
// Especially for ffi callbacks.
// Struct is passed in float registers in most ABIs.
@@ -5422,7 +5908,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// On arm64, both argument and return value are passed in by pointer.
DART_EXPORT Struct20BytesHomogeneousInt32
ReturnStructArgumentStruct20BytesHomogeneousInt32(
@@ -5442,7 +5928,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// On arm64, both argument and return value are passed in by pointer.
// Ints exhaust registers, so that pointer is passed on stack.
DART_EXPORT Struct20BytesHomogeneousInt32
@@ -5472,7 +5958,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test returning struct with inline array.
DART_EXPORT Struct8BytesInlineArrayInt
ReturnStructArgumentStruct8BytesInlineArrayInt(Struct8BytesInlineArrayInt a0) {
@@ -5501,7 +5987,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return value in FPU registers on arm hardfp and arm64.
DART_EXPORT StructStruct16BytesHomogeneousFloat2
ReturnStructArgumentStructStruct16BytesHomogeneous(
@@ -5521,7 +6007,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return value in FPU registers on arm64.
DART_EXPORT StructStruct32BytesHomogeneousDouble2
ReturnStructArgumentStructStruct32BytesHomogeneous(
@@ -5541,7 +6027,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// On x64 Linux, return value is split over FP and int registers.
DART_EXPORT StructStruct16BytesMixed3
ReturnStructArgumentStructStruct16BytesMixed3(StructStruct16BytesMixed3 a0) {
@@ -5562,7 +6048,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test alignment and padding of 16 byte int within struct.
DART_EXPORT StructAlignmentInt16 ReturnStructAlignmentInt16(int8_t a0,
int16_t a1,
@@ -5586,7 +6072,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test alignment and padding of 32 byte int within struct.
DART_EXPORT StructAlignmentInt32 ReturnStructAlignmentInt32(int8_t a0,
int32_t a1,
@@ -5610,7 +6096,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test alignment and padding of 64 byte int within struct.
DART_EXPORT StructAlignmentInt64 ReturnStructAlignmentInt64(int8_t a0,
int64_t a1,
@@ -5634,7 +6120,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Simple nested struct.
DART_EXPORT Struct8BytesNestedInt
ReturnStruct8BytesNestedInt(Struct4BytesHomogeneousInt16 a0,
@@ -5659,7 +6145,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Simple nested struct with floats.
DART_EXPORT Struct8BytesNestedFloat
ReturnStruct8BytesNestedFloat(Struct4BytesFloat a0, Struct4BytesFloat a1) {
@@ -5679,7 +6165,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// The nesting is irregular, testing homogenous float rules on arm and arm64,
// and the fpu register usage on x64.
DART_EXPORT Struct8BytesNestedFloat2
@@ -5700,7 +6186,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Simple nested struct with mixed members.
DART_EXPORT Struct8BytesNestedMixed
ReturnStruct8BytesNestedMixed(Struct4BytesHomogeneousInt16 a0,
@@ -5723,7 +6209,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Deeper nested struct to test recursive member access.
DART_EXPORT Struct16BytesNestedInt
ReturnStruct16BytesNestedInt(Struct8BytesNestedInt a0,
@@ -5755,7 +6241,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Even deeper nested struct to test recursive member access.
DART_EXPORT Struct32BytesNestedInt
ReturnStruct32BytesNestedInt(Struct16BytesNestedInt a0,
@@ -5804,7 +6290,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test alignment and padding of nested struct with 16 byte int.
DART_EXPORT StructNestedIntStructAlignmentInt16
ReturnStructNestedIntStructAlignmentInt16(StructAlignmentInt16 a0,
@@ -5834,7 +6320,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test alignment and padding of nested struct with 32 byte int.
DART_EXPORT StructNestedIntStructAlignmentInt32
ReturnStructNestedIntStructAlignmentInt32(StructAlignmentInt32 a0,
@@ -5864,7 +6350,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test alignment and padding of nested struct with 64 byte int.
DART_EXPORT StructNestedIntStructAlignmentInt64
ReturnStructNestedIntStructAlignmentInt64(StructAlignmentInt64 a0,
@@ -5894,7 +6380,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return big irregular struct as smoke test.
DART_EXPORT StructNestedIrregularEvenBigger
ReturnStructNestedIrregularEvenBigger(uint64_t a0,
@@ -5977,7 +6463,7 @@
return result;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Smallest struct with data.
// 10 struct arguments will exhaust available registers.
DART_EXPORT intptr_t TestPassStruct1ByteIntx10(
@@ -6047,7 +6533,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Not a multiple of word size, not a power of two.
// 10 struct arguments will exhaust available registers.
DART_EXPORT intptr_t TestPassStruct3BytesHomogeneousUint8x10(
@@ -6151,7 +6637,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Not a multiple of word size, not a power of two.
// With alignment rules taken into account size is 4 bytes.
// 10 struct arguments will exhaust available registers.
@@ -6235,7 +6721,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Exactly word size on 32-bit architectures.
// 10 struct arguments will exhaust available registers.
DART_EXPORT intptr_t TestPassStruct4BytesHomogeneousInt16x10(
@@ -6314,7 +6800,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Sub word size on 64 bit architectures.
// 10 struct arguments will exhaust available registers.
DART_EXPORT intptr_t TestPassStruct7BytesHomogeneousUint8x10(
@@ -6474,7 +6960,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Sub word size on 64 bit architectures.
// With alignment rules taken into account size is 8 bytes.
// 10 struct arguments will exhaust available registers.
@@ -6570,7 +7056,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Exactly word size struct on 64bit architectures.
// 10 struct arguments will exhaust available registers.
DART_EXPORT intptr_t TestPassStruct8BytesIntx10(
@@ -6662,7 +7148,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Arguments passed in FP registers as long as they fit.
// 10 struct arguments will exhaust available registers.
DART_EXPORT intptr_t TestPassStruct8BytesHomogeneousFloatx10(
@@ -6741,7 +7227,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// On x64, arguments go in int registers because it is not only float.
// 10 struct arguments will exhaust available registers.
DART_EXPORT intptr_t TestPassStruct8BytesMixedx10(
@@ -6833,7 +7319,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Argument is a single byte over a multiple of word size.
// 10 struct arguments will exhaust available registers.
// Struct only has 1-byte aligned fields to test struct alignment itself.
@@ -7026,7 +7512,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Argument is a single byte over a multiple of word size.
// With alignment rules taken into account size is 12 or 16 bytes.
// 10 struct arguments will exhaust available registers.
@@ -7111,7 +7597,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Arguments in FPU registers on arm hardfp and arm64.
// Struct arguments will exhaust available registers, and leave some empty.
// The last argument is to test whether arguments are backfilled.
@@ -7181,7 +7667,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// On Linux x64 argument is transferred on stack because it is over 16 bytes.
// Arguments in FPU registers on arm hardfp and arm64.
// 5 struct arguments will exhaust available registers.
@@ -7251,7 +7737,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// On x64, arguments are split over FP and int registers.
// On x64, it will exhaust the integer registers with the 6th argument.
// The rest goes on the stack.
@@ -7332,7 +7818,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// On x64, arguments are split over FP and int registers.
// On x64, it will exhaust the integer registers with the 6th argument.
// The rest goes on the stack.
@@ -7439,7 +7925,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Arguments are passed as pointer to copy on arm64.
// Tests that the memory allocated for copies are rounded up to word size.
DART_EXPORT intptr_t TestPassStruct17BytesIntx10(
@@ -7534,7 +8020,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// The minimum alignment of this struct is only 1 byte based on its fields.
// Test that the memory backing these structs is extended to the right size.
//
@@ -7875,7 +8361,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Argument too big to go into integer registers on arm64.
// The arguments are passed as pointers to copies.
// The amount of arguments exhausts the number of integer registers, such that
@@ -7994,7 +8480,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Argument too big to go into FPU registers in hardfp and arm64.
DART_EXPORT intptr_t TestPassStruct20BytesHomogeneousFloat(
// NOLINTNEXTLINE(whitespace/parens)
@@ -8035,7 +8521,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Arguments in FPU registers on arm64.
// 5 struct arguments will exhaust available registers.
DART_EXPORT intptr_t TestPassStruct32BytesHomogeneousDoublex5(
@@ -8104,7 +8590,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Argument too big to go into FPU registers in arm64.
DART_EXPORT intptr_t TestPassStruct40BytesHomogeneousDouble(
// NOLINTNEXTLINE(whitespace/parens)
@@ -8145,7 +8631,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test 1kb struct.
DART_EXPORT intptr_t TestPassStruct1024BytesHomogeneousUint64(
// NOLINTNEXTLINE(whitespace/parens)
@@ -8344,7 +8830,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Tests the alignment of structs in FPU registers and backfilling.
DART_EXPORT intptr_t TestPassFloatStruct16BytesHomogeneousFloatFloatStruct1(
// NOLINTNEXTLINE(whitespace/parens)
@@ -8421,7 +8907,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Tests the alignment of structs in FPU registers and backfilling.
DART_EXPORT intptr_t TestPassFloatStruct32BytesHomogeneousDoubleFloatStruct(
// NOLINTNEXTLINE(whitespace/parens)
@@ -8498,7 +8984,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Tests the alignment of structs in integers registers and on the stack.
// Arm32 aligns this struct at 8.
// Also, arm32 allocates the second struct partially in registers, partially
@@ -8570,7 +9056,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// On Linux x64, it will exhaust xmm registers first, after 6 doubles and 2
// structs. The rest of the structs will go on the stack.
// The int will be backfilled into the int register.
@@ -8645,7 +9131,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// On Linux x64, it will exhaust int registers first.
// The rest of the structs will go on the stack.
// The double will be backfilled into the xmm register.
@@ -8714,7 +9200,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// On various architectures, first struct is allocated on stack.
// Check that the other two arguments are allocated on registers.
DART_EXPORT intptr_t TestPassStruct40BytesHomogeneousDoubleStruct4BytesHomo(
@@ -8765,7 +9251,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test alignment and padding of 16 byte int within struct.
DART_EXPORT intptr_t TestPassInt32x8Doublex8Int64Int8Struct1ByteIntInt64Int(
// NOLINTNEXTLINE(whitespace/parens)
@@ -8955,7 +9441,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test alignment and padding of 16 byte int within struct.
DART_EXPORT intptr_t TestPassStructAlignmentInt16(
// NOLINTNEXTLINE(whitespace/parens)
@@ -8994,7 +9480,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test alignment and padding of 32 byte int within struct.
DART_EXPORT intptr_t TestPassStructAlignmentInt32(
// NOLINTNEXTLINE(whitespace/parens)
@@ -9033,7 +9519,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test alignment and padding of 64 byte int within struct.
DART_EXPORT intptr_t TestPassStructAlignmentInt64(
// NOLINTNEXTLINE(whitespace/parens)
@@ -9072,7 +9558,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Simple nested struct. No alignment gaps on any architectures.
// 10 arguments exhaust registers on all platforms.
DART_EXPORT intptr_t TestPassStruct8BytesNestedIntx10(
@@ -9179,7 +9665,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Simple nested struct. No alignment gaps on any architectures.
// 10 arguments exhaust fpu registers on all platforms.
DART_EXPORT intptr_t TestPassStruct8BytesNestedFloatx10(
@@ -9260,7 +9746,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Simple nested struct. No alignment gaps on any architectures.
// 10 arguments exhaust fpu registers on all platforms.
// The nesting is irregular, testing homogenous float rules on arm and arm64,
@@ -9342,7 +9828,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Simple nested struct. No alignment gaps on any architectures.
// 10 arguments exhaust all registers on all platforms.
DART_EXPORT intptr_t TestPassStruct8BytesNestedMixedx10(
@@ -9436,7 +9922,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Deeper nested struct to test recursive member access.
DART_EXPORT intptr_t TestPassStruct16BytesNestedIntx2(
// NOLINTNEXTLINE(whitespace/parens)
@@ -9494,7 +9980,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Even deeper nested struct to test recursive member access.
DART_EXPORT intptr_t TestPassStruct32BytesNestedIntx2(
// NOLINTNEXTLINE(whitespace/parens)
@@ -9577,7 +10063,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test alignment and padding of nested struct with 16 byte int.
DART_EXPORT intptr_t TestPassStructNestedIntStructAlignmentInt16(
// NOLINTNEXTLINE(whitespace/parens)
@@ -9621,7 +10107,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test alignment and padding of nested struct with 32 byte int.
DART_EXPORT intptr_t TestPassStructNestedIntStructAlignmentInt32(
// NOLINTNEXTLINE(whitespace/parens)
@@ -9665,7 +10151,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test alignment and padding of nested struct with 64 byte int.
DART_EXPORT intptr_t TestPassStructNestedIntStructAlignmentInt64(
// NOLINTNEXTLINE(whitespace/parens)
@@ -9709,7 +10195,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return big irregular struct as smoke test.
DART_EXPORT intptr_t TestPassStructNestedIrregularEvenBiggerx4(
// NOLINTNEXTLINE(whitespace/parens)
@@ -9940,7 +10426,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Simple struct with inline array.
DART_EXPORT intptr_t TestPassStruct8BytesInlineArrayIntx4(
// NOLINTNEXTLINE(whitespace/parens)
@@ -10035,7 +10521,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Irregular struct with inline array.
DART_EXPORT intptr_t TestPassStructInlineArrayIrregularx4(
// NOLINTNEXTLINE(whitespace/parens)
@@ -10107,7 +10593,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Regular larger struct with inline array.
DART_EXPORT intptr_t TestPassStructInlineArray100Bytes(
// NOLINTNEXTLINE(whitespace/parens)
@@ -10309,7 +10795,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Arguments in FPU registers on arm hardfp and arm64.
// 5 struct arguments will exhaust available registers.
DART_EXPORT intptr_t TestPassStructStruct16BytesHomogeneousFloat2x5(
@@ -10380,7 +10866,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Arguments in FPU registers on arm64.
// 5 struct arguments will exhaust available registers.
DART_EXPORT intptr_t TestPassStructStruct32BytesHomogeneousDouble2x5(
@@ -10451,7 +10937,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// On x64, arguments are split over FP and int registers.
// On x64, it will exhaust the integer registers with the 6th argument.
// The rest goes on the stack.
@@ -10589,7 +11075,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test multi dimensional inline array struct as argument.
DART_EXPORT intptr_t TestPassUint8Struct32BytesInlineArrayMultiDimensionalI(
// NOLINTNEXTLINE(whitespace/parens)
@@ -10739,7 +11225,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test struct in multi dimensional inline array.
DART_EXPORT intptr_t TestPassUint8Struct4BytesInlineArrayMultiDimensionalIn(
// NOLINTNEXTLINE(whitespace/parens)
@@ -10789,7 +11275,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Small struct with mis-aligned member.
DART_EXPORT intptr_t TestPassStruct3BytesPackedIntx10(
// NOLINTNEXTLINE(whitespace/parens)
@@ -10871,7 +11357,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Struct with mis-aligned member.
DART_EXPORT intptr_t TestPassStruct8BytesPackedIntx10(
// NOLINTNEXTLINE(whitespace/parens)
@@ -11003,7 +11489,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Struct with mis-aligned member.
// Tests backfilling of CPU and FPU registers.
DART_EXPORT intptr_t TestPassStruct9BytesPackedMixedx10DoubleInt32(
@@ -11093,7 +11579,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// This packed struct happens to have only aligned members.
DART_EXPORT intptr_t TestPassStruct5BytesPackedMixed(
// NOLINTNEXTLINE(whitespace/parens)
@@ -11130,7 +11616,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Check alignment of packed struct in non-packed struct.
DART_EXPORT intptr_t TestPassStructNestedAlignmentStruct5BytesPackedMixed(
// NOLINTNEXTLINE(whitespace/parens)
@@ -11169,7 +11655,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Check alignment of packed struct array in non-packed struct.
DART_EXPORT intptr_t TestPassStruct6BytesInlineArrayInt(
// NOLINTNEXTLINE(whitespace/parens)
@@ -11210,7 +11696,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Check alignment of packed struct array in non-packed struct.
DART_EXPORT intptr_t TestPassStruct15BytesInlineArrayMixed(
// NOLINTNEXTLINE(whitespace/parens)
@@ -11254,7 +11740,521 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
+// Check placement of mixed integer/float union.
+DART_EXPORT intptr_t TestPassUnion4BytesMixedx10(
+ // NOLINTNEXTLINE(whitespace/parens)
+ double (*f)(Union4BytesMixed a0,
+ Union4BytesMixed a1,
+ Union4BytesMixed a2,
+ Union4BytesMixed a3,
+ Union4BytesMixed a4,
+ Union4BytesMixed a5,
+ Union4BytesMixed a6,
+ Union4BytesMixed a7,
+ Union4BytesMixed a8,
+ Union4BytesMixed a9)) {
+ Union4BytesMixed a0;
+ Union4BytesMixed a1;
+ Union4BytesMixed a2;
+ Union4BytesMixed a3;
+ Union4BytesMixed a4;
+ Union4BytesMixed a5;
+ Union4BytesMixed a6;
+ Union4BytesMixed a7;
+ Union4BytesMixed a8;
+ Union4BytesMixed a9;
+
+ a0.a0 = 1;
+ a1.a0 = 2;
+ a2.a0 = 3;
+ a3.a0 = 4;
+ a4.a0 = 5;
+ a5.a0 = 6;
+ a6.a0 = 7;
+ a7.a0 = 8;
+ a8.a0 = 9;
+ a9.a0 = 10;
+
+ std::cout << "Calling TestPassUnion4BytesMixedx10("
+ << "((" << a0.a0 << ", " << a0.a1 << "), (" << a1.a0 << ", "
+ << a1.a1 << "), (" << a2.a0 << ", " << a2.a1 << "), (" << a3.a0
+ << ", " << a3.a1 << "), (" << a4.a0 << ", " << a4.a1 << "), ("
+ << a5.a0 << ", " << a5.a1 << "), (" << a6.a0 << ", " << a6.a1
+ << "), (" << a7.a0 << ", " << a7.a1 << "), (" << a8.a0 << ", "
+ << a8.a1 << "), (" << a9.a0 << ", " << a9.a1 << "))"
+ << ")\n";
+
+ double result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ std::cout << "result = " << result << "\n";
+
+ CHECK_APPROX(55.0, result);
+
+ // Pass argument that will make the Dart callback throw.
+ a0.a0 = 42;
+
+ result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ CHECK_APPROX(0.0, result);
+
+ // Pass argument that will make the Dart callback return null.
+ a0.a0 = 84;
+
+ result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ CHECK_APPROX(0.0, result);
+
+ return 0;
+}
+
+// Used for testing structs and unions by value.
+// Check placement of mixed floats union.
+DART_EXPORT intptr_t TestPassUnion8BytesNestedFloatx10(
+ // NOLINTNEXTLINE(whitespace/parens)
+ double (*f)(Union8BytesNestedFloat a0,
+ Union8BytesNestedFloat a1,
+ Union8BytesNestedFloat a2,
+ Union8BytesNestedFloat a3,
+ Union8BytesNestedFloat a4,
+ Union8BytesNestedFloat a5,
+ Union8BytesNestedFloat a6,
+ Union8BytesNestedFloat a7,
+ Union8BytesNestedFloat a8,
+ Union8BytesNestedFloat a9)) {
+ Union8BytesNestedFloat a0;
+ Union8BytesNestedFloat a1;
+ Union8BytesNestedFloat a2;
+ Union8BytesNestedFloat a3;
+ Union8BytesNestedFloat a4;
+ Union8BytesNestedFloat a5;
+ Union8BytesNestedFloat a6;
+ Union8BytesNestedFloat a7;
+ Union8BytesNestedFloat a8;
+ Union8BytesNestedFloat a9;
+
+ a0.a0 = -1.0;
+ a1.a0 = 2.0;
+ a2.a0 = -3.0;
+ a3.a0 = 4.0;
+ a4.a0 = -5.0;
+ a5.a0 = 6.0;
+ a6.a0 = -7.0;
+ a7.a0 = 8.0;
+ a8.a0 = -9.0;
+ a9.a0 = 10.0;
+
+ std::cout << "Calling TestPassUnion8BytesNestedFloatx10("
+ << "((" << a0.a0 << ", (" << a0.a1.a0 << ", " << a0.a1.a1 << ")), ("
+ << a1.a0 << ", (" << a1.a1.a0 << ", " << a1.a1.a1 << ")), ("
+ << a2.a0 << ", (" << a2.a1.a0 << ", " << a2.a1.a1 << ")), ("
+ << a3.a0 << ", (" << a3.a1.a0 << ", " << a3.a1.a1 << ")), ("
+ << a4.a0 << ", (" << a4.a1.a0 << ", " << a4.a1.a1 << ")), ("
+ << a5.a0 << ", (" << a5.a1.a0 << ", " << a5.a1.a1 << ")), ("
+ << a6.a0 << ", (" << a6.a1.a0 << ", " << a6.a1.a1 << ")), ("
+ << a7.a0 << ", (" << a7.a1.a0 << ", " << a7.a1.a1 << ")), ("
+ << a8.a0 << ", (" << a8.a1.a0 << ", " << a8.a1.a1 << ")), ("
+ << a9.a0 << ", (" << a9.a1.a0 << ", " << a9.a1.a1 << ")))"
+ << ")\n";
+
+ double result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ std::cout << "result = " << result << "\n";
+
+ CHECK_APPROX(5.0, result);
+
+ // Pass argument that will make the Dart callback throw.
+ a0.a0 = 42;
+
+ result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ CHECK_APPROX(0.0, result);
+
+ // Pass argument that will make the Dart callback return null.
+ a0.a0 = 84;
+
+ result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ CHECK_APPROX(0.0, result);
+
+ return 0;
+}
+
+// Used for testing structs and unions by value.
+// Mixed-size union argument.
+DART_EXPORT intptr_t TestPassUnion9BytesNestedIntx10(
+ // NOLINTNEXTLINE(whitespace/parens)
+ double (*f)(Union9BytesNestedInt a0,
+ Union9BytesNestedInt a1,
+ Union9BytesNestedInt a2,
+ Union9BytesNestedInt a3,
+ Union9BytesNestedInt a4,
+ Union9BytesNestedInt a5,
+ Union9BytesNestedInt a6,
+ Union9BytesNestedInt a7,
+ Union9BytesNestedInt a8,
+ Union9BytesNestedInt a9)) {
+ Union9BytesNestedInt a0;
+ Union9BytesNestedInt a1;
+ Union9BytesNestedInt a2;
+ Union9BytesNestedInt a3;
+ Union9BytesNestedInt a4;
+ Union9BytesNestedInt a5;
+ Union9BytesNestedInt a6;
+ Union9BytesNestedInt a7;
+ Union9BytesNestedInt a8;
+ Union9BytesNestedInt a9;
+
+ a0.a0.a0 = -1;
+ a0.a0.a1 = 2;
+ a0.a0.a2 = -3;
+ a1.a0.a0 = 4;
+ a1.a0.a1 = -5;
+ a1.a0.a2 = 6;
+ a2.a0.a0 = -7;
+ a2.a0.a1 = 8;
+ a2.a0.a2 = -9;
+ a3.a0.a0 = 10;
+ a3.a0.a1 = -11;
+ a3.a0.a2 = 12;
+ a4.a0.a0 = -13;
+ a4.a0.a1 = 14;
+ a4.a0.a2 = -15;
+ a5.a0.a0 = 16;
+ a5.a0.a1 = -17;
+ a5.a0.a2 = 18;
+ a6.a0.a0 = -19;
+ a6.a0.a1 = 20;
+ a6.a0.a2 = -21;
+ a7.a0.a0 = 22;
+ a7.a0.a1 = -23;
+ a7.a0.a2 = 24;
+ a8.a0.a0 = -25;
+ a8.a0.a1 = 26;
+ a8.a0.a2 = -27;
+ a9.a0.a0 = 28;
+ a9.a0.a1 = -29;
+ a9.a0.a2 = 30;
+
+ std::cout << "Calling TestPassUnion9BytesNestedIntx10("
+ << "(((" << a0.a0.a0 << ", " << a0.a0.a1 << ", " << a0.a0.a2
+ << "), (" << static_cast<int>(a0.a1.a0) << ", "
+ << static_cast<int>(a0.a1.a1) << ", " << static_cast<int>(a0.a1.a2)
+ << ", " << static_cast<int>(a0.a1.a3) << ", "
+ << static_cast<int>(a0.a1.a4) << ", " << static_cast<int>(a0.a1.a5)
+ << ", " << static_cast<int>(a0.a1.a6) << ", "
+ << static_cast<int>(a0.a1.a7) << ", " << static_cast<int>(a0.a1.a8)
+ << ")), ((" << a1.a0.a0 << ", " << a1.a0.a1 << ", " << a1.a0.a2
+ << "), (" << static_cast<int>(a1.a1.a0) << ", "
+ << static_cast<int>(a1.a1.a1) << ", " << static_cast<int>(a1.a1.a2)
+ << ", " << static_cast<int>(a1.a1.a3) << ", "
+ << static_cast<int>(a1.a1.a4) << ", " << static_cast<int>(a1.a1.a5)
+ << ", " << static_cast<int>(a1.a1.a6) << ", "
+ << static_cast<int>(a1.a1.a7) << ", " << static_cast<int>(a1.a1.a8)
+ << ")), ((" << a2.a0.a0 << ", " << a2.a0.a1 << ", " << a2.a0.a2
+ << "), (" << static_cast<int>(a2.a1.a0) << ", "
+ << static_cast<int>(a2.a1.a1) << ", " << static_cast<int>(a2.a1.a2)
+ << ", " << static_cast<int>(a2.a1.a3) << ", "
+ << static_cast<int>(a2.a1.a4) << ", " << static_cast<int>(a2.a1.a5)
+ << ", " << static_cast<int>(a2.a1.a6) << ", "
+ << static_cast<int>(a2.a1.a7) << ", " << static_cast<int>(a2.a1.a8)
+ << ")), ((" << a3.a0.a0 << ", " << a3.a0.a1 << ", " << a3.a0.a2
+ << "), (" << static_cast<int>(a3.a1.a0) << ", "
+ << static_cast<int>(a3.a1.a1) << ", " << static_cast<int>(a3.a1.a2)
+ << ", " << static_cast<int>(a3.a1.a3) << ", "
+ << static_cast<int>(a3.a1.a4) << ", " << static_cast<int>(a3.a1.a5)
+ << ", " << static_cast<int>(a3.a1.a6) << ", "
+ << static_cast<int>(a3.a1.a7) << ", " << static_cast<int>(a3.a1.a8)
+ << ")), ((" << a4.a0.a0 << ", " << a4.a0.a1 << ", " << a4.a0.a2
+ << "), (" << static_cast<int>(a4.a1.a0) << ", "
+ << static_cast<int>(a4.a1.a1) << ", " << static_cast<int>(a4.a1.a2)
+ << ", " << static_cast<int>(a4.a1.a3) << ", "
+ << static_cast<int>(a4.a1.a4) << ", " << static_cast<int>(a4.a1.a5)
+ << ", " << static_cast<int>(a4.a1.a6) << ", "
+ << static_cast<int>(a4.a1.a7) << ", " << static_cast<int>(a4.a1.a8)
+ << ")), ((" << a5.a0.a0 << ", " << a5.a0.a1 << ", " << a5.a0.a2
+ << "), (" << static_cast<int>(a5.a1.a0) << ", "
+ << static_cast<int>(a5.a1.a1) << ", " << static_cast<int>(a5.a1.a2)
+ << ", " << static_cast<int>(a5.a1.a3) << ", "
+ << static_cast<int>(a5.a1.a4) << ", " << static_cast<int>(a5.a1.a5)
+ << ", " << static_cast<int>(a5.a1.a6) << ", "
+ << static_cast<int>(a5.a1.a7) << ", " << static_cast<int>(a5.a1.a8)
+ << ")), ((" << a6.a0.a0 << ", " << a6.a0.a1 << ", " << a6.a0.a2
+ << "), (" << static_cast<int>(a6.a1.a0) << ", "
+ << static_cast<int>(a6.a1.a1) << ", " << static_cast<int>(a6.a1.a2)
+ << ", " << static_cast<int>(a6.a1.a3) << ", "
+ << static_cast<int>(a6.a1.a4) << ", " << static_cast<int>(a6.a1.a5)
+ << ", " << static_cast<int>(a6.a1.a6) << ", "
+ << static_cast<int>(a6.a1.a7) << ", " << static_cast<int>(a6.a1.a8)
+ << ")), ((" << a7.a0.a0 << ", " << a7.a0.a1 << ", " << a7.a0.a2
+ << "), (" << static_cast<int>(a7.a1.a0) << ", "
+ << static_cast<int>(a7.a1.a1) << ", " << static_cast<int>(a7.a1.a2)
+ << ", " << static_cast<int>(a7.a1.a3) << ", "
+ << static_cast<int>(a7.a1.a4) << ", " << static_cast<int>(a7.a1.a5)
+ << ", " << static_cast<int>(a7.a1.a6) << ", "
+ << static_cast<int>(a7.a1.a7) << ", " << static_cast<int>(a7.a1.a8)
+ << ")), ((" << a8.a0.a0 << ", " << a8.a0.a1 << ", " << a8.a0.a2
+ << "), (" << static_cast<int>(a8.a1.a0) << ", "
+ << static_cast<int>(a8.a1.a1) << ", " << static_cast<int>(a8.a1.a2)
+ << ", " << static_cast<int>(a8.a1.a3) << ", "
+ << static_cast<int>(a8.a1.a4) << ", " << static_cast<int>(a8.a1.a5)
+ << ", " << static_cast<int>(a8.a1.a6) << ", "
+ << static_cast<int>(a8.a1.a7) << ", " << static_cast<int>(a8.a1.a8)
+ << ")), ((" << a9.a0.a0 << ", " << a9.a0.a1 << ", " << a9.a0.a2
+ << "), (" << static_cast<int>(a9.a1.a0) << ", "
+ << static_cast<int>(a9.a1.a1) << ", " << static_cast<int>(a9.a1.a2)
+ << ", " << static_cast<int>(a9.a1.a3) << ", "
+ << static_cast<int>(a9.a1.a4) << ", " << static_cast<int>(a9.a1.a5)
+ << ", " << static_cast<int>(a9.a1.a6) << ", "
+ << static_cast<int>(a9.a1.a7) << ", " << static_cast<int>(a9.a1.a8)
+ << ")))"
+ << ")\n";
+
+ double result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ std::cout << "result = " << result << "\n";
+
+ CHECK_APPROX(15.0, result);
+
+ // Pass argument that will make the Dart callback throw.
+ a0.a0.a0 = 42;
+
+ result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ CHECK_APPROX(0.0, result);
+
+ // Pass argument that will make the Dart callback return null.
+ a0.a0.a0 = 84;
+
+ result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ CHECK_APPROX(0.0, result);
+
+ return 0;
+}
+
+// Used for testing structs and unions by value.
+// Union with homogenous floats.
+DART_EXPORT intptr_t TestPassUnion16BytesNestedInlineArrayFloatx10(
+ // NOLINTNEXTLINE(whitespace/parens)
+ double (*f)(Union16BytesNestedInlineArrayFloat a0,
+ Union16BytesNestedInlineArrayFloat a1,
+ Union16BytesNestedInlineArrayFloat a2,
+ Union16BytesNestedInlineArrayFloat a3,
+ Union16BytesNestedInlineArrayFloat a4,
+ Union16BytesNestedInlineArrayFloat a5,
+ Union16BytesNestedInlineArrayFloat a6,
+ Union16BytesNestedInlineArrayFloat a7,
+ Union16BytesNestedInlineArrayFloat a8,
+ Union16BytesNestedInlineArrayFloat a9)) {
+ Union16BytesNestedInlineArrayFloat a0;
+ Union16BytesNestedInlineArrayFloat a1;
+ Union16BytesNestedInlineArrayFloat a2;
+ Union16BytesNestedInlineArrayFloat a3;
+ Union16BytesNestedInlineArrayFloat a4;
+ Union16BytesNestedInlineArrayFloat a5;
+ Union16BytesNestedInlineArrayFloat a6;
+ Union16BytesNestedInlineArrayFloat a7;
+ Union16BytesNestedInlineArrayFloat a8;
+ Union16BytesNestedInlineArrayFloat a9;
+
+ a0.a0[0] = -1.0;
+ a0.a0[1] = 2.0;
+ a0.a0[2] = -3.0;
+ a0.a0[3] = 4.0;
+ a1.a0[0] = -5.0;
+ a1.a0[1] = 6.0;
+ a1.a0[2] = -7.0;
+ a1.a0[3] = 8.0;
+ a2.a0[0] = -9.0;
+ a2.a0[1] = 10.0;
+ a2.a0[2] = -11.0;
+ a2.a0[3] = 12.0;
+ a3.a0[0] = -13.0;
+ a3.a0[1] = 14.0;
+ a3.a0[2] = -15.0;
+ a3.a0[3] = 16.0;
+ a4.a0[0] = -17.0;
+ a4.a0[1] = 18.0;
+ a4.a0[2] = -19.0;
+ a4.a0[3] = 20.0;
+ a5.a0[0] = -21.0;
+ a5.a0[1] = 22.0;
+ a5.a0[2] = -23.0;
+ a5.a0[3] = 24.0;
+ a6.a0[0] = -25.0;
+ a6.a0[1] = 26.0;
+ a6.a0[2] = -27.0;
+ a6.a0[3] = 28.0;
+ a7.a0[0] = -29.0;
+ a7.a0[1] = 30.0;
+ a7.a0[2] = -31.0;
+ a7.a0[3] = 32.0;
+ a8.a0[0] = -33.0;
+ a8.a0[1] = 34.0;
+ a8.a0[2] = -35.0;
+ a8.a0[3] = 36.0;
+ a9.a0[0] = -37.0;
+ a9.a0[1] = 38.0;
+ a9.a0[2] = -39.0;
+ a9.a0[3] = 40.0;
+
+ std::cout << "Calling TestPassUnion16BytesNestedInlineArrayFloatx10("
+ << "(([" << a0.a0[0] << ", " << a0.a0[1] << ", " << a0.a0[2] << ", "
+ << a0.a0[3] << "], (" << a0.a1.a0 << ", " << a0.a1.a1 << ", "
+ << a0.a1.a2 << ", " << a0.a1.a3 << ")), ([" << a1.a0[0] << ", "
+ << a1.a0[1] << ", " << a1.a0[2] << ", " << a1.a0[3] << "], ("
+ << a1.a1.a0 << ", " << a1.a1.a1 << ", " << a1.a1.a2 << ", "
+ << a1.a1.a3 << ")), ([" << a2.a0[0] << ", " << a2.a0[1] << ", "
+ << a2.a0[2] << ", " << a2.a0[3] << "], (" << a2.a1.a0 << ", "
+ << a2.a1.a1 << ", " << a2.a1.a2 << ", " << a2.a1.a3 << ")), (["
+ << a3.a0[0] << ", " << a3.a0[1] << ", " << a3.a0[2] << ", "
+ << a3.a0[3] << "], (" << a3.a1.a0 << ", " << a3.a1.a1 << ", "
+ << a3.a1.a2 << ", " << a3.a1.a3 << ")), ([" << a4.a0[0] << ", "
+ << a4.a0[1] << ", " << a4.a0[2] << ", " << a4.a0[3] << "], ("
+ << a4.a1.a0 << ", " << a4.a1.a1 << ", " << a4.a1.a2 << ", "
+ << a4.a1.a3 << ")), ([" << a5.a0[0] << ", " << a5.a0[1] << ", "
+ << a5.a0[2] << ", " << a5.a0[3] << "], (" << a5.a1.a0 << ", "
+ << a5.a1.a1 << ", " << a5.a1.a2 << ", " << a5.a1.a3 << ")), (["
+ << a6.a0[0] << ", " << a6.a0[1] << ", " << a6.a0[2] << ", "
+ << a6.a0[3] << "], (" << a6.a1.a0 << ", " << a6.a1.a1 << ", "
+ << a6.a1.a2 << ", " << a6.a1.a3 << ")), ([" << a7.a0[0] << ", "
+ << a7.a0[1] << ", " << a7.a0[2] << ", " << a7.a0[3] << "], ("
+ << a7.a1.a0 << ", " << a7.a1.a1 << ", " << a7.a1.a2 << ", "
+ << a7.a1.a3 << ")), ([" << a8.a0[0] << ", " << a8.a0[1] << ", "
+ << a8.a0[2] << ", " << a8.a0[3] << "], (" << a8.a1.a0 << ", "
+ << a8.a1.a1 << ", " << a8.a1.a2 << ", " << a8.a1.a3 << ")), (["
+ << a9.a0[0] << ", " << a9.a0[1] << ", " << a9.a0[2] << ", "
+ << a9.a0[3] << "], (" << a9.a1.a0 << ", " << a9.a1.a1 << ", "
+ << a9.a1.a2 << ", " << a9.a1.a3 << ")))"
+ << ")\n";
+
+ double result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ std::cout << "result = " << result << "\n";
+
+ CHECK_APPROX(20.0, result);
+
+ // Pass argument that will make the Dart callback throw.
+ a0.a0[0] = 42;
+
+ result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ CHECK_APPROX(0.0, result);
+
+ // Pass argument that will make the Dart callback return null.
+ a0.a0[0] = 84;
+
+ result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ CHECK_APPROX(0.0, result);
+
+ return 0;
+}
+
+// Used for testing structs and unions by value.
+// Union with homogenous floats.
+DART_EXPORT intptr_t TestPassUnion16BytesNestedFloatx10(
+ // NOLINTNEXTLINE(whitespace/parens)
+ double (*f)(Union16BytesNestedFloat a0,
+ Union16BytesNestedFloat a1,
+ Union16BytesNestedFloat a2,
+ Union16BytesNestedFloat a3,
+ Union16BytesNestedFloat a4,
+ Union16BytesNestedFloat a5,
+ Union16BytesNestedFloat a6,
+ Union16BytesNestedFloat a7,
+ Union16BytesNestedFloat a8,
+ Union16BytesNestedFloat a9)) {
+ Union16BytesNestedFloat a0;
+ Union16BytesNestedFloat a1;
+ Union16BytesNestedFloat a2;
+ Union16BytesNestedFloat a3;
+ Union16BytesNestedFloat a4;
+ Union16BytesNestedFloat a5;
+ Union16BytesNestedFloat a6;
+ Union16BytesNestedFloat a7;
+ Union16BytesNestedFloat a8;
+ Union16BytesNestedFloat a9;
+
+ a0.a0.a0 = -1.0;
+ a0.a0.a1 = 2.0;
+ a1.a0.a0 = -3.0;
+ a1.a0.a1 = 4.0;
+ a2.a0.a0 = -5.0;
+ a2.a0.a1 = 6.0;
+ a3.a0.a0 = -7.0;
+ a3.a0.a1 = 8.0;
+ a4.a0.a0 = -9.0;
+ a4.a0.a1 = 10.0;
+ a5.a0.a0 = -11.0;
+ a5.a0.a1 = 12.0;
+ a6.a0.a0 = -13.0;
+ a6.a0.a1 = 14.0;
+ a7.a0.a0 = -15.0;
+ a7.a0.a1 = 16.0;
+ a8.a0.a0 = -17.0;
+ a8.a0.a1 = 18.0;
+ a9.a0.a0 = -19.0;
+ a9.a0.a1 = 20.0;
+
+ std::cout << "Calling TestPassUnion16BytesNestedFloatx10("
+ << "(((" << a0.a0.a0 << ", " << a0.a0.a1 << "), (" << a0.a1.a0
+ << ", " << a0.a1.a1 << ", " << a0.a1.a2 << "), (" << a0.a2.a0
+ << ", " << a0.a2.a1 << ", " << a0.a2.a2 << ", " << a0.a2.a3
+ << ")), ((" << a1.a0.a0 << ", " << a1.a0.a1 << "), (" << a1.a1.a0
+ << ", " << a1.a1.a1 << ", " << a1.a1.a2 << "), (" << a1.a2.a0
+ << ", " << a1.a2.a1 << ", " << a1.a2.a2 << ", " << a1.a2.a3
+ << ")), ((" << a2.a0.a0 << ", " << a2.a0.a1 << "), (" << a2.a1.a0
+ << ", " << a2.a1.a1 << ", " << a2.a1.a2 << "), (" << a2.a2.a0
+ << ", " << a2.a2.a1 << ", " << a2.a2.a2 << ", " << a2.a2.a3
+ << ")), ((" << a3.a0.a0 << ", " << a3.a0.a1 << "), (" << a3.a1.a0
+ << ", " << a3.a1.a1 << ", " << a3.a1.a2 << "), (" << a3.a2.a0
+ << ", " << a3.a2.a1 << ", " << a3.a2.a2 << ", " << a3.a2.a3
+ << ")), ((" << a4.a0.a0 << ", " << a4.a0.a1 << "), (" << a4.a1.a0
+ << ", " << a4.a1.a1 << ", " << a4.a1.a2 << "), (" << a4.a2.a0
+ << ", " << a4.a2.a1 << ", " << a4.a2.a2 << ", " << a4.a2.a3
+ << ")), ((" << a5.a0.a0 << ", " << a5.a0.a1 << "), (" << a5.a1.a0
+ << ", " << a5.a1.a1 << ", " << a5.a1.a2 << "), (" << a5.a2.a0
+ << ", " << a5.a2.a1 << ", " << a5.a2.a2 << ", " << a5.a2.a3
+ << ")), ((" << a6.a0.a0 << ", " << a6.a0.a1 << "), (" << a6.a1.a0
+ << ", " << a6.a1.a1 << ", " << a6.a1.a2 << "), (" << a6.a2.a0
+ << ", " << a6.a2.a1 << ", " << a6.a2.a2 << ", " << a6.a2.a3
+ << ")), ((" << a7.a0.a0 << ", " << a7.a0.a1 << "), (" << a7.a1.a0
+ << ", " << a7.a1.a1 << ", " << a7.a1.a2 << "), (" << a7.a2.a0
+ << ", " << a7.a2.a1 << ", " << a7.a2.a2 << ", " << a7.a2.a3
+ << ")), ((" << a8.a0.a0 << ", " << a8.a0.a1 << "), (" << a8.a1.a0
+ << ", " << a8.a1.a1 << ", " << a8.a1.a2 << "), (" << a8.a2.a0
+ << ", " << a8.a2.a1 << ", " << a8.a2.a2 << ", " << a8.a2.a3
+ << ")), ((" << a9.a0.a0 << ", " << a9.a0.a1 << "), (" << a9.a1.a0
+ << ", " << a9.a1.a1 << ", " << a9.a1.a2 << "), (" << a9.a2.a0
+ << ", " << a9.a2.a1 << ", " << a9.a2.a2 << ", " << a9.a2.a3 << ")))"
+ << ")\n";
+
+ double result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ std::cout << "result = " << result << "\n";
+
+ CHECK_APPROX(10.0, result);
+
+ // Pass argument that will make the Dart callback throw.
+ a0.a0.a0 = 42;
+
+ result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ CHECK_APPROX(0.0, result);
+
+ // Pass argument that will make the Dart callback return null.
+ a0.a0.a0 = 84;
+
+ result = f(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ CHECK_APPROX(0.0, result);
+
+ return 0;
+}
+
+// Used for testing structs and unions by value.
// Smallest struct with data.
DART_EXPORT intptr_t TestReturnStruct1ByteInt(
// NOLINTNEXTLINE(whitespace/parens)
@@ -11292,7 +12292,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Smaller than word size return value on all architectures.
DART_EXPORT intptr_t TestReturnStruct3BytesHomogeneousUint8(
// NOLINTNEXTLINE(whitespace/parens)
@@ -11343,7 +12343,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Smaller than word size return value on all architectures.
// With alignment rules taken into account size is 4 bytes.
DART_EXPORT intptr_t TestReturnStruct3BytesInt2ByteAligned(
@@ -11387,7 +12387,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Word size return value on 32 bit architectures..
DART_EXPORT intptr_t TestReturnStruct4BytesHomogeneousInt16(
// NOLINTNEXTLINE(whitespace/parens)
@@ -11430,7 +12430,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Non-wordsize return value.
DART_EXPORT intptr_t TestReturnStruct7BytesHomogeneousUint8(
// NOLINTNEXTLINE(whitespace/parens)
@@ -11513,7 +12513,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Non-wordsize return value.
// With alignment rules taken into account size is 8 bytes.
DART_EXPORT intptr_t TestReturnStruct7BytesInt4ByteAligned(
@@ -11563,7 +12563,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return value in integer registers on many architectures.
DART_EXPORT intptr_t TestReturnStruct8BytesInt(
// NOLINTNEXTLINE(whitespace/parens)
@@ -11611,7 +12611,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return value in FP registers on many architectures.
DART_EXPORT intptr_t TestReturnStruct8BytesHomogeneousFloat(
// NOLINTNEXTLINE(whitespace/parens)
@@ -11654,7 +12654,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return value split over FP and integer register in x64.
DART_EXPORT intptr_t TestReturnStruct8BytesMixed(
// NOLINTNEXTLINE(whitespace/parens)
@@ -11702,7 +12702,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// The minimum alignment of this struct is only 1 byte based on its fields.
// Test that the memory backing these structs is the right size and that
// dart:ffi trampolines do not write outside this size.
@@ -11802,7 +12802,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return value in two integer registers on x64.
// With alignment rules taken into account size is 12 or 16 bytes.
DART_EXPORT intptr_t TestReturnStruct9BytesInt4Or8ByteAligned(
@@ -11846,7 +12846,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return value in FPU registers, but does not use all registers on arm hardfp
// and arm64.
DART_EXPORT intptr_t TestReturnStruct12BytesHomogeneousFloat(
@@ -11895,7 +12895,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return value in FPU registers on arm hardfp and arm64.
DART_EXPORT intptr_t TestReturnStruct16BytesHomogeneousFloat(
// NOLINTNEXTLINE(whitespace/parens)
@@ -11950,7 +12950,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return value split over FP and integer register in x64.
DART_EXPORT intptr_t TestReturnStruct16BytesMixed(
// NOLINTNEXTLINE(whitespace/parens)
@@ -11993,7 +12993,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return value split over FP and integer register in x64.
// The integer register contains half float half int.
DART_EXPORT intptr_t TestReturnStruct16BytesMixed2(
@@ -12048,7 +13048,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Rerturn value returned in preallocated space passed by pointer on most ABIs.
// Is non word size on purpose, to test that structs are rounded up to word size
// on all ABIs.
@@ -12099,7 +13099,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// The minimum alignment of this struct is only 1 byte based on its fields.
// Test that the memory backing these structs is the right size and that
// dart:ffi trampolines do not write outside this size.
@@ -12278,7 +13278,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return value too big to go in cpu registers on arm64.
DART_EXPORT intptr_t TestReturnStruct20BytesHomogeneousInt32(
// NOLINTNEXTLINE(whitespace/parens)
@@ -12339,7 +13339,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return value too big to go in FPU registers on x64, arm hardfp and arm64.
DART_EXPORT intptr_t TestReturnStruct20BytesHomogeneousFloat(
// NOLINTNEXTLINE(whitespace/parens)
@@ -12400,7 +13400,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return value in FPU registers on arm64.
DART_EXPORT intptr_t TestReturnStruct32BytesHomogeneousDouble(
// NOLINTNEXTLINE(whitespace/parens)
@@ -12455,7 +13455,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return value too big to go in FPU registers on arm64.
DART_EXPORT intptr_t TestReturnStruct40BytesHomogeneousDouble(
// NOLINTNEXTLINE(whitespace/parens)
@@ -12516,7 +13516,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test 1kb struct.
DART_EXPORT intptr_t TestReturnStruct1024BytesHomogeneousUint64(
// NOLINTNEXTLINE(whitespace/parens)
@@ -13414,7 +14414,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Small struct with mis-aligned member.
DART_EXPORT intptr_t TestReturnStruct3BytesPackedInt(
// NOLINTNEXTLINE(whitespace/parens)
@@ -13457,7 +14457,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Struct with mis-aligned member.
DART_EXPORT intptr_t TestReturnStruct8BytesPackedInt(
// NOLINTNEXTLINE(whitespace/parens)
@@ -13521,7 +14521,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Struct with mis-aligned member.
// Tests backfilling of CPU and FPU registers.
DART_EXPORT intptr_t TestReturnStruct9BytesPackedMixed(
@@ -13565,7 +14565,184 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
+// Returning a mixed integer/float union.
+DART_EXPORT intptr_t TestReturnUnion4BytesMixed(
+ // NOLINTNEXTLINE(whitespace/parens)
+ Union4BytesMixed (*f)(uint32_t a0)) {
+ uint32_t a0;
+
+ a0 = 1;
+
+ std::cout << "Calling TestReturnUnion4BytesMixed("
+ << "(" << a0 << ")"
+ << ")\n";
+
+ Union4BytesMixed result = f(a0);
+
+ std::cout << "result = "
+ << "(" << result.a0 << ", " << result.a1 << ")"
+ << "\n";
+
+ CHECK_EQ(a0, result.a0);
+
+ // Pass argument that will make the Dart callback throw.
+ a0 = 42;
+
+ result = f(a0);
+
+ CHECK_EQ(0, result.a0);
+
+ // Pass argument that will make the Dart callback return null.
+ a0 = 84;
+
+ result = f(a0);
+
+ CHECK_EQ(0, result.a0);
+
+ return 0;
+}
+
+// Used for testing structs and unions by value.
+// Returning a floating point only union.
+DART_EXPORT intptr_t TestReturnUnion8BytesNestedFloat(
+ // NOLINTNEXTLINE(whitespace/parens)
+ Union8BytesNestedFloat (*f)(double a0)) {
+ double a0;
+
+ a0 = -1.0;
+
+ std::cout << "Calling TestReturnUnion8BytesNestedFloat("
+ << "(" << a0 << ")"
+ << ")\n";
+
+ Union8BytesNestedFloat result = f(a0);
+
+ std::cout << "result = "
+ << "(" << result.a0 << ", (" << result.a1.a0 << ", " << result.a1.a1
+ << "))"
+ << "\n";
+
+ CHECK_APPROX(a0, result.a0);
+
+ // Pass argument that will make the Dart callback throw.
+ a0 = 42;
+
+ result = f(a0);
+
+ CHECK_APPROX(0.0, result.a0);
+
+ // Pass argument that will make the Dart callback return null.
+ a0 = 84;
+
+ result = f(a0);
+
+ CHECK_APPROX(0.0, result.a0);
+
+ return 0;
+}
+
+// Used for testing structs and unions by value.
+// Returning a mixed-size union.
+DART_EXPORT intptr_t TestReturnUnion9BytesNestedInt(
+ // NOLINTNEXTLINE(whitespace/parens)
+ Union9BytesNestedInt (*f)(Struct8BytesInt a0)) {
+ Struct8BytesInt a0;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+
+ std::cout << "Calling TestReturnUnion9BytesNestedInt("
+ << "((" << a0.a0 << ", " << a0.a1 << ", " << a0.a2 << "))"
+ << ")\n";
+
+ Union9BytesNestedInt result = f(a0);
+
+ std::cout << "result = "
+ << "((" << result.a0.a0 << ", " << result.a0.a1 << ", "
+ << result.a0.a2 << "), (" << static_cast<int>(result.a1.a0) << ", "
+ << static_cast<int>(result.a1.a1) << ", "
+ << static_cast<int>(result.a1.a2) << ", "
+ << static_cast<int>(result.a1.a3) << ", "
+ << static_cast<int>(result.a1.a4) << ", "
+ << static_cast<int>(result.a1.a5) << ", "
+ << static_cast<int>(result.a1.a6) << ", "
+ << static_cast<int>(result.a1.a7) << ", "
+ << static_cast<int>(result.a1.a8) << "))"
+ << "\n";
+
+ CHECK_EQ(a0.a0, result.a0.a0);
+ CHECK_EQ(a0.a1, result.a0.a1);
+ CHECK_EQ(a0.a2, result.a0.a2);
+
+ // Pass argument that will make the Dart callback throw.
+ a0.a0 = 42;
+
+ result = f(a0);
+
+ CHECK_EQ(0, result.a0.a0);
+ CHECK_EQ(0, result.a0.a1);
+ CHECK_EQ(0, result.a0.a2);
+
+ // Pass argument that will make the Dart callback return null.
+ a0.a0 = 84;
+
+ result = f(a0);
+
+ CHECK_EQ(0, result.a0.a0);
+ CHECK_EQ(0, result.a0.a1);
+ CHECK_EQ(0, result.a0.a2);
+
+ return 0;
+}
+
+// Used for testing structs and unions by value.
+// Returning union with homogenous floats.
+DART_EXPORT intptr_t TestReturnUnion16BytesNestedFloat(
+ // NOLINTNEXTLINE(whitespace/parens)
+ Union16BytesNestedFloat (*f)(Struct8BytesHomogeneousFloat a0)) {
+ Struct8BytesHomogeneousFloat a0;
+
+ a0.a0 = -1.0;
+ a0.a1 = 2.0;
+
+ std::cout << "Calling TestReturnUnion16BytesNestedFloat("
+ << "((" << a0.a0 << ", " << a0.a1 << "))"
+ << ")\n";
+
+ Union16BytesNestedFloat result = f(a0);
+
+ std::cout << "result = "
+ << "((" << result.a0.a0 << ", " << result.a0.a1 << "), ("
+ << result.a1.a0 << ", " << result.a1.a1 << ", " << result.a1.a2
+ << "), (" << result.a2.a0 << ", " << result.a2.a1 << ", "
+ << result.a2.a2 << ", " << result.a2.a3 << "))"
+ << "\n";
+
+ CHECK_APPROX(a0.a0, result.a0.a0);
+ CHECK_APPROX(a0.a1, result.a0.a1);
+
+ // Pass argument that will make the Dart callback throw.
+ a0.a0 = 42;
+
+ result = f(a0);
+
+ CHECK_APPROX(0.0, result.a0.a0);
+ CHECK_APPROX(0.0, result.a0.a1);
+
+ // Pass argument that will make the Dart callback return null.
+ a0.a0 = 84;
+
+ result = f(a0);
+
+ CHECK_APPROX(0.0, result.a0.a0);
+ CHECK_APPROX(0.0, result.a0.a1);
+
+ return 0;
+}
+
+// Used for testing structs and unions by value.
// Test that a struct passed in as argument can be returned.
// Especially for ffi callbacks.
// Struct is passed in int registers in most ABIs.
@@ -13605,7 +14782,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test that a struct passed in as argument can be returned.
// Especially for ffi callbacks.
// Struct is passed on stack on all ABIs.
@@ -13671,7 +14848,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test that a struct passed in as argument can be returned.
// Especially for ffi callbacks.
// Struct is passed in float registers in most ABIs.
@@ -13715,7 +14892,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// On arm64, both argument and return value are passed in by pointer.
DART_EXPORT intptr_t TestReturnStructArgumentStruct20BytesHomogeneousInt32(
// NOLINTNEXTLINE(whitespace/parens)
@@ -13771,7 +14948,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// On arm64, both argument and return value are passed in by pointer.
// Ints exhaust registers, so that pointer is passed on stack.
DART_EXPORT intptr_t TestReturnStructArgumentInt32x8Struct20BytesHomogeneou(
@@ -13853,7 +15030,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test returning struct with inline array.
DART_EXPORT intptr_t TestReturnStructArgumentStruct8BytesInlineArrayInt(
// NOLINTNEXTLINE(whitespace/parens)
@@ -13916,7 +15093,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return value in FPU registers on arm hardfp and arm64.
DART_EXPORT intptr_t TestReturnStructArgumentStructStruct16BytesHomogeneous(
// NOLINTNEXTLINE(whitespace/parens)
@@ -13972,7 +15149,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return value in FPU registers on arm64.
DART_EXPORT intptr_t TestReturnStructArgumentStructStruct32BytesHomogeneous(
// NOLINTNEXTLINE(whitespace/parens)
@@ -14028,7 +15205,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// On x64 Linux, return value is split over FP and int registers.
DART_EXPORT intptr_t TestReturnStructArgumentStructStruct16BytesMixed3(
// NOLINTNEXTLINE(whitespace/parens)
@@ -14099,7 +15276,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test alignment and padding of 16 byte int within struct.
DART_EXPORT intptr_t TestReturnStructAlignmentInt16(
// NOLINTNEXTLINE(whitespace/parens)
@@ -14149,7 +15326,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test alignment and padding of 32 byte int within struct.
DART_EXPORT intptr_t TestReturnStructAlignmentInt32(
// NOLINTNEXTLINE(whitespace/parens)
@@ -14199,7 +15376,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test alignment and padding of 64 byte int within struct.
DART_EXPORT intptr_t TestReturnStructAlignmentInt64(
// NOLINTNEXTLINE(whitespace/parens)
@@ -14249,7 +15426,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Simple nested struct.
DART_EXPORT intptr_t TestReturnStruct8BytesNestedInt(
// NOLINTNEXTLINE(whitespace/parens)
@@ -14303,7 +15480,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Simple nested struct with floats.
DART_EXPORT intptr_t TestReturnStruct8BytesNestedFloat(
// NOLINTNEXTLINE(whitespace/parens)
@@ -14346,7 +15523,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// The nesting is irregular, testing homogenous float rules on arm and arm64,
// and the fpu register usage on x64.
DART_EXPORT intptr_t TestReturnStruct8BytesNestedFloat2(
@@ -14390,7 +15567,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Simple nested struct with mixed members.
DART_EXPORT intptr_t TestReturnStruct8BytesNestedMixed(
// NOLINTNEXTLINE(whitespace/parens)
@@ -14439,7 +15616,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Deeper nested struct to test recursive member access.
DART_EXPORT intptr_t TestReturnStruct16BytesNestedInt(
// NOLINTNEXTLINE(whitespace/parens)
@@ -14512,7 +15689,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Even deeper nested struct to test recursive member access.
DART_EXPORT intptr_t TestReturnStruct32BytesNestedInt(
// NOLINTNEXTLINE(whitespace/parens)
@@ -14626,7 +15803,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test alignment and padding of nested struct with 16 byte int.
DART_EXPORT intptr_t TestReturnStructNestedIntStructAlignmentInt16(
// NOLINTNEXTLINE(whitespace/parens)
@@ -14691,7 +15868,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test alignment and padding of nested struct with 32 byte int.
DART_EXPORT intptr_t TestReturnStructNestedIntStructAlignmentInt32(
// NOLINTNEXTLINE(whitespace/parens)
@@ -14756,7 +15933,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Test alignment and padding of nested struct with 64 byte int.
DART_EXPORT intptr_t TestReturnStructNestedIntStructAlignmentInt64(
// NOLINTNEXTLINE(whitespace/parens)
@@ -14821,7 +15998,7 @@
return 0;
}
-// Used for testing structs by value.
+// Used for testing structs and unions by value.
// Return big irregular struct as smoke test.
DART_EXPORT intptr_t TestReturnStructNestedIrregularEvenBigger(
// NOLINTNEXTLINE(whitespace/parens)
diff --git a/runtime/docs/dwarf_stack_traces.md b/runtime/docs/dwarf_stack_traces.md
index afddbc7..e1f6c5e 100644
--- a/runtime/docs/dwarf_stack_traces.md
+++ b/runtime/docs/dwarf_stack_traces.md
@@ -46,7 +46,7 @@
`--dwarf-stack-traces` in a 64-bit Linux development environment:
```bash
-$ python tools/build.py -a x64 -m release runtime_kernel runtime_precompiled
+$ python3 tools/build.py -a x64 -m release runtime_kernel runtime_precompiled
$ pkg/vm/tool/gen_kernel --platform out/ReleaseX64/vm_platform_strong.dill -o throws.dill throws.dart
diff --git a/runtime/observatory/update_sources.py b/runtime/observatory/update_sources.py
index 39f6ad3..a9eaef7 100755
--- a/runtime/observatory/update_sources.py
+++ b/runtime/observatory/update_sources.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
# 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
diff --git a/runtime/observatory_2/update_sources.py b/runtime/observatory_2/update_sources.py
index 39f6ad3..a9eaef7 100755
--- a/runtime/observatory_2/update_sources.py
+++ b/runtime/observatory_2/update_sources.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
# 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
diff --git a/runtime/tests/vm/dart/regress_45631_test.dart b/runtime/tests/vm/dart/regress_45631_test.dart
new file mode 100644
index 0000000..b6166cd
--- /dev/null
+++ b/runtime/tests/vm/dart/regress_45631_test.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for https://github.com/dart-lang/sdk/issues/45631.
+// Verifies that compiler doesn't reuse the same Slot for captured local
+// variables with the same name and offset.
+
+void main() {
+ for (int loc0 in [1]) {
+ () {
+ ~loc0;
+ }.call();
+ }
+ {
+ String loc0 = 'hi';
+ () {
+ loc0 = 'bye';
+ }.call();
+ }
+}
diff --git a/runtime/tests/vm/dart/regress_45691_test.dart b/runtime/tests/vm/dart/regress_45691_test.dart
new file mode 100644
index 0000000..f1c3d18
--- /dev/null
+++ b/runtime/tests/vm/dart/regress_45691_test.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for https://github.com/dart-lang/sdk/issues/45691.
+// Verifies that materialization of objects with uninitialized late fields
+// doesn't crash.
+
+// VMOptions=--optimization-counter-threshold=100 --deterministic
+
+import 'package:expect/expect.dart';
+
+class A {
+ late int x = int.parse('42');
+ int y = 10;
+}
+
+@pragma("vm:never-inline")
+void foo(num deopt) {
+ A a = A();
+ deopt + 1;
+ Expect.equals(10, a.y);
+}
+
+void main() {
+ for (int i = 0; i < 150; ++i) {
+ foo(i > 100 ? 1.0 : 2);
+ }
+}
diff --git a/runtime/tests/vm/dart_2/regress_45631_test.dart b/runtime/tests/vm/dart_2/regress_45631_test.dart
new file mode 100644
index 0000000..b6166cd
--- /dev/null
+++ b/runtime/tests/vm/dart_2/regress_45631_test.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for https://github.com/dart-lang/sdk/issues/45631.
+// Verifies that compiler doesn't reuse the same Slot for captured local
+// variables with the same name and offset.
+
+void main() {
+ for (int loc0 in [1]) {
+ () {
+ ~loc0;
+ }.call();
+ }
+ {
+ String loc0 = 'hi';
+ () {
+ loc0 = 'bye';
+ }.call();
+ }
+}
diff --git a/runtime/third_party/binary_size/src/explain_binary_size_delta.py b/runtime/third_party/binary_size/src/explain_binary_size_delta.py
index b6a0270..ed9c689 100755
--- a/runtime/third_party/binary_size/src/explain_binary_size_delta.py
+++ b/runtime/third_party/binary_size/src/explain_binary_size_delta.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
@@ -362,7 +362,7 @@
for section in sections:
allFiles = allFiles | section.sources
allFiles = allFiles | maybe_unchanged_sources
- print 'Source stats:'
+ print('Source stats:')
print(' %d sources encountered.' % len(allFiles))
print(' %d completely new.' % len(new_sources))
print(' %d removed completely.' % len(removed_sources))
@@ -374,7 +374,7 @@
if not showsources:
return # Per-source analysis, only if requested
- print 'Per-source Analysis:'
+ print('Per-source Analysis:')
delta_by_path = {}
for section in sections:
for path in section.symbols_by_path:
@@ -409,10 +409,10 @@
header = ' %s - Source: %s - (gained %d, lost %d)' % (DeltaStr(delta),
path, gain, loss)
divider = '-' * len(header)
- print ''
- print divider
- print header
- print divider
+ print('')
+ print(divider)
+ print(header)
+ print(divider)
if showsymbols:
def ExtractNewSize(tup):
@@ -424,7 +424,7 @@
return symbol_delta.old_size
if path in new_symbols.symbols_by_path:
- print ' New symbols:'
+ print(' New symbols:')
for symbol_name, symbol_type, symbol_delta in \
sorted(new_symbols.symbols_by_path[path],
key=ExtractNewSize,
@@ -434,7 +434,7 @@
symbol_type, symbol_delta.new_size,
SharedInfoStr(symbol_delta)))
if path in removed_symbols.symbols_by_path:
- print ' Removed symbols:'
+ print(' Removed symbols:')
for symbol_name, symbol_type, symbol_delta in \
sorted(removed_symbols.symbols_by_path[path],
key=ExtractOldSize):
@@ -446,7 +446,7 @@
type_str) in [(grown_symbols.symbols_by_path, "Grown"),
(shrunk_symbols.symbols_by_path, "Shrunk")]:
if path in changed_symbols_by_path:
- print ' %s symbols:' % type_str
+ print(' %s symbols:' % type_str)
def changed_symbol_sortkey(item):
symbol_name, _symbol_type, symbol_delta = item
@@ -505,9 +505,9 @@
parser.error('--nm2 is required')
symbols = []
for path in [opts.nm1, opts.nm2]:
- with file(path, 'r') as nm_input:
+ with open(path, 'r') as nm_input:
if opts.verbose:
- print 'parsing ' + path + '...'
+ print('parsing ' + path + '...')
symbols.append(list(binary_size_utils.ParseNm(nm_input)))
(added, removed, changed, unchanged) = Compare(symbols[0], symbols[1])
CrunchStats(added, removed, changed, unchanged,
diff --git a/runtime/third_party/binary_size/src/run_binary_size_analysis.py b/runtime/third_party/binary_size/src/run_binary_size_analysis.py
index d78e02d..ac41f4a 100755
--- a/runtime/third_party/binary_size/src/run_binary_size_analysis.py
+++ b/runtime/third_party/binary_size/src/run_binary_size_analysis.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
@@ -9,7 +9,6 @@
you desire.
"""
-import collections
import json
import logging
import multiprocessing
@@ -336,7 +335,7 @@
user_interrupted = True
print('Patience you must have my young padawan.')
- print ''
+ print('')
if user_interrupted:
print('Skipping the rest of the file mapping. '
@@ -379,9 +378,9 @@
if nm_process.returncode != 0:
if err_output:
- raise Exception, err_output
+ raise Exception(err_output)
else:
- raise Exception, process_output
+ raise Exception(process_output)
return process_output
@@ -393,15 +392,15 @@
outfile = tempfile.NamedTemporaryFile(delete=False).name
if verbose:
- print 'Running parallel addr2line, dumping symbols to ' + outfile
+ print('Running parallel addr2line, dumping symbols to ' + outfile)
RunElfSymbolizer(outfile, library, addr2line_binary, nm_binary, jobs,
disambiguate, src_path)
nm_infile = outfile
elif verbose:
- print 'Using nm input from ' + nm_infile
- with file(nm_infile, 'r') as infile:
+ print('Using nm input from ' + nm_infile)
+ with open(nm_infile, 'r') as infile:
return list(binary_size_utils.ParseNm(infile))
@@ -624,12 +623,12 @@
(not opts.nm_in)) or (opts.library and opts.nm_in):
parser.error('exactly one of --library or --nm-in is required')
if opts.nm_out:
- print >> sys.stderr, (
- 'WARNING: --nm-out is deprecated and has no effect.')
+ print('WARNING: --nm-out is deprecated and has no effect.',
+ file=sys.stderr)
if (opts.nm_in):
if opts.jobs:
- print >> sys.stderr, ('WARNING: --jobs has no effect '
- 'when used with --nm-in')
+ print('WARNING: --jobs has no effect when used with --nm-in',
+ file=sys.stderr)
if not opts.destdir:
parser.error('--destdir is a required argument')
if not opts.jobs:
@@ -666,7 +665,7 @@
# Prepare output directory and report guts
if not os.path.exists(opts.destdir):
- os.makedirs(opts.destdir, 0755)
+ os.makedirs(opts.destdir, 0o755)
nm_out = os.path.join(opts.destdir, 'nm.out')
if opts.no_nm_out:
nm_out = None
@@ -677,7 +676,7 @@
data_js_file_name = os.path.join(opts.destdir, 'data.js')
d3_out = os.path.join(opts.destdir, 'd3')
if not os.path.exists(d3_out):
- os.makedirs(d3_out, 0755)
+ os.makedirs(d3_out, 0o755)
d3_src = os.path.join(os.path.dirname(__file__), '..', '..', 'd3', 'src')
template_src = os.path.join(os.path.dirname(__file__), 'template')
shutil.copy(os.path.join(d3_src, 'LICENSE'), d3_out)
@@ -701,7 +700,7 @@
symbol_path_origin_dir = os.path.abspath(os.getcwd())
# Dump JSON for the HTML report.
DumpCompactTree(symbols, symbol_path_origin_dir, data_js_file_name)
- print 'Report saved to ' + opts.destdir + '/index.html'
+ print('Report saved to ' + opts.destdir + '/index.html')
if __name__ == '__main__':
diff --git a/runtime/tools/android_finder.py b/runtime/tools/android_finder.py
index c3d8249..6c8078c 100755
--- a/runtime/tools/android_finder.py
+++ b/runtime/tools/android_finder.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
diff --git a/runtime/tools/benchmark.py b/runtime/tools/benchmark.py
index ec0b5e6..0f6cd72 100755
--- a/runtime/tools/benchmark.py
+++ b/runtime/tools/benchmark.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
# Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
@@ -36,7 +36,8 @@
def ReadBenchmarkList(mode, path, core):
filename = GetBenchmarkFile([path])
benchmarks = dict()
- execfile(filename, benchmarks)
+ with open(filename) as infile:
+ exec(infile.read(), benchmarks)
if (mode == "release") and not core:
return benchmarks['SUPPORTED_BENCHMARKS']
else:
@@ -91,11 +92,11 @@
options.arch = options.arch.split(',')
for mode in options.mode:
if not mode in ['debug', 'release']:
- print "Unknown mode %s" % mode
+ print("Unknown mode %s" % mode)
return False
for arch in options.arch:
if not arch in ['ia32', 'x64', 'simarm', 'arm', 'dartc']:
- print "Unknown arch %s" % arch
+ print("Unknown arch %s" % arch)
return False
return True
@@ -138,7 +139,7 @@
GetBenchmarkFile([benchmark, 'dart', benchmark + '.dart']),
]
if options.verbose:
- print ' '.join(command)
+ print(' '.join(command))
subprocess.call(command)
return 0
diff --git a/runtime/tools/bin_to_assembly.py b/runtime/tools/bin_to_assembly.py
index 9ec13e7..b66c285 100755
--- a/runtime/tools/bin_to_assembly.py
+++ b/runtime/tools/bin_to_assembly.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
# 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
diff --git a/runtime/tools/bin_to_coff.py b/runtime/tools/bin_to_coff.py
index 1925bcd..f98f051f 100644
--- a/runtime/tools/bin_to_coff.py
+++ b/runtime/tools/bin_to_coff.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
# 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
@@ -54,8 +54,8 @@
# } SCNHDR;
SECTION_HEADER_FORMAT = '8sIIIIIIHHI'
SECTION_HEADER_SIZE = calcsize(SECTION_HEADER_FORMAT)
-SECTION_NAME_RODATA = '.rodata'
-SECTION_NAME_TEXT = '.text'
+SECTION_NAME_RODATA = b'.rodata'
+SECTION_NAME_TEXT = b'.text'
SECTION_PADDR = 0x0
SECTION_VADDR = 0x0
SECTION_RAW_DATA_PTR = (
@@ -130,13 +130,13 @@
includes_size_name = (args.size_name != None)
# Symbols on x86 are prefixed with '_'
- symbol_prefix = '' if args.use_64_bit else '_'
+ symbol_prefix = b'' if args.use_64_bit else b'_'
num_symbols = 2 if includes_size_name else 1
- symbol_name = symbol_prefix + args.symbol_name
+ symbol_name = symbol_prefix + args.symbol_name.encode()
size_symbol_name = None
if (includes_size_name):
size_symbol = args.size_name if args.size_name else args.symbol_name + "Size"
- size_symbol_name = symbol_prefix + size_symbol
+ size_symbol_name = symbol_prefix + size_symbol.encode()
size_symbol_format = SIZE_SYMBOL_FORMAT_X64 if args.use_64_bit else SIZE_FORMAT
size_symbol_size = SIZE_SYMBOL_LENGTH_X64 if args.use_64_bit else SIZE_LENGTH
@@ -237,14 +237,14 @@
symbol_len = len(symbol_name)
buff[offset:offset + symbol_len] = symbol_name
offset += symbol_len
- buff[offset] = '\0'
+ buff[offset] = b'\0'
offset += 1
if includes_size_name and long_size_symbol_name:
symbol_len = len(size_symbol_name)
buff[offset:offset + symbol_len] = size_symbol_name
offset += symbol_len
- buff[offset] = '\0'
+ buff[offset] = b'\0'
offset += 1
with open(args.output, 'wb') as f:
diff --git a/runtime/tools/compiler_layering_check.py b/runtime/tools/compiler_layering_check.py
index e686ce9..06d73d9 100755
--- a/runtime/tools/compiler_layering_check.py
+++ b/runtime/tools/compiler_layering_check.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
# 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
@@ -127,6 +127,6 @@
if __name__ == '__main__':
errors = DoCheck('.')
- print '\n'.join(errors)
+ print('\n'.join(errors))
if errors:
sys.exit(-1)
diff --git a/runtime/tools/create_archive.py b/runtime/tools/create_archive.py
index 7bc93d5..40d6813 100755
--- a/runtime/tools/create_archive.py
+++ b/runtime/tools/create_archive.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# 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.
diff --git a/runtime/tools/create_snapshot_bin.py b/runtime/tools/create_snapshot_bin.py
index 93c5b69..65c35a8 100755
--- a/runtime/tools/create_snapshot_bin.py
+++ b/runtime/tools/create_snapshot_bin.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
# Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
diff --git a/runtime/tools/create_snapshot_file.py b/runtime/tools/create_snapshot_file.py
index 4216366..2354acb 100755
--- a/runtime/tools/create_snapshot_file.py
+++ b/runtime/tools/create_snapshot_file.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
# Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
diff --git a/runtime/tools/create_string_literal.py b/runtime/tools/create_string_literal.py
index 68a969b..3065e7d 100755
--- a/runtime/tools/create_string_literal.py
+++ b/runtime/tools/create_string_literal.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
# Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
diff --git a/runtime/tools/embedder_layering_check.py b/runtime/tools/embedder_layering_check.py
index 8e33bf0..775040e 100644
--- a/runtime/tools/embedder_layering_check.py
+++ b/runtime/tools/embedder_layering_check.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
# 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
@@ -75,6 +75,6 @@
if __name__ == '__main__':
errors = DoCheck('.')
- print '\n'.join(errors)
+ print('\n'.join(errors))
if errors:
sys.exit(-1)
diff --git a/runtime/tools/gen_library_src_paths.py b/runtime/tools/gen_library_src_paths.py
index 97f4ae1..79ef9d8 100755
--- a/runtime/tools/gen_library_src_paths.py
+++ b/runtime/tools/gen_library_src_paths.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright (c) 2013, 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.
diff --git a/runtime/tools/utils.py b/runtime/tools/utils.py
index 8cec062..a70681d 100644
--- a/runtime/tools/utils.py
+++ b/runtime/tools/utils.py
@@ -5,17 +5,17 @@
# This file contains a set of utilities functions used by other Python-based
# scripts.
-import commands
import os
import platform
-import Queue
+import queue
import re
-import StringIO
import subprocess
import sys
import threading
import time
+from io import StringIO
+from subprocess import getoutput
# Try to guess the host operating system.
def GuessOS():
@@ -55,11 +55,11 @@
def GuessCpus():
if os.path.exists("/proc/cpuinfo"):
return int(
- commands.getoutput(
+ getoutput(
"GREP_OPTIONS= grep -E '^processor' /proc/cpuinfo | wc -l"))
if os.path.exists("/usr/bin/hostinfo"):
return int(
- commands.getoutput(
+ getoutput(
'/usr/bin/hostinfo | GREP_OPTIONS= grep "processors are logically available." | awk "{ print \$1 }"'
))
win_cpu_count = os.getenv("NUMBER_OF_PROCESSORS")
@@ -197,14 +197,14 @@
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
except OSError as e:
- if not isinstance(command, basestring):
+ if not isinstance(command, str):
command = ' '.join(command)
if printErrorInfo:
sys.stderr.write("Command failed: '%s'\n" % command)
raise Error(e)
def StartThread(out):
- queue = Queue.Queue()
+ queue = queue.Queue()
def EnqueueOutput(out, queue):
for line in iter(out.readline, b''):
@@ -226,7 +226,7 @@
out.write(line)
if out2 != None:
out2.write(line)
- except Queue.Empty:
+ except queue.Empty:
pass
outBuf = StringIO.StringIO()
@@ -252,7 +252,7 @@
out = outBuf.getvalue()
error = errorBuf.getvalue()
if returncode:
- if not isinstance(command, basestring):
+ if not isinstance(command, str):
command = ' '.join(command)
if printErrorInfo:
sys.stderr.write("Command failed: '%s'\n" % command)
@@ -266,10 +266,10 @@
def Main(argv):
- print "GuessOS() -> ", GuessOS()
- print "GuessArchitecture() -> ", GuessArchitecture()
- print "GuessCpus() -> ", GuessCpus()
- print "IsWindows() -> ", IsWindows()
+ print("GuessOS() -> ", GuessOS())
+ print("GuessArchitecture() -> ", GuessArchitecture())
+ print("GuessCpus() -> ", GuessCpus())
+ print("IsWindows() -> ", IsWindows())
class Error(Exception):
diff --git a/runtime/tools/valgrind.py b/runtime/tools/valgrind.py
index f82d6d3..ec0c886 100755
--- a/runtime/tools/valgrind.py
+++ b/runtime/tools/valgrind.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
#
# Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
diff --git a/runtime/vm/compiler/backend/slot.cc b/runtime/vm/compiler/backend/slot.cc
index eaf30b0..3cb6371 100644
--- a/runtime/vm/compiler/backend/slot.cc
+++ b/runtime/vm/compiler/backend/slot.cc
@@ -392,8 +392,10 @@
return true;
case Kind::kCapturedVariable:
- return (flags_ == other.flags_) && (DataAs<const String>()->ptr() ==
- other.DataAs<const String>()->ptr());
+ return (flags_ == other.flags_) &&
+ (DataAs<const String>()->ptr() ==
+ other.DataAs<const String>()->ptr()) &&
+ static_type_->Equals(*(other.static_type_));
case Kind::kDartField:
return other.DataAs<const Field>()->Original() ==
diff --git a/runtime/vm/compiler/ffi/native_type.h b/runtime/vm/compiler/ffi/native_type.h
index de69bd5..2ee284a 100644
--- a/runtime/vm/compiler/ffi/native_type.h
+++ b/runtime/vm/compiler/ffi/native_type.h
@@ -33,7 +33,7 @@
class NativeCompoundType;
// NativeTypes are the types used in calling convention specifications:
-// integers, floats, and composites.
+// integers, floats, and compounds.
//
// NativeTypes exclude C types which are not discussed in calling conventions:
// pointer types (they are lowered to integers).
diff --git a/runtime/vm/constants_arm.h b/runtime/vm/constants_arm.h
index 1b7fe4c..be35d85 100644
--- a/runtime/vm/constants_arm.h
+++ b/runtime/vm/constants_arm.h
@@ -547,7 +547,7 @@
static constexpr AlignmentStrategy kArgumentStackAlignment =
kAlignedToWordSizeBut8AlignedTo8;
- // How fields in composites are aligned.
+ // How fields in compounds are aligned.
#if defined(TARGET_OS_MACOS_IOS)
static constexpr AlignmentStrategy kFieldAlignment =
kAlignedToValueSizeBut8AlignedTo4;
diff --git a/runtime/vm/constants_arm64.h b/runtime/vm/constants_arm64.h
index a596a10..cf35be9 100644
--- a/runtime/vm/constants_arm64.h
+++ b/runtime/vm/constants_arm64.h
@@ -421,7 +421,7 @@
kAlignedToWordSize;
#endif
- // How fields in composites are aligned.
+ // How fields in compounds are aligned.
static constexpr AlignmentStrategy kFieldAlignment = kAlignedToValueSize;
// Whether 1 or 2 byte-sized arguments or return values are passed extended
diff --git a/runtime/vm/constants_ia32.h b/runtime/vm/constants_ia32.h
index a8baa9d..33096bb 100644
--- a/runtime/vm/constants_ia32.h
+++ b/runtime/vm/constants_ia32.h
@@ -315,7 +315,7 @@
static constexpr AlignmentStrategy kArgumentStackAlignment =
kAlignedToWordSize;
- // How fields in composites are aligned.
+ // How fields in compounds are aligned.
#if defined(TARGET_OS_WINDOWS)
static constexpr AlignmentStrategy kFieldAlignment = kAlignedToValueSize;
#else
diff --git a/runtime/vm/constants_x64.h b/runtime/vm/constants_x64.h
index e5f647e..ac85998 100644
--- a/runtime/vm/constants_x64.h
+++ b/runtime/vm/constants_x64.h
@@ -388,7 +388,7 @@
static constexpr AlignmentStrategy kArgumentStackAlignment =
kAlignedToWordSize;
- // How fields in composites are aligned.
+ // How fields in compounds are aligned.
static constexpr AlignmentStrategy kFieldAlignment = kAlignedToValueSize;
// Whether 1 or 2 byte-sized arguments or return values are passed extended
@@ -453,7 +453,7 @@
static constexpr AlignmentStrategy kArgumentStackAlignment =
kAlignedToWordSize;
- // How fields in composites are aligned.
+ // How fields in compounds are aligned.
static constexpr AlignmentStrategy kFieldAlignment = kAlignedToValueSize;
// Whether 1 or 2 byte-sized arguments or return values are passed extended
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index a87928a..852f3b5 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -991,17 +991,17 @@
obj1_ref->set_ptr(obj2_ref);
}
-// TODO(https://dartbug.com/38491): Reject Unions here as well.
-static bool IsFfiStruct(Thread* T, const Object& obj) {
+static bool IsFfiCompound(Thread* T, const Object& obj) {
if (obj.IsNull()) {
return false;
}
- // CFE guarantees we can only have direct subclasses of `Struct`
+ // CFE guarantees we can only have direct subclasses of `Struct` and `Union`
// (no implementations or indirect subclasses are allowed).
const auto& klass = Class::Handle(Z, obj.clazz());
const auto& super_klass = Class::Handle(Z, klass.SuperClass());
- if (super_klass.Name() != Symbols::Struct().ptr()) {
+ if (super_klass.Name() != Symbols::Struct().ptr() &&
+ super_klass.Name() != Symbols::Union().ptr()) {
return false;
}
const auto& library = Library::Handle(Z, super_klass.library());
@@ -1020,7 +1020,7 @@
if (ref.IsPointer()) {
return NULL;
}
- if (IsFfiStruct(thread, ref)) {
+ if (IsFfiCompound(thread, ref)) {
return NULL;
}
@@ -1054,7 +1054,7 @@
if (ref.IsPointer()) {
return NULL;
}
- if (IsFfiStruct(thread, ref)) {
+ if (IsFfiCompound(thread, ref)) {
return NULL;
}
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 6046c6e..4f333c6 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -3378,15 +3378,20 @@
Dart_NewWeakPersistentHandle(obj3, nullptr, 0, FinalizableHandleCallback);
EXPECT_EQ(ref3, static_cast<void*>(nullptr));
- // Subtype of Struct object.
+ // Subtype of Struct or Union object.
const char* kScriptChars = R"(
import 'dart:ffi';
class MyStruct extends Struct {
external Pointer notEmpty;
}
+
+ class MyUnion extends Union {
+ external Pointer notEmpty;
+ }
)";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
+
Dart_Handle my_struct_type =
Dart_GetNonNullableType(lib, NewString("MyStruct"), 0, NULL);
Dart_Handle obj4 = Dart_Allocate(my_struct_type);
@@ -3395,7 +3400,13 @@
Dart_NewWeakPersistentHandle(obj4, nullptr, 0, FinalizableHandleCallback);
EXPECT_EQ(ref4, static_cast<void*>(nullptr));
- // TODO(https://dartbug.com/38491): Reject Unions here as well.
+ Dart_Handle my_union_type =
+ Dart_GetNonNullableType(lib, NewString("MyUnion"), 0, NULL);
+ Dart_Handle obj5 = Dart_Allocate(my_union_type);
+ EXPECT_VALID(obj5);
+ Dart_WeakPersistentHandle ref5 =
+ Dart_NewWeakPersistentHandle(obj4, nullptr, 0, FinalizableHandleCallback);
+ EXPECT_EQ(ref5, static_cast<void*>(nullptr));
Dart_ExitScope();
}
@@ -3427,15 +3438,20 @@
Dart_NewFinalizableHandle(obj3, nullptr, 0, FinalizableHandleCallback);
EXPECT_EQ(ref3, static_cast<void*>(nullptr));
- // Subtype of Struct object.
+ // Subtype of Struct or Union object.
const char* kScriptChars = R"(
import 'dart:ffi';
class MyStruct extends Struct {
external Pointer notEmpty;
}
+
+ class MyUnion extends Union {
+ external Pointer notEmpty;
+ }
)";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
+
Dart_Handle my_struct_type =
Dart_GetNonNullableType(lib, NewString("MyStruct"), 0, NULL);
Dart_Handle obj4 = Dart_Allocate(my_struct_type);
@@ -3444,6 +3460,14 @@
Dart_NewFinalizableHandle(obj4, nullptr, 0, FinalizableHandleCallback);
EXPECT_EQ(ref4, static_cast<void*>(nullptr));
+ Dart_Handle my_union_type =
+ Dart_GetNonNullableType(lib, NewString("MyUnion"), 0, NULL);
+ Dart_Handle obj5 = Dart_Allocate(my_union_type);
+ EXPECT_VALID(obj5);
+ Dart_FinalizableHandle ref5 =
+ Dart_NewFinalizableHandle(obj4, nullptr, 0, FinalizableHandleCallback);
+ EXPECT_EQ(ref5, static_cast<void*>(nullptr));
+
Dart_ExitScope();
}
diff --git a/runtime/vm/deferred_objects.cc b/runtime/vm/deferred_objects.cc
index 27edd7a..8fa9865 100644
--- a/runtime/vm/deferred_objects.cc
+++ b/runtime/vm/deferred_objects.cc
@@ -440,7 +440,9 @@
offset ^= GetFieldOffset(i);
field ^= offset_map.At(offset.Value() / kWordSize);
value = GetValue(i);
- if (!field.IsNull()) {
+ ASSERT((value.ptr() != Object::sentinel().ptr()) ||
+ (!field.IsNull() && field.is_late()));
+ if (!field.IsNull() && (value.ptr() != Object::sentinel().ptr())) {
obj.SetField(field, value);
if (FLAG_trace_deoptimization_verbose) {
OS::PrintErr(" %s <- %s\n",
@@ -455,8 +457,11 @@
ASSERT(offset.Value() < cls.host_instance_size());
obj.SetFieldAtOffset(offset.Value(), value);
if (FLAG_trace_deoptimization_verbose) {
- OS::PrintErr(" null Field @ offset(%" Pd ") <- %s\n",
- offset.Value(), value.ToCString());
+ OS::PrintErr(
+ " %s @ offset(%" Pd ") <- %s\n",
+ (field.IsNull() ? "null Field"
+ : String::Handle(field.name()).ToCString()),
+ offset.Value(), value.ToCString());
}
}
}
diff --git a/runtime/vm/kernel_loader.cc b/runtime/vm/kernel_loader.cc
index 26329ce..45a4edd 100644
--- a/runtime/vm/kernel_loader.cc
+++ b/runtime/vm/kernel_loader.cc
@@ -1662,7 +1662,7 @@
// optimized. We immediately set the guarded_cid_ to kDynamicCid, which
// is effectively the same as calling this method first with Pointer and
// subsequently with TypedData with field guards.
- if (klass.Name() == Symbols::Compound().ptr() &&
+ if (klass.UserVisibleName() == Symbols::Compound().ptr() &&
Library::Handle(Z, klass.library()).url() == Symbols::DartFfi().ptr()) {
ASSERT(fields_.length() == 1);
ASSERT(String::Handle(Z, fields_[0]->name())
diff --git a/samples-dev/swarm/appengine/dev.html b/samples-dev/swarm/appengine/dev.html
index 2204ec9..672ec9c8 100644
--- a/samples-dev/swarm/appengine/dev.html
+++ b/samples-dev/swarm/appengine/dev.html
@@ -18,7 +18,7 @@
for UI development using something like: <pre>file:///Users/jimhug/dart-all/dart/samples/swarm/swarm.html</pre>.</p>
<p>When you are ready to test your new UI on this live server, first you
- need to run <pre>python update.py</pre> from your
+ need to run <pre>python3 update.py</pre> from your
<pre>dart/samples/swarm</pre> directory. This will build
both a self-contained html file for both js and dart code. Then,
use the link below to upload your files to this server. If you are
diff --git a/samples-dev/swarm/appengine/main.py b/samples-dev/swarm/appengine/main.py
index f047c47..4216fe8 100644
--- a/samples-dev/swarm/appengine/main.py
+++ b/samples-dev/swarm/appengine/main.py
@@ -2,7 +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.
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
import re, base64, logging, pickle, httplib2, time, urlparse, urllib2, urllib, StringIO, gzip, zipfile
diff --git a/samples-dev/swarm/buildapp.py b/samples-dev/swarm/buildapp.py
index 12d2a6a..b8198e1 100755
--- a/samples-dev/swarm/buildapp.py
+++ b/samples-dev/swarm/buildapp.py
@@ -2,7 +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.
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
# This script builds a Chrome App file (.crx) for Swarm
@@ -65,14 +65,14 @@
dartiumResult = createChromeApp(buildRoot, 'build_dart_app', 'swarm.crx')
dartCResult = createChromeApp(buildRoot, 'build_js_app', 'swarm-js.crx')
- print '''
+ print('''
Successfully created Chrome apps!
Dartium: file://%s
DartC/JS: file://%s
To install, open this URL in Chrome and select Continue at the bottom.
-''' % (dartiumResult, dartCResult)
+''' % (dartiumResult, dartCResult))
return 0
diff --git a/samples-dev/swarm/cacheimages.py b/samples-dev/swarm/cacheimages.py
index 0a8d1d3..2324125 100755
--- a/samples-dev/swarm/cacheimages.py
+++ b/samples-dev/swarm/cacheimages.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright (c) 2011, 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.
@@ -28,9 +28,9 @@
infile,
verbose=options.verbose,
encode_images=options.inline_images)
- print 'Converted ' + infile
- except BaseException, e:
- print 'Caught error: %s' % e
+ print('Converted ' + infile)
+ except BaseException as e:
+ print('Caught error: %s' % e)
def Flags():
@@ -53,13 +53,13 @@
global options
parser = Flags()
options, args = parser.parse_args()
- print "args: %s" % args
+ print("args: %s" % args)
if len(args) < 1 or 'help' in args[0]:
- print 'Usage: %s DIRECTORY' % basename(sys.argv[0])
+ print('Usage: %s DIRECTORY' % basename(sys.argv[0]))
return 1
dirname = args[0]
- print 'Searching directory ' + dirname
+ print('Searching directory ' + dirname)
files = []
for root, dirs, fnames in os.walk(dirname):
diff --git a/samples-dev/swarm/gen_manifest.py b/samples-dev/swarm/gen_manifest.py
index 4cc1280..d75356d 100755
--- a/samples-dev/swarm/gen_manifest.py
+++ b/samples-dev/swarm/gen_manifest.py
@@ -2,7 +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.
-#!/usr/bin/python2.6
+#!/usr/bin/env python3
#
"""
Usage: gen_manifest.py DIRECTORY EXTENSIONS CACHE-FILE HTML-FILES...
@@ -30,7 +30,7 @@
htmlFiles = sys.argv[4:]
os.chdir(cacheDir)
-print "Generating manifest from root path: " + cacheDir
+print("Generating manifest from root path: " + cacheDir)
patterns = extensions + htmlFiles
@@ -68,7 +68,7 @@
with open(manifestName, 'w') as f:
f.writelines(m + '\n' for m in manifest)
-print "Created manifest file: " + manifestName
+print("Created manifest file: " + manifestName)
for htmlFile in htmlFiles:
cachedHtmlFile = htmlFile.replace('.html', '-cache.html')
@@ -76,6 +76,6 @@
text = text.replace('<html>', '<html manifest="%s">' % manifestName, 1)
with open(cachedHtmlFile, 'w') as output:
output.write(text)
- print "Processed html file: %s -> %s" % (htmlFile, cachedHtmlFile)
+ print("Processed html file: %s -> %s" % (htmlFile, cachedHtmlFile))
-print "Successfully generated manifest and html files"
+print("Successfully generated manifest and html files")
diff --git a/samples-dev/swarm/update.py b/samples-dev/swarm/update.py
index 33526b0..5ff7000 100755
--- a/samples-dev/swarm/update.py
+++ b/samples-dev/swarm/update.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright (c) 2011, 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.
@@ -24,7 +24,7 @@
def convertOne(infile, options):
outDirBase = 'outcode'
outfile = join(outDirBase, infile)
- print 'converting %s to %s' % (infile, outfile)
+ print('converting %s to %s' % (infile, outfile))
if 'dart' in options.target:
htmlconverter.convertForDartium(infile, outDirBase,
diff --git a/sdk/lib/_http/embedder_config.dart b/sdk/lib/_http/embedder_config.dart
new file mode 100644
index 0000000..730bc2dd
--- /dev/null
+++ b/sdk/lib/_http/embedder_config.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._http;
+
+/// Embedder-specific `dart:_http` configuration.
+
+/// [HttpClient] will disallow HTTP URLs if this value is set to `false`.
+@pragma("vm:entry-point")
+bool _embedderAllowsHttp = true;
diff --git a/sdk/lib/_http/http.dart b/sdk/lib/_http/http.dart
index c4344d6..c20759f 100644
--- a/sdk/lib/_http/http.dart
+++ b/sdk/lib/_http/http.dart
@@ -24,6 +24,7 @@
import 'dart:typed_data';
part 'crypto.dart';
+part 'embedder_config.dart';
part 'http_date.dart';
part 'http_headers.dart';
part 'http_impl.dart';
diff --git a/sdk/lib/_http/http_impl.dart b/sdk/lib/_http/http_impl.dart
index 1f36df2..bd16cdc 100644
--- a/sdk/lib/_http/http_impl.dart
+++ b/sdk/lib/_http/http_impl.dart
@@ -2620,6 +2620,40 @@
set findProxy(String f(Uri uri)?) => _findProxy = f;
+ static void _startRequestTimelineEvent(
+ TimelineTask? timeline, String method, Uri uri) {
+ timeline?.start('HTTP CLIENT ${method.toUpperCase()}', arguments: {
+ 'method': method.toUpperCase(),
+ 'uri': uri.toString(),
+ });
+ }
+
+ /// Whether HTTP requests are currently allowed.
+ ///
+ /// If the [Zone] variable `#dart.library.io.allow_http` is set to a boolean,
+ /// it determines whether the HTTP protocol is allowed. If the zone variable
+ /// is set to any other non-null value, HTTP is not allowed.
+ /// Otherwise, if the `dart.library.io.allow_http` environment flag
+ /// is set to `false`, HTTP is not allowed.
+ /// Otherwise, [_embedderAllowsHttp] determines the result.
+ bool get _isHttpAllowed {
+ final zoneOverride = Zone.current[#dart.library.io.allow_http];
+ if (zoneOverride != null) return true == zoneOverride;
+ bool envOverride =
+ bool.fromEnvironment("dart.library.io.allow_http", defaultValue: true);
+ return envOverride && _embedderAllowsHttp;
+ }
+
+ bool _isLoopback(String host) {
+ if (host.isEmpty) return false;
+ if ("localhost" == host) return true;
+ try {
+ return InternetAddress(host).isLoopback;
+ } on ArgumentError {
+ return false;
+ }
+ }
+
Future<_HttpClientRequest> _openUrl(String method, Uri uri) {
if (_closing) {
throw new StateError("Client is closed");
@@ -2641,9 +2675,11 @@
}
bool isSecure = uri.isScheme("https");
- if (!isSecure && !isInsecureConnectionAllowed(uri.host)) {
- throw new StateError("Insecure HTTP is not allowed by platform: $uri");
+ if (!_isHttpAllowed && !isSecure && !_isLoopback(uri.host)) {
+ throw new StateError(
+ "Insecure HTTP is not allowed by the current platform: $uri");
}
+
int port = uri.port;
if (port == 0) {
port =
diff --git a/sdk/lib/_internal/js_runtime/lib/foreign_helper.dart b/sdk/lib/_internal/js_runtime/lib/foreign_helper.dart
index 3c9aed9..6e8cd72 100644
--- a/sdk/lib/_internal/js_runtime/lib/foreign_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/foreign_helper.dart
@@ -194,9 +194,6 @@
/// https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi.
external RAW_DART_FUNCTION_REF(Function function);
-/// Sets the current static state to [staticState].
-external void JS_SET_STATIC_STATE(staticState);
-
/// Returns the interceptor for class [type]. The interceptor is the type's
/// constructor's `prototype` property. [type] will typically be the class, not
/// an interface, e.g. `JS_INTERCEPTOR_CONSTANT(JSInt)`, not
@@ -213,9 +210,6 @@
/// Calls are replaced with a [HLoadType] SSA instruction.
external Object getJSArrayInteropRti();
-/// Returns the object corresponding to Namer.staticStateHolder.
-external JS_GET_STATIC_STATE();
-
/// Returns the JS name for [name] from the Namer.
external String JS_GET_NAME(JsGetName name);
diff --git a/sdk/lib/_internal/vm/lib/core_patch.dart b/sdk/lib/_internal/vm/lib/core_patch.dart
index d79e07d..b6587ef 100644
--- a/sdk/lib/_internal/vm/lib/core_patch.dart
+++ b/sdk/lib/_internal/vm/lib/core_patch.dart
@@ -49,7 +49,7 @@
import "dart:convert" show ascii, Encoding, json, latin1, utf8;
-import "dart:ffi" show Pointer, Struct;
+import "dart:ffi" show Pointer, Struct, Union;
import "dart:isolate" show Isolate;
diff --git a/sdk/lib/_internal/vm/lib/expando_patch.dart b/sdk/lib/_internal/vm/lib/expando_patch.dart
index 868e6238e..cacbc02 100644
--- a/sdk/lib/_internal/vm/lib/expando_patch.dart
+++ b/sdk/lib/_internal/vm/lib/expando_patch.dart
@@ -142,10 +142,10 @@
(object is num) ||
(object is String) ||
(object is Pointer) ||
- (object is Struct)) {
- // TODO(https://dartbug.com/38491): Reject Unions here as well.
+ (object is Struct) ||
+ (object is Union)) {
throw new ArgumentError.value(object,
- "Expandos are not allowed on strings, numbers, booleans, null, Pointers or Structs.");
+ "Expandos are not allowed on strings, numbers, booleans, null, Pointers, Structs or Unions.");
}
}
diff --git a/sdk/lib/_internal/vm/lib/ffi_patch.dart b/sdk/lib/_internal/vm/lib/ffi_patch.dart
index c9c3861..4290185 100644
--- a/sdk/lib/_internal/vm/lib/ffi_patch.dart
+++ b/sdk/lib/_internal/vm/lib/ffi_patch.dart
@@ -714,6 +714,16 @@
throw "UNREACHABLE: This case should have been rewritten in the CFE.";
}
+extension UnionPointer<T extends Union> on Pointer<T> {
+ @patch
+ T get ref =>
+ throw "UNREACHABLE: This case should have been rewritten in the CFE.";
+
+ @patch
+ T operator [](int index) =>
+ throw "UNREACHABLE: This case should have been rewritten in the CFE.";
+}
+
extension PointerArray<T extends NativeType> on Array<Pointer<T>> {
@patch
Pointer<T> operator [](int index) =>
@@ -742,6 +752,13 @@
}
}
+extension UnionArray<T extends Union> on Array<T> {
+ @patch
+ T operator [](int index) {
+ throw ArgumentError("S ($T) should be a subtype of Union at compile-time.");
+ }
+}
+
extension NativePort on SendPort {
@patch
int get nativePort native "SendPortImpl_get_id";
diff --git a/sdk/lib/_internal/vm/lib/ffi_struct_patch.dart b/sdk/lib/_internal/vm/lib/ffi_struct_patch.dart
index 1dd4726..00279f3 100644
--- a/sdk/lib/_internal/vm/lib/ffi_struct_patch.dart
+++ b/sdk/lib/_internal/vm/lib/ffi_struct_patch.dart
@@ -9,7 +9,13 @@
import 'dart:isolate';
@pragma("vm:entry-point")
-abstract class Struct extends NativeType {}
+abstract class _Compound extends NativeType {}
+
+@pragma("vm:entry-point")
+abstract class Struct extends _Compound {}
+
+@pragma("vm:entry-point")
+abstract class Union extends _Compound {}
@pragma("vm:entry-point")
class _FfiStructLayout {
diff --git a/sdk/lib/core/expando.dart b/sdk/lib/core/expando.dart
index c081df8..bcdee49 100644
--- a/sdk/lib/core/expando.dart
+++ b/sdk/lib/core/expando.dart
@@ -6,8 +6,8 @@
/// An [Expando] allows adding new properties to objects.
///
-/// Does not work on numbers, strings, booleans, `null`, `dart:ffi` pointers
-/// or `dart:ffi` structs.
+/// Does not work on numbers, strings, booleans, `null`, `dart:ffi` pointers,
+/// `dart:ffi` structs, or `dart:ffi` unions.
///
/// An `Expando` does not hold on to the added property value after an object
/// becomes inaccessible.
@@ -40,7 +40,7 @@
/// `null`.
///
/// The object must not be a number, a string, a boolean, `null`, a
- /// `dart:ffi` pointer, or a `dart:ffi` struct.
+ /// `dart:ffi` pointer, a `dart:ffi` struct, or a `dart:ffi` union.
external T? operator [](Object object);
/// Sets the value of this [Expando]'s property on the given
@@ -48,6 +48,6 @@
/// their value to `null`.
///
/// The object must not be a number, a string, a boolean, `null`, a
- /// `dart:ffi` pointer, or a `dart:ffi` struct.
+ /// `dart:ffi` pointer, a `dart:ffi` struct, or a `dart:ffi` union.
external void operator []=(Object object, T? value);
}
diff --git a/sdk/lib/ffi/ffi.dart b/sdk/lib/ffi/ffi.dart
index 733c8fe..369b389 100644
--- a/sdk/lib/ffi/ffi.dart
+++ b/sdk/lib/ffi/ffi.dart
@@ -19,6 +19,7 @@
part "annotations.dart";
part "dynamic_library.dart";
part "struct.dart";
+part "union.dart";
/// Number of bytes used by native type T.
///
@@ -692,6 +693,27 @@
external T operator [](int index);
}
+/// Extension on [Pointer] specialized for the type argument [Union].
+extension UnionPointer<T extends Union> on Pointer<T> {
+ /// Creates a reference to access the fields of this union backed by native
+ /// memory at [address].
+ ///
+ /// The [address] must be aligned according to the union alignment rules of
+ /// the platform.
+ ///
+ /// This extension method must be invoked with a compile-time constant [T].
+ external T get ref;
+
+ /// Creates a reference to access the fields of this union backed by native
+ /// memory at `address + sizeOf<T>() * index`.
+ ///
+ /// The [address] must be aligned according to the union alignment rules of
+ /// the platform.
+ ///
+ /// This extension method must be invoked with a compile-time constant [T].
+ external T operator [](int index);
+}
+
/// Bounds checking indexing methods on [Array]s of [Pointer].
extension PointerArray<T extends NativeType> on Array<Pointer<T>> {
external Pointer<T> operator [](int index);
@@ -705,6 +727,12 @@
external T operator [](int index);
}
+/// Bounds checking indexing methods on [Array]s of [Union].
+extension UnionArray<T extends Union> on Array<T> {
+ /// This extension method must be invoked with a compile-time constant [T].
+ external T operator [](int index);
+}
+
/// Bounds checking indexing methods on [Array]s of [Array].
extension ArrayArray<T extends NativeType> on Array<Array<T>> {
external Array<T> operator [](int index);
diff --git a/sdk/lib/ffi/ffi_sources.gni b/sdk/lib/ffi/ffi_sources.gni
index db03071..4152f91 100644
--- a/sdk/lib/ffi/ffi_sources.gni
+++ b/sdk/lib/ffi/ffi_sources.gni
@@ -11,4 +11,5 @@
"dynamic_library.dart",
"native_type.dart",
"struct.dart",
+ "union.dart",
]
diff --git a/sdk/lib/ffi/union.dart b/sdk/lib/ffi/union.dart
new file mode 100644
index 0000000..d0c7a66
--- /dev/null
+++ b/sdk/lib/ffi/union.dart
@@ -0,0 +1,58 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.ffi;
+
+/// The supertype of all FFI union types.
+///
+/// FFI union types should extend this class and declare fields corresponding
+/// to the underlying native union.
+///
+/// Field declarations in a [Union] subclass declaration are automatically
+/// given a setter and getter implementation which accesses the native union's
+/// field in memory.
+///
+/// All field declarations in a [Union] subclass declaration must either have
+/// type [int] or [float] and be annotated with a [NativeType] representing the
+/// native type, or must be of type [Pointer]. For example:
+///
+/// ```c
+/// typedef union {
+/// int a;
+/// float b;
+/// void* c;
+/// } my_union;
+/// ```
+///
+/// ```dart
+/// class MyUnion extends Union {
+/// @Int32()
+/// external int a;
+///
+/// @Float()
+/// external double b;
+///
+/// external Pointer<Void> c;
+/// }
+/// ```
+///
+/// All field declarations in a [Union] subclass declaration must be marked
+/// `external`. You cannot create instances of the class, only have it point to
+/// existing native memory, so there is no memory in which to store non-native
+/// fields. External fields also cannot be initialized by constructors since no
+/// Dart object is being created.
+///
+/// Instances of a subclass of [Union] have reference semantics and are backed
+/// by native memory. The may allocated via allocation or loaded from a
+/// [Pointer], but cannot be created by a generative constructor.
+abstract class Union extends _Compound {
+ /// Construct a reference to the [nullptr].
+ ///
+ /// Use [UnionPointer]'s `.ref` to gain references to native memory backed
+ /// unions.
+ Union() : super._();
+
+ Union._fromTypedDataBase(Object typedDataBase)
+ : super._fromTypedDataBase(typedDataBase);
+}
diff --git a/sdk/lib/io/embedder_config.dart b/sdk/lib/io/embedder_config.dart
index fcac6d1..fd5bb24 100644
--- a/sdk/lib/io/embedder_config.dart
+++ b/sdk/lib/io/embedder_config.dart
@@ -36,13 +36,18 @@
/// to all domains.
///
/// This setting can be overridden by per-domain policies.
+ @Deprecated(
+ "To be re-implemented in https://github.com/flutter/flutter/issues/54448")
@pragma('vm:entry-point')
static bool _mayInsecurelyConnectToAllDomains = true;
/// Domain network policies set by embedder.
+ @Deprecated(
+ "To be re-implemented in https://github.com/flutter/flutter/issues/54448")
@pragma('vm:entry-point')
static void _setDomainPolicies(String domainNetworkPolicyJson) {
- _domainPolicies = _constructDomainPolicies(domainNetworkPolicyJson);
+ // Doesn't do anything because the implementation has been reverted in
+ // https://github.com/flutter/flutter/issues/72723.
}
// TODO(zra): Consider adding:
diff --git a/sdk/lib/io/network_policy.dart b/sdk/lib/io/network_policy.dart
index 9fa586b..ef00ffc 100644
--- a/sdk/lib/io/network_policy.dart
+++ b/sdk/lib/io/network_policy.dart
@@ -6,6 +6,9 @@
/// Whether insecure connections to [host] are allowed.
///
+/// This API is deprecated and always returns true. See
+/// https://github.com/flutter/flutter/issues/72723 for more details.
+///
/// [host] must be a [String] or [InternetAddress].
///
/// If any of the domain policies match [host], the matching policy will make
@@ -14,179 +17,7 @@
/// used.
///
/// Loopback addresses are always allowed.
+@Deprecated("See https://github.com/flutter/flutter/issues/54448 for followup")
bool isInsecureConnectionAllowed(dynamic host) {
- String hostString;
- if (host is String) {
- try {
- if ("localhost" == host || InternetAddress(host).isLoopback) return true;
- } on ArgumentError {
- // Assume not loopback.
- }
- hostString = host;
- } else if (host is InternetAddress) {
- if (host.isLoopback) return true;
- hostString = host.host;
- } else {
- throw ArgumentError.value(
- host, "host", "Must be a String or InternetAddress");
- }
- final topMatchedPolicy = _findBestDomainNetworkPolicy(hostString);
- final envOverride = bool.fromEnvironment(
- "dart.library.io.may_insecurely_connect_to_all_domains",
- defaultValue: true);
- return topMatchedPolicy?.allowInsecureConnections ??
- (envOverride && _EmbedderConfig._mayInsecurelyConnectToAllDomains);
-}
-
-/// Policy for a specific domain.
-///
-/// [_DomainNetworkPolicy] can be used to create exceptions to the global
-/// network policy.
-class _DomainNetworkPolicy {
- /// https://tools.ietf.org/html/rfc1034#:~:text=Name%20space%20specifications
- ///
- /// We specifically do not allow IP addresses.
- static final _domainMatcher = RegExp(
- r"^(?:[a-z\d-]{1,63}\.)+[a-z][a-z\d-]{0,62}$",
- caseSensitive: false);
-
- /// The domain on which the policy is being set.
- ///
- /// This cannot be a numeric IP address.
- ///
- /// For example: `example.com`.
- final String domain;
-
- /// Whether to allow insecure socket connections for this domain.
- final bool allowInsecureConnections;
-
- /// Whether this domain policy covers sub-domains as well.
- ///
- /// If this is true, all subdomains inherit the same policy. For instance,
- /// a policy set on `example.com` would apply to `*.example.com` such as
- /// `subdomain.example.com` or `www.example.com`.
- final bool includesSubDomains;
-
- /// Creates a new domain exception in the network policy.
- ///
- /// [domain] is the domain on which the policy is being set.
- ///
- /// [includesSubDomains] determines whether the policy applies to
- /// all sub domains. If this is set to true, all subdomains inherit the
- /// same policy. For instance, a policy set on `example.com` would apply to
- /// `*.example.com` such as `subdomain.example.com` or `www.example.com`.
- ///
- /// [allowInsecureConnections] determines whether to allow insecure socket
- /// connections for this [domain].
- _DomainNetworkPolicy(this.domain,
- {this.includesSubDomains = false,
- this.allowInsecureConnections = false}) {
- if (domain.length > 255 || !_domainMatcher.hasMatch(domain)) {
- throw ArgumentError.value(domain, "domain", "Invalid domain name");
- }
- }
-
- /// Calculates how well the policy matches to a given host string.
- ///
- /// A host matches a [policy] if it ends with its [domain].
- ///
- /// A score is given to such a match depending on the specificity of the
- /// [domain]:
- ///
- /// * A longer domain receives a higher score.
- /// * A domain that does not allow sub domains receives a higher score.
- ///
- /// Returns -1 if the policy does not match.
- int matchScore(String host) {
- final domainLength = domain.length;
- final hostLength = host.length;
- final lengthDelta = hostLength - domainLength;
- if (host.endsWith(domain) &&
- (lengthDelta == 0 ||
- includesSubDomains && host.codeUnitAt(lengthDelta - 1) == 0x2e)) {
- return domainLength * 2 + (includesSubDomains ? 0 : 1);
- }
- return -1;
- }
-
- /// Checks whether the [policy] to be added conflicts with existing policies.
- ///
- /// Returns [true] if policy is safe to add to existing policy set and [false]
- /// if policy can safely be ignored.
- ///
- /// Throws [ArgumentError] if a conflict is detected.
- bool checkConflict(List<_DomainNetworkPolicy> existingPolicies) {
- for (final existingPolicy in existingPolicies) {
- if (includesSubDomains == existingPolicy.includesSubDomains &&
- domain == existingPolicy.domain) {
- if (allowInsecureConnections ==
- existingPolicy.allowInsecureConnections) {
- // This is a duplicate policy
- return false;
- }
- throw StateError("Contradiction in the domain security policies: "
- "'$this' contradicts '$existingPolicy'");
- }
- }
- return true;
- }
-
- /// This is used for encoding information about the policy in user visible
- /// errors.
- @override
- String toString() {
- final subDomainPrefix = includesSubDomains ? '*.' : '';
- final insecureConnectionPermission =
- allowInsecureConnections ? 'Allows' : 'Disallows';
- return "$subDomainPrefix$domain: "
- "$insecureConnectionPermission insecure connections";
- }
-}
-
-/// Finds the top [DomainNetworkPolicy] instance that match given a single
-/// [domain].
-///
-/// We order the policies according to how specific they are. The final policy
-/// for a given [domain] is determined by the top matching
-/// [DomainNetworkPolicy].
-///
-/// Returns null if there's no matching policy.
-_DomainNetworkPolicy? _findBestDomainNetworkPolicy(String domain) {
- var topScore = 0;
- _DomainNetworkPolicy? topPolicy;
- for (final _DomainNetworkPolicy policy in _domainPolicies) {
- final score = policy.matchScore(domain);
- if (score > topScore) {
- topScore = score;
- topPolicy = policy;
- }
- }
- return topPolicy;
-}
-
-/// Domain level policies that dart:io is enforcing.
-late List<_DomainNetworkPolicy> _domainPolicies =
- _constructDomainPolicies(null);
-
-List<_DomainNetworkPolicy> _constructDomainPolicies(
- String? domainPoliciesString) {
- final domainPolicies = <_DomainNetworkPolicy>[];
- domainPoliciesString ??= String.fromEnvironment(
- "dart.library.io.domain_network_policies",
- defaultValue: "");
- if (domainPoliciesString.isNotEmpty) {
- final List<dynamic> policiesJson = json.decode(domainPoliciesString);
- for (final List<dynamic> policyJson in policiesJson) {
- assert(policyJson.length == 3);
- final policy = _DomainNetworkPolicy(
- policyJson[0],
- includesSubDomains: policyJson[1],
- allowInsecureConnections: policyJson[2],
- );
- if (policy.checkConflict(domainPolicies)) {
- domainPolicies.add(policy);
- }
- }
- }
- return domainPolicies;
+ return true;
}
diff --git a/sdk/lib/libraries.yaml b/sdk/lib/libraries.yaml
index 87beca8..6262221 100644
--- a/sdk/lib/libraries.yaml
+++ b/sdk/lib/libraries.yaml
@@ -5,7 +5,7 @@
# Note: if you edit this file, you must also generate libraries.json in this
# directory:
#
-# python ./tools/yaml2json.py sdk/lib/libraries.yaml sdk/lib/libraries.json
+# python3 ./tools/yaml2json.py sdk/lib/libraries.yaml sdk/lib/libraries.json
#
# We currently have several different files that needs to be updated when
# changing libraries, sources, and patch files. See
diff --git a/sdk/lib/vmservice_libraries.yaml b/sdk/lib/vmservice_libraries.yaml
index 169d6af..c30ac8f 100644
--- a/sdk/lib/vmservice_libraries.yaml
+++ b/sdk/lib/vmservice_libraries.yaml
@@ -5,7 +5,7 @@
# Note: if you edit this file, you must also edit libraries.json in this
# directory:
#
-# python ./tools/yaml2json.py sdk/lib/vmservice_libraries.yaml sdk/lib/vmservice_libraries.json
+# python3 ./tools/yaml2json.py sdk/lib/vmservice_libraries.yaml sdk/lib/vmservice_libraries.json
#
# We currently have several different files that needs to be updated when
# changing libraries, sources, and patch files. See
diff --git a/tests/corelib/type_tostring_test.dart b/tests/corelib/type_tostring_test.dart
index 8e1c2d1..8f2fa68 100644
--- a/tests/corelib/type_tostring_test.dart
+++ b/tests/corelib/type_tostring_test.dart
@@ -128,7 +128,6 @@
typedef G4 = S Function<T>(S, T) Function<S>(S);
typedef G5 = S Function<S, T>(S, T);
-typedef Weird = Function Function<Function>(
- Function Function<Function>(Function));
+typedef Weird = X Function<X>(X Function<X>(X));
RegExp re(String source) => RegExp(source);
diff --git a/tests/corelib_2/type_tostring_test.dart b/tests/corelib_2/type_tostring_test.dart
index 8e1c2d1..8f2fa68 100644
--- a/tests/corelib_2/type_tostring_test.dart
+++ b/tests/corelib_2/type_tostring_test.dart
@@ -128,7 +128,6 @@
typedef G4 = S Function<T>(S, T) Function<S>(S);
typedef G5 = S Function<S, T>(S, T);
-typedef Weird = Function Function<Function>(
- Function Function<Function>(Function));
+typedef Weird = X Function<X>(X Function<X>(X));
RegExp re(String source) => RegExp(source);
diff --git a/tests/ffi/ffi.status b/tests/ffi/ffi.status
index f157962..82349e8 100644
--- a/tests/ffi/ffi.status
+++ b/tests/ffi/ffi.status
@@ -11,6 +11,9 @@
[ $system == android ]
*: Pass, Slow # https://github.com/dart-lang/sdk/issues/38489
+[ $arch == arm && $system == linux ]
+function_callbacks_structs_by_value_test: Slow # QEMU https://dartbug.com/45007
+
[ $compiler != dart2analyzer && $compiler != fasta && $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_structs_by_value_generated_test.dart b/tests/ffi/function_callbacks_structs_by_value_generated_test.dart
index 09648be..d13cf55 100644
--- a/tests/ffi/function_callbacks_structs_by_value_generated_test.dart
+++ b/tests/ffi/function_callbacks_structs_by_value_generated_test.dart
@@ -321,6 +321,31 @@
passStruct15BytesInlineArrayMixed, 0.0),
passStruct15BytesInlineArrayMixedAfterCallback),
CallbackTest.withCheck(
+ "PassUnion4BytesMixedx10",
+ Pointer.fromFunction<PassUnion4BytesMixedx10Type>(
+ passUnion4BytesMixedx10, 0.0),
+ passUnion4BytesMixedx10AfterCallback),
+ CallbackTest.withCheck(
+ "PassUnion8BytesNestedFloatx10",
+ Pointer.fromFunction<PassUnion8BytesNestedFloatx10Type>(
+ passUnion8BytesNestedFloatx10, 0.0),
+ passUnion8BytesNestedFloatx10AfterCallback),
+ CallbackTest.withCheck(
+ "PassUnion9BytesNestedIntx10",
+ Pointer.fromFunction<PassUnion9BytesNestedIntx10Type>(
+ passUnion9BytesNestedIntx10, 0.0),
+ passUnion9BytesNestedIntx10AfterCallback),
+ CallbackTest.withCheck(
+ "PassUnion16BytesNestedInlineArrayFloatx10",
+ Pointer.fromFunction<PassUnion16BytesNestedInlineArrayFloatx10Type>(
+ passUnion16BytesNestedInlineArrayFloatx10, 0.0),
+ passUnion16BytesNestedInlineArrayFloatx10AfterCallback),
+ CallbackTest.withCheck(
+ "PassUnion16BytesNestedFloatx10",
+ Pointer.fromFunction<PassUnion16BytesNestedFloatx10Type>(
+ passUnion16BytesNestedFloatx10, 0.0),
+ passUnion16BytesNestedFloatx10AfterCallback),
+ CallbackTest.withCheck(
"ReturnStruct1ByteInt",
Pointer.fromFunction<ReturnStruct1ByteIntType>(returnStruct1ByteInt),
returnStruct1ByteIntAfterCallback),
@@ -443,6 +468,25 @@
returnStruct9BytesPackedMixed),
returnStruct9BytesPackedMixedAfterCallback),
CallbackTest.withCheck(
+ "ReturnUnion4BytesMixed",
+ Pointer.fromFunction<ReturnUnion4BytesMixedType>(returnUnion4BytesMixed),
+ returnUnion4BytesMixedAfterCallback),
+ CallbackTest.withCheck(
+ "ReturnUnion8BytesNestedFloat",
+ Pointer.fromFunction<ReturnUnion8BytesNestedFloatType>(
+ returnUnion8BytesNestedFloat),
+ returnUnion8BytesNestedFloatAfterCallback),
+ CallbackTest.withCheck(
+ "ReturnUnion9BytesNestedInt",
+ Pointer.fromFunction<ReturnUnion9BytesNestedIntType>(
+ returnUnion9BytesNestedInt),
+ returnUnion9BytesNestedIntAfterCallback),
+ CallbackTest.withCheck(
+ "ReturnUnion16BytesNestedFloat",
+ Pointer.fromFunction<ReturnUnion16BytesNestedFloatType>(
+ returnUnion16BytesNestedFloat),
+ returnUnion16BytesNestedFloatAfterCallback),
+ CallbackTest.withCheck(
"ReturnStructArgumentStruct1ByteInt",
Pointer.fromFunction<ReturnStructArgumentStruct1ByteIntType>(
returnStructArgumentStruct1ByteInt),
@@ -6840,6 +6884,582 @@
Expect.approxEquals(3.0, result);
}
+typedef PassUnion4BytesMixedx10Type = Double Function(
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed);
+
+// Global variables to be able to test inputs after callback returned.
+Union4BytesMixed passUnion4BytesMixedx10_a0 = Union4BytesMixed();
+Union4BytesMixed passUnion4BytesMixedx10_a1 = Union4BytesMixed();
+Union4BytesMixed passUnion4BytesMixedx10_a2 = Union4BytesMixed();
+Union4BytesMixed passUnion4BytesMixedx10_a3 = Union4BytesMixed();
+Union4BytesMixed passUnion4BytesMixedx10_a4 = Union4BytesMixed();
+Union4BytesMixed passUnion4BytesMixedx10_a5 = Union4BytesMixed();
+Union4BytesMixed passUnion4BytesMixedx10_a6 = Union4BytesMixed();
+Union4BytesMixed passUnion4BytesMixedx10_a7 = Union4BytesMixed();
+Union4BytesMixed passUnion4BytesMixedx10_a8 = Union4BytesMixed();
+Union4BytesMixed passUnion4BytesMixedx10_a9 = Union4BytesMixed();
+
+// Result variable also global, so we can delete it after the callback.
+double passUnion4BytesMixedx10Result = 0.0;
+
+double passUnion4BytesMixedx10CalculateResult() {
+ double result = 0;
+
+ result += passUnion4BytesMixedx10_a0.a0;
+ result += passUnion4BytesMixedx10_a1.a0;
+ result += passUnion4BytesMixedx10_a2.a0;
+ result += passUnion4BytesMixedx10_a3.a0;
+ result += passUnion4BytesMixedx10_a4.a0;
+ result += passUnion4BytesMixedx10_a5.a0;
+ result += passUnion4BytesMixedx10_a6.a0;
+ result += passUnion4BytesMixedx10_a7.a0;
+ result += passUnion4BytesMixedx10_a8.a0;
+ result += passUnion4BytesMixedx10_a9.a0;
+
+ passUnion4BytesMixedx10Result = result;
+
+ return result;
+}
+
+/// Check placement of mixed integer/float union.
+double passUnion4BytesMixedx10(
+ Union4BytesMixed a0,
+ Union4BytesMixed a1,
+ Union4BytesMixed a2,
+ Union4BytesMixed a3,
+ Union4BytesMixed a4,
+ Union4BytesMixed a5,
+ Union4BytesMixed a6,
+ Union4BytesMixed a7,
+ Union4BytesMixed a8,
+ Union4BytesMixed a9) {
+ print(
+ "passUnion4BytesMixedx10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+ // In legacy mode, possibly return null.
+
+ // In both nnbd and legacy mode, possibly throw.
+ if (a0.a0 == 42 || a0.a0 == 84) {
+ print("throwing!");
+ throw Exception("PassUnion4BytesMixedx10 throwing on purpose!");
+ }
+
+ passUnion4BytesMixedx10_a0 = a0;
+ passUnion4BytesMixedx10_a1 = a1;
+ passUnion4BytesMixedx10_a2 = a2;
+ passUnion4BytesMixedx10_a3 = a3;
+ passUnion4BytesMixedx10_a4 = a4;
+ passUnion4BytesMixedx10_a5 = a5;
+ passUnion4BytesMixedx10_a6 = a6;
+ passUnion4BytesMixedx10_a7 = a7;
+ passUnion4BytesMixedx10_a8 = a8;
+ passUnion4BytesMixedx10_a9 = a9;
+
+ final result = passUnion4BytesMixedx10CalculateResult();
+
+ print("result = $result");
+
+ return result;
+}
+
+void passUnion4BytesMixedx10AfterCallback() {
+ final result = passUnion4BytesMixedx10CalculateResult();
+
+ print("after callback result = $result");
+
+ Expect.approxEquals(55.0, result);
+}
+
+typedef PassUnion8BytesNestedFloatx10Type = Double Function(
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat);
+
+// Global variables to be able to test inputs after callback returned.
+Union8BytesNestedFloat passUnion8BytesNestedFloatx10_a0 =
+ Union8BytesNestedFloat();
+Union8BytesNestedFloat passUnion8BytesNestedFloatx10_a1 =
+ Union8BytesNestedFloat();
+Union8BytesNestedFloat passUnion8BytesNestedFloatx10_a2 =
+ Union8BytesNestedFloat();
+Union8BytesNestedFloat passUnion8BytesNestedFloatx10_a3 =
+ Union8BytesNestedFloat();
+Union8BytesNestedFloat passUnion8BytesNestedFloatx10_a4 =
+ Union8BytesNestedFloat();
+Union8BytesNestedFloat passUnion8BytesNestedFloatx10_a5 =
+ Union8BytesNestedFloat();
+Union8BytesNestedFloat passUnion8BytesNestedFloatx10_a6 =
+ Union8BytesNestedFloat();
+Union8BytesNestedFloat passUnion8BytesNestedFloatx10_a7 =
+ Union8BytesNestedFloat();
+Union8BytesNestedFloat passUnion8BytesNestedFloatx10_a8 =
+ Union8BytesNestedFloat();
+Union8BytesNestedFloat passUnion8BytesNestedFloatx10_a9 =
+ Union8BytesNestedFloat();
+
+// Result variable also global, so we can delete it after the callback.
+double passUnion8BytesNestedFloatx10Result = 0.0;
+
+double passUnion8BytesNestedFloatx10CalculateResult() {
+ double result = 0;
+
+ result += passUnion8BytesNestedFloatx10_a0.a0;
+ result += passUnion8BytesNestedFloatx10_a1.a0;
+ result += passUnion8BytesNestedFloatx10_a2.a0;
+ result += passUnion8BytesNestedFloatx10_a3.a0;
+ result += passUnion8BytesNestedFloatx10_a4.a0;
+ result += passUnion8BytesNestedFloatx10_a5.a0;
+ result += passUnion8BytesNestedFloatx10_a6.a0;
+ result += passUnion8BytesNestedFloatx10_a7.a0;
+ result += passUnion8BytesNestedFloatx10_a8.a0;
+ result += passUnion8BytesNestedFloatx10_a9.a0;
+
+ passUnion8BytesNestedFloatx10Result = result;
+
+ return result;
+}
+
+/// Check placement of mixed floats union.
+double passUnion8BytesNestedFloatx10(
+ Union8BytesNestedFloat a0,
+ Union8BytesNestedFloat a1,
+ Union8BytesNestedFloat a2,
+ Union8BytesNestedFloat a3,
+ Union8BytesNestedFloat a4,
+ Union8BytesNestedFloat a5,
+ Union8BytesNestedFloat a6,
+ Union8BytesNestedFloat a7,
+ Union8BytesNestedFloat a8,
+ Union8BytesNestedFloat a9) {
+ print(
+ "passUnion8BytesNestedFloatx10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+ // In legacy mode, possibly return null.
+
+ // In both nnbd and legacy mode, possibly throw.
+ if (a0.a0 == 42 || a0.a0 == 84) {
+ print("throwing!");
+ throw Exception("PassUnion8BytesNestedFloatx10 throwing on purpose!");
+ }
+
+ passUnion8BytesNestedFloatx10_a0 = a0;
+ passUnion8BytesNestedFloatx10_a1 = a1;
+ passUnion8BytesNestedFloatx10_a2 = a2;
+ passUnion8BytesNestedFloatx10_a3 = a3;
+ passUnion8BytesNestedFloatx10_a4 = a4;
+ passUnion8BytesNestedFloatx10_a5 = a5;
+ passUnion8BytesNestedFloatx10_a6 = a6;
+ passUnion8BytesNestedFloatx10_a7 = a7;
+ passUnion8BytesNestedFloatx10_a8 = a8;
+ passUnion8BytesNestedFloatx10_a9 = a9;
+
+ final result = passUnion8BytesNestedFloatx10CalculateResult();
+
+ print("result = $result");
+
+ return result;
+}
+
+void passUnion8BytesNestedFloatx10AfterCallback() {
+ final result = passUnion8BytesNestedFloatx10CalculateResult();
+
+ print("after callback result = $result");
+
+ Expect.approxEquals(5.0, result);
+}
+
+typedef PassUnion9BytesNestedIntx10Type = Double Function(
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt);
+
+// Global variables to be able to test inputs after callback returned.
+Union9BytesNestedInt passUnion9BytesNestedIntx10_a0 = Union9BytesNestedInt();
+Union9BytesNestedInt passUnion9BytesNestedIntx10_a1 = Union9BytesNestedInt();
+Union9BytesNestedInt passUnion9BytesNestedIntx10_a2 = Union9BytesNestedInt();
+Union9BytesNestedInt passUnion9BytesNestedIntx10_a3 = Union9BytesNestedInt();
+Union9BytesNestedInt passUnion9BytesNestedIntx10_a4 = Union9BytesNestedInt();
+Union9BytesNestedInt passUnion9BytesNestedIntx10_a5 = Union9BytesNestedInt();
+Union9BytesNestedInt passUnion9BytesNestedIntx10_a6 = Union9BytesNestedInt();
+Union9BytesNestedInt passUnion9BytesNestedIntx10_a7 = Union9BytesNestedInt();
+Union9BytesNestedInt passUnion9BytesNestedIntx10_a8 = Union9BytesNestedInt();
+Union9BytesNestedInt passUnion9BytesNestedIntx10_a9 = Union9BytesNestedInt();
+
+// Result variable also global, so we can delete it after the callback.
+double passUnion9BytesNestedIntx10Result = 0.0;
+
+double passUnion9BytesNestedIntx10CalculateResult() {
+ double result = 0;
+
+ result += passUnion9BytesNestedIntx10_a0.a0.a0;
+ result += passUnion9BytesNestedIntx10_a0.a0.a1;
+ result += passUnion9BytesNestedIntx10_a0.a0.a2;
+ result += passUnion9BytesNestedIntx10_a1.a0.a0;
+ result += passUnion9BytesNestedIntx10_a1.a0.a1;
+ result += passUnion9BytesNestedIntx10_a1.a0.a2;
+ result += passUnion9BytesNestedIntx10_a2.a0.a0;
+ result += passUnion9BytesNestedIntx10_a2.a0.a1;
+ result += passUnion9BytesNestedIntx10_a2.a0.a2;
+ result += passUnion9BytesNestedIntx10_a3.a0.a0;
+ result += passUnion9BytesNestedIntx10_a3.a0.a1;
+ result += passUnion9BytesNestedIntx10_a3.a0.a2;
+ result += passUnion9BytesNestedIntx10_a4.a0.a0;
+ result += passUnion9BytesNestedIntx10_a4.a0.a1;
+ result += passUnion9BytesNestedIntx10_a4.a0.a2;
+ result += passUnion9BytesNestedIntx10_a5.a0.a0;
+ result += passUnion9BytesNestedIntx10_a5.a0.a1;
+ result += passUnion9BytesNestedIntx10_a5.a0.a2;
+ result += passUnion9BytesNestedIntx10_a6.a0.a0;
+ result += passUnion9BytesNestedIntx10_a6.a0.a1;
+ result += passUnion9BytesNestedIntx10_a6.a0.a2;
+ result += passUnion9BytesNestedIntx10_a7.a0.a0;
+ result += passUnion9BytesNestedIntx10_a7.a0.a1;
+ result += passUnion9BytesNestedIntx10_a7.a0.a2;
+ result += passUnion9BytesNestedIntx10_a8.a0.a0;
+ result += passUnion9BytesNestedIntx10_a8.a0.a1;
+ result += passUnion9BytesNestedIntx10_a8.a0.a2;
+ result += passUnion9BytesNestedIntx10_a9.a0.a0;
+ result += passUnion9BytesNestedIntx10_a9.a0.a1;
+ result += passUnion9BytesNestedIntx10_a9.a0.a2;
+
+ passUnion9BytesNestedIntx10Result = result;
+
+ return result;
+}
+
+/// Mixed-size union argument.
+double passUnion9BytesNestedIntx10(
+ Union9BytesNestedInt a0,
+ Union9BytesNestedInt a1,
+ Union9BytesNestedInt a2,
+ Union9BytesNestedInt a3,
+ Union9BytesNestedInt a4,
+ Union9BytesNestedInt a5,
+ Union9BytesNestedInt a6,
+ Union9BytesNestedInt a7,
+ Union9BytesNestedInt a8,
+ Union9BytesNestedInt a9) {
+ print(
+ "passUnion9BytesNestedIntx10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+ // In legacy mode, possibly return null.
+
+ // In both nnbd and legacy mode, possibly throw.
+ if (a0.a0.a0 == 42 || a0.a0.a0 == 84) {
+ print("throwing!");
+ throw Exception("PassUnion9BytesNestedIntx10 throwing on purpose!");
+ }
+
+ passUnion9BytesNestedIntx10_a0 = a0;
+ passUnion9BytesNestedIntx10_a1 = a1;
+ passUnion9BytesNestedIntx10_a2 = a2;
+ passUnion9BytesNestedIntx10_a3 = a3;
+ passUnion9BytesNestedIntx10_a4 = a4;
+ passUnion9BytesNestedIntx10_a5 = a5;
+ passUnion9BytesNestedIntx10_a6 = a6;
+ passUnion9BytesNestedIntx10_a7 = a7;
+ passUnion9BytesNestedIntx10_a8 = a8;
+ passUnion9BytesNestedIntx10_a9 = a9;
+
+ final result = passUnion9BytesNestedIntx10CalculateResult();
+
+ print("result = $result");
+
+ return result;
+}
+
+void passUnion9BytesNestedIntx10AfterCallback() {
+ final result = passUnion9BytesNestedIntx10CalculateResult();
+
+ print("after callback result = $result");
+
+ Expect.approxEquals(15.0, result);
+}
+
+typedef PassUnion16BytesNestedInlineArrayFloatx10Type = Double Function(
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat);
+
+// Global variables to be able to test inputs after callback returned.
+Union16BytesNestedInlineArrayFloat
+ passUnion16BytesNestedInlineArrayFloatx10_a0 =
+ Union16BytesNestedInlineArrayFloat();
+Union16BytesNestedInlineArrayFloat
+ passUnion16BytesNestedInlineArrayFloatx10_a1 =
+ Union16BytesNestedInlineArrayFloat();
+Union16BytesNestedInlineArrayFloat
+ passUnion16BytesNestedInlineArrayFloatx10_a2 =
+ Union16BytesNestedInlineArrayFloat();
+Union16BytesNestedInlineArrayFloat
+ passUnion16BytesNestedInlineArrayFloatx10_a3 =
+ Union16BytesNestedInlineArrayFloat();
+Union16BytesNestedInlineArrayFloat
+ passUnion16BytesNestedInlineArrayFloatx10_a4 =
+ Union16BytesNestedInlineArrayFloat();
+Union16BytesNestedInlineArrayFloat
+ passUnion16BytesNestedInlineArrayFloatx10_a5 =
+ Union16BytesNestedInlineArrayFloat();
+Union16BytesNestedInlineArrayFloat
+ passUnion16BytesNestedInlineArrayFloatx10_a6 =
+ Union16BytesNestedInlineArrayFloat();
+Union16BytesNestedInlineArrayFloat
+ passUnion16BytesNestedInlineArrayFloatx10_a7 =
+ Union16BytesNestedInlineArrayFloat();
+Union16BytesNestedInlineArrayFloat
+ passUnion16BytesNestedInlineArrayFloatx10_a8 =
+ Union16BytesNestedInlineArrayFloat();
+Union16BytesNestedInlineArrayFloat
+ passUnion16BytesNestedInlineArrayFloatx10_a9 =
+ Union16BytesNestedInlineArrayFloat();
+
+// Result variable also global, so we can delete it after the callback.
+double passUnion16BytesNestedInlineArrayFloatx10Result = 0.0;
+
+double passUnion16BytesNestedInlineArrayFloatx10CalculateResult() {
+ double result = 0;
+
+ result += passUnion16BytesNestedInlineArrayFloatx10_a0.a0[0];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a0.a0[1];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a0.a0[2];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a0.a0[3];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a1.a0[0];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a1.a0[1];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a1.a0[2];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a1.a0[3];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a2.a0[0];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a2.a0[1];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a2.a0[2];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a2.a0[3];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a3.a0[0];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a3.a0[1];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a3.a0[2];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a3.a0[3];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a4.a0[0];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a4.a0[1];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a4.a0[2];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a4.a0[3];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a5.a0[0];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a5.a0[1];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a5.a0[2];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a5.a0[3];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a6.a0[0];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a6.a0[1];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a6.a0[2];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a6.a0[3];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a7.a0[0];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a7.a0[1];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a7.a0[2];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a7.a0[3];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a8.a0[0];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a8.a0[1];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a8.a0[2];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a8.a0[3];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a9.a0[0];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a9.a0[1];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a9.a0[2];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a9.a0[3];
+
+ passUnion16BytesNestedInlineArrayFloatx10Result = result;
+
+ return result;
+}
+
+/// Union with homogenous floats.
+double passUnion16BytesNestedInlineArrayFloatx10(
+ Union16BytesNestedInlineArrayFloat a0,
+ Union16BytesNestedInlineArrayFloat a1,
+ Union16BytesNestedInlineArrayFloat a2,
+ Union16BytesNestedInlineArrayFloat a3,
+ Union16BytesNestedInlineArrayFloat a4,
+ Union16BytesNestedInlineArrayFloat a5,
+ Union16BytesNestedInlineArrayFloat a6,
+ Union16BytesNestedInlineArrayFloat a7,
+ Union16BytesNestedInlineArrayFloat a8,
+ Union16BytesNestedInlineArrayFloat a9) {
+ print(
+ "passUnion16BytesNestedInlineArrayFloatx10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+ // In legacy mode, possibly return null.
+
+ // In both nnbd and legacy mode, possibly throw.
+ if (a0.a0[0] == 42 || a0.a0[0] == 84) {
+ print("throwing!");
+ throw Exception(
+ "PassUnion16BytesNestedInlineArrayFloatx10 throwing on purpose!");
+ }
+
+ passUnion16BytesNestedInlineArrayFloatx10_a0 = a0;
+ passUnion16BytesNestedInlineArrayFloatx10_a1 = a1;
+ passUnion16BytesNestedInlineArrayFloatx10_a2 = a2;
+ passUnion16BytesNestedInlineArrayFloatx10_a3 = a3;
+ passUnion16BytesNestedInlineArrayFloatx10_a4 = a4;
+ passUnion16BytesNestedInlineArrayFloatx10_a5 = a5;
+ passUnion16BytesNestedInlineArrayFloatx10_a6 = a6;
+ passUnion16BytesNestedInlineArrayFloatx10_a7 = a7;
+ passUnion16BytesNestedInlineArrayFloatx10_a8 = a8;
+ passUnion16BytesNestedInlineArrayFloatx10_a9 = a9;
+
+ final result = passUnion16BytesNestedInlineArrayFloatx10CalculateResult();
+
+ print("result = $result");
+
+ return result;
+}
+
+void passUnion16BytesNestedInlineArrayFloatx10AfterCallback() {
+ final result = passUnion16BytesNestedInlineArrayFloatx10CalculateResult();
+
+ print("after callback result = $result");
+
+ Expect.approxEquals(20.0, result);
+}
+
+typedef PassUnion16BytesNestedFloatx10Type = Double Function(
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat);
+
+// Global variables to be able to test inputs after callback returned.
+Union16BytesNestedFloat passUnion16BytesNestedFloatx10_a0 =
+ Union16BytesNestedFloat();
+Union16BytesNestedFloat passUnion16BytesNestedFloatx10_a1 =
+ Union16BytesNestedFloat();
+Union16BytesNestedFloat passUnion16BytesNestedFloatx10_a2 =
+ Union16BytesNestedFloat();
+Union16BytesNestedFloat passUnion16BytesNestedFloatx10_a3 =
+ Union16BytesNestedFloat();
+Union16BytesNestedFloat passUnion16BytesNestedFloatx10_a4 =
+ Union16BytesNestedFloat();
+Union16BytesNestedFloat passUnion16BytesNestedFloatx10_a5 =
+ Union16BytesNestedFloat();
+Union16BytesNestedFloat passUnion16BytesNestedFloatx10_a6 =
+ Union16BytesNestedFloat();
+Union16BytesNestedFloat passUnion16BytesNestedFloatx10_a7 =
+ Union16BytesNestedFloat();
+Union16BytesNestedFloat passUnion16BytesNestedFloatx10_a8 =
+ Union16BytesNestedFloat();
+Union16BytesNestedFloat passUnion16BytesNestedFloatx10_a9 =
+ Union16BytesNestedFloat();
+
+// Result variable also global, so we can delete it after the callback.
+double passUnion16BytesNestedFloatx10Result = 0.0;
+
+double passUnion16BytesNestedFloatx10CalculateResult() {
+ double result = 0;
+
+ result += passUnion16BytesNestedFloatx10_a0.a0.a0;
+ result += passUnion16BytesNestedFloatx10_a0.a0.a1;
+ result += passUnion16BytesNestedFloatx10_a1.a0.a0;
+ result += passUnion16BytesNestedFloatx10_a1.a0.a1;
+ result += passUnion16BytesNestedFloatx10_a2.a0.a0;
+ result += passUnion16BytesNestedFloatx10_a2.a0.a1;
+ result += passUnion16BytesNestedFloatx10_a3.a0.a0;
+ result += passUnion16BytesNestedFloatx10_a3.a0.a1;
+ result += passUnion16BytesNestedFloatx10_a4.a0.a0;
+ result += passUnion16BytesNestedFloatx10_a4.a0.a1;
+ result += passUnion16BytesNestedFloatx10_a5.a0.a0;
+ result += passUnion16BytesNestedFloatx10_a5.a0.a1;
+ result += passUnion16BytesNestedFloatx10_a6.a0.a0;
+ result += passUnion16BytesNestedFloatx10_a6.a0.a1;
+ result += passUnion16BytesNestedFloatx10_a7.a0.a0;
+ result += passUnion16BytesNestedFloatx10_a7.a0.a1;
+ result += passUnion16BytesNestedFloatx10_a8.a0.a0;
+ result += passUnion16BytesNestedFloatx10_a8.a0.a1;
+ result += passUnion16BytesNestedFloatx10_a9.a0.a0;
+ result += passUnion16BytesNestedFloatx10_a9.a0.a1;
+
+ passUnion16BytesNestedFloatx10Result = result;
+
+ return result;
+}
+
+/// Union with homogenous floats.
+double passUnion16BytesNestedFloatx10(
+ Union16BytesNestedFloat a0,
+ Union16BytesNestedFloat a1,
+ Union16BytesNestedFloat a2,
+ Union16BytesNestedFloat a3,
+ Union16BytesNestedFloat a4,
+ Union16BytesNestedFloat a5,
+ Union16BytesNestedFloat a6,
+ Union16BytesNestedFloat a7,
+ Union16BytesNestedFloat a8,
+ Union16BytesNestedFloat a9) {
+ print(
+ "passUnion16BytesNestedFloatx10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+ // In legacy mode, possibly return null.
+
+ // In both nnbd and legacy mode, possibly throw.
+ if (a0.a0.a0 == 42 || a0.a0.a0 == 84) {
+ print("throwing!");
+ throw Exception("PassUnion16BytesNestedFloatx10 throwing on purpose!");
+ }
+
+ passUnion16BytesNestedFloatx10_a0 = a0;
+ passUnion16BytesNestedFloatx10_a1 = a1;
+ passUnion16BytesNestedFloatx10_a2 = a2;
+ passUnion16BytesNestedFloatx10_a3 = a3;
+ passUnion16BytesNestedFloatx10_a4 = a4;
+ passUnion16BytesNestedFloatx10_a5 = a5;
+ passUnion16BytesNestedFloatx10_a6 = a6;
+ passUnion16BytesNestedFloatx10_a7 = a7;
+ passUnion16BytesNestedFloatx10_a8 = a8;
+ passUnion16BytesNestedFloatx10_a9 = a9;
+
+ final result = passUnion16BytesNestedFloatx10CalculateResult();
+
+ print("result = $result");
+
+ return result;
+}
+
+void passUnion16BytesNestedFloatx10AfterCallback() {
+ final result = passUnion16BytesNestedFloatx10CalculateResult();
+
+ print("after callback result = $result");
+
+ Expect.approxEquals(10.0, result);
+}
+
typedef ReturnStruct1ByteIntType = Struct1ByteInt Function(Int8);
// Global variables to be able to test inputs after callback returned.
@@ -9089,6 +9709,216 @@
calloc.free(returnStruct9BytesPackedMixedResultPointer);
}
+typedef ReturnUnion4BytesMixedType = Union4BytesMixed Function(Uint32);
+
+// Global variables to be able to test inputs after callback returned.
+int returnUnion4BytesMixed_a0 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+Pointer<Union4BytesMixed> returnUnion4BytesMixedResultPointer = nullptr;
+
+Union4BytesMixed returnUnion4BytesMixedCalculateResult() {
+ final resultPointer = calloc<Union4BytesMixed>();
+ final result = resultPointer.ref;
+
+ result.a0 = returnUnion4BytesMixed_a0;
+
+ returnUnion4BytesMixedResultPointer = resultPointer;
+
+ return result;
+}
+
+/// Returning a mixed integer/float union.
+Union4BytesMixed returnUnion4BytesMixed(int a0) {
+ print("returnUnion4BytesMixed(${a0})");
+
+ // In legacy mode, possibly return null.
+
+ // In both nnbd and legacy mode, possibly throw.
+ if (a0 == 42 || a0 == 84) {
+ print("throwing!");
+ throw Exception("ReturnUnion4BytesMixed throwing on purpose!");
+ }
+
+ returnUnion4BytesMixed_a0 = a0;
+
+ final result = returnUnion4BytesMixedCalculateResult();
+
+ print("result = $result");
+
+ return result;
+}
+
+void returnUnion4BytesMixedAfterCallback() {
+ calloc.free(returnUnion4BytesMixedResultPointer);
+
+ final result = returnUnion4BytesMixedCalculateResult();
+
+ print("after callback result = $result");
+
+ calloc.free(returnUnion4BytesMixedResultPointer);
+}
+
+typedef ReturnUnion8BytesNestedFloatType = Union8BytesNestedFloat Function(
+ Double);
+
+// Global variables to be able to test inputs after callback returned.
+double returnUnion8BytesNestedFloat_a0 = 0.0;
+
+// Result variable also global, so we can delete it after the callback.
+Pointer<Union8BytesNestedFloat> returnUnion8BytesNestedFloatResultPointer =
+ nullptr;
+
+Union8BytesNestedFloat returnUnion8BytesNestedFloatCalculateResult() {
+ final resultPointer = calloc<Union8BytesNestedFloat>();
+ final result = resultPointer.ref;
+
+ result.a0 = returnUnion8BytesNestedFloat_a0;
+
+ returnUnion8BytesNestedFloatResultPointer = resultPointer;
+
+ return result;
+}
+
+/// Returning a floating point only union.
+Union8BytesNestedFloat returnUnion8BytesNestedFloat(double a0) {
+ print("returnUnion8BytesNestedFloat(${a0})");
+
+ // In legacy mode, possibly return null.
+
+ // In both nnbd and legacy mode, possibly throw.
+ if (a0 == 42 || a0 == 84) {
+ print("throwing!");
+ throw Exception("ReturnUnion8BytesNestedFloat throwing on purpose!");
+ }
+
+ returnUnion8BytesNestedFloat_a0 = a0;
+
+ final result = returnUnion8BytesNestedFloatCalculateResult();
+
+ print("result = $result");
+
+ return result;
+}
+
+void returnUnion8BytesNestedFloatAfterCallback() {
+ calloc.free(returnUnion8BytesNestedFloatResultPointer);
+
+ final result = returnUnion8BytesNestedFloatCalculateResult();
+
+ print("after callback result = $result");
+
+ calloc.free(returnUnion8BytesNestedFloatResultPointer);
+}
+
+typedef ReturnUnion9BytesNestedIntType = Union9BytesNestedInt Function(
+ Struct8BytesInt);
+
+// Global variables to be able to test inputs after callback returned.
+Struct8BytesInt returnUnion9BytesNestedInt_a0 = Struct8BytesInt();
+
+// Result variable also global, so we can delete it after the callback.
+Pointer<Union9BytesNestedInt> returnUnion9BytesNestedIntResultPointer = nullptr;
+
+Union9BytesNestedInt returnUnion9BytesNestedIntCalculateResult() {
+ final resultPointer = calloc<Union9BytesNestedInt>();
+ final result = resultPointer.ref;
+
+ result.a0.a0 = returnUnion9BytesNestedInt_a0.a0;
+ result.a0.a1 = returnUnion9BytesNestedInt_a0.a1;
+ result.a0.a2 = returnUnion9BytesNestedInt_a0.a2;
+
+ returnUnion9BytesNestedIntResultPointer = resultPointer;
+
+ return result;
+}
+
+/// Returning a mixed-size union.
+Union9BytesNestedInt returnUnion9BytesNestedInt(Struct8BytesInt a0) {
+ print("returnUnion9BytesNestedInt(${a0})");
+
+ // In legacy mode, possibly return null.
+
+ // In both nnbd and legacy mode, possibly throw.
+ if (a0.a0 == 42 || a0.a0 == 84) {
+ print("throwing!");
+ throw Exception("ReturnUnion9BytesNestedInt throwing on purpose!");
+ }
+
+ returnUnion9BytesNestedInt_a0 = a0;
+
+ final result = returnUnion9BytesNestedIntCalculateResult();
+
+ print("result = $result");
+
+ return result;
+}
+
+void returnUnion9BytesNestedIntAfterCallback() {
+ calloc.free(returnUnion9BytesNestedIntResultPointer);
+
+ final result = returnUnion9BytesNestedIntCalculateResult();
+
+ print("after callback result = $result");
+
+ calloc.free(returnUnion9BytesNestedIntResultPointer);
+}
+
+typedef ReturnUnion16BytesNestedFloatType = Union16BytesNestedFloat Function(
+ Struct8BytesHomogeneousFloat);
+
+// Global variables to be able to test inputs after callback returned.
+Struct8BytesHomogeneousFloat returnUnion16BytesNestedFloat_a0 =
+ Struct8BytesHomogeneousFloat();
+
+// Result variable also global, so we can delete it after the callback.
+Pointer<Union16BytesNestedFloat> returnUnion16BytesNestedFloatResultPointer =
+ nullptr;
+
+Union16BytesNestedFloat returnUnion16BytesNestedFloatCalculateResult() {
+ final resultPointer = calloc<Union16BytesNestedFloat>();
+ final result = resultPointer.ref;
+
+ result.a0.a0 = returnUnion16BytesNestedFloat_a0.a0;
+ result.a0.a1 = returnUnion16BytesNestedFloat_a0.a1;
+
+ returnUnion16BytesNestedFloatResultPointer = resultPointer;
+
+ return result;
+}
+
+/// Returning union with homogenous floats.
+Union16BytesNestedFloat returnUnion16BytesNestedFloat(
+ Struct8BytesHomogeneousFloat a0) {
+ print("returnUnion16BytesNestedFloat(${a0})");
+
+ // In legacy mode, possibly return null.
+
+ // In both nnbd and legacy mode, possibly throw.
+ if (a0.a0 == 42 || a0.a0 == 84) {
+ print("throwing!");
+ throw Exception("ReturnUnion16BytesNestedFloat throwing on purpose!");
+ }
+
+ returnUnion16BytesNestedFloat_a0 = a0;
+
+ final result = returnUnion16BytesNestedFloatCalculateResult();
+
+ print("result = $result");
+
+ return result;
+}
+
+void returnUnion16BytesNestedFloatAfterCallback() {
+ calloc.free(returnUnion16BytesNestedFloatResultPointer);
+
+ final result = returnUnion16BytesNestedFloatCalculateResult();
+
+ print("after callback result = $result");
+
+ calloc.free(returnUnion16BytesNestedFloatResultPointer);
+}
+
typedef ReturnStructArgumentStruct1ByteIntType = Struct1ByteInt Function(
Struct1ByteInt);
diff --git a/tests/ffi/function_structs_by_value_generated_test.dart b/tests/ffi/function_structs_by_value_generated_test.dart
index d52c0d3..e830631 100644
--- a/tests/ffi/function_structs_by_value_generated_test.dart
+++ b/tests/ffi/function_structs_by_value_generated_test.dart
@@ -77,6 +77,11 @@
testPassStructNestedAlignmentStruct5BytesPackedMixed();
testPassStruct6BytesInlineArrayInt();
testPassStruct15BytesInlineArrayMixed();
+ testPassUnion4BytesMixedx10();
+ testPassUnion8BytesNestedFloatx10();
+ testPassUnion9BytesNestedIntx10();
+ testPassUnion16BytesNestedInlineArrayFloatx10();
+ testPassUnion16BytesNestedFloatx10();
testReturnStruct1ByteInt();
testReturnStruct3BytesHomogeneousUint8();
testReturnStruct3BytesInt2ByteAligned();
@@ -102,6 +107,10 @@
testReturnStruct3BytesPackedInt();
testReturnStruct8BytesPackedInt();
testReturnStruct9BytesPackedMixed();
+ testReturnUnion4BytesMixed();
+ testReturnUnion8BytesNestedFloat();
+ testReturnUnion9BytesNestedInt();
+ testReturnUnion16BytesNestedFloat();
testReturnStructArgumentStruct1ByteInt();
testReturnStructArgumentInt32x8Struct1ByteInt();
testReturnStructArgumentStruct8BytesHomogeneousFloat();
@@ -1283,6 +1292,52 @@
String toString() => "(${[for (var i0 = 0; i0 < 3; i0 += 1) a0[i0]]})";
}
+class Union4BytesMixed extends Union {
+ @Uint32()
+ external int a0;
+
+ @Float()
+ external double a1;
+
+ String toString() => "(${a0}, ${a1})";
+}
+
+class Union8BytesNestedFloat extends Union {
+ @Double()
+ external double a0;
+
+ external Struct8BytesHomogeneousFloat a1;
+
+ String toString() => "(${a0}, ${a1})";
+}
+
+class Union9BytesNestedInt extends Union {
+ external Struct8BytesInt a0;
+
+ external Struct9BytesHomogeneousUint8 a1;
+
+ String toString() => "(${a0}, ${a1})";
+}
+
+class Union16BytesNestedInlineArrayFloat extends Union {
+ @Array(4)
+ external Array<Float> a0;
+
+ external Struct16BytesHomogeneousFloat a1;
+
+ String toString() => "(${[for (var i0 = 0; i0 < 4; i0 += 1) a0[i0]]}, ${a1})";
+}
+
+class Union16BytesNestedFloat extends Union {
+ external Struct8BytesHomogeneousFloat a0;
+
+ external Struct12BytesHomogeneousFloat a1;
+
+ external Struct16BytesHomogeneousFloat a2;
+
+ String toString() => "(${a0}, ${a1}, ${a2})";
+}
+
final passStruct1ByteIntx10 = ffiTestFunctions.lookupFunction<
Int64 Function(
Struct1ByteInt,
@@ -5916,6 +5971,453 @@
calloc.free(a0Pointer);
}
+final passUnion4BytesMixedx10 = ffiTestFunctions.lookupFunction<
+ Double Function(
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed),
+ double Function(
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed)>("PassUnion4BytesMixedx10");
+
+/// Check placement of mixed integer/float union.
+void testPassUnion4BytesMixedx10() {
+ final a0Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a9 = a9Pointer.ref;
+
+ a0.a0 = 1;
+ a1.a0 = 2;
+ a2.a0 = 3;
+ a3.a0 = 4;
+ a4.a0 = 5;
+ a5.a0 = 6;
+ a6.a0 = 7;
+ a7.a0 = 8;
+ a8.a0 = 9;
+ a9.a0 = 10;
+
+ final result =
+ passUnion4BytesMixedx10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(55.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passUnion8BytesNestedFloatx10 = ffiTestFunctions.lookupFunction<
+ Double Function(
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat),
+ double Function(
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat)>("PassUnion8BytesNestedFloatx10");
+
+/// Check placement of mixed floats union.
+void testPassUnion8BytesNestedFloatx10() {
+ final a0Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a9 = a9Pointer.ref;
+
+ a0.a0 = -1.0;
+ a1.a0 = 2.0;
+ a2.a0 = -3.0;
+ a3.a0 = 4.0;
+ a4.a0 = -5.0;
+ a5.a0 = 6.0;
+ a6.a0 = -7.0;
+ a7.a0 = 8.0;
+ a8.a0 = -9.0;
+ a9.a0 = 10.0;
+
+ final result =
+ passUnion8BytesNestedFloatx10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(5.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passUnion9BytesNestedIntx10 = ffiTestFunctions.lookupFunction<
+ Double Function(
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt),
+ double Function(
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt)>("PassUnion9BytesNestedIntx10");
+
+/// Mixed-size union argument.
+void testPassUnion9BytesNestedIntx10() {
+ final a0Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a9 = a9Pointer.ref;
+
+ a0.a0.a0 = -1;
+ a0.a0.a1 = 2;
+ a0.a0.a2 = -3;
+ a1.a0.a0 = 4;
+ a1.a0.a1 = -5;
+ a1.a0.a2 = 6;
+ a2.a0.a0 = -7;
+ a2.a0.a1 = 8;
+ a2.a0.a2 = -9;
+ a3.a0.a0 = 10;
+ a3.a0.a1 = -11;
+ a3.a0.a2 = 12;
+ a4.a0.a0 = -13;
+ a4.a0.a1 = 14;
+ a4.a0.a2 = -15;
+ a5.a0.a0 = 16;
+ a5.a0.a1 = -17;
+ a5.a0.a2 = 18;
+ a6.a0.a0 = -19;
+ a6.a0.a1 = 20;
+ a6.a0.a2 = -21;
+ a7.a0.a0 = 22;
+ a7.a0.a1 = -23;
+ a7.a0.a2 = 24;
+ a8.a0.a0 = -25;
+ a8.a0.a1 = 26;
+ a8.a0.a2 = -27;
+ a9.a0.a0 = 28;
+ a9.a0.a1 = -29;
+ a9.a0.a2 = 30;
+
+ final result =
+ passUnion9BytesNestedIntx10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(15.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passUnion16BytesNestedInlineArrayFloatx10 =
+ ffiTestFunctions.lookupFunction<
+ Double Function(
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat),
+ double Function(
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat)>(
+ "PassUnion16BytesNestedInlineArrayFloatx10");
+
+/// Union with homogenous floats.
+void testPassUnion16BytesNestedInlineArrayFloatx10() {
+ final a0Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a9 = a9Pointer.ref;
+
+ a0.a0[0] = -1.0;
+ a0.a0[1] = 2.0;
+ a0.a0[2] = -3.0;
+ a0.a0[3] = 4.0;
+ a1.a0[0] = -5.0;
+ a1.a0[1] = 6.0;
+ a1.a0[2] = -7.0;
+ a1.a0[3] = 8.0;
+ a2.a0[0] = -9.0;
+ a2.a0[1] = 10.0;
+ a2.a0[2] = -11.0;
+ a2.a0[3] = 12.0;
+ a3.a0[0] = -13.0;
+ a3.a0[1] = 14.0;
+ a3.a0[2] = -15.0;
+ a3.a0[3] = 16.0;
+ a4.a0[0] = -17.0;
+ a4.a0[1] = 18.0;
+ a4.a0[2] = -19.0;
+ a4.a0[3] = 20.0;
+ a5.a0[0] = -21.0;
+ a5.a0[1] = 22.0;
+ a5.a0[2] = -23.0;
+ a5.a0[3] = 24.0;
+ a6.a0[0] = -25.0;
+ a6.a0[1] = 26.0;
+ a6.a0[2] = -27.0;
+ a6.a0[3] = 28.0;
+ a7.a0[0] = -29.0;
+ a7.a0[1] = 30.0;
+ a7.a0[2] = -31.0;
+ a7.a0[3] = 32.0;
+ a8.a0[0] = -33.0;
+ a8.a0[1] = 34.0;
+ a8.a0[2] = -35.0;
+ a8.a0[3] = 36.0;
+ a9.a0[0] = -37.0;
+ a9.a0[1] = 38.0;
+ a9.a0[2] = -39.0;
+ a9.a0[3] = 40.0;
+
+ final result = passUnion16BytesNestedInlineArrayFloatx10(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(20.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passUnion16BytesNestedFloatx10 = ffiTestFunctions.lookupFunction<
+ Double Function(
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat),
+ double Function(
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat)>("PassUnion16BytesNestedFloatx10");
+
+/// Union with homogenous floats.
+void testPassUnion16BytesNestedFloatx10() {
+ final a0Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a9 = a9Pointer.ref;
+
+ a0.a0.a0 = -1.0;
+ a0.a0.a1 = 2.0;
+ a1.a0.a0 = -3.0;
+ a1.a0.a1 = 4.0;
+ a2.a0.a0 = -5.0;
+ a2.a0.a1 = 6.0;
+ a3.a0.a0 = -7.0;
+ a3.a0.a1 = 8.0;
+ a4.a0.a0 = -9.0;
+ a4.a0.a1 = 10.0;
+ a5.a0.a0 = -11.0;
+ a5.a0.a1 = 12.0;
+ a6.a0.a0 = -13.0;
+ a6.a0.a1 = 14.0;
+ a7.a0.a0 = -15.0;
+ a7.a0.a1 = 16.0;
+ a8.a0.a0 = -17.0;
+ a8.a0.a1 = 18.0;
+ a9.a0.a0 = -19.0;
+ a9.a0.a1 = 20.0;
+
+ final result =
+ passUnion16BytesNestedFloatx10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(10.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
final returnStruct1ByteInt = ffiTestFunctions.lookupFunction<
Struct1ByteInt Function(Int8),
Struct1ByteInt Function(int)>("ReturnStruct1ByteInt");
@@ -7406,6 +7908,88 @@
Expect.approxEquals(a1, result.a1);
}
+final returnUnion4BytesMixed = ffiTestFunctions.lookupFunction<
+ Union4BytesMixed Function(Uint32),
+ Union4BytesMixed Function(int)>("ReturnUnion4BytesMixed");
+
+/// Returning a mixed integer/float union.
+void testReturnUnion4BytesMixed() {
+ int a0;
+
+ a0 = 1;
+
+ final result = returnUnion4BytesMixed(a0);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+}
+
+final returnUnion8BytesNestedFloat = ffiTestFunctions.lookupFunction<
+ Union8BytesNestedFloat Function(Double),
+ Union8BytesNestedFloat Function(double)>("ReturnUnion8BytesNestedFloat");
+
+/// Returning a floating point only union.
+void testReturnUnion8BytesNestedFloat() {
+ double a0;
+
+ a0 = -1.0;
+
+ final result = returnUnion8BytesNestedFloat(a0);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0, result.a0);
+}
+
+final returnUnion9BytesNestedInt = ffiTestFunctions.lookupFunction<
+ Union9BytesNestedInt Function(Struct8BytesInt),
+ Union9BytesNestedInt Function(
+ Struct8BytesInt)>("ReturnUnion9BytesNestedInt");
+
+/// Returning a mixed-size union.
+void testReturnUnion9BytesNestedInt() {
+ final a0Pointer = calloc<Struct8BytesInt>();
+ final Struct8BytesInt a0 = a0Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+
+ final result = returnUnion9BytesNestedInt(a0);
+
+ print("result = $result");
+
+ Expect.equals(a0.a0, result.a0.a0);
+ Expect.equals(a0.a1, result.a0.a1);
+ Expect.equals(a0.a2, result.a0.a2);
+
+ calloc.free(a0Pointer);
+}
+
+final returnUnion16BytesNestedFloat = ffiTestFunctions.lookupFunction<
+ Union16BytesNestedFloat Function(Struct8BytesHomogeneousFloat),
+ Union16BytesNestedFloat Function(
+ Struct8BytesHomogeneousFloat)>("ReturnUnion16BytesNestedFloat");
+
+/// Returning union with homogenous floats.
+void testReturnUnion16BytesNestedFloat() {
+ final a0Pointer = calloc<Struct8BytesHomogeneousFloat>();
+ final Struct8BytesHomogeneousFloat a0 = a0Pointer.ref;
+
+ a0.a0 = -1.0;
+ a0.a1 = 2.0;
+
+ final result = returnUnion16BytesNestedFloat(a0);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0.a0, result.a0.a0);
+ Expect.approxEquals(a0.a1, result.a0.a1);
+
+ calloc.free(a0Pointer);
+}
+
final returnStructArgumentStruct1ByteInt = ffiTestFunctions.lookupFunction<
Struct1ByteInt Function(Struct1ByteInt),
Struct1ByteInt Function(
diff --git a/tests/ffi/generator/c_types.dart b/tests/ffi/generator/c_types.dart
index df3b44b..7236aed 100644
--- a/tests/ffi/generator/c_types.dart
+++ b/tests/ffi/generator/c_types.dart
@@ -2,6 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'dart:math' as math;
+
import 'utils.dart';
const int8 = FundamentalType(PrimitiveType.int8);
@@ -152,36 +154,70 @@
return result;
}
-class StructType extends CType {
+abstract class CompositeType extends CType {
final List<Member> members;
- final int? packing;
-
/// To disambiguate same size structs.
final String suffix;
/// To override names.
final String overrideName;
- StructType(List<CType> memberTypes, {int? this.packing})
+ CompositeType(List<CType> memberTypes)
: this.members = generateMemberNames(memberTypes),
this.suffix = "",
this.overrideName = "";
- StructType.disambiguate(List<CType> memberTypes, this.suffix,
- {int? this.packing})
+ CompositeType.disambiguate(List<CType> memberTypes, this.suffix)
: this.members = generateMemberNames(memberTypes),
this.overrideName = "";
- StructType.override(List<CType> memberTypes, this.overrideName,
- {int? this.packing})
+ CompositeType.override(List<CType> memberTypes, this.overrideName)
: this.members = generateMemberNames(memberTypes),
this.suffix = "";
List<CType> get memberTypes => members.map((a) => a.type).toList();
+ String get name;
+
String get cType => name;
String get dartCType => name;
String get dartType => name;
String get dartStructFieldAnnotation => "";
+ String get cKeyword;
+ String get dartSuperClass;
+
+ bool get isOnlyFloatingPoint =>
+ !memberTypes.map((e) => e.isOnlyFloatingPoint).contains(false);
+ bool get isOnlyInteger =>
+ !memberTypes.map((e) => e.isOnlyInteger).contains(false);
+
+ bool get isMixed => !isOnlyInteger && !isOnlyFloatingPoint;
+
+ bool get hasNestedStructs =>
+ members.map((e) => e.type is StructType).contains(true);
+
+ bool get hasInlineArrays =>
+ members.map((e) => e.type is FixedLengthArrayType).contains(true);
+
+ bool get hasMultiDimensionalInlineArrays => members
+ .map((e) => e.type)
+ .whereType<FixedLengthArrayType>()
+ .where((e) => e.isMulti)
+ .isNotEmpty;
+}
+
+class StructType extends CompositeType {
+ final int? packing;
+
+ StructType(List<CType> memberTypes, {int? this.packing}) : super(memberTypes);
+ StructType.disambiguate(List<CType> memberTypes, String suffix,
+ {int? this.packing})
+ : super.disambiguate(memberTypes, suffix);
+ StructType.override(List<CType> memberTypes, String overrideName,
+ {int? this.packing})
+ : super.override(memberTypes, overrideName);
+
+ String get cKeyword => "struct";
+ String get dartSuperClass => "Struct";
bool get hasSize =>
!memberTypes.map((e) => e.hasSize).contains(false) && !hasPadding;
@@ -201,30 +237,11 @@
return members[0].type.size < members[1].type.size;
}
- bool get hasNestedStructs =>
- members.map((e) => e.type is StructType).contains(true);
-
- bool get hasInlineArrays =>
- members.map((e) => e.type is FixedLengthArrayType).contains(true);
-
- bool get hasMultiDimensionalInlineArrays => members
- .map((e) => e.type)
- .whereType<FixedLengthArrayType>()
- .where((e) => e.isMulti)
- .isNotEmpty;
-
/// All members have the same type.
bool get isHomogeneous => memberTypes.toSet().length == 1;
- bool get isOnlyFloatingPoint =>
- !memberTypes.map((e) => e.isOnlyFloatingPoint).contains(false);
- bool get isOnlyInteger =>
- !memberTypes.map((e) => e.isOnlyInteger).contains(false);
-
- bool get isMixed => !isOnlyInteger && !isOnlyFloatingPoint;
-
String get name {
- String result = "Struct";
+ String result = dartSuperClass;
if (overrideName != "") {
return result + overrideName;
}
@@ -264,6 +281,46 @@
}
}
+class UnionType extends CompositeType {
+ UnionType(List<CType> memberTypes) : super(memberTypes);
+
+ String get cKeyword => "union";
+ String get dartSuperClass => "Union";
+
+ bool get hasSize => !memberTypes.map((e) => e.hasSize).contains(false);
+ int get size => memberTypes.fold(0, (int acc, e) => math.max(acc, e.size));
+
+ String get name {
+ String result = dartSuperClass;
+ if (overrideName != "") {
+ return result + overrideName;
+ }
+ if (hasSize) {
+ result += "${size}Byte" + (size != 1 ? "s" : "");
+ }
+ if (hasNestedStructs) {
+ result += "Nested";
+ }
+ if (hasInlineArrays) {
+ result += "InlineArray";
+ if (hasMultiDimensionalInlineArrays) {
+ result += "MultiDimensional";
+ }
+ }
+ if (members.length == 0) {
+ // No suffix.
+ } else if (isOnlyFloatingPoint) {
+ result += "Float";
+ } else if (isOnlyInteger) {
+ result += "Int";
+ } else {
+ result += "Mixed";
+ }
+ result += suffix;
+ return result;
+ }
+}
+
class FixedLengthArrayType extends CType {
final CType elementType;
final int length;
@@ -360,15 +417,20 @@
/// A suitable name based on the signature.
String get cName {
String result = "";
- if (arguments.containsStructs && returnValue is FundamentalType) {
+ if (arguments.containsComposites && returnValue is FundamentalType) {
result = "Pass";
} else if (returnValue is StructType &&
argumentTypes.contains(returnValue)) {
result = "ReturnStructArgument";
+ } else if (returnValue is UnionType &&
+ argumentTypes.contains(returnValue)) {
+ result = "ReturnUnionArgument";
} else if (returnValue is StructType) {
if (arguments.length == (returnValue as StructType).members.length) {
return "Return${returnValue.dartCType}";
}
+ } else if (returnValue is UnionType && arguments.length == 1) {
+ return "Return${returnValue.dartCType}";
} else {
result = "Uncategorized";
}
@@ -392,5 +454,6 @@
}
extension MemberList on List<Member> {
- bool get containsStructs => map((m) => m.type is StructType).contains(true);
+ bool get containsComposites =>
+ map((m) => m.type is CompositeType).contains(true);
}
diff --git a/tests/ffi/generator/structs_by_value_tests_configuration.dart b/tests/ffi/generator/structs_by_value_tests_configuration.dart
index 1ad3c11..07b5fd1 100644
--- a/tests/ffi/generator/structs_by_value_tests_configuration.dart
+++ b/tests/ffi/generator/structs_by_value_tests_configuration.dart
@@ -5,6 +5,12 @@
import 'c_types.dart';
final functions = [
+ ...functionsStructArguments,
+ ...functionsStructReturn,
+ ...functionsReturnArgument,
+];
+
+final functionsStructArguments = [
FunctionType(List.filled(10, struct1byteInt), int64, """
Smallest struct with data.
10 struct arguments will exhaust available registers."""),
@@ -358,6 +364,19 @@
double_,
"""
Check alignment of packed struct array in non-packed struct."""),
+ FunctionType(List.filled(10, union4bytesMixed), double_, """
+Check placement of mixed integer/float union."""),
+ FunctionType(List.filled(10, union8bytesFloat), double_, """
+Check placement of mixed floats union."""),
+ FunctionType(List.filled(10, union12bytesInt), double_, """
+Mixed-size union argument."""),
+ FunctionType(List.filled(10, union16bytesFloat), double_, """
+Union with homogenous floats."""),
+ FunctionType(List.filled(10, union16bytesFloat2), double_, """
+Union with homogenous floats."""),
+];
+
+final functionsStructReturn = [
FunctionType(struct1byteInt.memberTypes, struct1byteInt, """
Smallest struct with data."""),
FunctionType(struct3bytesInt.memberTypes, struct3bytesInt, """
@@ -421,6 +440,29 @@
Struct with mis-aligned member.
Tests backfilling of CPU and FPU registers."""),
FunctionType(
+ [union4bytesMixed.memberTypes.first],
+ union4bytesMixed,
+ """
+Returning a mixed integer/float union."""),
+ FunctionType(
+ [union8bytesFloat.memberTypes.first],
+ union8bytesFloat,
+ """
+Returning a floating point only union."""),
+ FunctionType(
+ [union12bytesInt.memberTypes.first],
+ union12bytesInt,
+ """
+Returning a mixed-size union."""),
+ FunctionType(
+ [union16bytesFloat2.memberTypes.first],
+ union16bytesFloat2,
+ """
+Returning union with homogenous floats."""),
+];
+
+final functionsReturnArgument = [
+ FunctionType(
[struct1byteInt],
struct1byteInt,
"""
@@ -515,7 +557,7 @@
Return big irregular struct as smoke test."""),
];
-final structs = [
+final compounds = [
struct1byteInt,
struct3bytesInt,
struct3bytesInt2,
@@ -574,6 +616,11 @@
struct8bytesPacked,
struct9bytesPacked,
struct15bytesPacked,
+ union4bytesMixed,
+ union8bytesFloat,
+ union12bytesInt,
+ union16bytesFloat,
+ union16bytesFloat2,
];
final struct1byteInt = StructType([int8]);
@@ -741,3 +788,23 @@
/// inline array, but not in the subsequent ones.
final struct15bytesPacked =
StructType([FixedLengthArrayType(struct5bytesPacked, 3)]);
+
+/// Mixed integer and float. Tests whether calling conventions put this in
+/// integer registers or not.
+final union4bytesMixed = UnionType([uint32, float]);
+
+/// Different types of float. Tests whether calling conventions put this in
+/// FPU registers or not.
+final union8bytesFloat = UnionType([double_, struct8bytesFloat]);
+
+/// This union has a size of 12, because of the 4-byte alignment of the first
+/// member.
+final union12bytesInt = UnionType([struct8bytesInt, struct9bytesInt]);
+
+/// This union has homogenous floats of the same sizes.
+final union16bytesFloat =
+ UnionType([FixedLengthArrayType(float, 4), struct16bytesFloat]);
+
+/// This union has homogenous floats of different sizes.
+final union16bytesFloat2 =
+ UnionType([struct8bytesFloat, struct12bytesFloat, struct16bytesFloat]);
diff --git a/tests/ffi/generator/structs_by_value_tests_generator.dart b/tests/ffi/generator/structs_by_value_tests_generator.dart
index c66dbea..0ab7739 100644
--- a/tests/ffi/generator/structs_by_value_tests_generator.dart
+++ b/tests/ffi/generator/structs_by_value_tests_generator.dart
@@ -24,14 +24,19 @@
extension on FunctionType {
TestType get testType {
- if (arguments.containsStructs && returnValue is FundamentalType) {
+ if (arguments.containsComposites && returnValue is FundamentalType) {
return TestType.structArguments;
}
- if (returnValue is StructType && argumentTypes.contains(returnValue)) {
+ if (returnValue is CompositeType && argumentTypes.contains(returnValue)) {
return TestType.structReturnArgument;
}
if (returnValue is StructType) {
- if (arguments.length == (returnValue as StructType).members.length) {
+ if (arguments.length == (returnValue as CompositeType).members.length) {
+ return TestType.structReturn;
+ }
+ }
+ if (returnValue is UnionType) {
+ if (arguments.length == 1) {
return TestType.structReturn;
}
}
@@ -52,7 +57,8 @@
return "<< $variableName";
case StructType:
- final this_ = this as StructType;
+ case UnionType:
+ final this_ = this as CompositeType;
return this_.members.coutExpression("$variableName.");
case FixedLengthArrayType:
@@ -102,6 +108,12 @@
final this_ = this as StructType;
return this_.members.addToResultStatements("$variableName.");
+ case UnionType:
+ final this_ = this as UnionType;
+ final member = this_.members.first;
+ return member.type
+ .addToResultStatements("$variableName.${member.name}");
+
case FixedLengthArrayType:
final this_ = this as FixedLengthArrayType;
final indices = [for (var i = 0; i < this_.length; i += 1) i];
@@ -139,6 +151,12 @@
final this_ = this as StructType;
return this_.members.assignValueStatements(a, "$variableName.");
+ case UnionType:
+ final this_ = this as UnionType;
+ final member = this_.members.first;
+ return member.type
+ .assignValueStatements(a, "$variableName.${member.name}");
+
case FixedLengthArrayType:
final this_ = this as FixedLengthArrayType;
final indices = [for (var i = 0; i < this_.length; i += 1) i];
@@ -224,6 +242,7 @@
return "${dartType} ${variableName};\n";
case StructType:
+ case UnionType:
return """
final ${variableName}Pointer = calloc<$dartType>();
final ${dartType} ${variableName} = ${variableName}Pointer.ref;
@@ -245,6 +264,7 @@
return "${dartType} ${variableName} = 0.0;\n";
case StructType:
+ case UnionType:
if (structsAsPointers) {
return "Pointer<${dartType}> ${variableName}Pointer = nullptr;\n";
} else {
@@ -278,6 +298,7 @@
return "";
case StructType:
+ case UnionType:
return "calloc.free(${variableName}Pointer);\n";
}
@@ -298,6 +319,7 @@
switch (this.runtimeType) {
case FundamentalType:
case StructType:
+ case UnionType:
return "${cType} ${variableName};\n";
}
@@ -432,7 +454,8 @@
return variableName;
case StructType:
- final this_ = this as StructType;
+ case UnionType:
+ final this_ = this as CompositeType;
return this_.members.firstArgumentName("$variableName.");
case FixedLengthArrayType:
@@ -453,9 +476,12 @@
}
}
-extension on StructType {
+extension on CompositeType {
String dartClass(bool nnbd) {
- final packingAnnotation = hasPacking ? "@Packed(${packing})" : "";
+ final self = this;
+ final packingAnnotation = (self is StructType) && self.hasPacking
+ ? "@Packed(${self.packing})"
+ : "";
String dartFields = "";
for (final member in members) {
dartFields += "${member.dartStructField(nnbd)}\n\n";
@@ -479,7 +505,7 @@
}).join(", ");
return """
$packingAnnotation
- class $name extends Struct {
+ class $name extends $dartSuperClass {
$dartFields
String toString() => "($toStringBody)";
@@ -488,16 +514,20 @@
}
String get cDefinition {
- final packingPragmaPush =
- hasPacking ? "#pragma pack(push, ${packing})" : "";
- final packingPragmaPop = hasPacking ? "#pragma pack(pop)" : "";
+ final self = this;
+ final packingPragmaPush = (self is StructType) && self.hasPacking
+ ? "#pragma pack(push, ${self.packing})"
+ : "";
+ final packingPragmaPop =
+ (self is StructType) && self.hasPacking ? "#pragma pack(pop)" : "";
+
String cFields = "";
for (final member in members) {
cFields += " ${member.cStructField}\n";
}
return """
$packingPragmaPush
- struct $name {
+ $cKeyword $name {
$cFields
};
$packingPragmaPop
@@ -727,7 +757,7 @@
arguments.map((e) => "${e.type.cType} ${e.name}").join(", ");
return """
- // Used for testing structs by value.
+ // Used for testing structs and unions by value.
${reason.makeCComment()}
DART_EXPORT ${returnValue.cType} $cName($argumentss) {
std::cout << \"$cName\" ${arguments.coutExpression()} << \"\\n\";
@@ -779,7 +809,7 @@
}
return """
- // Used for testing structs by value.
+ // Used for testing structs and unions by value.
${reason.makeCComment()}
DART_EXPORT intptr_t
Test$cName(
@@ -859,7 +889,7 @@
}
}
""");
- buffer.writeAll(structs.map((e) => e.dartClass(nnbd)));
+ buffer.writeAll(compounds.map((e) => e.dartClass(nnbd)));
buffer.writeAll(functions.map((e) => e.dartCallCode));
final path = callTestPath(nnbd);
@@ -984,7 +1014,7 @@
final StringBuffer buffer = StringBuffer();
buffer.write(headerC);
- buffer.writeAll(structs.map((e) => e.cDefinition));
+ buffer.writeAll(compounds.map((e) => e.cDefinition));
buffer.writeAll(functions.map((e) => e.cCallCode));
buffer.writeAll(functions.map((e) => e.cCallbackCode));
diff --git a/tests/ffi_2/ffi_2.status b/tests/ffi_2/ffi_2.status
index f157962..82349e8 100644
--- a/tests/ffi_2/ffi_2.status
+++ b/tests/ffi_2/ffi_2.status
@@ -11,6 +11,9 @@
[ $system == android ]
*: Pass, Slow # https://github.com/dart-lang/sdk/issues/38489
+[ $arch == arm && $system == linux ]
+function_callbacks_structs_by_value_test: Slow # QEMU https://dartbug.com/45007
+
[ $compiler != dart2analyzer && $compiler != fasta && $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_2/function_callbacks_structs_by_value_generated_test.dart b/tests/ffi_2/function_callbacks_structs_by_value_generated_test.dart
index c063d7f..c65a2d2 100644
--- a/tests/ffi_2/function_callbacks_structs_by_value_generated_test.dart
+++ b/tests/ffi_2/function_callbacks_structs_by_value_generated_test.dart
@@ -321,6 +321,31 @@
passStruct15BytesInlineArrayMixed, 0.0),
passStruct15BytesInlineArrayMixedAfterCallback),
CallbackTest.withCheck(
+ "PassUnion4BytesMixedx10",
+ Pointer.fromFunction<PassUnion4BytesMixedx10Type>(
+ passUnion4BytesMixedx10, 0.0),
+ passUnion4BytesMixedx10AfterCallback),
+ CallbackTest.withCheck(
+ "PassUnion8BytesNestedFloatx10",
+ Pointer.fromFunction<PassUnion8BytesNestedFloatx10Type>(
+ passUnion8BytesNestedFloatx10, 0.0),
+ passUnion8BytesNestedFloatx10AfterCallback),
+ CallbackTest.withCheck(
+ "PassUnion9BytesNestedIntx10",
+ Pointer.fromFunction<PassUnion9BytesNestedIntx10Type>(
+ passUnion9BytesNestedIntx10, 0.0),
+ passUnion9BytesNestedIntx10AfterCallback),
+ CallbackTest.withCheck(
+ "PassUnion16BytesNestedInlineArrayFloatx10",
+ Pointer.fromFunction<PassUnion16BytesNestedInlineArrayFloatx10Type>(
+ passUnion16BytesNestedInlineArrayFloatx10, 0.0),
+ passUnion16BytesNestedInlineArrayFloatx10AfterCallback),
+ CallbackTest.withCheck(
+ "PassUnion16BytesNestedFloatx10",
+ Pointer.fromFunction<PassUnion16BytesNestedFloatx10Type>(
+ passUnion16BytesNestedFloatx10, 0.0),
+ passUnion16BytesNestedFloatx10AfterCallback),
+ CallbackTest.withCheck(
"ReturnStruct1ByteInt",
Pointer.fromFunction<ReturnStruct1ByteIntType>(returnStruct1ByteInt),
returnStruct1ByteIntAfterCallback),
@@ -443,6 +468,25 @@
returnStruct9BytesPackedMixed),
returnStruct9BytesPackedMixedAfterCallback),
CallbackTest.withCheck(
+ "ReturnUnion4BytesMixed",
+ Pointer.fromFunction<ReturnUnion4BytesMixedType>(returnUnion4BytesMixed),
+ returnUnion4BytesMixedAfterCallback),
+ CallbackTest.withCheck(
+ "ReturnUnion8BytesNestedFloat",
+ Pointer.fromFunction<ReturnUnion8BytesNestedFloatType>(
+ returnUnion8BytesNestedFloat),
+ returnUnion8BytesNestedFloatAfterCallback),
+ CallbackTest.withCheck(
+ "ReturnUnion9BytesNestedInt",
+ Pointer.fromFunction<ReturnUnion9BytesNestedIntType>(
+ returnUnion9BytesNestedInt),
+ returnUnion9BytesNestedIntAfterCallback),
+ CallbackTest.withCheck(
+ "ReturnUnion16BytesNestedFloat",
+ Pointer.fromFunction<ReturnUnion16BytesNestedFloatType>(
+ returnUnion16BytesNestedFloat),
+ returnUnion16BytesNestedFloatAfterCallback),
+ CallbackTest.withCheck(
"ReturnStructArgumentStruct1ByteInt",
Pointer.fromFunction<ReturnStructArgumentStruct1ByteIntType>(
returnStructArgumentStruct1ByteInt),
@@ -7068,6 +7112,602 @@
Expect.approxEquals(3.0, result);
}
+typedef PassUnion4BytesMixedx10Type = Double Function(
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed);
+
+// Global variables to be able to test inputs after callback returned.
+Union4BytesMixed passUnion4BytesMixedx10_a0 = Union4BytesMixed();
+Union4BytesMixed passUnion4BytesMixedx10_a1 = Union4BytesMixed();
+Union4BytesMixed passUnion4BytesMixedx10_a2 = Union4BytesMixed();
+Union4BytesMixed passUnion4BytesMixedx10_a3 = Union4BytesMixed();
+Union4BytesMixed passUnion4BytesMixedx10_a4 = Union4BytesMixed();
+Union4BytesMixed passUnion4BytesMixedx10_a5 = Union4BytesMixed();
+Union4BytesMixed passUnion4BytesMixedx10_a6 = Union4BytesMixed();
+Union4BytesMixed passUnion4BytesMixedx10_a7 = Union4BytesMixed();
+Union4BytesMixed passUnion4BytesMixedx10_a8 = Union4BytesMixed();
+Union4BytesMixed passUnion4BytesMixedx10_a9 = Union4BytesMixed();
+
+// Result variable also global, so we can delete it after the callback.
+double passUnion4BytesMixedx10Result = 0.0;
+
+double passUnion4BytesMixedx10CalculateResult() {
+ double result = 0;
+
+ result += passUnion4BytesMixedx10_a0.a0;
+ result += passUnion4BytesMixedx10_a1.a0;
+ result += passUnion4BytesMixedx10_a2.a0;
+ result += passUnion4BytesMixedx10_a3.a0;
+ result += passUnion4BytesMixedx10_a4.a0;
+ result += passUnion4BytesMixedx10_a5.a0;
+ result += passUnion4BytesMixedx10_a6.a0;
+ result += passUnion4BytesMixedx10_a7.a0;
+ result += passUnion4BytesMixedx10_a8.a0;
+ result += passUnion4BytesMixedx10_a9.a0;
+
+ passUnion4BytesMixedx10Result = result;
+
+ return result;
+}
+
+/// Check placement of mixed integer/float union.
+double passUnion4BytesMixedx10(
+ Union4BytesMixed a0,
+ Union4BytesMixed a1,
+ Union4BytesMixed a2,
+ Union4BytesMixed a3,
+ Union4BytesMixed a4,
+ Union4BytesMixed a5,
+ Union4BytesMixed a6,
+ Union4BytesMixed a7,
+ Union4BytesMixed a8,
+ Union4BytesMixed a9) {
+ print(
+ "passUnion4BytesMixedx10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+ // In legacy mode, possibly return null.
+ if (a0.a0 == 84) {
+ print("returning null!");
+ return null;
+ }
+
+ // In both nnbd and legacy mode, possibly throw.
+ if (a0.a0 == 42 || a0.a0 == 84) {
+ print("throwing!");
+ throw Exception("PassUnion4BytesMixedx10 throwing on purpose!");
+ }
+
+ passUnion4BytesMixedx10_a0 = a0;
+ passUnion4BytesMixedx10_a1 = a1;
+ passUnion4BytesMixedx10_a2 = a2;
+ passUnion4BytesMixedx10_a3 = a3;
+ passUnion4BytesMixedx10_a4 = a4;
+ passUnion4BytesMixedx10_a5 = a5;
+ passUnion4BytesMixedx10_a6 = a6;
+ passUnion4BytesMixedx10_a7 = a7;
+ passUnion4BytesMixedx10_a8 = a8;
+ passUnion4BytesMixedx10_a9 = a9;
+
+ final result = passUnion4BytesMixedx10CalculateResult();
+
+ print("result = $result");
+
+ return result;
+}
+
+void passUnion4BytesMixedx10AfterCallback() {
+ final result = passUnion4BytesMixedx10CalculateResult();
+
+ print("after callback result = $result");
+
+ Expect.approxEquals(55.0, result);
+}
+
+typedef PassUnion8BytesNestedFloatx10Type = Double Function(
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat);
+
+// Global variables to be able to test inputs after callback returned.
+Union8BytesNestedFloat passUnion8BytesNestedFloatx10_a0 =
+ Union8BytesNestedFloat();
+Union8BytesNestedFloat passUnion8BytesNestedFloatx10_a1 =
+ Union8BytesNestedFloat();
+Union8BytesNestedFloat passUnion8BytesNestedFloatx10_a2 =
+ Union8BytesNestedFloat();
+Union8BytesNestedFloat passUnion8BytesNestedFloatx10_a3 =
+ Union8BytesNestedFloat();
+Union8BytesNestedFloat passUnion8BytesNestedFloatx10_a4 =
+ Union8BytesNestedFloat();
+Union8BytesNestedFloat passUnion8BytesNestedFloatx10_a5 =
+ Union8BytesNestedFloat();
+Union8BytesNestedFloat passUnion8BytesNestedFloatx10_a6 =
+ Union8BytesNestedFloat();
+Union8BytesNestedFloat passUnion8BytesNestedFloatx10_a7 =
+ Union8BytesNestedFloat();
+Union8BytesNestedFloat passUnion8BytesNestedFloatx10_a8 =
+ Union8BytesNestedFloat();
+Union8BytesNestedFloat passUnion8BytesNestedFloatx10_a9 =
+ Union8BytesNestedFloat();
+
+// Result variable also global, so we can delete it after the callback.
+double passUnion8BytesNestedFloatx10Result = 0.0;
+
+double passUnion8BytesNestedFloatx10CalculateResult() {
+ double result = 0;
+
+ result += passUnion8BytesNestedFloatx10_a0.a0;
+ result += passUnion8BytesNestedFloatx10_a1.a0;
+ result += passUnion8BytesNestedFloatx10_a2.a0;
+ result += passUnion8BytesNestedFloatx10_a3.a0;
+ result += passUnion8BytesNestedFloatx10_a4.a0;
+ result += passUnion8BytesNestedFloatx10_a5.a0;
+ result += passUnion8BytesNestedFloatx10_a6.a0;
+ result += passUnion8BytesNestedFloatx10_a7.a0;
+ result += passUnion8BytesNestedFloatx10_a8.a0;
+ result += passUnion8BytesNestedFloatx10_a9.a0;
+
+ passUnion8BytesNestedFloatx10Result = result;
+
+ return result;
+}
+
+/// Check placement of mixed floats union.
+double passUnion8BytesNestedFloatx10(
+ Union8BytesNestedFloat a0,
+ Union8BytesNestedFloat a1,
+ Union8BytesNestedFloat a2,
+ Union8BytesNestedFloat a3,
+ Union8BytesNestedFloat a4,
+ Union8BytesNestedFloat a5,
+ Union8BytesNestedFloat a6,
+ Union8BytesNestedFloat a7,
+ Union8BytesNestedFloat a8,
+ Union8BytesNestedFloat a9) {
+ print(
+ "passUnion8BytesNestedFloatx10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+ // In legacy mode, possibly return null.
+ if (a0.a0 == 84) {
+ print("returning null!");
+ return null;
+ }
+
+ // In both nnbd and legacy mode, possibly throw.
+ if (a0.a0 == 42 || a0.a0 == 84) {
+ print("throwing!");
+ throw Exception("PassUnion8BytesNestedFloatx10 throwing on purpose!");
+ }
+
+ passUnion8BytesNestedFloatx10_a0 = a0;
+ passUnion8BytesNestedFloatx10_a1 = a1;
+ passUnion8BytesNestedFloatx10_a2 = a2;
+ passUnion8BytesNestedFloatx10_a3 = a3;
+ passUnion8BytesNestedFloatx10_a4 = a4;
+ passUnion8BytesNestedFloatx10_a5 = a5;
+ passUnion8BytesNestedFloatx10_a6 = a6;
+ passUnion8BytesNestedFloatx10_a7 = a7;
+ passUnion8BytesNestedFloatx10_a8 = a8;
+ passUnion8BytesNestedFloatx10_a9 = a9;
+
+ final result = passUnion8BytesNestedFloatx10CalculateResult();
+
+ print("result = $result");
+
+ return result;
+}
+
+void passUnion8BytesNestedFloatx10AfterCallback() {
+ final result = passUnion8BytesNestedFloatx10CalculateResult();
+
+ print("after callback result = $result");
+
+ Expect.approxEquals(5.0, result);
+}
+
+typedef PassUnion9BytesNestedIntx10Type = Double Function(
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt);
+
+// Global variables to be able to test inputs after callback returned.
+Union9BytesNestedInt passUnion9BytesNestedIntx10_a0 = Union9BytesNestedInt();
+Union9BytesNestedInt passUnion9BytesNestedIntx10_a1 = Union9BytesNestedInt();
+Union9BytesNestedInt passUnion9BytesNestedIntx10_a2 = Union9BytesNestedInt();
+Union9BytesNestedInt passUnion9BytesNestedIntx10_a3 = Union9BytesNestedInt();
+Union9BytesNestedInt passUnion9BytesNestedIntx10_a4 = Union9BytesNestedInt();
+Union9BytesNestedInt passUnion9BytesNestedIntx10_a5 = Union9BytesNestedInt();
+Union9BytesNestedInt passUnion9BytesNestedIntx10_a6 = Union9BytesNestedInt();
+Union9BytesNestedInt passUnion9BytesNestedIntx10_a7 = Union9BytesNestedInt();
+Union9BytesNestedInt passUnion9BytesNestedIntx10_a8 = Union9BytesNestedInt();
+Union9BytesNestedInt passUnion9BytesNestedIntx10_a9 = Union9BytesNestedInt();
+
+// Result variable also global, so we can delete it after the callback.
+double passUnion9BytesNestedIntx10Result = 0.0;
+
+double passUnion9BytesNestedIntx10CalculateResult() {
+ double result = 0;
+
+ result += passUnion9BytesNestedIntx10_a0.a0.a0;
+ result += passUnion9BytesNestedIntx10_a0.a0.a1;
+ result += passUnion9BytesNestedIntx10_a0.a0.a2;
+ result += passUnion9BytesNestedIntx10_a1.a0.a0;
+ result += passUnion9BytesNestedIntx10_a1.a0.a1;
+ result += passUnion9BytesNestedIntx10_a1.a0.a2;
+ result += passUnion9BytesNestedIntx10_a2.a0.a0;
+ result += passUnion9BytesNestedIntx10_a2.a0.a1;
+ result += passUnion9BytesNestedIntx10_a2.a0.a2;
+ result += passUnion9BytesNestedIntx10_a3.a0.a0;
+ result += passUnion9BytesNestedIntx10_a3.a0.a1;
+ result += passUnion9BytesNestedIntx10_a3.a0.a2;
+ result += passUnion9BytesNestedIntx10_a4.a0.a0;
+ result += passUnion9BytesNestedIntx10_a4.a0.a1;
+ result += passUnion9BytesNestedIntx10_a4.a0.a2;
+ result += passUnion9BytesNestedIntx10_a5.a0.a0;
+ result += passUnion9BytesNestedIntx10_a5.a0.a1;
+ result += passUnion9BytesNestedIntx10_a5.a0.a2;
+ result += passUnion9BytesNestedIntx10_a6.a0.a0;
+ result += passUnion9BytesNestedIntx10_a6.a0.a1;
+ result += passUnion9BytesNestedIntx10_a6.a0.a2;
+ result += passUnion9BytesNestedIntx10_a7.a0.a0;
+ result += passUnion9BytesNestedIntx10_a7.a0.a1;
+ result += passUnion9BytesNestedIntx10_a7.a0.a2;
+ result += passUnion9BytesNestedIntx10_a8.a0.a0;
+ result += passUnion9BytesNestedIntx10_a8.a0.a1;
+ result += passUnion9BytesNestedIntx10_a8.a0.a2;
+ result += passUnion9BytesNestedIntx10_a9.a0.a0;
+ result += passUnion9BytesNestedIntx10_a9.a0.a1;
+ result += passUnion9BytesNestedIntx10_a9.a0.a2;
+
+ passUnion9BytesNestedIntx10Result = result;
+
+ return result;
+}
+
+/// Mixed-size union argument.
+double passUnion9BytesNestedIntx10(
+ Union9BytesNestedInt a0,
+ Union9BytesNestedInt a1,
+ Union9BytesNestedInt a2,
+ Union9BytesNestedInt a3,
+ Union9BytesNestedInt a4,
+ Union9BytesNestedInt a5,
+ Union9BytesNestedInt a6,
+ Union9BytesNestedInt a7,
+ Union9BytesNestedInt a8,
+ Union9BytesNestedInt a9) {
+ print(
+ "passUnion9BytesNestedIntx10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+ // In legacy mode, possibly return null.
+ if (a0.a0.a0 == 84) {
+ print("returning null!");
+ return null;
+ }
+
+ // In both nnbd and legacy mode, possibly throw.
+ if (a0.a0.a0 == 42 || a0.a0.a0 == 84) {
+ print("throwing!");
+ throw Exception("PassUnion9BytesNestedIntx10 throwing on purpose!");
+ }
+
+ passUnion9BytesNestedIntx10_a0 = a0;
+ passUnion9BytesNestedIntx10_a1 = a1;
+ passUnion9BytesNestedIntx10_a2 = a2;
+ passUnion9BytesNestedIntx10_a3 = a3;
+ passUnion9BytesNestedIntx10_a4 = a4;
+ passUnion9BytesNestedIntx10_a5 = a5;
+ passUnion9BytesNestedIntx10_a6 = a6;
+ passUnion9BytesNestedIntx10_a7 = a7;
+ passUnion9BytesNestedIntx10_a8 = a8;
+ passUnion9BytesNestedIntx10_a9 = a9;
+
+ final result = passUnion9BytesNestedIntx10CalculateResult();
+
+ print("result = $result");
+
+ return result;
+}
+
+void passUnion9BytesNestedIntx10AfterCallback() {
+ final result = passUnion9BytesNestedIntx10CalculateResult();
+
+ print("after callback result = $result");
+
+ Expect.approxEquals(15.0, result);
+}
+
+typedef PassUnion16BytesNestedInlineArrayFloatx10Type = Double Function(
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat);
+
+// Global variables to be able to test inputs after callback returned.
+Union16BytesNestedInlineArrayFloat
+ passUnion16BytesNestedInlineArrayFloatx10_a0 =
+ Union16BytesNestedInlineArrayFloat();
+Union16BytesNestedInlineArrayFloat
+ passUnion16BytesNestedInlineArrayFloatx10_a1 =
+ Union16BytesNestedInlineArrayFloat();
+Union16BytesNestedInlineArrayFloat
+ passUnion16BytesNestedInlineArrayFloatx10_a2 =
+ Union16BytesNestedInlineArrayFloat();
+Union16BytesNestedInlineArrayFloat
+ passUnion16BytesNestedInlineArrayFloatx10_a3 =
+ Union16BytesNestedInlineArrayFloat();
+Union16BytesNestedInlineArrayFloat
+ passUnion16BytesNestedInlineArrayFloatx10_a4 =
+ Union16BytesNestedInlineArrayFloat();
+Union16BytesNestedInlineArrayFloat
+ passUnion16BytesNestedInlineArrayFloatx10_a5 =
+ Union16BytesNestedInlineArrayFloat();
+Union16BytesNestedInlineArrayFloat
+ passUnion16BytesNestedInlineArrayFloatx10_a6 =
+ Union16BytesNestedInlineArrayFloat();
+Union16BytesNestedInlineArrayFloat
+ passUnion16BytesNestedInlineArrayFloatx10_a7 =
+ Union16BytesNestedInlineArrayFloat();
+Union16BytesNestedInlineArrayFloat
+ passUnion16BytesNestedInlineArrayFloatx10_a8 =
+ Union16BytesNestedInlineArrayFloat();
+Union16BytesNestedInlineArrayFloat
+ passUnion16BytesNestedInlineArrayFloatx10_a9 =
+ Union16BytesNestedInlineArrayFloat();
+
+// Result variable also global, so we can delete it after the callback.
+double passUnion16BytesNestedInlineArrayFloatx10Result = 0.0;
+
+double passUnion16BytesNestedInlineArrayFloatx10CalculateResult() {
+ double result = 0;
+
+ result += passUnion16BytesNestedInlineArrayFloatx10_a0.a0[0];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a0.a0[1];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a0.a0[2];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a0.a0[3];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a1.a0[0];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a1.a0[1];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a1.a0[2];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a1.a0[3];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a2.a0[0];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a2.a0[1];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a2.a0[2];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a2.a0[3];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a3.a0[0];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a3.a0[1];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a3.a0[2];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a3.a0[3];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a4.a0[0];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a4.a0[1];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a4.a0[2];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a4.a0[3];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a5.a0[0];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a5.a0[1];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a5.a0[2];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a5.a0[3];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a6.a0[0];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a6.a0[1];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a6.a0[2];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a6.a0[3];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a7.a0[0];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a7.a0[1];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a7.a0[2];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a7.a0[3];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a8.a0[0];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a8.a0[1];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a8.a0[2];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a8.a0[3];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a9.a0[0];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a9.a0[1];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a9.a0[2];
+ result += passUnion16BytesNestedInlineArrayFloatx10_a9.a0[3];
+
+ passUnion16BytesNestedInlineArrayFloatx10Result = result;
+
+ return result;
+}
+
+/// Union with homogenous floats.
+double passUnion16BytesNestedInlineArrayFloatx10(
+ Union16BytesNestedInlineArrayFloat a0,
+ Union16BytesNestedInlineArrayFloat a1,
+ Union16BytesNestedInlineArrayFloat a2,
+ Union16BytesNestedInlineArrayFloat a3,
+ Union16BytesNestedInlineArrayFloat a4,
+ Union16BytesNestedInlineArrayFloat a5,
+ Union16BytesNestedInlineArrayFloat a6,
+ Union16BytesNestedInlineArrayFloat a7,
+ Union16BytesNestedInlineArrayFloat a8,
+ Union16BytesNestedInlineArrayFloat a9) {
+ print(
+ "passUnion16BytesNestedInlineArrayFloatx10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+ // In legacy mode, possibly return null.
+ if (a0.a0[0] == 84) {
+ print("returning null!");
+ return null;
+ }
+
+ // In both nnbd and legacy mode, possibly throw.
+ if (a0.a0[0] == 42 || a0.a0[0] == 84) {
+ print("throwing!");
+ throw Exception(
+ "PassUnion16BytesNestedInlineArrayFloatx10 throwing on purpose!");
+ }
+
+ passUnion16BytesNestedInlineArrayFloatx10_a0 = a0;
+ passUnion16BytesNestedInlineArrayFloatx10_a1 = a1;
+ passUnion16BytesNestedInlineArrayFloatx10_a2 = a2;
+ passUnion16BytesNestedInlineArrayFloatx10_a3 = a3;
+ passUnion16BytesNestedInlineArrayFloatx10_a4 = a4;
+ passUnion16BytesNestedInlineArrayFloatx10_a5 = a5;
+ passUnion16BytesNestedInlineArrayFloatx10_a6 = a6;
+ passUnion16BytesNestedInlineArrayFloatx10_a7 = a7;
+ passUnion16BytesNestedInlineArrayFloatx10_a8 = a8;
+ passUnion16BytesNestedInlineArrayFloatx10_a9 = a9;
+
+ final result = passUnion16BytesNestedInlineArrayFloatx10CalculateResult();
+
+ print("result = $result");
+
+ return result;
+}
+
+void passUnion16BytesNestedInlineArrayFloatx10AfterCallback() {
+ final result = passUnion16BytesNestedInlineArrayFloatx10CalculateResult();
+
+ print("after callback result = $result");
+
+ Expect.approxEquals(20.0, result);
+}
+
+typedef PassUnion16BytesNestedFloatx10Type = Double Function(
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat);
+
+// Global variables to be able to test inputs after callback returned.
+Union16BytesNestedFloat passUnion16BytesNestedFloatx10_a0 =
+ Union16BytesNestedFloat();
+Union16BytesNestedFloat passUnion16BytesNestedFloatx10_a1 =
+ Union16BytesNestedFloat();
+Union16BytesNestedFloat passUnion16BytesNestedFloatx10_a2 =
+ Union16BytesNestedFloat();
+Union16BytesNestedFloat passUnion16BytesNestedFloatx10_a3 =
+ Union16BytesNestedFloat();
+Union16BytesNestedFloat passUnion16BytesNestedFloatx10_a4 =
+ Union16BytesNestedFloat();
+Union16BytesNestedFloat passUnion16BytesNestedFloatx10_a5 =
+ Union16BytesNestedFloat();
+Union16BytesNestedFloat passUnion16BytesNestedFloatx10_a6 =
+ Union16BytesNestedFloat();
+Union16BytesNestedFloat passUnion16BytesNestedFloatx10_a7 =
+ Union16BytesNestedFloat();
+Union16BytesNestedFloat passUnion16BytesNestedFloatx10_a8 =
+ Union16BytesNestedFloat();
+Union16BytesNestedFloat passUnion16BytesNestedFloatx10_a9 =
+ Union16BytesNestedFloat();
+
+// Result variable also global, so we can delete it after the callback.
+double passUnion16BytesNestedFloatx10Result = 0.0;
+
+double passUnion16BytesNestedFloatx10CalculateResult() {
+ double result = 0;
+
+ result += passUnion16BytesNestedFloatx10_a0.a0.a0;
+ result += passUnion16BytesNestedFloatx10_a0.a0.a1;
+ result += passUnion16BytesNestedFloatx10_a1.a0.a0;
+ result += passUnion16BytesNestedFloatx10_a1.a0.a1;
+ result += passUnion16BytesNestedFloatx10_a2.a0.a0;
+ result += passUnion16BytesNestedFloatx10_a2.a0.a1;
+ result += passUnion16BytesNestedFloatx10_a3.a0.a0;
+ result += passUnion16BytesNestedFloatx10_a3.a0.a1;
+ result += passUnion16BytesNestedFloatx10_a4.a0.a0;
+ result += passUnion16BytesNestedFloatx10_a4.a0.a1;
+ result += passUnion16BytesNestedFloatx10_a5.a0.a0;
+ result += passUnion16BytesNestedFloatx10_a5.a0.a1;
+ result += passUnion16BytesNestedFloatx10_a6.a0.a0;
+ result += passUnion16BytesNestedFloatx10_a6.a0.a1;
+ result += passUnion16BytesNestedFloatx10_a7.a0.a0;
+ result += passUnion16BytesNestedFloatx10_a7.a0.a1;
+ result += passUnion16BytesNestedFloatx10_a8.a0.a0;
+ result += passUnion16BytesNestedFloatx10_a8.a0.a1;
+ result += passUnion16BytesNestedFloatx10_a9.a0.a0;
+ result += passUnion16BytesNestedFloatx10_a9.a0.a1;
+
+ passUnion16BytesNestedFloatx10Result = result;
+
+ return result;
+}
+
+/// Union with homogenous floats.
+double passUnion16BytesNestedFloatx10(
+ Union16BytesNestedFloat a0,
+ Union16BytesNestedFloat a1,
+ Union16BytesNestedFloat a2,
+ Union16BytesNestedFloat a3,
+ Union16BytesNestedFloat a4,
+ Union16BytesNestedFloat a5,
+ Union16BytesNestedFloat a6,
+ Union16BytesNestedFloat a7,
+ Union16BytesNestedFloat a8,
+ Union16BytesNestedFloat a9) {
+ print(
+ "passUnion16BytesNestedFloatx10(${a0}, ${a1}, ${a2}, ${a3}, ${a4}, ${a5}, ${a6}, ${a7}, ${a8}, ${a9})");
+
+ // In legacy mode, possibly return null.
+ if (a0.a0.a0 == 84) {
+ print("returning null!");
+ return null;
+ }
+
+ // In both nnbd and legacy mode, possibly throw.
+ if (a0.a0.a0 == 42 || a0.a0.a0 == 84) {
+ print("throwing!");
+ throw Exception("PassUnion16BytesNestedFloatx10 throwing on purpose!");
+ }
+
+ passUnion16BytesNestedFloatx10_a0 = a0;
+ passUnion16BytesNestedFloatx10_a1 = a1;
+ passUnion16BytesNestedFloatx10_a2 = a2;
+ passUnion16BytesNestedFloatx10_a3 = a3;
+ passUnion16BytesNestedFloatx10_a4 = a4;
+ passUnion16BytesNestedFloatx10_a5 = a5;
+ passUnion16BytesNestedFloatx10_a6 = a6;
+ passUnion16BytesNestedFloatx10_a7 = a7;
+ passUnion16BytesNestedFloatx10_a8 = a8;
+ passUnion16BytesNestedFloatx10_a9 = a9;
+
+ final result = passUnion16BytesNestedFloatx10CalculateResult();
+
+ print("result = $result");
+
+ return result;
+}
+
+void passUnion16BytesNestedFloatx10AfterCallback() {
+ final result = passUnion16BytesNestedFloatx10CalculateResult();
+
+ print("after callback result = $result");
+
+ Expect.approxEquals(10.0, result);
+}
+
typedef ReturnStruct1ByteIntType = Struct1ByteInt Function(Int8);
// Global variables to be able to test inputs after callback returned.
@@ -9417,6 +10057,232 @@
calloc.free(returnStruct9BytesPackedMixedResultPointer);
}
+typedef ReturnUnion4BytesMixedType = Union4BytesMixed Function(Uint32);
+
+// Global variables to be able to test inputs after callback returned.
+int returnUnion4BytesMixed_a0 = 0;
+
+// Result variable also global, so we can delete it after the callback.
+Pointer<Union4BytesMixed> returnUnion4BytesMixedResultPointer = nullptr;
+
+Union4BytesMixed returnUnion4BytesMixedCalculateResult() {
+ final resultPointer = calloc<Union4BytesMixed>();
+ final result = resultPointer.ref;
+
+ result.a0 = returnUnion4BytesMixed_a0;
+
+ returnUnion4BytesMixedResultPointer = resultPointer;
+
+ return result;
+}
+
+/// Returning a mixed integer/float union.
+Union4BytesMixed returnUnion4BytesMixed(int a0) {
+ print("returnUnion4BytesMixed(${a0})");
+
+ // In legacy mode, possibly return null.
+ if (a0 == 84) {
+ print("returning null!");
+ return null;
+ }
+
+ // In both nnbd and legacy mode, possibly throw.
+ if (a0 == 42 || a0 == 84) {
+ print("throwing!");
+ throw Exception("ReturnUnion4BytesMixed throwing on purpose!");
+ }
+
+ returnUnion4BytesMixed_a0 = a0;
+
+ final result = returnUnion4BytesMixedCalculateResult();
+
+ print("result = $result");
+
+ return result;
+}
+
+void returnUnion4BytesMixedAfterCallback() {
+ calloc.free(returnUnion4BytesMixedResultPointer);
+
+ final result = returnUnion4BytesMixedCalculateResult();
+
+ print("after callback result = $result");
+
+ calloc.free(returnUnion4BytesMixedResultPointer);
+}
+
+typedef ReturnUnion8BytesNestedFloatType = Union8BytesNestedFloat Function(
+ Double);
+
+// Global variables to be able to test inputs after callback returned.
+double returnUnion8BytesNestedFloat_a0 = 0.0;
+
+// Result variable also global, so we can delete it after the callback.
+Pointer<Union8BytesNestedFloat> returnUnion8BytesNestedFloatResultPointer =
+ nullptr;
+
+Union8BytesNestedFloat returnUnion8BytesNestedFloatCalculateResult() {
+ final resultPointer = calloc<Union8BytesNestedFloat>();
+ final result = resultPointer.ref;
+
+ result.a0 = returnUnion8BytesNestedFloat_a0;
+
+ returnUnion8BytesNestedFloatResultPointer = resultPointer;
+
+ return result;
+}
+
+/// Returning a floating point only union.
+Union8BytesNestedFloat returnUnion8BytesNestedFloat(double a0) {
+ print("returnUnion8BytesNestedFloat(${a0})");
+
+ // In legacy mode, possibly return null.
+ if (a0 == 84) {
+ print("returning null!");
+ return null;
+ }
+
+ // In both nnbd and legacy mode, possibly throw.
+ if (a0 == 42 || a0 == 84) {
+ print("throwing!");
+ throw Exception("ReturnUnion8BytesNestedFloat throwing on purpose!");
+ }
+
+ returnUnion8BytesNestedFloat_a0 = a0;
+
+ final result = returnUnion8BytesNestedFloatCalculateResult();
+
+ print("result = $result");
+
+ return result;
+}
+
+void returnUnion8BytesNestedFloatAfterCallback() {
+ calloc.free(returnUnion8BytesNestedFloatResultPointer);
+
+ final result = returnUnion8BytesNestedFloatCalculateResult();
+
+ print("after callback result = $result");
+
+ calloc.free(returnUnion8BytesNestedFloatResultPointer);
+}
+
+typedef ReturnUnion9BytesNestedIntType = Union9BytesNestedInt Function(
+ Struct8BytesInt);
+
+// Global variables to be able to test inputs after callback returned.
+Struct8BytesInt returnUnion9BytesNestedInt_a0 = Struct8BytesInt();
+
+// Result variable also global, so we can delete it after the callback.
+Pointer<Union9BytesNestedInt> returnUnion9BytesNestedIntResultPointer = nullptr;
+
+Union9BytesNestedInt returnUnion9BytesNestedIntCalculateResult() {
+ final resultPointer = calloc<Union9BytesNestedInt>();
+ final result = resultPointer.ref;
+
+ result.a0.a0 = returnUnion9BytesNestedInt_a0.a0;
+ result.a0.a1 = returnUnion9BytesNestedInt_a0.a1;
+ result.a0.a2 = returnUnion9BytesNestedInt_a0.a2;
+
+ returnUnion9BytesNestedIntResultPointer = resultPointer;
+
+ return result;
+}
+
+/// Returning a mixed-size union.
+Union9BytesNestedInt returnUnion9BytesNestedInt(Struct8BytesInt a0) {
+ print("returnUnion9BytesNestedInt(${a0})");
+
+ // In legacy mode, possibly return null.
+ if (a0.a0 == 84) {
+ print("returning null!");
+ return null;
+ }
+
+ // In both nnbd and legacy mode, possibly throw.
+ if (a0.a0 == 42 || a0.a0 == 84) {
+ print("throwing!");
+ throw Exception("ReturnUnion9BytesNestedInt throwing on purpose!");
+ }
+
+ returnUnion9BytesNestedInt_a0 = a0;
+
+ final result = returnUnion9BytesNestedIntCalculateResult();
+
+ print("result = $result");
+
+ return result;
+}
+
+void returnUnion9BytesNestedIntAfterCallback() {
+ calloc.free(returnUnion9BytesNestedIntResultPointer);
+
+ final result = returnUnion9BytesNestedIntCalculateResult();
+
+ print("after callback result = $result");
+
+ calloc.free(returnUnion9BytesNestedIntResultPointer);
+}
+
+typedef ReturnUnion16BytesNestedFloatType = Union16BytesNestedFloat Function(
+ Struct8BytesHomogeneousFloat);
+
+// Global variables to be able to test inputs after callback returned.
+Struct8BytesHomogeneousFloat returnUnion16BytesNestedFloat_a0 =
+ Struct8BytesHomogeneousFloat();
+
+// Result variable also global, so we can delete it after the callback.
+Pointer<Union16BytesNestedFloat> returnUnion16BytesNestedFloatResultPointer =
+ nullptr;
+
+Union16BytesNestedFloat returnUnion16BytesNestedFloatCalculateResult() {
+ final resultPointer = calloc<Union16BytesNestedFloat>();
+ final result = resultPointer.ref;
+
+ result.a0.a0 = returnUnion16BytesNestedFloat_a0.a0;
+ result.a0.a1 = returnUnion16BytesNestedFloat_a0.a1;
+
+ returnUnion16BytesNestedFloatResultPointer = resultPointer;
+
+ return result;
+}
+
+/// Returning union with homogenous floats.
+Union16BytesNestedFloat returnUnion16BytesNestedFloat(
+ Struct8BytesHomogeneousFloat a0) {
+ print("returnUnion16BytesNestedFloat(${a0})");
+
+ // In legacy mode, possibly return null.
+ if (a0.a0 == 84) {
+ print("returning null!");
+ return null;
+ }
+
+ // In both nnbd and legacy mode, possibly throw.
+ if (a0.a0 == 42 || a0.a0 == 84) {
+ print("throwing!");
+ throw Exception("ReturnUnion16BytesNestedFloat throwing on purpose!");
+ }
+
+ returnUnion16BytesNestedFloat_a0 = a0;
+
+ final result = returnUnion16BytesNestedFloatCalculateResult();
+
+ print("result = $result");
+
+ return result;
+}
+
+void returnUnion16BytesNestedFloatAfterCallback() {
+ calloc.free(returnUnion16BytesNestedFloatResultPointer);
+
+ final result = returnUnion16BytesNestedFloatCalculateResult();
+
+ print("after callback result = $result");
+
+ calloc.free(returnUnion16BytesNestedFloatResultPointer);
+}
+
typedef ReturnStructArgumentStruct1ByteIntType = Struct1ByteInt Function(
Struct1ByteInt);
diff --git a/tests/ffi_2/function_structs_by_value_generated_test.dart b/tests/ffi_2/function_structs_by_value_generated_test.dart
index 48c7b59..156fc07 100644
--- a/tests/ffi_2/function_structs_by_value_generated_test.dart
+++ b/tests/ffi_2/function_structs_by_value_generated_test.dart
@@ -77,6 +77,11 @@
testPassStructNestedAlignmentStruct5BytesPackedMixed();
testPassStruct6BytesInlineArrayInt();
testPassStruct15BytesInlineArrayMixed();
+ testPassUnion4BytesMixedx10();
+ testPassUnion8BytesNestedFloatx10();
+ testPassUnion9BytesNestedIntx10();
+ testPassUnion16BytesNestedInlineArrayFloatx10();
+ testPassUnion16BytesNestedFloatx10();
testReturnStruct1ByteInt();
testReturnStruct3BytesHomogeneousUint8();
testReturnStruct3BytesInt2ByteAligned();
@@ -102,6 +107,10 @@
testReturnStruct3BytesPackedInt();
testReturnStruct8BytesPackedInt();
testReturnStruct9BytesPackedMixed();
+ testReturnUnion4BytesMixed();
+ testReturnUnion8BytesNestedFloat();
+ testReturnUnion9BytesNestedInt();
+ testReturnUnion16BytesNestedFloat();
testReturnStructArgumentStruct1ByteInt();
testReturnStructArgumentInt32x8Struct1ByteInt();
testReturnStructArgumentStruct8BytesHomogeneousFloat();
@@ -1283,6 +1292,52 @@
String toString() => "(${[for (var i0 = 0; i0 < 3; i0 += 1) a0[i0]]})";
}
+class Union4BytesMixed extends Union {
+ @Uint32()
+ int a0;
+
+ @Float()
+ double a1;
+
+ String toString() => "(${a0}, ${a1})";
+}
+
+class Union8BytesNestedFloat extends Union {
+ @Double()
+ double a0;
+
+ Struct8BytesHomogeneousFloat a1;
+
+ String toString() => "(${a0}, ${a1})";
+}
+
+class Union9BytesNestedInt extends Union {
+ Struct8BytesInt a0;
+
+ Struct9BytesHomogeneousUint8 a1;
+
+ String toString() => "(${a0}, ${a1})";
+}
+
+class Union16BytesNestedInlineArrayFloat extends Union {
+ @Array(4)
+ Array<Float> a0;
+
+ Struct16BytesHomogeneousFloat a1;
+
+ String toString() => "(${[for (var i0 = 0; i0 < 4; i0 += 1) a0[i0]]}, ${a1})";
+}
+
+class Union16BytesNestedFloat extends Union {
+ Struct8BytesHomogeneousFloat a0;
+
+ Struct12BytesHomogeneousFloat a1;
+
+ Struct16BytesHomogeneousFloat a2;
+
+ String toString() => "(${a0}, ${a1}, ${a2})";
+}
+
final passStruct1ByteIntx10 = ffiTestFunctions.lookupFunction<
Int64 Function(
Struct1ByteInt,
@@ -5916,6 +5971,453 @@
calloc.free(a0Pointer);
}
+final passUnion4BytesMixedx10 = ffiTestFunctions.lookupFunction<
+ Double Function(
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed),
+ double Function(
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed,
+ Union4BytesMixed)>("PassUnion4BytesMixedx10");
+
+/// Check placement of mixed integer/float union.
+void testPassUnion4BytesMixedx10() {
+ final a0Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Union4BytesMixed>();
+ final Union4BytesMixed a9 = a9Pointer.ref;
+
+ a0.a0 = 1;
+ a1.a0 = 2;
+ a2.a0 = 3;
+ a3.a0 = 4;
+ a4.a0 = 5;
+ a5.a0 = 6;
+ a6.a0 = 7;
+ a7.a0 = 8;
+ a8.a0 = 9;
+ a9.a0 = 10;
+
+ final result =
+ passUnion4BytesMixedx10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(55.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passUnion8BytesNestedFloatx10 = ffiTestFunctions.lookupFunction<
+ Double Function(
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat),
+ double Function(
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat,
+ Union8BytesNestedFloat)>("PassUnion8BytesNestedFloatx10");
+
+/// Check placement of mixed floats union.
+void testPassUnion8BytesNestedFloatx10() {
+ final a0Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Union8BytesNestedFloat>();
+ final Union8BytesNestedFloat a9 = a9Pointer.ref;
+
+ a0.a0 = -1.0;
+ a1.a0 = 2.0;
+ a2.a0 = -3.0;
+ a3.a0 = 4.0;
+ a4.a0 = -5.0;
+ a5.a0 = 6.0;
+ a6.a0 = -7.0;
+ a7.a0 = 8.0;
+ a8.a0 = -9.0;
+ a9.a0 = 10.0;
+
+ final result =
+ passUnion8BytesNestedFloatx10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(5.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passUnion9BytesNestedIntx10 = ffiTestFunctions.lookupFunction<
+ Double Function(
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt),
+ double Function(
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt,
+ Union9BytesNestedInt)>("PassUnion9BytesNestedIntx10");
+
+/// Mixed-size union argument.
+void testPassUnion9BytesNestedIntx10() {
+ final a0Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Union9BytesNestedInt>();
+ final Union9BytesNestedInt a9 = a9Pointer.ref;
+
+ a0.a0.a0 = -1;
+ a0.a0.a1 = 2;
+ a0.a0.a2 = -3;
+ a1.a0.a0 = 4;
+ a1.a0.a1 = -5;
+ a1.a0.a2 = 6;
+ a2.a0.a0 = -7;
+ a2.a0.a1 = 8;
+ a2.a0.a2 = -9;
+ a3.a0.a0 = 10;
+ a3.a0.a1 = -11;
+ a3.a0.a2 = 12;
+ a4.a0.a0 = -13;
+ a4.a0.a1 = 14;
+ a4.a0.a2 = -15;
+ a5.a0.a0 = 16;
+ a5.a0.a1 = -17;
+ a5.a0.a2 = 18;
+ a6.a0.a0 = -19;
+ a6.a0.a1 = 20;
+ a6.a0.a2 = -21;
+ a7.a0.a0 = 22;
+ a7.a0.a1 = -23;
+ a7.a0.a2 = 24;
+ a8.a0.a0 = -25;
+ a8.a0.a1 = 26;
+ a8.a0.a2 = -27;
+ a9.a0.a0 = 28;
+ a9.a0.a1 = -29;
+ a9.a0.a2 = 30;
+
+ final result =
+ passUnion9BytesNestedIntx10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(15.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passUnion16BytesNestedInlineArrayFloatx10 =
+ ffiTestFunctions.lookupFunction<
+ Double Function(
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat),
+ double Function(
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat,
+ Union16BytesNestedInlineArrayFloat)>(
+ "PassUnion16BytesNestedInlineArrayFloatx10");
+
+/// Union with homogenous floats.
+void testPassUnion16BytesNestedInlineArrayFloatx10() {
+ final a0Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Union16BytesNestedInlineArrayFloat>();
+ final Union16BytesNestedInlineArrayFloat a9 = a9Pointer.ref;
+
+ a0.a0[0] = -1.0;
+ a0.a0[1] = 2.0;
+ a0.a0[2] = -3.0;
+ a0.a0[3] = 4.0;
+ a1.a0[0] = -5.0;
+ a1.a0[1] = 6.0;
+ a1.a0[2] = -7.0;
+ a1.a0[3] = 8.0;
+ a2.a0[0] = -9.0;
+ a2.a0[1] = 10.0;
+ a2.a0[2] = -11.0;
+ a2.a0[3] = 12.0;
+ a3.a0[0] = -13.0;
+ a3.a0[1] = 14.0;
+ a3.a0[2] = -15.0;
+ a3.a0[3] = 16.0;
+ a4.a0[0] = -17.0;
+ a4.a0[1] = 18.0;
+ a4.a0[2] = -19.0;
+ a4.a0[3] = 20.0;
+ a5.a0[0] = -21.0;
+ a5.a0[1] = 22.0;
+ a5.a0[2] = -23.0;
+ a5.a0[3] = 24.0;
+ a6.a0[0] = -25.0;
+ a6.a0[1] = 26.0;
+ a6.a0[2] = -27.0;
+ a6.a0[3] = 28.0;
+ a7.a0[0] = -29.0;
+ a7.a0[1] = 30.0;
+ a7.a0[2] = -31.0;
+ a7.a0[3] = 32.0;
+ a8.a0[0] = -33.0;
+ a8.a0[1] = 34.0;
+ a8.a0[2] = -35.0;
+ a8.a0[3] = 36.0;
+ a9.a0[0] = -37.0;
+ a9.a0[1] = 38.0;
+ a9.a0[2] = -39.0;
+ a9.a0[3] = 40.0;
+
+ final result = passUnion16BytesNestedInlineArrayFloatx10(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(20.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
+final passUnion16BytesNestedFloatx10 = ffiTestFunctions.lookupFunction<
+ Double Function(
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat),
+ double Function(
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat,
+ Union16BytesNestedFloat)>("PassUnion16BytesNestedFloatx10");
+
+/// Union with homogenous floats.
+void testPassUnion16BytesNestedFloatx10() {
+ final a0Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a0 = a0Pointer.ref;
+ final a1Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a1 = a1Pointer.ref;
+ final a2Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a2 = a2Pointer.ref;
+ final a3Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a3 = a3Pointer.ref;
+ final a4Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a4 = a4Pointer.ref;
+ final a5Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a5 = a5Pointer.ref;
+ final a6Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a6 = a6Pointer.ref;
+ final a7Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a7 = a7Pointer.ref;
+ final a8Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a8 = a8Pointer.ref;
+ final a9Pointer = calloc<Union16BytesNestedFloat>();
+ final Union16BytesNestedFloat a9 = a9Pointer.ref;
+
+ a0.a0.a0 = -1.0;
+ a0.a0.a1 = 2.0;
+ a1.a0.a0 = -3.0;
+ a1.a0.a1 = 4.0;
+ a2.a0.a0 = -5.0;
+ a2.a0.a1 = 6.0;
+ a3.a0.a0 = -7.0;
+ a3.a0.a1 = 8.0;
+ a4.a0.a0 = -9.0;
+ a4.a0.a1 = 10.0;
+ a5.a0.a0 = -11.0;
+ a5.a0.a1 = 12.0;
+ a6.a0.a0 = -13.0;
+ a6.a0.a1 = 14.0;
+ a7.a0.a0 = -15.0;
+ a7.a0.a1 = 16.0;
+ a8.a0.a0 = -17.0;
+ a8.a0.a1 = 18.0;
+ a9.a0.a0 = -19.0;
+ a9.a0.a1 = 20.0;
+
+ final result =
+ passUnion16BytesNestedFloatx10(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+
+ print("result = $result");
+
+ Expect.approxEquals(10.0, result);
+
+ calloc.free(a0Pointer);
+ calloc.free(a1Pointer);
+ calloc.free(a2Pointer);
+ calloc.free(a3Pointer);
+ calloc.free(a4Pointer);
+ calloc.free(a5Pointer);
+ calloc.free(a6Pointer);
+ calloc.free(a7Pointer);
+ calloc.free(a8Pointer);
+ calloc.free(a9Pointer);
+}
+
final returnStruct1ByteInt = ffiTestFunctions.lookupFunction<
Struct1ByteInt Function(Int8),
Struct1ByteInt Function(int)>("ReturnStruct1ByteInt");
@@ -7406,6 +7908,88 @@
Expect.approxEquals(a1, result.a1);
}
+final returnUnion4BytesMixed = ffiTestFunctions.lookupFunction<
+ Union4BytesMixed Function(Uint32),
+ Union4BytesMixed Function(int)>("ReturnUnion4BytesMixed");
+
+/// Returning a mixed integer/float union.
+void testReturnUnion4BytesMixed() {
+ int a0;
+
+ a0 = 1;
+
+ final result = returnUnion4BytesMixed(a0);
+
+ print("result = $result");
+
+ Expect.equals(a0, result.a0);
+}
+
+final returnUnion8BytesNestedFloat = ffiTestFunctions.lookupFunction<
+ Union8BytesNestedFloat Function(Double),
+ Union8BytesNestedFloat Function(double)>("ReturnUnion8BytesNestedFloat");
+
+/// Returning a floating point only union.
+void testReturnUnion8BytesNestedFloat() {
+ double a0;
+
+ a0 = -1.0;
+
+ final result = returnUnion8BytesNestedFloat(a0);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0, result.a0);
+}
+
+final returnUnion9BytesNestedInt = ffiTestFunctions.lookupFunction<
+ Union9BytesNestedInt Function(Struct8BytesInt),
+ Union9BytesNestedInt Function(
+ Struct8BytesInt)>("ReturnUnion9BytesNestedInt");
+
+/// Returning a mixed-size union.
+void testReturnUnion9BytesNestedInt() {
+ final a0Pointer = calloc<Struct8BytesInt>();
+ final Struct8BytesInt a0 = a0Pointer.ref;
+
+ a0.a0 = -1;
+ a0.a1 = 2;
+ a0.a2 = -3;
+
+ final result = returnUnion9BytesNestedInt(a0);
+
+ print("result = $result");
+
+ Expect.equals(a0.a0, result.a0.a0);
+ Expect.equals(a0.a1, result.a0.a1);
+ Expect.equals(a0.a2, result.a0.a2);
+
+ calloc.free(a0Pointer);
+}
+
+final returnUnion16BytesNestedFloat = ffiTestFunctions.lookupFunction<
+ Union16BytesNestedFloat Function(Struct8BytesHomogeneousFloat),
+ Union16BytesNestedFloat Function(
+ Struct8BytesHomogeneousFloat)>("ReturnUnion16BytesNestedFloat");
+
+/// Returning union with homogenous floats.
+void testReturnUnion16BytesNestedFloat() {
+ final a0Pointer = calloc<Struct8BytesHomogeneousFloat>();
+ final Struct8BytesHomogeneousFloat a0 = a0Pointer.ref;
+
+ a0.a0 = -1.0;
+ a0.a1 = 2.0;
+
+ final result = returnUnion16BytesNestedFloat(a0);
+
+ print("result = $result");
+
+ Expect.approxEquals(a0.a0, result.a0.a0);
+ Expect.approxEquals(a0.a1, result.a0.a1);
+
+ calloc.free(a0Pointer);
+}
+
final returnStructArgumentStruct1ByteInt = ffiTestFunctions.lookupFunction<
Struct1ByteInt Function(Struct1ByteInt),
Struct1ByteInt Function(
diff --git a/tests/ffi_2/generator/c_types.dart b/tests/ffi_2/generator/c_types.dart
index df3b44b..7236aed 100644
--- a/tests/ffi_2/generator/c_types.dart
+++ b/tests/ffi_2/generator/c_types.dart
@@ -2,6 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'dart:math' as math;
+
import 'utils.dart';
const int8 = FundamentalType(PrimitiveType.int8);
@@ -152,36 +154,70 @@
return result;
}
-class StructType extends CType {
+abstract class CompositeType extends CType {
final List<Member> members;
- final int? packing;
-
/// To disambiguate same size structs.
final String suffix;
/// To override names.
final String overrideName;
- StructType(List<CType> memberTypes, {int? this.packing})
+ CompositeType(List<CType> memberTypes)
: this.members = generateMemberNames(memberTypes),
this.suffix = "",
this.overrideName = "";
- StructType.disambiguate(List<CType> memberTypes, this.suffix,
- {int? this.packing})
+ CompositeType.disambiguate(List<CType> memberTypes, this.suffix)
: this.members = generateMemberNames(memberTypes),
this.overrideName = "";
- StructType.override(List<CType> memberTypes, this.overrideName,
- {int? this.packing})
+ CompositeType.override(List<CType> memberTypes, this.overrideName)
: this.members = generateMemberNames(memberTypes),
this.suffix = "";
List<CType> get memberTypes => members.map((a) => a.type).toList();
+ String get name;
+
String get cType => name;
String get dartCType => name;
String get dartType => name;
String get dartStructFieldAnnotation => "";
+ String get cKeyword;
+ String get dartSuperClass;
+
+ bool get isOnlyFloatingPoint =>
+ !memberTypes.map((e) => e.isOnlyFloatingPoint).contains(false);
+ bool get isOnlyInteger =>
+ !memberTypes.map((e) => e.isOnlyInteger).contains(false);
+
+ bool get isMixed => !isOnlyInteger && !isOnlyFloatingPoint;
+
+ bool get hasNestedStructs =>
+ members.map((e) => e.type is StructType).contains(true);
+
+ bool get hasInlineArrays =>
+ members.map((e) => e.type is FixedLengthArrayType).contains(true);
+
+ bool get hasMultiDimensionalInlineArrays => members
+ .map((e) => e.type)
+ .whereType<FixedLengthArrayType>()
+ .where((e) => e.isMulti)
+ .isNotEmpty;
+}
+
+class StructType extends CompositeType {
+ final int? packing;
+
+ StructType(List<CType> memberTypes, {int? this.packing}) : super(memberTypes);
+ StructType.disambiguate(List<CType> memberTypes, String suffix,
+ {int? this.packing})
+ : super.disambiguate(memberTypes, suffix);
+ StructType.override(List<CType> memberTypes, String overrideName,
+ {int? this.packing})
+ : super.override(memberTypes, overrideName);
+
+ String get cKeyword => "struct";
+ String get dartSuperClass => "Struct";
bool get hasSize =>
!memberTypes.map((e) => e.hasSize).contains(false) && !hasPadding;
@@ -201,30 +237,11 @@
return members[0].type.size < members[1].type.size;
}
- bool get hasNestedStructs =>
- members.map((e) => e.type is StructType).contains(true);
-
- bool get hasInlineArrays =>
- members.map((e) => e.type is FixedLengthArrayType).contains(true);
-
- bool get hasMultiDimensionalInlineArrays => members
- .map((e) => e.type)
- .whereType<FixedLengthArrayType>()
- .where((e) => e.isMulti)
- .isNotEmpty;
-
/// All members have the same type.
bool get isHomogeneous => memberTypes.toSet().length == 1;
- bool get isOnlyFloatingPoint =>
- !memberTypes.map((e) => e.isOnlyFloatingPoint).contains(false);
- bool get isOnlyInteger =>
- !memberTypes.map((e) => e.isOnlyInteger).contains(false);
-
- bool get isMixed => !isOnlyInteger && !isOnlyFloatingPoint;
-
String get name {
- String result = "Struct";
+ String result = dartSuperClass;
if (overrideName != "") {
return result + overrideName;
}
@@ -264,6 +281,46 @@
}
}
+class UnionType extends CompositeType {
+ UnionType(List<CType> memberTypes) : super(memberTypes);
+
+ String get cKeyword => "union";
+ String get dartSuperClass => "Union";
+
+ bool get hasSize => !memberTypes.map((e) => e.hasSize).contains(false);
+ int get size => memberTypes.fold(0, (int acc, e) => math.max(acc, e.size));
+
+ String get name {
+ String result = dartSuperClass;
+ if (overrideName != "") {
+ return result + overrideName;
+ }
+ if (hasSize) {
+ result += "${size}Byte" + (size != 1 ? "s" : "");
+ }
+ if (hasNestedStructs) {
+ result += "Nested";
+ }
+ if (hasInlineArrays) {
+ result += "InlineArray";
+ if (hasMultiDimensionalInlineArrays) {
+ result += "MultiDimensional";
+ }
+ }
+ if (members.length == 0) {
+ // No suffix.
+ } else if (isOnlyFloatingPoint) {
+ result += "Float";
+ } else if (isOnlyInteger) {
+ result += "Int";
+ } else {
+ result += "Mixed";
+ }
+ result += suffix;
+ return result;
+ }
+}
+
class FixedLengthArrayType extends CType {
final CType elementType;
final int length;
@@ -360,15 +417,20 @@
/// A suitable name based on the signature.
String get cName {
String result = "";
- if (arguments.containsStructs && returnValue is FundamentalType) {
+ if (arguments.containsComposites && returnValue is FundamentalType) {
result = "Pass";
} else if (returnValue is StructType &&
argumentTypes.contains(returnValue)) {
result = "ReturnStructArgument";
+ } else if (returnValue is UnionType &&
+ argumentTypes.contains(returnValue)) {
+ result = "ReturnUnionArgument";
} else if (returnValue is StructType) {
if (arguments.length == (returnValue as StructType).members.length) {
return "Return${returnValue.dartCType}";
}
+ } else if (returnValue is UnionType && arguments.length == 1) {
+ return "Return${returnValue.dartCType}";
} else {
result = "Uncategorized";
}
@@ -392,5 +454,6 @@
}
extension MemberList on List<Member> {
- bool get containsStructs => map((m) => m.type is StructType).contains(true);
+ bool get containsComposites =>
+ map((m) => m.type is CompositeType).contains(true);
}
diff --git a/tests/ffi_2/generator/structs_by_value_tests_configuration.dart b/tests/ffi_2/generator/structs_by_value_tests_configuration.dart
index 1ad3c11..07b5fd1 100644
--- a/tests/ffi_2/generator/structs_by_value_tests_configuration.dart
+++ b/tests/ffi_2/generator/structs_by_value_tests_configuration.dart
@@ -5,6 +5,12 @@
import 'c_types.dart';
final functions = [
+ ...functionsStructArguments,
+ ...functionsStructReturn,
+ ...functionsReturnArgument,
+];
+
+final functionsStructArguments = [
FunctionType(List.filled(10, struct1byteInt), int64, """
Smallest struct with data.
10 struct arguments will exhaust available registers."""),
@@ -358,6 +364,19 @@
double_,
"""
Check alignment of packed struct array in non-packed struct."""),
+ FunctionType(List.filled(10, union4bytesMixed), double_, """
+Check placement of mixed integer/float union."""),
+ FunctionType(List.filled(10, union8bytesFloat), double_, """
+Check placement of mixed floats union."""),
+ FunctionType(List.filled(10, union12bytesInt), double_, """
+Mixed-size union argument."""),
+ FunctionType(List.filled(10, union16bytesFloat), double_, """
+Union with homogenous floats."""),
+ FunctionType(List.filled(10, union16bytesFloat2), double_, """
+Union with homogenous floats."""),
+];
+
+final functionsStructReturn = [
FunctionType(struct1byteInt.memberTypes, struct1byteInt, """
Smallest struct with data."""),
FunctionType(struct3bytesInt.memberTypes, struct3bytesInt, """
@@ -421,6 +440,29 @@
Struct with mis-aligned member.
Tests backfilling of CPU and FPU registers."""),
FunctionType(
+ [union4bytesMixed.memberTypes.first],
+ union4bytesMixed,
+ """
+Returning a mixed integer/float union."""),
+ FunctionType(
+ [union8bytesFloat.memberTypes.first],
+ union8bytesFloat,
+ """
+Returning a floating point only union."""),
+ FunctionType(
+ [union12bytesInt.memberTypes.first],
+ union12bytesInt,
+ """
+Returning a mixed-size union."""),
+ FunctionType(
+ [union16bytesFloat2.memberTypes.first],
+ union16bytesFloat2,
+ """
+Returning union with homogenous floats."""),
+];
+
+final functionsReturnArgument = [
+ FunctionType(
[struct1byteInt],
struct1byteInt,
"""
@@ -515,7 +557,7 @@
Return big irregular struct as smoke test."""),
];
-final structs = [
+final compounds = [
struct1byteInt,
struct3bytesInt,
struct3bytesInt2,
@@ -574,6 +616,11 @@
struct8bytesPacked,
struct9bytesPacked,
struct15bytesPacked,
+ union4bytesMixed,
+ union8bytesFloat,
+ union12bytesInt,
+ union16bytesFloat,
+ union16bytesFloat2,
];
final struct1byteInt = StructType([int8]);
@@ -741,3 +788,23 @@
/// inline array, but not in the subsequent ones.
final struct15bytesPacked =
StructType([FixedLengthArrayType(struct5bytesPacked, 3)]);
+
+/// Mixed integer and float. Tests whether calling conventions put this in
+/// integer registers or not.
+final union4bytesMixed = UnionType([uint32, float]);
+
+/// Different types of float. Tests whether calling conventions put this in
+/// FPU registers or not.
+final union8bytesFloat = UnionType([double_, struct8bytesFloat]);
+
+/// This union has a size of 12, because of the 4-byte alignment of the first
+/// member.
+final union12bytesInt = UnionType([struct8bytesInt, struct9bytesInt]);
+
+/// This union has homogenous floats of the same sizes.
+final union16bytesFloat =
+ UnionType([FixedLengthArrayType(float, 4), struct16bytesFloat]);
+
+/// This union has homogenous floats of different sizes.
+final union16bytesFloat2 =
+ UnionType([struct8bytesFloat, struct12bytesFloat, struct16bytesFloat]);
diff --git a/tests/ffi_2/generator/structs_by_value_tests_generator.dart b/tests/ffi_2/generator/structs_by_value_tests_generator.dart
index c66dbea..0ab7739 100644
--- a/tests/ffi_2/generator/structs_by_value_tests_generator.dart
+++ b/tests/ffi_2/generator/structs_by_value_tests_generator.dart
@@ -24,14 +24,19 @@
extension on FunctionType {
TestType get testType {
- if (arguments.containsStructs && returnValue is FundamentalType) {
+ if (arguments.containsComposites && returnValue is FundamentalType) {
return TestType.structArguments;
}
- if (returnValue is StructType && argumentTypes.contains(returnValue)) {
+ if (returnValue is CompositeType && argumentTypes.contains(returnValue)) {
return TestType.structReturnArgument;
}
if (returnValue is StructType) {
- if (arguments.length == (returnValue as StructType).members.length) {
+ if (arguments.length == (returnValue as CompositeType).members.length) {
+ return TestType.structReturn;
+ }
+ }
+ if (returnValue is UnionType) {
+ if (arguments.length == 1) {
return TestType.structReturn;
}
}
@@ -52,7 +57,8 @@
return "<< $variableName";
case StructType:
- final this_ = this as StructType;
+ case UnionType:
+ final this_ = this as CompositeType;
return this_.members.coutExpression("$variableName.");
case FixedLengthArrayType:
@@ -102,6 +108,12 @@
final this_ = this as StructType;
return this_.members.addToResultStatements("$variableName.");
+ case UnionType:
+ final this_ = this as UnionType;
+ final member = this_.members.first;
+ return member.type
+ .addToResultStatements("$variableName.${member.name}");
+
case FixedLengthArrayType:
final this_ = this as FixedLengthArrayType;
final indices = [for (var i = 0; i < this_.length; i += 1) i];
@@ -139,6 +151,12 @@
final this_ = this as StructType;
return this_.members.assignValueStatements(a, "$variableName.");
+ case UnionType:
+ final this_ = this as UnionType;
+ final member = this_.members.first;
+ return member.type
+ .assignValueStatements(a, "$variableName.${member.name}");
+
case FixedLengthArrayType:
final this_ = this as FixedLengthArrayType;
final indices = [for (var i = 0; i < this_.length; i += 1) i];
@@ -224,6 +242,7 @@
return "${dartType} ${variableName};\n";
case StructType:
+ case UnionType:
return """
final ${variableName}Pointer = calloc<$dartType>();
final ${dartType} ${variableName} = ${variableName}Pointer.ref;
@@ -245,6 +264,7 @@
return "${dartType} ${variableName} = 0.0;\n";
case StructType:
+ case UnionType:
if (structsAsPointers) {
return "Pointer<${dartType}> ${variableName}Pointer = nullptr;\n";
} else {
@@ -278,6 +298,7 @@
return "";
case StructType:
+ case UnionType:
return "calloc.free(${variableName}Pointer);\n";
}
@@ -298,6 +319,7 @@
switch (this.runtimeType) {
case FundamentalType:
case StructType:
+ case UnionType:
return "${cType} ${variableName};\n";
}
@@ -432,7 +454,8 @@
return variableName;
case StructType:
- final this_ = this as StructType;
+ case UnionType:
+ final this_ = this as CompositeType;
return this_.members.firstArgumentName("$variableName.");
case FixedLengthArrayType:
@@ -453,9 +476,12 @@
}
}
-extension on StructType {
+extension on CompositeType {
String dartClass(bool nnbd) {
- final packingAnnotation = hasPacking ? "@Packed(${packing})" : "";
+ final self = this;
+ final packingAnnotation = (self is StructType) && self.hasPacking
+ ? "@Packed(${self.packing})"
+ : "";
String dartFields = "";
for (final member in members) {
dartFields += "${member.dartStructField(nnbd)}\n\n";
@@ -479,7 +505,7 @@
}).join(", ");
return """
$packingAnnotation
- class $name extends Struct {
+ class $name extends $dartSuperClass {
$dartFields
String toString() => "($toStringBody)";
@@ -488,16 +514,20 @@
}
String get cDefinition {
- final packingPragmaPush =
- hasPacking ? "#pragma pack(push, ${packing})" : "";
- final packingPragmaPop = hasPacking ? "#pragma pack(pop)" : "";
+ final self = this;
+ final packingPragmaPush = (self is StructType) && self.hasPacking
+ ? "#pragma pack(push, ${self.packing})"
+ : "";
+ final packingPragmaPop =
+ (self is StructType) && self.hasPacking ? "#pragma pack(pop)" : "";
+
String cFields = "";
for (final member in members) {
cFields += " ${member.cStructField}\n";
}
return """
$packingPragmaPush
- struct $name {
+ $cKeyword $name {
$cFields
};
$packingPragmaPop
@@ -727,7 +757,7 @@
arguments.map((e) => "${e.type.cType} ${e.name}").join(", ");
return """
- // Used for testing structs by value.
+ // Used for testing structs and unions by value.
${reason.makeCComment()}
DART_EXPORT ${returnValue.cType} $cName($argumentss) {
std::cout << \"$cName\" ${arguments.coutExpression()} << \"\\n\";
@@ -779,7 +809,7 @@
}
return """
- // Used for testing structs by value.
+ // Used for testing structs and unions by value.
${reason.makeCComment()}
DART_EXPORT intptr_t
Test$cName(
@@ -859,7 +889,7 @@
}
}
""");
- buffer.writeAll(structs.map((e) => e.dartClass(nnbd)));
+ buffer.writeAll(compounds.map((e) => e.dartClass(nnbd)));
buffer.writeAll(functions.map((e) => e.dartCallCode));
final path = callTestPath(nnbd);
@@ -984,7 +1014,7 @@
final StringBuffer buffer = StringBuffer();
buffer.write(headerC);
- buffer.writeAll(structs.map((e) => e.cDefinition));
+ buffer.writeAll(compounds.map((e) => e.cDefinition));
buffer.writeAll(functions.map((e) => e.cCallCode));
buffer.writeAll(functions.map((e) => e.cCallbackCode));
diff --git a/tests/language/const_functions/const_functions_return_test.dart b/tests/language/const_functions/const_functions_return_test.dart
index 793c629..ffc1667 100644
--- a/tests/language/const_functions/const_functions_return_test.dart
+++ b/tests/language/const_functions/const_functions_return_test.dart
@@ -32,9 +32,22 @@
return null;
}
+const var5 = fn5();
+// ^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+// [web] Constant evaluation error:
+int fn5() {
+ try {
+ return throw 1;
+ } on int {
+ return 2;
+ }
+}
+
void main() {
Expect.equals((var1 as dynamic), null);
Expect.equals((var2 as dynamic), null);
Expect.equals(var3, null);
Expect.equals(var4, null);
+ Expect.equals(var5, 2);
}
diff --git a/tests/language/function/regress_45601_test.dart b/tests/language/function/regress_45601_test.dart
new file mode 100644
index 0000000..0a096f0
--- /dev/null
+++ b/tests/language/function/regress_45601_test.dart
@@ -0,0 +1,60 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+// Regression test for https://github.com/dart-lang/sdk/issues/45601
+// When comparing values of type `Function` for equality DDC was generating
+// code that would throw at runtime.
+
+class Wrapper {
+ Wrapper(this.function);
+
+ final Function function;
+
+ @override
+ bool operator ==(Object other) =>
+ other is Wrapper && function == other.function;
+
+ @override
+ int get hashCode => function.hashCode;
+}
+
+void main() {
+ final map = <Wrapper, int>{};
+ final ref = Wrapper(main);
+ map[ref] = 42;
+ Expect.equals(42, map[ref]);
+
+ testStaticEquality();
+ testDynamicEquality();
+}
+
+void fn<T>(T t) => null;
+
+/// Ensure `==` calls on function values that are statically typed as `Function`
+/// or `Function?` work as expected.
+void testStaticEquality() {
+ Function staticFunction = fn;
+ Expect.isTrue(staticFunction == fn);
+ Expect.isFalse(staticFunction == main);
+
+ Function? staticFunction2 = null;
+ Expect.isFalse(staticFunction2 == staticFunction);
+ staticFunction2 = fn;
+ Expect.isTrue(staticFunction2 == staticFunction);
+}
+
+/// Ensure `==` calls on function values that are statically typed as `dynamic`
+/// work as expected.
+void testDynamicEquality() {
+ dynamic dynamicFunction = fn;
+ Expect.isTrue(dynamicFunction == fn);
+ Expect.isFalse(dynamicFunction == main);
+
+ dynamic dynamicFunction2 = null;
+ Expect.isFalse(dynamicFunction2 == dynamicFunction);
+ dynamicFunction2 = fn;
+ Expect.isTrue(dynamicFunction2 == dynamicFunction);
+}
diff --git a/tests/language/interface/duplicate_interface_implements_test.dart b/tests/language/interface/duplicate_interface_implements_test.dart
index 4564aad..0c8555e 100644
--- a/tests/language/interface/duplicate_interface_implements_test.dart
+++ b/tests/language/interface/duplicate_interface_implements_test.dart
@@ -10,6 +10,7 @@
, alib.InterfA
//^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.IMPLEMENTS_REPEATED
+ // [cfe] 'InterfA' can only be implemented once.
{}
main() {
diff --git a/tests/language/regress/regress34488_test.dart b/tests/language/regress/regress34488_test.dart
index d41f9407..ff76512 100644
--- a/tests/language/regress/regress34488_test.dart
+++ b/tests/language/regress/regress34488_test.dart
@@ -32,9 +32,8 @@
// [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
// [cfe] The argument type 'String' can't be assigned to the parameter type 'int'.
d.h(i: 'bad');
- // ^^^^^^^^
+ // ^^^^^
// [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
- // ^
// [cfe] The argument type 'String' can't be assigned to the parameter type 'int'.
Object x = d.f(1);
// ^
diff --git a/tests/language/why_not_promoted/argument_type_not_assignable_nullability_error_test.dart b/tests/language/why_not_promoted/argument_type_not_assignable_nullability_error_test.dart
index e4a8ce7..c74a8b2 100644
--- a/tests/language/why_not_promoted/argument_type_not_assignable_nullability_error_test.dart
+++ b/tests/language/why_not_promoted/argument_type_not_assignable_nullability_error_test.dart
@@ -9,8 +9,8 @@
class C1 {
int? bad;
// ^^^
- // [context 21] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 47] 'bad' refers to a property so it couldn't be promoted.
+ // [context 22] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 48] 'bad' refers to a property so it couldn't be promoted.
f(int i) {}
}
@@ -18,16 +18,16 @@
if (c.bad == null) return;
c.f(c.bad);
// ^^^^^
- // [analyzer 21] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+ // [analyzer 22] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
// ^
- // [cfe 47] The argument type 'int?' can't be assigned to the parameter type 'int' because 'int?' is nullable and 'int' isn't.
+ // [cfe 48] The argument type 'int?' can't be assigned to the parameter type 'int' because 'int?' is nullable and 'int' isn't.
}
class C2 {
int? bad;
// ^^^
- // [context 43] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 48] 'bad' refers to a property so it couldn't be promoted.
+ // [context 39] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 49] 'bad' refers to a property so it couldn't be promoted.
f([int i = 0]) {}
}
@@ -35,50 +35,50 @@
if (c.bad == null) return;
c.f(c.bad);
// ^^^^^
- // [analyzer 43] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+ // [analyzer 39] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
// ^
- // [cfe 48] The argument type 'int?' can't be assigned to the parameter type 'int' because 'int?' is nullable and 'int' isn't.
+ // [cfe 49] The argument type 'int?' can't be assigned to the parameter type 'int' because 'int?' is nullable and 'int' isn't.
}
class C3 {
int? bad;
// ^^^
- // [context 7] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 49] 'bad' refers to a property so it couldn't be promoted.
+ // [context 6] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 50] 'bad' refers to a property so it couldn't be promoted.
f({required int i}) {}
}
required_named(C3 c) {
if (c.bad == null) return;
c.f(i: c.bad);
- // ^^^^^^^^
- // [analyzer 7] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+ // ^^^^^
+ // [analyzer 6] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
// ^
- // [cfe 49] The argument type 'int?' can't be assigned to the parameter type 'int' because 'int?' is nullable and 'int' isn't.
+ // [cfe 50] The argument type 'int?' can't be assigned to the parameter type 'int' because 'int?' is nullable and 'int' isn't.
}
class C4 {
int? bad;
// ^^^
- // [context 17] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 50] 'bad' refers to a property so it couldn't be promoted.
+ // [context 15] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 51] 'bad' refers to a property so it couldn't be promoted.
f({int i = 0}) {}
}
optional_named(C4 c) {
if (c.bad == null) return;
c.f(i: c.bad);
- // ^^^^^^^^
- // [analyzer 17] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+ // ^^^^^
+ // [analyzer 15] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
// ^
- // [cfe 50] The argument type 'int?' can't be assigned to the parameter type 'int' because 'int?' is nullable and 'int' isn't.
+ // [cfe 51] The argument type 'int?' can't be assigned to the parameter type 'int' because 'int?' is nullable and 'int' isn't.
}
class C5 {
List<int>? bad;
// ^^^
- // [context 38] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 51] 'bad' refers to a property so it couldn't be promoted.
+ // [context 37] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 52] 'bad' refers to a property so it couldn't be promoted.
f<T>(List<T> x) {}
}
@@ -86,16 +86,16 @@
if (c.bad == null) return;
c.f(c.bad);
// ^^^^^
- // [analyzer 38] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+ // [analyzer 37] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
// ^
- // [cfe 51] The argument type 'List<int>?' can't be assigned to the parameter type 'List<int>' because 'List<int>?' is nullable and 'List<int>' isn't.
+ // [cfe 52] The argument type 'List<int>?' can't be assigned to the parameter type 'List<int>' because 'List<int>?' is nullable and 'List<int>' isn't.
}
class C6 {
int? bad;
// ^^^
- // [context 5] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 52] 'bad' refers to a property so it couldn't be promoted.
+ // [context 4] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 53] 'bad' refers to a property so it couldn't be promoted.
C6(int i);
}
@@ -103,16 +103,16 @@
if (c.bad == null) return null;
return C6(c.bad);
// ^^^^^
- // [analyzer 5] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+ // [analyzer 4] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
// ^
- // [cfe 52] The argument type 'int?' can't be assigned to the parameter type 'int' because 'int?' is nullable and 'int' isn't.
+ // [cfe 53] The argument type 'int?' can't be assigned to the parameter type 'int' because 'int?' is nullable and 'int' isn't.
}
class C7 {
int? bad;
// ^^^
- // [context 24] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 53] 'bad' refers to a property so it couldn't be promoted.
+ // [context 25] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 54] 'bad' refers to a property so it couldn't be promoted.
C7(int i);
}
@@ -120,16 +120,16 @@
if (c.bad == null) return null;
return new C7(c.bad);
// ^^^^^
- // [analyzer 24] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+ // [analyzer 25] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
// ^
- // [cfe 53] The argument type 'int?' can't be assigned to the parameter type 'int' because 'int?' is nullable and 'int' isn't.
+ // [cfe 54] The argument type 'int?' can't be assigned to the parameter type 'int' because 'int?' is nullable and 'int' isn't.
}
class C8 {
int? bad;
// ^^^
// [context 32] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 54] 'bad' refers to a property so it couldn't be promoted.
+ // [context 55] 'bad' refers to a property so it couldn't be promoted.
}
userDefinableBinaryOpRhs(C8 c) {
@@ -138,7 +138,7 @@
// ^^^^^
// [analyzer 32] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
// ^
- // [cfe 54] A value of type 'int?' can't be assigned to a variable of type 'num' because 'int?' is nullable and 'num' isn't.
+ // [cfe 55] A value of type 'int?' can't be assigned to a variable of type 'num' because 'int?' is nullable and 'num' isn't.
}
class C9 {
@@ -180,10 +180,10 @@
class C11 {
bool? bad;
// ^^^
- // [context 15] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 16] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 55] 'bad' refers to a property so it couldn't be promoted.
+ // [context 13] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 18] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
// [context 56] 'bad' refers to a property so it couldn't be promoted.
+ // [context 57] 'bad' refers to a property so it couldn't be promoted.
f(bool b) {}
}
@@ -191,23 +191,23 @@
if (c.bad == null) return;
c.f(c.bad && b);
// ^^^^^
- // [analyzer 16] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+ // [analyzer 18] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// ^
- // [cfe 55] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+ // [cfe 56] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
c.f(b && c.bad);
// ^^^^^
- // [analyzer 15] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+ // [analyzer 13] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// ^
- // [cfe 56] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+ // [cfe 57] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
}
class C12 {
bool? bad;
// ^^^
- // [context 4] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 33] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 57] 'bad' refers to a property so it couldn't be promoted.
+ // [context 5] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 36] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
// [context 58] 'bad' refers to a property so it couldn't be promoted.
+ // [context 59] 'bad' refers to a property so it couldn't be promoted.
f(bool b) {}
}
@@ -215,51 +215,51 @@
if (c.bad == null) return;
c.f(c.bad || b);
// ^^^^^
- // [analyzer 4] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+ // [analyzer 5] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// ^
- // [cfe 57] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+ // [cfe 58] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
c.f(b || c.bad);
// ^^^^^
- // [analyzer 33] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+ // [analyzer 36] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// ^
- // [cfe 58] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+ // [cfe 59] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
}
class C13 {
bool? bad;
// ^^^
- // [context 3] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 59] 'bad' refers to a property so it couldn't be promoted.
+ // [context 2] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 60] 'bad' refers to a property so it couldn't be promoted.
}
assertStatementCondition(C13 c) {
if (c.bad == null) return;
assert(c.bad);
// ^^^^^
- // [analyzer 3] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+ // [analyzer 2] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// ^
- // [cfe 59] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+ // [cfe 60] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
}
class C14 {
bool? bad;
// ^^^
- // [context 13] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 60] 'bad' refers to a property so it couldn't be promoted.
+ // [context 8] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 61] 'bad' refers to a property so it couldn't be promoted.
C14.assertInitializerCondition(C14 c)
: bad = c.bad!,
assert(c.bad);
// ^^^^^
- // [analyzer 13] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+ // [analyzer 8] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// ^
- // [cfe 60] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+ // [cfe 61] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
}
class C15 {
bool? bad;
// ^^^
- // [context 46] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 61] 'bad' refers to a property so it couldn't be promoted.
+ // [context 47] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 62] 'bad' refers to a property so it couldn't be promoted.
f(bool b) {}
}
@@ -267,53 +267,53 @@
if (c.bad == null) return;
c.f(!c.bad);
// ^^^^^
- // [analyzer 46] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+ // [analyzer 47] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// ^
- // [cfe 61] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+ // [cfe 62] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
}
class C16 {
bool? bad;
// ^^^
// [context 9] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 10] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 11] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 12] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 62] 'bad' refers to a property so it couldn't be promoted.
+ // [context 16] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 17] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 19] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
// [context 63] 'bad' refers to a property so it couldn't be promoted.
// [context 64] 'bad' refers to a property so it couldn't be promoted.
// [context 65] 'bad' refers to a property so it couldn't be promoted.
+ // [context 66] 'bad' refers to a property so it couldn't be promoted.
}
forLoopCondition(C16 c) {
if (c.bad == null) return;
for (; c.bad;) {}
// ^^^^^
- // [analyzer 10] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+ // [analyzer 9] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// ^
- // [cfe 62] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+ // [cfe 63] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
[for (; c.bad;) null];
// ^^^^^
- // [analyzer 11] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+ // [analyzer 17] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// ^
- // [cfe 63] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+ // [cfe 64] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
({for (; c.bad;) null});
// ^^^^^
- // [analyzer 12] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
- // ^
- // [cfe 64] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
- ({for (; c.bad;) null: null});
- // ^^^^^
- // [analyzer 9] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+ // [analyzer 19] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// ^
// [cfe 65] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+ ({for (; c.bad;) null: null});
+ // ^^^^^
+ // [analyzer 16] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+ // ^
+ // [cfe 66] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
}
class C17 {
bool? bad;
// ^^^
- // [context 28] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 66] 'bad' refers to a property so it couldn't be promoted.
+ // [context 46] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 67] 'bad' refers to a property so it couldn't be promoted.
f(int i) {}
}
@@ -321,207 +321,207 @@
if (c.bad == null) return;
c.f(c.bad ? 1 : 2);
// ^^^^^
- // [analyzer 28] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+ // [analyzer 46] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// ^
- // [cfe 66] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+ // [cfe 67] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
}
class C18 {
bool? bad;
// ^^^
- // [context 1] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 67] 'bad' refers to a property so it couldn't be promoted.
+ // [context 7] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 68] 'bad' refers to a property so it couldn't be promoted.
}
doLoopCondition(C18 c) {
if (c.bad == null) return;
do {} while (c.bad);
// ^^^^^
- // [analyzer 1] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+ // [analyzer 7] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// ^
- // [cfe 67] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+ // [cfe 68] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
}
class C19 {
bool? bad;
// ^^^
- // [context 14] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 11] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 12] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
// [context 23] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 27] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 44] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 68] 'bad' refers to a property so it couldn't be promoted.
+ // [context 28] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
// [context 69] 'bad' refers to a property so it couldn't be promoted.
// [context 70] 'bad' refers to a property so it couldn't be promoted.
// [context 71] 'bad' refers to a property so it couldn't be promoted.
+ // [context 72] 'bad' refers to a property so it couldn't be promoted.
}
ifCondition(C19 c) {
if (c.bad == null) return;
if (c.bad) {}
// ^^^^^
- // [analyzer 44] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+ // [analyzer 23] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// ^
- // [cfe 68] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+ // [cfe 69] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
[if (c.bad) null];
// ^^^^^
- // [analyzer 27] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+ // [analyzer 28] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// ^
- // [cfe 69] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+ // [cfe 70] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
({if (c.bad) null});
// ^^^^^
- // [analyzer 23] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
- // ^
- // [cfe 70] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
- ({if (c.bad) null: null});
- // ^^^^^
- // [analyzer 14] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+ // [analyzer 11] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// ^
// [cfe 71] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+ ({if (c.bad) null: null});
+ // ^^^^^
+ // [analyzer 12] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+ // ^
+ // [cfe 72] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
}
class C20 {
bool? bad;
// ^^^
- // [context 19] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 72] 'bad' refers to a property so it couldn't be promoted.
+ // [context 21] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 73] 'bad' refers to a property so it couldn't be promoted.
}
whileCondition(C20 c) {
if (c.bad == null) return;
while (c.bad) {}
// ^^^^^
- // [analyzer 19] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+ // [analyzer 21] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
// ^
- // [cfe 72] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+ // [cfe 73] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
}
class C21 {
int? bad;
// ^^^
- // [context 35] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 73] 'bad' refers to a property so it couldn't be promoted.
+ // [context 45] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 74] 'bad' refers to a property so it couldn't be promoted.
}
assignmentRhs(C21 c, int i) {
if (c.bad == null) return;
i = c.bad;
// ^^^^^
- // [analyzer 35] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
+ // [analyzer 45] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
- // [cfe 73] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+ // [cfe 74] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
}
class C22 {
int? bad;
// ^^^
- // [context 34] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 74] 'bad' refers to a property so it couldn't be promoted.
+ // [context 43] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 75] 'bad' refers to a property so it couldn't be promoted.
}
variableInitializer(C22 c) {
if (c.bad == null) return;
int i = c.bad;
// ^^^^^
- // [analyzer 34] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
+ // [analyzer 43] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
- // [cfe 74] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+ // [cfe 75] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
}
class C23 {
int? bad;
// ^^^
- // [context 25] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 75] 'bad' refers to a property so it couldn't be promoted.
+ // [context 24] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 76] 'bad' refers to a property so it couldn't be promoted.
final int x;
final int y;
C23.constructorInitializer(C23 c)
: x = c.bad!,
y = c.bad;
// ^^^^^
- // [analyzer 25] COMPILE_TIME_ERROR.FIELD_INITIALIZER_NOT_ASSIGNABLE
+ // [analyzer 24] COMPILE_TIME_ERROR.FIELD_INITIALIZER_NOT_ASSIGNABLE
// ^
- // [cfe 75] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+ // [cfe 76] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
}
class C24 {
int? bad;
// ^^^
- // [context 6] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 8] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 29] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 36] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 76] 'bad' refers to a property so it couldn't be promoted.
+ // [context 3] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 30] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 33] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 34] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
// [context 77] 'bad' refers to a property so it couldn't be promoted.
// [context 78] 'bad' refers to a property so it couldn't be promoted.
// [context 79] 'bad' refers to a property so it couldn't be promoted.
+ // [context 80] 'bad' refers to a property so it couldn't be promoted.
}
forVariableInitializer(C24 c) {
if (c.bad == null) return;
for (int i = c.bad; false;) {}
// ^^^^^
- // [analyzer 36] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
+ // [analyzer 34] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
- // [cfe 76] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+ // [cfe 77] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
[for (int i = c.bad; false;) null];
// ^^^^^
- // [analyzer 29] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
+ // [analyzer 33] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
- // [cfe 77] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+ // [cfe 78] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
({for (int i = c.bad; false;) null});
// ^^^^^
- // [analyzer 8] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
- // ^
- // [cfe 78] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
- ({for (int i = c.bad; false;) null: null});
- // ^^^^^
- // [analyzer 6] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
+ // [analyzer 30] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe 79] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+ ({for (int i = c.bad; false;) null: null});
+ // ^^^^^
+ // [analyzer 3] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
+ // ^
+ // [cfe 80] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
}
class C25 {
int? bad;
// ^^^
- // [context 30] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 39] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 35] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
// [context 40] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 45] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 80] 'bad' refers to a property so it couldn't be promoted.
+ // [context 41] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 44] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
// [context 81] 'bad' refers to a property so it couldn't be promoted.
// [context 82] 'bad' refers to a property so it couldn't be promoted.
// [context 83] 'bad' refers to a property so it couldn't be promoted.
+ // [context 84] 'bad' refers to a property so it couldn't be promoted.
}
forAssignmentInitializer(C25 c, int i) {
if (c.bad == null) return;
for (i = c.bad; false;) {}
// ^^^^^
- // [analyzer 30] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
+ // [analyzer 35] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
- // [cfe 80] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+ // [cfe 81] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
[for (i = c.bad; false;) null];
// ^^^^^
- // [analyzer 45] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
+ // [analyzer 44] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
- // [cfe 81] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
- ({for (i = c.bad; false;) null});
- // ^^^^^
- // [analyzer 39] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
- // ^
// [cfe 82] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
- ({for (i = c.bad; false;) null: null});
+ ({for (i = c.bad; false;) null});
// ^^^^^
// [analyzer 40] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
// ^
// [cfe 83] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+ ({for (i = c.bad; false;) null: null});
+ // ^^^^^
+ // [analyzer 41] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
+ // ^
+ // [cfe 84] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
}
class C26 {
int? bad;
// ^^^
// [context 26] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 84] 'bad' refers to a property so it couldn't be promoted.
+ // [context 85] 'bad' refers to a property so it couldn't be promoted.
}
compoundAssignmentRhs(C26 c) {
@@ -531,30 +531,30 @@
// ^^^^^
// [analyzer 26] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
// ^
- // [cfe 84] A value of type 'int?' can't be assigned to a variable of type 'num' because 'int?' is nullable and 'num' isn't.
+ // [cfe 85] A value of type 'int?' can't be assigned to a variable of type 'num' because 'int?' is nullable and 'num' isn't.
}
class C27 {
int? bad;
// ^^^
- // [context 42] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 85] 'bad' refers to a property so it couldn't be promoted.
+ // [context 38] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 86] 'bad' refers to a property so it couldn't be promoted.
}
indexGet(C27 c, List<int> values) {
if (c.bad == null) return;
values[c.bad];
// ^^^^^
- // [analyzer 42] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+ // [analyzer 38] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
// ^
- // [cfe 85] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+ // [cfe 86] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
}
class C28 {
int? bad;
// ^^^
// [context 31] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 86] 'bad' refers to a property so it couldn't be promoted.
+ // [context 87] 'bad' refers to a property so it couldn't be promoted.
}
indexSet(C28 c, List<int> values) {
@@ -563,83 +563,103 @@
// ^^^^^
// [analyzer 31] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
// ^
- // [cfe 86] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+ // [cfe 87] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
}
class C29 {
int? bad;
// ^^^
- // [context 22] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 87] 'bad' refers to a property so it couldn't be promoted.
+ // [context 14] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 88] 'bad' refers to a property so it couldn't be promoted.
}
indexSetCompound(C29 c, List<int> values) {
if (c.bad == null) return;
values[c.bad] += 1;
// ^^^^^
- // [analyzer 22] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+ // [analyzer 14] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
// ^
- // [cfe 87] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+ // [cfe 88] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
}
class C30 {
int? bad;
// ^^^
- // [context 18] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 88] 'bad' refers to a property so it couldn't be promoted.
+ // [context 27] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 89] 'bad' refers to a property so it couldn't be promoted.
}
indexSetIfNull(C30 c, List<int?> values) {
if (c.bad == null) return;
values[c.bad] ??= 1;
// ^^^^^
- // [analyzer 18] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+ // [analyzer 27] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
// ^
- // [cfe 88] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+ // [cfe 89] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
}
class C31 {
int? bad;
// ^^^
+ // [context 1] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
// [context 20] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 41] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 89] 'bad' refers to a property so it couldn't be promoted.
// [context 90] 'bad' refers to a property so it couldn't be promoted.
+ // [context 91] 'bad' refers to a property so it couldn't be promoted.
}
indexSetPreIncDec(C31 c, List<int> values) {
if (c.bad == null) return;
++values[c.bad];
// ^^^^^
- // [analyzer 41] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
- // ^
- // [cfe 89] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
- --values[c.bad];
- // ^^^^^
// [analyzer 20] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
// ^
// [cfe 90] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+ --values[c.bad];
+ // ^^^^^
+ // [analyzer 1] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+ // ^
+ // [cfe 91] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
}
class C32 {
int? bad;
// ^^^
- // [context 2] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 37] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
- // [context 91] 'bad' refers to a property so it couldn't be promoted.
+ // [context 29] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 42] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
// [context 92] 'bad' refers to a property so it couldn't be promoted.
+ // [context 93] 'bad' refers to a property so it couldn't be promoted.
}
indexSetPostIncDec(C32 c, List<int> values) {
if (c.bad == null) return;
values[c.bad]++;
// ^^^^^
- // [analyzer 2] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
- // ^
- // [cfe 91] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
- values[c.bad]--;
- // ^^^^^
- // [analyzer 37] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+ // [analyzer 29] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
// ^
// [cfe 92] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+ values[c.bad]--;
+ // ^^^^^
+ // [analyzer 42] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+ // ^
+ // [cfe 93] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+}
+
+extension E33 on int {
+ void f() {}
+}
+
+class C33 {
+ int? bad;
+ // ^^^
+ // [context 10] 'bad' refers to a property so it couldn't be promoted. See http://dart.dev/go/non-promo-property
+ // [context 94] 'bad' refers to a property so it couldn't be promoted.
+}
+
+test(C33 c) {
+ if (c.bad == null) return;
+ E33(c.bad).f();
+ // ^^^^^
+ // [analyzer 10] COMPILE_TIME_ERROR.EXTENSION_OVERRIDE_ARGUMENT_NOT_ASSIGNABLE
+ // ^
+ // [cfe 94] The argument type 'int?' can't be assigned to the parameter type 'int' because 'int?' is nullable and 'int' isn't.
}
diff --git a/tests/language_2/function/regress_45601_test.dart b/tests/language_2/function/regress_45601_test.dart
new file mode 100644
index 0000000..e1a8c19
--- /dev/null
+++ b/tests/language_2/function/regress_45601_test.dart
@@ -0,0 +1,42 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+// Regression test for https://github.com/dart-lang/sdk/issues/45601
+// When comparing values of type `Function` for equality DDC was generating
+// code that would throw at runtime.
+
+void fn<T>(T t) => null;
+
+void main() {
+ testStaticEquality();
+ testDynamicEquality();
+}
+
+/// Ensure `==` calls on function values that are statically typed as `Function`
+/// work as expected.
+void testStaticEquality() {
+ Function staticFunction = fn;
+ Expect.isTrue(staticFunction == fn);
+ Expect.isFalse(staticFunction == main);
+
+ Function staticFunction2 = null;
+ Expect.isFalse(staticFunction2 == staticFunction);
+ staticFunction2 = fn;
+ Expect.isTrue(staticFunction2 == staticFunction);
+}
+
+/// Ensure `==` calls on function values that are statically typed as `dynamic`
+/// work as expected.
+void testDynamicEquality() {
+ dynamic dynamicFunction = fn;
+ Expect.isTrue(dynamicFunction == fn);
+ Expect.isFalse(dynamicFunction == main);
+
+ dynamic dynamicFunction2 = null;
+ Expect.isFalse(dynamicFunction2 == dynamicFunction);
+ dynamicFunction2 = fn;
+ Expect.isTrue(dynamicFunction2 == dynamicFunction);
+}
diff --git a/tests/language_2/interface/duplicate_interface_implements_test.dart b/tests/language_2/interface/duplicate_interface_implements_test.dart
index 4564aad..0c8555e 100644
--- a/tests/language_2/interface/duplicate_interface_implements_test.dart
+++ b/tests/language_2/interface/duplicate_interface_implements_test.dart
@@ -10,6 +10,7 @@
, alib.InterfA
//^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.IMPLEMENTS_REPEATED
+ // [cfe] 'InterfA' can only be implemented once.
{}
main() {
diff --git a/tests/language_2/regress/regress34488_test.dart b/tests/language_2/regress/regress34488_test.dart
index 0930f68..357087c 100644
--- a/tests/language_2/regress/regress34488_test.dart
+++ b/tests/language_2/regress/regress34488_test.dart
@@ -32,9 +32,8 @@
// [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
// [cfe] The argument type 'String' can't be assigned to the parameter type 'int'.
d.h(i: 'bad');
- // ^^^^^^^^
+ // ^^^^^
// [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
- // ^
// [cfe] The argument type 'String' can't be assigned to the parameter type 'int'.
Object x = d.f(1);
// ^
diff --git a/tests/standalone/io/http_ban_http_allowed_cases_test.dart b/tests/standalone/io/http_ban_http_allowed_cases_test.dart
deleted file mode 100644
index 92e23c7..0000000
--- a/tests/standalone/io/http_ban_http_allowed_cases_test.dart
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// This test file disallows VM from accepting insecure connections to all
-// domains and tests that HTTP connections to non-localhost targets fail.
-// HTTPS connections and localhost connections should still succeed.
-
-// SharedOptions=-Ddart.library.io.may_insecurely_connect_to_all_domains=false
-
-import "dart:async";
-import "dart:io";
-
-import "package:async_helper/async_helper.dart";
-
-import "http_bind_test.dart";
-
-Future<String> getLocalHostIP() async {
- final interfaces = await NetworkInterface.list(
- includeLoopback: false, type: InternetAddressType.IPv4);
- return interfaces.first.addresses.first.address;
-}
-
-Future<void> testBanHttp(String serverHost,
- Future<void> testCode(HttpClient client, Uri uri)) async {
- final httpClient = new HttpClient();
- final server = await HttpServer.bind(serverHost, 0);
- final uri = Uri(scheme: 'http', host: serverHost, port: server.port);
- try {
- await testCode(httpClient, uri);
- } finally {
- httpClient.close(force: true);
- await server.close();
- }
-}
-
-Future<void> testWithLoopback() async {
- await testBanHttp("127.0.0.1", (httpClient, uri) async {
- await asyncTest(() async =>
- await httpClient.getUrl(Uri.parse('http://localhost:${uri.port}')));
- await asyncTest(() async =>
- await httpClient.getUrl(Uri.parse('http://127.0.0.1:${uri.port}')));
- });
-}
-
-Future<void> testWithIPv6() async {
- if (await supportsIPV6()) {
- await testBanHttp("::1", (httpClient, uri) async {
- await asyncTest(() => httpClient.getUrl(uri));
- });
- }
-}
-
-Future<void> testWithHttps() async {
- await testBanHttp(await getLocalHostIP(), (httpClient, uri) async {
- asyncExpectThrows(
- () => httpClient.getUrl(Uri(
- scheme: 'https',
- host: uri.host,
- port: uri.port,
- )),
- (e) => e is SocketException || e is HandshakeException);
- });
-}
-
-main() {
- asyncStart();
- Future.wait(<Future>[
- testWithLoopback(),
- testWithIPv6(),
- testWithHttps(),
- ]).then((_) => asyncEnd());
-}
diff --git a/tests/standalone/io/http_ban_http_embedder_test.dart b/tests/standalone/io/http_ban_http_embedder_test.dart
new file mode 100644
index 0000000..7fd3cb3
--- /dev/null
+++ b/tests/standalone/io/http_ban_http_embedder_test.dart
@@ -0,0 +1,69 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// SharedOptions=-Ddart.library.io.allow_http=false
+
+import 'dart:async';
+import 'dart:io';
+
+import "package:async_helper/async_helper.dart";
+
+import 'http_ban_http_normal_test.dart';
+import 'http_bind_test.dart';
+
+Future<void> testWithHostname() async {
+ await testBanHttp(await getLocalHostIP(), (httpClient, httpUri) async {
+ asyncExpectThrows(
+ () async => await httpClient.getUrl(httpUri), (e) => e is StateError);
+ asyncExpectThrows(
+ () async => await runZoned(() => httpClient.getUrl(httpUri),
+ zoneValues: {#dart.library.io.allow_http: 'foo'}),
+ (e) => e is StateError);
+ asyncExpectThrows(
+ () async => await runZoned(() => httpClient.getUrl(httpUri),
+ zoneValues: {#dart.library.io.allow_http: false}),
+ (e) => e is StateError);
+ await asyncTest(() => runZoned(() => httpClient.getUrl(httpUri),
+ zoneValues: {#dart.library.io.allow_http: true}));
+ });
+}
+
+Future<void> testWithLoopback() async {
+ await testBanHttp("127.0.0.1", (httpClient, uri) async {
+ await asyncTest(
+ () => httpClient.getUrl(Uri.parse('http://localhost:${uri.port}')));
+ await asyncTest(
+ () => httpClient.getUrl(Uri.parse('http://127.0.0.1:${uri.port}')));
+ });
+}
+
+Future<void> testWithIPv6() async {
+ if (await supportsIPV6()) {
+ await testBanHttp("::1", (httpClient, uri) async {
+ await asyncTest(() => httpClient.getUrl(uri));
+ });
+ }
+}
+
+Future<void> testWithHTTPS() async {
+ await testBanHttp(await getLocalHostIP(), (httpClient, uri) async {
+ asyncExpectThrows(
+ () => httpClient.getUrl(Uri(
+ scheme: 'https',
+ host: uri.host,
+ port: uri.port,
+ )),
+ (e) => e is SocketException || e is HandshakeException);
+ });
+}
+
+main() {
+ asyncStart();
+ Future.wait(<Future>[
+ testWithHostname(),
+ testWithLoopback(),
+ testWithIPv6(),
+ testWithHTTPS(),
+ ]).then((_) => asyncEnd());
+}
diff --git a/tests/standalone/io/http_ban_http_normal_test.dart b/tests/standalone/io/http_ban_http_normal_test.dart
new file mode 100644
index 0000000..118dd4c
--- /dev/null
+++ b/tests/standalone/io/http_ban_http_normal_test.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io';
+
+import "package:async_helper/async_helper.dart";
+
+Future<String> getLocalHostIP() async {
+ final interfaces = await NetworkInterface.list(
+ includeLoopback: false, type: InternetAddressType.IPv4);
+ return interfaces.first.addresses.first.address;
+}
+
+Future<void> testBanHttp(String serverHost,
+ Future<void> testCode(HttpClient client, Uri uri)) async {
+ final httpClient = new HttpClient();
+ final server = await HttpServer.bind(serverHost, 0);
+ final uri = Uri(scheme: 'http', host: serverHost, port: server.port);
+ try {
+ await testCode(httpClient, uri);
+ } finally {
+ httpClient.close(force: true);
+ await server.close();
+ }
+}
+
+main() async {
+ await asyncTest(() async {
+ final host = await getLocalHostIP();
+ // Normal HTTP request succeeds.
+ await testBanHttp(host, (httpClient, uri) async {
+ await asyncTest(() => httpClient.getUrl(uri));
+ });
+ // We can ban HTTP explicitly.
+ await testBanHttp(host, (httpClient, uri) async {
+ asyncExpectThrows(
+ () async => await runZoned(() => httpClient.getUrl(uri),
+ zoneValues: {#dart.library.io.allow_http: false}),
+ (e) => e is StateError);
+ });
+ });
+}
diff --git a/tests/standalone/io/http_ban_insecure_connections_test.dart b/tests/standalone/io/http_ban_insecure_connections_test.dart
deleted file mode 100644
index ae51a37..0000000
--- a/tests/standalone/io/http_ban_insecure_connections_test.dart
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// This test file disallows VM from accepting insecure connections to all
-// domains and tests that HTTP connections to non-localhost targets fail.
-// HTTPS connections and localhost connections should still succeed.
-
-// SharedOptions=-Ddart.library.io.may_insecurely_connect_to_all_domains=false
-
-import "dart:async";
-import "dart:io";
-
-import "package:async_helper/async_helper.dart";
-
-Future<void> testWithHostname() async {
- final httpClient = new HttpClient();
- final uri = Uri(scheme: 'http', host: 'domain.invalid', port: 12345);
- asyncExpectThrows(
- () async => await httpClient.getUrl(uri),
- (e) =>
- e is StateError &&
- e.message.contains("Insecure HTTP is not allowed by platform"));
-}
-
-main() {
- asyncStart();
- testWithHostname().then((_) => asyncEnd());
-}
diff --git a/tests/standalone/io/http_cookie_date_test.dart b/tests/standalone/io/http_cookie_date_test.dart
index f750fdf..dc1787d 100644
--- a/tests/standalone/io/http_cookie_date_test.dart
+++ b/tests/standalone/io/http_cookie_date_test.dart
@@ -19,6 +19,7 @@
show Since, valueOfNonNullableParamWithDefault, HttpStatus;
part "../../../sdk/lib/_http/crypto.dart";
+part "../../../sdk/lib/_http/embedder_config.dart";
part "../../../sdk/lib/_http/http_impl.dart";
part "../../../sdk/lib/_http/http_date.dart";
part "../../../sdk/lib/_http/http_parser.dart";
diff --git a/tests/standalone/io/http_headers_test.dart b/tests/standalone/io/http_headers_test.dart
index 860b0b1..11e0f89 100644
--- a/tests/standalone/io/http_headers_test.dart
+++ b/tests/standalone/io/http_headers_test.dart
@@ -19,6 +19,7 @@
show Since, valueOfNonNullableParamWithDefault, HttpStatus;
part "../../../sdk/lib/_http/crypto.dart";
+part "../../../sdk/lib/_http/embedder_config.dart";
part "../../../sdk/lib/_http/http_impl.dart";
part "../../../sdk/lib/_http/http_date.dart";
part "../../../sdk/lib/_http/http_parser.dart";
diff --git a/tests/standalone/io/http_parser_test.dart b/tests/standalone/io/http_parser_test.dart
index c689a0c..300ed63 100644
--- a/tests/standalone/io/http_parser_test.dart
+++ b/tests/standalone/io/http_parser_test.dart
@@ -19,6 +19,7 @@
show Since, valueOfNonNullableParamWithDefault, HttpStatus;
part "../../../sdk/lib/_http/crypto.dart";
+part "../../../sdk/lib/_http/embedder_config.dart";
part "../../../sdk/lib/_http/http_impl.dart";
part "../../../sdk/lib/_http/http_date.dart";
part "../../../sdk/lib/_http/http_parser.dart";
diff --git a/tests/standalone/io/network_policy_configuration_test.dart b/tests/standalone/io/network_policy_configuration_test.dart
deleted file mode 100644
index 49e6c56..0000000
--- a/tests/standalone/io/network_policy_configuration_test.dart
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// SharedOptions=-Ddart.library.io.domain_network_policies=[["foobar.com",true,true],["foobar.com",true,true],["baz.foobar.com",true,true],["baz.foobar.com",false,false]] -Ddart.library.io.may_insecurely_connect_to_all_domains=false
-
-import 'dart:io';
-
-import "package:expect/expect.dart";
-
-void _checkAllows(List<String> domains) {
- for (final domain in domains) {
- Expect.isTrue(
- isInsecureConnectionAllowed(domain), "$domain should be allowed.");
- }
-}
-
-void _checkDenies(List<String> domains) {
- for (final domain in domains) {
- Expect.isFalse(
- isInsecureConnectionAllowed(domain), "$domain should not be allowed.");
- }
-}
-
-void main() {
- // These have no policy but the default is false.
- _checkDenies([
- "mailfoobar.com",
- "abc.com",
- "oobar.com",
- "foobar.co",
- "128.221.55.31",
- "fe80::4607:0bff:fea0:7747%invalid",
- ]);
- // These are explicitly denied.
- _checkDenies(["baz.foobar.com"]);
- _checkAllows(
- ["foobar.com", "test.baz.foobar.com", "test2.test.baz.foobar.com"]);
- _checkAllows(["::1", "localhost"]);
-}
diff --git a/tests/standalone/io/network_policy_invalid_domain_test.dart b/tests/standalone/io/network_policy_invalid_domain_test.dart
deleted file mode 100644
index 971996c..0000000
--- a/tests/standalone/io/network_policy_invalid_domain_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// SharedOptions=-Ddart.library.io.domain_network_policies=[["com",true,true]]
-
-import 'dart:io';
-
-import "package:expect/expect.dart";
-
-// This test passes in an invalid domain as a network policy and checks that
-// loading the policies throws.
-void main() {
- Expect.throwsArgumentError(() => isInsecureConnectionAllowed("test.com"));
-}
diff --git a/tests/standalone/io/network_policy_test.dart b/tests/standalone/io/network_policy_test.dart
new file mode 100644
index 0000000..2f9878d
--- /dev/null
+++ b/tests/standalone/io/network_policy_test.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import "package:expect/expect.dart";
+
+void _checkAllows(List<String> domains) {
+ for (final domain in domains) {
+ Expect.isTrue(
+ isInsecureConnectionAllowed(domain), "$domain should be allowed.");
+ }
+}
+
+void main() {
+ // All domains and addresses are allowed.
+ _checkAllows([
+ "mailfoobar.com",
+ "abc.com",
+ "oobar.com",
+ "foobar.co",
+ "128.221.55.31",
+ "fe80::4607:0bff:fea0:7747%invalid",
+ "baz.foobar.com",
+ "foobar.com",
+ "test.baz.foobar.com",
+ "test2.test.baz.foobar.com",
+ "::1",
+ "localhost",
+ ]);
+}
diff --git a/tests/standalone/io/network_policy_tie_breaker_test.dart b/tests/standalone/io/network_policy_tie_breaker_test.dart
deleted file mode 100644
index c25d3ac..0000000
--- a/tests/standalone/io/network_policy_tie_breaker_test.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// SharedOptions=-Ddart.library.io.domain_network_policies=[["baz.foobar.com",true,true],["baz.foobar.com",false,false]]
-
-import 'dart:io';
-
-import "package:expect/expect.dart";
-
-void main() {
- Expect.isFalse(isInsecureConnectionAllowed("baz.foobar.com"));
- Expect.isTrue(isInsecureConnectionAllowed("test.baz.foobar.com"));
-}
diff --git a/tests/standalone/io/web_socket_protocol_processor_test.dart b/tests/standalone/io/web_socket_protocol_processor_test.dart
index 71e7e45..344a0b9 100644
--- a/tests/standalone/io/web_socket_protocol_processor_test.dart
+++ b/tests/standalone/io/web_socket_protocol_processor_test.dart
@@ -20,6 +20,7 @@
show Since, valueOfNonNullableParamWithDefault, HttpStatus;
part "../../../sdk/lib/_http/crypto.dart";
+part "../../../sdk/lib/_http/embedder_config.dart";
part "../../../sdk/lib/_http/http_impl.dart";
part "../../../sdk/lib/_http/http_date.dart";
part "../../../sdk/lib/_http/http_parser.dart";
diff --git a/tests/standalone/standalone_kernel.status b/tests/standalone/standalone_kernel.status
index cf3bf1f..a628ff4 100644
--- a/tests/standalone/standalone_kernel.status
+++ b/tests/standalone/standalone_kernel.status
@@ -12,10 +12,8 @@
[ $system == android ]
entrypoints_verification_test: Skip # Requires shared objects which the test script doesn't "adb push".
-io/http_ban_http_allowed_cases_test: Skip # Depends on grabbing local hostname which isn't supported.
-io/network_policy_configuration_test: Skip # Can't pass -D params containing quotes to adb.
-io/network_policy_invalid_domain_test: Skip # Can't pass -D params containing quotes to adb.
-io/network_policy_tie_breaker_test: Skip # Can't pass -D params containing quotes to adb.
+io/http_ban_http_embedder_test: Skip # Requires http server bound to non-loopback; not provided by system.
+io/http_ban_http_normal_test: Skip # Requires http server bound to non-loopback; not provided by system.
[ $arch == ia32 && $builder_tag == optimization_counter_threshold ]
io/file_lock_test: SkipSlow # Timeout
diff --git a/tests/standalone_2/io/http_ban_http_allowed_cases_test.dart b/tests/standalone_2/io/http_ban_http_allowed_cases_test.dart
deleted file mode 100644
index 92e23c7..0000000
--- a/tests/standalone_2/io/http_ban_http_allowed_cases_test.dart
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// This test file disallows VM from accepting insecure connections to all
-// domains and tests that HTTP connections to non-localhost targets fail.
-// HTTPS connections and localhost connections should still succeed.
-
-// SharedOptions=-Ddart.library.io.may_insecurely_connect_to_all_domains=false
-
-import "dart:async";
-import "dart:io";
-
-import "package:async_helper/async_helper.dart";
-
-import "http_bind_test.dart";
-
-Future<String> getLocalHostIP() async {
- final interfaces = await NetworkInterface.list(
- includeLoopback: false, type: InternetAddressType.IPv4);
- return interfaces.first.addresses.first.address;
-}
-
-Future<void> testBanHttp(String serverHost,
- Future<void> testCode(HttpClient client, Uri uri)) async {
- final httpClient = new HttpClient();
- final server = await HttpServer.bind(serverHost, 0);
- final uri = Uri(scheme: 'http', host: serverHost, port: server.port);
- try {
- await testCode(httpClient, uri);
- } finally {
- httpClient.close(force: true);
- await server.close();
- }
-}
-
-Future<void> testWithLoopback() async {
- await testBanHttp("127.0.0.1", (httpClient, uri) async {
- await asyncTest(() async =>
- await httpClient.getUrl(Uri.parse('http://localhost:${uri.port}')));
- await asyncTest(() async =>
- await httpClient.getUrl(Uri.parse('http://127.0.0.1:${uri.port}')));
- });
-}
-
-Future<void> testWithIPv6() async {
- if (await supportsIPV6()) {
- await testBanHttp("::1", (httpClient, uri) async {
- await asyncTest(() => httpClient.getUrl(uri));
- });
- }
-}
-
-Future<void> testWithHttps() async {
- await testBanHttp(await getLocalHostIP(), (httpClient, uri) async {
- asyncExpectThrows(
- () => httpClient.getUrl(Uri(
- scheme: 'https',
- host: uri.host,
- port: uri.port,
- )),
- (e) => e is SocketException || e is HandshakeException);
- });
-}
-
-main() {
- asyncStart();
- Future.wait(<Future>[
- testWithLoopback(),
- testWithIPv6(),
- testWithHttps(),
- ]).then((_) => asyncEnd());
-}
diff --git a/tests/standalone_2/io/http_ban_http_embedder_test.dart b/tests/standalone_2/io/http_ban_http_embedder_test.dart
new file mode 100644
index 0000000..7fd3cb3
--- /dev/null
+++ b/tests/standalone_2/io/http_ban_http_embedder_test.dart
@@ -0,0 +1,69 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// SharedOptions=-Ddart.library.io.allow_http=false
+
+import 'dart:async';
+import 'dart:io';
+
+import "package:async_helper/async_helper.dart";
+
+import 'http_ban_http_normal_test.dart';
+import 'http_bind_test.dart';
+
+Future<void> testWithHostname() async {
+ await testBanHttp(await getLocalHostIP(), (httpClient, httpUri) async {
+ asyncExpectThrows(
+ () async => await httpClient.getUrl(httpUri), (e) => e is StateError);
+ asyncExpectThrows(
+ () async => await runZoned(() => httpClient.getUrl(httpUri),
+ zoneValues: {#dart.library.io.allow_http: 'foo'}),
+ (e) => e is StateError);
+ asyncExpectThrows(
+ () async => await runZoned(() => httpClient.getUrl(httpUri),
+ zoneValues: {#dart.library.io.allow_http: false}),
+ (e) => e is StateError);
+ await asyncTest(() => runZoned(() => httpClient.getUrl(httpUri),
+ zoneValues: {#dart.library.io.allow_http: true}));
+ });
+}
+
+Future<void> testWithLoopback() async {
+ await testBanHttp("127.0.0.1", (httpClient, uri) async {
+ await asyncTest(
+ () => httpClient.getUrl(Uri.parse('http://localhost:${uri.port}')));
+ await asyncTest(
+ () => httpClient.getUrl(Uri.parse('http://127.0.0.1:${uri.port}')));
+ });
+}
+
+Future<void> testWithIPv6() async {
+ if (await supportsIPV6()) {
+ await testBanHttp("::1", (httpClient, uri) async {
+ await asyncTest(() => httpClient.getUrl(uri));
+ });
+ }
+}
+
+Future<void> testWithHTTPS() async {
+ await testBanHttp(await getLocalHostIP(), (httpClient, uri) async {
+ asyncExpectThrows(
+ () => httpClient.getUrl(Uri(
+ scheme: 'https',
+ host: uri.host,
+ port: uri.port,
+ )),
+ (e) => e is SocketException || e is HandshakeException);
+ });
+}
+
+main() {
+ asyncStart();
+ Future.wait(<Future>[
+ testWithHostname(),
+ testWithLoopback(),
+ testWithIPv6(),
+ testWithHTTPS(),
+ ]).then((_) => asyncEnd());
+}
diff --git a/tests/standalone_2/io/http_ban_http_normal_test.dart b/tests/standalone_2/io/http_ban_http_normal_test.dart
new file mode 100644
index 0000000..118dd4c
--- /dev/null
+++ b/tests/standalone_2/io/http_ban_http_normal_test.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io';
+
+import "package:async_helper/async_helper.dart";
+
+Future<String> getLocalHostIP() async {
+ final interfaces = await NetworkInterface.list(
+ includeLoopback: false, type: InternetAddressType.IPv4);
+ return interfaces.first.addresses.first.address;
+}
+
+Future<void> testBanHttp(String serverHost,
+ Future<void> testCode(HttpClient client, Uri uri)) async {
+ final httpClient = new HttpClient();
+ final server = await HttpServer.bind(serverHost, 0);
+ final uri = Uri(scheme: 'http', host: serverHost, port: server.port);
+ try {
+ await testCode(httpClient, uri);
+ } finally {
+ httpClient.close(force: true);
+ await server.close();
+ }
+}
+
+main() async {
+ await asyncTest(() async {
+ final host = await getLocalHostIP();
+ // Normal HTTP request succeeds.
+ await testBanHttp(host, (httpClient, uri) async {
+ await asyncTest(() => httpClient.getUrl(uri));
+ });
+ // We can ban HTTP explicitly.
+ await testBanHttp(host, (httpClient, uri) async {
+ asyncExpectThrows(
+ () async => await runZoned(() => httpClient.getUrl(uri),
+ zoneValues: {#dart.library.io.allow_http: false}),
+ (e) => e is StateError);
+ });
+ });
+}
diff --git a/tests/standalone_2/io/http_ban_insecure_connections_test.dart b/tests/standalone_2/io/http_ban_insecure_connections_test.dart
deleted file mode 100644
index ae51a37..0000000
--- a/tests/standalone_2/io/http_ban_insecure_connections_test.dart
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// This test file disallows VM from accepting insecure connections to all
-// domains and tests that HTTP connections to non-localhost targets fail.
-// HTTPS connections and localhost connections should still succeed.
-
-// SharedOptions=-Ddart.library.io.may_insecurely_connect_to_all_domains=false
-
-import "dart:async";
-import "dart:io";
-
-import "package:async_helper/async_helper.dart";
-
-Future<void> testWithHostname() async {
- final httpClient = new HttpClient();
- final uri = Uri(scheme: 'http', host: 'domain.invalid', port: 12345);
- asyncExpectThrows(
- () async => await httpClient.getUrl(uri),
- (e) =>
- e is StateError &&
- e.message.contains("Insecure HTTP is not allowed by platform"));
-}
-
-main() {
- asyncStart();
- testWithHostname().then((_) => asyncEnd());
-}
diff --git a/tests/standalone_2/io/network_policy_configuration_test.dart b/tests/standalone_2/io/network_policy_configuration_test.dart
deleted file mode 100644
index 49e6c56..0000000
--- a/tests/standalone_2/io/network_policy_configuration_test.dart
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// SharedOptions=-Ddart.library.io.domain_network_policies=[["foobar.com",true,true],["foobar.com",true,true],["baz.foobar.com",true,true],["baz.foobar.com",false,false]] -Ddart.library.io.may_insecurely_connect_to_all_domains=false
-
-import 'dart:io';
-
-import "package:expect/expect.dart";
-
-void _checkAllows(List<String> domains) {
- for (final domain in domains) {
- Expect.isTrue(
- isInsecureConnectionAllowed(domain), "$domain should be allowed.");
- }
-}
-
-void _checkDenies(List<String> domains) {
- for (final domain in domains) {
- Expect.isFalse(
- isInsecureConnectionAllowed(domain), "$domain should not be allowed.");
- }
-}
-
-void main() {
- // These have no policy but the default is false.
- _checkDenies([
- "mailfoobar.com",
- "abc.com",
- "oobar.com",
- "foobar.co",
- "128.221.55.31",
- "fe80::4607:0bff:fea0:7747%invalid",
- ]);
- // These are explicitly denied.
- _checkDenies(["baz.foobar.com"]);
- _checkAllows(
- ["foobar.com", "test.baz.foobar.com", "test2.test.baz.foobar.com"]);
- _checkAllows(["::1", "localhost"]);
-}
diff --git a/tests/standalone_2/io/network_policy_invalid_domain_test.dart b/tests/standalone_2/io/network_policy_invalid_domain_test.dart
deleted file mode 100644
index 971996c..0000000
--- a/tests/standalone_2/io/network_policy_invalid_domain_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// SharedOptions=-Ddart.library.io.domain_network_policies=[["com",true,true]]
-
-import 'dart:io';
-
-import "package:expect/expect.dart";
-
-// This test passes in an invalid domain as a network policy and checks that
-// loading the policies throws.
-void main() {
- Expect.throwsArgumentError(() => isInsecureConnectionAllowed("test.com"));
-}
diff --git a/tests/standalone_2/io/network_policy_test.dart b/tests/standalone_2/io/network_policy_test.dart
new file mode 100644
index 0000000..2f9878d
--- /dev/null
+++ b/tests/standalone_2/io/network_policy_test.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import "package:expect/expect.dart";
+
+void _checkAllows(List<String> domains) {
+ for (final domain in domains) {
+ Expect.isTrue(
+ isInsecureConnectionAllowed(domain), "$domain should be allowed.");
+ }
+}
+
+void main() {
+ // All domains and addresses are allowed.
+ _checkAllows([
+ "mailfoobar.com",
+ "abc.com",
+ "oobar.com",
+ "foobar.co",
+ "128.221.55.31",
+ "fe80::4607:0bff:fea0:7747%invalid",
+ "baz.foobar.com",
+ "foobar.com",
+ "test.baz.foobar.com",
+ "test2.test.baz.foobar.com",
+ "::1",
+ "localhost",
+ ]);
+}
diff --git a/tests/standalone_2/io/network_policy_tie_breaker_test.dart b/tests/standalone_2/io/network_policy_tie_breaker_test.dart
deleted file mode 100644
index c25d3ac..0000000
--- a/tests/standalone_2/io/network_policy_tie_breaker_test.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// SharedOptions=-Ddart.library.io.domain_network_policies=[["baz.foobar.com",true,true],["baz.foobar.com",false,false]]
-
-import 'dart:io';
-
-import "package:expect/expect.dart";
-
-void main() {
- Expect.isFalse(isInsecureConnectionAllowed("baz.foobar.com"));
- Expect.isTrue(isInsecureConnectionAllowed("test.baz.foobar.com"));
-}
diff --git a/tests/standalone_2/standalone_2_kernel.status b/tests/standalone_2/standalone_2_kernel.status
index f5fb8ac..548f99c 100644
--- a/tests/standalone_2/standalone_2_kernel.status
+++ b/tests/standalone_2/standalone_2_kernel.status
@@ -14,10 +14,8 @@
[ $system == android ]
entrypoints_verification_test: Skip # Requires shared objects which the test script doesn't "adb push".
-io/http_ban_http_allowed_cases_test: Skip # Depends on grabbing local hostname which isn't supported.
-io/network_policy_configuration_test: Skip # Can't pass -D params containing quotes to adb.
-io/network_policy_invalid_domain_test: Skip # Can't pass -D params containing quotes to adb.
-io/network_policy_tie_breaker_test: Skip # Can't pass -D params containing quotes to adb.
+io/http_ban_http_embedder_test: Skip # Requires http server bound to non-loopback; not provided by system.
+io/http_ban_http_normal_test: Skip # Requires http server bound to non-loopback; not provided by system.
[ $arch == ia32 && $builder_tag == optimization_counter_threshold ]
io/file_lock_test: SkipSlow # Timeout
diff --git a/tools/VERSION b/tools/VERSION
index 8d5df1f..1916272 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 14
PATCH 0
-PRERELEASE 8
+PRERELEASE 9
PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/bots/bot_utils.py b/tools/bots/bot_utils.py
index 29f840b..5bd718b 100755
--- a/tools/bots/bot_utils.py
+++ b/tools/bots/bot_utils.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
# Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
@@ -7,8 +7,6 @@
import hashlib
import imp
import os
-import platform
-import string
import subprocess
import sys
@@ -176,20 +174,21 @@
def run(command, env=None, shell=False, throw_on_error=True):
- print "Running command: ", command
+ print("Running command: ", command)
- p = subprocess.Popen(
- command,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- env=env,
- shell=shell)
+ p = subprocess.Popen(command,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ env=env,
+ shell=shell,
+ universal_newlines=True)
(stdout, stderr) = p.communicate()
if throw_on_error and p.returncode != 0:
- print >> sys.stderr, "Failed to execute '%s'. Exit code: %s." % (
- command, p.returncode)
- print >> sys.stderr, "stdout: ", stdout
- print >> sys.stderr, "stderr: ", stderr
+ print("Failed to execute '%s'. Exit code: %s." %
+ (command, p.returncode),
+ file=sys.stderr)
+ print("stdout: ", stdout, file=sys.stderr)
+ print("stderr: ", stderr, file=sys.stderr)
raise Exception("Failed to execute %s." % command)
return (stdout, stderr, p.returncode)
@@ -307,7 +306,7 @@
with open(checksum_filename, 'w') as f:
f.write('%s *%s' % (checksum, mangled_filename))
- print "MD5 checksum of %s is %s" % (filename, checksum)
+ print("MD5 checksum of %s is %s" % (filename, checksum))
return checksum_filename
@@ -322,14 +321,14 @@
with open(checksum_filename, 'w') as f:
f.write('%s *%s' % (checksum, mangled_filename))
- print "SHA256 checksum of %s is %s" % (filename, checksum)
+ print("SHA256 checksum of %s is %s" % (filename, checksum))
return checksum_filename
def GetChannelFromName(name):
"""Get the channel from the name. Bleeding edge builders don't
have a suffix."""
- channel_name = string.split(name, '-').pop()
+ channel_name = name.split('-').pop()
if channel_name in Channel.ALL_CHANNELS:
return channel_name
return Channel.BLEEDING_EDGE
@@ -337,7 +336,7 @@
def GetSystemFromName(name):
"""Get the system from the name."""
- for part in string.split(name, '-'):
+ for part in name.split('-'):
if part in SYSTEM_RENAMES: return SYSTEM_RENAMES[part]
raise ValueError(
diff --git a/tools/bots/dart_sdk.py b/tools/bots/dart_sdk.py
index 8e7f6f9..0193969 100755
--- a/tools/bots/dart_sdk.py
+++ b/tools/bots/dart_sdk.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
# 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
@@ -233,8 +233,8 @@
def Run(command, env=None):
- print "Running %s" % ' '.join(command)
- print "Environment %s" % env
+ print("Running %s" % ' '.join(command))
+ print("Environment %s" % env)
sys.stdout.flush()
exit_code = subprocess.call(command)
if exit_code != 0:
diff --git a/tools/bots/linux_distribution_support.py b/tools/bots/linux_distribution_support.py
index 789fce8..04fb693 100644
--- a/tools/bots/linux_distribution_support.py
+++ b/tools/bots/linux_distribution_support.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
@@ -43,7 +43,7 @@
def Run(command):
- print "Running: %s" % ' '.join(command)
+ print("Running: %s" % ' '.join(command))
sys.stdout.flush()
no_color_env = dict(os.environ)
no_color_env['TERM'] = 'nocolor'
@@ -59,11 +59,11 @@
for path in paths:
if os.path.exists(path):
if not assume_installed:
- print 'Assumed not installed, found %s' % path
+ print('Assumed not installed, found %s' % path)
sys.exit(1)
else:
if assume_installed:
- print 'Assumed installed, but could not find %s' % path
+ print('Assumed installed, but could not find %s' % path)
sys.exit(1)
@@ -77,23 +77,23 @@
tarfilename = 'dart-%s.tar.gz' % version
tarfile = os.path.join(builddir, tarfilename)
- print 'Validating that we are on debian jessie'
+ print('Validating that we are on debian jessie')
args = ['cat', '/etc/os-release']
(stdout, stderr, exitcode) = bot_utils.run(args)
if exitcode != 0:
- print "Could not find linux system, exiting"
+ print("Could not find linux system, exiting")
sys.exit(1)
if not "jessie" in stdout:
- print "Trying to build debian bits but not on debian Jessie"
- print "You can't fix this, please contact dart-engprod@"
+ print("Trying to build debian bits but not on debian Jessie")
+ print("You can't fix this, please contact dart-engprod@")
sys.exit(1)
- print 'Building src tarball'
+ print('Building src tarball')
Run([
sys.executable, './tools/create_tarball.py', '--tar_filename', tarfile
])
- print 'Building Debian packages'
+ print('Building Debian packages')
Run([
sys.executable, './tools/create_debian_packages.py', '--tar_filename',
tarfile, '--out_dir', builddir
@@ -101,7 +101,7 @@
if os.path.exists('/usr/bin/dart') or os.path.exists(
'/usr/lib/dart/bin/dart2js'):
- print "Dart already installed, removing"
+ print("Dart already installed, removing")
UninstallDart()
TestInstallation(assume_installed=False)
diff --git a/tools/bots/pub_integration_test.py b/tools/bots/pub_integration_test.py
index 6d6ef43..7264279 100755
--- a/tools/bots/pub_integration_test.py
+++ b/tools/bots/pub_integration_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# 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.
diff --git a/tools/bots/upload_debian_packages.py b/tools/bots/upload_debian_packages.py
index 4ee7642..3fc08d4 100755
--- a/tools/bots/upload_debian_packages.py
+++ b/tools/bots/upload_debian_packages.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# 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
@@ -36,7 +36,7 @@
if __name__ == '__main__':
bot_name = os.environ.get('BUILDBOT_BUILDERNAME')
channel = bot_utils.GetChannelFromName(bot_name)
- if channel != bot_utils.Channel.BLEEDING_EDGE:
+ if channel not in (bot_utils.Channel.BLEEDING_EDGE, bot_utils.Channel.TRY):
builddir = os.path.join(bot_utils.DART_DIR, utils.GetBuildDir(HOST_OS),
'src_and_installation')
version = utils.GetVersion()
@@ -44,4 +44,4 @@
tarfile = os.path.join(builddir, tarfilename)
ArchiveArtifacts(tarfile, builddir, channel)
else:
- print 'Not uploading artifacts on bleeding edge'
+ print('Not uploading artifacts on bleeding edge')
diff --git a/tools/build.py b/tools/build.py
index 513bef8..fb17356 100755
--- a/tools/build.py
+++ b/tools/build.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
# 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
@@ -143,7 +143,7 @@
return False
goma_ctl = os.path.join(goma_dir, 'goma_ctl.py')
goma_ctl_command = [
- 'python',
+ 'python3',
goma_ctl,
'ensure_start',
]
diff --git a/tools/buildtools/update.py b/tools/buildtools/update.py
index a398225..bafeab1 100755
--- a/tools/buildtools/update.py
+++ b/tools/buildtools/update.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright 2017 The Dart project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
@@ -27,9 +27,9 @@
downloader_script = os.path.join(DEPOT_PATH,
'download_from_google_storage.py')
download_cmd = [
- 'python', downloader_script, '--no_auth', '--no_resume', '--quiet',
- '--platform=win', '--bucket', 'chromium-clang-format', '-s', sha1_file,
- '-o', output_dir
+ sys.executable, downloader_script, '--no_auth', '--no_resume',
+ '--quiet', '--platform=win', '--bucket', 'chromium-clang-format', '-s',
+ sha1_file, '-o', output_dir
]
return subprocess.call(download_cmd)
@@ -37,7 +37,7 @@
def CreateSymlink(symlink, link_name):
try:
os.symlink(symlink, link_name)
- except OSError, e:
+ except OSError as e:
if e.errno == errno.EEXIST:
os.remove(link_name)
os.symlink(symlink, link_name)
@@ -57,7 +57,7 @@
tools = 'linux64'
toolchain = 'linux-x64'
else:
- print 'Unknown platform: ' + sys.platform
+ print('Unknown platform: ' + sys.platform)
return 1
clang_format = os.path.join(BUILDTOOLS, toolchain, 'clang', 'bin',
diff --git a/tools/copy_dart.py b/tools/copy_dart.py
index dbb7ecf..fedc29b 100755
--- a/tools/copy_dart.py
+++ b/tools/copy_dart.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2.7
+#!/usr/bin/env python3
# Copyright (c) 2011, 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.
@@ -80,14 +80,14 @@
def main(outdir=None, *inputs):
if not outdir or not inputs:
- print "Usage: %s OUTDIR INPUTS" % sys.argv[0]
- print " OUTDIR is the war directory to copy to"
- print " INPUTS is a list of files or patterns used to specify the input"
- print " .dart files"
- print "This script should be run from the client root directory."
- print "Files will be merged and copied to: OUTDIR/relative-path-of-file,"
- print "except for dart files with absolute paths, which will be copied to"
- print " OUTDIR/absolute-path-as-directories"
+ print("""Usage: %s OUTDIR INPUTS
+ OUTDIR is the war directory to copy to
+ INPUTS is a list of files or patterns used to specify the input
+ .dart files
+This script should be run from the client root directory.
+Files will be merged and copied to: OUTDIR/relative-path-of-file,
+except for dart files with absolute paths, which will be copied to
+ OUTDIR/absolute-path-as-directories""" % sys.argv[0])
return 1
entry_libraries = []
diff --git a/tools/copy_tree.py b/tools/copy_tree.py
index f5c5c56..8c63308 100755
--- a/tools/copy_tree.py
+++ b/tools/copy_tree.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# 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.
diff --git a/tools/create_debian_chroot.sh b/tools/create_debian_chroot.sh
index 4376f3b..4e98093 100755
--- a/tools/create_debian_chroot.sh
+++ b/tools/create_debian_chroot.sh
@@ -72,7 +72,7 @@
jessie $CHROOT http://http.us.debian.org/debian/
chroot $CHROOT apt-get update
chroot $CHROOT apt-get -y install \
- debhelper python git gcc sudo make
+ debhelper python3 git gcc sudo make
# Add chrome-bot user.
chroot $CHROOT groupadd --gid 1001 chrome-bot
diff --git a/tools/create_debian_packages.py b/tools/create_debian_packages.py
index e0e81bb1..74b8a77 100755
--- a/tools/create_debian_packages.py
+++ b/tools/create_debian_packages.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
# Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
@@ -59,7 +59,7 @@
origtarname = 'dart_%s.orig.tar.gz' % version
if not exists(tarball):
- print 'Source tarball not found'
+ print('Source tarball not found')
return -1
with utils.TempDir() as temp_dir:
@@ -70,30 +70,30 @@
tar.extractall(path=temp_dir)
# Build source package.
- print "Building source package"
+ print("Building source package")
RunBuildPackage(['-S', '-us', '-uc'], join(temp_dir, tarroot))
# Build 32-bit binary package.
if 'ia32' in arch:
- print "Building i386 package"
+ print("Building i386 package")
RunBuildPackage(['-B', '-ai386', '-us', '-uc'],
join(temp_dir, tarroot))
# Build 64-bit binary package.
if 'x64' in arch:
- print "Building amd64 package"
+ print("Building amd64 package")
RunBuildPackage(['-B', '-aamd64', '-us', '-uc'],
join(temp_dir, tarroot))
# Build armhf binary package.
if 'armhf' in arch:
- print "Building armhf package"
+ print("Building armhf package")
RunBuildPackage(['-B', '-aarmhf', '-us', '-uc'],
join(temp_dir, tarroot), toolchain)
# Build armel binary package.
if 'armel' in arch:
- print "Building armel package"
+ print("Building armel package")
RunBuildPackage(['-B', '-aarmel', '-us', '-uc'],
join(temp_dir, tarroot), toolchain)
@@ -127,7 +127,7 @@
def Main():
if HOST_OS != 'linux':
- print 'Debian build only supported on linux'
+ print('Debian build only supported on linux')
return -1
options, args = BuildOptions().parse_args()
diff --git a/tools/create_pkg_manifest.py b/tools/create_pkg_manifest.py
index 0448ca9..0233b44 100755
--- a/tools/create_pkg_manifest.py
+++ b/tools/create_pkg_manifest.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright 2016 The Dart project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
diff --git a/tools/create_tarball.py b/tools/create_tarball.py
index ee5630a..6844cad 100755
--- a/tools/create_tarball.py
+++ b/tools/create_tarball.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
# Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
@@ -80,7 +80,7 @@
# out-of-the-box.
tar_info.name = join(versiondir, 'dart', original_name)
if verbose:
- print 'Adding %s as %s' % (original_name, tar_info.name)
+ print('Adding %s as %s' % (original_name, tar_info.name))
return tar_info
@@ -129,7 +129,7 @@
builddir = utils.GetBuildDir(HOST_OS)
ignoredPaths.append(builddir)
- print 'Creating tarball: %s' % tarfilename
+ print('Creating tarball: %s' % tarfilename)
with tarfile.open(tarfilename, mode='w:gz') as tar:
for f in listdir(DART_DIR):
tar.add(join(DART_DIR, f), filter=Filter)
@@ -165,7 +165,7 @@
def Main():
if HOST_OS != 'linux':
- print 'Tarball can only be created on linux'
+ print('Tarball can only be created on linux')
return -1
# Parse the options.
diff --git a/tools/create_timestamp_file.py b/tools/create_timestamp_file.py
index 8f449a6..bb48e7f 100755
--- a/tools/create_timestamp_file.py
+++ b/tools/create_timestamp_file.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright (c) 2013, 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.
diff --git a/tools/dom/dom.py b/tools/dom/dom.py
index 8fa8254..f986d3f 100755
--- a/tools/dom/dom.py
+++ b/tools/dom/dom.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
@@ -172,14 +172,14 @@
def call(args):
- print ' '.join(args)
+ print(' '.join(args))
pipe = subprocess.Popen(
args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, error = pipe.communicate()
if output:
- print output
+ print(output)
if error:
- print error
+ print(error)
return pipe.returncode
diff --git a/tools/dom/new_scripts/code_generator_dart.py b/tools/dom/new_scripts/code_generator_dart.py
index 6fdd2a9..2a92923 100644
--- a/tools/dom/new_scripts/code_generator_dart.py
+++ b/tools/dom/new_scripts/code_generator_dart.py
@@ -238,10 +238,9 @@
world['callbacks'].append(idl_world['callback'])
idl_pickle_file.close()
- world['interfaces'] = sorted(
- world['interfaces'], key=lambda (x): x['name'])
- world['callbacks'] = sorted(
- world['callbacks'], key=lambda (x): x['name'])
+ world['interfaces'] = sorted(world['interfaces'],
+ key=lambda x: x['name'])
+ world['callbacks'] = sorted(world['callbacks'], key=lambda x: x['name'])
template_contents = world
template_contents['code_generator'] = module_pyname
@@ -299,7 +298,7 @@
cache_dir = argv[1]
dummy_filename = argv[2]
except IndexError as err:
- print 'Usage: %s OUTPUT_DIR DUMMY_FILENAME' % argv[0]
+ print('Usage: %s OUTPUT_DIR DUMMY_FILENAME' % argv[0])
return 1
# Cache templates
diff --git a/tools/dom/new_scripts/compiler.py b/tools/dom/new_scripts/compiler.py
index 9a27581..7eb7270 100755
--- a/tools/dom/new_scripts/compiler.py
+++ b/tools/dom/new_scripts/compiler.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (C) 2014 Google Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
diff --git a/tools/dom/new_scripts/dart_compiler.py b/tools/dom/new_scripts/dart_compiler.py
index 5dd2b34..5a17629 100755
--- a/tools/dom/new_scripts/dart_compiler.py
+++ b/tools/dom/new_scripts/dart_compiler.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (C) 2013 Google Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
diff --git a/tools/dom/scripts/all_tests.py b/tools/dom/scripts/all_tests.py
index 40a5a49..f0e30ce 100755
--- a/tools/dom/scripts/all_tests.py
+++ b/tools/dom/scripts/all_tests.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2011, 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.
diff --git a/tools/dom/scripts/css_code_generator.py b/tools/dom/scripts/css_code_generator.py
index 9b5ccc5..717630b 100644
--- a/tools/dom/scripts/css_code_generator.py
+++ b/tools/dom/scripts/css_code_generator.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
#
# Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
diff --git a/tools/dom/scripts/dartdomgenerator.py b/tools/dom/scripts/dartdomgenerator.py
index bf2662d..6e529a4 100755
--- a/tools/dom/scripts/dartdomgenerator.py
+++ b/tools/dom/scripts/dartdomgenerator.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2011, 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.
@@ -96,8 +96,8 @@
update_dom_metadata=False,
logging_level=logging.WARNING,
dart_js_interop=False):
- print '\n ----- Accessing DOM using %s -----\n' % (
- 'dart:js' if dart_js_interop else 'C++')
+ print('\n ----- Accessing DOM using %s -----\n' %
+ ('dart:js' if dart_js_interop else 'C++'))
start_time = time.time()
@@ -130,8 +130,8 @@
renamer = HtmlRenamer(webkit_database, metadata)
type_registry = TypeRegistry(webkit_database, renamer)
- print 'GenerateFromDatabase %s seconds' % round(
- (time.time() - start_time), 2)
+ print('GenerateFromDatabase %s seconds' % round(
+ (time.time() - start_time), 2))
def RunGenerator(dart_libraries, dart_output_dir, template_loader,
backend_factory, dart_js_interop):
@@ -178,14 +178,14 @@
if file.endswith('darttemplate'):
dart_libraries._libraries['html'].AddFile(file)
- print '\nGenerating dart2js:\n'
+ print('\nGenerating dart2js:\n')
start_time = time.time()
RunGenerator(dart_libraries, dart_output_dir, template_loader,
backend_factory, dart_js_interop)
- print 'Generated dart2js in %s seconds' % round(
- time.time() - start_time, 2)
+ print('Generated dart2js in %s seconds' %
+ round(time.time() - start_time, 2))
emitters.Flush()
@@ -351,13 +351,13 @@
source, os.path.join('..', '..', '..', 'sdk', 'lib',
library_name, 'dart2js'))
- print '\nGenerating single file %s seconds' % round(
- time.time() - file_generation_start_time, 2)
+ print('\nGenerating single file %s seconds' %
+ round(time.time() - file_generation_start_time, 2))
end_time = time.time()
- print '\nDone (dartdomgenerator) %s seconds' % round(
- end_time - start_time, 2)
+ print('\nDone (dartdomgenerator) %s seconds' %
+ round(end_time - start_time, 2))
if __name__ == '__main__':
diff --git a/tools/dom/scripts/dartgenerator.py b/tools/dom/scripts/dartgenerator.py
index eb5674e..ceb213e 100755
--- a/tools/dom/scripts/dartgenerator.py
+++ b/tools/dom/scripts/dartgenerator.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2012, 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.
diff --git a/tools/dom/scripts/dartgenerator_test.py b/tools/dom/scripts/dartgenerator_test.py
index cfd7b2e..818d66e 100755
--- a/tools/dom/scripts/dartgenerator_test.py
+++ b/tools/dom/scripts/dartgenerator_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2012, 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.
diff --git a/tools/dom/scripts/dartmetadata.py b/tools/dom/scripts/dartmetadata.py
index 71f7602..4909c41 100644
--- a/tools/dom/scripts/dartmetadata.py
+++ b/tools/dom/scripts/dartmetadata.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2012, 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.
diff --git a/tools/dom/scripts/database.py b/tools/dom/scripts/database.py
index 2ec7589..75d8d2e 100755
--- a/tools/dom/scripts/database.py
+++ b/tools/dom/scripts/database.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2011, 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.
@@ -306,7 +306,7 @@
if type_def_name in self._all_type_defs:
raise RuntimeError('Typedef %s already exists' % type_def_name)
self._all_type_defs[type_def_name] = type_def
- print ' Added typedef %s' % type_def_name
+ print(' Added typedef %s' % type_def_name)
def TransitiveSecondaryParents(self, interface, propagate_event_target):
"""Returns a list of all non-primary parents.
diff --git a/tools/dom/scripts/database_test.py b/tools/dom/scripts/database_test.py
index 85c6e3e..a82ed24 100755
--- a/tools/dom/scripts/database_test.py
+++ b/tools/dom/scripts/database_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2011, 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.
diff --git a/tools/dom/scripts/databasebuilder.py b/tools/dom/scripts/databasebuilder.py
index e768ee4..c5327a7 100755
--- a/tools/dom/scripts/databasebuilder.py
+++ b/tools/dom/scripts/databasebuilder.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2011, 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.
@@ -92,11 +92,11 @@
idl_definition = build.idl_compiler.compile_file(idl_file_fullpath)
return idl_definition
except Exception as err:
- print 'ERROR: idl_compiler.py: ' + os.path.basename(file_name)
- print err
- print
- print 'Stack Dump:'
- print format_exception(err)
+ print('ERROR: idl_compiler.py: ' + os.path.basename(file_name))
+ print(err)
+ print()
+ print('Stack Dump:')
+ print(format_exception(err))
return 1
@@ -110,11 +110,11 @@
idl_definition = new_asts[name]
return IDLFile(idl_definition, file_name)
except Exception as err:
- print 'ERROR: loading AST from cache: ' + os.path.basename(file_name)
- print err
- print
- print 'Stack Dump:'
- print format_exception(err)
+ print('ERROR: loading AST from cache: ' + os.path.basename(file_name))
+ print(err)
+ print()
+ print('Stack Dump:')
+ print(format_exception(err))
return 1
@@ -159,11 +159,11 @@
idl_file_fullpath = os.path.realpath(idl_file)
self.idl_compiler.compile_file(idl_file_fullpath)
except Exception as err:
- print 'ERROR: idl_compiler.py: ' + os.path.basename(idl_file)
- print err
- print
- print 'Stack Dump:'
- print self.format_exception(err)
+ print('ERROR: idl_compiler.py: ' + os.path.basename(idl_file))
+ print(err)
+ print()
+ print('Stack Dump:')
+ print(self.format_exception(err))
return 1
@@ -593,8 +593,8 @@
self._info_collector.collect_info(file_path)
end_time = time.time()
- print 'Compute dependencies %s seconds' % round(
- (end_time - start_time), 2)
+ print('Compute dependencies %s seconds' % round(
+ (end_time - start_time), 2))
else:
# Compute the interface_info for dart.idl for implements defined. This
# file is special in that more than one interface can exist in this file.
@@ -614,14 +614,14 @@
os.path.splitext(os.path.basename(file_path))[0], ast)
end_time = time.time()
- print 'Compiled %s IDL files in %s seconds' % (
- len(file_paths), round((end_time - start_time), 2))
+ print('Compiled %s IDL files in %s seconds' %
+ (len(file_paths), round((end_time - start_time), 2)))
def _process_ast(self, filename, ast):
if len(ast) == 1:
ast = ast.values()[0]
else:
- print 'ERROR: Processing AST: ' + os.path.basename(file_name)
+ print('ERROR: Processing AST: ' + os.path.basename(file_name))
new_asts[filename] = ast
def import_idl_files(self, file_paths, import_options, is_dart_idl):
@@ -642,8 +642,8 @@
for warning in report_unions_to_any():
_logger.warning(warning)
- print 'Total %s files %sprocessed in databasebuilder in %s seconds' % \
- (len(file_paths), '', round((end_time - start_time), 2))
+ print('Total %s files %sprocessed in databasebuilder in %s seconds' % \
+ (len(file_paths), '', round((end_time - start_time), 2)))
def _process_idl_file(self, idl_file, import_options, dart_idl=False):
# TODO(terry): strip_ext_attributes on an idl_file does nothing.
@@ -862,27 +862,30 @@
# Report all interface marked with NoInterfaceObject and their usage.
self._output_examination(check_dictionaries=False)
- print '\nKey:'
- print ' (READ-ONLY) - read-only attribute has relationship'
- print ' (GET/SET) - attribute has relationship'
- print ' RETURN - operation\'s returned value has relationship'
- print ' (ARGUMENT) - operation\'s argument(s) has relationship'
- print ''
- print ' (New) - After dictionary name if constructor(s) exist'
- print ' (Ops,Props,New) after a NoInterfaceObject name is defined as:'
- print ' Ops - number of operations for a NoInterfaceObject'
- print ' Props - number of properties for a NoInterfaceObject'
- print ' New - T(#) number constructors for a NoInterfaceObject'
- print ' F no constructors for a NoInterfaceObject'
- print ' e.g., an interface 5 operations, 3 properties and 2'
- print ' constructors would display (5,3,T(2))'
+ print('''
+Key:
+ (READ-ONLY) - read-only attribute has relationship
+ (GET/SET) - attribute has relationship
+ RETURN - operation\'s returned value has relationship
+ (ARGUMENT) - operation\'s argument(s) has relationship
- print '\n\nExamination Complete\n'
+ (New) - After dictionary name if constructor(s) exist
+ (Ops,Props,New) after a NoInterfaceObject name is defined as:
+ Ops - number of operations for a NoInterfaceObject
+ Props - number of properties for a NoInterfaceObject
+ New - T(#) number constructors for a NoInterfaceObject
+ F no constructors for a NoInterfaceObject
+ e.g., an interface 5 operations, 3 properties and 2
+ constructors would display (5,3,T(2))
+
+
+Examination Complete
+''')
def _output_examination(self, check_dictionaries=True):
# Output diagnostics. First columns is Dictionary or NoInterfaceObject e.g.,
# | Dictionary | Used In Interface | Usage Operation/Attribute |
- print '\n\n'
+ print('\n\n')
title_bar = ['Dictionary', 'Used In Interface', 'Usage Operation/Attribute'] if check_dictionaries \
else ['NoInterfaceObject (Ops,Props,New)', 'Used In Interface', 'Usage Operation/Attribute']
self._tabulate_title(title_bar)
@@ -993,7 +996,8 @@
return
# If we get to this point, the IDL dictionary was never defined ... oops.
- print 'DIAGNOSE_ERROR: IDL Dictionary %s doesn\'t exist.' % dictionary_id
+ print('DIAGNOSE_ERROR: IDL Dictionary %s doesn\'t exist.' %
+ dictionary_id)
# Iterator function to look for any IDLType that is an interface marked with
# NoInterfaceObject then remember that interface.
diff --git a/tools/dom/scripts/databasebuilder_test.py b/tools/dom/scripts/databasebuilder_test.py
index c1132a1..7467b3e 100755
--- a/tools/dom/scripts/databasebuilder_test.py
+++ b/tools/dom/scripts/databasebuilder_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2011, 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.
diff --git a/tools/dom/scripts/emitter.py b/tools/dom/scripts/emitter.py
index 7d45fbe..21f4a17 100755
--- a/tools/dom/scripts/emitter.py
+++ b/tools/dom/scripts/emitter.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2011, 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.
diff --git a/tools/dom/scripts/emitter_test.py b/tools/dom/scripts/emitter_test.py
index f1d168e..eb50c2a 100755
--- a/tools/dom/scripts/emitter_test.py
+++ b/tools/dom/scripts/emitter_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2011, 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.
diff --git a/tools/dom/scripts/fremontcutbuilder.py b/tools/dom/scripts/fremontcutbuilder.py
index a9ce07c..bd5fcad 100755
--- a/tools/dom/scripts/fremontcutbuilder.py
+++ b/tools/dom/scripts/fremontcutbuilder.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2011, 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.
@@ -155,7 +155,7 @@
sorted(unknown_conditionals))
_logger.warning('Please update fremontcutbuilder.py')
- print 'Merging interfaces %s seconds' % round(time.time() - start_time, 2)
+ print('Merging interfaces %s seconds' % round(time.time() - start_time, 2))
return db
diff --git a/tools/dom/scripts/generate_blink_file.py b/tools/dom/scripts/generate_blink_file.py
index 6414f7a..4e9c2a4 100644
--- a/tools/dom/scripts/generate_blink_file.py
+++ b/tools/dom/scripts/generate_blink_file.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
#
# Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
@@ -199,7 +199,7 @@
bool TRACK_STATS = true;
dumpStats() {
print("------------ STATS ----------------");
- print(Blink_JsNative_DomException.getPropertyStats.toString());
+ print(Blink_JsNative_DomException.getPropertyStats.toString());
print(Blink_JsNative_DomException.setPropertyStats.toString());
print(Blink_JsNative_DomException.callMethodStats.toString());
print(Blink_JsNative_DomException.constructorStats.toString());
@@ -209,8 +209,8 @@
clearStats() {
Blink_JsNative_DomException.getPropertyStats.clear();
Blink_JsNative_DomException.setPropertyStats.clear();
- Blink_JsNative_DomException.callMethodStats.clear();
- Blink_JsNative_DomException.constructorStats.clear();
+ Blink_JsNative_DomException.callMethodStats.clear();
+ Blink_JsNative_DomException.constructorStats.clear();
}
class Blink_JsNative_DomException {
@@ -388,7 +388,7 @@
def ConstantOutputOrder(a, b):
"""Canonical output ordering for constants."""
- return cmp(a.id, b.id)
+ return (a.id > b.id) - (a.id < b.id)
def generate_parameter_entries(param_infos):
@@ -617,8 +617,8 @@
Select_Stub(OPERATION_2, is_native) % (name, interface.id,
name))
else:
- print "FATAL ERROR: _blink emitter operator %s.%s" % (
- interface.id, name)
+ print("FATAL ERROR: _blink emitter operator %s.%s" %
+ (interface.id, name))
exit
return
diff --git a/tools/dom/scripts/generator.py b/tools/dom/scripts/generator.py
index 9f64192..0a07e20 100644
--- a/tools/dom/scripts/generator.py
+++ b/tools/dom/scripts/generator.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2012, 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.
@@ -937,7 +937,7 @@
def ConstantOutputOrder(a, b):
"""Canonical output ordering for constants."""
- return cmp(a.id, b.id)
+ return (a.id > b.id) - (a.id < b.id)
def _FormatNameList(names):
@@ -2098,7 +2098,8 @@
# It's a typedef (implied union)
return self.TypeInfo('any')
else:
- print "ERROR: Unexpected interface, or type not found. %s" % type_name
+ print("ERROR: Unexpected interface, or type not found. %s" %
+ type_name)
if 'Callback' in interface.ext_attrs:
return CallbackIDLTypeInfo(
diff --git a/tools/dom/scripts/htmldartgenerator.py b/tools/dom/scripts/htmldartgenerator.py
index 08c65a8..7891aa3 100644
--- a/tools/dom/scripts/htmldartgenerator.py
+++ b/tools/dom/scripts/htmldartgenerator.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2012, 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.
@@ -760,8 +760,9 @@
if not (param_list.endswith(', mapArg') or
param_list.endswith(', options') or
param_list == mapArg):
- print "ERROR: %s.%s - Last parameter or only parameter %s is not of type Map" % (
- self._interface.id, html_name, mapArg)
+ print(
+ "ERROR: %s.%s - Last parameter or only parameter %s is not of type Map"
+ % (self._interface.id, html_name, mapArg))
param_list = '%s_dict' % param_list
if mapArgOptional:
diff --git a/tools/dom/scripts/htmleventgenerator.py b/tools/dom/scripts/htmleventgenerator.py
index fcad117..d614e88 100644
--- a/tools/dom/scripts/htmleventgenerator.py
+++ b/tools/dom/scripts/htmleventgenerator.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2012, 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.
diff --git a/tools/dom/scripts/htmlrenamer.py b/tools/dom/scripts/htmlrenamer.py
index 014e811..96cdf8a 100644
--- a/tools/dom/scripts/htmlrenamer.py
+++ b/tools/dom/scripts/htmlrenamer.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2012, 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.
diff --git a/tools/dom/scripts/idlnode.py b/tools/dom/scripts/idlnode.py
index 4518982..40e86e5 100644
--- a/tools/dom/scripts/idlnode.py
+++ b/tools/dom/scripts/idlnode.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2011, 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.
@@ -81,7 +81,7 @@
('%s %s' % (self.id, extras)).strip(),
hash(self))
return '<%s %s 0x%x>' % (type(self).__name__, extras, hash(self))
- except Exception, e:
+ except Exception as e:
return "can't convert to string: %s" % e
def _extra_repr(self):
@@ -264,7 +264,7 @@
}
result = label_field.get(label)
if result != '' and not (result):
- print 'FATAL ERROR: AST mapping name not found %s.' % label
+ print('FATAL ERROR: AST mapping name not found %s.' % label)
return result if result else ''
def _convert_all(self, ast, label, idlnode_ctor):
@@ -708,7 +708,7 @@
# should consider synthesizing a new interface (e.g., UnionType) that's
# both Type1 and Type2.
if not self.id:
- print '>>>> __module__ %s' % ast.__module__
+ print('>>>> __module__ %s' % ast.__module__)
raise SyntaxError('Could not parse type %s' % (ast))
def _label_to_type(self, label, ast):
diff --git a/tools/dom/scripts/idlnode_test.py b/tools/dom/scripts/idlnode_test.py
index 8c21546..61de65a 100755
--- a/tools/dom/scripts/idlnode_test.py
+++ b/tools/dom/scripts/idlnode_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2011, 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.
diff --git a/tools/dom/scripts/idlrenderer.py b/tools/dom/scripts/idlrenderer.py
index 40edc3d..ba095dd 100755
--- a/tools/dom/scripts/idlrenderer.py
+++ b/tools/dom/scripts/idlrenderer.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2011, 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.
diff --git a/tools/dom/scripts/idlrenderer_test.py b/tools/dom/scripts/idlrenderer_test.py
index dd057c2..000ef2a 100755
--- a/tools/dom/scripts/idlrenderer_test.py
+++ b/tools/dom/scripts/idlrenderer_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2011, 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.
diff --git a/tools/dom/scripts/idlsync.py b/tools/dom/scripts/idlsync.py
index 4402849..f95c0b9 100755
--- a/tools/dom/scripts/idlsync.py
+++ b/tools/dom/scripts/idlsync.py
@@ -10,14 +10,14 @@
#
# To update all *.idl, *.py, LICENSE files, and IDLExtendedAttributes.txt:
# > cd sdk
-# > python tools/dom/scripts/idlsync.py
+# > python3 tools/dom/scripts/idlsync.py
#
# Display blink files to delete, copy, update, and collisions to review:
-# > python tools/dom/scripts/idlsync.py --check
+# > python3 tools/dom/scripts/idlsync.py --check
#
# Bring over all blink files to dart/third_party/WebCore (*.py, *.idl, and
# IDLExtendedAttributes.txt):
-# > python tools/dom/scripts/idlsync.py
+# > python3 tools/dom/scripts/idlsync.py
#
# Update the DEPS file SHA for "WebCore_rev" with the committed changes of files
# in WebCore e.g., "WebCore_rev": "@NNNNNNNNNNNNNNNNNNNNNNNNN"
@@ -117,14 +117,14 @@
def RunCommand(cmd, valid_exits=[0]):
"""Executes a shell command and return its stdout."""
if isVerbose():
- print ' '.join(cmd)
+ print(' '.join(cmd))
pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output = pipe.communicate()
if pipe.returncode in valid_exits:
return output[0]
else:
- print output[1]
- print 'FAILED. RET_CODE=%d' % pipe.returncode
+ print(output[1])
+ print('FAILED. RET_CODE=%d' % pipe.returncode)
sys.exit(pipe.returncode)
@@ -298,7 +298,8 @@
remotes_list[1] == GIT_REMOTES_CHROMIUM):
return True
- print 'ERROR: Unable to find dart/dartium/src repository %s' % GIT_REMOTES_CHROMIUM
+ print('ERROR: Unable to find dart/dartium/src repository %s' %
+ GIT_REMOTES_CHROMIUM)
return False
@@ -348,25 +349,25 @@
# Get the SHA for the Chromium/WebKit changes for Dartium.
#revision = url[len(url_base):]
revision = foundIt.group(1)[1:]
- print '%s' % revision
+ print('%s' % revision)
return revision
def copy_subdir(src, src_prefix, dest, subdir):
idls_deleted = remove_obsolete_webcore_files(dest, src, subdir)
- print "%s files removed in WebCore %s" % (idls_deleted.__len__(), subdir)
+ print("%s files removed in WebCore %s" % (idls_deleted.__len__(), subdir))
if isVerbose():
for delete_file in idls_deleted:
- print " %s" % delete_file
+ print(" %s" % delete_file)
idls_copied, py_copied, other_copied = copy_files(
os.path.join(src, subdir), src_prefix, dest)
if idls_copied > 0:
- print "Copied %s IDLs to %s" % (idls_copied, subdir)
+ print("Copied %s IDLs to %s" % (idls_copied, subdir))
if py_copied > 0:
- print "Copied %s PYs to %s" % (py_copied, subdir)
+ print("Copied %s PYs to %s" % (py_copied, subdir))
if other_copied > 0:
- print "Copied %s other to %s\n" % (other_copied, subdir)
+ print("Copied %s other to %s\n" % (other_copied, subdir))
def main():
@@ -375,7 +376,8 @@
current_dir = os.path.dirname(os.path.abspath(__file__))
if not current_dir.endswith(SOURCE_FILE_DIR):
- print 'ERROR: idlsync.py not run in proper directory (%s)\n', current_dir
+ print('ERROR: idlsync.py not run in proper directory (%s)\n',
+ current_dir)
base_directory = current_dir[:current_dir.rfind(SOURCE_FILE_DIR)]
@@ -384,8 +386,8 @@
webcore_revision = GetDEPSWebCoreGitRevision(deps, 'webkit')
chromium_sha = getChromiumSHA()
if webcore_revision == chromium_sha:
- print "ERROR: Nothing to update in WebCore, WebCore_rev SHA in DEPS " \
- "matches Chromium GIT master SHA in %s" % options['webkit_dir']
+ print("ERROR: Nothing to update in WebCore, WebCore_rev SHA in DEPS "
+ "matches Chromium GIT master SHA in %s" % options['webkit_dir'])
return
start_time = time.time()
@@ -417,12 +419,14 @@
end_time = time.time()
- print 'WARNING: File(s) contain FIXMEDART and are NOT "git add " please review:'
+ print(
+ 'WARNING: File(s) contain FIXMEDART and are NOT "git add " please review:'
+ )
for warning in warning_messages:
- print ' %s' % warning
+ print(' %s' % warning)
- print '\nDone idlsync completed in %s seconds' % round(
- end_time - start_time, 2)
+ print('\nDone idlsync completed in %s seconds' %
+ round(end_time - start_time, 2))
if __name__ == '__main__':
diff --git a/tools/dom/scripts/mdnreader.py b/tools/dom/scripts/mdnreader.py
index 9fe43a3..b142b7a 100644
--- a/tools/dom/scripts/mdnreader.py
+++ b/tools/dom/scripts/mdnreader.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
diff --git a/tools/dom/scripts/monitored.py b/tools/dom/scripts/monitored.py
index 55d4e11..1b3babe 100644
--- a/tools/dom/scripts/monitored.py
+++ b/tools/dom/scripts/monitored.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2013, 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.
diff --git a/tools/dom/scripts/multiemitter.py b/tools/dom/scripts/multiemitter.py
index 64a8b2d..a897a16 100644
--- a/tools/dom/scripts/multiemitter.py
+++ b/tools/dom/scripts/multiemitter.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2011, 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.
diff --git a/tools/dom/scripts/multiemitter_test.py b/tools/dom/scripts/multiemitter_test.py
index 0b114a5..17c360d 100644
--- a/tools/dom/scripts/multiemitter_test.py
+++ b/tools/dom/scripts/multiemitter_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2011, 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.
diff --git a/tools/dom/scripts/systemhtml.py b/tools/dom/scripts/systemhtml.py
index 3b35750..5749cd9 100644
--- a/tools/dom/scripts/systemhtml.py
+++ b/tools/dom/scripts/systemhtml.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2012, 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.
@@ -2024,7 +2024,9 @@
-
1]
else:
- print "ERROR: Arguments exceede 20 - please fix Python code to handle more."
+ print(
+ "ERROR: Arguments exceede 20 - please fix Python code to handle more."
+ )
self._members_emitter.Emit(
' $RENAME$METADATA$MODIFIERS$TYPE$TARGET($PARAMS) =>\n'
' promiseToFuture(JS("", "#.$JSNAME($HASH_STR)", this$CALLING_PARAMS));\n',
diff --git a/tools/dom/scripts/systemnative.py b/tools/dom/scripts/systemnative.py
index 296bd67..2c2ab7c 100644
--- a/tools/dom/scripts/systemnative.py
+++ b/tools/dom/scripts/systemnative.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2012, 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.
diff --git a/tools/dom/scripts/templateloader.py b/tools/dom/scripts/templateloader.py
index fcbebe8..7e69a8e 100644
--- a/tools/dom/scripts/templateloader.py
+++ b/tools/dom/scripts/templateloader.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2011, 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.
diff --git a/tools/dom/scripts/templateloader_test.py b/tools/dom/scripts/templateloader_test.py
index edcd759..4b16df7 100755
--- a/tools/dom/scripts/templateloader_test.py
+++ b/tools/dom/scripts/templateloader_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
# Copyright (c) 2011, 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.
diff --git a/tools/find_depot_tools.py b/tools/find_depot_tools.py
index ed06c94..413a12f 100644
--- a/tools/find_depot_tools.py
+++ b/tools/find_depot_tools.py
@@ -6,10 +6,11 @@
imports breakpad.
"""
+from __future__ import print_function
+
import os
import sys
-
def IsRealDepotTools(path):
return os.path.isfile(os.path.join(path, 'gclient.py'))
@@ -35,7 +36,7 @@
return i
previous_dir = root_dir
root_dir = os.path.dirname(root_dir)
- print >> sys.stderr, 'Failed to find depot_tools'
+ print('Failed to find depot_tools', file=sys.stderr)
return None
diff --git a/tools/fuchsia/find_resources.py b/tools/fuchsia/find_resources.py
index 9d38053..f8b0518 100755
--- a/tools/fuchsia/find_resources.py
+++ b/tools/fuchsia/find_resources.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
# Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
@@ -24,34 +24,37 @@
def listFiles(path):
- allFiles = []
- for dirpath, dirs, files in os.walk(join(DART_DIR, path)):
- allFiles += [relpath(abspath(join(dirpath, p)), DART_DIR) for p in files]
- return allFiles
+ allFiles = []
+ for dirpath, dirs, files in os.walk(join(DART_DIR, path)):
+ allFiles += [
+ relpath(abspath(join(dirpath, p)), DART_DIR) for p in files
+ ]
+ return allFiles
def printOutput(files):
- print('[')
- print(',\n'.join([
- ' {\n "path": "%s",\n "dest": "data/%s"\n }' % (f, f) for f in files
- ]))
- print(']')
+ print('[')
+ print(',\n'.join([
+ ' {\n "path": "%s",\n "dest": "data/%s"\n }' % (f, f)
+ for f in files
+ ]))
+ print(']')
def main():
- if len(sys.argv) < 2:
- print('Expected at least 1 arg, the paths to search.')
- return 1
- allFiles = []
- for directory in sys.argv[1:]:
- files = listFiles(directory)
- if len(files) == 0:
- print('Did not find any files in the directory: ' + directory)
- return 2
- allFiles += files
- printOutput(sorted(allFiles))
- return 0
+ if len(sys.argv) < 2:
+ print('Expected at least 1 arg, the paths to search.')
+ return 1
+ allFiles = []
+ for directory in sys.argv[1:]:
+ files = listFiles(directory)
+ if len(files) == 0:
+ print('Did not find any files in the directory: ' + directory)
+ return 2
+ allFiles += files
+ printOutput(sorted(allFiles))
+ return 0
if __name__ == '__main__':
- sys.exit(main())
+ sys.exit(main())
diff --git a/tools/gen_fuchsia_test_manifest.py b/tools/gen_fuchsia_test_manifest.py
index fa754b5..d521e36 100755
--- a/tools/gen_fuchsia_test_manifest.py
+++ b/tools/gen_fuchsia_test_manifest.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright 2017 The Dart project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
diff --git a/tools/generate_buildfiles.py b/tools/generate_buildfiles.py
index 1de6936..693de54 100755
--- a/tools/generate_buildfiles.py
+++ b/tools/generate_buildfiles.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright 2016 The Dart project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
@@ -29,7 +29,7 @@
if not HOST_OS in ['linux', 'macos']:
return 0
gn_command = [
- 'python',
+ 'python3',
os.path.join(DART_ROOT, 'tools', 'gn.py'),
'-m',
'all',
@@ -48,7 +48,7 @@
if HOST_OS != 'linux':
return 0
gn_command = [
- 'python',
+ 'python3',
os.path.join(DART_ROOT, 'tools', 'gn.py'),
'-m',
'all',
@@ -63,7 +63,7 @@
def RunHostGn(options):
gn_command = [
- 'python',
+ 'python3',
os.path.join(DART_ROOT, 'tools', 'gn.py'),
'-m',
'all',
diff --git a/tools/generate_idefiles.py b/tools/generate_idefiles.py
index d84bcb2..7809c64 100755
--- a/tools/generate_idefiles.py
+++ b/tools/generate_idefiles.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
#
# 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
@@ -42,7 +42,7 @@
fname = os.path.join(options.dir, "compile_commands.json")
if os.path.isfile(fname) and not options.force:
- print fname + " already exists, use --force to override"
+ print(fname + " already exists, use --force to override")
return
gn_result = generate_buildfiles.RunGn(options)
@@ -132,7 +132,7 @@
fname = os.path.join(options.dir, "analysis_options.yaml")
if os.path.isfile(fname) and not options.force:
- print fname + " already exists, use --force to override"
+ print(fname + " already exists, use --force to override")
return
with open(fname, "w") as f:
diff --git a/tools/get_dot_git_folder.py b/tools/get_dot_git_folder.py
index 443addbf..482616c 100755
--- a/tools/get_dot_git_folder.py
+++ b/tools/get_dot_git_folder.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
@@ -8,7 +8,6 @@
import sys
import subprocess
-import os
import utils
@@ -24,13 +23,15 @@
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
stdin=subprocess.PIPE,
- shell=True)
+ shell=True,
+ universal_newlines=True)
else:
process = subprocess.Popen(args,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
stdin=subprocess.PIPE,
- shell=False)
+ shell=False,
+ universal_newlines=True)
outs, _ = process.communicate()
diff --git a/tools/gn.py b/tools/gn.py
index 6f2b0c1..dc355cf 100755
--- a/tools/gn.py
+++ b/tools/gn.py
@@ -1,11 +1,10 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright 2016 The Dart project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import argparse
import os
-import shutil
import subprocess
import sys
import time
@@ -64,7 +63,7 @@
return '%s=%d' % (key, value)
return '%s="%s"' % (key, value)
- return [merge(x, y) for x, y in gn_args.iteritems()]
+ return [merge(x, y) for x, y in gn_args.items()]
def HostCpuForArch(arch):
diff --git a/tools/linux_dist_support/debian/control b/tools/linux_dist_support/debian/control
index 04484ab..2043c95 100644
--- a/tools/linux_dist_support/debian/control
+++ b/tools/linux_dist_support/debian/control
@@ -4,7 +4,7 @@
Priority: optional
Standards-Version: 3.9.2
Build-Depends: debhelper (>= 9),
- python,
+ python3,
Package: dart
Architecture: amd64
diff --git a/tools/linux_dist_support/debian/rules b/tools/linux_dist_support/debian/rules
index da3ff23..1ccacf5 100755
--- a/tools/linux_dist_support/debian/rules
+++ b/tools/linux_dist_support/debian/rules
@@ -53,11 +53,11 @@
find . -name *.Makefile -execdir rm -f {} \;
override_dh_auto_configure:
- python dart/tools/generate_buildfiles.py
+ python3 dart/tools/generate_buildfiles.py
override_dh_auto_build:
cd dart; \
- python tools/build.py -v -m release -a $(ARCH) $(TOOLCHAIN) create_sdk; \
+ python3 tools/build.py -v -m release -a $(ARCH) $(TOOLCHAIN) create_sdk; \
cd ..
# Building the Dart SDK will already strip all binaries.
diff --git a/tools/list_dart_files.py b/tools/list_dart_files.py
index cc131de..ec9da09 100755
--- a/tools/list_dart_files.py
+++ b/tools/list_dart_files.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# 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.
@@ -9,7 +9,7 @@
produces absolute paths.
Usage:
- python tools/list_dart_files.py {absolute, relative} <directory> <pattern>
+ python3 tools/list_dart_files.py {absolute, relative} <directory> <pattern>
"""
import os
@@ -48,7 +48,7 @@
else:
fullname = os.path.relpath(os.path.join(root, filename))
fullname = fullname.replace(os.sep, '/')
- print (fullname)
+ print(fullname)
if __name__ == '__main__':
diff --git a/tools/make_version.py b/tools/make_version.py
index 0e6e8be..c99511b 100755
--- a/tools/make_version.py
+++ b/tools/make_version.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright (c) 2011, 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.
@@ -11,7 +11,6 @@
import hashlib
import os
import sys
-import time
import utils
# When these files change, snapshots created by the VM are potentially no longer
@@ -85,7 +84,7 @@
version_time = utils.GetGitTimestamp()
if version_time == None:
version_time = 'Unknown timestamp'
- version = version.replace('{{COMMIT_TIME}}', version_time.decode('utf-8'))
+ version = version.replace('{{COMMIT_TIME}}', version_time)
snapshot_hash = MakeSnapshotHashString()
version = version.replace('{{SNAPSHOT_HASH}}', snapshot_hash)
diff --git a/tools/patches/flutter-engine/apply.sh b/tools/patches/flutter-engine/apply.sh
index 91918a1..b5b7e0c5 100755
--- a/tools/patches/flutter-engine/apply.sh
+++ b/tools/patches/flutter-engine/apply.sh
@@ -57,7 +57,7 @@
# referencing.
# Normally gclient sync would update the cache - but we are bypassing
# it here.
- git_cache=$(python -c 'import imp; config = imp.load_source("config", ".gclient"); print getattr(config, "cache_dir", "")')
+ git_cache=$(python3 -c 'import imp; config = imp.load_source("config", ".gclient"); print(getattr(config, "cache_dir", ""))')
# DEPS file might have been patched with new version of packages that
# Dart SDK depends on. Get information about dependencies from the
diff --git a/tools/promote.py b/tools/promote.py
old mode 100644
new mode 100755
index 7b57fb3..966b735
--- a/tools/promote.py
+++ b/tools/promote.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
# Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
@@ -6,10 +6,8 @@
# Dart SDK promote tools.
-import imp
import optparse
import os
-import subprocess
import sys
import time
import urllib
@@ -28,7 +26,7 @@
locations.
Example: Promote version 2.5.0 on the stable channel:
- python editor/build/promote.py promote --channel=stable --version=2.5.0
+ python3 tools/promote.py promote --channel=stable --version=2.5.0
"""
result = optparse.OptionParser(usage=usage)
@@ -64,7 +62,7 @@
(options, args) = parser.parse_args()
def die(msg):
- print msg
+ print(msg)
parser.print_help()
sys.exit(1)
@@ -97,14 +95,14 @@
def UpdateDocs():
try:
- print 'Updating docs'
+ print('Updating docs')
url = 'http://api.dartlang.org/docs/releases/latest/?force_reload=true'
f = urllib.urlopen(url)
f.read()
- print 'Successfully updated api docs'
+ print('Successfully updated api docs')
except Exception as e:
- print 'Could not update api docs, please manually update them'
- print 'Failed with: %s' % e
+ print('Could not update api docs, please manually update them')
+ print('Failed with: %s' % e)
def _PromoteDartArchiveBuild(channel, source_channel, revision):
@@ -187,7 +185,7 @@
gsutilTool = join(DART_PATH, 'third_party', 'gsutil', 'gsutil')
command = [sys.executable, gsutilTool] + cmd
if DRY_RUN:
- print 'DRY runnning: %s' % command
+ print('DRY runnning: %s' % command)
return (None, None, 0)
return bot_utils.run(command, throw_on_error=throw_on_error)
diff --git a/tools/publish_pkg.py b/tools/publish_pkg.py
index 2ecf2ba..6cd50f0 100755
--- a/tools/publish_pkg.py
+++ b/tools/publish_pkg.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
# Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
@@ -25,7 +25,7 @@
pubspec = os.path.join(HOME, argv[1], 'pubspec.yaml')
if not os.path.exists(pubspec):
- print 'Error: did not find pubspec.yaml at ' + pubspec
+ print('Error: did not find pubspec.yaml at ' + pubspec)
return -1
with open(pubspec) as pubspecFile:
@@ -45,16 +45,17 @@
version = line[len('version:'):].strip()
if inDependencies:
if line.endswith(': any'):
- print 'Error in %s: should not use "any" version constraint: %s' % (
- pubspec, line)
+ print(
+ 'Error in %s: should not use "any" version constraint: %s' %
+ (pubspec, line))
return -1
if not version:
- print 'Error in %s: did not find package version.' % pubspec
+ print('Error in %s: did not find package version.' % pubspec)
return -1
if not foundSdkConstraint:
- print 'Error in %s: did not find SDK version constraint.' % pubspec
+ print('Error in %s: did not find SDK version constraint.' % pubspec)
return -1
tmpDir = tempfile.mkdtemp()
@@ -95,7 +96,7 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
''')
- print 'publishing version ' + version + ' of ' + argv[1] + ' to pub.\n'
+ print('publishing version ' + version + ' of ' + argv[1] + ' to pub.\n')
# TODO(jmesserly): this code puts things in the pub cache. Useful for testing
# without actually uploading.
diff --git a/tools/run_debian_build.sh b/tools/run_debian_build.sh
index e0d54a1..6fb1866 100755
--- a/tools/run_debian_build.sh
+++ b/tools/run_debian_build.sh
@@ -6,10 +6,11 @@
ninja=$(which ninja)
depot_tools=$(dirname $ninja)
-cmd="sed -i /jessie-updates/d /etc/apt/sources.list\
- && apt-get update && apt-get -y install build-essential debhelper git python\
- && PATH=\"$depot_tools:\$PATH\"\
- python tools/bots/linux_distribution_support.py"
+cmd="sed -i /jessie-updates/d /etc/apt/sources.list \
+ && apt-get update \
+ && apt-get -y install build-essential debhelper git python3 \
+ && PATH=\"$depot_tools:\$PATH\" \
+ python3 tools/bots/linux_distribution_support.py"
image="launcher.gcr.io/google/debian8:latest"
docker run -e BUILDBOT_BUILDERNAME -v $depot_tools:$depot_tools\
-v `pwd`:`pwd` -w `pwd` -i --rm $image bash -c "$cmd"
diff --git a/tools/spec_parse.py b/tools/spec_parse.py
index 90a97e8..d9238f5 100755
--- a/tools/spec_parse.py
+++ b/tools/spec_parse.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
# 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
diff --git a/tools/spec_parser/Dart.g b/tools/spec_parser/Dart.g
index e13e789..0da4bd2 100644
--- a/tools/spec_parser/Dart.g
+++ b/tools/spec_parser/Dart.g
@@ -360,23 +360,6 @@
| constructorSignature
;
-// https://github.com/dart-lang/sdk/issues/29501 reports on the problem which
-// was solved by adding a case for redirectingFactoryConstructorSignature.
-// TODO(eernst): Close that issue when this is integrated into the spec.
-
-// https://github.com/dart-lang/sdk/issues/29502 reports on the problem that
-// than external const factory constructor declaration cannot be derived by
-// the spec grammar (and also not by this grammar). The following fixes were
-// introduced for that: Added the 'factoryConstructorSignature' case below in
-// 'declaration'; also added 'CONST?' in the 'factoryConstructorSignature'
-// rule, such that const factories in general are allowed.
-// TODO(eernst): Close that issue when this is integrated into the spec.
-
-// TODO(eernst): Note that `EXTERNAL? STATIC? functionSignature` includes
-// `STATIC functionSignature`, but a static function cannot be abstract.
-// We might want to make that a syntax error rather than a static semantic
-// check.
-
declaration
: EXTERNAL factoryConstructorSignature
| EXTERNAL constantConstructorSignature
@@ -901,27 +884,7 @@
identifierNotFUNCTION
: IDENTIFIER
- | ABSTRACT // Built-in identifier.
- | AS // Built-in identifier.
- | COVARIANT // Built-in identifier.
- | DEFERRED // Built-in identifier.
- | DYNAMIC // Built-in identifier.
- | EXPORT // Built-in identifier.
- | EXTERNAL // Built-in identifier.
- | FACTORY // Built-in identifier.
- | GET // Built-in identifier.
- | IMPLEMENTS // Built-in identifier.
- | IMPORT // Built-in identifier.
- | INTERFACE // Built-in identifier.
- | LATE // Built-in identifier.
- | LIBRARY // Built-in identifier.
- | MIXIN // Built-in identifier.
- | OPERATOR // Built-in identifier.
- | PART // Built-in identifier.
- | REQUIRED // Built-in identifier.
- | SET // Built-in identifier.
- | STATIC // Built-in identifier.
- | TYPEDEF // Built-in identifier.
+ | builtInIdentifier
| ASYNC // Not a built-in identifier.
| HIDE // Not a built-in identifier.
| OF // Not a built-in identifier.
@@ -1219,7 +1182,7 @@
;
typeAlias
- : TYPEDEF typeIdentifier typeParameters? '=' functionType ';'
+ : TYPEDEF typeIdentifier typeParameters? '=' type ';'
| TYPEDEF functionTypeAlias
;
@@ -1258,8 +1221,8 @@
;
normalParameterType
- : typedIdentifier
- | type
+ : metadata typedIdentifier
+ | metadata type
;
optionalParameterTypes
@@ -1276,7 +1239,7 @@
;
namedParameterType
- : REQUIRED? typedIdentifier
+ : metadata REQUIRED? typedIdentifier
;
typedIdentifier
@@ -1290,7 +1253,7 @@
;
symbolLiteral
- : '#' (operator | (identifier ('.' identifier)*))
+ : '#' (operator | (identifier ('.' identifier)*) | VOID)
;
// Not used in the specification (needed here for <uri>).
@@ -1324,6 +1287,68 @@
MULTI_LINE_STRING_DQ_MID_END
;
+reservedWord
+ : ASSERT
+ | BREAK
+ | CASE
+ | CATCH
+ | CLASS
+ | CONST
+ | CONTINUE
+ | DEFAULT
+ | DO
+ | ELSE
+ | ENUM
+ | EXTENDS
+ | FALSE
+ | FINAL
+ | FINALLY
+ | FOR
+ | IF
+ | IN
+ | IS
+ | NEW
+ | NULL
+ | RETHROW
+ | RETURN
+ | SUPER
+ | SWITCH
+ | THIS
+ | THROW
+ | TRUE
+ | TRY
+ | VAR
+ | VOID
+ | WHILE
+ | WITH
+ ;
+
+builtInIdentifier
+ : ABSTRACT
+ | AS
+ | COVARIANT
+ | DEFERRED
+ | DYNAMIC
+ | EXPORT
+ | EXTENSION
+ | EXTERNAL
+ | FACTORY
+ | FUNCTION
+ | GET
+ | IMPLEMENTS
+ | IMPORT
+ | INTERFACE
+ | LATE
+ | LIBRARY
+ | OPERATOR
+ | MIXIN
+ | PART
+ | REQUIRED
+ | SET
+ | STATIC
+ | TYPEDEF
+ ;
+
// ---------------------------------------- Lexer rules.
fragment
diff --git a/tools/task_kill.py b/tools/task_kill.py
index 3c36acc..8281475 100755
--- a/tools/task_kill.py
+++ b/tools/task_kill.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
# Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
@@ -105,8 +105,11 @@
# Sample output:
# 1 /sbin/launchd
# 80943 /Applications/Safari.app/Contents/MacOS/Safari
- p = subprocess.Popen(
- cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
+ p = subprocess.Popen(cmd,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ shell=True,
+ universal_newlines=True)
output, stderr = p.communicate()
results = []
lines = output.splitlines()
@@ -123,8 +126,11 @@
cmd = 'tasklist /FI "IMAGENAME eq %s" /NH' % process_name
# Sample output:
# dart.exe 4356 Console 1 6,800 K
- p = subprocess.Popen(
- cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
+ p = subprocess.Popen(cmd,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ shell=True,
+ universal_newlines=True)
output, stderr = p.communicate()
results = []
lines = output.splitlines()
@@ -146,44 +152,44 @@
def PrintPidStackInfo(pid):
command_pattern = STACK_INFO_COMMAND.get(os_name, False)
if command_pattern:
- p = subprocess.Popen(
- command_pattern % pid,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- shell=True)
+ p = subprocess.Popen(command_pattern % pid,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ shell=True,
+ universal_newlines=True)
stdout, stderr = p.communicate()
stdout = stdout.splitlines()
stderr = stderr.splitlines()
- print " Stack:"
+ print(" Stack:")
for line in stdout:
- print " %s" % line
+ print(" %s" % line)
if stderr:
- print " Stack (stderr):"
+ print(" Stack (stderr):")
for line in stderr:
- print " %s" % line
+ print(" %s" % line)
def PrintPidInfo(pid, dump_stacks):
# We assume that the list command will return lines in the format:
# EXECUTABLE_PATH ARGS
# There may be blank strings in the output
- p = subprocess.Popen(
- INFO_COMMAND[os_name] % pid,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- shell=True)
+ p = subprocess.Popen(INFO_COMMAND[os_name] % pid,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ shell=True,
+ universal_newlines=True)
output, stderr = p.communicate()
lines = output.splitlines()
# Pop the header
lines.pop(0)
- print "Hanging process info:"
- print " PID: %s" % pid
+ print("Hanging process info:")
+ print(" PID: %s" % pid)
for line in lines:
# wmic will output a bunch of empty strings, we ignore these
- if line: print " Command line: %s" % line
+ if line: print(" Command line: %s" % line)
if dump_stacks:
PrintPidStackInfo(pid)
@@ -200,8 +206,11 @@
def KillWindows(pid):
# os.kill is not available until python 2.7
cmd = "taskkill /F /PID %s" % pid
- p = subprocess.Popen(
- cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
+ p = subprocess.Popen(cmd,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ shell=True,
+ universal_newlines=True)
p.communicate()
diff --git a/tools/test.py b/tools/test.py
index b106500..3e676fc 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -1,8 +1,9 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright (c) 2011, 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.
+from contextlib import ExitStack
import os
import string
import subprocess
@@ -35,7 +36,9 @@
android_platform_tools)
with utils.FileDescriptorLimitIncreaser():
- with utils.CoreDumpArchiver(args):
+ with ExitStack() as stack:
+ for ctx in utils.CoreDumpArchiver(args):
+ stack.enter_context(ctx)
exit_code = subprocess.call(command)
if cleanup_dart:
diff --git a/tools/utils.py b/tools/utils.py
index dcb68a5..9a0c720 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -192,82 +192,6 @@
return 2
-def GetWindowsRegistryKeyName(name):
- import win32process
- # Check if python process is 64-bit or if it's 32-bit running in 64-bit OS.
- # We need to know whether host is 64-bit so that we are looking in right
- # registry for Visual Studio path.
- if sys.maxsize > 2**32 or win32process.IsWow64Process():
- wow6432Node = 'Wow6432Node\\'
- else:
- wow6432Node = ''
- return r'SOFTWARE\{}{}'.format(wow6432Node, name)
-
-
-# Try to guess Visual Studio location when buiding on Windows.
-def GuessVisualStudioPath():
- defaultPath = r'C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7' \
- r'\IDE'
- defaultExecutable = 'devenv.com'
-
- if not IsWindows():
- return (defaultPath, defaultExecutable)
-
- keyNamesAndExecutables = [
- # Pair for non-Express editions.
- (GetWindowsRegistryKeyName(r'Microsoft\VisualStudio'), 'devenv.com'),
- # Pair for 2012 Express edition.
- (GetWindowsRegistryKeyName(r'Microsoft\VSWinExpress'),
- 'VSWinExpress.exe'),
- # Pair for pre-2012 Express editions.
- (GetWindowsRegistryKeyName(r'Microsoft\VCExpress'), 'VCExpress.exe')
- ]
-
- bestGuess = (0.0, (defaultPath, defaultExecutable))
-
- import _winreg
- for (keyName, executable) in keyNamesAndExecutables:
- try:
- key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, keyName)
- except WindowsError:
- # Can't find this key - moving on the next one.
- continue
-
- try:
- subkeyCounter = 0
- while True:
- try:
- subkeyName = _winreg.EnumKey(key, subkeyCounter)
- subkeyCounter += 1
- except WindowsError:
- # Reached end of enumeration. Moving on the next key.
- break
-
- match = re.match(r'^\d+\.\d+$', subkeyName)
- if match:
- with _winreg.OpenKey(key, subkeyName) as subkey:
- try:
- (installDir, registrytype) = _winreg.QueryValueEx(
- subkey, 'InstallDir')
- except WindowsError:
- # Can't find value under the key - continue to the next key.
- continue
- isExpress = executable != 'devenv.com'
- if not isExpress and subkeyName == '14.0':
- # Stop search since if we found non-Express VS2015 version
- # installed, which is preferred version.
- return installDir, executable
-
- version = float(subkeyName)
- # We prefer higher version of Visual Studio and given equal
- # version numbers we prefer non-Express edition.
- if version > bestGuess[0]:
- bestGuess = (version, (installDir, executable))
- finally:
- _winreg.CloseKey(key)
- return bestGuess[1]
-
-
# Returns true if we're running under Windows.
def IsWindows():
return GuessOS() == 'win32'
@@ -612,22 +536,6 @@
return None
-def Daemonize():
- """
- Create a detached background process (daemon). Returns True for
- the daemon, False for the parent process.
- See: http://www.faqs.org/faqs/unix-faq/programmer/faq/
- "1.7 How do I get my program to act like a daemon?"
- """
- if os.fork() > 0:
- return False
- os.setsid()
- if os.fork() > 0:
- exit(0)
- # TODO: What is this supposed to do? Didn't we already exit?
- raise
- return True
-
def CheckedUnlink(name):
"""Unlink a file without throwing an exception."""
@@ -666,11 +574,6 @@
' '.join(command), exit_code, exit_code & 0xffffffff))
-def Touch(name):
- with file(name, 'a'):
- os.utime(name, None)
-
-
def ExecuteCommand(cmd):
"""Execute a command in a subprocess."""
print('Executing: ' + ' '.join(cmd))
@@ -1206,21 +1109,19 @@
(arg[len(prefix):] for arg in args if arg.startswith(prefix)), None)
if not enabled:
- return NooptContextManager()
+ return (NooptContextManager(),)
osname = GuessOS()
if osname == 'linux':
- return contextlib.nested(LinuxCoreDumpEnabler(),
- LinuxCoreDumpArchiver(output_directory))
+ return (LinuxCoreDumpEnabler(), LinuxCoreDumpArchiver(output_directory))
elif osname == 'macos':
- return contextlib.nested(PosixCoreDumpEnabler(),
- MacOSCoreDumpArchiver(output_directory))
+ return (PosixCoreDumpEnabler(), MacOSCoreDumpArchiver(output_directory))
elif osname == 'win32':
- return contextlib.nested(WindowsCoreDumpEnabler(),
- WindowsCoreDumpArchiver(output_directory))
+ return (WindowsCoreDumpEnabler(),
+ WindowsCoreDumpArchiver(output_directory))
# We don't have support for MacOS yet.
- return NooptContextManager()
+ return (NooptContextManager(),)
def FileDescriptorLimitIncreaser():
@@ -1238,7 +1139,6 @@
print('GuessArchitecture() -> ', GuessArchitecture())
print('GuessCpus() -> ', GuessCpus())
print('IsWindows() -> ', IsWindows())
- print('GuessVisualStudioPath() -> ', GuessVisualStudioPath())
print('GetGitRevision() -> ', GetGitRevision())
print('GetGitTimestamp() -> ', GetGitTimestamp())
print('GetVersionFileContent() -> ', GetVersionFileContent())
diff --git a/tools/write_dartdoc_options_file.py b/tools/write_dartdoc_options_file.py
index b1d23f3..7e6567a 100755
--- a/tools/write_dartdoc_options_file.py
+++ b/tools/write_dartdoc_options_file.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# 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.
diff --git a/tools/write_revision_file.py b/tools/write_revision_file.py
index db85841..3b9dd7d 100755
--- a/tools/write_revision_file.py
+++ b/tools/write_revision_file.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# 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.
diff --git a/tools/write_version_file.py b/tools/write_version_file.py
index 75cbc09..aea586c 100755
--- a/tools/write_version_file.py
+++ b/tools/write_version_file.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# 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.
diff --git a/tools/yaml2json.py b/tools/yaml2json.py
index f9f3519..251f657 100755
--- a/tools/yaml2json.py
+++ b/tools/yaml2json.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# 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.
diff --git a/utils/compiler/create_snapshot_entry.dart b/utils/compiler/create_snapshot_entry.dart
index 5cf11a8..360debe 100644
--- a/utils/compiler/create_snapshot_entry.dart
+++ b/utils/compiler/create_snapshot_entry.dart
@@ -11,7 +11,7 @@
Future<String> getVersion(var rootPath) {
var printVersionScript = rootPath.resolve("tools/make_version.py");
- return Process.run("python", [printVersionScript.toFilePath(), "--quiet"],
+ return Process.run("python3", [printVersionScript.toFilePath(), "--quiet"],
runInShell: true)
.then((result) {
if (result.exitCode != 0) {