Version 2.8.0-dev.3.0
Merge commit 'd302d7f10ad90a7e093f38c17b804127db906ae7' into dev
diff --git a/DEPS b/DEPS
index 7b089e9..55417bd 100644
--- a/DEPS
+++ b/DEPS
@@ -476,7 +476,7 @@
"packages": [
{
"package": "dart/cfe/dart2js_dills",
- "version": "binary_version:29_36",
+ "version": "binary_version:29_37",
}
],
"dep_type": "cipd",
diff --git a/benchmarks/ListCopy/dart/ListCopy.dart b/benchmarks/ListCopy/dart/ListCopy.dart
new file mode 100644
index 0000000..e058928
--- /dev/null
+++ b/benchmarks/ListCopy/dart/ListCopy.dart
@@ -0,0 +1,151 @@
+// 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:collection';
+import 'dart:typed_data';
+import 'package:benchmark_harness/benchmark_harness.dart';
+
+// Benchmark for polymorphic list copying.
+//
+// Each benchmark creates a list from an Iterable. There are many slightly
+// different ways to do this.
+//
+// In each benchmark the call site is polymorphic in the input type to simulate
+// the behaviour of library methods in the context of a large application. The
+// input lists are skewed heavily to the default growable list. This attempts to
+// model 'real world' copying of 'ordinary' lists.
+//
+// The benchmarks are run for small lists (2 elements, names ending in
+// `.2`) and 'large' lists (100 elements or `.100`). The benchmarks are
+// normalized on the number of elements to make the input sizes comparable.
+//
+// Most inputs have type `Iterable<num>`, but contain only `int` values. This
+// allows is to compare the down-conversion versions of copying where each
+// element must be checked.
+
+class Benchmark extends BenchmarkBase {
+ final int length;
+ final Function() copy;
+
+ final List<Iterable<num>> inputs = [];
+
+ Benchmark(String name, this.length, this.copy)
+ : super('ListCopy.$name.$length');
+
+ void setup() {
+ // Ensure setup() is idempotent.
+ if (inputs.isNotEmpty) return;
+ List<num> base = List.generate(length, (i) => i + 1);
+ List<Iterable<num>> makeVariants() {
+ return [
+ // Weight ordinary lists more.
+ ...List.generate(19, (_) => List<num>.of(base)),
+
+ base.toList(growable: false),
+ List<num>.unmodifiable(base),
+ UnmodifiableListView(base),
+ base.reversed,
+ String.fromCharCodes(List<int>.from(base)).codeUnits,
+ Uint8List.fromList(List<int>.from(base)),
+ ];
+ }
+
+ const elements = 10000;
+ int totalLength = 0;
+ while (totalLength < elements) {
+ var variants = makeVariants();
+ inputs.addAll(variants);
+ totalLength += variants.fold(0, (sum, iterable) => sum + iterable.length);
+ }
+
+ // Sanity checks.
+ for (var sample in inputs) {
+ if (sample.length != length) throw 'Wrong length: $length $sample';
+ }
+ if (totalLength != elements) {
+ throw 'totalLength $totalLength != expected $elements';
+ }
+ }
+
+ void run() {
+ for (var sample in inputs) {
+ input = sample;
+ // Unroll loop 10 times to reduce loop overhead, which is about 15% for
+ // the fastest short input benchmarks.
+ copy();
+ copy();
+ copy();
+ copy();
+ copy();
+ copy();
+ copy();
+ copy();
+ copy();
+ copy();
+ }
+ if (output.length != inputs.first.length) throw 'Bad result: $output';
+ }
+}
+
+// All the 'copy' methods use [input] and [output] rather than a parameter and
+// return value to avoid any possibility of type check in the call sequence.
+Iterable<num> input;
+var output;
+
+List<Benchmark> makeBenchmarks(int length) => [
+ Benchmark('toList', length, () {
+ output = input.toList();
+ }),
+ Benchmark('toList.fixed', length, () {
+ output = input.toList(growable: false);
+ }),
+ Benchmark('List.of', length, () {
+ output = List<num>.of(input);
+ }),
+ Benchmark('List.of.fixed', length, () {
+ output = List<num>.of(input, growable: false);
+ }),
+ Benchmark('List.num.from', length, () {
+ output = List<num>.from(input);
+ }),
+ Benchmark('List.int.from', length, () {
+ output = List<int>.from(input);
+ }),
+ Benchmark('List.num.from.fixed', length, () {
+ output = List<num>.from(input, growable: false);
+ }),
+ Benchmark('List.int.from.fixed', length, () {
+ output = List<int>.from(input, growable: false);
+ }),
+ Benchmark('List.num.unmodifiable', length, () {
+ output = List<num>.unmodifiable(input);
+ }),
+ Benchmark('List.int.unmodifiable', length, () {
+ output = List<int>.unmodifiable(input);
+ }),
+ Benchmark('spread.num', length, () {
+ output = <num>[...input];
+ }),
+ Benchmark('spread.int', length, () {
+ output = <int>[...input];
+ }),
+ ];
+
+main() {
+ var benchmarks = [...makeBenchmarks(2), ...makeBenchmarks(100)];
+
+ // Warmup all benchmarks to ensure JIT compilers see full polymorphism.
+ for (var benchmark in benchmarks) {
+ benchmark.setup();
+ }
+
+ for (var benchmark in benchmarks) {
+ benchmark.warmup();
+ }
+
+ for (var benchmark in benchmarks) {
+ // `report` calls `setup`, but `setup` is idempotent.
+ benchmark.report();
+ }
+}
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 7a8e5b1..7aabba9 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -197,6 +197,16 @@
r"""Try marking the function body with either 'async' or 'async*', or removing the 'await' before the for loop.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeAwaitInLateLocalInitializer =
+ messageAwaitInLateLocalInitializer;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageAwaitInLateLocalInitializer = const MessageCode(
+ "AwaitInLateLocalInitializer",
+ message:
+ r"""`await` expressions are not supported in late local initializers.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeAwaitNotAsync = messageAwaitNotAsync;
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
diff --git a/pkg/_fe_analyzer_shared/test/inheritance/data/members_from_opt_in/main.dart b/pkg/_fe_analyzer_shared/test/inheritance/data/members_from_opt_in/main.dart
new file mode 100644
index 0000000..d6be79f
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/test/inheritance/data/members_from_opt_in/main.dart
@@ -0,0 +1,286 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// @dart=2.5
+
+/*library: nnbd=false*/
+
+import 'opt_in.dart';
+
+/*class: LegacyClass:Class,Interface,LegacyClass,Object*/
+class LegacyClass extends Class implements Interface {
+ /*member: LegacyClass.method1:int* Function()**/
+ /*member: LegacyClass.method2:int* Function()**/
+
+ /*member: LegacyClass.method3:int* Function()**/
+ int method3() => 0;
+
+ /*member: LegacyClass.method4:int* Function()**/
+ int method4() => 0;
+
+ /*member: LegacyClass.method5a:int* Function(int*,int*)**/
+ /*member: LegacyClass.method5b:int* Function(int*,[int*])**/
+ /*member: LegacyClass.method5c:int* Function([int*,int*])**/
+
+ /*member: LegacyClass.method6a:int* Function(int*,int*)**/
+ int method6a(int a, int b) => 0;
+
+ /*member: LegacyClass.method6b:int* Function(int*,[int*])**/
+ int method6b(int a, [int b]) => 0;
+
+ /*member: LegacyClass.method6c:int* Function([int*,int*])**/
+ int method6c([int a, int b]) => 0;
+
+ /*member: LegacyClass.method7a:int* Function(int*,{int* b})**/
+ /*member: LegacyClass.method7b:int* Function({int* a,int* b})**/
+
+ /*member: LegacyClass.method8a:int* Function(int*,{int* b})**/
+ int method8a(int a, {int b: 0}) => 0;
+
+ /*member: LegacyClass.method8b:int* Function({int* a,int* b})**/
+ int method8b({int a, int b: 0}) => 0;
+
+ /*member: LegacyClass.method9a:int* Function(int*,{int* b})**/
+ /*member: LegacyClass.method9b:int* Function({int* a,int* b})**/
+
+ /*member: LegacyClass.method10a:int* Function(int*,{int* b})**/
+ int method10a(int a, {int b}) => 0;
+
+ /*member: LegacyClass.method10b:int* Function({int* a,int* b})**/
+ int method10b({int a, int b}) => 0;
+
+ /*member: LegacyClass.getter1:int**/
+ /*member: LegacyClass.getter2:int**/
+
+ /*member: LegacyClass.getter3:int**/
+ int get getter3 => 0;
+
+ /*member: LegacyClass.getter4:int**/
+ int get getter4 => 0;
+
+ /*member: LegacyClass.setter1=:int**/
+
+ /*member: LegacyClass.setter2=:int**/
+
+ /*member: LegacyClass.setter3=:int**/
+ void set setter3(int value) {}
+
+ /*member: LegacyClass.setter4=:int**/
+ void set setter4(int value) {}
+
+ /*member: LegacyClass.field1:int**/
+ /*member: LegacyClass.field1=:int**/
+ /*member: LegacyClass.field2:int**/
+ /*member: LegacyClass.field2=:int**/
+
+ /*member: LegacyClass.field3:int**/
+ int field3;
+
+ /*member: LegacyClass.field4:int**/
+ int field4;
+
+ /*member: LegacyClass.field6a:int**/
+ var field6a = 0;
+
+ /*member: LegacyClass.field6b:int**/
+ var field6b = constant;
+
+ /*member: LegacyClass.field5:int**/
+ /*member: LegacyClass.field5=:int**/
+
+ /*member: LegacyClass.property1:int**/
+ /*member: LegacyClass.property1=:int**/
+ /*member: LegacyClass.property2:int**/
+ /*member: LegacyClass.property2=:int**/
+
+ /*member: LegacyClass.property3:int**/
+ int get property3 => 0;
+
+ /*member: LegacyClass.property3=:int**/
+ void set property3(int value) {}
+
+ /*member: LegacyClass.property4:int**/
+ int get property4 => 0;
+
+ /*member: LegacyClass.property4=:int**/
+ void set property4(int value) {}
+
+ /*member: LegacyClass.property5:int**/
+ /*member: LegacyClass.property5=:int**/
+ /*member: LegacyClass.property6:int**/
+ /*member: LegacyClass.property6=:int**/
+
+ /*member: LegacyClass.property7:int**/
+ int property7;
+
+ /*member: LegacyClass.property8:int**/
+ int property8;
+}
+
+/*class: LegacyClass2a:Class,LegacyClass2a,Object*/
+abstract class LegacyClass2a extends Class {
+ /*member: LegacyClass2a.field1:int**/
+ /*member: LegacyClass2a.field1=:int**/
+ /*member: LegacyClass2a.field2:int**/
+ /*member: LegacyClass2a.field2=:int**/
+ /*member: LegacyClass2a.field5:int**/
+ /*member: LegacyClass2a.field5=:int**/
+ /*member: LegacyClass2a.field6a:int**/
+ /*member: LegacyClass2a.field6a=:int**/
+ /*member: LegacyClass2a.field6b:int**/
+ /*member: LegacyClass2a.field6b=:int**/
+
+ /*member: LegacyClass2a.getter1:int**/
+ /*member: LegacyClass2a.getter2:int**/
+
+ /*member: LegacyClass2a.method1:int* Function()**/
+ /*member: LegacyClass2a.method2:int* Function()**/
+ /*member: LegacyClass2a.method5a:int* Function(int*,int*)**/
+ /*member: LegacyClass2a.method5b:int* Function(int*,[int*])**/
+ /*member: LegacyClass2a.method5c:int* Function([int*,int*])**/
+ /*member: LegacyClass2a.method7a:int* Function(int*,{int* b})**/
+ /*member: LegacyClass2a.method7b:int* Function({int* a,int* b})**/
+ /*member: LegacyClass2a.method9a:int* Function(int*,{int* b})**/
+ /*member: LegacyClass2a.method9b:int* Function({int* a,int* b})**/
+
+ /*member: LegacyClass2a.property1:int**/
+ /*member: LegacyClass2a.property1=:int**/
+ /*member: LegacyClass2a.property2:int**/
+ /*member: LegacyClass2a.property2=:int**/
+ /*member: LegacyClass2a.property5:int**/
+ /*member: LegacyClass2a.property5=:int**/
+ /*member: LegacyClass2a.property6:int**/
+ /*member: LegacyClass2a.property6=:int**/
+
+ /*member: LegacyClass2a.setter1=:int**/
+ /*member: LegacyClass2a.setter2=:int**/
+}
+
+/*class: LegacyInterface2:Interface,LegacyInterface2,Object*/
+abstract class LegacyInterface2 implements Interface {
+ /*member: LegacyInterface2.field1:int**/
+ /*member: LegacyInterface2.field1=:int**/
+ /*member: LegacyInterface2.field2:int**/
+ /*member: LegacyInterface2.field2=:int**/
+ /*member: LegacyInterface2.field3:int**/
+ /*member: LegacyInterface2.field3=:int**/
+ /*member: LegacyInterface2.field4:int**/
+ /*member: LegacyInterface2.field4=:int**/
+
+ /*member: LegacyInterface2.getter1:int**/
+ /*member: LegacyInterface2.getter2:int**/
+ /*member: LegacyInterface2.getter3:int**/
+ /*member: LegacyInterface2.getter4:int**/
+
+ /*member: LegacyInterface2.method1:int* Function()**/
+ /*member: LegacyInterface2.method2:int* Function()**/
+ /*member: LegacyInterface2.method3:int* Function()**/
+ /*member: LegacyInterface2.method4:int* Function()**/
+ /*member: LegacyInterface2.method5a:int* Function(int*,int*)**/
+ /*member: LegacyInterface2.method5b:int* Function(int*,[int*])**/
+ /*member: LegacyInterface2.method5c:int* Function([int*,int*])**/
+ /*member: LegacyInterface2.method6a:int* Function(int*,int*)**/
+ /*member: LegacyInterface2.method6b:int* Function(int*,[int*])**/
+ /*member: LegacyInterface2.method6c:int* Function([int*,int*])**/
+ /*member: LegacyInterface2.method7a:int* Function(int*,{int* b})**/
+ /*member: LegacyInterface2.method7b:int* Function({int* a,int* b})**/
+ /*member: LegacyInterface2.method8a:int* Function(int*,{int* b})**/
+ /*member: LegacyInterface2.method8b:int* Function({int* a,int* b})**/
+ /*member: LegacyInterface2.method9a:int* Function(int*,{int* b})**/
+ /*member: LegacyInterface2.method9b:int* Function({int* a,int* b})**/
+ /*member: LegacyInterface2.method10a:int* Function(int*,{int* b})**/
+ /*member: LegacyInterface2.method10b:int* Function({int* a,int* b})**/
+
+ /*member: LegacyInterface2.property1:int**/
+ /*member: LegacyInterface2.property1=:int**/
+ /*member: LegacyInterface2.property2:int**/
+ /*member: LegacyInterface2.property2=:int**/
+ /*member: LegacyInterface2.property3:int**/
+ /*member: LegacyInterface2.property3=:int**/
+ /*member: LegacyInterface2.property4:int**/
+ /*member: LegacyInterface2.property4=:int**/
+ /*member: LegacyInterface2.property5:int**/
+ /*member: LegacyInterface2.property5=:int**/
+ /*member: LegacyInterface2.property6:int**/
+ /*member: LegacyInterface2.property6=:int**/
+ /*member: LegacyInterface2.property7:int**/
+ /*member: LegacyInterface2.property7=:int**/
+ /*member: LegacyInterface2.property8:int**/
+ /*member: LegacyInterface2.property8=:int**/
+
+ /*member: LegacyInterface2.setter1=:int**/
+ /*member: LegacyInterface2.setter2=:int**/
+ /*member: LegacyInterface2.setter3=:int**/
+ /*member: LegacyInterface2.setter4=:int**/
+}
+
+/*class: LegacyClass2b:Class,Interface,LegacyClass2a,LegacyClass2b,LegacyInterface2,Object*/
+abstract class LegacyClass2b extends LegacyClass2a implements LegacyInterface2 {
+ /*member: LegacyClass2b.field1:int**/
+ /*member: LegacyClass2b.field1=:int**/
+ /*member: LegacyClass2b.field2:int**/
+ /*member: LegacyClass2b.field2=:int**/
+ /*member: LegacyClass2b.field3:int**/
+ /*member: LegacyClass2b.field3=:int**/
+ /*member: LegacyClass2b.field4:int**/
+ /*member: LegacyClass2b.field4=:int**/
+ /*member: LegacyClass2b.field5:int**/
+ /*member: LegacyClass2b.field5=:int**/
+ /*member: LegacyClass2b.field6a:int**/
+ /*member: LegacyClass2b.field6a=:int**/
+ /*member: LegacyClass2b.field6b:int**/
+ /*member: LegacyClass2b.field6b=:int**/
+
+ /*member: LegacyClass2b.getter1:int**/
+ /*member: LegacyClass2b.getter2:int**/
+ /*member: LegacyClass2b.getter3:int**/
+ /*member: LegacyClass2b.getter4:int**/
+
+ /*member: LegacyClass2b.method1:int* Function()**/
+ /*member: LegacyClass2b.method2:int* Function()**/
+ /*member: LegacyClass2b.method3:int* Function()**/
+ /*member: LegacyClass2b.method4:int* Function()**/
+ /*member: LegacyClass2b.method5a:int* Function(int*,int*)**/
+ /*member: LegacyClass2b.method5b:int* Function(int*,[int*])**/
+ /*member: LegacyClass2b.method5c:int* Function([int*,int*])**/
+ /*member: LegacyClass2b.method6a:int* Function(int*,int*)**/
+ /*member: LegacyClass2b.method6b:int* Function(int*,[int*])**/
+ /*member: LegacyClass2b.method6c:int* Function([int*,int*])**/
+ /*member: LegacyClass2b.method7a:int* Function(int*,{int* b})**/
+ /*member: LegacyClass2b.method7b:int* Function({int* a,int* b})**/
+ /*member: LegacyClass2b.method8a:int* Function(int*,{int* b})**/
+ /*member: LegacyClass2b.method8b:int* Function({int* a,int* b})**/
+ /*member: LegacyClass2b.method9a:int* Function(int*,{int* b})**/
+ /*member: LegacyClass2b.method9b:int* Function({int* a,int* b})**/
+ /*member: LegacyClass2b.method10a:int* Function(int*,{int* b})**/
+ /*member: LegacyClass2b.method10b:int* Function({int* a,int* b})**/
+
+ /*member: LegacyClass2b.property1:int**/
+ /*member: LegacyClass2b.property1=:int**/
+ /*member: LegacyClass2b.property2:int**/
+ /*member: LegacyClass2b.property2=:int**/
+ /*member: LegacyClass2b.property3:int**/
+ /*member: LegacyClass2b.property3=:int**/
+ /*member: LegacyClass2b.property4:int**/
+ /*member: LegacyClass2b.property4=:int**/
+ /*member: LegacyClass2b.property5:int**/
+ /*member: LegacyClass2b.property5=:int**/
+ /*member: LegacyClass2b.property6:int**/
+ /*member: LegacyClass2b.property6=:int**/
+ /*member: LegacyClass2b.property7:int**/
+ /*member: LegacyClass2b.property7=:int**/
+ /*member: LegacyClass2b.property8:int**/
+ /*member: LegacyClass2b.property8=:int**/
+
+ /*member: LegacyClass2b.setter1=:int**/
+ /*member: LegacyClass2b.setter2=:int**/
+ /*member: LegacyClass2b.setter3=:int**/
+ /*member: LegacyClass2b.setter4=:int**/
+}
+
+/*class: LegacyGenericClass1:GenericInterface<T*>,LegacyGenericClass1<T*>,Object*/
+abstract class LegacyGenericClass1<T> implements GenericInterface<T> {
+ /*member: LegacyGenericClass1.genericMethod1:S* Function<S>(T*,S*,{T* c,S* d})**/
+ /*member: LegacyGenericClass1.genericMethod2:S* Function<S>(T*,S*,[T*,S*])**/
+}
diff --git a/pkg/_fe_analyzer_shared/test/inheritance/data/members_from_opt_in/opt_in.dart b/pkg/_fe_analyzer_shared/test/inheritance/data/members_from_opt_in/opt_in.dart
new file mode 100644
index 0000000..ed18fed
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/test/inheritance/data/members_from_opt_in/opt_in.dart
@@ -0,0 +1,232 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/*library: nnbd=true*/
+
+/*class: Interface:Interface,Object*/
+abstract class Interface {
+ /*member: Interface.method1:int? Function()!*/
+ int? method1();
+
+ /*member: Interface.method2:int! Function()!*/
+ int method2();
+
+ /*member: Interface.method3:int! Function()!*/
+ int method3();
+
+ /*member: Interface.method4:int? Function()!*/
+ int? method4();
+
+ /*member: Interface.method5a:int! Function(int!,int?)!*/
+ int method5a(int a, int? b);
+
+ /*member: Interface.method5b:int! Function(int!,[int?])!*/
+ int method5b(int a, [int? b]);
+
+ /*member: Interface.method5c:int! Function([int!,int?])!*/
+ int method5c([int a, int? b]);
+
+ /*member: Interface.method6a:int? Function(int?,int!)!*/
+ int? method6a(int? a, int b);
+
+ /*member: Interface.method6b:int? Function(int?,[int!])!*/
+ int? method6b(int? a, [int b = 0]);
+
+ /*member: Interface.method6c:int? Function([int?,int!])!*/
+ int? method6c([int? a, int b = 0]);
+
+ /*member: Interface.method7a:int! Function(int!,{int? b})!*/
+ int method7a(int a, {int? b});
+
+ /*member: Interface.method7b:int! Function({int! a,int? b})!*/
+ int method7b({int a: 0, int? b});
+
+ /*member: Interface.method8a:int? Function(int?,{int! b})!*/
+ int? method8a(int? a, {int b: 0});
+
+ /*member: Interface.method8b:int? Function({int? a,int! b})!*/
+ int? method8b({int? a, int b: 0});
+
+ /*member: Interface.method9a:int! Function(int!,{required int? b})!*/
+ int method9a(int a, {required int? b});
+
+ /*member: Interface.method9b:int! Function({required int! a,required int? b})!*/
+ int method9b({required int a, required int? b});
+
+ /*member: Interface.method10a:int? Function(int?,{required int! b})!*/
+ int? method10a(int? a, {required int b});
+
+ /*member: Interface.method10b:int? Function({required int? a,required int! b})!*/
+ int? method10b({required int? a, required int b});
+
+ /*member: Interface.getter1:int?*/
+ int? get getter1;
+
+ /*member: Interface.getter2:int!*/
+ int get getter2;
+
+ /*member: Interface.getter3:int!*/
+ int get getter3;
+
+ /*member: Interface.getter4:int?*/
+ int? get getter4;
+
+ /*member: Interface.setter1=:int?*/
+ void set setter1(int? value);
+
+ /*member: Interface.setter2=:int!*/
+ void set setter2(int value);
+
+ /*member: Interface.setter3=:int!*/
+ void set setter3(int value);
+
+ /*member: Interface.setter4=:int?*/
+ void set setter4(int? value);
+
+ /*member: Interface.field1:int?*/
+ int? field1;
+
+ /*member: Interface.field2:int!*/
+ int field2 = 0;
+
+ /*member: Interface.field3:int!*/
+ int field3 = 0;
+
+ /*member: Interface.field4:int?*/
+ int? field4;
+
+ /*member: Interface.property1:int?*/
+ int? get property1;
+
+ /*member: Interface.property1=:int?*/
+ void set property1(int? value);
+
+ /*member: Interface.property2:int!*/
+ int get property2;
+
+ /*member: Interface.property2=:int!*/
+ void set property2(int value);
+
+ /*member: Interface.property3:int!*/
+ int get property3;
+
+ /*member: Interface.property3=:int!*/
+ void set property3(int value);
+
+ /*member: Interface.property4:int?*/
+ int? get property4;
+
+ /*member: Interface.property4=:int?*/
+ void set property4(int? value);
+
+ /*member: Interface.property5:int?*/
+ int? get property5;
+
+ /*member: Interface.property5=:int?*/
+ void set property5(int? value);
+
+ /*member: Interface.property6:int!*/
+ int get property6;
+
+ /*member: Interface.property6=:int!*/
+ void set property6(int value);
+
+ /*member: Interface.property7:int!*/
+ int get property7;
+
+ /*member: Interface.property7=:int!*/
+ void set property7(int value);
+
+ /*member: Interface.property8:int?*/
+ int? get property8;
+
+ /*member: Interface.property8=:int?*/
+ void set property8(int? value);
+}
+
+/*class: Class:Class,Object*/
+class Class {
+ /*member: Class.method1:int! Function()!*/
+ int method1() => 0;
+
+ /*member: Class.method2:int? Function()!*/
+ int? method2() => 0;
+
+ /*member: Class.method5a:int! Function(int!,int?)!*/
+ int method5a(int a, int? b) => 0;
+
+ /*member: Class.method5b:int! Function(int!,[int?])!*/
+ int method5b(int a, [int? b]) => 0;
+
+ /*member: Class.method5c:int! Function([int!,int?])!*/
+ int method5c([int a = 0, int? b]) => 0;
+
+ /*member: Class.method7a:int! Function(int!,{int? b})!*/
+ int method7a(int a, {int? b}) => 0;
+
+ /*member: Class.method7b:int! Function({int! a,int? b})!*/
+ int method7b({int a: 0, int? b}) => 0;
+
+ /*member: Class.method9a:int! Function(int!,{required int? b})!*/
+ int method9a(int a, {required int? b}) => 0;
+
+ /*member: Class.method9b:int! Function({required int! a,required int? b})!*/
+ int method9b({required int a, required int? b}) => 0;
+
+ /*member: Class.getter1:int!*/
+ int get getter1 => 0;
+
+ /*member: Class.getter2:int?*/
+ int? get getter2 => 0;
+
+ /*member: Class.setter1=:int!*/
+ void set setter1(int value) {}
+
+ /*member: Class.setter2=:int?*/
+ void set setter2(int? value) {}
+
+ /*member: Class.field1:int!*/
+ int field1 = 0;
+
+ /*member: Class.field2:int?*/
+ int? field2;
+
+ /*member: Class.field5:int!*/
+ var field5 = 0;
+
+ /*member: Class.field6a:int!*/
+ var field6a = 0;
+
+ /*member: Class.field6b:int?*/
+ var field6b = constant;
+
+ /*member: Class.property1:int!*/
+ int get property1 => 0;
+
+ /*member: Class.property1=:int!*/
+ void set property1(int value) {}
+
+ /*member: Class.property2:int?*/
+ int? get property2 => 0;
+
+ /*member: Class.property2=:int?*/
+ void set property2(int? value) {}
+
+ /*member: Class.property5:int!*/
+ int property5 = 0;
+
+ /*member: Class.property6:int?*/
+ int? property6;
+}
+
+const int? constant = 0;
+
+/*class: GenericInterface:GenericInterface<T>,Object*/
+abstract class GenericInterface<T> {
+ /*member: GenericInterface.genericMethod1:S Function<S>(T,S,{T c,S d})!*/
+ S genericMethod1<S>(T a, S b, {T c, S d});
+
+ /*member: GenericInterface.genericMethod2:S Function<S>(T,S,[T,S])!*/
+ S genericMethod2<S>(T a, S b, [T c, S d]);
+}
diff --git a/pkg/_fe_analyzer_shared/test/inheritance/data/members_from_opt_out/main.dart b/pkg/_fe_analyzer_shared/test/inheritance/data/members_from_opt_out/main.dart
new file mode 100644
index 0000000..2af78cb
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/test/inheritance/data/members_from_opt_out/main.dart
@@ -0,0 +1,305 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/*library: nnbd=true*/
+library main;
+
+import 'opt_out.dart';
+
+/*class: Interface:Interface,Object*/
+abstract class Interface {
+ /*member: Interface.method1:int! Function()!*/
+ int method1();
+
+ /*member: Interface.method2:int? Function()!*/
+ int? method2();
+
+ /*member: Interface.method3a:int! Function(int!,int!)!*/
+ int method3a(int a, int b);
+
+ /*member: Interface.method3b:int! Function(int!,[int!])!*/
+ int method3b(int a, [int b]);
+
+ /*member: Interface.method3c:int! Function([int!,int!])!*/
+ int method3c([int a, int b]);
+
+ /*member: Interface.method4a:int? Function(int?,int?)!*/
+ int? method4a(int? a, int? b);
+
+ /*member: Interface.method4b:int? Function(int?,[int?])!*/
+ int? method4b(int? a, [int? b]);
+
+ /*member: Interface.method4c:int? Function([int?,int?])!*/
+ int? method4c([int? a, int? b]);
+
+ /*member: Interface.method5a:int! Function(int!,{int! b})!*/
+ int method5a(int a, {int b: 0});
+
+ /*member: Interface.method5b:int! Function({int! a,int! b})!*/
+ int method5b({int a: 0, int b: 0});
+
+ /*member: Interface.method5c:int! Function({required int! a,required int! b})!*/
+ int method5c({required int a: 0, required int b: 0});
+
+ /*member: Interface.method6a:int? Function(int?,{int? b})!*/
+ int? method6a(int? a, {int? b});
+
+ /*member: Interface.method6b:int? Function({int? a,int? b})!*/
+ int? method6b({int? a, int? b});
+
+ /*member: Interface.method6c:int? Function({required int? a,required int? b})!*/
+ int? method6c({required int? a, required int? b});
+
+ /*member: Interface.getter1:int!*/
+ int get getter1;
+
+ /*member: Interface.getter2:int?*/
+ int? get getter2;
+
+ /*member: Interface.setter1=:int!*/
+ void set setter1(int value);
+
+ /*member: Interface.setter2=:int?*/
+ void set setter2(int? value);
+
+ /*member: Interface.field1:int!*/
+ int field1 = 0;
+
+ /*member: Interface.field2:int?*/
+ int? field2;
+
+ /*member: Interface.field3:int!*/
+ int get field3;
+
+ /*member: Interface.field3=:int!*/
+ void set field3(int value);
+
+ /*member: Interface.field4:int?*/
+ int? get field4;
+
+ /*member: Interface.field4=:int?*/
+ void set field4(int? value);
+
+ /*member: Interface.field5:int!*/
+ var field5 = 0;
+
+ /*member: Interface.field6:int?*/
+ var field6 = constant;
+
+ /*member: Interface.property1:int!*/
+ int get property1;
+
+ /*member: Interface.property1=:int!*/
+ void set property1(int value);
+
+ /*member: Interface.property2:int?*/
+ int? get property2;
+
+ /*member: Interface.property2=:int?*/
+ void set property2(int? value);
+
+ /*member: Interface.property3:int!*/
+ int property3 = 0;
+
+ /*member: Interface.property4:int?*/
+ int? property4;
+}
+
+/*class: Class1:Class1,LegacyClass,Object*/
+class Class1 extends LegacyClass {
+ /*member: Class1.method1:int* Function()**/
+ /*member: Class1.method2:int* Function()**/
+ /*member: Class1.method3a:int* Function(int*,int*)**/
+ /*member: Class1.method3b:int* Function(int*,[int*])**/
+ /*member: Class1.method3c:int* Function([int*,int*])**/
+ /*member: Class1.method4a:int* Function(int*,int*)**/
+ /*member: Class1.method4b:int* Function(int*,[int*])**/
+ /*member: Class1.method4c:int* Function([int*,int*])**/
+ /*member: Class1.method5a:int* Function(int*,{int* b})**/
+ /*member: Class1.method5b:int* Function({int* a,int* b})**/
+ /*member: Class1.method5c:int* Function({int* a,int* b})**/
+ /*member: Class1.method6a:int* Function(int*,{int* b})**/
+ /*member: Class1.method6b:int* Function({int* a,int* b})**/
+ /*member: Class1.method6c:int* Function({int* a,int* b})**/
+ /*member: Class1.getter1:int**/
+ /*member: Class1.getter2:int**/
+ /*member: Class1.setter1=:int**/
+ /*member: Class1.setter2=:int**/
+ /*member: Class1.field1:int**/
+ /*member: Class1.field2:int**/
+ /*member: Class1.field3:int**/
+ /*member: Class1.field4:int**/
+ /*member: Class1.field5:int**/
+ /*member: Class1.field6:int**/
+ /*member: Class1.property1:int**/
+ /*member: Class1.property1=:int**/
+ /*member: Class1.property2:int**/
+ /*member: Class1.property2=:int**/
+ /*member: Class1.property3:int**/
+ /*member: Class1.property3=:int**/
+ /*member: Class1.property4:int**/
+ /*member: Class1.property4=:int**/
+}
+
+/*class: Class2a:Class2a,Interface,LegacyClass,Object*/
+class Class2a extends LegacyClass implements Interface {
+ /*member: Class2a.method1:int! Function()!*/
+ /*member: Class2a.method2:int? Function()!*/
+ /*member: Class2a.method3a:int! Function(int!,int!)!*/
+ /*member: Class2a.method3b:int! Function(int!,[int!])!*/
+ /*member: Class2a.method3c:int! Function([int!,int!])!*/
+ /*member: Class2a.method4a:int? Function(int?,int?)!*/
+ /*member: Class2a.method4b:int? Function(int?,[int?])!*/
+ /*member: Class2a.method4c:int? Function([int?,int?])!*/
+ /*member: Class2a.method5a:int! Function(int!,{int! b})!*/
+ /*member: Class2a.method5b:int! Function({int! a,int! b})!*/
+ // TODO(johnniwinther): Should `method5c` be an error? It mixes required
+ // and optional named parameters.
+ /*member: Class2a.method5c:int! Function({int! a,int! b})!*/
+ /*member: Class2a.method6a:int? Function(int?,{int? b})!*/
+ /*member: Class2a.method6b:int? Function({int? a,int? b})!*/
+ // TODO(johnniwinther): Should `method6c` be an error? It mixes required
+ // and optional named parameters.
+ /*member: Class2a.method6c:int? Function({int? a,int? b})!*/
+ /*member: Class2a.getter1:int!*/
+ /*member: Class2a.getter2:int?*/
+ /*member: Class2a.setter1=:int!*/
+ /*member: Class2a.setter2=:int?*/
+ /*member: Class2a.field1:int!*/
+ /*member: Class2a.field1=:int!*/
+ /*member: Class2a.field2:int?*/
+ /*member: Class2a.field2=:int?*/
+ /*member: Class2a.field3:int!*/
+ /*member: Class2a.field3=:int!*/
+ /*member: Class2a.field4:int?*/
+ /*member: Class2a.field4=:int?*/
+ /*member: Class2a.field5:int!*/
+ /*member: Class2a.field5=:int!*/
+ /*member: Class2a.field6:int?*/
+ /*member: Class2a.field6=:int?*/
+ /*member: Class2a.property1:int!*/
+ /*member: Class2a.property1=:int!*/
+ /*member: Class2a.property2:int?*/
+ /*member: Class2a.property2=:int?*/
+ /*member: Class2a.property3:int!*/
+ /*member: Class2a.property3=:int!*/
+ /*member: Class2a.property4:int?*/
+ /*member: Class2a.property4=:int?*/
+}
+
+/*class: Class2b:Class2b,Interface,LegacyClass,Object*/
+class Class2b extends LegacyClass implements Interface {
+ /*member: Class2b.method1:int! Function()!*/
+ int method1() => 0;
+
+ /*member: Class2b.method2:int? Function()!*/
+ int? method2() => 0;
+
+ /*member: Class2b.method3a:int! Function(int!,int!)!*/
+ int method3a(int a, int b) => 0;
+
+ /*member: Class2b.method3b:int! Function(int!,[int!])!*/
+ int method3b(int a, [int b]) => 0;
+
+ /*member: Class2b.method3c:int! Function([int!,int!])!*/
+ int method3c([int a, int b]) => 0;
+
+ /*member: Class2b.method4a:int? Function(int?,int?)!*/
+ int? method4a(int? a, int? b) => 0;
+
+ /*member: Class2b.method4b:int? Function(int?,[int?])!*/
+ int? method4b(int? a, [int? b]) => 0;
+
+ /*member: Class2b.method4c:int? Function([int?,int?])!*/
+ int? method4c([int? a, int? b]) => 0;
+
+ /*member: Class2b.method5a:int! Function(int!,{int! b})!*/
+ int method5a(int a, {int b: 0}) => 0;
+
+ /*member: Class2b.method5b:int! Function({int! a,int! b})!*/
+ int method5b({int a: 0, int b: 0}) => 0;
+
+ /*member: Class2b.method5c:int! Function({required int! a,required int! b})!*/
+ int method5c({required int a: 0, required int b: 0}) => 0;
+
+ /*member: Class2b.method6a:int? Function(int?,{int? b})!*/
+ int? method6a(int? a, {int? b}) => 0;
+
+ /*member: Class2b.method6b:int? Function({int? a,int? b})!*/
+ int? method6b({int? a, int? b}) => 0;
+
+ /*member: Class2b.method6c:int? Function({required int? a,required int? b})!*/
+ int? method6c({required int? a, required int? b}) => 0;
+
+ /*member: Class2b.getter1:int!*/
+ int get getter1 => 0;
+
+ /*member: Class2b.getter2:int?*/
+ int? get getter2 => 0;
+
+ /*member: Class2b.setter1=:int!*/
+ void set setter1(int value) {}
+
+ /*member: Class2b.setter2=:int?*/
+ void set setter2(int? value) {}
+
+ /*member: Class2b.field1:int!*/
+ int field1 = 0;
+
+ /*member: Class2b.field2:int?*/
+ int? field2;
+
+ /*member: Class2b.field3:int!*/
+ int get field3 => 0;
+
+ /*member: Class2b.field3=:int!*/
+ void set field3(int value) {}
+
+ /*member: Class2b.field4:int?*/
+ int? get field4 => 0;
+
+ /*member: Class2b.field5:int!*/
+ int field5;
+
+ /*member: Class2b.field6:int?*/
+ int? field6;
+
+ /*member: Class2b.field4=:int?*/
+ void set field4(int? value) {}
+
+ /*member: Class2b.property1:int!*/
+ int get property1 => 0;
+
+ /*member: Class2b.property1=:int!*/
+ void set property1(int value) {}
+
+ /*member: Class2b.property2:int?*/
+ int? get property2 => 0;
+
+ /*member: Class2b.property2=:int?*/
+ void set property2(int? value) {}
+
+ /*member: Class2b.property3:int!*/
+ int property3 = 0;
+
+ /*member: Class2b.property4:int?*/
+ int? property4;
+}
+
+/*class: Class3a:Class3a,GenericLegacyClass<int!>,Object*/
+class Class3a extends GenericLegacyClass<int> {
+ /*member: Class3a.method1:int* Function()**/
+}
+
+/*class: Class3b:Class3b,GenericLegacyClass<int?>,Object*/
+class Class3b extends GenericLegacyClass<int?> {
+ /*member: Class3b.method1:int? Function()**/
+}
+
+/*class: Class3c:Class3c<S>,GenericLegacyClass<S>,Object*/
+class Class3c<S> extends GenericLegacyClass<S> {
+ /*member: Class3c.method1:S* Function()**/
+}
+
+const int? constant = 0;
diff --git a/pkg/_fe_analyzer_shared/test/inheritance/data/members_from_opt_out/opt_out.dart b/pkg/_fe_analyzer_shared/test/inheritance/data/members_from_opt_out/opt_out.dart
new file mode 100644
index 0000000..c1bd807
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/test/inheritance/data/members_from_opt_out/opt_out.dart
@@ -0,0 +1,113 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// @dart=2.5
+
+/*library: nnbd=false*/
+library opt_out;
+
+/*class: LegacyClass:LegacyClass,Object*/
+class LegacyClass {
+ /*member: LegacyClass.method1:int* Function()**/
+ int method1() => 0;
+
+ /*member: LegacyClass.method2:int* Function()**/
+ int method2() => 0;
+
+ /*member: LegacyClass.method3a:int* Function(int*,int*)**/
+ int method3a(int a, int b) => 0;
+
+ /*member: LegacyClass.method3b:int* Function(int*,[int*])**/
+ int method3b(int a, [int b]) => 0;
+
+ /*member: LegacyClass.method3c:int* Function([int*,int*])**/
+ int method3c([int a, int b]) => 0;
+
+ /*member: LegacyClass.method4a:int* Function(int*,int*)**/
+ int method4a(int a, int b) => 0;
+
+ /*member: LegacyClass.method4b:int* Function(int*,[int*])**/
+ int method4b(int a, [int b]) => 0;
+
+ /*member: LegacyClass.method4c:int* Function([int*,int*])**/
+ int method4c([int a, int b]) => 0;
+
+ /*member: LegacyClass.method5a:int* Function(int*,{int* b})**/
+ int method5a(int a, {int b}) => 0;
+
+ /*member: LegacyClass.method5b:int* Function({int* a,int* b})**/
+ int method5b({int a, int b}) => 0;
+
+ /*member: LegacyClass.method5c:int* Function({int* a,int* b})**/
+ int method5c({int a, int b}) => 0;
+
+ /*member: LegacyClass.method6a:int* Function(int*,{int* b})**/
+ int method6a(int a, {int b}) => 0;
+
+ /*member: LegacyClass.method6b:int* Function({int* a,int* b})**/
+ int method6b({int a, int b}) => 0;
+
+ /*member: LegacyClass.method6c:int* Function({int* a,int* b})**/
+ int method6c({int a, int b}) => 0;
+
+ /*member: LegacyClass.getter1:int**/
+ int get getter1 => 0;
+
+ /*member: LegacyClass.getter2:int**/
+ int get getter2 => 0;
+
+ /*member: LegacyClass.setter1=:int**/
+ void set setter1(int value) {}
+
+ /*member: LegacyClass.setter2=:int**/
+ void set setter2(int value) {}
+
+ /*member: LegacyClass.field1:int**/
+ int field1;
+
+ /*member: LegacyClass.field2:int**/
+ int field2;
+
+ /*member: LegacyClass.field3:int**/
+ int field3;
+
+ /*member: LegacyClass.field4:int**/
+ int field4;
+
+ /*member: LegacyClass.field5:int**/
+ var field5 = 0;
+
+ /*member: LegacyClass.field6:int**/
+ int field6 = 0;
+
+ /*member: LegacyClass.property1:int**/
+ int get property1 => 0;
+
+ /*member: LegacyClass.property1=:int**/
+ void set property1(int value) {}
+
+ /*member: LegacyClass.property2:int**/
+ int get property2 => 0;
+
+ /*member: LegacyClass.property2=:int**/
+ void set property2(int value) {}
+
+ /*member: LegacyClass.property3:int**/
+ int get property3 => 0;
+
+ /*member: LegacyClass.property3=:int**/
+ void set property3(int value) {}
+
+ /*member: LegacyClass.property4:int**/
+ int get property4 => 0;
+
+ /*member: LegacyClass.property4=:int**/
+ void set property4(int value) {}
+}
+
+/*class: GenericLegacyClass:GenericLegacyClass<T*>,Object*/
+class GenericLegacyClass<T> {
+ /*member: GenericLegacyClass.method1:T* Function()**/
+ T method1() => null;
+}
diff --git a/pkg/_fe_analyzer_shared/test/inheritance/data/members_opt_in.dart b/pkg/_fe_analyzer_shared/test/inheritance/data/members_opt_in.dart
new file mode 100644
index 0000000..199378bf
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/test/inheritance/data/members_opt_in.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/*library: nnbd=true*/
+
+abstract class /*class: A1:A1,Object*/ A1 {
+ void /*member: A1.close:void Function()!*/ close();
+}
+
+abstract class /*class: B1:B1,Object*/ B1 {
+ Object /*member: B1.close:Object! Function()!*/ close();
+}
+
+abstract class /*class: C1a:A1,B1,C1a,Object*/ C1a implements A1, B1 {
+ Object /*member: C1a.close:Object! Function()!*/ close();
+}
+
+abstract class /*class: C1b:A1,B1,C1b,Object*/ C1b implements B1, A1 {
+ Object /*member: C1b.close:Object! Function()!*/ close();
+}
+
+abstract class /*class: A2:A2<T>,Object*/ A2<T> {
+ void /*member: A2.close:void Function()!*/ close();
+}
+
+abstract class /*class: B2:B2<T>,Object*/ B2<T> {
+ Object /*member: B2.close:Object! Function()!*/ close();
+}
+
+abstract class /*class: C2a:A2<T>,B2<T>,C2a<T>,Object*/ C2a<T>
+ implements A2<T>, B2<T> {
+ Object /*member: C2a.close:Object! Function()!*/ close();
+}
+
+abstract class /*class: C2b:A2<T>,B2<T>,C2b<T>,Object*/ C2b<T>
+ implements B2<T>, A2<T> {
+ Object /*member: C2b.close:Object! Function()!*/ close();
+}
diff --git a/pkg/_fe_analyzer_shared/test/inheritance/data/members_opt_out.dart b/pkg/_fe_analyzer_shared/test/inheritance/data/members_opt_out.dart
new file mode 100644
index 0000000..db11524
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/test/inheritance/data/members_opt_out.dart
@@ -0,0 +1,68 @@
+// 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.6
+
+/*library: nnbd=false*/
+
+abstract class /*class: A1:A1,Object*/ A1 {
+ void /*member: A1.close:void Function()**/ close();
+}
+
+abstract class /*class: B1:B1,Object*/ B1 {
+ Object /*member: B1.close:Object* Function()**/ close();
+}
+
+abstract class /*class: C1a:A1,B1,C1a,Object*/ C1a implements A1, B1 {
+ Object /*member: C1a.close:Object* Function()**/ close();
+}
+
+abstract class /*class: C1b:A1,B1,C1b,Object*/ C1b implements B1, A1 {
+ Object /*member: C1b.close:Object* Function()**/ close();
+}
+
+abstract class /*class: A2:A2<T*>,Object*/ A2<T> {
+ void /*member: A2.close:void Function()**/ close();
+}
+
+abstract class /*class: B2a:B2a<T*>,Object*/ B2a<T> {
+ Object /*member: B2a.close:Object* Function()**/ close();
+}
+
+abstract class /*class: B2b:B2a<dynamic>,B2b<T*>,Object*/ B2b<T>
+ implements B2a {
+ Object /*member: B2b.close:Object* Function()**/ close();
+}
+
+abstract class /*class: C2a:A2<T*>,B2a<dynamic>,B2b<T*>,C2a<T*>,Object*/ C2a<T>
+ implements A2<T>, B2b<T> {
+ Object /*member: C2a.close:Object* Function()**/ close();
+}
+
+abstract class /*class: C2b:A2<T*>,B2a<dynamic>,B2b<T*>,C2b<T*>,Object*/ C2b<T>
+ implements B2b<T>, A2<T> {
+ Object /*member: C2b.close:Object* Function()**/ close();
+}
+
+abstract class /*class: A3a:A3a<T*>,Object*/ A3a<T> {
+ void /*member: A3a.close:void Function()**/ close();
+}
+
+abstract class /*class: A3b:A3a<T*>,A3b<T*>,Object*/ A3b<T> implements A3a<T> {
+ void /*member: A3b.close:void Function()**/ close();
+}
+
+abstract class /*class: B3:B3<T*>,Object*/ B3<T> {
+ Object /*member: B3.close:Object* Function()**/ close();
+}
+
+abstract class /*class: C3a:A3a<T*>,A3b<T*>,B3<T*>,C3a<T*>,Object*/ C3a<T>
+ implements A3b<T>, B3<T> {
+ Object /*member: C3a.close:Object* Function()**/ close();
+}
+
+abstract class /*class: C3b:A3a<T*>,A3b<T*>,B3<T*>,C3b<T*>,Object*/ C3b<T>
+ implements B3<T>, A3b<T> {
+ Object /*member: C3b.close:Object* Function()**/ close();
+}
diff --git a/pkg/_fe_analyzer_shared/test/inheritance/data/sink.dart b/pkg/_fe_analyzer_shared/test/inheritance/data/sink.dart
new file mode 100644
index 0000000..e1cc6c6
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/test/inheritance/data/sink.dart
@@ -0,0 +1,31 @@
+// 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.
+
+/*library: nnbd=false*/
+
+// @dart=2.6
+
+/*class: Sink:Object,Sink<T*>*/
+abstract class Sink<T> {
+ /*member: Sink.close:void Function()**/
+ void close();
+}
+
+/*class: EventSink:EventSink<T*>,Object,Sink<T*>*/
+abstract class EventSink<T> implements Sink<T> {
+ /*member: EventSink.close:void Function()**/
+ void close();
+}
+
+/*class: StreamConsumer:Object,StreamConsumer<S*>*/
+abstract class StreamConsumer<S> {
+ /*member: StreamConsumer.close:Future<dynamic>* Function()**/
+ Future close();
+}
+
+/*class: StreamSink:EventSink<S*>,Object,Sink<S*>,StreamConsumer<S*>,StreamSink<S*>*/
+abstract class StreamSink<S> implements EventSink<S>, StreamConsumer<S> {
+ /*member: StreamSink.close:Future<dynamic>* Function()**/
+ Future close();
+}
diff --git a/pkg/analysis_server/lib/src/edit/nnbd_migration/dart_page_script.dart b/pkg/analysis_server/lib/src/edit/nnbd_migration/dart_page_script.dart
index c991788..08077fa 100644
--- a/pkg/analysis_server/lib/src/edit/nnbd_migration/dart_page_script.dart
+++ b/pkg/analysis_server/lib/src/edit/nnbd_migration/dart_page_script.dart
@@ -173,6 +173,28 @@
});
}
+function debounce(fn, delay) {
+ var timeout;
+ return function() {
+ var later = function() {
+ timeout = null;
+ };
+ var callNow = !timeout;
+ clearTimeout(timeout);
+ timeout = setTimeout(later, delay);
+ if (callNow) fn.apply(this);
+ };
+};
+
+// Resize the fixed-size and fixed-position navigation panel.
+function resizeNav() {
+ const navInner = document.querySelector(".nav-inner");
+ // TODO(srawlins): I'm honestly not sure where 30 comes from; but without
+ // `- 30`, the navigation is too tall and the bottom cannot be seen.
+ const height = window.innerHeight - 30;
+ navInner.style.height = height + "px";
+}
+
document.addEventListener("DOMContentLoaded", (event) => {
const path = window.location.pathname;
const offset = getOffset(window.location.href);
@@ -183,6 +205,7 @@
loadFile(path, offset, lineNumber,
() => { pushState(path, offset, lineNumber) });
}
+ resizeNav();
addClickHandlers(".nav");
});
@@ -198,4 +221,28 @@
updatePage(" ", null);
}
});
+
+window.addEventListener("resize", (event) => {
+ debounce(resizeNav, 200)();
+});
+
+window.addEventListener("scroll", (event) => {
+ const nav = document.querySelector(".nav");
+ const navInner = nav.querySelector(".nav-inner");
+ const navTip = nav.querySelector(".nav-tip");
+ const navTipMarginBottom = 14;
+ if (window.pageYOffset >
+ nav.offsetTop + navTip.offsetHeight + navTipMarginBottom) {
+ if (!navInner.classList.contains("fixed")) {
+ nav.style.width = nav.offsetWidth + "px";
+ navInner.classList.add("fixed");
+ }
+ } else {
+ if (navInner.classList.contains("fixed")) {
+ nav.style.width = "";
+ navInner.classList.remove("fixed");
+ }
+ }
+ debounce(resizeNav, 200)();
+});
''';
diff --git a/pkg/analysis_server/lib/src/edit/nnbd_migration/dart_page_style.dart b/pkg/analysis_server/lib/src/edit/nnbd_migration/dart_page_style.dart
index a89349e..2be57cc 100644
--- a/pkg/analysis_server/lib/src/edit/nnbd_migration/dart_page_style.dart
+++ b/pkg/analysis_server/lib/src/edit/nnbd_migration/dart_page_style.dart
@@ -10,7 +10,7 @@
/* This allows very small files to be displayed lower than the very top of the
* screen.
*/
- margin-bottom: 100px;
+ margin: 8px;
padding: 0.5em;
}
@@ -20,7 +20,7 @@
margin: 0;
}
-h2.unit-name {
+h2#unit-name {
font-size: 1.2em;
font-weight: 600;
margin: 0;
@@ -31,7 +31,6 @@
flex-wrap: wrap;
}
-
.nav-link {
cursor: pointer;
}
@@ -39,30 +38,40 @@
.nav {
background-color: #282b2e;
flex-basis: 0;
- flex-grow: 1;
+ flex: 0 1 auto;
font-size: 14px;
/* 10px to match exact top margin of .content.
* 0.8em to pair with the -0.5em margin of .content, producing a net margin
* between the two of 0.3em.
*/
- margin: 10px 0.8em 10px 0;
- padding: 0.5em;
+ margin: 10px 0.8em 0 0;
}
.nav :first-child {
margin-top: 0;
}
-.nav .root {
+.nav-inner {
+ background-color: #282b2e;
+ overflow: auto;
+ padding: 7px 0 7px 7px;
+}
+
+.nav-inner.fixed {
+ position: fixed;
+ top: 0;
+}
+
+.nav-inner .root {
margin: 0;
}
-.nav .nav-link {
+.nav-inner .nav-link {
color: #33ccff;
margin-left: 1em;
}
-.nav .selected-file {
+.nav-inner .selected-file {
color: white;
cursor: inherit;
font-weight: 600;
@@ -70,13 +79,12 @@
}
.content {
- flex: 1;
+ flex: 1 1 700px;
font-family: monospace;
/* Vertical margin around content. */
margin: 10px 0;
/* Offset the margin introduced by the absolutely positioned child div. */
margin-left: -0.5em;
- min-width: 900px;
position: relative;
white-space: pre;
}
@@ -215,4 +223,8 @@
position: relative;
visibility: visible;
}
+
+.footer {
+ padding: 8px 8px 100px 8px;
+}
''';
diff --git a/pkg/analysis_server/lib/src/edit/nnbd_migration/instrumentation_renderer.dart b/pkg/analysis_server/lib/src/edit/nnbd_migration/instrumentation_renderer.dart
index bc23fbf..632fc35 100644
--- a/pkg/analysis_server/lib/src/edit/nnbd_migration/instrumentation_renderer.dart
+++ b/pkg/analysis_server/lib/src/edit/nnbd_migration/instrumentation_renderer.dart
@@ -29,15 +29,19 @@
<h2 id="unit-name"> </h2>
<div class="panels">
<div class="horizontal">
- <div class="nav" style="">
- <p>Select a source file below to preview the modifications.</p>
- <p class="root">{{ root }}</p>
- {{# links }}
- <a href="{{ path }}" class="nav-link"
- data-name="{{ name }}">{{ name }}</a>
- {{ modificationCount }}
- <br/>
- {{/ links }}
+ <div class="nav">
+ <p class="nav-tip">
+ Select a source file below to preview the modifications.
+ </p>
+ <div class="nav-inner">
+ <p class="root">{{ root }}</p>
+ {{# links }}
+ <a href="{{ path }}" class="nav-link"
+ data-name="{{ name }}">{{ name }}</a>
+ {{ modificationCount }}
+ <br/>
+ {{/ links }}
+ </div><!-- /nav-inner -->
</div><!-- /nav -->
'''
'<div class="content">'
@@ -46,10 +50,10 @@
'{{! The regions are then written again, overlaying the first copy of }}'
'{{! the content, to provide tooltips for modified regions. }}'
'</div><!-- /regions -->'
+ '<div class="footer"><em>Generated on {{ generationDate }}</em></div>'
'</div><!-- /content -->'
'''
</div><!-- /horizontal -->
- <div><em>Generated on {{ generationDate }}</em></div>
</div><!-- /panels -->
<script lang="javascript">
document.addEventListener("DOMContentLoaded", highlightAllCode);
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
index c2dbb1e..a3fdab1 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
@@ -12,7 +12,9 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/util/comment.dart';
+import 'package:meta/meta.dart';
/**
* Determine the number of arguments.
@@ -139,6 +141,64 @@
DartCompletionRequest request;
List<CompletionSuggestion> suggestions;
+ List<CompletionSuggestion> buildClosureSuggestions(
+ DartCompletionRequest request,
+ Expression argument,
+ DartType type,
+ ) {
+ if (type is FunctionType) {
+ var indent = getRequestLineIndent(request);
+ var parametersString = _buildClosureParameters(type);
+
+ var blockBuffer = StringBuffer(parametersString);
+ blockBuffer.writeln(' {');
+ blockBuffer.write('$indent ');
+ var blockSelectionOffset = blockBuffer.length;
+ blockBuffer.writeln();
+ blockBuffer.write('$indent}');
+
+ var expressionBuffer = StringBuffer(parametersString);
+ expressionBuffer.write(' => ');
+ var expressionSelectionOffset = expressionBuffer.length;
+
+ if (argument.endToken.next?.type != TokenType.COMMA) {
+ blockBuffer.write(',');
+ expressionBuffer.write(',');
+ }
+
+ CompletionSuggestion createSuggestion({
+ @required String completion,
+ @required String displayText,
+ @required int selectionOffset,
+ }) {
+ return CompletionSuggestion(
+ CompletionSuggestionKind.INVOCATION,
+ DART_RELEVANCE_HIGH,
+ completion,
+ selectionOffset,
+ 0,
+ false,
+ false,
+ displayText: displayText,
+ );
+ }
+
+ return [
+ createSuggestion(
+ completion: blockBuffer.toString(),
+ displayText: '$parametersString {}',
+ selectionOffset: blockSelectionOffset,
+ ),
+ createSuggestion(
+ completion: expressionBuffer.toString(),
+ displayText: '$parametersString =>',
+ selectionOffset: expressionSelectionOffset,
+ ),
+ ];
+ }
+ return const <CompletionSuggestion>[];
+ }
+
@override
Future<List<CompletionSuggestion>> computeSuggestions(
DartCompletionRequest request) async {
@@ -245,6 +305,14 @@
_addDefaultParamSuggestions(parameters, true);
} else if (_isInsertingToArgListWithSynthetic(request)) {
_addDefaultParamSuggestions(parameters, !_isFollowedByAComma(request));
+ } else {
+ final argument = request.target.containingNode;
+ if (argument is NamedExpression) {
+ final type = argument.staticParameterElement?.type;
+ final closureSuggestions =
+ buildClosureSuggestions(request, argument, type);
+ suggestions.addAll(closureSuggestions);
+ }
}
}
@@ -272,6 +340,38 @@
return newExpr != null && flutter.isWidgetCreation(newExpr);
}
+ static String _buildClosureParameters(FunctionType type) {
+ var buffer = StringBuffer();
+ buffer.write('(');
+
+ var hasNamed = false;
+ var hasOptionalPositional = false;
+ var parameters = type.parameters;
+ for (var i = 0; i < parameters.length; ++i) {
+ var parameter = parameters[i];
+ if (i != 0) {
+ buffer.write(', ');
+ }
+ if (parameter.isNamed && !hasNamed) {
+ hasNamed = true;
+ buffer.write('{');
+ } else if (parameter.isOptionalPositional && !hasOptionalPositional) {
+ hasOptionalPositional = true;
+ buffer.write('[');
+ }
+ buffer.write(parameter.name);
+ }
+
+ if (hasNamed) {
+ buffer.write('}');
+ } else if (hasOptionalPositional) {
+ buffer.write(']');
+ }
+
+ buffer.write(')');
+ return buffer.toString();
+ }
+
/**
* If the given [comment] is not `null`, fill the [suggestion] documentation
* fields.
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/inherited_reference_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/inherited_reference_contributor.dart
index 21c0085..e1c138d 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/inherited_reference_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/inherited_reference_contributor.dart
@@ -6,6 +6,7 @@
import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
import 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart';
+import 'package:analysis_server/src/services/completion/dart/utilities.dart';
import 'package:analysis_server/src/utilities/flutter.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
@@ -127,19 +128,7 @@
element.name == 'setState' &&
Flutter.of(request.result).isExactState(element.enclosingElement)) {
// Find the line indentation.
- String content = request.result.content;
- int lineStartOffset = request.offset;
- int notWhitespaceOffset = request.offset;
- for (; lineStartOffset > 0; lineStartOffset--) {
- var char = content.substring(lineStartOffset - 1, lineStartOffset);
- if (char == '\n') {
- break;
- }
- if (char != ' ' && char != '\t') {
- notWhitespaceOffset = lineStartOffset - 1;
- }
- }
- String indent = content.substring(lineStartOffset, notWhitespaceOffset);
+ String indent = getRequestLineIndent(request);
// Let the user know that we are going to insert a complete statement.
suggestion.displayText = 'setState(() {});';
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart b/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart
index cf43ac8..b2140d3 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart
@@ -24,6 +24,17 @@
const DYNAMIC = 'dynamic';
/**
+ * Sort by relevance first, highest to lowest, and then by the completion
+ * alphabetically.
+ */
+Comparator<CompletionSuggestion> completionComparator = (a, b) {
+ if (a.relevance == b.relevance) {
+ return a.completion.compareTo(b.completion);
+ }
+ return b.relevance.compareTo(a.relevance);
+};
+
+/**
* A marker used in place of `null` when a function has no return type.
*/
final TypeName NO_RETURN_TYPE = astFactory.typeName(
@@ -174,6 +185,22 @@
return null;
}
+String getRequestLineIndent(DartCompletionRequest request) {
+ var content = request.result.content;
+ var lineStartOffset = request.offset;
+ var notWhitespaceOffset = request.offset;
+ for (; lineStartOffset > 0; lineStartOffset--) {
+ var char = content.substring(lineStartOffset - 1, lineStartOffset);
+ if (char == '\n') {
+ break;
+ }
+ if (char != ' ' && char != '\t') {
+ notWhitespaceOffset = lineStartOffset - 1;
+ }
+ }
+ return content.substring(lineStartOffset, notWhitespaceOffset);
+}
+
String getTypeString(DartType type) {
if (type.isDynamic) {
return '';
diff --git a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
index 57f0293..e379cc2 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -1465,6 +1465,11 @@
int replaceOffset = 0;
bool hasBuildMethod = false;
+ var typeParams = '';
+ if (widgetClass.typeParameters != null) {
+ typeParams = utils.getNodeText(widgetClass.typeParameters);
+ }
+
/// Replace code between [replaceOffset] and [replaceEnd] with
/// `createState()`, empty line, or nothing.
void replaceInterval(int replaceEnd,
@@ -1480,7 +1485,8 @@
builder.writeln();
}
builder.writeln(' @override');
- builder.writeln(' $stateName createState() => $stateName();');
+ builder.writeln(
+ ' $stateName$typeParams createState() => $stateName$typeParams();');
if (hasEmptyLineAfterCreateState) {
builder.writeln();
}
@@ -1533,11 +1539,6 @@
builder.writeln();
builder.writeln();
- var typeParams = '';
- if (widgetClass.typeParameters != null) {
- typeParams = utils.getNodeText(widgetClass.typeParameters);
- }
-
builder.write('class $stateName$typeParams extends ');
builder.writeReference(stateClass);
diff --git a/pkg/analysis_server/test/abstract_context.dart b/pkg/analysis_server/test/abstract_context.dart
index e52b7b0..4b10bed 100644
--- a/pkg/analysis_server/test/abstract_context.dart
+++ b/pkg/analysis_server/test/abstract_context.dart
@@ -193,8 +193,8 @@
MockSdk(resourceProvider: resourceProvider);
newFolder('/home/test');
- newFile('/home/test/.packages', content: r'''
-test:file:///home/test/lib
+ newFile('/home/test/.packages', content: '''
+test:${toUriStr('/home/test/lib')}
''');
createAnalysisContexts();
diff --git a/pkg/analysis_server/test/analysis/get_hover_test.dart b/pkg/analysis_server/test/analysis/get_hover_test.dart
index d4fee97..b5319f5 100644
--- a/pkg/analysis_server/test/analysis/get_hover_test.dart
+++ b/pkg/analysis_server/test/analysis/get_hover_test.dart
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
-import 'dart:convert';
import 'package:analysis_server/protocol/protocol.dart';
import 'package:analysis_server/protocol/protocol_generated.dart';
@@ -648,18 +647,8 @@
}
''');
var hover = await prepareHover('f(null)');
- _assertJsonText(hover, r'''
-{
- "offset": 39,
- "length": 1,
- "containingLibraryPath": "/project/bin/test.dart",
- "containingLibraryName": "bin/test.dart",
- "elementDescription": "int? f(double? a)",
- "elementKind": "function",
- "isDeprecated": false,
- "staticType": "int? Function(double?)"
-}
-''');
+ expect(hover.elementDescription, 'int? f(double? a)');
+ expect(hover.staticType, 'int? Function(double?)');
}
test_parameter_declaration_fieldFormal() async {
@@ -727,15 +716,4 @@
expect(hover.elementKind, 'parameter');
expect(hover.staticType, 'int');
}
-
- void _assertJsonText(Object object, String expected) {
- expected = expected.trimRight();
- var actual = JsonEncoder.withIndent(' ').convert(object);
- if (actual != expected) {
- print('-----');
- print(actual);
- print('-----');
- }
- expect(actual, expected);
- }
}
diff --git a/pkg/analysis_server/test/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index 895a345..3fa52ff 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -621,7 +621,7 @@
String packagePathFoo = convertPath('/package1/foo');
String packageRootPath = convertPath('/package2/foo');
newFile('$projPath/${ContextManagerImpl.PACKAGE_SPEC_NAME}',
- content: 'foo:file:///package1/foo');
+ content: 'foo:${toUriStr('/package1/foo')}');
Folder packageFolder = resourceProvider.newFolder(packagePathFoo);
List<String> includedPaths = <String>[projPath];
List<String> excludedPaths = <String>[];
@@ -874,7 +874,7 @@
void test_setRoots_newlyAddedFoldersGetProperPackageMap() {
String packagePath = convertPath('/package/foo');
newFile('$projPath/${ContextManagerImpl.PACKAGE_SPEC_NAME}',
- content: 'foo:file:///package/foo');
+ content: 'foo:${toUriStr('/package/foo')}');
Folder packageFolder = resourceProvider.newFolder(packagePath);
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
expect(
@@ -1058,7 +1058,7 @@
String packageRootPath = convertPath('/package2/foo');
Folder packageFolder = resourceProvider.newFolder(packagePathFoo);
newFile('$projPath/${ContextManagerImpl.PACKAGE_SPEC_NAME}',
- content: 'foo:file:///package1/foo');
+ content: 'foo:${toUriStr('/package1/foo')}');
List<String> includedPaths = <String>[projPath];
List<String> excludedPaths = <String>[];
manager.setRoots(includedPaths, excludedPaths,
@@ -1879,7 +1879,7 @@
''');
// Setup analysis options file which includes another options file.
newFile('$projPath/${ContextManagerImpl.PACKAGE_SPEC_NAME}',
- content: 'boo:$booLibPosixPath\n');
+ content: 'boo:${toUriStr(booLibPosixPath)}\n');
newFile('$projPath/$optionsFileName', content: r'''
include: package:boo/other_options.yaml
''');
diff --git a/pkg/analysis_server/test/domain_analysis_test.dart b/pkg/analysis_server/test/domain_analysis_test.dart
index 6213a77..a3b10b3 100644
--- a/pkg/analysis_server/test/domain_analysis_test.dart
+++ b/pkg/analysis_server/test/domain_analysis_test.dart
@@ -319,7 +319,8 @@
library lib_a;
class A {}
''').path;
- newFile('/project/.packages', content: 'pkgA:file:///packages/pkgA');
+ newFile('/project/.packages',
+ content: 'pkgA:${toUriStr('/packages/pkgA')}');
addTestFile('''
import 'package:pkgA/libA.dart';
main(A a) {
diff --git a/pkg/analysis_server/test/integration/completion/list_token_details_test.dart b/pkg/analysis_server/test/integration/completion/list_token_details_test.dart
index 486ba83..c49b7fb 100644
--- a/pkg/analysis_server/test/integration/completion/list_token_details_test.dart
+++ b/pkg/analysis_server/test/integration/completion/list_token_details_test.dart
@@ -42,7 +42,7 @@
class A {}
''');
writeFile(path.join(testPackagePath, '.packages'), '''
-a:file://$aLibPath
+a:file://${path.toUri(aLibPath)}
test_package:lib/
''');
String testFilePath = path.join(testPackagePath, 'lib', 'test.dart');
diff --git a/pkg/analysis_server/test/search/type_hierarchy_test.dart b/pkg/analysis_server/test/search/type_hierarchy_test.dart
index 9ba052d..a2a1be0 100644
--- a/pkg/analysis_server/test/search/type_hierarchy_test.dart
+++ b/pkg/analysis_server/test/search/type_hierarchy_test.dart
@@ -170,10 +170,10 @@
class B extends A {}
''');
newFile('/packages/pkgA/.packages',
- content: 'pkgA:file:///packages/pkgA/lib');
+ content: 'pkgA:${toUriStr('/packages/pkgA/lib')}');
// reference the package from a project
newFile('$projectPath/.packages',
- content: 'pkgA:file:///packages/pkgA/lib');
+ content: 'pkgA:${toUriStr('/packages/pkgA/lib')}');
addTestFile('''
import 'package:pkgA/libA.dart';
class C extends A {}
diff --git a/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart
index d1e5ff2..8336ebe 100644
--- a/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart
@@ -248,6 +248,134 @@
assertNoSuggestions();
}
+ test_ArgumentList_closureFunction_namedParameter() async {
+ addTestSource(r'''
+void f({void Function(int a, String b) closure}) {}
+
+void main() {
+ f(closure: ^);
+}
+''');
+ await computeSuggestions();
+
+ assertSuggest(
+ '(a, b) => ,',
+ relevance: DART_RELEVANCE_HIGH,
+ selectionOffset: 10,
+ );
+
+ assertSuggest(
+ '''
+(a, b) {
+${' ' * 4}
+${' ' * 2}},''',
+ selectionOffset: 13,
+ );
+ }
+
+ test_ArgumentList_closureFunction_namedParameter_hasComma() async {
+ addTestSource(r'''
+void f({void Function(int a, String b) closure}) {}
+
+void main() {
+ f(
+ closure: ^,
+ );
+}
+''');
+ await computeSuggestions();
+
+ assertSuggest(
+ '(a, b) => ',
+ selectionOffset: 10,
+ );
+
+ assertSuggest(
+ '''
+(a, b) {
+${' ' * 6}
+${' ' * 4}}''',
+ selectionOffset: 15,
+ );
+ }
+
+ /// todo (pq): implement positional functional parameters
+ @failingTest
+ test_ArgumentList_closureFunction_positionalParameter() async {
+ addTestSource(r'''
+void f(void Function(int a, int b) closure) {}
+
+void main() {
+ f(^);
+}
+''');
+ await computeSuggestions();
+
+ assertSuggest(
+ '(a, b, c) => ,',
+ selectionOffset: 13,
+ );
+ }
+
+ test_ArgumentList_closureMethod_namedParameter() async {
+ addTestSource(r'''
+class C {
+ void f({void Function(int a, String b) closure}) {}
+
+ void main() {
+ f(closure: ^);
+ }
+}
+''');
+ await computeSuggestions();
+
+ assertSuggest(
+ '(a, b) => ,',
+ selectionOffset: 10,
+ );
+
+ assertSuggest(
+ '''
+(a, b) {
+${' ' * 6}
+${' ' * 4}},''',
+ selectionOffset: 15,
+ );
+ }
+
+ test_ArgumentList_closureParameterOptionalNamed() async {
+ addTestSource(r'''
+void f({void Function(int a, {int b, int c}) closure}) {}
+
+void main() {
+ f(closure: ^);
+}
+''');
+ await computeSuggestions();
+
+ assertSuggest(
+ '(a, {b, c}) => ,',
+ selectionOffset: 15,
+ );
+ }
+
+ test_ArgumentList_closureParameterOptionalPositional() async {
+ addTestSource(r'''
+void f({void Function(int a, [int b, int c]) closure]) {}
+
+void main() {
+ f(closure: ^);
+}
+''');
+ await computeSuggestions();
+
+ assertSuggest(
+ '(a, [b, c]) => ,',
+ relevance: DART_RELEVANCE_HIGH,
+ selectionOffset: 15,
+ );
+ }
+
test_ArgumentList_Flutter_InstanceCreationExpression_0() async {
addFlutterPackage();
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 25ba5d3..df904f2 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
@@ -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'
show DartCompletionManager, DartCompletionRequestImpl;
+import 'package:analysis_server/src/services/completion/dart/utilities.dart';
import 'package:analyzer/src/generated/parser.dart' as analyzer;
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:meta/meta.dart';
@@ -22,6 +23,25 @@
return c1.compareTo(c2);
}
+SuggestionMatcher suggestionHas(
+ {@required String completion,
+ ElementKind element,
+ CompletionSuggestionKind kind}) =>
+ (CompletionSuggestion s) {
+ if (s.completion == completion) {
+ if (element != null && s.element?.kind != element) {
+ return false;
+ }
+ if (kind != null && s.kind != kind) {
+ return false;
+ }
+ return true;
+ }
+ return false;
+ };
+
+typedef SuggestionMatcher = bool Function(CompletionSuggestion suggestion);
+
/// Base class for tests that validate individual [DartCompletionContributor]
/// suggestions.
abstract class DartCompletionContributorTest
@@ -57,6 +77,15 @@
return completionManager.computeSuggestions(baseRequest);
}
+ /// Display sorted suggestions.
+ void printSuggestions() {
+ suggestions.sort(completionComparator);
+ for (var s in suggestions) {
+ print(
+ '[${s.relevance}] ${s.completion} • ${s.element?.kind?.name ?? ""} ${s.kind.name} ${s.element?.location?.file ?? ""}');
+ }
+ }
+
@override
setUp() {
super.setUp();
@@ -74,6 +103,7 @@
DartCompletionRequest request;
List<CompletionSuggestion> suggestions;
+
/**
* If `true` and `null` is specified as the suggestion's expected returnType
* then the actual suggestion is expected to have a `dynamic` returnType.
@@ -82,7 +112,6 @@
* Eventually all tests should be converted and this getter removed.
*/
bool get isNullExpectedReturnTypeConsideredDynamic => true;
-
/**
* Return `true` if contributors should suggest constructors in contexts where
* there is no `new` or `const` keyword.
@@ -144,7 +173,7 @@
CompletionSuggestion assertSuggest(String completion,
{CompletionSuggestionKind csKind = CompletionSuggestionKind.INVOCATION,
- int relevance = DART_RELEVANCE_DEFAULT,
+ int relevance,
ElementKind elemKind,
bool isDeprecated = false,
bool isPotential = false,
@@ -161,9 +190,9 @@
failedCompletion('expected $completion $csKind $elemKind', suggestions);
}
expect(cs.kind, equals(csKind));
- if (isDeprecated) {
- expect(cs.relevance, equals(DART_RELEVANCE_LOW));
- } else {
+ // todo (pq): remove when all relevance tests have been migrated
+ // see: https://github.com/dart-lang/sdk/issues/40104
+ if (relevance != null) {
expect(cs.relevance, equals(relevance), reason: completion);
}
expect(cs.selectionOffset, equals(selectionOffset ?? completion.length));
@@ -200,7 +229,7 @@
}
CompletionSuggestion assertSuggestClass(String name,
- {int relevance = DART_RELEVANCE_DEFAULT,
+ {int relevance,
CompletionSuggestionKind kind = CompletionSuggestionKind.INVOCATION,
bool isDeprecated = false,
String elemFile,
@@ -224,7 +253,7 @@
}
CompletionSuggestion assertSuggestClassTypeAlias(String name,
- {int relevance = DART_RELEVANCE_DEFAULT,
+ {int relevance,
CompletionSuggestionKind kind = CompletionSuggestionKind.INVOCATION}) {
CompletionSuggestion cs =
assertSuggest(name, csKind: kind, relevance: relevance);
@@ -239,7 +268,7 @@
}
CompletionSuggestion assertSuggestConstructor(String name,
- {int relevance = DART_RELEVANCE_DEFAULT,
+ {int relevance,
String elementName,
int elemOffset,
String defaultArgListString = _UNCHECKED,
@@ -272,6 +301,11 @@
{int relevance = DART_RELEVANCE_DEFAULT,
bool isDeprecated = false,
bool hasTypeBoost = false}) {
+ // todo (pq): remove when all relevance tests have been migrated
+ // see: https://github.com/dart-lang/sdk/issues/40104
+ if (isDeprecated) {
+ relevance = DART_RELEVANCE_LOW;
+ }
if (hasTypeBoost) {
relevance += DART_RELEVANCE_BOOST_TYPE;
}
@@ -284,7 +318,7 @@
}
CompletionSuggestion assertSuggestField(String name, String type,
- {int relevance = DART_RELEVANCE_DEFAULT,
+ {int relevance,
CompletionSuggestionKind kind = CompletionSuggestionKind.INVOCATION,
bool isDeprecated = false}) {
CompletionSuggestion cs = assertSuggest(name,
@@ -308,7 +342,7 @@
CompletionSuggestion assertSuggestFunction(String name, String returnType,
{CompletionSuggestionKind kind = CompletionSuggestionKind.INVOCATION,
bool isDeprecated = false,
- int relevance = DART_RELEVANCE_DEFAULT,
+ int relevance,
String defaultArgListString = _UNCHECKED,
List<int> defaultArgumentListTextRanges}) {
CompletionSuggestion cs = assertSuggest(name,
@@ -344,7 +378,7 @@
String name,
String returnType, {
bool isDeprecated = false,
- int relevance = DART_RELEVANCE_DEFAULT,
+ int relevance,
CompletionSuggestionKind kind = CompletionSuggestionKind.INVOCATION,
}) {
CompletionSuggestion cs = assertSuggest(name,
@@ -374,7 +408,7 @@
}
CompletionSuggestion assertSuggestGetter(String name, String returnType,
- {int relevance = DART_RELEVANCE_DEFAULT,
+ {int relevance,
CompletionSuggestionKind kind = CompletionSuggestionKind.INVOCATION,
bool isDeprecated = false}) {
CompletionSuggestion cs = assertSuggest(name,
@@ -396,7 +430,7 @@
CompletionSuggestion assertSuggestMethod(
String name, String declaringType, String returnType,
- {int relevance = DART_RELEVANCE_DEFAULT,
+ {int relevance,
CompletionSuggestionKind kind = CompletionSuggestionKind.INVOCATION,
bool isDeprecated = false,
String defaultArgListString = _UNCHECKED,
@@ -423,7 +457,7 @@
}
CompletionSuggestion assertSuggestMixin(String name,
- {int relevance = DART_RELEVANCE_DEFAULT,
+ {int relevance,
CompletionSuggestionKind kind = CompletionSuggestionKind.INVOCATION,
bool isDeprecated = false,
String elemFile,
@@ -447,7 +481,7 @@
}
CompletionSuggestion assertSuggestName(String name,
- {int relevance = DART_RELEVANCE_DEFAULT,
+ {int relevance,
CompletionSuggestionKind kind = CompletionSuggestionKind.IDENTIFIER,
bool isDeprecated = false}) {
CompletionSuggestion cs = assertSuggest(name,
@@ -459,7 +493,7 @@
}
CompletionSuggestion assertSuggestSetter(String name,
- {int relevance = DART_RELEVANCE_DEFAULT,
+ {int relevance,
CompletionSuggestionKind kind = CompletionSuggestionKind.INVOCATION}) {
CompletionSuggestion cs = assertSuggest(name,
csKind: kind, relevance: relevance, elemKind: ElementKind.SETTER);
@@ -480,7 +514,7 @@
CompletionSuggestion assertSuggestTopLevelVar(
String name,
String returnType, {
- int relevance = DART_RELEVANCE_DEFAULT,
+ int relevance,
CompletionSuggestionKind kind = CompletionSuggestionKind.INVOCATION,
}) {
CompletionSuggestion cs =
@@ -530,7 +564,7 @@
if (completions != null) {
sb.write('\n found');
completions.toList()
- ..sort(suggestionComparator)
+ ..sort(completionComparator)
..forEach((CompletionSuggestion suggestion) {
sb.write('\n ${suggestion.completion} -> $suggestion');
});
@@ -591,4 +625,14 @@
super.setUp();
testFile = convertPath('/home/test/lib/test.dart');
}
+
+ CompletionSuggestion suggestionWith(
+ {@required String completion,
+ ElementKind element,
+ CompletionSuggestionKind kind}) {
+ final matches = suggestions.where(
+ suggestionHas(completion: completion, element: element, kind: kind));
+ expect(matches, hasLength(1));
+ return matches.first;
+ }
}
diff --git a/pkg/analysis_server/test/services/completion/dart/imported_reference_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/imported_reference_contributor_test.dart
index feae0c9..a717054 100644
--- a/pkg/analysis_server/test/services/completion/dart/imported_reference_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/imported_reference_contributor_test.dart
@@ -4464,4 +4464,16 @@
await computeSuggestions();
assertSuggestMixin('M');
}
+
+ test_YieldStatement() async {
+ addTestSource('''
+void main() async* {
+ yield ^
+}
+''');
+ await computeSuggestions();
+
+ // Sanity check any completions.
+ assertSuggestClass('Object');
+ }
}
diff --git a/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart
index c0111db..28662d4 100644
--- a/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart
@@ -5007,6 +5007,18 @@
await computeSuggestions();
assertSuggestMixin('M');
}
+
+ test_YieldStatement() async {
+ addTestSource('''
+void main() async* {
+ var value;
+ yield v^
+}
+''');
+ await computeSuggestions();
+
+ assertSuggestLocalVariable('value', null);
+ }
}
@reflectiveTest
diff --git a/pkg/analysis_server/test/services/completion/dart/relevance/arglist_parameter_relevance_test.dart b/pkg/analysis_server/test/services/completion/dart/relevance/arglist_parameter_relevance_test.dart
new file mode 100644
index 0000000..34e36ee
--- /dev/null
+++ b/pkg/analysis_server/test/services/completion/dart/relevance/arglist_parameter_relevance_test.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer_plugin/utilities/completion/relevance.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../completion_contributor_util.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(ArglistParameterRelevanceTest);
+ });
+}
+
+@reflectiveTest
+class ArglistParameterRelevanceTest extends DartCompletionManagerTest {
+ test_closureParam() async {
+ addTestSource(r'''
+void f({void Function(int a, {int b, int c}) closure}) {}
+
+void main() {
+ f(closure: ^);
+}
+''');
+ await computeSuggestions();
+
+ assertSuggest(
+ '(a, {b, c}) => ,',
+ // todo (pq): replace w/ a test of relative relevance
+ relevance: DART_RELEVANCE_HIGH,
+ selectionOffset: 15,
+ );
+ }
+}
diff --git a/pkg/analysis_server/test/services/completion/dart/relevance/bool_assignment_relevance_test.dart b/pkg/analysis_server/test/services/completion/dart/relevance/bool_assignment_relevance_test.dart
new file mode 100644
index 0000000..f39ef0d
--- /dev/null
+++ b/pkg/analysis_server/test/services/completion/dart/relevance/bool_assignment_relevance_test.dart
@@ -0,0 +1,72 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer_plugin/protocol/protocol_common.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../completion_contributor_util.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(BoolAssignmentRelevanceTest);
+ });
+}
+
+@reflectiveTest
+class BoolAssignmentRelevanceTest extends DartCompletionManagerTest {
+ /// These are 2 failing tests for http://dartbug.com/37907:
+ /// "Suggest `false` above other results when autocompleting a bool setter"
+ @failingTest
+ test_boolLiterals_local() async {
+ addTestSource('''
+foo() {
+ bool b;
+ b = ^
+}
+''');
+ await computeSuggestions();
+
+ var trueSuggestion = suggestionWith(
+ completion: 'true', kind: CompletionSuggestionKind.KEYWORD);
+
+ var falseSuggestion = suggestionWith(
+ completion: 'false', kind: CompletionSuggestionKind.KEYWORD);
+
+ var bLocalVar = suggestionWith(
+ completion: 'b',
+ element: ElementKind.LOCAL_VARIABLE,
+ kind: CompletionSuggestionKind.INVOCATION);
+
+ expect(trueSuggestion.relevance, greaterThan(bLocalVar.relevance));
+ expect(falseSuggestion.relevance, greaterThan(bLocalVar.relevance));
+ }
+
+ @failingTest
+ test_boolLiterals_imported() async {
+ addTestSource('''
+foo() {
+ bool b;
+ b = ^
+}
+''');
+ await computeSuggestions();
+
+ var trueSuggestion = suggestionWith(
+ completion: 'true', kind: CompletionSuggestionKind.KEYWORD);
+
+ var falseSuggestion = suggestionWith(
+ completion: 'false', kind: CompletionSuggestionKind.KEYWORD);
+
+ var boolFromEnvironment = suggestionWith(
+ completion: 'bool.fromEnvironment',
+ element: ElementKind.CONSTRUCTOR,
+ kind: CompletionSuggestionKind.INVOCATION);
+
+ expect(
+ trueSuggestion.relevance, greaterThan(boolFromEnvironment.relevance));
+ expect(
+ falseSuggestion.relevance, greaterThan(boolFromEnvironment.relevance));
+ }
+}
diff --git a/pkg/analysis_server/test/services/completion/dart/relevance/deprecated_member_relevance_test.dart b/pkg/analysis_server/test/services/completion/dart/relevance/deprecated_member_relevance_test.dart
new file mode 100644
index 0000000..dbc3884
--- /dev/null
+++ b/pkg/analysis_server/test/services/completion/dart/relevance/deprecated_member_relevance_test.dart
@@ -0,0 +1,46 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer_plugin/protocol/protocol_common.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../completion_contributor_util.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(DeprecatedMemberRelevanceTest);
+ });
+}
+
+@reflectiveTest
+class DeprecatedMemberRelevanceTest extends DartCompletionManagerTest {
+ test_deprecated() async {
+ addTestSource('''
+class A {
+ void a1() { }
+ @deprecated
+ void a2() { }
+}
+
+void main() {
+ var a = A();
+ a.^
+}
+''');
+ await computeSuggestions();
+
+ expect(
+ suggestionWith(
+ completion: 'a2',
+ element: ElementKind.METHOD,
+ kind: CompletionSuggestionKind.INVOCATION)
+ .relevance,
+ lessThan(suggestionWith(
+ completion: 'a1',
+ element: ElementKind.METHOD,
+ kind: CompletionSuggestionKind.INVOCATION)
+ .relevance));
+ }
+}
diff --git a/pkg/analysis_server/test/services/completion/dart/relevance/test_all.dart b/pkg/analysis_server/test/services/completion/dart/relevance/test_all.dart
new file mode 100644
index 0000000..36651e0
--- /dev/null
+++ b/pkg/analysis_server/test/services/completion/dart/relevance/test_all.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'arglist_parameter_relevance_test.dart' as arglist_parameters;
+import 'bool_assignment_relevance_test.dart' as bool_assignments;
+import 'deprecated_member_relevance_test.dart' as deprecated_members;
+
+main() {
+ defineReflectiveSuite(() {
+ arglist_parameters.main();
+ bool_assignments.main();
+ deprecated_members.main();
+ });
+}
diff --git a/pkg/analysis_server/test/services/completion/dart/test_all.dart b/pkg/analysis_server/test/services/completion/dart/test_all.dart
index 3bf866a..834e5cf 100644
--- a/pkg/analysis_server/test/services/completion/dart/test_all.dart
+++ b/pkg/analysis_server/test/services/completion/dart/test_all.dart
@@ -27,6 +27,7 @@
import 'local_reference_contributor_test.dart' as local_ref_test;
import 'named_constructor_contributor_test.dart' as named_contributor_test;
import 'override_contributor_test.dart' as override_contributor_test;
+import 'relevance/test_all.dart' as relevance_tests;
import 'static_member_contributor_test.dart' as static_contributor_test;
import 'type_member_contributor_test.dart' as type_member_contributor_test;
import 'uri_contributor_test.dart' as uri_contributor_test;
@@ -58,6 +59,7 @@
local_ref_test.main();
named_contributor_test.main();
override_contributor_test.main();
+ relevance_tests.main();
static_contributor_test.main();
type_member_contributor_test.main();
uri_contributor_test.main();
diff --git a/pkg/analysis_server/test/src/services/correction/assist/flutter_convert_to_stateful_widget_test.dart b/pkg/analysis_server/test/src/services/correction/assist/flutter_convert_to_stateful_widget_test.dart
index 8d38b88..bb90063 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/flutter_convert_to_stateful_widget_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/flutter_convert_to_stateful_widget_test.dart
@@ -65,7 +65,7 @@
class MyWidget<T> extends StatefulWidget {
@override
- _MyWidgetState createState() => _MyWidgetState();
+ _MyWidgetState<T> createState() => _MyWidgetState<T>();
}
class _MyWidgetState<T> extends State<MyWidget<T>> {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_unused_element_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_unused_element_test.dart
index 77d6f54..9f6a7928 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_unused_element_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_unused_element_test.dart
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analyzer/error/error.dart';
+import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -22,12 +24,13 @@
test_class_notUsed_inClassMember() async {
await resolveTestUnit(r'''
class _A {
- static staticMethod() {
+ staticMethod() {
new _A();
}
}
''');
- // todo (pq): consider supporting the case where references are limited to within the class.
+ // TODO(pq): consider supporting the case where references are limited to
+ // within the class.
await assertNoFix();
}
@@ -57,7 +60,9 @@
enum _MyEnum {A, B, C}
''');
await assertHasFix(r'''
-''');
+''', errorFilter: (AnalysisError error) {
+ return error.errorCode == HintCode.UNUSED_ELEMENT;
+ });
}
test_functionLocal_notUsed_noReference() async {
@@ -132,6 +137,52 @@
''');
}
+ test_staticMethod_extension_notUsed_noReference() async {
+ await resolveTestUnit(r'''
+extension _E on String {
+ static int m1() => 3;
+ int m2() => 7;
+}
+void f() => print(_E("hello").m2());
+''');
+ await assertHasFix(r'''
+extension _E on String {
+ int m2() => 7;
+}
+void f() => print(_E("hello").m2());
+''');
+ }
+
+ test_staticMethod_mixim_notUsed_noReference() async {
+ await resolveTestUnit(r'''
+mixin _M {
+ static int m1() => 3;
+}
+class C with _M {}
+void f(C c) {}
+''');
+ await assertHasFix(r'''
+mixin _M {
+}
+class C with _M {}
+void f(C c) {}
+''');
+ }
+
+ test_staticMethod_notUsed_noReference() async {
+ await resolveTestUnit(r'''
+class _A {
+ static int m() => 7;
+}
+void f(_A a) {}
+''');
+ await assertHasFix(r'''
+class _A {
+}
+void f(_A a) {}
+''');
+ }
+
test_topLevelVariable_notUsed() async {
await resolveTestUnit(r'''
int _a = 1;
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_unused_field_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_unused_field_test.dart
index a398ef8..139fb95 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_unused_field_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_unused_field_test.dart
@@ -19,6 +19,18 @@
@override
FixKind get kind => DartFixKind.REMOVE_UNUSED_FIELD;
+ @FailingTest(reason: 'Unimplemented')
+ test_enumValue_notUsed_noReference() async {
+ await resolveTestUnit(r'''
+enum _E { a, b, c }
+bool f(_E e) => e == _E.a || e == _E.b;
+''');
+ await assertHasFix(r'''
+enum _E { a, b }
+bool f(_E e) => e == _E.a || e == _E.b;
+''');
+ }
+
test_unusedField_notUsed_assign() async {
await resolveTestUnit(r'''
class A {
diff --git a/pkg/analysis_server/tool/completion_metrics/completion_metrics.dart b/pkg/analysis_server/tool/completion_metrics/completion_metrics.dart
new file mode 100644
index 0000000..792ee56
--- /dev/null
+++ b/pkg/analysis_server/tool/completion_metrics/completion_metrics.dart
@@ -0,0 +1,105 @@
+// 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:math';
+
+import 'package:analysis_server/src/protocol_server.dart';
+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:analysis_server/src/services/completion/dart/utilities.dart';
+import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/src/generated/engine.dart';
+
+import 'visitors.dart';
+
+int includedCount = 0;
+int notIncludedCount = 0;
+
+const bool doPrintExpectedCompletions = true;
+
+main() {
+ List<String> analysisRoots = [''];
+ _computeCompletionMetrics(PhysicalResourceProvider.INSTANCE, analysisRoots);
+}
+
+/// TODO(jwren) put the following methods into a class
+Future _computeCompletionMetrics(
+ ResourceProvider resourceProvider, List<String> analysisRoots) async {
+ for (var root in analysisRoots) {
+ print('Analyzing root: $root');
+ final collection = AnalysisContextCollection(
+ includedPaths: [root],
+ resourceProvider: resourceProvider,
+ );
+
+ for (var context in collection.contexts) {
+ for (var filePath in context.contextRoot.analyzedFiles()) {
+ if (AnalysisEngine.isDartFileName(filePath)) {
+ try {
+ final result =
+ await context.currentSession.getResolvedUnit(filePath);
+ final visitor = CompletionMetricVisitor();
+
+ result.unit.accept(visitor);
+ var expectedCompletions = visitor.expectedCompletions;
+
+ for (var expectedCompletion in expectedCompletions) {
+ var completionContributor = DartCompletionManager();
+ var completionRequestImpl = CompletionRequestImpl(
+ result,
+ expectedCompletion.offset,
+ CompletionPerformance(),
+ );
+ var suggestions = await completionContributor
+ .computeSuggestions(completionRequestImpl);
+ suggestions.sort(completionComparator);
+
+ var fraction =
+ _placementInSuggestionList(suggestions, expectedCompletion);
+ if (fraction.y != 0) {
+ includedCount++;
+ } else {
+ notIncludedCount++;
+ if (doPrintExpectedCompletions) {
+ print(
+ '\t$filePath at ${expectedCompletion.offset} did not include \'${expectedCompletion.completion}\'');
+ }
+ }
+ }
+ } catch (e) {
+ print('Exception caught analyzing: $filePath');
+ print(e.toString());
+ }
+ }
+ }
+ }
+ }
+ print('done $includedCount $notIncludedCount');
+
+ final percentIncluded = includedCount / (includedCount + notIncludedCount);
+ final percentNotIncluded =
+ notIncludedCount / (includedCount + notIncludedCount);
+ print(
+ 'done ${_formatPercentToString(percentIncluded)} ${_formatPercentToString(percentNotIncluded)}');
+}
+
+Point<int> _placementInSuggestionList(List<CompletionSuggestion> suggestions,
+ ExpectedCompletion expectedCompletion) {
+ var i = 1;
+ for (var completionSuggestion in suggestions) {
+ if (expectedCompletion.matches(completionSuggestion)) {
+ return Point(i, suggestions.length);
+ }
+ i++;
+ }
+ return Point(0, 0);
+}
+
+String _formatPercentToString(double percent, [fractionDigits = 1]) {
+ return (percent * 100).toStringAsFixed(fractionDigits) + '%';
+}
diff --git a/pkg/analysis_server/tool/completion_metrics/visitors.dart b/pkg/analysis_server/tool/completion_metrics/visitors.dart
new file mode 100644
index 0000000..f569338
--- /dev/null
+++ b/pkg/analysis_server/tool/completion_metrics/visitors.dart
@@ -0,0 +1,132 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/protocol_server.dart' as protocol;
+import 'package:analysis_server/src/services/completion/dart/keyword_contributor.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/syntactic_entity.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+
+class CompletionMetricVisitor extends RecursiveAstVisitor {
+ // TODO(jwren) implement missing visit* methods
+
+ final List<ExpectedCompletion> expectedCompletions;
+
+ CompletionMetricVisitor() : expectedCompletions = <ExpectedCompletion>[];
+
+ safelyRecordKeywordCompletion(SyntacticEntity entity) {
+ safelyRecordEntity(entity, kind: protocol.CompletionSuggestionKind.KEYWORD);
+ }
+
+ safelyRecordEntity(SyntacticEntity entity,
+ {protocol.CompletionSuggestionKind kind,
+ protocol.ElementKind elementKind}) {
+ // Only record if this entity is not null, has a length, etc.
+ if (entity != null && entity.offset > 0 && entity.length > 0) {
+ // Some special cases in the if and if-else blocks, 'import' from the
+ // DAS is "import '';" which we want to be sure to match.
+ if (entity.toString() == 'async') {
+ expectedCompletions.add(ExpectedCompletion.specialCompletionString(
+ entity, ASYNC_STAR, kind, elementKind));
+ } else if (entity.toString() == 'default') {
+ expectedCompletions.add(ExpectedCompletion.specialCompletionString(
+ entity, DEFAULT_COLON, kind, elementKind));
+ } else if (entity.toString() == 'deferred') {
+ expectedCompletions.add(ExpectedCompletion.specialCompletionString(
+ entity, DEFERRED_AS, kind, elementKind));
+ } else if (entity.toString() == 'export') {
+ expectedCompletions.add(ExpectedCompletion.specialCompletionString(
+ entity, EXPORT_STATEMENT, kind, elementKind));
+ } else if (entity.toString() == 'import') {
+ expectedCompletions.add(ExpectedCompletion.specialCompletionString(
+ entity, IMPORT_STATEMENT, kind, elementKind));
+ } else if (entity.toString() == 'part') {
+ expectedCompletions.add(ExpectedCompletion.specialCompletionString(
+ entity, PART_STATEMENT, kind, elementKind));
+ } else if (entity.toString() == 'sync') {
+ expectedCompletions.add(ExpectedCompletion.specialCompletionString(
+ entity, SYNC_STAR, kind, elementKind));
+ } else if (entity.toString() == 'yield') {
+ expectedCompletions.add(ExpectedCompletion.specialCompletionString(
+ entity, YIELD_STAR, kind, elementKind));
+ } else {
+ expectedCompletions.add(ExpectedCompletion(entity, kind, elementKind));
+ }
+ }
+ }
+
+ @override
+ visitDoStatement(DoStatement node) {
+ safelyRecordKeywordCompletion(node.doKeyword);
+ return super.visitDoStatement(node);
+ }
+
+ @override
+ visitIfStatement(IfStatement node) {
+ safelyRecordKeywordCompletion(node.ifKeyword);
+ return super.visitIfStatement(node);
+ }
+
+ @override
+ visitImportDirective(ImportDirective node) {
+ safelyRecordKeywordCompletion(node.keyword);
+ safelyRecordKeywordCompletion(node.asKeyword);
+ return super.visitImportDirective(node);
+ }
+
+ @override
+ visitSimpleIdentifier(SimpleIdentifier node) {
+ if (!node.isSynthetic && !node.inDeclarationContext()) {
+ var elementKind;
+ if (node.staticElement?.kind != null) {
+ elementKind = protocol.convertElementKind(node.staticElement?.kind);
+ }
+ safelyRecordEntity(node, elementKind: elementKind);
+ }
+ return super.visitSimpleIdentifier(node);
+ }
+}
+
+class ExpectedCompletion {
+ final SyntacticEntity _entity;
+
+ /// Some completions are special cased from the DAS "import" for instance is
+ /// suggested as a completion "import '';", the completion string here in this
+ /// instance would have the value "import '';".
+ final String _completionString;
+
+ final protocol.CompletionSuggestionKind _kind;
+
+ final protocol.ElementKind _elementKind;
+
+ ExpectedCompletion(this._entity, this._kind, this._elementKind)
+ : _completionString = null;
+
+ ExpectedCompletion.specialCompletionString(
+ this._entity, this._completionString, this._kind, this._elementKind);
+
+ SyntacticEntity get syntacticEntity => _entity;
+
+ String get completion => _completionString ?? _entity.toString();
+
+ int get offset => _entity.offset;
+
+ protocol.CompletionSuggestionKind get kind => _kind;
+
+ protocol.ElementKind get elementKind => _elementKind;
+
+ bool matches(protocol.CompletionSuggestion completionSuggestion) {
+ if (completionSuggestion.completion == completion) {
+ if (kind != null && completionSuggestion.kind != kind) {
+ return false;
+ }
+ if (elementKind != null &&
+ completionSuggestion.element?.kind != elementKind) {
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 53e94bc..61084a9 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -417,6 +417,7 @@
HintCode.OVERRIDE_ON_NON_OVERRIDING_METHOD,
HintCode.OVERRIDE_ON_NON_OVERRIDING_SETTER,
HintCode.PACKAGE_IMPORT_CONTAINS_DOT_DOT,
+ HintCode.RECEIVER_OF_TYPE_NEVER,
HintCode.SDK_VERSION_ASYNC_EXPORTED_FROM_CORE,
HintCode.SDK_VERSION_AS_EXPRESSION_IN_CONST_CONTEXT,
HintCode.SDK_VERSION_BOOL_OPERATOR_IN_CONST_CONTEXT,
@@ -735,7 +736,6 @@
StaticWarningCode.INSTANTIATE_ABSTRACT_CLASS,
StaticWarningCode.INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_NAMED,
StaticWarningCode.INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_POSITIONAL,
- StaticWarningCode.INVALID_USE_OF_NEVER_VALUE,
StaticWarningCode.INVALID_USE_OF_NULL_VALUE,
StaticWarningCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE,
StaticWarningCode.MAP_KEY_TYPE_NOT_ASSIGNABLE,
diff --git a/pkg/analyzer/lib/src/context/builder.dart b/pkg/analyzer/lib/src/context/builder.dart
index b12d22e..0ac63bf 100644
--- a/pkg/analyzer/lib/src/context/builder.dart
+++ b/pkg/analyzer/lib/src/context/builder.dart
@@ -41,7 +41,6 @@
import 'package:analyzer/src/workspace/pub.dart';
import 'package:analyzer/src/workspace/workspace.dart';
import 'package:args/args.dart';
-import 'package:package_config/packages.dart' as package_config;
import 'package:path/src/context.dart';
import 'package:yaml/yaml.dart';
@@ -538,21 +537,6 @@
return null;
}
- static Map<String, List<Folder>> convertPackagesToMap(
- ResourceProvider resourceProvider,
- package_config.Packages packages,
- ) {
- Map<String, List<Folder>> folderMap = HashMap<String, List<Folder>>();
- if (packages != null && packages != package_config.Packages.noPackages) {
- var pathContext = resourceProvider.pathContext;
- packages.asMap().forEach((String packageName, Uri uri) {
- String path = fileUriToNormalizedPath(pathContext, uri);
- folderMap[packageName] = [resourceProvider.getFolder(path)];
- });
- }
- return folderMap;
- }
-
static Workspace createWorkspace(ResourceProvider resourceProvider,
String rootPath, ContextBuilder contextBuilder) {
var packages = contextBuilder.createPackageMap(rootPath);
diff --git a/pkg/analyzer/lib/src/context/packages.dart b/pkg/analyzer/lib/src/context/packages.dart
index 2552f33..b66b107 100644
--- a/pkg/analyzer/lib/src/context/packages.dart
+++ b/pkg/analyzer/lib/src/context/packages.dart
@@ -9,6 +9,37 @@
import 'package:package_config/packages_file.dart' as dot_packages;
import 'package:pub_semver/pub_semver.dart';
+/// Find [Packages] starting from the given [start] resource.
+///
+/// Looks for `.dart_tool/package_config.json` or `.packages` in the given
+/// and parent directories.
+Packages findPackagesFrom(ResourceProvider provider, Resource start) {
+ for (var current = start; current != null; current = current.parent) {
+ if (current is Folder) {
+ try {
+ var jsonFile = current
+ .getChildAssumingFolder('.dart_tool')
+ .getChildAssumingFile('package_config.json');
+ if (jsonFile.exists) {
+ return parsePackageConfigJsonFile(provider, jsonFile);
+ }
+ } catch (e) {
+ return Packages.empty;
+ }
+
+ try {
+ var dotFile = current.getChildAssumingFile('.packages');
+ if (dotFile.exists) {
+ return parseDotPackagesFile(provider, dotFile);
+ }
+ } catch (e) {
+ return Packages.empty;
+ }
+ }
+ }
+ return Packages.empty;
+}
+
/// Parse the [file] as a `.packages` file.
Packages parseDotPackagesFile(ResourceProvider provider, File file) {
var uri = file.toUri();
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index bdd7dc6..ceabe27 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -89,7 +89,7 @@
/// TODO(scheglov) Clean up the list of implicitly analyzed files.
class AnalysisDriver implements AnalysisDriverGeneric {
/// The version of data format, should be incremented on every format change.
- static const int DATA_VERSION = 94;
+ static const int DATA_VERSION = 95;
/// The length of the list returned by [_computeDeclaredVariablesSignature].
static const int _declaredVariablesSignatureLength = 4;
diff --git a/pkg/analyzer/lib/src/dart/analysis/feature_set_provider.dart b/pkg/analyzer/lib/src/dart/analysis/feature_set_provider.dart
index 1d30292..092f0b2 100644
--- a/pkg/analyzer/lib/src/dart/analysis/feature_set_provider.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/feature_set_provider.dart
@@ -102,25 +102,7 @@
return Packages(const {});
}
- var current = resourceProvider.getFolder(contextRoot.root);
- for (; current != null; current = current.parent) {
- try {
- var jsonFile = current
- .getChildAssumingFolder('.dart_tool')
- .getChildAssumingFile('package_config.json');
- if (jsonFile.exists) {
- return parsePackageConfigJsonFile(resourceProvider, jsonFile);
- }
- } catch (_) {}
-
- try {
- var dotFile = current.getChildAssumingFile('.packages');
- if (dotFile.exists) {
- return parseDotPackagesFile(resourceProvider, dotFile);
- }
- } catch (_) {}
- }
-
- return Packages(const {});
+ var rootFolder = resourceProvider.getFolder(contextRoot.root);
+ return findPackagesFrom(resourceProvider, rootFolder);
}
}
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
index be22490..d0a5a00 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
@@ -1351,6 +1351,27 @@
"A package import shouldn't contain '..'.");
/**
+ * It is not an error to call or tear-off a method, setter, or getter, or to
+ * read or write a field, on a receiver of static type `Never`.
+ * Implementations that provide feedback about dead or unreachable code are
+ * encouraged to indicate that any arguments to the invocation are
+ * unreachable.
+ *
+ * It is not an error to apply an expression of type `Never` in the function
+ * position of a function call. Implementations that provide feedback about
+ * dead or unreachable code are encouraged to indicate that any arguments to
+ * the call are unreachable.
+ *
+ * Parameters: none
+ */
+ static const HintCode RECEIVER_OF_TYPE_NEVER = HintCode(
+ 'RECEIVER_OF_TYPE_NEVER',
+ 'The receiver expression is of type Never, and will never complete '
+ 'with a value.',
+ correction: 'Try checking for throw expressions or type errors in the'
+ ' target expression');
+
+ /**
* No parameters.
*/
// #### Description
diff --git a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
new file mode 100644
index 0000000..fea4045
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
@@ -0,0 +1,328 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/dart/element/type_provider.dart';
+import 'package:analyzer/error/listener.dart';
+import 'package:analyzer/src/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
+import 'package:analyzer/src/dart/resolver/invocation_inference_helper.dart';
+import 'package:analyzer/src/dart/resolver/resolution_result.dart';
+import 'package:analyzer/src/dart/resolver/type_property_resolver.dart';
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/element_type_provider.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/type_system.dart';
+import 'package:analyzer/src/task/strong/checker.dart';
+import 'package:meta/meta.dart';
+
+/// Helper for resolving [AssignmentExpression]s.
+class AssignmentExpressionResolver {
+ final ResolverVisitor _resolver;
+ final FlowAnalysisHelper _flowAnalysis;
+ final ElementTypeProvider _elementTypeProvider;
+ final TypePropertyResolver _typePropertyResolver;
+ final InvocationInferenceHelper _inferenceHelper;
+
+ AssignmentExpressionResolver({
+ @required ResolverVisitor resolver,
+ @required FlowAnalysisHelper flowAnalysis,
+ @required ElementTypeProvider elementTypeProvider,
+ }) : _resolver = resolver,
+ _flowAnalysis = flowAnalysis,
+ _elementTypeProvider = elementTypeProvider,
+ _typePropertyResolver = resolver.typePropertyResolver,
+ _inferenceHelper = resolver.inferenceHelper;
+
+ ErrorReporter get _errorReporter => _resolver.errorReporter;
+
+ bool get _isNonNullableByDefault => _typeSystem.isNonNullableByDefault;
+
+ TypeProvider get _typeProvider => _resolver.typeProvider;
+
+ TypeSystemImpl get _typeSystem => _resolver.typeSystem;
+
+ void resolve(AssignmentExpressionImpl node) {
+ var left = node.leftHandSide;
+ var right = node.rightHandSide;
+
+ left?.accept(_resolver);
+ left = node.leftHandSide;
+
+ var leftLocalVariable = _flowAnalysis?.assignmentExpression(node);
+
+ TokenType operator = node.operator.type;
+ if (operator == TokenType.EQ ||
+ operator == TokenType.QUESTION_QUESTION_EQ) {
+ InferenceContext.setType(right, left.staticType);
+ }
+
+ right?.accept(_resolver);
+ right = node.rightHandSide;
+
+ _resolve1(node);
+ _resolve2(node);
+
+ _flowAnalysis?.assignmentExpression_afterRight(
+ node,
+ leftLocalVariable,
+ operator == TokenType.QUESTION_QUESTION_EQ
+ ? node.rightHandSide.staticType
+ : node.staticType);
+ }
+
+ void _resolve1(AssignmentExpressionImpl node) {
+ Token operator = node.operator;
+ TokenType operatorType = operator.type;
+ Expression leftHandSide = node.leftHandSide;
+ DartType staticType = _getStaticType1(leftHandSide, read: true);
+
+ if (identical(staticType, NeverTypeImpl.instance)) {
+ return;
+ }
+
+ // For any compound assignments to a void or nullable variable, report it.
+ // Example: `y += voidFn()`, not allowed.
+ if (operatorType != TokenType.EQ) {
+ if (staticType != null && staticType.isVoid) {
+ _errorReporter.reportErrorForToken(
+ StaticWarningCode.USE_OF_VOID_RESULT,
+ operator,
+ );
+ return;
+ }
+ }
+
+ if (operatorType != TokenType.AMPERSAND_AMPERSAND_EQ &&
+ operatorType != TokenType.BAR_BAR_EQ &&
+ operatorType != TokenType.EQ &&
+ operatorType != TokenType.QUESTION_QUESTION_EQ) {
+ operatorType = operatorFromCompoundAssignment(operatorType);
+ if (leftHandSide != null) {
+ String methodName = operatorType.lexeme;
+ // TODO(brianwilkerson) Change the [methodNameNode] from the left hand
+ // side to the operator.
+ var result = _typePropertyResolver.resolve(
+ receiver: leftHandSide,
+ receiverType: staticType,
+ name: methodName,
+ receiverErrorNode: leftHandSide,
+ nameErrorNode: leftHandSide,
+ );
+ node.staticElement = result.getter;
+ if (_shouldReportInvalidMember(staticType, result)) {
+ _errorReporter.reportErrorForToken(
+ StaticTypeWarningCode.UNDEFINED_OPERATOR,
+ operator,
+ [methodName, staticType],
+ );
+ }
+ }
+ }
+ }
+
+ /**
+ * Return `true` if we should report an error for the lookup [result] on
+ * the [type].
+ *
+ * TODO(scheglov) this is duplicate
+ */
+ bool _shouldReportInvalidMember(DartType type, ResolutionResult result) {
+ if (result.isNone && type != null && !type.isDynamic) {
+ if (_typeSystem.isNonNullableByDefault &&
+ _typeSystem.isPotentiallyNullable(type)) {
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Return the static type of the given [expression] that is to be used for
+ * type analysis.
+ *
+ * TODO(scheglov) this is duplicate
+ */
+ DartType _getStaticType1(Expression expression, {bool read = false}) {
+ if (expression is NullLiteral) {
+ return _typeProvider.nullType;
+ }
+ DartType type = read
+ ? getReadType(expression, elementTypeProvider: _elementTypeProvider)
+ : expression.staticType;
+ return _resolveTypeParameter(type);
+ }
+
+ /**
+ * If the given [type] is a type parameter, resolve it to the type that should
+ * be used when looking up members. Otherwise, return the original type.
+ *
+ * TODO(scheglov) this is duplicate
+ */
+ DartType _resolveTypeParameter(DartType type) =>
+ type?.resolveToBound(_typeProvider.objectType);
+
+ void _resolve2(AssignmentExpressionImpl node) {
+ TokenType operator = node.operator.type;
+ if (operator == TokenType.EQ) {
+ Expression rightHandSide = node.rightHandSide;
+ DartType staticType = _getStaticType2(rightHandSide);
+ _inferenceHelper.recordStaticType(node, staticType);
+ } else if (operator == TokenType.QUESTION_QUESTION_EQ) {
+ if (_isNonNullableByDefault) {
+ // The static type of a compound assignment using ??= with NNBD is the
+ // least upper bound of the static types of the LHS and RHS after
+ // promoting the LHS/ to non-null (as we know its value will not be used
+ // if null)
+ _analyzeLeastUpperBoundTypes(
+ node,
+ _typeSystem.promoteToNonNull(
+ _getExpressionType(node.leftHandSide, read: true)),
+ _getExpressionType(node.rightHandSide, read: true));
+ } else {
+ // The static type of a compound assignment using ??= before NNBD is the
+ // least upper bound of the static types of the LHS and RHS.
+ _analyzeLeastUpperBound(node, node.leftHandSide, node.rightHandSide,
+ read: true);
+ }
+ } else if (operator == TokenType.AMPERSAND_AMPERSAND_EQ ||
+ operator == TokenType.BAR_BAR_EQ) {
+ _inferenceHelper.recordStaticType(
+ node, _nonNullable(_typeProvider.boolType));
+ } else {
+ var rightType = node.rightHandSide.staticType;
+
+ var leftReadType = _getStaticType2(node.leftHandSide, read: true);
+ if (identical(leftReadType, NeverTypeImpl.instance)) {
+ _inferenceHelper.recordStaticType(node, rightType);
+ return;
+ }
+
+ var operatorElement = node.staticElement;
+ var type =
+ _elementTypeProvider.safeExecutableReturnType(operatorElement) ??
+ DynamicTypeImpl.instance;
+ type = _typeSystem.refineBinaryExpressionType(
+ leftReadType,
+ operator,
+ rightType,
+ type,
+ );
+ _inferenceHelper.recordStaticType(node, type);
+
+ var leftWriteType = _getStaticType2(node.leftHandSide);
+ if (!_typeSystem.isAssignableTo(type, leftWriteType)) {
+ _resolver.errorReporter.reportErrorForNode(
+ StaticTypeWarningCode.INVALID_ASSIGNMENT,
+ node.rightHandSide,
+ [type, leftWriteType],
+ );
+ }
+ }
+ _resolver.nullShortingTermination(node);
+ }
+
+ /// Return the non-nullable variant of the [type] if NNBD is enabled, otherwise
+ /// return the type itself.
+ ///
+ /// TODO(scheglov) this is duplicate
+ DartType _nonNullable(DartType type) {
+ if (_isNonNullableByDefault) {
+ return _typeSystem.promoteToNonNull(type);
+ }
+ return type;
+ }
+
+ /**
+ * Set the static type of [node] to be the least upper bound of the static
+ * types of subexpressions [expr1] and [expr2].
+ *
+ * TODO(scheglov) this is duplicate
+ */
+ void _analyzeLeastUpperBound(
+ Expression node, Expression expr1, Expression expr2,
+ {bool read = false}) {
+ DartType staticType1 = _getExpressionType(expr1, read: read);
+ DartType staticType2 = _getExpressionType(expr2, read: read);
+
+ _analyzeLeastUpperBoundTypes(node, staticType1, staticType2);
+ }
+
+ /**
+ * Gets the definite type of expression, which can be used in cases where
+ * the most precise type is desired, for example computing the least upper
+ * bound.
+ *
+ * See [getExpressionType] for more information. Without strong mode, this is
+ * equivalent to [_getStaticType].
+ *
+ * TODO(scheglov) this is duplicate
+ */
+ DartType _getExpressionType(Expression expr, {bool read = false}) =>
+ getExpressionType(expr, _typeSystem, _typeProvider,
+ read: read, elementTypeProvider: _elementTypeProvider);
+
+ /**
+ * Set the static type of [node] to be the least upper bound of the static
+ * types [staticType1] and [staticType2].
+ *
+ * TODO(scheglov) this is duplicate
+ */
+ void _analyzeLeastUpperBoundTypes(
+ Expression node, DartType staticType1, DartType staticType2) {
+ if (staticType1 == null) {
+ // TODO(brianwilkerson) Determine whether this can still happen.
+ staticType1 = DynamicTypeImpl.instance;
+ }
+
+ if (staticType2 == null) {
+ // TODO(brianwilkerson) Determine whether this can still happen.
+ staticType2 = DynamicTypeImpl.instance;
+ }
+
+ DartType staticType =
+ _typeSystem.getLeastUpperBound(staticType1, staticType2) ??
+ DynamicTypeImpl.instance;
+
+ staticType = _resolver.toLegacyTypeIfOptOut(staticType);
+
+ _inferenceHelper.recordStaticType(node, staticType);
+ }
+
+ /**
+ * Return the static type of the given [expression].
+ *
+ * TODO(scheglov) this is duplicate
+ */
+ DartType _getStaticType2(Expression expression, {bool read = false}) {
+ DartType type;
+ if (read) {
+ type = getReadType(expression, elementTypeProvider: _elementTypeProvider);
+ } else {
+ if (expression is SimpleIdentifier && expression.inSetterContext()) {
+ var element = expression.staticElement;
+ if (element is PromotableElement) {
+ // We're writing to the element so ignore promotions.
+ type = _elementTypeProvider.getVariableType(element);
+ } else {
+ type = expression.staticType;
+ }
+ } else {
+ type = expression.staticType;
+ }
+ }
+ if (type == null) {
+ // TODO(brianwilkerson) Determine the conditions for which the static type
+ // is null.
+ return DynamicTypeImpl.instance;
+ }
+ return type;
+ }
+}
diff --git a/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
index 061b865..9d93bd7 100644
--- a/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
@@ -52,7 +52,13 @@
TypeSystemImpl get _typeSystem => _resolver.typeSystem;
void resolve(BinaryExpressionImpl node) {
- TokenType operator = node.operator.type;
+ var operator = node.operator.type;
+
+ if (operator == TokenType.QUESTION_QUESTION) {
+ _resolveIfNull(node);
+ return;
+ }
+
Expression left = node.leftOperand;
Expression right = node.rightOperand;
var flow = _flowAnalysis?.flow;
@@ -101,13 +107,6 @@
_flowAnalysis?.flow?.equalityOp_end(node, right,
notEqual: operator == TokenType.BANG_EQ);
} else {
- if (operator == TokenType.QUESTION_QUESTION) {
- var leftContextType = InferenceContext.getContext(node);
- if (leftContextType != null && _isNonNullableByDefault) {
- leftContextType = _typeSystem.makeNullable(leftContextType);
- }
- InferenceContext.setType(left, leftContextType);
- }
// TODO(scheglov) Do we need these checks for null?
left?.accept(_resolver);
@@ -115,52 +114,22 @@
// operator method, if applicable.
_resolve1(node);
- if (operator == TokenType.QUESTION_QUESTION) {
- // Set the right side, either from the context, or using the information
- // from the left side if it is more precise.
- DartType contextType = InferenceContext.getContext(node);
- DartType leftType = left?.staticType;
- if (contextType == null || contextType.isDynamic) {
- contextType = leftType;
- }
- InferenceContext.setType(right, contextType);
- } else {
- var invokeType = node.staticInvokeType;
- if (invokeType != null && invokeType.parameters.isNotEmpty) {
- // If this is a user-defined operator, set the right operand context
- // using the operator method's parameter type.
- var rightParam = invokeType.parameters[0];
- InferenceContext.setType(
- right, _elementTypeProvider.getVariableType(rightParam));
- }
+ var invokeType = node.staticInvokeType;
+ if (invokeType != null && invokeType.parameters.isNotEmpty) {
+ // If this is a user-defined operator, set the right operand context
+ // using the operator method's parameter type.
+ var rightParam = invokeType.parameters[0];
+ InferenceContext.setType(
+ right, _elementTypeProvider.getVariableType(rightParam));
}
- if (operator == TokenType.QUESTION_QUESTION) {
- flow?.ifNullExpression_rightBegin(node.leftOperand);
- right.accept(_resolver);
- flow?.ifNullExpression_end();
- } else {
- // TODO(scheglov) Do we need these checks for null?
- right?.accept(_resolver);
- }
+ // TODO(scheglov) Do we need these checks for null?
+ right?.accept(_resolver);
}
_resolve2(node);
}
/// Set the static type of [node] to be the least upper bound of the static
- /// types of subexpressions [expr1] and [expr2].
- ///
- /// TODO(scheglov) this is duplicate
- void _analyzeLeastUpperBound(
- Expression node, Expression expr1, Expression expr2,
- {bool read = false}) {
- DartType staticType1 = _getExpressionType(expr1, read: read);
- DartType staticType2 = _getExpressionType(expr2, read: read);
-
- _analyzeLeastUpperBoundTypes(node, staticType1, staticType2);
- }
-
- /// Set the static type of [node] to be the least upper bound of the static
/// types [staticType1] and [staticType2].
///
/// TODO(scheglov) this is duplicate
@@ -221,27 +190,6 @@
}
void _resolve2(BinaryExpressionImpl node) {
- if (node.operator.type == TokenType.QUESTION_QUESTION) {
- if (_isNonNullableByDefault) {
- // The static type of a compound assignment using ??= with NNBD is the
- // least upper bound of the static types of the LHS and RHS after
- // promoting the LHS/ to non-null (as we know its value will not be used
- // if null)
- _analyzeLeastUpperBoundTypes(
- node,
- _typeSystem.promoteToNonNull(
- _getExpressionType(node.leftOperand, read: true)),
- _getExpressionType(node.rightOperand, read: true));
- } else {
- // Without NNBD, evaluation of an if-null expression e of the form
- // e1 ?? e2 is equivalent to the evaluation of the expression
- // ((x) => x == null ? e2 : x)(e1). The static type of e is the least
- // upper bound of the static type of e1 and the static type of e2.
- _analyzeLeastUpperBound(node, node.leftOperand, node.rightOperand);
- }
- return;
- }
-
if (identical(node.leftOperand.staticType, NeverTypeImpl.instance)) {
_inferenceHelper.recordStaticType(node, NeverTypeImpl.instance);
return;
@@ -281,7 +229,7 @@
if (identical(leftType, NeverTypeImpl.instance)) {
_resolver.errorReporter.reportErrorForNode(
- StaticWarningCode.INVALID_USE_OF_NEVER_VALUE,
+ HintCode.RECEIVER_OF_TYPE_NEVER,
leftOperand,
);
return;
@@ -315,6 +263,43 @@
}
}
+ void _resolveIfNull(BinaryExpressionImpl node) {
+ var left = node.leftOperand;
+ var right = node.rightOperand;
+ var flow = _flowAnalysis?.flow;
+
+ var leftContextType = InferenceContext.getContext(node);
+ if (leftContextType != null && _isNonNullableByDefault) {
+ leftContextType = _typeSystem.makeNullable(leftContextType);
+ }
+ InferenceContext.setType(left, leftContextType);
+
+ left.accept(_resolver);
+ left = node.leftOperand;
+ var leftType = _getExpressionType(left, read: false);
+
+ var rightContextType = InferenceContext.getContext(node);
+ if (rightContextType == null || rightContextType.isDynamic) {
+ rightContextType = leftType;
+ }
+ InferenceContext.setType(right, rightContextType);
+
+ flow?.ifNullExpression_rightBegin(left);
+ right.accept(_resolver);
+ right = node.rightOperand;
+ flow?.ifNullExpression_end();
+
+ // TODO(scheglov) This (and above) is absolutely wrong, and convoluted.
+ // This is just the status quo, until we can make types straight.
+ var rightType = _getExpressionType(right, read: false);
+ if (_isNonNullableByDefault) {
+ var promotedLeftType = _typeSystem.promoteToNonNull(leftType);
+ _analyzeLeastUpperBoundTypes(node, promotedLeftType, rightType);
+ } else {
+ _analyzeLeastUpperBoundTypes(node, leftType, rightType);
+ }
+ }
+
/// If the given [type] is a type parameter, resolve it to the type that should
/// be used when looking up members. Otherwise, return the original type.
///
diff --git a/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart
index 6acef20..516298a 100644
--- a/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart
@@ -36,16 +36,33 @@
ExtensionMemberResolver get _extensionResolver => _resolver.extensionResolver;
void resolve(FunctionExpressionInvocationImpl node) {
- var rawType = _resolveCallElement(node);
+ var function = node.function;
- if (rawType == null) {
- _setExplicitTypeArgumentTypes(node);
- _resolveArguments(node);
- node.staticInvokeType = DynamicTypeImpl.instance;
- node.staticType = DynamicTypeImpl.instance;
+ if (function is ExtensionOverride) {
+ _resolveReceiverExtensionOverride(node, function);
return;
}
+ var receiverType = function.staticType;
+ if (receiverType is FunctionType) {
+ _resolve(node, receiverType);
+ return;
+ }
+
+ if (receiverType is InterfaceType) {
+ _resolveReceiverInterfaceType(node, function, receiverType);
+ return;
+ }
+
+ if (identical(receiverType, NeverTypeImpl.instance)) {
+ _unresolved(node, NeverTypeImpl.instance);
+ return;
+ }
+
+ _unresolved(node, DynamicTypeImpl.instance);
+ }
+
+ void _resolve(FunctionExpressionInvocationImpl node, FunctionType rawType) {
_inferenceHelper.resolveFunctionExpressionInvocation(
node: node,
rawType: rawType,
@@ -62,60 +79,66 @@
node.argumentList.accept(_resolver);
}
- FunctionType _resolveCallElement(FunctionExpressionInvocation node) {
- Expression function = node.function;
+ void _resolveReceiverExtensionOverride(
+ FunctionExpressionInvocation node,
+ ExtensionOverride function,
+ ) {
+ var result = _extensionResolver.getOverrideMember(
+ function,
+ FunctionElement.CALL_METHOD_NAME,
+ );
+ var callElement = result.getter;
+ node.staticElement = callElement;
- if (function is ExtensionOverride) {
- var result = _extensionResolver.getOverrideMember(
+ if (callElement == null) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.INVOCATION_OF_EXTENSION_WITHOUT_CALL,
function,
- FunctionElement.CALL_METHOD_NAME,
+ [function.extensionName.name],
);
- var callElement = result.getter;
- node.staticElement = callElement;
-
- if (callElement == null) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.INVOCATION_OF_EXTENSION_WITHOUT_CALL,
- function,
- [function.extensionName.name],
- );
- return null;
- }
-
- if (callElement.isStatic) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.EXTENSION_OVERRIDE_ACCESS_TO_STATIC_MEMBER,
- node.argumentList,
- );
- }
-
- return _elementTypeProvider.getExecutableType(callElement);
+ return _unresolved(node, DynamicTypeImpl.instance);
}
- var receiverType = function.staticType;
- if (receiverType is FunctionType) {
- return receiverType;
- }
-
- if (receiverType is InterfaceType) {
- var result = _typePropertyResolver.resolve(
- receiver: function,
- receiverType: receiverType,
- name: FunctionElement.CALL_METHOD_NAME,
- receiverErrorNode: function,
- nameErrorNode: function,
+ if (callElement.isStatic) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.EXTENSION_OVERRIDE_ACCESS_TO_STATIC_MEMBER,
+ node.argumentList,
);
- var callElement = result.getter;
-
- if (callElement?.kind != ElementKind.METHOD) {
- return null;
- }
-
- node.staticElement = callElement;
- return _elementTypeProvider.getExecutableType(callElement);
}
- return null;
+ var rawType = _elementTypeProvider.getExecutableType(callElement);
+ _resolve(node, rawType);
+ }
+
+ void _resolveReceiverInterfaceType(
+ FunctionExpressionInvocationImpl node,
+ Expression function,
+ InterfaceType receiverType,
+ ) {
+ var result = _typePropertyResolver.resolve(
+ receiver: function,
+ receiverType: receiverType,
+ name: FunctionElement.CALL_METHOD_NAME,
+ receiverErrorNode: function,
+ nameErrorNode: function,
+ );
+ var callElement = result.getter;
+
+ if (callElement?.kind != ElementKind.METHOD) {
+ _unresolved(node, DynamicTypeImpl.instance);
+ return;
+ }
+
+ node.staticElement = callElement;
+ var rawType = _elementTypeProvider.getExecutableType(callElement);
+ _resolve(node, rawType);
+ }
+
+ void _unresolved(FunctionExpressionInvocationImpl node, DartType type) {
+ _setExplicitTypeArgumentTypes(node);
+ _resolveArguments(node);
+ node.staticInvokeType = DynamicTypeImpl.instance;
+ node.staticType = type;
}
/// Inference cannot be done, we still want to fill type argument types.
diff --git a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
index a80d2d0..92b8434 100644
--- a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
@@ -474,7 +474,7 @@
_resolveArguments(node);
_resolver.errorReporter.reportErrorForNode(
- StaticWarningCode.INVALID_USE_OF_NEVER_VALUE,
+ HintCode.RECEIVER_OF_TYPE_NEVER,
receiver,
);
return;
diff --git a/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
index 4416b89..696c113 100644
--- a/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
@@ -45,11 +45,6 @@
TypeSystemImpl get _typeSystem => _resolver.typeSystem;
void resolve(PostfixExpressionImpl node) {
- if (node.operator.type == TokenType.BANG) {
- _resolveNullCheck(node);
- return;
- }
-
node.operand.accept(_resolver);
var receiverType = getReadType(
@@ -57,6 +52,11 @@
elementTypeProvider: _elementTypeProvider,
);
+ if (node.operator.type == TokenType.BANG) {
+ _resolveNullCheck(node, receiverType);
+ return;
+ }
+
_resolve1(node, receiverType);
_resolve2(node, receiverType);
}
@@ -131,7 +131,7 @@
if (identical(receiverType, NeverTypeImpl.instance)) {
_resolver.errorReporter.reportErrorForNode(
- StaticWarningCode.INVALID_USE_OF_NEVER_VALUE,
+ HintCode.RECEIVER_OF_TYPE_NEVER,
operand,
);
return;
@@ -189,28 +189,11 @@
_inferenceHelper.recordStaticType(node, receiverType);
}
- void _resolveNullCheck(PostfixExpressionImpl node) {
- var operand = node.operand;
-
- var contextType = InferenceContext.getContext(node);
- if (contextType != null) {
- if (_isNonNullableByDefault) {
- contextType = _typeSystem.makeNullable(contextType);
- }
- InferenceContext.setType(operand, contextType);
- }
-
- operand.accept(_resolver);
-
- var operandType = getReadType(
- operand,
- elementTypeProvider: _elementTypeProvider,
- );
-
+ void _resolveNullCheck(PostfixExpressionImpl node, DartType operandType) {
var type = _typeSystem.promoteToNonNull(operandType);
_inferenceHelper.recordStaticType(node, type);
- _flowAnalysis?.flow?.nonNullAssert_end(operand);
+ _flowAnalysis?.flow?.nonNullAssert_end(node.operand);
}
/// Return `true` if we should report an error for the lookup [result] on
diff --git a/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
index 1ad1850..12a9597 100644
--- a/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
@@ -190,7 +190,7 @@
if (identical(staticType, NeverTypeImpl.instance)) {
_resolver.errorReporter.reportErrorForNode(
- StaticWarningCode.INVALID_USE_OF_NEVER_VALUE,
+ HintCode.RECEIVER_OF_TYPE_NEVER,
operand,
);
return;
diff --git a/pkg/analyzer/lib/src/dart/resolver/typed_literal_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/typed_literal_resolver.dart
index d46d7d8..e268abc 100644
--- a/pkg/analyzer/lib/src/dart/resolver/typed_literal_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/typed_literal_resolver.dart
@@ -21,24 +21,24 @@
/// Helper for resolving [ListLiteral]s and [SetOrMapLiteral]s.
class TypedLiteralResolver {
final ResolverVisitor _resolver;
-
final TypeSystemImpl _typeSystem;
final TypeProviderImpl _typeProvider;
final ErrorReporter _errorReporter;
final bool _strictInference;
final bool _uiAsCodeEnabled;
+
final bool _isNonNullableByDefault;
- factory TypedLiteralResolver(
- ResolverVisitor resolver, FeatureSet featureSet) {
+ factory TypedLiteralResolver(ResolverVisitor resolver, FeatureSet featureSet,
+ TypeSystemImpl typeSystem, TypeProviderImpl typeProvider) {
var library = resolver.definingLibrary as LibraryElementImpl;
var analysisOptions = library.context.analysisOptions;
var analysisOptionsImpl = analysisOptions as AnalysisOptionsImpl;
return TypedLiteralResolver._(
resolver,
- library.typeSystem,
- library.typeProvider,
+ typeSystem,
+ typeProvider,
resolver.errorReporter,
analysisOptionsImpl.strictInference,
featureSet.isEnabled(Feature.control_flow_collections) ||
@@ -541,6 +541,9 @@
InferenceContext.setType(element.key, keyType);
InferenceContext.setType(element.value, valueType);
} else if (element is SpreadElement) {
+ if (_isNonNullableByDefault && element.isNullAware) {
+ iterableType = _typeSystem.makeNullable(iterableType);
+ }
InferenceContext.setType(element.expression, iterableType);
}
}
diff --git a/pkg/analyzer/lib/src/dart/scanner/scanner.dart b/pkg/analyzer/lib/src/dart/scanner/scanner.dart
index ec2b621..6058b89 100644
--- a/pkg/analyzer/lib/src/dart/scanner/scanner.dart
+++ b/pkg/analyzer/lib/src/dart/scanner/scanner.dart
@@ -4,9 +4,9 @@
import 'package:_fe_analyzer_shared/src/scanner/errors.dart'
show translateErrorToken;
+import 'package:_fe_analyzer_shared/src/scanner/scanner.dart' as fasta;
import 'package:_fe_analyzer_shared/src/scanner/token.dart'
show Token, TokenType;
-import 'package:_fe_analyzer_shared/src/scanner/scanner.dart' as fasta;
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/error/listener.dart';
@@ -190,9 +190,11 @@
void _languageVersionChanged(
fasta.Scanner scanner, fasta.LanguageVersionToken languageVersion) {
if (_featureSet != null) {
- _featureSet = _featureSet.restrictToVersion(
- Version(languageVersion.major, languageVersion.minor, 0));
- scanner.configuration = buildConfig(_featureSet);
+ if (languageVersion.major >= 0 && languageVersion.minor >= 0) {
+ _featureSet = _featureSet.restrictToVersion(
+ Version(languageVersion.major, languageVersion.minor, 0));
+ scanner.configuration = buildConfig(_featureSet);
+ }
}
}
diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
index 305d02c..3696add 100644
--- a/pkg/analyzer/lib/src/error/codes.dart
+++ b/pkg/analyzer/lib/src/error/codes.dart
@@ -7589,24 +7589,6 @@
errorSeverity: ErrorSeverity.WARNING);
/**
- * It is an error to call a method or getter on an expression of type `Never`,
- * or to invoke it as if it were a function.
- *
- * Go out of our way to provide a *little* more information here because many
- * dart users probably have never heard of the type Never. Be careful however
- * of providing too much information or it only becomes more confusing. Hard
- * balance to strike.
- *
- * Parameters: none
- */
- static const StaticWarningCode INVALID_USE_OF_NEVER_VALUE = StaticWarningCode(
- 'INVALID_USE_OF_NEVER_VALUE',
- 'This expression is invalid because its target is of type Never and'
- ' will never complete with a value',
- correction: 'Try checking for throw expressions or type errors in the'
- ' target expression');
-
- /**
* For the purposes of experimenting with potential non-null type semantics.
*
* Whereas [UNCHECKED_USE_OF_NULLABLE] refers to using a value of type T? as
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 e753bd3..1b84b71 100644
--- a/pkg/analyzer/lib/src/error/unused_local_elements_verifier.dart
+++ b/pkg/analyzer/lib/src/error/unused_local_elements_verifier.dart
@@ -264,11 +264,23 @@
return false;
}
+ bool _isPrivateClassOrExtension(Element element) =>
+ (element is ClassElement || element is ExtensionElement) &&
+ element.isPrivate;
+
/// Returns whether [element] is a private element which is read somewhere in
/// the library.
bool _isReadMember(Element element) {
+ bool elementIsStaticVariable =
+ element is VariableElement && element.isStatic;
if (element.isPublic) {
- return true;
+ if (_isPrivateClassOrExtension(element.enclosingElement) &&
+ elementIsStaticVariable) {
+ // Public static fields of private classes, mixins, and extensions are
+ // inaccessible from outside the library in which they are declared.
+ } else {
+ return true;
+ }
}
if (element.isSynthetic) {
return true;
@@ -281,6 +293,9 @@
return true;
}
+ if (elementIsStaticVariable) {
+ return false;
+ }
return _overridesUsedElement(element);
}
@@ -301,7 +316,14 @@
bool _isUsedMember(Element element) {
if (element.isPublic) {
- return true;
+ if (_isPrivateClassOrExtension(element.enclosingElement) &&
+ element is ExecutableElement &&
+ element.isStatic) {
+ // Public static members of private classes, mixins, and extensions are
+ // inaccessible from outside the library in which they are declared.
+ } else {
+ return true;
+ }
}
if (element.isSynthetic) {
return true;
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index 885602f..bec6557 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -159,53 +159,6 @@
TypeSystemImpl get _typeSystem => _resolver.typeSystem;
@override
- void visitAssignmentExpression(AssignmentExpression node) {
- Token operator = node.operator;
- TokenType operatorType = operator.type;
- Expression leftHandSide = node.leftHandSide;
- DartType staticType = _getStaticType(leftHandSide, read: true);
-
- // For any compound assignments to a void or nullable variable, report it.
- // Example: `y += voidFn()`, not allowed.
- if (operatorType != TokenType.EQ) {
- if (staticType != null && staticType.isVoid) {
- _errorReporter.reportErrorForToken(
- StaticWarningCode.USE_OF_VOID_RESULT,
- operator,
- );
- return;
- }
- }
-
- if (operatorType != TokenType.AMPERSAND_AMPERSAND_EQ &&
- operatorType != TokenType.BAR_BAR_EQ &&
- operatorType != TokenType.EQ &&
- operatorType != TokenType.QUESTION_QUESTION_EQ) {
- operatorType = operatorFromCompoundAssignment(operatorType);
- if (leftHandSide != null) {
- String methodName = operatorType.lexeme;
- // TODO(brianwilkerson) Change the [methodNameNode] from the left hand
- // side to the operator.
- var result = _typePropertyResolver.resolve(
- receiver: leftHandSide,
- receiverType: staticType,
- name: methodName,
- receiverErrorNode: leftHandSide,
- nameErrorNode: leftHandSide,
- );
- node.staticElement = result.getter;
- if (_shouldReportInvalidMember(staticType, result)) {
- _errorReporter.reportErrorForToken(
- StaticTypeWarningCode.UNDEFINED_OPERATOR,
- operator,
- [methodName, staticType],
- );
- }
- }
- }
- }
-
- @override
void visitBreakStatement(BreakStatement node) {
node.target = _lookupBreakOrContinueTarget(node, node.label, false);
}
@@ -454,7 +407,7 @@
if (identical(targetType, NeverTypeImpl.instance)) {
_resolver.errorReporter.reportErrorForNode(
- StaticWarningCode.INVALID_USE_OF_NEVER_VALUE,
+ HintCode.RECEIVER_OF_TYPE_NEVER,
target,
);
return;
@@ -967,7 +920,7 @@
);
} else if (identical(staticType, NeverTypeImpl.instance)) {
_resolver.errorReporter.reportErrorForNode(
- StaticWarningCode.INVALID_USE_OF_NEVER_VALUE,
+ HintCode.RECEIVER_OF_TYPE_NEVER,
target,
);
} else {
@@ -1591,11 +1544,15 @@
// A more specific error will be reported in ErrorVerifier.
}
} else if (result.isNone) {
- _errorReporter.reportErrorForNode(
- StaticTypeWarningCode.UNDEFINED_SETTER,
- propertyName,
- [propertyName.name, staticType],
- );
+ if (staticType is NeverTypeImpl) {
+ // OK
+ } else {
+ _errorReporter.reportErrorForNode(
+ StaticTypeWarningCode.UNDEFINED_SETTER,
+ propertyName,
+ [propertyName.name, staticType],
+ );
+ }
}
}
}
@@ -1686,21 +1643,6 @@
type?.resolveToBound(_typeProvider.objectType);
/**
- * Return `true` if we should report an error for the lookup [result] on
- * the [type].
- */
- bool _shouldReportInvalidMember(DartType type, ResolutionResult result) {
- if (result.isNone && type != null && !type.isDynamic) {
- if (_typeSystem.isNonNullableByDefault &&
- _typeSystem.isPotentiallyNullable(type)) {
- return false;
- }
- return true;
- }
- return false;
- }
-
- /**
* Checks whether the given [expression] is a reference to a class. If it is
* then the element representing the class is returned, otherwise `null` is
* returned.
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 1672467..a3d1669 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -3177,8 +3177,7 @@
return;
}
- if (lhs is IndexExpression &&
- identical(lhs.staticType, NeverTypeImpl.instance)) {
+ if (identical(lhs.staticType, NeverTypeImpl.instance)) {
return;
}
@@ -4812,7 +4811,7 @@
* `(throw x).toString()` which is clearly something between a mistake and
* dead code.
*
- * See [StaticWarningCode.INVALID_USE_OF_NEVER_VALUE].
+ * See [StaticWarningCode.RECEIVER_OF_TYPE_NEVER].
*/
bool _checkForUseOfNever(Expression expression) {
if (expression == null ||
@@ -4821,7 +4820,7 @@
}
_errorReporter.reportErrorForNode(
- StaticWarningCode.INVALID_USE_OF_NEVER_VALUE, expression);
+ HintCode.RECEIVER_OF_TYPE_NEVER, expression);
return true;
}
diff --git a/pkg/analyzer/lib/src/generated/migration.dart b/pkg/analyzer/lib/src/generated/migration.dart
index 0e9647d..29ab66e 100644
--- a/pkg/analyzer/lib/src/generated/migration.dart
+++ b/pkg/analyzer/lib/src/generated/migration.dart
@@ -11,6 +11,14 @@
/// Hooks used by resolution to communicate with the migration engine.
abstract class MigrationResolutionHooks implements ElementTypeProvider {
+ /// Called when the resolver is visiting an if statement, if element, or
+ /// conditional expression, to determine whether the condition is known to
+ /// evaluate to `true` or `false`.
+ ///
+ /// If the condition is known to evaluate to `true` or `false`, then the value
+ /// it is known to evaluate to is returned. Otherwise `null` is returned.
+ bool getConditionalKnownValue(AstNode node);
+
/// Called when the resolver is visiting a [TypeAnnotation] AST node. Should
/// return the type of the [TypeAnnotation] after migrations have been
/// applied.
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 50f345c..20f89af 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -6,7 +6,6 @@
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/nullability_suffix.dart';
@@ -23,6 +22,7 @@
import 'package:analyzer/src/dart/element/nullability_eliminator.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type_provider.dart';
+import 'package:analyzer/src/dart/resolver/assignment_expression_resolver.dart';
import 'package:analyzer/src/dart/resolver/binary_expression_resolver.dart';
import 'package:analyzer/src/dart/resolver/extension_member_resolver.dart';
import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
@@ -209,6 +209,7 @@
/// Helper for resolving [ListLiteral] and [SetOrMapLiteral].
TypedLiteralResolver _typedLiteralResolver;
+ AssignmentExpressionResolver _assignmentExpressionResolver;
BinaryExpressionResolver _binaryExpressionResolver;
FunctionExpressionInvocationResolver _functionExpressionInvocationResolver;
PostfixExpressionResolver _postfixExpressionResolver;
@@ -266,7 +267,7 @@
///
/// The stack contains a `null` sentinel as its first entry so that it is
/// always safe to use `.last` to examine the top of the stack.
- final List<Expression> unfinishedNullShorts = [null];
+ final List<Expression> _unfinishedNullShorts = [null];
/// Initialize a newly created visitor to resolve the nodes in an AST node.
///
@@ -329,7 +330,8 @@
typeSystem: typeSystem,
errorReporter: errorReporter,
);
- this._typedLiteralResolver = TypedLiteralResolver(this, _featureSet);
+ this._typedLiteralResolver =
+ TypedLiteralResolver(this, _featureSet, typeSystem, typeProvider);
this.extensionResolver = ExtensionMemberResolver(this);
this.typePropertyResolver = TypePropertyResolver(this);
this.inferenceHelper = InvocationInferenceHelper(
@@ -340,6 +342,11 @@
errorReporter: errorReporter,
typeSystem: typeSystem,
);
+ this._assignmentExpressionResolver = AssignmentExpressionResolver(
+ resolver: this,
+ flowAnalysis: _flowAnalysis,
+ elementTypeProvider: _elementTypeProvider,
+ );
this._binaryExpressionResolver = BinaryExpressionResolver(
resolver: this,
promoteManager: _promoteManager,
@@ -464,6 +471,20 @@
}).toList());
}
+ /// If we reached a null-shorting termination, and the [node] has null
+ /// shorting, make the type of the [node] nullable.
+ void nullShortingTermination(Expression node) {
+ if (!_isNonNullableByDefault) return;
+
+ if (identical(_unfinishedNullShorts.last, node)) {
+ do {
+ _unfinishedNullShorts.removeLast();
+ _flowAnalysis.flow.nullAwareAccess_end();
+ } while (identical(_unfinishedNullShorts.last, node));
+ node.staticType = typeSystem.makeNullable(node.staticType);
+ }
+ }
+
/// If it is appropriate to do so, override the current type of the static
/// element associated with the given expression with the given type.
/// Generally speaking, it is appropriate if the given type is more specific
@@ -621,28 +642,7 @@
@override
void visitAssignmentExpression(AssignmentExpression node) {
- var left = node.leftHandSide;
- var right = node.rightHandSide;
-
- left?.accept(this);
-
- var leftLocalVariable = _flowAnalysis?.assignmentExpression(node);
-
- TokenType operator = node.operator.type;
- if (operator == TokenType.EQ ||
- operator == TokenType.QUESTION_QUESTION_EQ) {
- InferenceContext.setType(right, left.staticType);
- }
-
- right?.accept(this);
- node.accept(elementResolver);
- node.accept(typeAnalyzer);
- _flowAnalysis?.assignmentExpression_afterRight(
- node,
- leftLocalVariable,
- operator == TokenType.QUESTION_QUESTION_EQ
- ? node.rightHandSide.staticType
- : node.staticType);
+ _assignmentExpressionResolver.resolve(node);
}
@override
@@ -1374,7 +1374,7 @@
node.target?.accept(this);
if (node.isNullAware && _isNonNullableByDefault) {
_flowAnalysis.flow.nullAwareAccess_rightBegin(node.target);
- unfinishedNullShorts.add(node.nullShortingTermination);
+ _unfinishedNullShorts.add(node.nullShortingTermination);
}
node.accept(elementResolver);
var method = node.staticElement;
@@ -1542,7 +1542,7 @@
node.target?.accept(this);
if (node.isNullAware && _isNonNullableByDefault) {
_flowAnalysis.flow.nullAwareAccess_rightBegin(node.target);
- unfinishedNullShorts.add(node.nullShortingTermination);
+ _unfinishedNullShorts.add(node.nullShortingTermination);
}
node.accept(elementResolver);
node.accept(typeAnalyzer);
@@ -2098,6 +2098,20 @@
FlowAnalysisHelperForMigration(
typeSystem, migrationResolutionHooks),
migrationResolutionHooks);
+
+ @override
+ void visitIfStatement(IfStatement node) {
+ var conditionalKnownValue =
+ (_elementTypeProvider as MigrationResolutionHooks)
+ .getConditionalKnownValue(node);
+ if (conditionalKnownValue == null) {
+ super.visitIfStatement(node);
+ return;
+ } else {
+ (conditionalKnownValue ? node.thenStatement : node.elseStatement)
+ ?.accept(this);
+ }
+ }
}
/// The abstract class `ScopedVisitor` maintains name and label scopes as an AST
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 7114129..0507f27 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -4,7 +4,6 @@
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/nullability_suffix.dart';
@@ -227,97 +226,6 @@
}
/**
- * The Dart Language Specification, 12.18: <blockquote>... an assignment <i>a</i> of the form <i>v
- * = e</i> ...
- *
- * It is a static type warning if the static type of <i>e</i> may not be assigned to the static
- * type of <i>v</i>.
- *
- * The static type of the expression <i>v = e</i> is the static type of <i>e</i>.
- *
- * ... an assignment of the form <i>C.v = e</i> ...
- *
- * It is a static type warning if the static type of <i>e</i> may not be assigned to the static
- * type of <i>C.v</i>.
- *
- * The static type of the expression <i>C.v = e</i> is the static type of <i>e</i>.
- *
- * ... an assignment of the form <i>e<sub>1</sub>.v = e<sub>2</sub></i> ...
- *
- * Let <i>T</i> be the static type of <i>e<sub>1</sub></i>. It is a static type warning if
- * <i>T</i> does not have an accessible instance setter named <i>v=</i>. It is a static type
- * warning if the static type of <i>e<sub>2</sub></i> may not be assigned to <i>T</i>.
- *
- * The static type of the expression <i>e<sub>1</sub>.v = e<sub>2</sub></i> is the static type of
- * <i>e<sub>2</sub></i>.
- *
- * ... an assignment of the form <i>e<sub>1</sub>[e<sub>2</sub>] = e<sub>3</sub></i> ...
- *
- * The static type of the expression <i>e<sub>1</sub>[e<sub>2</sub>] = e<sub>3</sub></i> is the
- * static type of <i>e<sub>3</sub></i>.
- *
- * A compound assignment of the form <i>v op= e</i> is equivalent to <i>v = v op e</i>. A compound
- * assignment of the form <i>C.v op= e</i> is equivalent to <i>C.v = C.v op e</i>. A compound
- * assignment of the form <i>e<sub>1</sub>.v op= e<sub>2</sub></i> is equivalent to <i>((x) => x.v
- * = x.v op e<sub>2</sub>)(e<sub>1</sub>)</i> where <i>x</i> is a variable that is not used in
- * <i>e<sub>2</sub></i>. A compound assignment of the form <i>e<sub>1</sub>[e<sub>2</sub>] op=
- * e<sub>3</sub></i> is equivalent to <i>((a, i) => a[i] = a[i] op e<sub>3</sub>)(e<sub>1</sub>,
- * e<sub>2</sub>)</i> where <i>a</i> and <i>i</i> are a variables that are not used in
- * <i>e<sub>3</sub></i>.</blockquote>
- */
- @override
- void visitAssignmentExpression(AssignmentExpression node) {
- TokenType operator = node.operator.type;
- if (operator == TokenType.EQ) {
- Expression rightHandSide = node.rightHandSide;
- DartType staticType = _getStaticType(rightHandSide);
- _recordStaticType(node, staticType);
- } else if (operator == TokenType.QUESTION_QUESTION_EQ) {
- if (_isNonNullableByDefault) {
- // The static type of a compound assignment using ??= with NNBD is the
- // least upper bound of the static types of the LHS and RHS after
- // promoting the LHS/ to non-null (as we know its value will not be used
- // if null)
- _analyzeLeastUpperBoundTypes(
- node,
- _typeSystem.promoteToNonNull(
- _getExpressionType(node.leftHandSide, read: true)),
- _getExpressionType(node.rightHandSide, read: true));
- } else {
- // The static type of a compound assignment using ??= before NNBD is the
- // least upper bound of the static types of the LHS and RHS.
- _analyzeLeastUpperBound(node, node.leftHandSide, node.rightHandSide,
- read: true);
- }
- } else if (operator == TokenType.AMPERSAND_AMPERSAND_EQ ||
- operator == TokenType.BAR_BAR_EQ) {
- _recordStaticType(node, _nonNullable(_typeProvider.boolType));
- } else {
- var operatorElement = node.staticElement;
- var type =
- _elementTypeProvider.safeExecutableReturnType(operatorElement) ??
- _dynamicType;
- type = _typeSystem.refineBinaryExpressionType(
- _getStaticType(node.leftHandSide, read: true),
- operator,
- node.rightHandSide.staticType,
- type,
- );
- _recordStaticType(node, type);
-
- var leftWriteType = _getStaticType(node.leftHandSide);
- if (!_typeSystem.isAssignableTo(type, leftWriteType)) {
- _resolver.errorReporter.reportErrorForNode(
- StaticTypeWarningCode.INVALID_ASSIGNMENT,
- node.rightHandSide,
- [type, leftWriteType],
- );
- }
- }
- _nullShortingTermination(node);
- }
-
- /**
* The Dart Language Specification, 16.29 (Await Expressions):
*
* The static type of [the expression "await e"] is flatten(T) where T is
@@ -472,7 +380,7 @@
_recordStaticType(node, type);
}
- _nullShortingTermination(node);
+ _resolver.nullShortingTermination(node);
}
/**
@@ -670,7 +578,7 @@
if (!_inferObjectAccess(node, staticType, propertyName)) {
_recordStaticType(propertyName, staticType);
_recordStaticType(node, staticType);
- _nullShortingTermination(node);
+ _resolver.nullShortingTermination(node);
}
}
@@ -1197,20 +1105,6 @@
return type;
}
- /// If we reached a null-shorting termination, and the [node] has null
- /// shorting, make the type of the [node] nullable.
- void _nullShortingTermination(Expression node) {
- if (!_isNonNullableByDefault) return;
-
- if (identical(_resolver.unfinishedNullShorts.last, node)) {
- do {
- _resolver.unfinishedNullShorts.removeLast();
- _flowAnalysis.flow.nullAwareAccess_end();
- } while (identical(_resolver.unfinishedNullShorts.last, node));
- node.staticType = _typeSystem.makeNullable(node.staticType);
- }
- }
-
/**
* Record that the static type of the given node is the given type.
*
diff --git a/pkg/analyzer/lib/src/test_utilities/find_node.dart b/pkg/analyzer/lib/src/test_utilities/find_node.dart
index 5075f49..12bcfe9 100644
--- a/pkg/analyzer/lib/src/test_utilities/find_node.dart
+++ b/pkg/analyzer/lib/src/test_utilities/find_node.dart
@@ -147,6 +147,10 @@
return _node(search, (n) => n is GenericFunctionType);
}
+ IfElement ifElement(String search) {
+ return _node(search, (n) => n is IfElement);
+ }
+
ImportDirective import(String search) {
return _node(search, (n) => n is ImportDirective);
}
diff --git a/pkg/analyzer/test/generated/element_resolver_test.dart b/pkg/analyzer/test/generated/element_resolver_test.dart
index 8cf3d18..5deef1f 100644
--- a/pkg/analyzer/test/generated/element_resolver_test.dart
+++ b/pkg/analyzer/test/generated/element_resolver_test.dart
@@ -419,28 +419,6 @@
_listener.assertNoErrors();
}
- test_visitAssignmentExpression_compound() async {
- InterfaceType intType = _typeProvider.intType;
- SimpleIdentifier leftHandSide = AstTestFactory.identifier3("a");
- leftHandSide.staticType = intType;
- AssignmentExpression assignment = AstTestFactory.assignmentExpression(
- leftHandSide, TokenType.PLUS_EQ, AstTestFactory.integer(1));
- _resolveNode(assignment);
- expect(
- assignment.staticElement, same(_typeProvider.numType.getMethod('+')));
- _listener.assertNoErrors();
- }
-
- test_visitAssignmentExpression_simple() async {
- AssignmentExpression expression = AstTestFactory.assignmentExpression(
- AstTestFactory.identifier3("x"),
- TokenType.EQ,
- AstTestFactory.integer(0));
- _resolveNode(expression);
- expect(expression.staticElement, isNull);
- _listener.assertNoErrors();
- }
-
test_visitBreakStatement_withLabel() async {
// loop: while (true) {
// break loop;
diff --git a/pkg/analyzer/test/generated/scanner_test.dart b/pkg/analyzer/test/generated/scanner_test.dart
index bec2ac5..f37d25e 100644
--- a/pkg/analyzer/test/generated/scanner_test.dart
+++ b/pkg/analyzer/test/generated/scanner_test.dart
@@ -5,11 +5,14 @@
import 'package:_fe_analyzer_shared/src/scanner/error_token.dart';
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/error/listener.dart';
import 'package:analyzer/source/line_info.dart';
import 'package:analyzer/src/dart/ast/token.dart';
import 'package:analyzer/src/dart/scanner/reader.dart';
import 'package:analyzer/src/dart/scanner/scanner.dart';
import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/string_source.dart';
+import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -18,6 +21,7 @@
main() {
defineReflectiveSuite(() {
defineReflectiveTests(LineInfoTest);
+ defineReflectiveTests(ScannerTest);
});
}
@@ -183,6 +187,49 @@
}
}
+@reflectiveTest
+class ScannerTest with ResourceProviderMixin {
+ test_featureSet() {
+ var scanner = _createScanner(r'''
+// @dart = 2.0
+''');
+ var defaultFeatureSet = FeatureSet.fromEnableFlags([]);
+ expect(defaultFeatureSet.isEnabled(Feature.extension_methods), isTrue);
+
+ scanner.configureFeatures(FeatureSet.forTesting());
+ scanner.tokenize();
+
+ var featureSet = scanner.featureSet;
+ expect(featureSet.isEnabled(Feature.extension_methods), isFalse);
+ }
+
+ test_featureSet_majorOverflow() {
+ var scanner = _createScanner(r'''
+// @dart = 99999999999999999999999999999999.0
+''');
+ scanner.configureFeatures(FeatureSet.forTesting());
+ scanner.tokenize();
+ // Don't check features, but should not crash.
+ }
+
+ test_featureSet_minorOverflow() {
+ var scanner = _createScanner(r'''
+// @dart = 2.99999999999999999999999999999999
+''');
+ scanner.configureFeatures(FeatureSet.forTesting());
+ scanner.tokenize();
+ // Don't check features, but should not crash.
+ }
+
+ Scanner _createScanner(String content) {
+ var path = convertPath('/test/lib/a.dart');
+ var source = StringSource(content, path);
+ var reader = CharSequenceReader(content);
+ var errorCollector = RecordingErrorListener();
+ return Scanner(source, reader, errorCollector);
+ }
+}
+
/**
* An `ExpectedLocation` encodes information about the expected location of a
* given offset in source code.
diff --git a/pkg/analyzer/test/generated/static_type_analyzer_test.dart b/pkg/analyzer/test/generated/static_type_analyzer_test.dart
index 90ae072..0fb0a7f 100644
--- a/pkg/analyzer/test/generated/static_type_analyzer_test.dart
+++ b/pkg/analyzer/test/generated/static_type_analyzer_test.dart
@@ -403,29 +403,6 @@
_listener.assertNoErrors();
}
- void test_visitAssignmentExpression_compound_lazy() {
- validate(TokenType operator) {
- InterfaceType boolType = _typeProvider.boolType;
- SimpleIdentifier identifier = _resolvedVariable(boolType, "b");
- AssignmentExpression node = AstTestFactory.assignmentExpression(
- identifier, operator, _resolvedBool(true));
- expect(_analyze(node), same(boolType));
- _listener.assertNoErrors();
- }
-
- validate(TokenType.AMPERSAND_AMPERSAND_EQ);
- validate(TokenType.BAR_BAR_EQ);
- }
-
- void test_visitAssignmentExpression_simple() {
- // i = 0
- InterfaceType intType = _typeProvider.intType;
- Expression node = AstTestFactory.assignmentExpression(
- _resolvedVariable(intType, "i"), TokenType.EQ, _resolvedInteger(0));
- expect(_analyze(node), same(intType));
- _listener.assertNoErrors();
- }
-
void test_visitAwaitExpression_flattened() {
// await e, where e has type Future<Future<int>>
InterfaceType intType = _typeProvider.intType;
@@ -1120,16 +1097,6 @@
DartType _flatten(DartType type) => _typeSystem.flatten(type);
/**
- * Return a boolean literal with the given [value] that has been resolved to
- * the correct type.
- */
- BooleanLiteral _resolvedBool(bool value) {
- BooleanLiteral literal = AstTestFactory.booleanLiteral(value);
- literal.staticType = _typeProvider.intType;
- return literal;
- }
-
- /**
* Return an integer literal that has been resolved to the correct type.
*
* @param value the value of the literal
diff --git a/pkg/analyzer/test/src/context/builder_test.dart b/pkg/analyzer/test/src/context/builder_test.dart
index ff0feb7..7e58e58 100644
--- a/pkg/analyzer/test/src/context/builder_test.dart
+++ b/pkg/analyzer/test/src/context/builder_test.dart
@@ -599,7 +599,9 @@
expected.lint = true;
expected.lintRules = <Linter>[_mockLintRule];
String packagesFilePath = convertPath('/some/directory/path/.packages');
- newFile(packagesFilePath, content: 'flutter:/pkg/flutter/lib/');
+ newFile(packagesFilePath, content: '''
+flutter:${toUriStr('/pkg/flutter/lib/')}
+''');
newFile('/pkg/flutter/lib/analysis_options_user.yaml', content: '''
linter:
rules:
diff --git a/pkg/analyzer/test/src/context/packages_test.dart b/pkg/analyzer/test/src/context/packages_test.dart
index 0e01a4f..044313a 100644
--- a/pkg/analyzer/test/src/context/packages_test.dart
+++ b/pkg/analyzer/test/src/context/packages_test.dart
@@ -21,6 +21,87 @@
newFile('/test/lib/test.dart', content: '');
}
+ void test_findPackagesFrom_fallbackToDotPackages() {
+ newFile('/test/.packages', content: '''
+test:lib/
+bbb:${toUriStr('/packages/bbb/lib')}
+''');
+
+ var packages = findPackagesFrom(
+ resourceProvider,
+ getFile('/test/lib/a.dart'),
+ );
+
+ _assertPackage(
+ packages,
+ name: 'test',
+ expectedLibPath: '/test/lib',
+ expectedVersion: null,
+ );
+
+ _assertPackage(
+ packages,
+ name: 'bbb',
+ expectedLibPath: '/packages/bbb/lib',
+ expectedVersion: null,
+ );
+ }
+
+ void test_findPackagesFrom_missing() {
+ var packages = findPackagesFrom(
+ resourceProvider,
+ getFile('/test/lib/a.dart'),
+ );
+
+ expect(packages.packages, isEmpty);
+ }
+
+ void test_findPackagesFrom_preferPackageConfig() {
+ newFile('/test/.dart_tool/package_config.json', content: '''
+{
+ "configVersion": 2,
+ "packages": [
+ {
+ "name": "test",
+ "rootUri": "../",
+ "packageUri": "lib/",
+ "languageVersion": "2.6"
+ },
+ {
+ "name": "aaa",
+ "rootUri": "${toUriStr('/packages/aaa')}",
+ "packageUri": "lib/",
+ "languageVersion": "2.3"
+ }
+ ]
+}
+''');
+
+ newFile('/test/.packages', content: '''
+test:lib/
+bbb:${toUriStr('/packages/bbb/lib')}
+''');
+
+ var packages = findPackagesFrom(
+ resourceProvider,
+ getFile('/test/lib/a.dart'),
+ );
+
+ _assertPackage(
+ packages,
+ name: 'test',
+ expectedLibPath: '/test/lib',
+ expectedVersion: Version(2, 6, 0),
+ );
+
+ _assertPackage(
+ packages,
+ name: 'aaa',
+ expectedLibPath: '/packages/aaa/lib',
+ expectedVersion: Version(2, 3, 0),
+ );
+ }
+
test_parseDotPackagesFile() {
var file = newFile('/test/.packages', content: '''
# Generated by pub
diff --git a/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart
index 083f98c..ab574a6 100644
--- a/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart
@@ -196,7 +196,7 @@
@override
bool get typeToStringWithNullability => true;
- test_ifNull_left_nullable() async {
+ test_ifNull_left_nullableContext() async {
await assertNoErrorsInCode(r'''
T f<T>(T t) => t;
@@ -217,4 +217,46 @@
type: 'int',
);
}
+
+ test_ifNull_nullableInt_int() async {
+ await assertNoErrorsInCode(r'''
+main(int? x, int y) {
+ x ?? y;
+}
+''');
+
+ assertBinaryExpression(
+ findNode.binary('x ?? y'),
+ element: null,
+ type: 'int',
+ );
+ }
+
+ test_ifNull_nullableInt_nullableDouble() async {
+ await assertNoErrorsInCode(r'''
+main(int? x, double? y) {
+ x ?? y;
+}
+''');
+
+ assertBinaryExpression(
+ findNode.binary('x ?? y'),
+ element: null,
+ type: 'num?',
+ );
+ }
+
+ test_ifNull_nullableInt_nullableInt() async {
+ await assertNoErrorsInCode(r'''
+main(int? x) {
+ x ?? x;
+}
+''');
+
+ assertBinaryExpression(
+ findNode.binary('x ?? x'),
+ element: null,
+ type: 'int?',
+ );
+ }
}
diff --git a/pkg/analyzer/test/src/dart/resolution/class_test.dart b/pkg/analyzer/test/src/dart/resolution/class_test.dart
index f5fceea..72deb9d 100644
--- a/pkg/analyzer/test/src/dart/resolution/class_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/class_test.dart
@@ -18,139 +18,6 @@
@reflectiveTest
class ClassDriverResolutionTest extends DriverResolutionTest
with ElementsTypesMixin {
- test_abstractSuperMemberReference_getter() async {
- await assertErrorsInCode(r'''
-abstract class A {
- get foo;
-}
-abstract class B extends A {
- bar() {
- super.foo; // ref
- }
-}
-''', [
- error(CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE, 81, 3),
- ]);
- assertElement(findNode.simple('foo; // ref'), findElement.getter('foo'));
- }
-
- test_abstractSuperMemberReference_getter2() async {
- await assertErrorsInCode(r'''
-abstract class Foo {
- String get foo;
-}
-
-abstract class Bar implements Foo {
-}
-
-class Baz extends Bar {
- String get foo => super.foo; // ref
-}
-''', [
- error(CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE, 131, 3),
- ]);
- assertElement(
- findNode.simple('foo; // ref'),
- findElement.getter('foo', of: 'Foo'),
- );
- }
-
- test_abstractSuperMemberReference_method_reference() async {
- await assertErrorsInCode(r'''
-abstract class A {
- foo();
-}
-abstract class B extends A {
- bar() {
- super.foo; // ref
- }
-}
-''', [
- error(CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE, 79, 3),
- ]);
- assertElement(findNode.simple('foo; // ref'), findElement.method('foo'));
- }
-
- test_abstractSuperMemberReference_OK_superHasConcrete_mixinHasAbstract_method() async {
- await assertNoErrorsInCode('''
-class A {
- void foo() {}
-}
-
-abstract class B {
- void foo();
-}
-
-class C extends A with B {
- void bar() {
- super.foo(); // ref
- }
-}
-''');
- assertElement(
- findNode.simple('foo(); // ref'),
- findElement.method('foo', of: 'A'),
- );
- }
-
- test_abstractSuperMemberReference_OK_superSuperHasConcrete_getter() async {
- await assertNoErrorsInCode('''
-abstract class A {
- int get foo => 0;
-}
-
-abstract class B extends A {
- int get foo;
-}
-
-class C extends B {
- int get bar => super.foo; // ref
-}
-''');
- assertElement(
- findNode.simple('foo; // ref'),
- findElement.getter('foo', of: 'A'),
- );
- }
-
- test_abstractSuperMemberReference_OK_superSuperHasConcrete_setter() async {
- await assertNoErrorsInCode('''
-abstract class A {
- void set foo(_) {}
-}
-
-abstract class B extends A {
- void set foo(_);
-}
-
-class C extends B {
- void bar() {
- super.foo = 0;
- }
-}
-''');
- assertElement(
- findNode.simple('foo = 0;'),
- findElement.setter('foo', of: 'A'),
- );
- }
-
- test_abstractSuperMemberReference_setter() async {
- await assertErrorsInCode(r'''
-abstract class A {
- set foo(_);
-}
-abstract class B extends A {
- bar() {
- super.foo = 0;
- }
-}
-''', [
- error(CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE, 84, 3),
- ]);
- assertElement(findNode.simple('foo = 0;'), findElement.setter('foo'));
- }
-
test_element_allSupertypes() async {
await assertNoErrorsInCode(r'''
class A {}
diff --git a/pkg/analyzer/test/src/dart/resolution/function_expression_invocation_test.dart b/pkg/analyzer/test/src/dart/resolution/function_expression_invocation_test.dart
index 4de479a..bd90019 100644
--- a/pkg/analyzer/test/src/dart/resolution/function_expression_invocation_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/function_expression_invocation_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/src/dart/analysis/experiments.dart';
+import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -145,4 +146,44 @@
type: 'int',
);
}
+
+ test_never() async {
+ await assertErrorsInCode(r'''
+main(Never x) {
+ x<int>(1 + 2);
+}
+''', [
+ error(HintCode.RECEIVER_OF_TYPE_NEVER, 18, 1),
+ ]);
+
+ assertFunctionExpressionInvocation(
+ findNode.functionExpressionInvocation('x<int>(1 + 2)'),
+ element: null,
+ typeArgumentTypes: ['int'],
+ invokeType: 'dynamic',
+ type: 'Never',
+ );
+
+ assertType(findNode.binary('1 + 2'), 'int');
+ }
+
+ test_neverQ() async {
+ await assertErrorsInCode(r'''
+main(Never? x) {
+ x<int>(1 + 2);
+}
+''', [
+ error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 19, 1),
+ ]);
+
+ assertFunctionExpressionInvocation(
+ findNode.functionExpressionInvocation('x<int>(1 + 2)'),
+ element: null,
+ typeArgumentTypes: ['int'],
+ invokeType: 'dynamic',
+ type: 'dynamic',
+ );
+
+ assertType(findNode.binary('1 + 2'), 'int');
+ }
}
diff --git a/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart b/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
index 0420fdf..8bedd48 100644
--- a/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
@@ -4,7 +4,9 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/analysis/experiments.dart';
import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/engine.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'driver_resolution.dart';
@@ -12,158 +14,12 @@
main() {
defineReflectiveSuite(() {
defineReflectiveTests(MethodInvocationResolutionTest);
+ defineReflectiveTests(MethodInvocationResolutionWithNnbdTest);
});
}
@reflectiveTest
class MethodInvocationResolutionTest extends DriverResolutionTest {
- test_error_abstractSuperMemberReference() async {
- await assertErrorsInCode(r'''
-abstract class A {
- void foo(int _);
-}
-abstract class B extends A {
- void bar() {
- super.foo(0);
- }
-
- void foo(int _) {} // does not matter
-}
-''', [
- error(CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE, 94, 3),
- ]);
-
- var invocation = findNode.methodInvocation('foo(0)');
- assertMethodInvocation(
- invocation,
- findElement.method('foo', of: 'A'),
- 'void Function(int)',
- );
- assertSuperExpression(invocation.target);
- }
-
- test_error_abstractSuperMemberReference_mixin_implements() async {
- await assertErrorsInCode(r'''
-class A {
- void foo(int _) {}
-}
-
-mixin M implements A {
- void bar() {
- super.foo(0);
- }
-}
-''', [
- error(CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE, 82, 3),
- ]);
-
- var invocation = findNode.methodInvocation('foo(0)');
- assertMethodInvocation(
- invocation,
- findElement.method('foo', of: 'A'),
- 'void Function(int)',
- );
- assertSuperExpression(invocation.target);
- }
-
- test_error_abstractSuperMemberReference_mixinHasNoSuchMethod() async {
- await assertErrorsInCode('''
-class A {
- int foo();
- noSuchMethod(im) => 42;
-}
-
-class B extends Object with A {
- foo() => super.foo(); // ref
- noSuchMethod(im) => 87;
-}
-''', [
- error(CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE, 101, 3),
- ]);
-
- var invocation = findNode.methodInvocation('foo(); // ref');
- assertMethodInvocation(
- invocation,
- findElement.method('foo', of: 'A'),
- 'int Function()',
- );
- assertSuperExpression(invocation.target);
- }
-
- test_error_abstractSuperMemberReference_OK_mixinHasConcrete() async {
- await assertNoErrorsInCode('''
-class A {}
-
-class M {
- void foo(int _) {}
-}
-
-class B = A with M;
-
-class C extends B {
- void bar() {
- super.foo(0);
- }
-}
-''');
-
- var invocation = findNode.methodInvocation('foo(0)');
- assertMethodInvocation(
- invocation,
- findElement.method('foo', of: 'M'),
- 'void Function(int)',
- );
- assertSuperExpression(invocation.target);
- }
-
- test_error_abstractSuperMemberReference_OK_superHasNoSuchMethod() async {
- await assertNoErrorsInCode(r'''
-class A {
- int foo();
- noSuchMethod(im) => 42;
-}
-
-class B extends A {
- int foo() => super.foo(); // ref
- noSuchMethod(im) => 87;
-}
-''');
-
- var invocation = findNode.methodInvocation('super.foo(); // ref');
- assertMethodInvocation(
- invocation,
- findElement.method('foo', of: 'A'),
- 'int Function()',
- );
- assertSuperExpression(invocation.target);
- }
-
- test_error_abstractSuperMemberReference_OK_superSuperHasConcrete() async {
- await assertNoErrorsInCode('''
-abstract class A {
- void foo(int _) {}
-}
-
-abstract class B extends A {
- void foo(int _);
-}
-
-class C extends B {
- void bar() {
- super.foo(0);
- }
-}
-''');
-
- var invocation = findNode.methodInvocation('foo(0)');
- assertMethodInvocation(
- invocation,
- findElement.method('foo', of: 'A'),
- 'void Function(int)',
- );
- assertSuperExpression(invocation.target);
- }
-
test_error_ambiguousImport_topFunction() async {
newFile('/test/lib/a.dart', content: r'''
void foo(int _) {}
@@ -1836,3 +1692,150 @@
// );
}
}
+
+@reflectiveTest
+class MethodInvocationResolutionWithNnbdTest extends DriverResolutionTest {
+ @override
+ AnalysisOptionsImpl get analysisOptions =>
+ AnalysisOptionsImpl()..enabledExperiments = [EnableString.non_nullable];
+
+ test_hasReceiver_interfaceTypeQ_defined() async {
+ await assertErrorsInCode(r'''
+class A {
+ void foo() {}
+}
+
+main(A? a) {
+ a.foo();
+}
+''', [
+ error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 44, 1),
+ ]);
+
+ assertMethodInvocation2(
+ findNode.methodInvocation('a.foo()'),
+ element: findElement.method('foo', of: 'A'),
+ typeArgumentTypes: [],
+ invokeType: 'void Function()',
+ type: 'void',
+ );
+ }
+
+ test_hasReceiver_interfaceTypeQ_defined_extension() async {
+ await assertErrorsInCode(r'''
+class A {
+ void foo() {}
+}
+
+extension E on A {
+ void foo() {}
+}
+
+main(A? a) {
+ a.foo();
+}
+''', [
+ error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 82, 1),
+ ]);
+
+ assertMethodInvocation2(
+ findNode.methodInvocation('a.foo()'),
+ element: findElement.method('foo', of: 'A'),
+ typeArgumentTypes: [],
+ invokeType: 'void Function()',
+ type: 'void',
+ );
+ }
+
+ test_hasReceiver_interfaceTypeQ_defined_extensionQ() async {
+ await assertNoErrorsInCode(r'''
+class A {
+ void foo() {}
+}
+
+extension E on A? {
+ void foo() {}
+}
+
+main(A? a) {
+ a.foo();
+}
+''');
+
+ assertMethodInvocation2(
+ findNode.methodInvocation('a.foo()'),
+ element: findElement.method('foo', of: 'E'),
+ typeArgumentTypes: [],
+ invokeType: 'void Function()',
+ type: 'void',
+ );
+ }
+
+ test_hasReceiver_interfaceTypeQ_notDefined() async {
+ await assertErrorsInCode(r'''
+class A {}
+
+main(A? a) {
+ a.foo();
+}
+''', [
+ error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 27, 1),
+ error(StaticTypeWarningCode.UNDEFINED_METHOD, 29, 3),
+ ]);
+
+ assertMethodInvocation2(
+ findNode.methodInvocation('a.foo()'),
+ element: null,
+ typeArgumentTypes: [],
+ invokeType: 'dynamic',
+ type: 'dynamic',
+ );
+ }
+
+ test_hasReceiver_interfaceTypeQ_notDefined_extension() async {
+ await assertErrorsInCode(r'''
+class A {}
+
+extension E on A {
+ void foo() {}
+}
+
+main(A? a) {
+ a.foo();
+}
+''', [
+ error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 65, 1),
+ error(StaticTypeWarningCode.UNDEFINED_METHOD, 67, 3),
+ ]);
+
+ assertMethodInvocation2(
+ findNode.methodInvocation('a.foo()'),
+ element: null,
+ typeArgumentTypes: [],
+ invokeType: 'dynamic',
+ type: 'dynamic',
+ );
+ }
+
+ test_hasReceiver_interfaceTypeQ_notDefined_extensionQ() async {
+ await assertNoErrorsInCode(r'''
+class A {}
+
+extension E on A? {
+ void foo() {}
+}
+
+main(A? a) {
+ a.foo();
+}
+''');
+
+ assertMethodInvocation2(
+ findNode.methodInvocation('a.foo()'),
+ element: findElement.method('foo', of: 'E'),
+ typeArgumentTypes: [],
+ invokeType: 'void Function()',
+ type: 'void',
+ );
+ }
+}
diff --git a/pkg/analyzer/test/src/dart/resolution/non_nullable_test.dart b/pkg/analyzer/test/src/dart/resolution/non_nullable_test.dart
index 1f63ff2..5b0222e 100644
--- a/pkg/analyzer/test/src/dart/resolution/non_nullable_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/non_nullable_test.dart
@@ -150,27 +150,6 @@
assertType(findNode.methodInvocation('c?.x()'), 'bool?');
}
- test_local_nullCoalesce_nullableInt_int() async {
- await assertNoErrorsInCode(r'''
-main() {
- int? x;
- int y = 0;
- x ?? y;
-}
-''');
- assertType(findNode.binary('x ?? y'), 'int');
- }
-
- test_local_nullCoalesce_nullableInt_nullableInt() async {
- await assertNoErrorsInCode(r'''
-main() {
- int? x;
- x ?? x;
-}
-''');
- assertType(findNode.binary('x ?? x'), 'int?');
- }
-
test_local_nullCoalesceAssign_nullableInt_int() async {
await assertNoErrorsInCode(r'''
main() {
@@ -376,24 +355,6 @@
assertType(findNode.methodInvocation('c?.x()'), 'bool?');
}
- test_parameter_nullCoalesce_nullableInt_int() async {
- await assertNoErrorsInCode(r'''
-main(int? x, int y) {
- x ?? y;
-}
-''');
- assertType(findNode.binary('x ?? y'), 'int');
- }
-
- test_parameter_nullCoalesce_nullableInt_nullableInt() async {
- await assertNoErrorsInCode(r'''
-main(int? x) {
- x ?? x;
-}
-''');
- assertType(findNode.binary('x ?? x'), 'int?');
- }
-
test_parameter_nullCoalesceAssign_nullableInt_int() async {
await assertNoErrorsInCode(r'''
main(int? x, int y) {
diff --git a/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart
index ea38101..c8e1653 100644
--- a/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart
@@ -129,28 +129,6 @@
assertType(findNode.postfix('x!'), 'Never');
}
- test_nullCheck_nullableContext() async {
- await assertNoErrorsInCode(r'''
-T f<T>(T t) => t;
-
-int g() => f(null)!;
-''');
-
- assertMethodInvocation2(
- findNode.methodInvocation('f(null)'),
- element: findElement.topFunction('f'),
- typeArgumentTypes: ['int?'],
- invokeType: 'int? Function(int?)',
- type: 'int?',
- );
-
- assertPostfixExpression(
- findNode.postfix('f(null)!'),
- element: null,
- type: 'int',
- );
- }
-
test_nullCheck_typeParameter() async {
await assertNoErrorsInCode(r'''
f<T>(T? x) {
diff --git a/pkg/analyzer/test/src/dart/resolution/property_access_test.dart b/pkg/analyzer/test/src/dart/resolution/property_access_test.dart
index a407ade..0f92987 100644
--- a/pkg/analyzer/test/src/dart/resolution/property_access_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/property_access_test.dart
@@ -18,90 +18,6 @@
@reflectiveTest
class PropertyAccessResolutionTest extends DriverResolutionTest {
- test_get_error_abstractSuperMemberReference_mixinHasNoSuchMethod() async {
- await assertErrorsInCode('''
-class A {
- int get foo;
- noSuchMethod(im) => 1;
-}
-
-class B extends Object with A {
- get foo => super.foo; // ref
- noSuchMethod(im) => 2;
-}
-''', [
- error(CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE, 104, 3),
- ]);
-
- var access = findNode.propertyAccess('foo; // ref');
- assertPropertyAccess(access, findElement.getter('foo', of: 'A'), 'int');
- assertSuperExpression(access.target);
- }
-
- test_get_error_abstractSuperMemberReference_OK_superHasNoSuchMethod() async {
- await assertNoErrorsInCode(r'''
-class A {
- int get foo;
- noSuchMethod(im) => 1;
-}
-
-class B extends A {
- get foo => super.foo; // ref
- noSuchMethod(im) => 2;
-}
-''');
-
- var access = findNode.propertyAccess('super.foo; // ref');
- assertPropertyAccess(access, findElement.getter('foo', of: 'A'), 'int');
- assertSuperExpression(access.target);
- }
-
- test_set_error_abstractSuperMemberReference_mixinHasNoSuchMethod() async {
- await assertErrorsInCode('''
-class A {
- set foo(int a);
- noSuchMethod(im) {}
-}
-
-class B extends Object with A {
- set foo(v) => super.foo = v; // ref
- noSuchMethod(im) {}
-}
-''', [
- error(CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE, 107, 3),
- ]);
-
- var access = findNode.propertyAccess('foo = v; // ref');
- assertPropertyAccess(
- access,
- findElement.setter('foo', of: 'A'),
- 'int',
- );
- assertSuperExpression(access.target);
- }
-
- test_set_error_abstractSuperMemberReference_OK_superHasNoSuchMethod() async {
- await assertNoErrorsInCode(r'''
-class A {
- set foo(int a);
- noSuchMethod(im) => 1;
-}
-
-class B extends A {
- set foo(v) => super.foo = v; // ref
- noSuchMethod(im) => 2;
-}
-''');
-
- var access = findNode.propertyAccess('foo = v; // ref');
- assertPropertyAccess(
- access,
- findElement.setter('foo', of: 'A'),
- 'int',
- );
- assertSuperExpression(access.target);
- }
-
test_tearOff_method() async {
await assertNoErrorsInCode('''
class A {
diff --git a/pkg/analyzer/test/src/dart/resolution/resolution.dart b/pkg/analyzer/test/src/dart/resolution/resolution.dart
index 2f29a52..0ca1c8b 100644
--- a/pkg/analyzer/test/src/dart/resolution/resolution.dart
+++ b/pkg/analyzer/test/src/dart/resolution/resolution.dart
@@ -75,6 +75,15 @@
newFile('/test/lib/test.dart', content: content);
}
+ void assertAssignment(
+ AssignmentExpression node, {
+ @required ExecutableElement operatorElement,
+ @required String type,
+ }) {
+ expect(node.staticElement, same(operatorElement));
+ assertType(node, type);
+ }
+
void assertAuxElement(AstNode node, Element expected) {
var auxElements = getNodeAuxElements(node);
expect(auxElements?.staticElement, same(expected));
diff --git a/pkg/analyzer/test/src/dart/resolution/type_inference/list_literal_test.dart b/pkg/analyzer/test/src/dart/resolution/type_inference/list_literal_test.dart
index 913e53b..f7fad59 100644
--- a/pkg/analyzer/test/src/dart/resolution/type_inference/list_literal_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/type_inference/list_literal_test.dart
@@ -311,6 +311,24 @@
@override
bool get typeToStringWithNullability => true;
+ test_context_spread_nullAware() async {
+ await assertNoErrorsInCode('''
+T f<T>(T t) => t;
+
+main() {
+ <int>[...?f(null)];
+}
+''');
+
+ assertMethodInvocation2(
+ findNode.methodInvocation('f(null)'),
+ element: findElement.topFunction('f'),
+ typeArgumentTypes: ['Iterable<int>?'],
+ invokeType: 'Iterable<int>? Function(Iterable<int>?)',
+ type: 'Iterable<int>?',
+ );
+ }
+
test_nested_hasNull_1() async {
await assertNoErrorsInCode('''
main() {
diff --git a/pkg/analyzer/test/src/dart/resolution/type_inference/map_literal_test.dart b/pkg/analyzer/test/src/dart/resolution/type_inference/map_literal_test.dart
index b14de64..9ec241a 100644
--- a/pkg/analyzer/test/src/dart/resolution/type_inference/map_literal_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/type_inference/map_literal_test.dart
@@ -358,4 +358,22 @@
assertType(setOrMapLiteral('{}; // 3'), 'Map<String, T?>');
assertType(setOrMapLiteral('{}; // 4'), 'Map<String, T?>');
}
+
+ test_context_spread_nullAware() async {
+ await assertNoErrorsInCode('''
+T f<T>(T t) => t;
+
+main() {
+ <int, double>{...?f(null)};
+}
+''');
+
+ assertMethodInvocation2(
+ findNode.methodInvocation('f(null)'),
+ element: findElement.topFunction('f'),
+ typeArgumentTypes: ['Map<int, double>?'],
+ invokeType: 'Map<int, double>? Function(Map<int, double>?)',
+ type: 'Map<int, double>?',
+ );
+ }
}
diff --git a/pkg/analyzer/test/src/diagnostics/abstract_super_member_reference_test.dart b/pkg/analyzer/test/src/diagnostics/abstract_super_member_reference_test.dart
new file mode 100644
index 0000000..cb4fedd
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/abstract_super_member_reference_test.dart
@@ -0,0 +1,410 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/src/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(AbstractSuperMemberReferenceTest);
+ });
+}
+
+@reflectiveTest
+class AbstractSuperMemberReferenceTest extends DriverResolutionTest {
+ test_methodInvocation_mixin_implements() async {
+ await assertErrorsInCode(r'''
+class A {
+ void foo(int _) {}
+}
+
+mixin M implements A {
+ void bar() {
+ super.foo(0);
+ }
+}
+''', [
+ error(CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE, 82, 3),
+ ]);
+
+ assertMethodInvocation2(
+ findNode.methodInvocation('super.foo(0)'),
+ element: findElement.method('foo', of: 'A'),
+ typeArgumentTypes: [],
+ invokeType: 'void Function(int)',
+ type: 'void',
+ );
+ }
+
+ test_methodInvocation_mixinHasConcrete() async {
+ await assertNoErrorsInCode('''
+class A {}
+
+class M {
+ void foo() {}
+}
+
+class B = A with M;
+
+class C extends B {
+ void bar() {
+ super.foo();
+ }
+}
+''');
+
+ assertMethodInvocation2(
+ findNode.methodInvocation('super.foo()'),
+ element: findElement.method('foo', of: 'M'),
+ typeArgumentTypes: [],
+ invokeType: 'void Function()',
+ type: 'void',
+ );
+ }
+
+ test_methodInvocation_mixinHasNoSuchMethod() async {
+ await assertErrorsInCode('''
+class A {
+ void foo();
+ noSuchMethod(im) => 42;
+}
+
+class B extends Object with A {
+ void foo() => super.foo(); // ref
+ noSuchMethod(im) => 87;
+}
+''', [
+ error(CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE, 107, 3),
+ ]);
+
+ assertMethodInvocation2(
+ findNode.methodInvocation('super.foo()'),
+ element: findElement.method('foo', of: 'A'),
+ typeArgumentTypes: [],
+ invokeType: 'void Function()',
+ type: 'void',
+ );
+ }
+
+ test_methodInvocation_superHasAbstract() async {
+ await assertErrorsInCode(r'''
+abstract class A {
+ void foo(int _);
+}
+
+abstract class B extends A {
+ void bar() {
+ super.foo(0);
+ }
+
+ void foo(int _) {} // does not matter
+}
+''', [
+ error(CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE, 95, 3),
+ ]);
+
+ assertMethodInvocation2(
+ findNode.methodInvocation('super.foo(0)'),
+ element: findElement.method('foo', of: 'A'),
+ typeArgumentTypes: [],
+ invokeType: 'void Function(int)',
+ type: 'void',
+ );
+ }
+
+ test_methodInvocation_superHasConcrete_mixinHasAbstract() async {
+ await assertNoErrorsInCode('''
+class A {
+ void foo() {}
+}
+
+abstract class B {
+ void foo();
+}
+
+class C extends A with B {
+ void bar() {
+ super.foo(); // ref
+ }
+}
+''');
+
+ assertMethodInvocation2(
+ findNode.methodInvocation('foo(); // ref'),
+ element: findElement.method('foo', of: 'A'),
+ typeArgumentTypes: [],
+ invokeType: 'void Function()',
+ type: 'void',
+ );
+ }
+
+ test_methodInvocation_superHasNoSuchMethod() async {
+ await assertNoErrorsInCode(r'''
+class A {
+ int foo();
+ noSuchMethod(im) => 42;
+}
+
+class B extends A {
+ int foo() => super.foo(); // ref
+ noSuchMethod(im) => 87;
+}
+''');
+
+ assertMethodInvocation2(
+ findNode.methodInvocation('super.foo()'),
+ element: findElement.method('foo', of: 'A'),
+ typeArgumentTypes: [],
+ invokeType: 'int Function()',
+ type: 'int',
+ );
+ }
+
+ test_methodInvocation_superSuperHasConcrete() async {
+ await assertNoErrorsInCode('''
+abstract class A {
+ void foo() {}
+}
+
+abstract class B extends A {
+ void foo();
+}
+
+class C extends B {
+ void bar() {
+ super.foo();
+ }
+}
+''');
+
+ assertMethodInvocation2(
+ findNode.methodInvocation('super.foo()'),
+ element: findElement.method('foo', of: 'A'),
+ typeArgumentTypes: [],
+ invokeType: 'void Function()',
+ type: 'void',
+ );
+ }
+
+ test_propertyAccess_getter() async {
+ await assertErrorsInCode(r'''
+abstract class A {
+ int get foo;
+}
+
+abstract class B extends A {
+ bar() {
+ super.foo; // ref
+ }
+}
+''', [
+ error(CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE, 86, 3),
+ ]);
+
+ assertPropertyAccess(
+ findNode.propertyAccess('super.foo'),
+ findElement.getter('foo'),
+ 'int',
+ );
+ }
+
+ test_propertyAccess_getter_mixinHasNoSuchMethod() async {
+ await assertErrorsInCode('''
+class A {
+ int get foo;
+ noSuchMethod(im) => 1;
+}
+
+class B extends Object with A {
+ int get foo => super.foo; // ref
+ noSuchMethod(im) => 2;
+}
+''', [
+ error(CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE, 108, 3),
+ ]);
+
+ assertPropertyAccess(
+ findNode.propertyAccess('super.foo'),
+ findElement.getter('foo', of: 'A'),
+ 'int',
+ );
+ }
+
+ test_propertyAccess_getter_superHasNoSuchMethod() async {
+ await assertNoErrorsInCode(r'''
+class A {
+ int get foo;
+ noSuchMethod(im) => 1;
+}
+
+class B extends A {
+ get foo => super.foo; // ref
+ noSuchMethod(im) => 2;
+}
+''');
+
+ assertPropertyAccess(
+ findNode.propertyAccess('super.foo'),
+ findElement.getter('foo', of: 'A'),
+ 'int',
+ );
+ }
+
+ test_propertyAccess_getter_superImplements() async {
+ await assertErrorsInCode(r'''
+class A {
+ int get foo => 0;
+}
+
+abstract class B implements A {
+}
+
+class C extends B {
+ int get foo => super.foo; // ref
+}
+''', [
+ error(CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE, 111, 3),
+ ]);
+
+ assertPropertyAccess(
+ findNode.propertyAccess('super.foo'),
+ findElement.getter('foo', of: 'A'),
+ 'int',
+ );
+ }
+
+ test_propertyAccess_getter_superSuperHasConcrete() async {
+ await assertNoErrorsInCode('''
+abstract class A {
+ int get foo => 0;
+}
+
+abstract class B extends A {
+ int get foo;
+}
+
+class C extends B {
+ int get bar => super.foo; // ref
+}
+''');
+
+ assertPropertyAccess(
+ findNode.propertyAccess('super.foo'),
+ findElement.getter('foo', of: 'A'),
+ 'int',
+ );
+ }
+
+ test_propertyAccess_method_tearOff_abstract() async {
+ await assertErrorsInCode(r'''
+abstract class A {
+ void foo();
+}
+
+abstract class B extends A {
+ void bar() {
+ super.foo; // ref
+ }
+}
+''', [
+ error(CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE, 90, 3),
+ ]);
+
+ assertPropertyAccess(
+ findNode.propertyAccess('super.foo'),
+ findElement.method('foo'),
+ 'void Function()',
+ );
+ }
+
+ test_propertyAccess_setter() async {
+ await assertErrorsInCode(r'''
+abstract class A {
+ set foo(int _);
+}
+
+abstract class B extends A {
+ void bar() {
+ super.foo = 0;
+ }
+}
+''', [
+ error(CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE, 94, 3),
+ ]);
+
+ assertPropertyAccess(
+ findNode.propertyAccess('super.foo'),
+ findElement.setter('foo', of: 'A'),
+ 'int',
+ );
+ }
+
+ test_propertyAccess_setter_mixinHasNoSuchMethod() async {
+ await assertErrorsInCode('''
+class A {
+ set foo(int a);
+ noSuchMethod(im) {}
+}
+
+class B extends Object with A {
+ set foo(int a) => super.foo = a; // ref
+ noSuchMethod(im) {}
+}
+''', [
+ error(CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE, 111, 3),
+ ]);
+
+ assertPropertyAccess(
+ findNode.propertyAccess('super.foo'),
+ findElement.setter('foo', of: 'A'),
+ 'int',
+ );
+ }
+
+ test_propertyAccess_setter_superHasNoSuchMethod() async {
+ await assertNoErrorsInCode(r'''
+class A {
+ set foo(int a);
+ noSuchMethod(im) => 1;
+}
+
+class B extends A {
+ set foo(int a) => super.foo = a; // ref
+ noSuchMethod(im) => 2;
+}
+''');
+
+ assertPropertyAccess(
+ findNode.propertyAccess('super.foo'),
+ findElement.setter('foo', of: 'A'),
+ 'int',
+ );
+ }
+
+ test_propertyAccess_setter_superSuperHasConcrete() async {
+ await assertNoErrorsInCode('''
+abstract class A {
+ void set foo(int _) {}
+}
+
+abstract class B extends A {
+ void set foo(int _);
+}
+
+class C extends B {
+ void bar() {
+ super.foo = 0;
+ }
+}
+''');
+
+ assertPropertyAccess(
+ findNode.propertyAccess('super.foo'),
+ findElement.setter('foo', of: 'A'),
+ 'int',
+ );
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_visibility_annotation_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_visibility_annotation_test.dart
index b827bcc..24aa6a1 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_visibility_annotation_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_visibility_annotation_test.dart
@@ -82,10 +82,10 @@
test_privateEnum() async {
await assertErrorsInCode(r'''
import 'package:meta/meta.dart';
-@visibleForTesting enum _E {a, b, c}
+@visibleForTesting enum _E {a, b}
+void f(_E e) => e == _E.a || e == _E.b;
''', [
error(HintCode.INVALID_VISIBILITY_ANNOTATION, 33, 18),
- error(HintCode.UNUSED_ELEMENT, 57, 2),
]);
}
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_use_of_never_value_test.dart b/pkg/analyzer/test/src/diagnostics/receiver_of_type_never_test.dart
similarity index 87%
rename from pkg/analyzer/test/src/diagnostics/invalid_use_of_never_value_test.dart
rename to pkg/analyzer/test/src/diagnostics/receiver_of_type_never_test.dart
index 7994df2..441ecf9 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_use_of_never_value_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/receiver_of_type_never_test.dart
@@ -31,7 +31,7 @@
x == 1 + 2;
}
''', [
- error(StaticWarningCode.INVALID_USE_OF_NEVER_VALUE, 23, 1),
+ error(HintCode.RECEIVER_OF_TYPE_NEVER, 23, 1),
]);
assertBinaryExpression(
@@ -49,7 +49,7 @@
x + (1 + 2);
}
''', [
- error(StaticWarningCode.INVALID_USE_OF_NEVER_VALUE, 23, 1),
+ error(HintCode.RECEIVER_OF_TYPE_NEVER, 23, 1),
]);
assertBinaryExpression(
@@ -117,7 +117,7 @@
x();
}
''', [
- error(StaticWarningCode.INVALID_USE_OF_NEVER_VALUE, 23, 1),
+ error(HintCode.RECEIVER_OF_TYPE_NEVER, 23, 1),
]);
}
@@ -137,7 +137,7 @@
x[0];
}
''', [
- error(StaticWarningCode.INVALID_USE_OF_NEVER_VALUE, 23, 1),
+ error(HintCode.RECEIVER_OF_TYPE_NEVER, 23, 1),
]);
assertIndexExpression(
@@ -154,7 +154,7 @@
x[0] += 1 + 2;
}
''', [
- error(StaticWarningCode.INVALID_USE_OF_NEVER_VALUE, 23, 1),
+ error(HintCode.RECEIVER_OF_TYPE_NEVER, 23, 1),
]);
assertIndexExpression(
@@ -173,7 +173,7 @@
x[0] = 1 + 2;
}
''', [
- error(StaticWarningCode.INVALID_USE_OF_NEVER_VALUE, 23, 1),
+ error(HintCode.RECEIVER_OF_TYPE_NEVER, 23, 1),
]);
assertIndexExpression(
@@ -259,7 +259,7 @@
x.foo(1 + 2);
}
''', [
- error(StaticWarningCode.INVALID_USE_OF_NEVER_VALUE, 23, 1),
+ error(HintCode.RECEIVER_OF_TYPE_NEVER, 23, 1),
]);
assertMethodInvocation(
@@ -279,7 +279,7 @@
x.toString(1 + 2);
}
''', [
- error(StaticWarningCode.INVALID_USE_OF_NEVER_VALUE, 23, 1),
+ error(HintCode.RECEIVER_OF_TYPE_NEVER, 23, 1),
]);
assertMethodInvocation(
@@ -319,7 +319,7 @@
x++;
}
''', [
- error(StaticWarningCode.INVALID_USE_OF_NEVER_VALUE, 23, 1),
+ error(HintCode.RECEIVER_OF_TYPE_NEVER, 23, 1),
]);
assertPostfixExpression(
@@ -352,7 +352,7 @@
++x;
}
''', [
- error(StaticWarningCode.INVALID_USE_OF_NEVER_VALUE, 25, 1),
+ error(HintCode.RECEIVER_OF_TYPE_NEVER, 25, 1),
]);
assertPrefixExpression(
@@ -378,7 +378,7 @@
);
}
- test_propertyAccess_never() async {
+ test_propertyAccess_never_read() async {
await assertNoErrorsInCode(r'''
void main(Never x) {
x.foo;
@@ -392,7 +392,7 @@
);
}
- test_propertyAccess_never_hashCode() async {
+ test_propertyAccess_never_read_hashCode() async {
await assertNoErrorsInCode(r'''
void main(Never x) {
x.hashCode;
@@ -406,6 +406,26 @@
);
}
+ test_propertyAccess_never_readWrite() async {
+ await assertNoErrorsInCode(r'''
+void main(Never x) {
+ x.foo += 0;
+}
+''');
+
+ assertSimpleIdentifier(
+ findNode.simple('foo'),
+ element: null,
+ type: 'Never',
+ );
+
+ assertAssignment(
+ findNode.assignment('foo += 0'),
+ operatorElement: null,
+ type: 'int',
+ );
+ }
+
test_propertyAccess_never_tearOff_toString() async {
await assertNoErrorsInCode(r'''
void main(Never x) {
@@ -420,7 +440,27 @@
);
}
- test_propertyAccess_neverQ() async {
+ test_propertyAccess_never_write() async {
+ await assertNoErrorsInCode(r'''
+void main(Never x) {
+ x.foo = 0;
+}
+''');
+
+ assertSimpleIdentifier(
+ findNode.simple('foo'),
+ element: null,
+ type: 'Never',
+ );
+
+ assertAssignment(
+ findNode.assignment('foo = 0'),
+ operatorElement: null,
+ type: 'int',
+ );
+ }
+
+ test_propertyAccess_neverQ_read() async {
await assertErrorsInCode(r'''
void main(Never? x) {
x.foo;
@@ -436,7 +476,7 @@
);
}
- test_propertyAccess_neverQ_hashCode() async {
+ test_propertyAccess_neverQ_read_hashCode() async {
await assertNoErrorsInCode(r'''
void main(Never? x) {
x.hashCode;
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index 85bb4cc..51c8156 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -4,6 +4,8 @@
import 'package:test_reflective_loader/test_reflective_loader.dart';
+import 'abstract_super_member_reference_test.dart'
+ as abstract_super_member_reference;
import 'ambiguous_export_test.dart' as ambiguous_export;
import 'ambiguous_extension_member_access_test.dart'
as ambiguous_extension_member_access;
@@ -207,7 +209,6 @@
import 'invalid_uri_test.dart' as invalid_uri;
import 'invalid_use_of_covariant_in_extension_test.dart'
as invalid_use_of_covariant_in_extension;
-import 'invalid_use_of_never_value_test.dart' as invalid_use_of_never_value;
import 'invalid_use_of_null_value_test.dart' as invalid_use_of_null_value;
import 'invalid_use_of_protected_member_test.dart'
as invalid_use_of_protected_member;
@@ -342,6 +343,7 @@
import 'private_collision_in_mixin_application_test.dart'
as private_collision_in_mixin_application;
import 'private_optional_parameter_test.dart' as private_optional_parameter;
+import 'receiver_of_type_never_test.dart' as receiver_of_type_never;
import 'recursive_compile_time_constant_test.dart'
as recursive_compile_time_constant;
import 'recursive_constructor_redirect_test.dart'
@@ -481,6 +483,7 @@
main() {
defineReflectiveSuite(() {
+ abstract_super_member_reference.main();
ambiguous_export.main();
ambiguous_extension_member_access.main();
ambiguous_import.main();
@@ -618,7 +621,6 @@
invalid_type_argument_in_const_set.main();
invalid_uri.main();
invalid_use_of_covariant_in_extension.main();
- invalid_use_of_never_value.main();
invalid_use_of_null_value.main();
invalid_use_of_protected_member.main();
invalid_use_of_visible_for_template_member.main();
@@ -711,6 +713,7 @@
prefix_identifier_not_followed_by_dot.main();
private_collision_in_mixin_application.main();
private_optional_parameter.main();
+ receiver_of_type_never.main();
recursive_compile_time_constant.main();
recursive_constructor_redirect.main();
recursive_factory_redirect.main();
diff --git a/pkg/analyzer/test/src/diagnostics/unused_element_test.dart b/pkg/analyzer/test/src/diagnostics/unused_element_test.dart
index ed63a7e..c74fea2 100644
--- a/pkg/analyzer/test/src/diagnostics/unused_element_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/unused_element_test.dart
@@ -96,6 +96,7 @@
}
''', [
error(HintCode.UNUSED_ELEMENT, 6, 2),
+ error(HintCode.UNUSED_ELEMENT, 20, 12),
]);
}
@@ -205,17 +206,19 @@
test_enum_isUsed_fieldReference() async {
await assertNoErrorsInCode(r'''
-enum _MyEnum {A, B, C}
+enum _MyEnum {A}
main() {
- print(_MyEnum.B);
+ _MyEnum.A;
}
''');
}
test_enum_notUsed_noReference() async {
await assertErrorsInCode(r'''
-enum _MyEnum {A, B, C}
-main() {
+enum _MyEnum {A, B}
+void f(d) {
+ d.A;
+ d.B;
}
''', [
error(HintCode.UNUSED_ELEMENT, 5, 7),
@@ -782,6 +785,79 @@
]);
}
+ test_publicStaticMethod_privateClass_isUsed() async {
+ await assertNoErrorsInCode(r'''
+class _A {
+ static void m() {}
+}
+void main() {
+ _A.m();
+}
+''');
+ }
+
+ test_publicStaticMethod_privateClass_notUsed() async {
+ await assertErrorsInCode(r'''
+class _A {
+ static void m() {}
+}
+void f(_A a) {}
+''', [
+ error(HintCode.UNUSED_ELEMENT, 25, 1),
+ ]);
+ }
+
+ test_publicStaticMethod_privateExtension_isUsed() async {
+ await assertNoErrorsInCode(r'''
+extension _A on String {
+ static void m() {}
+}
+void main() {
+ _A.m();
+}
+''');
+ }
+
+ test_publicStaticMethod_privateExtension_notUsed() async {
+ await assertErrorsInCode(r'''
+extension _A on String {
+ static void m() {}
+}
+''', [
+ error(HintCode.UNUSED_ELEMENT, 39, 1),
+ ]);
+ }
+
+ test_publicStaticMethod_privateMixin_isUsed() async {
+ await assertNoErrorsInCode(r'''
+mixin _A {
+ static void m() {}
+}
+void main() {
+ _A.m();
+}
+''');
+ }
+
+ test_publicStaticMethod_privateMixin_notUsed() async {
+ await assertErrorsInCode(r'''
+mixin _A {
+ static void m() {}
+}
+void main() {
+ _A;
+}
+''', [
+ error(HintCode.UNUSED_ELEMENT, 25, 1),
+ ]);
+ }
+
+ test_publicTopLevelFunction_notUsed() async {
+ await assertNoErrorsInCode(r'''
+int get a => 1;
+''');
+ }
+
test_setter_isUsed_invocation_implicitThis() async {
await assertNoErrorsInCode(r'''
class A {
diff --git a/pkg/analyzer/test/src/diagnostics/unused_field_test.dart b/pkg/analyzer/test/src/diagnostics/unused_field_test.dart
index c898d14..cb92c0d 100644
--- a/pkg/analyzer/test/src/diagnostics/unused_field_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/unused_field_test.dart
@@ -88,6 +88,47 @@
''');
}
+ test_isUsed_privateEnum_publicValue() async {
+ await assertNoErrorsInCode(r'''
+enum _Foo {a, b}
+f() => print('${_Foo.a}${_Foo.b}');
+''');
+ }
+
+ test_isUsed_publicEnum_privateValue() async {
+ await assertNoErrorsInCode(r'''
+enum Foo {_a, _b}
+f() => print('${Foo._a}${Foo._b}');
+''');
+ }
+
+ test_isUsed_publicStaticField_privateClass() async {
+ await assertNoErrorsInCode(r'''
+class _A {
+ static String f1 = "x";
+}
+void main() => print(_A.f1);
+''');
+ }
+
+ test_isUsed_publicStaticField_privateExtension() async {
+ await assertNoErrorsInCode(r'''
+extension _A on String {
+ static String f1 = "x";
+}
+void main() => print(_A.f1);
+''');
+ }
+
+ test_isUsed_publicStaticField_privateMixin() async {
+ await assertNoErrorsInCode(r'''
+mixin _A {
+ static String f1 = "x";
+}
+void main() => print(_A.f1);
+''');
+ }
+
test_isUsed_reference_implicitThis() async {
await assertNoErrorsInCode(r'''
class A {
@@ -278,6 +319,55 @@
]);
}
+ test_notUsed_privateEnum_publicValue() async {
+ await assertErrorsInCode(r'''
+enum _Foo {a}
+f() => _Foo;
+''', [
+ error(HintCode.UNUSED_FIELD, 11, 1),
+ ]);
+ }
+
+ test_notUsed_publicEnum_privateValue() async {
+ await assertErrorsInCode(r'''
+enum Foo {_a}
+''', [
+ error(HintCode.UNUSED_FIELD, 10, 2),
+ ]);
+ }
+
+ test_notUsed_publicStaticField_privateClass() async {
+ await assertErrorsInCode(r'''
+class _A {
+ static String f1 = "x";
+}
+void main() => print(_A);
+''', [
+ error(HintCode.UNUSED_FIELD, 27, 2),
+ ]);
+ }
+
+ test_notUsed_publicStaticField_privateExtension() async {
+ await assertErrorsInCode(r'''
+extension _A on String {
+ static String f1 = "x";
+}
+''', [
+ error(HintCode.UNUSED_FIELD, 41, 2),
+ ]);
+ }
+
+ test_notUsed_publicStaticField_privateMixin() async {
+ await assertErrorsInCode(r'''
+mixin _A {
+ static String f1 = "x";
+}
+void main() => print(_A);
+''', [
+ error(HintCode.UNUSED_FIELD, 27, 2),
+ ]);
+ }
+
test_notUsed_referenceInComment() async {
await assertErrorsInCode(r'''
/// [A._f] is great.
diff --git a/pkg/analyzer_cli/lib/src/driver.dart b/pkg/analyzer_cli/lib/src/driver.dart
index 1c968c8..1aa38a4 100644
--- a/pkg/analyzer_cli/lib/src/driver.dart
+++ b/pkg/analyzer_cli/lib/src/driver.dart
@@ -11,6 +11,7 @@
import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:analyzer/src/context/builder.dart';
import 'package:analyzer/src/context/context_root.dart';
+import 'package:analyzer/src/context/packages.dart';
import 'package:analyzer/src/dart/analysis/byte_store.dart';
import 'package:analyzer/src/dart/analysis/driver.dart';
import 'package:analyzer/src/dart/analysis/file_state.dart';
@@ -34,7 +35,6 @@
import 'package:analyzer/src/summary/summary_file_builder.dart';
import 'package:analyzer/src/summary/summary_sdk.dart' show SummaryBasedDartSdk;
import 'package:analyzer/src/task/options.dart';
-import 'package:analyzer/src/util/uri.dart';
import 'package:analyzer/src/util/yaml.dart';
import 'package:analyzer_cli/src/analyzer_impl.dart';
import 'package:analyzer_cli/src/batch_mode.dart';
@@ -48,10 +48,6 @@
import 'package:analyzer_cli/starter.dart' show CommandLineStarter;
import 'package:linter/src/rules.dart' as linter;
import 'package:meta/meta.dart';
-import 'package:package_config/discovery.dart' as pkg_discovery;
-import 'package:package_config/packages.dart' show Packages;
-import 'package:package_config/packages_file.dart' as pkgfile show parse;
-import 'package:package_config/src/packages_impl.dart' show MapPackages;
import 'package:path/path.dart' as path;
import 'package:yaml/yaml.dart';
@@ -591,44 +587,28 @@
scheduler.start();
}
- /// Return discovered packagespec, or `null` if none is found.
- Packages _discoverPackagespec(Uri root) {
- try {
- Packages packages = pkg_discovery.findPackagesFromFile(root);
- if (packages != Packages.noPackages) {
- return packages;
- }
- } catch (_) {
- // Ignore and fall through to null.
- }
-
- return null;
- }
-
_PackageInfo _findPackages(CommandLineOptions options) {
Packages packages;
Map<String, List<Folder>> packageMap;
if (options.packageConfigPath != null) {
- String packageConfigPath = options.packageConfigPath;
- Uri fileUri = Uri.file(packageConfigPath);
+ String path = normalizePath(options.packageConfigPath);
try {
- io.File configFile = io.File.fromUri(fileUri).absolute;
- List<int> bytes = configFile.readAsBytesSync();
- Map<String, Uri> map = pkgfile.parse(bytes, configFile.uri);
- packages = MapPackages(map);
+ var packages = parseDotPackagesFile(
+ resourceProvider,
+ resourceProvider.getFile(path),
+ );
packageMap = _getPackageMap(packages);
} catch (e) {
- printAndFail(
- 'Unable to read package config data from $packageConfigPath: $e');
+ printAndFail('Unable to read package config data from $path: $e');
}
} else if (options.packageRootPath != null) {
- packageMap = _PackageRootPackageMapBuilder.buildPackageMap(
- options.packageRootPath);
+ var path = normalizePath(options.packageRootPath);
+ packageMap = _PackageRootPackageMapBuilder.buildPackageMap(path);
} else {
Resource cwd = resourceProvider.getResource(path.current);
// Look for .packages.
- packages = _discoverPackagespec(Uri.directory(cwd.path));
+ packages = findPackagesFrom(resourceProvider, cwd);
packageMap = _getPackageMap(packages);
}
@@ -640,13 +620,11 @@
return null;
}
- Map<String, List<Folder>> folderMap = <String, List<Folder>>{};
- var pathContext = resourceProvider.pathContext;
- packages.asMap().forEach((String packagePath, Uri uri) {
- String path = fileUriToNormalizedPath(pathContext, uri);
- folderMap[packagePath] = [resourceProvider.getFolder(path)];
- });
- return folderMap;
+ var packageMap = <String, List<Folder>>{};
+ for (var package in packages.packages) {
+ packageMap[package.name] = [package.libFolder];
+ }
+ return packageMap;
}
/// Returns `true` if this relative path is a hidden directory.
diff --git a/pkg/analyzer_cli/tool/perf.dart b/pkg/analyzer_cli/tool/perf.dart
index 5e6e272..3419e96 100644
--- a/pkg/analyzer_cli/tool/perf.dart
+++ b/pkg/analyzer_cli/tool/perf.dart
@@ -10,9 +10,11 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/error/listener.dart';
+import 'package:analyzer/file_system/file_system.dart'
+ show Folder, ResourceUriResolver;
import 'package:analyzer/file_system/physical_file_system.dart'
show PhysicalResourceProvider;
-import 'package:analyzer/src/context/builder.dart';
+import 'package:analyzer/src/context/packages.dart';
import 'package:analyzer/src/dart/scanner/reader.dart';
import 'package:analyzer/src/dart/scanner/scanner.dart';
import 'package:analyzer/src/dart/sdk/sdk.dart' show FolderBasedDartSdk;
@@ -21,7 +23,6 @@
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/source_io.dart';
import 'package:analyzer/src/source/package_map_resolver.dart';
-import 'package:package_config/discovery.dart';
main(List<String> args) async {
// TODO(sigmund): provide sdk folder as well.
@@ -34,7 +35,7 @@
var bench = args[0];
var entryUri = Uri.base.resolve(args[1]);
- await setup(entryUri);
+ await setup(args[1]);
if (bench == 'scan') {
Set<Source> files = scanReachableFiles(entryUri);
@@ -180,10 +181,19 @@
/// Sets up analyzer to be able to load and resolve app, packages, and sdk
/// sources.
-Future setup(Uri entryUri) async {
+Future setup(String path) async {
var provider = PhysicalResourceProvider.INSTANCE;
- var packageMap = ContextBuilder.convertPackagesToMap(
- provider, await findPackages(entryUri));
+
+ var packages = findPackagesFrom(
+ provider,
+ provider.getResource(path),
+ );
+
+ var packageMap = <String, List<Folder>>{};
+ for (var package in packages.packages) {
+ packageMap[package.name] = [package.libFolder];
+ }
+
sources = SourceFactory([
ResourceUriResolver(provider),
PackageMapUriResolver(provider, packageMap),
diff --git a/pkg/analyzer_plugin/CHANGELOG.md b/pkg/analyzer_plugin/CHANGELOG.md
index 6172dd2..c9543da 100644
--- a/pkg/analyzer_plugin/CHANGELOG.md
+++ b/pkg/analyzer_plugin/CHANGELOG.md
@@ -1,3 +1,6 @@
+## 0.2.2
+- Change supported analyzer version to `^0.39.0`
+
## 0.2.1
- Bump maximum supported version of the analyzer to `<0.39.0`.
- Bug fixes: #37916, #38326.
diff --git a/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart b/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart
index 86403e9..0e802e7 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/completion/optype.dart
@@ -1202,6 +1202,14 @@
optype.includeTypeNameSuggestions = true;
}
+ @override
+ void visitYieldStatement(YieldStatement node) {
+ if (identical(entity, node.expression)) {
+ optype.includeReturnValueSuggestions = true;
+ optype.includeTypeNameSuggestions = true;
+ }
+ }
+
bool _isEntityPrevTokenSynthetic() {
Object entity = this.entity;
if (entity is AstNode) {
diff --git a/pkg/analyzer_plugin/pubspec.yaml b/pkg/analyzer_plugin/pubspec.yaml
index 72ea138..2975a31 100644
--- a/pkg/analyzer_plugin/pubspec.yaml
+++ b/pkg/analyzer_plugin/pubspec.yaml
@@ -1,6 +1,6 @@
name: analyzer_plugin
description: A framework and support code for building plugins for the analysis server.
-version: 0.2.1
+version: 0.2.2
author: Dart Team <misc@dartlang.org>
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/analyzer_plugin
@@ -8,7 +8,7 @@
sdk: '>=2.3.0 <3.0.0'
dependencies:
- analyzer: '>=0.35.3 <0.39.0'
+ analyzer: '^0.39.0'
charcode: '^1.1.0'
dart_style: '^1.2.0'
html: '>=0.13.1 <0.15.0'
diff --git a/pkg/analyzer_plugin/test/support/abstract_context.dart b/pkg/analyzer_plugin/test/support/abstract_context.dart
index eee4c1f..155e3c1 100644
--- a/pkg/analyzer_plugin/test/support/abstract_context.dart
+++ b/pkg/analyzer_plugin/test/support/abstract_context.dart
@@ -118,8 +118,8 @@
MockSdk(resourceProvider: resourceProvider);
newFolder('/home/test');
- newFile('/home/test/.packages', content: r'''
-test:file:///home/test/lib
+ newFile('/home/test/.packages', content: '''
+test:${toUriStr('/home/test/lib')}
''');
_createDriver();
diff --git a/pkg/compiler/lib/src/commandline_options.dart b/pkg/compiler/lib/src/commandline_options.dart
index 39bb7b7..3ab91bc 100644
--- a/pkg/compiler/lib/src/commandline_options.dart
+++ b/pkg/compiler/lib/src/commandline_options.dart
@@ -94,6 +94,8 @@
static const String serverMode = '--server-mode';
+ static const String nonNullableMode = '--non-nullable-mode';
+
static const String newDeferredSplit = '--new-deferred-split';
static const String reportInvalidInferredDeferredTypes =
'--report-invalid-deferred-types';
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index 24bdf93..304bc8b 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -333,6 +333,16 @@
"supported formats are: json or binary");
}
+ void setNonNullableMode(String argument) {
+ if (argument == "${Flags.nonNullableMode}=strong" ||
+ argument == "${Flags.nonNullableMode}=weak") {
+ passThrough(argument);
+ return;
+ }
+ helpAndFail("Error: Unsupported '$argument', "
+ "supported modes are: strong (default) or weak");
+ }
+
void handleThrowOnError(String argument) {
throwOnError = true;
String parameter = extractParameter(argument, isOptionalArgument: true);
@@ -456,6 +466,7 @@
new OptionHandler(Flags.laxRuntimeTypeToString, passThrough),
new OptionHandler(Flags.benchmarkingProduction, passThrough),
new OptionHandler(Flags.benchmarkingExperiment, passThrough),
+ new OptionHandler('${Flags.nonNullableMode}=.+', setNonNullableMode),
// TODO(floitsch): remove conditional directives flag.
// We don't provide the info-message yet, since we haven't publicly
diff --git a/pkg/compiler/lib/src/inferrer/abstract_value_domain.dart b/pkg/compiler/lib/src/inferrer/abstract_value_domain.dart
index 28fbbb1..6eed483 100644
--- a/pkg/compiler/lib/src/inferrer/abstract_value_domain.dart
+++ b/pkg/compiler/lib/src/inferrer/abstract_value_domain.dart
@@ -563,10 +563,6 @@
/// Returns an [AbstractBool] that describes if the set of runtime values of
/// [subset] are known to all be in the set of runtime values of [superset].
- AbstractBool contains(AbstractValue superset, AbstractValue subset);
-
- /// Returns an [AbstractBool] that describes if the set of runtime values of
- /// [subset] are known to all be in the set of runtime values of [superset].
AbstractBool isIn(AbstractValue subset, AbstractValue superset);
/// Returns the [MemberEntity] that is known to always be hit at runtime
diff --git a/pkg/compiler/lib/src/inferrer/trivial.dart b/pkg/compiler/lib/src/inferrer/trivial.dart
index 07c10d4..b8ea357 100644
--- a/pkg/compiler/lib/src/inferrer/trivial.dart
+++ b/pkg/compiler/lib/src/inferrer/trivial.dart
@@ -57,10 +57,6 @@
AbstractBool.Maybe;
@override
- AbstractBool contains(AbstractValue superset, AbstractValue subset) =>
- AbstractBool.Maybe;
-
- @override
AbstractBool needsNoSuchMethodHandling(
AbstractValue receiver, Selector selector) =>
AbstractBool.Maybe;
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
index 0e3fd2d..3cbac15 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
@@ -1665,15 +1665,6 @@
AbstractValue input = inputs.first.type;
AbstractValue intersection =
abstractValueDomain.intersection(input, typeAnnotation);
- if (debug.ANOMALY_WARN) {
- if (abstractValueDomain.contains(input, intersection).isDefinitelyFalse ||
- abstractValueDomain
- .contains(typeAnnotation, intersection)
- .isDefinitelyFalse) {
- print("ANOMALY WARNING: narrowed $input to $intersection via "
- "$typeAnnotation");
- }
- }
return intersection;
}
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/masks.dart b/pkg/compiler/lib/src/inferrer/typemasks/masks.dart
index 4f94658..b14ebae 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/masks.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/masks.dart
@@ -320,7 +320,7 @@
@override
AbstractBool containsType(TypeMask typeMask, ClassEntity cls) {
- return AbstractBool.trueOrMaybe(_containsType(typeMask, cls));
+ return AbstractBool.trueOrFalse(_containsType(typeMask, cls));
}
bool _containsType(TypeMask typeMask, ClassEntity cls) {
@@ -704,13 +704,6 @@
}
@override
- AbstractBool contains(
- covariant TypeMask superset, covariant TypeMask subset) {
- return AbstractBool.maybeOrFalse(
- superset.containsMask(subset, _closedWorld));
- }
-
- @override
AbstractBool isIn(covariant TypeMask subset, covariant TypeMask superset) {
return AbstractBool.trueOrMaybe(subset.isInMask(superset, _closedWorld));
}
diff --git a/pkg/compiler/lib/src/js_emitter/constant_ordering.dart b/pkg/compiler/lib/src/js_emitter/constant_ordering.dart
index bdfb63f..e7158dd 100644
--- a/pkg/compiler/lib/src/js_emitter/constant_ordering.dart
+++ b/pkg/compiler/lib/src/js_emitter/constant_ordering.dart
@@ -36,13 +36,6 @@
return a.accept(this, b);
}
- static int compareNullable<T>(int compare(T a, T b), T a, T b) {
- if (a == null && b == null) return 0;
- if (a == null) return -1;
- if (b == null) return 1;
- return compare(a, b);
- }
-
static int compareLists<S, T>(int compare(S a, T b), List<S> a, List<T> b) {
int r = a.length.compareTo(b.length);
if (r != 0) return r;
diff --git a/pkg/compiler/lib/src/js_model/js_world.dart b/pkg/compiler/lib/src/js_model/js_world.dart
index ca2f1be..0b2a816 100644
--- a/pkg/compiler/lib/src/js_model/js_world.dart
+++ b/pkg/compiler/lib/src/js_model/js_world.dart
@@ -452,13 +452,30 @@
}
}
+ ClassEntity __functionLub;
+ ClassEntity get _functionLub => __functionLub ??=
+ getLubOfInstantiatedSubtypes(commonElements.functionClass);
+
@override
bool includesClosureCall(Selector selector, AbstractValue receiver) {
return selector.name == Identifiers.call &&
(receiver == null ||
- // TODO(johnniwinther): Should this have been `intersects` instead?
+ // This is logically equivalent to the former implementation using
+ // `abstractValueDomain.contains` (which wrapped `containsMask`).
+ // The switch to `abstractValueDomain.containsType` is because
+ // `contains` was generally unsound but happened to work correctly
+ // here. See https://dart-review.googlesource.com/c/sdk/+/130565
+ // for further discussion.
+ //
+ // This checks if the receiver mask contains the entire type cone
+ // originating from [_functionLub] and may therefore be unsound if
+ // the receiver mask contains only part of the type cone. (Is this
+ // possible?)
+ //
+ // TODO(fishythefish): Use `isDisjoint` or equivalent instead of
+ // `containsType` once we can ensure it's fast enough.
abstractValueDomain
- .contains(receiver, abstractValueDomain.functionType)
+ .containsType(receiver, _functionLub)
.isPotentiallyTrue);
}
diff --git a/pkg/compiler/lib/src/kernel/env.dart b/pkg/compiler/lib/src/kernel/env.dart
index 6cb57dd..207fb45 100644
--- a/pkg/compiler/lib/src/kernel/env.dart
+++ b/pkg/compiler/lib/src/kernel/env.dart
@@ -5,7 +5,7 @@
library dart2js.kernel.env;
import 'package:front_end/src/api_unstable/dart2js.dart'
- show isRedirectingFactory;
+ show isRedirectingFactory, isRedirectingFactoryField;
import 'package:kernel/ast.dart' as ir;
import 'package:kernel/clone.dart';
@@ -119,8 +119,7 @@
_memberMap = <String, ir.Member>{};
_setterMap = <String, ir.Member>{};
for (ir.Member member in library.members) {
- if (member.name.name.contains('#')) {
- // Skip synthetic .dill members.
+ if (isRedirectingFactoryField(member)) {
continue;
}
if (member is ir.Procedure) {
@@ -375,11 +374,8 @@
void addField(ir.Field member, {bool includeStatic}) {
if (!includeStatic && member.isStatic) return;
+ if (isRedirectingFactoryField(member)) return;
var name = member.name.name;
- if (name.contains('#')) {
- // Skip synthetic .dill members.
- return;
- }
_memberMap[name] = member;
if (member.isMutable) {
_setterMap[name] = member;
@@ -417,7 +413,6 @@
}
}
var name = member.name.name;
- assert(!name.contains('#'));
if (member.kind == ir.ProcedureKind.Factory) {
if (isRedirectingFactory(member)) {
// Don't include redirecting factories.
@@ -439,7 +434,6 @@
void addConstructors(ir.Class c) {
for (ir.Constructor member in c.constructors) {
var name = member.name.name;
- assert(!name.contains('#'));
_constructorMap[name] = member;
}
}
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index 3e9206e..2035966 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -326,6 +326,14 @@
/// Whether to use the new RTI representation (default).
bool useNewRti = true;
+ /// Whether null-safety (non-nullable types) are enabled.
+ bool get useNullSafety =>
+ languageExperiments[fe.ExperimentalFlag.nonNullable];
+
+ /// When null-safety is enabled, whether the compiler should emit code with
+ /// weak or strong semantics.
+ bool useWeakNullSafetySemantics = false;
+
/// The path to the file that contains the profiled allocations.
///
/// The file must contain the Map that was produced by using
@@ -436,7 +444,10 @@
..codegenShard = _extractIntOption(options, '${Flags.codegenShard}=')
..codegenShards = _extractIntOption(options, '${Flags.codegenShards}=')
..cfeOnly = _hasOption(options, Flags.cfeOnly)
- ..debugGlobalInference = _hasOption(options, Flags.debugGlobalInference);
+ ..debugGlobalInference = _hasOption(options, Flags.debugGlobalInference)
+ ..useWeakNullSafetySemantics = _extractStringOption(
+ options, '${Flags.nonNullableMode}=', 'strong') ==
+ 'weak';
}
void validate() {
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index e1dc2d3..409aac3 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -4810,20 +4810,9 @@
.isPotentiallyTrue) {
// Overwrite the type with the narrower type.
code.instructionType = trustedMask;
- } else if (_abstractValueDomain
- .contains(trustedMask, code.instructionType)
- .isPotentiallyTrue) {
- // It is acceptable for the type parameter to be broader than the
- // specified type.
- } else {
- reporter.reportErrorMessage(
- _elementMap.getSpannable(targetElement, invocation),
- MessageKind.GENERIC, {
- 'text': 'Type argument too narrow for specified behavior type '
- '(${trustedMask} does not allow '
- 'all values in ${code.instructionType})'
- });
}
+ // It is acceptable for the type parameter to be broader than the
+ // specified type.
}
}
diff --git a/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart b/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
index b251b40..6f2fe52 100644
--- a/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
+++ b/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'dart:collection';
+import 'package:front_end/src/api_unstable/ddc.dart';
import 'package:kernel/core_types.dart';
import 'package:kernel/kernel.dart';
@@ -239,7 +240,7 @@
/// if the field [f] is storing that information, otherwise returns `null`.
Iterable<Member> getRedirectingFactories(Field f) {
// TODO(jmesserly): this relies on implementation details in Kernel
- if (f.name.name == '_redirecting#') {
+ if (isRedirectingFactoryField(f)) {
assert(f.isStatic);
var list = f.initializer as ListLiteral;
return list.expressions.map((e) => (e as StaticGet).target);
diff --git a/pkg/front_end/analysis_options_no_lints.yaml b/pkg/front_end/analysis_options_no_lints.yaml
index c24332a..44e9d25 100644
--- a/pkg/front_end/analysis_options_no_lints.yaml
+++ b/pkg/front_end/analysis_options_no_lints.yaml
@@ -11,6 +11,7 @@
- test/id_testing/data/**
- test/language_versioning/data/**
- test/patching/data/**
+ - test/static_types/data/**
errors:
# Allow having TODOs in the code
todo: ignore
diff --git a/pkg/front_end/lib/src/api_unstable/dart2js.dart b/pkg/front_end/lib/src/api_unstable/dart2js.dart
index 668533014..e28f84d 100644
--- a/pkg/front_end/lib/src/api_unstable/dart2js.dart
+++ b/pkg/front_end/lib/src/api_unstable/dart2js.dart
@@ -109,6 +109,9 @@
export '../compute_platform_binaries_location.dart'
show computePlatformBinariesLocation;
+export '../fasta/kernel/redirecting_factory_body.dart'
+ show isRedirectingFactoryField;
+
export '../fasta/operator.dart' show operatorFromString;
export 'compiler_state.dart' show InitializedCompilerState;
diff --git a/pkg/front_end/lib/src/api_unstable/ddc.dart b/pkg/front_end/lib/src/api_unstable/ddc.dart
index bd2044e..412e59f 100644
--- a/pkg/front_end/lib/src/api_unstable/ddc.dart
+++ b/pkg/front_end/lib/src/api_unstable/ddc.dart
@@ -61,7 +61,7 @@
export '../fasta/incremental_compiler.dart' show IncrementalCompiler;
export '../fasta/kernel/redirecting_factory_body.dart'
- show RedirectingFactoryBody;
+ show RedirectingFactoryBody, isRedirectingFactoryField;
export '../fasta/type_inference/type_schema_environment.dart'
show TypeSchemaEnvironment;
diff --git a/pkg/front_end/lib/src/api_unstable/vm.dart b/pkg/front_end/lib/src/api_unstable/vm.dart
index c6e6a46..469da44 100644
--- a/pkg/front_end/lib/src/api_unstable/vm.dart
+++ b/pkg/front_end/lib/src/api_unstable/vm.dart
@@ -60,6 +60,9 @@
export '../fasta/hybrid_file_system.dart' show HybridFileSystem;
+export '../fasta/kernel/redirecting_factory_body.dart'
+ show isRedirectingFactoryField;
+
export '../fasta/kernel/utils.dart'
show
createExpressionEvaluationComponent,
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 5015bbd..b9b7fcb 100644
--- a/pkg/front_end/lib/src/fasta/builder/class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
@@ -101,7 +101,8 @@
templateRedirectingFactoryIncompatibleTypeArgument,
templateTypeArgumentMismatch;
-import '../kernel/redirecting_factory_body.dart' show getRedirectingFactoryBody;
+import '../kernel/redirecting_factory_body.dart'
+ show getRedirectingFactoryBody, redirectingName;
import '../kernel/kernel_target.dart' show KernelTarget;
@@ -252,12 +253,6 @@
callback(Member declaredMember, Member interfaceMember, bool isSetter),
{bool isInterfaceCheck = false});
- void checkOverrides(
- ClassHierarchy hierarchy, TypeEnvironment typeEnvironment);
-
- void checkAbstractMembers(CoreTypes coreTypes, ClassHierarchy hierarchy,
- TypeEnvironment typeEnvironment);
-
bool hasUserDefinedNoSuchMethod(
Class klass, ClassHierarchy hierarchy, Class objectClass);
@@ -970,7 +965,6 @@
// [constructor.target].
//
// TODO(ahe): Add a kernel node to represent redirecting factory bodies.
- const String redirectingName = "_redirecting#";
DillMemberBuilder constructorsField =
origin.scope.lookupLocalMember(redirectingName, setter: false);
if (constructorsField == null) {
@@ -1077,14 +1071,6 @@
}
@override
- void checkOverrides(
- ClassHierarchy hierarchy, TypeEnvironment typeEnvironment) {}
-
- @override
- void checkAbstractMembers(CoreTypes coreTypes, ClassHierarchy hierarchy,
- TypeEnvironment typeEnvironment) {}
-
- @override
bool hasUserDefinedNoSuchMethod(
Class klass, ClassHierarchy hierarchy, Class objectClass) {
Member noSuchMethod = hierarchy.getDispatchTarget(klass, noSuchMethodName);
diff --git a/pkg/front_end/lib/src/fasta/builder/field_builder.dart b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
index ed82b58..b0c57b9 100644
--- a/pkg/front_end/lib/src/fasta/builder/field_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
@@ -8,6 +8,7 @@
import 'package:kernel/ast.dart' hide MapEntry;
import 'package:kernel/core_types.dart';
+import 'package:kernel/src/legacy_erasure.dart';
import '../constant_context.dart' show ConstantContext;
@@ -139,6 +140,8 @@
}
}
+ SourceLibraryBuilder get library => super.library;
+
Member get member => _fieldEncoding.field;
String get debugName => "FieldBuilder";
@@ -331,6 +334,12 @@
if (fieldType is ImplicitFieldType) {
// `fieldType` may have changed if a circularity was detected when
// [inferredType] was computed.
+ if (library.loader.target.enableNonNullable) {
+ if (!library.isNonNullableByDefault) {
+ inferredType = legacyErasure(
+ library.loader.typeInferenceEngine.coreTypes, inferredType);
+ }
+ }
fieldType = inferredType;
IncludesTypeParametersNonCovariantly needsCheckVisitor;
@@ -590,6 +599,26 @@
return initializers;
}
+ /// Creates an [Expression] that reads [_field].
+ ///
+ /// If [needsPromotion] is `true`, the field will be read through a `let`
+ /// expression that promotes the expression to [_type]. This is needed for a
+ /// sound encoding of fields with type variable type of undetermined
+ /// nullability.
+ Expression _createFieldRead({bool needsPromotion: false}) {
+ if (needsPromotion) {
+ VariableDeclaration variable = new VariableDeclaration.forValue(
+ _createFieldGet(_field),
+ type: _type.withNullability(Nullability.nullable))
+ ..fileOffset = fileOffset;
+ return new Let(
+ variable, new VariableGet(variable, _type)..fileOffset = fileOffset);
+ } else {
+ return _createFieldGet(_field);
+ }
+ }
+
+ /// Creates an [Expression] that reads [field].
Expression _createFieldGet(Field field) {
if (field.isStatic) {
return new StaticGet(field)..fileOffset = fileOffset;
@@ -600,6 +629,7 @@
}
}
+ /// Creates an [Expression] that writes [value] to [field].
Expression _createFieldSet(Field field, Expression value) {
if (field.isStatic) {
return new StaticSet(field, value)..fileOffset = fileOffset;
@@ -769,7 +799,7 @@
assert(_type != null, "Type has not been computed for field $name.");
return late_lowering.createGetterWithInitializer(
fileOffset, name, _type, initializer,
- createVariableRead: () => _createFieldGet(_field),
+ createVariableRead: _createFieldRead,
createVariableWrite: (Expression value) =>
_createFieldSet(_field, value),
createIsSetRead: () => _createFieldGet(_lateIsSetField),
@@ -785,7 +815,7 @@
assert(_type != null, "Type has not been computed for field $name.");
return late_lowering.createGetterBodyWithoutInitializer(
coreTypes, fileOffset, name, type, 'Field',
- createVariableRead: () => _createFieldGet(_field),
+ createVariableRead: _createFieldRead,
createIsSetRead: () => _createFieldGet(_lateIsSetField));
}
}
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart
index 5296ed7..18cdf42 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart
@@ -43,7 +43,8 @@
templateTypeNotFound,
templateUnspecified;
-import '../kernel/redirecting_factory_body.dart' show RedirectingFactoryBody;
+import '../kernel/redirecting_factory_body.dart'
+ show RedirectingFactoryBody, isRedirectingFactoryField;
import '../problems.dart' show internalProblem, unhandled, unimplemented;
@@ -160,7 +161,7 @@
cls.procedures.forEach(classBulder.addMember);
cls.constructors.forEach(classBulder.addMember);
for (Field field in cls.fields) {
- if (field.name.name == "_redirecting#") {
+ if (isRedirectingFactoryField(field)) {
ListLiteral initializer = field.initializer;
for (StaticGet get in initializer.expressions) {
RedirectingFactoryBody.restoreFromDill(get.target);
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index 132c992..0855ea2 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -245,7 +245,7 @@
/// This is used to determine whether instance properties are available.
bool inFieldInitializer = false;
- /// `true` if this access is directly in a field initializer of a late field.
+ /// `true` if we are directly in a field initializer of a late field.
///
/// For instance in `<init>` in
///
@@ -257,6 +257,23 @@
///
bool inLateFieldInitializer = false;
+ /// `true` if we are directly in the initializer of a late local.
+ ///
+ /// For instance in `<init>` in
+ ///
+ /// method() {
+ /// late var foo = <init>;
+ /// }
+ /// class Class {
+ /// method() {
+ /// late var bar = <init>;
+ /// }
+ /// }
+ ///
+ bool get inLateLocalInitializer => _localInitializerState.head;
+
+ Link<bool> _localInitializerState = const Link<bool>().prepend(false);
+
List<Initializer> _initializers;
bool inCatchClause = false;
@@ -402,6 +419,15 @@
DartType get implicitTypeArgument => const ImplicitTypeArgument();
+ void _enterLocalState({bool inLateLocalInitializer: false}) {
+ _localInitializerState =
+ _localInitializerState.prepend(inLateLocalInitializer);
+ }
+
+ void _exitLocalState() {
+ _localInitializerState = _localInitializerState.tail;
+ }
+
@override
void registerVariableAssignment(VariableDeclaration variable) {
typePromoter?.mutateVariable(variable, functionNestingLevel);
@@ -2353,6 +2379,7 @@
UnresolvedType type = pop();
int modifiers = (lateToken != null ? lateMask : 0) |
Modifier.validateVarFinalOrConst(varFinalOrConst?.lexeme);
+ _enterLocalState(inLateLocalInitializer: lateToken != null);
super.push(currentLocalVariableModifiers);
super.push(currentLocalVariableType ?? NullValue.Type);
currentLocalVariableType = type;
@@ -2405,6 +2432,7 @@
}
push(forest.variablesDeclaration(variables, uri));
}
+ _exitLocalState();
}
/// Stack containing assigned variables info for try statements.
@@ -2706,7 +2734,14 @@
@override
void endAwaitExpression(Token keyword, Token endToken) {
debugEvent("AwaitExpression");
- push(forest.createAwaitExpression(offsetForToken(keyword), popForValue()));
+ int fileOffset = offsetForToken(keyword);
+ Expression value = popForValue();
+ if (inLateLocalInitializer) {
+ push(buildProblem(fasta.messageAwaitInLateLocalInitializer, fileOffset,
+ keyword.charCount));
+ } else {
+ push(forest.createAwaitExpression(fileOffset, value));
+ }
}
@override
@@ -4337,6 +4372,7 @@
}
void enterFunction() {
+ _enterLocalState();
debugEvent("enterFunction");
functionNestingLevel++;
push(switchScope ?? NullValue.SwitchScope);
@@ -4356,6 +4392,7 @@
List<TypeVariableBuilder> typeVariables = pop();
exitLocalScope();
push(typeVariables ?? NullValue.TypeVariables);
+ _exitLocalState();
}
@override
diff --git a/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart b/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
index 1febb17..384eff8 100644
--- a/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
@@ -4,24 +4,7 @@
library fasta.class_hierarchy_builder;
-import 'package:kernel/ast.dart'
- show
- Class,
- DartType,
- Field,
- FunctionNode,
- InterfaceType,
- InvalidType,
- Library,
- Member,
- Name,
- Nullability,
- Procedure,
- ProcedureKind,
- Supertype,
- TypeParameter,
- TypeParameterType,
- VariableDeclaration;
+import 'package:kernel/ast.dart' hide MapEntry;
import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
@@ -106,6 +89,7 @@
}
int compareDeclarations(ClassMember a, ClassMember b) {
+ if (a == b) return 0;
return ClassHierarchy.compareMembers(a.member, b.member);
}
@@ -253,8 +237,9 @@
}
ClassHierarchyNode getNodeFromClass(ClassBuilder classBuilder) {
- return nodes[classBuilder.cls] ??=
- new ClassHierarchyNodeBuilder(this, classBuilder).build();
+ return nodes[classBuilder.cls] ??= new ClassHierarchyNodeBuilder(
+ this, classBuilder, loader.target.enableNonNullable)
+ .build();
}
ClassHierarchyNode getNodeFromType(TypeBuilder type) {
@@ -280,7 +265,12 @@
Builder supertypeDeclaration = supertypeNode.classBuilder;
if (depth < supertypes.length) {
TypeBuilder asSupertypeOf = supertypes[depth];
- if (asSupertypeOf.declaration == supertypeDeclaration) {
+ TypeDeclarationBuilder declaration = asSupertypeOf.declaration;
+ if (declaration is TypeAliasBuilder) {
+ TypeAliasBuilder aliasBuilder = declaration;
+ declaration = aliasBuilder.unaliasDeclaration;
+ }
+ if (declaration == supertypeDeclaration) {
return asSupertypeOf;
}
}
@@ -437,8 +427,9 @@
for (int i = 0; i < classes.length; i++) {
ClassBuilder classBuilder = classes[i];
if (!classBuilder.isPatch) {
- hierarchy.nodes[classBuilder.cls] =
- new ClassHierarchyNodeBuilder(hierarchy, classBuilder).build();
+ hierarchy.nodes[classBuilder.cls] = new ClassHierarchyNodeBuilder(
+ hierarchy, classBuilder, loader.target.enableNonNullable)
+ .build();
} else {
// TODO(ahe): Merge the injected members of patch into the hierarchy
// node of `cls.origin`.
@@ -453,14 +444,21 @@
final ClassBuilder classBuilder;
+ /// Whether non-nullable types are supported.
+ final bool enableNonNullable;
+
bool hasNoSuchMethod = false;
List<ClassMember> abstractMembers = null;
- ClassHierarchyNodeBuilder(this.hierarchy, this.classBuilder);
+ ClassHierarchyNodeBuilder(
+ this.hierarchy, this.classBuilder, this.enableNonNullable);
ClassBuilder get objectClass => hierarchy.objectClassBuilder;
+ bool get shouldModifyKernel =>
+ classBuilder.library.loader == hierarchy.loader;
+
final Map<Class, Substitution> substitutions = <Class, Substitution>{};
/// When merging `aList` and `bList`, [a] (from `aList`) and [b] (from
@@ -512,18 +510,14 @@
classBuilder,
a,
AbstractMemberOverridingImplementation.selectConcrete(b),
- mergeKind == MergeKind.superclassSetters,
- classBuilder.library.loader == hierarchy.loader);
+ mergeKind.forSetters,
+ shouldModifyKernel);
hierarchy.delayedMemberChecks.add(result);
}
} else if (classBuilder.isMixinApplication &&
a.classBuilder != classBuilder) {
result = InheritedImplementationInterfaceConflict.combined(
- classBuilder,
- a,
- b,
- mergeKind == MergeKind.superclassSetters,
- classBuilder.library.loader == hierarchy.loader,
+ classBuilder, a, b, mergeKind.forSetters, shouldModifyKernel,
isInheritableConflict: false);
if (result is DelayedMember) {
hierarchy.delayedMemberChecks.add(result);
@@ -560,13 +554,13 @@
break;
case MergeKind.interfacesMembers:
- result = InterfaceConflict.combined(classBuilder, a, b, false,
- classBuilder.library.loader == hierarchy.loader);
+ result = InterfaceConflict.combined(
+ classBuilder, a, b, false, shouldModifyKernel);
break;
case MergeKind.interfacesSetters:
- result = InterfaceConflict.combined(classBuilder, a, b, true,
- classBuilder.library.loader == hierarchy.loader);
+ result = InterfaceConflict.combined(
+ classBuilder, a, b, true, shouldModifyKernel);
break;
case MergeKind.supertypesMembers:
@@ -592,18 +586,10 @@
} else {
if (isAbstract(a)) {
result = InterfaceConflict.combined(
- classBuilder,
- a,
- b,
- mergeKind == MergeKind.supertypesSetters,
- classBuilder.library.loader == hierarchy.loader);
+ classBuilder, a, b, mergeKind.forSetters, shouldModifyKernel);
} else {
result = InheritedImplementationInterfaceConflict.combined(
- classBuilder,
- a,
- b,
- mergeKind == MergeKind.supertypesSetters,
- classBuilder.library.loader == hierarchy.loader);
+ classBuilder, a, b, mergeKind.forSetters, shouldModifyKernel);
}
debug?.log("supertypes: ${result}");
if (result is DelayedMember) {
@@ -1160,20 +1146,18 @@
///
/// If [mergeKind] is `MergeKind.supertypes`, [member] isn't
/// implementing/overriding anything.
- void handleOnlyA(ClassMember member, MergeKind mergeKind) {
- if (mergeKind == MergeKind.interfacesMembers ||
- mergeKind == MergeKind.interfacesSetters) {
- return;
+ ClassMember handleOnlyA(ClassMember member, MergeKind mergeKind) {
+ if (mergeKind.betweenInterfaces) {
+ return member;
}
// TODO(ahe): Enable this optimization:
// if (cls is DillClassBuilder) return;
- // assert(mergeKind == MergeKind.interfaces ||
+ // assert(mergeKind.betweenInterfaces ||
// member is! InterfaceConflict);
- if ((mergeKind == MergeKind.superclassMembers ||
- mergeKind == MergeKind.superclassSetters) &&
- isAbstract(member)) {
+ if ((mergeKind.fromSuperclass) && isAbstract(member)) {
recordAbstractMember(member);
}
+ return member;
}
/// When merging `aList` and `bList`, [member] was only found in `bList`.
@@ -1186,32 +1170,40 @@
/// If [mergeKind] is `MergeKind.supertypes`, [member] is implicitly
/// abstract, and not implemented.
ClassMember handleOnlyB(ClassMember member, MergeKind mergeKind) {
- if (mergeKind == MergeKind.interfacesMembers ||
- mergeKind == MergeKind.interfacesSetters) {
+ if (mergeKind.betweenInterfaces) {
return member;
}
// TODO(ahe): Enable this optimization:
// if (cls is DillClassBuilder) return member;
Member target = member.member;
- if ((mergeKind == MergeKind.supertypesMembers ||
- mergeKind == MergeKind.supertypesSetters) ||
- ((mergeKind == MergeKind.superclassMembers ||
- mergeKind == MergeKind.superclassSetters) &&
- target.isAbstract)) {
+ if (mergeKind.fromInterfaces ||
+ (mergeKind.fromSuperclass && target.isAbstract)) {
if (isNameVisibleIn(target.name, classBuilder.library)) {
recordAbstractMember(member);
}
}
- if (mergeKind == MergeKind.superclassMembers &&
+ if (mergeKind.fromSuperclass &&
target.enclosingClass != objectClass.cls &&
target.name == noSuchMethodName) {
hasNoSuchMethod = true;
}
- if (mergeKind != MergeKind.membersWithSetters &&
- mergeKind != MergeKind.settersWithMembers &&
+ if (!mergeKind.forMembersVsSetters &&
member is DelayedMember &&
member.isInheritableConflict) {
- hierarchy.delayedMemberChecks.add(member.withParent(classBuilder));
+ DelayedMember delayedMember = member;
+ member = delayedMember.withParent(classBuilder);
+ hierarchy.delayedMemberChecks.add(member);
+ }
+ if (mergeKind.intoCurrentClass &&
+ hierarchy.loader.target.enableNonNullable) {
+ if (member.classBuilder.library.isNonNullableByDefault &&
+ !classBuilder.library.isNonNullableByDefault) {
+ if (member is! DelayedMember) {
+ member = new InterfaceConflict(
+ classBuilder, [member], mergeKind.forSetters, shouldModifyKernel);
+ hierarchy.delayedMemberChecks.add(member);
+ }
+ }
}
return member;
}
@@ -1697,6 +1689,7 @@
List<ClassMember> merge(
List<ClassMember> aList, List<ClassMember> bList, MergeKind mergeKind) {
+ bool changed = false;
final List<ClassMember> result = new List<ClassMember>.filled(
aList.length + bList.length, null,
growable: true);
@@ -1706,9 +1699,7 @@
while (i < aList.length && j < bList.length) {
final ClassMember a = aList[i];
final ClassMember b = bList[j];
- if ((mergeKind == MergeKind.interfacesMembers ||
- mergeKind == MergeKind.interfacesSetters) &&
- a.isStatic) {
+ if (mergeKind.betweenInterfaces && a.isStatic) {
i++;
continue;
}
@@ -1719,36 +1710,61 @@
final int compare = compareDeclarations(a, b);
if (compare == 0) {
result[storeIndex++] = handleMergeConflict(a, b, mergeKind);
+ changed = true;
i++;
j++;
} else if (compare < 0) {
- handleOnlyA(a, mergeKind);
- result[storeIndex++] = a;
+ ClassMember member = handleOnlyA(a, mergeKind);
+ result[storeIndex++] = member;
+ if (!identical(member, a)) {
+ changed = true;
+ }
i++;
} else {
- result[storeIndex++] = handleOnlyB(b, mergeKind);
+ ClassMember member = handleOnlyB(b, mergeKind);
+ result[storeIndex++] = member;
+ if (!identical(member, b)) {
+ changed = true;
+ }
j++;
}
}
while (i < aList.length) {
final ClassMember a = aList[i];
- if (!(mergeKind == MergeKind.interfacesMembers ||
- mergeKind == MergeKind.interfacesSetters) ||
- !a.isStatic) {
- handleOnlyA(a, mergeKind);
- result[storeIndex++] = a;
+ if (!mergeKind.betweenInterfaces || !a.isStatic) {
+ ClassMember member = handleOnlyA(a, mergeKind);
+ result[storeIndex++] = member;
+ if (!identical(member, a)) {
+ changed = true;
+ }
}
i++;
}
while (j < bList.length) {
final ClassMember b = bList[j];
if (!b.isStatic) {
- result[storeIndex++] = handleOnlyB(b, mergeKind);
+ ClassMember member = handleOnlyB(b, mergeKind);
+ result[storeIndex++] = member;
+ if (!identical(member, b)) {
+ changed = true;
+ }
}
j++;
}
- if (aList.isEmpty && storeIndex == bList.length) return bList;
- if (bList.isEmpty && storeIndex == aList.length) return aList;
+ if (!changed && aList.isEmpty && storeIndex == bList.length) {
+ assert(
+ _equalsList(result, bList, storeIndex),
+ "List mismatch: Expected: ${bList}, "
+ "actual ${result.sublist(0, storeIndex)}");
+ return bList;
+ }
+ if (!changed && bList.isEmpty && storeIndex == aList.length) {
+ assert(
+ _equalsList(result, aList, storeIndex),
+ "List mismatch: Expected: ${aList}, "
+ "actual ${result.sublist(0, storeIndex)}");
+ return aList;
+ }
return result..length = storeIndex;
}
@@ -1980,30 +1996,77 @@
MergeResult(this.mergedMembers, this.mergedSetters);
}
-enum MergeKind {
+class MergeKind {
+ final String name;
+
+ final bool forSetters;
+
+ final bool betweenInterfaces;
+
+ final bool fromSuperclass;
+
+ final bool fromInterfaces;
+
+ final bool forMembersVsSetters;
+
+ final bool intoCurrentClass;
+
+ const MergeKind(this.name,
+ {this.forSetters: false,
+ this.betweenInterfaces: false,
+ this.fromSuperclass: false,
+ this.fromInterfaces: false,
+ this.forMembersVsSetters: false,
+ this.intoCurrentClass: false});
+
+ String toString() => 'MergeKind($name)';
+
/// Merging superclass members with the current class.
- superclassMembers,
+ static const MergeKind superclassMembers = const MergeKind(
+ 'Merging superclass members with the current class.',
+ fromSuperclass: true,
+ intoCurrentClass: true);
/// Merging superclass setters with the current class.
- superclassSetters,
+ static const MergeKind superclassSetters = const MergeKind(
+ 'Merging superclass setters with the current class.',
+ fromSuperclass: true,
+ intoCurrentClass: true,
+ forSetters: true);
/// Merging members of two interfaces.
- interfacesMembers,
+ static const MergeKind interfacesMembers = const MergeKind(
+ 'Merging members of two interfaces.',
+ betweenInterfaces: true);
/// Merging setters of two interfaces.
- interfacesSetters,
+ static const MergeKind interfacesSetters = const MergeKind(
+ 'Merging setters of two interfaces.',
+ betweenInterfaces: true,
+ forSetters: true);
/// Merging class members with interface members.
- supertypesMembers,
+ static const MergeKind supertypesMembers = const MergeKind(
+ 'Merging class members with interface members.',
+ fromInterfaces: true,
+ intoCurrentClass: true);
/// Merging class setters with interface setters.
- supertypesSetters,
+ static const MergeKind supertypesSetters = const MergeKind(
+ 'Merging class setters with interface setters.',
+ fromInterfaces: true,
+ intoCurrentClass: true,
+ forSetters: true);
/// Merging members with inherited setters.
- membersWithSetters,
+ static const MergeKind membersWithSetters = const MergeKind(
+ 'Merging members with inherited setters.',
+ forMembersVsSetters: true);
/// Merging setters with inherited members.
- settersWithMembers,
+ static const MergeKind settersWithMembers = const MergeKind(
+ 'Merging setters with inherited members.',
+ forMembersVsSetters: true);
}
List<LocatedMessage> inheritedConflictContext(ClassMember a, ClassMember b) {
@@ -2637,6 +2700,13 @@
concreteImplementation, isSetter, modifyKernel);
}
+ @override
+ String toString() {
+ return "AbstractMemberOverridingImplementation("
+ "${classBuilder.fullNameForErrors}, "
+ "[${declarations.map(fullName).join(', ')}])";
+ }
+
static ClassMember selectAbstract(ClassMember declaration) {
if (declaration is AbstractMemberOverridingImplementation) {
return declaration.abstractMember;
@@ -2830,3 +2900,14 @@
? declaration.formals[index].type != null
: true;
}
+
+/// Returns `true` if the first [length] elements of [a] and [b] are the same.
+bool _equalsList(List<ClassMember> a, List<ClassMember> b, int length) {
+ if (a.length < length || b.length < length) return false;
+ for (int index = 0; index < length; index++) {
+ if (a[index] != b[index]) {
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/forwarding_node.dart b/pkg/front_end/lib/src/fasta/kernel/forwarding_node.dart
index 55ee9ab..7e3c6140 100644
--- a/pkg/front_end/lib/src/fasta/kernel/forwarding_node.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/forwarding_node.dart
@@ -30,6 +30,9 @@
import "package:kernel/type_algebra.dart" show Substitution;
+import "package:kernel/src/legacy_erasure.dart";
+import "package:kernel/src/nnbd_top_merge.dart";
+
import "../builder/class_builder.dart";
import "../problems.dart" show unhandled;
@@ -77,8 +80,38 @@
/// stub is introduced as a place to put the checks.
Member _computeCovarianceFixes() {
Member interfaceMember = combinedMemberSignatureResult.member;
- Substitution substitution =
- _substitutionFor(interfaceMember, enclosingClass);
+
+ List<TypeParameter> interfaceMemberTypeParameters =
+ interfaceMember.function?.typeParameters ?? [];
+
+ List<TypeParameter> stubTypeParameters;
+ if (interfaceMember.enclosingClass != enclosingClass &&
+ interfaceMemberTypeParameters.isNotEmpty) {
+ // Create type parameters for the stub up front. These are needed to
+ // ensure the [substitutions] are alpha renamed to the same type
+ // parameters.
+ stubTypeParameters = new List<TypeParameter>.filled(
+ interfaceMemberTypeParameters.length, null);
+ for (int i = 0; i < interfaceMemberTypeParameters.length; i++) {
+ TypeParameter targetTypeParameter = interfaceMemberTypeParameters[i];
+ TypeParameter typeParameter = new TypeParameter(
+ targetTypeParameter.name, null)
+ ..isGenericCovariantImpl = targetTypeParameter.isGenericCovariantImpl;
+ stubTypeParameters[i] = typeParameter;
+ }
+ }
+
+ List<Substitution> substitutions =
+ new List<Substitution>(_candidates.length);
+ Substitution substitution;
+ for (int j = 0; j < _candidates.length; j++) {
+ Member otherMember = getCandidateAt(j);
+ substitutions[j] =
+ _substitutionFor(stubTypeParameters, otherMember, enclosingClass);
+ if (otherMember == interfaceMember) {
+ substitution = substitutions[j];
+ }
+ }
// We always create a forwarding stub when we've inherited a member from an
// interface other than the first override candidate. This is to work
// around a bug in the Kernel type checker where it chooses the first
@@ -89,7 +122,8 @@
Member stub = interfaceMember.enclosingClass == enclosingClass ||
interfaceMember == getCandidateAt(0)
? interfaceMember
- : _createForwardingStub(substitution, interfaceMember);
+ : _createForwardingStub(
+ stubTypeParameters, substitution, interfaceMember);
FunctionNode interfaceFunction = interfaceMember.function;
List<VariableDeclaration> interfacePositionalParameters =
@@ -99,10 +133,20 @@
List<TypeParameter> interfaceTypeParameters =
interfaceFunction?.typeParameters ?? [];
- void createStubIfNeeded() {
- if (stub != interfaceMember) return;
+ void createStubIfNeeded({bool forMemberSignature: false}) {
+ if (stub != interfaceMember) {
+ Procedure procedure = stub;
+ if (forMemberSignature) {
+ procedure.isMemberSignature = true;
+ } else {
+ procedure.isForwardingStub = true;
+ }
+ return;
+ }
if (interfaceMember.enclosingClass == enclosingClass) return;
- stub = _createForwardingStub(substitution, interfaceMember);
+ stub = _createForwardingStub(
+ stubTypeParameters, substitution, interfaceMember,
+ forMemberSignature: forMemberSignature);
}
bool isImplCreated = false;
@@ -125,15 +169,36 @@
bool needsCheck(DartType type) => needsCheckVisitor == null
? false
: substitution.substituteType(type).accept(needsCheckVisitor);
+ bool enableNonNullable = hierarchy.loader.target.enableNonNullable;
+ bool isNonNullableByDefault =
+ enableNonNullable && parent.library.isNonNullableByDefault;
+
+ DartType initialType(DartType a) {
+ if (!enableNonNullable) return null;
+ if (!isNonNullableByDefault) {
+ a = legacyErasure(hierarchy.coreTypes, a);
+ }
+ return a;
+ }
+
+ DartType mergeTypes(DartType a, DartType b) {
+ if (a == null) return null;
+ if (!isNonNullableByDefault) {
+ b = legacyErasure(hierarchy.coreTypes, b);
+ }
+ return nnbdTopMerge(hierarchy.coreTypes, a, b);
+ }
+
for (int i = 0; i < interfacePositionalParameters.length; i++) {
VariableDeclaration parameter = interfacePositionalParameters[i];
+ DartType parameterType = parameter.type;
+ DartType type = initialType(substitution.substituteType(parameterType));
bool isGenericCovariantImpl =
parameter.isGenericCovariantImpl || needsCheck(parameter.type);
bool isCovariant = parameter.isCovariant;
VariableDeclaration superParameter = parameter;
for (int j = 0; j < _candidates.length; j++) {
Member otherMember = getCandidateAt(j);
- if (otherMember is ForwardingNode) continue;
List<VariableDeclaration> otherPositionalParameters =
getPositionalParameters(otherMember);
if (otherPositionalParameters.length <= i) continue;
@@ -146,6 +211,8 @@
if (otherParameter.isCovariant) {
isCovariant = true;
}
+ type = mergeTypes(
+ type, substitutions[j].substituteType(otherParameter.type));
}
if (isGenericCovariantImpl) {
if (!superParameter.isGenericCovariantImpl) {
@@ -165,9 +232,19 @@
stub.function.positionalParameters[i].isCovariant = true;
}
}
+ if (enableNonNullable) {
+ if (type != null && type != parameterType) {
+ // TODO(johnniwinther): Report an error when [type] is null; this
+ // means that nnbd-top-merge was not defined.
+ createStubIfNeeded(forMemberSignature: true);
+ stub.function.positionalParameters[i].type = type;
+ }
+ }
}
for (int i = 0; i < interfaceNamedParameters.length; i++) {
VariableDeclaration parameter = interfaceNamedParameters[i];
+ DartType parameterType = parameter.type;
+ DartType type = initialType(substitution.substituteType(parameterType));
bool isGenericCovariantImpl =
parameter.isGenericCovariantImpl || needsCheck(parameter.type);
bool isCovariant = parameter.isCovariant;
@@ -186,6 +263,8 @@
if (otherParameter.isCovariant) {
isCovariant = true;
}
+ type = mergeTypes(
+ type, substitutions[j].substituteType(otherParameter.type));
}
if (isGenericCovariantImpl) {
if (!superParameter.isGenericCovariantImpl) {
@@ -205,6 +284,14 @@
stub.function.namedParameters[i].isCovariant = true;
}
}
+ if (enableNonNullable) {
+ if (type != null && type != parameterType) {
+ // TODO(johnniwinther): Report an error when [type] is null; this
+ // means that nnbd-top-merge was not defined.
+ createStubIfNeeded(forMemberSignature: true);
+ stub.function.namedParameters[i].type = type;
+ }
+ }
}
for (int i = 0; i < interfaceTypeParameters.length; i++) {
TypeParameter typeParameter = interfaceTypeParameters[i];
@@ -234,6 +321,22 @@
}
}
}
+ if (enableNonNullable) {
+ DartType returnType =
+ substitution.substituteType(getReturnType(interfaceMember));
+ DartType type = initialType(returnType);
+ for (int j = 0; j < _candidates.length; j++) {
+ Member otherMember = getCandidateAt(j);
+ type = mergeTypes(
+ type, substitutions[j].substituteType(getReturnType(otherMember)));
+ }
+ if (type != null && type != returnType) {
+ // TODO(johnniwinther): Report an error when [type] is null; this
+ // means that nnbd-top-merge was not defined.
+ createStubIfNeeded(forMemberSignature: true);
+ stub.function.returnType = type;
+ }
+ }
return stub;
}
@@ -299,7 +402,9 @@
}
/// Creates a forwarding stub based on the given [target].
- Procedure _createForwardingStub(Substitution substitution, Member target) {
+ Procedure _createForwardingStub(List<TypeParameter> typeParameters,
+ Substitution substitution, Member target,
+ {bool forMemberSignature: false}) {
VariableDeclaration copyParameter(VariableDeclaration parameter) {
return new VariableDeclaration(parameter.name,
type: substitution.substituteType(parameter.type),
@@ -309,21 +414,14 @@
List<TypeParameter> targetTypeParameters =
target.function?.typeParameters ?? [];
- List<TypeParameter> typeParameters;
- if (targetTypeParameters.isNotEmpty) {
- typeParameters =
- new List<TypeParameter>.filled(targetTypeParameters.length, null);
+ if (typeParameters != null) {
Map<TypeParameter, DartType> additionalSubstitution =
<TypeParameter, DartType>{};
for (int i = 0; i < targetTypeParameters.length; i++) {
TypeParameter targetTypeParameter = targetTypeParameters[i];
- TypeParameter typeParameter = new TypeParameter(
- targetTypeParameter.name, null)
- ..isGenericCovariantImpl = targetTypeParameter.isGenericCovariantImpl;
- typeParameters[i] = typeParameter;
additionalSubstitution[targetTypeParameter] =
new TypeParameterType.forAlphaRenaming(
- targetTypeParameter, typeParameter);
+ targetTypeParameter, typeParameters[i]);
}
substitution = Substitution.combine(
substitution, Substitution.fromMap(additionalSubstitution));
@@ -350,7 +448,8 @@
}
return new Procedure(name, kind, function,
isAbstract: true,
- isForwardingStub: true,
+ isForwardingStub: !forMemberSignature,
+ isMemberSignature: forMemberSignature,
fileUri: enclosingClass.fileUri,
forwardingStubInterfaceTarget: finalTarget)
..startFileOffset = enclosingClass.fileOffset
@@ -380,12 +479,27 @@
}
}
- Substitution _substitutionFor(Member candidate, Class class_) {
- return Substitution.fromInterfaceType(hierarchy.getKernelTypeAsInstanceOf(
- hierarchy.coreTypes
- .thisInterfaceType(class_, class_.enclosingLibrary.nonNullable),
- candidate.enclosingClass,
- class_.enclosingLibrary));
+ Substitution _substitutionFor(
+ List<TypeParameter> stubTypeParameters, Member candidate, Class class_) {
+ Substitution substitution = Substitution.fromInterfaceType(
+ hierarchy.getKernelTypeAsInstanceOf(
+ hierarchy.coreTypes
+ .thisInterfaceType(class_, class_.enclosingLibrary.nonNullable),
+ candidate.enclosingClass,
+ class_.enclosingLibrary));
+ if (stubTypeParameters != null) {
+ // If the stub is generic ensure that type parameters are alpha renamed
+ // to the [stubTypeParameters].
+ Map<TypeParameter, TypeParameterType> map = {};
+ for (int i = 0; i < stubTypeParameters.length; i++) {
+ TypeParameter typeParameter = candidate.function.typeParameters[i];
+ map[typeParameter] = new TypeParameterType.forAlphaRenaming(
+ typeParameter, stubTypeParameters[i]);
+ }
+ substitution =
+ Substitution.combine(substitution, Substitution.fromMap(map));
+ }
+ return substitution;
}
List<VariableDeclaration> getPositionalParameters(Member member) {
diff --git a/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart b/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart
index f6b8941..a437394a 100644
--- a/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart
@@ -8,7 +8,9 @@
import 'package:kernel/ast.dart'
show DartType, DartTypeVisitor, DartTypeVisitor1, Nullability, Visitor;
+
import 'package:kernel/src/assumptions.dart';
+import 'package:kernel/src/legacy_erasure.dart';
import '../builder/field_builder.dart';
@@ -103,6 +105,13 @@
}
DartType inferType() {
- return _targetFieldBuilder.fieldType = _root.inferType();
+ DartType type = _root.inferType();
+ if (_targetFieldBuilder.library.loader.target.enableNonNullable) {
+ if (!_targetFieldBuilder.library.isNonNullableByDefault) {
+ type =
+ legacyErasure(_targetFieldBuilder.library.loader.coreTypes, type);
+ }
+ }
+ return _targetFieldBuilder.fieldType = type;
}
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
index b85cda9..18d1a77 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -5091,7 +5091,14 @@
result.add(isSetVariable);
}
- Expression createVariableRead() => new VariableGet(node);
+ Expression createVariableRead({bool needsPromotion: false}) {
+ if (needsPromotion) {
+ return new VariableGet(node, node.type);
+ } else {
+ return new VariableGet(node);
+ }
+ }
+
Expression createIsSetRead() => new VariableGet(isSetVariable);
Expression createVariableWrite(Expression value) =>
new VariableSet(node, value);
diff --git a/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart b/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart
index 3f0a3c4..ca339e3 100644
--- a/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart
@@ -9,7 +9,7 @@
Statement createGetterWithInitializer(
int fileOffset, String name, DartType type, Expression initializer,
- {Expression createVariableRead(),
+ {Expression createVariableRead({bool needsPromotion}),
Expression createVariableWrite(Expression value),
Expression createIsSetRead(),
Expression createIsSetWrite(Expression value)}) {
@@ -36,7 +36,11 @@
]),
null)
..fileOffset = fileOffset,
- new ReturnStatement(createVariableRead()..fileOffset = fileOffset)
+ new ReturnStatement(
+ // If [type] is a type variable with undetermined nullability we need
+ // to create a read of the field that is promoted to the type variable
+ // type.
+ createVariableRead(needsPromotion: type.isPotentiallyNonNullable))
..fileOffset = fileOffset
])
..fileOffset = fileOffset;
@@ -45,7 +49,7 @@
//
// return let # = _#field in # == null ? _#field = <init> : #;
VariableDeclaration variable = new VariableDeclaration.forValue(
- createVariableRead()..fileOffset = fileOffset,
+ createVariableRead(needsPromotion: false)..fileOffset = fileOffset,
type: type.withNullability(Nullability.nullable))
..fileOffset = fileOffset;
return new ReturnStatement(
@@ -71,7 +75,8 @@
Statement createGetterBodyWithoutInitializer(CoreTypes coreTypes,
int fileOffset, String name, DartType type, String variableKindName,
- {Expression createVariableRead(), Expression createIsSetRead()}) {
+ {Expression createVariableRead({bool needsPromotion}),
+ Expression createIsSetRead()}) {
Expression exception = new Throw(new ConstructorInvocation(
coreTypes.lateInitializationErrorConstructor,
new Arguments(<Expression>[
@@ -87,8 +92,12 @@
//
// return _#isSet#field ? _#field : throw '...';
return new ReturnStatement(
- new ConditionalExpression(createIsSetRead()..fileOffset = fileOffset,
- createVariableRead()..fileOffset = fileOffset, exception, type)
+ new ConditionalExpression(
+ createIsSetRead()..fileOffset = fileOffset,
+ createVariableRead(needsPromotion: type.isPotentiallyNonNullable)
+ ..fileOffset = fileOffset,
+ exception,
+ type)
..fileOffset = fileOffset)
..fileOffset = fileOffset;
} else {
diff --git a/pkg/front_end/lib/src/fasta/kernel/redirecting_factory_body.dart b/pkg/front_end/lib/src/fasta/kernel/redirecting_factory_body.dart
index 5added1..6b88bcd 100644
--- a/pkg/front_end/lib/src/fasta/kernel/redirecting_factory_body.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/redirecting_factory_body.dart
@@ -9,6 +9,7 @@
DartType,
Expression,
ExpressionStatement,
+ Field,
FunctionNode,
InvalidExpression,
Let,
@@ -24,6 +25,21 @@
import 'body_builder.dart' show EnsureLoaded;
+/// Name used for a static field holding redirecting factory information.
+const String redirectingName = "_redirecting#";
+
+/// Returns `true` if [member] is synthesized field holding the names of
+/// redirecting factories declared in the same class.
+///
+/// This field should be special-cased by backends.
+bool isRedirectingFactoryField(Member member) {
+ return member is Field &&
+ member.isStatic &&
+ member.name.name == redirectingName;
+}
+
+/// Name used for a synthesized let variable used to encode redirecting factory
+/// information in a factory method body.
const String letName = "#redirecting_factory";
class RedirectingFactoryBody extends ExpressionStatement {
diff --git a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
index 09fc289..d7cee7f 100644
--- a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
@@ -95,8 +95,6 @@
import '../scope.dart';
-import '../source/source_library_builder.dart' show SourceLibraryBuilder;
-
import 'source_library_builder.dart' show SourceLibraryBuilder;
Class initializeClass(
diff --git a/pkg/front_end/lib/src/testing/id_testing_helper.dart b/pkg/front_end/lib/src/testing/id_testing_helper.dart
index e88e95a..63dbae5 100644
--- a/pkg/front_end/lib/src/testing/id_testing_helper.dart
+++ b/pkg/front_end/lib/src/testing/id_testing_helper.dart
@@ -120,9 +120,13 @@
int offset;
if (id.className != null) {
Class cls = lookupClass(library, id.className);
- member = lookupClassMember(cls, id.memberName);
- offset = member.fileOffset;
- if (offset == -1) {
+ member = lookupClassMember(cls, id.memberName, required: false);
+ if (member != null) {
+ offset = member.fileOffset;
+ if (offset == -1) {
+ offset = cls.fileOffset;
+ }
+ } else {
offset = cls.fileOffset;
}
} else {
diff --git a/pkg/front_end/lib/src/testing/id_testing_utils.dart b/pkg/front_end/lib/src/testing/id_testing_utils.dart
index 91d6e0a..b399707 100644
--- a/pkg/front_end/lib/src/testing/id_testing_utils.dart
+++ b/pkg/front_end/lib/src/testing/id_testing_utils.dart
@@ -505,6 +505,9 @@
comma = '';
for (NamedType namedParameter in node.namedParameters) {
sb.write(comma);
+ if (namedParameter.isRequired) {
+ sb.write('required ');
+ }
visit(namedParameter.type);
sb.write(' ');
sb.write(namedParameter.name);
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index 694f491..8600797 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -26,6 +26,8 @@
AsyncAsIdentifier/example: Fail
AwaitAsIdentifier/example: Fail
AwaitNotAsync/example: Fail
+AwaitInLateLocalInitializer/analyzerCode: Fail
+AwaitInLateLocalInitializer/example: Fail
BuiltInIdentifierAsType/example: Fail
BuiltInIdentifierInDeclaration/example: Fail
BytecodeLimitExceededTooManyArguments/analyzerCode: Fail
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 035c8e2..e538ddc 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -3768,3 +3768,6 @@
ValueForRequiredParameterNotProvidedWarning:
template: "Missing required named parameter '#name'."
severity: WARNING
+
+AwaitInLateLocalInitializer:
+ template: "`await` expressions are not supported in late local initializers."
diff --git a/pkg/front_end/test/id_tests/inheritance_test.dart b/pkg/front_end/test/id_tests/inheritance_test.dart
index 81f4c90..9bf13d2 100644
--- a/pkg/front_end/test/id_tests/inheritance_test.dart
+++ b/pkg/front_end/test/id_tests/inheritance_test.dart
@@ -3,13 +3,12 @@
// BSD-style license that can be found in the LICENSE file.
import 'dart:io' show Directory, Platform;
-import 'package:_fe_analyzer_shared/src/testing/id.dart' show ActualData, Id;
-import 'package:_fe_analyzer_shared/src/testing/id_testing.dart'
- show DataInterpreter, runTests;
+import 'package:_fe_analyzer_shared/src/testing/id.dart';
import 'package:_fe_analyzer_shared/src/testing/id_testing.dart';
import 'package:front_end/src/fasta/kernel/kernel_api.dart';
import 'package:front_end/src/testing/id_testing_helper.dart';
import 'package:front_end/src/testing/id_testing_utils.dart';
+import 'package:front_end/src/testing/id_extractor.dart';
import 'package:kernel/ast.dart';
main(List<String> args) async {
@@ -17,7 +16,7 @@
.resolve('../../../_fe_analyzer_shared/test/inheritance/data'));
await runTests<String>(dataDir,
args: args,
- supportedMarkers: cfeAnalyzerMarkers,
+ supportedMarkers: [cfeMarker],
createUriForFileName: createUriForFileName,
onFailure: onFailure,
runTest: runTestFor(
@@ -60,10 +59,12 @@
class InheritanceDataExtractor extends CfeDataExtractor<String> {
final ClassHierarchy _hierarchy;
+ final CoreTypes _coreTypes;
InheritanceDataExtractor(InternalCompilerResult compilerResult,
Map<Id, ActualData<String>> actualMap)
: _hierarchy = compilerResult.classHierarchy,
+ _coreTypes = compilerResult.coreTypes,
super(compilerResult, actualMap);
@override
@@ -72,6 +73,80 @@
}
@override
+ void computeForClass(Class node) {
+ super.computeForClass(node);
+
+ Set<Name> getters = _hierarchy
+ .getInterfaceMembers(node)
+ .map((Member member) => member.name)
+ .toSet();
+ Set<Name> setters = _hierarchy
+ .getInterfaceMembers(node, setters: true)
+ .where((Member member) =>
+ member is Procedure && member.kind == ProcedureKind.Setter)
+ .map((Member member) => member.name)
+ .toSet();
+
+ void addMember(Name name, {bool setter}) {
+ Member member = _hierarchy.getInterfaceMember(node, name, setter: setter);
+ if (member.enclosingClass == _coreTypes.objectClass) {
+ return;
+ }
+ InterfaceType supertype = _hierarchy.getTypeAsInstanceOf(
+ _coreTypes.thisInterfaceType(node, node.enclosingLibrary.nonNullable),
+ member.enclosingClass,
+ node.enclosingLibrary,
+ _coreTypes);
+ Substitution substitution = Substitution.fromInterfaceType(supertype);
+ DartType type;
+ if (member is Procedure) {
+ if (member.kind == ProcedureKind.Getter) {
+ type = substitution.substituteType(member.function.returnType);
+ } else if (member.kind == ProcedureKind.Setter) {
+ type = substitution
+ .substituteType(member.function.positionalParameters.single.type);
+ } else {
+ type = substitution.substituteType(member.function
+ .computeThisFunctionType(member.enclosingLibrary.nonNullable));
+ }
+ } else if (member is Field) {
+ type = substitution.substituteType(member.type);
+ }
+ if (type == null) {
+ return;
+ }
+
+ String memberName = name.name;
+ if (member is Procedure && member.kind == ProcedureKind.Setter) {
+ memberName += '=';
+ }
+ MemberId id = new MemberId.internal(memberName, className: node.name);
+
+ TreeNode nodeWithOffset;
+ if (member.enclosingClass == node) {
+ nodeWithOffset = computeTreeNodeWithOffset(member);
+ } else {
+ nodeWithOffset = computeTreeNodeWithOffset(node);
+ }
+
+ registerValue(
+ nodeWithOffset?.location?.file,
+ nodeWithOffset?.fileOffset,
+ id,
+ typeToText(type, TypeRepresentation.implicitUndetermined),
+ member);
+ }
+
+ for (Name name in getters) {
+ addMember(name, setter: false);
+ }
+
+ for (Name name in setters) {
+ addMember(name, setter: true);
+ }
+ }
+
+ @override
String computeClassValue(Id id, Class node) {
List<String> supertypes = <String>[];
for (Class superclass in computeAllSuperclasses(node)) {
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 8d05fec..55e557c 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -144,8 +144,11 @@
clarification
clashes
class's
+class2a
+class2b
class3a
class3b
+class3c
class4a
class4b
class4c
@@ -532,12 +535,20 @@
locationd
logging
lots
+lp
lparen
+lq
+lr
lry
ls
lt
+lu
lub
+lv
lvalue
+lx
+ly
+lz
m
maintaining
mangled
@@ -555,6 +566,24 @@
method2b
method3a
method3b
+method3c
+method4a
+method4b
+method4c
+method5a
+method5b
+method5c
+method6a
+method6b
+method6c
+method7a
+method7b
+method8a
+method8b
+method9a
+method9b
+method10a
+method10b
mi
migration
mime
diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt
index 3872b60..c9e81d4 100644
--- a/pkg/front_end/test/spell_checking_list_common.txt
+++ b/pkg/front_end/test/spell_checking_list_common.txt
@@ -383,6 +383,7 @@
cascaded
cascading
case
+cased
cases
casting
catch
@@ -589,6 +590,7 @@
constuctor
consume
consumed
+consumer
consuming
contain
contained
@@ -1424,6 +1426,7 @@
inheritable
inheritance
inherited
+inheriting
inherits
initial
initialization
@@ -2199,6 +2202,7 @@
promote
promoted
promoter
+promotes
promotion
promotions
propagate
@@ -2647,6 +2651,7 @@
sorting
sorts
sought
+sound
source
sources
space
diff --git a/pkg/front_end/test/static_types/data/from_opt_in/main.dart b/pkg/front_end/test/static_types/data/from_opt_in/main.dart
new file mode 100644
index 0000000..df616be
--- /dev/null
+++ b/pkg/front_end/test/static_types/data/from_opt_in/main.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// @dart=2.5
+
+/*library: nnbd=false*/
+
+import 'opt_in.dart';
+
+class LegacyClass extends Class implements Interface {
+ int method3() => /*int*/ 0;
+
+ int method4() => /*int*/ 0;
+}
+
+main() {
+ LegacyClass c = new /*LegacyClass*/ LegacyClass();
+ /*LegacyClass*/ c. /*invoke: int*/ method1();
+ /*LegacyClass*/ c. /*invoke: int*/ method2();
+ /*LegacyClass*/ c. /*invoke: int*/ method3();
+ /*LegacyClass*/ c. /*invoke: int*/ method4();
+}
diff --git a/pkg/front_end/test/static_types/data/from_opt_in/opt_in.dart b/pkg/front_end/test/static_types/data/from_opt_in/opt_in.dart
new file mode 100644
index 0000000..a0e60e2
--- /dev/null
+++ b/pkg/front_end/test/static_types/data/from_opt_in/opt_in.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/*library: nnbd=true*/
+
+abstract class Interface {
+ int? method1();
+ int method2();
+ int? method3();
+ int method4();
+}
+
+class Class {
+ int method1() => /*int!*/ 0;
+ int? method2() => /*int!*/ 0;
+}
diff --git a/pkg/front_end/test/static_types/data/from_opt_out/main.dart b/pkg/front_end/test/static_types/data/from_opt_out/main.dart
new file mode 100644
index 0000000..13870b0
--- /dev/null
+++ b/pkg/front_end/test/static_types/data/from_opt_out/main.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/*library: nnbd=true*/
+
+import 'opt_out.dart';
+
+abstract class Interface {
+ int? method1();
+ int method2();
+ int? method3();
+ int method4();
+}
+
+class Class1 extends LegacyClass {
+ int method1() => /*int!*/ 0;
+ int? method2() => /*int!*/ 0;
+}
+
+class Class2 extends LegacyClass implements Interface {}
+
+main() {
+ Class1 c1 = new /*Class1!*/ Class1();
+ /*Class1!*/ c1. /*invoke: int!*/ method1();
+ /*Class1!*/ c1. /*invoke: int?*/ method2();
+ /*Class1!*/ c1. /*invoke: int*/ method3();
+ /*Class1!*/ c1. /*invoke: int*/ method4();
+ Interface i = new /*Class2!*/ Class2();
+ /*Interface!*/ i. /*invoke: int?*/ method1();
+ /*Interface!*/ i. /*invoke: int!*/ method2();
+ /*Interface!*/ i. /*invoke: int?*/ method3();
+ /*Interface!*/ i. /*invoke: int!*/ method4();
+ Class2 c2 = new /*Class2!*/ Class2();
+ /*Class2!*/ c2. /*invoke: int?*/ method1();
+ /*Class2!*/ c2. /*invoke: int!*/ method2();
+ /*Class2!*/ c2. /*invoke: int?*/ method3();
+ /*Class2!*/ c2. /*invoke: int!*/ method4();
+}
diff --git a/pkg/front_end/test/static_types/data/from_opt_out/opt_out.dart b/pkg/front_end/test/static_types/data/from_opt_out/opt_out.dart
new file mode 100644
index 0000000..988df32
--- /dev/null
+++ b/pkg/front_end/test/static_types/data/from_opt_out/opt_out.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// @dart=2.5
+
+/*library: nnbd=false*/
+
+class LegacyClass {
+ int method1() => /*int*/ 0;
+
+ int method2() => /*int*/ 0;
+
+ int method3() => /*int*/ 0;
+
+ int method4() => /*int*/ 0;
+}
diff --git a/pkg/front_end/test/static_types/static_type_test.dart b/pkg/front_end/test/static_types/static_type_test.dart
index 7da8681..a20a633 100644
--- a/pkg/front_end/test/static_types/static_type_test.dart
+++ b/pkg/front_end/test/static_types/static_type_test.dart
@@ -21,7 +21,14 @@
createUriForFileName: createUriForFileName,
onFailure: onFailure,
runTest: runTestFor(const StaticTypeDataComputer(),
- [defaultCfeConfig, cfeNonNullableConfig]));
+ [defaultCfeConfig, cfeNonNullableConfig]),
+ skipMap: {
+ defaultCfeConfig.marker: [
+ // NNBD-only tests.
+ 'from_opt_in',
+ 'from_opt_out',
+ ]
+ });
}
class StaticTypeDataComputer extends DataComputer<String> {
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/await_in_non_async.yaml.world.1.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/await_in_non_async.yaml.world.1.expect
index c58b401..30e56b1 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/await_in_non_async.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/await_in_non_async.yaml.world.1.expect
@@ -8,9 +8,9 @@
}
And 19 platform libraries:
- - dart:vmservice_io
- dart:_http
- dart:_builtin
+ - dart:vmservice_io
- dart:async
- dart:cli
- dart:collection
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/await_in_non_async.yaml.world.2.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/await_in_non_async.yaml.world.2.expect
index ea10dfd..5d64fb9 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/await_in_non_async.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/await_in_non_async.yaml.world.2.expect
@@ -15,9 +15,9 @@
}
And 19 platform libraries:
- - dart:vmservice_io
- dart:_http
- dart:_builtin
+ - dart:vmservice_io
- dart:async
- dart:cli
- dart:collection
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/load_from_component_explicitly_import_dart_core.yaml.world.1.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/load_from_component_explicitly_import_dart_core.yaml.world.1.expect
index 4e19cd5..9605a7f 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/load_from_component_explicitly_import_dart_core.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/load_from_component_explicitly_import_dart_core.yaml.world.1.expect
@@ -17,9 +17,9 @@
}
And 19 platform libraries:
- - dart:vmservice_io
- dart:_http
- dart:_builtin
+ - dart:vmservice_io
- dart:async
- dart:cli
- dart:collection
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/load_from_component_explicitly_import_dart_core.yaml.world.2.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/load_from_component_explicitly_import_dart_core.yaml.world.2.expect
index 4e19cd5..9605a7f 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/load_from_component_explicitly_import_dart_core.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/load_from_component_explicitly_import_dart_core.yaml.world.2.expect
@@ -17,9 +17,9 @@
}
And 19 platform libraries:
- - dart:vmservice_io
- dart:_http
- dart:_builtin
+ - dart:vmservice_io
- dart:async
- dart:cli
- dart:collection
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/omit_platform_works_3.yaml.world.1.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/omit_platform_works_3.yaml.world.1.expect
index 62daba9..6c58888 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/omit_platform_works_3.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/omit_platform_works_3.yaml.world.1.expect
@@ -7,9 +7,9 @@
}
And 19 platform libraries:
- - dart:vmservice_io
- dart:_http
- dart:_builtin
+ - dart:vmservice_io
- dart:async
- dart:cli
- dart:collection
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/omit_platform_works_3.yaml.world.4.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/omit_platform_works_3.yaml.world.4.expect
index 6a5ad02..ee707d8 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/omit_platform_works_3.yaml.world.4.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/omit_platform_works_3.yaml.world.4.expect
@@ -15,9 +15,9 @@
}
And 19 platform libraries:
- - dart:vmservice_io
- dart:_http
- dart:_builtin
+ - dart:vmservice_io
- dart:async
- dart:cli
- dart:collection
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/omit_platform_works_3.yaml.world.5.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/omit_platform_works_3.yaml.world.5.expect
index d78d309..b397a3b 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/omit_platform_works_3.yaml.world.5.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/omit_platform_works_3.yaml.world.5.expect
@@ -15,9 +15,9 @@
}
And 19 platform libraries:
- - dart:vmservice_io
- dart:_http
- dart:_builtin
+ - dart:vmservice_io
- dart:async
- dart:cli
- dart:collection
diff --git a/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart b/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart
index 896f009..0be2f75 100644
--- a/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart
+++ b/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart
@@ -4,7 +4,7 @@
late int lateTopLevelField1 = 123;
-class Class {
+class Class<T> {
static late int lateStaticField1 = 87;
static late int lateStaticField2 = 42;
@@ -15,15 +15,27 @@
}
late int lateInstanceField = 16;
+ final T field;
+ late T lateGenericField1 = field;
+ late T lateGenericField2 = field;
- instanceMethod() {
+ Class(this.field);
+
+ instanceMethod(T value) {
expect(16, lateInstanceField);
lateInstanceField = 17;
expect(17, lateInstanceField);
+
+ expect(field, lateGenericField1);
+ lateGenericField1 = value;
+ expect(value, lateGenericField1);
+
+ lateGenericField2 = value;
+ expect(value, lateGenericField2);
}
}
-extension Extension on Class {
+extension Extension<T> on Class<T> {
static late int lateExtensionField1 = 87;
static late int lateExtensionField2 = 42;
@@ -44,7 +56,7 @@
expect(88, Class.lateStaticField1);
Class.staticMethod();
- new Class().instanceMethod();
+ new Class<int>(0).instanceMethod(42);
expect(87, Extension.lateExtensionField1);
Extension.lateExtensionField1 = 88;
diff --git a/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart.outline.expect b/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart.outline.expect
index d47aaf2..a39d7fc 100644
--- a/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart.outline.expect
+++ b/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart.outline.expect
@@ -2,11 +2,16 @@
import self as self;
import "dart:core" as core;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? _#lateStaticField1;
static field core::int? _#lateStaticField2;
field core::int? _#lateInstanceField;
- synthetic constructor •() → self::Class
+ final field self::Class::T% field;
+ generic-covariant-impl field self::Class::T? _#lateGenericField1;
+ field core::bool _#lateGenericField1#isSet;
+ generic-covariant-impl field self::Class::T? _#lateGenericField2;
+ field core::bool _#lateGenericField2#isSet;
+ constructor •(self::Class::T% field) → self::Class<self::Class::T%>
;
static get lateStaticField1() → core::int;
static set lateStaticField1(core::int #t1) → void;
@@ -16,10 +21,14 @@
;
get lateInstanceField() → core::int;
set lateInstanceField(core::int #t3) → void;
- method instanceMethod() → dynamic
+ get lateGenericField1() → self::Class::T%;
+ set lateGenericField1(self::Class::T% #t4) → void;
+ get lateGenericField2() → self::Class::T%;
+ set lateGenericField2(self::Class::T% #t5) → void;
+ method instanceMethod(generic-covariant-impl self::Class::T% value) → dynamic
;
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
static get lateExtensionField1 = get self::Extension|lateExtensionField1;
static set lateExtensionField1 = set self::Extension|lateExtensionField1;
@@ -32,11 +41,11 @@
static field core::int? _#Extension|lateExtensionField1;
static field core::int? _#Extension|lateExtensionField2;
static get lateTopLevelField1() → core::int;
-static set lateTopLevelField1(core::int #t4) → void;
+static set lateTopLevelField1(core::int #t6) → void;
static get Extension|lateExtensionField1() → core::int;
-static set Extension|lateExtensionField1(core::int #t5) → void;
+static set Extension|lateExtensionField1(core::int #t7) → void;
static get Extension|lateExtensionField2() → core::int;
-static set Extension|lateExtensionField2(core::int #t6) → void;
+static set Extension|lateExtensionField2(core::int #t8) → void;
static method Extension|staticMethod() → dynamic
;
static method main() → dynamic
diff --git a/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart.strong.expect
index b5758c3..d990f22 100644
--- a/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart.strong.expect
+++ b/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart.strong.expect
@@ -2,12 +2,17 @@
import self as self;
import "dart:core" as core;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? _#lateStaticField1 = null;
static field core::int? _#lateStaticField2 = null;
field core::int? _#lateInstanceField = null;
- synthetic constructor •() → self::Class
- : super core::Object::•()
+ final field self::Class::T% field;
+ generic-covariant-impl field self::Class::T? _#lateGenericField1 = null;
+ field core::bool _#lateGenericField1#isSet = false;
+ generic-covariant-impl field self::Class::T? _#lateGenericField2 = null;
+ field core::bool _#lateGenericField2#isSet = false;
+ constructor •(self::Class::T% field) → self::Class<self::Class::T%>
+ : self::Class::field = field, super core::Object::•()
;
static get lateStaticField1() → core::int
return let final core::int? #t1 = self::Class::_#lateStaticField1 in #t1.==(null) ?{core::int} self::Class::_#lateStaticField1 = 87 : #t1{core::int};
@@ -26,13 +31,40 @@
return let final core::int? #t5 = this.{self::Class::_#lateInstanceField} in #t5.==(null) ?{core::int} this.{self::Class::_#lateInstanceField} = 16 : #t5{core::int};
set lateInstanceField(core::int #t6) → void
this.{self::Class::_#lateInstanceField} = #t6;
- method instanceMethod() → dynamic {
+ get lateGenericField1() → self::Class::T% {
+ if(!this.{self::Class::_#lateGenericField1#isSet}) {
+ this.{self::Class::_#lateGenericField1#isSet} = true;
+ this.{self::Class::_#lateGenericField1} = this.{self::Class::field};
+ }
+ return let final self::Class::T? #t7 = this.{self::Class::_#lateGenericField1} in #t7{self::Class::T%};
+ }
+ set lateGenericField1(self::Class::T% #t8) → void {
+ this.{self::Class::_#lateGenericField1#isSet} = true;
+ this.{self::Class::_#lateGenericField1} = #t8;
+ }
+ get lateGenericField2() → self::Class::T% {
+ if(!this.{self::Class::_#lateGenericField2#isSet}) {
+ this.{self::Class::_#lateGenericField2#isSet} = true;
+ this.{self::Class::_#lateGenericField2} = this.{self::Class::field};
+ }
+ return let final self::Class::T? #t9 = this.{self::Class::_#lateGenericField2} in #t9{self::Class::T%};
+ }
+ set lateGenericField2(self::Class::T% #t10) → void {
+ this.{self::Class::_#lateGenericField2#isSet} = true;
+ this.{self::Class::_#lateGenericField2} = #t10;
+ }
+ method instanceMethod(generic-covariant-impl self::Class::T% value) → dynamic {
self::expect(16, this.{self::Class::lateInstanceField});
this.{self::Class::lateInstanceField} = 17;
self::expect(17, this.{self::Class::lateInstanceField});
+ self::expect(this.{self::Class::field}, this.{self::Class::lateGenericField1});
+ this.{self::Class::lateGenericField1} = value;
+ self::expect(value, this.{self::Class::lateGenericField1});
+ this.{self::Class::lateGenericField2} = value;
+ self::expect(value, this.{self::Class::lateGenericField2});
}
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
static get lateExtensionField1 = get self::Extension|lateExtensionField1;
static set lateExtensionField1 = set self::Extension|lateExtensionField1;
@@ -45,17 +77,17 @@
static field core::int? _#Extension|lateExtensionField1 = null;
static field core::int? _#Extension|lateExtensionField2 = null;
static get lateTopLevelField1() → core::int
- return let final core::int? #t7 = self::_#lateTopLevelField1 in #t7.==(null) ?{core::int} self::_#lateTopLevelField1 = 123 : #t7{core::int};
-static set lateTopLevelField1(core::int #t8) → void
- self::_#lateTopLevelField1 = #t8;
+ return let final core::int? #t11 = self::_#lateTopLevelField1 in #t11.==(null) ?{core::int} self::_#lateTopLevelField1 = 123 : #t11{core::int};
+static set lateTopLevelField1(core::int #t12) → void
+ self::_#lateTopLevelField1 = #t12;
static get Extension|lateExtensionField1() → core::int
- return let final core::int? #t9 = self::_#Extension|lateExtensionField1 in #t9.==(null) ?{core::int} self::_#Extension|lateExtensionField1 = 87 : #t9{core::int};
-static set Extension|lateExtensionField1(core::int #t10) → void
- self::_#Extension|lateExtensionField1 = #t10;
+ return let final core::int? #t13 = self::_#Extension|lateExtensionField1 in #t13.==(null) ?{core::int} self::_#Extension|lateExtensionField1 = 87 : #t13{core::int};
+static set Extension|lateExtensionField1(core::int #t14) → void
+ self::_#Extension|lateExtensionField1 = #t14;
static get Extension|lateExtensionField2() → core::int
- return let final core::int? #t11 = self::_#Extension|lateExtensionField2 in #t11.==(null) ?{core::int} self::_#Extension|lateExtensionField2 = 42 : #t11{core::int};
-static set Extension|lateExtensionField2(core::int #t12) → void
- self::_#Extension|lateExtensionField2 = #t12;
+ return let final core::int? #t15 = self::_#Extension|lateExtensionField2 in #t15.==(null) ?{core::int} self::_#Extension|lateExtensionField2 = 42 : #t15{core::int};
+static set Extension|lateExtensionField2(core::int #t16) → void
+ self::_#Extension|lateExtensionField2 = #t16;
static method Extension|staticMethod() → dynamic {
self::expect(42, self::Extension|lateExtensionField2);
self::Extension|lateExtensionField2 = 43;
@@ -69,7 +101,7 @@
self::Class::lateStaticField1 = 88;
self::expect(88, self::Class::lateStaticField1);
self::Class::staticMethod();
- new self::Class::•().{self::Class::instanceMethod}();
+ new self::Class::•<core::int>(0).{self::Class::instanceMethod}(42);
self::expect(87, self::Extension|lateExtensionField1);
self::Extension|lateExtensionField1 = 88;
self::expect(88, self::Extension|lateExtensionField1);
diff --git a/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart.strong.transformed.expect
index b5758c3..d990f22 100644
--- a/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart.strong.transformed.expect
@@ -2,12 +2,17 @@
import self as self;
import "dart:core" as core;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? _#lateStaticField1 = null;
static field core::int? _#lateStaticField2 = null;
field core::int? _#lateInstanceField = null;
- synthetic constructor •() → self::Class
- : super core::Object::•()
+ final field self::Class::T% field;
+ generic-covariant-impl field self::Class::T? _#lateGenericField1 = null;
+ field core::bool _#lateGenericField1#isSet = false;
+ generic-covariant-impl field self::Class::T? _#lateGenericField2 = null;
+ field core::bool _#lateGenericField2#isSet = false;
+ constructor •(self::Class::T% field) → self::Class<self::Class::T%>
+ : self::Class::field = field, super core::Object::•()
;
static get lateStaticField1() → core::int
return let final core::int? #t1 = self::Class::_#lateStaticField1 in #t1.==(null) ?{core::int} self::Class::_#lateStaticField1 = 87 : #t1{core::int};
@@ -26,13 +31,40 @@
return let final core::int? #t5 = this.{self::Class::_#lateInstanceField} in #t5.==(null) ?{core::int} this.{self::Class::_#lateInstanceField} = 16 : #t5{core::int};
set lateInstanceField(core::int #t6) → void
this.{self::Class::_#lateInstanceField} = #t6;
- method instanceMethod() → dynamic {
+ get lateGenericField1() → self::Class::T% {
+ if(!this.{self::Class::_#lateGenericField1#isSet}) {
+ this.{self::Class::_#lateGenericField1#isSet} = true;
+ this.{self::Class::_#lateGenericField1} = this.{self::Class::field};
+ }
+ return let final self::Class::T? #t7 = this.{self::Class::_#lateGenericField1} in #t7{self::Class::T%};
+ }
+ set lateGenericField1(self::Class::T% #t8) → void {
+ this.{self::Class::_#lateGenericField1#isSet} = true;
+ this.{self::Class::_#lateGenericField1} = #t8;
+ }
+ get lateGenericField2() → self::Class::T% {
+ if(!this.{self::Class::_#lateGenericField2#isSet}) {
+ this.{self::Class::_#lateGenericField2#isSet} = true;
+ this.{self::Class::_#lateGenericField2} = this.{self::Class::field};
+ }
+ return let final self::Class::T? #t9 = this.{self::Class::_#lateGenericField2} in #t9{self::Class::T%};
+ }
+ set lateGenericField2(self::Class::T% #t10) → void {
+ this.{self::Class::_#lateGenericField2#isSet} = true;
+ this.{self::Class::_#lateGenericField2} = #t10;
+ }
+ method instanceMethod(generic-covariant-impl self::Class::T% value) → dynamic {
self::expect(16, this.{self::Class::lateInstanceField});
this.{self::Class::lateInstanceField} = 17;
self::expect(17, this.{self::Class::lateInstanceField});
+ self::expect(this.{self::Class::field}, this.{self::Class::lateGenericField1});
+ this.{self::Class::lateGenericField1} = value;
+ self::expect(value, this.{self::Class::lateGenericField1});
+ this.{self::Class::lateGenericField2} = value;
+ self::expect(value, this.{self::Class::lateGenericField2});
}
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
static get lateExtensionField1 = get self::Extension|lateExtensionField1;
static set lateExtensionField1 = set self::Extension|lateExtensionField1;
@@ -45,17 +77,17 @@
static field core::int? _#Extension|lateExtensionField1 = null;
static field core::int? _#Extension|lateExtensionField2 = null;
static get lateTopLevelField1() → core::int
- return let final core::int? #t7 = self::_#lateTopLevelField1 in #t7.==(null) ?{core::int} self::_#lateTopLevelField1 = 123 : #t7{core::int};
-static set lateTopLevelField1(core::int #t8) → void
- self::_#lateTopLevelField1 = #t8;
+ return let final core::int? #t11 = self::_#lateTopLevelField1 in #t11.==(null) ?{core::int} self::_#lateTopLevelField1 = 123 : #t11{core::int};
+static set lateTopLevelField1(core::int #t12) → void
+ self::_#lateTopLevelField1 = #t12;
static get Extension|lateExtensionField1() → core::int
- return let final core::int? #t9 = self::_#Extension|lateExtensionField1 in #t9.==(null) ?{core::int} self::_#Extension|lateExtensionField1 = 87 : #t9{core::int};
-static set Extension|lateExtensionField1(core::int #t10) → void
- self::_#Extension|lateExtensionField1 = #t10;
+ return let final core::int? #t13 = self::_#Extension|lateExtensionField1 in #t13.==(null) ?{core::int} self::_#Extension|lateExtensionField1 = 87 : #t13{core::int};
+static set Extension|lateExtensionField1(core::int #t14) → void
+ self::_#Extension|lateExtensionField1 = #t14;
static get Extension|lateExtensionField2() → core::int
- return let final core::int? #t11 = self::_#Extension|lateExtensionField2 in #t11.==(null) ?{core::int} self::_#Extension|lateExtensionField2 = 42 : #t11{core::int};
-static set Extension|lateExtensionField2(core::int #t12) → void
- self::_#Extension|lateExtensionField2 = #t12;
+ return let final core::int? #t15 = self::_#Extension|lateExtensionField2 in #t15.==(null) ?{core::int} self::_#Extension|lateExtensionField2 = 42 : #t15{core::int};
+static set Extension|lateExtensionField2(core::int #t16) → void
+ self::_#Extension|lateExtensionField2 = #t16;
static method Extension|staticMethod() → dynamic {
self::expect(42, self::Extension|lateExtensionField2);
self::Extension|lateExtensionField2 = 43;
@@ -69,7 +101,7 @@
self::Class::lateStaticField1 = 88;
self::expect(88, self::Class::lateStaticField1);
self::Class::staticMethod();
- new self::Class::•().{self::Class::instanceMethod}();
+ new self::Class::•<core::int>(0).{self::Class::instanceMethod}(42);
self::expect(87, self::Extension|lateExtensionField1);
self::Extension|lateExtensionField1 = 88;
self::expect(88, self::Extension|lateExtensionField1);
diff --git a/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart.weak.expect b/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart.weak.expect
index b5758c3..d990f22 100644
--- a/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart.weak.expect
@@ -2,12 +2,17 @@
import self as self;
import "dart:core" as core;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? _#lateStaticField1 = null;
static field core::int? _#lateStaticField2 = null;
field core::int? _#lateInstanceField = null;
- synthetic constructor •() → self::Class
- : super core::Object::•()
+ final field self::Class::T% field;
+ generic-covariant-impl field self::Class::T? _#lateGenericField1 = null;
+ field core::bool _#lateGenericField1#isSet = false;
+ generic-covariant-impl field self::Class::T? _#lateGenericField2 = null;
+ field core::bool _#lateGenericField2#isSet = false;
+ constructor •(self::Class::T% field) → self::Class<self::Class::T%>
+ : self::Class::field = field, super core::Object::•()
;
static get lateStaticField1() → core::int
return let final core::int? #t1 = self::Class::_#lateStaticField1 in #t1.==(null) ?{core::int} self::Class::_#lateStaticField1 = 87 : #t1{core::int};
@@ -26,13 +31,40 @@
return let final core::int? #t5 = this.{self::Class::_#lateInstanceField} in #t5.==(null) ?{core::int} this.{self::Class::_#lateInstanceField} = 16 : #t5{core::int};
set lateInstanceField(core::int #t6) → void
this.{self::Class::_#lateInstanceField} = #t6;
- method instanceMethod() → dynamic {
+ get lateGenericField1() → self::Class::T% {
+ if(!this.{self::Class::_#lateGenericField1#isSet}) {
+ this.{self::Class::_#lateGenericField1#isSet} = true;
+ this.{self::Class::_#lateGenericField1} = this.{self::Class::field};
+ }
+ return let final self::Class::T? #t7 = this.{self::Class::_#lateGenericField1} in #t7{self::Class::T%};
+ }
+ set lateGenericField1(self::Class::T% #t8) → void {
+ this.{self::Class::_#lateGenericField1#isSet} = true;
+ this.{self::Class::_#lateGenericField1} = #t8;
+ }
+ get lateGenericField2() → self::Class::T% {
+ if(!this.{self::Class::_#lateGenericField2#isSet}) {
+ this.{self::Class::_#lateGenericField2#isSet} = true;
+ this.{self::Class::_#lateGenericField2} = this.{self::Class::field};
+ }
+ return let final self::Class::T? #t9 = this.{self::Class::_#lateGenericField2} in #t9{self::Class::T%};
+ }
+ set lateGenericField2(self::Class::T% #t10) → void {
+ this.{self::Class::_#lateGenericField2#isSet} = true;
+ this.{self::Class::_#lateGenericField2} = #t10;
+ }
+ method instanceMethod(generic-covariant-impl self::Class::T% value) → dynamic {
self::expect(16, this.{self::Class::lateInstanceField});
this.{self::Class::lateInstanceField} = 17;
self::expect(17, this.{self::Class::lateInstanceField});
+ self::expect(this.{self::Class::field}, this.{self::Class::lateGenericField1});
+ this.{self::Class::lateGenericField1} = value;
+ self::expect(value, this.{self::Class::lateGenericField1});
+ this.{self::Class::lateGenericField2} = value;
+ self::expect(value, this.{self::Class::lateGenericField2});
}
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
static get lateExtensionField1 = get self::Extension|lateExtensionField1;
static set lateExtensionField1 = set self::Extension|lateExtensionField1;
@@ -45,17 +77,17 @@
static field core::int? _#Extension|lateExtensionField1 = null;
static field core::int? _#Extension|lateExtensionField2 = null;
static get lateTopLevelField1() → core::int
- return let final core::int? #t7 = self::_#lateTopLevelField1 in #t7.==(null) ?{core::int} self::_#lateTopLevelField1 = 123 : #t7{core::int};
-static set lateTopLevelField1(core::int #t8) → void
- self::_#lateTopLevelField1 = #t8;
+ return let final core::int? #t11 = self::_#lateTopLevelField1 in #t11.==(null) ?{core::int} self::_#lateTopLevelField1 = 123 : #t11{core::int};
+static set lateTopLevelField1(core::int #t12) → void
+ self::_#lateTopLevelField1 = #t12;
static get Extension|lateExtensionField1() → core::int
- return let final core::int? #t9 = self::_#Extension|lateExtensionField1 in #t9.==(null) ?{core::int} self::_#Extension|lateExtensionField1 = 87 : #t9{core::int};
-static set Extension|lateExtensionField1(core::int #t10) → void
- self::_#Extension|lateExtensionField1 = #t10;
+ return let final core::int? #t13 = self::_#Extension|lateExtensionField1 in #t13.==(null) ?{core::int} self::_#Extension|lateExtensionField1 = 87 : #t13{core::int};
+static set Extension|lateExtensionField1(core::int #t14) → void
+ self::_#Extension|lateExtensionField1 = #t14;
static get Extension|lateExtensionField2() → core::int
- return let final core::int? #t11 = self::_#Extension|lateExtensionField2 in #t11.==(null) ?{core::int} self::_#Extension|lateExtensionField2 = 42 : #t11{core::int};
-static set Extension|lateExtensionField2(core::int #t12) → void
- self::_#Extension|lateExtensionField2 = #t12;
+ return let final core::int? #t15 = self::_#Extension|lateExtensionField2 in #t15.==(null) ?{core::int} self::_#Extension|lateExtensionField2 = 42 : #t15{core::int};
+static set Extension|lateExtensionField2(core::int #t16) → void
+ self::_#Extension|lateExtensionField2 = #t16;
static method Extension|staticMethod() → dynamic {
self::expect(42, self::Extension|lateExtensionField2);
self::Extension|lateExtensionField2 = 43;
@@ -69,7 +101,7 @@
self::Class::lateStaticField1 = 88;
self::expect(88, self::Class::lateStaticField1);
self::Class::staticMethod();
- new self::Class::•().{self::Class::instanceMethod}();
+ new self::Class::•<core::int>(0).{self::Class::instanceMethod}(42);
self::expect(87, self::Extension|lateExtensionField1);
self::Extension|lateExtensionField1 = 88;
self::expect(88, self::Extension|lateExtensionField1);
diff --git a/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart.weak.transformed.expect
index b5758c3..d990f22 100644
--- a/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart.weak.transformed.expect
@@ -2,12 +2,17 @@
import self as self;
import "dart:core" as core;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? _#lateStaticField1 = null;
static field core::int? _#lateStaticField2 = null;
field core::int? _#lateInstanceField = null;
- synthetic constructor •() → self::Class
- : super core::Object::•()
+ final field self::Class::T% field;
+ generic-covariant-impl field self::Class::T? _#lateGenericField1 = null;
+ field core::bool _#lateGenericField1#isSet = false;
+ generic-covariant-impl field self::Class::T? _#lateGenericField2 = null;
+ field core::bool _#lateGenericField2#isSet = false;
+ constructor •(self::Class::T% field) → self::Class<self::Class::T%>
+ : self::Class::field = field, super core::Object::•()
;
static get lateStaticField1() → core::int
return let final core::int? #t1 = self::Class::_#lateStaticField1 in #t1.==(null) ?{core::int} self::Class::_#lateStaticField1 = 87 : #t1{core::int};
@@ -26,13 +31,40 @@
return let final core::int? #t5 = this.{self::Class::_#lateInstanceField} in #t5.==(null) ?{core::int} this.{self::Class::_#lateInstanceField} = 16 : #t5{core::int};
set lateInstanceField(core::int #t6) → void
this.{self::Class::_#lateInstanceField} = #t6;
- method instanceMethod() → dynamic {
+ get lateGenericField1() → self::Class::T% {
+ if(!this.{self::Class::_#lateGenericField1#isSet}) {
+ this.{self::Class::_#lateGenericField1#isSet} = true;
+ this.{self::Class::_#lateGenericField1} = this.{self::Class::field};
+ }
+ return let final self::Class::T? #t7 = this.{self::Class::_#lateGenericField1} in #t7{self::Class::T%};
+ }
+ set lateGenericField1(self::Class::T% #t8) → void {
+ this.{self::Class::_#lateGenericField1#isSet} = true;
+ this.{self::Class::_#lateGenericField1} = #t8;
+ }
+ get lateGenericField2() → self::Class::T% {
+ if(!this.{self::Class::_#lateGenericField2#isSet}) {
+ this.{self::Class::_#lateGenericField2#isSet} = true;
+ this.{self::Class::_#lateGenericField2} = this.{self::Class::field};
+ }
+ return let final self::Class::T? #t9 = this.{self::Class::_#lateGenericField2} in #t9{self::Class::T%};
+ }
+ set lateGenericField2(self::Class::T% #t10) → void {
+ this.{self::Class::_#lateGenericField2#isSet} = true;
+ this.{self::Class::_#lateGenericField2} = #t10;
+ }
+ method instanceMethod(generic-covariant-impl self::Class::T% value) → dynamic {
self::expect(16, this.{self::Class::lateInstanceField});
this.{self::Class::lateInstanceField} = 17;
self::expect(17, this.{self::Class::lateInstanceField});
+ self::expect(this.{self::Class::field}, this.{self::Class::lateGenericField1});
+ this.{self::Class::lateGenericField1} = value;
+ self::expect(value, this.{self::Class::lateGenericField1});
+ this.{self::Class::lateGenericField2} = value;
+ self::expect(value, this.{self::Class::lateGenericField2});
}
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
static get lateExtensionField1 = get self::Extension|lateExtensionField1;
static set lateExtensionField1 = set self::Extension|lateExtensionField1;
@@ -45,17 +77,17 @@
static field core::int? _#Extension|lateExtensionField1 = null;
static field core::int? _#Extension|lateExtensionField2 = null;
static get lateTopLevelField1() → core::int
- return let final core::int? #t7 = self::_#lateTopLevelField1 in #t7.==(null) ?{core::int} self::_#lateTopLevelField1 = 123 : #t7{core::int};
-static set lateTopLevelField1(core::int #t8) → void
- self::_#lateTopLevelField1 = #t8;
+ return let final core::int? #t11 = self::_#lateTopLevelField1 in #t11.==(null) ?{core::int} self::_#lateTopLevelField1 = 123 : #t11{core::int};
+static set lateTopLevelField1(core::int #t12) → void
+ self::_#lateTopLevelField1 = #t12;
static get Extension|lateExtensionField1() → core::int
- return let final core::int? #t9 = self::_#Extension|lateExtensionField1 in #t9.==(null) ?{core::int} self::_#Extension|lateExtensionField1 = 87 : #t9{core::int};
-static set Extension|lateExtensionField1(core::int #t10) → void
- self::_#Extension|lateExtensionField1 = #t10;
+ return let final core::int? #t13 = self::_#Extension|lateExtensionField1 in #t13.==(null) ?{core::int} self::_#Extension|lateExtensionField1 = 87 : #t13{core::int};
+static set Extension|lateExtensionField1(core::int #t14) → void
+ self::_#Extension|lateExtensionField1 = #t14;
static get Extension|lateExtensionField2() → core::int
- return let final core::int? #t11 = self::_#Extension|lateExtensionField2 in #t11.==(null) ?{core::int} self::_#Extension|lateExtensionField2 = 42 : #t11{core::int};
-static set Extension|lateExtensionField2(core::int #t12) → void
- self::_#Extension|lateExtensionField2 = #t12;
+ return let final core::int? #t15 = self::_#Extension|lateExtensionField2 in #t15.==(null) ?{core::int} self::_#Extension|lateExtensionField2 = 42 : #t15{core::int};
+static set Extension|lateExtensionField2(core::int #t16) → void
+ self::_#Extension|lateExtensionField2 = #t16;
static method Extension|staticMethod() → dynamic {
self::expect(42, self::Extension|lateExtensionField2);
self::Extension|lateExtensionField2 = 43;
@@ -69,7 +101,7 @@
self::Class::lateStaticField1 = 88;
self::expect(88, self::Class::lateStaticField1);
self::Class::staticMethod();
- new self::Class::•().{self::Class::instanceMethod}();
+ new self::Class::•<core::int>(0).{self::Class::instanceMethod}(42);
self::expect(87, self::Extension|lateExtensionField1);
self::Extension|lateExtensionField1 = 88;
self::expect(88, self::Extension|lateExtensionField1);
diff --git a/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart b/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart
index f341089..fc77d31 100644
--- a/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart
+++ b/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart
@@ -4,7 +4,7 @@
late int lateTopLevelField;
-class Class {
+class Class<T> {
static late int lateStaticField1;
static late int lateStaticField2;
@@ -17,15 +17,22 @@
late int lateInstanceField;
- instanceMethod() {
+ late T lateGenericInstanceField;
+
+ instanceMethod(T value) {
throws(() => lateInstanceField,
'Read value from uninitialized Class.lateInstanceField');
lateInstanceField = 16;
expect(16, lateInstanceField);
+
+ throws(() => lateGenericInstanceField,
+ 'Read value from uninitialized Class.lateGenericInstanceField');
+ lateGenericInstanceField = value;
+ expect(value, lateGenericInstanceField);
}
}
-extension Extension on Class {
+extension Extension<T> on Class<T> {
static late int lateExtensionField1;
static late int lateExtensionField2;
@@ -49,14 +56,19 @@
expect(87, Class.lateStaticField1);
Class.staticMethod();
- new Class().instanceMethod();
+ new Class<int>().instanceMethod(0);
- var c = new Class();
+ var c = new Class<int>();
throws(() => c.lateInstanceField,
'Read value from uninitialized Class.lateInstanceField');
c.lateInstanceField = 16;
expect(16, c.lateInstanceField);
+ throws(() => c.lateGenericInstanceField,
+ 'Read value from uninitialized Class.lateGenericInstanceField');
+ c.lateGenericInstanceField = 0;
+ expect(0, c.lateGenericInstanceField);
+
throws(() => Extension.lateExtensionField1,
'Read value from uninitialized Extension.lateExtensionField1');
Extension.lateExtensionField1 = 87;
diff --git a/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.outline.expect b/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.outline.expect
index a48eba7..ffdf14a 100644
--- a/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.outline.expect
+++ b/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.outline.expect
@@ -2,11 +2,13 @@
import self as self;
import "dart:core" as core;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? _#lateStaticField1;
static field core::int? _#lateStaticField2;
field core::int? _#lateInstanceField;
- synthetic constructor •() → self::Class
+ generic-covariant-impl field self::Class::T? _#lateGenericInstanceField;
+ field core::bool _#lateGenericInstanceField#isSet;
+ synthetic constructor •() → self::Class<self::Class::T%>
;
static get lateStaticField1() → core::int;
static set lateStaticField1(core::int #t1) → void;
@@ -16,10 +18,12 @@
;
get lateInstanceField() → core::int;
set lateInstanceField(core::int #t3) → void;
- method instanceMethod() → dynamic
+ get lateGenericInstanceField() → self::Class::T%;
+ set lateGenericInstanceField(self::Class::T% #t4) → void;
+ method instanceMethod(generic-covariant-impl self::Class::T% value) → dynamic
;
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
static get lateExtensionField1 = get self::Extension|lateExtensionField1;
static set lateExtensionField1 = set self::Extension|lateExtensionField1;
@@ -32,11 +36,11 @@
static field core::int? _#Extension|lateExtensionField1;
static field core::int? _#Extension|lateExtensionField2;
static get lateTopLevelField() → core::int;
-static set lateTopLevelField(core::int #t4) → void;
+static set lateTopLevelField(core::int #t5) → void;
static get Extension|lateExtensionField1() → core::int;
-static set Extension|lateExtensionField1(core::int #t5) → void;
+static set Extension|lateExtensionField1(core::int #t6) → void;
static get Extension|lateExtensionField2() → core::int;
-static set Extension|lateExtensionField2(core::int #t6) → void;
+static set Extension|lateExtensionField2(core::int #t7) → void;
static method Extension|staticMethod() → dynamic
;
static method main() → dynamic
diff --git a/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.strong.expect
index 092ce77..61dfded 100644
--- a/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.strong.expect
+++ b/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.strong.expect
@@ -3,11 +3,13 @@
import "dart:core" as core;
import "dart:_internal" as _in;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? _#lateStaticField1 = null;
static field core::int? _#lateStaticField2 = null;
field core::int? _#lateInstanceField = null;
- synthetic constructor •() → self::Class
+ generic-covariant-impl field self::Class::T? _#lateGenericInstanceField = null;
+ field core::bool _#lateGenericInstanceField#isSet = false;
+ synthetic constructor •() → self::Class<self::Class::T%>
: super core::Object::•()
;
static get lateStaticField1() → core::int
@@ -27,13 +29,22 @@
return let final core::int? #t5 = this.{self::Class::_#lateInstanceField} in #t5.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'lateInstanceField' has not been initialized.") : #t5{core::int};
set lateInstanceField(core::int #t6) → void
this.{self::Class::_#lateInstanceField} = #t6;
- method instanceMethod() → dynamic {
+ get lateGenericInstanceField() → self::Class::T%
+ return this.{self::Class::_#lateGenericInstanceField#isSet} ?{self::Class::T%} let final self::Class::T? #t7 = this.{self::Class::_#lateGenericInstanceField} in #t7{self::Class::T%} : throw new _in::LateInitializationErrorImpl::•("Field 'lateGenericInstanceField' has not been initialized.");
+ set lateGenericInstanceField(self::Class::T% #t8) → void {
+ this.{self::Class::_#lateGenericInstanceField#isSet} = true;
+ this.{self::Class::_#lateGenericInstanceField} = #t8;
+ }
+ method instanceMethod(generic-covariant-impl self::Class::T% value) → dynamic {
self::throws(() → core::int => this.{self::Class::lateInstanceField}, "Read value from uninitialized Class.lateInstanceField");
this.{self::Class::lateInstanceField} = 16;
self::expect(16, this.{self::Class::lateInstanceField});
+ self::throws(() → self::Class::T% => this.{self::Class::lateGenericInstanceField}, "Read value from uninitialized Class.lateGenericInstanceField");
+ this.{self::Class::lateGenericInstanceField} = value;
+ self::expect(value, this.{self::Class::lateGenericInstanceField});
}
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
static get lateExtensionField1 = get self::Extension|lateExtensionField1;
static set lateExtensionField1 = set self::Extension|lateExtensionField1;
@@ -46,17 +57,17 @@
static field core::int? _#Extension|lateExtensionField1 = null;
static field core::int? _#Extension|lateExtensionField2 = null;
static get lateTopLevelField() → core::int
- return let final core::int? #t7 = self::_#lateTopLevelField in #t7.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField' has not been initialized.") : #t7{core::int};
-static set lateTopLevelField(core::int #t8) → void
- self::_#lateTopLevelField = #t8;
+ return let final core::int? #t9 = self::_#lateTopLevelField in #t9.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField' has not been initialized.") : #t9{core::int};
+static set lateTopLevelField(core::int #t10) → void
+ self::_#lateTopLevelField = #t10;
static get Extension|lateExtensionField1() → core::int
- return let final core::int? #t9 = self::_#Extension|lateExtensionField1 in #t9.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has not been initialized.") : #t9{core::int};
-static set Extension|lateExtensionField1(core::int #t10) → void
- self::_#Extension|lateExtensionField1 = #t10;
+ return let final core::int? #t11 = self::_#Extension|lateExtensionField1 in #t11.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has not been initialized.") : #t11{core::int};
+static set Extension|lateExtensionField1(core::int #t12) → void
+ self::_#Extension|lateExtensionField1 = #t12;
static get Extension|lateExtensionField2() → core::int
- return let final core::int? #t11 = self::_#Extension|lateExtensionField2 in #t11.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has not been initialized.") : #t11{core::int};
-static set Extension|lateExtensionField2(core::int #t12) → void
- self::_#Extension|lateExtensionField2 = #t12;
+ return let final core::int? #t13 = self::_#Extension|lateExtensionField2 in #t13.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has not been initialized.") : #t13{core::int};
+static set Extension|lateExtensionField2(core::int #t14) → void
+ self::_#Extension|lateExtensionField2 = #t14;
static method Extension|staticMethod() → dynamic {
self::throws(() → core::int => self::Extension|lateExtensionField2, "Read value from uninitialized Class.lateExtensionField2");
self::Extension|lateExtensionField2 = 42;
@@ -70,11 +81,14 @@
self::Class::lateStaticField1 = 87;
self::expect(87, self::Class::lateStaticField1);
self::Class::staticMethod();
- new self::Class::•().{self::Class::instanceMethod}();
- self::Class c = new self::Class::•();
+ new self::Class::•<core::int>().{self::Class::instanceMethod}(0);
+ self::Class<core::int> c = new self::Class::•<core::int>();
self::throws(() → core::int => c.{self::Class::lateInstanceField}, "Read value from uninitialized Class.lateInstanceField");
c.{self::Class::lateInstanceField} = 16;
self::expect(16, c.{self::Class::lateInstanceField});
+ self::throws(() → core::int => c.{self::Class::lateGenericInstanceField}, "Read value from uninitialized Class.lateGenericInstanceField");
+ c.{self::Class::lateGenericInstanceField} = 0;
+ self::expect(0, c.{self::Class::lateGenericInstanceField});
self::throws(() → core::int => self::Extension|lateExtensionField1, "Read value from uninitialized Extension.lateExtensionField1");
self::Extension|lateExtensionField1 = 87;
self::expect(87, self::Extension|lateExtensionField1);
diff --git a/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.strong.transformed.expect
index 092ce77..61dfded 100644
--- a/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.strong.transformed.expect
@@ -3,11 +3,13 @@
import "dart:core" as core;
import "dart:_internal" as _in;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? _#lateStaticField1 = null;
static field core::int? _#lateStaticField2 = null;
field core::int? _#lateInstanceField = null;
- synthetic constructor •() → self::Class
+ generic-covariant-impl field self::Class::T? _#lateGenericInstanceField = null;
+ field core::bool _#lateGenericInstanceField#isSet = false;
+ synthetic constructor •() → self::Class<self::Class::T%>
: super core::Object::•()
;
static get lateStaticField1() → core::int
@@ -27,13 +29,22 @@
return let final core::int? #t5 = this.{self::Class::_#lateInstanceField} in #t5.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'lateInstanceField' has not been initialized.") : #t5{core::int};
set lateInstanceField(core::int #t6) → void
this.{self::Class::_#lateInstanceField} = #t6;
- method instanceMethod() → dynamic {
+ get lateGenericInstanceField() → self::Class::T%
+ return this.{self::Class::_#lateGenericInstanceField#isSet} ?{self::Class::T%} let final self::Class::T? #t7 = this.{self::Class::_#lateGenericInstanceField} in #t7{self::Class::T%} : throw new _in::LateInitializationErrorImpl::•("Field 'lateGenericInstanceField' has not been initialized.");
+ set lateGenericInstanceField(self::Class::T% #t8) → void {
+ this.{self::Class::_#lateGenericInstanceField#isSet} = true;
+ this.{self::Class::_#lateGenericInstanceField} = #t8;
+ }
+ method instanceMethod(generic-covariant-impl self::Class::T% value) → dynamic {
self::throws(() → core::int => this.{self::Class::lateInstanceField}, "Read value from uninitialized Class.lateInstanceField");
this.{self::Class::lateInstanceField} = 16;
self::expect(16, this.{self::Class::lateInstanceField});
+ self::throws(() → self::Class::T% => this.{self::Class::lateGenericInstanceField}, "Read value from uninitialized Class.lateGenericInstanceField");
+ this.{self::Class::lateGenericInstanceField} = value;
+ self::expect(value, this.{self::Class::lateGenericInstanceField});
}
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
static get lateExtensionField1 = get self::Extension|lateExtensionField1;
static set lateExtensionField1 = set self::Extension|lateExtensionField1;
@@ -46,17 +57,17 @@
static field core::int? _#Extension|lateExtensionField1 = null;
static field core::int? _#Extension|lateExtensionField2 = null;
static get lateTopLevelField() → core::int
- return let final core::int? #t7 = self::_#lateTopLevelField in #t7.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField' has not been initialized.") : #t7{core::int};
-static set lateTopLevelField(core::int #t8) → void
- self::_#lateTopLevelField = #t8;
+ return let final core::int? #t9 = self::_#lateTopLevelField in #t9.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField' has not been initialized.") : #t9{core::int};
+static set lateTopLevelField(core::int #t10) → void
+ self::_#lateTopLevelField = #t10;
static get Extension|lateExtensionField1() → core::int
- return let final core::int? #t9 = self::_#Extension|lateExtensionField1 in #t9.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has not been initialized.") : #t9{core::int};
-static set Extension|lateExtensionField1(core::int #t10) → void
- self::_#Extension|lateExtensionField1 = #t10;
+ return let final core::int? #t11 = self::_#Extension|lateExtensionField1 in #t11.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has not been initialized.") : #t11{core::int};
+static set Extension|lateExtensionField1(core::int #t12) → void
+ self::_#Extension|lateExtensionField1 = #t12;
static get Extension|lateExtensionField2() → core::int
- return let final core::int? #t11 = self::_#Extension|lateExtensionField2 in #t11.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has not been initialized.") : #t11{core::int};
-static set Extension|lateExtensionField2(core::int #t12) → void
- self::_#Extension|lateExtensionField2 = #t12;
+ return let final core::int? #t13 = self::_#Extension|lateExtensionField2 in #t13.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has not been initialized.") : #t13{core::int};
+static set Extension|lateExtensionField2(core::int #t14) → void
+ self::_#Extension|lateExtensionField2 = #t14;
static method Extension|staticMethod() → dynamic {
self::throws(() → core::int => self::Extension|lateExtensionField2, "Read value from uninitialized Class.lateExtensionField2");
self::Extension|lateExtensionField2 = 42;
@@ -70,11 +81,14 @@
self::Class::lateStaticField1 = 87;
self::expect(87, self::Class::lateStaticField1);
self::Class::staticMethod();
- new self::Class::•().{self::Class::instanceMethod}();
- self::Class c = new self::Class::•();
+ new self::Class::•<core::int>().{self::Class::instanceMethod}(0);
+ self::Class<core::int> c = new self::Class::•<core::int>();
self::throws(() → core::int => c.{self::Class::lateInstanceField}, "Read value from uninitialized Class.lateInstanceField");
c.{self::Class::lateInstanceField} = 16;
self::expect(16, c.{self::Class::lateInstanceField});
+ self::throws(() → core::int => c.{self::Class::lateGenericInstanceField}, "Read value from uninitialized Class.lateGenericInstanceField");
+ c.{self::Class::lateGenericInstanceField} = 0;
+ self::expect(0, c.{self::Class::lateGenericInstanceField});
self::throws(() → core::int => self::Extension|lateExtensionField1, "Read value from uninitialized Extension.lateExtensionField1");
self::Extension|lateExtensionField1 = 87;
self::expect(87, self::Extension|lateExtensionField1);
diff --git a/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.weak.expect b/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.weak.expect
index 092ce77..61dfded 100644
--- a/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.weak.expect
@@ -3,11 +3,13 @@
import "dart:core" as core;
import "dart:_internal" as _in;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? _#lateStaticField1 = null;
static field core::int? _#lateStaticField2 = null;
field core::int? _#lateInstanceField = null;
- synthetic constructor •() → self::Class
+ generic-covariant-impl field self::Class::T? _#lateGenericInstanceField = null;
+ field core::bool _#lateGenericInstanceField#isSet = false;
+ synthetic constructor •() → self::Class<self::Class::T%>
: super core::Object::•()
;
static get lateStaticField1() → core::int
@@ -27,13 +29,22 @@
return let final core::int? #t5 = this.{self::Class::_#lateInstanceField} in #t5.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'lateInstanceField' has not been initialized.") : #t5{core::int};
set lateInstanceField(core::int #t6) → void
this.{self::Class::_#lateInstanceField} = #t6;
- method instanceMethod() → dynamic {
+ get lateGenericInstanceField() → self::Class::T%
+ return this.{self::Class::_#lateGenericInstanceField#isSet} ?{self::Class::T%} let final self::Class::T? #t7 = this.{self::Class::_#lateGenericInstanceField} in #t7{self::Class::T%} : throw new _in::LateInitializationErrorImpl::•("Field 'lateGenericInstanceField' has not been initialized.");
+ set lateGenericInstanceField(self::Class::T% #t8) → void {
+ this.{self::Class::_#lateGenericInstanceField#isSet} = true;
+ this.{self::Class::_#lateGenericInstanceField} = #t8;
+ }
+ method instanceMethod(generic-covariant-impl self::Class::T% value) → dynamic {
self::throws(() → core::int => this.{self::Class::lateInstanceField}, "Read value from uninitialized Class.lateInstanceField");
this.{self::Class::lateInstanceField} = 16;
self::expect(16, this.{self::Class::lateInstanceField});
+ self::throws(() → self::Class::T% => this.{self::Class::lateGenericInstanceField}, "Read value from uninitialized Class.lateGenericInstanceField");
+ this.{self::Class::lateGenericInstanceField} = value;
+ self::expect(value, this.{self::Class::lateGenericInstanceField});
}
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
static get lateExtensionField1 = get self::Extension|lateExtensionField1;
static set lateExtensionField1 = set self::Extension|lateExtensionField1;
@@ -46,17 +57,17 @@
static field core::int? _#Extension|lateExtensionField1 = null;
static field core::int? _#Extension|lateExtensionField2 = null;
static get lateTopLevelField() → core::int
- return let final core::int? #t7 = self::_#lateTopLevelField in #t7.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField' has not been initialized.") : #t7{core::int};
-static set lateTopLevelField(core::int #t8) → void
- self::_#lateTopLevelField = #t8;
+ return let final core::int? #t9 = self::_#lateTopLevelField in #t9.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField' has not been initialized.") : #t9{core::int};
+static set lateTopLevelField(core::int #t10) → void
+ self::_#lateTopLevelField = #t10;
static get Extension|lateExtensionField1() → core::int
- return let final core::int? #t9 = self::_#Extension|lateExtensionField1 in #t9.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has not been initialized.") : #t9{core::int};
-static set Extension|lateExtensionField1(core::int #t10) → void
- self::_#Extension|lateExtensionField1 = #t10;
+ return let final core::int? #t11 = self::_#Extension|lateExtensionField1 in #t11.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has not been initialized.") : #t11{core::int};
+static set Extension|lateExtensionField1(core::int #t12) → void
+ self::_#Extension|lateExtensionField1 = #t12;
static get Extension|lateExtensionField2() → core::int
- return let final core::int? #t11 = self::_#Extension|lateExtensionField2 in #t11.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has not been initialized.") : #t11{core::int};
-static set Extension|lateExtensionField2(core::int #t12) → void
- self::_#Extension|lateExtensionField2 = #t12;
+ return let final core::int? #t13 = self::_#Extension|lateExtensionField2 in #t13.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has not been initialized.") : #t13{core::int};
+static set Extension|lateExtensionField2(core::int #t14) → void
+ self::_#Extension|lateExtensionField2 = #t14;
static method Extension|staticMethod() → dynamic {
self::throws(() → core::int => self::Extension|lateExtensionField2, "Read value from uninitialized Class.lateExtensionField2");
self::Extension|lateExtensionField2 = 42;
@@ -70,11 +81,14 @@
self::Class::lateStaticField1 = 87;
self::expect(87, self::Class::lateStaticField1);
self::Class::staticMethod();
- new self::Class::•().{self::Class::instanceMethod}();
- self::Class c = new self::Class::•();
+ new self::Class::•<core::int>().{self::Class::instanceMethod}(0);
+ self::Class<core::int> c = new self::Class::•<core::int>();
self::throws(() → core::int => c.{self::Class::lateInstanceField}, "Read value from uninitialized Class.lateInstanceField");
c.{self::Class::lateInstanceField} = 16;
self::expect(16, c.{self::Class::lateInstanceField});
+ self::throws(() → core::int => c.{self::Class::lateGenericInstanceField}, "Read value from uninitialized Class.lateGenericInstanceField");
+ c.{self::Class::lateGenericInstanceField} = 0;
+ self::expect(0, c.{self::Class::lateGenericInstanceField});
self::throws(() → core::int => self::Extension|lateExtensionField1, "Read value from uninitialized Extension.lateExtensionField1");
self::Extension|lateExtensionField1 = 87;
self::expect(87, self::Extension|lateExtensionField1);
diff --git a/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.weak.transformed.expect
index 092ce77..61dfded 100644
--- a/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.weak.transformed.expect
@@ -3,11 +3,13 @@
import "dart:core" as core;
import "dart:_internal" as _in;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? _#lateStaticField1 = null;
static field core::int? _#lateStaticField2 = null;
field core::int? _#lateInstanceField = null;
- synthetic constructor •() → self::Class
+ generic-covariant-impl field self::Class::T? _#lateGenericInstanceField = null;
+ field core::bool _#lateGenericInstanceField#isSet = false;
+ synthetic constructor •() → self::Class<self::Class::T%>
: super core::Object::•()
;
static get lateStaticField1() → core::int
@@ -27,13 +29,22 @@
return let final core::int? #t5 = this.{self::Class::_#lateInstanceField} in #t5.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'lateInstanceField' has not been initialized.") : #t5{core::int};
set lateInstanceField(core::int #t6) → void
this.{self::Class::_#lateInstanceField} = #t6;
- method instanceMethod() → dynamic {
+ get lateGenericInstanceField() → self::Class::T%
+ return this.{self::Class::_#lateGenericInstanceField#isSet} ?{self::Class::T%} let final self::Class::T? #t7 = this.{self::Class::_#lateGenericInstanceField} in #t7{self::Class::T%} : throw new _in::LateInitializationErrorImpl::•("Field 'lateGenericInstanceField' has not been initialized.");
+ set lateGenericInstanceField(self::Class::T% #t8) → void {
+ this.{self::Class::_#lateGenericInstanceField#isSet} = true;
+ this.{self::Class::_#lateGenericInstanceField} = #t8;
+ }
+ method instanceMethod(generic-covariant-impl self::Class::T% value) → dynamic {
self::throws(() → core::int => this.{self::Class::lateInstanceField}, "Read value from uninitialized Class.lateInstanceField");
this.{self::Class::lateInstanceField} = 16;
self::expect(16, this.{self::Class::lateInstanceField});
+ self::throws(() → self::Class::T% => this.{self::Class::lateGenericInstanceField}, "Read value from uninitialized Class.lateGenericInstanceField");
+ this.{self::Class::lateGenericInstanceField} = value;
+ self::expect(value, this.{self::Class::lateGenericInstanceField});
}
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
static get lateExtensionField1 = get self::Extension|lateExtensionField1;
static set lateExtensionField1 = set self::Extension|lateExtensionField1;
@@ -46,17 +57,17 @@
static field core::int? _#Extension|lateExtensionField1 = null;
static field core::int? _#Extension|lateExtensionField2 = null;
static get lateTopLevelField() → core::int
- return let final core::int? #t7 = self::_#lateTopLevelField in #t7.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField' has not been initialized.") : #t7{core::int};
-static set lateTopLevelField(core::int #t8) → void
- self::_#lateTopLevelField = #t8;
+ return let final core::int? #t9 = self::_#lateTopLevelField in #t9.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField' has not been initialized.") : #t9{core::int};
+static set lateTopLevelField(core::int #t10) → void
+ self::_#lateTopLevelField = #t10;
static get Extension|lateExtensionField1() → core::int
- return let final core::int? #t9 = self::_#Extension|lateExtensionField1 in #t9.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has not been initialized.") : #t9{core::int};
-static set Extension|lateExtensionField1(core::int #t10) → void
- self::_#Extension|lateExtensionField1 = #t10;
+ return let final core::int? #t11 = self::_#Extension|lateExtensionField1 in #t11.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has not been initialized.") : #t11{core::int};
+static set Extension|lateExtensionField1(core::int #t12) → void
+ self::_#Extension|lateExtensionField1 = #t12;
static get Extension|lateExtensionField2() → core::int
- return let final core::int? #t11 = self::_#Extension|lateExtensionField2 in #t11.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has not been initialized.") : #t11{core::int};
-static set Extension|lateExtensionField2(core::int #t12) → void
- self::_#Extension|lateExtensionField2 = #t12;
+ return let final core::int? #t13 = self::_#Extension|lateExtensionField2 in #t13.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has not been initialized.") : #t13{core::int};
+static set Extension|lateExtensionField2(core::int #t14) → void
+ self::_#Extension|lateExtensionField2 = #t14;
static method Extension|staticMethod() → dynamic {
self::throws(() → core::int => self::Extension|lateExtensionField2, "Read value from uninitialized Class.lateExtensionField2");
self::Extension|lateExtensionField2 = 42;
@@ -70,11 +81,14 @@
self::Class::lateStaticField1 = 87;
self::expect(87, self::Class::lateStaticField1);
self::Class::staticMethod();
- new self::Class::•().{self::Class::instanceMethod}();
- self::Class c = new self::Class::•();
+ new self::Class::•<core::int>().{self::Class::instanceMethod}(0);
+ self::Class<core::int> c = new self::Class::•<core::int>();
self::throws(() → core::int => c.{self::Class::lateInstanceField}, "Read value from uninitialized Class.lateInstanceField");
c.{self::Class::lateInstanceField} = 16;
self::expect(16, c.{self::Class::lateInstanceField});
+ self::throws(() → core::int => c.{self::Class::lateGenericInstanceField}, "Read value from uninitialized Class.lateGenericInstanceField");
+ c.{self::Class::lateGenericInstanceField} = 0;
+ self::expect(0, c.{self::Class::lateGenericInstanceField});
self::throws(() → core::int => self::Extension|lateExtensionField1, "Read value from uninitialized Extension.lateExtensionField1");
self::Extension|lateExtensionField1 = 87;
self::expect(87, self::Extension|lateExtensionField1);
diff --git a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart
index dcff292..6a2269e 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart
+++ b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart
@@ -9,7 +9,7 @@
late final int lateTopLevelField1 = initLateTopLevelField1(123);
-class Class {
+class Class<T> {
static int? lateStaticField1Init;
static int initLateStaticField1(int value) {
return lateStaticField1Init = value;
@@ -37,14 +37,28 @@
late final int lateInstanceField = initLateInstanceField(16);
+ T? lateGenericFieldInit;
+ T initLateGenericField(T value) {
+ return lateGenericFieldInit = value;
+ }
+
+ final T field;
+ late final T lateGenericField = initLateGenericField(field);
+
+ Class(this.field);
+
instanceMethod() {
expect(null, lateInstanceFieldInit);
expect(16, lateInstanceField);
expect(16, lateInstanceFieldInit);
+
+ expect(null, lateGenericFieldInit);
+ expect(field, lateGenericField);
+ expect(field, lateGenericFieldInit);
}
}
-extension Extension on Class {
+extension Extension<T> on Class<T> {
static int? lateExtensionField1Init;
static int initLateExtensionField1(int value) {
return lateExtensionField1Init = value;
@@ -76,7 +90,7 @@
expect(87, Class.lateStaticField1Init);
Class.staticMethod();
- new Class().instanceMethod();
+ new Class<int>(0).instanceMethod();
expect(null, Extension.lateExtensionField1Init);
expect(87, Extension.lateExtensionField1);
diff --git a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.outline.expect b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.outline.expect
index ffc68c7..cf3a5eb 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.outline.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.outline.expect
@@ -2,14 +2,18 @@
import self as self;
import "dart:core" as core;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? lateStaticField1Init;
static field core::int? _#lateStaticField1;
static field core::int? lateStaticField2Init;
static field core::int? _#lateStaticField2;
field core::int? lateInstanceFieldInit;
field core::int? _#lateInstanceField;
- synthetic constructor •() → self::Class
+ generic-covariant-impl field self::Class::T? lateGenericFieldInit;
+ final field self::Class::T% field;
+ field self::Class::T? _#lateGenericField;
+ field core::bool _#lateGenericField#isSet;
+ constructor •(self::Class::T% field) → self::Class<self::Class::T%>
;
static method initLateStaticField1(core::int value) → core::int
;
@@ -22,10 +26,13 @@
method initLateInstanceField(core::int value) → core::int
;
get lateInstanceField() → core::int;
+ method initLateGenericField(generic-covariant-impl self::Class::T% value) → self::Class::T%
+ ;
+ get lateGenericField() → self::Class::T%;
method instanceMethod() → dynamic
;
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static field lateExtensionField1Init = self::Extension|lateExtensionField1Init;
static method initLateExtensionField1 = self::Extension|initLateExtensionField1;
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
diff --git a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.strong.expect
index 67e2378..6f2bab2 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.strong.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.strong.expect
@@ -2,15 +2,19 @@
import self as self;
import "dart:core" as core;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? lateStaticField1Init = null;
static field core::int? _#lateStaticField1 = null;
static field core::int? lateStaticField2Init = null;
static field core::int? _#lateStaticField2 = null;
field core::int? lateInstanceFieldInit = null;
field core::int? _#lateInstanceField = null;
- synthetic constructor •() → self::Class
- : super core::Object::•()
+ generic-covariant-impl field self::Class::T? lateGenericFieldInit = null;
+ final field self::Class::T% field;
+ field self::Class::T? _#lateGenericField = null;
+ field core::bool _#lateGenericField#isSet = false;
+ constructor •(self::Class::T% field) → self::Class<self::Class::T%>
+ : self::Class::field = field, super core::Object::•()
;
static method initLateStaticField1(core::int value) → core::int {
return self::Class::lateStaticField1Init = value;
@@ -32,13 +36,26 @@
}
get lateInstanceField() → core::int
return let final core::int? #t3 = this.{self::Class::_#lateInstanceField} in #t3.==(null) ?{core::int} this.{self::Class::_#lateInstanceField} = this.{self::Class::initLateInstanceField}(16) : #t3{core::int};
+ method initLateGenericField(generic-covariant-impl self::Class::T% value) → self::Class::T% {
+ return this.{self::Class::lateGenericFieldInit} = value;
+ }
+ get lateGenericField() → self::Class::T% {
+ if(!this.{self::Class::_#lateGenericField#isSet}) {
+ this.{self::Class::_#lateGenericField#isSet} = true;
+ this.{self::Class::_#lateGenericField} = this.{self::Class::initLateGenericField}(this.{self::Class::field});
+ }
+ return let final self::Class::T? #t4 = this.{self::Class::_#lateGenericField} in #t4{self::Class::T%};
+ }
method instanceMethod() → dynamic {
self::expect(null, this.{self::Class::lateInstanceFieldInit});
self::expect(16, this.{self::Class::lateInstanceField});
self::expect(16, this.{self::Class::lateInstanceFieldInit});
+ self::expect(null, this.{self::Class::lateGenericFieldInit});
+ self::expect(this.{self::Class::field}, this.{self::Class::lateGenericField});
+ self::expect(this.{self::Class::field}, this.{self::Class::lateGenericFieldInit});
}
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static field lateExtensionField1Init = self::Extension|lateExtensionField1Init;
static method initLateExtensionField1 = self::Extension|initLateExtensionField1;
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
@@ -59,17 +76,17 @@
return self::lateTopLevelField1Init = value;
}
static get lateTopLevelField1() → core::int
- return let final core::int? #t4 = self::_#lateTopLevelField1 in #t4.==(null) ?{core::int} self::_#lateTopLevelField1 = self::initLateTopLevelField1(123) : #t4{core::int};
+ return let final core::int? #t5 = self::_#lateTopLevelField1 in #t5.==(null) ?{core::int} self::_#lateTopLevelField1 = self::initLateTopLevelField1(123) : #t5{core::int};
static method Extension|initLateExtensionField1(core::int value) → core::int {
return self::Extension|lateExtensionField1Init = value;
}
static get Extension|lateExtensionField1() → core::int
- return let final core::int? #t5 = self::_#Extension|lateExtensionField1 in #t5.==(null) ?{core::int} self::_#Extension|lateExtensionField1 = self::Extension|initLateExtensionField1(87) : #t5{core::int};
+ return let final core::int? #t6 = self::_#Extension|lateExtensionField1 in #t6.==(null) ?{core::int} self::_#Extension|lateExtensionField1 = self::Extension|initLateExtensionField1(87) : #t6{core::int};
static method Extension|initLateExtensionField2(core::int value) → core::int {
return self::Extension|lateExtensionField2Init = value;
}
static get Extension|lateExtensionField2() → core::int
- return let final core::int? #t6 = self::_#Extension|lateExtensionField2 in #t6.==(null) ?{core::int} self::_#Extension|lateExtensionField2 = self::Extension|initLateExtensionField2(42) : #t6{core::int};
+ return let final core::int? #t7 = self::_#Extension|lateExtensionField2 in #t7.==(null) ?{core::int} self::_#Extension|lateExtensionField2 = self::Extension|initLateExtensionField2(42) : #t7{core::int};
static method Extension|staticMethod() → dynamic {
self::expect(null, self::Extension|lateExtensionField2Init);
self::expect(42, self::Extension|lateExtensionField2);
@@ -83,7 +100,7 @@
self::expect(87, self::Class::lateStaticField1);
self::expect(87, self::Class::lateStaticField1Init);
self::Class::staticMethod();
- new self::Class::•().{self::Class::instanceMethod}();
+ new self::Class::•<core::int>(0).{self::Class::instanceMethod}();
self::expect(null, self::Extension|lateExtensionField1Init);
self::expect(87, self::Extension|lateExtensionField1);
self::expect(87, self::Extension|lateExtensionField1Init);
diff --git a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.strong.transformed.expect
index 67e2378..6f2bab2 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.strong.transformed.expect
@@ -2,15 +2,19 @@
import self as self;
import "dart:core" as core;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? lateStaticField1Init = null;
static field core::int? _#lateStaticField1 = null;
static field core::int? lateStaticField2Init = null;
static field core::int? _#lateStaticField2 = null;
field core::int? lateInstanceFieldInit = null;
field core::int? _#lateInstanceField = null;
- synthetic constructor •() → self::Class
- : super core::Object::•()
+ generic-covariant-impl field self::Class::T? lateGenericFieldInit = null;
+ final field self::Class::T% field;
+ field self::Class::T? _#lateGenericField = null;
+ field core::bool _#lateGenericField#isSet = false;
+ constructor •(self::Class::T% field) → self::Class<self::Class::T%>
+ : self::Class::field = field, super core::Object::•()
;
static method initLateStaticField1(core::int value) → core::int {
return self::Class::lateStaticField1Init = value;
@@ -32,13 +36,26 @@
}
get lateInstanceField() → core::int
return let final core::int? #t3 = this.{self::Class::_#lateInstanceField} in #t3.==(null) ?{core::int} this.{self::Class::_#lateInstanceField} = this.{self::Class::initLateInstanceField}(16) : #t3{core::int};
+ method initLateGenericField(generic-covariant-impl self::Class::T% value) → self::Class::T% {
+ return this.{self::Class::lateGenericFieldInit} = value;
+ }
+ get lateGenericField() → self::Class::T% {
+ if(!this.{self::Class::_#lateGenericField#isSet}) {
+ this.{self::Class::_#lateGenericField#isSet} = true;
+ this.{self::Class::_#lateGenericField} = this.{self::Class::initLateGenericField}(this.{self::Class::field});
+ }
+ return let final self::Class::T? #t4 = this.{self::Class::_#lateGenericField} in #t4{self::Class::T%};
+ }
method instanceMethod() → dynamic {
self::expect(null, this.{self::Class::lateInstanceFieldInit});
self::expect(16, this.{self::Class::lateInstanceField});
self::expect(16, this.{self::Class::lateInstanceFieldInit});
+ self::expect(null, this.{self::Class::lateGenericFieldInit});
+ self::expect(this.{self::Class::field}, this.{self::Class::lateGenericField});
+ self::expect(this.{self::Class::field}, this.{self::Class::lateGenericFieldInit});
}
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static field lateExtensionField1Init = self::Extension|lateExtensionField1Init;
static method initLateExtensionField1 = self::Extension|initLateExtensionField1;
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
@@ -59,17 +76,17 @@
return self::lateTopLevelField1Init = value;
}
static get lateTopLevelField1() → core::int
- return let final core::int? #t4 = self::_#lateTopLevelField1 in #t4.==(null) ?{core::int} self::_#lateTopLevelField1 = self::initLateTopLevelField1(123) : #t4{core::int};
+ return let final core::int? #t5 = self::_#lateTopLevelField1 in #t5.==(null) ?{core::int} self::_#lateTopLevelField1 = self::initLateTopLevelField1(123) : #t5{core::int};
static method Extension|initLateExtensionField1(core::int value) → core::int {
return self::Extension|lateExtensionField1Init = value;
}
static get Extension|lateExtensionField1() → core::int
- return let final core::int? #t5 = self::_#Extension|lateExtensionField1 in #t5.==(null) ?{core::int} self::_#Extension|lateExtensionField1 = self::Extension|initLateExtensionField1(87) : #t5{core::int};
+ return let final core::int? #t6 = self::_#Extension|lateExtensionField1 in #t6.==(null) ?{core::int} self::_#Extension|lateExtensionField1 = self::Extension|initLateExtensionField1(87) : #t6{core::int};
static method Extension|initLateExtensionField2(core::int value) → core::int {
return self::Extension|lateExtensionField2Init = value;
}
static get Extension|lateExtensionField2() → core::int
- return let final core::int? #t6 = self::_#Extension|lateExtensionField2 in #t6.==(null) ?{core::int} self::_#Extension|lateExtensionField2 = self::Extension|initLateExtensionField2(42) : #t6{core::int};
+ return let final core::int? #t7 = self::_#Extension|lateExtensionField2 in #t7.==(null) ?{core::int} self::_#Extension|lateExtensionField2 = self::Extension|initLateExtensionField2(42) : #t7{core::int};
static method Extension|staticMethod() → dynamic {
self::expect(null, self::Extension|lateExtensionField2Init);
self::expect(42, self::Extension|lateExtensionField2);
@@ -83,7 +100,7 @@
self::expect(87, self::Class::lateStaticField1);
self::expect(87, self::Class::lateStaticField1Init);
self::Class::staticMethod();
- new self::Class::•().{self::Class::instanceMethod}();
+ new self::Class::•<core::int>(0).{self::Class::instanceMethod}();
self::expect(null, self::Extension|lateExtensionField1Init);
self::expect(87, self::Extension|lateExtensionField1);
self::expect(87, self::Extension|lateExtensionField1Init);
diff --git a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.expect b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.expect
index 67e2378..6f2bab2 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.expect
@@ -2,15 +2,19 @@
import self as self;
import "dart:core" as core;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? lateStaticField1Init = null;
static field core::int? _#lateStaticField1 = null;
static field core::int? lateStaticField2Init = null;
static field core::int? _#lateStaticField2 = null;
field core::int? lateInstanceFieldInit = null;
field core::int? _#lateInstanceField = null;
- synthetic constructor •() → self::Class
- : super core::Object::•()
+ generic-covariant-impl field self::Class::T? lateGenericFieldInit = null;
+ final field self::Class::T% field;
+ field self::Class::T? _#lateGenericField = null;
+ field core::bool _#lateGenericField#isSet = false;
+ constructor •(self::Class::T% field) → self::Class<self::Class::T%>
+ : self::Class::field = field, super core::Object::•()
;
static method initLateStaticField1(core::int value) → core::int {
return self::Class::lateStaticField1Init = value;
@@ -32,13 +36,26 @@
}
get lateInstanceField() → core::int
return let final core::int? #t3 = this.{self::Class::_#lateInstanceField} in #t3.==(null) ?{core::int} this.{self::Class::_#lateInstanceField} = this.{self::Class::initLateInstanceField}(16) : #t3{core::int};
+ method initLateGenericField(generic-covariant-impl self::Class::T% value) → self::Class::T% {
+ return this.{self::Class::lateGenericFieldInit} = value;
+ }
+ get lateGenericField() → self::Class::T% {
+ if(!this.{self::Class::_#lateGenericField#isSet}) {
+ this.{self::Class::_#lateGenericField#isSet} = true;
+ this.{self::Class::_#lateGenericField} = this.{self::Class::initLateGenericField}(this.{self::Class::field});
+ }
+ return let final self::Class::T? #t4 = this.{self::Class::_#lateGenericField} in #t4{self::Class::T%};
+ }
method instanceMethod() → dynamic {
self::expect(null, this.{self::Class::lateInstanceFieldInit});
self::expect(16, this.{self::Class::lateInstanceField});
self::expect(16, this.{self::Class::lateInstanceFieldInit});
+ self::expect(null, this.{self::Class::lateGenericFieldInit});
+ self::expect(this.{self::Class::field}, this.{self::Class::lateGenericField});
+ self::expect(this.{self::Class::field}, this.{self::Class::lateGenericFieldInit});
}
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static field lateExtensionField1Init = self::Extension|lateExtensionField1Init;
static method initLateExtensionField1 = self::Extension|initLateExtensionField1;
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
@@ -59,17 +76,17 @@
return self::lateTopLevelField1Init = value;
}
static get lateTopLevelField1() → core::int
- return let final core::int? #t4 = self::_#lateTopLevelField1 in #t4.==(null) ?{core::int} self::_#lateTopLevelField1 = self::initLateTopLevelField1(123) : #t4{core::int};
+ return let final core::int? #t5 = self::_#lateTopLevelField1 in #t5.==(null) ?{core::int} self::_#lateTopLevelField1 = self::initLateTopLevelField1(123) : #t5{core::int};
static method Extension|initLateExtensionField1(core::int value) → core::int {
return self::Extension|lateExtensionField1Init = value;
}
static get Extension|lateExtensionField1() → core::int
- return let final core::int? #t5 = self::_#Extension|lateExtensionField1 in #t5.==(null) ?{core::int} self::_#Extension|lateExtensionField1 = self::Extension|initLateExtensionField1(87) : #t5{core::int};
+ return let final core::int? #t6 = self::_#Extension|lateExtensionField1 in #t6.==(null) ?{core::int} self::_#Extension|lateExtensionField1 = self::Extension|initLateExtensionField1(87) : #t6{core::int};
static method Extension|initLateExtensionField2(core::int value) → core::int {
return self::Extension|lateExtensionField2Init = value;
}
static get Extension|lateExtensionField2() → core::int
- return let final core::int? #t6 = self::_#Extension|lateExtensionField2 in #t6.==(null) ?{core::int} self::_#Extension|lateExtensionField2 = self::Extension|initLateExtensionField2(42) : #t6{core::int};
+ return let final core::int? #t7 = self::_#Extension|lateExtensionField2 in #t7.==(null) ?{core::int} self::_#Extension|lateExtensionField2 = self::Extension|initLateExtensionField2(42) : #t7{core::int};
static method Extension|staticMethod() → dynamic {
self::expect(null, self::Extension|lateExtensionField2Init);
self::expect(42, self::Extension|lateExtensionField2);
@@ -83,7 +100,7 @@
self::expect(87, self::Class::lateStaticField1);
self::expect(87, self::Class::lateStaticField1Init);
self::Class::staticMethod();
- new self::Class::•().{self::Class::instanceMethod}();
+ new self::Class::•<core::int>(0).{self::Class::instanceMethod}();
self::expect(null, self::Extension|lateExtensionField1Init);
self::expect(87, self::Extension|lateExtensionField1);
self::expect(87, self::Extension|lateExtensionField1Init);
diff --git a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.transformed.expect
index 67e2378..6f2bab2 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.transformed.expect
@@ -2,15 +2,19 @@
import self as self;
import "dart:core" as core;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? lateStaticField1Init = null;
static field core::int? _#lateStaticField1 = null;
static field core::int? lateStaticField2Init = null;
static field core::int? _#lateStaticField2 = null;
field core::int? lateInstanceFieldInit = null;
field core::int? _#lateInstanceField = null;
- synthetic constructor •() → self::Class
- : super core::Object::•()
+ generic-covariant-impl field self::Class::T? lateGenericFieldInit = null;
+ final field self::Class::T% field;
+ field self::Class::T? _#lateGenericField = null;
+ field core::bool _#lateGenericField#isSet = false;
+ constructor •(self::Class::T% field) → self::Class<self::Class::T%>
+ : self::Class::field = field, super core::Object::•()
;
static method initLateStaticField1(core::int value) → core::int {
return self::Class::lateStaticField1Init = value;
@@ -32,13 +36,26 @@
}
get lateInstanceField() → core::int
return let final core::int? #t3 = this.{self::Class::_#lateInstanceField} in #t3.==(null) ?{core::int} this.{self::Class::_#lateInstanceField} = this.{self::Class::initLateInstanceField}(16) : #t3{core::int};
+ method initLateGenericField(generic-covariant-impl self::Class::T% value) → self::Class::T% {
+ return this.{self::Class::lateGenericFieldInit} = value;
+ }
+ get lateGenericField() → self::Class::T% {
+ if(!this.{self::Class::_#lateGenericField#isSet}) {
+ this.{self::Class::_#lateGenericField#isSet} = true;
+ this.{self::Class::_#lateGenericField} = this.{self::Class::initLateGenericField}(this.{self::Class::field});
+ }
+ return let final self::Class::T? #t4 = this.{self::Class::_#lateGenericField} in #t4{self::Class::T%};
+ }
method instanceMethod() → dynamic {
self::expect(null, this.{self::Class::lateInstanceFieldInit});
self::expect(16, this.{self::Class::lateInstanceField});
self::expect(16, this.{self::Class::lateInstanceFieldInit});
+ self::expect(null, this.{self::Class::lateGenericFieldInit});
+ self::expect(this.{self::Class::field}, this.{self::Class::lateGenericField});
+ self::expect(this.{self::Class::field}, this.{self::Class::lateGenericFieldInit});
}
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static field lateExtensionField1Init = self::Extension|lateExtensionField1Init;
static method initLateExtensionField1 = self::Extension|initLateExtensionField1;
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
@@ -59,17 +76,17 @@
return self::lateTopLevelField1Init = value;
}
static get lateTopLevelField1() → core::int
- return let final core::int? #t4 = self::_#lateTopLevelField1 in #t4.==(null) ?{core::int} self::_#lateTopLevelField1 = self::initLateTopLevelField1(123) : #t4{core::int};
+ return let final core::int? #t5 = self::_#lateTopLevelField1 in #t5.==(null) ?{core::int} self::_#lateTopLevelField1 = self::initLateTopLevelField1(123) : #t5{core::int};
static method Extension|initLateExtensionField1(core::int value) → core::int {
return self::Extension|lateExtensionField1Init = value;
}
static get Extension|lateExtensionField1() → core::int
- return let final core::int? #t5 = self::_#Extension|lateExtensionField1 in #t5.==(null) ?{core::int} self::_#Extension|lateExtensionField1 = self::Extension|initLateExtensionField1(87) : #t5{core::int};
+ return let final core::int? #t6 = self::_#Extension|lateExtensionField1 in #t6.==(null) ?{core::int} self::_#Extension|lateExtensionField1 = self::Extension|initLateExtensionField1(87) : #t6{core::int};
static method Extension|initLateExtensionField2(core::int value) → core::int {
return self::Extension|lateExtensionField2Init = value;
}
static get Extension|lateExtensionField2() → core::int
- return let final core::int? #t6 = self::_#Extension|lateExtensionField2 in #t6.==(null) ?{core::int} self::_#Extension|lateExtensionField2 = self::Extension|initLateExtensionField2(42) : #t6{core::int};
+ return let final core::int? #t7 = self::_#Extension|lateExtensionField2 in #t7.==(null) ?{core::int} self::_#Extension|lateExtensionField2 = self::Extension|initLateExtensionField2(42) : #t7{core::int};
static method Extension|staticMethod() → dynamic {
self::expect(null, self::Extension|lateExtensionField2Init);
self::expect(42, self::Extension|lateExtensionField2);
@@ -83,7 +100,7 @@
self::expect(87, self::Class::lateStaticField1);
self::expect(87, self::Class::lateStaticField1Init);
self::Class::staticMethod();
- new self::Class::•().{self::Class::instanceMethod}();
+ new self::Class::•<core::int>(0).{self::Class::instanceMethod}();
self::expect(null, self::Extension|lateExtensionField1Init);
self::expect(87, self::Extension|lateExtensionField1);
self::expect(87, self::Extension|lateExtensionField1Init);
diff --git a/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart b/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart
index d2a2bd7..4cbc166 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart
+++ b/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart
@@ -13,6 +13,23 @@
expect(null, lateLocalInit);
expect(123, lateLocal);
expect(123, lateLocalInit);
+
+ local<T>(T value) {
+ T? lateGenericLocalInit;
+ T initLateGenericLocal(T value) {
+ return lateGenericLocalInit = value;
+ }
+
+ late final T lateGenericLocal = initLateGenericLocal(value);
+
+ expect(null, lateGenericLocalInit);
+ expect(value, lateGenericLocal);
+ expect(value, lateGenericLocalInit);
+ }
+
+ local<int?>(null);
+ local<int?>(42);
+ local<int>(42);
}
expect(expected, actual) {
diff --git a/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart.strong.expect
index 3c9d2c6..3ccf892 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart.strong.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart.strong.expect
@@ -13,6 +13,27 @@
self::expect(null, lateLocalInit);
self::expect(123, #lateLocal#get.call());
self::expect(123, lateLocalInit);
+ function local<T extends core::Object? = dynamic>(T% value) → core::Null? {
+ T? lateGenericLocalInit;
+ function initLateGenericLocal(T% value) → T% {
+ return lateGenericLocalInit = value;
+ }
+ final T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T% {
+ if(!#lateGenericLocal#isSet) {
+ #lateGenericLocal#isSet = true;
+ lateGenericLocal = initLateGenericLocal.call(value);
+ }
+ return lateGenericLocal{T%};
+ }
+ self::expect(null, lateGenericLocalInit);
+ self::expect(value, #lateGenericLocal#get.call());
+ self::expect(value, lateGenericLocalInit);
+ }
+ local.call<core::int?>(null);
+ local.call<core::int?>(42);
+ local.call<core::int>(42);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart.strong.transformed.expect
index 3c9d2c6..3ccf892 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart.strong.transformed.expect
@@ -13,6 +13,27 @@
self::expect(null, lateLocalInit);
self::expect(123, #lateLocal#get.call());
self::expect(123, lateLocalInit);
+ function local<T extends core::Object? = dynamic>(T% value) → core::Null? {
+ T? lateGenericLocalInit;
+ function initLateGenericLocal(T% value) → T% {
+ return lateGenericLocalInit = value;
+ }
+ final T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T% {
+ if(!#lateGenericLocal#isSet) {
+ #lateGenericLocal#isSet = true;
+ lateGenericLocal = initLateGenericLocal.call(value);
+ }
+ return lateGenericLocal{T%};
+ }
+ self::expect(null, lateGenericLocalInit);
+ self::expect(value, #lateGenericLocal#get.call());
+ self::expect(value, lateGenericLocalInit);
+ }
+ local.call<core::int?>(null);
+ local.call<core::int?>(42);
+ local.call<core::int>(42);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart.weak.expect b/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart.weak.expect
index 3c9d2c6..3ccf892 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart.weak.expect
@@ -13,6 +13,27 @@
self::expect(null, lateLocalInit);
self::expect(123, #lateLocal#get.call());
self::expect(123, lateLocalInit);
+ function local<T extends core::Object? = dynamic>(T% value) → core::Null? {
+ T? lateGenericLocalInit;
+ function initLateGenericLocal(T% value) → T% {
+ return lateGenericLocalInit = value;
+ }
+ final T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T% {
+ if(!#lateGenericLocal#isSet) {
+ #lateGenericLocal#isSet = true;
+ lateGenericLocal = initLateGenericLocal.call(value);
+ }
+ return lateGenericLocal{T%};
+ }
+ self::expect(null, lateGenericLocalInit);
+ self::expect(value, #lateGenericLocal#get.call());
+ self::expect(value, lateGenericLocalInit);
+ }
+ local.call<core::int?>(null);
+ local.call<core::int?>(42);
+ local.call<core::int>(42);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart.weak.transformed.expect
index 3c9d2c6..3ccf892 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart.weak.transformed.expect
@@ -13,6 +13,27 @@
self::expect(null, lateLocalInit);
self::expect(123, #lateLocal#get.call());
self::expect(123, lateLocalInit);
+ function local<T extends core::Object? = dynamic>(T% value) → core::Null? {
+ T? lateGenericLocalInit;
+ function initLateGenericLocal(T% value) → T% {
+ return lateGenericLocalInit = value;
+ }
+ final T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T% {
+ if(!#lateGenericLocal#isSet) {
+ #lateGenericLocal#isSet = true;
+ lateGenericLocal = initLateGenericLocal.call(value);
+ }
+ return lateGenericLocal{T%};
+ }
+ self::expect(null, lateGenericLocalInit);
+ self::expect(value, #lateGenericLocal#get.call());
+ self::expect(value, lateGenericLocalInit);
+ }
+ local.call<core::int?>(null);
+ local.call<core::int?>(42);
+ local.call<core::int>(42);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart b/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart
index 33f43cb..e0d1275 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart
+++ b/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart
@@ -9,6 +9,21 @@
expect(123, lateLocal = 123);
expect(123, lateLocal);
throws(() => lateLocal = 124, 'Write value to initialized lateLocal');
+
+ local<T>(T value) {
+ late final T lateGenericLocal;
+
+ throws(() => lateGenericLocal,
+ 'Read value from uninitialized lateGenericLocal');
+ expect(value, lateGenericLocal = value);
+ expect(value, lateGenericLocal);
+ throws(() => lateGenericLocal = value,
+ 'Write value to initialized lateGenericLocal');
+ }
+
+ local<int?>(null);
+ local<int?>(42);
+ local<int>(42);
}
expect(expected, actual) {
diff --git a/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart.strong.expect
index e918f09..4719f92 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart.strong.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart.strong.expect
@@ -16,6 +16,26 @@
self::expect(123, #lateLocal#set.call(123));
self::expect(123, #lateLocal#get.call());
self::throws(() → core::int => #lateLocal#set.call(124), "Write value to initialized lateLocal");
+ function local<T extends core::Object? = dynamic>(T% value) → core::Null? {
+ final T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T%
+ return #lateGenericLocal#isSet ?{T%} lateGenericLocal{T%} : throw new _in::LateInitializationErrorImpl::•("Local 'lateGenericLocal' has not been initialized.");
+ function #lateGenericLocal#set(T% #t3) → dynamic
+ if(#lateGenericLocal#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Local 'lateGenericLocal' has already been initialized.");
+ else {
+ #lateGenericLocal#isSet = true;
+ return lateGenericLocal = #t3;
+ }
+ self::throws(() → T? => #lateGenericLocal#get.call(), "Read value from uninitialized lateGenericLocal");
+ self::expect(value, #lateGenericLocal#set.call(value));
+ self::expect(value, #lateGenericLocal#get.call());
+ self::throws(() → T% => #lateGenericLocal#set.call(value), "Write value to initialized lateGenericLocal");
+ }
+ local.call<core::int?>(null);
+ local.call<core::int?>(42);
+ local.call<core::int>(42);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart.strong.transformed.expect
index e918f09..4719f92 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart.strong.transformed.expect
@@ -16,6 +16,26 @@
self::expect(123, #lateLocal#set.call(123));
self::expect(123, #lateLocal#get.call());
self::throws(() → core::int => #lateLocal#set.call(124), "Write value to initialized lateLocal");
+ function local<T extends core::Object? = dynamic>(T% value) → core::Null? {
+ final T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T%
+ return #lateGenericLocal#isSet ?{T%} lateGenericLocal{T%} : throw new _in::LateInitializationErrorImpl::•("Local 'lateGenericLocal' has not been initialized.");
+ function #lateGenericLocal#set(T% #t3) → dynamic
+ if(#lateGenericLocal#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Local 'lateGenericLocal' has already been initialized.");
+ else {
+ #lateGenericLocal#isSet = true;
+ return lateGenericLocal = #t3;
+ }
+ self::throws(() → T? => #lateGenericLocal#get.call(), "Read value from uninitialized lateGenericLocal");
+ self::expect(value, #lateGenericLocal#set.call(value));
+ self::expect(value, #lateGenericLocal#get.call());
+ self::throws(() → T% => #lateGenericLocal#set.call(value), "Write value to initialized lateGenericLocal");
+ }
+ local.call<core::int?>(null);
+ local.call<core::int?>(42);
+ local.call<core::int>(42);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart.weak.expect b/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart.weak.expect
index e918f09..4719f92 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart.weak.expect
@@ -16,6 +16,26 @@
self::expect(123, #lateLocal#set.call(123));
self::expect(123, #lateLocal#get.call());
self::throws(() → core::int => #lateLocal#set.call(124), "Write value to initialized lateLocal");
+ function local<T extends core::Object? = dynamic>(T% value) → core::Null? {
+ final T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T%
+ return #lateGenericLocal#isSet ?{T%} lateGenericLocal{T%} : throw new _in::LateInitializationErrorImpl::•("Local 'lateGenericLocal' has not been initialized.");
+ function #lateGenericLocal#set(T% #t3) → dynamic
+ if(#lateGenericLocal#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Local 'lateGenericLocal' has already been initialized.");
+ else {
+ #lateGenericLocal#isSet = true;
+ return lateGenericLocal = #t3;
+ }
+ self::throws(() → T? => #lateGenericLocal#get.call(), "Read value from uninitialized lateGenericLocal");
+ self::expect(value, #lateGenericLocal#set.call(value));
+ self::expect(value, #lateGenericLocal#get.call());
+ self::throws(() → T% => #lateGenericLocal#set.call(value), "Write value to initialized lateGenericLocal");
+ }
+ local.call<core::int?>(null);
+ local.call<core::int?>(42);
+ local.call<core::int>(42);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart.weak.transformed.expect
index e918f09..4719f92 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart.weak.transformed.expect
@@ -16,6 +16,26 @@
self::expect(123, #lateLocal#set.call(123));
self::expect(123, #lateLocal#get.call());
self::throws(() → core::int => #lateLocal#set.call(124), "Write value to initialized lateLocal");
+ function local<T extends core::Object? = dynamic>(T% value) → core::Null? {
+ final T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T%
+ return #lateGenericLocal#isSet ?{T%} lateGenericLocal{T%} : throw new _in::LateInitializationErrorImpl::•("Local 'lateGenericLocal' has not been initialized.");
+ function #lateGenericLocal#set(T% #t3) → dynamic
+ if(#lateGenericLocal#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Local 'lateGenericLocal' has already been initialized.");
+ else {
+ #lateGenericLocal#isSet = true;
+ return lateGenericLocal = #t3;
+ }
+ self::throws(() → T? => #lateGenericLocal#get.call(), "Read value from uninitialized lateGenericLocal");
+ self::expect(value, #lateGenericLocal#set.call(value));
+ self::expect(value, #lateGenericLocal#get.call());
+ self::throws(() → T% => #lateGenericLocal#set.call(value), "Write value to initialized lateGenericLocal");
+ }
+ local.call<core::int?>(null);
+ local.call<core::int?>(42);
+ local.call<core::int>(42);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart
index 04dbcab..92b4b25 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart
@@ -9,7 +9,7 @@
late final int? lateTopLevelField1 = initLateTopLevelField1(123);
-class Class {
+class Class<T> {
static int? lateStaticField1Init;
static int? initLateStaticField1(int value) {
return lateStaticField1Init = value;
@@ -37,14 +37,28 @@
late final int? lateInstanceField = initLateInstanceField(16);
+ T? lateGenericInstanceFieldInit;
+ T? initLateGenericInstanceField(T? value) {
+ return lateGenericInstanceFieldInit = value;
+ }
+
+ final T? field;
+ late final T? lateGenericInstanceField = initLateGenericInstanceField(field);
+
+ Class(this.field);
+
instanceMethod() {
expect(null, lateInstanceFieldInit);
expect(16, lateInstanceField);
expect(16, lateInstanceFieldInit);
+
+ expect(null, lateGenericInstanceFieldInit);
+ expect(field, lateGenericInstanceField);
+ expect(field, lateGenericInstanceFieldInit);
}
}
-extension Extension on Class {
+extension Extension<T> on Class<T> {
static int? lateExtensionField1Init;
static int? initLateExtensionField1(int value) {
return lateExtensionField1Init = value;
@@ -76,7 +90,9 @@
expect(87, Class.lateStaticField1Init);
Class.staticMethod();
- new Class().instanceMethod();
+ new Class<int?>(null).instanceMethod();
+ new Class<int?>(0).instanceMethod();
+ new Class<int>(0).instanceMethod();
expect(null, Extension.lateExtensionField1Init);
expect(87, Extension.lateExtensionField1);
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.outline.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.outline.expect
index e6fb499..8938ef7 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.outline.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.outline.expect
@@ -2,7 +2,7 @@
import self as self;
import "dart:core" as core;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? lateStaticField1Init;
static field core::int? _#lateStaticField1;
static field core::bool _#lateStaticField1#isSet;
@@ -12,7 +12,11 @@
field core::int? lateInstanceFieldInit;
field core::int? _#lateInstanceField;
field core::bool _#lateInstanceField#isSet;
- synthetic constructor •() → self::Class
+ generic-covariant-impl field self::Class::T? lateGenericInstanceFieldInit;
+ final field self::Class::T? field;
+ field self::Class::T? _#lateGenericInstanceField;
+ field core::bool _#lateGenericInstanceField#isSet;
+ constructor •(self::Class::T? field) → self::Class<self::Class::T%>
;
static method initLateStaticField1(core::int value) → core::int?
;
@@ -25,10 +29,13 @@
method initLateInstanceField(core::int value) → core::int?
;
get lateInstanceField() → core::int?;
+ method initLateGenericInstanceField(generic-covariant-impl self::Class::T? value) → self::Class::T?
+ ;
+ get lateGenericInstanceField() → self::Class::T?;
method instanceMethod() → dynamic
;
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static field lateExtensionField1Init = self::Extension|lateExtensionField1Init;
static method initLateExtensionField1 = self::Extension|initLateExtensionField1;
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.strong.expect
index 6bcc89e..92df976 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.strong.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.strong.expect
@@ -2,7 +2,7 @@
import self as self;
import "dart:core" as core;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? lateStaticField1Init = null;
static field core::int? _#lateStaticField1 = null;
static field core::bool _#lateStaticField1#isSet = false;
@@ -12,8 +12,12 @@
field core::int? lateInstanceFieldInit = null;
field core::int? _#lateInstanceField = null;
field core::bool _#lateInstanceField#isSet = false;
- synthetic constructor •() → self::Class
- : super core::Object::•()
+ generic-covariant-impl field self::Class::T? lateGenericInstanceFieldInit = null;
+ final field self::Class::T? field;
+ field self::Class::T? _#lateGenericInstanceField = null;
+ field core::bool _#lateGenericInstanceField#isSet = false;
+ constructor •(self::Class::T? field) → self::Class<self::Class::T%>
+ : self::Class::field = field, super core::Object::•()
;
static method initLateStaticField1(core::int value) → core::int? {
return self::Class::lateStaticField1Init = value;
@@ -50,13 +54,26 @@
}
return this.{self::Class::_#lateInstanceField};
}
+ method initLateGenericInstanceField(generic-covariant-impl self::Class::T? value) → self::Class::T? {
+ return this.{self::Class::lateGenericInstanceFieldInit} = value;
+ }
+ get lateGenericInstanceField() → self::Class::T? {
+ if(!this.{self::Class::_#lateGenericInstanceField#isSet}) {
+ this.{self::Class::_#lateGenericInstanceField#isSet} = true;
+ this.{self::Class::_#lateGenericInstanceField} = this.{self::Class::initLateGenericInstanceField}(this.{self::Class::field});
+ }
+ return this.{self::Class::_#lateGenericInstanceField};
+ }
method instanceMethod() → dynamic {
self::expect(null, this.{self::Class::lateInstanceFieldInit});
self::expect(16, this.{self::Class::lateInstanceField});
self::expect(16, this.{self::Class::lateInstanceFieldInit});
+ self::expect(null, this.{self::Class::lateGenericInstanceFieldInit});
+ self::expect(this.{self::Class::field}, this.{self::Class::lateGenericInstanceField});
+ self::expect(this.{self::Class::field}, this.{self::Class::lateGenericInstanceFieldInit});
}
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static field lateExtensionField1Init = self::Extension|lateExtensionField1Init;
static method initLateExtensionField1 = self::Extension|initLateExtensionField1;
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
@@ -121,7 +138,9 @@
self::expect(87, self::Class::lateStaticField1);
self::expect(87, self::Class::lateStaticField1Init);
self::Class::staticMethod();
- new self::Class::•().{self::Class::instanceMethod}();
+ new self::Class::•<core::int?>(null).{self::Class::instanceMethod}();
+ new self::Class::•<core::int?>(0).{self::Class::instanceMethod}();
+ new self::Class::•<core::int>(0).{self::Class::instanceMethod}();
self::expect(null, self::Extension|lateExtensionField1Init);
self::expect(87, self::Extension|lateExtensionField1);
self::expect(87, self::Extension|lateExtensionField1Init);
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.strong.transformed.expect
index 6bcc89e..92df976 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.strong.transformed.expect
@@ -2,7 +2,7 @@
import self as self;
import "dart:core" as core;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? lateStaticField1Init = null;
static field core::int? _#lateStaticField1 = null;
static field core::bool _#lateStaticField1#isSet = false;
@@ -12,8 +12,12 @@
field core::int? lateInstanceFieldInit = null;
field core::int? _#lateInstanceField = null;
field core::bool _#lateInstanceField#isSet = false;
- synthetic constructor •() → self::Class
- : super core::Object::•()
+ generic-covariant-impl field self::Class::T? lateGenericInstanceFieldInit = null;
+ final field self::Class::T? field;
+ field self::Class::T? _#lateGenericInstanceField = null;
+ field core::bool _#lateGenericInstanceField#isSet = false;
+ constructor •(self::Class::T? field) → self::Class<self::Class::T%>
+ : self::Class::field = field, super core::Object::•()
;
static method initLateStaticField1(core::int value) → core::int? {
return self::Class::lateStaticField1Init = value;
@@ -50,13 +54,26 @@
}
return this.{self::Class::_#lateInstanceField};
}
+ method initLateGenericInstanceField(generic-covariant-impl self::Class::T? value) → self::Class::T? {
+ return this.{self::Class::lateGenericInstanceFieldInit} = value;
+ }
+ get lateGenericInstanceField() → self::Class::T? {
+ if(!this.{self::Class::_#lateGenericInstanceField#isSet}) {
+ this.{self::Class::_#lateGenericInstanceField#isSet} = true;
+ this.{self::Class::_#lateGenericInstanceField} = this.{self::Class::initLateGenericInstanceField}(this.{self::Class::field});
+ }
+ return this.{self::Class::_#lateGenericInstanceField};
+ }
method instanceMethod() → dynamic {
self::expect(null, this.{self::Class::lateInstanceFieldInit});
self::expect(16, this.{self::Class::lateInstanceField});
self::expect(16, this.{self::Class::lateInstanceFieldInit});
+ self::expect(null, this.{self::Class::lateGenericInstanceFieldInit});
+ self::expect(this.{self::Class::field}, this.{self::Class::lateGenericInstanceField});
+ self::expect(this.{self::Class::field}, this.{self::Class::lateGenericInstanceFieldInit});
}
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static field lateExtensionField1Init = self::Extension|lateExtensionField1Init;
static method initLateExtensionField1 = self::Extension|initLateExtensionField1;
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
@@ -121,7 +138,9 @@
self::expect(87, self::Class::lateStaticField1);
self::expect(87, self::Class::lateStaticField1Init);
self::Class::staticMethod();
- new self::Class::•().{self::Class::instanceMethod}();
+ new self::Class::•<core::int?>(null).{self::Class::instanceMethod}();
+ new self::Class::•<core::int?>(0).{self::Class::instanceMethod}();
+ new self::Class::•<core::int>(0).{self::Class::instanceMethod}();
self::expect(null, self::Extension|lateExtensionField1Init);
self::expect(87, self::Extension|lateExtensionField1);
self::expect(87, self::Extension|lateExtensionField1Init);
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.weak.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.weak.expect
index 6bcc89e..92df976 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.weak.expect
@@ -2,7 +2,7 @@
import self as self;
import "dart:core" as core;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? lateStaticField1Init = null;
static field core::int? _#lateStaticField1 = null;
static field core::bool _#lateStaticField1#isSet = false;
@@ -12,8 +12,12 @@
field core::int? lateInstanceFieldInit = null;
field core::int? _#lateInstanceField = null;
field core::bool _#lateInstanceField#isSet = false;
- synthetic constructor •() → self::Class
- : super core::Object::•()
+ generic-covariant-impl field self::Class::T? lateGenericInstanceFieldInit = null;
+ final field self::Class::T? field;
+ field self::Class::T? _#lateGenericInstanceField = null;
+ field core::bool _#lateGenericInstanceField#isSet = false;
+ constructor •(self::Class::T? field) → self::Class<self::Class::T%>
+ : self::Class::field = field, super core::Object::•()
;
static method initLateStaticField1(core::int value) → core::int? {
return self::Class::lateStaticField1Init = value;
@@ -50,13 +54,26 @@
}
return this.{self::Class::_#lateInstanceField};
}
+ method initLateGenericInstanceField(generic-covariant-impl self::Class::T? value) → self::Class::T? {
+ return this.{self::Class::lateGenericInstanceFieldInit} = value;
+ }
+ get lateGenericInstanceField() → self::Class::T? {
+ if(!this.{self::Class::_#lateGenericInstanceField#isSet}) {
+ this.{self::Class::_#lateGenericInstanceField#isSet} = true;
+ this.{self::Class::_#lateGenericInstanceField} = this.{self::Class::initLateGenericInstanceField}(this.{self::Class::field});
+ }
+ return this.{self::Class::_#lateGenericInstanceField};
+ }
method instanceMethod() → dynamic {
self::expect(null, this.{self::Class::lateInstanceFieldInit});
self::expect(16, this.{self::Class::lateInstanceField});
self::expect(16, this.{self::Class::lateInstanceFieldInit});
+ self::expect(null, this.{self::Class::lateGenericInstanceFieldInit});
+ self::expect(this.{self::Class::field}, this.{self::Class::lateGenericInstanceField});
+ self::expect(this.{self::Class::field}, this.{self::Class::lateGenericInstanceFieldInit});
}
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static field lateExtensionField1Init = self::Extension|lateExtensionField1Init;
static method initLateExtensionField1 = self::Extension|initLateExtensionField1;
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
@@ -121,7 +138,9 @@
self::expect(87, self::Class::lateStaticField1);
self::expect(87, self::Class::lateStaticField1Init);
self::Class::staticMethod();
- new self::Class::•().{self::Class::instanceMethod}();
+ new self::Class::•<core::int?>(null).{self::Class::instanceMethod}();
+ new self::Class::•<core::int?>(0).{self::Class::instanceMethod}();
+ new self::Class::•<core::int>(0).{self::Class::instanceMethod}();
self::expect(null, self::Extension|lateExtensionField1Init);
self::expect(87, self::Extension|lateExtensionField1);
self::expect(87, self::Extension|lateExtensionField1Init);
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.weak.transformed.expect
index 6bcc89e..92df976 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.weak.transformed.expect
@@ -2,7 +2,7 @@
import self as self;
import "dart:core" as core;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? lateStaticField1Init = null;
static field core::int? _#lateStaticField1 = null;
static field core::bool _#lateStaticField1#isSet = false;
@@ -12,8 +12,12 @@
field core::int? lateInstanceFieldInit = null;
field core::int? _#lateInstanceField = null;
field core::bool _#lateInstanceField#isSet = false;
- synthetic constructor •() → self::Class
- : super core::Object::•()
+ generic-covariant-impl field self::Class::T? lateGenericInstanceFieldInit = null;
+ final field self::Class::T? field;
+ field self::Class::T? _#lateGenericInstanceField = null;
+ field core::bool _#lateGenericInstanceField#isSet = false;
+ constructor •(self::Class::T? field) → self::Class<self::Class::T%>
+ : self::Class::field = field, super core::Object::•()
;
static method initLateStaticField1(core::int value) → core::int? {
return self::Class::lateStaticField1Init = value;
@@ -50,13 +54,26 @@
}
return this.{self::Class::_#lateInstanceField};
}
+ method initLateGenericInstanceField(generic-covariant-impl self::Class::T? value) → self::Class::T? {
+ return this.{self::Class::lateGenericInstanceFieldInit} = value;
+ }
+ get lateGenericInstanceField() → self::Class::T? {
+ if(!this.{self::Class::_#lateGenericInstanceField#isSet}) {
+ this.{self::Class::_#lateGenericInstanceField#isSet} = true;
+ this.{self::Class::_#lateGenericInstanceField} = this.{self::Class::initLateGenericInstanceField}(this.{self::Class::field});
+ }
+ return this.{self::Class::_#lateGenericInstanceField};
+ }
method instanceMethod() → dynamic {
self::expect(null, this.{self::Class::lateInstanceFieldInit});
self::expect(16, this.{self::Class::lateInstanceField});
self::expect(16, this.{self::Class::lateInstanceFieldInit});
+ self::expect(null, this.{self::Class::lateGenericInstanceFieldInit});
+ self::expect(this.{self::Class::field}, this.{self::Class::lateGenericInstanceField});
+ self::expect(this.{self::Class::field}, this.{self::Class::lateGenericInstanceFieldInit});
}
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static field lateExtensionField1Init = self::Extension|lateExtensionField1Init;
static method initLateExtensionField1 = self::Extension|initLateExtensionField1;
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
@@ -121,7 +138,9 @@
self::expect(87, self::Class::lateStaticField1);
self::expect(87, self::Class::lateStaticField1Init);
self::Class::staticMethod();
- new self::Class::•().{self::Class::instanceMethod}();
+ new self::Class::•<core::int?>(null).{self::Class::instanceMethod}();
+ new self::Class::•<core::int?>(0).{self::Class::instanceMethod}();
+ new self::Class::•<core::int>(0).{self::Class::instanceMethod}();
self::expect(null, self::Extension|lateExtensionField1Init);
self::expect(87, self::Extension|lateExtensionField1);
self::expect(87, self::Extension|lateExtensionField1Init);
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart
index 1493ede..9967557 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart
@@ -4,7 +4,7 @@
late final int? lateTopLevelField;
-class Class {
+class Class<T> {
static late final int? lateStaticField1;
static late final int? lateStaticField2;
@@ -19,17 +19,26 @@
late final int? lateInstanceField;
- instanceMethod() {
+ late final T? lateGenericInstanceField;
+
+ instanceMethod(T value) {
throws(() => lateInstanceField,
'Read value from uninitialized Class.lateInstanceField');
lateInstanceField = 16;
expect(16, lateInstanceField);
throws(() => lateInstanceField = 17,
'Write value to initialized Class.lateInstanceField');
+
+ throws(() => lateGenericInstanceField,
+ 'Read value from uninitialized Class.lateGenericInstanceField');
+ lateGenericInstanceField = value;
+ expect(value, lateGenericInstanceField);
+ throws(() => lateGenericInstanceField = value,
+ 'Write value to initialized Class.lateGenericInstanceField');
}
}
-extension Extension on Class {
+extension Extension<T> on Class<T> {
static late final int? lateExtensionField1;
static late final int? lateExtensionField2;
@@ -59,7 +68,9 @@
'Write value to initialized Class.lateStaticField1');
Class.staticMethod();
- new Class().instanceMethod();
+ new Class<int?>().instanceMethod(null);
+ new Class<int?>().instanceMethod(0);
+ new Class<int>().instanceMethod(0);
throws(() => Extension.lateExtensionField1,
'Read value from uninitialized Extension.lateExtensionField1');
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.outline.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.outline.expect
index bc1aaf1..aeb9eb7 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.outline.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.outline.expect
@@ -2,14 +2,16 @@
import self as self;
import "dart:core" as core;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? _#lateStaticField1;
static field core::bool _#lateStaticField1#isSet;
static field core::int? _#lateStaticField2;
static field core::bool _#lateStaticField2#isSet;
field core::int? _#lateInstanceField;
field core::bool _#lateInstanceField#isSet;
- synthetic constructor •() → self::Class
+ field self::Class::T? _#lateGenericInstanceField;
+ field core::bool _#lateGenericInstanceField#isSet;
+ synthetic constructor •() → self::Class<self::Class::T%>
;
static get lateStaticField1() → core::int?;
static set lateStaticField1(core::int? #t1) → void;
@@ -19,10 +21,12 @@
;
get lateInstanceField() → core::int?;
set lateInstanceField(core::int? #t3) → void;
- method instanceMethod() → dynamic
+ get lateGenericInstanceField() → self::Class::T?;
+ set lateGenericInstanceField(self::Class::T? #t4) → void;
+ method instanceMethod(generic-covariant-impl self::Class::T% value) → dynamic
;
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
static field lateExtensionField1 = self::_#Extension|lateExtensionField1#isSet;
static get lateExtensionField1 = get self::Extension|lateExtensionField1;
@@ -40,11 +44,11 @@
static field core::int? _#Extension|lateExtensionField2;
static field core::bool _#Extension|lateExtensionField2#isSet;
static get lateTopLevelField() → core::int?;
-static set lateTopLevelField(core::int? #t4) → void;
+static set lateTopLevelField(core::int? #t5) → void;
static get Extension|lateExtensionField1() → core::int?;
-static set Extension|lateExtensionField1(core::int? #t5) → void;
+static set Extension|lateExtensionField1(core::int? #t6) → void;
static get Extension|lateExtensionField2() → core::int?;
-static set Extension|lateExtensionField2(core::int? #t6) → void;
+static set Extension|lateExtensionField2(core::int? #t7) → void;
static method Extension|staticMethod() → dynamic
;
static method main() → dynamic
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.strong.expect
index ca3128d..987bda1 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.strong.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.strong.expect
@@ -3,14 +3,16 @@
import "dart:core" as core;
import "dart:_internal" as _in;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? _#lateStaticField1 = null;
static field core::bool _#lateStaticField1#isSet = false;
static field core::int? _#lateStaticField2 = null;
static field core::bool _#lateStaticField2#isSet = false;
field core::int? _#lateInstanceField = null;
field core::bool _#lateInstanceField#isSet = false;
- synthetic constructor •() → self::Class
+ field self::Class::T? _#lateGenericInstanceField = null;
+ field core::bool _#lateGenericInstanceField#isSet = false;
+ synthetic constructor •() → self::Class<self::Class::T%>
: super core::Object::•()
;
static get lateStaticField1() → core::int?
@@ -46,14 +48,27 @@
this.{self::Class::_#lateInstanceField#isSet} = true;
this.{self::Class::_#lateInstanceField} = #t3;
}
- method instanceMethod() → dynamic {
+ get lateGenericInstanceField() → self::Class::T?
+ return this.{self::Class::_#lateGenericInstanceField#isSet} ?{self::Class::T?} this.{self::Class::_#lateGenericInstanceField} : throw new _in::LateInitializationErrorImpl::•("Field 'lateGenericInstanceField' has not been initialized.");
+ set lateGenericInstanceField(self::Class::T? #t4) → void
+ if(this.{self::Class::_#lateGenericInstanceField#isSet})
+ throw new _in::LateInitializationErrorImpl::•("Field 'lateGenericInstanceField' has already been initialized.");
+ else {
+ this.{self::Class::_#lateGenericInstanceField#isSet} = true;
+ this.{self::Class::_#lateGenericInstanceField} = #t4;
+ }
+ method instanceMethod(generic-covariant-impl self::Class::T% value) → dynamic {
self::throws(() → core::int? => this.{self::Class::lateInstanceField}, "Read value from uninitialized Class.lateInstanceField");
this.{self::Class::lateInstanceField} = 16;
self::expect(16, this.{self::Class::lateInstanceField});
self::throws(() → core::int => this.{self::Class::lateInstanceField} = 17, "Write value to initialized Class.lateInstanceField");
+ self::throws(() → self::Class::T? => this.{self::Class::lateGenericInstanceField}, "Read value from uninitialized Class.lateGenericInstanceField");
+ this.{self::Class::lateGenericInstanceField} = value;
+ self::expect(value, this.{self::Class::lateGenericInstanceField});
+ self::throws(() → self::Class::T% => this.{self::Class::lateGenericInstanceField} = value, "Write value to initialized Class.lateGenericInstanceField");
}
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
static field lateExtensionField1 = self::_#Extension|lateExtensionField1#isSet;
static get lateExtensionField1 = get self::Extension|lateExtensionField1;
@@ -72,30 +87,30 @@
static field core::bool _#Extension|lateExtensionField2#isSet = false;
static get lateTopLevelField() → core::int?
return self::_#lateTopLevelField#isSet ?{core::int?} self::_#lateTopLevelField : throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField' has not been initialized.");
-static set lateTopLevelField(core::int? #t4) → void
+static set lateTopLevelField(core::int? #t5) → void
if(self::_#lateTopLevelField#isSet)
throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField' has already been initialized.");
else {
self::_#lateTopLevelField#isSet = true;
- self::_#lateTopLevelField = #t4;
+ self::_#lateTopLevelField = #t5;
}
static get Extension|lateExtensionField1() → core::int?
return self::_#Extension|lateExtensionField1#isSet ?{core::int?} self::_#Extension|lateExtensionField1 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has not been initialized.");
-static set Extension|lateExtensionField1(core::int? #t5) → void
+static set Extension|lateExtensionField1(core::int? #t6) → void
if(self::_#Extension|lateExtensionField1#isSet)
throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has already been initialized.");
else {
self::_#Extension|lateExtensionField1#isSet = true;
- self::_#Extension|lateExtensionField1 = #t5;
+ self::_#Extension|lateExtensionField1 = #t6;
}
static get Extension|lateExtensionField2() → core::int?
return self::_#Extension|lateExtensionField2#isSet ?{core::int?} self::_#Extension|lateExtensionField2 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has not been initialized.");
-static set Extension|lateExtensionField2(core::int? #t6) → void
+static set Extension|lateExtensionField2(core::int? #t7) → void
if(self::_#Extension|lateExtensionField2#isSet)
throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has already been initialized.");
else {
self::_#Extension|lateExtensionField2#isSet = true;
- self::_#Extension|lateExtensionField2 = #t6;
+ self::_#Extension|lateExtensionField2 = #t7;
}
static method Extension|staticMethod() → dynamic {
self::throws(() → core::int? => self::Extension|lateExtensionField2, "Read value from uninitialized Class.lateExtensionField2");
@@ -113,7 +128,9 @@
self::expect(87, self::Class::lateStaticField1);
self::throws(() → core::int => self::Class::lateStaticField1 = 88, "Write value to initialized Class.lateStaticField1");
self::Class::staticMethod();
- new self::Class::•().{self::Class::instanceMethod}();
+ new self::Class::•<core::int?>().{self::Class::instanceMethod}(null);
+ new self::Class::•<core::int?>().{self::Class::instanceMethod}(0);
+ new self::Class::•<core::int>().{self::Class::instanceMethod}(0);
self::throws(() → core::int? => self::Extension|lateExtensionField1, "Read value from uninitialized Extension.lateExtensionField1");
self::Extension|lateExtensionField1 = 87;
self::expect(87, self::Extension|lateExtensionField1);
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.strong.transformed.expect
index ca3128d..987bda1 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.strong.transformed.expect
@@ -3,14 +3,16 @@
import "dart:core" as core;
import "dart:_internal" as _in;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? _#lateStaticField1 = null;
static field core::bool _#lateStaticField1#isSet = false;
static field core::int? _#lateStaticField2 = null;
static field core::bool _#lateStaticField2#isSet = false;
field core::int? _#lateInstanceField = null;
field core::bool _#lateInstanceField#isSet = false;
- synthetic constructor •() → self::Class
+ field self::Class::T? _#lateGenericInstanceField = null;
+ field core::bool _#lateGenericInstanceField#isSet = false;
+ synthetic constructor •() → self::Class<self::Class::T%>
: super core::Object::•()
;
static get lateStaticField1() → core::int?
@@ -46,14 +48,27 @@
this.{self::Class::_#lateInstanceField#isSet} = true;
this.{self::Class::_#lateInstanceField} = #t3;
}
- method instanceMethod() → dynamic {
+ get lateGenericInstanceField() → self::Class::T?
+ return this.{self::Class::_#lateGenericInstanceField#isSet} ?{self::Class::T?} this.{self::Class::_#lateGenericInstanceField} : throw new _in::LateInitializationErrorImpl::•("Field 'lateGenericInstanceField' has not been initialized.");
+ set lateGenericInstanceField(self::Class::T? #t4) → void
+ if(this.{self::Class::_#lateGenericInstanceField#isSet})
+ throw new _in::LateInitializationErrorImpl::•("Field 'lateGenericInstanceField' has already been initialized.");
+ else {
+ this.{self::Class::_#lateGenericInstanceField#isSet} = true;
+ this.{self::Class::_#lateGenericInstanceField} = #t4;
+ }
+ method instanceMethod(generic-covariant-impl self::Class::T% value) → dynamic {
self::throws(() → core::int? => this.{self::Class::lateInstanceField}, "Read value from uninitialized Class.lateInstanceField");
this.{self::Class::lateInstanceField} = 16;
self::expect(16, this.{self::Class::lateInstanceField});
self::throws(() → core::int => this.{self::Class::lateInstanceField} = 17, "Write value to initialized Class.lateInstanceField");
+ self::throws(() → self::Class::T? => this.{self::Class::lateGenericInstanceField}, "Read value from uninitialized Class.lateGenericInstanceField");
+ this.{self::Class::lateGenericInstanceField} = value;
+ self::expect(value, this.{self::Class::lateGenericInstanceField});
+ self::throws(() → self::Class::T% => this.{self::Class::lateGenericInstanceField} = value, "Write value to initialized Class.lateGenericInstanceField");
}
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
static field lateExtensionField1 = self::_#Extension|lateExtensionField1#isSet;
static get lateExtensionField1 = get self::Extension|lateExtensionField1;
@@ -72,30 +87,30 @@
static field core::bool _#Extension|lateExtensionField2#isSet = false;
static get lateTopLevelField() → core::int?
return self::_#lateTopLevelField#isSet ?{core::int?} self::_#lateTopLevelField : throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField' has not been initialized.");
-static set lateTopLevelField(core::int? #t4) → void
+static set lateTopLevelField(core::int? #t5) → void
if(self::_#lateTopLevelField#isSet)
throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField' has already been initialized.");
else {
self::_#lateTopLevelField#isSet = true;
- self::_#lateTopLevelField = #t4;
+ self::_#lateTopLevelField = #t5;
}
static get Extension|lateExtensionField1() → core::int?
return self::_#Extension|lateExtensionField1#isSet ?{core::int?} self::_#Extension|lateExtensionField1 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has not been initialized.");
-static set Extension|lateExtensionField1(core::int? #t5) → void
+static set Extension|lateExtensionField1(core::int? #t6) → void
if(self::_#Extension|lateExtensionField1#isSet)
throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has already been initialized.");
else {
self::_#Extension|lateExtensionField1#isSet = true;
- self::_#Extension|lateExtensionField1 = #t5;
+ self::_#Extension|lateExtensionField1 = #t6;
}
static get Extension|lateExtensionField2() → core::int?
return self::_#Extension|lateExtensionField2#isSet ?{core::int?} self::_#Extension|lateExtensionField2 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has not been initialized.");
-static set Extension|lateExtensionField2(core::int? #t6) → void
+static set Extension|lateExtensionField2(core::int? #t7) → void
if(self::_#Extension|lateExtensionField2#isSet)
throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has already been initialized.");
else {
self::_#Extension|lateExtensionField2#isSet = true;
- self::_#Extension|lateExtensionField2 = #t6;
+ self::_#Extension|lateExtensionField2 = #t7;
}
static method Extension|staticMethod() → dynamic {
self::throws(() → core::int? => self::Extension|lateExtensionField2, "Read value from uninitialized Class.lateExtensionField2");
@@ -113,7 +128,9 @@
self::expect(87, self::Class::lateStaticField1);
self::throws(() → core::int => self::Class::lateStaticField1 = 88, "Write value to initialized Class.lateStaticField1");
self::Class::staticMethod();
- new self::Class::•().{self::Class::instanceMethod}();
+ new self::Class::•<core::int?>().{self::Class::instanceMethod}(null);
+ new self::Class::•<core::int?>().{self::Class::instanceMethod}(0);
+ new self::Class::•<core::int>().{self::Class::instanceMethod}(0);
self::throws(() → core::int? => self::Extension|lateExtensionField1, "Read value from uninitialized Extension.lateExtensionField1");
self::Extension|lateExtensionField1 = 87;
self::expect(87, self::Extension|lateExtensionField1);
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.weak.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.weak.expect
index ca3128d..987bda1 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.weak.expect
@@ -3,14 +3,16 @@
import "dart:core" as core;
import "dart:_internal" as _in;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? _#lateStaticField1 = null;
static field core::bool _#lateStaticField1#isSet = false;
static field core::int? _#lateStaticField2 = null;
static field core::bool _#lateStaticField2#isSet = false;
field core::int? _#lateInstanceField = null;
field core::bool _#lateInstanceField#isSet = false;
- synthetic constructor •() → self::Class
+ field self::Class::T? _#lateGenericInstanceField = null;
+ field core::bool _#lateGenericInstanceField#isSet = false;
+ synthetic constructor •() → self::Class<self::Class::T%>
: super core::Object::•()
;
static get lateStaticField1() → core::int?
@@ -46,14 +48,27 @@
this.{self::Class::_#lateInstanceField#isSet} = true;
this.{self::Class::_#lateInstanceField} = #t3;
}
- method instanceMethod() → dynamic {
+ get lateGenericInstanceField() → self::Class::T?
+ return this.{self::Class::_#lateGenericInstanceField#isSet} ?{self::Class::T?} this.{self::Class::_#lateGenericInstanceField} : throw new _in::LateInitializationErrorImpl::•("Field 'lateGenericInstanceField' has not been initialized.");
+ set lateGenericInstanceField(self::Class::T? #t4) → void
+ if(this.{self::Class::_#lateGenericInstanceField#isSet})
+ throw new _in::LateInitializationErrorImpl::•("Field 'lateGenericInstanceField' has already been initialized.");
+ else {
+ this.{self::Class::_#lateGenericInstanceField#isSet} = true;
+ this.{self::Class::_#lateGenericInstanceField} = #t4;
+ }
+ method instanceMethod(generic-covariant-impl self::Class::T% value) → dynamic {
self::throws(() → core::int? => this.{self::Class::lateInstanceField}, "Read value from uninitialized Class.lateInstanceField");
this.{self::Class::lateInstanceField} = 16;
self::expect(16, this.{self::Class::lateInstanceField});
self::throws(() → core::int => this.{self::Class::lateInstanceField} = 17, "Write value to initialized Class.lateInstanceField");
+ self::throws(() → self::Class::T? => this.{self::Class::lateGenericInstanceField}, "Read value from uninitialized Class.lateGenericInstanceField");
+ this.{self::Class::lateGenericInstanceField} = value;
+ self::expect(value, this.{self::Class::lateGenericInstanceField});
+ self::throws(() → self::Class::T% => this.{self::Class::lateGenericInstanceField} = value, "Write value to initialized Class.lateGenericInstanceField");
}
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
static field lateExtensionField1 = self::_#Extension|lateExtensionField1#isSet;
static get lateExtensionField1 = get self::Extension|lateExtensionField1;
@@ -72,30 +87,30 @@
static field core::bool _#Extension|lateExtensionField2#isSet = false;
static get lateTopLevelField() → core::int?
return self::_#lateTopLevelField#isSet ?{core::int?} self::_#lateTopLevelField : throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField' has not been initialized.");
-static set lateTopLevelField(core::int? #t4) → void
+static set lateTopLevelField(core::int? #t5) → void
if(self::_#lateTopLevelField#isSet)
throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField' has already been initialized.");
else {
self::_#lateTopLevelField#isSet = true;
- self::_#lateTopLevelField = #t4;
+ self::_#lateTopLevelField = #t5;
}
static get Extension|lateExtensionField1() → core::int?
return self::_#Extension|lateExtensionField1#isSet ?{core::int?} self::_#Extension|lateExtensionField1 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has not been initialized.");
-static set Extension|lateExtensionField1(core::int? #t5) → void
+static set Extension|lateExtensionField1(core::int? #t6) → void
if(self::_#Extension|lateExtensionField1#isSet)
throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has already been initialized.");
else {
self::_#Extension|lateExtensionField1#isSet = true;
- self::_#Extension|lateExtensionField1 = #t5;
+ self::_#Extension|lateExtensionField1 = #t6;
}
static get Extension|lateExtensionField2() → core::int?
return self::_#Extension|lateExtensionField2#isSet ?{core::int?} self::_#Extension|lateExtensionField2 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has not been initialized.");
-static set Extension|lateExtensionField2(core::int? #t6) → void
+static set Extension|lateExtensionField2(core::int? #t7) → void
if(self::_#Extension|lateExtensionField2#isSet)
throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has already been initialized.");
else {
self::_#Extension|lateExtensionField2#isSet = true;
- self::_#Extension|lateExtensionField2 = #t6;
+ self::_#Extension|lateExtensionField2 = #t7;
}
static method Extension|staticMethod() → dynamic {
self::throws(() → core::int? => self::Extension|lateExtensionField2, "Read value from uninitialized Class.lateExtensionField2");
@@ -113,7 +128,9 @@
self::expect(87, self::Class::lateStaticField1);
self::throws(() → core::int => self::Class::lateStaticField1 = 88, "Write value to initialized Class.lateStaticField1");
self::Class::staticMethod();
- new self::Class::•().{self::Class::instanceMethod}();
+ new self::Class::•<core::int?>().{self::Class::instanceMethod}(null);
+ new self::Class::•<core::int?>().{self::Class::instanceMethod}(0);
+ new self::Class::•<core::int>().{self::Class::instanceMethod}(0);
self::throws(() → core::int? => self::Extension|lateExtensionField1, "Read value from uninitialized Extension.lateExtensionField1");
self::Extension|lateExtensionField1 = 87;
self::expect(87, self::Extension|lateExtensionField1);
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.weak.transformed.expect
index ca3128d..987bda1 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.weak.transformed.expect
@@ -3,14 +3,16 @@
import "dart:core" as core;
import "dart:_internal" as _in;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? _#lateStaticField1 = null;
static field core::bool _#lateStaticField1#isSet = false;
static field core::int? _#lateStaticField2 = null;
static field core::bool _#lateStaticField2#isSet = false;
field core::int? _#lateInstanceField = null;
field core::bool _#lateInstanceField#isSet = false;
- synthetic constructor •() → self::Class
+ field self::Class::T? _#lateGenericInstanceField = null;
+ field core::bool _#lateGenericInstanceField#isSet = false;
+ synthetic constructor •() → self::Class<self::Class::T%>
: super core::Object::•()
;
static get lateStaticField1() → core::int?
@@ -46,14 +48,27 @@
this.{self::Class::_#lateInstanceField#isSet} = true;
this.{self::Class::_#lateInstanceField} = #t3;
}
- method instanceMethod() → dynamic {
+ get lateGenericInstanceField() → self::Class::T?
+ return this.{self::Class::_#lateGenericInstanceField#isSet} ?{self::Class::T?} this.{self::Class::_#lateGenericInstanceField} : throw new _in::LateInitializationErrorImpl::•("Field 'lateGenericInstanceField' has not been initialized.");
+ set lateGenericInstanceField(self::Class::T? #t4) → void
+ if(this.{self::Class::_#lateGenericInstanceField#isSet})
+ throw new _in::LateInitializationErrorImpl::•("Field 'lateGenericInstanceField' has already been initialized.");
+ else {
+ this.{self::Class::_#lateGenericInstanceField#isSet} = true;
+ this.{self::Class::_#lateGenericInstanceField} = #t4;
+ }
+ method instanceMethod(generic-covariant-impl self::Class::T% value) → dynamic {
self::throws(() → core::int? => this.{self::Class::lateInstanceField}, "Read value from uninitialized Class.lateInstanceField");
this.{self::Class::lateInstanceField} = 16;
self::expect(16, this.{self::Class::lateInstanceField});
self::throws(() → core::int => this.{self::Class::lateInstanceField} = 17, "Write value to initialized Class.lateInstanceField");
+ self::throws(() → self::Class::T? => this.{self::Class::lateGenericInstanceField}, "Read value from uninitialized Class.lateGenericInstanceField");
+ this.{self::Class::lateGenericInstanceField} = value;
+ self::expect(value, this.{self::Class::lateGenericInstanceField});
+ self::throws(() → self::Class::T% => this.{self::Class::lateGenericInstanceField} = value, "Write value to initialized Class.lateGenericInstanceField");
}
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
static field lateExtensionField1 = self::_#Extension|lateExtensionField1#isSet;
static get lateExtensionField1 = get self::Extension|lateExtensionField1;
@@ -72,30 +87,30 @@
static field core::bool _#Extension|lateExtensionField2#isSet = false;
static get lateTopLevelField() → core::int?
return self::_#lateTopLevelField#isSet ?{core::int?} self::_#lateTopLevelField : throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField' has not been initialized.");
-static set lateTopLevelField(core::int? #t4) → void
+static set lateTopLevelField(core::int? #t5) → void
if(self::_#lateTopLevelField#isSet)
throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField' has already been initialized.");
else {
self::_#lateTopLevelField#isSet = true;
- self::_#lateTopLevelField = #t4;
+ self::_#lateTopLevelField = #t5;
}
static get Extension|lateExtensionField1() → core::int?
return self::_#Extension|lateExtensionField1#isSet ?{core::int?} self::_#Extension|lateExtensionField1 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has not been initialized.");
-static set Extension|lateExtensionField1(core::int? #t5) → void
+static set Extension|lateExtensionField1(core::int? #t6) → void
if(self::_#Extension|lateExtensionField1#isSet)
throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has already been initialized.");
else {
self::_#Extension|lateExtensionField1#isSet = true;
- self::_#Extension|lateExtensionField1 = #t5;
+ self::_#Extension|lateExtensionField1 = #t6;
}
static get Extension|lateExtensionField2() → core::int?
return self::_#Extension|lateExtensionField2#isSet ?{core::int?} self::_#Extension|lateExtensionField2 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has not been initialized.");
-static set Extension|lateExtensionField2(core::int? #t6) → void
+static set Extension|lateExtensionField2(core::int? #t7) → void
if(self::_#Extension|lateExtensionField2#isSet)
throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has already been initialized.");
else {
self::_#Extension|lateExtensionField2#isSet = true;
- self::_#Extension|lateExtensionField2 = #t6;
+ self::_#Extension|lateExtensionField2 = #t7;
}
static method Extension|staticMethod() → dynamic {
self::throws(() → core::int? => self::Extension|lateExtensionField2, "Read value from uninitialized Class.lateExtensionField2");
@@ -113,7 +128,9 @@
self::expect(87, self::Class::lateStaticField1);
self::throws(() → core::int => self::Class::lateStaticField1 = 88, "Write value to initialized Class.lateStaticField1");
self::Class::staticMethod();
- new self::Class::•().{self::Class::instanceMethod}();
+ new self::Class::•<core::int?>().{self::Class::instanceMethod}(null);
+ new self::Class::•<core::int?>().{self::Class::instanceMethod}(0);
+ new self::Class::•<core::int>().{self::Class::instanceMethod}(0);
self::throws(() → core::int? => self::Extension|lateExtensionField1, "Read value from uninitialized Extension.lateExtensionField1");
self::Extension|lateExtensionField1 = 87;
self::expect(87, self::Extension|lateExtensionField1);
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart
index 778e612..8161ba2 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart
@@ -13,6 +13,23 @@
expect(null, lateLocalInit);
expect(123, lateLocal);
expect(123, lateLocalInit);
+
+ local<T>(T? value) {
+ T? lateGenericLocalInit;
+ T? initLateGenericLocal(T? value) {
+ return lateGenericLocalInit = value;
+ }
+
+ late final T? lateGenericLocal = initLateGenericLocal(value);
+
+ expect(null, lateGenericLocalInit);
+ expect(value, lateGenericLocal);
+ expect(value, lateGenericLocalInit);
+ }
+
+ local<int?>(null);
+ local<int?>(42);
+ local<int>(42);
}
expect(expected, actual) {
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart.strong.expect
index f019032..c925621 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart.strong.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart.strong.expect
@@ -19,6 +19,27 @@
self::expect(null, lateLocalInit);
self::expect(123, #lateLocal#get.call());
self::expect(123, lateLocalInit);
+ function local<T extends core::Object? = dynamic>(T? value) → core::Null? {
+ T? lateGenericLocalInit;
+ function initLateGenericLocal(T? value) → T? {
+ return lateGenericLocalInit = value;
+ }
+ final T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T? {
+ if(!#lateGenericLocal#isSet) {
+ #lateGenericLocal#isSet = true;
+ lateGenericLocal = initLateGenericLocal.call(value);
+ }
+ return lateGenericLocal;
+ }
+ self::expect(null, lateGenericLocalInit);
+ self::expect(value, #lateGenericLocal#get.call());
+ self::expect(value, lateGenericLocalInit);
+ }
+ local.call<core::int?>(null);
+ local.call<core::int?>(42);
+ local.call<core::int>(42);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart.strong.transformed.expect
index f019032..c925621 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart.strong.transformed.expect
@@ -19,6 +19,27 @@
self::expect(null, lateLocalInit);
self::expect(123, #lateLocal#get.call());
self::expect(123, lateLocalInit);
+ function local<T extends core::Object? = dynamic>(T? value) → core::Null? {
+ T? lateGenericLocalInit;
+ function initLateGenericLocal(T? value) → T? {
+ return lateGenericLocalInit = value;
+ }
+ final T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T? {
+ if(!#lateGenericLocal#isSet) {
+ #lateGenericLocal#isSet = true;
+ lateGenericLocal = initLateGenericLocal.call(value);
+ }
+ return lateGenericLocal;
+ }
+ self::expect(null, lateGenericLocalInit);
+ self::expect(value, #lateGenericLocal#get.call());
+ self::expect(value, lateGenericLocalInit);
+ }
+ local.call<core::int?>(null);
+ local.call<core::int?>(42);
+ local.call<core::int>(42);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart.weak.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart.weak.expect
index f019032..c925621 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart.weak.expect
@@ -19,6 +19,27 @@
self::expect(null, lateLocalInit);
self::expect(123, #lateLocal#get.call());
self::expect(123, lateLocalInit);
+ function local<T extends core::Object? = dynamic>(T? value) → core::Null? {
+ T? lateGenericLocalInit;
+ function initLateGenericLocal(T? value) → T? {
+ return lateGenericLocalInit = value;
+ }
+ final T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T? {
+ if(!#lateGenericLocal#isSet) {
+ #lateGenericLocal#isSet = true;
+ lateGenericLocal = initLateGenericLocal.call(value);
+ }
+ return lateGenericLocal;
+ }
+ self::expect(null, lateGenericLocalInit);
+ self::expect(value, #lateGenericLocal#get.call());
+ self::expect(value, lateGenericLocalInit);
+ }
+ local.call<core::int?>(null);
+ local.call<core::int?>(42);
+ local.call<core::int>(42);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart.weak.transformed.expect
index f019032..c925621 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart.weak.transformed.expect
@@ -19,6 +19,27 @@
self::expect(null, lateLocalInit);
self::expect(123, #lateLocal#get.call());
self::expect(123, lateLocalInit);
+ function local<T extends core::Object? = dynamic>(T? value) → core::Null? {
+ T? lateGenericLocalInit;
+ function initLateGenericLocal(T? value) → T? {
+ return lateGenericLocalInit = value;
+ }
+ final T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T? {
+ if(!#lateGenericLocal#isSet) {
+ #lateGenericLocal#isSet = true;
+ lateGenericLocal = initLateGenericLocal.call(value);
+ }
+ return lateGenericLocal;
+ }
+ self::expect(null, lateGenericLocalInit);
+ self::expect(value, #lateGenericLocal#get.call());
+ self::expect(value, lateGenericLocalInit);
+ }
+ local.call<core::int?>(null);
+ local.call<core::int?>(42);
+ local.call<core::int>(42);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart
index cfa53bc..3ee8c4b 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart
@@ -9,6 +9,22 @@
expect(123, lateLocal = 123);
expect(123, lateLocal);
throws(() => lateLocal = 124, 'Write value to initialized lateLocal');
+
+ local<T>(T? value) {
+ late final T? lateGenericLocal;
+
+ throws(() => lateGenericLocal,
+ 'Read value from uninitialized lateGenericLocal');
+ expect(value, lateGenericLocal = value);
+ expect(value, lateGenericLocal);
+ throws(() => lateGenericLocal = value,
+ 'Write value to initialized lateGenericLocal');
+ }
+
+ local<int?>(null);
+ local<int?>(0);
+ local<int>(null);
+ local<int>(0);
}
expect(expected, actual) {
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart.strong.expect
index 268b399..d623c5e 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart.strong.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart.strong.expect
@@ -19,6 +19,27 @@
self::expect(123, #lateLocal#set.call(123));
self::expect(123, #lateLocal#get.call());
self::throws(() → core::int => #lateLocal#set.call(124), "Write value to initialized lateLocal");
+ function local<T extends core::Object? = dynamic>(T? value) → core::Null? {
+ final T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T?
+ return #lateGenericLocal#isSet ?{T?} lateGenericLocal : throw new _in::LateInitializationErrorImpl::•("Local 'lateGenericLocal' has not been initialized.");
+ function #lateGenericLocal#set(T? #t2) → dynamic
+ if(#lateGenericLocal#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Local 'lateGenericLocal' has already been initialized.");
+ else {
+ #lateGenericLocal#isSet = true;
+ return lateGenericLocal = #t2;
+ }
+ self::throws(() → T? => #lateGenericLocal#get.call(), "Read value from uninitialized lateGenericLocal");
+ self::expect(value, #lateGenericLocal#set.call(value));
+ self::expect(value, #lateGenericLocal#get.call());
+ self::throws(() → T? => #lateGenericLocal#set.call(value), "Write value to initialized lateGenericLocal");
+ }
+ local.call<core::int?>(null);
+ local.call<core::int?>(0);
+ local.call<core::int>(null);
+ local.call<core::int>(0);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart.strong.transformed.expect
index 268b399..d623c5e 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart.strong.transformed.expect
@@ -19,6 +19,27 @@
self::expect(123, #lateLocal#set.call(123));
self::expect(123, #lateLocal#get.call());
self::throws(() → core::int => #lateLocal#set.call(124), "Write value to initialized lateLocal");
+ function local<T extends core::Object? = dynamic>(T? value) → core::Null? {
+ final T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T?
+ return #lateGenericLocal#isSet ?{T?} lateGenericLocal : throw new _in::LateInitializationErrorImpl::•("Local 'lateGenericLocal' has not been initialized.");
+ function #lateGenericLocal#set(T? #t2) → dynamic
+ if(#lateGenericLocal#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Local 'lateGenericLocal' has already been initialized.");
+ else {
+ #lateGenericLocal#isSet = true;
+ return lateGenericLocal = #t2;
+ }
+ self::throws(() → T? => #lateGenericLocal#get.call(), "Read value from uninitialized lateGenericLocal");
+ self::expect(value, #lateGenericLocal#set.call(value));
+ self::expect(value, #lateGenericLocal#get.call());
+ self::throws(() → T? => #lateGenericLocal#set.call(value), "Write value to initialized lateGenericLocal");
+ }
+ local.call<core::int?>(null);
+ local.call<core::int?>(0);
+ local.call<core::int>(null);
+ local.call<core::int>(0);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart.weak.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart.weak.expect
index 268b399..d623c5e 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart.weak.expect
@@ -19,6 +19,27 @@
self::expect(123, #lateLocal#set.call(123));
self::expect(123, #lateLocal#get.call());
self::throws(() → core::int => #lateLocal#set.call(124), "Write value to initialized lateLocal");
+ function local<T extends core::Object? = dynamic>(T? value) → core::Null? {
+ final T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T?
+ return #lateGenericLocal#isSet ?{T?} lateGenericLocal : throw new _in::LateInitializationErrorImpl::•("Local 'lateGenericLocal' has not been initialized.");
+ function #lateGenericLocal#set(T? #t2) → dynamic
+ if(#lateGenericLocal#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Local 'lateGenericLocal' has already been initialized.");
+ else {
+ #lateGenericLocal#isSet = true;
+ return lateGenericLocal = #t2;
+ }
+ self::throws(() → T? => #lateGenericLocal#get.call(), "Read value from uninitialized lateGenericLocal");
+ self::expect(value, #lateGenericLocal#set.call(value));
+ self::expect(value, #lateGenericLocal#get.call());
+ self::throws(() → T? => #lateGenericLocal#set.call(value), "Write value to initialized lateGenericLocal");
+ }
+ local.call<core::int?>(null);
+ local.call<core::int?>(0);
+ local.call<core::int>(null);
+ local.call<core::int>(0);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart.weak.transformed.expect
index 268b399..d623c5e 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart.weak.transformed.expect
@@ -19,6 +19,27 @@
self::expect(123, #lateLocal#set.call(123));
self::expect(123, #lateLocal#get.call());
self::throws(() → core::int => #lateLocal#set.call(124), "Write value to initialized lateLocal");
+ function local<T extends core::Object? = dynamic>(T? value) → core::Null? {
+ final T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T?
+ return #lateGenericLocal#isSet ?{T?} lateGenericLocal : throw new _in::LateInitializationErrorImpl::•("Local 'lateGenericLocal' has not been initialized.");
+ function #lateGenericLocal#set(T? #t2) → dynamic
+ if(#lateGenericLocal#isSet)
+ throw new _in::LateInitializationErrorImpl::•("Local 'lateGenericLocal' has already been initialized.");
+ else {
+ #lateGenericLocal#isSet = true;
+ return lateGenericLocal = #t2;
+ }
+ self::throws(() → T? => #lateGenericLocal#get.call(), "Read value from uninitialized lateGenericLocal");
+ self::expect(value, #lateGenericLocal#set.call(value));
+ self::expect(value, #lateGenericLocal#get.call());
+ self::throws(() → T? => #lateGenericLocal#set.call(value), "Write value to initialized lateGenericLocal");
+ }
+ local.call<core::int?>(null);
+ local.call<core::int?>(0);
+ local.call<core::int>(null);
+ local.call<core::int>(0);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart b/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart
index 6363618..489af50 100644
--- a/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart
+++ b/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart
@@ -8,6 +8,18 @@
expect(123, lateLocal);
expect(124, lateLocal = 124);
expect(124, lateLocal);
+
+ local<T>(T value1, T value2) {
+ late T lateGenericLocal = value1;
+
+ expect(value1, lateGenericLocal);
+ expect(value2, lateGenericLocal = value2);
+ expect(value2, lateGenericLocal);
+ }
+
+ local<int?>(null, 0);
+ local<int?>(0, null);
+ local<int>(0, 42);
}
expect(expected, actual) {
diff --git a/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart.strong.expect
index 5633dbf..363c922 100644
--- a/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart.strong.expect
+++ b/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart.strong.expect
@@ -11,6 +11,27 @@
self::expect(123, #lateLocal#get.call());
self::expect(124, #lateLocal#set.call(124));
self::expect(124, #lateLocal#get.call());
+ function local<T extends core::Object? = dynamic>(T% value1, T% value2) → core::Null? {
+ T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T% {
+ if(!#lateGenericLocal#isSet) {
+ #lateGenericLocal#isSet = true;
+ lateGenericLocal = value1;
+ }
+ return lateGenericLocal{T%};
+ }
+ function #lateGenericLocal#set(T% #t3) → dynamic {
+ #lateGenericLocal#isSet = true;
+ return lateGenericLocal = #t3;
+ }
+ self::expect(value1, #lateGenericLocal#get.call());
+ self::expect(value2, #lateGenericLocal#set.call(value2));
+ self::expect(value2, #lateGenericLocal#get.call());
+ }
+ local.call<core::int?>(null, 0);
+ local.call<core::int?>(0, null);
+ local.call<core::int>(0, 42);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart.strong.transformed.expect
index 5633dbf..363c922 100644
--- a/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart.strong.transformed.expect
@@ -11,6 +11,27 @@
self::expect(123, #lateLocal#get.call());
self::expect(124, #lateLocal#set.call(124));
self::expect(124, #lateLocal#get.call());
+ function local<T extends core::Object? = dynamic>(T% value1, T% value2) → core::Null? {
+ T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T% {
+ if(!#lateGenericLocal#isSet) {
+ #lateGenericLocal#isSet = true;
+ lateGenericLocal = value1;
+ }
+ return lateGenericLocal{T%};
+ }
+ function #lateGenericLocal#set(T% #t3) → dynamic {
+ #lateGenericLocal#isSet = true;
+ return lateGenericLocal = #t3;
+ }
+ self::expect(value1, #lateGenericLocal#get.call());
+ self::expect(value2, #lateGenericLocal#set.call(value2));
+ self::expect(value2, #lateGenericLocal#get.call());
+ }
+ local.call<core::int?>(null, 0);
+ local.call<core::int?>(0, null);
+ local.call<core::int>(0, 42);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart.weak.expect b/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart.weak.expect
index 5633dbf..363c922 100644
--- a/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart.weak.expect
@@ -11,6 +11,27 @@
self::expect(123, #lateLocal#get.call());
self::expect(124, #lateLocal#set.call(124));
self::expect(124, #lateLocal#get.call());
+ function local<T extends core::Object? = dynamic>(T% value1, T% value2) → core::Null? {
+ T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T% {
+ if(!#lateGenericLocal#isSet) {
+ #lateGenericLocal#isSet = true;
+ lateGenericLocal = value1;
+ }
+ return lateGenericLocal{T%};
+ }
+ function #lateGenericLocal#set(T% #t3) → dynamic {
+ #lateGenericLocal#isSet = true;
+ return lateGenericLocal = #t3;
+ }
+ self::expect(value1, #lateGenericLocal#get.call());
+ self::expect(value2, #lateGenericLocal#set.call(value2));
+ self::expect(value2, #lateGenericLocal#get.call());
+ }
+ local.call<core::int?>(null, 0);
+ local.call<core::int?>(0, null);
+ local.call<core::int>(0, 42);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart.weak.transformed.expect
index 5633dbf..363c922 100644
--- a/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart.weak.transformed.expect
@@ -11,6 +11,27 @@
self::expect(123, #lateLocal#get.call());
self::expect(124, #lateLocal#set.call(124));
self::expect(124, #lateLocal#get.call());
+ function local<T extends core::Object? = dynamic>(T% value1, T% value2) → core::Null? {
+ T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T% {
+ if(!#lateGenericLocal#isSet) {
+ #lateGenericLocal#isSet = true;
+ lateGenericLocal = value1;
+ }
+ return lateGenericLocal{T%};
+ }
+ function #lateGenericLocal#set(T% #t3) → dynamic {
+ #lateGenericLocal#isSet = true;
+ return lateGenericLocal = #t3;
+ }
+ self::expect(value1, #lateGenericLocal#get.call());
+ self::expect(value2, #lateGenericLocal#set.call(value2));
+ self::expect(value2, #lateGenericLocal#get.call());
+ }
+ local.call<core::int?>(null, 0);
+ local.call<core::int?>(0, null);
+ local.call<core::int>(0, 42);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart b/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart
index 0cb0e98..819dc30 100644
--- a/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart
+++ b/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart
@@ -7,6 +7,18 @@
throws(() => lateLocal, 'Read value from uninitialized lateLocal');
expect(123, lateLocal = 123);
expect(123, lateLocal);
+
+ local<T>(T value) {
+ late T lateGenericLocal;
+ throws(() => lateGenericLocal,
+ 'Read value from uninitialized lateGenericLocal');
+ expect(value, lateGenericLocal = value);
+ expect(value, lateGenericLocal);
+ }
+
+ local<int?>(null);
+ local<int?>(0);
+ local<int>(0);
}
expect(expected, actual) {
diff --git a/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart.strong.expect
index 26d533b..353612c 100644
--- a/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart.strong.expect
+++ b/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart.strong.expect
@@ -12,6 +12,22 @@
self::throws(() → core::int? => #lateLocal#get.call(), "Read value from uninitialized lateLocal");
self::expect(123, #lateLocal#set.call(123));
self::expect(123, #lateLocal#get.call());
+ function local<T extends core::Object? = dynamic>(T% value) → core::Null? {
+ T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T%
+ return #lateGenericLocal#isSet ?{T%} lateGenericLocal{T%} : throw new _in::LateInitializationErrorImpl::•("Local 'lateGenericLocal' has not been initialized.");
+ function #lateGenericLocal#set(T% #t3) → dynamic {
+ #lateGenericLocal#isSet = true;
+ return lateGenericLocal = #t3;
+ }
+ self::throws(() → T? => #lateGenericLocal#get.call(), "Read value from uninitialized lateGenericLocal");
+ self::expect(value, #lateGenericLocal#set.call(value));
+ self::expect(value, #lateGenericLocal#get.call());
+ }
+ local.call<core::int?>(null);
+ local.call<core::int?>(0);
+ local.call<core::int>(0);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart.strong.transformed.expect
index 26d533b..353612c 100644
--- a/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart.strong.transformed.expect
@@ -12,6 +12,22 @@
self::throws(() → core::int? => #lateLocal#get.call(), "Read value from uninitialized lateLocal");
self::expect(123, #lateLocal#set.call(123));
self::expect(123, #lateLocal#get.call());
+ function local<T extends core::Object? = dynamic>(T% value) → core::Null? {
+ T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T%
+ return #lateGenericLocal#isSet ?{T%} lateGenericLocal{T%} : throw new _in::LateInitializationErrorImpl::•("Local 'lateGenericLocal' has not been initialized.");
+ function #lateGenericLocal#set(T% #t3) → dynamic {
+ #lateGenericLocal#isSet = true;
+ return lateGenericLocal = #t3;
+ }
+ self::throws(() → T? => #lateGenericLocal#get.call(), "Read value from uninitialized lateGenericLocal");
+ self::expect(value, #lateGenericLocal#set.call(value));
+ self::expect(value, #lateGenericLocal#get.call());
+ }
+ local.call<core::int?>(null);
+ local.call<core::int?>(0);
+ local.call<core::int>(0);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart.weak.expect b/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart.weak.expect
index 26d533b..353612c 100644
--- a/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart.weak.expect
@@ -12,6 +12,22 @@
self::throws(() → core::int? => #lateLocal#get.call(), "Read value from uninitialized lateLocal");
self::expect(123, #lateLocal#set.call(123));
self::expect(123, #lateLocal#get.call());
+ function local<T extends core::Object? = dynamic>(T% value) → core::Null? {
+ T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T%
+ return #lateGenericLocal#isSet ?{T%} lateGenericLocal{T%} : throw new _in::LateInitializationErrorImpl::•("Local 'lateGenericLocal' has not been initialized.");
+ function #lateGenericLocal#set(T% #t3) → dynamic {
+ #lateGenericLocal#isSet = true;
+ return lateGenericLocal = #t3;
+ }
+ self::throws(() → T? => #lateGenericLocal#get.call(), "Read value from uninitialized lateGenericLocal");
+ self::expect(value, #lateGenericLocal#set.call(value));
+ self::expect(value, #lateGenericLocal#get.call());
+ }
+ local.call<core::int?>(null);
+ local.call<core::int?>(0);
+ local.call<core::int>(0);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart.weak.transformed.expect
index 26d533b..353612c 100644
--- a/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart.weak.transformed.expect
@@ -12,6 +12,22 @@
self::throws(() → core::int? => #lateLocal#get.call(), "Read value from uninitialized lateLocal");
self::expect(123, #lateLocal#set.call(123));
self::expect(123, #lateLocal#get.call());
+ function local<T extends core::Object? = dynamic>(T% value) → core::Null? {
+ T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T%
+ return #lateGenericLocal#isSet ?{T%} lateGenericLocal{T%} : throw new _in::LateInitializationErrorImpl::•("Local 'lateGenericLocal' has not been initialized.");
+ function #lateGenericLocal#set(T% #t3) → dynamic {
+ #lateGenericLocal#isSet = true;
+ return lateGenericLocal = #t3;
+ }
+ self::throws(() → T? => #lateGenericLocal#get.call(), "Read value from uninitialized lateGenericLocal");
+ self::expect(value, #lateGenericLocal#set.call(value));
+ self::expect(value, #lateGenericLocal#get.call());
+ }
+ local.call<core::int?>(null);
+ local.call<core::int?>(0);
+ local.call<core::int>(0);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart b/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart
index 9c90916..7d83dfe 100644
--- a/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart
@@ -5,7 +5,7 @@
int? lateTopLevelField1Init() => 123;
late int? lateTopLevelField1 = lateTopLevelField1Init();
-class Class {
+class Class<T> {
static int? lateStaticField1Init() => 87;
static late int? lateStaticField1 = lateStaticField1Init();
static int? lateStaticField2Init() => 42;
@@ -20,14 +20,24 @@
int? lateInstanceFieldInit() => 16;
late int? lateInstanceField = lateInstanceFieldInit();
- instanceMethod() {
+ final T? field;
+ T? lateGenericInstanceFieldInit() => field;
+ late T? lateGenericInstanceField = lateGenericInstanceFieldInit();
+
+ Class(this.field);
+
+ instanceMethod(T? value) {
expect(16, lateInstanceField);
lateInstanceField = 17;
expect(17, lateInstanceField);
+
+ expect(field, lateGenericInstanceField);
+ lateGenericInstanceField = value;
+ expect(value, lateGenericInstanceField);
}
}
-extension Extension on Class {
+extension Extension<T> on Class<T> {
static int? lateExtensionField1Init() => 87;
static late int? lateExtensionField1 = lateExtensionField1Init();
static int? lateExtensionField2Init() => 42;
@@ -50,7 +60,10 @@
expect(88, Class.lateStaticField1);
Class.staticMethod();
- new Class().instanceMethod();
+ new Class<int?>(null).instanceMethod(0);
+ new Class<int?>(0).instanceMethod(null);
+ new Class<int>(null).instanceMethod(0);
+ new Class<int>(0).instanceMethod(null);
expect(87, Extension.lateExtensionField1);
Extension.lateExtensionField1 = 88;
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart.outline.expect b/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart.outline.expect
index 0e2d5ce..42a5d1b 100644
--- a/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart.outline.expect
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart.outline.expect
@@ -2,14 +2,17 @@
import self as self;
import "dart:core" as core;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? _#lateStaticField1;
static field core::bool _#lateStaticField1#isSet;
static field core::int? _#lateStaticField2;
static field core::bool _#lateStaticField2#isSet;
field core::int? _#lateInstanceField;
field core::bool _#lateInstanceField#isSet;
- synthetic constructor •() → self::Class
+ final field self::Class::T? field;
+ generic-covariant-impl field self::Class::T? _#lateGenericInstanceField;
+ field core::bool _#lateGenericInstanceField#isSet;
+ constructor •(self::Class::T? field) → self::Class<self::Class::T%>
;
static method lateStaticField1Init() → core::int?
;
@@ -25,10 +28,14 @@
;
get lateInstanceField() → core::int?;
set lateInstanceField(core::int? #t3) → void;
- method instanceMethod() → dynamic
+ method lateGenericInstanceFieldInit() → self::Class::T?
+ ;
+ get lateGenericInstanceField() → self::Class::T?;
+ set lateGenericInstanceField(self::Class::T? #t4) → void;
+ method instanceMethod(generic-covariant-impl self::Class::T? value) → dynamic
;
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static method lateExtensionField1Init = self::Extension|lateExtensionField1Init;
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
static field lateExtensionField1 = self::_#Extension|lateExtensionField1#isSet;
@@ -50,15 +57,15 @@
static method lateTopLevelField1Init() → core::int?
;
static get lateTopLevelField1() → core::int?;
-static set lateTopLevelField1(core::int? #t4) → void;
+static set lateTopLevelField1(core::int? #t5) → void;
static method Extension|lateExtensionField1Init() → core::int?
;
static get Extension|lateExtensionField1() → core::int?;
-static set Extension|lateExtensionField1(core::int? #t5) → void;
+static set Extension|lateExtensionField1(core::int? #t6) → void;
static method Extension|lateExtensionField2Init() → core::int?
;
static get Extension|lateExtensionField2() → core::int?;
-static set Extension|lateExtensionField2(core::int? #t6) → void;
+static set Extension|lateExtensionField2(core::int? #t7) → void;
static method Extension|staticMethod() → dynamic
;
static method main() → dynamic
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart.strong.expect
index 9ee88bb..a90900a 100644
--- a/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart.strong.expect
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart.strong.expect
@@ -2,15 +2,18 @@
import self as self;
import "dart:core" as core;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? _#lateStaticField1 = null;
static field core::bool _#lateStaticField1#isSet = false;
static field core::int? _#lateStaticField2 = null;
static field core::bool _#lateStaticField2#isSet = false;
field core::int? _#lateInstanceField = null;
field core::bool _#lateInstanceField#isSet = false;
- synthetic constructor •() → self::Class
- : super core::Object::•()
+ final field self::Class::T? field;
+ generic-covariant-impl field self::Class::T? _#lateGenericInstanceField = null;
+ field core::bool _#lateGenericInstanceField#isSet = false;
+ constructor •(self::Class::T? field) → self::Class<self::Class::T%>
+ : self::Class::field = field, super core::Object::•()
;
static method lateStaticField1Init() → core::int?
return 87;
@@ -56,13 +59,29 @@
this.{self::Class::_#lateInstanceField#isSet} = true;
this.{self::Class::_#lateInstanceField} = #t3;
}
- method instanceMethod() → dynamic {
+ method lateGenericInstanceFieldInit() → self::Class::T?
+ return this.{self::Class::field};
+ get lateGenericInstanceField() → self::Class::T? {
+ if(!this.{self::Class::_#lateGenericInstanceField#isSet}) {
+ this.{self::Class::_#lateGenericInstanceField#isSet} = true;
+ this.{self::Class::_#lateGenericInstanceField} = this.{self::Class::lateGenericInstanceFieldInit}();
+ }
+ return this.{self::Class::_#lateGenericInstanceField};
+ }
+ set lateGenericInstanceField(self::Class::T? #t4) → void {
+ this.{self::Class::_#lateGenericInstanceField#isSet} = true;
+ this.{self::Class::_#lateGenericInstanceField} = #t4;
+ }
+ method instanceMethod(generic-covariant-impl self::Class::T? value) → dynamic {
self::expect(16, this.{self::Class::lateInstanceField});
this.{self::Class::lateInstanceField} = 17;
self::expect(17, this.{self::Class::lateInstanceField});
+ self::expect(this.{self::Class::field}, this.{self::Class::lateGenericInstanceField});
+ this.{self::Class::lateGenericInstanceField} = value;
+ self::expect(value, this.{self::Class::lateGenericInstanceField});
}
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static method lateExtensionField1Init = self::Extension|lateExtensionField1Init;
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
static field lateExtensionField1 = self::_#Extension|lateExtensionField1#isSet;
@@ -90,9 +109,9 @@
}
return self::_#lateTopLevelField1;
}
-static set lateTopLevelField1(core::int? #t4) → void {
+static set lateTopLevelField1(core::int? #t5) → void {
self::_#lateTopLevelField1#isSet = true;
- self::_#lateTopLevelField1 = #t4;
+ self::_#lateTopLevelField1 = #t5;
}
static method Extension|lateExtensionField1Init() → core::int?
return 87;
@@ -103,9 +122,9 @@
}
return self::_#Extension|lateExtensionField1;
}
-static set Extension|lateExtensionField1(core::int? #t5) → void {
+static set Extension|lateExtensionField1(core::int? #t6) → void {
self::_#Extension|lateExtensionField1#isSet = true;
- self::_#Extension|lateExtensionField1 = #t5;
+ self::_#Extension|lateExtensionField1 = #t6;
}
static method Extension|lateExtensionField2Init() → core::int?
return 42;
@@ -116,9 +135,9 @@
}
return self::_#Extension|lateExtensionField2;
}
-static set Extension|lateExtensionField2(core::int? #t6) → void {
+static set Extension|lateExtensionField2(core::int? #t7) → void {
self::_#Extension|lateExtensionField2#isSet = true;
- self::_#Extension|lateExtensionField2 = #t6;
+ self::_#Extension|lateExtensionField2 = #t7;
}
static method Extension|staticMethod() → dynamic {
self::expect(42, self::Extension|lateExtensionField2);
@@ -133,7 +152,10 @@
self::Class::lateStaticField1 = 88;
self::expect(88, self::Class::lateStaticField1);
self::Class::staticMethod();
- new self::Class::•().{self::Class::instanceMethod}();
+ new self::Class::•<core::int?>(null).{self::Class::instanceMethod}(0);
+ new self::Class::•<core::int?>(0).{self::Class::instanceMethod}(null);
+ new self::Class::•<core::int>(null).{self::Class::instanceMethod}(0);
+ new self::Class::•<core::int>(0).{self::Class::instanceMethod}(null);
self::expect(87, self::Extension|lateExtensionField1);
self::Extension|lateExtensionField1 = 88;
self::expect(88, self::Extension|lateExtensionField1);
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart.strong.transformed.expect
index 9ee88bb..a90900a 100644
--- a/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart.strong.transformed.expect
@@ -2,15 +2,18 @@
import self as self;
import "dart:core" as core;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? _#lateStaticField1 = null;
static field core::bool _#lateStaticField1#isSet = false;
static field core::int? _#lateStaticField2 = null;
static field core::bool _#lateStaticField2#isSet = false;
field core::int? _#lateInstanceField = null;
field core::bool _#lateInstanceField#isSet = false;
- synthetic constructor •() → self::Class
- : super core::Object::•()
+ final field self::Class::T? field;
+ generic-covariant-impl field self::Class::T? _#lateGenericInstanceField = null;
+ field core::bool _#lateGenericInstanceField#isSet = false;
+ constructor •(self::Class::T? field) → self::Class<self::Class::T%>
+ : self::Class::field = field, super core::Object::•()
;
static method lateStaticField1Init() → core::int?
return 87;
@@ -56,13 +59,29 @@
this.{self::Class::_#lateInstanceField#isSet} = true;
this.{self::Class::_#lateInstanceField} = #t3;
}
- method instanceMethod() → dynamic {
+ method lateGenericInstanceFieldInit() → self::Class::T?
+ return this.{self::Class::field};
+ get lateGenericInstanceField() → self::Class::T? {
+ if(!this.{self::Class::_#lateGenericInstanceField#isSet}) {
+ this.{self::Class::_#lateGenericInstanceField#isSet} = true;
+ this.{self::Class::_#lateGenericInstanceField} = this.{self::Class::lateGenericInstanceFieldInit}();
+ }
+ return this.{self::Class::_#lateGenericInstanceField};
+ }
+ set lateGenericInstanceField(self::Class::T? #t4) → void {
+ this.{self::Class::_#lateGenericInstanceField#isSet} = true;
+ this.{self::Class::_#lateGenericInstanceField} = #t4;
+ }
+ method instanceMethod(generic-covariant-impl self::Class::T? value) → dynamic {
self::expect(16, this.{self::Class::lateInstanceField});
this.{self::Class::lateInstanceField} = 17;
self::expect(17, this.{self::Class::lateInstanceField});
+ self::expect(this.{self::Class::field}, this.{self::Class::lateGenericInstanceField});
+ this.{self::Class::lateGenericInstanceField} = value;
+ self::expect(value, this.{self::Class::lateGenericInstanceField});
}
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static method lateExtensionField1Init = self::Extension|lateExtensionField1Init;
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
static field lateExtensionField1 = self::_#Extension|lateExtensionField1#isSet;
@@ -90,9 +109,9 @@
}
return self::_#lateTopLevelField1;
}
-static set lateTopLevelField1(core::int? #t4) → void {
+static set lateTopLevelField1(core::int? #t5) → void {
self::_#lateTopLevelField1#isSet = true;
- self::_#lateTopLevelField1 = #t4;
+ self::_#lateTopLevelField1 = #t5;
}
static method Extension|lateExtensionField1Init() → core::int?
return 87;
@@ -103,9 +122,9 @@
}
return self::_#Extension|lateExtensionField1;
}
-static set Extension|lateExtensionField1(core::int? #t5) → void {
+static set Extension|lateExtensionField1(core::int? #t6) → void {
self::_#Extension|lateExtensionField1#isSet = true;
- self::_#Extension|lateExtensionField1 = #t5;
+ self::_#Extension|lateExtensionField1 = #t6;
}
static method Extension|lateExtensionField2Init() → core::int?
return 42;
@@ -116,9 +135,9 @@
}
return self::_#Extension|lateExtensionField2;
}
-static set Extension|lateExtensionField2(core::int? #t6) → void {
+static set Extension|lateExtensionField2(core::int? #t7) → void {
self::_#Extension|lateExtensionField2#isSet = true;
- self::_#Extension|lateExtensionField2 = #t6;
+ self::_#Extension|lateExtensionField2 = #t7;
}
static method Extension|staticMethod() → dynamic {
self::expect(42, self::Extension|lateExtensionField2);
@@ -133,7 +152,10 @@
self::Class::lateStaticField1 = 88;
self::expect(88, self::Class::lateStaticField1);
self::Class::staticMethod();
- new self::Class::•().{self::Class::instanceMethod}();
+ new self::Class::•<core::int?>(null).{self::Class::instanceMethod}(0);
+ new self::Class::•<core::int?>(0).{self::Class::instanceMethod}(null);
+ new self::Class::•<core::int>(null).{self::Class::instanceMethod}(0);
+ new self::Class::•<core::int>(0).{self::Class::instanceMethod}(null);
self::expect(87, self::Extension|lateExtensionField1);
self::Extension|lateExtensionField1 = 88;
self::expect(88, self::Extension|lateExtensionField1);
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart.weak.expect b/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart.weak.expect
index 9ee88bb..a90900a 100644
--- a/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart.weak.expect
@@ -2,15 +2,18 @@
import self as self;
import "dart:core" as core;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? _#lateStaticField1 = null;
static field core::bool _#lateStaticField1#isSet = false;
static field core::int? _#lateStaticField2 = null;
static field core::bool _#lateStaticField2#isSet = false;
field core::int? _#lateInstanceField = null;
field core::bool _#lateInstanceField#isSet = false;
- synthetic constructor •() → self::Class
- : super core::Object::•()
+ final field self::Class::T? field;
+ generic-covariant-impl field self::Class::T? _#lateGenericInstanceField = null;
+ field core::bool _#lateGenericInstanceField#isSet = false;
+ constructor •(self::Class::T? field) → self::Class<self::Class::T%>
+ : self::Class::field = field, super core::Object::•()
;
static method lateStaticField1Init() → core::int?
return 87;
@@ -56,13 +59,29 @@
this.{self::Class::_#lateInstanceField#isSet} = true;
this.{self::Class::_#lateInstanceField} = #t3;
}
- method instanceMethod() → dynamic {
+ method lateGenericInstanceFieldInit() → self::Class::T?
+ return this.{self::Class::field};
+ get lateGenericInstanceField() → self::Class::T? {
+ if(!this.{self::Class::_#lateGenericInstanceField#isSet}) {
+ this.{self::Class::_#lateGenericInstanceField#isSet} = true;
+ this.{self::Class::_#lateGenericInstanceField} = this.{self::Class::lateGenericInstanceFieldInit}();
+ }
+ return this.{self::Class::_#lateGenericInstanceField};
+ }
+ set lateGenericInstanceField(self::Class::T? #t4) → void {
+ this.{self::Class::_#lateGenericInstanceField#isSet} = true;
+ this.{self::Class::_#lateGenericInstanceField} = #t4;
+ }
+ method instanceMethod(generic-covariant-impl self::Class::T? value) → dynamic {
self::expect(16, this.{self::Class::lateInstanceField});
this.{self::Class::lateInstanceField} = 17;
self::expect(17, this.{self::Class::lateInstanceField});
+ self::expect(this.{self::Class::field}, this.{self::Class::lateGenericInstanceField});
+ this.{self::Class::lateGenericInstanceField} = value;
+ self::expect(value, this.{self::Class::lateGenericInstanceField});
}
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static method lateExtensionField1Init = self::Extension|lateExtensionField1Init;
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
static field lateExtensionField1 = self::_#Extension|lateExtensionField1#isSet;
@@ -90,9 +109,9 @@
}
return self::_#lateTopLevelField1;
}
-static set lateTopLevelField1(core::int? #t4) → void {
+static set lateTopLevelField1(core::int? #t5) → void {
self::_#lateTopLevelField1#isSet = true;
- self::_#lateTopLevelField1 = #t4;
+ self::_#lateTopLevelField1 = #t5;
}
static method Extension|lateExtensionField1Init() → core::int?
return 87;
@@ -103,9 +122,9 @@
}
return self::_#Extension|lateExtensionField1;
}
-static set Extension|lateExtensionField1(core::int? #t5) → void {
+static set Extension|lateExtensionField1(core::int? #t6) → void {
self::_#Extension|lateExtensionField1#isSet = true;
- self::_#Extension|lateExtensionField1 = #t5;
+ self::_#Extension|lateExtensionField1 = #t6;
}
static method Extension|lateExtensionField2Init() → core::int?
return 42;
@@ -116,9 +135,9 @@
}
return self::_#Extension|lateExtensionField2;
}
-static set Extension|lateExtensionField2(core::int? #t6) → void {
+static set Extension|lateExtensionField2(core::int? #t7) → void {
self::_#Extension|lateExtensionField2#isSet = true;
- self::_#Extension|lateExtensionField2 = #t6;
+ self::_#Extension|lateExtensionField2 = #t7;
}
static method Extension|staticMethod() → dynamic {
self::expect(42, self::Extension|lateExtensionField2);
@@ -133,7 +152,10 @@
self::Class::lateStaticField1 = 88;
self::expect(88, self::Class::lateStaticField1);
self::Class::staticMethod();
- new self::Class::•().{self::Class::instanceMethod}();
+ new self::Class::•<core::int?>(null).{self::Class::instanceMethod}(0);
+ new self::Class::•<core::int?>(0).{self::Class::instanceMethod}(null);
+ new self::Class::•<core::int>(null).{self::Class::instanceMethod}(0);
+ new self::Class::•<core::int>(0).{self::Class::instanceMethod}(null);
self::expect(87, self::Extension|lateExtensionField1);
self::Extension|lateExtensionField1 = 88;
self::expect(88, self::Extension|lateExtensionField1);
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart.weak.transformed.expect
index 9ee88bb..a90900a 100644
--- a/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart.weak.transformed.expect
@@ -2,15 +2,18 @@
import self as self;
import "dart:core" as core;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? _#lateStaticField1 = null;
static field core::bool _#lateStaticField1#isSet = false;
static field core::int? _#lateStaticField2 = null;
static field core::bool _#lateStaticField2#isSet = false;
field core::int? _#lateInstanceField = null;
field core::bool _#lateInstanceField#isSet = false;
- synthetic constructor •() → self::Class
- : super core::Object::•()
+ final field self::Class::T? field;
+ generic-covariant-impl field self::Class::T? _#lateGenericInstanceField = null;
+ field core::bool _#lateGenericInstanceField#isSet = false;
+ constructor •(self::Class::T? field) → self::Class<self::Class::T%>
+ : self::Class::field = field, super core::Object::•()
;
static method lateStaticField1Init() → core::int?
return 87;
@@ -56,13 +59,29 @@
this.{self::Class::_#lateInstanceField#isSet} = true;
this.{self::Class::_#lateInstanceField} = #t3;
}
- method instanceMethod() → dynamic {
+ method lateGenericInstanceFieldInit() → self::Class::T?
+ return this.{self::Class::field};
+ get lateGenericInstanceField() → self::Class::T? {
+ if(!this.{self::Class::_#lateGenericInstanceField#isSet}) {
+ this.{self::Class::_#lateGenericInstanceField#isSet} = true;
+ this.{self::Class::_#lateGenericInstanceField} = this.{self::Class::lateGenericInstanceFieldInit}();
+ }
+ return this.{self::Class::_#lateGenericInstanceField};
+ }
+ set lateGenericInstanceField(self::Class::T? #t4) → void {
+ this.{self::Class::_#lateGenericInstanceField#isSet} = true;
+ this.{self::Class::_#lateGenericInstanceField} = #t4;
+ }
+ method instanceMethod(generic-covariant-impl self::Class::T? value) → dynamic {
self::expect(16, this.{self::Class::lateInstanceField});
this.{self::Class::lateInstanceField} = 17;
self::expect(17, this.{self::Class::lateInstanceField});
+ self::expect(this.{self::Class::field}, this.{self::Class::lateGenericInstanceField});
+ this.{self::Class::lateGenericInstanceField} = value;
+ self::expect(value, this.{self::Class::lateGenericInstanceField});
}
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static method lateExtensionField1Init = self::Extension|lateExtensionField1Init;
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
static field lateExtensionField1 = self::_#Extension|lateExtensionField1#isSet;
@@ -90,9 +109,9 @@
}
return self::_#lateTopLevelField1;
}
-static set lateTopLevelField1(core::int? #t4) → void {
+static set lateTopLevelField1(core::int? #t5) → void {
self::_#lateTopLevelField1#isSet = true;
- self::_#lateTopLevelField1 = #t4;
+ self::_#lateTopLevelField1 = #t5;
}
static method Extension|lateExtensionField1Init() → core::int?
return 87;
@@ -103,9 +122,9 @@
}
return self::_#Extension|lateExtensionField1;
}
-static set Extension|lateExtensionField1(core::int? #t5) → void {
+static set Extension|lateExtensionField1(core::int? #t6) → void {
self::_#Extension|lateExtensionField1#isSet = true;
- self::_#Extension|lateExtensionField1 = #t5;
+ self::_#Extension|lateExtensionField1 = #t6;
}
static method Extension|lateExtensionField2Init() → core::int?
return 42;
@@ -116,9 +135,9 @@
}
return self::_#Extension|lateExtensionField2;
}
-static set Extension|lateExtensionField2(core::int? #t6) → void {
+static set Extension|lateExtensionField2(core::int? #t7) → void {
self::_#Extension|lateExtensionField2#isSet = true;
- self::_#Extension|lateExtensionField2 = #t6;
+ self::_#Extension|lateExtensionField2 = #t7;
}
static method Extension|staticMethod() → dynamic {
self::expect(42, self::Extension|lateExtensionField2);
@@ -133,7 +152,10 @@
self::Class::lateStaticField1 = 88;
self::expect(88, self::Class::lateStaticField1);
self::Class::staticMethod();
- new self::Class::•().{self::Class::instanceMethod}();
+ new self::Class::•<core::int?>(null).{self::Class::instanceMethod}(0);
+ new self::Class::•<core::int?>(0).{self::Class::instanceMethod}(null);
+ new self::Class::•<core::int>(null).{self::Class::instanceMethod}(0);
+ new self::Class::•<core::int>(0).{self::Class::instanceMethod}(null);
self::expect(87, self::Extension|lateExtensionField1);
self::Extension|lateExtensionField1 = 88;
self::expect(88, self::Extension|lateExtensionField1);
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart b/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart
index d036884..0d7df55 100644
--- a/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart
@@ -4,7 +4,7 @@
late int? lateTopLevelField;
-class Class {
+class Class<T> {
static late int? lateStaticField1;
static late int? lateStaticField2;
@@ -17,15 +17,22 @@
late int? lateInstanceField;
- instanceMethod() {
+ late T? lateGenericInstanceField;
+
+ instanceMethod(T? value) {
throws(() => lateInstanceField,
'Read value from uninitialized Class.lateInstanceField');
lateInstanceField = 16;
expect(16, lateInstanceField);
+
+ throws(() => lateGenericInstanceField,
+ 'Read value from uninitialized Class.lateGenericInstanceField');
+ lateGenericInstanceField = value;
+ expect(value, lateGenericInstanceField);
}
}
-extension Extension on Class {
+extension Extension<T> on Class<T> {
static late int? lateExtensionField1;
static late int? lateExtensionField2;
@@ -56,6 +63,11 @@
expect(87, Extension.lateExtensionField1);
Extension.staticMethod();
+
+ new Class<int?>().instanceMethod(null);
+ new Class<int?>().instanceMethod(0);
+ new Class<int>().instanceMethod(null);
+ new Class<int>().instanceMethod(0);
}
expect(expected, actual) {
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart.outline.expect b/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart.outline.expect
index bc1aaf1..9d6eba5 100644
--- a/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart.outline.expect
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart.outline.expect
@@ -2,14 +2,16 @@
import self as self;
import "dart:core" as core;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? _#lateStaticField1;
static field core::bool _#lateStaticField1#isSet;
static field core::int? _#lateStaticField2;
static field core::bool _#lateStaticField2#isSet;
field core::int? _#lateInstanceField;
field core::bool _#lateInstanceField#isSet;
- synthetic constructor •() → self::Class
+ generic-covariant-impl field self::Class::T? _#lateGenericInstanceField;
+ field core::bool _#lateGenericInstanceField#isSet;
+ synthetic constructor •() → self::Class<self::Class::T%>
;
static get lateStaticField1() → core::int?;
static set lateStaticField1(core::int? #t1) → void;
@@ -19,10 +21,12 @@
;
get lateInstanceField() → core::int?;
set lateInstanceField(core::int? #t3) → void;
- method instanceMethod() → dynamic
+ get lateGenericInstanceField() → self::Class::T?;
+ set lateGenericInstanceField(self::Class::T? #t4) → void;
+ method instanceMethod(generic-covariant-impl self::Class::T? value) → dynamic
;
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
static field lateExtensionField1 = self::_#Extension|lateExtensionField1#isSet;
static get lateExtensionField1 = get self::Extension|lateExtensionField1;
@@ -40,11 +44,11 @@
static field core::int? _#Extension|lateExtensionField2;
static field core::bool _#Extension|lateExtensionField2#isSet;
static get lateTopLevelField() → core::int?;
-static set lateTopLevelField(core::int? #t4) → void;
+static set lateTopLevelField(core::int? #t5) → void;
static get Extension|lateExtensionField1() → core::int?;
-static set Extension|lateExtensionField1(core::int? #t5) → void;
+static set Extension|lateExtensionField1(core::int? #t6) → void;
static get Extension|lateExtensionField2() → core::int?;
-static set Extension|lateExtensionField2(core::int? #t6) → void;
+static set Extension|lateExtensionField2(core::int? #t7) → void;
static method Extension|staticMethod() → dynamic
;
static method main() → dynamic
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart.strong.expect
index e5753c8..95cb961 100644
--- a/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart.strong.expect
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart.strong.expect
@@ -3,14 +3,16 @@
import "dart:core" as core;
import "dart:_internal" as _in;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? _#lateStaticField1 = null;
static field core::bool _#lateStaticField1#isSet = false;
static field core::int? _#lateStaticField2 = null;
static field core::bool _#lateStaticField2#isSet = false;
field core::int? _#lateInstanceField = null;
field core::bool _#lateInstanceField#isSet = false;
- synthetic constructor •() → self::Class
+ generic-covariant-impl field self::Class::T? _#lateGenericInstanceField = null;
+ field core::bool _#lateGenericInstanceField#isSet = false;
+ synthetic constructor •() → self::Class<self::Class::T%>
: super core::Object::•()
;
static get lateStaticField1() → core::int?
@@ -36,13 +38,22 @@
this.{self::Class::_#lateInstanceField#isSet} = true;
this.{self::Class::_#lateInstanceField} = #t3;
}
- method instanceMethod() → dynamic {
+ get lateGenericInstanceField() → self::Class::T?
+ return this.{self::Class::_#lateGenericInstanceField#isSet} ?{self::Class::T?} this.{self::Class::_#lateGenericInstanceField} : throw new _in::LateInitializationErrorImpl::•("Field 'lateGenericInstanceField' has not been initialized.");
+ set lateGenericInstanceField(self::Class::T? #t4) → void {
+ this.{self::Class::_#lateGenericInstanceField#isSet} = true;
+ this.{self::Class::_#lateGenericInstanceField} = #t4;
+ }
+ method instanceMethod(generic-covariant-impl self::Class::T? value) → dynamic {
self::throws(() → core::int? => this.{self::Class::lateInstanceField}, "Read value from uninitialized Class.lateInstanceField");
this.{self::Class::lateInstanceField} = 16;
self::expect(16, this.{self::Class::lateInstanceField});
+ self::throws(() → self::Class::T? => this.{self::Class::lateGenericInstanceField}, "Read value from uninitialized Class.lateGenericInstanceField");
+ this.{self::Class::lateGenericInstanceField} = value;
+ self::expect(value, this.{self::Class::lateGenericInstanceField});
}
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
static field lateExtensionField1 = self::_#Extension|lateExtensionField1#isSet;
static get lateExtensionField1 = get self::Extension|lateExtensionField1;
@@ -61,21 +72,21 @@
static field core::bool _#Extension|lateExtensionField2#isSet = false;
static get lateTopLevelField() → core::int?
return self::_#lateTopLevelField#isSet ?{core::int?} self::_#lateTopLevelField : throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField' has not been initialized.");
-static set lateTopLevelField(core::int? #t4) → void {
+static set lateTopLevelField(core::int? #t5) → void {
self::_#lateTopLevelField#isSet = true;
- self::_#lateTopLevelField = #t4;
+ self::_#lateTopLevelField = #t5;
}
static get Extension|lateExtensionField1() → core::int?
return self::_#Extension|lateExtensionField1#isSet ?{core::int?} self::_#Extension|lateExtensionField1 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has not been initialized.");
-static set Extension|lateExtensionField1(core::int? #t5) → void {
+static set Extension|lateExtensionField1(core::int? #t6) → void {
self::_#Extension|lateExtensionField1#isSet = true;
- self::_#Extension|lateExtensionField1 = #t5;
+ self::_#Extension|lateExtensionField1 = #t6;
}
static get Extension|lateExtensionField2() → core::int?
return self::_#Extension|lateExtensionField2#isSet ?{core::int?} self::_#Extension|lateExtensionField2 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has not been initialized.");
-static set Extension|lateExtensionField2(core::int? #t6) → void {
+static set Extension|lateExtensionField2(core::int? #t7) → void {
self::_#Extension|lateExtensionField2#isSet = true;
- self::_#Extension|lateExtensionField2 = #t6;
+ self::_#Extension|lateExtensionField2 = #t7;
}
static method Extension|staticMethod() → dynamic {
self::throws(() → core::int? => self::Extension|lateExtensionField2, "Read value from uninitialized Class.lateExtensionField2");
@@ -94,6 +105,10 @@
self::Extension|lateExtensionField1 = 87;
self::expect(87, self::Extension|lateExtensionField1);
self::Extension|staticMethod();
+ new self::Class::•<core::int?>().{self::Class::instanceMethod}(null);
+ new self::Class::•<core::int?>().{self::Class::instanceMethod}(0);
+ new self::Class::•<core::int>().{self::Class::instanceMethod}(null);
+ new self::Class::•<core::int>().{self::Class::instanceMethod}(0);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart.strong.transformed.expect
index e5753c8..95cb961 100644
--- a/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart.strong.transformed.expect
@@ -3,14 +3,16 @@
import "dart:core" as core;
import "dart:_internal" as _in;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? _#lateStaticField1 = null;
static field core::bool _#lateStaticField1#isSet = false;
static field core::int? _#lateStaticField2 = null;
static field core::bool _#lateStaticField2#isSet = false;
field core::int? _#lateInstanceField = null;
field core::bool _#lateInstanceField#isSet = false;
- synthetic constructor •() → self::Class
+ generic-covariant-impl field self::Class::T? _#lateGenericInstanceField = null;
+ field core::bool _#lateGenericInstanceField#isSet = false;
+ synthetic constructor •() → self::Class<self::Class::T%>
: super core::Object::•()
;
static get lateStaticField1() → core::int?
@@ -36,13 +38,22 @@
this.{self::Class::_#lateInstanceField#isSet} = true;
this.{self::Class::_#lateInstanceField} = #t3;
}
- method instanceMethod() → dynamic {
+ get lateGenericInstanceField() → self::Class::T?
+ return this.{self::Class::_#lateGenericInstanceField#isSet} ?{self::Class::T?} this.{self::Class::_#lateGenericInstanceField} : throw new _in::LateInitializationErrorImpl::•("Field 'lateGenericInstanceField' has not been initialized.");
+ set lateGenericInstanceField(self::Class::T? #t4) → void {
+ this.{self::Class::_#lateGenericInstanceField#isSet} = true;
+ this.{self::Class::_#lateGenericInstanceField} = #t4;
+ }
+ method instanceMethod(generic-covariant-impl self::Class::T? value) → dynamic {
self::throws(() → core::int? => this.{self::Class::lateInstanceField}, "Read value from uninitialized Class.lateInstanceField");
this.{self::Class::lateInstanceField} = 16;
self::expect(16, this.{self::Class::lateInstanceField});
+ self::throws(() → self::Class::T? => this.{self::Class::lateGenericInstanceField}, "Read value from uninitialized Class.lateGenericInstanceField");
+ this.{self::Class::lateGenericInstanceField} = value;
+ self::expect(value, this.{self::Class::lateGenericInstanceField});
}
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
static field lateExtensionField1 = self::_#Extension|lateExtensionField1#isSet;
static get lateExtensionField1 = get self::Extension|lateExtensionField1;
@@ -61,21 +72,21 @@
static field core::bool _#Extension|lateExtensionField2#isSet = false;
static get lateTopLevelField() → core::int?
return self::_#lateTopLevelField#isSet ?{core::int?} self::_#lateTopLevelField : throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField' has not been initialized.");
-static set lateTopLevelField(core::int? #t4) → void {
+static set lateTopLevelField(core::int? #t5) → void {
self::_#lateTopLevelField#isSet = true;
- self::_#lateTopLevelField = #t4;
+ self::_#lateTopLevelField = #t5;
}
static get Extension|lateExtensionField1() → core::int?
return self::_#Extension|lateExtensionField1#isSet ?{core::int?} self::_#Extension|lateExtensionField1 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has not been initialized.");
-static set Extension|lateExtensionField1(core::int? #t5) → void {
+static set Extension|lateExtensionField1(core::int? #t6) → void {
self::_#Extension|lateExtensionField1#isSet = true;
- self::_#Extension|lateExtensionField1 = #t5;
+ self::_#Extension|lateExtensionField1 = #t6;
}
static get Extension|lateExtensionField2() → core::int?
return self::_#Extension|lateExtensionField2#isSet ?{core::int?} self::_#Extension|lateExtensionField2 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has not been initialized.");
-static set Extension|lateExtensionField2(core::int? #t6) → void {
+static set Extension|lateExtensionField2(core::int? #t7) → void {
self::_#Extension|lateExtensionField2#isSet = true;
- self::_#Extension|lateExtensionField2 = #t6;
+ self::_#Extension|lateExtensionField2 = #t7;
}
static method Extension|staticMethod() → dynamic {
self::throws(() → core::int? => self::Extension|lateExtensionField2, "Read value from uninitialized Class.lateExtensionField2");
@@ -94,6 +105,10 @@
self::Extension|lateExtensionField1 = 87;
self::expect(87, self::Extension|lateExtensionField1);
self::Extension|staticMethod();
+ new self::Class::•<core::int?>().{self::Class::instanceMethod}(null);
+ new self::Class::•<core::int?>().{self::Class::instanceMethod}(0);
+ new self::Class::•<core::int>().{self::Class::instanceMethod}(null);
+ new self::Class::•<core::int>().{self::Class::instanceMethod}(0);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart.weak.expect b/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart.weak.expect
index e5753c8..95cb961 100644
--- a/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart.weak.expect
@@ -3,14 +3,16 @@
import "dart:core" as core;
import "dart:_internal" as _in;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? _#lateStaticField1 = null;
static field core::bool _#lateStaticField1#isSet = false;
static field core::int? _#lateStaticField2 = null;
static field core::bool _#lateStaticField2#isSet = false;
field core::int? _#lateInstanceField = null;
field core::bool _#lateInstanceField#isSet = false;
- synthetic constructor •() → self::Class
+ generic-covariant-impl field self::Class::T? _#lateGenericInstanceField = null;
+ field core::bool _#lateGenericInstanceField#isSet = false;
+ synthetic constructor •() → self::Class<self::Class::T%>
: super core::Object::•()
;
static get lateStaticField1() → core::int?
@@ -36,13 +38,22 @@
this.{self::Class::_#lateInstanceField#isSet} = true;
this.{self::Class::_#lateInstanceField} = #t3;
}
- method instanceMethod() → dynamic {
+ get lateGenericInstanceField() → self::Class::T?
+ return this.{self::Class::_#lateGenericInstanceField#isSet} ?{self::Class::T?} this.{self::Class::_#lateGenericInstanceField} : throw new _in::LateInitializationErrorImpl::•("Field 'lateGenericInstanceField' has not been initialized.");
+ set lateGenericInstanceField(self::Class::T? #t4) → void {
+ this.{self::Class::_#lateGenericInstanceField#isSet} = true;
+ this.{self::Class::_#lateGenericInstanceField} = #t4;
+ }
+ method instanceMethod(generic-covariant-impl self::Class::T? value) → dynamic {
self::throws(() → core::int? => this.{self::Class::lateInstanceField}, "Read value from uninitialized Class.lateInstanceField");
this.{self::Class::lateInstanceField} = 16;
self::expect(16, this.{self::Class::lateInstanceField});
+ self::throws(() → self::Class::T? => this.{self::Class::lateGenericInstanceField}, "Read value from uninitialized Class.lateGenericInstanceField");
+ this.{self::Class::lateGenericInstanceField} = value;
+ self::expect(value, this.{self::Class::lateGenericInstanceField});
}
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
static field lateExtensionField1 = self::_#Extension|lateExtensionField1#isSet;
static get lateExtensionField1 = get self::Extension|lateExtensionField1;
@@ -61,21 +72,21 @@
static field core::bool _#Extension|lateExtensionField2#isSet = false;
static get lateTopLevelField() → core::int?
return self::_#lateTopLevelField#isSet ?{core::int?} self::_#lateTopLevelField : throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField' has not been initialized.");
-static set lateTopLevelField(core::int? #t4) → void {
+static set lateTopLevelField(core::int? #t5) → void {
self::_#lateTopLevelField#isSet = true;
- self::_#lateTopLevelField = #t4;
+ self::_#lateTopLevelField = #t5;
}
static get Extension|lateExtensionField1() → core::int?
return self::_#Extension|lateExtensionField1#isSet ?{core::int?} self::_#Extension|lateExtensionField1 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has not been initialized.");
-static set Extension|lateExtensionField1(core::int? #t5) → void {
+static set Extension|lateExtensionField1(core::int? #t6) → void {
self::_#Extension|lateExtensionField1#isSet = true;
- self::_#Extension|lateExtensionField1 = #t5;
+ self::_#Extension|lateExtensionField1 = #t6;
}
static get Extension|lateExtensionField2() → core::int?
return self::_#Extension|lateExtensionField2#isSet ?{core::int?} self::_#Extension|lateExtensionField2 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has not been initialized.");
-static set Extension|lateExtensionField2(core::int? #t6) → void {
+static set Extension|lateExtensionField2(core::int? #t7) → void {
self::_#Extension|lateExtensionField2#isSet = true;
- self::_#Extension|lateExtensionField2 = #t6;
+ self::_#Extension|lateExtensionField2 = #t7;
}
static method Extension|staticMethod() → dynamic {
self::throws(() → core::int? => self::Extension|lateExtensionField2, "Read value from uninitialized Class.lateExtensionField2");
@@ -94,6 +105,10 @@
self::Extension|lateExtensionField1 = 87;
self::expect(87, self::Extension|lateExtensionField1);
self::Extension|staticMethod();
+ new self::Class::•<core::int?>().{self::Class::instanceMethod}(null);
+ new self::Class::•<core::int?>().{self::Class::instanceMethod}(0);
+ new self::Class::•<core::int>().{self::Class::instanceMethod}(null);
+ new self::Class::•<core::int>().{self::Class::instanceMethod}(0);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart.weak.transformed.expect
index e5753c8..95cb961 100644
--- a/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart.weak.transformed.expect
@@ -3,14 +3,16 @@
import "dart:core" as core;
import "dart:_internal" as _in;
-class Class extends core::Object {
+class Class<T extends core::Object? = dynamic> extends core::Object {
static field core::int? _#lateStaticField1 = null;
static field core::bool _#lateStaticField1#isSet = false;
static field core::int? _#lateStaticField2 = null;
static field core::bool _#lateStaticField2#isSet = false;
field core::int? _#lateInstanceField = null;
field core::bool _#lateInstanceField#isSet = false;
- synthetic constructor •() → self::Class
+ generic-covariant-impl field self::Class::T? _#lateGenericInstanceField = null;
+ field core::bool _#lateGenericInstanceField#isSet = false;
+ synthetic constructor •() → self::Class<self::Class::T%>
: super core::Object::•()
;
static get lateStaticField1() → core::int?
@@ -36,13 +38,22 @@
this.{self::Class::_#lateInstanceField#isSet} = true;
this.{self::Class::_#lateInstanceField} = #t3;
}
- method instanceMethod() → dynamic {
+ get lateGenericInstanceField() → self::Class::T?
+ return this.{self::Class::_#lateGenericInstanceField#isSet} ?{self::Class::T?} this.{self::Class::_#lateGenericInstanceField} : throw new _in::LateInitializationErrorImpl::•("Field 'lateGenericInstanceField' has not been initialized.");
+ set lateGenericInstanceField(self::Class::T? #t4) → void {
+ this.{self::Class::_#lateGenericInstanceField#isSet} = true;
+ this.{self::Class::_#lateGenericInstanceField} = #t4;
+ }
+ method instanceMethod(generic-covariant-impl self::Class::T? value) → dynamic {
self::throws(() → core::int? => this.{self::Class::lateInstanceField}, "Read value from uninitialized Class.lateInstanceField");
this.{self::Class::lateInstanceField} = 16;
self::expect(16, this.{self::Class::lateInstanceField});
+ self::throws(() → self::Class::T? => this.{self::Class::lateGenericInstanceField}, "Read value from uninitialized Class.lateGenericInstanceField");
+ this.{self::Class::lateGenericInstanceField} = value;
+ self::expect(value, this.{self::Class::lateGenericInstanceField});
}
}
-extension Extension on self::Class {
+extension Extension<T extends core::Object? = dynamic> on self::Class<T%> {
static field lateExtensionField1 = self::_#Extension|lateExtensionField1;
static field lateExtensionField1 = self::_#Extension|lateExtensionField1#isSet;
static get lateExtensionField1 = get self::Extension|lateExtensionField1;
@@ -61,21 +72,21 @@
static field core::bool _#Extension|lateExtensionField2#isSet = false;
static get lateTopLevelField() → core::int?
return self::_#lateTopLevelField#isSet ?{core::int?} self::_#lateTopLevelField : throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField' has not been initialized.");
-static set lateTopLevelField(core::int? #t4) → void {
+static set lateTopLevelField(core::int? #t5) → void {
self::_#lateTopLevelField#isSet = true;
- self::_#lateTopLevelField = #t4;
+ self::_#lateTopLevelField = #t5;
}
static get Extension|lateExtensionField1() → core::int?
return self::_#Extension|lateExtensionField1#isSet ?{core::int?} self::_#Extension|lateExtensionField1 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has not been initialized.");
-static set Extension|lateExtensionField1(core::int? #t5) → void {
+static set Extension|lateExtensionField1(core::int? #t6) → void {
self::_#Extension|lateExtensionField1#isSet = true;
- self::_#Extension|lateExtensionField1 = #t5;
+ self::_#Extension|lateExtensionField1 = #t6;
}
static get Extension|lateExtensionField2() → core::int?
return self::_#Extension|lateExtensionField2#isSet ?{core::int?} self::_#Extension|lateExtensionField2 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has not been initialized.");
-static set Extension|lateExtensionField2(core::int? #t6) → void {
+static set Extension|lateExtensionField2(core::int? #t7) → void {
self::_#Extension|lateExtensionField2#isSet = true;
- self::_#Extension|lateExtensionField2 = #t6;
+ self::_#Extension|lateExtensionField2 = #t7;
}
static method Extension|staticMethod() → dynamic {
self::throws(() → core::int? => self::Extension|lateExtensionField2, "Read value from uninitialized Class.lateExtensionField2");
@@ -94,6 +105,10 @@
self::Extension|lateExtensionField1 = 87;
self::expect(87, self::Extension|lateExtensionField1);
self::Extension|staticMethod();
+ new self::Class::•<core::int?>().{self::Class::instanceMethod}(null);
+ new self::Class::•<core::int?>().{self::Class::instanceMethod}(0);
+ new self::Class::•<core::int>().{self::Class::instanceMethod}(null);
+ new self::Class::•<core::int>().{self::Class::instanceMethod}(0);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart b/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart
index a59e3f2..93ce4fa 100644
--- a/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart
@@ -10,6 +10,19 @@
expect(123, lateLocal);
expect(124, lateLocal = 124);
expect(124, lateLocal);
+
+ local<T>(T? value1, T? value2) {
+ late T? lateGenericLocal = value1;
+
+ expect(value1, lateGenericLocal);
+ expect(value2, lateGenericLocal = value2);
+ expect(value2, lateGenericLocal);
+ }
+
+ local<int?>(null, 0);
+ local<int?>(0, null);
+ local<int>(null, 0);
+ local<int>(0, null);
}
expect(expected, actual) {
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart.strong.expect
index 850613c..9363ab8 100644
--- a/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart.strong.expect
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart.strong.expect
@@ -21,6 +21,28 @@
self::expect(123, #lateLocal#get.call());
self::expect(124, #lateLocal#set.call(124));
self::expect(124, #lateLocal#get.call());
+ function local<T extends core::Object? = dynamic>(T? value1, T? value2) → core::Null? {
+ T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T? {
+ if(!#lateGenericLocal#isSet) {
+ #lateGenericLocal#isSet = true;
+ lateGenericLocal = value1;
+ }
+ return lateGenericLocal;
+ }
+ function #lateGenericLocal#set(T? #t2) → dynamic {
+ #lateGenericLocal#isSet = true;
+ return lateGenericLocal = #t2;
+ }
+ self::expect(value1, #lateGenericLocal#get.call());
+ self::expect(value2, #lateGenericLocal#set.call(value2));
+ self::expect(value2, #lateGenericLocal#get.call());
+ }
+ local.call<core::int?>(null, 0);
+ local.call<core::int?>(0, null);
+ local.call<core::int>(null, 0);
+ local.call<core::int>(0, null);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart.strong.transformed.expect
index 850613c..9363ab8 100644
--- a/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart.strong.transformed.expect
@@ -21,6 +21,28 @@
self::expect(123, #lateLocal#get.call());
self::expect(124, #lateLocal#set.call(124));
self::expect(124, #lateLocal#get.call());
+ function local<T extends core::Object? = dynamic>(T? value1, T? value2) → core::Null? {
+ T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T? {
+ if(!#lateGenericLocal#isSet) {
+ #lateGenericLocal#isSet = true;
+ lateGenericLocal = value1;
+ }
+ return lateGenericLocal;
+ }
+ function #lateGenericLocal#set(T? #t2) → dynamic {
+ #lateGenericLocal#isSet = true;
+ return lateGenericLocal = #t2;
+ }
+ self::expect(value1, #lateGenericLocal#get.call());
+ self::expect(value2, #lateGenericLocal#set.call(value2));
+ self::expect(value2, #lateGenericLocal#get.call());
+ }
+ local.call<core::int?>(null, 0);
+ local.call<core::int?>(0, null);
+ local.call<core::int>(null, 0);
+ local.call<core::int>(0, null);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart.weak.expect b/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart.weak.expect
index 850613c..9363ab8 100644
--- a/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart.weak.expect
@@ -21,6 +21,28 @@
self::expect(123, #lateLocal#get.call());
self::expect(124, #lateLocal#set.call(124));
self::expect(124, #lateLocal#get.call());
+ function local<T extends core::Object? = dynamic>(T? value1, T? value2) → core::Null? {
+ T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T? {
+ if(!#lateGenericLocal#isSet) {
+ #lateGenericLocal#isSet = true;
+ lateGenericLocal = value1;
+ }
+ return lateGenericLocal;
+ }
+ function #lateGenericLocal#set(T? #t2) → dynamic {
+ #lateGenericLocal#isSet = true;
+ return lateGenericLocal = #t2;
+ }
+ self::expect(value1, #lateGenericLocal#get.call());
+ self::expect(value2, #lateGenericLocal#set.call(value2));
+ self::expect(value2, #lateGenericLocal#get.call());
+ }
+ local.call<core::int?>(null, 0);
+ local.call<core::int?>(0, null);
+ local.call<core::int>(null, 0);
+ local.call<core::int>(0, null);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart.weak.transformed.expect
index 850613c..9363ab8 100644
--- a/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart.weak.transformed.expect
@@ -21,6 +21,28 @@
self::expect(123, #lateLocal#get.call());
self::expect(124, #lateLocal#set.call(124));
self::expect(124, #lateLocal#get.call());
+ function local<T extends core::Object? = dynamic>(T? value1, T? value2) → core::Null? {
+ T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T? {
+ if(!#lateGenericLocal#isSet) {
+ #lateGenericLocal#isSet = true;
+ lateGenericLocal = value1;
+ }
+ return lateGenericLocal;
+ }
+ function #lateGenericLocal#set(T? #t2) → dynamic {
+ #lateGenericLocal#isSet = true;
+ return lateGenericLocal = #t2;
+ }
+ self::expect(value1, #lateGenericLocal#get.call());
+ self::expect(value2, #lateGenericLocal#set.call(value2));
+ self::expect(value2, #lateGenericLocal#get.call());
+ }
+ local.call<core::int?>(null, 0);
+ local.call<core::int?>(0, null);
+ local.call<core::int>(null, 0);
+ local.call<core::int>(0, null);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart b/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart
index d23214d..70b36f7 100644
--- a/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart
@@ -7,6 +7,19 @@
throws(() => lateLocal, 'Read value from uninitialized lateLocal');
expect(123, lateLocal = 123);
expect(123, lateLocal);
+
+ local<T>(T? value) {
+ late T? lateGenericLocal;
+ throws(() => lateGenericLocal,
+ 'Read value from uninitialized lateGenericLocal');
+ expect(value, lateGenericLocal = value);
+ expect(value, lateGenericLocal);
+ }
+
+ local<int?>(null);
+ local<int?>(0);
+ local<int>(null);
+ local<int>(0);
}
expect(expected, actual) {
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart.strong.expect
index 1ce4c50..29c9282 100644
--- a/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart.strong.expect
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart.strong.expect
@@ -15,6 +15,23 @@
self::throws(() → core::int? => #lateLocal#get.call(), "Read value from uninitialized lateLocal");
self::expect(123, #lateLocal#set.call(123));
self::expect(123, #lateLocal#get.call());
+ function local<T extends core::Object? = dynamic>(T? value) → core::Null? {
+ T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T?
+ return #lateGenericLocal#isSet ?{T?} lateGenericLocal : throw new _in::LateInitializationErrorImpl::•("Local 'lateGenericLocal' has not been initialized.");
+ function #lateGenericLocal#set(T? #t2) → dynamic {
+ #lateGenericLocal#isSet = true;
+ return lateGenericLocal = #t2;
+ }
+ self::throws(() → T? => #lateGenericLocal#get.call(), "Read value from uninitialized lateGenericLocal");
+ self::expect(value, #lateGenericLocal#set.call(value));
+ self::expect(value, #lateGenericLocal#get.call());
+ }
+ local.call<core::int?>(null);
+ local.call<core::int?>(0);
+ local.call<core::int>(null);
+ local.call<core::int>(0);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart.strong.transformed.expect
index 1ce4c50..29c9282 100644
--- a/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart.strong.transformed.expect
@@ -15,6 +15,23 @@
self::throws(() → core::int? => #lateLocal#get.call(), "Read value from uninitialized lateLocal");
self::expect(123, #lateLocal#set.call(123));
self::expect(123, #lateLocal#get.call());
+ function local<T extends core::Object? = dynamic>(T? value) → core::Null? {
+ T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T?
+ return #lateGenericLocal#isSet ?{T?} lateGenericLocal : throw new _in::LateInitializationErrorImpl::•("Local 'lateGenericLocal' has not been initialized.");
+ function #lateGenericLocal#set(T? #t2) → dynamic {
+ #lateGenericLocal#isSet = true;
+ return lateGenericLocal = #t2;
+ }
+ self::throws(() → T? => #lateGenericLocal#get.call(), "Read value from uninitialized lateGenericLocal");
+ self::expect(value, #lateGenericLocal#set.call(value));
+ self::expect(value, #lateGenericLocal#get.call());
+ }
+ local.call<core::int?>(null);
+ local.call<core::int?>(0);
+ local.call<core::int>(null);
+ local.call<core::int>(0);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart.weak.expect b/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart.weak.expect
index 1ce4c50..29c9282 100644
--- a/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart.weak.expect
@@ -15,6 +15,23 @@
self::throws(() → core::int? => #lateLocal#get.call(), "Read value from uninitialized lateLocal");
self::expect(123, #lateLocal#set.call(123));
self::expect(123, #lateLocal#get.call());
+ function local<T extends core::Object? = dynamic>(T? value) → core::Null? {
+ T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T?
+ return #lateGenericLocal#isSet ?{T?} lateGenericLocal : throw new _in::LateInitializationErrorImpl::•("Local 'lateGenericLocal' has not been initialized.");
+ function #lateGenericLocal#set(T? #t2) → dynamic {
+ #lateGenericLocal#isSet = true;
+ return lateGenericLocal = #t2;
+ }
+ self::throws(() → T? => #lateGenericLocal#get.call(), "Read value from uninitialized lateGenericLocal");
+ self::expect(value, #lateGenericLocal#set.call(value));
+ self::expect(value, #lateGenericLocal#get.call());
+ }
+ local.call<core::int?>(null);
+ local.call<core::int?>(0);
+ local.call<core::int>(null);
+ local.call<core::int>(0);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart.weak.transformed.expect
index 1ce4c50..29c9282 100644
--- a/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart.weak.transformed.expect
@@ -15,6 +15,23 @@
self::throws(() → core::int? => #lateLocal#get.call(), "Read value from uninitialized lateLocal");
self::expect(123, #lateLocal#set.call(123));
self::expect(123, #lateLocal#get.call());
+ function local<T extends core::Object? = dynamic>(T? value) → core::Null? {
+ T? lateGenericLocal;
+ core::bool #lateGenericLocal#isSet = false;
+ function #lateGenericLocal#get() → T?
+ return #lateGenericLocal#isSet ?{T?} lateGenericLocal : throw new _in::LateInitializationErrorImpl::•("Local 'lateGenericLocal' has not been initialized.");
+ function #lateGenericLocal#set(T? #t2) → dynamic {
+ #lateGenericLocal#isSet = true;
+ return lateGenericLocal = #t2;
+ }
+ self::throws(() → T? => #lateGenericLocal#get.call(), "Read value from uninitialized lateGenericLocal");
+ self::expect(value, #lateGenericLocal#set.call(value));
+ self::expect(value, #lateGenericLocal#get.call());
+ }
+ local.call<core::int?>(null);
+ local.call<core::int?>(0);
+ local.call<core::int>(null);
+ local.call<core::int>(0);
}
static method expect(dynamic expected, dynamic actual) → dynamic {
if(!expected.{core::Object::==}(actual))
diff --git a/pkg/front_end/testcases/nnbd/definite_assignment_and_completion.dart b/pkg/front_end/testcases/nnbd/definite_assignment_and_completion.dart
new file mode 100644
index 0000000..3114c78
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/definite_assignment_and_completion.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This test checks for compile-time errors related to definite assignment and
+// completion.
+
+int foo() {
+ int x;
+ return x;
+}
+
+int bar() {}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/definite_assignment_and_completion.dart.outline.expect b/pkg/front_end/testcases/nnbd/definite_assignment_and_completion.dart.outline.expect
new file mode 100644
index 0000000..7dc40d1
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/definite_assignment_and_completion.dart.outline.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo() → core::int
+ ;
+static method bar() → core::int
+ ;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/nnbd/definite_assignment_and_completion.dart.strong.expect b/pkg/front_end/testcases/nnbd/definite_assignment_and_completion.dart.strong.expect
new file mode 100644
index 0000000..c56d12d
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/definite_assignment_and_completion.dart.strong.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo() → core::int {
+ core::int x;
+ return x;
+}
+static method bar() → core::int {}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/definite_assignment_and_completion.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/definite_assignment_and_completion.dart.strong.transformed.expect
new file mode 100644
index 0000000..c56d12d
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/definite_assignment_and_completion.dart.strong.transformed.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo() → core::int {
+ core::int x;
+ return x;
+}
+static method bar() → core::int {}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/definite_assignment_and_completion.dart.weak.expect b/pkg/front_end/testcases/nnbd/definite_assignment_and_completion.dart.weak.expect
new file mode 100644
index 0000000..c56d12d
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/definite_assignment_and_completion.dart.weak.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo() → core::int {
+ core::int x;
+ return x;
+}
+static method bar() → core::int {}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/definite_assignment_and_completion.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/definite_assignment_and_completion.dart.weak.transformed.expect
new file mode 100644
index 0000000..c56d12d
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/definite_assignment_and_completion.dart.weak.transformed.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo() → core::int {
+ core::int x;
+ return x;
+}
+static method bar() → core::int {}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/forbidden_supers.dart b/pkg/front_end/testcases/nnbd/forbidden_supers.dart
new file mode 100644
index 0000000..80fde61
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/forbidden_supers.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This test checks for compile-time errors in cases when either Never or T? is
+// extended, implemented, or mixed in, where T is a type.
+
+class A {}
+
+class B {}
+
+class C extends B with A? {}
+class C1 extends B with Never {}
+
+class D extends A? {}
+class D1 extends Never {}
+
+class E implements B? {}
+class E1 implements Never {}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/forbidden_supers.dart.outline.expect b/pkg/front_end/testcases/nnbd/forbidden_supers.dart.outline.expect
new file mode 100644
index 0000000..14fa9bf
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/forbidden_supers.dart.outline.expect
@@ -0,0 +1,75 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/forbidden_supers.dart:13:7: Error: The type 'Never' can't be mixed in.
+// class C1 extends B with Never {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/forbidden_supers.dart:13:7: Error: The type 'Never' can't be used as supertype.
+// class C1 extends B with Never {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/forbidden_supers.dart:16:7: Error: The type 'Never' can't be used as supertype.
+// class D1 extends Never {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/forbidden_supers.dart:19:7: Error: The type 'Never' can't be used as supertype.
+// class E1 implements Never {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/forbidden_supers.dart:16:7: Error: The type 'Never' can't be used in an 'extends' clause.
+// class D1 extends Never {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/forbidden_supers.dart:19:7: Error: The type 'Never' can't be used in an 'implements' clause.
+// class E1 implements Never {}
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ synthetic constructor •() → self::A
+ ;
+}
+class B extends core::Object {
+ synthetic constructor •() → self::B
+ ;
+}
+abstract class _C&B&A = self::B with self::A {
+ synthetic constructor •() → self::_C&B&A
+ : super self::B::•()
+ ;
+}
+class C extends self::_C&B&A {
+ synthetic constructor •() → self::C
+ ;
+}
+abstract class _C1&B&Never extends self::B {
+ synthetic constructor •() → self::_C1&B&Never
+ : super self::B::•()
+ ;
+}
+class C1 extends self::_C1&B&Never {
+ synthetic constructor •() → self::C1
+ ;
+}
+class D extends self::A {
+ synthetic constructor •() → self::D
+ ;
+}
+class D1 extends core::Object {
+ synthetic constructor •() → self::D1
+ ;
+}
+class E extends core::Object implements self::B {
+ synthetic constructor •() → self::E
+ ;
+}
+class E1 extends core::Object {
+ synthetic constructor •() → self::E1
+ ;
+}
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/nnbd/forbidden_supers.dart.strong.expect b/pkg/front_end/testcases/nnbd/forbidden_supers.dart.strong.expect
new file mode 100644
index 0000000..a7be0e3
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/forbidden_supers.dart.strong.expect
@@ -0,0 +1,82 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/forbidden_supers.dart:13:7: Error: The type 'Never' can't be mixed in.
+// class C1 extends B with Never {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/forbidden_supers.dart:13:7: Error: The type 'Never' can't be used as supertype.
+// class C1 extends B with Never {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/forbidden_supers.dart:16:7: Error: The type 'Never' can't be used as supertype.
+// class D1 extends Never {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/forbidden_supers.dart:19:7: Error: The type 'Never' can't be used as supertype.
+// class E1 implements Never {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/forbidden_supers.dart:16:7: Error: The type 'Never' can't be used in an 'extends' clause.
+// class D1 extends Never {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/forbidden_supers.dart:19:7: Error: The type 'Never' can't be used in an 'implements' clause.
+// class E1 implements Never {}
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ synthetic constructor •() → self::A
+ : super core::Object::•()
+ ;
+}
+class B extends core::Object {
+ synthetic constructor •() → self::B
+ : super core::Object::•()
+ ;
+}
+abstract class _C&B&A = self::B with self::A {
+ synthetic constructor •() → self::_C&B&A
+ : super self::B::•()
+ ;
+}
+class C extends self::_C&B&A {
+ synthetic constructor •() → self::C
+ : super self::_C&B&A::•()
+ ;
+}
+abstract class _C1&B&Never extends self::B {
+ synthetic constructor •() → self::_C1&B&Never
+ : super self::B::•()
+ ;
+}
+class C1 extends self::_C1&B&Never {
+ synthetic constructor •() → self::C1
+ : super self::_C1&B&Never::•()
+ ;
+}
+class D extends self::A {
+ synthetic constructor •() → self::D
+ : super self::A::•()
+ ;
+}
+class D1 extends core::Object {
+ synthetic constructor •() → self::D1
+ : super core::Object::•()
+ ;
+}
+class E extends core::Object implements self::B {
+ synthetic constructor •() → self::E
+ : super core::Object::•()
+ ;
+}
+class E1 extends core::Object {
+ synthetic constructor •() → self::E1
+ : super core::Object::•()
+ ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/forbidden_supers.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/forbidden_supers.dart.strong.transformed.expect
new file mode 100644
index 0000000..de6ba93
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/forbidden_supers.dart.strong.transformed.expect
@@ -0,0 +1,82 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/forbidden_supers.dart:13:7: Error: The type 'Never' can't be mixed in.
+// class C1 extends B with Never {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/forbidden_supers.dart:13:7: Error: The type 'Never' can't be used as supertype.
+// class C1 extends B with Never {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/forbidden_supers.dart:16:7: Error: The type 'Never' can't be used as supertype.
+// class D1 extends Never {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/forbidden_supers.dart:19:7: Error: The type 'Never' can't be used as supertype.
+// class E1 implements Never {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/forbidden_supers.dart:16:7: Error: The type 'Never' can't be used in an 'extends' clause.
+// class D1 extends Never {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/forbidden_supers.dart:19:7: Error: The type 'Never' can't be used in an 'implements' clause.
+// class E1 implements Never {}
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ synthetic constructor •() → self::A
+ : super core::Object::•()
+ ;
+}
+class B extends core::Object {
+ synthetic constructor •() → self::B
+ : super core::Object::•()
+ ;
+}
+abstract class _C&B&A extends self::B implements self::A {
+ synthetic constructor •() → self::_C&B&A
+ : super self::B::•()
+ ;
+}
+class C extends self::_C&B&A {
+ synthetic constructor •() → self::C
+ : super self::_C&B&A::•()
+ ;
+}
+abstract class _C1&B&Never extends self::B {
+ synthetic constructor •() → self::_C1&B&Never
+ : super self::B::•()
+ ;
+}
+class C1 extends self::_C1&B&Never {
+ synthetic constructor •() → self::C1
+ : super self::_C1&B&Never::•()
+ ;
+}
+class D extends self::A {
+ synthetic constructor •() → self::D
+ : super self::A::•()
+ ;
+}
+class D1 extends core::Object {
+ synthetic constructor •() → self::D1
+ : super core::Object::•()
+ ;
+}
+class E extends core::Object implements self::B {
+ synthetic constructor •() → self::E
+ : super core::Object::•()
+ ;
+}
+class E1 extends core::Object {
+ synthetic constructor •() → self::E1
+ : super core::Object::•()
+ ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/forbidden_supers.dart.weak.expect b/pkg/front_end/testcases/nnbd/forbidden_supers.dart.weak.expect
new file mode 100644
index 0000000..a7be0e3
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/forbidden_supers.dart.weak.expect
@@ -0,0 +1,82 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/forbidden_supers.dart:13:7: Error: The type 'Never' can't be mixed in.
+// class C1 extends B with Never {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/forbidden_supers.dart:13:7: Error: The type 'Never' can't be used as supertype.
+// class C1 extends B with Never {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/forbidden_supers.dart:16:7: Error: The type 'Never' can't be used as supertype.
+// class D1 extends Never {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/forbidden_supers.dart:19:7: Error: The type 'Never' can't be used as supertype.
+// class E1 implements Never {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/forbidden_supers.dart:16:7: Error: The type 'Never' can't be used in an 'extends' clause.
+// class D1 extends Never {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/forbidden_supers.dart:19:7: Error: The type 'Never' can't be used in an 'implements' clause.
+// class E1 implements Never {}
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ synthetic constructor •() → self::A
+ : super core::Object::•()
+ ;
+}
+class B extends core::Object {
+ synthetic constructor •() → self::B
+ : super core::Object::•()
+ ;
+}
+abstract class _C&B&A = self::B with self::A {
+ synthetic constructor •() → self::_C&B&A
+ : super self::B::•()
+ ;
+}
+class C extends self::_C&B&A {
+ synthetic constructor •() → self::C
+ : super self::_C&B&A::•()
+ ;
+}
+abstract class _C1&B&Never extends self::B {
+ synthetic constructor •() → self::_C1&B&Never
+ : super self::B::•()
+ ;
+}
+class C1 extends self::_C1&B&Never {
+ synthetic constructor •() → self::C1
+ : super self::_C1&B&Never::•()
+ ;
+}
+class D extends self::A {
+ synthetic constructor •() → self::D
+ : super self::A::•()
+ ;
+}
+class D1 extends core::Object {
+ synthetic constructor •() → self::D1
+ : super core::Object::•()
+ ;
+}
+class E extends core::Object implements self::B {
+ synthetic constructor •() → self::E
+ : super core::Object::•()
+ ;
+}
+class E1 extends core::Object {
+ synthetic constructor •() → self::E1
+ : super core::Object::•()
+ ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/forbidden_supers.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/forbidden_supers.dart.weak.transformed.expect
new file mode 100644
index 0000000..de6ba93
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/forbidden_supers.dart.weak.transformed.expect
@@ -0,0 +1,82 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/forbidden_supers.dart:13:7: Error: The type 'Never' can't be mixed in.
+// class C1 extends B with Never {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/forbidden_supers.dart:13:7: Error: The type 'Never' can't be used as supertype.
+// class C1 extends B with Never {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/forbidden_supers.dart:16:7: Error: The type 'Never' can't be used as supertype.
+// class D1 extends Never {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/forbidden_supers.dart:19:7: Error: The type 'Never' can't be used as supertype.
+// class E1 implements Never {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/forbidden_supers.dart:16:7: Error: The type 'Never' can't be used in an 'extends' clause.
+// class D1 extends Never {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/forbidden_supers.dart:19:7: Error: The type 'Never' can't be used in an 'implements' clause.
+// class E1 implements Never {}
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ synthetic constructor •() → self::A
+ : super core::Object::•()
+ ;
+}
+class B extends core::Object {
+ synthetic constructor •() → self::B
+ : super core::Object::•()
+ ;
+}
+abstract class _C&B&A extends self::B implements self::A {
+ synthetic constructor •() → self::_C&B&A
+ : super self::B::•()
+ ;
+}
+class C extends self::_C&B&A {
+ synthetic constructor •() → self::C
+ : super self::_C&B&A::•()
+ ;
+}
+abstract class _C1&B&Never extends self::B {
+ synthetic constructor •() → self::_C1&B&Never
+ : super self::B::•()
+ ;
+}
+class C1 extends self::_C1&B&Never {
+ synthetic constructor •() → self::C1
+ : super self::_C1&B&Never::•()
+ ;
+}
+class D extends self::A {
+ synthetic constructor •() → self::D
+ : super self::A::•()
+ ;
+}
+class D1 extends core::Object {
+ synthetic constructor •() → self::D1
+ : super core::Object::•()
+ ;
+}
+class E extends core::Object implements self::B {
+ synthetic constructor •() → self::E
+ : super core::Object::•()
+ ;
+}
+class E1 extends core::Object {
+ synthetic constructor •() → self::E1
+ : super core::Object::•()
+ ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/forin.dart b/pkg/front_end/testcases/nnbd/forin.dart
new file mode 100644
index 0000000..05b3a79
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/forin.dart
@@ -0,0 +1,33 @@
+// 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.
+
+// The test checks that only subtypes of Iterable<dynamic> and "dynamic" are
+// allowed as the iterable in a for-in loop.
+
+error(Iterable<int>? i2, List<int>? l2, Object o1, Object? o2) {
+ for (int x in i2) x;
+ [for (int x in i2) x];
+
+ for (int x in l2) x;
+ [for (int x in l2) x];
+
+ for (int x in o1) x;
+ [for (int x in o1) x];
+
+ for (int x in o2) x;
+ [for (int x in o2) x];
+}
+
+ok(Iterable<int> i1, List<int> l1, dynamic d) {
+ for (int x in i1) x;
+ [for (int x in i1) x];
+
+ for (int x in l1) x;
+ [for (int x in l1) x];
+
+ for (int x in d) x;
+ [for (int x in d) x];
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/forin.dart.outline.expect b/pkg/front_end/testcases/nnbd/forin.dart.outline.expect
new file mode 100644
index 0000000..33cd4d6
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/forin.dart.outline.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method error(core::Iterable<core::int>? i2, core::List<core::int>? l2, core::Object o1, core::Object? o2) → dynamic
+ ;
+static method ok(core::Iterable<core::int> i1, core::List<core::int> l1, dynamic d) → dynamic
+ ;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/nnbd/forin.dart.strong.expect b/pkg/front_end/testcases/nnbd/forin.dart.strong.expect
new file mode 100644
index 0000000..dc3ec6b
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/forin.dart.strong.expect
@@ -0,0 +1,149 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/forin.dart:9:17: Error: The type 'Iterable<int>?' used in the 'for' loop must implement 'Iterable<dynamic>'.
+// - 'Iterable' is from 'dart:core'.
+// for (int x in i2) x;
+// ^
+//
+// pkg/front_end/testcases/nnbd/forin.dart:10:18: Error: The type 'Iterable<int>?' used in the 'for' loop must implement 'Iterable<dynamic>'.
+// - 'Iterable' is from 'dart:core'.
+// [for (int x in i2) x];
+// ^
+//
+// pkg/front_end/testcases/nnbd/forin.dart:12:17: Error: The type 'List<int>?' used in the 'for' loop must implement 'Iterable<dynamic>'.
+// - 'List' is from 'dart:core'.
+// - 'Iterable' is from 'dart:core'.
+// for (int x in l2) x;
+// ^
+//
+// pkg/front_end/testcases/nnbd/forin.dart:13:18: Error: The type 'List<int>?' used in the 'for' loop must implement 'Iterable<dynamic>'.
+// - 'List' is from 'dart:core'.
+// - 'Iterable' is from 'dart:core'.
+// [for (int x in l2) x];
+// ^
+//
+// pkg/front_end/testcases/nnbd/forin.dart:15:17: Error: The type 'Object' used in the 'for' loop must implement 'Iterable<dynamic>'.
+// - 'Object' is from 'dart:core'.
+// - 'Iterable' is from 'dart:core'.
+// for (int x in o1) x;
+// ^
+//
+// pkg/front_end/testcases/nnbd/forin.dart:16:18: Error: The type 'Object' used in the 'for' loop must implement 'Iterable<dynamic>'.
+// - 'Object' is from 'dart:core'.
+// - 'Iterable' is from 'dart:core'.
+// [for (int x in o1) x];
+// ^
+//
+// pkg/front_end/testcases/nnbd/forin.dart:18:17: Error: The type 'Object?' used in the 'for' loop must implement 'Iterable<dynamic>'.
+// - 'Object' is from 'dart:core'.
+// - 'Iterable' is from 'dart:core'.
+// for (int x in o2) x;
+// ^
+//
+// pkg/front_end/testcases/nnbd/forin.dart:19:18: Error: The type 'Object?' used in the 'for' loop must implement 'Iterable<dynamic>'.
+// - 'Object' is from 'dart:core'.
+// - 'Iterable' is from 'dart:core'.
+// [for (int x in o2) x];
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+static method error(core::Iterable<core::int>? i2, core::List<core::int>? l2, core::Object o1, core::Object? o2) → dynamic {
+ for (core::int x in let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/forin.dart:9:17: Error: The type 'Iterable<int>?' used in the 'for' loop must implement 'Iterable<dynamic>'.
+ - 'Iterable' is from 'dart:core'.
+ for (int x in i2) x;
+ ^" in i2 as{TypeError} core::Iterable<dynamic>)
+ x;
+ block {
+ final core::List<core::int> #t2 = <core::int>[];
+ for (core::int x in let final<BottomType> #t3 = invalid-expression "pkg/front_end/testcases/nnbd/forin.dart:10:18: Error: The type 'Iterable<int>?' used in the 'for' loop must implement 'Iterable<dynamic>'.
+ - 'Iterable' is from 'dart:core'.
+ [for (int x in i2) x];
+ ^" in i2 as{TypeError} core::Iterable<dynamic>)
+ #t2.{core::List::add}(x);
+ } =>#t2;
+ for (core::int x in let final<BottomType> #t4 = invalid-expression "pkg/front_end/testcases/nnbd/forin.dart:12:17: Error: The type 'List<int>?' used in the 'for' loop must implement 'Iterable<dynamic>'.
+ - 'List' is from 'dart:core'.
+ - 'Iterable' is from 'dart:core'.
+ for (int x in l2) x;
+ ^" in l2 as{TypeError} core::Iterable<dynamic>)
+ x;
+ block {
+ final core::List<core::int> #t5 = <core::int>[];
+ for (core::int x in let final<BottomType> #t6 = invalid-expression "pkg/front_end/testcases/nnbd/forin.dart:13:18: Error: The type 'List<int>?' used in the 'for' loop must implement 'Iterable<dynamic>'.
+ - 'List' is from 'dart:core'.
+ - 'Iterable' is from 'dart:core'.
+ [for (int x in l2) x];
+ ^" in l2 as{TypeError} core::Iterable<dynamic>)
+ #t5.{core::List::add}(x);
+ } =>#t5;
+ for (final dynamic #t7 in let final<BottomType> #t8 = invalid-expression "pkg/front_end/testcases/nnbd/forin.dart:15:17: Error: The type 'Object' used in the 'for' loop must implement 'Iterable<dynamic>'.
+ - 'Object' is from 'dart:core'.
+ - 'Iterable' is from 'dart:core'.
+ for (int x in o1) x;
+ ^" in o1 as{TypeError} core::Iterable<dynamic>) {
+ core::int x = #t7 as{TypeError} core::int;
+ x;
+ }
+ block {
+ final core::List<core::int> #t9 = <core::int>[];
+ for (final dynamic #t10 in let final<BottomType> #t11 = invalid-expression "pkg/front_end/testcases/nnbd/forin.dart:16:18: Error: The type 'Object' used in the 'for' loop must implement 'Iterable<dynamic>'.
+ - 'Object' is from 'dart:core'.
+ - 'Iterable' is from 'dart:core'.
+ [for (int x in o1) x];
+ ^" in o1 as{TypeError} core::Iterable<dynamic>) {
+ core::int x = #t10 as{TypeError} core::int;
+ #t9.{core::List::add}(x);
+ }
+ } =>#t9;
+ for (final dynamic #t12 in let final<BottomType> #t13 = invalid-expression "pkg/front_end/testcases/nnbd/forin.dart:18:17: Error: The type 'Object?' used in the 'for' loop must implement 'Iterable<dynamic>'.
+ - 'Object' is from 'dart:core'.
+ - 'Iterable' is from 'dart:core'.
+ for (int x in o2) x;
+ ^" in o2 as{TypeError} core::Iterable<dynamic>) {
+ core::int x = #t12 as{TypeError} core::int;
+ x;
+ }
+ block {
+ final core::List<core::int> #t14 = <core::int>[];
+ for (final dynamic #t15 in let final<BottomType> #t16 = invalid-expression "pkg/front_end/testcases/nnbd/forin.dart:19:18: Error: The type 'Object?' used in the 'for' loop must implement 'Iterable<dynamic>'.
+ - 'Object' is from 'dart:core'.
+ - 'Iterable' is from 'dart:core'.
+ [for (int x in o2) x];
+ ^" in o2 as{TypeError} core::Iterable<dynamic>) {
+ core::int x = #t15 as{TypeError} core::int;
+ #t14.{core::List::add}(x);
+ }
+ } =>#t14;
+}
+static method ok(core::Iterable<core::int> i1, core::List<core::int> l1, dynamic d) → dynamic {
+ for (core::int x in i1)
+ x;
+ block {
+ final core::List<core::int> #t17 = <core::int>[];
+ for (core::int x in i1)
+ #t17.{core::List::add}(x);
+ } =>#t17;
+ for (core::int x in l1)
+ x;
+ block {
+ final core::List<core::int> #t18 = <core::int>[];
+ for (core::int x in l1)
+ #t18.{core::List::add}(x);
+ } =>#t18;
+ for (final dynamic #t19 in d as{TypeError} core::Iterable<dynamic>) {
+ core::int x = #t19 as{TypeError} core::int;
+ x;
+ }
+ block {
+ final core::List<core::int> #t20 = <core::int>[];
+ for (final dynamic #t21 in d as{TypeError} core::Iterable<dynamic>) {
+ core::int x = #t21 as{TypeError} core::int;
+ #t20.{core::List::add}(x);
+ }
+ } =>#t20;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/forin.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/forin.dart.strong.transformed.expect
new file mode 100644
index 0000000..04b46d0
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/forin.dart.strong.transformed.expect
@@ -0,0 +1,226 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/forin.dart:9:17: Error: The type 'Iterable<int>?' used in the 'for' loop must implement 'Iterable<dynamic>'.
+// - 'Iterable' is from 'dart:core'.
+// for (int x in i2) x;
+// ^
+//
+// pkg/front_end/testcases/nnbd/forin.dart:10:18: Error: The type 'Iterable<int>?' used in the 'for' loop must implement 'Iterable<dynamic>'.
+// - 'Iterable' is from 'dart:core'.
+// [for (int x in i2) x];
+// ^
+//
+// pkg/front_end/testcases/nnbd/forin.dart:12:17: Error: The type 'List<int>?' used in the 'for' loop must implement 'Iterable<dynamic>'.
+// - 'List' is from 'dart:core'.
+// - 'Iterable' is from 'dart:core'.
+// for (int x in l2) x;
+// ^
+//
+// pkg/front_end/testcases/nnbd/forin.dart:13:18: Error: The type 'List<int>?' used in the 'for' loop must implement 'Iterable<dynamic>'.
+// - 'List' is from 'dart:core'.
+// - 'Iterable' is from 'dart:core'.
+// [for (int x in l2) x];
+// ^
+//
+// pkg/front_end/testcases/nnbd/forin.dart:15:17: Error: The type 'Object' used in the 'for' loop must implement 'Iterable<dynamic>'.
+// - 'Object' is from 'dart:core'.
+// - 'Iterable' is from 'dart:core'.
+// for (int x in o1) x;
+// ^
+//
+// pkg/front_end/testcases/nnbd/forin.dart:16:18: Error: The type 'Object' used in the 'for' loop must implement 'Iterable<dynamic>'.
+// - 'Object' is from 'dart:core'.
+// - 'Iterable' is from 'dart:core'.
+// [for (int x in o1) x];
+// ^
+//
+// pkg/front_end/testcases/nnbd/forin.dart:18:17: Error: The type 'Object?' used in the 'for' loop must implement 'Iterable<dynamic>'.
+// - 'Object' is from 'dart:core'.
+// - 'Iterable' is from 'dart:core'.
+// for (int x in o2) x;
+// ^
+//
+// pkg/front_end/testcases/nnbd/forin.dart:19:18: Error: The type 'Object?' used in the 'for' loop must implement 'Iterable<dynamic>'.
+// - 'Object' is from 'dart:core'.
+// - 'Iterable' is from 'dart:core'.
+// [for (int x in o2) x];
+// ^
+//
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+static method error(core::Iterable<core::int>? i2, core::List<core::int>? l2, core::Object o1, core::Object? o2) → dynamic {
+ {
+ core::Iterator<dynamic>* :sync-for-iterator = _in::unsafeCast<core::Iterable<dynamic>*>(let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/forin.dart:9:17: Error: The type 'Iterable<int>?' used in the 'for' loop must implement 'Iterable<dynamic>'.
+ - 'Iterable' is from 'dart:core'.
+ for (int x in i2) x;
+ ^" in i2 as{TypeError} core::Iterable<dynamic>).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ core::int x = :sync-for-iterator.{core::Iterator::current};
+ x;
+ }
+ }
+ block {
+ final core::List<core::int> #t2 = <core::int>[];
+ {
+ core::Iterator<dynamic>* :sync-for-iterator = _in::unsafeCast<core::Iterable<dynamic>*>(let final<BottomType> #t3 = invalid-expression "pkg/front_end/testcases/nnbd/forin.dart:10:18: Error: The type 'Iterable<int>?' used in the 'for' loop must implement 'Iterable<dynamic>'.
+ - 'Iterable' is from 'dart:core'.
+ [for (int x in i2) x];
+ ^" in i2 as{TypeError} core::Iterable<dynamic>).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ core::int x = :sync-for-iterator.{core::Iterator::current};
+ #t2.{core::List::add}(x);
+ }
+ }
+ } =>#t2;
+ {
+ core::Iterator<dynamic>* :sync-for-iterator = _in::unsafeCast<core::Iterable<dynamic>*>(let final<BottomType> #t4 = invalid-expression "pkg/front_end/testcases/nnbd/forin.dart:12:17: Error: The type 'List<int>?' used in the 'for' loop must implement 'Iterable<dynamic>'.
+ - 'List' is from 'dart:core'.
+ - 'Iterable' is from 'dart:core'.
+ for (int x in l2) x;
+ ^" in l2 as{TypeError} core::Iterable<dynamic>).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ core::int x = :sync-for-iterator.{core::Iterator::current};
+ x;
+ }
+ }
+ block {
+ final core::List<core::int> #t5 = <core::int>[];
+ {
+ core::Iterator<dynamic>* :sync-for-iterator = _in::unsafeCast<core::Iterable<dynamic>*>(let final<BottomType> #t6 = invalid-expression "pkg/front_end/testcases/nnbd/forin.dart:13:18: Error: The type 'List<int>?' used in the 'for' loop must implement 'Iterable<dynamic>'.
+ - 'List' is from 'dart:core'.
+ - 'Iterable' is from 'dart:core'.
+ [for (int x in l2) x];
+ ^" in l2 as{TypeError} core::Iterable<dynamic>).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ core::int x = :sync-for-iterator.{core::Iterator::current};
+ #t5.{core::List::add}(x);
+ }
+ }
+ } =>#t5;
+ {
+ core::Iterator<dynamic>* :sync-for-iterator = _in::unsafeCast<core::Iterable<dynamic>*>(let final<BottomType> #t7 = invalid-expression "pkg/front_end/testcases/nnbd/forin.dart:15:17: Error: The type 'Object' used in the 'for' loop must implement 'Iterable<dynamic>'.
+ - 'Object' is from 'dart:core'.
+ - 'Iterable' is from 'dart:core'.
+ for (int x in o1) x;
+ ^" in o1 as{TypeError} core::Iterable<dynamic>).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ final dynamic #t8 = :sync-for-iterator.{core::Iterator::current};
+ {
+ core::int x = #t8 as{TypeError} core::int;
+ x;
+ }
+ }
+ }
+ block {
+ final core::List<core::int> #t9 = <core::int>[];
+ {
+ core::Iterator<dynamic>* :sync-for-iterator = _in::unsafeCast<core::Iterable<dynamic>*>(let final<BottomType> #t10 = invalid-expression "pkg/front_end/testcases/nnbd/forin.dart:16:18: Error: The type 'Object' used in the 'for' loop must implement 'Iterable<dynamic>'.
+ - 'Object' is from 'dart:core'.
+ - 'Iterable' is from 'dart:core'.
+ [for (int x in o1) x];
+ ^" in o1 as{TypeError} core::Iterable<dynamic>).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ final dynamic #t11 = :sync-for-iterator.{core::Iterator::current};
+ {
+ core::int x = #t11 as{TypeError} core::int;
+ #t9.{core::List::add}(x);
+ }
+ }
+ }
+ } =>#t9;
+ {
+ core::Iterator<dynamic>* :sync-for-iterator = _in::unsafeCast<core::Iterable<dynamic>*>(let final<BottomType> #t12 = invalid-expression "pkg/front_end/testcases/nnbd/forin.dart:18:17: Error: The type 'Object?' used in the 'for' loop must implement 'Iterable<dynamic>'.
+ - 'Object' is from 'dart:core'.
+ - 'Iterable' is from 'dart:core'.
+ for (int x in o2) x;
+ ^" in o2 as{TypeError} core::Iterable<dynamic>).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ final dynamic #t13 = :sync-for-iterator.{core::Iterator::current};
+ {
+ core::int x = #t13 as{TypeError} core::int;
+ x;
+ }
+ }
+ }
+ block {
+ final core::List<core::int> #t14 = <core::int>[];
+ {
+ core::Iterator<dynamic>* :sync-for-iterator = _in::unsafeCast<core::Iterable<dynamic>*>(let final<BottomType> #t15 = invalid-expression "pkg/front_end/testcases/nnbd/forin.dart:19:18: Error: The type 'Object?' used in the 'for' loop must implement 'Iterable<dynamic>'.
+ - 'Object' is from 'dart:core'.
+ - 'Iterable' is from 'dart:core'.
+ [for (int x in o2) x];
+ ^" in o2 as{TypeError} core::Iterable<dynamic>).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ final dynamic #t16 = :sync-for-iterator.{core::Iterator::current};
+ {
+ core::int x = #t16 as{TypeError} core::int;
+ #t14.{core::List::add}(x);
+ }
+ }
+ }
+ } =>#t14;
+}
+static method ok(core::Iterable<core::int> i1, core::List<core::int> l1, dynamic d) → dynamic {
+ {
+ core::Iterator<core::int>* :sync-for-iterator = _in::unsafeCast<core::Iterable<core::int>*>(i1).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ core::int x = :sync-for-iterator.{core::Iterator::current};
+ x;
+ }
+ }
+ block {
+ final core::List<core::int> #t17 = <core::int>[];
+ {
+ core::Iterator<core::int>* :sync-for-iterator = _in::unsafeCast<core::Iterable<core::int>*>(i1).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ core::int x = :sync-for-iterator.{core::Iterator::current};
+ #t17.{core::List::add}(x);
+ }
+ }
+ } =>#t17;
+ {
+ core::Iterator<core::int*>* :sync-for-iterator = _in::unsafeCast<core::Iterable<core::int*>*>(l1).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ core::int x = :sync-for-iterator.{core::Iterator::current};
+ x;
+ }
+ }
+ block {
+ final core::List<core::int> #t18 = <core::int>[];
+ {
+ core::Iterator<core::int*>* :sync-for-iterator = _in::unsafeCast<core::Iterable<core::int*>*>(l1).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ core::int x = :sync-for-iterator.{core::Iterator::current};
+ #t18.{core::List::add}(x);
+ }
+ }
+ } =>#t18;
+ {
+ core::Iterator<dynamic>* :sync-for-iterator = _in::unsafeCast<core::Iterable<dynamic>*>(d as{TypeError} core::Iterable<dynamic>).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ final dynamic #t19 = :sync-for-iterator.{core::Iterator::current};
+ {
+ core::int x = #t19 as{TypeError} core::int;
+ x;
+ }
+ }
+ }
+ block {
+ final core::List<core::int> #t20 = <core::int>[];
+ {
+ core::Iterator<dynamic>* :sync-for-iterator = _in::unsafeCast<core::Iterable<dynamic>*>(d as{TypeError} core::Iterable<dynamic>).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ final dynamic #t21 = :sync-for-iterator.{core::Iterator::current};
+ {
+ core::int x = #t21 as{TypeError} core::int;
+ #t20.{core::List::add}(x);
+ }
+ }
+ }
+ } =>#t20;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/forin.dart.weak.expect b/pkg/front_end/testcases/nnbd/forin.dart.weak.expect
new file mode 100644
index 0000000..12c0f2c
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/forin.dart.weak.expect
@@ -0,0 +1,119 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/forin.dart:9:17: Warning: Assigning value of type 'Iterable<int>?' to a variable of type 'Iterable<dynamic>'.
+// - 'Iterable' is from 'dart:core'.
+// for (int x in i2) x;
+// ^
+//
+// pkg/front_end/testcases/nnbd/forin.dart:10:18: Warning: Assigning value of type 'Iterable<int>?' to a variable of type 'Iterable<dynamic>'.
+// - 'Iterable' is from 'dart:core'.
+// [for (int x in i2) x];
+// ^
+//
+// pkg/front_end/testcases/nnbd/forin.dart:12:17: Warning: Assigning value of type 'List<int>?' to a variable of type 'Iterable<dynamic>'.
+// - 'List' is from 'dart:core'.
+// - 'Iterable' is from 'dart:core'.
+// for (int x in l2) x;
+// ^
+//
+// pkg/front_end/testcases/nnbd/forin.dart:13:18: Warning: Assigning value of type 'List<int>?' to a variable of type 'Iterable<dynamic>'.
+// - 'List' is from 'dart:core'.
+// - 'Iterable' is from 'dart:core'.
+// [for (int x in l2) x];
+// ^
+//
+// pkg/front_end/testcases/nnbd/forin.dart:15:17: Warning: Assigning value of type 'Object' to a variable of type 'Iterable<dynamic>'.
+// - 'Object' is from 'dart:core'.
+// - 'Iterable' is from 'dart:core'.
+// for (int x in o1) x;
+// ^
+//
+// pkg/front_end/testcases/nnbd/forin.dart:16:18: Warning: Assigning value of type 'Object' to a variable of type 'Iterable<dynamic>'.
+// - 'Object' is from 'dart:core'.
+// - 'Iterable' is from 'dart:core'.
+// [for (int x in o1) x];
+// ^
+//
+// pkg/front_end/testcases/nnbd/forin.dart:18:17: Warning: Assigning value of type 'Object?' to a variable of type 'Iterable<dynamic>'.
+// - 'Object' is from 'dart:core'.
+// - 'Iterable' is from 'dart:core'.
+// for (int x in o2) x;
+// ^
+//
+// pkg/front_end/testcases/nnbd/forin.dart:19:18: Warning: Assigning value of type 'Object?' to a variable of type 'Iterable<dynamic>'.
+// - 'Object' is from 'dart:core'.
+// - 'Iterable' is from 'dart:core'.
+// [for (int x in o2) x];
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+static method error(core::Iterable<core::int>? i2, core::List<core::int>? l2, core::Object o1, core::Object? o2) → dynamic {
+ for (core::int x in i2)
+ x;
+ block {
+ final core::List<core::int> #t1 = <core::int>[];
+ for (core::int x in i2)
+ #t1.{core::List::add}(x);
+ } =>#t1;
+ for (core::int x in l2)
+ x;
+ block {
+ final core::List<core::int> #t2 = <core::int>[];
+ for (core::int x in l2)
+ #t2.{core::List::add}(x);
+ } =>#t2;
+ for (final dynamic #t3 in o1 as{TypeError} core::Iterable<dynamic>) {
+ core::int x = #t3 as{TypeError} core::int;
+ x;
+ }
+ block {
+ final core::List<core::int> #t4 = <core::int>[];
+ for (final dynamic #t5 in o1 as{TypeError} core::Iterable<dynamic>) {
+ core::int x = #t5 as{TypeError} core::int;
+ #t4.{core::List::add}(x);
+ }
+ } =>#t4;
+ for (final dynamic #t6 in o2 as{TypeError} core::Iterable<dynamic>) {
+ core::int x = #t6 as{TypeError} core::int;
+ x;
+ }
+ block {
+ final core::List<core::int> #t7 = <core::int>[];
+ for (final dynamic #t8 in o2 as{TypeError} core::Iterable<dynamic>) {
+ core::int x = #t8 as{TypeError} core::int;
+ #t7.{core::List::add}(x);
+ }
+ } =>#t7;
+}
+static method ok(core::Iterable<core::int> i1, core::List<core::int> l1, dynamic d) → dynamic {
+ for (core::int x in i1)
+ x;
+ block {
+ final core::List<core::int> #t9 = <core::int>[];
+ for (core::int x in i1)
+ #t9.{core::List::add}(x);
+ } =>#t9;
+ for (core::int x in l1)
+ x;
+ block {
+ final core::List<core::int> #t10 = <core::int>[];
+ for (core::int x in l1)
+ #t10.{core::List::add}(x);
+ } =>#t10;
+ for (final dynamic #t11 in d as{TypeError} core::Iterable<dynamic>) {
+ core::int x = #t11 as{TypeError} core::int;
+ x;
+ }
+ block {
+ final core::List<core::int> #t12 = <core::int>[];
+ for (final dynamic #t13 in d as{TypeError} core::Iterable<dynamic>) {
+ core::int x = #t13 as{TypeError} core::int;
+ #t12.{core::List::add}(x);
+ }
+ } =>#t12;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/forin.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/forin.dart.weak.transformed.expect
new file mode 100644
index 0000000..1cf6aaf
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/forin.dart.weak.transformed.expect
@@ -0,0 +1,196 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/forin.dart:9:17: Warning: Assigning value of type 'Iterable<int>?' to a variable of type 'Iterable<dynamic>'.
+// - 'Iterable' is from 'dart:core'.
+// for (int x in i2) x;
+// ^
+//
+// pkg/front_end/testcases/nnbd/forin.dart:10:18: Warning: Assigning value of type 'Iterable<int>?' to a variable of type 'Iterable<dynamic>'.
+// - 'Iterable' is from 'dart:core'.
+// [for (int x in i2) x];
+// ^
+//
+// pkg/front_end/testcases/nnbd/forin.dart:12:17: Warning: Assigning value of type 'List<int>?' to a variable of type 'Iterable<dynamic>'.
+// - 'List' is from 'dart:core'.
+// - 'Iterable' is from 'dart:core'.
+// for (int x in l2) x;
+// ^
+//
+// pkg/front_end/testcases/nnbd/forin.dart:13:18: Warning: Assigning value of type 'List<int>?' to a variable of type 'Iterable<dynamic>'.
+// - 'List' is from 'dart:core'.
+// - 'Iterable' is from 'dart:core'.
+// [for (int x in l2) x];
+// ^
+//
+// pkg/front_end/testcases/nnbd/forin.dart:15:17: Warning: Assigning value of type 'Object' to a variable of type 'Iterable<dynamic>'.
+// - 'Object' is from 'dart:core'.
+// - 'Iterable' is from 'dart:core'.
+// for (int x in o1) x;
+// ^
+//
+// pkg/front_end/testcases/nnbd/forin.dart:16:18: Warning: Assigning value of type 'Object' to a variable of type 'Iterable<dynamic>'.
+// - 'Object' is from 'dart:core'.
+// - 'Iterable' is from 'dart:core'.
+// [for (int x in o1) x];
+// ^
+//
+// pkg/front_end/testcases/nnbd/forin.dart:18:17: Warning: Assigning value of type 'Object?' to a variable of type 'Iterable<dynamic>'.
+// - 'Object' is from 'dart:core'.
+// - 'Iterable' is from 'dart:core'.
+// for (int x in o2) x;
+// ^
+//
+// pkg/front_end/testcases/nnbd/forin.dart:19:18: Warning: Assigning value of type 'Object?' to a variable of type 'Iterable<dynamic>'.
+// - 'Object' is from 'dart:core'.
+// - 'Iterable' is from 'dart:core'.
+// [for (int x in o2) x];
+// ^
+//
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+static method error(core::Iterable<core::int>? i2, core::List<core::int>? l2, core::Object o1, core::Object? o2) → dynamic {
+ {
+ core::Iterator<core::int>* :sync-for-iterator = _in::unsafeCast<core::Iterable<core::int>*>(i2).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ core::int x = :sync-for-iterator.{core::Iterator::current};
+ x;
+ }
+ }
+ block {
+ final core::List<core::int> #t1 = <core::int>[];
+ {
+ core::Iterator<core::int>* :sync-for-iterator = _in::unsafeCast<core::Iterable<core::int>*>(i2).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ core::int x = :sync-for-iterator.{core::Iterator::current};
+ #t1.{core::List::add}(x);
+ }
+ }
+ } =>#t1;
+ {
+ core::Iterator<core::int*>* :sync-for-iterator = _in::unsafeCast<core::Iterable<core::int*>*>(l2).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ core::int x = :sync-for-iterator.{core::Iterator::current};
+ x;
+ }
+ }
+ block {
+ final core::List<core::int> #t2 = <core::int>[];
+ {
+ core::Iterator<core::int*>* :sync-for-iterator = _in::unsafeCast<core::Iterable<core::int*>*>(l2).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ core::int x = :sync-for-iterator.{core::Iterator::current};
+ #t2.{core::List::add}(x);
+ }
+ }
+ } =>#t2;
+ {
+ core::Iterator<dynamic>* :sync-for-iterator = _in::unsafeCast<core::Iterable<dynamic>*>(o1 as{TypeError} core::Iterable<dynamic>).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ final dynamic #t3 = :sync-for-iterator.{core::Iterator::current};
+ {
+ core::int x = #t3 as{TypeError} core::int;
+ x;
+ }
+ }
+ }
+ block {
+ final core::List<core::int> #t4 = <core::int>[];
+ {
+ core::Iterator<dynamic>* :sync-for-iterator = _in::unsafeCast<core::Iterable<dynamic>*>(o1 as{TypeError} core::Iterable<dynamic>).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ final dynamic #t5 = :sync-for-iterator.{core::Iterator::current};
+ {
+ core::int x = #t5 as{TypeError} core::int;
+ #t4.{core::List::add}(x);
+ }
+ }
+ }
+ } =>#t4;
+ {
+ core::Iterator<dynamic>* :sync-for-iterator = _in::unsafeCast<core::Iterable<dynamic>*>(o2 as{TypeError} core::Iterable<dynamic>).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ final dynamic #t6 = :sync-for-iterator.{core::Iterator::current};
+ {
+ core::int x = #t6 as{TypeError} core::int;
+ x;
+ }
+ }
+ }
+ block {
+ final core::List<core::int> #t7 = <core::int>[];
+ {
+ core::Iterator<dynamic>* :sync-for-iterator = _in::unsafeCast<core::Iterable<dynamic>*>(o2 as{TypeError} core::Iterable<dynamic>).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ final dynamic #t8 = :sync-for-iterator.{core::Iterator::current};
+ {
+ core::int x = #t8 as{TypeError} core::int;
+ #t7.{core::List::add}(x);
+ }
+ }
+ }
+ } =>#t7;
+}
+static method ok(core::Iterable<core::int> i1, core::List<core::int> l1, dynamic d) → dynamic {
+ {
+ core::Iterator<core::int>* :sync-for-iterator = _in::unsafeCast<core::Iterable<core::int>*>(i1).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ core::int x = :sync-for-iterator.{core::Iterator::current};
+ x;
+ }
+ }
+ block {
+ final core::List<core::int> #t9 = <core::int>[];
+ {
+ core::Iterator<core::int>* :sync-for-iterator = _in::unsafeCast<core::Iterable<core::int>*>(i1).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ core::int x = :sync-for-iterator.{core::Iterator::current};
+ #t9.{core::List::add}(x);
+ }
+ }
+ } =>#t9;
+ {
+ core::Iterator<core::int*>* :sync-for-iterator = _in::unsafeCast<core::Iterable<core::int*>*>(l1).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ core::int x = :sync-for-iterator.{core::Iterator::current};
+ x;
+ }
+ }
+ block {
+ final core::List<core::int> #t10 = <core::int>[];
+ {
+ core::Iterator<core::int*>* :sync-for-iterator = _in::unsafeCast<core::Iterable<core::int*>*>(l1).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ core::int x = :sync-for-iterator.{core::Iterator::current};
+ #t10.{core::List::add}(x);
+ }
+ }
+ } =>#t10;
+ {
+ core::Iterator<dynamic>* :sync-for-iterator = _in::unsafeCast<core::Iterable<dynamic>*>(d as{TypeError} core::Iterable<dynamic>).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ final dynamic #t11 = :sync-for-iterator.{core::Iterator::current};
+ {
+ core::int x = #t11 as{TypeError} core::int;
+ x;
+ }
+ }
+ }
+ block {
+ final core::List<core::int> #t12 = <core::int>[];
+ {
+ core::Iterator<dynamic>* :sync-for-iterator = _in::unsafeCast<core::Iterable<dynamic>*>(d as{TypeError} core::Iterable<dynamic>).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ final dynamic #t13 = :sync-for-iterator.{core::Iterator::current};
+ {
+ core::int x = #t13 as{TypeError} core::int;
+ #t12.{core::List::add}(x);
+ }
+ }
+ }
+ } =>#t12;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/later.dart b/pkg/front_end/testcases/nnbd/later.dart
new file mode 100644
index 0000000..c43f4b5
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/later.dart
@@ -0,0 +1,57 @@
+// 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 checks for compile-time errors and their absence for some use cases
+// of late fields and variables.
+
+class A {
+ int a = 42;
+ late int b = (this.a * 2) >> 1; // Ok.
+
+ foo(late int x) {}
+}
+
+bar(late int x) {}
+
+baz() {
+ try {
+ throw "baz";
+ } on dynamic catch (late e, late t) {}
+ for (late int i = 0; i < 10; ++i) {
+ print("baz");
+ }
+ for (late String s in ["baz"]) {
+ print(s);
+ }
+ [for (late int i = 0; i < 10; ++i) i];
+}
+
+hest() async {
+ await for (late String s in new Stream.fromIterable(["hest"])) {
+ print(s);
+ }
+ return "hest";
+}
+
+fisk() async {
+ late String s1 = await hest();
+ late String s2 = '${fisk}${await hest()}${fisk}';
+ late Function f = () async => await hest();
+}
+
+class B {
+ late final int x = 42;
+
+ const B();
+}
+
+class C {
+ late final int x;
+
+ initVars() {
+ x = 42; // Ok: [x] doesn't have an initializer.
+ }
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/later.dart.outline.expect b/pkg/front_end/testcases/nnbd/later.dart.outline.expect
new file mode 100644
index 0000000..c3b7544
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/later.dart.outline.expect
@@ -0,0 +1,48 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/later.dart:12:7: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// foo(late int x) {}
+// ^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:15:5: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// bar(late int x) {}
+// ^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ field core::int a;
+ late field core::int b;
+ synthetic constructor •() → self::A
+ ;
+ method foo(core::int x) → dynamic
+ ;
+}
+class B extends core::Object {
+ late final field core::int x = 42;
+ const constructor •() → self::B
+ : super core::Object::•()
+ ;
+}
+class C extends core::Object {
+ late final field core::int x;
+ synthetic constructor •() → self::C
+ ;
+ method initVars() → dynamic
+ ;
+}
+static method bar(core::int x) → dynamic
+ ;
+static method baz() → dynamic
+ ;
+static method hest() → dynamic
+ ;
+static method fisk() → dynamic
+ ;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/nnbd/later.dart.strong.expect b/pkg/front_end/testcases/nnbd/later.dart.strong.expect
new file mode 100644
index 0000000..723db80
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/later.dart.strong.expect
@@ -0,0 +1,131 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/later.dart:12:7: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// foo(late int x) {}
+// ^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:15:5: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// bar(late int x) {}
+// ^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:20:28: Error: 'catch' must be followed by '(identifier)' or '(identifier, identifier)'.
+// No types are needed, the first is given by 'on', the second is always 'StackTrace'.
+// } on dynamic catch (late e, late t) {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/later.dart:20:31: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// } on dynamic catch (late e, late t) {}
+// ^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:20:36: Error: 'catch' must be followed by '(identifier)' or '(identifier, identifier)'.
+// No types are needed, the first is given by 'on', the second is always 'StackTrace'.
+// } on dynamic catch (late e, late t) {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/later.dart:21:8: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// for (late int i = 0; i < 10; ++i) {
+// ^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:24:8: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// for (late String s in ["baz"]) {
+// ^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:27:9: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// [for (late int i = 0; i < 10; ++i) i];
+// ^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:31:14: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// await for (late String s in new Stream.fromIterable(["hest"])) {
+// ^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:38:20: Error: `await` expressions are not supported in late local initializers.
+// late String s1 = await hest();
+// ^^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:39:30: Error: `await` expressions are not supported in late local initializers.
+// late String s2 = '${fisk}${await hest()}${fisk}';
+// ^^^^^
+//
+import self as self;
+import "dart:core" as core;
+import "dart:async" as asy;
+
+class A extends core::Object {
+ field core::int a = 42;
+ late field core::int b = this.{self::A::a}.{core::num::*}(2).{core::int::>>}(1);
+ synthetic constructor •() → self::A
+ : super core::Object::•()
+ ;
+ method foo(core::int x) → dynamic {}
+}
+class B extends core::Object {
+ late final field core::int x = 42;
+ const constructor •() → self::B
+ : super core::Object::•()
+ ;
+}
+class C extends core::Object {
+ late final field core::int x;
+ synthetic constructor •() → self::C
+ : super core::Object::•()
+ ;
+ method initVars() → dynamic {
+ this.{self::C::x} = 42;
+ }
+}
+static method bar(core::int x) → dynamic {}
+static method baz() → dynamic {
+ {
+ {
+ invalid-expression "pkg/front_end/testcases/nnbd/later.dart:20:36: Error: 'catch' must be followed by '(identifier)' or '(identifier, identifier)'.
+No types are needed, the first is given by 'on', the second is always 'StackTrace'.
+ } on dynamic catch (late e, late t) {}
+ ^";
+ }
+ try {
+ throw "baz";
+ }
+ on dynamic catch(final dynamic late, final core::StackTrace e) {
+ }
+ }
+ for (late core::int i = 0; i.{core::num::<}(10); i = i.{core::num::+}(1)) {
+ core::print("baz");
+ }
+ for (late core::String s in <core::String>["baz"]) {
+ core::print(s);
+ }
+ block {
+ final core::List<core::int> #t1 = <core::int>[];
+ for (late core::int i = 0; i.{core::num::<}(10); i = i.{core::num::+}(1))
+ #t1.{core::List::add}(i);
+ } =>#t1;
+}
+static method hest() → dynamic async {
+ await for (late core::String s in asy::Stream::fromIterable<core::String>(<core::String*>["hest"])) {
+ core::print(s);
+ }
+ return "hest";
+}
+static method fisk() → dynamic async {
+ late core::String s1 = invalid-expression "pkg/front_end/testcases/nnbd/later.dart:38:20: Error: `await` expressions are not supported in late local initializers.
+ late String s1 = await hest();
+ ^^^^^" as{TypeError} core::String;
+ late core::String s2 = "${#C1}${invalid-expression "pkg/front_end/testcases/nnbd/later.dart:39:30: Error: `await` expressions are not supported in late local initializers.
+ late String s2 = '\${fisk}\${await hest()}\${fisk}';
+ ^^^^^"}${#C1}";
+ late core::Function f = () → asy::Future<dynamic> async => await self::hest();
+}
+static method main() → dynamic {}
+
+constants {
+ #C1 = tearoff self::fisk
+}
diff --git a/pkg/front_end/testcases/nnbd/later.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/later.dart.strong.transformed.expect
new file mode 100644
index 0000000..0973de4
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/later.dart.strong.transformed.expect
@@ -0,0 +1,248 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/later.dart:12:7: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// foo(late int x) {}
+// ^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:15:5: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// bar(late int x) {}
+// ^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:20:28: Error: 'catch' must be followed by '(identifier)' or '(identifier, identifier)'.
+// No types are needed, the first is given by 'on', the second is always 'StackTrace'.
+// } on dynamic catch (late e, late t) {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/later.dart:20:31: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// } on dynamic catch (late e, late t) {}
+// ^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:20:36: Error: 'catch' must be followed by '(identifier)' or '(identifier, identifier)'.
+// No types are needed, the first is given by 'on', the second is always 'StackTrace'.
+// } on dynamic catch (late e, late t) {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/later.dart:21:8: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// for (late int i = 0; i < 10; ++i) {
+// ^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:24:8: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// for (late String s in ["baz"]) {
+// ^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:27:9: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// [for (late int i = 0; i < 10; ++i) i];
+// ^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:31:14: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// await for (late String s in new Stream.fromIterable(["hest"])) {
+// ^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:38:20: Error: `await` expressions are not supported in late local initializers.
+// late String s1 = await hest();
+// ^^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:39:30: Error: `await` expressions are not supported in late local initializers.
+// late String s2 = '${fisk}${await hest()}${fisk}';
+// ^^^^^
+//
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+import "dart:async" as asy;
+
+class A extends core::Object {
+ field core::int a = 42;
+ late field core::int b = this.{self::A::a}.{core::num::*}(2).{core::int::>>}(1);
+ synthetic constructor •() → self::A
+ : super core::Object::•()
+ ;
+ method foo(core::int x) → dynamic {}
+}
+class B extends core::Object {
+ late final field core::int x = 42;
+ const constructor •() → self::B
+ : super core::Object::•()
+ ;
+}
+class C extends core::Object {
+ late final field core::int x;
+ synthetic constructor •() → self::C
+ : super core::Object::•()
+ ;
+ method initVars() → dynamic {
+ this.{self::C::x} = 42;
+ }
+}
+static method bar(core::int x) → dynamic {}
+static method baz() → dynamic {
+ {
+ {
+ invalid-expression "pkg/front_end/testcases/nnbd/later.dart:20:36: Error: 'catch' must be followed by '(identifier)' or '(identifier, identifier)'.
+No types are needed, the first is given by 'on', the second is always 'StackTrace'.
+ } on dynamic catch (late e, late t) {}
+ ^";
+ }
+ try {
+ throw "baz";
+ }
+ on dynamic catch(final dynamic late, final core::StackTrace e) {
+ }
+ }
+ for (late core::int i = 0; i.{core::num::<}(10); i = i.{core::num::+}(1)) {
+ core::print("baz");
+ }
+ {
+ core::Iterator<core::String*>* :sync-for-iterator = _in::unsafeCast<core::Iterable<core::String*>*>(<core::String>["baz"]).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ function #s#initializer() → core::String
+ return :sync-for-iterator.{core::Iterator::current};
+ late core::String s = #s#initializer.call();
+ {
+ core::print(s);
+ }
+ }
+ }
+ block {
+ final core::List<core::int> #t1 = <core::int>[];
+ for (late core::int i = 0; i.{core::num::<}(10); i = i.{core::num::+}(1))
+ #t1.{core::List::add}(i);
+ } =>#t1;
+}
+static method hest() → dynamic /* originally async */ {
+ final asy::_AsyncAwaitCompleter<dynamic> :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
+ asy::FutureOr<dynamic>? :return_value;
+ dynamic :async_stack_trace;
+ dynamic :async_op_then;
+ dynamic :async_op_error;
+ core::int :await_jump_var = 0;
+ dynamic :await_ctx_var;
+ dynamic :saved_try_context_var0;
+ dynamic :saved_try_context_var1;
+ dynamic :exception0;
+ dynamic :stack_trace0;
+ function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding
+ try {
+ #L1:
+ {
+ {
+ dynamic :stream = asy::Stream::fromIterable<core::String>(<core::String*>["hest"]);
+ asy::_asyncStarListenHelper(:stream, :async_op);
+ asy::_StreamIterator<core::String>? :for-iterator = new asy::_StreamIterator::•<core::String>(:stream);
+ try
+ #L2:
+ while (true) {
+ dynamic #t2 = asy::_asyncStarMoveNextHelper(:stream);
+ [yield] let dynamic #t3 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
+ if(_in::unsafeCast<core::bool*>(:result)) {
+ function #s#initializer() → core::String
+ return :for-iterator.{asy::_StreamIterator::current};
+ late core::String s = #s#initializer.call();
+ {
+ core::print(s);
+ }
+ }
+ else
+ break #L2;
+ }
+ finally
+ if(!:for-iterator.{asy::_StreamIterator::_subscription}.{core::Object::==}(null)) {
+ [yield] let dynamic #t4 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::cancel}(), :async_op_then, :async_op_error, :async_op) in null;
+ :result;
+ }
+ }
+ :return_value = "hest";
+ break #L1;
+ }
+ asy::_completeOnAsyncReturn(:async_completer, :return_value);
+ return;
+ }
+ on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+ :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+ }
+ :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+ :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+ :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+ :async_completer.start(:async_op);
+ return :async_completer.{asy::Completer::future};
+}
+static method fisk() → dynamic /* originally async */ {
+ final asy::_AsyncAwaitCompleter<dynamic> :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
+ asy::FutureOr<dynamic>? :return_value;
+ dynamic :async_stack_trace;
+ dynamic :async_op_then;
+ dynamic :async_op_error;
+ core::int :await_jump_var = 0;
+ dynamic :await_ctx_var;
+ function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding
+ try {
+ #L3:
+ {
+ function #s1#initializer() → core::String
+ return invalid-expression "pkg/front_end/testcases/nnbd/later.dart:38:20: Error: `await` expressions are not supported in late local initializers.
+ late String s1 = await hest();
+ ^^^^^" as{TypeError} core::String;
+ late core::String s1 = #s1#initializer.call();
+ function #s2#initializer() → core::String
+ return "${#C1}${invalid-expression "pkg/front_end/testcases/nnbd/later.dart:39:30: Error: `await` expressions are not supported in late local initializers.
+ late String s2 = '\${fisk}\${await hest()}\${fisk}';
+ ^^^^^"}${#C1}";
+ late core::String s2 = #s2#initializer.call();
+ function #f#initializer() → core::Function
+ return () → asy::Future<dynamic> /* originally async */ {
+ final asy::_AsyncAwaitCompleter<dynamic> :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
+ asy::FutureOr<dynamic>? :return_value;
+ dynamic :async_stack_trace;
+ dynamic :async_op_then;
+ dynamic :async_op_error;
+ core::int :await_jump_var = 0;
+ dynamic :await_ctx_var;
+ dynamic :saved_try_context_var0;
+ function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding
+ try {
+ #L4:
+ {
+ [yield] let dynamic #t5 = asy::_awaitHelper(self::hest(), :async_op_then, :async_op_error, :async_op) in null;
+ :return_value = :result;
+ break #L4;
+ }
+ asy::_completeOnAsyncReturn(:async_completer, :return_value);
+ return;
+ }
+ on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+ :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+ }
+ :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+ :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+ :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+ :async_completer.start(:async_op);
+ return :async_completer.{asy::Completer::future};
+ };
+ late core::Function f = #f#initializer.call();
+ }
+ asy::_completeOnAsyncReturn(:async_completer, :return_value);
+ return;
+ }
+ on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+ :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+ }
+ :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+ :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+ :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+ :async_completer.start(:async_op);
+ return :async_completer.{asy::Completer::future};
+}
+static method main() → dynamic {}
+
+constants {
+ #C1 = tearoff self::fisk
+}
diff --git a/pkg/front_end/testcases/nnbd/later.dart.weak.expect b/pkg/front_end/testcases/nnbd/later.dart.weak.expect
new file mode 100644
index 0000000..723db80
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/later.dart.weak.expect
@@ -0,0 +1,131 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/later.dart:12:7: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// foo(late int x) {}
+// ^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:15:5: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// bar(late int x) {}
+// ^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:20:28: Error: 'catch' must be followed by '(identifier)' or '(identifier, identifier)'.
+// No types are needed, the first is given by 'on', the second is always 'StackTrace'.
+// } on dynamic catch (late e, late t) {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/later.dart:20:31: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// } on dynamic catch (late e, late t) {}
+// ^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:20:36: Error: 'catch' must be followed by '(identifier)' or '(identifier, identifier)'.
+// No types are needed, the first is given by 'on', the second is always 'StackTrace'.
+// } on dynamic catch (late e, late t) {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/later.dart:21:8: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// for (late int i = 0; i < 10; ++i) {
+// ^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:24:8: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// for (late String s in ["baz"]) {
+// ^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:27:9: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// [for (late int i = 0; i < 10; ++i) i];
+// ^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:31:14: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// await for (late String s in new Stream.fromIterable(["hest"])) {
+// ^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:38:20: Error: `await` expressions are not supported in late local initializers.
+// late String s1 = await hest();
+// ^^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:39:30: Error: `await` expressions are not supported in late local initializers.
+// late String s2 = '${fisk}${await hest()}${fisk}';
+// ^^^^^
+//
+import self as self;
+import "dart:core" as core;
+import "dart:async" as asy;
+
+class A extends core::Object {
+ field core::int a = 42;
+ late field core::int b = this.{self::A::a}.{core::num::*}(2).{core::int::>>}(1);
+ synthetic constructor •() → self::A
+ : super core::Object::•()
+ ;
+ method foo(core::int x) → dynamic {}
+}
+class B extends core::Object {
+ late final field core::int x = 42;
+ const constructor •() → self::B
+ : super core::Object::•()
+ ;
+}
+class C extends core::Object {
+ late final field core::int x;
+ synthetic constructor •() → self::C
+ : super core::Object::•()
+ ;
+ method initVars() → dynamic {
+ this.{self::C::x} = 42;
+ }
+}
+static method bar(core::int x) → dynamic {}
+static method baz() → dynamic {
+ {
+ {
+ invalid-expression "pkg/front_end/testcases/nnbd/later.dart:20:36: Error: 'catch' must be followed by '(identifier)' or '(identifier, identifier)'.
+No types are needed, the first is given by 'on', the second is always 'StackTrace'.
+ } on dynamic catch (late e, late t) {}
+ ^";
+ }
+ try {
+ throw "baz";
+ }
+ on dynamic catch(final dynamic late, final core::StackTrace e) {
+ }
+ }
+ for (late core::int i = 0; i.{core::num::<}(10); i = i.{core::num::+}(1)) {
+ core::print("baz");
+ }
+ for (late core::String s in <core::String>["baz"]) {
+ core::print(s);
+ }
+ block {
+ final core::List<core::int> #t1 = <core::int>[];
+ for (late core::int i = 0; i.{core::num::<}(10); i = i.{core::num::+}(1))
+ #t1.{core::List::add}(i);
+ } =>#t1;
+}
+static method hest() → dynamic async {
+ await for (late core::String s in asy::Stream::fromIterable<core::String>(<core::String*>["hest"])) {
+ core::print(s);
+ }
+ return "hest";
+}
+static method fisk() → dynamic async {
+ late core::String s1 = invalid-expression "pkg/front_end/testcases/nnbd/later.dart:38:20: Error: `await` expressions are not supported in late local initializers.
+ late String s1 = await hest();
+ ^^^^^" as{TypeError} core::String;
+ late core::String s2 = "${#C1}${invalid-expression "pkg/front_end/testcases/nnbd/later.dart:39:30: Error: `await` expressions are not supported in late local initializers.
+ late String s2 = '\${fisk}\${await hest()}\${fisk}';
+ ^^^^^"}${#C1}";
+ late core::Function f = () → asy::Future<dynamic> async => await self::hest();
+}
+static method main() → dynamic {}
+
+constants {
+ #C1 = tearoff self::fisk
+}
diff --git a/pkg/front_end/testcases/nnbd/later.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/later.dart.weak.transformed.expect
new file mode 100644
index 0000000..0973de4
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/later.dart.weak.transformed.expect
@@ -0,0 +1,248 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/later.dart:12:7: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// foo(late int x) {}
+// ^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:15:5: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// bar(late int x) {}
+// ^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:20:28: Error: 'catch' must be followed by '(identifier)' or '(identifier, identifier)'.
+// No types are needed, the first is given by 'on', the second is always 'StackTrace'.
+// } on dynamic catch (late e, late t) {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/later.dart:20:31: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// } on dynamic catch (late e, late t) {}
+// ^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:20:36: Error: 'catch' must be followed by '(identifier)' or '(identifier, identifier)'.
+// No types are needed, the first is given by 'on', the second is always 'StackTrace'.
+// } on dynamic catch (late e, late t) {}
+// ^
+//
+// pkg/front_end/testcases/nnbd/later.dart:21:8: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// for (late int i = 0; i < 10; ++i) {
+// ^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:24:8: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// for (late String s in ["baz"]) {
+// ^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:27:9: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// [for (late int i = 0; i < 10; ++i) i];
+// ^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:31:14: Error: Can't have modifier 'late' here.
+// Try removing 'late'.
+// await for (late String s in new Stream.fromIterable(["hest"])) {
+// ^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:38:20: Error: `await` expressions are not supported in late local initializers.
+// late String s1 = await hest();
+// ^^^^^
+//
+// pkg/front_end/testcases/nnbd/later.dart:39:30: Error: `await` expressions are not supported in late local initializers.
+// late String s2 = '${fisk}${await hest()}${fisk}';
+// ^^^^^
+//
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+import "dart:async" as asy;
+
+class A extends core::Object {
+ field core::int a = 42;
+ late field core::int b = this.{self::A::a}.{core::num::*}(2).{core::int::>>}(1);
+ synthetic constructor •() → self::A
+ : super core::Object::•()
+ ;
+ method foo(core::int x) → dynamic {}
+}
+class B extends core::Object {
+ late final field core::int x = 42;
+ const constructor •() → self::B
+ : super core::Object::•()
+ ;
+}
+class C extends core::Object {
+ late final field core::int x;
+ synthetic constructor •() → self::C
+ : super core::Object::•()
+ ;
+ method initVars() → dynamic {
+ this.{self::C::x} = 42;
+ }
+}
+static method bar(core::int x) → dynamic {}
+static method baz() → dynamic {
+ {
+ {
+ invalid-expression "pkg/front_end/testcases/nnbd/later.dart:20:36: Error: 'catch' must be followed by '(identifier)' or '(identifier, identifier)'.
+No types are needed, the first is given by 'on', the second is always 'StackTrace'.
+ } on dynamic catch (late e, late t) {}
+ ^";
+ }
+ try {
+ throw "baz";
+ }
+ on dynamic catch(final dynamic late, final core::StackTrace e) {
+ }
+ }
+ for (late core::int i = 0; i.{core::num::<}(10); i = i.{core::num::+}(1)) {
+ core::print("baz");
+ }
+ {
+ core::Iterator<core::String*>* :sync-for-iterator = _in::unsafeCast<core::Iterable<core::String*>*>(<core::String>["baz"]).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ function #s#initializer() → core::String
+ return :sync-for-iterator.{core::Iterator::current};
+ late core::String s = #s#initializer.call();
+ {
+ core::print(s);
+ }
+ }
+ }
+ block {
+ final core::List<core::int> #t1 = <core::int>[];
+ for (late core::int i = 0; i.{core::num::<}(10); i = i.{core::num::+}(1))
+ #t1.{core::List::add}(i);
+ } =>#t1;
+}
+static method hest() → dynamic /* originally async */ {
+ final asy::_AsyncAwaitCompleter<dynamic> :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
+ asy::FutureOr<dynamic>? :return_value;
+ dynamic :async_stack_trace;
+ dynamic :async_op_then;
+ dynamic :async_op_error;
+ core::int :await_jump_var = 0;
+ dynamic :await_ctx_var;
+ dynamic :saved_try_context_var0;
+ dynamic :saved_try_context_var1;
+ dynamic :exception0;
+ dynamic :stack_trace0;
+ function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding
+ try {
+ #L1:
+ {
+ {
+ dynamic :stream = asy::Stream::fromIterable<core::String>(<core::String*>["hest"]);
+ asy::_asyncStarListenHelper(:stream, :async_op);
+ asy::_StreamIterator<core::String>? :for-iterator = new asy::_StreamIterator::•<core::String>(:stream);
+ try
+ #L2:
+ while (true) {
+ dynamic #t2 = asy::_asyncStarMoveNextHelper(:stream);
+ [yield] let dynamic #t3 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
+ if(_in::unsafeCast<core::bool*>(:result)) {
+ function #s#initializer() → core::String
+ return :for-iterator.{asy::_StreamIterator::current};
+ late core::String s = #s#initializer.call();
+ {
+ core::print(s);
+ }
+ }
+ else
+ break #L2;
+ }
+ finally
+ if(!:for-iterator.{asy::_StreamIterator::_subscription}.{core::Object::==}(null)) {
+ [yield] let dynamic #t4 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::cancel}(), :async_op_then, :async_op_error, :async_op) in null;
+ :result;
+ }
+ }
+ :return_value = "hest";
+ break #L1;
+ }
+ asy::_completeOnAsyncReturn(:async_completer, :return_value);
+ return;
+ }
+ on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+ :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+ }
+ :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+ :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+ :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+ :async_completer.start(:async_op);
+ return :async_completer.{asy::Completer::future};
+}
+static method fisk() → dynamic /* originally async */ {
+ final asy::_AsyncAwaitCompleter<dynamic> :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
+ asy::FutureOr<dynamic>? :return_value;
+ dynamic :async_stack_trace;
+ dynamic :async_op_then;
+ dynamic :async_op_error;
+ core::int :await_jump_var = 0;
+ dynamic :await_ctx_var;
+ function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding
+ try {
+ #L3:
+ {
+ function #s1#initializer() → core::String
+ return invalid-expression "pkg/front_end/testcases/nnbd/later.dart:38:20: Error: `await` expressions are not supported in late local initializers.
+ late String s1 = await hest();
+ ^^^^^" as{TypeError} core::String;
+ late core::String s1 = #s1#initializer.call();
+ function #s2#initializer() → core::String
+ return "${#C1}${invalid-expression "pkg/front_end/testcases/nnbd/later.dart:39:30: Error: `await` expressions are not supported in late local initializers.
+ late String s2 = '\${fisk}\${await hest()}\${fisk}';
+ ^^^^^"}${#C1}";
+ late core::String s2 = #s2#initializer.call();
+ function #f#initializer() → core::Function
+ return () → asy::Future<dynamic> /* originally async */ {
+ final asy::_AsyncAwaitCompleter<dynamic> :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
+ asy::FutureOr<dynamic>? :return_value;
+ dynamic :async_stack_trace;
+ dynamic :async_op_then;
+ dynamic :async_op_error;
+ core::int :await_jump_var = 0;
+ dynamic :await_ctx_var;
+ dynamic :saved_try_context_var0;
+ function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding
+ try {
+ #L4:
+ {
+ [yield] let dynamic #t5 = asy::_awaitHelper(self::hest(), :async_op_then, :async_op_error, :async_op) in null;
+ :return_value = :result;
+ break #L4;
+ }
+ asy::_completeOnAsyncReturn(:async_completer, :return_value);
+ return;
+ }
+ on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+ :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+ }
+ :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+ :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+ :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+ :async_completer.start(:async_op);
+ return :async_completer.{asy::Completer::future};
+ };
+ late core::Function f = #f#initializer.call();
+ }
+ asy::_completeOnAsyncReturn(:async_completer, :return_value);
+ return;
+ }
+ on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+ :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+ }
+ :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+ :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+ :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+ :async_completer.start(:async_op);
+ return :async_completer.{asy::Completer::future};
+}
+static method main() → dynamic {}
+
+constants {
+ #C1 = tearoff self::fisk
+}
diff --git a/pkg/front_end/testcases/nnbd/list_constructor.dart b/pkg/front_end/testcases/nnbd/list_constructor.dart
new file mode 100644
index 0000000..95543ad
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/list_constructor.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// The test checks that it's an error to invoke the default constructor of List
+// with potentially non-nullable type argument and specify the length.
+
+foo<T extends Object?>() {
+ new List<T>(42);
+ new List<int?>(42);
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/list_constructor.dart.outline.expect b/pkg/front_end/testcases/nnbd/list_constructor.dart.outline.expect
new file mode 100644
index 0000000..00f17da
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/list_constructor.dart.outline.expect
@@ -0,0 +1,8 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo<T extends core::Object? = core::Object?>() → dynamic
+ ;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/nnbd/list_constructor.dart.strong.expect b/pkg/front_end/testcases/nnbd/list_constructor.dart.strong.expect
new file mode 100644
index 0000000..638b5be
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/list_constructor.dart.strong.expect
@@ -0,0 +1,9 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo<T extends core::Object? = core::Object?>() → dynamic {
+ core::List::•<self::foo::T%>(42);
+ core::List::•<core::int?>(42);
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/list_constructor.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/list_constructor.dart.strong.transformed.expect
new file mode 100644
index 0000000..1f48f90
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/list_constructor.dart.strong.transformed.expect
@@ -0,0 +1,9 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo<T extends core::Object? = core::Object?>() → dynamic {
+ core::_List::•<self::foo::T%>(42);
+ core::_List::•<core::int?>(42);
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/list_constructor.dart.weak.expect b/pkg/front_end/testcases/nnbd/list_constructor.dart.weak.expect
new file mode 100644
index 0000000..638b5be
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/list_constructor.dart.weak.expect
@@ -0,0 +1,9 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo<T extends core::Object? = core::Object?>() → dynamic {
+ core::List::•<self::foo::T%>(42);
+ core::List::•<core::int?>(42);
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/list_constructor.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/list_constructor.dart.weak.transformed.expect
new file mode 100644
index 0000000..1f48f90
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/list_constructor.dart.weak.transformed.expect
@@ -0,0 +1,9 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo<T extends core::Object? = core::Object?>() → dynamic {
+ core::_List::•<self::foo::T%>(42);
+ core::_List::•<core::int?>(42);
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_in.dart b/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_in.dart
new file mode 100644
index 0000000..9db578a
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_in.dart
@@ -0,0 +1,55 @@
+// 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.5
+
+/*cfe.library: nnbd=false*/
+
+import 'member_inheritance_from_opt_in_lib.dart';
+
+class LegacyClass extends Class implements Interface {
+ int method3() => 0;
+
+ int method4() => 0;
+
+ int method6a(int a, int b) => 0;
+
+ int method6b(int a, [int b]) => 0;
+
+ int method6c([int a, int b]) => 0;
+
+ int method8a(int a, {int b: 0}) => 0;
+
+ int method8b({int a, int b: 0}) => 0;
+
+ int method10a(int a, {int b}) => 0;
+
+ int method10b({int a, int b}) => 0;
+
+ int get getter3 => 0;
+
+ int get getter4 => 0;
+
+ void set setter3(int value) {}
+
+ void set setter4(int value) {}
+
+ int field3;
+
+ int field4;
+
+ int get property3 => 0;
+
+ void set property3(int value) {}
+
+ int get property4 => 0;
+
+ void set property4(int value) {}
+
+ int property7;
+
+ int property8;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_in.dart.outline.expect b/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_in.dart.outline.expect
new file mode 100644
index 0000000..dcd675f
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_in.dart.outline.expect
@@ -0,0 +1,173 @@
+library;
+import self as self;
+import "member_inheritance_from_opt_in_lib.dart" as mem;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///member_inheritance_from_opt_in_lib.dart";
+
+class LegacyClass extends mem::Class implements mem::Interface {
+ field core::int* field3;
+ field core::int* field4;
+ field core::int* property7;
+ field core::int* property8;
+ synthetic constructor •() → self::LegacyClass*
+ ;
+ method method3() → core::int*
+ ;
+ method method4() → core::int*
+ ;
+ method method6a(core::int* a, core::int* b) → core::int*
+ ;
+ method method6b(core::int* a, [core::int* b]) → core::int*
+ ;
+ method method6c([core::int* a, core::int* b]) → core::int*
+ ;
+ method method8a(core::int* a, {core::int* b = 0}) → core::int*
+ ;
+ method method8b({core::int* a, core::int* b = 0}) → core::int*
+ ;
+ method method10a(core::int* a, {core::int* b}) → core::int*
+ ;
+ method method10b({core::int* a, core::int* b}) → core::int*
+ ;
+ get getter3() → core::int*
+ ;
+ get getter4() → core::int*
+ ;
+ set setter3(core::int* value) → void
+ ;
+ set setter4(core::int* value) → void
+ ;
+ get property3() → core::int*
+ ;
+ set property3(core::int* value) → void
+ ;
+ get property4() → core::int*
+ ;
+ set property4(core::int* value) → void
+ ;
+ abstract member-signature get property6() → core::int*;
+ abstract member-signature get getter1() → core::int*;
+ abstract member-signature get field1() → core::int*;
+ abstract member-signature get field2() → core::int*;
+ abstract member-signature get getter2() → core::int*;
+ abstract member-signature method method5a(core::int* a, core::int* b) → core::int*;
+ abstract member-signature method method9a(core::int* a, {core::int* b}) → core::int*;
+ abstract member-signature method method5c([core::int* a, core::int* b]) → core::int*;
+ abstract member-signature get property5() → core::int*;
+ abstract member-signature method method2() → core::int*;
+ abstract member-signature method method7a(core::int* a, {core::int* b}) → core::int*;
+ abstract member-signature method method5b(core::int* a, [core::int* b]) → core::int*;
+ abstract member-signature method method9b({core::int* a, core::int* b}) → core::int*;
+ abstract member-signature method method1() → core::int*;
+ abstract member-signature get property1() → core::int*;
+ abstract member-signature get property2() → core::int*;
+ abstract member-signature method method7b({core::int* a, core::int* b}) → core::int*;
+ abstract member-signature set setter1(core::int* value) → void;
+ abstract member-signature set property6(core::int* _) → void;
+ abstract member-signature set field1(core::int* _) → void;
+ abstract member-signature set field2(core::int* _) → void;
+ abstract member-signature set property5(core::int* _) → void;
+ abstract member-signature set setter2(core::int* value) → void;
+ abstract member-signature set property1(core::int* value) → void;
+ abstract member-signature set property2(core::int* value) → void;
+}
+static method main() → dynamic
+ ;
+
+library;
+import self as mem;
+import "dart:core" as core;
+
+abstract class Interface extends core::Object {
+ field core::int? field1;
+ field core::int field2;
+ field core::int field3;
+ field core::int? field4;
+ synthetic constructor •() → mem::Interface
+ ;
+ abstract method method1() → core::int?;
+ abstract method method2() → core::int;
+ abstract method method3() → core::int;
+ abstract method method4() → core::int?;
+ abstract method method5a(core::int a, core::int? b) → core::int;
+ abstract method method5b(core::int a, [core::int? b]) → core::int;
+ abstract method method5c([core::int a = 0, core::int? b]) → core::int;
+ abstract method method6a(core::int? a, core::int b) → core::int?;
+ abstract method method6b(core::int? a, [core::int b = 0]) → core::int?;
+ abstract method method6c([core::int? a, core::int b = 0]) → core::int?;
+ abstract method method7a(core::int a, {core::int? b}) → core::int;
+ abstract method method7b({core::int a = 0, core::int? b}) → core::int;
+ abstract method method8a(core::int? a, {core::int b = 0}) → core::int?;
+ abstract method method8b({core::int? a, core::int b = 0}) → core::int?;
+ abstract method method9a(core::int a, {required core::int? b}) → core::int;
+ abstract method method9b({required core::int a, required core::int? b}) → core::int;
+ abstract method method10a(core::int? a, {required core::int b}) → core::int?;
+ abstract method method10b({required core::int? a, required core::int b}) → core::int?;
+ abstract get getter1() → core::int?;
+ abstract get getter2() → core::int;
+ abstract get getter3() → core::int;
+ abstract get getter4() → core::int?;
+ abstract set setter1(core::int? value) → void;
+ abstract set setter2(core::int value) → void;
+ abstract set setter3(core::int value) → void;
+ abstract set setter4(core::int? value) → void;
+ abstract get property1() → core::int?;
+ abstract set property1(core::int? value) → void;
+ abstract get property2() → core::int;
+ abstract set property2(core::int value) → void;
+ abstract get property3() → core::int;
+ abstract set property3(core::int value) → void;
+ abstract get property4() → core::int?;
+ abstract set property4(core::int? value) → void;
+ abstract get property5() → core::int?;
+ abstract set property5(core::int? value) → void;
+ abstract get property6() → core::int;
+ abstract set property6(core::int value) → void;
+ abstract get property7() → core::int;
+ abstract set property7(core::int value) → void;
+ abstract get property8() → core::int?;
+ abstract set property8(core::int? value) → void;
+}
+class Class extends core::Object {
+ field core::int field1;
+ field core::int? field2;
+ field core::int property5;
+ field core::int? property6;
+ synthetic constructor •() → mem::Class
+ ;
+ method method1() → core::int
+ ;
+ method method2() → core::int?
+ ;
+ method method5a(core::int a, core::int? b) → core::int
+ ;
+ method method5b(core::int a, [core::int? b]) → core::int
+ ;
+ method method5c([core::int a = 0, core::int? b]) → core::int
+ ;
+ method method7a(core::int a, {core::int? b}) → core::int
+ ;
+ method method7b({core::int a = 0, core::int? b}) → core::int
+ ;
+ method method9a(core::int a, {required core::int? b}) → core::int
+ ;
+ method method9b({required core::int a, required core::int? b}) → core::int
+ ;
+ get getter1() → core::int
+ ;
+ get getter2() → core::int?
+ ;
+ set setter1(core::int value) → void
+ ;
+ set setter2(core::int? value) → void
+ ;
+ get property1() → core::int
+ ;
+ set property1(core::int value) → void
+ ;
+ get property2() → core::int?
+ ;
+ set property2(core::int? value) → void
+ ;
+}
diff --git a/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_in.dart.strong.expect b/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_in.dart.strong.expect
new file mode 100644
index 0000000..c6a3171
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_in.dart.strong.expect
@@ -0,0 +1,172 @@
+library;
+import self as self;
+import "member_inheritance_from_opt_in_lib.dart" as mem;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///member_inheritance_from_opt_in_lib.dart";
+
+class LegacyClass extends mem::Class implements mem::Interface {
+ field core::int* field3 = null;
+ field core::int* field4 = null;
+ field core::int* property7 = null;
+ field core::int* property8 = null;
+ synthetic constructor •() → self::LegacyClass*
+ : super mem::Class::•()
+ ;
+ method method3() → core::int*
+ return 0;
+ method method4() → core::int*
+ return 0;
+ method method6a(core::int* a, core::int* b) → core::int*
+ return 0;
+ method method6b(core::int* a, [core::int* b = #C1]) → core::int*
+ return 0;
+ method method6c([core::int* a = #C1, core::int* b = #C1]) → core::int*
+ return 0;
+ method method8a(core::int* a, {core::int* b = #C2}) → core::int*
+ return 0;
+ method method8b({core::int* a = #C1, core::int* b = #C2}) → core::int*
+ return 0;
+ method method10a(core::int* a, {core::int* b = #C1}) → core::int*
+ return 0;
+ method method10b({core::int* a = #C1, core::int* b = #C1}) → core::int*
+ return 0;
+ get getter3() → core::int*
+ return 0;
+ get getter4() → core::int*
+ return 0;
+ set setter3(core::int* value) → void {}
+ set setter4(core::int* value) → void {}
+ get property3() → core::int*
+ return 0;
+ set property3(core::int* value) → void {}
+ get property4() → core::int*
+ return 0;
+ set property4(core::int* value) → void {}
+ abstract member-signature get property6() → core::int*;
+ abstract member-signature get getter1() → core::int*;
+ abstract member-signature get field1() → core::int*;
+ abstract member-signature get field2() → core::int*;
+ abstract member-signature get getter2() → core::int*;
+ abstract member-signature method method5a(core::int* a, core::int* b) → core::int*;
+ abstract member-signature method method9a(core::int* a, {core::int* b = #C1}) → core::int*;
+ abstract member-signature method method5c([core::int* a = #C2, core::int* b = #C1]) → core::int*;
+ abstract member-signature get property5() → core::int*;
+ abstract member-signature method method2() → core::int*;
+ abstract member-signature method method7a(core::int* a, {core::int* b = #C1}) → core::int*;
+ abstract member-signature method method5b(core::int* a, [core::int* b = #C1]) → core::int*;
+ abstract member-signature method method9b({core::int* a = #C1, core::int* b = #C1}) → core::int*;
+ abstract member-signature method method1() → core::int*;
+ abstract member-signature get property1() → core::int*;
+ abstract member-signature get property2() → core::int*;
+ abstract member-signature method method7b({core::int* a = #C2, core::int* b = #C1}) → core::int*;
+ abstract member-signature set setter1(core::int* value) → void;
+ abstract member-signature set property6(core::int* _) → void;
+ abstract member-signature set field1(core::int* _) → void;
+ abstract member-signature set field2(core::int* _) → void;
+ abstract member-signature set property5(core::int* _) → void;
+ abstract member-signature set setter2(core::int* value) → void;
+ abstract member-signature set property1(core::int* value) → void;
+ abstract member-signature set property2(core::int* value) → void;
+}
+static method main() → dynamic {}
+
+library;
+import self as mem;
+import "dart:core" as core;
+
+abstract class Interface extends core::Object {
+ field core::int? field1 = null;
+ field core::int field2 = 0;
+ field core::int field3 = 0;
+ field core::int? field4 = null;
+ synthetic constructor •() → mem::Interface
+ : super core::Object::•()
+ ;
+ abstract method method1() → core::int?;
+ abstract method method2() → core::int;
+ abstract method method3() → core::int;
+ abstract method method4() → core::int?;
+ abstract method method5a(core::int a, core::int? b) → core::int;
+ abstract method method5b(core::int a, [core::int? b = #C1]) → core::int;
+ abstract method method5c([core::int a = #C2, core::int? b = #C1]) → core::int;
+ abstract method method6a(core::int? a, core::int b) → core::int?;
+ abstract method method6b(core::int? a, [core::int b = #C2]) → core::int?;
+ abstract method method6c([core::int? a = #C1, core::int b = #C2]) → core::int?;
+ abstract method method7a(core::int a, {core::int? b = #C1}) → core::int;
+ abstract method method7b({core::int a = #C2, core::int? b = #C1}) → core::int;
+ abstract method method8a(core::int? a, {core::int b = #C2}) → core::int?;
+ abstract method method8b({core::int? a = #C1, core::int b = #C2}) → core::int?;
+ abstract method method9a(core::int a, {required core::int? b = #C1}) → core::int;
+ abstract method method9b({required core::int a = #C1, required core::int? b = #C1}) → core::int;
+ abstract method method10a(core::int? a, {required core::int b = #C1}) → core::int?;
+ abstract method method10b({required core::int? a = #C1, required core::int b = #C1}) → core::int?;
+ abstract get getter1() → core::int?;
+ abstract get getter2() → core::int;
+ abstract get getter3() → core::int;
+ abstract get getter4() → core::int?;
+ abstract set setter1(core::int? value) → void;
+ abstract set setter2(core::int value) → void;
+ abstract set setter3(core::int value) → void;
+ abstract set setter4(core::int? value) → void;
+ abstract get property1() → core::int?;
+ abstract set property1(core::int? value) → void;
+ abstract get property2() → core::int;
+ abstract set property2(core::int value) → void;
+ abstract get property3() → core::int;
+ abstract set property3(core::int value) → void;
+ abstract get property4() → core::int?;
+ abstract set property4(core::int? value) → void;
+ abstract get property5() → core::int?;
+ abstract set property5(core::int? value) → void;
+ abstract get property6() → core::int;
+ abstract set property6(core::int value) → void;
+ abstract get property7() → core::int;
+ abstract set property7(core::int value) → void;
+ abstract get property8() → core::int?;
+ abstract set property8(core::int? value) → void;
+}
+class Class extends core::Object {
+ field core::int field1 = 0;
+ field core::int? field2 = null;
+ field core::int property5 = 0;
+ field core::int? property6 = null;
+ synthetic constructor •() → mem::Class
+ : super core::Object::•()
+ ;
+ method method1() → core::int
+ return 0;
+ method method2() → core::int?
+ return 0;
+ method method5a(core::int a, core::int? b) → core::int
+ return 0;
+ method method5b(core::int a, [core::int? b = #C1]) → core::int
+ return 0;
+ method method5c([core::int a = #C2, core::int? b = #C1]) → core::int
+ return 0;
+ method method7a(core::int a, {core::int? b = #C1}) → core::int
+ return 0;
+ method method7b({core::int a = #C2, core::int? b = #C1}) → core::int
+ return 0;
+ method method9a(core::int a, {required core::int? b = #C1}) → core::int
+ return 0;
+ method method9b({required core::int a = #C1, required core::int? b = #C1}) → core::int
+ return 0;
+ get getter1() → core::int
+ return 0;
+ get getter2() → core::int?
+ return 0;
+ set setter1(core::int value) → void {}
+ set setter2(core::int? value) → void {}
+ get property1() → core::int
+ return 0;
+ set property1(core::int value) → void {}
+ get property2() → core::int?
+ return 0;
+ set property2(core::int? value) → void {}
+}
+
+constants {
+ #C1 = null
+ #C2 = 0
+}
diff --git a/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_in.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_in.dart.strong.transformed.expect
new file mode 100644
index 0000000..c6a3171
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_in.dart.strong.transformed.expect
@@ -0,0 +1,172 @@
+library;
+import self as self;
+import "member_inheritance_from_opt_in_lib.dart" as mem;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///member_inheritance_from_opt_in_lib.dart";
+
+class LegacyClass extends mem::Class implements mem::Interface {
+ field core::int* field3 = null;
+ field core::int* field4 = null;
+ field core::int* property7 = null;
+ field core::int* property8 = null;
+ synthetic constructor •() → self::LegacyClass*
+ : super mem::Class::•()
+ ;
+ method method3() → core::int*
+ return 0;
+ method method4() → core::int*
+ return 0;
+ method method6a(core::int* a, core::int* b) → core::int*
+ return 0;
+ method method6b(core::int* a, [core::int* b = #C1]) → core::int*
+ return 0;
+ method method6c([core::int* a = #C1, core::int* b = #C1]) → core::int*
+ return 0;
+ method method8a(core::int* a, {core::int* b = #C2}) → core::int*
+ return 0;
+ method method8b({core::int* a = #C1, core::int* b = #C2}) → core::int*
+ return 0;
+ method method10a(core::int* a, {core::int* b = #C1}) → core::int*
+ return 0;
+ method method10b({core::int* a = #C1, core::int* b = #C1}) → core::int*
+ return 0;
+ get getter3() → core::int*
+ return 0;
+ get getter4() → core::int*
+ return 0;
+ set setter3(core::int* value) → void {}
+ set setter4(core::int* value) → void {}
+ get property3() → core::int*
+ return 0;
+ set property3(core::int* value) → void {}
+ get property4() → core::int*
+ return 0;
+ set property4(core::int* value) → void {}
+ abstract member-signature get property6() → core::int*;
+ abstract member-signature get getter1() → core::int*;
+ abstract member-signature get field1() → core::int*;
+ abstract member-signature get field2() → core::int*;
+ abstract member-signature get getter2() → core::int*;
+ abstract member-signature method method5a(core::int* a, core::int* b) → core::int*;
+ abstract member-signature method method9a(core::int* a, {core::int* b = #C1}) → core::int*;
+ abstract member-signature method method5c([core::int* a = #C2, core::int* b = #C1]) → core::int*;
+ abstract member-signature get property5() → core::int*;
+ abstract member-signature method method2() → core::int*;
+ abstract member-signature method method7a(core::int* a, {core::int* b = #C1}) → core::int*;
+ abstract member-signature method method5b(core::int* a, [core::int* b = #C1]) → core::int*;
+ abstract member-signature method method9b({core::int* a = #C1, core::int* b = #C1}) → core::int*;
+ abstract member-signature method method1() → core::int*;
+ abstract member-signature get property1() → core::int*;
+ abstract member-signature get property2() → core::int*;
+ abstract member-signature method method7b({core::int* a = #C2, core::int* b = #C1}) → core::int*;
+ abstract member-signature set setter1(core::int* value) → void;
+ abstract member-signature set property6(core::int* _) → void;
+ abstract member-signature set field1(core::int* _) → void;
+ abstract member-signature set field2(core::int* _) → void;
+ abstract member-signature set property5(core::int* _) → void;
+ abstract member-signature set setter2(core::int* value) → void;
+ abstract member-signature set property1(core::int* value) → void;
+ abstract member-signature set property2(core::int* value) → void;
+}
+static method main() → dynamic {}
+
+library;
+import self as mem;
+import "dart:core" as core;
+
+abstract class Interface extends core::Object {
+ field core::int? field1 = null;
+ field core::int field2 = 0;
+ field core::int field3 = 0;
+ field core::int? field4 = null;
+ synthetic constructor •() → mem::Interface
+ : super core::Object::•()
+ ;
+ abstract method method1() → core::int?;
+ abstract method method2() → core::int;
+ abstract method method3() → core::int;
+ abstract method method4() → core::int?;
+ abstract method method5a(core::int a, core::int? b) → core::int;
+ abstract method method5b(core::int a, [core::int? b = #C1]) → core::int;
+ abstract method method5c([core::int a = #C2, core::int? b = #C1]) → core::int;
+ abstract method method6a(core::int? a, core::int b) → core::int?;
+ abstract method method6b(core::int? a, [core::int b = #C2]) → core::int?;
+ abstract method method6c([core::int? a = #C1, core::int b = #C2]) → core::int?;
+ abstract method method7a(core::int a, {core::int? b = #C1}) → core::int;
+ abstract method method7b({core::int a = #C2, core::int? b = #C1}) → core::int;
+ abstract method method8a(core::int? a, {core::int b = #C2}) → core::int?;
+ abstract method method8b({core::int? a = #C1, core::int b = #C2}) → core::int?;
+ abstract method method9a(core::int a, {required core::int? b = #C1}) → core::int;
+ abstract method method9b({required core::int a = #C1, required core::int? b = #C1}) → core::int;
+ abstract method method10a(core::int? a, {required core::int b = #C1}) → core::int?;
+ abstract method method10b({required core::int? a = #C1, required core::int b = #C1}) → core::int?;
+ abstract get getter1() → core::int?;
+ abstract get getter2() → core::int;
+ abstract get getter3() → core::int;
+ abstract get getter4() → core::int?;
+ abstract set setter1(core::int? value) → void;
+ abstract set setter2(core::int value) → void;
+ abstract set setter3(core::int value) → void;
+ abstract set setter4(core::int? value) → void;
+ abstract get property1() → core::int?;
+ abstract set property1(core::int? value) → void;
+ abstract get property2() → core::int;
+ abstract set property2(core::int value) → void;
+ abstract get property3() → core::int;
+ abstract set property3(core::int value) → void;
+ abstract get property4() → core::int?;
+ abstract set property4(core::int? value) → void;
+ abstract get property5() → core::int?;
+ abstract set property5(core::int? value) → void;
+ abstract get property6() → core::int;
+ abstract set property6(core::int value) → void;
+ abstract get property7() → core::int;
+ abstract set property7(core::int value) → void;
+ abstract get property8() → core::int?;
+ abstract set property8(core::int? value) → void;
+}
+class Class extends core::Object {
+ field core::int field1 = 0;
+ field core::int? field2 = null;
+ field core::int property5 = 0;
+ field core::int? property6 = null;
+ synthetic constructor •() → mem::Class
+ : super core::Object::•()
+ ;
+ method method1() → core::int
+ return 0;
+ method method2() → core::int?
+ return 0;
+ method method5a(core::int a, core::int? b) → core::int
+ return 0;
+ method method5b(core::int a, [core::int? b = #C1]) → core::int
+ return 0;
+ method method5c([core::int a = #C2, core::int? b = #C1]) → core::int
+ return 0;
+ method method7a(core::int a, {core::int? b = #C1}) → core::int
+ return 0;
+ method method7b({core::int a = #C2, core::int? b = #C1}) → core::int
+ return 0;
+ method method9a(core::int a, {required core::int? b = #C1}) → core::int
+ return 0;
+ method method9b({required core::int a = #C1, required core::int? b = #C1}) → core::int
+ return 0;
+ get getter1() → core::int
+ return 0;
+ get getter2() → core::int?
+ return 0;
+ set setter1(core::int value) → void {}
+ set setter2(core::int? value) → void {}
+ get property1() → core::int
+ return 0;
+ set property1(core::int value) → void {}
+ get property2() → core::int?
+ return 0;
+ set property2(core::int? value) → void {}
+}
+
+constants {
+ #C1 = null
+ #C2 = 0
+}
diff --git a/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_in.dart.weak.expect b/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_in.dart.weak.expect
new file mode 100644
index 0000000..c6a3171
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_in.dart.weak.expect
@@ -0,0 +1,172 @@
+library;
+import self as self;
+import "member_inheritance_from_opt_in_lib.dart" as mem;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///member_inheritance_from_opt_in_lib.dart";
+
+class LegacyClass extends mem::Class implements mem::Interface {
+ field core::int* field3 = null;
+ field core::int* field4 = null;
+ field core::int* property7 = null;
+ field core::int* property8 = null;
+ synthetic constructor •() → self::LegacyClass*
+ : super mem::Class::•()
+ ;
+ method method3() → core::int*
+ return 0;
+ method method4() → core::int*
+ return 0;
+ method method6a(core::int* a, core::int* b) → core::int*
+ return 0;
+ method method6b(core::int* a, [core::int* b = #C1]) → core::int*
+ return 0;
+ method method6c([core::int* a = #C1, core::int* b = #C1]) → core::int*
+ return 0;
+ method method8a(core::int* a, {core::int* b = #C2}) → core::int*
+ return 0;
+ method method8b({core::int* a = #C1, core::int* b = #C2}) → core::int*
+ return 0;
+ method method10a(core::int* a, {core::int* b = #C1}) → core::int*
+ return 0;
+ method method10b({core::int* a = #C1, core::int* b = #C1}) → core::int*
+ return 0;
+ get getter3() → core::int*
+ return 0;
+ get getter4() → core::int*
+ return 0;
+ set setter3(core::int* value) → void {}
+ set setter4(core::int* value) → void {}
+ get property3() → core::int*
+ return 0;
+ set property3(core::int* value) → void {}
+ get property4() → core::int*
+ return 0;
+ set property4(core::int* value) → void {}
+ abstract member-signature get property6() → core::int*;
+ abstract member-signature get getter1() → core::int*;
+ abstract member-signature get field1() → core::int*;
+ abstract member-signature get field2() → core::int*;
+ abstract member-signature get getter2() → core::int*;
+ abstract member-signature method method5a(core::int* a, core::int* b) → core::int*;
+ abstract member-signature method method9a(core::int* a, {core::int* b = #C1}) → core::int*;
+ abstract member-signature method method5c([core::int* a = #C2, core::int* b = #C1]) → core::int*;
+ abstract member-signature get property5() → core::int*;
+ abstract member-signature method method2() → core::int*;
+ abstract member-signature method method7a(core::int* a, {core::int* b = #C1}) → core::int*;
+ abstract member-signature method method5b(core::int* a, [core::int* b = #C1]) → core::int*;
+ abstract member-signature method method9b({core::int* a = #C1, core::int* b = #C1}) → core::int*;
+ abstract member-signature method method1() → core::int*;
+ abstract member-signature get property1() → core::int*;
+ abstract member-signature get property2() → core::int*;
+ abstract member-signature method method7b({core::int* a = #C2, core::int* b = #C1}) → core::int*;
+ abstract member-signature set setter1(core::int* value) → void;
+ abstract member-signature set property6(core::int* _) → void;
+ abstract member-signature set field1(core::int* _) → void;
+ abstract member-signature set field2(core::int* _) → void;
+ abstract member-signature set property5(core::int* _) → void;
+ abstract member-signature set setter2(core::int* value) → void;
+ abstract member-signature set property1(core::int* value) → void;
+ abstract member-signature set property2(core::int* value) → void;
+}
+static method main() → dynamic {}
+
+library;
+import self as mem;
+import "dart:core" as core;
+
+abstract class Interface extends core::Object {
+ field core::int? field1 = null;
+ field core::int field2 = 0;
+ field core::int field3 = 0;
+ field core::int? field4 = null;
+ synthetic constructor •() → mem::Interface
+ : super core::Object::•()
+ ;
+ abstract method method1() → core::int?;
+ abstract method method2() → core::int;
+ abstract method method3() → core::int;
+ abstract method method4() → core::int?;
+ abstract method method5a(core::int a, core::int? b) → core::int;
+ abstract method method5b(core::int a, [core::int? b = #C1]) → core::int;
+ abstract method method5c([core::int a = #C2, core::int? b = #C1]) → core::int;
+ abstract method method6a(core::int? a, core::int b) → core::int?;
+ abstract method method6b(core::int? a, [core::int b = #C2]) → core::int?;
+ abstract method method6c([core::int? a = #C1, core::int b = #C2]) → core::int?;
+ abstract method method7a(core::int a, {core::int? b = #C1}) → core::int;
+ abstract method method7b({core::int a = #C2, core::int? b = #C1}) → core::int;
+ abstract method method8a(core::int? a, {core::int b = #C2}) → core::int?;
+ abstract method method8b({core::int? a = #C1, core::int b = #C2}) → core::int?;
+ abstract method method9a(core::int a, {required core::int? b = #C1}) → core::int;
+ abstract method method9b({required core::int a = #C1, required core::int? b = #C1}) → core::int;
+ abstract method method10a(core::int? a, {required core::int b = #C1}) → core::int?;
+ abstract method method10b({required core::int? a = #C1, required core::int b = #C1}) → core::int?;
+ abstract get getter1() → core::int?;
+ abstract get getter2() → core::int;
+ abstract get getter3() → core::int;
+ abstract get getter4() → core::int?;
+ abstract set setter1(core::int? value) → void;
+ abstract set setter2(core::int value) → void;
+ abstract set setter3(core::int value) → void;
+ abstract set setter4(core::int? value) → void;
+ abstract get property1() → core::int?;
+ abstract set property1(core::int? value) → void;
+ abstract get property2() → core::int;
+ abstract set property2(core::int value) → void;
+ abstract get property3() → core::int;
+ abstract set property3(core::int value) → void;
+ abstract get property4() → core::int?;
+ abstract set property4(core::int? value) → void;
+ abstract get property5() → core::int?;
+ abstract set property5(core::int? value) → void;
+ abstract get property6() → core::int;
+ abstract set property6(core::int value) → void;
+ abstract get property7() → core::int;
+ abstract set property7(core::int value) → void;
+ abstract get property8() → core::int?;
+ abstract set property8(core::int? value) → void;
+}
+class Class extends core::Object {
+ field core::int field1 = 0;
+ field core::int? field2 = null;
+ field core::int property5 = 0;
+ field core::int? property6 = null;
+ synthetic constructor •() → mem::Class
+ : super core::Object::•()
+ ;
+ method method1() → core::int
+ return 0;
+ method method2() → core::int?
+ return 0;
+ method method5a(core::int a, core::int? b) → core::int
+ return 0;
+ method method5b(core::int a, [core::int? b = #C1]) → core::int
+ return 0;
+ method method5c([core::int a = #C2, core::int? b = #C1]) → core::int
+ return 0;
+ method method7a(core::int a, {core::int? b = #C1}) → core::int
+ return 0;
+ method method7b({core::int a = #C2, core::int? b = #C1}) → core::int
+ return 0;
+ method method9a(core::int a, {required core::int? b = #C1}) → core::int
+ return 0;
+ method method9b({required core::int a = #C1, required core::int? b = #C1}) → core::int
+ return 0;
+ get getter1() → core::int
+ return 0;
+ get getter2() → core::int?
+ return 0;
+ set setter1(core::int value) → void {}
+ set setter2(core::int? value) → void {}
+ get property1() → core::int
+ return 0;
+ set property1(core::int value) → void {}
+ get property2() → core::int?
+ return 0;
+ set property2(core::int? value) → void {}
+}
+
+constants {
+ #C1 = null
+ #C2 = 0
+}
diff --git a/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_in.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_in.dart.weak.transformed.expect
new file mode 100644
index 0000000..c6a3171
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_in.dart.weak.transformed.expect
@@ -0,0 +1,172 @@
+library;
+import self as self;
+import "member_inheritance_from_opt_in_lib.dart" as mem;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///member_inheritance_from_opt_in_lib.dart";
+
+class LegacyClass extends mem::Class implements mem::Interface {
+ field core::int* field3 = null;
+ field core::int* field4 = null;
+ field core::int* property7 = null;
+ field core::int* property8 = null;
+ synthetic constructor •() → self::LegacyClass*
+ : super mem::Class::•()
+ ;
+ method method3() → core::int*
+ return 0;
+ method method4() → core::int*
+ return 0;
+ method method6a(core::int* a, core::int* b) → core::int*
+ return 0;
+ method method6b(core::int* a, [core::int* b = #C1]) → core::int*
+ return 0;
+ method method6c([core::int* a = #C1, core::int* b = #C1]) → core::int*
+ return 0;
+ method method8a(core::int* a, {core::int* b = #C2}) → core::int*
+ return 0;
+ method method8b({core::int* a = #C1, core::int* b = #C2}) → core::int*
+ return 0;
+ method method10a(core::int* a, {core::int* b = #C1}) → core::int*
+ return 0;
+ method method10b({core::int* a = #C1, core::int* b = #C1}) → core::int*
+ return 0;
+ get getter3() → core::int*
+ return 0;
+ get getter4() → core::int*
+ return 0;
+ set setter3(core::int* value) → void {}
+ set setter4(core::int* value) → void {}
+ get property3() → core::int*
+ return 0;
+ set property3(core::int* value) → void {}
+ get property4() → core::int*
+ return 0;
+ set property4(core::int* value) → void {}
+ abstract member-signature get property6() → core::int*;
+ abstract member-signature get getter1() → core::int*;
+ abstract member-signature get field1() → core::int*;
+ abstract member-signature get field2() → core::int*;
+ abstract member-signature get getter2() → core::int*;
+ abstract member-signature method method5a(core::int* a, core::int* b) → core::int*;
+ abstract member-signature method method9a(core::int* a, {core::int* b = #C1}) → core::int*;
+ abstract member-signature method method5c([core::int* a = #C2, core::int* b = #C1]) → core::int*;
+ abstract member-signature get property5() → core::int*;
+ abstract member-signature method method2() → core::int*;
+ abstract member-signature method method7a(core::int* a, {core::int* b = #C1}) → core::int*;
+ abstract member-signature method method5b(core::int* a, [core::int* b = #C1]) → core::int*;
+ abstract member-signature method method9b({core::int* a = #C1, core::int* b = #C1}) → core::int*;
+ abstract member-signature method method1() → core::int*;
+ abstract member-signature get property1() → core::int*;
+ abstract member-signature get property2() → core::int*;
+ abstract member-signature method method7b({core::int* a = #C2, core::int* b = #C1}) → core::int*;
+ abstract member-signature set setter1(core::int* value) → void;
+ abstract member-signature set property6(core::int* _) → void;
+ abstract member-signature set field1(core::int* _) → void;
+ abstract member-signature set field2(core::int* _) → void;
+ abstract member-signature set property5(core::int* _) → void;
+ abstract member-signature set setter2(core::int* value) → void;
+ abstract member-signature set property1(core::int* value) → void;
+ abstract member-signature set property2(core::int* value) → void;
+}
+static method main() → dynamic {}
+
+library;
+import self as mem;
+import "dart:core" as core;
+
+abstract class Interface extends core::Object {
+ field core::int? field1 = null;
+ field core::int field2 = 0;
+ field core::int field3 = 0;
+ field core::int? field4 = null;
+ synthetic constructor •() → mem::Interface
+ : super core::Object::•()
+ ;
+ abstract method method1() → core::int?;
+ abstract method method2() → core::int;
+ abstract method method3() → core::int;
+ abstract method method4() → core::int?;
+ abstract method method5a(core::int a, core::int? b) → core::int;
+ abstract method method5b(core::int a, [core::int? b = #C1]) → core::int;
+ abstract method method5c([core::int a = #C2, core::int? b = #C1]) → core::int;
+ abstract method method6a(core::int? a, core::int b) → core::int?;
+ abstract method method6b(core::int? a, [core::int b = #C2]) → core::int?;
+ abstract method method6c([core::int? a = #C1, core::int b = #C2]) → core::int?;
+ abstract method method7a(core::int a, {core::int? b = #C1}) → core::int;
+ abstract method method7b({core::int a = #C2, core::int? b = #C1}) → core::int;
+ abstract method method8a(core::int? a, {core::int b = #C2}) → core::int?;
+ abstract method method8b({core::int? a = #C1, core::int b = #C2}) → core::int?;
+ abstract method method9a(core::int a, {required core::int? b = #C1}) → core::int;
+ abstract method method9b({required core::int a = #C1, required core::int? b = #C1}) → core::int;
+ abstract method method10a(core::int? a, {required core::int b = #C1}) → core::int?;
+ abstract method method10b({required core::int? a = #C1, required core::int b = #C1}) → core::int?;
+ abstract get getter1() → core::int?;
+ abstract get getter2() → core::int;
+ abstract get getter3() → core::int;
+ abstract get getter4() → core::int?;
+ abstract set setter1(core::int? value) → void;
+ abstract set setter2(core::int value) → void;
+ abstract set setter3(core::int value) → void;
+ abstract set setter4(core::int? value) → void;
+ abstract get property1() → core::int?;
+ abstract set property1(core::int? value) → void;
+ abstract get property2() → core::int;
+ abstract set property2(core::int value) → void;
+ abstract get property3() → core::int;
+ abstract set property3(core::int value) → void;
+ abstract get property4() → core::int?;
+ abstract set property4(core::int? value) → void;
+ abstract get property5() → core::int?;
+ abstract set property5(core::int? value) → void;
+ abstract get property6() → core::int;
+ abstract set property6(core::int value) → void;
+ abstract get property7() → core::int;
+ abstract set property7(core::int value) → void;
+ abstract get property8() → core::int?;
+ abstract set property8(core::int? value) → void;
+}
+class Class extends core::Object {
+ field core::int field1 = 0;
+ field core::int? field2 = null;
+ field core::int property5 = 0;
+ field core::int? property6 = null;
+ synthetic constructor •() → mem::Class
+ : super core::Object::•()
+ ;
+ method method1() → core::int
+ return 0;
+ method method2() → core::int?
+ return 0;
+ method method5a(core::int a, core::int? b) → core::int
+ return 0;
+ method method5b(core::int a, [core::int? b = #C1]) → core::int
+ return 0;
+ method method5c([core::int a = #C2, core::int? b = #C1]) → core::int
+ return 0;
+ method method7a(core::int a, {core::int? b = #C1}) → core::int
+ return 0;
+ method method7b({core::int a = #C2, core::int? b = #C1}) → core::int
+ return 0;
+ method method9a(core::int a, {required core::int? b = #C1}) → core::int
+ return 0;
+ method method9b({required core::int a = #C1, required core::int? b = #C1}) → core::int
+ return 0;
+ get getter1() → core::int
+ return 0;
+ get getter2() → core::int?
+ return 0;
+ set setter1(core::int value) → void {}
+ set setter2(core::int? value) → void {}
+ get property1() → core::int
+ return 0;
+ set property1(core::int value) → void {}
+ get property2() → core::int?
+ return 0;
+ set property2(core::int? value) → void {}
+}
+
+constants {
+ #C1 = null
+ #C2 = 0
+}
diff --git a/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_in_lib.dart b/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_in_lib.dart
new file mode 100644
index 0000000..596f43a
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_in_lib.dart
@@ -0,0 +1,141 @@
+// 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.
+
+abstract class Interface {
+ int? method1();
+
+ int method2();
+
+ int method3();
+
+ int? method4();
+
+ int method5a(int a, int? b);
+
+ int method5b(int a, [int? b]);
+
+ int method5c([int a = 0, int? b]);
+
+ int? method6a(int? a, int b);
+
+ int? method6b(int? a, [int b = 0]);
+
+ int? method6c([int? a, int b = 0]);
+
+ int method7a(int a, {int? b});
+
+ int method7b({int a: 0, int? b});
+
+ int? method8a(int? a, {int b: 0});
+
+ int? method8b({int? a, int b: 0});
+
+ int method9a(int a, {required int? b});
+
+ int method9b({required int a, required int? b});
+
+ int? method10a(int? a, {required int b});
+
+ int? method10b({required int? a, required int b});
+
+ int? get getter1;
+
+ int get getter2;
+
+ int get getter3;
+
+ int? get getter4;
+
+ void set setter1(int? value);
+
+ void set setter2(int value);
+
+ void set setter3(int value);
+
+ void set setter4(int? value);
+
+ int? field1;
+
+ int field2 = 0;
+
+ int field3 = 0;
+
+ int? field4;
+
+ int? get property1;
+
+ void set property1(int? value);
+
+ int get property2;
+
+ void set property2(int value);
+
+ int get property3;
+
+ void set property3(int value);
+
+ int? get property4;
+
+ void set property4(int? value);
+
+ int? get property5;
+
+ void set property5(int? value);
+
+ int get property6;
+
+ void set property6(int value);
+
+ int get property7;
+
+ void set property7(int value);
+
+ int? get property8;
+
+ void set property8(int? value);
+}
+
+class Class {
+ int method1() => 0;
+
+ int? method2() => 0;
+
+ int method5a(int a, int? b) => 0;
+
+ int method5b(int a, [int? b]) => 0;
+
+ int method5c([int a = 0, int? b]) => 0;
+
+ int method7a(int a, {int? b}) => 0;
+
+ int method7b({int a = 0, int? b}) => 0;
+
+ int method9a(int a, {required int? b}) => 0;
+
+ int method9b({required int a, required int? b}) => 0;
+
+ int get getter1 => 0;
+
+ int? get getter2 => 0;
+
+ void set setter1(int value) {}
+
+ void set setter2(int? value) {}
+
+ int field1 = 0;
+
+ int? field2;
+
+ int get property1 => 0;
+
+ void set property1(int value) {}
+
+ int? get property2 => 0;
+
+ void set property2(int? value) {}
+
+ int property5 = 0;
+
+ int? property6;
+}
diff --git a/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_out.dart b/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_out.dart
new file mode 100644
index 0000000..cd4a076
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_out.dart
@@ -0,0 +1,143 @@
+// 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.
+
+library main;
+
+import 'member_inheritance_from_opt_out_lib.dart';
+
+abstract class Interface {
+ int method1();
+
+ int? method2();
+
+ int method3a(int a, int b);
+
+ int method3b(int a, [int b]);
+
+ int method3c([int a, int b]);
+
+ int? method4a(int? a, int? b);
+
+ int? method4b(int? a, [int? b]);
+
+ int? method4c([int? a, int? b]);
+
+ int method5a(int a, {int b: 0});
+
+ int method5b({int a: 0, int b: 0});
+
+ int method5c({required int a, required int b});
+
+ int? method6a(int? a, {int? b});
+
+ int? method6b({int? a, int? b});
+
+ int? method6c({required int? a, required int? b});
+
+ int get getter1;
+
+ int? get getter2;
+
+ void set setter1(int value);
+
+ void set setter2(int? value);
+
+ int field1 = 0;
+
+ int? field2;
+
+ int get field3;
+
+ void set field3(int value);
+
+ int? get field4;
+
+ void set field4(int? value);
+
+ int get property1;
+
+ void set property1(int value);
+
+ int? get property2;
+
+ void set property2(int? value);
+
+ int property3 = 0;
+
+ int? property4;
+}
+
+class Class1 extends LegacyClass {}
+
+class Class2a extends LegacyClass implements Interface {}
+
+class Class2b extends LegacyClass implements Interface {
+ int method1() => 0;
+
+ int? method2() => 0;
+
+ int method3a(int a, int b) => 0;
+
+ int method3b(int a, [int b]) => 0;
+
+ int method3c([int a, int b]) => 0;
+
+ int? method4a(int? a, int? b) => 0;
+
+ int? method4b(int? a, [int? b]) => 0;
+
+ int? method4c([int? a, int? b]) => 0;
+
+ int method5a(int a, {int b: 0}) => 0;
+
+ int method5b({int a: 0, int b: 0}) => 0;
+
+ int method5c({required int a, required int b}) => 0;
+
+ int? method6a(int? a, {int? b}) => 0;
+
+ int? method6b({int? a, int? b}) => 0;
+
+ int? method6c({required int? a, required int? b}) => 0;
+
+ int get getter1 => 0;
+
+ int? get getter2 => 0;
+
+ void set setter1(int value) {}
+
+ void set setter2(int? value) {}
+
+ int field1 = 0;
+
+ int? field2;
+
+ int get field3 => 0;
+
+ void set field3(int value) {}
+
+ int? get field4 => 0;
+
+ void set field4(int? value) {}
+
+ int get property1 => 0;
+
+ void set property1(int value) {}
+
+ int? get property2 => 0;
+
+ void set property2(int? value) {}
+
+ int property3 = 0;
+
+ int? property4;
+}
+
+class Class3a extends GenericLegacyClass<int> {}
+
+class Class3b extends GenericLegacyClass<int?> {}
+
+class Class3c<S> extends GenericLegacyClass<S> {}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_out.dart.outline.expect b/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_out.dart.outline.expect
new file mode 100644
index 0000000..ea1d831
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_out.dart.outline.expect
@@ -0,0 +1,228 @@
+library main;
+import self as self;
+import "dart:core" as core;
+import "member_inheritance_from_opt_out_lib.dart" as opt;
+
+import "org-dartlang-testcase:///member_inheritance_from_opt_out_lib.dart";
+
+abstract class Interface extends core::Object {
+ field core::int field1;
+ field core::int? field2;
+ field core::int property3;
+ field core::int? property4;
+ synthetic constructor •() → self::Interface
+ ;
+ abstract method method1() → core::int;
+ abstract method method2() → core::int?;
+ abstract method method3a(core::int a, core::int b) → core::int;
+ abstract method method3b(core::int a, [core::int b]) → core::int;
+ abstract method method3c([core::int a, core::int b]) → core::int;
+ abstract method method4a(core::int? a, core::int? b) → core::int?;
+ abstract method method4b(core::int? a, [core::int? b]) → core::int?;
+ abstract method method4c([core::int? a, core::int? b]) → core::int?;
+ abstract method method5a(core::int a, {core::int b = 0}) → core::int;
+ abstract method method5b({core::int a = 0, core::int b = 0}) → core::int;
+ abstract method method5c({required core::int a, required core::int b}) → core::int;
+ abstract method method6a(core::int? a, {core::int? b}) → core::int?;
+ abstract method method6b({core::int? a, core::int? b}) → core::int?;
+ abstract method method6c({required core::int? a, required core::int? b}) → core::int?;
+ abstract get getter1() → core::int;
+ abstract get getter2() → core::int?;
+ abstract set setter1(core::int value) → void;
+ abstract set setter2(core::int? value) → void;
+ abstract get field3() → core::int;
+ abstract set field3(core::int value) → void;
+ abstract get field4() → core::int?;
+ abstract set field4(core::int? value) → void;
+ abstract get property1() → core::int;
+ abstract set property1(core::int value) → void;
+ abstract get property2() → core::int?;
+ abstract set property2(core::int? value) → void;
+}
+class Class1 extends opt::LegacyClass {
+ synthetic constructor •() → self::Class1
+ ;
+}
+class Class2a extends opt::LegacyClass implements self::Interface {
+ synthetic constructor •() → self::Class2a
+ ;
+ abstract member-signature method method4a(core::int? a, core::int? b) → core::int?;
+ abstract member-signature method method4c([core::int? a, core::int? b]) → core::int?;
+ abstract member-signature get getter1() → core::int;
+ abstract member-signature get field1() → core::int;
+ abstract member-signature method method3a(core::int a, core::int b) → core::int;
+ abstract member-signature get field4() → core::int?;
+ abstract member-signature get property3() → core::int;
+ abstract member-signature get field2() → core::int?;
+ abstract member-signature method method6a(core::int? a, {core::int? b}) → core::int?;
+ abstract member-signature get getter2() → core::int?;
+ abstract member-signature method method5a(core::int a, {core::int b}) → core::int;
+ abstract member-signature method method5c({core::int a, core::int b}) → core::int;
+ abstract member-signature get property4() → core::int?;
+ abstract member-signature method method6b({core::int? a, core::int? b}) → core::int?;
+ abstract member-signature method method6c({core::int? a, core::int? b}) → core::int?;
+ abstract member-signature method method2() → core::int?;
+ abstract member-signature method method5b({core::int a, core::int b}) → core::int;
+ abstract member-signature method method4b(core::int? a, [core::int? b]) → core::int?;
+ abstract member-signature get field3() → core::int;
+ abstract member-signature method method3c([core::int a, core::int b]) → core::int;
+ abstract member-signature method method1() → core::int;
+ abstract member-signature get property1() → core::int;
+ abstract member-signature get property2() → core::int?;
+ abstract member-signature method method3b(core::int a, [core::int b]) → core::int;
+ abstract member-signature set setter1(core::int value) → void;
+ abstract member-signature set field1(core::int _) → void;
+ abstract member-signature set field4(core::int? _) → void;
+ abstract member-signature set property3(core::int value) → void;
+ abstract member-signature set field2(core::int? _) → void;
+ abstract member-signature set property4(core::int? value) → void;
+ abstract member-signature set setter2(core::int? value) → void;
+ abstract member-signature set field3(core::int _) → void;
+ abstract member-signature set property1(core::int value) → void;
+ abstract member-signature set property2(core::int? value) → void;
+}
+class Class2b extends opt::LegacyClass implements self::Interface {
+ field core::int field1;
+ field core::int? field2;
+ field core::int property3;
+ field core::int? property4;
+ synthetic constructor •() → self::Class2b
+ ;
+ method method1() → core::int
+ ;
+ method method2() → core::int?
+ ;
+ method method3a(core::int a, core::int b) → core::int
+ ;
+ method method3b(core::int a, [core::int b]) → core::int
+ ;
+ method method3c([core::int a, core::int b]) → core::int
+ ;
+ method method4a(core::int? a, core::int? b) → core::int?
+ ;
+ method method4b(core::int? a, [core::int? b]) → core::int?
+ ;
+ method method4c([core::int? a, core::int? b]) → core::int?
+ ;
+ method method5a(core::int a, {core::int b = 0}) → core::int
+ ;
+ method method5b({core::int a = 0, core::int b = 0}) → core::int
+ ;
+ method method5c({required core::int a, required core::int b}) → core::int
+ ;
+ method method6a(core::int? a, {core::int? b}) → core::int?
+ ;
+ method method6b({core::int? a, core::int? b}) → core::int?
+ ;
+ method method6c({required core::int? a, required core::int? b}) → core::int?
+ ;
+ get getter1() → core::int
+ ;
+ get getter2() → core::int?
+ ;
+ set setter1(core::int value) → void
+ ;
+ set setter2(core::int? value) → void
+ ;
+ get field3() → core::int
+ ;
+ set field3(core::int value) → void
+ ;
+ get field4() → core::int?
+ ;
+ set field4(core::int? value) → void
+ ;
+ get property1() → core::int
+ ;
+ set property1(core::int value) → void
+ ;
+ get property2() → core::int?
+ ;
+ set property2(core::int? value) → void
+ ;
+}
+class Class3a extends opt::GenericLegacyClass<core::int> {
+ synthetic constructor •() → self::Class3a
+ ;
+}
+class Class3b extends opt::GenericLegacyClass<core::int?> {
+ synthetic constructor •() → self::Class3b
+ ;
+}
+class Class3c<S extends core::Object? = dynamic> extends opt::GenericLegacyClass<self::Class3c::S%> {
+ synthetic constructor •() → self::Class3c<self::Class3c::S%>
+ ;
+}
+static method main() → dynamic
+ ;
+
+library opt_out;
+import self as opt;
+import "dart:core" as core;
+
+class LegacyClass extends core::Object {
+ field core::int* field1;
+ field core::int* field2;
+ field core::int* field3;
+ field core::int* field4;
+ synthetic constructor •() → opt::LegacyClass*
+ ;
+ method method1() → core::int*
+ ;
+ method method2() → core::int*
+ ;
+ method method3a(core::int* a, core::int* b) → core::int*
+ ;
+ method method3b(core::int* a, [core::int* b]) → core::int*
+ ;
+ method method3c([core::int* a, core::int* b]) → core::int*
+ ;
+ method method4a(core::int* a, core::int* b) → core::int*
+ ;
+ method method4b(core::int* a, [core::int* b]) → core::int*
+ ;
+ method method4c([core::int* a, core::int* b]) → core::int*
+ ;
+ method method5a(core::int* a, {core::int* b}) → core::int*
+ ;
+ method method5b({core::int* a, core::int* b}) → core::int*
+ ;
+ method method5c({core::int* a, core::int* b}) → core::int*
+ ;
+ method method6a(core::int* a, {core::int* b}) → core::int*
+ ;
+ method method6b({core::int* a, core::int* b}) → core::int*
+ ;
+ method method6c({core::int* a, core::int* b}) → core::int*
+ ;
+ get getter1() → core::int*
+ ;
+ get getter2() → core::int*
+ ;
+ set setter1(core::int* value) → void
+ ;
+ set setter2(core::int* value) → void
+ ;
+ get property1() → core::int*
+ ;
+ set property1(core::int* value) → void
+ ;
+ get property2() → core::int*
+ ;
+ set property2(core::int* value) → void
+ ;
+ get property3() → core::int*
+ ;
+ set property3(core::int* value) → void
+ ;
+ get property4() → core::int*
+ ;
+ set property4(core::int* value) → void
+ ;
+}
+class GenericLegacyClass<T extends core::Object* = dynamic> extends core::Object {
+ synthetic constructor •() → opt::GenericLegacyClass<opt::GenericLegacyClass::T*>*
+ ;
+ method method1() → opt::GenericLegacyClass::T*
+ ;
+}
diff --git a/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_out.dart.strong.expect b/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_out.dart.strong.expect
new file mode 100644
index 0000000..0f04f45
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_out.dart.strong.expect
@@ -0,0 +1,229 @@
+library main;
+import self as self;
+import "dart:core" as core;
+import "member_inheritance_from_opt_out_lib.dart" as opt;
+
+import "org-dartlang-testcase:///member_inheritance_from_opt_out_lib.dart";
+
+abstract class Interface extends core::Object {
+ field core::int field1 = 0;
+ field core::int? field2 = null;
+ field core::int property3 = 0;
+ field core::int? property4 = null;
+ synthetic constructor •() → self::Interface
+ : super core::Object::•()
+ ;
+ abstract method method1() → core::int;
+ abstract method method2() → core::int?;
+ abstract method method3a(core::int a, core::int b) → core::int;
+ abstract method method3b(core::int a, [core::int b = #C1]) → core::int;
+ abstract method method3c([core::int a = #C1, core::int b = #C1]) → core::int;
+ abstract method method4a(core::int? a, core::int? b) → core::int?;
+ abstract method method4b(core::int? a, [core::int? b = #C1]) → core::int?;
+ abstract method method4c([core::int? a = #C1, core::int? b = #C1]) → core::int?;
+ abstract method method5a(core::int a, {core::int b = #C2}) → core::int;
+ abstract method method5b({core::int a = #C2, core::int b = #C2}) → core::int;
+ abstract method method5c({required core::int a = #C1, required core::int b = #C1}) → core::int;
+ abstract method method6a(core::int? a, {core::int? b = #C1}) → core::int?;
+ abstract method method6b({core::int? a = #C1, core::int? b = #C1}) → core::int?;
+ abstract method method6c({required core::int? a = #C1, required core::int? b = #C1}) → core::int?;
+ abstract get getter1() → core::int;
+ abstract get getter2() → core::int?;
+ abstract set setter1(core::int value) → void;
+ abstract set setter2(core::int? value) → void;
+ abstract get field3() → core::int;
+ abstract set field3(core::int value) → void;
+ abstract get field4() → core::int?;
+ abstract set field4(core::int? value) → void;
+ abstract get property1() → core::int;
+ abstract set property1(core::int value) → void;
+ abstract get property2() → core::int?;
+ abstract set property2(core::int? value) → void;
+}
+class Class1 extends opt::LegacyClass {
+ synthetic constructor •() → self::Class1
+ : super opt::LegacyClass::•()
+ ;
+}
+class Class2a extends opt::LegacyClass implements self::Interface {
+ synthetic constructor •() → self::Class2a
+ : super opt::LegacyClass::•()
+ ;
+ abstract member-signature method method4a(core::int? a, core::int? b) → core::int?;
+ abstract member-signature method method4c([core::int? a = #C1, core::int? b = #C1]) → core::int?;
+ abstract member-signature get getter1() → core::int;
+ abstract member-signature get field1() → core::int;
+ abstract member-signature method method3a(core::int a, core::int b) → core::int;
+ abstract member-signature get field4() → core::int?;
+ abstract member-signature get property3() → core::int;
+ abstract member-signature get field2() → core::int?;
+ abstract member-signature method method6a(core::int? a, {core::int? b = #C1}) → core::int?;
+ abstract member-signature get getter2() → core::int?;
+ abstract member-signature method method5a(core::int a, {core::int b = #C1}) → core::int;
+ abstract member-signature method method5c({core::int a = #C1, core::int b = #C1}) → core::int;
+ abstract member-signature get property4() → core::int?;
+ abstract member-signature method method6b({core::int? a = #C1, core::int? b = #C1}) → core::int?;
+ abstract member-signature method method6c({core::int? a = #C1, core::int? b = #C1}) → core::int?;
+ abstract member-signature method method2() → core::int?;
+ abstract member-signature method method5b({core::int a = #C1, core::int b = #C1}) → core::int;
+ abstract member-signature method method4b(core::int? a, [core::int? b = #C1]) → core::int?;
+ abstract member-signature get field3() → core::int;
+ abstract member-signature method method3c([core::int a = #C1, core::int b = #C1]) → core::int;
+ abstract member-signature method method1() → core::int;
+ abstract member-signature get property1() → core::int;
+ abstract member-signature get property2() → core::int?;
+ abstract member-signature method method3b(core::int a, [core::int b = #C1]) → core::int;
+ abstract member-signature set setter1(core::int value) → void;
+ abstract member-signature set field1(core::int _) → void;
+ abstract member-signature set field4(core::int? _) → void;
+ abstract member-signature set property3(core::int value) → void;
+ abstract member-signature set field2(core::int? _) → void;
+ abstract member-signature set property4(core::int? value) → void;
+ abstract member-signature set setter2(core::int? value) → void;
+ abstract member-signature set field3(core::int _) → void;
+ abstract member-signature set property1(core::int value) → void;
+ abstract member-signature set property2(core::int? value) → void;
+}
+class Class2b extends opt::LegacyClass implements self::Interface {
+ field core::int field1 = 0;
+ field core::int? field2 = null;
+ field core::int property3 = 0;
+ field core::int? property4 = null;
+ synthetic constructor •() → self::Class2b
+ : super opt::LegacyClass::•()
+ ;
+ method method1() → core::int
+ return 0;
+ method method2() → core::int?
+ return 0;
+ method method3a(core::int a, core::int b) → core::int
+ return 0;
+ method method3b(core::int a, [core::int b = #C1]) → core::int
+ return 0;
+ method method3c([core::int a = #C1, core::int b = #C1]) → core::int
+ return 0;
+ method method4a(core::int? a, core::int? b) → core::int?
+ return 0;
+ method method4b(core::int? a, [core::int? b = #C1]) → core::int?
+ return 0;
+ method method4c([core::int? a = #C1, core::int? b = #C1]) → core::int?
+ return 0;
+ method method5a(core::int a, {core::int b = #C2}) → core::int
+ return 0;
+ method method5b({core::int a = #C2, core::int b = #C2}) → core::int
+ return 0;
+ method method5c({required core::int a = #C1, required core::int b = #C1}) → core::int
+ return 0;
+ method method6a(core::int? a, {core::int? b = #C1}) → core::int?
+ return 0;
+ method method6b({core::int? a = #C1, core::int? b = #C1}) → core::int?
+ return 0;
+ method method6c({required core::int? a = #C1, required core::int? b = #C1}) → core::int?
+ return 0;
+ get getter1() → core::int
+ return 0;
+ get getter2() → core::int?
+ return 0;
+ set setter1(core::int value) → void {}
+ set setter2(core::int? value) → void {}
+ get field3() → core::int
+ return 0;
+ set field3(core::int value) → void {}
+ get field4() → core::int?
+ return 0;
+ set field4(core::int? value) → void {}
+ get property1() → core::int
+ return 0;
+ set property1(core::int value) → void {}
+ get property2() → core::int?
+ return 0;
+ set property2(core::int? value) → void {}
+}
+class Class3a extends opt::GenericLegacyClass<core::int> {
+ synthetic constructor •() → self::Class3a
+ : super opt::GenericLegacyClass::•()
+ ;
+}
+class Class3b extends opt::GenericLegacyClass<core::int?> {
+ synthetic constructor •() → self::Class3b
+ : super opt::GenericLegacyClass::•()
+ ;
+}
+class Class3c<S extends core::Object? = dynamic> extends opt::GenericLegacyClass<self::Class3c::S%> {
+ synthetic constructor •() → self::Class3c<self::Class3c::S%>
+ : super opt::GenericLegacyClass::•()
+ ;
+}
+static method main() → dynamic {}
+
+library opt_out;
+import self as opt;
+import "dart:core" as core;
+
+class LegacyClass extends core::Object {
+ field core::int* field1 = null;
+ field core::int* field2 = null;
+ field core::int* field3 = null;
+ field core::int* field4 = null;
+ synthetic constructor •() → opt::LegacyClass*
+ : super core::Object::•()
+ ;
+ method method1() → core::int*
+ return 0;
+ method method2() → core::int*
+ return 0;
+ method method3a(core::int* a, core::int* b) → core::int*
+ return 0;
+ method method3b(core::int* a, [core::int* b = #C1]) → core::int*
+ return 0;
+ method method3c([core::int* a = #C1, core::int* b = #C1]) → core::int*
+ return 0;
+ method method4a(core::int* a, core::int* b) → core::int*
+ return 0;
+ method method4b(core::int* a, [core::int* b = #C1]) → core::int*
+ return 0;
+ method method4c([core::int* a = #C1, core::int* b = #C1]) → core::int*
+ return 0;
+ method method5a(core::int* a, {core::int* b = #C1}) → core::int*
+ return 0;
+ method method5b({core::int* a = #C1, core::int* b = #C1}) → core::int*
+ return 0;
+ method method5c({core::int* a = #C1, core::int* b = #C1}) → core::int*
+ return 0;
+ method method6a(core::int* a, {core::int* b = #C1}) → core::int*
+ return 0;
+ method method6b({core::int* a = #C1, core::int* b = #C1}) → core::int*
+ return 0;
+ method method6c({core::int* a = #C1, core::int* b = #C1}) → core::int*
+ return 0;
+ get getter1() → core::int*
+ return 0;
+ get getter2() → core::int*
+ return 0;
+ set setter1(core::int* value) → void {}
+ set setter2(core::int* value) → void {}
+ get property1() → core::int*
+ return 0;
+ set property1(core::int* value) → void {}
+ get property2() → core::int*
+ return 0;
+ set property2(core::int* value) → void {}
+ get property3() → core::int*
+ return 0;
+ set property3(core::int* value) → void {}
+ get property4() → core::int*
+ return 0;
+ set property4(core::int* value) → void {}
+}
+class GenericLegacyClass<T extends core::Object* = dynamic> extends core::Object {
+ synthetic constructor •() → opt::GenericLegacyClass<opt::GenericLegacyClass::T*>*
+ : super core::Object::•()
+ ;
+ method method1() → opt::GenericLegacyClass::T*
+ return null;
+}
+
+constants {
+ #C1 = null
+ #C2 = 0
+}
diff --git a/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_out.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_out.dart.strong.transformed.expect
new file mode 100644
index 0000000..0f04f45
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_out.dart.strong.transformed.expect
@@ -0,0 +1,229 @@
+library main;
+import self as self;
+import "dart:core" as core;
+import "member_inheritance_from_opt_out_lib.dart" as opt;
+
+import "org-dartlang-testcase:///member_inheritance_from_opt_out_lib.dart";
+
+abstract class Interface extends core::Object {
+ field core::int field1 = 0;
+ field core::int? field2 = null;
+ field core::int property3 = 0;
+ field core::int? property4 = null;
+ synthetic constructor •() → self::Interface
+ : super core::Object::•()
+ ;
+ abstract method method1() → core::int;
+ abstract method method2() → core::int?;
+ abstract method method3a(core::int a, core::int b) → core::int;
+ abstract method method3b(core::int a, [core::int b = #C1]) → core::int;
+ abstract method method3c([core::int a = #C1, core::int b = #C1]) → core::int;
+ abstract method method4a(core::int? a, core::int? b) → core::int?;
+ abstract method method4b(core::int? a, [core::int? b = #C1]) → core::int?;
+ abstract method method4c([core::int? a = #C1, core::int? b = #C1]) → core::int?;
+ abstract method method5a(core::int a, {core::int b = #C2}) → core::int;
+ abstract method method5b({core::int a = #C2, core::int b = #C2}) → core::int;
+ abstract method method5c({required core::int a = #C1, required core::int b = #C1}) → core::int;
+ abstract method method6a(core::int? a, {core::int? b = #C1}) → core::int?;
+ abstract method method6b({core::int? a = #C1, core::int? b = #C1}) → core::int?;
+ abstract method method6c({required core::int? a = #C1, required core::int? b = #C1}) → core::int?;
+ abstract get getter1() → core::int;
+ abstract get getter2() → core::int?;
+ abstract set setter1(core::int value) → void;
+ abstract set setter2(core::int? value) → void;
+ abstract get field3() → core::int;
+ abstract set field3(core::int value) → void;
+ abstract get field4() → core::int?;
+ abstract set field4(core::int? value) → void;
+ abstract get property1() → core::int;
+ abstract set property1(core::int value) → void;
+ abstract get property2() → core::int?;
+ abstract set property2(core::int? value) → void;
+}
+class Class1 extends opt::LegacyClass {
+ synthetic constructor •() → self::Class1
+ : super opt::LegacyClass::•()
+ ;
+}
+class Class2a extends opt::LegacyClass implements self::Interface {
+ synthetic constructor •() → self::Class2a
+ : super opt::LegacyClass::•()
+ ;
+ abstract member-signature method method4a(core::int? a, core::int? b) → core::int?;
+ abstract member-signature method method4c([core::int? a = #C1, core::int? b = #C1]) → core::int?;
+ abstract member-signature get getter1() → core::int;
+ abstract member-signature get field1() → core::int;
+ abstract member-signature method method3a(core::int a, core::int b) → core::int;
+ abstract member-signature get field4() → core::int?;
+ abstract member-signature get property3() → core::int;
+ abstract member-signature get field2() → core::int?;
+ abstract member-signature method method6a(core::int? a, {core::int? b = #C1}) → core::int?;
+ abstract member-signature get getter2() → core::int?;
+ abstract member-signature method method5a(core::int a, {core::int b = #C1}) → core::int;
+ abstract member-signature method method5c({core::int a = #C1, core::int b = #C1}) → core::int;
+ abstract member-signature get property4() → core::int?;
+ abstract member-signature method method6b({core::int? a = #C1, core::int? b = #C1}) → core::int?;
+ abstract member-signature method method6c({core::int? a = #C1, core::int? b = #C1}) → core::int?;
+ abstract member-signature method method2() → core::int?;
+ abstract member-signature method method5b({core::int a = #C1, core::int b = #C1}) → core::int;
+ abstract member-signature method method4b(core::int? a, [core::int? b = #C1]) → core::int?;
+ abstract member-signature get field3() → core::int;
+ abstract member-signature method method3c([core::int a = #C1, core::int b = #C1]) → core::int;
+ abstract member-signature method method1() → core::int;
+ abstract member-signature get property1() → core::int;
+ abstract member-signature get property2() → core::int?;
+ abstract member-signature method method3b(core::int a, [core::int b = #C1]) → core::int;
+ abstract member-signature set setter1(core::int value) → void;
+ abstract member-signature set field1(core::int _) → void;
+ abstract member-signature set field4(core::int? _) → void;
+ abstract member-signature set property3(core::int value) → void;
+ abstract member-signature set field2(core::int? _) → void;
+ abstract member-signature set property4(core::int? value) → void;
+ abstract member-signature set setter2(core::int? value) → void;
+ abstract member-signature set field3(core::int _) → void;
+ abstract member-signature set property1(core::int value) → void;
+ abstract member-signature set property2(core::int? value) → void;
+}
+class Class2b extends opt::LegacyClass implements self::Interface {
+ field core::int field1 = 0;
+ field core::int? field2 = null;
+ field core::int property3 = 0;
+ field core::int? property4 = null;
+ synthetic constructor •() → self::Class2b
+ : super opt::LegacyClass::•()
+ ;
+ method method1() → core::int
+ return 0;
+ method method2() → core::int?
+ return 0;
+ method method3a(core::int a, core::int b) → core::int
+ return 0;
+ method method3b(core::int a, [core::int b = #C1]) → core::int
+ return 0;
+ method method3c([core::int a = #C1, core::int b = #C1]) → core::int
+ return 0;
+ method method4a(core::int? a, core::int? b) → core::int?
+ return 0;
+ method method4b(core::int? a, [core::int? b = #C1]) → core::int?
+ return 0;
+ method method4c([core::int? a = #C1, core::int? b = #C1]) → core::int?
+ return 0;
+ method method5a(core::int a, {core::int b = #C2}) → core::int
+ return 0;
+ method method5b({core::int a = #C2, core::int b = #C2}) → core::int
+ return 0;
+ method method5c({required core::int a = #C1, required core::int b = #C1}) → core::int
+ return 0;
+ method method6a(core::int? a, {core::int? b = #C1}) → core::int?
+ return 0;
+ method method6b({core::int? a = #C1, core::int? b = #C1}) → core::int?
+ return 0;
+ method method6c({required core::int? a = #C1, required core::int? b = #C1}) → core::int?
+ return 0;
+ get getter1() → core::int
+ return 0;
+ get getter2() → core::int?
+ return 0;
+ set setter1(core::int value) → void {}
+ set setter2(core::int? value) → void {}
+ get field3() → core::int
+ return 0;
+ set field3(core::int value) → void {}
+ get field4() → core::int?
+ return 0;
+ set field4(core::int? value) → void {}
+ get property1() → core::int
+ return 0;
+ set property1(core::int value) → void {}
+ get property2() → core::int?
+ return 0;
+ set property2(core::int? value) → void {}
+}
+class Class3a extends opt::GenericLegacyClass<core::int> {
+ synthetic constructor •() → self::Class3a
+ : super opt::GenericLegacyClass::•()
+ ;
+}
+class Class3b extends opt::GenericLegacyClass<core::int?> {
+ synthetic constructor •() → self::Class3b
+ : super opt::GenericLegacyClass::•()
+ ;
+}
+class Class3c<S extends core::Object? = dynamic> extends opt::GenericLegacyClass<self::Class3c::S%> {
+ synthetic constructor •() → self::Class3c<self::Class3c::S%>
+ : super opt::GenericLegacyClass::•()
+ ;
+}
+static method main() → dynamic {}
+
+library opt_out;
+import self as opt;
+import "dart:core" as core;
+
+class LegacyClass extends core::Object {
+ field core::int* field1 = null;
+ field core::int* field2 = null;
+ field core::int* field3 = null;
+ field core::int* field4 = null;
+ synthetic constructor •() → opt::LegacyClass*
+ : super core::Object::•()
+ ;
+ method method1() → core::int*
+ return 0;
+ method method2() → core::int*
+ return 0;
+ method method3a(core::int* a, core::int* b) → core::int*
+ return 0;
+ method method3b(core::int* a, [core::int* b = #C1]) → core::int*
+ return 0;
+ method method3c([core::int* a = #C1, core::int* b = #C1]) → core::int*
+ return 0;
+ method method4a(core::int* a, core::int* b) → core::int*
+ return 0;
+ method method4b(core::int* a, [core::int* b = #C1]) → core::int*
+ return 0;
+ method method4c([core::int* a = #C1, core::int* b = #C1]) → core::int*
+ return 0;
+ method method5a(core::int* a, {core::int* b = #C1}) → core::int*
+ return 0;
+ method method5b({core::int* a = #C1, core::int* b = #C1}) → core::int*
+ return 0;
+ method method5c({core::int* a = #C1, core::int* b = #C1}) → core::int*
+ return 0;
+ method method6a(core::int* a, {core::int* b = #C1}) → core::int*
+ return 0;
+ method method6b({core::int* a = #C1, core::int* b = #C1}) → core::int*
+ return 0;
+ method method6c({core::int* a = #C1, core::int* b = #C1}) → core::int*
+ return 0;
+ get getter1() → core::int*
+ return 0;
+ get getter2() → core::int*
+ return 0;
+ set setter1(core::int* value) → void {}
+ set setter2(core::int* value) → void {}
+ get property1() → core::int*
+ return 0;
+ set property1(core::int* value) → void {}
+ get property2() → core::int*
+ return 0;
+ set property2(core::int* value) → void {}
+ get property3() → core::int*
+ return 0;
+ set property3(core::int* value) → void {}
+ get property4() → core::int*
+ return 0;
+ set property4(core::int* value) → void {}
+}
+class GenericLegacyClass<T extends core::Object* = dynamic> extends core::Object {
+ synthetic constructor •() → opt::GenericLegacyClass<opt::GenericLegacyClass::T*>*
+ : super core::Object::•()
+ ;
+ method method1() → opt::GenericLegacyClass::T*
+ return null;
+}
+
+constants {
+ #C1 = null
+ #C2 = 0
+}
diff --git a/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_out.dart.weak.expect b/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_out.dart.weak.expect
new file mode 100644
index 0000000..0f04f45
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_out.dart.weak.expect
@@ -0,0 +1,229 @@
+library main;
+import self as self;
+import "dart:core" as core;
+import "member_inheritance_from_opt_out_lib.dart" as opt;
+
+import "org-dartlang-testcase:///member_inheritance_from_opt_out_lib.dart";
+
+abstract class Interface extends core::Object {
+ field core::int field1 = 0;
+ field core::int? field2 = null;
+ field core::int property3 = 0;
+ field core::int? property4 = null;
+ synthetic constructor •() → self::Interface
+ : super core::Object::•()
+ ;
+ abstract method method1() → core::int;
+ abstract method method2() → core::int?;
+ abstract method method3a(core::int a, core::int b) → core::int;
+ abstract method method3b(core::int a, [core::int b = #C1]) → core::int;
+ abstract method method3c([core::int a = #C1, core::int b = #C1]) → core::int;
+ abstract method method4a(core::int? a, core::int? b) → core::int?;
+ abstract method method4b(core::int? a, [core::int? b = #C1]) → core::int?;
+ abstract method method4c([core::int? a = #C1, core::int? b = #C1]) → core::int?;
+ abstract method method5a(core::int a, {core::int b = #C2}) → core::int;
+ abstract method method5b({core::int a = #C2, core::int b = #C2}) → core::int;
+ abstract method method5c({required core::int a = #C1, required core::int b = #C1}) → core::int;
+ abstract method method6a(core::int? a, {core::int? b = #C1}) → core::int?;
+ abstract method method6b({core::int? a = #C1, core::int? b = #C1}) → core::int?;
+ abstract method method6c({required core::int? a = #C1, required core::int? b = #C1}) → core::int?;
+ abstract get getter1() → core::int;
+ abstract get getter2() → core::int?;
+ abstract set setter1(core::int value) → void;
+ abstract set setter2(core::int? value) → void;
+ abstract get field3() → core::int;
+ abstract set field3(core::int value) → void;
+ abstract get field4() → core::int?;
+ abstract set field4(core::int? value) → void;
+ abstract get property1() → core::int;
+ abstract set property1(core::int value) → void;
+ abstract get property2() → core::int?;
+ abstract set property2(core::int? value) → void;
+}
+class Class1 extends opt::LegacyClass {
+ synthetic constructor •() → self::Class1
+ : super opt::LegacyClass::•()
+ ;
+}
+class Class2a extends opt::LegacyClass implements self::Interface {
+ synthetic constructor •() → self::Class2a
+ : super opt::LegacyClass::•()
+ ;
+ abstract member-signature method method4a(core::int? a, core::int? b) → core::int?;
+ abstract member-signature method method4c([core::int? a = #C1, core::int? b = #C1]) → core::int?;
+ abstract member-signature get getter1() → core::int;
+ abstract member-signature get field1() → core::int;
+ abstract member-signature method method3a(core::int a, core::int b) → core::int;
+ abstract member-signature get field4() → core::int?;
+ abstract member-signature get property3() → core::int;
+ abstract member-signature get field2() → core::int?;
+ abstract member-signature method method6a(core::int? a, {core::int? b = #C1}) → core::int?;
+ abstract member-signature get getter2() → core::int?;
+ abstract member-signature method method5a(core::int a, {core::int b = #C1}) → core::int;
+ abstract member-signature method method5c({core::int a = #C1, core::int b = #C1}) → core::int;
+ abstract member-signature get property4() → core::int?;
+ abstract member-signature method method6b({core::int? a = #C1, core::int? b = #C1}) → core::int?;
+ abstract member-signature method method6c({core::int? a = #C1, core::int? b = #C1}) → core::int?;
+ abstract member-signature method method2() → core::int?;
+ abstract member-signature method method5b({core::int a = #C1, core::int b = #C1}) → core::int;
+ abstract member-signature method method4b(core::int? a, [core::int? b = #C1]) → core::int?;
+ abstract member-signature get field3() → core::int;
+ abstract member-signature method method3c([core::int a = #C1, core::int b = #C1]) → core::int;
+ abstract member-signature method method1() → core::int;
+ abstract member-signature get property1() → core::int;
+ abstract member-signature get property2() → core::int?;
+ abstract member-signature method method3b(core::int a, [core::int b = #C1]) → core::int;
+ abstract member-signature set setter1(core::int value) → void;
+ abstract member-signature set field1(core::int _) → void;
+ abstract member-signature set field4(core::int? _) → void;
+ abstract member-signature set property3(core::int value) → void;
+ abstract member-signature set field2(core::int? _) → void;
+ abstract member-signature set property4(core::int? value) → void;
+ abstract member-signature set setter2(core::int? value) → void;
+ abstract member-signature set field3(core::int _) → void;
+ abstract member-signature set property1(core::int value) → void;
+ abstract member-signature set property2(core::int? value) → void;
+}
+class Class2b extends opt::LegacyClass implements self::Interface {
+ field core::int field1 = 0;
+ field core::int? field2 = null;
+ field core::int property3 = 0;
+ field core::int? property4 = null;
+ synthetic constructor •() → self::Class2b
+ : super opt::LegacyClass::•()
+ ;
+ method method1() → core::int
+ return 0;
+ method method2() → core::int?
+ return 0;
+ method method3a(core::int a, core::int b) → core::int
+ return 0;
+ method method3b(core::int a, [core::int b = #C1]) → core::int
+ return 0;
+ method method3c([core::int a = #C1, core::int b = #C1]) → core::int
+ return 0;
+ method method4a(core::int? a, core::int? b) → core::int?
+ return 0;
+ method method4b(core::int? a, [core::int? b = #C1]) → core::int?
+ return 0;
+ method method4c([core::int? a = #C1, core::int? b = #C1]) → core::int?
+ return 0;
+ method method5a(core::int a, {core::int b = #C2}) → core::int
+ return 0;
+ method method5b({core::int a = #C2, core::int b = #C2}) → core::int
+ return 0;
+ method method5c({required core::int a = #C1, required core::int b = #C1}) → core::int
+ return 0;
+ method method6a(core::int? a, {core::int? b = #C1}) → core::int?
+ return 0;
+ method method6b({core::int? a = #C1, core::int? b = #C1}) → core::int?
+ return 0;
+ method method6c({required core::int? a = #C1, required core::int? b = #C1}) → core::int?
+ return 0;
+ get getter1() → core::int
+ return 0;
+ get getter2() → core::int?
+ return 0;
+ set setter1(core::int value) → void {}
+ set setter2(core::int? value) → void {}
+ get field3() → core::int
+ return 0;
+ set field3(core::int value) → void {}
+ get field4() → core::int?
+ return 0;
+ set field4(core::int? value) → void {}
+ get property1() → core::int
+ return 0;
+ set property1(core::int value) → void {}
+ get property2() → core::int?
+ return 0;
+ set property2(core::int? value) → void {}
+}
+class Class3a extends opt::GenericLegacyClass<core::int> {
+ synthetic constructor •() → self::Class3a
+ : super opt::GenericLegacyClass::•()
+ ;
+}
+class Class3b extends opt::GenericLegacyClass<core::int?> {
+ synthetic constructor •() → self::Class3b
+ : super opt::GenericLegacyClass::•()
+ ;
+}
+class Class3c<S extends core::Object? = dynamic> extends opt::GenericLegacyClass<self::Class3c::S%> {
+ synthetic constructor •() → self::Class3c<self::Class3c::S%>
+ : super opt::GenericLegacyClass::•()
+ ;
+}
+static method main() → dynamic {}
+
+library opt_out;
+import self as opt;
+import "dart:core" as core;
+
+class LegacyClass extends core::Object {
+ field core::int* field1 = null;
+ field core::int* field2 = null;
+ field core::int* field3 = null;
+ field core::int* field4 = null;
+ synthetic constructor •() → opt::LegacyClass*
+ : super core::Object::•()
+ ;
+ method method1() → core::int*
+ return 0;
+ method method2() → core::int*
+ return 0;
+ method method3a(core::int* a, core::int* b) → core::int*
+ return 0;
+ method method3b(core::int* a, [core::int* b = #C1]) → core::int*
+ return 0;
+ method method3c([core::int* a = #C1, core::int* b = #C1]) → core::int*
+ return 0;
+ method method4a(core::int* a, core::int* b) → core::int*
+ return 0;
+ method method4b(core::int* a, [core::int* b = #C1]) → core::int*
+ return 0;
+ method method4c([core::int* a = #C1, core::int* b = #C1]) → core::int*
+ return 0;
+ method method5a(core::int* a, {core::int* b = #C1}) → core::int*
+ return 0;
+ method method5b({core::int* a = #C1, core::int* b = #C1}) → core::int*
+ return 0;
+ method method5c({core::int* a = #C1, core::int* b = #C1}) → core::int*
+ return 0;
+ method method6a(core::int* a, {core::int* b = #C1}) → core::int*
+ return 0;
+ method method6b({core::int* a = #C1, core::int* b = #C1}) → core::int*
+ return 0;
+ method method6c({core::int* a = #C1, core::int* b = #C1}) → core::int*
+ return 0;
+ get getter1() → core::int*
+ return 0;
+ get getter2() → core::int*
+ return 0;
+ set setter1(core::int* value) → void {}
+ set setter2(core::int* value) → void {}
+ get property1() → core::int*
+ return 0;
+ set property1(core::int* value) → void {}
+ get property2() → core::int*
+ return 0;
+ set property2(core::int* value) → void {}
+ get property3() → core::int*
+ return 0;
+ set property3(core::int* value) → void {}
+ get property4() → core::int*
+ return 0;
+ set property4(core::int* value) → void {}
+}
+class GenericLegacyClass<T extends core::Object* = dynamic> extends core::Object {
+ synthetic constructor •() → opt::GenericLegacyClass<opt::GenericLegacyClass::T*>*
+ : super core::Object::•()
+ ;
+ method method1() → opt::GenericLegacyClass::T*
+ return null;
+}
+
+constants {
+ #C1 = null
+ #C2 = 0
+}
diff --git a/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_out.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_out.dart.weak.transformed.expect
new file mode 100644
index 0000000..0f04f45
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_out.dart.weak.transformed.expect
@@ -0,0 +1,229 @@
+library main;
+import self as self;
+import "dart:core" as core;
+import "member_inheritance_from_opt_out_lib.dart" as opt;
+
+import "org-dartlang-testcase:///member_inheritance_from_opt_out_lib.dart";
+
+abstract class Interface extends core::Object {
+ field core::int field1 = 0;
+ field core::int? field2 = null;
+ field core::int property3 = 0;
+ field core::int? property4 = null;
+ synthetic constructor •() → self::Interface
+ : super core::Object::•()
+ ;
+ abstract method method1() → core::int;
+ abstract method method2() → core::int?;
+ abstract method method3a(core::int a, core::int b) → core::int;
+ abstract method method3b(core::int a, [core::int b = #C1]) → core::int;
+ abstract method method3c([core::int a = #C1, core::int b = #C1]) → core::int;
+ abstract method method4a(core::int? a, core::int? b) → core::int?;
+ abstract method method4b(core::int? a, [core::int? b = #C1]) → core::int?;
+ abstract method method4c([core::int? a = #C1, core::int? b = #C1]) → core::int?;
+ abstract method method5a(core::int a, {core::int b = #C2}) → core::int;
+ abstract method method5b({core::int a = #C2, core::int b = #C2}) → core::int;
+ abstract method method5c({required core::int a = #C1, required core::int b = #C1}) → core::int;
+ abstract method method6a(core::int? a, {core::int? b = #C1}) → core::int?;
+ abstract method method6b({core::int? a = #C1, core::int? b = #C1}) → core::int?;
+ abstract method method6c({required core::int? a = #C1, required core::int? b = #C1}) → core::int?;
+ abstract get getter1() → core::int;
+ abstract get getter2() → core::int?;
+ abstract set setter1(core::int value) → void;
+ abstract set setter2(core::int? value) → void;
+ abstract get field3() → core::int;
+ abstract set field3(core::int value) → void;
+ abstract get field4() → core::int?;
+ abstract set field4(core::int? value) → void;
+ abstract get property1() → core::int;
+ abstract set property1(core::int value) → void;
+ abstract get property2() → core::int?;
+ abstract set property2(core::int? value) → void;
+}
+class Class1 extends opt::LegacyClass {
+ synthetic constructor •() → self::Class1
+ : super opt::LegacyClass::•()
+ ;
+}
+class Class2a extends opt::LegacyClass implements self::Interface {
+ synthetic constructor •() → self::Class2a
+ : super opt::LegacyClass::•()
+ ;
+ abstract member-signature method method4a(core::int? a, core::int? b) → core::int?;
+ abstract member-signature method method4c([core::int? a = #C1, core::int? b = #C1]) → core::int?;
+ abstract member-signature get getter1() → core::int;
+ abstract member-signature get field1() → core::int;
+ abstract member-signature method method3a(core::int a, core::int b) → core::int;
+ abstract member-signature get field4() → core::int?;
+ abstract member-signature get property3() → core::int;
+ abstract member-signature get field2() → core::int?;
+ abstract member-signature method method6a(core::int? a, {core::int? b = #C1}) → core::int?;
+ abstract member-signature get getter2() → core::int?;
+ abstract member-signature method method5a(core::int a, {core::int b = #C1}) → core::int;
+ abstract member-signature method method5c({core::int a = #C1, core::int b = #C1}) → core::int;
+ abstract member-signature get property4() → core::int?;
+ abstract member-signature method method6b({core::int? a = #C1, core::int? b = #C1}) → core::int?;
+ abstract member-signature method method6c({core::int? a = #C1, core::int? b = #C1}) → core::int?;
+ abstract member-signature method method2() → core::int?;
+ abstract member-signature method method5b({core::int a = #C1, core::int b = #C1}) → core::int;
+ abstract member-signature method method4b(core::int? a, [core::int? b = #C1]) → core::int?;
+ abstract member-signature get field3() → core::int;
+ abstract member-signature method method3c([core::int a = #C1, core::int b = #C1]) → core::int;
+ abstract member-signature method method1() → core::int;
+ abstract member-signature get property1() → core::int;
+ abstract member-signature get property2() → core::int?;
+ abstract member-signature method method3b(core::int a, [core::int b = #C1]) → core::int;
+ abstract member-signature set setter1(core::int value) → void;
+ abstract member-signature set field1(core::int _) → void;
+ abstract member-signature set field4(core::int? _) → void;
+ abstract member-signature set property3(core::int value) → void;
+ abstract member-signature set field2(core::int? _) → void;
+ abstract member-signature set property4(core::int? value) → void;
+ abstract member-signature set setter2(core::int? value) → void;
+ abstract member-signature set field3(core::int _) → void;
+ abstract member-signature set property1(core::int value) → void;
+ abstract member-signature set property2(core::int? value) → void;
+}
+class Class2b extends opt::LegacyClass implements self::Interface {
+ field core::int field1 = 0;
+ field core::int? field2 = null;
+ field core::int property3 = 0;
+ field core::int? property4 = null;
+ synthetic constructor •() → self::Class2b
+ : super opt::LegacyClass::•()
+ ;
+ method method1() → core::int
+ return 0;
+ method method2() → core::int?
+ return 0;
+ method method3a(core::int a, core::int b) → core::int
+ return 0;
+ method method3b(core::int a, [core::int b = #C1]) → core::int
+ return 0;
+ method method3c([core::int a = #C1, core::int b = #C1]) → core::int
+ return 0;
+ method method4a(core::int? a, core::int? b) → core::int?
+ return 0;
+ method method4b(core::int? a, [core::int? b = #C1]) → core::int?
+ return 0;
+ method method4c([core::int? a = #C1, core::int? b = #C1]) → core::int?
+ return 0;
+ method method5a(core::int a, {core::int b = #C2}) → core::int
+ return 0;
+ method method5b({core::int a = #C2, core::int b = #C2}) → core::int
+ return 0;
+ method method5c({required core::int a = #C1, required core::int b = #C1}) → core::int
+ return 0;
+ method method6a(core::int? a, {core::int? b = #C1}) → core::int?
+ return 0;
+ method method6b({core::int? a = #C1, core::int? b = #C1}) → core::int?
+ return 0;
+ method method6c({required core::int? a = #C1, required core::int? b = #C1}) → core::int?
+ return 0;
+ get getter1() → core::int
+ return 0;
+ get getter2() → core::int?
+ return 0;
+ set setter1(core::int value) → void {}
+ set setter2(core::int? value) → void {}
+ get field3() → core::int
+ return 0;
+ set field3(core::int value) → void {}
+ get field4() → core::int?
+ return 0;
+ set field4(core::int? value) → void {}
+ get property1() → core::int
+ return 0;
+ set property1(core::int value) → void {}
+ get property2() → core::int?
+ return 0;
+ set property2(core::int? value) → void {}
+}
+class Class3a extends opt::GenericLegacyClass<core::int> {
+ synthetic constructor •() → self::Class3a
+ : super opt::GenericLegacyClass::•()
+ ;
+}
+class Class3b extends opt::GenericLegacyClass<core::int?> {
+ synthetic constructor •() → self::Class3b
+ : super opt::GenericLegacyClass::•()
+ ;
+}
+class Class3c<S extends core::Object? = dynamic> extends opt::GenericLegacyClass<self::Class3c::S%> {
+ synthetic constructor •() → self::Class3c<self::Class3c::S%>
+ : super opt::GenericLegacyClass::•()
+ ;
+}
+static method main() → dynamic {}
+
+library opt_out;
+import self as opt;
+import "dart:core" as core;
+
+class LegacyClass extends core::Object {
+ field core::int* field1 = null;
+ field core::int* field2 = null;
+ field core::int* field3 = null;
+ field core::int* field4 = null;
+ synthetic constructor •() → opt::LegacyClass*
+ : super core::Object::•()
+ ;
+ method method1() → core::int*
+ return 0;
+ method method2() → core::int*
+ return 0;
+ method method3a(core::int* a, core::int* b) → core::int*
+ return 0;
+ method method3b(core::int* a, [core::int* b = #C1]) → core::int*
+ return 0;
+ method method3c([core::int* a = #C1, core::int* b = #C1]) → core::int*
+ return 0;
+ method method4a(core::int* a, core::int* b) → core::int*
+ return 0;
+ method method4b(core::int* a, [core::int* b = #C1]) → core::int*
+ return 0;
+ method method4c([core::int* a = #C1, core::int* b = #C1]) → core::int*
+ return 0;
+ method method5a(core::int* a, {core::int* b = #C1}) → core::int*
+ return 0;
+ method method5b({core::int* a = #C1, core::int* b = #C1}) → core::int*
+ return 0;
+ method method5c({core::int* a = #C1, core::int* b = #C1}) → core::int*
+ return 0;
+ method method6a(core::int* a, {core::int* b = #C1}) → core::int*
+ return 0;
+ method method6b({core::int* a = #C1, core::int* b = #C1}) → core::int*
+ return 0;
+ method method6c({core::int* a = #C1, core::int* b = #C1}) → core::int*
+ return 0;
+ get getter1() → core::int*
+ return 0;
+ get getter2() → core::int*
+ return 0;
+ set setter1(core::int* value) → void {}
+ set setter2(core::int* value) → void {}
+ get property1() → core::int*
+ return 0;
+ set property1(core::int* value) → void {}
+ get property2() → core::int*
+ return 0;
+ set property2(core::int* value) → void {}
+ get property3() → core::int*
+ return 0;
+ set property3(core::int* value) → void {}
+ get property4() → core::int*
+ return 0;
+ set property4(core::int* value) → void {}
+}
+class GenericLegacyClass<T extends core::Object* = dynamic> extends core::Object {
+ synthetic constructor •() → opt::GenericLegacyClass<opt::GenericLegacyClass::T*>*
+ : super core::Object::•()
+ ;
+ method method1() → opt::GenericLegacyClass::T*
+ return null;
+}
+
+constants {
+ #C1 = null
+ #C2 = 0
+}
diff --git a/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_out_lib.dart b/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_out_lib.dart
new file mode 100644
index 0000000..d7d4f9f
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/member_inheritance_from_opt_out_lib.dart
@@ -0,0 +1,73 @@
+// 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.5
+
+library opt_out;
+
+class LegacyClass {
+ int method1() => 0;
+
+ int method2() => 0;
+
+ int method3a(int a, int b) => 0;
+
+ int method3b(int a, [int b]) => 0;
+
+ int method3c([int a, int b]) => 0;
+
+ int method4a(int a, int b) => 0;
+
+ int method4b(int a, [int b]) => 0;
+
+ int method4c([int a, int b]) => 0;
+
+ int method5a(int a, {int b}) => 0;
+
+ int method5b({int a, int b}) => 0;
+
+ int method5c({int a, int b}) => 0;
+
+ int method6a(int a, {int b}) => 0;
+
+ int method6b({int a, int b}) => 0;
+
+ int method6c({int a, int b}) => 0;
+
+ int get getter1 => 0;
+
+ int get getter2 => 0;
+
+ void set setter1(int value) {}
+
+ void set setter2(int value) {}
+
+ int field1;
+
+ int field2;
+
+ int field3;
+
+ int field4;
+
+ int get property1 => 0;
+
+ void set property1(int value) {}
+
+ int get property2 => 0;
+
+ void set property2(int value) {}
+
+ int get property3 => 0;
+
+ void set property3(int value) {}
+
+ int get property4 => 0;
+
+ void set property4(int value) {}
+}
+
+class GenericLegacyClass<T> {
+ T method1() => null;
+}
diff --git a/pkg/front_end/testcases/nnbd/nullable_receiver.dart b/pkg/front_end/testcases/nnbd/nullable_receiver.dart
new file mode 100644
index 0000000..98c3f88
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/nullable_receiver.dart
@@ -0,0 +1,47 @@
+// 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.
+
+// The test checks for compile-time errors or their absence for cases involving
+// nullable receiver.
+
+class A {
+ foo() {}
+ int get bar => 42;
+ void set baz(int value) {}
+ void call() {}
+}
+
+error(String? s, A? a) {
+ s.length;
+ s.substring(1, 1);
+
+ a.foo();
+ a.bar;
+ a.baz = 42;
+ a();
+
+ Function f1 = a;
+ void Function() f2 = a;
+ void Function()? f3 = a;
+}
+
+// It's ok to invoke members of Object on nullable types.
+ok(String? s, A? a, Invocation i) {
+ s == s;
+ a == a;
+
+ s.hashCode;
+ a.hashCode;
+
+ s.toString();
+ a.toString();
+
+ try { s.noSuchMethod(i); } catch (e, t) {}
+ try { a.noSuchMethod(i); } catch (e, t) {}
+
+ s.runtimeType;
+ a.runtimeType;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/nullable_receiver.dart.outline.expect b/pkg/front_end/testcases/nnbd/nullable_receiver.dart.outline.expect
new file mode 100644
index 0000000..65602b3
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/nullable_receiver.dart.outline.expect
@@ -0,0 +1,22 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ synthetic constructor •() → self::A
+ ;
+ method foo() → dynamic
+ ;
+ get bar() → core::int
+ ;
+ set baz(core::int value) → void
+ ;
+ method call() → void
+ ;
+}
+static method error(core::String? s, self::A? a) → dynamic
+ ;
+static method ok(core::String? s, self::A? a, core::Invocation i) → dynamic
+ ;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/nnbd/nullable_receiver.dart.strong.expect b/pkg/front_end/testcases/nnbd/nullable_receiver.dart.strong.expect
new file mode 100644
index 0000000..c298044
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/nullable_receiver.dart.strong.expect
@@ -0,0 +1,117 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:16:5: Error: Property 'length' cannot be accessed on 'String?' because it is potentially null.
+// Try accessing using ?. instead.
+// s.length;
+// ^
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:20:5: Error: Property 'bar' cannot be accessed on 'A?' because it is potentially null.
+// - 'A' is from 'pkg/front_end/testcases/nnbd/nullable_receiver.dart'.
+// Try accessing using ?. instead.
+// a.bar;
+// ^
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:24:12: Error: A value of type 'void Function()?' can't be assigned to a variable of type 'Function'.
+// - 'Function' is from 'dart:core'.
+// Function f1 = a;
+// ^
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:25:19: Error: A value of type 'void Function()?' can't be assigned to a variable of type 'void Function()'.
+// void Function() f2 = a;
+// ^
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:34:5: Error: Property 'hashCode' cannot be accessed on 'String?' because it is potentially null.
+// Try accessing using ?. instead.
+// s.hashCode;
+// ^
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:35:5: Error: Property 'hashCode' cannot be accessed on 'A?' because it is potentially null.
+// - 'A' is from 'pkg/front_end/testcases/nnbd/nullable_receiver.dart'.
+// Try accessing using ?. instead.
+// a.hashCode;
+// ^
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:43:5: Error: Property 'runtimeType' cannot be accessed on 'String?' because it is potentially null.
+// Try accessing using ?. instead.
+// s.runtimeType;
+// ^
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:44:5: Error: Property 'runtimeType' cannot be accessed on 'A?' because it is potentially null.
+// - 'A' is from 'pkg/front_end/testcases/nnbd/nullable_receiver.dart'.
+// Try accessing using ?. instead.
+// a.runtimeType;
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ synthetic constructor •() → self::A
+ : super core::Object::•()
+ ;
+ method foo() → dynamic {}
+ get bar() → core::int
+ return 42;
+ set baz(core::int value) → void {}
+ method call() → void {}
+}
+static method error(core::String? s, self::A? a) → dynamic {
+ let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/nullable_receiver.dart:16:5: Error: Property 'length' cannot be accessed on 'String?' because it is potentially null.
+Try accessing using ?. instead.
+ s.length;
+ ^" in s.{core::String::length};
+ s.{core::String::substring}(1, 1);
+ a.{self::A::foo}();
+ let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/nnbd/nullable_receiver.dart:20:5: Error: Property 'bar' cannot be accessed on 'A?' because it is potentially null.
+ - 'A' is from 'pkg/front_end/testcases/nnbd/nullable_receiver.dart'.
+Try accessing using ?. instead.
+ a.bar;
+ ^" in a.{self::A::bar};
+ a.{self::A::baz} = 42;
+ a.{self::A::call}();
+ core::Function f1 = let final<BottomType> #t3 = invalid-expression "pkg/front_end/testcases/nnbd/nullable_receiver.dart:24:12: Error: A value of type 'void Function()?' can't be assigned to a variable of type 'Function'.
+ - 'Function' is from 'dart:core'.
+ Function f1 = a;
+ ^" in (let final self::A? #t4 = a in #t4.==(null) ?{() →? void} null : #t4.{self::A::call}) as{TypeError} core::Function;
+ () → void f2 = let final<BottomType> #t5 = invalid-expression "pkg/front_end/testcases/nnbd/nullable_receiver.dart:25:19: Error: A value of type 'void Function()?' can't be assigned to a variable of type 'void Function()'.
+ void Function() f2 = a;
+ ^" in (let final self::A? #t6 = a in #t6.==(null) ?{() →? void} null : #t6.{self::A::call}) as{TypeError} () → void;
+ () →? void f3 = let final self::A? #t7 = a in #t7.==(null) ?{() →? void} null : #t7.{self::A::call};
+}
+static method ok(core::String? s, self::A? a, core::Invocation i) → dynamic {
+ s.{core::String::==}(s);
+ a.{core::Object::==}(a);
+ let final<BottomType> #t8 = invalid-expression "pkg/front_end/testcases/nnbd/nullable_receiver.dart:34:5: Error: Property 'hashCode' cannot be accessed on 'String?' because it is potentially null.
+Try accessing using ?. instead.
+ s.hashCode;
+ ^" in s.{core::String::hashCode};
+ let final<BottomType> #t9 = invalid-expression "pkg/front_end/testcases/nnbd/nullable_receiver.dart:35:5: Error: Property 'hashCode' cannot be accessed on 'A?' because it is potentially null.
+ - 'A' is from 'pkg/front_end/testcases/nnbd/nullable_receiver.dart'.
+Try accessing using ?. instead.
+ a.hashCode;
+ ^" in a.{core::Object::hashCode};
+ s.{core::Object::toString}();
+ a.{core::Object::toString}();
+ try {
+ s.{core::Object::noSuchMethod}(i);
+ }
+ on dynamic catch(final dynamic e, final core::StackTrace t) {
+ }
+ try {
+ a.{core::Object::noSuchMethod}(i);
+ }
+ on dynamic catch(final dynamic e, final core::StackTrace t) {
+ }
+ let final<BottomType> #t10 = invalid-expression "pkg/front_end/testcases/nnbd/nullable_receiver.dart:43:5: Error: Property 'runtimeType' cannot be accessed on 'String?' because it is potentially null.
+Try accessing using ?. instead.
+ s.runtimeType;
+ ^" in s.{core::Object::runtimeType};
+ let final<BottomType> #t11 = invalid-expression "pkg/front_end/testcases/nnbd/nullable_receiver.dart:44:5: Error: Property 'runtimeType' cannot be accessed on 'A?' because it is potentially null.
+ - 'A' is from 'pkg/front_end/testcases/nnbd/nullable_receiver.dart'.
+Try accessing using ?. instead.
+ a.runtimeType;
+ ^" in a.{core::Object::runtimeType};
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/nullable_receiver.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/nullable_receiver.dart.strong.transformed.expect
new file mode 100644
index 0000000..c298044
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/nullable_receiver.dart.strong.transformed.expect
@@ -0,0 +1,117 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:16:5: Error: Property 'length' cannot be accessed on 'String?' because it is potentially null.
+// Try accessing using ?. instead.
+// s.length;
+// ^
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:20:5: Error: Property 'bar' cannot be accessed on 'A?' because it is potentially null.
+// - 'A' is from 'pkg/front_end/testcases/nnbd/nullable_receiver.dart'.
+// Try accessing using ?. instead.
+// a.bar;
+// ^
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:24:12: Error: A value of type 'void Function()?' can't be assigned to a variable of type 'Function'.
+// - 'Function' is from 'dart:core'.
+// Function f1 = a;
+// ^
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:25:19: Error: A value of type 'void Function()?' can't be assigned to a variable of type 'void Function()'.
+// void Function() f2 = a;
+// ^
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:34:5: Error: Property 'hashCode' cannot be accessed on 'String?' because it is potentially null.
+// Try accessing using ?. instead.
+// s.hashCode;
+// ^
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:35:5: Error: Property 'hashCode' cannot be accessed on 'A?' because it is potentially null.
+// - 'A' is from 'pkg/front_end/testcases/nnbd/nullable_receiver.dart'.
+// Try accessing using ?. instead.
+// a.hashCode;
+// ^
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:43:5: Error: Property 'runtimeType' cannot be accessed on 'String?' because it is potentially null.
+// Try accessing using ?. instead.
+// s.runtimeType;
+// ^
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:44:5: Error: Property 'runtimeType' cannot be accessed on 'A?' because it is potentially null.
+// - 'A' is from 'pkg/front_end/testcases/nnbd/nullable_receiver.dart'.
+// Try accessing using ?. instead.
+// a.runtimeType;
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ synthetic constructor •() → self::A
+ : super core::Object::•()
+ ;
+ method foo() → dynamic {}
+ get bar() → core::int
+ return 42;
+ set baz(core::int value) → void {}
+ method call() → void {}
+}
+static method error(core::String? s, self::A? a) → dynamic {
+ let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/nullable_receiver.dart:16:5: Error: Property 'length' cannot be accessed on 'String?' because it is potentially null.
+Try accessing using ?. instead.
+ s.length;
+ ^" in s.{core::String::length};
+ s.{core::String::substring}(1, 1);
+ a.{self::A::foo}();
+ let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/nnbd/nullable_receiver.dart:20:5: Error: Property 'bar' cannot be accessed on 'A?' because it is potentially null.
+ - 'A' is from 'pkg/front_end/testcases/nnbd/nullable_receiver.dart'.
+Try accessing using ?. instead.
+ a.bar;
+ ^" in a.{self::A::bar};
+ a.{self::A::baz} = 42;
+ a.{self::A::call}();
+ core::Function f1 = let final<BottomType> #t3 = invalid-expression "pkg/front_end/testcases/nnbd/nullable_receiver.dart:24:12: Error: A value of type 'void Function()?' can't be assigned to a variable of type 'Function'.
+ - 'Function' is from 'dart:core'.
+ Function f1 = a;
+ ^" in (let final self::A? #t4 = a in #t4.==(null) ?{() →? void} null : #t4.{self::A::call}) as{TypeError} core::Function;
+ () → void f2 = let final<BottomType> #t5 = invalid-expression "pkg/front_end/testcases/nnbd/nullable_receiver.dart:25:19: Error: A value of type 'void Function()?' can't be assigned to a variable of type 'void Function()'.
+ void Function() f2 = a;
+ ^" in (let final self::A? #t6 = a in #t6.==(null) ?{() →? void} null : #t6.{self::A::call}) as{TypeError} () → void;
+ () →? void f3 = let final self::A? #t7 = a in #t7.==(null) ?{() →? void} null : #t7.{self::A::call};
+}
+static method ok(core::String? s, self::A? a, core::Invocation i) → dynamic {
+ s.{core::String::==}(s);
+ a.{core::Object::==}(a);
+ let final<BottomType> #t8 = invalid-expression "pkg/front_end/testcases/nnbd/nullable_receiver.dart:34:5: Error: Property 'hashCode' cannot be accessed on 'String?' because it is potentially null.
+Try accessing using ?. instead.
+ s.hashCode;
+ ^" in s.{core::String::hashCode};
+ let final<BottomType> #t9 = invalid-expression "pkg/front_end/testcases/nnbd/nullable_receiver.dart:35:5: Error: Property 'hashCode' cannot be accessed on 'A?' because it is potentially null.
+ - 'A' is from 'pkg/front_end/testcases/nnbd/nullable_receiver.dart'.
+Try accessing using ?. instead.
+ a.hashCode;
+ ^" in a.{core::Object::hashCode};
+ s.{core::Object::toString}();
+ a.{core::Object::toString}();
+ try {
+ s.{core::Object::noSuchMethod}(i);
+ }
+ on dynamic catch(final dynamic e, final core::StackTrace t) {
+ }
+ try {
+ a.{core::Object::noSuchMethod}(i);
+ }
+ on dynamic catch(final dynamic e, final core::StackTrace t) {
+ }
+ let final<BottomType> #t10 = invalid-expression "pkg/front_end/testcases/nnbd/nullable_receiver.dart:43:5: Error: Property 'runtimeType' cannot be accessed on 'String?' because it is potentially null.
+Try accessing using ?. instead.
+ s.runtimeType;
+ ^" in s.{core::Object::runtimeType};
+ let final<BottomType> #t11 = invalid-expression "pkg/front_end/testcases/nnbd/nullable_receiver.dart:44:5: Error: Property 'runtimeType' cannot be accessed on 'A?' because it is potentially null.
+ - 'A' is from 'pkg/front_end/testcases/nnbd/nullable_receiver.dart'.
+Try accessing using ?. instead.
+ a.runtimeType;
+ ^" in a.{core::Object::runtimeType};
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/nullable_receiver.dart.weak.expect b/pkg/front_end/testcases/nnbd/nullable_receiver.dart.weak.expect
new file mode 100644
index 0000000..5d3c3c6
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/nullable_receiver.dart.weak.expect
@@ -0,0 +1,91 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:16:5: Warning: Property 'length' is accessed on 'String?' which is potentially null.
+// Try accessing using ?. instead.
+// s.length;
+// ^
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:20:5: Warning: Property 'bar' is accessed on 'A?' which is potentially null.
+// - 'A' is from 'pkg/front_end/testcases/nnbd/nullable_receiver.dart'.
+// Try accessing using ?. instead.
+// a.bar;
+// ^
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:24:12: Warning: Assigning value of type 'void Function()?' to a variable of type 'Function'.
+// - 'Function' is from 'dart:core'.
+// Function f1 = a;
+// ^
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:25:19: Warning: Assigning value of type 'void Function()?' to a variable of type 'void Function()'.
+// void Function() f2 = a;
+// ^
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:34:5: Warning: Property 'hashCode' is accessed on 'String?' which is potentially null.
+// Try accessing using ?. instead.
+// s.hashCode;
+// ^
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:35:5: Warning: Property 'hashCode' is accessed on 'A?' which is potentially null.
+// - 'A' is from 'pkg/front_end/testcases/nnbd/nullable_receiver.dart'.
+// Try accessing using ?. instead.
+// a.hashCode;
+// ^
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:43:5: Warning: Property 'runtimeType' is accessed on 'String?' which is potentially null.
+// Try accessing using ?. instead.
+// s.runtimeType;
+// ^
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:44:5: Warning: Property 'runtimeType' is accessed on 'A?' which is potentially null.
+// - 'A' is from 'pkg/front_end/testcases/nnbd/nullable_receiver.dart'.
+// Try accessing using ?. instead.
+// a.runtimeType;
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ synthetic constructor •() → self::A
+ : super core::Object::•()
+ ;
+ method foo() → dynamic {}
+ get bar() → core::int
+ return 42;
+ set baz(core::int value) → void {}
+ method call() → void {}
+}
+static method error(core::String? s, self::A? a) → dynamic {
+ s.{core::String::length};
+ s.{core::String::substring}(1, 1);
+ a.{self::A::foo}();
+ a.{self::A::bar};
+ a.{self::A::baz} = 42;
+ a.{self::A::call}();
+ core::Function f1 = let final self::A? #t1 = a in #t1.==(null) ?{() →? void} null : #t1.{self::A::call};
+ () → void f2 = let final self::A? #t2 = a in #t2.==(null) ?{() →? void} null : #t2.{self::A::call};
+ () →? void f3 = let final self::A? #t3 = a in #t3.==(null) ?{() →? void} null : #t3.{self::A::call};
+}
+static method ok(core::String? s, self::A? a, core::Invocation i) → dynamic {
+ s.{core::String::==}(s);
+ a.{core::Object::==}(a);
+ s.{core::String::hashCode};
+ a.{core::Object::hashCode};
+ s.{core::Object::toString}();
+ a.{core::Object::toString}();
+ try {
+ s.{core::Object::noSuchMethod}(i);
+ }
+ on dynamic catch(final dynamic e, final core::StackTrace t) {
+ }
+ try {
+ a.{core::Object::noSuchMethod}(i);
+ }
+ on dynamic catch(final dynamic e, final core::StackTrace t) {
+ }
+ s.{core::Object::runtimeType};
+ a.{core::Object::runtimeType};
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/nullable_receiver.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/nullable_receiver.dart.weak.transformed.expect
new file mode 100644
index 0000000..5d3c3c6
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/nullable_receiver.dart.weak.transformed.expect
@@ -0,0 +1,91 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:16:5: Warning: Property 'length' is accessed on 'String?' which is potentially null.
+// Try accessing using ?. instead.
+// s.length;
+// ^
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:20:5: Warning: Property 'bar' is accessed on 'A?' which is potentially null.
+// - 'A' is from 'pkg/front_end/testcases/nnbd/nullable_receiver.dart'.
+// Try accessing using ?. instead.
+// a.bar;
+// ^
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:24:12: Warning: Assigning value of type 'void Function()?' to a variable of type 'Function'.
+// - 'Function' is from 'dart:core'.
+// Function f1 = a;
+// ^
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:25:19: Warning: Assigning value of type 'void Function()?' to a variable of type 'void Function()'.
+// void Function() f2 = a;
+// ^
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:34:5: Warning: Property 'hashCode' is accessed on 'String?' which is potentially null.
+// Try accessing using ?. instead.
+// s.hashCode;
+// ^
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:35:5: Warning: Property 'hashCode' is accessed on 'A?' which is potentially null.
+// - 'A' is from 'pkg/front_end/testcases/nnbd/nullable_receiver.dart'.
+// Try accessing using ?. instead.
+// a.hashCode;
+// ^
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:43:5: Warning: Property 'runtimeType' is accessed on 'String?' which is potentially null.
+// Try accessing using ?. instead.
+// s.runtimeType;
+// ^
+//
+// pkg/front_end/testcases/nnbd/nullable_receiver.dart:44:5: Warning: Property 'runtimeType' is accessed on 'A?' which is potentially null.
+// - 'A' is from 'pkg/front_end/testcases/nnbd/nullable_receiver.dart'.
+// Try accessing using ?. instead.
+// a.runtimeType;
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ synthetic constructor •() → self::A
+ : super core::Object::•()
+ ;
+ method foo() → dynamic {}
+ get bar() → core::int
+ return 42;
+ set baz(core::int value) → void {}
+ method call() → void {}
+}
+static method error(core::String? s, self::A? a) → dynamic {
+ s.{core::String::length};
+ s.{core::String::substring}(1, 1);
+ a.{self::A::foo}();
+ a.{self::A::bar};
+ a.{self::A::baz} = 42;
+ a.{self::A::call}();
+ core::Function f1 = let final self::A? #t1 = a in #t1.==(null) ?{() →? void} null : #t1.{self::A::call};
+ () → void f2 = let final self::A? #t2 = a in #t2.==(null) ?{() →? void} null : #t2.{self::A::call};
+ () →? void f3 = let final self::A? #t3 = a in #t3.==(null) ?{() →? void} null : #t3.{self::A::call};
+}
+static method ok(core::String? s, self::A? a, core::Invocation i) → dynamic {
+ s.{core::String::==}(s);
+ a.{core::Object::==}(a);
+ s.{core::String::hashCode};
+ a.{core::Object::hashCode};
+ s.{core::Object::toString}();
+ a.{core::Object::toString}();
+ try {
+ s.{core::Object::noSuchMethod}(i);
+ }
+ on dynamic catch(final dynamic e, final core::StackTrace t) {
+ }
+ try {
+ a.{core::Object::noSuchMethod}(i);
+ }
+ on dynamic catch(final dynamic e, final core::StackTrace t) {
+ }
+ s.{core::Object::runtimeType};
+ a.{core::Object::runtimeType};
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart b/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart
new file mode 100644
index 0000000..ae83e07
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.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.
+
+// The test checks for compile-time errors and their absence for cases involving
+// fields of potentially non-nullable types.
+
+int x;
+int? y; // Ok: it's nullable.
+late int z; // Ok: it's late.
+
+class A<T extends Object?> {
+ static int x;
+ static int? y; // Ok: it's nullable.
+ static late int z; // Ok: it's late.
+
+ int lx;
+ int? ly; // Ok: it's nullable.
+ late int? lz; // Ok: it's late.
+ int lv; // Ok: initialized in an initializing formal.
+ int lu; // Ok: initialized in an initializer list entry.
+
+ T lt;
+ T? ls; // Ok: it's nullable.
+ late T lr; // Ok: it's late.
+ T lp; // Ok: initialized in an initializing formal.
+ T lq; // Ok: initialized in an initializer list entry.
+
+ A(this.lv, this.lp, T t) : this.lu = 42, this.lq = t;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.outline.expect b/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.outline.expect
new file mode 100644
index 0000000..153b9bb
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.outline.expect
@@ -0,0 +1,26 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A<T extends core::Object? = core::Object?> extends core::Object {
+ static field core::int x;
+ static field core::int? y;
+ late static field core::int z;
+ field core::int lx;
+ field core::int? ly;
+ late field core::int? lz;
+ field core::int lv;
+ field core::int lu;
+ generic-covariant-impl field self::A::T% lt;
+ generic-covariant-impl field self::A::T? ls;
+ late generic-covariant-impl field self::A::T% lr;
+ generic-covariant-impl field self::A::T% lp;
+ generic-covariant-impl field self::A::T% lq;
+ constructor •(core::int lv, self::A::T% lp, self::A::T% t) → self::A<self::A::T%>
+ ;
+}
+static field core::int x;
+static field core::int? y;
+late static field core::int z;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.strong.expect b/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.strong.expect
new file mode 100644
index 0000000..80be9f2
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.strong.expect
@@ -0,0 +1,26 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A<T extends core::Object? = core::Object?> extends core::Object {
+ static field core::int x = null;
+ static field core::int? y = null;
+ late static field core::int z;
+ field core::int lx = null;
+ field core::int? ly = null;
+ late field core::int? lz;
+ field core::int lv;
+ field core::int lu;
+ generic-covariant-impl field self::A::T% lt = null;
+ generic-covariant-impl field self::A::T? ls = null;
+ late generic-covariant-impl field self::A::T% lr;
+ generic-covariant-impl field self::A::T% lp;
+ generic-covariant-impl field self::A::T% lq;
+ constructor •(core::int lv, self::A::T% lp, self::A::T% t) → self::A<self::A::T%>
+ : self::A::lv = lv, self::A::lp = lp, self::A::lu = 42, self::A::lq = t, super core::Object::•()
+ ;
+}
+static field core::int x;
+static field core::int? y;
+late static field core::int z;
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.strong.transformed.expect
new file mode 100644
index 0000000..80be9f2
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.strong.transformed.expect
@@ -0,0 +1,26 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A<T extends core::Object? = core::Object?> extends core::Object {
+ static field core::int x = null;
+ static field core::int? y = null;
+ late static field core::int z;
+ field core::int lx = null;
+ field core::int? ly = null;
+ late field core::int? lz;
+ field core::int lv;
+ field core::int lu;
+ generic-covariant-impl field self::A::T% lt = null;
+ generic-covariant-impl field self::A::T? ls = null;
+ late generic-covariant-impl field self::A::T% lr;
+ generic-covariant-impl field self::A::T% lp;
+ generic-covariant-impl field self::A::T% lq;
+ constructor •(core::int lv, self::A::T% lp, self::A::T% t) → self::A<self::A::T%>
+ : self::A::lv = lv, self::A::lp = lp, self::A::lu = 42, self::A::lq = t, super core::Object::•()
+ ;
+}
+static field core::int x;
+static field core::int? y;
+late static field core::int z;
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.weak.expect b/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.weak.expect
new file mode 100644
index 0000000..80be9f2
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.weak.expect
@@ -0,0 +1,26 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A<T extends core::Object? = core::Object?> extends core::Object {
+ static field core::int x = null;
+ static field core::int? y = null;
+ late static field core::int z;
+ field core::int lx = null;
+ field core::int? ly = null;
+ late field core::int? lz;
+ field core::int lv;
+ field core::int lu;
+ generic-covariant-impl field self::A::T% lt = null;
+ generic-covariant-impl field self::A::T? ls = null;
+ late generic-covariant-impl field self::A::T% lr;
+ generic-covariant-impl field self::A::T% lp;
+ generic-covariant-impl field self::A::T% lq;
+ constructor •(core::int lv, self::A::T% lp, self::A::T% t) → self::A<self::A::T%>
+ : self::A::lv = lv, self::A::lp = lp, self::A::lu = 42, self::A::lq = t, super core::Object::•()
+ ;
+}
+static field core::int x;
+static field core::int? y;
+late static field core::int z;
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.weak.transformed.expect
new file mode 100644
index 0000000..80be9f2
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/potentially_non_nullable_field.dart.weak.transformed.expect
@@ -0,0 +1,26 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A<T extends core::Object? = core::Object?> extends core::Object {
+ static field core::int x = null;
+ static field core::int? y = null;
+ late static field core::int z;
+ field core::int lx = null;
+ field core::int? ly = null;
+ late field core::int? lz;
+ field core::int lv;
+ field core::int lu;
+ generic-covariant-impl field self::A::T% lt = null;
+ generic-covariant-impl field self::A::T? ls = null;
+ late generic-covariant-impl field self::A::T% lr;
+ generic-covariant-impl field self::A::T% lp;
+ generic-covariant-impl field self::A::T% lq;
+ constructor •(core::int lv, self::A::T% lp, self::A::T% t) → self::A<self::A::T%>
+ : self::A::lv = lv, self::A::lp = lp, self::A::lu = 42, self::A::lq = t, super core::Object::•()
+ ;
+}
+static field core::int x;
+static field core::int? y;
+late static field core::int z;
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/required_named_parameter.dart b/pkg/front_end/testcases/nnbd/required_named_parameter.dart
index 49a509e..97f1ba3 100644
--- a/pkg/front_end/testcases/nnbd/required_named_parameter.dart
+++ b/pkg/front_end/testcases/nnbd/required_named_parameter.dart
@@ -4,8 +4,10 @@
// Should be a compile-time error / warning.
foo({required int parameter = 42}) {}
+foo2({int parameter}) {}
// Should be ok.
bar({required int parameter}) {}
+bar2({int parameter = 42}) {}
main() {}
diff --git a/pkg/front_end/testcases/nnbd/required_named_parameter.dart.outline.expect b/pkg/front_end/testcases/nnbd/required_named_parameter.dart.outline.expect
index 385108f..a0fc817 100644
--- a/pkg/front_end/testcases/nnbd/required_named_parameter.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/required_named_parameter.dart.outline.expect
@@ -11,7 +11,11 @@
static method foo({required core::int parameter}) → dynamic
;
+static method foo2({core::int parameter}) → dynamic
+ ;
static method bar({required core::int parameter}) → dynamic
;
+static method bar2({core::int parameter}) → dynamic
+ ;
static method main() → dynamic
;
diff --git a/pkg/front_end/testcases/nnbd/required_named_parameter.dart.strong.expect b/pkg/front_end/testcases/nnbd/required_named_parameter.dart.strong.expect
index b865c67..ff04da2 100644
--- a/pkg/front_end/testcases/nnbd/required_named_parameter.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/required_named_parameter.dart.strong.expect
@@ -10,7 +10,9 @@
import "dart:core" as core;
static method foo({required core::int parameter = #C1}) → dynamic {}
+static method foo2({core::int parameter = #C2}) → dynamic {}
static method bar({required core::int parameter = #C2}) → dynamic {}
+static method bar2({core::int parameter = #C1}) → dynamic {}
static method main() → dynamic {}
constants {
diff --git a/pkg/front_end/testcases/nnbd/required_named_parameter.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/required_named_parameter.dart.strong.transformed.expect
index b865c67..ff04da2 100644
--- a/pkg/front_end/testcases/nnbd/required_named_parameter.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/required_named_parameter.dart.strong.transformed.expect
@@ -10,7 +10,9 @@
import "dart:core" as core;
static method foo({required core::int parameter = #C1}) → dynamic {}
+static method foo2({core::int parameter = #C2}) → dynamic {}
static method bar({required core::int parameter = #C2}) → dynamic {}
+static method bar2({core::int parameter = #C1}) → dynamic {}
static method main() → dynamic {}
constants {
diff --git a/pkg/front_end/testcases/nnbd/required_named_parameter.dart.weak.expect b/pkg/front_end/testcases/nnbd/required_named_parameter.dart.weak.expect
index 0ccf7a2d..1686682 100644
--- a/pkg/front_end/testcases/nnbd/required_named_parameter.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/required_named_parameter.dart.weak.expect
@@ -10,7 +10,9 @@
import "dart:core" as core;
static method foo({required core::int parameter = #C1}) → dynamic {}
+static method foo2({core::int parameter = #C2}) → dynamic {}
static method bar({required core::int parameter = #C2}) → dynamic {}
+static method bar2({core::int parameter = #C1}) → dynamic {}
static method main() → dynamic {}
constants {
diff --git a/pkg/front_end/testcases/nnbd/required_named_parameter.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/required_named_parameter.dart.weak.transformed.expect
index 0ccf7a2d..1686682 100644
--- a/pkg/front_end/testcases/nnbd/required_named_parameter.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/required_named_parameter.dart.weak.transformed.expect
@@ -10,7 +10,9 @@
import "dart:core" as core;
static method foo({required core::int parameter = #C1}) → dynamic {}
+static method foo2({core::int parameter = #C2}) → dynamic {}
static method bar({required core::int parameter = #C2}) → dynamic {}
+static method bar2({core::int parameter = #C1}) → dynamic {}
static method main() → dynamic {}
constants {
diff --git a/pkg/front_end/testcases/nnbd/sink_hierarchy.dart b/pkg/front_end/testcases/nnbd/sink_hierarchy.dart
new file mode 100644
index 0000000..963e45f
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/sink_hierarchy.dart
@@ -0,0 +1,23 @@
+// 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.6
+
+abstract class Sink<T> {
+ void close();
+}
+
+abstract class EventSink<T> implements Sink<T> {
+ void close();
+}
+
+abstract class StreamConsumer<S> {
+ Future close();
+}
+
+abstract class StreamSink<S> implements EventSink<S>, StreamConsumer<S> {
+ Future close();
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/sink_hierarchy.dart.outline.expect b/pkg/front_end/testcases/nnbd/sink_hierarchy.dart.outline.expect
new file mode 100644
index 0000000..b423e94
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/sink_hierarchy.dart.outline.expect
@@ -0,0 +1,27 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "dart:async" as asy;
+
+abstract class Sink<T extends core::Object* = dynamic> extends core::Object {
+ synthetic constructor •() → self::Sink<self::Sink::T*>*
+ ;
+ abstract method close() → void;
+}
+abstract class EventSink<T extends core::Object* = dynamic> extends core::Object implements self::Sink<self::EventSink::T*> {
+ synthetic constructor •() → self::EventSink<self::EventSink::T*>*
+ ;
+ abstract method close() → void;
+}
+abstract class StreamConsumer<S extends core::Object* = dynamic> extends core::Object {
+ synthetic constructor •() → self::StreamConsumer<self::StreamConsumer::S*>*
+ ;
+ abstract method close() → asy::Future<dynamic>*;
+}
+abstract class StreamSink<S extends core::Object* = dynamic> extends core::Object implements self::EventSink<self::StreamSink::S*>, self::StreamConsumer<self::StreamSink::S*> {
+ synthetic constructor •() → self::StreamSink<self::StreamSink::S*>*
+ ;
+ abstract method close() → asy::Future<dynamic>*;
+}
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/nnbd/sink_hierarchy.dart.strong.expect b/pkg/front_end/testcases/nnbd/sink_hierarchy.dart.strong.expect
new file mode 100644
index 0000000..bd5a1e5
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/sink_hierarchy.dart.strong.expect
@@ -0,0 +1,30 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "dart:async" as asy;
+
+abstract class Sink<T extends core::Object* = dynamic> extends core::Object {
+ synthetic constructor •() → self::Sink<self::Sink::T*>*
+ : super core::Object::•()
+ ;
+ abstract method close() → void;
+}
+abstract class EventSink<T extends core::Object* = dynamic> extends core::Object implements self::Sink<self::EventSink::T*> {
+ synthetic constructor •() → self::EventSink<self::EventSink::T*>*
+ : super core::Object::•()
+ ;
+ abstract method close() → void;
+}
+abstract class StreamConsumer<S extends core::Object* = dynamic> extends core::Object {
+ synthetic constructor •() → self::StreamConsumer<self::StreamConsumer::S*>*
+ : super core::Object::•()
+ ;
+ abstract method close() → asy::Future<dynamic>*;
+}
+abstract class StreamSink<S extends core::Object* = dynamic> extends core::Object implements self::EventSink<self::StreamSink::S*>, self::StreamConsumer<self::StreamSink::S*> {
+ synthetic constructor •() → self::StreamSink<self::StreamSink::S*>*
+ : super core::Object::•()
+ ;
+ abstract method close() → asy::Future<dynamic>*;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/sink_hierarchy.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/sink_hierarchy.dart.strong.transformed.expect
new file mode 100644
index 0000000..bd5a1e5
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/sink_hierarchy.dart.strong.transformed.expect
@@ -0,0 +1,30 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "dart:async" as asy;
+
+abstract class Sink<T extends core::Object* = dynamic> extends core::Object {
+ synthetic constructor •() → self::Sink<self::Sink::T*>*
+ : super core::Object::•()
+ ;
+ abstract method close() → void;
+}
+abstract class EventSink<T extends core::Object* = dynamic> extends core::Object implements self::Sink<self::EventSink::T*> {
+ synthetic constructor •() → self::EventSink<self::EventSink::T*>*
+ : super core::Object::•()
+ ;
+ abstract method close() → void;
+}
+abstract class StreamConsumer<S extends core::Object* = dynamic> extends core::Object {
+ synthetic constructor •() → self::StreamConsumer<self::StreamConsumer::S*>*
+ : super core::Object::•()
+ ;
+ abstract method close() → asy::Future<dynamic>*;
+}
+abstract class StreamSink<S extends core::Object* = dynamic> extends core::Object implements self::EventSink<self::StreamSink::S*>, self::StreamConsumer<self::StreamSink::S*> {
+ synthetic constructor •() → self::StreamSink<self::StreamSink::S*>*
+ : super core::Object::•()
+ ;
+ abstract method close() → asy::Future<dynamic>*;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/sink_hierarchy.dart.weak.expect b/pkg/front_end/testcases/nnbd/sink_hierarchy.dart.weak.expect
new file mode 100644
index 0000000..bd5a1e5
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/sink_hierarchy.dart.weak.expect
@@ -0,0 +1,30 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "dart:async" as asy;
+
+abstract class Sink<T extends core::Object* = dynamic> extends core::Object {
+ synthetic constructor •() → self::Sink<self::Sink::T*>*
+ : super core::Object::•()
+ ;
+ abstract method close() → void;
+}
+abstract class EventSink<T extends core::Object* = dynamic> extends core::Object implements self::Sink<self::EventSink::T*> {
+ synthetic constructor •() → self::EventSink<self::EventSink::T*>*
+ : super core::Object::•()
+ ;
+ abstract method close() → void;
+}
+abstract class StreamConsumer<S extends core::Object* = dynamic> extends core::Object {
+ synthetic constructor •() → self::StreamConsumer<self::StreamConsumer::S*>*
+ : super core::Object::•()
+ ;
+ abstract method close() → asy::Future<dynamic>*;
+}
+abstract class StreamSink<S extends core::Object* = dynamic> extends core::Object implements self::EventSink<self::StreamSink::S*>, self::StreamConsumer<self::StreamSink::S*> {
+ synthetic constructor •() → self::StreamSink<self::StreamSink::S*>*
+ : super core::Object::•()
+ ;
+ abstract method close() → asy::Future<dynamic>*;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/sink_hierarchy.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/sink_hierarchy.dart.weak.transformed.expect
new file mode 100644
index 0000000..bd5a1e5
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/sink_hierarchy.dart.weak.transformed.expect
@@ -0,0 +1,30 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "dart:async" as asy;
+
+abstract class Sink<T extends core::Object* = dynamic> extends core::Object {
+ synthetic constructor •() → self::Sink<self::Sink::T*>*
+ : super core::Object::•()
+ ;
+ abstract method close() → void;
+}
+abstract class EventSink<T extends core::Object* = dynamic> extends core::Object implements self::Sink<self::EventSink::T*> {
+ synthetic constructor •() → self::EventSink<self::EventSink::T*>*
+ : super core::Object::•()
+ ;
+ abstract method close() → void;
+}
+abstract class StreamConsumer<S extends core::Object* = dynamic> extends core::Object {
+ synthetic constructor •() → self::StreamConsumer<self::StreamConsumer::S*>*
+ : super core::Object::•()
+ ;
+ abstract method close() → asy::Future<dynamic>*;
+}
+abstract class StreamSink<S extends core::Object* = dynamic> extends core::Object implements self::EventSink<self::StreamSink::S*>, self::StreamConsumer<self::StreamSink::S*> {
+ synthetic constructor •() → self::StreamSink<self::StreamSink::S*>*
+ : super core::Object::•()
+ ;
+ abstract method close() → asy::Future<dynamic>*;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart b/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart
new file mode 100644
index 0000000..89fe8b0
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart
@@ -0,0 +1,18 @@
+// 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.
+
+// The test checks for compile-time warnings about expressions of strictly
+// non-nullable types being used in positions typically occupied by those of
+// nullable types, that is, in various null-aware expressions.
+
+warning(String s, List<String> l) {
+ s?.length;
+ s?..length;
+ s ?? "foo";
+ s ??= "foo";
+ [...?l];
+ s!;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.outline.expect b/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.outline.expect
new file mode 100644
index 0000000..f2afe48
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.outline.expect
@@ -0,0 +1,8 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method warning(core::String s, core::List<core::String> l) → dynamic
+ ;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.strong.expect b/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.strong.expect
new file mode 100644
index 0000000..7bac66b
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.strong.expect
@@ -0,0 +1,19 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method warning(core::String s, core::List<core::String> l) → dynamic {
+ let final core::String #t1 = s in #t1.{core::String::==}(null) ?{core::int*} null : #t1.{core::String::length};
+ let final core::String #t2 = s in #t2.{core::String::==}(null) ?{core::String} null : let final void #t3 = #t2.{core::String::length} in #t2;
+ let final core::String #t4 = s in #t4.{core::String::==}(null) ?{core::String} "foo" : #t4;
+ s.{core::String::==}(null) ?{core::String} s = "foo" : null;
+ block {
+ final core::List<core::String*> #t5 = <core::String*>[];
+ final core::Iterable<core::String*>? #t6 = l;
+ if(!#t6.{core::Object::==}(null))
+ for (final core::String* #t7 in #t6{core::Iterable<core::String*>})
+ #t5.{core::List::add}(#t7);
+ } =>#t5;
+ s!;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.strong.transformed.expect
new file mode 100644
index 0000000..ec3449a
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.strong.transformed.expect
@@ -0,0 +1,24 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+static method warning(core::String s, core::List<core::String> l) → dynamic {
+ let final core::String #t1 = s in #t1.{core::String::==}(null) ?{core::int*} null : #t1.{core::String::length};
+ let final core::String #t2 = s in #t2.{core::String::==}(null) ?{core::String} null : let final void #t3 = #t2.{core::String::length} in #t2;
+ let final core::String #t4 = s in #t4.{core::String::==}(null) ?{core::String} "foo" : #t4;
+ s.{core::String::==}(null) ?{core::String} s = "foo" : null;
+ block {
+ final core::List<core::String*> #t5 = <core::String*>[];
+ final core::Iterable<core::String*>? #t6 = l;
+ if(!#t6.{core::Object::==}(null)) {
+ core::Iterator<core::String*>* :sync-for-iterator = _in::unsafeCast<core::Iterable<core::String*>*>(#t6{core::Iterable<core::String*>}).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ final core::String* #t7 = :sync-for-iterator.{core::Iterator::current};
+ #t5.{core::List::add}(#t7);
+ }
+ }
+ } =>#t5;
+ s!;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.weak.expect b/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.weak.expect
new file mode 100644
index 0000000..7bac66b
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.weak.expect
@@ -0,0 +1,19 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method warning(core::String s, core::List<core::String> l) → dynamic {
+ let final core::String #t1 = s in #t1.{core::String::==}(null) ?{core::int*} null : #t1.{core::String::length};
+ let final core::String #t2 = s in #t2.{core::String::==}(null) ?{core::String} null : let final void #t3 = #t2.{core::String::length} in #t2;
+ let final core::String #t4 = s in #t4.{core::String::==}(null) ?{core::String} "foo" : #t4;
+ s.{core::String::==}(null) ?{core::String} s = "foo" : null;
+ block {
+ final core::List<core::String*> #t5 = <core::String*>[];
+ final core::Iterable<core::String*>? #t6 = l;
+ if(!#t6.{core::Object::==}(null))
+ for (final core::String* #t7 in #t6{core::Iterable<core::String*>})
+ #t5.{core::List::add}(#t7);
+ } =>#t5;
+ s!;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.weak.transformed.expect
new file mode 100644
index 0000000..ec3449a
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/strictly_non_nullable_warnings.dart.weak.transformed.expect
@@ -0,0 +1,24 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+static method warning(core::String s, core::List<core::String> l) → dynamic {
+ let final core::String #t1 = s in #t1.{core::String::==}(null) ?{core::int*} null : #t1.{core::String::length};
+ let final core::String #t2 = s in #t2.{core::String::==}(null) ?{core::String} null : let final void #t3 = #t2.{core::String::length} in #t2;
+ let final core::String #t4 = s in #t4.{core::String::==}(null) ?{core::String} "foo" : #t4;
+ s.{core::String::==}(null) ?{core::String} s = "foo" : null;
+ block {
+ final core::List<core::String*> #t5 = <core::String*>[];
+ final core::Iterable<core::String*>? #t6 = l;
+ if(!#t6.{core::Object::==}(null)) {
+ core::Iterator<core::String*>* :sync-for-iterator = _in::unsafeCast<core::Iterable<core::String*>*>(#t6{core::Iterable<core::String*>}).{core::Iterable::iterator};
+ for (; :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ final core::String* #t7 = :sync-for-iterator.{core::Iterator::current};
+ #t5.{core::List::add}(#t7);
+ }
+ }
+ } =>#t5;
+ s!;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index d96b9d1..17d8d69 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -928,6 +928,10 @@
late_lowering/late_nullable_local_without_initializer: TextSerializationFailure
new_const_insertion/simple: TextSerializationFailure # Was: Pass
nnbd/assignability: TextSerializationFailure
+nnbd/definite_assignment_and_completion
+nnbd/definite_assignment_and_completion: TextSerializationFailure
+nnbd/forbidden_supers: TextSerializationFailure
+nnbd/forin: TextSerializationFailure
nnbd/function_types: TextSerializationFailure
nnbd/infer_if_null: TextSerializationFailure
nnbd/inheritance_from_opt_in: TypeCheckError
@@ -938,6 +942,10 @@
nnbd/issue_39286: TextSerializationFailure
nnbd/issue_39286_2: TextSerializationFailure
nnbd/late: TextSerializationFailure
+nnbd/later: TextSerializationFailure
+nnbd/list_constructor: TextSerializationFailure
+nnbd/member_inheritance_from_opt_in: TextSerializationFailure
+nnbd/member_inheritance_from_opt_out: TextSerializationFailure
nnbd/messages_with_types_opt_in: TypeCheckError
nnbd/messages_with_types_opt_out: TypeCheckError
nnbd/missing_required_named_parameter: TextSerializationFailure
@@ -954,11 +962,15 @@
nnbd/nullable_access: TextSerializationFailure
nnbd/nullable_null: TextSerializationFailure
nnbd/nullable_param: TextSerializationFailure
+nnbd/nullable_receiver: TextSerializationFailure
nnbd/opt_out: TextSerializationFailure
+nnbd/potentially_non_nullable_field: TextSerializationFailure
nnbd/regress_null_aware: TextSerializationFailure
nnbd/required: TextSerializationFailure
nnbd/required_named_parameter: TextSerializationFailure
nnbd/simple_never: TextSerializationFailure
+nnbd/sink_hierarchy: TextSerializationFailure
+nnbd/strictly_non_nullable_warnings: TextSerializationFailure
nnbd/substitution_in_inference: TextSerializationFailure
nnbd/type_parameter_types: TextSerializationFailure
no_such_method_forwarders/abstract_accessors_from_field: TextSerializationFailure # Was: Pass
diff --git a/pkg/front_end/testing.json b/pkg/front_end/testing.json
index dfecc60..82cbcc1 100644
--- a/pkg/front_end/testing.json
+++ b/pkg/front_end/testing.json
@@ -434,12 +434,8 @@
"test/extensions/data/",
"test/id_testing/data/",
"test/language_versioning/data/",
- "test/flow_analysis/assigned_variables/data/",
- "test/flow_analysis/definite_assignment/data/",
- "test/flow_analysis/nullability/data/",
- "test/flow_analysis/reachability/data/",
- "test/flow_analysis/type_promotion/data/",
- "test/patching/data"
+ "test/patching/data",
+ "test/static_types/data/"
]
}
}
diff --git a/pkg/front_end/testing_with_lints.json b/pkg/front_end/testing_with_lints.json
index 8f65ff9..78fdd07 100644
--- a/pkg/front_end/testing_with_lints.json
+++ b/pkg/front_end/testing_with_lints.json
@@ -15,12 +15,8 @@
"test/extensions/data/",
"test/id_testing/data/",
"test/language_versioning/data/",
- "test/flow_analysis/assigned_variables/data/",
- "test/flow_analysis/definite_assignment/data/",
- "test/flow_analysis/nullability/data/",
- "test/flow_analysis/reachability/data/",
- "test/flow_analysis/type_promotion/data/",
- "test/patching/data/"
+ "test/patching/data/",
+ "test/static_types/data/"
]
}
}
diff --git a/pkg/front_end/tool/perf.dart b/pkg/front_end/tool/perf.dart
index 2c6fd5b..edec99c 100644
--- a/pkg/front_end/tool/perf.dart
+++ b/pkg/front_end/tool/perf.dart
@@ -23,16 +23,15 @@
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/error/listener.dart';
-import 'package:analyzer/file_system/physical_file_system.dart'
- show PhysicalResourceProvider;
-import 'package:analyzer/src/context/builder.dart';
+import 'package:analyzer/file_system/file_system.dart' show Folder;
+import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/src/context/packages.dart';
import 'package:analyzer/src/dart/sdk/sdk.dart' show FolderBasedDartSdk;
import 'package:analyzer/src/file_system/file_system.dart';
import 'package:analyzer/src/generated/parser.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/source_io.dart';
import 'package:analyzer/src/source/package_map_resolver.dart';
-import 'package:package_config/discovery.dart';
import 'package:path/path.dart' as path;
main(List<String> args) async {
@@ -45,7 +44,7 @@
var bench = args[0];
var entryUri = Uri.base.resolve(args[1]);
- await setup(entryUri);
+ await setup(path.fromUri(entryUri));
Set<Source> files = scanReachableFiles(entryUri);
var handlers = {
@@ -196,10 +195,19 @@
/// Sets up analyzer to be able to load and resolve app, packages, and sdk
/// sources.
-Future setup(Uri entryUri) async {
+Future setup(String path) async {
var provider = PhysicalResourceProvider.INSTANCE;
- var packageMap = ContextBuilder.convertPackagesToMap(
- provider, await findPackages(entryUri));
+
+ var packages = findPackagesFrom(
+ provider,
+ provider.getResource(path),
+ );
+
+ var packageMap = <String, List<Folder>>{};
+ for (var package in packages.packages) {
+ packageMap[package.name] = [package.libFolder];
+ }
+
sources = new SourceFactory([
new ResourceUriResolver(provider),
new PackageMapUriResolver(provider, packageMap),
diff --git a/pkg/kernel/binary.md b/pkg/kernel/binary.md
index 55e003a..12f3b1f 100644
--- a/pkg/kernel/binary.md
+++ b/pkg/kernel/binary.md
@@ -143,7 +143,7 @@
type ComponentFile {
UInt32 magic = 0x90ABCDEF;
- UInt32 formatVersion = 36;
+ UInt32 formatVersion = 37;
List<String> problemsAsJson; // Described in problems.md.
Library[] libraries;
UriSource sourceMap;
@@ -409,7 +409,7 @@
Byte kind; // Index into the ProcedureKind enum above.
UInt flags (isStatic, isAbstract, isExternal, isConst, isForwardingStub,
isForwardingSemiStub, isRedirectingFactoryConstructor,
- isNoSuchMethodForwarder, isExtensionMember);
+ isNoSuchMethodForwarder, isExtensionMember, isMemberSignature);
Name name;
List<Expression> annotations;
// Only present if the 'isForwardingStub' flag is set.
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index c68657b..4cb08a9 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -2018,6 +2018,7 @@
bool isConst: false,
bool isForwardingStub: false,
bool isForwardingSemiStub: false,
+ bool isMemberSignature: false,
bool isExtensionMember: false,
int transformerFlags: 0,
Uri fileUri,
@@ -2030,6 +2031,7 @@
isExternal: isExternal,
isConst: isConst,
isForwardingStub: isForwardingStub,
+ isMemberSignature: isMemberSignature,
isForwardingSemiStub: isForwardingSemiStub,
isExtensionMember: isExtensionMember,
transformerFlags: transformerFlags,
@@ -2047,6 +2049,7 @@
bool isConst: false,
bool isForwardingStub: false,
bool isForwardingSemiStub: false,
+ bool isMemberSignature: false,
bool isExtensionMember: false,
int transformerFlags: 0,
Uri fileUri,
@@ -2061,6 +2064,7 @@
this.isConst = isConst;
this.isForwardingStub = isForwardingStub;
this.isForwardingSemiStub = isForwardingSemiStub;
+ this.isMemberSignature = isMemberSignature;
this.isExtensionMember = isExtensionMember;
this.transformerFlags = transformerFlags;
}
@@ -2075,6 +2079,7 @@
static const int FlagRedirectingFactoryConstructor = 1 << 6;
static const int FlagNoSuchMethodForwarder = 1 << 7;
static const int FlagExtensionMember = 1 << 8;
+ static const int FlagMemberSignature = 1 << 9;
bool get isStatic => flags & FlagStatic != 0;
bool get isAbstract => flags & FlagAbstract != 0;
@@ -2098,6 +2103,15 @@
/// stub, it was present in the original source as an abstract method.
bool get isForwardingSemiStub => flags & FlagForwardingSemiStub != 0;
+ /// If set, this method is a class member added to show the type of an
+ /// inherited member.
+ ///
+ /// This is used when the type of the inherited member cannot be computed
+ /// directly from the member(s) in the supertypes. For instance in case of
+ /// an nnbd opt-out class inheriting from an nnbd opt-in class; here all nnbd-
+ /// aware types are replaced with legacy types in the inherited signature.
+ bool get isMemberSignature => flags & FlagMemberSignature != 0;
+
// Indicates if this [Procedure] represents a redirecting factory constructor
// and doesn't have a runnable body.
bool get isRedirectingFactoryConstructor {
@@ -2141,6 +2155,11 @@
: (flags & ~FlagForwardingSemiStub);
}
+ void set isMemberSignature(bool value) {
+ flags =
+ value ? (flags | FlagMemberSignature) : (flags & ~FlagMemberSignature);
+ }
+
void set isRedirectingFactoryConstructor(bool value) {
flags = value
? (flags | FlagRedirectingFactoryConstructor)
diff --git a/pkg/kernel/lib/binary/tag.dart b/pkg/kernel/lib/binary/tag.dart
index 00e609f..9ed4051 100644
--- a/pkg/kernel/lib/binary/tag.dart
+++ b/pkg/kernel/lib/binary/tag.dart
@@ -149,7 +149,7 @@
/// Internal version of kernel binary format.
/// Bump it when making incompatible changes in kernel binaries.
/// Keep in sync with runtime/vm/kernel_binary.h, pkg/kernel/binary.md.
- static const int BinaryFormatVersion = 36;
+ static const int BinaryFormatVersion = 37;
}
abstract class ConstantTag {
diff --git a/pkg/kernel/lib/class_hierarchy.dart b/pkg/kernel/lib/class_hierarchy.dart
index 39b6ac1..4ac5d73 100644
--- a/pkg/kernel/lib/class_hierarchy.dart
+++ b/pkg/kernel/lib/class_hierarchy.dart
@@ -259,6 +259,7 @@
/// Compares members by name, using the same sort order as
/// [getDeclaredMembers] and [getInterfaceMembers].
static int compareMembers(Member first, Member second) {
+ if (first == second) return 0;
return compareNames(first.name, second.name);
}
diff --git a/pkg/kernel/lib/text/ast_to_text.dart b/pkg/kernel/lib/text/ast_to_text.dart
index 5ae2df6..015b3b8 100644
--- a/pkg/kernel/lib/text/ast_to_text.dart
+++ b/pkg/kernel/lib/text/ast_to_text.dart
@@ -1088,6 +1088,7 @@
writeModifier(node.isAbstract, 'abstract');
writeModifier(node.isForwardingStub, 'forwarding-stub');
writeModifier(node.isForwardingSemiStub, 'forwarding-semi-stub');
+ writeModifier(node.isMemberSignature, 'member-signature');
writeModifier(node.isNoSuchMethodForwarder, 'no-such-method-forwarder');
writeWord(procedureKindToString(node.kind));
if ((node.enclosingClass == null &&
diff --git a/pkg/nnbd_migration/lib/src/conditional_discard.dart b/pkg/nnbd_migration/lib/src/conditional_discard.dart
index 8495d47..dfddc9b 100644
--- a/pkg/nnbd_migration/lib/src/conditional_discard.dart
+++ b/pkg/nnbd_migration/lib/src/conditional_discard.dart
@@ -11,6 +11,9 @@
/// This information will be associated with an Expression in the input program
/// whose boolean value influences control flow (e.g. the condition of an `if`
/// statement).
+///
+/// TODO(paulberry): simplify this once PotentialModification is no longer
+/// needed.
class ConditionalDiscard {
/// Nullability node that will be `nullable` if the code path that results
/// from the condition evaluating to `true` will be reachable after
diff --git a/pkg/nnbd_migration/lib/src/edit_plan.dart b/pkg/nnbd_migration/lib/src/edit_plan.dart
index e93001c..c6464d8 100644
--- a/pkg/nnbd_migration/lib/src/edit_plan.dart
+++ b/pkg/nnbd_migration/lib/src/edit_plan.dart
@@ -6,9 +6,43 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/precedence.dart';
+import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/source/line_info.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:meta/meta.dart';
+import 'package:nnbd_migration/instrumentation.dart';
+
+Map<int, List<AtomicEdit>> _removeCode(
+ int offset, int end, _RemovalStyle removalStyle) {
+ if (offset < end) {
+ // TODO(paulberry): handle preexisting comments?
+ switch (removalStyle) {
+ case _RemovalStyle.commentSpace:
+ return {
+ offset: [AtomicEdit.insert('/* ')],
+ end: [AtomicEdit.insert('*/ ')]
+ };
+ case _RemovalStyle.delete:
+ return {
+ offset: [AtomicEdit.delete(end - offset)]
+ };
+ case _RemovalStyle.spaceComment:
+ return {
+ offset: [AtomicEdit.insert(' /*')],
+ end: [AtomicEdit.insert(' */')]
+ };
+ case _RemovalStyle.spaceInsideComment:
+ return {
+ offset: [AtomicEdit.insert('/* ')],
+ end: [AtomicEdit.insert(' */')]
+ };
+ }
+ throw StateError('Null value for removalStyle');
+ } else {
+ return null;
+ }
+}
/// A single atomic change to a source file, decoupled from the location at
/// which the change is made. The [EditPlan] class performs its duties by
@@ -66,6 +100,26 @@
}
}
+/// An atomic edit that has a reason associated with it.
+class AtomicEditWithReason extends AtomicEdit {
+ /// The reason for the edit.
+ final FixReasonInfo fixReason;
+
+ /// Initialize an edit to delete [length] characters.
+ const AtomicEditWithReason.delete(int length, this.fixReason)
+ : super.delete(length);
+
+ /// Initialize an edit to insert the [replacement] characters.
+ const AtomicEditWithReason.insert(String replacement, this.fixReason)
+ : super.insert(replacement);
+
+ /// Initialize an edit to replace [length] characters with the [replacement]
+ /// characters.
+ const AtomicEditWithReason.replace(
+ int length, String replacement, this.fixReason)
+ : super.replace(length, replacement);
+}
+
/// An [EditPlan] is a builder capable of accumulating a set of edits to be
/// applied to a given [AstNode].
///
@@ -88,20 +142,6 @@
/// AST node being replaced. For edit plans that insert or delete AST nodes,
/// this is the parent of the AST nodes that will be inserted or deleted.
AstNode get parentNode;
-
- /// Returns a new [EditPlan] that replicates this [EditPlan], but may
- /// incorporate relevant information obtained from the parent of [sourceNode].
- /// For example, if this [EditPlan] would produce an expression that might or
- /// might not need parentheses, and the parent of [sourceNode] is a
- /// [ParenthesizedExpression], then an [EditPlan] is produced that will either
- /// preserve the existing parentheses, or remove them, as appropriate.
- ///
- /// May return `this`, if no information needs to be incorporated from the
- /// parent.
- ///
- /// This method is used when composing and finalizing plans, to ensure that
- /// parentheses are removed when they are no longer needed.
- NodeProducingEditPlan _incorporateParent();
}
/// Factory class for creating [EditPlan]s.
@@ -111,7 +151,25 @@
/// that is removed.
final bool removeViaComments;
- EditPlanner({this.removeViaComments = false});
+ /// The line info for the source file being edited. This is used when
+ /// removing statements that fill one or more lines, so that we can remove
+ /// the indentation as well as the statement, and avoid leaving behind ugly
+ /// whitespace.
+ final LineInfo lineInfo;
+
+ /// The text of the source file being edited. This is used when removing
+ /// code, so that we can figure out if it is safe to remove adjoining
+ /// whitespace.
+ final String sourceText;
+
+ EditPlanner(this.lineInfo, this.sourceText, {this.removeViaComments = false});
+
+ /// Creates a [_PassThroughBuilder] object based around [node].
+ ///
+ /// Exposed so that we can substitute a mock class in unit tests.
+ @visibleForTesting
+ PassThroughBuilder createPassThroughBuilder(AstNode node) =>
+ _PassThroughBuilderImpl(node);
/// Creates a new edit plan that consists of executing [innerPlan], and then
/// removing from the source code any code that is in [sourceNode] but not in
@@ -126,8 +184,9 @@
/// caller.
NodeProducingEditPlan extract(
AstNode sourceNode, NodeProducingEditPlan innerPlan) {
- if (!identical(innerPlan.sourceNode.parent, sourceNode)) {
- innerPlan = innerPlan._incorporateParent();
+ var parent = innerPlan.sourceNode.parent;
+ if (!identical(parent, sourceNode) && parent is ParenthesizedExpression) {
+ innerPlan = _ProvisionalParenEditPlan(parent, innerPlan);
}
return _ExtractEditPlan(sourceNode, innerPlan, this);
}
@@ -139,25 +198,118 @@
/// Finalizing an [EditPlan] is a destructive operation; it should not be used
/// again after it is finalized.
Map<int, List<AtomicEdit>> finalize(EditPlan plan) {
- var incorporatedPlan = plan._incorporateParent();
- return incorporatedPlan
- ._getChanges(incorporatedPlan.parensNeededFromContext(null));
+ // Convert to a plan for the top level CompilationUnit.
+ var parent = plan.parentNode;
+ if (parent != null) {
+ var unit = parent.thisOrAncestorOfType<CompilationUnit>();
+ plan = passThrough(unit, innerPlans: [plan]);
+ }
+ // The plan for a compilation unit should always be a NodeProducingEditPlan.
+ // So we can just ask it for its changes.
+ return (plan as NodeProducingEditPlan)._getChanges(false);
}
/// Creates a new edit plan that makes no changes to [node], but may make
/// changes to some of its descendants (specified via [innerPlans]).
///
+ /// Note that the [innerPlans] must be specified in document order.
+ ///
/// All plans in [innerPlans] will be finalized as a side effect (either
/// immediately or when the newly created plan is finalized), so they should
/// not be re-used by the caller.
NodeProducingEditPlan passThrough(AstNode node,
{Iterable<EditPlan> innerPlans = const []}) {
- if (node is ParenthesizedExpression) {
- return _ProvisionalParenEditPlan(
- node, _PassThroughEditPlan(node.expression, innerPlans: innerPlans));
- } else {
- return _PassThroughEditPlan(node, innerPlans: innerPlans);
+ // It's possible that some of the inner plans are nested more deeply within
+ // [node] than others. We want to group these inner plans together into
+ // pass through plans at each level in the AST until we bubble up to [node].
+ // To do so, we form a stack of [_PassThroughBuilder] objects to handle each
+ // level of AST depth, where the first entry in the stack corresponds to
+ // [node], and each subsequent entry will correspond to a child of the
+ // previous.
+ var builderStack = [createPassThroughBuilder(node)];
+ var ancestryPath = <AstNode>[];
+ for (var plan in innerPlans) {
+ // Compute the ancestryPath (the path from `plan.parentNode` up to
+ // `node`). Note that whereas builderStack walks stepwise down the AST,
+ // ancestryStack will walk stepwise up the AST, with the last entry of
+ // ancestryStack corresponding to the first entry of builderStack. We
+ // re-use the same list for each loop iteration to reduce GC load.
+ ancestryPath.clear();
+ for (var parent = plan.parentNode;
+ !identical(parent, node);
+ parent = parent.parent) {
+ ancestryPath.add(parent);
+ }
+ ancestryPath.add(node);
+ // Find the deepest entry in builderStack that's on the ancestryPath.
+ var builderIndex = _findMatchingBuilder(builderStack, ancestryPath);
+ // We're finished with all builders beyond that entry.
+ while (builderStack.length > builderIndex + 1) {
+ var passThrough = builderStack.removeLast().finish(this);
+ builderStack.last.add(passThrough);
+ }
+ // And we may need to add new builders to make our way down to
+ // `plan.parentNode`.
+ while (builderStack.length < ancestryPath.length) {
+ // Since builderStack and ancestryPath walk in different directions
+ // through the AST, when building entry builderIndex, we need to count
+ // backwards from the end of ancestryPath to figure out which node to
+ // associate the builder with.
+ builderStack.add(createPassThroughBuilder(
+ ancestryPath[ancestryPath.length - builderStack.length - 1]));
+ }
+ // Now the deepest entry in the builderStack corresponds to
+ // `plan.parentNode`, so we can add the plan to it.
+ builderStack.last.add(plan);
}
+ // We're now finished with all builders.
+ while (true) {
+ var passThrough = builderStack.removeLast().finish(this);
+ if (builderStack.isEmpty) return passThrough;
+ builderStack.last.add(passThrough);
+ }
+ }
+
+ /// Creates a new edit plan that removes [node] from the AST.
+ ///
+ /// [node] must be one element of a variable length sequence maintained by
+ /// [node]'s parent (for example, a statement in a block, an element in a
+ /// list, a declaration in a class, etc.)
+ EditPlan removeNode(AstNode sourceNode) {
+ var parent = sourceNode.parent;
+ var sequenceNodes = _computeSequenceNodes(parent);
+ if (sequenceNodes == null) {
+ throw StateError(
+ 'Cannot remove node whose parent is of type ${parent.runtimeType}');
+ }
+ var index = sequenceNodes.indexOf(sourceNode);
+ assert(index != -1);
+ return _RemoveEditPlan(parent, index, index);
+ }
+
+ /// Creates a new edit plan that removes a sequence of adjacent nodes from
+ /// the AST, starting with [firstSourceNode] and ending with [lastSourceNode].
+ ///
+ /// [firstSourceNode] and [lastSourceNode] must be elements of a variable
+ /// length sequence maintained by their (common) parent (for example,
+ /// statements in a block, elements in a list, declarations in a class, etc.)
+ /// [lastSourceNode] must come after [firstSourceNode].
+ ///
+ /// If [firstSourceNode] and [lastSourceNode] are the same node, then the
+ /// behavior is identical to [removeNode] (i.e. just the one node is removed).
+ EditPlan removeNodes(AstNode firstSourceNode, AstNode lastSourceNode) {
+ var parent = firstSourceNode.parent;
+ assert(identical(lastSourceNode.parent, parent));
+ var sequenceNodes = _computeSequenceNodes(parent);
+ if (sequenceNodes == null) {
+ throw StateError(
+ 'Cannot remove node whose parent is of type ${parent.runtimeType}');
+ }
+ var firstIndex = sequenceNodes.indexOf(firstSourceNode);
+ assert(firstIndex != -1);
+ var lastIndex = sequenceNodes.indexOf(lastSourceNode, firstIndex);
+ assert(lastIndex >= firstIndex);
+ return _RemoveEditPlan(parent, firstIndex, lastIndex);
}
/// Creates a new edit plan that consists of executing [innerPlan], and then
@@ -210,6 +362,124 @@
: endsInCascade,
innerChanges);
}
+
+ /// Walks backward through the source text, starting at [offset] and stopping
+ /// before passing any non-whitespace character.
+ ///
+ /// Does not walk further than [limit] (which should be less than or equal to
+ /// [offset]).
+ int _backAcrossWhitespace(int offset, int limit) {
+ assert(limit <= offset);
+ return limit + sourceText.substring(limit, offset).trimRight().length;
+ }
+
+ /// Walks backward through the source text, starting at [offset] and stopping
+ /// when the beginning of the line is reached.
+ ///
+ /// If [offset] is at the beginning of the line, it is returned unchanged.
+ int _backToLineStart(int offset) {
+ var lineNumber = lineInfo.getLocation(offset).lineNumber;
+ // lineNumber is one-based, but lineInfo.lineStarts expects a zero-based
+ // index, so we need `lineInfo.lineStarts[lineNumber - 1]`.
+ return lineInfo.lineStarts[lineNumber - 1];
+ }
+
+ /// Finds the deepest entry in [builderStack] that matches an entry in
+ /// [ancestryStack], taking advantage of the fact that [builderStack] walks
+ /// stepwise down the AST, and [ancestryStack] walks stepwise up the AST, with
+ /// the last entry of [ancestryStack] corresponding to the first entry of
+ /// [builderStack].
+ int _findMatchingBuilder(
+ List<PassThroughBuilder> builderStack, List<AstNode> ancestryStack) {
+ var builderIndex = builderStack.length - 1;
+ while (builderIndex > 0) {
+ var ancestryIndex = ancestryStack.length - builderIndex - 1;
+ if (ancestryIndex >= 0 &&
+ identical(
+ builderStack[builderIndex].node, ancestryStack[ancestryIndex])) {
+ break;
+ }
+ --builderIndex;
+ }
+ return builderIndex;
+ }
+
+ /// Walks forward through the source text, starting at [offset] and stopping
+ /// before passing any non-whitespace character.
+ ///
+ /// Does not walk further than [limit] (which should be greater than or equal
+ /// to [offset]).
+ int _forwardAcrossWhitespace(int offset, int limit) {
+ return limit - sourceText.substring(offset, limit).trimLeft().length;
+ }
+
+ /// Walks forward through the source text, starting at [offset] and stopping
+ /// at the beginning of the next line (or at the end of the document, if this
+ /// line is the last line).
+ int _forwardToLineEnd(int offset) {
+ int lineNumber = lineInfo.getLocation(offset).lineNumber;
+ // lineNumber is one-based, so if it is equal to
+ // `lineInfo.lineStarts.length`, then we are on the last line.
+ if (lineNumber >= lineInfo.lineStarts.length) {
+ return sourceText.length;
+ }
+ // lineInfo.lineStarts expects a zero-based index, so
+ // `lineInfo.lineStarts[lineNumber]` gives us the beginning of the next
+ // line.
+ return lineInfo.lineStarts[lineNumber];
+ }
+
+ /// Determines whether the given source [offset] comes just after an opener
+ /// ('(', '[', or '{').
+ bool _isJustAfterOpener(int offset) =>
+ offset > 0 && const ['(', '[', '{'].contains(sourceText[offset - 1]);
+
+ /// Determines whether the given source [end] comes just before a closer
+ /// (')', ']', or '}').
+ bool _isJustBeforeCloser(int end) =>
+ end < sourceText.length &&
+ const [')', ']', '}'].contains(sourceText[end]);
+
+ /// Determines if the characters between [offset] and [end] in the source text
+ /// are all whitespace characters.
+ bool _isWhitespaceRange(int offset, int end) {
+ return sourceText.substring(offset, end).trimRight().isEmpty;
+ }
+
+ /// If the given [node] maintains a variable-length sequence of child nodes,
+ /// returns a list containing those child nodes, otherwise returns `null`.
+ ///
+ /// The returned list may or may not be the exact list used by the node to
+ /// maintain its child nodes. For example, [CompilationUnit] maintains its
+ /// directives and declarations in separate lists, so the returned list is
+ /// a new list containing both directives and declarations.
+ static List<AstNode> _computeSequenceNodes(AstNode node) {
+ if (node is Block) {
+ return node.statements;
+ } else if (node is ListLiteral) {
+ return node.elements;
+ } else if (node is SetOrMapLiteral) {
+ return node.elements;
+ } else if (node is ArgumentList) {
+ return node.arguments;
+ } else if (node is FormalParameterList) {
+ return node.parameters;
+ } else if (node is VariableDeclarationList) {
+ return node.variables;
+ } else if (node is TypeArgumentList) {
+ return node.arguments;
+ } else if (node is TypeParameterList) {
+ return node.typeParameters;
+ } else if (node is EnumDeclaration) {
+ return node.constants;
+ } else if (node is ClassDeclaration) {
+ return node.members;
+ } else if (node is CompilationUnit) {
+ return [...node.directives, ...node.declarations];
+ } else {
+ return null;
+ }
+ }
}
/// Specialization of [EditPlan] for the situation where the text being produced
@@ -266,16 +536,6 @@
/// finalized.
Map<int, List<AtomicEdit>> _getChanges(bool parens);
- @override
- NodeProducingEditPlan _incorporateParent() {
- var parent = sourceNode.parent;
- if (parent is ParenthesizedExpression) {
- return _ProvisionalParenEditPlan(parent, this);
- } else {
- return this;
- }
- }
-
/// Determines if the text that would be produced by [EditPlan] needs to be
/// surrounded by parens, based on the context in which it will be used.
bool _parensNeeded(
@@ -284,6 +544,22 @@
bool allowCascade = false});
}
+/// Data structure that accumulates together a set of [EditPlans] sharing a
+/// common parent node, and groups them together into an [EditPlan] with a
+/// parent node one level up the AST.
+@visibleForTesting
+abstract class PassThroughBuilder {
+ /// The AST node that is the parent of all the [EditPlan]s being accumulated.
+ AstNode get node;
+
+ /// Accumulate another edit plan.
+ void add(EditPlan innerPlan);
+
+ /// Called when no more edit plans need to be added. Returns the final
+ /// [EditPlan].
+ NodeProducingEditPlan finish(EditPlanner planner);
+}
+
/// Visitor that determines whether a given [AstNode] ends in a cascade.
class _EndsInCascadeVisitor extends UnifyingAstVisitor<void> {
bool endsInCascade = false;
@@ -343,32 +619,6 @@
}
return changes;
}
-
- static Map<int, List<AtomicEdit>> _removeCode(
- int offset, int end, _RemovalStyle removalStyle) {
- if (offset < end) {
- // TODO(paulberry): handle preexisting comments?
- switch (removalStyle) {
- case _RemovalStyle.commentSpace:
- return {
- offset: [AtomicEdit.insert('/* ')],
- end: [AtomicEdit.insert('*/ ')]
- };
- case _RemovalStyle.delete:
- return {
- offset: [AtomicEdit.delete(end - offset)]
- };
- case _RemovalStyle.spaceComment:
- return {
- offset: [AtomicEdit.insert(' /*')],
- end: [AtomicEdit.insert(' */')]
- };
- }
- throw StateError('Null value for removalStyle');
- } else {
- return null;
- }
- }
}
/// [EditPlan] representing additional edits performed on the result of a
@@ -607,36 +857,72 @@
}
}
-/// [EditPlan] representing an AstNode that is not to be changed, but may have
-/// some changes applied to some of its descendants.
-class _PassThroughEditPlan extends _SimpleEditPlan {
- factory _PassThroughEditPlan(AstNode node,
- {Iterable<EditPlan> innerPlans = const []}) {
- bool /*?*/ endsInCascade = node is CascadeExpression ? true : null;
- Map<int, List<AtomicEdit>> changes;
- for (var innerPlan in innerPlans) {
- if (!identical(innerPlan.parentNode, node)) {
- innerPlan = innerPlan._incorporateParent();
- }
+class _PassThroughBuilderImpl implements PassThroughBuilder {
+ @override
+ final AstNode node;
+
+ /// The [EditPlan]s accumulated so far.
+ final List<EditPlan> innerPlans = [];
+
+ /// The [EditPlanner] currently being used to create this
+ /// [_PassThroughEditPlan].
+ EditPlanner planner;
+
+ /// Determination of whether the resulting [EditPlan] will end in a cascade,
+ /// or `null` if it is not yet known.
+ bool endsInCascade;
+
+ /// The set of changes aggregated together so far.
+ Map<int, List<AtomicEdit>> changes;
+
+ /// Index into [innerPlans] of the plan to process next.
+ int planIndex = 0;
+
+ /// If [node] is a sequence, the list of its child nodes. Otherwise `null`.
+ List<AstNode> sequenceNodes;
+
+ /// If [node] is a sequence that uses separators (e.g. a list literal, which
+ /// uses comma separators), a list of its separators. Otherwise `null`.
+ List<Token> separators;
+
+ /// If [separators] is non-null, and nodes are being removed from the
+ /// sequence, this boolean indicates whether each node should be removed along
+ /// with the separator that *precedes* it.
+ ///
+ /// `false` indicates that each node should be removed along with the
+ /// separator that *follows* it.
+ bool removeLeadingSeparators = false;
+
+ _PassThroughBuilderImpl(this.node);
+
+ @override
+ void add(EditPlan innerPlan) {
+ assert(identical(innerPlan.parentNode, node));
+ innerPlans.add(innerPlan);
+ }
+
+ @override
+ NodeProducingEditPlan finish(EditPlanner planner) {
+ this.planner = planner;
+ var node = this.node;
+ if (node is ParenthesizedExpression) {
+ assert(innerPlans.length <= 1);
+ var innerPlan = innerPlans.isEmpty
+ ? planner.passThrough(node.expression)
+ : innerPlans[0];
if (innerPlan is NodeProducingEditPlan) {
- var parensNeeded = innerPlan.parensNeededFromContext(node);
- assert(_checkParenLogic(innerPlan, parensNeeded));
- if (!parensNeeded && innerPlan is _ProvisionalParenEditPlan) {
- var innerInnerPlan = innerPlan.innerPlan;
- if (innerInnerPlan is _PassThroughEditPlan) {
- // Input source code had redundant parens, so keep them.
- parensNeeded = true;
- }
- }
- changes += innerPlan._getChanges(parensNeeded);
- if (endsInCascade == null && innerPlan.sourceNode.end == node.end) {
- endsInCascade = !parensNeeded && innerPlan.endsInCascade;
- }
- } else {
- // TODO(paulberry): handle this case.
- throw UnimplementedError('Inner plan is not node-producing');
+ return _ProvisionalParenEditPlan(node, innerPlan);
}
}
+
+ // Make a provisional determination of whether the result will end in a
+ // cascade.
+ // TODO(paulberry): can we make some of these computations lazy?
+ endsInCascade = node is CascadeExpression ? true : null;
+ sequenceNodes = EditPlanner._computeSequenceNodes(node);
+ separators =
+ sequenceNodes == null ? null : _computeSeparators(node, sequenceNodes);
+ _processPlans();
return _PassThroughEditPlan._(
node,
node is Expression ? node.precedence : Precedence.primary,
@@ -644,9 +930,173 @@
changes);
}
- _PassThroughEditPlan._(AstNode node, Precedence precedence,
- bool endsInCascade, Map<int, List<AtomicEdit>> innerChanges)
- : super(node, precedence, endsInCascade, innerChanges);
+ /// Starting at index [planIndex] of [innerPlans] (whose value is [plan]),
+ /// scans forward to see if there is a range of inner plans that remove a
+ /// contiguous range of AST nodes.
+ ///
+ /// Returns the index into [innerPlans] of the last such contiguous plan, or
+ /// [planIndex] if a contiguous range of removals wasn't found.
+ int _findConsecutiveRemovals(int planIndex, _RemoveEditPlan plan) {
+ assert(identical(innerPlans[planIndex], plan));
+ var lastRemovePlanIndex = planIndex;
+ var lastRemoveEditPlan = plan;
+ while (lastRemovePlanIndex + 1 < innerPlans.length) {
+ var nextPlan = innerPlans[lastRemovePlanIndex + 1];
+ if (nextPlan is _RemoveEditPlan) {
+ if (nextPlan.firstChildIndex == lastRemoveEditPlan.lastChildIndex + 1) {
+ // Removals are consecutive. Slurp up.
+ lastRemovePlanIndex++;
+ lastRemoveEditPlan = nextPlan;
+ continue;
+ }
+ }
+ break;
+ }
+ return lastRemovePlanIndex;
+ }
+
+ /// Processes an inner plan of type [NodeProducingEditPlan], and updates
+ /// [planIndex] to point to the next inner plan.
+ void _handleNodeProducingEditPlan(NodeProducingEditPlan innerPlan) {
+ var parensNeeded = innerPlan.parensNeededFromContext(node);
+ assert(_checkParenLogic(innerPlan, parensNeeded));
+ if (!parensNeeded && innerPlan is _ProvisionalParenEditPlan) {
+ var innerInnerPlan = innerPlan.innerPlan;
+ if (innerInnerPlan is _PassThroughEditPlan) {
+ // Input source code had redundant parens, so keep them.
+ parensNeeded = true;
+ }
+ }
+ changes += innerPlan._getChanges(parensNeeded);
+ if (endsInCascade == null && innerPlan.sourceNode.end == node.end) {
+ endsInCascade = !parensNeeded && innerPlan.endsInCascade;
+ }
+ planIndex++;
+ }
+
+ /// Processes one or more inner plans of type [_RemoveEditPlan], and updates
+ /// [planIndex] to point to the next inner plan.
+ void _handleRemoveEditPlans(_RemoveEditPlan firstPlan) {
+ assert(identical(firstPlan.parentNode, node));
+ var firstPlanIndex = planIndex;
+ var lastPlanIndex = _findConsecutiveRemovals(firstPlanIndex, firstPlan);
+ var lastPlan = innerPlans[lastPlanIndex] as _RemoveEditPlan;
+ int lastRemovalEnd;
+ int nextRemovalOffset;
+ removeLeadingSeparators = separators != null &&
+ firstPlan.firstChildIndex != 0 &&
+ lastPlan.lastChildIndex >= separators.length;
+ if (planner.removeViaComments) {
+ nextRemovalOffset = _removalOffset(firstPlan);
+ lastRemovalEnd = _removalEnd(lastPlan);
+ } else {
+ var firstRemovalOffset = _removalOffset(firstPlan);
+ var firstLineStart = planner._backToLineStart(firstRemovalOffset);
+ var startsOnLineBoundary =
+ planner._isWhitespaceRange(firstLineStart, firstRemovalOffset);
+ lastRemovalEnd = _removalEnd(lastPlan);
+ var lastLineEnd = planner._forwardToLineEnd(lastRemovalEnd);
+ var endsOnLineBoundary =
+ planner._isWhitespaceRange(lastRemovalEnd, lastLineEnd);
+ if (!endsOnLineBoundary) {
+ // E.g. removing B and C, and possibly A, from `A; B; C; D;`. Want to
+ // remove the whitespace after `C;`.
+ lastRemovalEnd =
+ planner._forwardAcrossWhitespace(lastRemovalEnd, lastLineEnd);
+ } else if (!startsOnLineBoundary) {
+ // E.g. removing B and C from `A; B; C;`. Want to remove the whitespace
+ // before `B`.
+ firstRemovalOffset =
+ planner._backAcrossWhitespace(firstRemovalOffset, firstLineStart);
+ } else {
+ // Removing whole lines.
+ firstRemovalOffset = firstLineStart;
+ lastRemovalEnd = lastLineEnd;
+ }
+ if (firstPlanIndex == 0 && lastPlanIndex == sequenceNodes.length - 1) {
+ // We're removing everything. Try to remove additional whitespace so
+ // that we're left with just `()`, `{}`, or `[]`.
+ var candidateFirstRemovalOffset =
+ planner._backAcrossWhitespace(firstRemovalOffset, node.offset);
+ if (planner._isJustAfterOpener(candidateFirstRemovalOffset)) {
+ var candidateLastRemovalEnd =
+ planner._forwardAcrossWhitespace(lastRemovalEnd, node.end);
+ if (planner._isJustBeforeCloser(candidateLastRemovalEnd)) {
+ firstRemovalOffset = candidateFirstRemovalOffset;
+ lastRemovalEnd = candidateLastRemovalEnd;
+ }
+ }
+ }
+ nextRemovalOffset = firstRemovalOffset;
+ }
+
+ for (; planIndex <= lastPlanIndex; planIndex++) {
+ var offset = nextRemovalOffset;
+ int end;
+ if (planIndex == lastPlanIndex) {
+ end = lastRemovalEnd;
+ } else {
+ var innerPlan = innerPlans[planIndex + 1] as _RemoveEditPlan;
+ assert(identical(innerPlan.parentNode, node));
+ nextRemovalOffset = _removalOffset(innerPlan);
+ if (planner.removeViaComments) {
+ end = _removalEnd(innerPlans[planIndex] as _RemoveEditPlan);
+ } else {
+ var lineStart = planner._backToLineStart(nextRemovalOffset);
+ if (planner._isWhitespaceRange(lineStart, nextRemovalOffset)) {
+ // The next node to remove starts at the beginning of a line
+ // (possibly with whitespace before it). Consider the removal of
+ // the whitespace to be part of removing the next node.
+ nextRemovalOffset = lineStart;
+ }
+ end = nextRemovalOffset;
+ }
+ }
+ changes += _removeCode(
+ offset,
+ end,
+ planner.removeViaComments
+ ? _RemovalStyle.spaceInsideComment
+ : _RemovalStyle.delete);
+ }
+ }
+
+ /// Walks through the plans in [innerPlans], adjusting them as necessary and
+ /// collecting their changes in [changes].
+ void _processPlans() {
+ while (planIndex < innerPlans.length) {
+ var innerPlan = innerPlans[planIndex];
+ if (innerPlan is NodeProducingEditPlan) {
+ _handleNodeProducingEditPlan(innerPlan);
+ } else if (innerPlan is _RemoveEditPlan) {
+ _handleRemoveEditPlans(innerPlan);
+ } else {
+ throw UnimplementedError('Unrecognized inner plan type');
+ }
+ }
+ }
+
+ /// Computes the end for the text that should be removed by the given
+ /// [innerPlan].
+ int _removalEnd(_RemoveEditPlan innerPlan) {
+ if (separators != null &&
+ !removeLeadingSeparators &&
+ innerPlan.lastChildIndex < separators.length) {
+ return separators[innerPlan.lastChildIndex].end;
+ } else {
+ return sequenceNodes[innerPlan.lastChildIndex].end;
+ }
+ }
+
+ /// Computes the offset for the text that should be removed by the given
+ /// [innerPlan].
+ int _removalOffset(_RemoveEditPlan innerPlan) {
+ if (separators != null && removeLeadingSeparators) {
+ return separators[innerPlan.firstChildIndex - 1].offset;
+ } else {
+ return sequenceNodes[innerPlan.firstChildIndex].offset;
+ }
+ }
static bool _checkParenLogic(EditPlan innerPlan, bool parensNeeded) {
if (innerPlan is _SimpleEditPlan && innerPlan._innerChanges == null) {
@@ -657,6 +1107,37 @@
}
return true;
}
+
+ /// Compute the set of tokens used by the given [parent] node to separate its
+ /// [childNodes].
+ static List<Token> _computeSeparators(
+ AstNode parent, List<AstNode> childNodes) {
+ if (parent is Block ||
+ parent is ClassDeclaration ||
+ parent is CompilationUnit) {
+ // These parent types don't use separators.
+ return null;
+ } else {
+ var result = <Token>[];
+ for (var child in childNodes) {
+ var separator = child.endToken.next;
+ if (separator != null && separator.type == TokenType.COMMA) {
+ result.add(separator);
+ }
+ }
+ assert(result.length == childNodes.length ||
+ result.length == childNodes.length - 1);
+ return result;
+ }
+ }
+}
+
+/// [EditPlan] representing an AstNode that is not to be changed, but may have
+/// some changes applied to some of its descendants.
+class _PassThroughEditPlan extends _SimpleEditPlan {
+ _PassThroughEditPlan._(AstNode node, Precedence precedence,
+ bool endsInCascade, Map<int, List<AtomicEdit>> innerChanges)
+ : super(node, precedence, endsInCascade, innerChanges);
}
/// [EditPlan] applying to a [ParenthesizedExpression]. Unlike the normal
@@ -701,6 +1182,30 @@
/// Code should be removed by commenting it out. Inserted comment delimiters
/// should be a space followed by a comment delimiter (i.e. ` /*` and ` */`).
spaceComment,
+
+ /// Code should be removed by commenting it out. Inserted comment delimiters
+ /// should have a space inside the comment.
+ spaceInsideComment,
+}
+
+/// [EditPlan] representing one or more AstNodes that are to be removed from
+/// their (common) parent, which must be an AST node that stores a list of
+/// sub-nodes.
+///
+/// If more than one node is to be removed by this [EditPlan], they must be
+/// contiguous.
+class _RemoveEditPlan extends EditPlan {
+ @override
+ final AstNode parentNode;
+
+ /// Index of the node to be removed within the parent.
+ final int firstChildIndex;
+
+ /// Index of the node to be removed within the parent.
+ final int lastChildIndex;
+
+ _RemoveEditPlan(this.parentNode, this.firstChildIndex, this.lastChildIndex)
+ : super._();
}
/// Implementation of [EditPlan] underlying simple cases where no computation
diff --git a/pkg/nnbd_migration/lib/src/fix_aggregator.dart b/pkg/nnbd_migration/lib/src/fix_aggregator.dart
index ffdd042..76c403d 100644
--- a/pkg/nnbd_migration/lib/src/fix_aggregator.dart
+++ b/pkg/nnbd_migration/lib/src/fix_aggregator.dart
@@ -5,6 +5,7 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/precedence.dart';
import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:nnbd_migration/src/decorated_type.dart';
import 'package:nnbd_migration/src/edit_plan.dart';
/// Implementation of [NodeChange] representing the addition of the keyword
@@ -25,6 +26,60 @@
}
}
+/// Implementation of [NodeChange] representing the removal of a dead branch
+/// because the conditional expression in an if statement, if element, or
+/// conditional expression has been determined to always evaluate to either
+/// `true` or `false`.
+///
+/// TODO(paulberry): store additional information necessary to include in the
+/// preview.
+class EliminateDeadIf extends NodeChange {
+ /// The value that the conditional expression has been determined to always
+ /// evaluate to
+ final bool conditionValue;
+
+ const EliminateDeadIf(this.conditionValue);
+
+ @override
+ EditPlan apply(AstNode node, FixAggregator aggregator) {
+ // TODO(paulberry): do we need to detect whether the condition has side
+ // effects? For now, assuming no.
+ AstNode nodeToKeep;
+ if (node is IfStatement) {
+ nodeToKeep = conditionValue ? node.thenStatement : node.elseStatement;
+ } else if (node is ConditionalExpression) {
+ nodeToKeep = conditionValue ? node.thenExpression : node.elseExpression;
+ } else if (node is IfElement) {
+ nodeToKeep = conditionValue ? node.thenElement : node.elseElement;
+ } else {
+ throw StateError(
+ "EliminateDeadIf applied to an AST node that's not an if");
+ }
+ if (nodeToKeep == null) {
+ return aggregator.planner.removeNode(node);
+ }
+ if (nodeToKeep is Block) {
+ if (nodeToKeep.statements.isEmpty) {
+ return aggregator.planner.removeNode(node);
+ } else if (nodeToKeep.statements.length == 1) {
+ var singleStatement = nodeToKeep.statements[0];
+ if (singleStatement is VariableDeclarationStatement) {
+ // It's not safe to eliminate the {} because it increases the scope of
+ // the variable declarations
+ } else {
+ return aggregator.planner.extract(node,
+ aggregator.planner.passThrough(nodeToKeep.statements.single));
+ }
+ }
+ }
+ return aggregator.planner
+ .extract(node, aggregator.planner.passThrough(nodeToKeep));
+ }
+
+ @override
+ String toString() => 'EliminateDeadIf($conditionValue)';
+}
+
/// Visitor that combines together the changes produced by [FixBuilder] into a
/// concrete set of source code edits using the infrastructure of [EditPlan].
class FixAggregator extends UnifyingAstVisitor<void> {
@@ -41,12 +96,17 @@
/// Gathers all the changes to nodes descended from [node] into a single
/// [EditPlan].
- NodeProducingEditPlan innerPlanForNode(AstNode node) {
+ NodeProducingEditPlan innerPlanForNode(AstNode node) =>
+ planner.passThrough(node, innerPlans: innerPlansForNode(node));
+
+ /// Gathers all the changes to nodes descended from [node] into a list of
+ /// [EditPlan]s, one for each change.
+ List<EditPlan> innerPlansForNode(AstNode node) {
var previousPlans = _plans;
try {
_plans = [];
node.visitChildren(this);
- return planner.passThrough(node, innerPlans: _plans);
+ return _plans;
} finally {
_plans = previousPlans;
}
@@ -67,8 +127,10 @@
/// Runs the [FixAggregator] on a [unit] and returns the resulting edits.
static Map<int, List<AtomicEdit>> run(
- CompilationUnit unit, Map<AstNode, NodeChange> changes) {
- var planner = EditPlanner();
+ CompilationUnit unit, String sourceText, Map<AstNode, NodeChange> changes,
+ {bool removeViaComments: false}) {
+ var planner = EditPlanner(unit.lineInfo, sourceText,
+ removeViaComments: removeViaComments);
var aggregator = FixAggregator._(planner, changes);
unit.accept(aggregator);
if (aggregator._plans.isEmpty) return {};
@@ -107,19 +169,19 @@
/// Implementation of [NodeChange] representing the addition of a trailing `?`
/// to a type.
-///
-/// TODO(paulberry): store additional information necessary to include in the
-/// preview.
class MakeNullable extends _NestableChange {
- const MakeNullable(
+ /// The decorated type to which a question mark is being added.
+ final DecoratedType decoratedType;
+
+ const MakeNullable(this.decoratedType,
[NodeChange<NodeProducingEditPlan> inner = const NoChange()])
: super(inner);
@override
EditPlan apply(AstNode node, FixAggregator aggregator) {
var innerPlan = _inner.apply(node, aggregator);
- return aggregator.planner
- .surround(innerPlan, suffix: [const AtomicEdit.insert('?')]);
+ return aggregator.planner.surround(innerPlan,
+ suffix: [AtomicEditWithReason.insert('?', decoratedType.node)]);
}
}
diff --git a/pkg/nnbd_migration/lib/src/fix_builder.dart b/pkg/nnbd_migration/lib/src/fix_builder.dart
index 2097229..a64053f 100644
--- a/pkg/nnbd_migration/lib/src/fix_builder.dart
+++ b/pkg/nnbd_migration/lib/src/fix_builder.dart
@@ -198,6 +198,23 @@
MigrationResolutionHooksImpl(this._fixBuilder);
@override
+ bool getConditionalKnownValue(AstNode node) {
+ // TODO(paulberry): handle things other than IfStatement.
+ var conditionalDiscard =
+ _fixBuilder._variables.getConditionalDiscard(_fixBuilder.source, node);
+ if (conditionalDiscard == null) {
+ return null;
+ } else {
+ if (conditionalDiscard.keepTrue && conditionalDiscard.keepFalse) {
+ return null;
+ }
+ var conditionValue = conditionalDiscard.keepTrue;
+ _fixBuilder._addChange(node, EliminateDeadIf(conditionValue));
+ return conditionValue;
+ }
+ }
+
+ @override
List<ParameterElement> getExecutableParameters(ExecutableElement element) =>
getExecutableType(element).parameters;
@@ -285,7 +302,9 @@
_fixBuilder._variables.decoratedTypeAnnotation(source, node);
var type = decoratedType.type;
if (!type.isDynamic && !type.isVoid && decoratedType.node.isNullable) {
- _fixBuilder._addChange(node, MakeNullable());
+ var decoratedType =
+ _fixBuilder._variables.decoratedTypeAnnotation(source, node);
+ _fixBuilder._addChange(node, MakeNullable(decoratedType));
}
if (node is TypeName) {
var typeArguments = node.typeArguments;
diff --git a/pkg/nnbd_migration/lib/src/nullability_migration_impl.dart b/pkg/nnbd_migration/lib/src/nullability_migration_impl.dart
index cff8c09..3a7646b 100644
--- a/pkg/nnbd_migration/lib/src/nullability_migration_impl.dart
+++ b/pkg/nnbd_migration/lib/src/nullability_migration_impl.dart
@@ -43,6 +43,11 @@
/// Currently defaults to `false`.
final bool useFixBuilder;
+ /// Indicates whether code removed by the migration engine should be removed
+ /// by commenting it out. A value of `false` means to actually delete the
+ /// code that is removed.
+ final bool removeViaComments;
+
/// Prepares to perform nullability migration.
///
/// If [permissive] is `true`, exception handling logic will try to proceed
@@ -57,17 +62,16 @@
///
/// Optional parameter [removeViaComments] indicates whether dead code should
/// be removed in its entirety (the default) or removed by commenting it out.
- /// TODO(paulberry): wire this up.
NullabilityMigrationImpl(NullabilityMigrationListener listener,
{bool permissive: false,
NullabilityMigrationInstrumentation instrumentation,
bool useFixBuilder: false,
bool removeViaComments = false})
: this._(listener, NullabilityGraph(instrumentation: instrumentation),
- permissive, instrumentation, useFixBuilder);
+ permissive, instrumentation, useFixBuilder, removeViaComments);
NullabilityMigrationImpl._(this.listener, this._graph, this._permissive,
- this._instrumentation, this.useFixBuilder) {
+ this._instrumentation, this.useFixBuilder, this.removeViaComments) {
_instrumentation?.immutableNodes(_graph.never, _graph.always);
}
@@ -90,15 +94,20 @@
_variables,
library);
fixBuilder.visitAll(unit);
- var changes = FixAggregator.run(unit, fixBuilder.changes);
+ var changes = FixAggregator.run(unit, result.content, fixBuilder.changes,
+ removeViaComments: removeViaComments);
for (var entry in changes.entries) {
final lineInfo = LineInfo.fromContent(source.contents.data);
var fix = _SingleNullabilityFix(
source, const _DummyPotentialModification(), lineInfo);
listener.addFix(fix);
- // TODO(paulberry): don't pass null to instrumentation.
- _instrumentation?.fix(fix, null);
- listener.addEdit(fix, entry.value.toSourceEdit(entry.key));
+ var edits = entry.value;
+ _instrumentation?.fix(
+ fix,
+ edits
+ .whereType<AtomicEditWithReason>()
+ .map((edit) => edit.fixReason));
+ listener.addEdit(fix, edits.toSourceEdit(entry.key));
}
}
diff --git a/pkg/nnbd_migration/lib/src/variables.dart b/pkg/nnbd_migration/lib/src/variables.dart
index d190727..8db150a 100644
--- a/pkg/nnbd_migration/lib/src/variables.dart
+++ b/pkg/nnbd_migration/lib/src/variables.dart
@@ -22,6 +22,8 @@
class Variables implements VariableRecorder, VariableRepository {
final NullabilityGraph _graph;
+ final _conditionalDiscards = <Source, Map<int, ConditionalDiscard>>{};
+
final _decoratedElementTypes = <Element, DecoratedType>{};
final _decoratedTypeParameterBounds = <Element, DecoratedType>{};
@@ -104,12 +106,16 @@
}
}
+ ConditionalDiscard getConditionalDiscard(Source source, AstNode node) =>
+ (_conditionalDiscards[source] ?? {})[node.offset];
+
Map<Source, List<PotentialModification>> getPotentialModifications() =>
_potentialModifications;
@override
void recordConditionalDiscard(
Source source, AstNode node, ConditionalDiscard conditionalDiscard) {
+ (_conditionalDiscards[source] ??= {})[node.offset] = conditionalDiscard;
_addPotentialModification(
source, ConditionalModification(node, conditionalDiscard));
}
diff --git a/pkg/nnbd_migration/test/api_test.dart b/pkg/nnbd_migration/test/api_test.dart
index 8aaf324..54aa90b 100644
--- a/pkg/nnbd_migration/test/api_test.dart
+++ b/pkg/nnbd_migration/test/api_test.dart
@@ -2075,6 +2075,7 @@
await _checkSingleFileChanges(content, expected);
}
+ @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/38472')
Future<void> test_ifStatement_nullCheck_noElse() async {
var content = '''
int f(int x) {
@@ -2084,7 +2085,6 @@
''';
var expected = '''
int f(int x) {
- if (x == null) return 0;
return x;
}
''';
@@ -3854,11 +3854,6 @@
@override
@FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/38472')
- Future<void> test_discard_simple_condition() =>
- super.test_discard_simple_condition();
-
- @override
- @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/38472')
Future<void> test_downcast_dynamic_function_to_functionType() =>
super.test_downcast_dynamic_function_to_functionType();
@@ -3883,11 +3878,6 @@
@override
@FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/40023')
- Future<void> test_extension_nullableOnType_typeArgument() =>
- super.test_extension_nullableOnType_typeArgument();
-
- @override
- @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/40023')
Future<void> test_extension_nullableOnType_viaImplicitInvocation() =>
super.test_extension_nullableOnType_viaImplicitInvocation();
@@ -3898,25 +3888,6 @@
@override
@FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/38472')
- Future<void> test_field_initializer_untyped_list_literal() =>
- super.test_field_initializer_untyped_list_literal();
-
- @override
- @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/38472')
- Future<void> test_field_initializer_untyped_map_literal() =>
- super.test_field_initializer_untyped_map_literal();
-
- @override
- @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/38472')
- Future<void> test_field_initializer_untyped_set_literal() =>
- super.test_field_initializer_untyped_set_literal();
-
- @override
- @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/38472')
- Future<void> test_for_each_basic() => super.test_for_each_basic();
-
- @override
- @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/38472')
Future<void> test_generic_exact_propagation() =>
super.test_generic_exact_propagation();
@@ -3925,6 +3896,11 @@
Future<void> test_generic_exact_propagation_premigratedListClass() =>
super.test_generic_exact_propagation_premigratedListClass();
+ /// Test fails under the pre-FixBuilder implementation; passes now.
+ @override
+ Future<void> test_ifStatement_nullCheck_noElse() =>
+ super.test_ifStatement_nullCheck_noElse();
+
@override
@FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/38472')
Future<void> test_instance_creation_generic() =>
diff --git a/pkg/nnbd_migration/test/edit_plan_test.dart b/pkg/nnbd_migration/test/edit_plan_test.dart
index 8287884..5990bb9 100644
--- a/pkg/nnbd_migration/test/edit_plan_test.dart
+++ b/pkg/nnbd_migration/test/edit_plan_test.dart
@@ -5,6 +5,7 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/precedence.dart';
import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/source/line_info.dart';
import 'package:nnbd_migration/src/edit_plan.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -23,15 +24,27 @@
class EditPlanTest extends AbstractSingleUnitTest {
String code;
- var planner = EditPlanner();
+ EditPlanner _planner;
+
+ EditPlanner get planner {
+ if (_planner == null) createPlanner();
+ return _planner;
+ }
Future<void> analyze(String code) async {
this.code = code;
await resolveTestUnit(code);
}
- void checkPlan(EditPlan plan, String expected) {
- expect(planner.finalize(plan).applyTo(code), expected);
+ Map<int, List<AtomicEdit>> checkPlan(EditPlan plan, String expected) {
+ var changes = planner.finalize(plan);
+ expect(changes.applyTo(code), expected);
+ return changes;
+ }
+
+ void createPlanner({bool removeViaComments: false}) {
+ _planner = EditPlanner(testUnit.lineInfo, code,
+ removeViaComments: removeViaComments);
}
NodeProducingEditPlan extract(AstNode inner, AstNode outer) =>
@@ -74,7 +87,7 @@
// We can tell that the parens have been finalized because `endsInCascade`
// returns false now.
expect(plan.endsInCascade, false);
- checkPlan(plan, 'f(a, c) => a..b = c = (1..isEven);');
+ checkPlan(plan, 'f(a, c) => a..b = (c = 1..isEven);');
}
}
@@ -126,23 +139,38 @@
'var x = 1 + 2 << 4;');
}
+ Future<void> test_extract_remove_redundant_parens() async {
+ await analyze('var x = (1 * 2) + 3;');
+ var times = findNode.binary('*');
+ checkPlan(extract(times, times.parent), 'var x = 1 * 2 + 3;');
+ }
+
+ Future<void> test_extract_try_to_remove_necessary_parens() async {
+ // This is a weird corner case. We try to extract the expression `1 + 2`
+ // from `( 1 + 2 )`, meaning we should remove parens. But the parens are
+ // necessary. So we create fresh ones (without the spaces).
+ await analyze('var x = ( 1 + 2 ) * 3;');
+ var plus = findNode.binary('+');
+ checkPlan(extract(plus, plus.parent), 'var x = (1 + 2) * 3;');
+ }
+
Future<void> test_extract_using_comments_inner() async {
- planner = EditPlanner(removeViaComments: true);
await analyze('var x = 1 + 2 * 3;');
+ createPlanner(removeViaComments: true);
checkPlan(extract(findNode.integerLiteral('2'), findNode.binary('+')),
'var x = /* 1 + */ 2 /* * 3 */;');
}
Future<void> test_extract_using_comments_left() async {
- planner = EditPlanner(removeViaComments: true);
await analyze('var x = 1 + 2;');
+ createPlanner(removeViaComments: true);
checkPlan(extract(findNode.integerLiteral('1'), findNode.binary('+')),
'var x = 1 /* + 2 */;');
}
Future<void> test_extract_using_comments_right() async {
- planner = EditPlanner(removeViaComments: true);
await analyze('var x = 1 + 2;');
+ createPlanner(removeViaComments: true);
checkPlan(extract(findNode.integerLiteral('2'), findNode.binary('+')),
'var x = /* 1 + */ 2;');
}
@@ -158,6 +186,574 @@
'var x = 0; var y = 0;');
}
+ Future<void> test_passThrough_remove_statement() async {
+ await analyze('''
+void f() {
+ var x = () {
+ 1;
+ 2;
+ 3;
+ };
+}
+''');
+ var innerPlan = planner.removeNode(findNode.statement('2'));
+ var outerPlan = planner.passThrough(findNode.variableDeclaration('x'),
+ innerPlans: [innerPlan]);
+ checkPlan(outerPlan, '''
+void f() {
+ var x = () {
+ 1;
+ 3;
+ };
+}
+''');
+ }
+
+ Future<void> test_remove_argument() async {
+ await analyze('f(dynamic d) => d(1, 2, 3);');
+ var i2 = findNode.integerLiteral('2');
+ var changes = checkPlan(planner.removeNode(i2), 'f(dynamic d) => d(1, 3);');
+ expect(changes.keys, [i2.offset]);
+ }
+
+ Future<void> test_remove_class_member() async {
+ await analyze('''
+class C {
+ int x;
+ int y;
+ int z;
+}
+''');
+ var declaration = findNode.fieldDeclaration('y');
+ var changes = checkPlan(planner.removeNode(declaration), '''
+class C {
+ int x;
+ int z;
+}
+''');
+ expect(changes.keys, [declaration.offset - 2]);
+ }
+
+ Future<void>
+ test_remove_elements_of_related_lists_at_different_levels() async {
+ await analyze('var x = [[1, 2], 3, 4];');
+ var i2 = findNode.integerLiteral('2');
+ var i3 = findNode.integerLiteral('3');
+ checkPlan(
+ planner.passThrough(testUnit,
+ innerPlans: [planner.removeNode(i2), planner.removeNode(i3)]),
+ 'var x = [[1], 4];');
+ }
+
+ Future<void>
+ test_remove_elements_of_sibling_lists_passThrough_container() async {
+ await analyze('var x = [[1, 2], [3, 4]];');
+ var i2 = findNode.integerLiteral('2');
+ var i3 = findNode.integerLiteral('3');
+ checkPlan(
+ planner.passThrough(i2.parent.parent,
+ innerPlans: [planner.removeNode(i2), planner.removeNode(i3)]),
+ 'var x = [[1], [4]];');
+ }
+
+ Future<void> test_remove_elements_of_sibling_lists_passThrough_unit() async {
+ await analyze('var x = [[1, 2], [3, 4]];');
+ var i2 = findNode.integerLiteral('2');
+ var i3 = findNode.integerLiteral('3');
+ checkPlan(
+ planner.passThrough(testUnit,
+ innerPlans: [planner.removeNode(i2), planner.removeNode(i3)]),
+ 'var x = [[1], [4]];');
+ }
+
+ Future<void> test_remove_enum_constant() async {
+ await analyze('''
+enum E {
+ A,
+ B,
+ C
+}
+''');
+ var enumConstant = findNode.simple('B').parent;
+ var changes = checkPlan(planner.removeNode(enumConstant), '''
+enum E {
+ A,
+ C
+}
+''');
+ expect(changes.keys, [enumConstant.offset - 2]);
+ }
+
+ Future<void> test_remove_field_declaration() async {
+ await analyze('''
+class C {
+ int x, y, z;
+}
+''');
+ var declaration = findNode.simple('y').parent;
+ var changes = checkPlan(planner.removeNode(declaration), '''
+class C {
+ int x, z;
+}
+''');
+ expect(changes.keys, [declaration.offset]);
+ }
+
+ Future<void> test_remove_list_element() async {
+ await analyze('var x = [1, 2, 3];');
+ var i2 = findNode.integerLiteral('2');
+ var changes = checkPlan(planner.removeNode(i2), 'var x = [1, 3];');
+ expect(changes.keys, [i2.offset]);
+ }
+
+ Future<void> test_remove_list_element_at_list_end() async {
+ await analyze('var x = [1, 2, 3];');
+ var i2 = findNode.integerLiteral('2');
+ var i3 = findNode.integerLiteral('3');
+ var changes = checkPlan(planner.removeNode(i3), 'var x = [1, 2];');
+ expect(changes.keys, [i2.end]);
+ }
+
+ Future<void> test_remove_list_element_singleton() async {
+ await analyze('var x = [1];');
+ var i1 = findNode.integerLiteral('1');
+ checkPlan(planner.removeNode(i1), 'var x = [];');
+ }
+
+ Future<void> test_remove_list_element_with_trailing_separator() async {
+ await analyze('var x = [1, 2, 3, ];');
+ var i3 = findNode.integerLiteral('3');
+ checkPlan(planner.removeNode(i3), 'var x = [1, 2, ];');
+ }
+
+ Future<void> test_remove_list_elements() async {
+ await analyze('var x = [1, 2, 3, 4, 5];');
+ var i2 = findNode.integerLiteral('2');
+ var i4 = findNode.integerLiteral('4');
+ var changes = checkPlan(
+ planner.passThrough(i2.parent,
+ innerPlans: [planner.removeNode(i2), planner.removeNode(i4)]),
+ 'var x = [1, 3, 5];');
+ expect(changes.keys, unorderedEquals([i2.offset, i4.offset]));
+ }
+
+ Future<void> test_remove_list_elements_all() async {
+ await analyze('var x = [1, 2];');
+ var i1 = findNode.integerLiteral('1');
+ var i2 = findNode.integerLiteral('2');
+ checkPlan(
+ planner.passThrough(i1.parent,
+ innerPlans: [planner.removeNode(i1), planner.removeNode(i2)]),
+ 'var x = [];');
+ }
+
+ Future<void> test_remove_list_elements_all_asUnit() async {
+ await analyze('var x = [1, 2];');
+ var i1 = findNode.integerLiteral('1');
+ var i2 = findNode.integerLiteral('2');
+ checkPlan(planner.removeNodes(i1, i2), 'var x = [];');
+ }
+
+ Future<void> test_remove_list_elements_all_passThrough_unit() async {
+ await analyze('var x = [1, 2];');
+ var i1 = findNode.integerLiteral('1');
+ var i2 = findNode.integerLiteral('2');
+ checkPlan(
+ planner.passThrough(testUnit,
+ innerPlans: [planner.removeNode(i1), planner.removeNode(i2)]),
+ 'var x = [];');
+ }
+
+ Future<void> test_remove_list_elements_at_list_end() async {
+ await analyze('var x = [1, 2, 3];');
+ var i1 = findNode.integerLiteral('1');
+ var i2 = findNode.integerLiteral('2');
+ var i3 = findNode.integerLiteral('3');
+ var changes = checkPlan(
+ planner.passThrough(i2.parent,
+ innerPlans: [planner.removeNode(i2), planner.removeNode(i3)]),
+ 'var x = [1];');
+ expect(changes.keys, unorderedEquals([i1.end, i2.end]));
+ }
+
+ Future<void> test_remove_list_elements_at_list_end_asUnit() async {
+ await analyze('var x = [1, 2, 3];');
+ var i1 = findNode.integerLiteral('1');
+ var i2 = findNode.integerLiteral('2');
+ var i3 = findNode.integerLiteral('3');
+ var changes = checkPlan(planner.removeNodes(i2, i3), 'var x = [1];');
+ expect(changes.keys, [i1.end]);
+ }
+
+ Future<void> test_remove_list_elements_consecutive_asUnit() async {
+ await analyze('var x = [1, 2, 3, 4];');
+ var i2 = findNode.integerLiteral('2');
+ var i3 = findNode.integerLiteral('3');
+ var changes = checkPlan(planner.removeNodes(i2, i3), 'var x = [1, 4];');
+ expect(changes.keys, [i2.offset]);
+ }
+
+ Future<void>
+ test_remove_list_elements_consecutive_at_list_end_using_comments() async {
+ await analyze('var x = [1, 2, 3];');
+ var i2 = findNode.integerLiteral('2');
+ var i3 = findNode.integerLiteral('3');
+ createPlanner(removeViaComments: true);
+ checkPlan(
+ planner.passThrough(i2.parent,
+ innerPlans: [planner.removeNode(i2), planner.removeNode(i3)]),
+ 'var x = [1/* , 2 *//* , 3 */];');
+ }
+
+ Future<void> test_remove_list_elements_consecutive_using_comments() async {
+ await analyze('var x = [1, 2, 3, 4];');
+ var i2 = findNode.integerLiteral('2');
+ var i3 = findNode.integerLiteral('3');
+ createPlanner(removeViaComments: true);
+ checkPlan(
+ planner.passThrough(i2.parent,
+ innerPlans: [planner.removeNode(i2), planner.removeNode(i3)]),
+ 'var x = [1, /* 2, */ /* 3, */ 4];');
+ }
+
+ Future<void> test_remove_list_elements_using_comments() async {
+ await analyze('var x = [1, 2, 3, 4, 5];');
+ var i2 = findNode.integerLiteral('2');
+ var i4 = findNode.integerLiteral('4');
+ createPlanner(removeViaComments: true);
+ checkPlan(
+ planner.passThrough(i2.parent,
+ innerPlans: [planner.removeNode(i2), planner.removeNode(i4)]),
+ 'var x = [1, /* 2, */ 3, /* 4, */ 5];');
+ }
+
+ Future<void> test_remove_map_element() async {
+ await analyze('var x = {1: 2, 3: 4, 5: 6};');
+ var entry = findNode.integerLiteral('3').parent;
+ var changes = checkPlan(planner.removeNode(entry), 'var x = {1: 2, 5: 6};');
+ expect(changes.keys, [entry.offset]);
+ }
+
+ Future<void> test_remove_parameter() async {
+ await analyze('f(int x, int y, int z) => null;');
+ var parameter = findNode.simple('y').parent;
+ var changes =
+ checkPlan(planner.removeNode(parameter), 'f(int x, int z) => null;');
+ expect(changes.keys, [parameter.offset]);
+ }
+
+ Future<void> test_remove_set_element() async {
+ await analyze('var x = {1, 2, 3};');
+ var i2 = findNode.integerLiteral('2');
+ var changes = checkPlan(planner.removeNode(i2), 'var x = {1, 3};');
+ expect(changes.keys, [i2.offset]);
+ }
+
+ Future<void> test_remove_statement() async {
+ await analyze('''
+void f() {
+ 1;
+ 2;
+ 3;
+}
+''');
+ checkPlan(planner.removeNode(findNode.statement('2')), '''
+void f() {
+ 1;
+ 3;
+}
+''');
+ }
+
+ Future<void> test_remove_statement_first_of_many_on_line() async {
+ await analyze('''
+void f() {
+ 1;
+ 2; 3;
+ 4;
+}
+''');
+ checkPlan(planner.removeNode(findNode.statement('2')), '''
+void f() {
+ 1;
+ 3;
+ 4;
+}
+''');
+ }
+
+ Future<void> test_remove_statement_last_of_many_on_line() async {
+ await analyze('''
+void f() {
+ 1;
+ 2; 3;
+ 4;
+}
+''');
+ checkPlan(planner.removeNode(findNode.statement('3')), '''
+void f() {
+ 1;
+ 2;
+ 4;
+}
+''');
+ }
+
+ Future<void> test_remove_statement_middle_of_many_on_line() async {
+ await analyze('''
+void f() {
+ 1;
+ 2; 3; 4;
+ 5;
+}
+''');
+ checkPlan(planner.removeNode(findNode.statement('3')), '''
+void f() {
+ 1;
+ 2; 4;
+ 5;
+}
+''');
+ }
+
+ Future<void> test_remove_statement_using_comments() async {
+ await analyze('''
+void f() {
+ 1;
+ 2;
+ 3;
+}
+''');
+ createPlanner(removeViaComments: true);
+ checkPlan(planner.removeNode(findNode.statement('2')), '''
+void f() {
+ 1;
+ /* 2; */
+ 3;
+}
+''');
+ }
+
+ Future<void> test_remove_statements_asUnit() async {
+ await analyze('''
+void f() {
+ 1;
+ 2;
+
+ 3;
+ 4;
+}
+''');
+ var s2 = findNode.statement('2');
+ var s3 = findNode.statement('3');
+ var changes = checkPlan(planner.removeNodes(s2, s3), '''
+void f() {
+ 1;
+ 4;
+}
+''');
+ expect(changes, hasLength(1));
+ }
+
+ Future<void> test_remove_statements_consecutive_three() async {
+ await analyze('''
+void f() {
+ 1;
+ 2;
+
+ 3;
+
+ 4;
+ 5;
+}
+''');
+ var s2 = findNode.statement('2');
+ var s3 = findNode.statement('3');
+ var s4 = findNode.statement('4');
+ var changes = checkPlan(
+ planner.passThrough(s2.parent, innerPlans: [
+ planner.removeNode(s2),
+ planner.removeNode(s3),
+ planner.removeNode(s4)
+ ]),
+ '''
+void f() {
+ 1;
+ 5;
+}
+''');
+ expect(changes.keys,
+ unorderedEquals([s2.offset - 2, s3.offset - 2, s4.offset - 2]));
+ }
+
+ Future<void> test_remove_statements_consecutive_two() async {
+ await analyze('''
+void f() {
+ 1;
+ 2;
+
+ 3;
+ 4;
+}
+''');
+ var s2 = findNode.statement('2');
+ var s3 = findNode.statement('3');
+ var changes = checkPlan(
+ planner.passThrough(s2.parent,
+ innerPlans: [planner.removeNode(s2), planner.removeNode(s3)]),
+ '''
+void f() {
+ 1;
+ 4;
+}
+''');
+ expect(changes.keys, unorderedEquals([s2.offset - 2, s3.offset - 2]));
+ }
+
+ Future<void> test_remove_statements_nonconsecutive() async {
+ await analyze('''
+void f() {
+ 1;
+ 2;
+ 3;
+ 4;
+ 5;
+}
+''');
+ var s2 = findNode.statement('2');
+ var s4 = findNode.statement('4');
+ var changes = checkPlan(
+ planner.passThrough(s2.parent,
+ innerPlans: [planner.removeNode(s2), planner.removeNode(s4)]),
+ '''
+void f() {
+ 1;
+ 3;
+ 5;
+}
+''');
+ expect(changes, hasLength(2));
+ }
+
+ Future<void> test_remove_statements_singleton() async {
+ await analyze('''
+void f() {
+ 1;
+}
+''');
+ checkPlan(planner.removeNode(findNode.statement('1')), '''
+void f() {}
+''');
+ }
+
+ Future<void> test_remove_statements_singleton_with_following_comment() async {
+ await analyze('''
+void f() {
+ 1;
+ // Foo
+}
+''');
+ checkPlan(planner.removeNode(findNode.statement('1')), '''
+void f() {
+ // Foo
+}
+''');
+ }
+
+ Future<void> test_remove_statements_singleton_with_preceding_comment() async {
+ await analyze('''
+void f() {
+ // Foo
+ 1;
+}
+''');
+ checkPlan(planner.removeNode(findNode.statement('1')), '''
+void f() {
+ // Foo
+}
+''');
+ }
+
+ Future<void> test_remove_statements_using_comments() async {
+ await analyze('''
+void f() {
+ 1;
+ 2;
+ 3;
+ 4;
+}
+''');
+ createPlanner(removeViaComments: true);
+ var s2 = findNode.statement('2');
+ var s3 = findNode.statement('3');
+ checkPlan(
+ planner.passThrough(s2.parent,
+ innerPlans: [planner.removeNode(s2), planner.removeNode(s3)]),
+ '''
+void f() {
+ 1;
+ /* 2; */
+ /* 3; */
+ 4;
+}
+''');
+ }
+
+ Future<void> test_remove_top_level_declaration() async {
+ await analyze('''
+class C {}
+class D {}
+class E {}
+''');
+ var declaration = findNode.classDeclaration('D');
+ var changes = checkPlan(planner.removeNode(declaration), '''
+class C {}
+class E {}
+''');
+ expect(changes.keys, [declaration.offset]);
+ }
+
+ Future<void> test_remove_top_level_directive() async {
+ await analyze('''
+import 'dart:io';
+import 'dart:async';
+import 'dart:math';
+''');
+ var directive = findNode.import('async');
+ var changes = checkPlan(planner.removeNode(directive), '''
+import 'dart:io';
+import 'dart:math';
+''');
+ expect(changes.keys, [directive.offset]);
+ }
+
+ Future<void> test_remove_type_argument() async {
+ await analyze('''
+class C<T, U, V> {}
+C<int, double, String> c;
+''');
+ var typeArgument = findNode.simple('double').parent;
+ var changes = checkPlan(planner.removeNode(typeArgument), '''
+class C<T, U, V> {}
+C<int, String> c;
+''');
+ expect(changes.keys, [typeArgument.offset]);
+ }
+
+ Future<void> test_remove_type_parameter() async {
+ await analyze('class C<T, U, V> {}');
+ var parameter = findNode.simple('U').parent;
+ var changes = checkPlan(planner.removeNode(parameter), 'class C<T, V> {}');
+ expect(changes.keys, [parameter.offset]);
+ }
+
+ Future<void> test_remove_variable_declaration() async {
+ await analyze('int x, y, z;');
+ var declaration = findNode.simple('y').parent;
+ var changes = checkPlan(planner.removeNode(declaration), 'int x, z;');
+ expect(changes.keys, [declaration.offset]);
+ }
+
Future<void> test_surround_allowCascade() async {
await analyze('f(x) => 1..isEven;');
checkPlan(
@@ -273,6 +869,24 @@
'var x = 1..isEven;');
}
+ Future<void> test_surround_suffix_parenthesized() async {
+ await analyze('var x = (1);');
+ checkPlan(
+ planner.surround(planner.passThrough(findNode.integerLiteral('1')),
+ suffix: [AtomicEdit.insert('..isEven')]),
+ 'var x = 1..isEven;');
+ }
+
+ Future<void> test_surround_suffix_parenthesized_passThrough_unit() async {
+ await analyze('var x = (1);');
+ checkPlan(
+ planner.passThrough(testUnit, innerPlans: [
+ planner.surround(planner.passThrough(findNode.integerLiteral('1')),
+ suffix: [AtomicEdit.insert('..isEven')])
+ ]),
+ 'var x = 1..isEven;');
+ }
+
Future<void> test_surround_threshold() async {
await analyze('var x = 1 < 2;');
checkPlan(
@@ -323,7 +937,7 @@
class PrecedenceTest extends AbstractSingleUnitTest {
Future<void> checkPrecedence(String content) async {
await resolveTestUnit(content);
- testUnit.accept(_PrecedenceChecker());
+ testUnit.accept(_PrecedenceChecker(testUnit.lineInfo, testCode));
}
Future<void> test_precedence_as() async {
@@ -436,13 +1050,17 @@
Future<void> test_precedenceChecker_detects_unnecessary_paren() async {
await resolveTestUnit('var x = (1);');
- expect(() => testUnit.accept(_PrecedenceChecker()),
+ expect(
+ () => testUnit.accept(_PrecedenceChecker(testUnit.lineInfo, testCode)),
throwsA(TypeMatcher<TestFailure>()));
}
}
class _PrecedenceChecker extends UnifyingAstVisitor<void> {
- final planner = EditPlanner();
+ final EditPlanner planner;
+
+ _PrecedenceChecker(LineInfo lineInfo, String sourceText)
+ : planner = EditPlanner(lineInfo, sourceText);
@override
void visitNode(AstNode node) {
diff --git a/pkg/nnbd_migration/test/edit_planner_pass_through_merging_test.dart b/pkg/nnbd_migration/test/edit_planner_pass_through_merging_test.dart
new file mode 100644
index 0000000..1bc5d2a
--- /dev/null
+++ b/pkg/nnbd_migration/test/edit_planner_pass_through_merging_test.dart
@@ -0,0 +1,115 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/source/line_info.dart';
+import 'package:nnbd_migration/src/edit_plan.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'abstract_single_unit.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(PassThroughMergingTest);
+ });
+}
+
+/// Tests to make sure the algorithm used by [EditPlaner.passThrough] is
+/// correct.
+@reflectiveTest
+class PassThroughMergingTest extends AbstractSingleUnitTest {
+ Future<void> test_creates_pass_through_plans_stepwise() async {
+ await resolveTestUnit('var x = [[[1]]];');
+ var plan = _EditPlannerForTesting(testCode).passThrough(
+ findNode.listLiteral('[[['),
+ innerPlans: [_MockPlan(findNode.integerLiteral('1'))]);
+ expect(plan.toString(),
+ 'plan([[[1]]], [plan([[1]], [plan([1], [plan(1)])])])');
+ }
+
+ Future<void> test_merge_plans_at_lower_level() async {
+ await resolveTestUnit('var x = [[1, 2]];');
+ var plan = _EditPlannerForTesting(testCode)
+ .passThrough(findNode.listLiteral('[['), innerPlans: [
+ _MockPlan(findNode.integerLiteral('1')),
+ _MockPlan(findNode.integerLiteral('2'))
+ ]);
+ expect(
+ plan.toString(), 'plan([[1, 2]], [plan([1, 2], [plan(1), plan(2)])])');
+ }
+
+ Future<void> test_merge_plans_at_top_level() async {
+ await resolveTestUnit('var x = [[1], [2]];');
+ var plan = _EditPlannerForTesting(testCode)
+ .passThrough(findNode.listLiteral('[['), innerPlans: [
+ _MockPlan(findNode.integerLiteral('1')),
+ _MockPlan(findNode.integerLiteral('2'))
+ ]);
+ expect(plan.toString(),
+ 'plan([[1], [2]], [plan([1], [plan(1)]), plan([2], [plan(2)])])');
+ }
+
+ Future<void> test_merge_plans_at_varying_levels() async {
+ await resolveTestUnit('var x = [1, [2, 3], 4];');
+ var plan = _EditPlannerForTesting(testCode)
+ .passThrough(findNode.listLiteral('[1'), innerPlans: [
+ _MockPlan(findNode.integerLiteral('1')),
+ _MockPlan(findNode.integerLiteral('2')),
+ _MockPlan(findNode.integerLiteral('3')),
+ _MockPlan(findNode.integerLiteral('4'))
+ ]);
+ expect(
+ plan.toString(),
+ 'plan([1, [2, 3], 4], [plan(1), plan([2, 3], [plan(2), plan(3)]), '
+ 'plan(4)])');
+ }
+}
+
+class _EditPlannerForTesting extends EditPlanner {
+ _EditPlannerForTesting(String content)
+ : super(LineInfo.fromContent(content), content);
+
+ @override
+ PassThroughBuilder createPassThroughBuilder(AstNode node) =>
+ _MockPassThroughBuilder(node);
+}
+
+class _MockPassThroughBuilder implements PassThroughBuilder {
+ final List<EditPlan> _innerPlans = [];
+
+ @override
+ final AstNode node;
+
+ _MockPassThroughBuilder(this.node);
+
+ @override
+ void add(EditPlan innerPlan) {
+ _innerPlans.add(innerPlan);
+ }
+
+ @override
+ NodeProducingEditPlan finish(EditPlanner planner) {
+ return _MockPlan(node, _innerPlans);
+ }
+}
+
+class _MockPlan implements NodeProducingEditPlan {
+ final AstNode _node;
+
+ final List<EditPlan> _innerPlans;
+
+ _MockPlan(this._node, [List<EditPlan> innerPlans = const []])
+ : _innerPlans = innerPlans;
+
+ @override
+ AstNode get parentNode => _node.parent;
+
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+
+ @override
+ String toString() =>
+ _innerPlans.isEmpty ? 'plan($_node)' : 'plan($_node, $_innerPlans)';
+}
diff --git a/pkg/nnbd_migration/test/fix_aggregator_test.dart b/pkg/nnbd_migration/test/fix_aggregator_test.dart
index 3d5009e..35ebd36 100644
--- a/pkg/nnbd_migration/test/fix_aggregator_test.dart
+++ b/pkg/nnbd_migration/test/fix_aggregator_test.dart
@@ -3,8 +3,10 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/ast/ast.dart';
+import 'package:nnbd_migration/src/decorated_type.dart';
import 'package:nnbd_migration/src/edit_plan.dart';
import 'package:nnbd_migration/src/fix_aggregator.dart';
+import 'package:nnbd_migration/src/nullability_node.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -37,6 +39,215 @@
expect(previewInfo.applyTo(code), 'f(a, b) => (a! + b!)!;');
}
+ Future<void> test_eliminateDeadIf_element_delete_drop_completely() async {
+ await analyze('''
+List<int> f(int i) {
+ return [if (i == null) null];
+}
+''');
+ var previewInfo = run({findNode.ifElement('=='): EliminateDeadIf(false)});
+ expect(previewInfo.applyTo(code), '''
+List<int> f(int i) {
+ return [];
+}
+''');
+ }
+
+ Future<void> test_eliminateDeadIf_element_delete_keep_else() async {
+ await analyze('''
+List<int> f(int i) {
+ return [if (i == null) null else i + 1];
+}
+''');
+ var previewInfo = run({findNode.ifElement('=='): EliminateDeadIf(false)});
+ expect(previewInfo.applyTo(code), '''
+List<int> f(int i) {
+ return [i + 1];
+}
+''');
+ }
+
+ Future<void> test_eliminateDeadIf_element_delete_keep_then() async {
+ await analyze('''
+List<int> f(int i) {
+ return [if (i == null) null else i + 1];
+}
+''');
+ var previewInfo = run({findNode.ifElement('=='): EliminateDeadIf(true)});
+ expect(previewInfo.applyTo(code), '''
+List<int> f(int i) {
+ return [null];
+}
+''');
+ }
+
+ Future<void> test_eliminateDeadIf_expression_delete_keep_else() async {
+ await analyze('''
+int f(int i) {
+ return i == null ? null : i + 1;
+}
+''');
+ var previewInfo =
+ run({findNode.conditionalExpression('=='): EliminateDeadIf(false)});
+ expect(previewInfo.applyTo(code), '''
+int f(int i) {
+ return i + 1;
+}
+''');
+ }
+
+ Future<void> test_eliminateDeadIf_expression_delete_keep_then() async {
+ await analyze('''
+int f(int i) {
+ return i == null ? null : i + 1;
+}
+''');
+ var previewInfo =
+ run({findNode.conditionalExpression('=='): EliminateDeadIf(true)});
+ expect(previewInfo.applyTo(code), '''
+int f(int i) {
+ return null;
+}
+''');
+ }
+
+ Future<void> test_eliminateDeadIf_statement_comment_keep_else() async {
+ await analyze('''
+int f(int i) {
+ if (i == null) {
+ return null;
+ } else {
+ return i + 1;
+ }
+}
+''');
+ var previewInfo = run({findNode.statement('if'): EliminateDeadIf(false)},
+ removeViaComments: true);
+ expect(previewInfo.applyTo(code), '''
+int f(int i) {
+ /* if (i == null) {
+ return null;
+ } else {
+ */ return i + 1; /*
+ } */
+}
+''');
+ }
+
+ Future<void> test_eliminateDeadIf_statement_comment_keep_then() async {
+ await analyze('''
+int f(int i) {
+ if (i == null) {
+ return null;
+ } else {
+ return i + 1;
+ }
+}
+''');
+ var previewInfo = run({findNode.statement('if'): EliminateDeadIf(true)},
+ removeViaComments: true);
+ expect(previewInfo.applyTo(code), '''
+int f(int i) {
+ /* if (i == null) {
+ */ return null; /*
+ } else {
+ return i + 1;
+ } */
+}
+''');
+ }
+
+ Future<void>
+ test_eliminateDeadIf_statement_delete_drop_completely_false() async {
+ await analyze('''
+void f(int i) {
+ if (i == null) {
+ print('null');
+ }
+}
+''');
+ var previewInfo = run({findNode.statement('if'): EliminateDeadIf(false)});
+ expect(previewInfo.applyTo(code), '''
+void f(int i) {}
+''');
+ }
+
+ Future<void>
+ test_eliminateDeadIf_statement_delete_drop_completely_true() async {
+ await analyze('''
+void f(int i) {
+ if (i != null) {} else {
+ print('null');
+ }
+}
+''');
+ var previewInfo = run({findNode.statement('if'): EliminateDeadIf(true)});
+ expect(previewInfo.applyTo(code), '''
+void f(int i) {}
+''');
+ }
+
+ Future<void> test_eliminateDeadIf_statement_delete_keep_else() async {
+ await analyze('''
+int f(int i) {
+ if (i == null) {
+ return null;
+ } else {
+ return i + 1;
+ }
+}
+''');
+ var previewInfo = run({findNode.statement('if'): EliminateDeadIf(false)});
+ expect(previewInfo.applyTo(code), '''
+int f(int i) {
+ return i + 1;
+}
+''');
+ }
+
+ Future<void> test_eliminateDeadIf_statement_delete_keep_then() async {
+ await analyze('''
+int f(int i) {
+ if (i != null) {
+ return i + 1;
+ } else {
+ return null;
+ }
+}
+''');
+ var previewInfo = run({findNode.statement('if'): EliminateDeadIf(true)});
+ expect(previewInfo.applyTo(code), '''
+int f(int i) {
+ return i + 1;
+}
+''');
+ }
+
+ Future<void>
+ test_eliminateDeadIf_statement_delete_keep_then_declaration() async {
+ await analyze('''
+void f(int i, String callback()) {
+ if (i != null) {
+ var i = callback();
+ } else {
+ return;
+ }
+ print(i);
+}
+''');
+ // In this case we have to keep the block so that the scope of `var i`
+ // doesn't widen.
+ var previewInfo = run({findNode.statement('if'): EliminateDeadIf(true)});
+ expect(previewInfo.applyTo(code), '''
+void f(int i, String callback()) {
+ {
+ var i = callback();
+ }
+ print(i);
+}
+''');
+ }
+
Future<void> test_introduceAs_distant_parens_no_longer_needed() async {
// Note: in principle it would be nice to delete the outer parens, but it's
// difficult to see that they used to be necessary and aren't anymore, so we
@@ -71,7 +282,7 @@
Future<void> test_makeNullable() async {
await analyze('f(int x) {}');
var typeName = findNode.typeName('int');
- var previewInfo = run({typeName: const MakeNullable()});
+ var previewInfo = run({typeName: MakeNullable(MockDecoratedType())});
expect(previewInfo.applyTo(code), 'f(int? x) {}');
}
@@ -142,13 +353,21 @@
}
Future<void> test_removeAs_parens_needed_due_to_cascade() async {
- // Note: spaces around parens to verify that we don't remove the old parens
- // and create new ones.
- await analyze('f(a, c) => a..b = throw ( c..d ) as int;');
+ // Note: parens are needed, and they could either be around `c..d` or around
+ // `throw c..d`. In an ideal world, we would see that we can just keep the
+ // parens we have, but this is difficult because we don't see that the
+ // parens are needed until we walk far enough up the AST to see that we're
+ // inside a casade expression. So we drop the parens and then create new
+ // ones surrounding `throw c..d`.
+ //
+ // Strictly speaking the code we produce is correct, it's just making a
+ // slightly larger edit than necessary. This is presumably a really rare
+ // corner case so for now we're not worrying about it.
+ await analyze('f(a, c) => a..b = throw (c..d) as int;');
var cd = findNode.cascade('c..d');
var cast = cd.parent.parent;
var previewInfo = run({cast: const RemoveAs()});
- expect(previewInfo.applyTo(code), 'f(a, c) => a..b = throw ( c..d );');
+ expect(previewInfo.applyTo(code), 'f(a, c) => a..b = (throw c..d);');
}
Future<void>
@@ -199,7 +418,19 @@
await resolveTestUnit(code);
}
- Map<int, List<AtomicEdit>> run(Map<AstNode, NodeChange> changes) {
- return FixAggregator.run(testUnit, changes);
+ Map<int, List<AtomicEdit>> run(Map<AstNode, NodeChange> changes,
+ {bool removeViaComments: false}) {
+ return FixAggregator.run(testUnit, testCode, changes,
+ removeViaComments: removeViaComments);
+ }
+}
+
+class MockDecoratedType implements DecoratedType {
+ @override
+ NullabilityNode get node => NullabilityNode.forTypeAnnotation(0);
+
+ @override
+ noSuchMethod(Invocation invocation) {
+ return super.noSuchMethod(invocation);
}
}
diff --git a/pkg/nnbd_migration/test/fix_builder_test.dart b/pkg/nnbd_migration/test/fix_builder_test.dart
index ee03cff..19ad529 100644
--- a/pkg/nnbd_migration/test/fix_builder_test.dart
+++ b/pkg/nnbd_migration/test/fix_builder_test.dart
@@ -1110,6 +1110,36 @@
changes: {findNode.propertyAccess('c.f'): isNullCheck});
}
+ Future<void> test_ifStatement_dead_else() async {
+ await analyze('''
+_f(int x, int/*?*/ y) {
+ if (x != null) {
+ print(x + 1);
+ } else {
+ print(y + 1);
+ }
+}
+''');
+ var ifStatement = findNode.statement('if');
+ visitStatement(ifStatement,
+ changes: {ifStatement: isEliminateDeadIf(true)});
+ }
+
+ Future<void> test_ifStatement_dead_then() async {
+ await analyze('''
+_f(int x, int/*?*/ y) {
+ if (x == null) {
+ print(y + 1);
+ } else {
+ print(x + 1);
+ }
+}
+''');
+ var ifStatement = findNode.statement('if');
+ visitStatement(ifStatement,
+ changes: {ifStatement: isEliminateDeadIf(false)});
+ }
+
Future<void> test_ifStatement_flow_promote_in_else() async {
await analyze('''
_f(int/*?*/ x) {
@@ -1226,6 +1256,11 @@
visitSubexpression(findNode.integerLiteral('1'), 'int');
}
+ Future<void> test_list_unchanged() async {
+ await analyze('_f(int x) => [x];');
+ visitSubexpression(findNode.listLiteral('['), 'List<int>');
+ }
+
Future<void> test_listLiteral_typed() async {
await analyze('''
_f() => <int>[];
@@ -2278,4 +2313,8 @@
.thisOrAncestorMatching((ancestor) => identical(ancestor, scope)) !=
null;
}
+
+ static Matcher isEliminateDeadIf(bool knownValue) =>
+ TypeMatcher<EliminateDeadIf>()
+ .having((c) => c.conditionValue, 'conditionValue', knownValue);
}
diff --git a/pkg/nnbd_migration/test/test_all.dart b/pkg/nnbd_migration/test/test_all.dart
index f5e2719..0267b31 100644
--- a/pkg/nnbd_migration/test/test_all.dart
+++ b/pkg/nnbd_migration/test/test_all.dart
@@ -13,6 +13,8 @@
as edge_builder_flow_analysis_test;
import 'edge_builder_test.dart' as edge_builder_test;
import 'edit_plan_test.dart' as edit_plan_test;
+import 'edit_planner_pass_through_merging_test.dart'
+ as edit_planner_pass_through_merging_test;
import 'fix_aggregator_test.dart' as fix_aggregator_test;
import 'fix_builder_test.dart' as fix_builder_test;
import 'instrumentation_test.dart' as instrumentation_test;
@@ -31,6 +33,7 @@
edge_builder_flow_analysis_test.main();
edge_builder_test.main();
edit_plan_test.main();
+ edit_planner_pass_through_merging_test.main();
fix_aggregator_test.main();
fix_builder_test.main();
instrumentation_test.main();
diff --git a/pkg/vm/lib/bytecode/gen_bytecode.dart b/pkg/vm/lib/bytecode/gen_bytecode.dart
index 05ba2426..c0d2628 100644
--- a/pkg/vm/lib/bytecode/gen_bytecode.dart
+++ b/pkg/vm/lib/bytecode/gen_bytecode.dart
@@ -8,6 +8,7 @@
show
CompilerContext,
Severity,
+ isRedirectingFactoryField,
messageBytecodeLimitExceededTooManyArguments,
noLength,
templateIllegalRecursiveType;
@@ -957,7 +958,7 @@
// contain incorrect kernel AST, e.g. StaticGet which takes tear-off
// of a constructor. Do not generate bytecode for them, as they should
// never be used.
- if (member.isStatic && member.name.name == "_redirecting#") {
+ if (isRedirectingFactoryField(member)) {
return false;
}
return hasInitializerCode(member);
diff --git a/runtime/bin/ffi_test/ffi_test_functions.cc b/runtime/bin/ffi_test/ffi_test_functions.cc
index 0f52f7c..583c603 100644
--- a/runtime/bin/ffi_test/ffi_test_functions.cc
+++ b/runtime/bin/ffi_test/ffi_test_functions.cc
@@ -186,6 +186,28 @@
return retval;
}
+// Sums many ints.
+// Used for testing calling conventions. With small integers on stack slots we
+// test stack alignment.
+DART_EXPORT int16_t SumManySmallInts(int8_t a,
+ int16_t b,
+ int8_t c,
+ int16_t d,
+ int8_t e,
+ int16_t f,
+ int8_t g,
+ int16_t h,
+ int8_t i,
+ int16_t j) {
+ std::cout << "SumManySmallInts(" << static_cast<int>(a) << ", " << b << ", "
+ << static_cast<int>(c) << ", " << d << ", " << static_cast<int>(e)
+ << ", " << f << ", " << static_cast<int>(g) << ", " << h << ", "
+ << static_cast<int>(i) << ", " << j << ")\n";
+ int16_t retval = a + b + c + d + e + f + g + h + i + j;
+ std::cout << "returning " << retval << "\n";
+ return retval;
+}
+
// Sums an odd number of ints.
// Used for testing calling conventions. With so many arguments, and an odd
// number of arguments, we are testing stack alignment on various architectures.
diff --git a/runtime/bin/vmservice/.gitignore b/runtime/bin/vmservice/.gitignore
deleted file mode 100644
index b183031..0000000
--- a/runtime/bin/vmservice/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-.buildlog
-pubspec.lock
diff --git a/runtime/bin/vmservice/vmservice_sources.gni b/runtime/bin/vmservice/vmservice_sources.gni
deleted file mode 100644
index d326c2a..0000000
--- a/runtime/bin/vmservice/vmservice_sources.gni
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
-# for details. All rights reserved. Use of this source code is governed by a
-# BSD-style license that can be found in the LICENSE file.
-
-# This file contains all Dart sources for the dart:io implementation of
-# the VM Service server.
-vmservice_sources = [
- "server.dart",
- "vmservice_io.dart",
-]
diff --git a/runtime/observatory/lib/object_graph.dart b/runtime/observatory/lib/object_graph.dart
index 1bf79ca..18426bb 100644
--- a/runtime/observatory/lib/object_graph.dart
+++ b/runtime/observatory/lib/object_graph.dart
@@ -335,15 +335,9 @@
_VerticesIterator(this._graph);
bool moveNext() {
- while (_nextId <= _graph._N) {
- // A retained size of zero means the object was unreachable.
- if (_graph._retainedSizes[_nextId] != 0) {
- current = new _SnapshotObject._(_nextId++, _graph, "");
- return true;
- }
- _nextId++;
- }
- return false;
+ if (_nextId == _graph._N) return false;
+ current = new _SnapshotObject._(_nextId++, _graph, "");
+ return true;
}
}
@@ -366,10 +360,8 @@
_InstancesIterator(this._graph, this._cid);
bool moveNext() {
- while (_nextId <= _graph._N) {
- // A retained size of zero means the object was unreachable.
- if (_graph._cids[_nextId] == _cid &&
- _graph._retainedSizes[_nextId] != 0) {
+ while (_nextId < _graph._N) {
+ if (_graph._cids[_nextId] == _cid) {
current = new _SnapshotObject._(_nextId++, _graph, "");
return true;
}
@@ -1185,13 +1177,10 @@
cls.liveInstanceCount++;
}
- // Start with retained size as shallow size + external size. For reachable
- // objects only; leave unreachable objects with a retained size of 0 so
- // they can be filtered during graph iterations.
+ // Start with retained size as shallow size + external size.
var retainedSizes = new Uint32List(N + 1);
- for (var i = 0; i <= Nconnected; i++) {
- var v = vertex[i];
- retainedSizes[v] = internalSizes[v] + externalSizes[v];
+ for (var i = 0; i < N + 1; i++) {
+ retainedSizes[i] = internalSizes[i] + externalSizes[i];
}
// In post order (bottom up), add retained size to dominator's retained
diff --git a/runtime/observatory/tests/service/object_graph_vm_test.dart b/runtime/observatory/tests/service/object_graph_vm_test.dart
index 5458b49..dd4b936 100644
--- a/runtime/observatory/tests/service/object_graph_vm_test.dart
+++ b/runtime/observatory/tests/service/object_graph_vm_test.dart
@@ -82,69 +82,6 @@
// Check that the short list retains more than the long list inside.
// and specifically, that it retains exactly itself + the long one.
expect(first.retainedSize, equals(first.shallowSize + second.shallowSize));
-
- // Verify sizes of classes are the appropriates sums of their instances.
- // This also verifies that the class instance iterators are visiting the
- // correct set of objects (e.g., not including dead objects).
- for (SnapshotClass klass in graph.classes) {
- int shallowSum = 0;
- int internalSum = 0;
- int externalSum = 0;
- for (SnapshotObject instance in klass.instances) {
- if (instance == graph.root) {
- // The root may have 0 self size.
- expect(instance.internalSize, greaterThanOrEqualTo(0));
- expect(instance.externalSize, greaterThanOrEqualTo(0));
- expect(instance.shallowSize, greaterThanOrEqualTo(0));
- } else {
- // All other objects are heap objects with positive size.
- expect(instance.internalSize, greaterThan(0));
- expect(instance.externalSize, greaterThanOrEqualTo(0));
- expect(instance.shallowSize, greaterThan(0));
- }
- expect(instance.retainedSize, greaterThan(0));
- expect(instance.shallowSize,
- equals(instance.internalSize + instance.externalSize));
- shallowSum += instance.shallowSize;
- internalSum += instance.internalSize;
- externalSum += instance.externalSize;
- }
- expect(shallowSum, equals(klass.shallowSize));
- expect(internalSum, equals(klass.internalSize));
- expect(externalSum, equals(klass.externalSize));
- expect(
- klass.shallowSize, equals(klass.internalSize + klass.externalSize));
- }
-
- // Verify sizes of the overall graph are the appropriates sums of all
- // instances. This also verifies that the all instances iterator is visiting
- // the correct set of objects (e.g., not including dead objects).
- int shallowSum = 0;
- int internalSum = 0;
- int externalSum = 0;
- for (SnapshotObject instance in graph.objects) {
- if (instance == graph.root) {
- // The root may have 0 self size.
- expect(instance.internalSize, greaterThanOrEqualTo(0));
- expect(instance.externalSize, greaterThanOrEqualTo(0));
- expect(instance.shallowSize, greaterThanOrEqualTo(0));
- } else {
- // All other objects are heap objects with positive size.
- expect(instance.internalSize, greaterThan(0));
- expect(instance.externalSize, greaterThanOrEqualTo(0));
- expect(instance.shallowSize, greaterThan(0));
- }
- expect(instance.retainedSize, greaterThan(0));
- expect(instance.shallowSize,
- equals(instance.internalSize + instance.externalSize));
- shallowSum += instance.shallowSize;
- internalSum += instance.internalSize;
- externalSum += instance.externalSize;
- }
- expect(shallowSum, equals(graph.size));
- expect(internalSum, equals(graph.internalSize));
- expect(externalSum, equals(graph.externalSize));
- expect(graph.size, equals(graph.internalSize + graph.externalSize));
},
];
diff --git a/runtime/observatory/tests/service/verify_http_timeline_test.dart b/runtime/observatory/tests/service/verify_http_timeline_test.dart
index 9b41df0..dfd6ad8 100644
--- a/runtime/observatory/tests/service/verify_http_timeline_test.dart
+++ b/runtime/observatory/tests/service/verify_http_timeline_test.dart
@@ -44,7 +44,7 @@
.then((_) async {
try {
await f();
- } on HttpException catch (_) {} on SocketException catch (_) {} on StateError catch (_) {}
+ } on HttpException catch (_) {} on SocketException catch (_) {} on StateError catch (_) {} on OSError catch (_) {}
});
Uri randomlyAddRequestParams(Uri uri) {
diff --git a/runtime/tests/vm/dart/rematerialize_unboxed_double_field_test.dart b/runtime/tests/vm/dart/rematerialize_unboxed_double_field_test.dart
new file mode 100644
index 0000000..8442c38
--- /dev/null
+++ b/runtime/tests/vm/dart/rematerialize_unboxed_double_field_test.dart
@@ -0,0 +1,42 @@
+// 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.
+//
+// VMOptions=--deterministic --optimization-counter-threshold=10 --unbox-numeric-fields
+
+import 'package:expect/expect.dart';
+
+const magicDouble = 42.0;
+
+class C {
+ double d = magicDouble;
+}
+
+class NoopSink {
+ void leak(C c) {}
+}
+
+class RealSink {
+ static C o;
+ void leak(C c) {
+ o = c;
+ }
+}
+
+void foo(sink) {
+ sink.leak(C());
+}
+
+void main(List<String> args) {
+ var c = C();
+ for (var i = 0; i < 100; i++) c.d = 2.0;
+
+ for (var i = 0; i < 100; i++) {
+ foo(NoopSink());
+ }
+
+ foo(RealSink());
+ RealSink.o.d += 1234.0;
+ final TWO = args.length > 1024 ? "~" : 2;
+ Expect.equals(double.parse("4${TWO}.0"), magicDouble);
+}
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index ea7ef8c..a7b520f 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -1232,7 +1232,6 @@
zone, enum_cls.LookupStaticField(Symbols::_DeletedEnumSentinel()));
ASSERT(!sentinel.IsNull());
sentinel.SetStaticValue(enum_value, true);
- sentinel.RecordStore(enum_value);
ASSERT(enum_cls.is_declared_in_bytecode() || enum_cls.kernel_offset() > 0);
Error& error = Error::Handle(zone);
diff --git a/runtime/vm/class_table.cc b/runtime/vm/class_table.cc
index 195333e..23acce5 100644
--- a/runtime/vm/class_table.cc
+++ b/runtime/vm/class_table.cc
@@ -232,13 +232,6 @@
void SharedClassTable::Grow(intptr_t new_capacity) {
ASSERT(new_capacity >= capacity_);
-#ifndef PRODUCT
- // Wait for any marking tasks to complete. Allocation stats in the
- // marker rely on the class table size not changing.
- Thread* thread = Thread::Current();
- thread->heap()->WaitForMarkerTasks(thread);
-#endif
-
intptr_t* new_table = static_cast<intptr_t*>(
malloc(new_capacity * sizeof(intptr_t))); // NOLINT
memmove(new_table, table_, top_ * sizeof(intptr_t));
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index 36be191..8647cb8 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -2016,38 +2016,39 @@
}
void FlowGraphCompiler::EmitPolymorphicInstanceCall(
+ const PolymorphicInstanceCallInstr* call,
const CallTargets& targets,
- const InstanceCallInstr& original_call,
ArgumentsInfo args_info,
intptr_t deopt_id,
TokenPosition token_pos,
LocationSummary* locs,
bool complete,
intptr_t total_ic_calls) {
+ ASSERT(call != nullptr);
if (FLAG_polymorphic_with_deopt) {
compiler::Label* deopt =
AddDeoptStub(deopt_id, ICData::kDeoptPolymorphicInstanceCallTestFail);
compiler::Label ok;
- EmitTestAndCall(targets, original_call.function_name(), args_info,
+ EmitTestAndCall(targets, call->function_name(), args_info,
deopt, // No cid match.
&ok, // Found cid.
deopt_id, token_pos, locs, complete, total_ic_calls,
- original_call.entry_kind());
+ call->entry_kind());
assembler()->Bind(&ok);
} else {
if (complete) {
compiler::Label ok;
- EmitTestAndCall(targets, original_call.function_name(), args_info,
+ EmitTestAndCall(targets, call->function_name(), args_info,
NULL, // No cid match.
&ok, // Found cid.
deopt_id, token_pos, locs, true, total_ic_calls,
- original_call.entry_kind());
+ call->entry_kind());
assembler()->Bind(&ok);
} else {
- const ICData& unary_checks = ICData::ZoneHandle(
- zone(), original_call.ic_data()->AsUnaryClassChecks());
+ const ICData& unary_checks =
+ ICData::ZoneHandle(zone(), call->ic_data()->AsUnaryClassChecks());
EmitInstanceCallAOT(unary_checks, deopt_id, token_pos, locs,
- original_call.entry_kind());
+ call->entry_kind());
}
}
}
@@ -2240,6 +2241,20 @@
(type.IsTypeParameter() || (type.IsType() && type.IsInstantiated())));
}
+FlowGraphCompiler::TypeTestStubKind
+FlowGraphCompiler::GetTypeTestStubKindForTypeParameter(
+ const TypeParameter& type_param) {
+ // TODO(regis): Revisit the bound check taking NNBD into consideration.
+ // If it's guaranteed, by type-parameter bound, that the type parameter will
+ // never have a value of a function type, then we can safely do a 4-type
+ // test instead of a 6-type test.
+ const AbstractType& bound = AbstractType::Handle(zone(), type_param.bound());
+ return !bound.NNBD_IsTopType() && !bound.IsFunctionType() &&
+ !bound.IsDartFunctionType() && bound.IsType()
+ ? kTestTypeFourArgs
+ : kTestTypeSixArgs;
+}
+
void FlowGraphCompiler::GenerateAssertAssignableViaTypeTestingStub(
const AbstractType& dst_type,
const String& dst_name,
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.h b/runtime/vm/compiler/backend/flow_graph_compiler.h
index 38d30c0..6f7b426 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.h
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.h
@@ -638,15 +638,14 @@
LocationSummary* locs,
Code::EntryKind entry_kind);
- void EmitPolymorphicInstanceCall(
- const CallTargets& targets,
- const InstanceCallInstr& original_instruction,
- ArgumentsInfo args_info,
- intptr_t deopt_id,
- TokenPosition token_pos,
- LocationSummary* locs,
- bool complete,
- intptr_t total_call_count);
+ void EmitPolymorphicInstanceCall(const PolymorphicInstanceCallInstr* call,
+ const CallTargets& targets,
+ ArgumentsInfo args_info,
+ intptr_t deopt_id,
+ TokenPosition token_pos,
+ LocationSummary* locs,
+ bool complete,
+ intptr_t total_call_count);
// Pass a value for try-index where block is not available (e.g. slow path).
void EmitMegamorphicInstanceCall(const String& function_name,
@@ -985,6 +984,10 @@
kTestTypeSixArgs,
};
+ // Returns type test stub kind for a type test against type parameter type.
+ TypeTestStubKind GetTypeTestStubKindForTypeParameter(
+ const TypeParameter& type_param);
+
RawSubtypeTestCache* GenerateCallSubtypeTestStub(
TypeTestStubKind test_kind,
Register instance_reg,
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
index 521bc11..bc3c01e 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
@@ -468,7 +468,6 @@
// Skip check if destination is a dynamic type.
if (type.IsTypeParameter()) {
const TypeParameter& type_param = TypeParameter::Cast(type);
- const AbstractType& bound = AbstractType::Handle(type_param.bound());
__ ldm(IA, SP,
(1 << kFunctionTypeArgumentsReg) |
@@ -504,16 +503,7 @@
// Smi can be handled by type test cache.
__ Bind(¬_smi);
- // TODO(regis): Revisit the bound check taking NNBD into consideration.
- // TODO(alexmarkov): Fix issue #40066.
- // If it's guaranteed, by type-parameter bound, that the type parameter will
- // never have a value of a function type, then we can safely do a 4-type
- // test instead of a 6-type test.
- auto test_kind = !bound.NNBD_IsTopType() && !bound.IsFunctionType() &&
- !bound.IsDartFunctionType() && bound.IsType()
- ? kTestTypeSixArgs
- : kTestTypeFourArgs;
-
+ const auto test_kind = GetTypeTestStubKindForTypeParameter(type_param);
const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle(
zone(), GenerateCallSubtypeTestStub(
test_kind, kInstanceReg, kInstantiatorTypeArgumentsReg,
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
index b4ee10f..d88102c 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
@@ -451,7 +451,6 @@
// Skip check if destination is a dynamic type.
if (type.IsTypeParameter()) {
const TypeParameter& type_param = TypeParameter::Cast(type);
- const AbstractType& bound = AbstractType::Handle(type_param.bound());
// Get instantiator type args (high, R1) and function type args (low, R2).
__ ldp(R2, R1,
@@ -483,16 +482,7 @@
// Smi can be handled by type test cache.
__ Bind(¬_smi);
- // TODO(regis): Revisit the bound check taking NNBD into consideration.
- // TODO(alexmarkov): Fix issue #40066.
- // If it's guaranteed, by type-parameter bound, that the type parameter will
- // never have a value of a function type, then we can safely do a 4-type
- // test instead of a 6-type test.
- auto test_kind = !bound.NNBD_IsTopType() && !bound.IsFunctionType() &&
- !bound.IsDartFunctionType() && bound.IsType()
- ? kTestTypeSixArgs
- : kTestTypeFourArgs;
-
+ const auto test_kind = GetTypeTestStubKindForTypeParameter(type_param);
const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle(
zone(), GenerateCallSubtypeTestStub(
test_kind, kInstanceReg, kInstantiatorTypeArgumentsReg,
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
index 594ac84..ffe5bd0 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
@@ -446,7 +446,6 @@
compiler::Immediate(reinterpret_cast<intptr_t>(Object::null()));
if (type.IsTypeParameter()) {
const TypeParameter& type_param = TypeParameter::Cast(type);
- const AbstractType& bound = AbstractType::Handle(type_param.bound());
__ movl(EDX, compiler::Address(
ESP, 1 * kWordSize)); // Get instantiator type args.
@@ -482,15 +481,7 @@
// Smi can be handled by type test cache.
__ Bind(¬_smi);
- // TODO(regis): Revisit the bound check taking NNBD into consideration.
- // TODO(alexmarkov): Fix issue #40066.
- // If it's guaranteed, by type-parameter bound, that the type parameter will
- // never have a value of a function type.
- auto test_kind = !bound.NNBD_IsTopType() && !bound.IsFunctionType() &&
- !bound.IsDartFunctionType() && bound.IsType()
- ? kTestTypeSixArgs
- : kTestTypeFourArgs;
-
+ const auto test_kind = GetTypeTestStubKindForTypeParameter(type_param);
const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle(
zone(), GenerateCallSubtypeTestStub(
test_kind, kInstanceReg, kInstantiatorTypeArgumentsReg,
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
index 9485ea4..26be96d 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
@@ -476,7 +476,6 @@
// Skip check if destination is a dynamic type.
if (type.IsTypeParameter()) {
const TypeParameter& type_param = TypeParameter::Cast(type);
- const AbstractType& bound = AbstractType::Handle(type_param.bound());
// RDX: instantiator type arguments.
// RCX: function type arguments.
@@ -509,16 +508,7 @@
// Smi can be handled by type test cache.
__ Bind(¬_smi);
- // TODO(regis): Revisit the bound check taking NNBD into consideration.
- // TODO(alexmarkov): Fix issue #40066.
- // If it's guaranteed, by type-parameter bound, that the type parameter will
- // never have a value of a function type, then we can safely do a 4-type
- // test instead of a 6-type test.
- auto test_kind = !bound.NNBD_IsTopType() && !bound.IsFunctionType() &&
- !bound.IsDartFunctionType() && bound.IsType()
- ? kTestTypeSixArgs
- : kTestTypeFourArgs;
-
+ const auto test_kind = GetTypeTestStubKindForTypeParameter(type_param);
const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle(
zone(), GenerateCallSubtypeTestStub(
test_kind, kInstanceReg, kInstantiatorTypeArgumentsReg,
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index d78a065..7cdad60 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -45,10 +45,7 @@
two_args_smi_icd,
true,
"Generate special IC stubs for two args Smi operations");
-DEFINE_FLAG(bool,
- unbox_numeric_fields,
- true,
- "Support unboxed double and float32x4 fields.");
+DECLARE_FLAG(bool, unbox_numeric_fields);
class SubclassFinder {
public:
@@ -556,33 +553,18 @@
}
const ICData* Instruction::GetICData(
- const ZoneGrowableArray<const ICData*>& ic_data_array) const {
+ const ZoneGrowableArray<const ICData*>& ic_data_array,
+ intptr_t deopt_id,
+ bool is_static_call) {
// The deopt_id can be outside the range of the IC data array for
// computations added in the optimizing compiler.
- ASSERT(deopt_id_ != DeoptId::kNone);
- if (deopt_id_ < ic_data_array.length()) {
- const ICData* result = ic_data_array[deopt_id_];
-#if defined(DEBUG)
- if (result != NULL) {
- switch (tag()) {
- case kInstanceCall:
- if (result->is_static_call()) {
- FATAL("ICData tag mismatch");
- }
- break;
- case kStaticCall:
- if (!result->is_static_call()) {
- FATAL("ICData tag mismatch");
- }
- break;
- default:
- UNREACHABLE();
- }
- }
-#endif
- return result;
+ ASSERT(deopt_id != DeoptId::kNone);
+ if (deopt_id >= ic_data_array.length()) {
+ return nullptr;
}
- return NULL;
+ const ICData* result = ic_data_array[deopt_id];
+ ASSERT(result == nullptr || is_static_call == result->is_static_call());
+ return result;
}
intptr_t Instruction::Hashcode() const {
@@ -1326,8 +1308,8 @@
// Default implementation of visiting basic blocks. Can be overridden.
void FlowGraphVisitor::VisitBlocks() {
ASSERT(current_iterator_ == NULL);
- for (intptr_t i = 0; i < block_order_.length(); ++i) {
- BlockEntryInstr* entry = block_order_[i];
+ for (intptr_t i = 0; i < block_order_->length(); ++i) {
+ BlockEntryInstr* entry = (*block_order_)[i];
entry->Accept(this);
ForwardInstructionIterator it(entry);
current_iterator_ = ⁢
@@ -4343,7 +4325,7 @@
return Library::IsPrivateCoreLibName(function_name(), name);
}
-RawFunction* InstanceCallInstr::ResolveForReceiverClass(
+RawFunction* InstanceCallBaseInstr::ResolveForReceiverClass(
const Class& cls,
bool allow_add /* = true */) {
const Array& args_desc_array = Array::Handle(GetArgumentsDescriptor());
@@ -4463,9 +4445,9 @@
void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
ArgumentsInfo args_info(type_args_len(), ArgumentCount(), argument_names());
- compiler->EmitPolymorphicInstanceCall(targets_, *instance_call(), args_info,
- deopt_id(), token_pos(), locs(),
- complete(), total_call_count());
+ compiler->EmitPolymorphicInstanceCall(this, targets(), args_info, deopt_id(),
+ token_pos(), locs(), complete(),
+ total_call_count());
}
RawType* PolymorphicInstanceCallInstr::ComputeRuntimeType(
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index 9d4e713..8bf7f24 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -496,14 +496,15 @@
M(SimdOp, kNoGC)
#define FOR_EACH_ABSTRACT_INSTRUCTION(M) \
+ M(Allocation, _) \
+ M(BinaryIntegerOp, _) \
M(BlockEntry, _) \
M(BoxInteger, _) \
- M(UnboxInteger, _) \
M(Comparison, _) \
- M(UnaryIntegerOp, _) \
- M(BinaryIntegerOp, _) \
+ M(InstanceCallBase, _) \
M(ShiftIntegerOp, _) \
- M(Allocation, _)
+ M(UnaryIntegerOp, _) \
+ M(UnboxInteger, _)
#define FORWARD_DECLARATION(type, attrs) class type##Instr;
FOR_EACH_INSTRUCTION(FORWARD_DECLARATION)
@@ -791,8 +792,10 @@
return GetDeoptId();
}
- const ICData* GetICData(
- const ZoneGrowableArray<const ICData*>& ic_data_array) const;
+ static const ICData* GetICData(
+ const ZoneGrowableArray<const ICData*>& ic_data_array,
+ intptr_t deopt_id,
+ bool is_static_call);
virtual TokenPosition token_pos() const { return TokenPosition::kNoSource; }
@@ -3706,34 +3709,32 @@
DISALLOW_COPY_AND_ASSIGN(ClosureCallInstr);
};
-class InstanceCallInstr : public TemplateDartCall<0> {
+// Common base class for various kinds of instance call instructions
+// (InstanceCallInstr, PolymorphicInstanceCallInstr).
+class InstanceCallBaseInstr : public TemplateDartCall<0> {
public:
- InstanceCallInstr(
- TokenPosition token_pos,
- const String& function_name,
- Token::Kind token_kind,
- InputsArray* arguments,
- intptr_t type_args_len,
- const Array& argument_names,
- intptr_t checked_argument_count,
- const ZoneGrowableArray<const ICData*>& ic_data_array,
- intptr_t deopt_id,
- const Function& interface_target = Function::null_function())
+ InstanceCallBaseInstr(TokenPosition token_pos,
+ const String& function_name,
+ Token::Kind token_kind,
+ InputsArray* arguments,
+ intptr_t type_args_len,
+ const Array& argument_names,
+ const ICData* ic_data,
+ intptr_t deopt_id,
+ const Function& interface_target)
: TemplateDartCall(deopt_id,
type_args_len,
argument_names,
arguments,
token_pos),
- ic_data_(NULL),
+ ic_data_(ic_data),
function_name_(function_name),
token_kind_(token_kind),
- checked_argument_count_(checked_argument_count),
interface_target_(interface_target),
- result_type_(NULL),
+ result_type_(nullptr),
has_unique_selector_(false) {
- ic_data_ = GetICData(ic_data_array);
ASSERT(function_name.IsNotTemporaryScopedHandle());
- ASSERT(interface_target_.IsNotTemporaryScopedHandle());
+ ASSERT(interface_target.IsNotTemporaryScopedHandle());
ASSERT(!arguments->is_empty());
ASSERT(Token::IsBinaryOperator(token_kind) ||
Token::IsEqualityOperator(token_kind) ||
@@ -3745,72 +3746,25 @@
token_kind == Token::kSET || token_kind == Token::kILLEGAL);
}
- InstanceCallInstr(
- TokenPosition token_pos,
- const String& function_name,
- Token::Kind token_kind,
- InputsArray* arguments,
- intptr_t type_args_len,
- const Array& argument_names,
- intptr_t checked_argument_count,
- intptr_t deopt_id,
- const Function& interface_target = Function::null_function())
- : TemplateDartCall(deopt_id,
- type_args_len,
- argument_names,
- arguments,
- token_pos),
- ic_data_(NULL),
- function_name_(function_name),
- token_kind_(token_kind),
- checked_argument_count_(checked_argument_count),
- interface_target_(interface_target),
- result_type_(NULL),
- has_unique_selector_(false) {
- ASSERT(function_name.IsNotTemporaryScopedHandle());
- ASSERT(interface_target_.IsNotTemporaryScopedHandle());
- ASSERT(!arguments->is_empty());
- ASSERT(Token::IsBinaryOperator(token_kind) ||
- Token::IsEqualityOperator(token_kind) ||
- Token::IsRelationalOperator(token_kind) ||
- Token::IsUnaryOperator(token_kind) ||
- Token::IsIndexOperator(token_kind) ||
- Token::IsTypeTestOperator(token_kind) ||
- Token::IsTypeCastOperator(token_kind) || token_kind == Token::kGET ||
- token_kind == Token::kSET || token_kind == Token::kILLEGAL);
- }
-
- DECLARE_INSTRUCTION(InstanceCall)
-
const ICData* ic_data() const { return ic_data_; }
- bool HasICData() const { return (ic_data() != NULL) && !ic_data()->IsNull(); }
+ bool HasICData() const {
+ return (ic_data() != nullptr) && !ic_data()->IsNull();
+ }
// ICData can be replaced by optimizer.
void set_ic_data(const ICData* value) { ic_data_ = value; }
const String& function_name() const { return function_name_; }
Token::Kind token_kind() const { return token_kind_; }
- intptr_t checked_argument_count() const { return checked_argument_count_; }
const Function& interface_target() const { return interface_target_; }
- void set_receivers_static_type(const AbstractType* receiver_type) {
- ASSERT(receiver_type != nullptr);
- receivers_static_type_ = receiver_type;
- }
-
bool has_unique_selector() const { return has_unique_selector_; }
void set_has_unique_selector(bool b) { has_unique_selector_ = b; }
- virtual intptr_t CallCount() const {
- return ic_data() == NULL ? 0 : ic_data()->AggregateCount();
- }
-
virtual CompileType ComputeType() const;
virtual bool ComputeCanDeoptimize() const { return !FLAG_precompiled_mode; }
- virtual Definition* Canonicalize(FlowGraph* flow_graph);
-
virtual bool CanBecomeDeoptimizationTarget() const {
// Instance calls that are specialized by the optimizer need a
// deoptimization descriptor before the call.
@@ -3826,69 +3780,144 @@
CompileType* result_type() const { return result_type_; }
intptr_t result_cid() const {
- if (result_type_ == NULL) {
+ if (result_type_ == nullptr) {
return kDynamicCid;
}
return result_type_->ToCid();
}
- PRINT_OPERANDS_TO_SUPPORT
- ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
- ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
-
- bool MatchesCoreName(const String& name);
-
RawFunction* ResolveForReceiverClass(const Class& cls, bool allow_add = true);
Code::EntryKind entry_kind() const { return entry_kind_; }
-
void set_entry_kind(Code::EntryKind value) { entry_kind_ = value; }
- const CallTargets& Targets();
- void SetTargets(const CallTargets* targets) { targets_ = targets; }
+ ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
+ ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
+ DEFINE_INSTRUCTION_TYPE_CHECK(InstanceCallBase);
+
+ protected:
+ friend class CallSpecializer;
+ void set_ic_data(ICData* value) { ic_data_ = value; }
+ void set_result_type(CompileType* result_type) { result_type_ = result_type; }
+
+ private:
+ const ICData* ic_data_;
+ const String& function_name_;
+ const Token::Kind token_kind_; // Binary op, unary op, kGET or kILLEGAL.
+ const Function& interface_target_;
+ CompileType* result_type_; // Inferred result type.
+ bool has_unique_selector_;
+ Code::EntryKind entry_kind_ = Code::EntryKind::kNormal;
+
+ DISALLOW_COPY_AND_ASSIGN(InstanceCallBaseInstr);
+};
+
+class InstanceCallInstr : public InstanceCallBaseInstr {
+ public:
+ InstanceCallInstr(
+ TokenPosition token_pos,
+ const String& function_name,
+ Token::Kind token_kind,
+ InputsArray* arguments,
+ intptr_t type_args_len,
+ const Array& argument_names,
+ intptr_t checked_argument_count,
+ const ZoneGrowableArray<const ICData*>& ic_data_array,
+ intptr_t deopt_id,
+ const Function& interface_target = Function::null_function())
+ : InstanceCallBaseInstr(
+ token_pos,
+ function_name,
+ token_kind,
+ arguments,
+ type_args_len,
+ argument_names,
+ GetICData(ic_data_array, deopt_id, /*is_static_call=*/false),
+ deopt_id,
+ interface_target),
+ checked_argument_count_(checked_argument_count) {}
+
+ InstanceCallInstr(
+ TokenPosition token_pos,
+ const String& function_name,
+ Token::Kind token_kind,
+ InputsArray* arguments,
+ intptr_t type_args_len,
+ const Array& argument_names,
+ intptr_t checked_argument_count,
+ intptr_t deopt_id,
+ const Function& interface_target = Function::null_function())
+ : InstanceCallBaseInstr(token_pos,
+ function_name,
+ token_kind,
+ arguments,
+ type_args_len,
+ argument_names,
+ /*ic_data=*/nullptr,
+ deopt_id,
+ interface_target),
+ checked_argument_count_(checked_argument_count) {}
+
+ DECLARE_INSTRUCTION(InstanceCall)
+
+ intptr_t checked_argument_count() const { return checked_argument_count_; }
+
+ virtual intptr_t CallCount() const {
+ return ic_data() == nullptr ? 0 : ic_data()->AggregateCount();
+ }
+
+ void set_receivers_static_type(const AbstractType* receiver_type) {
+ ASSERT(receiver_type != nullptr);
+ receivers_static_type_ = receiver_type;
+ }
+
+ virtual Definition* Canonicalize(FlowGraph* flow_graph);
+
+ PRINT_OPERANDS_TO_SUPPORT
+ ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
+
+ bool MatchesCoreName(const String& name);
const class BinaryFeedback& BinaryFeedback();
void SetBinaryFeedback(const class BinaryFeedback* binary) {
binary_ = binary;
}
- protected:
- friend class CallSpecializer;
- void set_ic_data(ICData* value) { ic_data_ = value; }
+ const CallTargets& Targets();
+ void SetTargets(const CallTargets* targets) { targets_ = targets; }
private:
- const ICData* ic_data_;
const CallTargets* targets_ = nullptr;
const class BinaryFeedback* binary_ = nullptr;
- const String& function_name_;
- const Token::Kind token_kind_; // Binary op, unary op, kGET or kILLEGAL.
const intptr_t checked_argument_count_;
- const Function& interface_target_;
- CompileType* result_type_; // Inferred result type.
- bool has_unique_selector_;
- Code::EntryKind entry_kind_ = Code::EntryKind::kNormal;
-
const AbstractType* receivers_static_type_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(InstanceCallInstr);
};
-class PolymorphicInstanceCallInstr : public TemplateDartCall<0> {
+class PolymorphicInstanceCallInstr : public InstanceCallBaseInstr {
public:
// Generate a replacement polymorphic call instruction.
static PolymorphicInstanceCallInstr* FromCall(Zone* zone,
- InstanceCallInstr* call,
+ InstanceCallBaseInstr* call,
const CallTargets& targets,
bool complete) {
- return FromCall(zone, call, call, targets, complete);
- }
-
- static PolymorphicInstanceCallInstr* FromCall(
- Zone* zone,
- PolymorphicInstanceCallInstr* call,
- const CallTargets& targets,
- bool complete) {
- return FromCall(zone, call, call->instance_call(), targets, complete);
+ ASSERT(!call->HasPushArguments());
+ InputsArray* args = new (zone) InputsArray(zone, call->ArgumentCount());
+ for (intptr_t i = 0, n = call->ArgumentCount(); i < n; ++i) {
+ args->Add(call->ArgumentValueAt(i)->CopyWithType(zone));
+ }
+ auto new_call = new (zone) PolymorphicInstanceCallInstr(
+ call->token_pos(), call->function_name(), call->token_kind(), args,
+ call->type_args_len(), call->argument_names(), call->ic_data(),
+ call->deopt_id(), call->interface_target(), targets, complete);
+ if (call->has_inlining_id()) {
+ new_call->set_inlining_id(call->inlining_id());
+ }
+ new_call->set_result_type(call->result_type());
+ new_call->set_entry_kind(call->entry_kind());
+ new_call->set_has_unique_selector(call->has_unique_selector());
+ return new_call;
}
bool complete() const { return complete_; }
@@ -3917,70 +3946,40 @@
DECLARE_INSTRUCTION(PolymorphicInstanceCall)
- virtual bool ComputeCanDeoptimize() const { return !FLAG_precompiled_mode; }
-
- virtual bool HasUnknownSideEffects() const { return true; }
-
virtual Definition* Canonicalize(FlowGraph* graph);
static RawType* ComputeRuntimeType(const CallTargets& targets);
- CompileType* result_type() const { return instance_call()->result_type(); }
- intptr_t result_cid() const { return instance_call()->result_cid(); }
- const String& function_name() const {
- return instance_call()->function_name();
- }
- Token::Kind token_kind() const { return instance_call()->token_kind(); }
- Code::EntryKind entry_kind() const { return instance_call()->entry_kind(); }
- const ICData* ic_data() const { return instance_call()->ic_data(); }
- bool has_unique_selector() const {
- return instance_call()->has_unique_selector();
- }
- RawFunction* ResolveForReceiverClass(const Class& cls) {
- return instance_call()->ResolveForReceiverClass(cls);
- }
-
PRINT_OPERANDS_TO_SUPPORT
- ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
private:
- PolymorphicInstanceCallInstr(InstanceCallInstr* instance_call,
+ PolymorphicInstanceCallInstr(TokenPosition token_pos,
+ const String& function_name,
+ Token::Kind token_kind,
InputsArray* arguments,
+ intptr_t type_args_len,
+ const Array& argument_names,
+ const ICData* ic_data,
+ intptr_t deopt_id,
+ const Function& interface_target,
const CallTargets& targets,
bool complete)
- : TemplateDartCall<0>(instance_call->deopt_id(),
- instance_call->type_args_len(),
- instance_call->argument_names(),
- arguments,
- instance_call->token_pos()),
- instance_call_(instance_call),
+ : InstanceCallBaseInstr(token_pos,
+ function_name,
+ token_kind,
+ arguments,
+ type_args_len,
+ argument_names,
+ ic_data,
+ deopt_id,
+ interface_target),
targets_(targets),
complete_(complete) {
- ASSERT(instance_call_ != nullptr);
ASSERT(targets.length() != 0);
total_call_count_ = CallCount();
}
- static PolymorphicInstanceCallInstr* FromCall(
- Zone* zone,
- Instruction* call_for_arguments,
- InstanceCallInstr* call_for_attributes,
- const CallTargets& targets,
- bool complete) {
- ASSERT(!call_for_arguments->HasPushArguments());
- InputsArray* args =
- new (zone) InputsArray(zone, call_for_arguments->ArgumentCount());
- for (intptr_t i = 0, n = call_for_arguments->ArgumentCount(); i < n; ++i) {
- args->Add(call_for_arguments->ArgumentValueAt(i)->CopyWithType(zone));
- }
- return new (zone) PolymorphicInstanceCallInstr(call_for_attributes, args,
- targets, complete);
- }
-
- InstanceCallInstr* instance_call() const { return instance_call_; }
-
- InstanceCallInstr* instance_call_;
const CallTargets& targets_;
const bool complete_;
intptr_t total_call_count_;
@@ -4299,7 +4298,7 @@
result_type_(NULL),
is_known_list_constructor_(false),
identity_(AliasIdentity::Unknown()) {
- ic_data_ = GetICData(ic_data_array);
+ ic_data_ = GetICData(ic_data_array, deopt_id, /*is_static_call=*/true);
ASSERT(function.IsZoneHandle());
ASSERT(!function.IsNull());
}
@@ -8835,7 +8834,7 @@
class FlowGraphVisitor : public ValueObject {
public:
explicit FlowGraphVisitor(const GrowableArray<BlockEntryInstr*>& block_order)
- : current_iterator_(NULL), block_order_(block_order) {}
+ : current_iterator_(NULL), block_order_(&block_order) {}
virtual ~FlowGraphVisitor() {}
ForwardInstructionIterator* current_iterator() const {
@@ -8856,10 +8855,14 @@
#undef DECLARE_VISIT_INSTRUCTION
protected:
+ void set_block_order(const GrowableArray<BlockEntryInstr*>& block_order) {
+ block_order_ = &block_order;
+ }
+
ForwardInstructionIterator* current_iterator_;
private:
- const GrowableArray<BlockEntryInstr*>& block_order_;
+ const GrowableArray<BlockEntryInstr*>* block_order_;
DISALLOW_COPY_AND_ASSIGN(FlowGraphVisitor);
};
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index b0efd4e..055963c 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -381,15 +381,19 @@
// R4: Arguments descriptor.
// R0: Function.
ASSERT(locs()->in(0).reg() == R0);
- __ ldr(CODE_REG,
- compiler::FieldAddress(R0, compiler::target::Function::code_offset()));
- __ ldr(R2, compiler::FieldAddress(
- R0, compiler::target::Code::function_entry_point_offset(
- entry_kind())));
+ if (!FLAG_precompiled_mode || !FLAG_use_bare_instructions) {
+ __ ldr(CODE_REG, compiler::FieldAddress(
+ R0, compiler::target::Function::code_offset()));
+ }
+ __ ldr(R2,
+ compiler::FieldAddress(
+ R0, compiler::target::Function::entry_point_offset(entry_kind())));
// R2: instructions entry point.
- // R9: Smi 0 (no IC data; the lazy-compile stub expects a GC-safe value).
- __ LoadImmediate(R9, 0);
+ if (!FLAG_precompiled_mode) {
+ // R9: Smi 0 (no IC data; the lazy-compile stub expects a GC-safe value).
+ __ LoadImmediate(R9, 0);
+ }
__ blx(R2);
compiler->EmitCallsiteMetadata(token_pos(), deopt_id(),
RawPcDescriptors::kOther, locs());
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index 45a4987..7a56b46 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -319,14 +319,18 @@
// R4: Arguments descriptor.
// R0: Function.
ASSERT(locs()->in(0).reg() == R0);
- __ LoadFieldFromOffset(CODE_REG, R0, Function::code_offset());
+ if (!FLAG_precompiled_mode || !FLAG_use_bare_instructions) {
+ __ LoadFieldFromOffset(CODE_REG, R0,
+ compiler::target::Function::code_offset());
+ }
__ LoadFieldFromOffset(
- R2, CODE_REG, compiler::target::Code::entry_point_offset(entry_kind()));
+ R2, R0, compiler::target::Function::entry_point_offset(entry_kind()));
// R2: instructions.
- // R5: Smi 0 (no IC data; the lazy-compile stub expects a GC-safe value).
- __ LoadImmediate(R5, 0);
- //??
+ if (!FLAG_precompiled_mode) {
+ // R5: Smi 0 (no IC data; the lazy-compile stub expects a GC-safe value).
+ __ LoadImmediate(R5, 0);
+ }
__ blr(R2);
compiler->EmitCallsiteMetadata(token_pos(), deopt_id(),
RawPcDescriptors::kOther, locs());
diff --git a/runtime/vm/compiler/backend/il_deserializer.cc b/runtime/vm/compiler/backend/il_deserializer.cc
index 6251bf8..5f91cf9 100644
--- a/runtime/vm/compiler/backend/il_deserializer.cc
+++ b/runtime/vm/compiler/backend/il_deserializer.cc
@@ -8,6 +8,7 @@
#include "vm/compiler/backend/il_serializer.h"
#include "vm/compiler/backend/range_analysis.h"
+#include "vm/compiler/call_specializer.h"
#include "vm/compiler/jit/compiler.h"
#include "vm/flags.h"
#include "vm/json_writer.h"
@@ -126,7 +127,7 @@
}
void FlowGraphDeserializer::RoundTripSerialization(CompilerPassState* state) {
- auto const flow_graph = state->flow_graph;
+ auto const flow_graph = state->flow_graph();
// The deserialized flow graph must be in the same zone as the original flow
// graph, to ensure it has the right lifetime. Thus, we leave an explicit
@@ -195,7 +196,9 @@
if (FLAG_print_json_round_trip_results) PrintRoundTripResults(zone, results);
- if (new_graph != nullptr) state->flow_graph = new_graph;
+ if (new_graph != nullptr) {
+ state->set_flow_graph(new_graph);
+ }
}
#define HANDLED_CASE(name) \
@@ -346,7 +349,13 @@
}
flow_graph_->set_max_block_id(max_block_id_);
- flow_graph_->set_current_ssa_temp_index(max_ssa_index_ + 1);
+ // The highest numbered SSA temp might need two slots (e.g. for unboxed
+ // integers on 32-bit platforms), so we add 2 to the highest seen SSA temp
+ // index to get to the new current SSA temp index. In cases where the highest
+ // numbered SSA temp originally had only one slot assigned, this can result
+ // in different SSA temp numbering in later passes between the original and
+ // deserialized graphs.
+ flow_graph_->set_current_ssa_temp_index(max_ssa_index_ + 2);
// Now that the deserializer has finished re-creating all the blocks in the
// flow graph, the blocks must be rediscovered. In addition, if ComputeSSA
// has already been run, dominators must be recomputed as well.
diff --git a/runtime/vm/compiler/backend/il_printer.cc b/runtime/vm/compiler/backend/il_printer.cc
index d039bf3..78b937e 100644
--- a/runtime/vm/compiler/backend/il_printer.cc
+++ b/runtime/vm/compiler/backend/il_printer.cc
@@ -532,8 +532,7 @@
}
void PolymorphicInstanceCallInstr::PrintOperandsTo(BufferFormatter* f) const {
- f->Print(" %s<%" Pd ">", instance_call()->function_name().ToCString(),
- instance_call()->type_args_len());
+ f->Print(" %s<%" Pd ">", function_name().ToCString(), type_args_len());
for (intptr_t i = 0; i < ArgumentCount(); ++i) {
f->Print(", ");
ArgumentValueAt(i)->PrintTo(f);
@@ -542,7 +541,7 @@
if (complete()) {
f->Print(" COMPLETE");
}
- if (instance_call()->entry_kind() == Code::EntryKind::kUnchecked) {
+ if (entry_kind() == Code::EntryKind::kUnchecked) {
f->Print(" using unchecked entrypoint");
}
}
diff --git a/runtime/vm/compiler/backend/il_serializer.cc b/runtime/vm/compiler/backend/il_serializer.cc
index e1032a2..2ec431ae 100644
--- a/runtime/vm/compiler/backend/il_serializer.cc
+++ b/runtime/vm/compiler/backend/il_serializer.cc
@@ -1211,12 +1211,13 @@
}
}
-void InstanceCallInstr::AddOperandsToSExpression(SExpList* sexp,
- FlowGraphSerializer* s) const {
+void InstanceCallBaseInstr::AddOperandsToSExpression(
+ SExpList* sexp,
+ FlowGraphSerializer* s) const {
Instruction::AddOperandsToSExpression(sexp, s);
}
-void InstanceCallInstr::AddExtraInfoToSExpression(
+void InstanceCallBaseInstr::AddExtraInfoToSExpression(
SExpList* sexp,
FlowGraphSerializer* s) const {
TemplateDartCall<0>::AddExtraInfoToSExpression(sexp, s);
@@ -1243,9 +1244,6 @@
if (token_kind() != Token::kILLEGAL) {
s->AddExtraSymbol(sexp, "token_kind", Token::Str(token_kind()));
}
- if (checked_argument_count() > 0 || FLAG_verbose_flow_graph_serialization) {
- s->AddExtraInteger(sexp, "checked_arg_count", checked_argument_count());
- }
if (ShouldSerializeType(result_type())) {
sexp->AddExtra("result_type", result_type()->ToSExpression(s));
@@ -1258,19 +1256,21 @@
}
}
-void PolymorphicInstanceCallInstr::AddOperandsToSExpression(
+void InstanceCallInstr::AddExtraInfoToSExpression(
SExpList* sexp,
FlowGraphSerializer* s) const {
- Instruction::AddOperandsToSExpression(sexp, s);
+ InstanceCallBaseInstr::AddExtraInfoToSExpression(sexp, s);
+
+ if (checked_argument_count() > 0 || FLAG_verbose_flow_graph_serialization) {
+ s->AddExtraInteger(sexp, "checked_arg_count", checked_argument_count());
+ }
}
void PolymorphicInstanceCallInstr::AddExtraInfoToSExpression(
SExpList* sexp,
FlowGraphSerializer* s) const {
- TemplateDartCall<0>::AddExtraInfoToSExpression(sexp, s);
- // TODO(alexmarkov): figure out how to serialize information from
- // inner InstanceCall
- // sexp->AddExtra("instance_call", instance_call()->ToSExpression(s));
+ InstanceCallBaseInstr::AddExtraInfoToSExpression(sexp, s);
+
if (targets().length() > 0 || FLAG_verbose_flow_graph_serialization) {
auto elem_list = new (s->zone()) SExpList(s->zone());
for (intptr_t i = 0; i < targets().length(); i++) {
diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc
index 43e04dd..dd48008 100644
--- a/runtime/vm/compiler/backend/il_x64.cc
+++ b/runtime/vm/compiler/backend/il_x64.cc
@@ -6752,14 +6752,21 @@
// Function in RAX.
ASSERT(locs()->in(0).reg() == RAX);
- __ movq(CODE_REG, compiler::FieldAddress(RAX, Function::code_offset()));
- __ movq(RCX, compiler::FieldAddress(
- RAX, Code::function_entry_point_offset(entry_kind())));
+ if (!FLAG_precompiled_mode || !FLAG_use_bare_instructions) {
+ __ movq(CODE_REG, compiler::FieldAddress(
+ RAX, compiler::target::Function::code_offset()));
+ }
+ __ movq(
+ RCX,
+ compiler::FieldAddress(
+ RAX, compiler::target::Function::entry_point_offset(entry_kind())));
// RAX: Function.
// R10: Arguments descriptor array.
- // RBX: Smi 0 (no IC data; the lazy-compile stub expects a GC-safe value).
- __ xorq(RBX, RBX);
+ if (!FLAG_precompiled_mode) {
+ // RBX: Smi 0 (no IC data; the lazy-compile stub expects a GC-safe value).
+ __ xorq(RBX, RBX);
+ }
__ call(RCX);
compiler->EmitCallsiteMetadata(token_pos(), deopt_id(),
RawPcDescriptors::kOther, locs());
diff --git a/runtime/vm/compiler/backend/type_propagator.cc b/runtime/vm/compiler/backend/type_propagator.cc
index 0fd3634..6133a0a 100644
--- a/runtime/vm/compiler/backend/type_propagator.cc
+++ b/runtime/vm/compiler/backend/type_propagator.cc
@@ -1261,7 +1261,7 @@
&Object::dynamic_type());
}
-CompileType InstanceCallInstr::ComputeType() const {
+CompileType InstanceCallBaseInstr::ComputeType() const {
// TODO(alexmarkov): calculate type of InstanceCallInstr eagerly
// (in optimized mode) and avoid keeping separate result_type.
CompileType* inferred_type = result_type();
@@ -1310,13 +1310,8 @@
}
}
- if (Isolate::Current()->can_use_strong_mode_types()) {
- CompileType* type = instance_call()->Type();
- TraceStrongModeType(this, type);
- return is_nullable ? *type : type->CopyNonNullable();
- }
-
- return CompileType::Dynamic();
+ CompileType type = InstanceCallBaseInstr::ComputeType();
+ return is_nullable ? type : type.CopyNonNullable();
}
CompileType StaticCallInstr::ComputeType() const {
diff --git a/runtime/vm/compiler/call_specializer.h b/runtime/vm/compiler/call_specializer.h
index 940243d..bc8544d 100644
--- a/runtime/vm/compiler/call_specializer.h
+++ b/runtime/vm/compiler/call_specializer.h
@@ -41,6 +41,11 @@
FlowGraph* flow_graph() const { return flow_graph_; }
+ void set_flow_graph(FlowGraph* flow_graph) {
+ flow_graph_ = flow_graph;
+ set_block_order(flow_graph->reverse_postorder());
+ }
+
// Use ICData to optimize, replace or eliminate instructions.
void ApplyICData();
diff --git a/runtime/vm/compiler/compiler_pass.cc b/runtime/vm/compiler/compiler_pass.cc
index 82f1c16..1142355 100644
--- a/runtime/vm/compiler/compiler_pass.cc
+++ b/runtime/vm/compiler/compiler_pass.cc
@@ -34,7 +34,7 @@
\
protected: \
virtual bool DoBody(CompilerPassState* state) const { \
- FlowGraph* flow_graph = state->flow_graph; \
+ FlowGraph* flow_graph = state->flow_graph(); \
USE(flow_graph); \
Body; \
} \
@@ -67,6 +67,13 @@
DECLARE_FLAG(bool, print_flow_graph);
DECLARE_FLAG(bool, print_flow_graph_optimized);
+void CompilerPassState::set_flow_graph(FlowGraph* flow_graph) {
+ flow_graph_ = flow_graph;
+ if (call_specializer != nullptr) {
+ call_specializer->set_flow_graph(flow_graph);
+ }
+}
+
static const char* kCompilerPassesUsage =
"=== How to use --compiler-passes flag\n"
"\n"
@@ -191,7 +198,7 @@
}
PrintGraph(state, kTraceAfter, round);
#if defined(DEBUG)
- FlowGraphChecker(state->flow_graph).Check(name());
+ FlowGraphChecker(state->flow_graph()).Check(name());
#endif
}
}
@@ -200,7 +207,7 @@
Flag mask,
intptr_t round) const {
const intptr_t current_flags = flags() | state->sticky_flags;
- FlowGraph* flow_graph = state->flow_graph;
+ FlowGraph* flow_graph = state->flow_graph();
if ((FLAG_print_flow_graph || FLAG_print_flow_graph_optimized) &&
flow_graph->should_print() && ((current_flags & mask) != 0)) {
@@ -271,7 +278,7 @@
}
INVOKE_PASS(AllocateRegisters);
INVOKE_PASS(ReorderBlocks);
- return pass_state->flow_graph;
+ return pass_state->flow_graph();
}
FlowGraph* CompilerPass::RunPipeline(PipelineMode mode,
@@ -355,7 +362,7 @@
}
INVOKE_PASS(AllocateRegisters);
INVOKE_PASS(ReorderBlocks);
- return pass_state->flow_graph;
+ return pass_state->flow_graph();
}
FlowGraph* CompilerPass::RunPipelineWithPasses(
@@ -364,7 +371,7 @@
for (auto pass_id : passes) {
passes_[pass_id]->Run(state);
}
- return state->flow_graph;
+ return state->flow_graph();
}
COMPILER_PASS(ComputeSSA, {
@@ -583,7 +590,7 @@
COMPILER_PASS(RoundTripSerialization, {
FlowGraphDeserializer::RoundTripSerialization(state);
- ASSERT(state->flow_graph != nullptr);
+ ASSERT(state->flow_graph() != nullptr);
})
} // namespace dart
diff --git a/runtime/vm/compiler/compiler_pass.h b/runtime/vm/compiler/compiler_pass.h
index b5dd477..a9d1f87 100644
--- a/runtime/vm/compiler/compiler_pass.h
+++ b/runtime/vm/compiler/compiler_pass.h
@@ -67,18 +67,20 @@
SpeculativeInliningPolicy* speculative_policy,
Precompiler* precompiler = NULL)
: thread(thread),
- flow_graph(flow_graph),
precompiler(precompiler),
inlining_depth(0),
sinking(NULL),
call_specializer(NULL),
speculative_policy(speculative_policy),
reorder_blocks(false),
- sticky_flags(0) {
- }
+ sticky_flags(0),
+ flow_graph_(flow_graph) {}
+
+ FlowGraph* flow_graph() const { return flow_graph_; }
+
+ void set_flow_graph(FlowGraph* flow_graph);
Thread* const thread;
- FlowGraph* flow_graph;
Precompiler* const precompiler;
int inlining_depth;
AllocationSinking* sinking;
@@ -98,6 +100,9 @@
bool reorder_blocks;
intptr_t sticky_flags;
+
+ private:
+ FlowGraph* flow_graph_;
};
class CompilerPass {
diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h
index b1d1bd3..9dd83de 100644
--- a/runtime/vm/compiler/runtime_api.h
+++ b/runtime/vm/compiler/runtime_api.h
@@ -423,9 +423,8 @@
class Function : public AllStatic {
public:
static word code_offset();
- static word entry_point_offset();
+ static word entry_point_offset(CodeEntryKind kind = CodeEntryKind::kNormal);
static word usage_counter_offset();
- static word unchecked_entry_point_offset();
};
class ICData : public AllStatic {
@@ -807,7 +806,6 @@
static word object_pool_offset();
static word entry_point_offset(CodeEntryKind kind = CodeEntryKind::kNormal);
- static word function_entry_point_offset(CodeEntryKind kind);
static word saved_instructions_offset();
static word owner_offset();
};
diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h
index 94bdeb6..2fb12cf 100644
--- a/runtime/vm/compiler/runtime_offsets_extracted.h
+++ b/runtime/vm/compiler/runtime_offsets_extracted.h
@@ -111,9 +111,8 @@
static constexpr dart::compiler::target::word Field_is_nullable_offset = 46;
static constexpr dart::compiler::target::word Field_kind_bits_offset = 60;
static constexpr dart::compiler::target::word Function_code_offset = 44;
-static constexpr dart::compiler::target::word Function_entry_point_offset = 4;
-static constexpr dart::compiler::target::word
- Function_unchecked_entry_point_offset = 8;
+static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
+ 4, 8};
static constexpr dart::compiler::target::word Function_usage_counter_offset =
76;
static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -361,8 +360,6 @@
static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
4, 12, 8, 16};
static constexpr dart::compiler::target::word
- Code_function_entry_point_offset[] = {4, 8};
-static constexpr dart::compiler::target::word
Thread_write_barrier_wrappers_thread_offset[] = {
628, 632, 636, 640, 644, -1, 648, 652,
656, 660, -1, -1, -1, -1, -1, -1};
@@ -485,9 +482,8 @@
static constexpr dart::compiler::target::word Field_is_nullable_offset = 82;
static constexpr dart::compiler::target::word Field_kind_bits_offset = 104;
static constexpr dart::compiler::target::word Function_code_offset = 88;
-static constexpr dart::compiler::target::word Function_entry_point_offset = 8;
-static constexpr dart::compiler::target::word
- Function_unchecked_entry_point_offset = 16;
+static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
+ 8, 16};
static constexpr dart::compiler::target::word Function_usage_counter_offset =
132;
static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -737,8 +733,6 @@
static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
8, 24, 16, 32};
static constexpr dart::compiler::target::word
- Code_function_entry_point_offset[] = {8, 16};
-static constexpr dart::compiler::target::word
Thread_write_barrier_wrappers_thread_offset[] = {
1248, 1256, 1264, 1272, -1, -1, 1280, 1288,
1296, 1304, 1312, -1, 1320, 1328, -1, -1};
@@ -859,9 +853,8 @@
static constexpr dart::compiler::target::word Field_is_nullable_offset = 46;
static constexpr dart::compiler::target::word Field_kind_bits_offset = 60;
static constexpr dart::compiler::target::word Function_code_offset = 44;
-static constexpr dart::compiler::target::word Function_entry_point_offset = 4;
-static constexpr dart::compiler::target::word
- Function_unchecked_entry_point_offset = 8;
+static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
+ 4, 8};
static constexpr dart::compiler::target::word Function_usage_counter_offset =
76;
static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -1108,8 +1101,6 @@
static constexpr dart::compiler::target::word ClassTable_element_size = 1;
static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
4, 12, 8, 16};
-static constexpr dart::compiler::target::word
- Code_function_entry_point_offset[] = {4, 8};
static constexpr dart::compiler::target::word Array_header_size = 12;
static constexpr dart::compiler::target::word Context_header_size = 12;
static constexpr dart::compiler::target::word Double_InstanceSize = 16;
@@ -1229,9 +1220,8 @@
static constexpr dart::compiler::target::word Field_is_nullable_offset = 82;
static constexpr dart::compiler::target::word Field_kind_bits_offset = 104;
static constexpr dart::compiler::target::word Function_code_offset = 88;
-static constexpr dart::compiler::target::word Function_entry_point_offset = 8;
-static constexpr dart::compiler::target::word
- Function_unchecked_entry_point_offset = 16;
+static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
+ 8, 16};
static constexpr dart::compiler::target::word Function_usage_counter_offset =
132;
static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -1481,8 +1471,6 @@
static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
8, 24, 16, 32};
static constexpr dart::compiler::target::word
- Code_function_entry_point_offset[] = {8, 16};
-static constexpr dart::compiler::target::word
Thread_write_barrier_wrappers_thread_offset[] = {
1248, 1256, 1264, 1272, 1280, 1288, 1296, 1304, 1312, 1320, 1328,
1336, 1344, 1352, 1360, -1, -1, -1, -1, 1368, 1376, 1384,
diff --git a/runtime/vm/compiler/runtime_offsets_list.h b/runtime/vm/compiler/runtime_offsets_list.h
index 5c88c8e..b2ba63a 100644
--- a/runtime/vm/compiler/runtime_offsets_list.h
+++ b/runtime/vm/compiler/runtime_offsets_list.h
@@ -90,8 +90,8 @@
PRECOMP_NO_CHECK(FIELD(Field, is_nullable_offset)) \
PRECOMP_NO_CHECK(FIELD(Field, kind_bits_offset)) \
FIELD(Function, code_offset) \
- FIELD(Function, entry_point_offset) \
- FIELD(Function, unchecked_entry_point_offset) \
+ RANGE(Function, entry_point_offset, CodeEntryKind, CodeEntryKind::kNormal, \
+ CodeEntryKind::kUnchecked, [](CodeEntryKind value) { return true; }) \
PRECOMP_NO_CHECK(FIELD(Function, usage_counter_offset)) \
FIELD(GrowableObjectArray, data_offset) \
FIELD(GrowableObjectArray, length_offset) \
@@ -244,9 +244,6 @@
RANGE(Code, entry_point_offset, CodeEntryKind, CodeEntryKind::kNormal, \
CodeEntryKind::kMonomorphicUnchecked, \
[](CodeEntryKind value) { return true; }) \
- RANGE(Code, function_entry_point_offset, CodeEntryKind, \
- CodeEntryKind::kNormal, CodeEntryKind::kUnchecked, \
- [](CodeEntryKind value) { return true; }) \
ONLY_IN_ARM_ARM64_X64(RANGE( \
Thread, write_barrier_wrappers_thread_offset, Register, 0, \
kNumberOfCpuRegisters - 1, \
diff --git a/runtime/vm/compiler/stub_code_compiler_arm.cc b/runtime/vm/compiler/stub_code_compiler_arm.cc
index 0af2249..c0f58fc 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm.cc
@@ -2057,8 +2057,10 @@
__ mov(R3, Operand(target::Function::entry_point_offset() - kHeapObjectTag));
__ b(&done);
__ BindUncheckedEntryPoint();
- __ mov(R3, Operand(target::Function::unchecked_entry_point_offset() -
- kHeapObjectTag));
+ __ mov(
+ R3,
+ Operand(target::Function::entry_point_offset(CodeEntryKind::kUnchecked) -
+ kHeapObjectTag));
__ Bind(&done);
}
diff --git a/runtime/vm/compiler/stub_code_compiler_arm64.cc b/runtime/vm/compiler/stub_code_compiler_arm64.cc
index a1162b8..9d9e357 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm64.cc
@@ -2159,7 +2159,8 @@
__ b(&done);
__ BindUncheckedEntryPoint();
__ LoadImmediate(
- R8, target::Function::unchecked_entry_point_offset() - kHeapObjectTag);
+ R8, target::Function::entry_point_offset(CodeEntryKind::kUnchecked) -
+ kHeapObjectTag);
__ Bind(&done);
}
diff --git a/runtime/vm/compiler/stub_code_compiler_ia32.cc b/runtime/vm/compiler/stub_code_compiler_ia32.cc
index 4b42c72..3e5ae59 100644
--- a/runtime/vm/compiler/stub_code_compiler_ia32.cc
+++ b/runtime/vm/compiler/stub_code_compiler_ia32.cc
@@ -1921,8 +1921,7 @@
__ Bind(&call_target_function);
__ Comment("Call target");
// EAX: Target function.
- __ jmp(
- FieldAddress(EAX, target::Code::function_entry_point_offset(entry_kind)));
+ __ jmp(FieldAddress(EAX, target::Function::entry_point_offset(entry_kind)));
#if !defined(PRODUCT)
if (optimized == kUnoptimized) {
@@ -2088,8 +2087,7 @@
// Get function and call it, if possible.
__ movl(EAX, Address(EBX, target_offset));
- __ jmp(
- FieldAddress(EAX, target::Code::function_entry_point_offset(entry_kind)));
+ __ jmp(FieldAddress(EAX, target::Function::entry_point_offset(entry_kind)));
#if !defined(PRODUCT)
__ Bind(&stepping);
diff --git a/runtime/vm/compiler/stub_code_compiler_x64.cc b/runtime/vm/compiler/stub_code_compiler_x64.cc
index 1a105a8..bf6415f 100644
--- a/runtime/vm/compiler/stub_code_compiler_x64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_x64.cc
@@ -2087,7 +2087,8 @@
Immediate(target::Function::entry_point_offset() - kHeapObjectTag));
__ jmp(&done);
__ BindUncheckedEntryPoint();
- __ movq(R8, Immediate(target::Function::unchecked_entry_point_offset() -
+ __ movq(R8, Immediate(target::Function::entry_point_offset(
+ CodeEntryKind::kUnchecked) -
kHeapObjectTag));
__ Bind(&done);
}
@@ -2329,7 +2330,8 @@
__ Comment("Call target (via unchecked entry point)");
__ movq(RAX, Address(R13, target_offset));
__ movq(CODE_REG, FieldAddress(RAX, target::Function::code_offset()));
- __ jmp(FieldAddress(RAX, target::Function::unchecked_entry_point_offset()));
+ __ jmp(FieldAddress(
+ RAX, target::Function::entry_point_offset(CodeEntryKind::kUnchecked)));
}
#if !defined(PRODUCT)
diff --git a/runtime/vm/heap/marker.cc b/runtime/vm/heap/marker.cc
index f3ac03a..add8913 100644
--- a/runtime/vm/heap/marker.cc
+++ b/runtime/vm/heap/marker.cc
@@ -90,11 +90,6 @@
MarkingStack* deferred_marking_stack)
: ObjectPointerVisitor(isolate),
thread_(Thread::Current()),
-#ifndef PRODUCT
- num_classes_(isolate->shared_class_table()->Capacity()),
- class_stats_count_(new intptr_t[num_classes_]),
- class_stats_size_(new intptr_t[num_classes_]),
-#endif // !PRODUCT
page_space_(page_space),
work_list_(marking_stack),
deferred_work_list_(deferred_marking_stack),
@@ -102,33 +97,12 @@
marked_bytes_(0),
marked_micros_(0) {
ASSERT(thread_->isolate() == isolate);
-#ifndef PRODUCT
- for (intptr_t i = 0; i < num_classes_; i++) {
- class_stats_count_[i] = 0;
- class_stats_size_[i] = 0;
- }
-#endif // !PRODUCT
- }
-
- ~MarkingVisitorBase() {
-#ifndef PRODUCT
- delete[] class_stats_count_;
- delete[] class_stats_size_;
-#endif // !PRODUCT
}
uintptr_t marked_bytes() const { return marked_bytes_; }
int64_t marked_micros() const { return marked_micros_; }
void AddMicros(int64_t micros) { marked_micros_ += micros; }
-#ifndef PRODUCT
- intptr_t live_count(intptr_t class_id) {
- return class_stats_count_[class_id];
- }
-
- intptr_t live_size(intptr_t class_id) { return class_stats_size_[class_id]; }
-#endif // !PRODUCT
-
bool ProcessPendingWeakProperties() {
bool marked = false;
RawWeakProperty* cur_weak = delayed_weak_properties_;
@@ -178,7 +152,6 @@
size = ProcessWeakProperty(raw_weak);
}
marked_bytes_ += size;
- NOT_IN_PRODUCT(UpdateLiveOld(class_id, size));
raw_obj = work_list_.Pop();
} while (raw_obj != NULL);
@@ -252,7 +225,6 @@
// double-counting.
if (TryAcquireMarkBit(raw_obj)) {
marked_bytes_ += size;
- NOT_IN_PRODUCT(UpdateLiveOld(class_id, size));
}
}
}
@@ -344,20 +316,7 @@
PushMarked(raw_obj);
}
-#ifndef PRODUCT
- void UpdateLiveOld(intptr_t class_id, intptr_t size) {
- ASSERT(class_id < num_classes_);
- class_stats_count_[class_id] += 1;
- class_stats_size_[class_id] += size;
- }
-#endif // !PRODUCT
-
Thread* thread_;
-#ifndef PRODUCT
- intptr_t num_classes_;
- intptr_t* class_stats_count_;
- intptr_t* class_stats_size_;
-#endif // !PRODUCT
PageSpace* page_space_;
MarkerWorkList work_list_;
MarkerWorkList deferred_work_list_;
@@ -419,7 +378,113 @@
#endif
}
-void GCMarker::Epilogue() {
+void GCMarker::Epilogue() {}
+
+enum RootSlices {
+ kIsolate = 0,
+ kNewSpace = 1,
+ kNumRootSlices = 2,
+};
+
+void GCMarker::ResetSlices() {
+ root_slices_started_ = 0;
+ root_slices_finished_ = 0;
+ weak_slices_started_ = 0;
+}
+
+void GCMarker::IterateRoots(ObjectPointerVisitor* visitor) {
+ for (;;) {
+ intptr_t slice = root_slices_started_.fetch_add(1);
+ if (slice >= kNumRootSlices) {
+ return; // No more slices.
+ }
+
+ switch (slice) {
+ case kIsolate: {
+ TIMELINE_FUNCTION_GC_DURATION(Thread::Current(), "ProcessIsolate");
+ isolate_->VisitObjectPointers(visitor,
+ ValidationPolicy::kDontValidateFrames);
+ break;
+ }
+ case kNewSpace: {
+ TIMELINE_FUNCTION_GC_DURATION(Thread::Current(), "ProcessNewSpace");
+ heap_->new_space()->VisitObjectPointers(visitor);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+
+ MonitorLocker ml(&root_slices_monitor_);
+ root_slices_finished_++;
+ if (root_slices_finished_ == kNumRootSlices) {
+ ml.Notify();
+ }
+ }
+}
+
+enum WeakSlices {
+ kWeakHandles = 0,
+ kWeakTables,
+ kObjectIdRing,
+ kRememberedSet,
+ kNumWeakSlices,
+};
+
+void GCMarker::IterateWeakRoots(Thread* thread) {
+ for (;;) {
+ intptr_t slice = weak_slices_started_.fetch_add(1);
+ if (slice >= kNumWeakSlices) {
+ return; // No more slices.
+ }
+
+ switch (slice) {
+ case kWeakHandles:
+ ProcessWeakHandles(thread);
+ break;
+ case kWeakTables:
+ ProcessWeakTables(thread);
+ break;
+ case kObjectIdRing:
+ ProcessObjectIdTable(thread);
+ break;
+ case kRememberedSet:
+ ProcessRememberedSet(thread);
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+}
+
+void GCMarker::ProcessWeakHandles(Thread* thread) {
+ TIMELINE_FUNCTION_GC_DURATION(thread, "ProcessWeakHandles");
+ MarkingWeakVisitor visitor(thread);
+ ApiState* state = isolate_->api_state();
+ ASSERT(state != NULL);
+ isolate_->VisitWeakPersistentHandles(&visitor);
+}
+
+void GCMarker::ProcessWeakTables(Thread* thread) {
+ TIMELINE_FUNCTION_GC_DURATION(thread, "ProcessWeakTables");
+ for (int sel = 0; sel < Heap::kNumWeakSelectors; sel++) {
+ WeakTable* table =
+ heap_->GetWeakTable(Heap::kOld, static_cast<Heap::WeakSelector>(sel));
+ intptr_t size = table->size();
+ for (intptr_t i = 0; i < size; i++) {
+ if (table->IsValidEntryAtExclusive(i)) {
+ RawObject* raw_obj = table->ObjectAtExclusive(i);
+ ASSERT(raw_obj->IsHeapObject());
+ if (!raw_obj->IsMarked()) {
+ table->InvalidateAtExclusive(i);
+ }
+ }
+ }
+ }
+}
+
+void GCMarker::ProcessRememberedSet(Thread* thread) {
+ TIMELINE_FUNCTION_GC_DURATION(thread, "ProcessRememberedSet");
// Filter collected objects from the remembered set.
StoreBuffer* store_buffer = isolate_->store_buffer();
StoreBufferBlock* reading = store_buffer->Blocks();
@@ -448,72 +513,6 @@
store_buffer->PushBlock(writing, StoreBuffer::kIgnoreThreshold);
}
-enum RootSlices {
- kIsolate = 0,
- kNewSpace = 1,
- kNumRootSlices = 2,
-};
-
-void GCMarker::ResetRootSlices() {
- root_slices_not_started_ = kNumRootSlices;
- root_slices_not_finished_ = kNumRootSlices;
-}
-
-void GCMarker::IterateRoots(ObjectPointerVisitor* visitor) {
- for (;;) {
- intptr_t task = root_slices_not_started_.fetch_sub(1) - 1;
- if (task < 0) {
- return; // No more tasks.
- }
-
- switch (task) {
- case kIsolate: {
- TIMELINE_FUNCTION_GC_DURATION(Thread::Current(), "ProcessRoots");
- isolate_->VisitObjectPointers(visitor,
- ValidationPolicy::kDontValidateFrames);
- break;
- }
- case kNewSpace: {
- TIMELINE_FUNCTION_GC_DURATION(Thread::Current(), "ProcessNewSpace");
- heap_->new_space()->VisitObjectPointers(visitor);
- break;
- }
- default:
- FATAL1("%" Pd, task);
- UNREACHABLE();
- }
-
- MonitorLocker ml(&root_slices_monitor_);
- root_slices_not_finished_--;
- if (root_slices_not_finished_ == 0) {
- ml.Notify();
- }
- }
-}
-
-void GCMarker::IterateWeakRoots(HandleVisitor* visitor) {
- ApiState* state = isolate_->api_state();
- ASSERT(state != NULL);
- isolate_->VisitWeakPersistentHandles(visitor);
-}
-
-void GCMarker::ProcessWeakTables(PageSpace* page_space) {
- for (int sel = 0; sel < Heap::kNumWeakSelectors; sel++) {
- WeakTable* table =
- heap_->GetWeakTable(Heap::kOld, static_cast<Heap::WeakSelector>(sel));
- intptr_t size = table->size();
- for (intptr_t i = 0; i < size; i++) {
- if (table->IsValidEntryAtExclusive(i)) {
- RawObject* raw_obj = table->ObjectAtExclusive(i);
- ASSERT(raw_obj->IsHeapObject());
- if (!raw_obj->IsMarked()) {
- table->InvalidateAtExclusive(i);
- }
- }
- }
- }
-}
-
class ObjectIdRingClearPointerVisitor : public ObjectPointerVisitor {
public:
explicit ObjectIdRingClearPointerVisitor(Isolate* isolate)
@@ -531,11 +530,12 @@
}
};
-void GCMarker::ProcessObjectIdTable() {
+void GCMarker::ProcessObjectIdTable(Thread* thread) {
#ifndef PRODUCT
if (!FLAG_support_service) {
return;
}
+ TIMELINE_FUNCTION_GC_DURATION(thread, "ProcessObjectIdTable");
ObjectIdRingClearPointerVisitor visitor(isolate_);
ObjectIdRing* ring = isolate_->object_id_ring();
ASSERT(ring != NULL);
@@ -563,7 +563,8 @@
Thread::EnterIsolateAsHelper(isolate_, Thread::kMarkerTask, true);
ASSERT(result);
{
- TIMELINE_FUNCTION_GC_DURATION(Thread::Current(), "ParallelMark");
+ Thread* thread = Thread::Current();
+ TIMELINE_FUNCTION_GC_DURATION(thread, "ParallelMark");
int64_t start = OS::GetCurrentMonotonicMicros();
// Phase 1: Iterate over roots and drain marking stack in tasks.
@@ -623,12 +624,15 @@
barrier_->Sync();
} while (more_to_mark);
+ // Phase 2: deferred marking.
visitor_->FinalizeDeferredMarking();
-
- // Phase 2: Weak processing and follow-up marking on main thread.
barrier_->Sync();
- // Phase 3: Finalize results from all markers (detach code, etc.).
+ // Phase 3: Weak processing.
+ marker_->IterateWeakRoots(thread);
+ barrier_->Sync();
+
+ // Phase 4: Gather statistics from all markers.
int64_t stop = OS::GetCurrentMonotonicMicros();
visitor_->AddMicros(stop - start);
if (FLAG_log_marker_tasks) {
@@ -786,7 +790,7 @@
page_space->concurrent_marker_tasks() + num_tasks);
}
- ResetRootSlices();
+ ResetSlices();
for (intptr_t i = 0; i < num_tasks; i++) {
ASSERT(visitors_[i] == NULL);
visitors_[i] = new SyncMarkingVisitor(isolate_, page_space, &marking_stack_,
@@ -800,7 +804,7 @@
// Wait for roots to be marked before exiting safepoint.
MonitorLocker ml(&root_slices_monitor_);
- while (root_slices_not_finished_ > 0) {
+ while (root_slices_finished_ != kNumRootSlices) {
ml.Wait();
}
}
@@ -820,16 +824,12 @@
// Mark everything on main thread.
UnsyncMarkingVisitor mark(isolate_, page_space, &marking_stack_,
&deferred_marking_stack_);
- ResetRootSlices();
+ ResetSlices();
IterateRoots(&mark);
mark.ProcessDeferredMarking();
mark.DrainMarkingStack();
mark.FinalizeDeferredMarking();
- {
- TIMELINE_FUNCTION_GC_DURATION(thread, "ProcessWeakHandles");
- MarkingWeakVisitor mark_weak(thread);
- IterateWeakRoots(&mark_weak);
- }
+ IterateWeakRoots(thread);
// All marking done; detach code, etc.
int64_t stop = OS::GetCurrentMonotonicMicros();
mark.AddMicros(stop - start);
@@ -837,7 +837,7 @@
} else {
ThreadBarrier barrier(num_tasks + 1, heap_->barrier(),
heap_->barrier_done());
- ResetRootSlices();
+ ResetSlices();
// Used to coordinate draining among tasks; all start out as 'busy'.
RelaxedAtomic<uintptr_t> num_busy(num_tasks);
// Phase 1: Iterate over roots and drain marking stack in tasks.
@@ -876,19 +876,16 @@
barrier.Sync();
} while (more_to_mark);
- // Phase 2: Weak processing on main thread.
- {
- TIMELINE_FUNCTION_GC_DURATION(thread, "ProcessWeakHandles");
- MarkingWeakVisitor mark_weak(thread);
- IterateWeakRoots(&mark_weak);
- }
+ // Phase 2: Deferred marking.
barrier.Sync();
- // Phase 3: Finalize results from all markers (detach code, etc.).
+ // Phase 3: Weak processing.
+ IterateWeakRoots(thread);
+ barrier.Sync();
+
+ // Phase 4: Gather statistics from all markers.
barrier.Exit();
}
- ProcessWeakTables(page_space);
- ProcessObjectIdTable();
}
Epilogue();
}
diff --git a/runtime/vm/heap/marker.h b/runtime/vm/heap/marker.h
index 2fd9282..35ebea9 100644
--- a/runtime/vm/heap/marker.h
+++ b/runtime/vm/heap/marker.h
@@ -20,6 +20,7 @@
class RawWeakProperty;
template <bool sync>
class MarkingVisitorBase;
+class Thread;
// The class GCMarker is used to mark reachable old generation objects as part
// of the mark-sweep collection. The marking bit used is defined in RawObject.
@@ -47,13 +48,13 @@
private:
void Prologue();
void Epilogue();
- void ResetRootSlices();
+ void ResetSlices();
void IterateRoots(ObjectPointerVisitor* visitor);
- void IterateWeakRoots(HandleVisitor* visitor);
- template <class MarkingVisitorType>
- void IterateWeakReferences(MarkingVisitorType* visitor);
- void ProcessWeakTables(PageSpace* page_space);
- void ProcessObjectIdTable();
+ void IterateWeakRoots(Thread* thread);
+ void ProcessWeakHandles(Thread* thread);
+ void ProcessWeakTables(Thread* thread);
+ void ProcessRememberedSet(Thread* thread);
+ void ProcessObjectIdTable(Thread* thread);
// Called by anyone: finalize and accumulate stats from 'visitor'.
template <class MarkingVisitorType>
@@ -66,8 +67,9 @@
MarkingVisitorBase<true>** visitors_;
Monitor root_slices_monitor_;
- RelaxedAtomic<intptr_t> root_slices_not_started_;
- intptr_t root_slices_not_finished_;
+ RelaxedAtomic<intptr_t> root_slices_started_;
+ intptr_t root_slices_finished_;
+ RelaxedAtomic<intptr_t> weak_slices_started_;
Mutex stats_mutex_;
uintptr_t marked_bytes_;
diff --git a/runtime/vm/heap/pages.cc b/runtime/vm/heap/pages.cc
index 15700c1..6c5a066 100644
--- a/runtime/vm/heap/pages.cc
+++ b/runtime/vm/heap/pages.cc
@@ -221,6 +221,12 @@
: freelist_(),
heap_(heap),
pages_lock_(),
+ pages_(NULL),
+ pages_tail_(NULL),
+ exec_pages_(NULL),
+ exec_pages_tail_(NULL),
+ large_pages_(NULL),
+ image_pages_(NULL),
bump_top_(0),
bump_end_(0),
max_capacity_in_words_(max_capacity_in_words),
@@ -267,95 +273,49 @@
return page_size >> kWordSizeLog2;
}
-void PageSpace::AddPageLocked(HeapPage* page) {
- if (pages_ == nullptr) {
- pages_ = page;
- } else {
- pages_tail_->set_next(page);
- }
- pages_tail_ = page;
-}
-
-void PageSpace::AddLargePageLocked(HeapPage* page) {
- if (large_pages_ == nullptr) {
- large_pages_ = page;
- } else {
- large_pages_tail_->set_next(page);
- }
- large_pages_tail_ = page;
-}
-
-void PageSpace::AddExecPageLocked(HeapPage* page) {
- if (exec_pages_ == nullptr) {
- exec_pages_ = page;
- } else {
- if (FLAG_write_protect_code) {
- exec_pages_tail_->WriteProtect(false);
- }
- exec_pages_tail_->set_next(page);
- if (FLAG_write_protect_code) {
- exec_pages_tail_->WriteProtect(true);
- }
- }
- exec_pages_tail_ = page;
-}
-
-void PageSpace::RemovePageLocked(HeapPage* page, HeapPage* previous_page) {
- if (previous_page != NULL) {
- previous_page->set_next(page->next());
- } else {
- pages_ = page->next();
- }
- if (page == pages_tail_) {
- pages_tail_ = previous_page;
- }
-}
-
-void PageSpace::RemoveLargePageLocked(HeapPage* page, HeapPage* previous_page) {
- if (previous_page != NULL) {
- previous_page->set_next(page->next());
- } else {
- large_pages_ = page->next();
- }
- if (page == large_pages_tail_) {
- large_pages_tail_ = previous_page;
- }
-}
-
-void PageSpace::RemoveExecPageLocked(HeapPage* page, HeapPage* previous_page) {
- if (previous_page != NULL) {
- previous_page->set_next(page->next());
- } else {
- exec_pages_ = page->next();
- }
- if (page == exec_pages_tail_) {
- exec_pages_tail_ = previous_page;
- }
-}
-
HeapPage* PageSpace::AllocatePage(HeapPage::PageType type, bool link) {
{
MutexLocker ml(&pages_lock_);
if (!CanIncreaseCapacityInWordsLocked(kPageSizeInWords)) {
- return nullptr;
+ return NULL;
}
IncreaseCapacityInWordsLocked(kPageSizeInWords);
}
const bool is_exec = (type == HeapPage::kExecutable);
const char* name = Heap::RegionName(is_exec ? Heap::kCode : Heap::kOld);
HeapPage* page = HeapPage::Allocate(kPageSizeInWords, type, name);
- if (page == nullptr) {
+ if (page == NULL) {
RELEASE_ASSERT(!FLAG_abort_on_oom);
IncreaseCapacityInWords(-kPageSizeInWords);
- return nullptr;
+ return NULL;
}
MutexLocker ml(&pages_lock_);
if (link) {
- if (is_exec) {
- AddExecPageLocked(page);
+ if (!is_exec) {
+ if (pages_ == NULL) {
+ pages_ = page;
+ } else {
+ pages_tail_->set_next(page);
+ }
+ pages_tail_ = page;
} else {
- AddPageLocked(page);
+ // Should not allocate executable pages when running from a precompiled
+ // snapshot.
+ ASSERT(Dart::vm_snapshot_kind() != Snapshot::kFullAOT);
+
+ if (exec_pages_ == NULL) {
+ exec_pages_ = page;
+ } else {
+ if (FLAG_write_protect_code) {
+ exec_pages_tail_->WriteProtect(false);
+ }
+ exec_pages_tail_->set_next(page);
+ if (FLAG_write_protect_code) {
+ exec_pages_tail_->WriteProtect(true);
+ }
+ }
+ exec_pages_tail_ = page;
}
}
@@ -372,28 +332,26 @@
{
MutexLocker ml(&pages_lock_);
if (!CanIncreaseCapacityInWordsLocked(page_size_in_words)) {
- return nullptr;
+ return NULL;
}
IncreaseCapacityInWordsLocked(page_size_in_words);
}
const bool is_exec = (type == HeapPage::kExecutable);
const char* name = Heap::RegionName(is_exec ? Heap::kCode : Heap::kOld);
HeapPage* page = HeapPage::Allocate(page_size_in_words, type, name);
+ {
+ MutexLocker ml(&pages_lock_);
+ if (page == nullptr) {
+ IncreaseCapacityInWordsLocked(-page_size_in_words);
+ return nullptr;
+ }
+ page->set_next(large_pages_);
+ large_pages_ = page;
- MutexLocker ml(&pages_lock_);
- if (page == nullptr) {
- IncreaseCapacityInWordsLocked(-page_size_in_words);
- return nullptr;
+ // Only one object in this page (at least until Array::MakeFixedLength
+ // is called).
+ page->set_object_end(page->object_start() + size);
}
- if (is_exec) {
- AddExecPageLocked(page);
- } else {
- AddLargePageLocked(page);
- }
-
- // Only one object in this page (at least until Array::MakeFixedLength
- // is called).
- page->set_object_end(page->object_start() + size);
return page;
}
@@ -418,10 +376,26 @@
{
MutexLocker ml(&pages_lock_);
IncreaseCapacityInWordsLocked(-(page->memory_->size() >> kWordSizeLog2));
- if (is_exec) {
- RemoveExecPageLocked(page, previous_page);
+ if (!is_exec) {
+ // Remove the page from the list of data pages.
+ if (previous_page != NULL) {
+ previous_page->set_next(page->next());
+ } else {
+ pages_ = page->next();
+ }
+ if (page == pages_tail_) {
+ pages_tail_ = previous_page;
+ }
} else {
- RemovePageLocked(page, previous_page);
+ // Remove the page from the list of executable pages.
+ if (previous_page != NULL) {
+ previous_page->set_next(page->next());
+ } else {
+ exec_pages_ = page->next();
+ }
+ if (page == exec_pages_tail_) {
+ exec_pages_tail_ = previous_page;
+ }
}
}
// TODO(iposva): Consider adding to a pool of empty pages.
@@ -429,10 +403,16 @@
}
void PageSpace::FreeLargePage(HeapPage* page, HeapPage* previous_page) {
- ASSERT(page->type() != HeapPage::kExecutable);
- MutexLocker ml(&pages_lock_);
- IncreaseCapacityInWordsLocked(-(page->memory_->size() >> kWordSizeLog2));
- RemoveLargePageLocked(page, previous_page);
+ // Thread should be at a safepoint when this code is called and hence
+ // it is not necessary to lock large_pages_.
+ ASSERT(Thread::Current()->IsAtSafepoint());
+ IncreaseCapacityInWords(-(page->memory_->size() >> kWordSizeLog2));
+ // Remove the page from the list.
+ if (previous_page != NULL) {
+ previous_page->set_next(page->next());
+ } else {
+ large_pages_ = page->next();
+ }
page->Deallocate();
}
@@ -1152,18 +1132,36 @@
OS::PrintErr(" done.\n");
}
- // Executable pages are always swept immediately to simplify
- // code protection.
-
- TIMELINE_FUNCTION_GC_DURATION(thread, "SweepExecutable");
+ TIMELINE_FUNCTION_GC_DURATION(thread, "SweepLargeAndExecutablePages");
GCSweeper sweeper;
+
+ // During stop-the-world phases we should use bulk lock when adding
+ // elements to the free list.
+ MutexLocker mld(freelist_[HeapPage::kData].mutex());
+ MutexLocker mle(freelist_[HeapPage::kExecutable].mutex());
+
+ // Large and executable pages are always swept immediately.
HeapPage* prev_page = NULL;
- HeapPage* page = exec_pages_;
- FreeList* freelist = &freelist_[HeapPage::kExecutable];
- MutexLocker ml(freelist->mutex());
+ HeapPage* page = large_pages_;
while (page != NULL) {
HeapPage* next_page = page->next();
- bool page_in_use = sweeper.SweepPage(page, freelist, true /*is_locked*/);
+ const intptr_t words_to_end = sweeper.SweepLargePage(page);
+ if (words_to_end == 0) {
+ FreeLargePage(page, prev_page);
+ } else {
+ TruncateLargePage(page, words_to_end << kWordSizeLog2);
+ prev_page = page;
+ }
+ // Advance to the next page.
+ page = next_page;
+ }
+
+ prev_page = NULL;
+ page = exec_pages_;
+ FreeList* freelist = &freelist_[HeapPage::kExecutable];
+ while (page != NULL) {
+ HeapPage* next_page = page->next();
+ bool page_in_use = sweeper.SweepPage(page, freelist, true);
if (page_in_use) {
prev_page = page;
} else {
@@ -1177,14 +1175,12 @@
}
if (compact) {
- SweepLarge();
Compact(thread);
set_phase(kDone);
} else if (FLAG_concurrent_sweep) {
ConcurrentSweep(isolate);
} else {
- SweepLarge();
- Sweep();
+ BlockingSweep();
set_phase(kDone);
}
@@ -1217,38 +1213,19 @@
}
}
-void PageSpace::SweepLarge() {
- TIMELINE_FUNCTION_GC_DURATION(Thread::Current(), "SweepLarge");
-
- GCSweeper sweeper;
- HeapPage* prev_page = nullptr;
- HeapPage* page = large_pages_;
- while (page != nullptr) {
- HeapPage* next_page = page->next();
- const intptr_t words_to_end = sweeper.SweepLargePage(page);
- if (words_to_end == 0) {
- FreeLargePage(page, prev_page);
- } else {
- TruncateLargePage(page, words_to_end << kWordSizeLog2);
- prev_page = page;
- }
- // Advance to the next page.
- page = next_page;
- }
-}
-
-void PageSpace::Sweep() {
+void PageSpace::BlockingSweep() {
TIMELINE_FUNCTION_GC_DURATION(Thread::Current(), "Sweep");
+ MutexLocker mld(freelist_[HeapPage::kData].mutex());
+ MutexLocker mle(freelist_[HeapPage::kExecutable].mutex());
+
+ // Sweep all regular sized pages now.
GCSweeper sweeper;
- HeapPage* prev_page = nullptr;
+ HeapPage* prev_page = NULL;
HeapPage* page = pages_;
- FreeList* freelist = &freelist_[HeapPage::kData];
- MutexLocker ml(freelist_->mutex());
- while (page != nullptr) {
+ while (page != NULL) {
HeapPage* next_page = page->next();
- ASSERT(page->type() == HeapPage::kData);
- bool page_in_use = sweeper.SweepPage(page, freelist, true /*is_locked*/);
+ bool page_in_use = sweeper.SweepPage(page, &freelist_[page->type()], true);
if (page_in_use) {
prev_page = page;
} else {
@@ -1267,8 +1244,8 @@
void PageSpace::ConcurrentSweep(Isolate* isolate) {
// Start the concurrent sweeper task now.
- GCSweeper::SweepConcurrent(isolate, pages_, pages_tail_, large_pages_,
- large_pages_tail_, &freelist_[HeapPage::kData]);
+ GCSweeper::SweepConcurrent(isolate, pages_, pages_tail_,
+ &freelist_[HeapPage::kData]);
}
void PageSpace::Compact(Thread* thread) {
diff --git a/runtime/vm/heap/pages.h b/runtime/vm/heap/pages.h
index 417e14d..83ca216 100644
--- a/runtime/vm/heap/pages.h
+++ b/runtime/vm/heap/pages.h
@@ -479,19 +479,10 @@
// Makes bump block walkable; do not call concurrently with mutator.
void MakeIterable() const;
-
- void AddPageLocked(HeapPage* page);
- void AddLargePageLocked(HeapPage* page);
- void AddExecPageLocked(HeapPage* page);
- void RemovePageLocked(HeapPage* page, HeapPage* previous_page);
- void RemoveLargePageLocked(HeapPage* page, HeapPage* previous_page);
- void RemoveExecPageLocked(HeapPage* page, HeapPage* previous_page);
-
HeapPage* AllocatePage(HeapPage::PageType type, bool link = true);
- HeapPage* AllocateLargePage(intptr_t size, HeapPage::PageType type);
-
- void TruncateLargePage(HeapPage* page, intptr_t new_object_size_in_bytes);
void FreePage(HeapPage* page, HeapPage* previous_page);
+ HeapPage* AllocateLargePage(intptr_t size, HeapPage::PageType type);
+ void TruncateLargePage(HeapPage* page, intptr_t new_object_size_in_bytes);
void FreeLargePage(HeapPage* page, HeapPage* previous_page);
void FreePages(HeapPage* pages);
@@ -499,8 +490,7 @@
bool finalize,
int64_t pre_wait_for_sweepers,
int64_t pre_safe_point);
- void SweepLarge();
- void Sweep();
+ void BlockingSweep();
void ConcurrentSweep(Isolate* isolate);
void Compact(Thread* thread);
@@ -523,13 +513,12 @@
// Use ExclusivePageIterator for safe access to these.
mutable Mutex pages_lock_;
- HeapPage* pages_ = nullptr;
- HeapPage* pages_tail_ = nullptr;
- HeapPage* exec_pages_ = nullptr;
- HeapPage* exec_pages_tail_ = nullptr;
- HeapPage* large_pages_ = nullptr;
- HeapPage* large_pages_tail_ = nullptr;
- HeapPage* image_pages_ = nullptr;
+ HeapPage* pages_;
+ HeapPage* pages_tail_;
+ HeapPage* exec_pages_;
+ HeapPage* exec_pages_tail_;
+ HeapPage* large_pages_;
+ HeapPage* image_pages_;
// A block of memory in a data page, managed by bump allocation. The remainder
// is kept formatted as a FreeListElement, but is not in any freelist.
diff --git a/runtime/vm/heap/sweeper.cc b/runtime/vm/heap/sweeper.cc
index 2786390..fa294d9 100644
--- a/runtime/vm/heap/sweeper.cc
+++ b/runtime/vm/heap/sweeper.cc
@@ -110,15 +110,11 @@
PageSpace* old_space,
HeapPage* first,
HeapPage* last,
- HeapPage* large_first,
- HeapPage* large_last,
FreeList* freelist)
: task_isolate_(isolate),
old_space_(old_space),
first_(first),
last_(last),
- large_first_(large_first),
- large_last_(large_last),
freelist_(freelist) {
ASSERT(task_isolate_ != NULL);
ASSERT(first_ != NULL);
@@ -136,35 +132,14 @@
ASSERT(result);
{
Thread* thread = Thread::Current();
- ASSERT(thread->BypassSafepoints()); // Or we should be checking in.
TIMELINE_FUNCTION_GC_DURATION(thread, "ConcurrentSweep");
GCSweeper sweeper;
- HeapPage* page = large_first_;
+ HeapPage* page = first_;
HeapPage* prev_page = NULL;
- while (page != NULL) {
- HeapPage* next_page;
- if (page == large_last_) {
- // Don't access page->next(), which would be a race with mutator
- // allocating new pages.
- next_page = NULL;
- } else {
- next_page = page->next();
- }
- ASSERT(page->type() == HeapPage::kData);
- const intptr_t words_to_end = sweeper.SweepLargePage(page);
- if (words_to_end == 0) {
- old_space_->FreeLargePage(page, prev_page);
- } else {
- old_space_->TruncateLargePage(page, words_to_end << kWordSizeLog2);
- prev_page = page;
- }
- page = next_page;
- }
- page = first_;
- prev_page = NULL;
while (page != NULL) {
+ ASSERT(thread->BypassSafepoints()); // Or we should be checking in.
HeapPage* next_page;
if (page == last_) {
// Don't access page->next(), which would be a race with mutator
@@ -206,20 +181,15 @@
PageSpace* old_space_;
HeapPage* first_;
HeapPage* last_;
- HeapPage* large_first_;
- HeapPage* large_last_;
FreeList* freelist_;
};
void GCSweeper::SweepConcurrent(Isolate* isolate,
HeapPage* first,
HeapPage* last,
- HeapPage* large_first,
- HeapPage* large_last,
FreeList* freelist) {
bool result = Dart::thread_pool()->Run<ConcurrentSweeperTask>(
- isolate, isolate->heap()->old_space(), first, last, large_first,
- large_last, freelist);
+ isolate, isolate->heap()->old_space(), first, last, freelist);
ASSERT(result);
}
diff --git a/runtime/vm/heap/sweeper.h b/runtime/vm/heap/sweeper.h
index 068a30d..609b962 100644
--- a/runtime/vm/heap/sweeper.h
+++ b/runtime/vm/heap/sweeper.h
@@ -38,8 +38,6 @@
static void SweepConcurrent(Isolate* isolate,
HeapPage* first,
HeapPage* last,
- HeapPage* large_first,
- HeapPage* large_last,
FreeList* freelist);
};
diff --git a/runtime/vm/kernel_binary.h b/runtime/vm/kernel_binary.h
index d739365..2061521 100644
--- a/runtime/vm/kernel_binary.h
+++ b/runtime/vm/kernel_binary.h
@@ -20,7 +20,7 @@
// Both version numbers are inclusive.
static const uint32_t kMinSupportedKernelFormatVersion = 29;
-static const uint32_t kMaxSupportedKernelFormatVersion = 36;
+static const uint32_t kMaxSupportedKernelFormatVersion = 37;
// Keep in sync with package:kernel/lib/binary/tag.dart
#define KERNEL_TAG_LIST(V) \
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 8564b07..419a241 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -93,6 +93,11 @@
DECLARE_FLAG(bool, precompiled_mode);
DECLARE_FLAG(int, max_polymorphic_checks);
+DEFINE_FLAG(bool,
+ unbox_numeric_fields,
+ true,
+ "Support unboxed double and float32x4 fields.");
+
static const char* const kGetterPrefix = "get:";
static const intptr_t kGetterPrefixLength = strlen(kGetterPrefix);
static const char* const kSetterPrefix = "set:";
@@ -8637,6 +8642,27 @@
}
}
+void Instance::SetField(const Field& field, const Object& value) const {
+ field.RecordStore(value);
+ const Object* stored_value = field.CloneForUnboxed(value);
+ StorePointer(FieldAddr(field), stored_value->raw());
+}
+
+const Object* Field::CloneForUnboxed(const Object& value) const {
+ if (FLAG_unbox_numeric_fields && is_unboxing_candidate() && !is_nullable()) {
+ switch (guarded_cid()) {
+ case kDoubleCid:
+ case kFloat32x4Cid:
+ case kFloat64x2Cid:
+ return &Object::Handle(Object::Clone(value, Heap::kNew));
+ default:
+ // Not a supported unboxed field type.
+ return &value;
+ }
+ }
+ return &value;
+}
+
void Field::SetOriginal(const Field& value) const {
ASSERT(value.IsOriginal());
ASSERT(!value.IsNull());
@@ -8828,7 +8854,7 @@
result.set_end_token_pos(end_token_pos);
result.set_has_nontrivial_initializer(false);
result.set_has_initializer(false);
- result.set_is_unboxing_candidate(!is_final && !is_late);
+ result.set_is_unboxing_candidate(!is_final && !is_late && !is_static);
result.set_initializer_changed_after_initialization(false);
NOT_IN_PRECOMPILED(result.set_is_declared_in_bytecode(false));
NOT_IN_PRECOMPILED(result.set_binary_declaration_offset(0));
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index c36d28c..e0bcdb9 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -3857,6 +3857,10 @@
void set_type_test_cache(const SubtypeTestCache& cache) const;
#endif
+ // Unboxed fields require exclusive ownership of the box.
+ // Ensure this by cloning the box if necessary.
+ const Object* CloneForUnboxed(const Object& value) const;
+
private:
static void InitializeNew(const Field& result,
const String& name,
@@ -5353,18 +5357,6 @@
}
}
- static intptr_t function_entry_point_offset(EntryKind kind) {
- switch (kind) {
- case EntryKind::kNormal:
- return Function::entry_point_offset();
- case EntryKind::kUnchecked:
- return Function::unchecked_entry_point_offset();
- default:
- ASSERT(false && "Invalid entry kind.");
- UNREACHABLE();
- }
- }
-
RawObjectPool* object_pool() const { return raw_ptr()->object_pool_; }
static intptr_t object_pool_offset() {
return OFFSET_OF(RawCode, object_pool_);
@@ -6522,10 +6514,7 @@
RawObject* GetField(const Field& field) const { return *FieldAddr(field); }
- void SetField(const Field& field, const Object& value) const {
- field.RecordStore(value);
- StorePointer(FieldAddr(field), value.raw());
- }
+ void SetField(const Field& field, const Object& value) const;
RawAbstractType* GetType(Heap::Space space) const;
diff --git a/samples/ffi/sample_ffi_functions.dart b/samples/ffi/sample_ffi_functions.dart
index 72db3eb..ed641e9 100644
--- a/samples/ffi/sample_ffi_functions.dart
+++ b/samples/ffi/sample_ffi_functions.dart
@@ -20,6 +20,8 @@
typedef NativeFloatUnaryOp = Float Function(Float);
typedef NativeDecenaryOp = IntPtr Function(IntPtr, IntPtr, IntPtr, IntPtr,
IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr);
+typedef NativeDecenaryOp2 = Int16 Function(
+ Int8, Int16, Int8, Int16, Int8, Int16, Int8, Int16, Int8, Int16);
typedef NativeDoubleDecenaryOp = Double Function(Double, Double, Double, Double,
Double, Double, Double, Double, Double, Double);
typedef NativeVigesimalOp = Double Function(
@@ -150,6 +152,15 @@
}
{
+ // Function with many arguments: arguments get passed in registers and stack.
+ DecenaryOp sumManyInts = ffiTestFunctions
+ .lookupFunction<NativeDecenaryOp2, DecenaryOp>("SumManySmallInts");
+ var result = sumManyInts(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+ print(result);
+ print(result.runtimeType);
+ }
+
+ {
// Function with many double arguments.
DoubleDecenaryOp sumManyDoubles = ffiTestFunctions.lookupFunction<
NativeDoubleDecenaryOp, DoubleDecenaryOp>("SumManyDoubles");
diff --git a/sdk/lib/_internal/js_dev_runtime/libraries.dart b/sdk/lib/_internal/js_dev_runtime/libraries.dart
index 283133c..88b2efa 100644
--- a/sdk/lib/_internal/js_dev_runtime/libraries.dart
+++ b/sdk/lib/_internal/js_dev_runtime/libraries.dart
@@ -91,7 +91,7 @@
maturity: Maturity.STABLE,
platforms: DART2JS_PLATFORM,
dart2jsPatchPath: "_internal/js_runtime/lib/js_patch.dart"),
- "js_util": const LibraryInfo("js_util/dart2js/js_util_dart2js.dart",
+ "js_util": const LibraryInfo("js_util/js_util.dart",
categories: "Client",
maturity: Maturity.STABLE,
platforms: DART2JS_PLATFORM),
diff --git a/sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart b/sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart
index af9ae7d..0d8628d 100644
--- a/sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart
+++ b/sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart
@@ -553,6 +553,12 @@
}
@patch
+ factory List.of(Iterable<E> elements, {bool growable = true}) {
+ // TODO(32937): Specialize to benefit from known element type.
+ return List.from(elements, growable: growable);
+ }
+
+ @patch
factory List.unmodifiable(Iterable elements) {
var list = List<E>.from(elements);
JSArray.markUnmodifiableList(list);
diff --git a/sdk/lib/_internal/js_runtime/lib/core_patch.dart b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
index 2f9c880..5a80b9b 100644
--- a/sdk/lib/_internal/js_runtime/lib/core_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
@@ -441,6 +441,12 @@
}
@patch
+ factory List.of(Iterable<E> elements, {bool growable: true}) {
+ // TODO(32937): Specialize to benefit from known element type.
+ return List.from(elements, growable: growable);
+ }
+
+ @patch
factory List.unmodifiable(Iterable elements) {
List result = new List<E>.from(elements, growable: false);
return makeFixedListUnmodifiable(result);
diff --git a/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart b/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
index d86d322..2975bdc 100644
--- a/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
+++ b/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
@@ -101,7 +101,7 @@
dart2jsPatchPath: "js/_js_client.dart",
documented: false,
platforms: DART2JS_PLATFORM),
- "js_util": const LibraryInfo("js_util/dart2js/js_util_dart2js.dart",
+ "js_util": const LibraryInfo("js_util/js_util.dart",
categories: "Client",
maturity: Maturity.STABLE,
platforms: DART2JS_PLATFORM),
diff --git a/runtime/bin/vmservice/vmservice_io.dart b/sdk/lib/_internal/vm/bin/vmservice_io.dart
similarity index 99%
rename from runtime/bin/vmservice/vmservice_io.dart
rename to sdk/lib/_internal/vm/bin/vmservice_io.dart
index 46fb27e..29fa6db 100644
--- a/runtime/bin/vmservice/vmservice_io.dart
+++ b/sdk/lib/_internal/vm/bin/vmservice_io.dart
@@ -14,7 +14,7 @@
import 'dart:typed_data';
import 'dart:_vmservice';
-part 'server.dart';
+part 'vmservice_server.dart';
// The TCP ip/port that the HTTP server listens on.
@pragma("vm:entry-point")
diff --git a/runtime/bin/vmservice/server.dart b/sdk/lib/_internal/vm/bin/vmservice_server.dart
similarity index 98%
rename from runtime/bin/vmservice/server.dart
rename to sdk/lib/_internal/vm/bin/vmservice_server.dart
index e3388a8a..46ac1e2 100644
--- a/runtime/bin/vmservice/server.dart
+++ b/sdk/lib/_internal/vm/bin/vmservice_server.dart
@@ -379,7 +379,7 @@
'uri': serverAddress.toString(),
};
final file = File.fromUri(Uri.parse(_serviceInfoFilename));
- file.writeAsString(json.encode(serviceInfo));
+ return file.writeAsString(json.encode(serviceInfo));
}
Future startup() async {
@@ -440,7 +440,7 @@
new File(path)..createSync(recursive: true);
}
if (_serviceInfoFilename != null && _serviceInfoFilename.isNotEmpty) {
- _dumpServiceInfoToFile();
+ await _dumpServiceInfoToFile();
}
// Server is up and running.
_notifyServerState(serverAddress.toString());
diff --git a/sdk/lib/_internal/vm/lib/array_patch.dart b/sdk/lib/_internal/vm/lib/array_patch.dart
index 26e6865..fff0490 100644
--- a/sdk/lib/_internal/vm/lib/array_patch.dart
+++ b/sdk/lib/_internal/vm/lib/array_patch.dart
@@ -60,6 +60,12 @@
}
@patch
+ factory List.of(Iterable<E> elements, {bool growable: true}) {
+ // TODO(32937): Specialize to benefit from known element type.
+ return List.from(elements, growable: growable);
+ }
+
+ @patch
factory List.unmodifiable(Iterable elements) {
final result = new List<E>.from(elements, growable: false);
return makeFixedListUnmodifiable(result);
diff --git a/sdk/lib/_internal/vm/lib/mirrors_impl.dart b/sdk/lib/_internal/vm/lib/mirrors_impl.dart
index 8101907..0bad369 100644
--- a/sdk/lib/_internal/vm/lib/mirrors_impl.dart
+++ b/sdk/lib/_internal/vm/lib/mirrors_impl.dart
@@ -14,9 +14,13 @@
String toString() => _msg;
}
-String _n(Symbol symbol) => internal.Symbol.getName(symbol);
+String _n(Symbol symbol) => internal.Symbol.getName(symbol as internal.Symbol);
Symbol _s(String name) {
+ return new internal.Symbol.unvalidated(name);
+}
+
+Symbol _sOpt(String name) {
if (name == null) return null;
return new internal.Symbol.unvalidated(name);
}
@@ -67,6 +71,14 @@
List<dynamic> _metadata(reflectee) native 'DeclarationMirror_metadata';
+List<InstanceMirror> _wrapMetadata(List reflectees) {
+ var mirrors = new List<InstanceMirror>();
+ for (var reflectee in reflectees) {
+ mirrors.add(reflect(reflectee));
+ }
+ return new UnmodifiableListView<InstanceMirror>(mirrors);
+}
+
bool _subtypeTest(Type a, Type b) native 'TypeMirror_subtypeTest';
class _MirrorSystem extends MirrorSystem {
@@ -90,10 +102,9 @@
IsolateMirror _isolate;
IsolateMirror get isolate {
- if (_isolate == null) {
- _isolate = _computeIsolate();
- }
- return _isolate;
+ var i = _isolate;
+ if (i != null) return i;
+ return _isolate = _computeIsolate();
}
static IsolateMirror _computeIsolate() native "MirrorSystem_isolate";
@@ -267,12 +278,12 @@
ClassMirror _type;
ClassMirror get type {
- if (_type == null) {
- // Note it not safe to use reflectee.runtimeType because runtimeType may
- // be overridden.
- _type = reflectType(_computeType(reflectee));
- }
- return _type;
+ var t = _type;
+ if (t != null) return t;
+
+ // Note it not safe to use reflectee.runtimeType because runtimeType may
+ // be overridden.
+ return _type = reflectType(_computeType(reflectee)) as ClassMirror;
}
// LocalInstanceMirrors always reflect local instances
@@ -339,14 +350,13 @@
MethodMirror _function;
MethodMirror get function {
- if (_function == null) {
- _function = _computeFunction(reflectee);
- }
- return _function;
+ var f = _function;
+ if (f != null) return f;
+ return _function = _computeFunction(reflectee);
}
- InstanceMirror apply(List<Object> positionalArguments,
- [Map<Symbol, Object> namedArguments]) {
+ InstanceMirror apply(List positionalArguments,
+ [Map<Symbol, dynamic> namedArguments]) {
return this.invoke(#call, positionalArguments, namedArguments);
}
@@ -385,7 +395,7 @@
this._isTransformedMixinApplication,
this._isGenericDeclaration,
this.isEnum)
- : this._simpleName = _s(simpleName),
+ : this._simpleName = _sOpt(simpleName),
this._reflectedType = reflectedType,
this._instantiator = reflectedType,
super._(reflectee);
@@ -401,26 +411,26 @@
Symbol get simpleName {
// All but anonymous mixin applications have their name set at construction.
- if (_simpleName == null) {
- _simpleName = this._mixinApplicationName;
- }
- return _simpleName;
+ var n = _simpleName;
+ if (n != null) return n;
+
+ return _simpleName = this._mixinApplicationName;
}
Symbol _qualifiedName;
Symbol get qualifiedName {
- if (_qualifiedName == null) {
- _qualifiedName = _computeQualifiedName(owner, simpleName);
- }
- return _qualifiedName;
+ var n = _qualifiedName;
+ if (n != null) return n;
+
+ return _qualifiedName = _computeQualifiedName(owner, simpleName);
}
DeclarationMirror get owner {
- if (_owner == null) {
- var uri = _ClassMirror._libraryUri(_reflectee);
- _owner = currentMirrorSystem().libraries[Uri.parse(uri)];
- }
- return _owner;
+ var o = _owner;
+ if (o != null) return o;
+
+ var uri = _ClassMirror._libraryUri(_reflectee);
+ return _owner = currentMirrorSystem().libraries[Uri.parse(uri)];
}
bool get isPrivate => _n(simpleName).startsWith('_');
@@ -441,8 +451,9 @@
// Object has no superclass.
return null;
}
- _trueSuperclassField = reflectType(supertype);
- _trueSuperclassField._instantiator = _instantiator;
+ var supertypeMirror = reflectType(supertype) as _ClassMirror;
+ supertypeMirror._instantiator = _instantiator;
+ _trueSuperclassField = supertypeMirror;
}
return _trueSuperclassField;
}
@@ -453,108 +464,112 @@
var _superinterfaces;
List<ClassMirror> get superinterfaces {
- if (_superinterfaces == null) {
- var interfaceTypes = isOriginalDeclaration
- ? _nativeInterfaces(_reflectedType)
- : _nativeInterfacesInstantiated(_reflectedType);
- if (_isTransformedMixinApplication) {
- interfaceTypes = interfaceTypes.sublist(0, interfaceTypes.length - 1);
- }
- var interfaceMirrors = new List<ClassMirror>();
- for (var interfaceType in interfaceTypes) {
- interfaceMirrors.add(reflectType(interfaceType));
- }
- _superinterfaces =
- new UnmodifiableListView<ClassMirror>(interfaceMirrors);
+ var i = _superinterfaces;
+ if (i != null) return i;
+
+ var interfaceTypes = isOriginalDeclaration
+ ? _nativeInterfaces(_reflectedType)
+ : _nativeInterfacesInstantiated(_reflectedType);
+ if (_isTransformedMixinApplication) {
+ interfaceTypes = interfaceTypes.sublist(0, interfaceTypes.length - 1);
}
- return _superinterfaces;
+ var interfaceMirrors = new List<ClassMirror>();
+ for (var interfaceType in interfaceTypes) {
+ interfaceMirrors.add(reflectType(interfaceType) as ClassMirror);
+ }
+ return _superinterfaces =
+ new UnmodifiableListView<ClassMirror>(interfaceMirrors);
}
- get _mixinApplicationName {
+ Symbol get _mixinApplicationName {
var mixins = new List<ClassMirror>();
var klass = this;
while (_nativeMixin(klass._reflectedType) != null) {
mixins.add(klass.mixin);
- klass = klass.superclass;
+ klass = klass.superclass as _ClassMirror;
}
return _s(_n(klass.qualifiedName) +
' with ' +
- mixins.reversed.map((m) => _n(m.qualifiedName)).join(', '));
+ mixins.reversed.map((ClassMirror m) => _n(m.qualifiedName)).join(', '));
}
- var _mixin;
+ ClassMirror _mixin;
ClassMirror get mixin {
- if (_mixin == null) {
- Type mixinType = _nativeMixinInstantiated(_reflectedType, _instantiator);
- if (mixinType == null) {
- // The reflectee is not a mixin application.
- _mixin = this;
- } else {
- _mixin = reflectType(mixinType);
- }
+ var m = _mixin;
+ if (m != null) return m;
+
+ Type mixinType = _nativeMixinInstantiated(_reflectedType, _instantiator);
+ if (mixinType == null) {
+ // The reflectee is not a mixin application.
+ return _mixin = this;
+ } else {
+ return _mixin = reflectType(mixinType) as ClassMirror;
}
- return _mixin;
}
var _cachedStaticMembers;
Map<Symbol, MethodMirror> get staticMembers {
- if (_cachedStaticMembers == null) {
- var result = new Map<Symbol, MethodMirror>();
- declarations.values.forEach((decl) {
- if (decl is MethodMirror && decl.isStatic && !decl.isConstructor) {
- result[decl.simpleName] = decl;
+ var m = _cachedStaticMembers;
+ if (m != null) m;
+
+ var result = new Map<Symbol, MethodMirror>();
+ var library = this.owner as LibraryMirror;
+ declarations.values.forEach((decl) {
+ if (decl is MethodMirror && decl.isStatic && !decl.isConstructor) {
+ result[decl.simpleName] = decl;
+ }
+ if (decl is VariableMirror && decl.isStatic) {
+ var getterName = decl.simpleName;
+ result[getterName] =
+ new _SyntheticAccessor(this, getterName, true, true, false, decl);
+ if (!decl.isFinal) {
+ var setterName = _asSetter(decl.simpleName, library);
+ result[setterName] = new _SyntheticAccessor(
+ this, setterName, false, true, false, decl);
}
- if (decl is VariableMirror && decl.isStatic) {
- var getterName = decl.simpleName;
- result[getterName] =
- new _SyntheticAccessor(this, getterName, true, true, false, decl);
- if (!decl.isFinal) {
- var setterName = _asSetter(decl.simpleName, this.owner);
- result[setterName] = new _SyntheticAccessor(
- this, setterName, false, true, false, decl);
- }
- }
- });
- _cachedStaticMembers =
- new UnmodifiableMapView<Symbol, MethodMirror>(result);
- }
- return _cachedStaticMembers;
+ }
+ });
+ return _cachedStaticMembers =
+ new UnmodifiableMapView<Symbol, MethodMirror>(result);
}
var _cachedInstanceMembers;
Map<Symbol, MethodMirror> get instanceMembers {
- if (_cachedInstanceMembers == null) {
- var result = new Map<Symbol, MethodMirror>();
- if (superclass != null) {
- result.addAll(superclass.instanceMembers);
- }
- declarations.values.forEach((decl) {
- if (decl is MethodMirror &&
- !decl.isStatic &&
- !decl.isConstructor &&
- !decl.isAbstract) {
- result[decl.simpleName] = decl;
- }
- if (decl is VariableMirror && !decl.isStatic) {
- var getterName = decl.simpleName;
- result[getterName] = new _SyntheticAccessor(
- this, getterName, true, false, false, decl);
- if (!decl.isFinal) {
- var setterName = _asSetter(decl.simpleName, this.owner);
- result[setterName] = new _SyntheticAccessor(
- this, setterName, false, false, false, decl);
- }
- }
- });
- _cachedInstanceMembers =
- new UnmodifiableMapView<Symbol, MethodMirror>(result);
+ var m = _cachedInstanceMembers;
+ if (m != null) return m;
+
+ var result = new Map<Symbol, MethodMirror>();
+ var library = this.owner as LibraryMirror;
+ var sup = superclass;
+ if (sup != null) {
+ result.addAll(sup.instanceMembers);
}
- return _cachedInstanceMembers;
+ declarations.values.forEach((decl) {
+ if (decl is MethodMirror &&
+ !decl.isStatic &&
+ !decl.isConstructor &&
+ !decl.isAbstract) {
+ result[decl.simpleName] = decl;
+ }
+ if (decl is VariableMirror && !decl.isStatic) {
+ var getterName = decl.simpleName;
+ result[getterName] =
+ new _SyntheticAccessor(this, getterName, true, false, false, decl);
+ if (!decl.isFinal) {
+ var setterName = _asSetter(decl.simpleName, library);
+ result[setterName] = new _SyntheticAccessor(
+ this, setterName, false, false, false, decl);
+ }
+ }
+ });
+ return _cachedInstanceMembers =
+ new UnmodifiableMapView<Symbol, MethodMirror>(result);
}
Map<Symbol, DeclarationMirror> _declarations;
Map<Symbol, DeclarationMirror> get declarations {
- if (_declarations != null) return _declarations;
+ var d = _declarations;
+ if (d != null) return d;
var decls = new Map<Symbol, DeclarationMirror>();
@@ -586,37 +601,37 @@
List<TypeVariableMirror> _typeVariables;
List<TypeVariableMirror> get typeVariables {
- if (_typeVariables == null) {
- if (!_isTransformedMixinApplication && _isAnonymousMixinApplication) {
- return _typeVariables = const <TypeVariableMirror>[];
- }
- _typeVariables = new List<TypeVariableMirror>();
+ var v = _typeVariables;
+ if (v != null) return v;
- List params = _ClassMirror_type_variables(_reflectee);
- ClassMirror owner = originalDeclaration;
- var mirror;
- for (var i = 0; i < params.length; i += 2) {
- mirror = new _TypeVariableMirror._(params[i + 1], params[i], owner);
- _typeVariables.add(mirror);
- }
- _typeVariables =
- new UnmodifiableListView<TypeVariableMirror>(_typeVariables);
+ if (!_isTransformedMixinApplication && _isAnonymousMixinApplication) {
+ return _typeVariables = const <TypeVariableMirror>[];
}
- return _typeVariables;
+ var result = new List<TypeVariableMirror>();
+
+ List params = _ClassMirror_type_variables(_reflectee);
+ ClassMirror owner = originalDeclaration;
+ var mirror;
+ for (var i = 0; i < params.length; i += 2) {
+ mirror = new _TypeVariableMirror._(params[i + 1], params[i], owner);
+ result.add(mirror);
+ }
+ return _typeVariables =
+ new UnmodifiableListView<TypeVariableMirror>(result);
}
List<TypeMirror> _typeArguments;
List<TypeMirror> get typeArguments {
- if (_typeArguments == null) {
- if (_isGenericDeclaration ||
- (!_isTransformedMixinApplication && _isAnonymousMixinApplication)) {
- _typeArguments = const <TypeMirror>[];
- } else {
- _typeArguments = new UnmodifiableListView<TypeMirror>(
- _computeTypeArguments(_reflectedType).cast<TypeMirror>());
- }
+ var a = _typeArguments;
+ if (a != null) return a;
+
+ if (_isGenericDeclaration ||
+ (!_isTransformedMixinApplication && _isAnonymousMixinApplication)) {
+ return _typeArguments = const <TypeMirror>[];
+ } else {
+ return _typeArguments = new UnmodifiableListView<TypeMirror>(
+ _computeTypeArguments(_reflectedType).cast<TypeMirror>());
}
- return _typeArguments;
}
bool get isOriginalDeclaration => !_isGeneric || _isGenericDeclaration;
@@ -655,10 +670,7 @@
}
List<InstanceMirror> get metadata {
- // Get the metadata objects, convert them into InstanceMirrors using
- // reflect() and then make them into a Dart list.
- return new UnmodifiableListView<InstanceMirror>(
- _metadata(_reflectee).map(reflect));
+ return _wrapMetadata(_metadata(_reflectee));
}
bool operator ==(other) {
@@ -686,12 +698,12 @@
bool isSubclassOf(ClassMirror other) {
if (other is! ClassMirror) throw new ArgumentError(other);
- ClassMirror otherDeclaration = other.originalDeclaration;
+ ClassMirror otherDeclaration = other.originalDeclaration as ClassMirror;
ClassMirror c = this;
while (c != null) {
- c = c.originalDeclaration;
+ c = c.originalDeclaration as ClassMirror;
if (c == otherDeclaration) return true;
- c = c.superclass;
+ c = c.superclass as ClassMirror;
}
return false;
}
@@ -748,45 +760,41 @@
// FunctionTypeMirrors have a simpleName generated from their signature.
Symbol _simpleName;
Symbol get simpleName {
- if (_simpleName == null) {
- _simpleName = _s(_makeSignatureString(returnType, parameters));
- }
- return _simpleName;
+ var n = _simpleName;
+ if (n != null) return n;
+ return _simpleName = _s(_makeSignatureString(returnType, parameters));
}
MethodMirror _callMethod;
MethodMirror get callMethod {
- if (_callMethod == null) {
- _callMethod = _FunctionTypeMirror_call_method(_functionReflectee);
- }
- return _callMethod;
+ var m = _callMethod;
+ if (m != null) return m;
+ return _callMethod = _FunctionTypeMirror_call_method(_functionReflectee);
}
TypeMirror _returnType;
TypeMirror get returnType {
- if (_returnType == null) {
- _returnType =
- reflectType(_FunctionTypeMirror_return_type(_functionReflectee));
- }
- return _returnType;
+ var t = _returnType;
+ if (t != null) return t;
+ return _returnType =
+ reflectType(_FunctionTypeMirror_return_type(_functionReflectee));
}
List<ParameterMirror> _parameters;
List<ParameterMirror> get parameters {
- if (_parameters == null) {
- _parameters = _FunctionTypeMirror_parameters(_functionReflectee)
- .cast<ParameterMirror>();
- _parameters = new UnmodifiableListView<ParameterMirror>(_parameters);
- }
- return _parameters;
+ var p = _parameters;
+ if (p != null) return p;
+ return _parameters = new UnmodifiableListView<ParameterMirror>(
+ _FunctionTypeMirror_parameters(_functionReflectee)
+ .cast<ParameterMirror>());
}
bool get isOriginalDeclaration => true;
ClassMirror get originalDeclaration => this;
- get typeVariables => const <TypeVariableMirror>[];
- get typeArguments => const <TypeMirror>[];
- get metadata => const <InstanceMirror>[];
- get location => null;
+ List<TypeVariableMirror> get typeVariables => const <TypeVariableMirror>[];
+ List<TypeMirror> get typeArguments => const <TypeMirror>[];
+ List<InstanceMirror> get metadata => const <InstanceMirror>[];
+ SourceLocation get location => null;
String toString() => "FunctionTypeMirror on '${_n(simpleName)}'";
@@ -810,10 +818,9 @@
Symbol _qualifiedName;
Symbol get qualifiedName {
- if (_qualifiedName == null) {
- _qualifiedName = _computeQualifiedName(owner, simpleName);
- }
- return _qualifiedName;
+ var n = _qualifiedName;
+ if (n != null) return n;
+ return _qualifiedName = _computeQualifiedName(owner, simpleName);
}
bool get isPrivate => _n(simpleName).startsWith('_');
@@ -823,10 +830,7 @@
}
List<InstanceMirror> get metadata {
- // Get the metadata objects, convert them into InstanceMirrors using
- // reflect() and then make them into a Dart list.
- return new UnmodifiableListView<InstanceMirror>(
- _metadata(_reflectee).map(reflect));
+ return _wrapMetadata(_metadata(_reflectee));
}
bool operator ==(other) {
@@ -844,11 +848,10 @@
DeclarationMirror _owner;
DeclarationMirror get owner {
- if (_owner == null) {
- _owner = (_TypeVariableMirror_owner(_reflectee) as TypeMirror)
- .originalDeclaration;
- }
- return _owner;
+ var o = _owner;
+ if (o != null) return o;
+ return _owner = (_TypeVariableMirror_owner(_reflectee) as TypeMirror)
+ .originalDeclaration;
}
bool get isStatic => false;
@@ -856,10 +859,10 @@
TypeMirror _upperBound;
TypeMirror get upperBound {
- if (_upperBound == null) {
- _upperBound = reflectType(_TypeVariableMirror_upper_bound(_reflectee));
- }
- return _upperBound;
+ var b = _upperBound;
+ if (b != null) return b;
+ return _upperBound =
+ reflectType(_TypeVariableMirror_upper_bound(_reflectee));
}
bool get hasReflectedType => false;
@@ -877,7 +880,7 @@
String toString() => "TypeVariableMirror on '${_n(simpleName)}'";
- operator ==(other) {
+ bool operator ==(other) {
return other is TypeVariableMirror &&
simpleName == other.simpleName &&
owner == other.owner;
@@ -920,20 +923,19 @@
DeclarationMirror _owner;
DeclarationMirror get owner {
- if (_owner == null) {
- var uri = _ClassMirror._libraryUri(_reflectee);
- _owner = currentMirrorSystem().libraries[Uri.parse(uri)];
- }
- return _owner;
+ var o = _owner;
+ if (o != null) return o;
+ var uri = _ClassMirror._libraryUri(_reflectee);
+ return _owner = currentMirrorSystem().libraries[Uri.parse(uri)];
}
_FunctionTypeMirror _referent;
FunctionTypeMirror get referent {
- if (_referent == null) {
- _referent = _nativeReferent(_reflectedType);
- _referent._instantiator = _reflectedType;
- }
- return _referent;
+ var r = _referent;
+ if (r != null) return r;
+ var result = _nativeReferent(_reflectedType) as _FunctionTypeMirror;
+ result._instantiator = _reflectedType;
+ return _referent = result;
}
bool get hasReflectedType => !_isGenericDeclaration;
@@ -957,31 +959,33 @@
List<TypeVariableMirror> _typeVariables;
List<TypeVariableMirror> get typeVariables {
- if (_typeVariables == null) {
- _typeVariables = new List<TypeVariableMirror>();
- List params = _ClassMirror._ClassMirror_type_variables(_reflectee);
- TypedefMirror owner = originalDeclaration;
- var mirror;
- for (var i = 0; i < params.length; i += 2) {
- mirror = new _TypeVariableMirror._(params[i + 1], params[i], owner);
- _typeVariables.add(mirror);
- }
+ var v = _typeVariables;
+ if (v != null) return v;
+
+ var result = new List<TypeVariableMirror>();
+ List params = _ClassMirror._ClassMirror_type_variables(_reflectee);
+ TypedefMirror owner = originalDeclaration;
+ var mirror;
+ for (var i = 0; i < params.length; i += 2) {
+ mirror = new _TypeVariableMirror._(params[i + 1], params[i], owner);
+ result.add(mirror);
}
- return _typeVariables;
+ return _typeVariables =
+ new UnmodifiableListView<TypeVariableMirror>(result);
}
List<TypeMirror> _typeArguments;
List<TypeMirror> get typeArguments {
- if (_typeArguments == null) {
- if (_isGenericDeclaration) {
- _typeArguments = const <TypeMirror>[];
- } else {
- _typeArguments = new UnmodifiableListView<TypeMirror>(
- _ClassMirror._computeTypeArguments(_reflectedType)
- .cast<TypeMirror>());
- }
+ var a = _typeArguments;
+ if (a != null) return a;
+
+ if (_isGenericDeclaration) {
+ return _typeArguments = const <TypeMirror>[];
+ } else {
+ return _typeArguments = new UnmodifiableListView<TypeMirror>(
+ _ClassMirror._computeTypeArguments(_reflectedType)
+ .cast<TypeMirror>());
}
- return _typeArguments;
}
String toString() => "TypedefMirror on '${_n(simpleName)}'";
@@ -1033,7 +1037,8 @@
Map<Symbol, DeclarationMirror> _declarations;
Map<Symbol, DeclarationMirror> get declarations {
- if (_declarations != null) return _declarations;
+ var d = _declarations;
+ if (d != null) return d;
var decls = new Map<Symbol, DeclarationMirror>();
var members = _computeMembers(_reflectee);
@@ -1050,10 +1055,7 @@
}
List<InstanceMirror> get metadata {
- // Get the metadata objects, convert them into InstanceMirrors using
- // reflect() and then make them into a Dart list.
- return new UnmodifiableListView<InstanceMirror>(
- _metadata(_reflectee).map(reflect));
+ return _wrapMetadata(_metadata(_reflectee));
}
bool operator ==(other) {
@@ -1067,12 +1069,11 @@
var _cachedLibraryDependencies;
get libraryDependencies {
- if (_cachedLibraryDependencies == null) {
- _cachedLibraryDependencies =
- new UnmodifiableListView<LibraryDependencyMirror>(
- _libraryDependencies(_reflectee).cast<LibraryDependencyMirror>());
- }
- return _cachedLibraryDependencies;
+ var d = _cachedLibraryDependencies;
+ if (d != null) return d;
+ return _cachedLibraryDependencies =
+ new UnmodifiableListView<LibraryDependencyMirror>(
+ _libraryDependencies(_reflectee).cast<LibraryDependencyMirror>());
}
List<dynamic> _libraryDependencies(reflectee)
@@ -1107,11 +1108,10 @@
this.isImport,
this.isDeferred,
List<dynamic> unwrappedMetadata)
- : prefix = _s(prefixString),
+ : prefix = _sOpt(prefixString),
combinators = new UnmodifiableListView<CombinatorMirror>(
mutableCombinators.cast<CombinatorMirror>()),
- metadata = new UnmodifiableListView<InstanceMirror>(
- unwrappedMetadata.map(reflect));
+ metadata = _wrapMetadata(unwrappedMetadata);
bool get isExport => !isImport;
@@ -1200,10 +1200,9 @@
DeclarationMirror get owner {
// For nested closures it is possible, that the mirror for the owner has not
// been created yet.
- if (_owner == null) {
- _owner = _MethodMirror_owner(_reflectee, _instantiator);
- }
- return _owner;
+ var o = _owner;
+ if (o != null) return o;
+ return _owner = _MethodMirror_owner(_reflectee, _instantiator);
}
bool get isPrivate =>
@@ -1213,48 +1212,47 @@
TypeMirror _returnType;
TypeMirror get returnType {
- if (_returnType == null) {
- if (isConstructor) {
- _returnType = owner;
- } else {
- _returnType =
- reflectType(_MethodMirror_return_type(_reflectee, _instantiator));
- }
+ var t = _returnType;
+ if (t != null) return t;
+ if (isConstructor) {
+ return _returnType = owner as _ClassMirror;
+ } else {
+ return _returnType =
+ reflectType(_MethodMirror_return_type(_reflectee, _instantiator));
}
- return _returnType;
}
List<ParameterMirror> _parameters;
List<ParameterMirror> get parameters {
- if (_parameters == null) {
- _parameters = new UnmodifiableListView<ParameterMirror>(
- _MethodMirror_parameters(_reflectee).cast<ParameterMirror>());
- }
- return _parameters;
+ var p = _parameters;
+ if (p != null) return p;
+ return _parameters = new UnmodifiableListView<ParameterMirror>(
+ _MethodMirror_parameters(_reflectee).cast<ParameterMirror>());
}
bool get isRegularMethod => !isGetter && !isSetter && !isConstructor;
Symbol _constructorName;
Symbol get constructorName {
- if (_constructorName == null) {
- if (!isConstructor) {
- _constructorName = _s('');
+ var n = _constructorName;
+ if (n != null) return n;
+
+ if (!isConstructor) {
+ return _constructorName = _s('');
+ } else {
+ var parts = MirrorSystem.getName(simpleName).split('.');
+ if (parts.length > 2) {
+ throw new _InternalMirrorError(
+ 'Internal error in MethodMirror.constructorName: '
+ 'malformed name <$simpleName>');
+ } else if (parts.length == 2) {
+ LibraryMirror definingLibrary = owner.owner as _LibraryMirror;
+ return _constructorName =
+ MirrorSystem.getSymbol(parts[1], definingLibrary);
} else {
- var parts = MirrorSystem.getName(simpleName).split('.');
- if (parts.length > 2) {
- throw new _InternalMirrorError(
- 'Internal error in MethodMirror.constructorName: '
- 'malformed name <$simpleName>');
- } else if (parts.length == 2) {
- LibraryMirror definingLibrary = owner.owner;
- _constructorName = MirrorSystem.getSymbol(parts[1], definingLibrary);
- } else {
- _constructorName = _s('');
- }
+ return _constructorName = _s('');
}
}
- return _constructorName;
}
String get source => _MethodMirror_source(_reflectee);
@@ -1310,10 +1308,9 @@
TypeMirror _type;
TypeMirror get type {
- if (_type == null) {
- _type = reflectType(_VariableMirror_type(_reflectee, _instantiator));
- }
- return _type;
+ var t = _type;
+ if (t != null) return t;
+ return _type = reflectType(_VariableMirror_type(_reflectee, _instantiator));
}
String toString() =>
@@ -1369,18 +1366,17 @@
}
List<InstanceMirror> get metadata {
- if (_unmirroredMetadata == null) return const <InstanceMirror>[];
- return new UnmodifiableListView<InstanceMirror>(
- _unmirroredMetadata.map(reflect));
+ var m = _unmirroredMetadata;
+ if (m == null) return const <InstanceMirror>[];
+ return _wrapMetadata(m);
}
TypeMirror _type;
TypeMirror get type {
- if (_type == null) {
- _type = reflectType(
- _ParameterMirror_type(_reflectee, _position, _instantiator));
- }
- return _type;
+ var t = _type;
+ if (t != null) return t;
+ return _type = reflectType(
+ _ParameterMirror_type(_reflectee, _position, _instantiator));
}
String toString() => "ParameterMirror on '${_n(simpleName)}'";
@@ -1450,7 +1446,7 @@
: new _InstanceMirror._(reflectee);
}
- static ClassMirror _makeLocalClassMirror(Type key)
+ static _ClassMirror _makeLocalClassMirror(Type key)
native "Mirrors_makeLocalClassMirror";
static TypeMirror _makeLocalTypeMirror(Type key)
native "Mirrors_makeLocalTypeMirror";
diff --git a/sdk/lib/_internal/vm/lib/mirrors_patch.dart b/sdk/lib/_internal/vm/lib/mirrors_patch.dart
index 1adbcbb..299ff50 100644
--- a/sdk/lib/_internal/vm/lib/mirrors_patch.dart
+++ b/sdk/lib/_internal/vm/lib/mirrors_patch.dart
@@ -75,7 +75,7 @@
@patch
static String getName(Symbol symbol) {
- return internal.Symbol.computeUnmangledName(symbol);
+ return internal.Symbol.computeUnmangledName(symbol as internal.Symbol);
}
@patch
diff --git a/sdk/lib/core/list.dart b/sdk/lib/core/list.dart
index 9500c56..647f277 100644
--- a/sdk/lib/core/list.dart
+++ b/sdk/lib/core/list.dart
@@ -139,8 +139,7 @@
* This constructor creates a growable list when [growable] is true;
* otherwise, it returns a fixed-length list.
*/
- factory List.of(Iterable<E> elements, {bool growable = true}) =>
- List<E>.from(elements, growable: growable);
+ external factory List.of(Iterable<E> elements, {bool growable = true});
/**
* Generates a list of values.
@@ -729,5 +728,5 @@
* Even if [other] is also a list, the equality comparison
* does not compare the elements of the two lists.
*/
- bool operator ==(Object other);
+ bool operator ==(Object other);
}
diff --git a/sdk_nnbd/lib/js_util/dart2js/js_util_dart2js.dart b/sdk/lib/js_util/js_util.dart
similarity index 96%
rename from sdk_nnbd/lib/js_util/dart2js/js_util_dart2js.dart
rename to sdk/lib/js_util/js_util.dart
index a01a537..7718644 100644
--- a/sdk_nnbd/lib/js_util/dart2js/js_util_dart2js.dart
+++ b/sdk/lib/js_util/js_util.dart
@@ -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.
-// @dart = 2.5
+// @dart = 2.6
/// Utility methods to efficiently manipulate typed JSInterop objects in cases
/// where the name to call is not known at runtime. You should only use these
@@ -30,13 +30,13 @@
/// JavaScript type, and all other objects are proxied.
jsify(object) {
if ((object is! Map) && (object is! Iterable)) {
- throw new ArgumentError("object must be a Map or Iterable");
+ throw ArgumentError("object must be a Map or Iterable");
}
return _convertDataTree(object);
}
_convertDataTree(data) {
- var _convertedObjects = new HashMap.identity();
+ var _convertedObjects = HashMap.identity();
_convert(o) {
if (_convertedObjects.containsKey(o)) {
@@ -65,13 +65,16 @@
newObject() => JS('=Object', '{}');
bool hasProperty(o, name) => JS('bool', '# in #', name, o);
+
getProperty(o, name) => JS('Object|Null', '#[#]', o, name);
+
setProperty(o, name, value) => JS('', '#[#]=#', o, name, value);
callMethod(o, String method, List args) =>
JS('Object|Null', '#[#].apply(#, #)', o, method, o, args);
bool instanceof(o, Function type) => JS('bool', '# instanceof #', o, type);
+
callConstructor(Function constr, List arguments) {
if (arguments == null) {
return JS('Object', 'new #()', constr);
diff --git a/sdk/lib/js_util/js_util_sources.gni b/sdk/lib/js_util/js_util_sources.gni
index 3b7c1b1..ad6a4f0 100644
--- a/sdk/lib/js_util/js_util_sources.gni
+++ b/sdk/lib/js_util/js_util_sources.gni
@@ -2,4 +2,4 @@
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
-js_util_sdk_sources = [ "dart2js/js_util_dart2js.dart" ]
+js_util_sdk_sources = [ "js_util.dart", "dart2js/js_util_dart2js.dart" ]
diff --git a/sdk/lib/libraries.json b/sdk/lib/libraries.json
index f31091f..1241331 100644
--- a/sdk/lib/libraries.json
+++ b/sdk/lib/libraries.json
@@ -154,7 +154,7 @@
"uri": "vmservice/vmservice.dart"
},
"vmservice_io": {
- "uri": "../../runtime/bin/vmservice/vmservice_io.dart"
+ "uri": "_internal/vm/bin/vmservice_io.dart"
}
}
},
@@ -211,7 +211,7 @@
"patches": "js/_js_client.dart"
},
"js_util": {
- "uri": "js_util/dart2js/js_util_dart2js.dart"
+ "uri": "js_util/js_util.dart"
},
"math": {
"uri": "math/math.dart",
@@ -321,7 +321,7 @@
"patches": "js/_js_server.dart"
},
"js_util": {
- "uri": "js_util/dart2js/js_util_dart2js.dart"
+ "uri": "js_util/js_util.dart"
},
"math": {
"uri": "math/math.dart",
@@ -468,7 +468,7 @@
"patches": "_internal/js_dev_runtime/patch/js_patch.dart"
},
"js_util": {
- "uri": "_internal/js_dev_runtime/lib/js_util/dart2js/js_util_dart2js.dart"
+ "uri": "js_util/js_util.dart"
},
"svg": {
"uri": "svg/dart2js/svg_dart2js.dart"
diff --git a/sdk/lib/libraries.yaml b/sdk/lib/libraries.yaml
index d4a3d8b..191c2c3 100644
--- a/sdk/lib/libraries.yaml
+++ b/sdk/lib/libraries.yaml
@@ -153,7 +153,7 @@
uri: "vmservice/vmservice.dart"
vmservice_io:
- uri: "../../runtime/bin/vmservice/vmservice_io.dart"
+ uri: "_internal/vm/bin/vmservice_io.dart"
dart2js:
libraries:
@@ -208,7 +208,7 @@
patches: "js/_js_client.dart"
js_util:
- uri: "js_util/dart2js/js_util_dart2js.dart"
+ uri: "js_util/js_util.dart"
math:
uri: "math/math.dart"
@@ -316,7 +316,7 @@
patches: "js/_js_server.dart"
js_util:
- uri: "js_util/dart2js/js_util_dart2js.dart"
+ uri: "js_util/js_util.dart"
math:
uri: "math/math.dart"
@@ -461,7 +461,7 @@
patches: "_internal/js_dev_runtime/patch/js_patch.dart"
js_util:
- uri: "_internal/js_dev_runtime/lib/js_util/dart2js/js_util_dart2js.dart"
+ uri: "js_util/js_util.dart"
svg:
uri: "svg/dart2js/svg_dart2js.dart"
diff --git a/sdk/lib/vmservice_libraries.json b/sdk/lib/vmservice_libraries.json
index c25ffe5..af43f48 100644
--- a/sdk/lib/vmservice_libraries.json
+++ b/sdk/lib/vmservice_libraries.json
@@ -2,11 +2,11 @@
"vm": {
"libraries": {
"vmservice_io": {
- "uri": "../../runtime/bin/vmservice/vmservice_io.dart"
+ "uri": "_internal/vm/bin/vmservice_io.dart"
},
"_vmservice": {
"uri": "vmservice/vmservice.dart"
}
}
}
-}
\ No newline at end of file
+}
diff --git a/sdk/lib/vmservice_libraries.yaml b/sdk/lib/vmservice_libraries.yaml
index 737e361..169d6af 100644
--- a/sdk/lib/vmservice_libraries.yaml
+++ b/sdk/lib/vmservice_libraries.yaml
@@ -17,4 +17,4 @@
uri: "vmservice/vmservice.dart"
vmservice_io:
- uri: "../../runtime/bin/vmservice/vmservice_io.dart"
+ uri: "_internal/vm/bin/vmservice_io.dart"
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/lib/js_util/dart2js/js_util_dart2js.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/lib/js_util/dart2js/js_util_dart2js.dart
deleted file mode 100644
index 1cccbaa..0000000
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/lib/js_util/dart2js/js_util_dart2js.dart
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// @dart = 2.5
-
-/// Utility methods to efficiently manipulate typed JSInterop objects in cases
-/// where the name to call is not known at runtime. You should only use these
-/// methods when the same effect cannot be achieved with @JS annotations.
-/// These methods would be extension methods on JSObject if Dart supported
-/// extension methods.
-library dart.js_util;
-
-import 'dart:_foreign_helper' show JS;
-import 'dart:collection' show HashMap;
-import 'dart:async' show Completer;
-import 'dart:_js_helper' show convertDartClosureToJS;
-
-/// WARNING: performance of this method is much worse than other uitil
-/// methods in this library. Only use this method as a last resort.
-///
-/// Recursively converts a JSON-like collection of Dart objects to a
-/// collection of JavaScript objects and returns a [JsObject] proxy to it.
-///
-/// [object] must be a [Map] or [Iterable], the contents of which are also
-/// converted. Maps and Iterables are copied to a new JavaScript object.
-/// Primitives and other transferrable values are directly converted to their
-/// JavaScript type, and all other objects are proxied.
-jsify(object) {
- if ((object is! Map) && (object is! Iterable)) {
- throw ArgumentError("object must be a Map or Iterable");
- }
- return _convertDataTree(object);
-}
-
-_convertDataTree(data) {
- var _convertedObjects = HashMap.identity();
-
- _convert(o) {
- if (_convertedObjects.containsKey(o)) {
- return _convertedObjects[o];
- }
- if (o is Map) {
- final convertedMap = JS('=Object', '{}');
- _convertedObjects[o] = convertedMap;
- for (var key in o.keys) {
- JS('=Object', '#[#]=#', convertedMap, key, _convert(o[key]));
- }
- return convertedMap;
- } else if (o is Iterable) {
- var convertedList = [];
- _convertedObjects[o] = convertedList;
- convertedList.addAll(o.map(_convert));
- return convertedList;
- } else {
- return o;
- }
- }
-
- return _convert(data);
-}
-
-newObject() => JS('=Object', '{}');
-
-hasProperty(o, name) => JS<bool>('!', '# in #', name, o);
-getProperty(o, name) => JS('Object', '#[#]', o, name);
-setProperty(o, name, value) => JS('', '#[#]=#', o, name, value);
-
-callMethod(o, String method, List args) =>
- JS('Object', '#[#].apply(#, #)', o, method, o, args);
-
-instanceof(o, Function type) => JS<bool>('!', '# instanceof #', o, type);
-callConstructor(Function constr, List arguments) {
- if (arguments == null) {
- return JS('Object', 'new #()', constr);
- }
-
- if (JS<bool>('!', '# instanceof Array', arguments)) {
- int argumentCount = JS('!', '#.length', arguments);
- switch (argumentCount) {
- case 0:
- return JS('Object', 'new #()', constr);
-
- case 1:
- var arg0 = JS('', '#[0]', arguments);
- return JS('Object', 'new #(#)', constr, arg0);
-
- case 2:
- var arg0 = JS('', '#[0]', arguments);
- var arg1 = JS('', '#[1]', arguments);
- return JS('Object', 'new #(#, #)', constr, arg0, arg1);
-
- case 3:
- var arg0 = JS('', '#[0]', arguments);
- var arg1 = JS('', '#[1]', arguments);
- var arg2 = JS('', '#[2]', arguments);
- return JS('Object', 'new #(#, #, #)', constr, arg0, arg1, arg2);
-
- case 4:
- var arg0 = JS('', '#[0]', arguments);
- var arg1 = JS('', '#[1]', arguments);
- var arg2 = JS('', '#[2]', arguments);
- var arg3 = JS('', '#[3]', arguments);
- return JS(
- 'Object', 'new #(#, #, #, #)', constr, arg0, arg1, arg2, arg3);
- }
- }
-
- // The following code solves the problem of invoking a JavaScript
- // constructor with an unknown number arguments.
- // First bind the constructor to the argument list using bind.apply().
- // The first argument to bind() is the binding of 't', so add 'null' to
- // the arguments list passed to apply().
- // After that, use the JavaScript 'new' operator which overrides any binding
- // of 'this' with the new instance.
- var args = <dynamic>[null]..addAll(arguments);
- var factoryFunction = JS('', '#.bind.apply(#, #)', constr, constr, args);
- // Without this line, calling factoryFunction as a constructor throws
- JS<String>('!', 'String(#)', factoryFunction);
- // This could return an UnknownJavaScriptObject, or a native
- // object for which there is an interceptor
- return JS('Object', 'new #()', factoryFunction);
-
- // TODO(sra): Investigate:
- //
- // var jsObj = JS('', 'Object.create(#.prototype)', constr);
- // JS('', '#.apply(#, #)', constr, jsObj,
- // []..addAll(arguments.map(_convertToJS)));
- // return _wrapToDart(jsObj);
-}
-
-/// Converts a JavaScript Promise to a Dart [Future].
-///
-/// ```dart
-/// @JS()
-/// external Promise<num> get threePromise; // Resolves to 3
-///
-/// final Future<num> threeFuture = promiseToFuture(threePromise);
-///
-/// final three = await threeFuture; // == 3
-/// ```
-Future<T> promiseToFuture<T>(jsPromise) {
- final completer = Completer<T>();
-
- final success = convertDartClosureToJS((r) => completer.complete(r), 1);
- final error = convertDartClosureToJS((e) => completer.completeError(e), 1);
-
- JS('', '#.then(#, #)', jsPromise, success, error);
- return completer.future;
-}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/core_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/core_patch.dart
index 1f1c981..9121353 100644
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/core_patch.dart
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/core_patch.dart
@@ -555,6 +555,12 @@
}
@patch
+ factory List.of(Iterable<E> elements, {bool growable = true}) {
+ // TODO(32937): Specialize to benefit from known element type.
+ return List.from(elements, growable: growable);
+ }
+
+ @patch
factory List.unmodifiable(Iterable elements) {
var list = List<E>.from(elements);
JSArray.markUnmodifiableList(list);
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/mirrors_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/mirrors_patch.dart
index 9aca3ee..b018b3f 100644
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/mirrors_patch.dart
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/mirrors_patch.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.5
-
// Patch library for dart:mirrors.
import 'dart:_js_helper' show patch;
@@ -46,7 +44,7 @@
}
@patch
-TypeMirror reflectType(Type type, [List<Type> typeArguments]) {
+TypeMirror reflectType(Type type, [List<Type> typeArguments = const <Type>[]]) {
if (typeArguments != null) {
type = _instantiateClass(type, typeArguments);
}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
index edde391..9161304 100644
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
@@ -1494,7 +1494,7 @@
}
}
for (var name in supertypeRequiredNamed.keys) {
- var subtypeParamType = subtypeRequiredNamed[name] ?? subtypeNamed[name];
+ var subtypeParamType = subtypeRequiredNamed[name] ?? subtypeNamed[name]!;
if (!_isSubtypeMatch(supertypeRequiredNamed[name]!, subtypeParamType)) {
return false;
}
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_mirrors.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_mirrors.dart
index 42db17d..4d66e7d 100644
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_mirrors.dart
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_mirrors.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.5
-
library dart._js_mirrors;
import 'dart:mirrors';
@@ -37,7 +35,7 @@
}
}
-TypeMirror reflectType(Type key) {
+TypeMirror reflectType(Type key, [List<Type> typeArguments = const <Type>[]]) {
var unwrapped = dart.unwrapType(key);
var property =
JS('', 'Object.getOwnPropertyDescriptor(#, #)', unwrapped, _typeMirror);
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/mirror_helper.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/mirror_helper.dart
index 96d2da9..1b78136 100644
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/private/mirror_helper.dart
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/mirror_helper.dart
@@ -1,7 +1,6 @@
// 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.
-// @dart = 2.5
/**
* Helps dealing with reflection in the case that the source code has been
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/core_patch.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/core_patch.dart
index ce924cd..cc6e81e 100644
--- a/sdk_nnbd/lib/_internal/js_runtime/lib/core_patch.dart
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/core_patch.dart
@@ -441,6 +441,12 @@
}
@patch
+ factory List.of(Iterable<E> elements, {bool growable: true}) {
+ // TODO(32937): Specialize to benefit from known element type.
+ return List.from(elements, growable: growable);
+ }
+
+ @patch
factory List.unmodifiable(Iterable elements) {
List result = new List<E>.from(elements, growable: false);
return makeFixedListUnmodifiable(result);
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/mirrors_patch_cfe.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/mirrors_patch_cfe.dart
index 005b14f..40490a3 100644
--- a/sdk_nnbd/lib/_internal/js_runtime/lib/mirrors_patch_cfe.dart
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/mirrors_patch_cfe.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.5
-
// Patch library for dart:mirrors.
import 'dart:_js_helper' show patch;
@@ -22,5 +20,5 @@
ClassMirror reflectClass(Type key) => throw new UnsupportedError(_message);
@patch
-TypeMirror reflectType(Type key, [List<Type> typeArguments]) =>
+TypeMirror reflectType(Type key, [List<Type> typeArguments = const <Type>[]]) =>
throw new UnsupportedError(_message);
diff --git a/sdk_nnbd/lib/_internal/sdk_library_metadata/lib/libraries.dart b/sdk_nnbd/lib/_internal/sdk_library_metadata/lib/libraries.dart
index b8e584b..2b3e33c 100644
--- a/sdk_nnbd/lib/_internal/sdk_library_metadata/lib/libraries.dart
+++ b/sdk_nnbd/lib/_internal/sdk_library_metadata/lib/libraries.dart
@@ -101,7 +101,7 @@
dart2jsPatchPath: "js/_js_client.dart",
documented: false,
platforms: DART2JS_PLATFORM),
- "js_util": const LibraryInfo("js_util/dart2js/js_util_dart2js.dart",
+ "js_util": const LibraryInfo("js_util/js_util.dart",
categories: "Client",
maturity: Maturity.STABLE,
platforms: DART2JS_PLATFORM),
diff --git a/runtime/bin/vmservice/vmservice_io.dart b/sdk_nnbd/lib/_internal/vm/bin/vmservice_io.dart
similarity index 73%
copy from runtime/bin/vmservice/vmservice_io.dart
copy to sdk_nnbd/lib/_internal/vm/bin/vmservice_io.dart
index 46fb27e..6ab703d 100644
--- a/runtime/bin/vmservice/vmservice_io.dart
+++ b/sdk_nnbd/lib/_internal/vm/bin/vmservice_io.dart
@@ -2,58 +2,55 @@
// for 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.6
-
library vmservice_io;
import 'dart:async';
-import 'dart:collection';
import 'dart:convert';
import 'dart:io';
-import 'dart:isolate';
-import 'dart:typed_data';
import 'dart:_vmservice';
-part 'server.dart';
+part 'vmservice_server.dart';
// The TCP ip/port that the HTTP server listens on.
@pragma("vm:entry-point")
-int _port;
+int _port = 0;
@pragma("vm:entry-point")
-String _ip;
+String _ip = '';
// Should the HTTP server auto start?
@pragma("vm:entry-point")
-bool _autoStart;
+bool _autoStart = false;
// Should the HTTP server require an auth code?
@pragma("vm:entry-point")
-bool _authCodesDisabled;
+bool _authCodesDisabled = false;
// Should the HTTP server run in devmode?
@pragma("vm:entry-point")
-bool _originCheckDisabled;
+bool _originCheckDisabled = false;
// Location of file to output VM service connection info.
@pragma("vm:entry-point")
-String _serviceInfoFilename;
+String? _serviceInfoFilename;
@pragma("vm:entry-point")
bool _isWindows = false;
@pragma("vm:entry-point")
bool _isFuchsia = false;
@pragma("vm:entry-point")
-var _signalWatch;
+var _signalWatch = null;
var _signalSubscription;
// HTTP server.
-Server server;
-Future<Server> serverFuture;
+Server? server;
+Future<Server>? serverFuture;
-_lazyServerBoot() {
+Server _lazyServerBoot() {
if (server != null) {
- return;
+ return server!;
}
// Lazily create service.
- var service = new VMService();
+ var service = VMService();
// Lazily create server.
- server = new Server(service, _ip, _port, _originCheckDisabled,
+ final _server = Server(service, _ip, _port, _originCheckDisabled,
_authCodesDisabled, _serviceInfoFilename);
+ server = _server;
+ return _server;
}
Future cleanupCallback() async {
@@ -64,13 +61,13 @@
}
if (server != null) {
try {
- await server.cleanup(true);
+ await server!.cleanup(true);
} catch (e, st) {
print("Error in vm-service shutdown: $e\n$st\n");
}
}
if (_registerSignalHandlerTimer != null) {
- _registerSignalHandlerTimer.cancel();
+ _registerSignalHandlerTimer!.cancel();
_registerSignalHandlerTimer = null;
}
// Call out to embedder's shutdown callback.
@@ -81,37 +78,37 @@
Directory temp = await Directory.systemTemp.createTemp(base);
// Underneath the temporary directory, create a directory with the
// same name as the DevFS name [base].
- var fsUri = temp.uri.resolveUri(new Uri.directory(base));
- await new Directory.fromUri(fsUri).create();
+ var fsUri = temp.uri.resolveUri(Uri.directory(base));
+ await Directory.fromUri(fsUri).create();
return fsUri;
}
Future deleteDirCallback(Uri path) async {
- Directory dir = new Directory.fromUri(path);
+ Directory dir = Directory.fromUri(path);
await dir.delete(recursive: true);
}
class PendingWrite {
PendingWrite(this.uri, this.bytes);
- final Completer completer = new Completer();
+ final Completer completer = Completer();
final Uri uri;
final List<int> bytes;
Future write() async {
- var file = new File.fromUri(uri);
+ var file = File.fromUri(uri);
var parent_directory = file.parent;
await parent_directory.create(recursive: true);
if (await file.exists()) {
await file.delete();
}
- var result = await file.writeAsBytes(bytes);
+ await file.writeAsBytes(bytes);
completer.complete(null);
WriteLimiter._writeCompleted();
}
}
class WriteLimiter {
- static final List<PendingWrite> pendingWrites = new List<PendingWrite>();
+ static final List<PendingWrite> pendingWrites = <PendingWrite>[];
// non-rooted Android devices have a very low limit for the number of
// open files. Artificially cap ourselves to 16.
@@ -120,7 +117,7 @@
static Future scheduleWrite(Uri path, List<int> bytes) async {
// Create a new pending write.
- PendingWrite pw = new PendingWrite(path, bytes);
+ PendingWrite pw = PendingWrite(path, bytes);
pendingWrites.add(pw);
_maybeWriteFiles();
return pw.completer.future;
@@ -149,8 +146,8 @@
return WriteLimiter.scheduleWrite(path, bytes);
}
-Future writeStreamFileCallback(Uri path, Stream<List<int>> bytes) async {
- var file = new File.fromUri(path);
+Future<void> writeStreamFileCallback(Uri path, Stream<List<int>> bytes) async {
+ var file = File.fromUri(path);
var parent_directory = file.parent;
await parent_directory.create(recursive: true);
if (await file.exists()) {
@@ -162,19 +159,19 @@
}
Future<List<int>> readFileCallback(Uri path) async {
- var file = new File.fromUri(path);
+ var file = File.fromUri(path);
return await file.readAsBytes();
}
Future<List<Map<String, dynamic>>> listFilesCallback(Uri dirPath) async {
- var dir = new Directory.fromUri(dirPath);
+ var dir = Directory.fromUri(dirPath);
var dirPathStr = dirPath.path;
var stream = dir.list(recursive: true);
var result = <Map<String, dynamic>>[];
await for (var fileEntity in stream) {
- var filePath = new Uri.file(fileEntity.path).path;
+ var filePath = Uri.file(fileEntity.path).path;
var stat = await fileEntity.stat();
- if (stat.type == FileSystemEntityType.FILE &&
+ if (stat.type == FileSystemEntityType.file &&
filePath.startsWith(dirPathStr)) {
var map = <String, dynamic>{};
map['name'] = '/' + filePath.substring(dirPathStr.length);
@@ -186,28 +183,22 @@
return result;
}
-Future<Uri> serverInformationCallback() async {
- _lazyServerBoot();
- return server.serverAddress;
-}
+Future<Uri> serverInformationCallback() async =>
+ await _lazyServerBoot().serverAddress!;
Future<Uri> webServerControlCallback(bool enable) async {
- _lazyServerBoot();
- if (server.running == enable) {
- // No change.
- return server.serverAddress;
+ final _server = _lazyServerBoot();
+ if (_server.running != enable) {
+ if (enable) {
+ await _server.startup();
+ } else {
+ await _server.shutdown(true);
+ }
}
-
- if (enable) {
- await server.startup();
- return server.serverAddress;
- } else {
- await server.shutdown(true);
- return server.serverAddress;
- }
+ return _server.serverAddress!;
}
-Null _clearFuture(_) {
+void _clearFuture(_) {
serverFuture = null;
}
@@ -216,16 +207,16 @@
// Still waiting.
return;
}
- _lazyServerBoot();
+ final _server = _lazyServerBoot();
// Toggle HTTP server.
- if (server.running) {
- serverFuture = server.shutdown(true).then(_clearFuture);
+ if (_server.running) {
+ _server.shutdown(true).then(_clearFuture);
} else {
- serverFuture = server.startup().then(_clearFuture);
+ _server.startup().then(_clearFuture);
}
}
-Timer _registerSignalHandlerTimer;
+Timer? _registerSignalHandlerTimer;
_registerSignalHandler() {
_registerSignalHandlerTimer = null;
@@ -237,7 +228,7 @@
// Cannot register for signals on Windows or Fuchsia.
return;
}
- _signalSubscription = _signalWatch(ProcessSignal.SIGQUIT).listen(_onSignal);
+ _signalSubscription = _signalWatch(ProcessSignal.sigquit).listen(_onSignal);
}
@pragma("vm:entry-point", !const bool.fromEnvironment("dart.vm.product"))
@@ -254,17 +245,17 @@
VMServiceEmbedderHooks.webServerControl = webServerControlCallback;
// Always instantiate the vmservice object so that the exit message
// can be delivered and waiting loaders can be cancelled.
- new VMService();
+ VMService();
if (_autoStart) {
- _lazyServerBoot();
- server.startup();
+ final _server = _lazyServerBoot();
+ _server.startup();
// It's just here to push an event on the event loop so that we invoke the
// scheduled microtasks.
Timer.run(() {});
}
// Register signal handler after a small delay to avoid stalling main
// isolate startup.
- _registerSignalHandlerTimer = new Timer(shortDelay, _registerSignalHandler);
+ _registerSignalHandlerTimer = Timer(shortDelay, _registerSignalHandler);
}
_shutdown() native "VMServiceIO_Shutdown";
diff --git a/runtime/bin/vmservice/server.dart b/sdk_nnbd/lib/_internal/vm/bin/vmservice_server.dart
similarity index 82%
copy from runtime/bin/vmservice/server.dart
copy to sdk_nnbd/lib/_internal/vm/bin/vmservice_server.dart
index e3388a8a..d94fc54 100644
--- a/runtime/bin/vmservice/server.dart
+++ b/sdk_nnbd/lib/_internal/vm/bin/vmservice_server.dart
@@ -2,11 +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.6
-
part of vmservice_io;
-final bool silentObservatory = new bool.fromEnvironment('SILENT_OBSERVATORY');
+final bool silentObservatory = bool.fromEnvironment('SILENT_OBSERVATORY');
void serverPrint(String s) {
if (silentObservatory) {
@@ -17,10 +15,10 @@
}
class WebSocketClient extends Client {
- static const int PARSE_ERROR_CODE = 4000;
- static const int BINARY_MESSAGE_ERROR_CODE = 4001;
- static const int NOT_MAP_ERROR_CODE = 4002;
- static const int ID_ERROR_CODE = 4003;
+ static const int parseErrorCode = 4000;
+ static const int binaryMessageErrorCode = 4001;
+ static const int notMapErrorCode = 4002;
+ static const int idErrorCode = 4003;
final WebSocket socket;
WebSocketClient(this.socket, VMService service) : super(service) {
@@ -40,15 +38,15 @@
try {
map = json.decode(message);
} catch (e) {
- socket.close(PARSE_ERROR_CODE, 'Message parse error: $e');
+ socket.close(parseErrorCode, 'Message parse error: $e');
return;
}
if (map is! Map) {
- socket.close(NOT_MAP_ERROR_CODE, 'Message must be a JSON map.');
+ socket.close(notMapErrorCode, 'Message must be a JSON map.');
return;
}
try {
- final rpc = new Message.fromJsonRpc(this, map);
+ final rpc = Message.fromJsonRpc(this, map);
switch (rpc.type) {
case MessageType.Request:
onRequest(rpc);
@@ -61,18 +59,14 @@
break;
}
} catch (e) {
- socket.close(ID_ERROR_CODE, e.message);
+ socket.close(idErrorCode, e.message);
}
} else {
- socket.close(BINARY_MESSAGE_ERROR_CODE, 'Message must be a string.');
+ socket.close(binaryMessageErrorCode, 'Message must be a string.');
}
}
void post(Response result) {
- if (result == null) {
- // Do nothing.
- return;
- }
try {
switch (result.kind) {
case ResponsePayloadKind.String:
@@ -89,17 +83,16 @@
}
}
- dynamic toJson() {
- Map map = super.toJson();
- map['type'] = 'WebSocketClient';
- map['socket'] = '$socket';
- return map;
- }
+ Map toJson() => {
+ ...super.toJson(),
+ 'type': 'WebSocketClient',
+ 'socket': '$socket',
+ };
}
class HttpRequestClient extends Client {
static ContentType jsonContentType =
- new ContentType("application", "json", charset: "utf-8");
+ ContentType("application", "json", charset: "utf-8");
final HttpRequest request;
HttpRequestClient(this.request, VMService service)
@@ -111,10 +104,6 @@
}
void post(Response result) {
- if (result == null) {
- close();
- return;
- }
HttpResponse response = request.response;
// We closed the connection for bad origins earlier.
response.headers.add('Access-Control-Allow-Origin', '*');
@@ -150,19 +139,20 @@
final int _port;
final bool _originCheckDisabled;
final bool _authCodesDisabled;
- final String _serviceInfoFilename;
- HttpServer _server;
+ final String? _serviceInfoFilename;
+ HttpServer? _server;
bool get running => _server != null;
/// Returns the server address including the auth token.
- Uri get serverAddress {
+ Uri? get serverAddress {
if (!running) {
return null;
}
- var ip = _server.address.address;
- var port = _server.port;
+ final server = _server!;
+ var ip = server.address.address;
+ var port = server.port;
var path = !_authCodesDisabled ? "$serviceAuthToken/" : "/";
- return new Uri(scheme: 'http', host: ip, port: port, path: path);
+ return Uri(scheme: 'http', host: ip, port: port, path: path);
}
// On Fuchsia, authentication codes are disabled by default. To enable, the authentication token
@@ -187,9 +177,10 @@
return true;
}
- if ((uri.port == _server.port) &&
- ((uri.host == _server.address.address) ||
- (uri.host == _server.address.host))) {
+ final server = _server!;
+ if ((uri.port == server.port) &&
+ ((uri.host == server.address.address) ||
+ (uri.host == server.address.host))) {
return true;
}
@@ -202,7 +193,7 @@
return true;
}
// First check the web-socket specific origin.
- List<String> origins = request.headers["Sec-WebSocket-Origin"];
+ List<String>? origins = request.headers["Sec-WebSocket-Origin"];
if (origins == null) {
// Fall back to the general Origin field.
origins = request.headers["Origin"];
@@ -268,15 +259,15 @@
List fsNameList;
List fsPathList;
- List fsPathBase64List;
- List fsUriBase64List;
- Object fsName;
- Object fsPath;
- Object fsUri;
+ List? fsPathBase64List;
+ List? fsUriBase64List;
+ Object? fsName;
+ Object? fsPath;
+ Uri? fsUri;
try {
// Extract the fs name and fs path from the request headers.
- fsNameList = request.headers['dev_fs_name'];
+ fsNameList = request.headers['dev_fs_name']!;
fsName = fsNameList[0];
// Prefer Uri encoding first.
@@ -288,7 +279,7 @@
// Fallback to path encoding.
if (fsUri == null) {
- fsPathList = request.headers['dev_fs_path'];
+ fsPathList = request.headers['dev_fs_path']!;
fsPathBase64List = request.headers['dev_fs_path_b64'];
// If the 'dev_fs_path_b64' header field was sent, use that instead.
if ((fsPathBase64List != null) && (fsPathBase64List.length > 0)) {
@@ -302,7 +293,7 @@
String result;
try {
result = await _service.devfs.handlePutStream(fsName, fsPath, fsUri,
- request.cast<List<int>>().transform(GZIP.decoder));
+ request.cast<List<int>>().transform(gzip.decoder));
} catch (e) {
request.response.statusCode = HttpStatus.internalServerError;
request.response.write(e);
@@ -338,7 +329,7 @@
// The URI contains the valid auth token but is missing a trailing '/'.
// Redirect to the same URI with the trailing '/' to correctly serve
// index.html.
- request.response.redirect(result as Uri);
+ request.response.redirect(result);
request.response.close();
return;
}
@@ -348,18 +339,18 @@
WebSocketTransformer.upgrade(request,
compression: CompressionOptions.compressionOff)
.then((WebSocket webSocket) {
- new WebSocketClient(webSocket, _service);
+ WebSocketClient(webSocket, _service);
});
return;
}
if (assets == null) {
- request.response.headers.contentType = ContentType.TEXT;
+ request.response.headers.contentType = ContentType.text;
request.response.write("This VM was built without the Observatory UI.");
request.response.close();
return;
}
- Asset asset = assets[path];
+ Asset? asset = assets[path];
if (asset != null) {
// Serving up a static asset (e.g. .css, .html, .png).
request.response.headers.contentType = ContentType.parse(asset.mimeType);
@@ -368,8 +359,8 @@
return;
}
// HTTP based service request.
- final client = new HttpRequestClient(request, _service);
- final message = new Message.fromUri(
+ final client = HttpRequestClient(request, _service);
+ final message = Message.fromUri(
client, Uri(path: path, queryParameters: request.uri.queryParameters));
client.onRequest(message); // exception free, no need to try catch
}
@@ -379,7 +370,7 @@
'uri': serverAddress.toString(),
};
final file = File.fromUri(Uri.parse(_serviceInfoFilename));
- file.writeAsString(json.encode(serviceInfo));
+ return file.writeAsString(json.encode(serviceInfo));
}
Future startup() async {
@@ -398,7 +389,7 @@
// Prefer IPv4 addresses.
for (var i = 0; i < addresses.length; i++) {
address = addresses[i];
- if (address.type == InternetAddressType.IP_V4) break;
+ if (address.type == InternetAddressType.IPv4) break;
}
_server = await HttpServer.bind(address, _port);
return true;
@@ -422,7 +413,7 @@
onServerAddressChange(null);
return this;
}
- await new Future<Null>.delayed(const Duration(seconds: 1));
+ await Future<void>.delayed(const Duration(seconds: 1));
}
if (_service.isExiting) {
serverPrint('Observatory HTTP server exiting before listening as '
@@ -430,17 +421,18 @@
await shutdown(true);
return this;
}
- _server.listen(_requestHandler, cancelOnError: true);
+ final server = _server!;
+ server.listen(_requestHandler, cancelOnError: true);
serverPrint('Observatory listening on $serverAddress');
if (Platform.isFuchsia) {
// Create a file with the port number.
String tmp = Directory.systemTemp.path;
- String path = "$tmp/dart.services/${_server.port}";
+ String path = "$tmp/dart.services/${server.port}";
serverPrint("Creating $path");
- new File(path)..createSync(recursive: true);
+ File(path)..createSync(recursive: true);
}
if (_serviceInfoFilename != null && _serviceInfoFilename.isNotEmpty) {
- _dumpServiceInfoToFile();
+ await _dumpServiceInfoToFile();
}
// Server is up and running.
_notifyServerState(serverAddress.toString());
@@ -448,28 +440,29 @@
return this;
}
- Future cleanup(bool force) {
+ Future<void> cleanup(bool force) {
if (_server == null) {
- return new Future.value(null);
+ return Future.value();
}
+ final server = _server!;
if (Platform.isFuchsia) {
// Remove the file with the port number.
String tmp = Directory.systemTemp.path;
- String path = "$tmp/dart.services/${_server.port}";
+ String path = "$tmp/dart.services/${server.port}";
serverPrint("Deleting $path");
- new File(path)..deleteSync();
+ File(path)..deleteSync();
}
- return _server.close(force: force);
+ return server.close(force: force);
}
Future shutdown(bool forced) {
if (_server == null) {
// Not started.
- return new Future.value(this);
+ return Future.value(this);
}
// Shutdown HTTP server and subscription.
- Uri oldServerAddress = serverAddress;
+ Uri oldServerAddress = serverAddress!;
return cleanup(forced).then((_) {
serverPrint('Observatory no longer listening on $oldServerAddress');
_server = null;
diff --git a/sdk_nnbd/lib/_internal/vm/lib/array_patch.dart b/sdk_nnbd/lib/_internal/vm/lib/array_patch.dart
index f19d3a8..6ad5297 100644
--- a/sdk_nnbd/lib/_internal/vm/lib/array_patch.dart
+++ b/sdk_nnbd/lib/_internal/vm/lib/array_patch.dart
@@ -63,6 +63,12 @@
}
@patch
+ factory List.of(Iterable<E> elements, {bool growable: true}) {
+ // TODO(32937): Specialize to benefit from known element type.
+ return List.from(elements, growable: growable);
+ }
+
+ @patch
factory List.unmodifiable(Iterable elements) {
final result = new List<E>.from(elements, growable: false);
return makeFixedListUnmodifiable(result);
diff --git a/sdk_nnbd/lib/_internal/vm/lib/mirrors_impl.dart b/sdk_nnbd/lib/_internal/vm/lib/mirrors_impl.dart
index b0231b2..9cf6af2 100644
--- a/sdk_nnbd/lib/_internal/vm/lib/mirrors_impl.dart
+++ b/sdk_nnbd/lib/_internal/vm/lib/mirrors_impl.dart
@@ -12,14 +12,18 @@
String toString() => _msg;
}
-String _n(Symbol symbol) => internal.Symbol.getName(symbol);
+String _n(Symbol symbol) => internal.Symbol.getName(symbol as internal.Symbol);
Symbol _s(String name) {
+ return new internal.Symbol.unvalidated(name);
+}
+
+Symbol? _sOpt(String? name) {
if (name == null) return null;
return new internal.Symbol.unvalidated(name);
}
-Symbol _computeQualifiedName(DeclarationMirror owner, Symbol simpleName) {
+Symbol _computeQualifiedName(DeclarationMirror? owner, Symbol simpleName) {
if (owner == null) return simpleName;
return _s('${_n(owner.qualifiedName)}.${_n(simpleName)}');
}
@@ -61,10 +65,18 @@
return buf.toString();
}
-SourceLocation _location(reflectee) native "DeclarationMirror_location";
+SourceLocation? _location(reflectee) native "DeclarationMirror_location";
List<dynamic> _metadata(reflectee) native 'DeclarationMirror_metadata';
+List<InstanceMirror> _wrapMetadata(List reflectees) {
+ var mirrors = new List<InstanceMirror>();
+ for (var reflectee in reflectees) {
+ mirrors.add(reflect(reflectee));
+ }
+ return new UnmodifiableListView<InstanceMirror>(mirrors);
+}
+
bool _subtypeTest(Type a, Type b) native 'TypeMirror_subtypeTest';
class _MirrorSystem extends MirrorSystem {
@@ -86,12 +98,11 @@
static List<dynamic> _computeLibraries() native "MirrorSystem_libraries";
- IsolateMirror _isolate;
+ IsolateMirror? _isolate;
IsolateMirror get isolate {
- if (_isolate == null) {
- _isolate = _computeIsolate();
- }
- return _isolate;
+ var i = _isolate;
+ if (i != null) return i;
+ return _isolate = _computeIsolate();
}
static IsolateMirror _computeIsolate() native "MirrorSystem_isolate";
@@ -172,9 +183,9 @@
<ParameterMirror>[new _SyntheticSetterParameter(this, this._target)]);
}
- SourceLocation get location => null;
+ SourceLocation? get location => null;
List<InstanceMirror> get metadata => const <InstanceMirror>[];
- String get source => null;
+ String? get source => null;
}
class _SyntheticSetterParameter implements ParameterMirror {
@@ -196,8 +207,8 @@
bool get isPrivate => false;
bool get isExtensionMember => false;
bool get hasDefaultValue => false;
- InstanceMirror get defaultValue => null;
- SourceLocation get location => null;
+ InstanceMirror? get defaultValue => null;
+ SourceLocation? get location => null;
List<InstanceMirror> get metadata => const <InstanceMirror>[];
}
@@ -211,9 +222,9 @@
_ObjectMirror._(this._reflectee);
InstanceMirror invoke(Symbol memberName, List positionalArguments,
- [Map<Symbol, dynamic> namedArguments]) {
+ [Map<Symbol, dynamic> namedArguments = const <Symbol, dynamic>{}]) {
int numPositionalArguments = positionalArguments.length;
- int numNamedArguments = namedArguments != null ? namedArguments.length : 0;
+ int numNamedArguments = namedArguments.length;
int numArguments = numPositionalArguments + numNamedArguments;
List arguments = new List(numArguments);
arguments.setRange(0, numPositionalArguments, positionalArguments);
@@ -263,14 +274,14 @@
class _InstanceMirror extends _ObjectMirror implements InstanceMirror {
_InstanceMirror._(reflectee) : super._(reflectee);
- ClassMirror _type;
+ ClassMirror? _type;
ClassMirror get type {
- if (_type == null) {
- // Note it not safe to use reflectee.runtimeType because runtimeType may
- // be overridden.
- _type = reflectType(_computeType(reflectee));
- }
- return _type;
+ var t = _type;
+ if (t != null) return t;
+
+ // Note it not safe to use reflectee.runtimeType because runtimeType may
+ // be overridden.
+ return _type = reflectType(_computeType(reflectee)) as ClassMirror;
}
// LocalInstanceMirrors always reflect local instances
@@ -301,9 +312,9 @@
// Override to include the receiver in the arguments.
InstanceMirror invoke(Symbol memberName, List positionalArguments,
- [Map<Symbol, dynamic> namedArguments]) {
+ [Map<Symbol, dynamic> namedArguments = const <Symbol, dynamic>{}]) {
int numPositionalArguments = positionalArguments.length + 1; // Receiver.
- int numNamedArguments = namedArguments != null ? namedArguments.length : 0;
+ int numNamedArguments = namedArguments.length;
int numArguments = numPositionalArguments + numNamedArguments;
List arguments = new List(numArguments);
arguments[0] = _reflectee; // Receiver.
@@ -335,16 +346,15 @@
class _ClosureMirror extends _InstanceMirror implements ClosureMirror {
_ClosureMirror._(reflectee) : super._(reflectee);
- MethodMirror _function;
+ MethodMirror? _function;
MethodMirror get function {
- if (_function == null) {
- _function = _computeFunction(reflectee);
- }
- return _function;
+ var f = _function;
+ if (f != null) return f;
+ return _function = _computeFunction(reflectee);
}
- InstanceMirror apply(List<Object> positionalArguments,
- [Map<Symbol, Object> namedArguments]) {
+ InstanceMirror apply(List positionalArguments,
+ [Map<Symbol, dynamic> namedArguments = const <Symbol, dynamic>{}]) {
return this.invoke(#call, positionalArguments, namedArguments);
}
@@ -359,8 +369,8 @@
class _ClassMirror extends _ObjectMirror implements ClassMirror, _TypeMirror {
final Type _reflectedType;
- Symbol _simpleName;
- DeclarationMirror _owner;
+ Symbol? _simpleName;
+ DeclarationMirror? _owner;
final bool isAbstract;
final bool _isGeneric;
@@ -376,14 +386,14 @@
_ClassMirror._(
reflectee,
reflectedType,
- String simpleName,
+ String? simpleName,
this._owner,
this.isAbstract,
this._isGeneric,
this._isTransformedMixinApplication,
this._isGenericDeclaration,
this.isEnum)
- : this._simpleName = _s(simpleName),
+ : this._simpleName = _sOpt(simpleName),
this._reflectedType = reflectedType,
this._instantiator = reflectedType,
super._(reflectee);
@@ -399,38 +409,38 @@
Symbol get simpleName {
// All but anonymous mixin applications have their name set at construction.
- if (_simpleName == null) {
- _simpleName = this._mixinApplicationName;
- }
- return _simpleName;
+ var n = _simpleName;
+ if (n != null) return n;
+
+ return _simpleName = this._mixinApplicationName;
}
- Symbol _qualifiedName;
+ Symbol? _qualifiedName;
Symbol get qualifiedName {
- if (_qualifiedName == null) {
- _qualifiedName = _computeQualifiedName(owner, simpleName);
- }
- return _qualifiedName;
+ var n = _qualifiedName;
+ if (n != null) return n;
+
+ return _qualifiedName = _computeQualifiedName(owner, simpleName);
}
DeclarationMirror get owner {
- if (_owner == null) {
- var uri = _ClassMirror._libraryUri(_reflectee);
- _owner = currentMirrorSystem().libraries[Uri.parse(uri)];
- }
- return _owner;
+ var o = _owner;
+ if (o != null) return o;
+
+ var uri = _ClassMirror._libraryUri(_reflectee);
+ return _owner = currentMirrorSystem().libraries[Uri.parse(uri)];
}
bool get isPrivate => _n(simpleName).startsWith('_');
bool get isTopLevel => true;
- SourceLocation get location {
+ SourceLocation? get location {
return _location(_reflectee);
}
- _ClassMirror _trueSuperclassField;
- _ClassMirror get _trueSuperclass {
+ _ClassMirror? _trueSuperclassField;
+ _ClassMirror? get _trueSuperclass {
if (_trueSuperclassField == null) {
Type supertype = isOriginalDeclaration
? _supertype(_reflectedType)
@@ -439,120 +449,125 @@
// Object has no superclass.
return null;
}
- _trueSuperclassField = reflectType(supertype);
- _trueSuperclassField._instantiator = _instantiator;
+ var supertypeMirror = reflectType(supertype) as _ClassMirror;
+ supertypeMirror._instantiator = _instantiator;
+ _trueSuperclassField = supertypeMirror;
}
return _trueSuperclassField;
}
- ClassMirror get superclass {
+ ClassMirror? get superclass {
return _trueSuperclass;
}
var _superinterfaces;
List<ClassMirror> get superinterfaces {
- if (_superinterfaces == null) {
- var interfaceTypes = isOriginalDeclaration
- ? _nativeInterfaces(_reflectedType)
- : _nativeInterfacesInstantiated(_reflectedType);
- if (_isTransformedMixinApplication) {
- interfaceTypes = interfaceTypes.sublist(0, interfaceTypes.length - 1);
- }
- var interfaceMirrors = new List<ClassMirror>();
- for (var interfaceType in interfaceTypes) {
- interfaceMirrors.add(reflectType(interfaceType));
- }
- _superinterfaces =
- new UnmodifiableListView<ClassMirror>(interfaceMirrors);
+ var i = _superinterfaces;
+ if (i != null) return i;
+
+ var interfaceTypes = isOriginalDeclaration
+ ? _nativeInterfaces(_reflectedType)
+ : _nativeInterfacesInstantiated(_reflectedType);
+ if (_isTransformedMixinApplication) {
+ interfaceTypes = interfaceTypes.sublist(0, interfaceTypes.length - 1);
}
- return _superinterfaces;
+ var interfaceMirrors = new List<ClassMirror>();
+ for (var interfaceType in interfaceTypes) {
+ interfaceMirrors.add(reflectType(interfaceType) as ClassMirror);
+ }
+ return _superinterfaces =
+ new UnmodifiableListView<ClassMirror>(interfaceMirrors);
}
- get _mixinApplicationName {
+ Symbol get _mixinApplicationName {
var mixins = new List<ClassMirror>();
var klass = this;
while (_nativeMixin(klass._reflectedType) != null) {
mixins.add(klass.mixin);
- klass = klass.superclass;
+ klass = klass.superclass as _ClassMirror;
}
return _s(_n(klass.qualifiedName) +
' with ' +
- mixins.reversed.map((m) => _n(m.qualifiedName)).join(', '));
+ mixins.reversed.map((ClassMirror m) => _n(m.qualifiedName)).join(', '));
}
- var _mixin;
+ ClassMirror? _mixin;
ClassMirror get mixin {
- if (_mixin == null) {
- Type mixinType = _nativeMixinInstantiated(_reflectedType, _instantiator);
- if (mixinType == null) {
- // The reflectee is not a mixin application.
- _mixin = this;
- } else {
- _mixin = reflectType(mixinType);
- }
+ var m = _mixin;
+ if (m != null) return m;
+
+ Type mixinType = _nativeMixinInstantiated(_reflectedType, _instantiator);
+ if (mixinType == null) {
+ // The reflectee is not a mixin application.
+ return _mixin = this;
+ } else {
+ return _mixin = reflectType(mixinType) as ClassMirror;
}
- return _mixin;
}
var _cachedStaticMembers;
Map<Symbol, MethodMirror> get staticMembers {
- if (_cachedStaticMembers == null) {
- var result = new Map<Symbol, MethodMirror>();
- declarations.values.forEach((decl) {
- if (decl is MethodMirror && decl.isStatic && !decl.isConstructor) {
- result[decl.simpleName] = decl;
+ var m = _cachedStaticMembers;
+ if (m != null) m;
+
+ var result = new Map<Symbol, MethodMirror>();
+ var library = this.owner as LibraryMirror;
+ declarations.values.forEach((decl) {
+ if (decl is MethodMirror && decl.isStatic && !decl.isConstructor) {
+ result[decl.simpleName] = decl;
+ }
+ if (decl is VariableMirror && decl.isStatic) {
+ var getterName = decl.simpleName;
+ result[getterName] =
+ new _SyntheticAccessor(this, getterName, true, true, false, decl);
+ if (!decl.isFinal) {
+ var setterName = _asSetter(decl.simpleName, library);
+ result[setterName] = new _SyntheticAccessor(
+ this, setterName, false, true, false, decl);
}
- if (decl is VariableMirror && decl.isStatic) {
- var getterName = decl.simpleName;
- result[getterName] =
- new _SyntheticAccessor(this, getterName, true, true, false, decl);
- if (!decl.isFinal) {
- var setterName = _asSetter(decl.simpleName, this.owner);
- result[setterName] = new _SyntheticAccessor(
- this, setterName, false, true, false, decl);
- }
- }
- });
- _cachedStaticMembers =
- new UnmodifiableMapView<Symbol, MethodMirror>(result);
- }
- return _cachedStaticMembers;
+ }
+ });
+ return _cachedStaticMembers =
+ new UnmodifiableMapView<Symbol, MethodMirror>(result);
}
var _cachedInstanceMembers;
Map<Symbol, MethodMirror> get instanceMembers {
- if (_cachedInstanceMembers == null) {
- var result = new Map<Symbol, MethodMirror>();
- if (superclass != null) {
- result.addAll(superclass.instanceMembers);
- }
- declarations.values.forEach((decl) {
- if (decl is MethodMirror &&
- !decl.isStatic &&
- !decl.isConstructor &&
- !decl.isAbstract) {
- result[decl.simpleName] = decl;
- }
- if (decl is VariableMirror && !decl.isStatic) {
- var getterName = decl.simpleName;
- result[getterName] = new _SyntheticAccessor(
- this, getterName, true, false, false, decl);
- if (!decl.isFinal) {
- var setterName = _asSetter(decl.simpleName, this.owner);
- result[setterName] = new _SyntheticAccessor(
- this, setterName, false, false, false, decl);
- }
- }
- });
- _cachedInstanceMembers =
- new UnmodifiableMapView<Symbol, MethodMirror>(result);
+ var m = _cachedInstanceMembers;
+ if (m != null) return m;
+
+ var result = new Map<Symbol, MethodMirror>();
+ var library = this.owner as LibraryMirror;
+ var sup = superclass;
+ if (sup != null) {
+ result.addAll(sup.instanceMembers);
}
- return _cachedInstanceMembers;
+ declarations.values.forEach((decl) {
+ if (decl is MethodMirror &&
+ !decl.isStatic &&
+ !decl.isConstructor &&
+ !decl.isAbstract) {
+ result[decl.simpleName] = decl;
+ }
+ if (decl is VariableMirror && !decl.isStatic) {
+ var getterName = decl.simpleName;
+ result[getterName] =
+ new _SyntheticAccessor(this, getterName, true, false, false, decl);
+ if (!decl.isFinal) {
+ var setterName = _asSetter(decl.simpleName, library);
+ result[setterName] = new _SyntheticAccessor(
+ this, setterName, false, false, false, decl);
+ }
+ }
+ });
+ return _cachedInstanceMembers =
+ new UnmodifiableMapView<Symbol, MethodMirror>(result);
}
- Map<Symbol, DeclarationMirror> _declarations;
+ Map<Symbol, DeclarationMirror>? _declarations;
Map<Symbol, DeclarationMirror> get declarations {
- if (_declarations != null) return _declarations;
+ var d = _declarations;
+ if (d != null) return d;
var decls = new Map<Symbol, DeclarationMirror>();
@@ -582,39 +597,39 @@
return true;
}
- List<TypeVariableMirror> _typeVariables;
+ List<TypeVariableMirror>? _typeVariables;
List<TypeVariableMirror> get typeVariables {
- if (_typeVariables == null) {
- if (!_isTransformedMixinApplication && _isAnonymousMixinApplication) {
- return _typeVariables = const <TypeVariableMirror>[];
- }
- _typeVariables = new List<TypeVariableMirror>();
+ var v = _typeVariables;
+ if (v != null) return v;
- List params = _ClassMirror_type_variables(_reflectee);
- ClassMirror owner = originalDeclaration;
- var mirror;
- for (var i = 0; i < params.length; i += 2) {
- mirror = new _TypeVariableMirror._(params[i + 1], params[i], owner);
- _typeVariables.add(mirror);
- }
- _typeVariables =
- new UnmodifiableListView<TypeVariableMirror>(_typeVariables);
+ if (!_isTransformedMixinApplication && _isAnonymousMixinApplication) {
+ return _typeVariables = const <TypeVariableMirror>[];
}
- return _typeVariables;
+ var result = new List<TypeVariableMirror>();
+
+ List params = _ClassMirror_type_variables(_reflectee);
+ ClassMirror owner = originalDeclaration;
+ var mirror;
+ for (var i = 0; i < params.length; i += 2) {
+ mirror = new _TypeVariableMirror._(params[i + 1], params[i], owner);
+ result.add(mirror);
+ }
+ return _typeVariables =
+ new UnmodifiableListView<TypeVariableMirror>(result);
}
- List<TypeMirror> _typeArguments;
+ List<TypeMirror>? _typeArguments;
List<TypeMirror> get typeArguments {
- if (_typeArguments == null) {
- if (_isGenericDeclaration ||
- (!_isTransformedMixinApplication && _isAnonymousMixinApplication)) {
- _typeArguments = const <TypeMirror>[];
- } else {
- _typeArguments = new UnmodifiableListView<TypeMirror>(
- _computeTypeArguments(_reflectedType).cast<TypeMirror>());
- }
+ var a = _typeArguments;
+ if (a != null) return a;
+
+ if (_isGenericDeclaration ||
+ (!_isTransformedMixinApplication && _isAnonymousMixinApplication)) {
+ return _typeArguments = const <TypeMirror>[];
+ } else {
+ return _typeArguments = new UnmodifiableListView<TypeMirror>(
+ _computeTypeArguments(_reflectedType).cast<TypeMirror>());
}
- return _typeArguments;
}
bool get isOriginalDeclaration => !_isGeneric || _isGenericDeclaration;
@@ -630,11 +645,11 @@
String toString() => "ClassMirror on '${MirrorSystem.getName(simpleName)}'";
InstanceMirror newInstance(Symbol constructorName, List positionalArguments,
- [Map<Symbol, dynamic> namedArguments]) {
+ [Map<Symbol, dynamic> namedArguments = const <Symbol, dynamic>{}]) {
// Native code will add the 1 or 2 implicit arguments depending on whether
// we end up invoking a factory or constructor respectively.
int numPositionalArguments = positionalArguments.length;
- int numNamedArguments = namedArguments != null ? namedArguments.length : 0;
+ int numNamedArguments = namedArguments.length;
int numArguments = numPositionalArguments + numNamedArguments;
List arguments = new List(numArguments);
arguments.setRange(0, numPositionalArguments, positionalArguments);
@@ -653,10 +668,7 @@
}
List<InstanceMirror> get metadata {
- // Get the metadata objects, convert them into InstanceMirrors using
- // reflect() and then make them into a Dart list.
- return new UnmodifiableListView<InstanceMirror>(
- _metadata(_reflectee).map(reflect));
+ return _wrapMetadata(_metadata(_reflectee));
}
bool operator ==(other) {
@@ -684,12 +696,12 @@
bool isSubclassOf(ClassMirror other) {
if (other is! ClassMirror) throw new ArgumentError(other);
- ClassMirror otherDeclaration = other.originalDeclaration;
+ ClassMirror otherDeclaration = other.originalDeclaration as ClassMirror;
ClassMirror c = this;
while (c != null) {
- c = c.originalDeclaration;
+ c = c.originalDeclaration as ClassMirror;
if (c == otherDeclaration) return true;
- c = c.superclass;
+ c = c.superclass as ClassMirror;
}
return false;
}
@@ -744,47 +756,43 @@
bool get _isAnonymousMixinApplication => false;
// FunctionTypeMirrors have a simpleName generated from their signature.
- Symbol _simpleName;
+ Symbol? _simpleName;
Symbol get simpleName {
- if (_simpleName == null) {
- _simpleName = _s(_makeSignatureString(returnType, parameters));
- }
- return _simpleName;
+ var n = _simpleName;
+ if (n != null) return n;
+ return _simpleName = _s(_makeSignatureString(returnType, parameters));
}
- MethodMirror _callMethod;
+ MethodMirror? _callMethod;
MethodMirror get callMethod {
- if (_callMethod == null) {
- _callMethod = _FunctionTypeMirror_call_method(_functionReflectee);
- }
- return _callMethod;
+ var m = _callMethod;
+ if (m != null) return m;
+ return _callMethod = _FunctionTypeMirror_call_method(_functionReflectee);
}
- TypeMirror _returnType;
+ TypeMirror? _returnType;
TypeMirror get returnType {
- if (_returnType == null) {
- _returnType =
- reflectType(_FunctionTypeMirror_return_type(_functionReflectee));
- }
- return _returnType;
+ var t = _returnType;
+ if (t != null) return t;
+ return _returnType =
+ reflectType(_FunctionTypeMirror_return_type(_functionReflectee));
}
- List<ParameterMirror> _parameters;
+ List<ParameterMirror>? _parameters;
List<ParameterMirror> get parameters {
- if (_parameters == null) {
- _parameters = _FunctionTypeMirror_parameters(_functionReflectee)
- .cast<ParameterMirror>();
- _parameters = new UnmodifiableListView<ParameterMirror>(_parameters);
- }
- return _parameters;
+ var p = _parameters;
+ if (p != null) return p;
+ return _parameters = new UnmodifiableListView<ParameterMirror>(
+ _FunctionTypeMirror_parameters(_functionReflectee)
+ .cast<ParameterMirror>());
}
bool get isOriginalDeclaration => true;
ClassMirror get originalDeclaration => this;
- get typeVariables => const <TypeVariableMirror>[];
- get typeArguments => const <TypeMirror>[];
- get metadata => const <InstanceMirror>[];
- get location => null;
+ List<TypeVariableMirror> get typeVariables => const <TypeVariableMirror>[];
+ List<TypeMirror> get typeArguments => const <TypeMirror>[];
+ List<InstanceMirror> get metadata => const <InstanceMirror>[];
+ SourceLocation? get location => null;
String toString() => "FunctionTypeMirror on '${_n(simpleName)}'";
@@ -806,25 +814,21 @@
Symbol get simpleName => _simpleName;
- Symbol _qualifiedName;
+ Symbol? _qualifiedName;
Symbol get qualifiedName {
- if (_qualifiedName == null) {
- _qualifiedName = _computeQualifiedName(owner, simpleName);
- }
- return _qualifiedName;
+ var n = _qualifiedName;
+ if (n != null) return n;
+ return _qualifiedName = _computeQualifiedName(owner, simpleName);
}
bool get isPrivate => _n(simpleName).startsWith('_');
- SourceLocation get location {
+ SourceLocation? get location {
return _location(_reflectee);
}
List<InstanceMirror> get metadata {
- // Get the metadata objects, convert them into InstanceMirrors using
- // reflect() and then make them into a Dart list.
- return new UnmodifiableListView<InstanceMirror>(
- _metadata(_reflectee).map(reflect));
+ return _wrapMetadata(_metadata(_reflectee));
}
bool operator ==(other) {
@@ -840,24 +844,23 @@
_TypeVariableMirror._(reflectee, String simpleName, this._owner)
: super._(reflectee, _s(simpleName));
- DeclarationMirror _owner;
+ DeclarationMirror? _owner;
DeclarationMirror get owner {
- if (_owner == null) {
- _owner = (_TypeVariableMirror_owner(_reflectee) as TypeMirror)
- .originalDeclaration;
- }
- return _owner;
+ var o = _owner;
+ if (o != null) return o;
+ return _owner = (_TypeVariableMirror_owner(_reflectee) as TypeMirror)
+ .originalDeclaration;
}
bool get isStatic => false;
bool get isTopLevel => false;
- TypeMirror _upperBound;
+ TypeMirror? _upperBound;
TypeMirror get upperBound {
- if (_upperBound == null) {
- _upperBound = reflectType(_TypeVariableMirror_upper_bound(_reflectee));
- }
- return _upperBound;
+ var b = _upperBound;
+ if (b != null) return b;
+ return _upperBound =
+ reflectType(_TypeVariableMirror_upper_bound(_reflectee));
}
bool get hasReflectedType => false;
@@ -875,7 +878,7 @@
String toString() => "TypeVariableMirror on '${_n(simpleName)}'";
- operator ==(other) {
+ bool operator ==(other) {
return other is TypeVariableMirror &&
simpleName == other.simpleName &&
owner == other.owner;
@@ -916,22 +919,21 @@
bool get isTopLevel => true;
- DeclarationMirror _owner;
+ DeclarationMirror? _owner;
DeclarationMirror get owner {
- if (_owner == null) {
- var uri = _ClassMirror._libraryUri(_reflectee);
- _owner = currentMirrorSystem().libraries[Uri.parse(uri)];
- }
- return _owner;
+ var o = _owner;
+ if (o != null) return o;
+ var uri = _ClassMirror._libraryUri(_reflectee);
+ return _owner = currentMirrorSystem().libraries[Uri.parse(uri)];
}
- _FunctionTypeMirror _referent;
+ _FunctionTypeMirror? _referent;
FunctionTypeMirror get referent {
- if (_referent == null) {
- _referent = _nativeReferent(_reflectedType);
- _referent._instantiator = _reflectedType;
- }
- return _referent;
+ var r = _referent;
+ if (r != null) return r;
+ var result = _nativeReferent(_reflectedType) as _FunctionTypeMirror;
+ result._instantiator = _reflectedType;
+ return _referent = result;
}
bool get hasReflectedType => !_isGenericDeclaration;
@@ -953,33 +955,35 @@
}
}
- List<TypeVariableMirror> _typeVariables;
+ List<TypeVariableMirror>? _typeVariables;
List<TypeVariableMirror> get typeVariables {
- if (_typeVariables == null) {
- _typeVariables = new List<TypeVariableMirror>();
- List params = _ClassMirror._ClassMirror_type_variables(_reflectee);
- TypedefMirror owner = originalDeclaration;
- var mirror;
- for (var i = 0; i < params.length; i += 2) {
- mirror = new _TypeVariableMirror._(params[i + 1], params[i], owner);
- _typeVariables.add(mirror);
- }
+ var v = _typeVariables;
+ if (v != null) return v;
+
+ var result = new List<TypeVariableMirror>();
+ List params = _ClassMirror._ClassMirror_type_variables(_reflectee);
+ TypedefMirror owner = originalDeclaration;
+ var mirror;
+ for (var i = 0; i < params.length; i += 2) {
+ mirror = new _TypeVariableMirror._(params[i + 1], params[i], owner);
+ result.add(mirror);
}
- return _typeVariables;
+ return _typeVariables =
+ new UnmodifiableListView<TypeVariableMirror>(result);
}
- List<TypeMirror> _typeArguments;
+ List<TypeMirror>? _typeArguments;
List<TypeMirror> get typeArguments {
- if (_typeArguments == null) {
- if (_isGenericDeclaration) {
- _typeArguments = const <TypeMirror>[];
- } else {
- _typeArguments = new UnmodifiableListView<TypeMirror>(
- _ClassMirror._computeTypeArguments(_reflectedType)
- .cast<TypeMirror>());
- }
+ var a = _typeArguments;
+ if (a != null) return a;
+
+ if (_isGenericDeclaration) {
+ return _typeArguments = const <TypeMirror>[];
+ } else {
+ return _typeArguments = new UnmodifiableListView<TypeMirror>(
+ _ClassMirror._computeTypeArguments(_reflectedType)
+ .cast<TypeMirror>());
}
- return _typeArguments;
}
String toString() => "TypedefMirror on '${_n(simpleName)}'";
@@ -1022,16 +1026,17 @@
// The simple name and the qualified name are the same for a library.
Symbol get qualifiedName => simpleName;
- DeclarationMirror get owner => null;
+ DeclarationMirror? get owner => null;
bool get isPrivate => false;
bool get isTopLevel => false;
- Type get _instantiator => null;
+ Type? get _instantiator => null;
- Map<Symbol, DeclarationMirror> _declarations;
+ Map<Symbol, DeclarationMirror>? _declarations;
Map<Symbol, DeclarationMirror> get declarations {
- if (_declarations != null) return _declarations;
+ var d = _declarations;
+ if (d != null) return d;
var decls = new Map<Symbol, DeclarationMirror>();
var members = _computeMembers(_reflectee);
@@ -1043,15 +1048,12 @@
new UnmodifiableMapView<Symbol, DeclarationMirror>(decls);
}
- SourceLocation get location {
+ SourceLocation? get location {
return _location(_reflectee);
}
List<InstanceMirror> get metadata {
- // Get the metadata objects, convert them into InstanceMirrors using
- // reflect() and then make them into a Dart list.
- return new UnmodifiableListView<InstanceMirror>(
- _metadata(_reflectee).map(reflect));
+ return _wrapMetadata(_metadata(_reflectee));
}
bool operator ==(other) {
@@ -1065,12 +1067,11 @@
var _cachedLibraryDependencies;
get libraryDependencies {
- if (_cachedLibraryDependencies == null) {
- _cachedLibraryDependencies =
- new UnmodifiableListView<LibraryDependencyMirror>(
- _libraryDependencies(_reflectee).cast<LibraryDependencyMirror>());
- }
- return _cachedLibraryDependencies;
+ var d = _cachedLibraryDependencies;
+ if (d != null) return d;
+ return _cachedLibraryDependencies =
+ new UnmodifiableListView<LibraryDependencyMirror>(
+ _libraryDependencies(_reflectee).cast<LibraryDependencyMirror>());
}
List<dynamic> _libraryDependencies(reflectee)
@@ -1092,7 +1093,7 @@
final LibraryMirror sourceLibrary;
var _targetMirrorOrPrefix;
final List<CombinatorMirror> combinators;
- final Symbol prefix;
+ final Symbol? prefix;
final bool isImport;
final bool isDeferred;
final List<InstanceMirror> metadata;
@@ -1105,15 +1106,14 @@
this.isImport,
this.isDeferred,
List<dynamic> unwrappedMetadata)
- : prefix = _s(prefixString),
+ : prefix = _sOpt(prefixString),
combinators = new UnmodifiableListView<CombinatorMirror>(
mutableCombinators.cast<CombinatorMirror>()),
- metadata = new UnmodifiableListView<InstanceMirror>(
- unwrappedMetadata.map(reflect));
+ metadata = _wrapMetadata(unwrappedMetadata);
bool get isExport => !isImport;
- LibraryMirror get targetLibrary {
+ LibraryMirror? get targetLibrary {
if (_targetMirrorOrPrefix is _LibraryMirror) {
return _targetMirrorOrPrefix;
}
@@ -1137,7 +1137,7 @@
static LibraryMirror _tryUpgradePrefix(libraryPrefix)
native "LibraryMirror_fromPrefix";
- SourceLocation get location => null;
+ SourceLocation? get location => null;
}
class _CombinatorMirror extends Mirror implements CombinatorMirror {
@@ -1194,14 +1194,13 @@
];
bool get isOperator => _operators.contains(_n(simpleName));
- DeclarationMirror _owner;
+ DeclarationMirror? _owner;
DeclarationMirror get owner {
// For nested closures it is possible, that the mirror for the owner has not
// been created yet.
- if (_owner == null) {
- _owner = _MethodMirror_owner(_reflectee, _instantiator);
- }
- return _owner;
+ var o = _owner;
+ if (o != null) return o;
+ return _owner = _MethodMirror_owner(_reflectee, _instantiator);
}
bool get isPrivate =>
@@ -1209,53 +1208,52 @@
bool get isTopLevel => owner is LibraryMirror;
- TypeMirror _returnType;
+ TypeMirror? _returnType;
TypeMirror get returnType {
- if (_returnType == null) {
- if (isConstructor) {
- _returnType = owner;
- } else {
- _returnType =
- reflectType(_MethodMirror_return_type(_reflectee, _instantiator));
- }
+ var t = _returnType;
+ if (t != null) return t;
+ if (isConstructor) {
+ return _returnType = owner as _ClassMirror;
+ } else {
+ return _returnType =
+ reflectType(_MethodMirror_return_type(_reflectee, _instantiator));
}
- return _returnType;
}
- List<ParameterMirror> _parameters;
+ List<ParameterMirror>? _parameters;
List<ParameterMirror> get parameters {
- if (_parameters == null) {
- _parameters = new UnmodifiableListView<ParameterMirror>(
- _MethodMirror_parameters(_reflectee).cast<ParameterMirror>());
- }
- return _parameters;
+ var p = _parameters;
+ if (p != null) return p;
+ return _parameters = new UnmodifiableListView<ParameterMirror>(
+ _MethodMirror_parameters(_reflectee).cast<ParameterMirror>());
}
bool get isRegularMethod => !isGetter && !isSetter && !isConstructor;
- Symbol _constructorName;
+ Symbol? _constructorName;
Symbol get constructorName {
- if (_constructorName == null) {
- if (!isConstructor) {
- _constructorName = _s('');
+ var n = _constructorName;
+ if (n != null) return n;
+
+ if (!isConstructor) {
+ return _constructorName = _s('');
+ } else {
+ var parts = MirrorSystem.getName(simpleName).split('.');
+ if (parts.length > 2) {
+ throw new _InternalMirrorError(
+ 'Internal error in MethodMirror.constructorName: '
+ 'malformed name <$simpleName>');
+ } else if (parts.length == 2) {
+ LibraryMirror definingLibrary = owner.owner as _LibraryMirror;
+ return _constructorName =
+ MirrorSystem.getSymbol(parts[1], definingLibrary);
} else {
- var parts = MirrorSystem.getName(simpleName).split('.');
- if (parts.length > 2) {
- throw new _InternalMirrorError(
- 'Internal error in MethodMirror.constructorName: '
- 'malformed name <$simpleName>');
- } else if (parts.length == 2) {
- LibraryMirror definingLibrary = owner.owner;
- _constructorName = MirrorSystem.getSymbol(parts[1], definingLibrary);
- } else {
- _constructorName = _s('');
- }
+ return _constructorName = _s('');
}
}
- return _constructorName;
}
- String get source => _MethodMirror_source(_reflectee);
+ String? get source => _MethodMirror_source(_reflectee);
void _patchConstructorName(ownerName) {
var cn = _n(constructorName);
@@ -1277,7 +1275,7 @@
List<dynamic> _MethodMirror_parameters(reflectee)
native "MethodMirror_parameters";
- static String _MethodMirror_source(reflectee) native "MethodMirror_source";
+ static String? _MethodMirror_source(reflectee) native "MethodMirror_source";
}
class _VariableMirror extends _DeclarationMirror implements VariableMirror {
@@ -1293,7 +1291,7 @@
bool get isTopLevel => owner is LibraryMirror;
- Type get _instantiator {
+ Type? get _instantiator {
final o = owner; // Note: need local variable for promotion to happen.
if (o is _ClassMirror) {
return o._instantiator;
@@ -1306,12 +1304,11 @@
}
}
- TypeMirror _type;
+ TypeMirror? _type;
TypeMirror get type {
- if (_type == null) {
- _type = reflectType(_VariableMirror_type(_reflectee, _instantiator));
- }
- return _type;
+ var t = _type;
+ if (t != null) return t;
+ return _type = reflectType(_VariableMirror_type(_reflectee, _instantiator));
}
String toString() =>
@@ -1349,8 +1346,8 @@
);
Object _defaultValueReflectee;
- InstanceMirror _defaultValue;
- InstanceMirror get defaultValue {
+ InstanceMirror? _defaultValue;
+ InstanceMirror? get defaultValue {
if (!isOptional) {
return null;
}
@@ -1362,23 +1359,22 @@
bool get hasDefaultValue => _defaultValueReflectee != null;
- SourceLocation get location {
+ SourceLocation? get location {
throw new UnsupportedError("ParameterMirror.location unimplemented");
}
List<InstanceMirror> get metadata {
- if (_unmirroredMetadata == null) return const <InstanceMirror>[];
- return new UnmodifiableListView<InstanceMirror>(
- _unmirroredMetadata.map(reflect));
+ var m = _unmirroredMetadata;
+ if (m == null) return const <InstanceMirror>[];
+ return _wrapMetadata(m);
}
- TypeMirror _type;
+ TypeMirror? _type;
TypeMirror get type {
- if (_type == null) {
- _type = reflectType(
- _ParameterMirror_type(_reflectee, _position, _instantiator));
- }
- return _type;
+ var t = _type;
+ if (t != null) return t;
+ return _type = reflectType(
+ _ParameterMirror_type(_reflectee, _position, _instantiator));
}
String toString() => "ParameterMirror on '${_n(simpleName)}'";
@@ -1396,9 +1392,9 @@
bool get isPrivate => false;
bool get isTopLevel => true;
- DeclarationMirror get owner => null;
+ DeclarationMirror? get owner => null;
- SourceLocation get location => null;
+ SourceLocation? get location => null;
List<InstanceMirror> get metadata => const <InstanceMirror>[];
bool get hasReflectedType => simpleName == #dynamic;
@@ -1448,7 +1444,7 @@
: new _InstanceMirror._(reflectee);
}
- static ClassMirror _makeLocalClassMirror(Type key)
+ static _ClassMirror _makeLocalClassMirror(Type key)
native "Mirrors_makeLocalClassMirror";
static TypeMirror _makeLocalTypeMirror(Type key)
native "Mirrors_makeLocalTypeMirror";
@@ -1470,8 +1466,9 @@
return classMirror;
}
- static TypeMirror reflectType(Type key, [List<Type> typeArguments]) {
- if (typeArguments != null) {
+ static TypeMirror reflectType(Type key,
+ [List<Type> typeArguments = const <Type>[]]) {
+ if (typeArguments.length != 0) {
key = _instantiateType(key, typeArguments);
}
var typeMirror = _instantiationCache[key];
diff --git a/sdk_nnbd/lib/_internal/vm/lib/mirrors_patch.dart b/sdk_nnbd/lib/_internal/vm/lib/mirrors_patch.dart
index 623fd65..ca51d0c 100644
--- a/sdk_nnbd/lib/_internal/vm/lib/mirrors_patch.dart
+++ b/sdk_nnbd/lib/_internal/vm/lib/mirrors_patch.dart
@@ -50,7 +50,7 @@
}
@patch
-TypeMirror reflectType(Type key, [List<Type> typeArguments]) {
+TypeMirror reflectType(Type key, [List<Type> typeArguments = const <Type>[]]) {
return _Mirrors.reflectType(key, typeArguments);
}
@@ -73,17 +73,17 @@
@patch
static String getName(Symbol symbol) {
- return internal.Symbol.computeUnmangledName(symbol);
+ return internal.Symbol.computeUnmangledName(symbol as internal.Symbol);
}
@patch
- static Symbol getSymbol(String name, [LibraryMirror library]) {
- if ((library != null && library is! _LocalLibraryMirror) ||
+ static Symbol getSymbol(String name, [LibraryMirror? library]) {
+ if ((library != null && library is! _LibraryMirror) ||
((name.length > 0) && (name[0] == '_') && (library == null))) {
throw new ArgumentError(library);
}
if (library != null) {
- name = _mangleName(name, (library as _LocalLibraryMirror)._reflectee);
+ name = _mangleName(name, (library as _LibraryMirror)._reflectee);
}
return new internal.Symbol.unvalidated(name);
}
diff --git a/sdk_nnbd/lib/_internal/vm/lib/wasm_patch.dart b/sdk_nnbd/lib/_internal/vm/lib/wasm_patch.dart
index 1372932..78c474a 100644
--- a/sdk_nnbd/lib/_internal/vm/lib/wasm_patch.dart
+++ b/sdk_nnbd/lib/_internal/vm/lib/wasm_patch.dart
@@ -37,7 +37,7 @@
@patch
class WasmMemory {
@patch
- factory WasmMemory(int initialPages, [int maxPages]) {
+ factory WasmMemory(int initialPages, [int? maxPages]) {
return _NativeWasmMemory(initialPages, maxPages);
}
}
@@ -108,7 +108,7 @@
int _pages;
Uint8List _buffer;
- _NativeWasmMemory(int initialPages, int maxPages) : _pages = initialPages {
+ _NativeWasmMemory(int initialPages, int? maxPages) : _pages = initialPages {
_buffer = _init(initialPages, maxPages);
}
@@ -131,7 +131,7 @@
return oldPages;
}
- Uint8List _init(int initialPages, int maxPages) native 'Wasm_initMemory';
+ Uint8List _init(int initialPages, int? maxPages) native 'Wasm_initMemory';
Uint8List _grow(int deltaPages) native 'Wasm_growMemory';
Uint8List _initFromInstance(_NativeWasmInstance inst)
native 'Wasm_initMemoryFromInstance';
diff --git a/sdk_nnbd/lib/async/stream.dart b/sdk_nnbd/lib/async/stream.dart
index afcd3c5..2a24b97 100644
--- a/sdk_nnbd/lib/async/stream.dart
+++ b/sdk_nnbd/lib/async/stream.dart
@@ -497,7 +497,9 @@
StreamSubscription<T> subscription = this.listen(null,
onError: controller._addError, // Avoid Zone error replacement.
onDone: controller.close);
- final add = controller.add;
+ FutureOr<Null> add(E value) {
+ controller.add(value);
+ }
final addError = controller._addError;
subscription.onData((T event) {
FutureOr<E> newValue;
@@ -1275,7 +1277,7 @@
_completeWithErrorCallback(future, e, s);
}
}, cancelOnError: true);
- subscription.onError((T value) {
+ subscription.onData((T value) {
if (foundResult) {
// This is the second element we get.
try {
diff --git a/sdk_nnbd/lib/async/stream_impl.dart b/sdk_nnbd/lib/async/stream_impl.dart
index 7ed7a7c..257551b 100644
--- a/sdk_nnbd/lib/async/stream_impl.dart
+++ b/sdk_nnbd/lib/async/stream_impl.dart
@@ -329,12 +329,7 @@
* of pending events later (if necessary).
*/
void _addPending(_DelayedEvent event) {
- // TODO(lrn): Restore to:
- // _StreamImplEvents<T> pending = (_pending ??= _StreamImplEvents<T>());
- // when that type-checks.
- var streamEvents = _StreamImplEvents<T>();
- _pending ??= streamEvents;
- _StreamImplEvents<T> pending = streamEvents;
+ var pending = (_pending ??= _StreamImplEvents<T>()) as _StreamImplEvents<T>;
pending.add(event);
if (!_hasPending) {
_state |= _STATE_HAS_PENDING;
diff --git a/sdk_nnbd/lib/cli/cli.dart b/sdk_nnbd/lib/cli/cli.dart
index 4748181..9c19c3a 100644
--- a/sdk_nnbd/lib/cli/cli.dart
+++ b/sdk_nnbd/lib/cli/cli.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.5
-
/// {@category VM}
library dart.cli;
diff --git a/sdk_nnbd/lib/cli/wait_for.dart b/sdk_nnbd/lib/cli/wait_for.dart
index d4dd71e..3c9525b 100644
--- a/sdk_nnbd/lib/cli/wait_for.dart
+++ b/sdk_nnbd/lib/cli/wait_for.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.5
-
part of dart.cli;
/**
@@ -55,10 +53,10 @@
// native implementation. In the standalone VM this is set to _waitForEvent()
// above. If it is null, calling waitFor() will throw an UnsupportedError.
@pragma("vm:entry-point")
-void Function(int) _waitForEventClosure;
+void Function(int)? _waitForEventClosure;
class _WaitForUtils {
- static void waitForEvent({Duration timeout}) {
+ static void waitForEvent({Duration? timeout}) {
if (_waitForEventClosure == null) {
throw new UnsupportedError("waitFor is not supported by this embedder");
}
@@ -113,11 +111,11 @@
* subsequent calls block waiting for a condition that is only satisfied when
* an earlier call returns.
*/
-T waitFor<T>(Future<T> future, {Duration timeout}) {
- T result;
+T waitFor<T>(Future<T> future, {Duration? timeout}) {
+ late T result;
bool futureCompleted = false;
- Object error;
- StackTrace stacktrace;
+ Object? error;
+ StackTrace? stacktrace;
future.then((r) {
futureCompleted = true;
result = r;
@@ -126,13 +124,13 @@
stacktrace = st;
});
- Stopwatch s;
+ late Stopwatch s;
if (timeout != null) {
s = new Stopwatch()..start();
}
Timer.run(() {}); // Enusre there is at least one message.
while (!futureCompleted && (error == null)) {
- Duration remaining;
+ Duration? remaining;
if (timeout != null) {
if (s.elapsed >= timeout) {
throw new TimeoutException("waitFor() timed out", timeout);
diff --git a/sdk_nnbd/lib/core/list.dart b/sdk_nnbd/lib/core/list.dart
index f72158f..a6be658 100644
--- a/sdk_nnbd/lib/core/list.dart
+++ b/sdk_nnbd/lib/core/list.dart
@@ -157,8 +157,7 @@
* This constructor creates a growable list when [growable] is true;
* otherwise, it returns a fixed-length list.
*/
- factory List.of(Iterable<E> elements, {bool growable = true}) =>
- List<E>.from(elements, growable: growable);
+ external factory List.of(Iterable<E> elements, {bool growable = true});
/**
* Generates a list of values.
diff --git a/sdk_nnbd/lib/js_util/dart2js/js_util_dart2js.dart b/sdk_nnbd/lib/js_util/js_util.dart
similarity index 96%
copy from sdk_nnbd/lib/js_util/dart2js/js_util_dart2js.dart
copy to sdk_nnbd/lib/js_util/js_util.dart
index a01a537..7718644 100644
--- a/sdk_nnbd/lib/js_util/dart2js/js_util_dart2js.dart
+++ b/sdk_nnbd/lib/js_util/js_util.dart
@@ -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.
-// @dart = 2.5
+// @dart = 2.6
/// Utility methods to efficiently manipulate typed JSInterop objects in cases
/// where the name to call is not known at runtime. You should only use these
@@ -30,13 +30,13 @@
/// JavaScript type, and all other objects are proxied.
jsify(object) {
if ((object is! Map) && (object is! Iterable)) {
- throw new ArgumentError("object must be a Map or Iterable");
+ throw ArgumentError("object must be a Map or Iterable");
}
return _convertDataTree(object);
}
_convertDataTree(data) {
- var _convertedObjects = new HashMap.identity();
+ var _convertedObjects = HashMap.identity();
_convert(o) {
if (_convertedObjects.containsKey(o)) {
@@ -65,13 +65,16 @@
newObject() => JS('=Object', '{}');
bool hasProperty(o, name) => JS('bool', '# in #', name, o);
+
getProperty(o, name) => JS('Object|Null', '#[#]', o, name);
+
setProperty(o, name, value) => JS('', '#[#]=#', o, name, value);
callMethod(o, String method, List args) =>
JS('Object|Null', '#[#].apply(#, #)', o, method, o, args);
bool instanceof(o, Function type) => JS('bool', '# instanceof #', o, type);
+
callConstructor(Function constr, List arguments) {
if (arguments == null) {
return JS('Object', 'new #()', constr);
diff --git a/sdk_nnbd/lib/js_util/js_util_sources.gni b/sdk_nnbd/lib/js_util/js_util_sources.gni
index 3b7c1b1..d3ac6d2 100644
--- a/sdk_nnbd/lib/js_util/js_util_sources.gni
+++ b/sdk_nnbd/lib/js_util/js_util_sources.gni
@@ -2,4 +2,4 @@
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
-js_util_sdk_sources = [ "dart2js/js_util_dart2js.dart" ]
+js_util_sdk_sources = [ "js_util.dart" ]
diff --git a/sdk_nnbd/lib/libraries.json b/sdk_nnbd/lib/libraries.json
index 3391292..7ef76a8 100644
--- a/sdk_nnbd/lib/libraries.json
+++ b/sdk_nnbd/lib/libraries.json
@@ -130,20 +130,20 @@
"patches": "../../sdk/lib/_internal/vm/lib/math_patch.dart"
},
"mirrors": {
- "uri": "../../sdk/lib/mirrors/mirrors.dart",
+ "uri": "mirrors/mirrors.dart",
"patches": [
- "../../sdk/lib/_internal/vm/lib/mirrors_patch.dart",
- "../../sdk/lib/_internal/vm/lib/mirrors_impl.dart",
- "../../sdk/lib/_internal/vm/lib/mirror_reference.dart"
+ "_internal/vm/lib/mirrors_patch.dart",
+ "_internal/vm/lib/mirrors_impl.dart",
+ "_internal/vm/lib/mirror_reference.dart"
]
},
"nativewrappers": {
"uri": "../../sdk/lib/html/dartium/nativewrappers.dart"
},
"cli": {
- "uri": "../../sdk/lib/cli/cli.dart",
+ "uri": "cli/cli.dart",
"patches": [
- "../../sdk/lib/_internal/vm/bin/cli_patch.dart"
+ "_internal/vm/bin/cli_patch.dart"
]
},
"typed_data": {
@@ -151,10 +151,10 @@
"patches": "../../sdk/lib/_internal/vm/lib/typed_data_patch.dart"
},
"_vmservice": {
- "uri": "../../sdk/lib/vmservice/vmservice.dart"
+ "uri": "vmservice/vmservice.dart"
},
"vmservice_io": {
- "uri": "../../runtime/bin/vmservice/vmservice_io.dart"
+ "uri": "_internal/vm/bin/vmservice_io.dart"
}
}
},
@@ -211,7 +211,7 @@
"patches": "../../sdk/lib/js/_js_client.dart"
},
"js_util": {
- "uri": "../../sdk/lib/js_util/dart2js/js_util_dart2js.dart"
+ "uri": "../../sdk/lib/js_util/js_util.dart"
},
"math": {
"uri": "../../sdk/lib/math/math.dart",
@@ -321,7 +321,7 @@
"patches": "../../sdk/lib/js/_js_server.dart"
},
"js_util": {
- "uri": "../../sdk/lib/js_util/dart2js/js_util_dart2js.dart"
+ "uri": "../../sdk/lib/js_util/js_util.dart"
},
"math": {
"uri": "../../sdk/lib/math/math.dart",
@@ -468,7 +468,7 @@
"patches": "_internal/js_dev_runtime/patch/js_patch.dart"
},
"js_util": {
- "uri": "_internal/js_dev_runtime/lib/js_util/dart2js/js_util_dart2js.dart"
+ "uri": "js_util/js_util.dart"
},
"svg": {
"uri": "svg/dart2js/svg_dart2js.dart"
diff --git a/sdk_nnbd/lib/libraries.yaml b/sdk_nnbd/lib/libraries.yaml
index 1aa29b8..d5079fa 100644
--- a/sdk_nnbd/lib/libraries.yaml
+++ b/sdk_nnbd/lib/libraries.yaml
@@ -95,9 +95,9 @@
- "../../sdk/lib/_internal/vm/lib/ffi_native_type_patch.dart"
wasm:
- uri: "../../sdk/lib/wasm/wasm.dart"
+ uri: "wasm/wasm.dart"
patches:
- - "../../sdk/lib/_internal/vm/lib/wasm_patch.dart"
+ - "_internal/vm/lib/wasm_patch.dart"
_http:
uri: "../../sdk/lib/_http/http.dart"
@@ -131,29 +131,29 @@
patches: "../../sdk/lib/_internal/vm/lib/math_patch.dart"
mirrors:
- uri: "../../sdk/lib/mirrors/mirrors.dart"
+ uri: "mirrors/mirrors.dart"
patches:
- - "../../sdk/lib/_internal/vm/lib/mirrors_patch.dart"
- - "../../sdk/lib/_internal/vm/lib/mirrors_impl.dart"
- - "../../sdk/lib/_internal/vm/lib/mirror_reference.dart"
+ - "_internal/vm/lib/mirrors_patch.dart"
+ - "_internal/vm/lib/mirrors_impl.dart"
+ - "_internal/vm/lib/mirror_reference.dart"
nativewrappers:
uri: "../../sdk/lib/html/dartium/nativewrappers.dart"
cli:
- uri: "../../sdk/lib/cli/cli.dart"
+ uri: "cli/cli.dart"
patches:
- - "../../sdk/lib/_internal/vm/bin/cli_patch.dart"
+ - "_internal/vm/bin/cli_patch.dart"
typed_data:
uri: "../../sdk/lib/typed_data/typed_data.dart"
patches: "../../sdk/lib/_internal/vm/lib/typed_data_patch.dart"
_vmservice:
- uri: "../../sdk/lib/vmservice/vmservice.dart"
+ uri: "vmservice/vmservice.dart"
vmservice_io:
- uri: "../../runtime/bin/vmservice/vmservice_io.dart"
+ uri: "_internal/vm/bin/vmservice_io.dart"
dart2js:
libraries:
@@ -208,7 +208,7 @@
patches: "../../sdk/lib/js/_js_client.dart"
js_util:
- uri: "../../sdk/lib/js_util/dart2js/js_util_dart2js.dart"
+ uri: "../../sdk/lib/js_util/js_util.dart"
math:
uri: "../../sdk/lib/math/math.dart"
@@ -316,7 +316,7 @@
patches: "../../sdk/lib/js/_js_server.dart"
js_util:
- uri: "../../sdk/lib/js_util/dart2js/js_util_dart2js.dart"
+ uri: "../../sdk/lib/js_util/js_util.dart"
math:
uri: "../../sdk/lib/math/math.dart"
@@ -461,7 +461,7 @@
patches: "_internal/js_dev_runtime/patch/js_patch.dart"
js_util:
- uri: "_internal/js_dev_runtime/lib/js_util/dart2js/js_util_dart2js.dart"
+ uri: "js_util/js_util.dart"
svg:
uri: "svg/dart2js/svg_dart2js.dart"
diff --git a/sdk_nnbd/lib/mirrors/mirrors.dart b/sdk_nnbd/lib/mirrors/mirrors.dart
index ec27699..d8ed89f 100644
--- a/sdk_nnbd/lib/mirrors/mirrors.dart
+++ b/sdk_nnbd/lib/mirrors/mirrors.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.5
-
// For the purposes of the mirrors library, we adopt a naming
// convention with respect to getters and setters. Specifically, for
// some variable or field...
@@ -132,7 +130,7 @@
* Using this method may result in larger output. If possible, use
* the const constructor of [Symbol] or symbol literals.
*/
- external static Symbol getSymbol(String name, [LibraryMirror library]);
+ external static Symbol getSymbol(String name, [LibraryMirror? library]);
}
/**
@@ -184,7 +182,8 @@
* function can only be used to obtain type mirrors on types of the current
* isolate.
*/
-external TypeMirror reflectType(Type key, [List<Type> typeArguments]);
+external TypeMirror reflectType(Type key,
+ [List<Type> typeArguments = const <Type>[]]);
/**
* A [Mirror] reflects some Dart language entity.
@@ -293,7 +292,7 @@
* * For a parameter, local variable or local function the owner is the
* immediately enclosing function.
*/
- DeclarationMirror get owner;
+ DeclarationMirror? get owner;
/**
* Whether this declaration is library private.
@@ -345,7 +344,7 @@
*
* This operation is optional and may throw an [UnsupportedError].
*/
- SourceLocation get location;
+ SourceLocation? get location;
/**
* A list of the metadata associated with this declaration.
@@ -406,7 +405,7 @@
* TODO(turnidge): Handle optional & named arguments.
*/
InstanceMirror invoke(Symbol memberName, List positionalArguments,
- [Map<Symbol, dynamic> namedArguments]);
+ [Map<Symbol, dynamic> namedArguments = const <Symbol, dynamic>{}]);
/**
* Invokes a getter and returns a mirror on the result.
@@ -598,7 +597,7 @@
* method throws *e*.
*/
InstanceMirror apply(List positionalArguments,
- [Map<Symbol, dynamic> namedArguments]);
+ [Map<Symbol, dynamic> namedArguments = const <Symbol, dynamic>{}]);
}
/**
@@ -656,17 +655,17 @@
/// Returns the library mirror of the library that is imported or exported,
/// or null if the library is not loaded.
- LibraryMirror get targetLibrary;
+ LibraryMirror? get targetLibrary;
/// Returns the prefix if this is a prefixed import and `null` otherwise.
- Symbol get prefix;
+ Symbol? get prefix;
/// Returns the list of show/hide combinators on the import/export
/// declaration.
List<CombinatorMirror> get combinators;
/// Returns the source location for this import/export declaration.
- SourceLocation get location;
+ SourceLocation? get location;
List<InstanceMirror> get metadata;
@@ -781,7 +780,7 @@
*
* If this type is [:Object:], the superclass will be null.
*/
- ClassMirror get superclass;
+ ClassMirror? get superclass;
/**
* A list of mirrors on the superinterfaces of the reflectee.
@@ -879,7 +878,7 @@
* catch), this method throws *e*.
*/
InstanceMirror newInstance(Symbol constructorName, List positionalArguments,
- [Map<Symbol, dynamic> namedArguments]);
+ [Map<Symbol, dynamic> namedArguments = const <Symbol, dynamic>{}]);
/**
* Whether this mirror is equal to [other].
@@ -983,7 +982,7 @@
/**
* The source code for the reflectee, if available. Otherwise null.
*/
- String get source;
+ String? get source;
/**
* A list of mirrors on the parameters for the reflectee.
@@ -1171,7 +1170,7 @@
*
* Returns `null` for a required parameter.
*/
- InstanceMirror get defaultValue;
+ InstanceMirror? get defaultValue;
}
/**
diff --git a/sdk_nnbd/lib/vmservice/asset.dart b/sdk_nnbd/lib/vmservice/asset.dart
index a6b3927..484dc33 100644
--- a/sdk_nnbd/lib/vmservice/asset.dart
+++ b/sdk_nnbd/lib/vmservice/asset.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.5
-
part of dart._vmservice;
class Asset {
@@ -39,15 +37,15 @@
}
}
- static Map<String, Asset> request() {
- Uint8List tarBytes = _requestAssets();
+ static Map<String, Asset>? request() {
+ Uint8List? tarBytes = _requestAssets();
if (tarBytes == null) {
return null;
}
List assetList = _decodeAssets(tarBytes);
- Map<String, Asset> assets = new HashMap<String, Asset>();
+ Map<String, Asset> assets = HashMap<String, Asset>();
for (int i = 0; i < assetList.length; i += 2) {
- var a = new Asset(assetList[i], assetList[i + 1]);
+ var a = Asset(assetList[i], assetList[i + 1]);
assets[a.name] = a;
}
return assets;
@@ -58,7 +56,7 @@
List _decodeAssets(Uint8List data) native "VMService_DecodeAssets";
-Map<String, Asset> _assets;
+Map<String, Asset>? _assets;
Map<String, Asset> get assets {
if (_assets == null) {
try {
@@ -67,5 +65,5 @@
print('Could not load Observatory assets: $e');
}
}
- return _assets;
+ return _assets!;
}
diff --git a/sdk_nnbd/lib/vmservice/client.dart b/sdk_nnbd/lib/vmservice/client.dart
index 70d978c..cbe365e 100644
--- a/sdk_nnbd/lib/vmservice/client.dart
+++ b/sdk_nnbd/lib/vmservice/client.dart
@@ -2,11 +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.5
-
part of dart._vmservice;
-typedef void ClientServiceHandle(Message response);
+typedef void ClientServiceHandle(Message? response);
// A service client.
abstract class Client {
@@ -14,18 +12,18 @@
final bool sendEvents;
/// A set streamIds which describes the streams the client is connected to
- final Set<String> streams = new Set<String>();
+ final Set<String> streams = <String>{};
/// Services registered and their aliases
/// key: service
/// value: alias
- final Map<String, String> services = new Map<String, String>();
+ final Map<String, String> services = <String, String>{};
/// Callbacks registered for service invocations set to the client
/// key: RPC id used for the request
/// value: callback that should be invoked
final Map<String, ClientServiceHandle> serviceHandles =
- new Map<String, ClientServiceHandle>();
+ <String, ClientServiceHandle>{};
Client(this.service, {bool sendEvents: true}) : this.sendEvents = sendEvents {
service._addClient(this);
@@ -58,10 +56,8 @@
service.routeRequest(service, message);
}
- // Sends a result to the client. Implemented in subclasses.
+ // Sends a result to the client. Implemented in subclasses.
void post(Response result);
- dynamic toJson() {
- return {};
- }
+ dynamic toJson() => {};
}
diff --git a/sdk_nnbd/lib/vmservice/constants.dart b/sdk_nnbd/lib/vmservice/constants.dart
index 5edd3ef..914576b 100644
--- a/sdk_nnbd/lib/vmservice/constants.dart
+++ b/sdk_nnbd/lib/vmservice/constants.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.5
-
part of dart._vmservice;
// These must be kept in sync with runtime/vm/service.cc.
diff --git a/sdk_nnbd/lib/vmservice/devfs.dart b/sdk_nnbd/lib/vmservice/devfs.dart
index d5ca40f..3eeb14c 100644
--- a/sdk_nnbd/lib/vmservice/devfs.dart
+++ b/sdk_nnbd/lib/vmservice/devfs.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.5
-
part of dart._vmservice;
String _encodeDevFSDisabledError(Message message) {
@@ -27,7 +25,7 @@
final String name;
final Uri uri;
- Uri resolvePath(String path) {
+ Uri? resolvePath(String path) {
if (path.startsWith('/')) {
path = path.substring(1);
}
@@ -36,19 +34,21 @@
}
Uri pathUri;
try {
- pathUri = new Uri.file(path);
- } on FormatException catch (e) {
+ pathUri = Uri.file(path);
+ // ignore: unused_catch_clause
+ } on FormatException catch (_) {
return null;
}
return resolve(pathUri);
}
- Uri resolve(Uri pathUri) {
+ Uri? resolve(Uri pathUri) {
try {
// Make sure that this pathUri can be converted to a file path.
pathUri.toFilePath();
- } on UnsupportedError catch (e) {
+ // ignore: unused_catch_clause
+ } on UnsupportedError catch (_) {
return null;
}
@@ -60,21 +60,19 @@
return resolvedUri;
}
- Map toMap() {
- return {
- 'type': 'FileSystem',
- 'name': name,
- 'uri': uri.toString(),
- };
- }
+ Map<String, String> toMap() => {
+ 'type': 'FileSystem',
+ 'name': name,
+ 'uri': uri.toString(),
+ };
}
class DevFS {
DevFS();
- Map<String, _FileSystem> _fsMap = {};
+ final Map<String, _FileSystem> _fsMap = {};
- final Set _rpcNames = new Set.from([
+ final Set _rpcNames = <String>{
'_listDevFS',
'_createDevFS',
'_deleteDevFS',
@@ -82,7 +80,7 @@
'_writeDevFSFile',
'_writeDevFSFiles',
'_listDevFSFiles',
- ]);
+ };
void cleanup() {
var deleteDir = VMServiceEmbedderHooks.deleteDir;
@@ -102,7 +100,7 @@
}
Future<String> handleMessage(Message message) async {
- switch (message.method) {
+ switch (message.method!) {
case '_listDevFS':
return _listDevFS(message);
case '_createDevFS':
@@ -124,9 +122,9 @@
}
Future<String> handlePutStream(
- Object fsName, Object path, Uri fsUri, Stream<List<int>> bytes) async {
+ Object? fsName, Object? path, Uri? fsUri, Stream<List<int>> bytes) async {
// A dummy Message for error message construction.
- Message message = new Message.forMethod('_writeDevFSFile');
+ Message message = Message.forMethod('_writeDevFSFile');
var writeStreamFile = VMServiceEmbedderHooks.writeStreamFile;
if (writeStreamFile == null) {
return _encodeDevFSDisabledError(message);
@@ -141,7 +139,7 @@
if (fs == null) {
return _encodeFileSystemDoesNotExistError(message, fsName);
}
- Uri uri = fsUri;
+ Uri? uri = fsUri;
if (uri == null) {
if (path == null) {
return encodeMissingParamError(message, 'path');
@@ -187,7 +185,7 @@
return _encodeFileSystemAlreadyExistsError(message, fsName);
}
var tempDir = await createTempDir(fsName);
- fs = new _FileSystem(fsName, tempDir);
+ fs = _FileSystem(fsName, tempDir);
_fsMap[fsName] = fs;
return encodeResult(message, fs.toMap());
}
@@ -228,7 +226,7 @@
if (fs == null) {
return _encodeFileSystemDoesNotExistError(message, fsName);
}
- Uri uri;
+ Uri? uri;
if (message.params['uri'] != null) {
try {
var uriParam = message.params['uri'];
@@ -282,7 +280,7 @@
if (fs == null) {
return _encodeFileSystemDoesNotExistError(message, fsName);
}
- Uri uri;
+ Uri? uri;
if (message.params['uri'] != null) {
try {
var uriParam = message.params['uri'];
diff --git a/sdk_nnbd/lib/vmservice/message.dart b/sdk_nnbd/lib/vmservice/message.dart
index efe0f06..51d8d22 100644
--- a/sdk_nnbd/lib/vmservice/message.dart
+++ b/sdk_nnbd/lib/vmservice/message.dart
@@ -2,19 +2,17 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// @dart = 2.5
-
part of dart._vmservice;
enum MessageType { Request, Notification, Response }
class Message {
- final Completer<Response> _completer = new Completer<Response>.sync();
+ final Completer<Response> _completer = Completer<Response>.sync();
bool get completed => _completer.isCompleted;
/// Future of response.
Future<Response> get response => _completer.future;
- Client client;
+ Client? client;
// Is a notification message (no serial)
final MessageType type;
@@ -22,35 +20,35 @@
// Client-side identifier for this message.
final serial;
- final String method;
+ final String? method;
- final Map params = new Map();
- final Map result = new Map();
- final Map error = new Map();
+ final Map<String, dynamic> params = {};
+ final Map result = {};
+ final Map error = {};
- factory Message.fromJsonRpc(Client client, Map map) {
+ factory Message.fromJsonRpc(Client? client, Map map) {
if (map.containsKey('id')) {
final id = map['id'];
if (id != null && id is! num && id is! String) {
- throw new Exception('"id" must be a number, string, or null.');
+ throw Exception('"id" must be a number, string, or null.');
}
if (map.containsKey('method')) {
- return new Message._fromJsonRpcRequest(client, map);
+ return Message._fromJsonRpcRequest(client, map);
}
if (map.containsKey('result')) {
- return new Message._fromJsonRpcResult(client, map);
+ return Message._fromJsonRpcResult(client, map);
}
if (map.containsKey('error')) {
- return new Message._fromJsonRpcError(client, map);
+ return Message._fromJsonRpcError(client, map);
}
} else if (map.containsKey('method')) {
- return new Message._fromJsonRpcNotification(client, map);
+ return Message._fromJsonRpcNotification(client, map);
}
- throw new Exception('Invalid message format');
+ throw Exception('Invalid message format');
}
// http://www.jsonrpc.org/specification#request_object
- Message._fromJsonRpcRequest(Client client, Map map)
+ Message._fromJsonRpcRequest(Client? client, Map map)
: client = client,
type = MessageType.Request,
serial = map['id'],
@@ -61,7 +59,7 @@
}
// http://www.jsonrpc.org/specification#notification
- Message._fromJsonRpcNotification(Client client, Map map)
+ Message._fromJsonRpcNotification(Client? client, Map map)
: client = client,
type = MessageType.Notification,
method = map['method'],
@@ -72,7 +70,7 @@
}
// http://www.jsonrpc.org/specification#response_object
- Message._fromJsonRpcResult(Client client, Map map)
+ Message._fromJsonRpcResult(Client? client, Map map)
: client = client,
type = MessageType.Response,
serial = map['id'],
@@ -81,7 +79,7 @@
}
// http://www.jsonrpc.org/specification#response_object
- Message._fromJsonRpcError(Client client, Map map)
+ Message._fromJsonRpcError(Client? client, Map map)
: client = client,
type = MessageType.Response,
serial = map['id'],
@@ -120,15 +118,13 @@
params['isolateId'] = isolate.serviceId;
}
- Uri toUri() {
- return new Uri(path: method, queryParameters: params);
- }
+ Uri toUri() => Uri(path: method!, queryParameters: params);
dynamic toJson() {
throw 'unsupported';
}
- dynamic forwardToJson([Map overloads]) {
+ dynamic forwardToJson([Map? overloads]) {
Map<dynamic, dynamic> json = {'jsonrpc': '2.0', 'id': serial};
switch (type) {
case MessageType.Request:
@@ -157,25 +153,21 @@
// This has a side effect that boolean literal values like true become 'true'
// and thus indistinguishable from the string literal 'true'.
List<String> _makeAllString(List list) {
- if (list == null) {
- return null;
- }
- var new_list = new List<String>(list.length);
- for (var i = 0; i < list.length; i++) {
- new_list[i] = list[i].toString();
- }
- return new_list;
+ var newList = <String>[
+ for (final e in list) e.toString(),
+ ];
+ return newList;
}
Future<Response> sendToIsolate(SendPort sendPort) {
- final receivePort = new RawReceivePort();
+ final receivePort = RawReceivePort();
receivePort.handler = (value) {
receivePort.close();
_setResponseFromPort(value);
};
var keys = _makeAllString(params.keys.toList(growable: false));
var values = _makeAllString(params.values.toList(growable: false));
- var request = new List(6)
+ var request = List(6)
..[0] = 0 // Make room for OOB message type.
..[1] = receivePort.sendPort
..[2] = serial
@@ -184,7 +176,7 @@
..[5] = values;
if (!sendIsolateServiceMessage(sendPort, request)) {
receivePort.close();
- _completer.complete(new Response.internalError(
+ _completer.complete(Response.internalError(
'could not send message [${serial}] to isolate'));
}
return _completer.future;
@@ -212,19 +204,19 @@
}
Future<Response> sendToVM() {
- final receivePort = new RawReceivePort();
+ final receivePort = RawReceivePort();
receivePort.handler = (value) {
receivePort.close();
_setResponseFromPort(value);
};
var keys = params.keys.toList(growable: false);
var values = params.values.toList(growable: false);
- if (!_methodNeedsObjectParameters(method)) {
+ if (!_methodNeedsObjectParameters(method!)) {
keys = _makeAllString(keys);
values = _makeAllString(values);
}
- final request = new List(6)
+ final request = List(6)
..[0] = 0 // Make room for OOB message type.
..[1] = receivePort.sendPort
..[2] = serial
@@ -232,7 +224,7 @@
..[4] = keys
..[5] = values;
- if (_methodNeedsObjectParameters(method)) {
+ if (_methodNeedsObjectParameters(method!)) {
// We use a different method invocation path here.
sendObjectRootServiceMessage(request);
} else {
@@ -252,7 +244,7 @@
}
void setResponse(String response) {
- _completer.complete(new Response(ResponsePayloadKind.String, response));
+ _completer.complete(Response(ResponsePayloadKind.String, response));
}
void setErrorResponse(int code, String details) {
diff --git a/sdk_nnbd/lib/vmservice/message_router.dart b/sdk_nnbd/lib/vmservice/message_router.dart
index 6c6c746..3af7319 100644
--- a/sdk_nnbd/lib/vmservice/message_router.dart
+++ b/sdk_nnbd/lib/vmservice/message_router.dart
@@ -2,12 +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.5
-
part of dart._vmservice;
abstract class MessageRouter {
- Future<Response> routeRequest(VMService service, Message message);
+ Future<Response?> routeRequest(VMService service, Message message);
void routeResponse(Message message);
}
@@ -35,6 +33,8 @@
case ResponsePayloadKind.Binary:
case ResponsePayloadKind.Utf8String:
return payload is Uint8List;
+ default:
+ return false;
}
}());
}
@@ -45,7 +45,7 @@
: this(ResponsePayloadKind.String, json.encode(value));
factory Response.internalError(String message) {
- return new Response.json({
+ return Response.json({
'type': 'ServiceError',
'id': '',
'kind': 'InternalError',
@@ -59,13 +59,12 @@
/// Utf8String: a single element list containing Uint8List
factory Response.from(Object value) {
if (value is String) {
- return new Response(ResponsePayloadKind.String, value);
+ return Response(ResponsePayloadKind.String, value);
} else if (value is Uint8List) {
- return new Response(ResponsePayloadKind.Binary, value);
+ return Response(ResponsePayloadKind.Binary, value);
} else if (value is List) {
assert(value.length == 1);
- return new Response(
- ResponsePayloadKind.Utf8String, value[0] as Uint8List);
+ return Response(ResponsePayloadKind.Utf8String, value[0] as Uint8List);
} else if (value is Response) {
return value;
} else {
diff --git a/sdk_nnbd/lib/vmservice/named_lookup.dart b/sdk_nnbd/lib/vmservice/named_lookup.dart
index a53c57a..176d1a7 100644
--- a/sdk_nnbd/lib/vmservice/named_lookup.dart
+++ b/sdk_nnbd/lib/vmservice/named_lookup.dart
@@ -2,18 +2,16 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// @dart = 2.5
-
part of dart._vmservice;
/// Set like containes which automatically generated String ids for its items
-class NamedLookup<E> extends Object with IterableMixin<E> {
+class NamedLookup<E extends Object> extends Object with IterableMixin<E> {
final IdGenerator _generator;
- final Map<String, E> _elements = new Map<String, E>();
- final Map<E, String> _ids = new Map<E, String>();
+ final Map<String, E> _elements = <String, E>{};
+ final Map<E, String> _ids = <E, String>{};
NamedLookup({String prologue = ''})
- : _generator = new IdGenerator(prologue: prologue);
+ : _generator = IdGenerator(prologue: prologue);
void add(E e) {
final id = _generator.newId();
@@ -22,13 +20,13 @@
}
void remove(E e) {
- final id = _ids.remove(e);
+ final id = _ids.remove(e)!;
_elements.remove(id);
_generator.release(id);
}
- E operator [](String id) => _elements[id];
- String keyOf(E e) => _ids[e];
+ E operator [](String id) => _elements[id]!;
+ String keyOf(E e) => _ids[e]!;
Iterator<E> get iterator => _ids.keys.iterator;
}
@@ -38,10 +36,10 @@
/// Fixed initial part of the id
final String prologue;
// Ids in use
- final Set<String> _used = new Set<String>();
+ final Set<String> _used = <String>{};
/// Ids that has been released (use these before generate new ones)
- final Set<String> _free = new Set<String>();
+ final Set<String> _free = <String>{};
/// Next id to generate if no one can be recycled (first use _free);
int _next = 0;
diff --git a/sdk_nnbd/lib/vmservice/running_isolate.dart b/sdk_nnbd/lib/vmservice/running_isolate.dart
index cfe9be9..8a6dd36 100644
--- a/sdk_nnbd/lib/vmservice/running_isolate.dart
+++ b/sdk_nnbd/lib/vmservice/running_isolate.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.5
-
part of dart._vmservice;
class RunningIsolate implements MessageRouter {
diff --git a/sdk_nnbd/lib/vmservice/running_isolates.dart b/sdk_nnbd/lib/vmservice/running_isolates.dart
index e925e03..5f99a26 100644
--- a/sdk_nnbd/lib/vmservice/running_isolates.dart
+++ b/sdk_nnbd/lib/vmservice/running_isolates.dart
@@ -2,13 +2,11 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// @dart = 2.5
-
part of dart._vmservice;
class RunningIsolates implements MessageRouter {
- final Map<int, RunningIsolate> isolates = new Map<int, RunningIsolate>();
- int _rootPortId;
+ final Map<int, RunningIsolate> isolates = <int, RunningIsolate>{};
+ int? _rootPortId;
RunningIsolates();
@@ -16,7 +14,7 @@
if (_rootPortId == null) {
_rootPortId = portId;
}
- var ri = new RunningIsolate(portId, sp, name);
+ var ri = RunningIsolate(portId, sp, name);
isolates[portId] = ri;
}
@@ -29,7 +27,7 @@
@override
Future<Response> routeRequest(VMService service, Message message) {
- String isolateParam = message.params['isolateId'];
+ String isolateParam = message.params['isolateId']!;
int isolateId;
if (!isolateParam.startsWith('isolates/')) {
message.setErrorResponse(
@@ -38,7 +36,7 @@
}
isolateParam = isolateParam.substring('isolates/'.length);
if (isolateParam == 'root') {
- isolateId = _rootPortId;
+ isolateId = _rootPortId!;
} else {
try {
isolateId = int.parse(isolateParam);
@@ -62,7 +60,7 @@
}
if (message.method == 'evaluateInFrame' || message.method == 'evaluate') {
- return new _Evaluator(message, isolate, service).run();
+ return _Evaluator(message, isolate, service).run();
} else {
return isolate.routeRequest(service, message);
}
@@ -81,7 +79,7 @@
Map<String, dynamic> responseJson = buildScopeResponse.decodeJson();
if (responseJson.containsKey('error')) {
- return new Response.from(encodeCompilationError(
+ return Response.from(encodeCompilationError(
_message, responseJson['error']['data']['details']));
}
@@ -89,9 +87,9 @@
try {
kernelBase64 = await _compileExpression(responseJson['result']);
} catch (e) {
- return new Response.from(encodeCompilationError(_message, e.toString()));
+ return Response.from(encodeCompilationError(_message, e.toString()));
}
- return _evaluateCompiledExpression(kernelBase64);
+ return await _evaluateCompiledExpression(kernelBase64);
}
Message _message;
@@ -110,7 +108,7 @@
buildScopeParams['params']['scope'] = _message.params['scope'];
}
var buildScope =
- new Message._fromJsonRpcRequest(_message.client, buildScopeParams);
+ Message._fromJsonRpcRequest(_message.client!, buildScopeParams);
// Decode the JSON and and insert it into the map. The map key
// is the request Uri.
@@ -119,37 +117,37 @@
Future<String> _compileExpression(
Map<String, dynamic> buildScopeResponseResult) {
- Client externalClient =
+ Client? externalClient =
_service._findFirstClientThatHandlesService('compileExpression');
- Map compileParams = {
- 'isolateId': _message.params['isolateId'],
- 'expression': _message.params['expression'],
- 'definitions': buildScopeResponseResult['param_names'],
- 'typeDefinitions': buildScopeResponseResult['type_params_names'],
- 'libraryUri': buildScopeResponseResult['libraryUri'],
- 'isStatic': buildScopeResponseResult['isStatic'],
+ final compileParams = <String, String>{
+ 'isolateId': _message.params['isolateId']!,
+ 'expression': _message.params['expression']!,
+ 'definitions': buildScopeResponseResult['param_names']!,
+ 'typeDefinitions': buildScopeResponseResult['type_params_names']!,
+ 'libraryUri': buildScopeResponseResult['libraryUri']!,
+ 'isStatic': buildScopeResponseResult['isStatic']!,
};
dynamic klass = buildScopeResponseResult['klass'];
if (klass != null) {
compileParams['klass'] = klass;
}
if (externalClient != null) {
- var compileExpression = new Message.forMethod('compileExpression');
+ var compileExpression = Message.forMethod('compileExpression');
compileExpression.client = externalClient;
compileExpression.params.addAll(compileParams);
final id = _service._serviceRequests.newId();
final oldId = _message.serial;
- final completer = new Completer<String>();
- externalClient.serviceHandles[id] = (Message m) {
+ final completer = Completer<String>();
+ externalClient.serviceHandles[id] = (Message? m) {
if (m != null) {
completer.complete(json.encode(m.forwardToJson({'id': oldId})));
} else {
completer.complete(encodeRpcError(_message, kServiceDisappeared));
}
};
- externalClient.post(new Response.json(compileExpression
+ externalClient.post(Response.json(compileExpression
.forwardToJson({'id': id, 'method': 'compileExpression'})));
return completer.future
.then((String s) => jsonDecode(s))
@@ -167,8 +165,8 @@
'id': _message.serial,
'params': compileParams,
};
- var compileExpression = new Message._fromJsonRpcRequest(
- _message.client, compileExpressionParams);
+ var compileExpression = Message._fromJsonRpcRequest(
+ _message.client!, compileExpressionParams);
return _isolate
.routeRequest(_service, compileExpression)
@@ -197,7 +195,7 @@
runParams['params']['scope'] = _message.params['scope'];
}
var runExpression =
- new Message._fromJsonRpcRequest(_message.client, runParams);
+ Message._fromJsonRpcRequest(_message.client!, runParams);
return _isolate.routeRequest(_service, runExpression); // _message
} else {
// empty kernel indicates dart1 mode
diff --git a/sdk_nnbd/lib/vmservice/vmservice.dart b/sdk_nnbd/lib/vmservice/vmservice.dart
index aa7878f..fa5ac5c 100644
--- a/sdk_nnbd/lib/vmservice/vmservice.dart
+++ b/sdk_nnbd/lib/vmservice/vmservice.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.5
-
library dart._vmservice;
import 'dart:async';
@@ -23,8 +21,8 @@
part 'message_router.dart';
part 'named_lookup.dart';
-final RawReceivePort isolateControlPort = new RawReceivePort();
-final RawReceivePort scriptLoadPort = new RawReceivePort();
+final RawReceivePort isolateControlPort = RawReceivePort();
+final RawReceivePort scriptLoadPort = RawReceivePort();
abstract class IsolateEmbedderData {
void cleanup();
@@ -32,8 +30,8 @@
String _makeAuthToken() {
final kTokenByteSize = 8;
- Uint8List bytes = new Uint8List(kTokenByteSize);
- Random random = new Random.secure();
+ Uint8List bytes = Uint8List(kTokenByteSize);
+ Random random = Random.secure();
for (int i = 0; i < kTokenByteSize; i++) {
bytes[i] = random.nextInt(256);
}
@@ -47,7 +45,7 @@
// anything implementing IsolateEmbedderData. When an isolate goes away,
// the cleanup method will be invoked after being removed from the map.
final Map<int, IsolateEmbedderData> isolateEmbedderData =
- new Map<int, IsolateEmbedderData>();
+ <int, IsolateEmbedderData>{};
// These must be kept in sync with the declarations in vm/json_stream.h.
const kParseError = -32700;
@@ -94,7 +92,7 @@
'due to the current configuration',
};
-String encodeRpcError(Message message, int code, {String details}) {
+String encodeRpcError(Message message, int code, {String? details}) {
var response = {
'jsonrpc': '2.0',
'id': message.serial,
@@ -180,31 +178,31 @@
/// Hooks that are setup by the embedder.
class VMServiceEmbedderHooks {
- static ServerStartCallback serverStart;
- static ServerStopCallback serverStop;
- static CleanupCallback cleanup;
- static CreateTempDirCallback createTempDir;
- static DeleteDirCallback deleteDir;
- static WriteFileCallback writeFile;
- static WriteStreamFileCallback writeStreamFile;
- static ReadFileCallback readFile;
- static ListFilesCallback listFiles;
- static ServerInformationCallback serverInformation;
- static WebServerControlCallback webServerControl;
+ static ServerStartCallback? serverStart;
+ static ServerStopCallback? serverStop;
+ static CleanupCallback? cleanup;
+ static CreateTempDirCallback? createTempDir;
+ static DeleteDirCallback? deleteDir;
+ static WriteFileCallback? writeFile;
+ static WriteStreamFileCallback? writeStreamFile;
+ static ReadFileCallback? readFile;
+ static ListFilesCallback? listFiles;
+ static ServerInformationCallback? serverInformation;
+ static WebServerControlCallback? webServerControl;
}
class VMService extends MessageRouter {
- static VMService _instance;
+ static VMService? _instance;
static const serviceNamespace = 's';
/// Collection of currently connected clients.
final NamedLookup<Client> clients =
- new NamedLookup<Client>(prologue: serviceNamespace);
- final IdGenerator _serviceRequests = new IdGenerator(prologue: 'sr');
+ NamedLookup<Client>(prologue: serviceNamespace);
+ final IdGenerator _serviceRequests = IdGenerator(prologue: 'sr');
/// Collection of currently running isolates.
- RunningIsolates runningIsolates = new RunningIsolates();
+ RunningIsolates runningIsolates = RunningIsolates();
/// Flag to indicate VM service is exiting.
bool isExiting = false;
@@ -212,7 +210,7 @@
/// A port used to receive events from the VM.
final RawReceivePort eventPort;
- final devfs = new DevFS();
+ final devfs = DevFS();
void _addClient(Client client) {
assert(client.streams.isEmpty);
@@ -231,7 +229,7 @@
for (var service in client.services.keys) {
_eventMessageHandler(
'Service',
- new Response.json({
+ Response.json({
'jsonrpc': '2.0',
'method': 'streamNotify',
'params': {
@@ -239,7 +237,7 @@
'event': {
"type": "Event",
"kind": "ServiceUnregistered",
- 'timestamp': new DateTime.now().millisecondsSinceEpoch,
+ 'timestamp': DateTime.now().millisecondsSinceEpoch,
'service': service,
'method': namespace + '.' + service,
}
@@ -267,15 +265,12 @@
break;
case Constants.ISOLATE_SHUTDOWN_MESSAGE_ID:
runningIsolates.isolateShutdown(portId, sp);
- IsolateEmbedderData ied = isolateEmbedderData.remove(portId);
- if (ied != null) {
- ied.cleanup();
- }
+ isolateEmbedderData.remove(portId)?.cleanup();
break;
}
}
- Future<Null> _serverMessageHandler(int code, SendPort sp, bool enable) async {
+ Future<void> _serverMessageHandler(int code, SendPort sp, bool enable) async {
switch (code) {
case Constants.WEB_SERVER_CONTROL_MESSAGE_ID:
if (VMServiceEmbedderHooks.webServerControl == null) {
@@ -296,28 +291,28 @@
}
}
- Future<Null> _handleNativeRpcCall(message, SendPort replyPort) async {
+ Future<void> _handleNativeRpcCall(message, SendPort replyPort) async {
// Keep in sync with "runtime/vm/service_isolate.cc:InvokeServiceRpc".
Response response;
try {
- final Message rpc = new Message.fromJsonRpc(
+ final Message rpc = Message.fromJsonRpc(
null, json.decode(utf8.decode(message as List<int>)));
if (rpc.type != MessageType.Request) {
- response = new Response.internalError(
+ response = Response.internalError(
'The client sent a non-request json-rpc message.');
} else {
- response = await routeRequest(this, rpc);
+ response = (await routeRequest(this, rpc))!;
}
} catch (exception) {
- response = new Response.internalError(
+ response = Response.internalError(
'The rpc call resulted in exception: $exception.');
}
- List<int> bytes;
+ late List<int> bytes;
switch (response.kind) {
case ResponsePayloadKind.String:
bytes = utf8.encode(response.payload);
- bytes = bytes is Uint8List ? bytes : new Uint8List.fromList(bytes);
+ bytes = bytes is Uint8List ? bytes : Uint8List.fromList(bytes);
break;
case ResponsePayloadKind.Binary:
case ResponsePayloadKind.Utf8String:
@@ -358,7 +353,7 @@
if (message is List) {
if (message.length == 2) {
// This is an event.
- _eventMessageHandler(message[0], new Response.from(message[1]));
+ _eventMessageHandler(message[0], Response.from(message[1]));
return;
}
if (message.length == 1) {
@@ -395,11 +390,13 @@
}
factory VMService() {
- if (VMService._instance == null) {
- VMService._instance = new VMService._internal();
+ VMService? instance = VMService._instance;
+ if (instance == null) {
+ instance = VMService._internal();
+ VMService._instance = instance;
_onStart();
}
- return _instance;
+ return instance;
}
bool _isAnyClientSubscribed(String streamId) {
@@ -411,7 +408,7 @@
return false;
}
- Client _findFirstClientThatHandlesService(String service) {
+ Client? _findFirstClientThatHandlesService(String service) {
if (clients != null) {
for (Client c in clients) {
if (c.services.containsKey(service)) {
@@ -426,8 +423,8 @@
static const serviceStreams = const [kServiceStream];
Future<String> _streamListen(Message message) async {
- var client = message.client;
- var streamId = message.params['streamId'];
+ var client = message.client!;
+ var streamId = message.params['streamId']!;
if (client.streams.contains(streamId)) {
return encodeRpcError(message, kStreamAlreadySubscribed);
@@ -457,8 +454,8 @@
}
Future<String> _streamCancel(Message message) async {
- var client = message.client;
- var streamId = message.params['streamId'];
+ var client = message.client!;
+ var streamId = message.params['streamId']!;
if (!client.streams.contains(streamId)) {
return encodeRpcError(message, kStreamNotSubscribed);
@@ -479,7 +476,7 @@
static String _getMethod(String method) => method.split('.').last;
Future<String> _registerService(Message message) async {
- final client = message.client;
+ final client = message.client!;
final service = message.params['service'];
final alias = message.params['alias'];
@@ -496,7 +493,7 @@
}
client.services[service] = alias;
- bool removed;
+ bool removed = false;
try {
// Do not send streaming events to the client which registers the service
removed = client.streams.remove(kServiceStream);
@@ -509,10 +506,10 @@
}
_sendServiceRegisteredEvent(Client client, String service,
- {Client target}) async {
+ {Client? target}) async {
final namespace = clients.keyOf(client);
final alias = client.services[service];
- final event = new Response.json({
+ final event = Response.json({
'jsonrpc': '2.0',
'method': 'streamNotify',
'params': {
@@ -520,7 +517,7 @@
'event': {
"type": "Event",
"kind": "ServiceRegistered",
- 'timestamp': new DateTime.now().millisecondsSinceEpoch,
+ 'timestamp': DateTime.now().millisecondsSinceEpoch,
'service': service,
'method': namespace + '.' + service,
'alias': alias
@@ -535,23 +532,23 @@
}
Future<String> _handleService(Message message) async {
- final namespace = _getNamespace(message.method);
- final method = _getMethod(message.method);
+ final namespace = _getNamespace(message.method!);
+ final method = _getMethod(message.method!);
final client = clients[namespace];
if (client != null) {
if (client.services.containsKey(method)) {
final id = _serviceRequests.newId();
final oldId = message.serial;
- final completer = new Completer<String>();
- client.serviceHandles[id] = (Message m) {
+ final completer = Completer<String>();
+ client.serviceHandles[id] = (Message? m) {
if (m != null) {
completer.complete(json.encode(m.forwardToJson({'id': oldId})));
} else {
completer.complete(encodeRpcError(message, kServiceDisappeared));
}
};
- client.post(new Response.json(
- message.forwardToJson({'id': id, 'method': method})));
+ client.post(
+ Response.json(message.forwardToJson({'id': id, 'method': method})));
return completer.future;
}
}
@@ -575,7 +572,7 @@
return encodeInvalidParamError(message, 'uri');
}
var args = message.params['args'];
- var argsOfString = new List<String>();
+ var argsOfString = <String>[];
if (args != null) {
if (args is! List) {
return encodeInvalidParamError(message, 'args');
@@ -598,14 +595,14 @@
return encodeSuccess(message);
}
- Future<Response> routeRequest(VMService _, Message message) async {
+ Future<Response?> routeRequest(VMService _, Message message) async {
final response = await _routeRequestImpl(message);
if (response == null) {
// We should only have a null response for Notifications.
assert(message.type == MessageType.Notification);
return null;
}
- return new Response.from(response);
+ return Response.from(response);
}
Future _routeRequestImpl(Message message) async {
@@ -628,7 +625,7 @@
if (devfs.shouldHandleMessage(message)) {
return await devfs.handleMessage(message);
}
- if (_hasNamespace(message.method)) {
+ if (_hasNamespace(message.method!)) {
return await _handleService(message);
}
if (message.params['isolateId'] != null) {
@@ -642,9 +639,9 @@
}
void routeResponse(message) {
- final client = message.client;
+ final client = message.client!;
if (client.serviceHandles.containsKey(message.serial)) {
- client.serviceHandles.remove(message.serial)(message);
+ client.serviceHandles.remove(message.serial)!(message);
_serviceRequests.release(message.serial);
}
}
@@ -658,8 +655,9 @@
}
@pragma("vm:entry-point", !const bool.fromEnvironment("dart.vm.product"))
+// ignore: unused_element
void _registerIsolate(int port_id, SendPort sp, String name) {
- var service = new VMService();
+ var service = VMService();
service.runningIsolates.isolateStartup(port_id, sp, name);
}
@@ -670,7 +668,7 @@
void _onExit() native "VMService_OnExit";
/// Notify the VM that the server's address has changed.
-void onServerAddressChange(String address)
+void onServerAddressChange(String? address)
native "VMService_OnServerAddressChange";
/// Subscribe to a service stream.
diff --git a/sdk_nnbd/lib/vmservice_libraries.json b/sdk_nnbd/lib/vmservice_libraries.json
index c25ffe5..d0b1297 100644
--- a/sdk_nnbd/lib/vmservice_libraries.json
+++ b/sdk_nnbd/lib/vmservice_libraries.json
@@ -1,11 +1,13 @@
{
+ "comment:0": "NOTE: THIS FILE IS GENERATED. DO NOT EDIT.",
+ "comment:1": "Instead modify 'sdk_nnbd/lib/vmservice_libraries.yaml' and follow the instructions therein.",
"vm": {
"libraries": {
- "vmservice_io": {
- "uri": "../../runtime/bin/vmservice/vmservice_io.dart"
- },
"_vmservice": {
"uri": "vmservice/vmservice.dart"
+ },
+ "vmservice_io": {
+ "uri": "_internal/vm/bin/vmservice_io.dart"
}
}
}
diff --git a/sdk_nnbd/lib/vmservice_libraries.yaml b/sdk_nnbd/lib/vmservice_libraries.yaml
index 737e361..169d6af 100644
--- a/sdk_nnbd/lib/vmservice_libraries.yaml
+++ b/sdk_nnbd/lib/vmservice_libraries.yaml
@@ -17,4 +17,4 @@
uri: "vmservice/vmservice.dart"
vmservice_io:
- uri: "../../runtime/bin/vmservice/vmservice_io.dart"
+ uri: "_internal/vm/bin/vmservice_io.dart"
diff --git a/sdk_nnbd/lib/wasm/wasm.dart b/sdk_nnbd/lib/wasm/wasm.dart
index f1c05c7..768445e 100644
--- a/sdk_nnbd/lib/wasm/wasm.dart
+++ b/sdk_nnbd/lib/wasm/wasm.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.5
-
/// {@category VM}
/// {@nodoc}
library dart.wasm;
@@ -57,7 +55,7 @@
abstract class WasmMemory {
// Create a new memory with the given number of initial pages, and optional
// maximum number of pages.
- external factory WasmMemory(int initialPages, [int maxPages]);
+ external factory WasmMemory(int initialPages, [int? maxPages]);
// The WASM spec defines the page size as 64KiB.
static const int kPageSizeInBytes = 64 * 1024;
diff --git a/tests/compiler/dart2js/analyses/analysis_helper.dart b/tests/compiler/dart2js/analyses/analysis_helper.dart
index 4cef73d..b422f84 100644
--- a/tests/compiler/dart2js/analyses/analysis_helper.dart
+++ b/tests/compiler/dart2js/analyses/analysis_helper.dart
@@ -20,7 +20,7 @@
import 'package:expect/expect.dart';
import 'package:front_end/src/api_prototype/constant_evaluator.dart' as ir;
import 'package:front_end/src/api_unstable/dart2js.dart'
- show isRedirectingFactory, relativizeUri;
+ show isRedirectingFactory, isRedirectingFactoryField, relativizeUri;
import 'package:kernel/ast.dart' as ir;
import 'package:kernel/class_hierarchy.dart' as ir;
import 'package:kernel/core_types.dart' as ir;
@@ -102,10 +102,6 @@
// Don't visit redirecting factories.
return;
}
- if (node.name.name.contains('#')) {
- // Skip synthetic .dill members.
- return;
- }
staticTypeContext = new ir.StaticTypeContext(node, typeEnvironment);
variableScopeModel =
new ScopeModel.from(node, _constantEvaluator).variableScopeModel;
@@ -116,7 +112,7 @@
@override
Null visitField(ir.Field node) {
- if (node.name.name.contains('#')) {
+ if (isRedirectingFactoryField(node)) {
// Skip synthetic .dill members.
return;
}
@@ -130,10 +126,6 @@
@override
Null visitConstructor(ir.Constructor node) {
- if (node.name.name.contains('#')) {
- // Skip synthetic .dill members.
- return;
- }
staticTypeContext = new ir.StaticTypeContext(node, typeEnvironment);
variableScopeModel =
new ScopeModel.from(node, _constantEvaluator).variableScopeModel;
diff --git a/tests/compiler/dartdevc_native/nnbd_strong_subtype_test.dart b/tests/compiler/dartdevc_native/nnbd_strong_subtype_test.dart
index dbb63a7..2f3cf75 100644
--- a/tests/compiler/dartdevc_native/nnbd_strong_subtype_test.dart
+++ b/tests/compiler/dartdevc_native/nnbd_strong_subtype_test.dart
@@ -6,7 +6,7 @@
import 'dart:async';
-import 'runtime_utils.dart';
+import 'runtime_utils.dart' show voidType;
import 'runtime_utils_nnbd.dart';
class A {}
diff --git a/tests/compiler/dartdevc_native/nnbd_weak_subtype_test.dart b/tests/compiler/dartdevc_native/nnbd_weak_subtype_test.dart
index f0e56fa..a21a178 100644
--- a/tests/compiler/dartdevc_native/nnbd_weak_subtype_test.dart
+++ b/tests/compiler/dartdevc_native/nnbd_weak_subtype_test.dart
@@ -6,7 +6,7 @@
import 'dart:async';
-import 'runtime_utils.dart';
+import 'runtime_utils.dart' show voidType;
import 'runtime_utils_nnbd.dart';
class A {}
diff --git a/tests/compiler/dartdevc_native/runtime_utils_nnbd.dart b/tests/compiler/dartdevc_native/runtime_utils_nnbd.dart
index 4d3aa65..8743e56 100644
--- a/tests/compiler/dartdevc_native/runtime_utils_nnbd.dart
+++ b/tests/compiler/dartdevc_native/runtime_utils_nnbd.dart
@@ -2,21 +2,109 @@
// for 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:_foreign_helper' show JS;
import 'dart:_runtime' as dart;
+import 'package:expect/expect.dart';
+
/// The runtime representation of the never type.
final neverType = dart.wrapType(dart.never_);
+/// Unwrap the user code type representation to expose the runtime
+/// representation of [t].
+///
+/// Legacy types (produced by the legacy helper below) are returned unchanged
+/// because they are created unwrapped since wrapping will strip the legacy from
+/// them by design.
+Object unwrap(Type t) => t is dart.LegacyType ? t : dart.unwrapType(t);
+
/// Returns tWrapped? as a wrapped type.
Type nullable(Type tWrapped) {
- var t = dart.unwrapType(tWrapped);
+ var t = unwrap(tWrapped);
var tNullable = dart.nullable(t);
return dart.wrapType(tNullable);
}
-/// Returns tWrapped* as a wrapped type.
+/// Returns tWrapped* as an *unwrapped* type when it produces a legacy type, and
+/// a *wrapped* type when the legacy has been normalized away.
+///
+/// For example DDC does not create a legacy dynamic type, only dynamic.
+///
+/// This is the only helper to return an unwrapped version of a type because
+/// wrapping a legacy type will strip off the legacy by design.
Type legacy(Type tWrapped) {
- var t = dart.unwrapType(tWrapped);
+ var t = unwrap(tWrapped);
var tLegacy = dart.legacy(t);
- return dart.wrapType(tLegacy);
+ // During normalization some types never get created as legacy versions.
+ // Ex: dynamic.
+ return tLegacy is dart.LegacyType ? tLegacy : dart.wrapType(tLegacy);
+}
+
+// Returns sWrapped<tWrapped> as a wrapped type.
+Type generic1(Type sWrapped, Type tWrapped) {
+ var s = unwrap(sWrapped);
+ var t = unwrap(tWrapped);
+ var sGeneric = dart.getGenericClass(s);
+ return dart.wrapType(JS('', '#(#)', sGeneric, t));
+}
+
+// Returns sWrapped<tWrapped, rWrapped> as a wrapped type.
+Type generic2(Type sWrapped, Type tWrapped, Type rWrapped) {
+ var s = unwrap(sWrapped);
+ var t = unwrap(tWrapped);
+ var r = unwrap(rWrapped);
+ var sGeneric = dart.getGenericClass(s);
+ return dart.wrapType(JS('', '#(#, #)', sGeneric, t, r));
+}
+
+// Returns a function type of argWrapped -> returnWrapped as a wrapped type.
+Type function1(Type returnWrapped, Type argWrapped) {
+ var returnType = unwrap(returnWrapped);
+ var argType = unwrap(argWrapped);
+ var fun = dart.fnType(returnType, [argType]);
+ return dart.wrapType(fun);
+}
+
+// Returns a function type with a bounded type argument that takes no argument
+// and returns void as a wrapped type.
+Type genericFunction(Type boundWrapped) => dart.wrapType(
+ dart.gFnType((T) => [dart.VoidType, []], (T) => [unwrap(boundWrapped)]));
+
+// Returns a function type with a bounded generic return type of
+// <T extends boundWrapped> argWrapped -> T as a wrapped type.
+Type functionGenericReturn(Type boundWrapped, Type argWrapped) =>
+ dart.wrapType(dart.gFnType(
+ (T) => [
+ T,
+ [unwrap(argWrapped)]
+ ],
+ (T) => [unwrap(boundWrapped)]));
+
+// Returns a function with a bounded generic argument type of
+// <T extends boundWrapped> T -> returnWrapped as a wrapped type.
+Type functionGenericArg(Type boundWrapped, Type returnWrapped) =>
+ dart.wrapType(dart.gFnType(
+ (T) => [
+ unwrap(returnWrapped),
+ [T]
+ ],
+ (T) => [unwrap(boundWrapped)]));
+
+void checkSubtype(Type sWrapped, Type tWrapped) {
+ var s = unwrap(sWrapped);
+ var t = unwrap(tWrapped);
+ Expect.isTrue(dart.isSubtypeOf(s, t), '$s should be subtype of $t.');
+}
+
+void checkProperSubtype(Type sWrapped, Type tWrapped) {
+ var s = unwrap(sWrapped);
+ var t = unwrap(tWrapped);
+ Expect.isTrue(dart.isSubtypeOf(s, t), '$s should be subtype of $t.');
+ checkSubtypeFailure(tWrapped, sWrapped);
+}
+
+void checkSubtypeFailure(Type sWrapped, Type tWrapped) {
+ var s = unwrap(sWrapped);
+ var t = unwrap(tWrapped);
+ Expect.isFalse(dart.isSubtypeOf(s, t), '$s should not be subtype of $t.');
}
diff --git a/tests/ffi/function_callbacks_test.dart b/tests/ffi/function_callbacks_test.dart
index 33241f2..9b59fb4 100644
--- a/tests/ffi/function_callbacks_test.dart
+++ b/tests/ffi/function_callbacks_test.dart
@@ -45,24 +45,40 @@
}
typedef SimpleAdditionType = Int32 Function(Int32, Int32);
-int simpleAddition(int x, int y) => x + y;
+int simpleAddition(int x, int y) {
+ print("simpleAddition($x, $y)");
+ return x + y;
+}
typedef IntComputationType = Int64 Function(Int8, Int16, Int32, Int64);
-int intComputation(int a, int b, int c, int d) => d - c + b - a;
+int intComputation(int a, int b, int c, int d) {
+ print("intComputation($a, $b, $c, $d)");
+ return d - c + b - a;
+}
typedef UintComputationType = Uint64 Function(Uint8, Uint16, Uint32, Uint64);
-int uintComputation(int a, int b, int c, int d) => d - c + b - a;
+int uintComputation(int a, int b, int c, int d) {
+ print("uintComputation($a, $b, $c, $d)");
+ return d - c + b - a;
+}
typedef SimpleMultiplyType = Double Function(Double);
-double simpleMultiply(double x) => x * 1.337;
+double simpleMultiply(double x) {
+ print("simpleMultiply($x)");
+ return x * 1.337;
+}
typedef SimpleMultiplyFloatType = Float Function(Float);
-double simpleMultiplyFloat(double x) => x * 1.337;
+double simpleMultiplyFloat(double x) {
+ print("simpleMultiplyFloat($x)");
+ return x * 1.337;
+}
typedef ManyIntsType = IntPtr Function(IntPtr, IntPtr, IntPtr, IntPtr, IntPtr,
IntPtr, IntPtr, IntPtr, IntPtr, IntPtr);
int manyInts(
int a, int b, int c, int d, int e, int f, int g, int h, int i, int j) {
+ print("manyInts($a, $b, $c, $d, $e, $f, $g, $h, $i, $j");
return a + b + c + d + e + f + g + h + i + j;
}
@@ -70,6 +86,7 @@
Double, Double, Double, Double, Double, Double);
double manyDoubles(double a, double b, double c, double d, double e, double f,
double g, double h, double i, double j) {
+ print("manyDoubles($a, $b, $c, $d, $e, $f, $g, $h, $i, $j");
return a + b + c + d + e + f + g + h + i + j;
}
@@ -115,6 +132,8 @@
double _18,
int _19,
double _20) {
+ print("manyArgs( $_1, $_2, $_3, $_4, $_5, $_6, $_7, $_8, $_9, $_10," +
+ "$_11, $_12, $_13, $_14, $_15, $_16, $_17, $_18, $_19, $_20)");
return _1 +
_2 +
_3 +
diff --git a/tests/ffi/function_test.dart b/tests/ffi/function_test.dart
index 5ed233d..644605a 100644
--- a/tests/ffi/function_test.dart
+++ b/tests/ffi/function_test.dart
@@ -33,6 +33,7 @@
testNativeFunctionManyArguments2();
testNativeFunctionManyArguments3();
testNativeFunctionManyArguments4();
+ testNativeFunctionManyArguments5();
testNativeFunctionPointer();
testNullInt();
testNullDouble();
@@ -229,6 +230,8 @@
typedef NativeDecenaryOp = IntPtr Function(IntPtr, IntPtr, IntPtr, IntPtr,
IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr);
+typedef NativeDecenaryOp2 = Int16 Function(
+ Int8, Int16, Int8, Int16, Int8, Int16, Int8, Int16, Int8, Int16);
typedef DecenaryOp = int Function(
int, int, int, int, int, int, int, int, int, int);
@@ -239,6 +242,13 @@
Expect.equals(55, sumManyInts(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
}
+DecenaryOp sumManySmallInts = ffiTestFunctions
+ .lookupFunction<NativeDecenaryOp2, DecenaryOp>("SumManySmallInts");
+
+void testNativeFunctionManyArguments5() {
+ Expect.equals(55, sumManySmallInts(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
+}
+
typedef NativeUndenaryOp = IntPtr Function(IntPtr, IntPtr, IntPtr, IntPtr,
IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr);
typedef UndenaryOp = int Function(
diff --git a/tests/language/nnbd/syntax/class_member_declarations_error_test.dart b/tests/language/nnbd/syntax/class_member_declarations_error_test.dart
new file mode 100644
index 0000000..59f708f
--- /dev/null
+++ b/tests/language/nnbd/syntax/class_member_declarations_error_test.dart
@@ -0,0 +1,166 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// SharedOptions=--enable-experiment=non-nullable
+
+class A {
+ static late x1;
+ // ^^^^
+ // [analyzer] unspecified
+ // [cfe] unspecified
+ static late x5 = 0;
+ // ^^^^
+ // [analyzer] unspecified
+ // [cfe] unspecified
+
+ static final late x9;
+ // ^^^^
+ // [analyzer] SYNTACTIC_ERROR.MODIFIER_OUT_OF_ORDER
+ // [cfe] The modifier 'late' should be before the modifier 'final'.
+ static final late A x10;
+ // ^^^^
+ // [analyzer] SYNTACTIC_ERROR.MODIFIER_OUT_OF_ORDER
+ // [cfe] The modifier 'late' should be before the modifier 'final'.
+ static final late x11 = 0;
+ // ^^^^
+ // [analyzer] SYNTACTIC_ERROR.MODIFIER_OUT_OF_ORDER
+ // [cfe] The modifier 'late' should be before the modifier 'final'.
+ static final late A x12 = null;
+ // ^^^^
+ // [analyzer] SYNTACTIC_ERROR.MODIFIER_OUT_OF_ORDER
+ // [cfe] The modifier 'late' should be before the modifier 'final'.
+ // ^^^^
+ // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT
+
+ covariant late x15;
+ // ^^^^
+ // [analyzer] unspecified
+ // [cfe] unspecified
+ covariant late x16 = '';
+ // ^^^^
+ // [analyzer] unspecified
+ // [cfe] unspecified
+
+ late covariant var x17;
+ // ^^^^^^^^^
+ // [analyzer] SYNTACTIC_ERROR.MODIFIER_OUT_OF_ORDER
+ // [cfe] The modifier 'covariant' should be before the modifier 'late'.
+ late covariant var x18 = '';
+ // ^^^^^^^^^
+ // [analyzer] SYNTACTIC_ERROR.MODIFIER_OUT_OF_ORDER
+ // [cfe] The modifier 'covariant' should be before the modifier 'late'.
+ late covariant x19;
+ // ^^^^^^^^^
+ // [analyzer] SYNTACTIC_ERROR.MODIFIER_OUT_OF_ORDER
+ // [cfe] The modifier 'covariant' should be before the modifier 'late'.
+ late covariant x20 = '';
+ // ^^^^^^^^^
+ // [analyzer] SYNTACTIC_ERROR.MODIFIER_OUT_OF_ORDER
+ // [cfe] The modifier 'covariant' should be before the modifier 'late'.
+
+ covariant var late x21;
+ // ^^^^
+ // [analyzer] SYNTACTIC_ERROR.MODIFIER_OUT_OF_ORDER
+ // [cfe] The modifier 'late' should be before the modifier 'var'.
+ covariant var late x22 = '';
+ // ^^^^
+ // [analyzer] SYNTACTIC_ERROR.MODIFIER_OUT_OF_ORDER
+ // [cfe] The modifier 'late' should be before the modifier 'var'.
+
+ covariant double late x23;
+ // ^^^^
+ // [analyzer] COMPILE_TIME_ERROR.NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD
+ // [cfe] Expected ';' after this.
+ // ^^^^
+ // [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN
+ // ^^^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_CONST_FINAL_VAR_OR_TYPE
+ // [cfe] Variables must be declared using the keywords 'const', 'final', 'var' or a type name.
+ covariant String late x24 = '';
+ // ^^^^
+ // [analyzer] COMPILE_TIME_ERROR.DUPLICATE_DEFINITION
+ // [cfe] 'late' is already declared in this scope.
+ // ^^^^
+ // [analyzer] COMPILE_TIME_ERROR.NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD
+ // [cfe] Expected ';' after this.
+ // ^^^^
+ // [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN
+ // ^^^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_CONST_FINAL_VAR_OR_TYPE
+ // [cfe] Variables must be declared using the keywords 'const', 'final', 'var' or a type name.
+
+ late x25;
+ // ^^^^
+ // [analyzer] unspecified
+ // [cfe] unspecified
+ late x29 = 0;
+ // ^^^^
+ // [analyzer] unspecified
+ // [cfe] unspecified
+
+ final late x33;
+ // ^^^^
+ // [analyzer] SYNTACTIC_ERROR.MODIFIER_OUT_OF_ORDER
+ // [cfe] The modifier 'late' should be before the modifier 'final'.
+ int late x34;
+ // ^^^^
+ // [analyzer] COMPILE_TIME_ERROR.DUPLICATE_DEFINITION
+ // [cfe] 'late' is already declared in this scope.
+ // ^^^^
+ // [analyzer] COMPILE_TIME_ERROR.NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD
+ // [cfe] Expected ';' after this.
+ // ^^^^
+ // [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN
+ // ^^^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_CONST_FINAL_VAR_OR_TYPE
+ // [cfe] Variables must be declared using the keywords 'const', 'final', 'var' or a type name.
+ var late x35;
+ // ^^^^
+ // [analyzer] SYNTACTIC_ERROR.MODIFIER_OUT_OF_ORDER
+ // [cfe] The modifier 'late' should be before the modifier 'var'.
+ final late A x36;
+ // ^^^^
+ // [analyzer] SYNTACTIC_ERROR.MODIFIER_OUT_OF_ORDER
+ // [cfe] The modifier 'late' should be before the modifier 'final'.
+ final late x37 = 0;
+ // ^^^^
+ // [analyzer] SYNTACTIC_ERROR.MODIFIER_OUT_OF_ORDER
+ // [cfe] The modifier 'late' should be before the modifier 'final'.
+ int late x38 = 0;
+ // ^^^^
+ // [analyzer] COMPILE_TIME_ERROR.DUPLICATE_DEFINITION
+ // [cfe] 'late' is already declared in this scope.
+ // ^^^^
+ // [analyzer] COMPILE_TIME_ERROR.NOT_INITIALIZED_NON_NULLABLE_INSTANCE_FIELD
+ // [cfe] Expected ';' after this.
+ // ^^^^
+ // [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN
+ // ^^^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_CONST_FINAL_VAR_OR_TYPE
+ // [cfe] Variables must be declared using the keywords 'const', 'final', 'var' or a type name.
+ var late x39 = 0;
+ // ^^^^
+ // [analyzer] SYNTACTIC_ERROR.MODIFIER_OUT_OF_ORDER
+ // [cfe] The modifier 'late' should be before the modifier 'var'.
+ final late A? x40 = null;
+ // ^^^^
+ // [analyzer] SYNTACTIC_ERROR.MODIFIER_OUT_OF_ORDER
+ // [cfe] The modifier 'late' should be before the modifier 'final'.
+
+}
+
+abstract class B {
+ m1(int some, regular, covariant parameters, {
+ required p1,
+ required p2 = null,
+ // ^^
+ // [analyzer] COMPILE_TIME_ERROR.DEFAULT_VALUE_ON_REQUIRED_PARAMETER
+ // [cfe] unspecified
+ required covariant p3,
+ required covariant int p4,
+ });
+}
+
+main() {
+}
diff --git a/tests/language/nnbd/syntax/class_member_declarations_test.dart b/tests/language/nnbd/syntax/class_member_declarations_test.dart
index bea6423..3aa7d26 100644
--- a/tests/language/nnbd/syntax/class_member_declarations_test.dart
+++ b/tests/language/nnbd/syntax/class_member_declarations_test.dart
@@ -5,57 +5,26 @@
// SharedOptions=--enable-experiment=non-nullable
class A {
- static late x1; //# 01: syntax error
static late final x2;
static late int x3;
static late final A x4;
- static late x5 = 0; //# 02: syntax error
static late final x6 = 0;
static late int x7 = 0;
static late final A? x8 = null;
- static final late x9; //# 03: syntax error
- static final late A x10; //# 04: syntax error
- static final late x11 = 0; //# 05: syntax error
- static final late A x12 = null; //# 06: syntax error
-
covariant late var x13;
covariant late var x14 = '';
- covariant late x15; //# 07: syntax error
- covariant late x16 = ''; //# 08: syntax error
-
- late covariant var x17; //# 09: syntax error
- late covariant var x18 = ''; //# 10: syntax error
- late covariant x19; //# 11: syntax error
- late covariant x20 = ''; //# 12: syntax error
-
- covariant var late x21; //# 13: syntax error
- covariant var late x22 = ''; //# 14: syntax error
covariant late double x23;
covariant late String x24 = '';
- covariant double late x23; //# 15: syntax error
- covariant String late x24 = ''; //# 16: syntax error
-
- late x25; //# 17: syntax error
late final x26;
late int x27;
late final A x28;
- late x29 = 0; //# 18: syntax error
late final x30 = 0;
late int x31 = 0;
late final A? x32 = null;
- final late x33; //# 19: syntax error
- int late x34; //# 20: syntax error
- var late x35; //# 21: syntax error
- final late A x36; //# 22: syntax error
- final late x37 = 0; //# 23: syntax error
- int late x38 = 0; //# 24: syntax error
- var late x39 = 0; //# 25: syntax error
- final late A? x40 = null; //# 26: syntax error
-
List foo() {
final x41 = true;
late final x42;
@@ -65,16 +34,20 @@
}
abstract class B {
- m1(int some, regular, covariant parameters, {
- required p1,
- // required p2 = null, // Likely intended to be an error.
- required covariant p3,
- required covariant int p4,
+ m1(
+ int some,
+ regular,
+ covariant parameters, {
+ required p1,
+ required covariant p3,
+ required covariant int p4,
});
}
main() {
A? a;
String? s = '';
- a?..foo().length..x27 = s!.toString().length;
+ a
+ ?..foo().length
+ ..x27 = s!.toString().length;
}
diff --git a/tests/language_2/async_star/async_star2_regression_test.dart b/tests/language_2/async_star/async_star2_regression_test.dart
new file mode 100644
index 0000000..7c8acfc
--- /dev/null
+++ b/tests/language_2/async_star/async_star2_regression_test.dart
@@ -0,0 +1,30 @@
+// 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.
+
+library async_start_test;
+
+import "dart:async";
+
+import "package:expect/expect.dart";
+
+void main() async {
+ var results = [];
+
+ f() async* {
+ yield 0;
+ yield 1;
+ yield 2;
+ }
+
+ //Broken, the value 1 was lost.
+ await for (var i in f()) {
+ results.add(i);
+ if (i == 0) {
+ // This should pause the stream subscription.
+ await Future.delayed(Duration(milliseconds: 500));
+ }
+ }
+
+ Expect.listEquals([0, 1, 2], results);
+}
diff --git a/tests/language_2/async_star/async_star2_test.dart b/tests/language_2/async_star/async_star2_test.dart
deleted file mode 100644
index 72d772e..0000000
--- a/tests/language_2/async_star/async_star2_test.dart
+++ /dev/null
@@ -1,1024 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library async_start_test;
-
-import "dart:async";
-
-import "package:async_helper/async_minitest.dart";
-
-main() {
- group("basic", () {
- test("empty", () {
- f() async* {}
- return f().toList().then((v) {
- expect(v, equals([]));
- });
- });
-
- test("single", () {
- f() async* {
- yield 42;
- }
-
- return f().toList().then((v) {
- expect(v, equals([42]));
- });
- });
-
- test("call delays", () {
- var list = [];
- f() async* {
- list.add(1);
- yield 2;
- }
-
- var res = f().forEach(list.add);
- list.add(0);
- return res.whenComplete(() {
- expect(list, equals([0, 1, 2]));
- });
- });
-
- test("throws", () {
- f() async* {
- yield 1;
- throw 2;
- }
-
- var completer = new Completer();
- var list = [];
- f().listen(list.add,
- onError: (v) => list.add("$v"), onDone: completer.complete);
- return completer.future.whenComplete(() {
- expect(list, equals([1, "2"]));
- });
- });
-
- test("multiple", () {
- f() async* {
- for (int i = 0; i < 10; i++) {
- yield i;
- }
- }
-
- return expectList(f(), new List.generate(10, id));
- });
-
- test("allows await", () {
- f() async* {
- var x = await new Future.value(42);
- yield x;
- x = await new Future.value(42);
- }
-
- return expectList(f(), [42]);
- });
-
- test("allows await in loop", () {
- f() async* {
- for (int i = 0; i < 10; i++) {
- yield await i;
- }
- }
-
- return expectList(f(), new List.generate(10, id));
- });
-
- test("allows yield*", () {
- f() async* {
- yield* new Stream.fromIterable([1, 2, 3]);
- }
-
- return expectList(f(), [1, 2, 3]);
- });
-
- test("allows yield* of async*", () {
- f(n) async* {
- yield n;
- if (n == 0) return;
- yield* f(n - 1);
- yield n;
- }
-
- return expectList(f(3), [3, 2, 1, 0, 1, 2, 3]);
- });
-
- test("Cannot yield* non-stream", () {
- f(Object s) async* {
- yield* s;
- }
-
- return f(42).transform(getErrors).single.then((v) {
- // Not implementing Stream.
- expect(v is Error, isTrue);
- });
- });
-
- test("Cannot yield* non-stream 2", () {
- f(Object s) async* {
- yield* s;
- }
-
- return f(new NotAStream()).transform(getErrors).single.then((v) {
- // Not implementing Stream.
- expect(v is Error, isTrue);
- });
- });
- });
-
- group("yield statement context", () {
- test("plain", () {
- f() async* {
- yield 0;
- }
-
- return expectList(f(), [0]);
- });
-
- test("if-then-else", () {
- f(b) async* {
- if (b)
- yield 0;
- else
- yield 1;
- }
-
- return expectList(f(true), [0]).whenComplete(() {
- expectList(f(false), [1]);
- });
- });
-
- test("block", () {
- f() async* {
- yield 0;
- {
- yield 1;
- }
- yield 2;
- }
-
- return expectList(f(), [0, 1, 2]);
- });
-
- test("labeled", () {
- f() async* {
- label1:
- yield 0;
- }
-
- return expectList(f(), [0]);
- });
-
- // VM issue 2238
- test("labeled 2", () { // //# 01: ok
- f() async* { // //# 01: continued
- label1: label2: yield 0; // //# 01: continued
- } // //# 01: continued
- return expectList(f(), [0]); // //# 01: continued
- }); // //# 01: continued
-
- test("for-loop", () {
- f() async* {
- for (int i = 0; i < 3; i++) yield i;
- }
-
- return expectList(f(), [0, 1, 2]);
- });
-
- test("for-in-loop", () {
- f() async* {
- for (var i in [0, 1, 2]) yield i;
- }
-
- return expectList(f(), [0, 1, 2]);
- });
-
- test("await for-in-loop", () {
- f() async* {
- await for (var i in new Stream.fromIterable([0, 1, 2])) yield i;
- }
-
- return expectList(f(), [0, 1, 2]);
- });
-
- test("while-loop", () {
- f() async* {
- int i = 0;
- while (i < 3) yield i++;
- }
-
- return expectList(f(), [0, 1, 2]);
- });
-
- test("do-while-loop", () {
- f() async* {
- int i = 0;
- do yield i++; while (i < 3);
- }
-
- return expectList(f(), [0, 1, 2]);
- });
-
- test("try-catch-finally", () {
- f() async* {
- try {
- yield 0;
- } catch (e) {
- yield 1;
- } finally {
- yield 2;
- }
- }
-
- return expectList(f(), [0, 2]);
- });
-
- test("try-catch-finally 2", () {
- f() async* {
- try {
- yield throw 0;
- } catch (e) {
- yield 1;
- } finally {
- yield 2;
- }
- }
-
- return expectList(f(), [1, 2]);
- });
-
- test("switch-case", () {
- f(v) async* {
- switch (v) {
- case 0:
- yield 0;
- continue label1;
- label1:
- case 1:
- yield 1;
- break;
- default:
- yield 2;
- }
- }
- return expectList(f(0), [0, 1]).whenComplete(() {
- return expectList(f(1), [1]);
- }).whenComplete(() {
- return expectList(f(2), [2]);
- });
- });
-
- test("dead-code return", () {
- f() async* {
- return;
- yield 1;
- }
-
- return expectList(f(), []);
- });
-
- test("dead-code throw", () {
- f() async* {
- try {
- throw 0;
- yield 1;
- } catch (_) {}
- }
-
- return expectList(f(), []);
- });
-
- test("dead-code break", () {
- f() async* {
- while (true) {
- break;
- yield 1;
- }
- }
-
- return expectList(f(), []);
- });
-
- test("dead-code break 2", () {
- f() async* {
- label:
- {
- break label;
- yield 1;
- }
- }
-
- return expectList(f(), []);
- });
-
- test("dead-code continue", () {
- f() async* {
- do {
- continue;
- yield 1;
- } while (false);
- }
-
- return expectList(f(), []);
- });
- });
-
- group("yield expressions", () {
- test("local variable", () {
- f() async* {
- var x = 42;
- yield x;
- }
-
- return expectList(f(), [42]);
- });
-
- test("constant variable", () {
- f() async* {
- const x = 42;
- yield x;
- }
-
- return expectList(f(), [42]);
- });
-
- test("function call", () {
- g() => 42;
- f() async* {
- yield g();
- }
-
- return expectList(f(), [42]);
- });
-
- test("unary operator", () {
- f() async* {
- var x = -42;
- yield -x;
- }
-
- return expectList(f(), [42]);
- });
-
- test("binary operator", () {
- f() async* {
- var x = 21;
- yield x + x;
- }
-
- return expectList(f(), [42]);
- });
-
- test("ternary operator", () {
- f() async* {
- var x = 21;
- yield x == 21 ? x + x : x;
- }
-
- return expectList(f(), [42]);
- });
-
- test("suffix post-increment", () {
- f() async* {
- var x = 42;
- yield x++;
- }
-
- return expectList(f(), [42]);
- });
-
- test("suffix pre-increment", () {
- f() async* {
- var x = 41;
- yield ++x;
- }
-
- return expectList(f(), [42]);
- });
-
- test("assignment", () {
- f() async* {
- var x = 37;
- yield x = 42;
- }
-
- return expectList(f(), [42]);
- });
-
- test("assignment op", () {
- f() async* {
- var x = 41;
- yield x += 1;
- }
-
- return expectList(f(), [42]);
- });
-
- test("await", () {
- f() async* {
- yield await new Future.value(42);
- }
-
- return expectList(f(), [42]);
- });
-
- test("index operator", () {
- f() async* {
- var x = [42];
- yield x[0];
- }
-
- return expectList(f(), [42]);
- });
-
- test("function expression block", () {
- var o = new Object();
- f() async* {
- yield () {
- return o;
- };
- }
-
- return f().first.then((v) {
- expect(v(), same(o));
- });
- });
-
- test("function expression arrow", () {
- var o = new Object();
- f() async* {
- yield () => o;
- }
-
- return f().first.then((v) {
- expect(v(), same(o));
- });
- });
-
- test("function expression block async", () {
- var o = new Object();
- f() async* {
- yield () async {
- return o;
- };
- }
-
- return f().first.then((v) => v()).then((v) {
- expect(v, same(o));
- });
- });
-
- test("function expression arrow async", () {
- var o = new Object();
- f() async* {
- yield () async => o;
- }
-
- return f().first.then((v) => v()).then((v) {
- expect(v, same(o));
- });
- });
-
- test("function expression block async*", () {
- var o = new Object();
- f() async* {
- yield () async* {
- yield o;
- };
- }
-
- return f().first.then((v) => v().first).then((v) {
- expect(v, same(o));
- });
- });
- });
-
- group("loops", () {
- test("simple yield", () {
- f() async* {
- for (int i = 0; i < 3; i++) {
- yield i;
- }
- }
-
- return expectList(f(), [0, 1, 2]);
- });
-
- test("yield in double loop", () {
- f() async* {
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 2; j++) {
- yield i * 2 + j;
- }
- }
- }
-
- return expectList(f(), [0, 1, 2, 3, 4, 5]);
- });
-
- test("yield in try body", () {
- var list = [];
- f() async* {
- for (int i = 0; i < 3; i++) {
- try {
- yield i;
- } finally {
- list.add("$i");
- }
- }
- }
-
- return expectList(f(), [0, 1, 2]).whenComplete(() {
- expect(list, equals(["0", "1", "2"]));
- });
- });
-
- test("yield in catch", () {
- var list = [];
- f() async* {
- for (int i = 0; i < 3; i++) {
- try {
- throw i;
- } catch (e) {
- yield e;
- } finally {
- list.add("$i");
- }
- }
- }
-
- return expectList(f(), [0, 1, 2]).whenComplete(() {
- expect(list, equals(["0", "1", "2"]));
- });
- });
-
- test("yield in finally", () {
- var list = [];
- f() async* {
- for (int i = 0; i < 3; i++) {
- try {
- throw i;
- } finally {
- yield i;
- list.add("$i");
- continue;
- }
- }
- }
-
- return expectList(f(), [0, 1, 2]).whenComplete(() {
- expect(list, equals(["0", "1", "2"]));
- });
- });
-
- test("keep yielding after cancel", () {
- f() async* {
- for (int i = 0; i < 10; i++) {
- try {
- yield i;
- } finally {
- continue;
- }
- }
- }
-
- return expectList(f().take(3), [0, 1, 2]);
- });
- });
-
- group("canceling", () {
- // Stream.take(n) automatically cancels after seeing the n'th value.
-
- test("cancels at yield", () {
- Completer exits = new Completer();
- var list = [];
- f() async* {
- try {
- list.add(0);
- list.add(1);
- yield null;
- list.add(2);
- } finally {
- exits.complete(3);
- }
- }
-
- // No events must be fired synchronously in response to a listen.
- var subscription = f().listen((v) {
- fail("Received event $v");
- }, onDone: () {
- fail("Received done");
- });
- // No events must be delivered after a cancel.
- subscription.cancel();
- return exits.future.then((v) {
- expect(v, equals(3));
- expect(list, equals([0, 1]));
- });
- });
-
- test("does cancel eventually", () {
- var exits = new Completer();
- var list = [];
- f() async* {
- int i = 0;
- try {
- while (true) yield i++;
- } finally {
- list.add("a");
- exits.complete(i);
- }
- }
-
- return expectList(f().take(5), [0, 1, 2, 3, 4])
- .then((_) => exits.future)
- .then((v) {
- expect(v, greaterThan(4));
- expect(list, ["a"]);
- });
- });
-
- group("at index", () {
- f() async* {
- try {
- yield await new Future.microtask(() => 1);
- } finally {
- try {
- yield await new Future.microtask(() => 2);
- } finally {
- yield await new Future.microtask(() => 3);
- }
- }
- }
-
- test("- all, sanity check", () {
- return expectList(f(), [1, 2, 3]);
- });
- test("after end", () {
- return expectList(f().take(4), [1, 2, 3]);
- });
- test("at end", () {
- return expectList(f().take(3), [1, 2, 3]);
- });
- test("before end", () {
- return expectList(f().take(2), [1, 2]);
- });
- test("early", () {
- return expectList(f().take(1), [1]);
- });
- test("at start", () {
- return expectList(f().take(0), []);
- });
- });
-
- test("regression-fugl/fisk", () {
- var res = [];
- fisk() async* {
- res.add("+fisk");
- try {
- for (int i = 0; i < 2; i++) {
- yield await new Future.microtask(() => i);
- }
- } finally {
- res.add("-fisk");
- }
- }
-
- fugl(int count) async {
- res.add("fisk $count");
- try {
- await for(int i in fisk().take(count)) res.add(i);
- } finally {
- res.add("done");
- }
- }
-
- return fugl(3).whenComplete(() => fugl(2))
- .whenComplete(() => fugl(1))
- .whenComplete(() {
- expect(res, ["fisk 3", "+fisk", 0, 1, "-fisk", "done",
- "fisk 2", "+fisk", 0, 1, "-fisk", "done",
- "fisk 1", "+fisk", 0, "-fisk", "done", ]);
- });
- });
- });
-
- group("pausing", () {
- test("pauses execution at yield for at least a microtask", () {
- var list = [];
- f() async* {
- list.add(1);
- yield 2;
- list.add(3);
- yield 4;
- list.add(5);
- }
-
- var done = new Completer();
- var sub = f().listen((v) {
- if (v == 2) {
- expect(list, equals([1]));
- } else if (v == 4) {
- expect(list, equals([1, 3]));
- } else {
- fail("Unexpected value $v");
- }
- }, onDone: () {
- expect(list, equals([1, 3, 5]));
- done.complete();
- });
- return done.future;
- });
-
- test("pause stops execution at yield", () {
- var list = [];
- f() async* {
- list.add(1);
- yield 2;
- list.add(3);
- yield 4;
- list.add(5);
- }
-
- var done = new Completer();
- var sub;
- sub = f().listen((v) {
- if (v == 2) {
- expect(list, equals([1]));
- sub.pause();
- new Timer(MS * 300, () {
- expect(list.length, lessThan(3));
- sub.resume();
- });
- } else if (v == 4) {
- expect(list, equals([1, 3]));
- } else {
- fail("Unexpected value $v");
- }
- }, onDone: () {
- expect(list, equals([1, 3, 5]));
- done.complete();
- });
- return done.future;
- });
-
- test("pause stops execution at yield 2", () {
- var list = [];
- f() async* {
- int i = 0;
- while (true) {
- yield i;
- list.add(i);
- i++;
- }
- }
-
- int expected = 0;
- var done = new Completer();
- var sub;
- sub = f().listen((v) {
- expect(v, equals(expected++));
- if (v % 5 == 0) {
- sub.pause(new Future.delayed(MS * 300));
- } else if (v == 17) {
- sub.cancel();
- done.complete();
- }
- }, onDone: () {
- fail("Unexpected done!");
- });
- return done.future.whenComplete(() {
- expect(list.length == 18 || list.length == 19, isTrue);
- });
- });
-
- test("canceling while paused at yield", () { // //# 02: ok
- var list = []; // //# 02: continued
- var sync = new Sync(); // //# 02: continued
- f() async* { // //# 02: continued
- list.add("*1"); // //# 02: continued
- yield 1; // //# 02: continued
- await sync.wait(); // //# 02: continued
- sync.release(); // //# 02: continued
- list.add("*2"); // //# 02: continued
- yield 2; // //# 02: continued
- list.add("*3"); // //# 02: continued
- }; // //# 02: continued
- var stream = f(); // //# 02: continued
- // TODO(jmesserly): added workaround for:
- // https://github.com/dart-lang/dev_compiler/issues/269
- var sub = stream.listen((x) => list.add(x)); // //# 02: continued
- return sync.wait().whenComplete(() { // //# 02: continued
- expect(list, equals(["*1", 1])); // //# 02: continued
- sub.pause(); // //# 02: continued
- return sync.wait(); // //# 02: continued
- }).whenComplete(() { // //# 02: continued
- expect(list, equals(["*1", 1, "*2"])); // //# 02: continued
- sub.cancel(); // //# 02: continued
- return new Future.delayed(MS * 200, () { // //# 02: continued
- // Should not have yielded 2 or added *3 while paused. // //# 02: continued
- expect(list, equals(["*1", 1, "*2"])); // //# 02: continued
- }); // //# 02: continued
- }); // //# 02: continued
- }); // //# 02: continued
- });
-
- group("await for", () {
- mkStream(int n) async* {
- for (int i = 0; i < n; i++) yield i;
- }
-
- test("simple stream", () {
- f(s) async {
- var r = 0;
- await for (var v in s) r += v;
- return r;
- }
-
- return f(mkStream(5)).then((v) {
- expect(v, equals(10));
- });
- });
-
- test("simple stream, await", () {
- f(s) async {
- var r = 0;
- await for (var v in s) r += await new Future.microtask(() => v);
- return r;
- }
-
- return f(mkStream(5)).then((v) {
- expect(v, equals(10));
- });
- });
-
- test("simple stream - take", () { // //# 03: ok
- f(s) async { // //# 03: continued
- var r = 0; // //# 03: continued
- await for(var v in s.take(5)) r += v; // //# 03: continued
- return r; // //# 03: continued
- } // //# 03: continued
- return f(mkStream(10)).then((v) { // //# 03: continued
- expect(v, equals(10)); // //# 03: continued
- }); // //# 03: continued
- }); // //# 03: continued
-
- test("simple stream reyield", () {
- f(s) async* {
- var r = 0;
- await for (var v in s) yield r += v;
- }
-
- return expectList(f(mkStream(5)), [0, 1, 3, 6, 10]);
- });
-
- test("simple stream, await, reyield", () {
- f(s) async* {
- var r = 0;
- await for (var v in s) yield r += await new Future.microtask(() => v);
- }
-
- return expectList(f(mkStream(5)), [0, 1, 3, 6, 10]);
- });
-
- test("simple stream - take, reyield", () { // //# 04: ok
- f(s) async* { // //# 04: continued
- var r = 0; // //# 04: continued
- await for(var v in s.take(5)) yield r += v; // //# 04: continued
- } // //# 04: continued
- return expectList(f(mkStream(10)), [0, 1, 3, 6, 10]); // //# 04: continued
- }); // //# 04: continued
-
- test("nested", () {
- f() async {
- var r = 0;
- await for (var i in mkStream(5)) {
- await for (var j in mkStream(3)) {
- r += i * j;
- }
- }
- return r;
- }
-
- return f().then((v) {
- expect(v, equals((1 + 2 + 3 + 4) * (1 + 2)));
- });
- });
-
- test("nested, await", () {
- f() async {
- var r = 0;
- await for (var i in mkStream(5)) {
- await for (var j in mkStream(3)) {
- r += await new Future.microtask(() => i * j);
- }
- }
- return r;
- }
-
- return f().then((v) {
- expect(v, equals((1 + 2 + 3 + 4) * (1 + 2)));
- });
- });
-
- test("nested, await * 2", () {
- f() async {
- var r = 0;
- await for (var i in mkStream(5)) {
- var ai = await new Future.microtask(() => i);
- await for (var j in mkStream(3)) {
- r += await new Future.microtask(() => ai * j);
- }
- }
- return r;
- }
-
- return f().then((v) {
- expect(v, equals((1 + 2 + 3 + 4) * (1 + 2)));
- });
- });
-
- test("await pauses loop", () { // //# 05: ok
- var sc; // //# 05: continued
- var i = 0; // //# 05: continued
- void send() { // //# 05: continued
- if (i == 5) { // //# 05: continued
- sc.close(); // //# 05: continued
- } else { // //# 05: continued
- sc.add(i++); // //# 05: continued
- } // //# 05: continued
- } // //# 05: continued
- sc = new StreamController(onListen: send, onResume: send); // //# 05: continued
- f(s) async { // //# 05: continued
- var r = 0; // //# 05: continued
- await for (var i in s) { // //# 05: continued
- r += await new Future.delayed(MS * 10, () => i); // //# 05: continued
- } // //# 05: continued
- return r; // //# 05: continued
- } // //# 05: continued
- return f(sc.stream).then((v) { // //# 05: continued
- expect(v, equals(10)); // //# 05: continued
- }); // //# 05: continued
- }); // //# 05: continued
- });
-}
-
-// Obscuring identity function.
-id(x) {
- try {
- if (x != null) throw x;
- } catch (e) {
- return e;
- }
- return null;
-}
-
-expectList(stream, list) {
- return stream.toList().then((v) {
- expect(v, equals(list));
- });
-}
-
-const MS = const Duration(milliseconds: 1);
-
-StreamTransformer getErrors = new StreamTransformer.fromHandlers(handleData: (data, sink) {
- fail("Unexpected value");
-}, handleError: (e, s, sink) {
- sink.add(e);
-}, handleDone: (sink) {
- sink.close();
-});
-
-class NotAStream {
- listen(oData, {onError, onDone, cancelOnError}) {
- fail("Not implementing Stream.");
- }
-}
-
-/**
- * Allows two asynchronous executions to synchronize.
- *
- * Calling [wait] and waiting for the returned future to complete will
- * wait for the other executions to call [wait] again. At that point,
- * the waiting execution is allowed to continue (the returned future completes),
- * and the more resent call to [wait] is now the waiting execution.
- */
-class Sync {
- Completer _completer = null;
- // Release whoever is currently waiting and start waiting yourself.
- Future wait([v]) {
- if (_completer != null) _completer.complete(v);
- _completer = new Completer();
- return _completer.future;
- }
-
- // Release whoever is currently waiting.
- void release([v]) {
- if (_completer != null) {
- _completer.complete(v);
- _completer = null;
- }
- }
-}
diff --git a/tests/language_2/async_star/await_for_test.dart b/tests/language_2/async_star/await_for_test.dart
new file mode 100644
index 0000000..fb99084
--- /dev/null
+++ b/tests/language_2/async_star/await_for_test.dart
@@ -0,0 +1,148 @@
+// 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 'package:async_helper/async_minitest.dart';
+
+import 'utils.dart';
+
+main() {
+ test('simple stream', () {
+ f(s) async {
+ var r = 0;
+ await for (var v in s) r += v;
+ return r;
+ }
+
+ return f(mkStream(5)).then((v) {
+ expect(v, equals(10));
+ });
+ });
+
+ test('simple stream, await', () {
+ f(s) async {
+ var r = 0;
+ await for (var v in s) r += await Future.microtask(() => v);
+ return r;
+ }
+
+ return f(mkStream(5)).then((v) {
+ expect(v, equals(10));
+ });
+ });
+
+ test('simple stream - take', () {
+ f(s) async {
+ var r = 0;
+ await for (var v in s.take(5)) r += v;
+ return r;
+ }
+
+ return f(mkStream(10)).then((v) {
+ expect(v, equals(10));
+ });
+ });
+
+ test('simple stream reyield', () {
+ f(s) async* {
+ var r = 0;
+ await for (var v in s) yield r += v;
+ }
+
+ return expectList(f(mkStream(5)), [0, 1, 3, 6, 10]);
+ });
+
+ test('simple stream, await, reyield', () {
+ f(s) async* {
+ var r = 0;
+ await for (var v in s) yield r += await Future.microtask(() => v);
+ }
+
+ return expectList(f(mkStream(5)), [0, 1, 3, 6, 10]);
+ });
+
+ test('simple stream - take, reyield', () {
+ f(s) async* {
+ var r = 0;
+ await for (var v in s.take(5)) yield r += v;
+ }
+
+ return expectList(f(mkStream(10)), [0, 1, 3, 6, 10]);
+ });
+
+ test('nested', () {
+ f() async {
+ var r = 0;
+ await for (var i in mkStream(5)) {
+ await for (var j in mkStream(3)) {
+ r += i * j;
+ }
+ }
+ return r;
+ }
+
+ return f().then((v) {
+ expect(v, equals((1 + 2 + 3 + 4) * (1 + 2)));
+ });
+ });
+
+ test('nested, await', () {
+ f() async {
+ var r = 0;
+ await for (var i in mkStream(5)) {
+ await for (var j in mkStream(3)) {
+ r += await Future.microtask(() => i * j);
+ }
+ }
+ return r;
+ }
+
+ return f().then((v) {
+ expect(v, equals((1 + 2 + 3 + 4) * (1 + 2)));
+ });
+ });
+
+ test('nested, await * 2', () {
+ f() async {
+ var r = 0;
+ await for (var i in mkStream(5)) {
+ var ai = await Future.microtask(() => i);
+ await for (var j in mkStream(3)) {
+ r += await Future.microtask(() => ai * j);
+ }
+ }
+ return r;
+ }
+
+ return f().then((v) {
+ expect(v, equals((1 + 2 + 3 + 4) * (1 + 2)));
+ });
+ });
+
+ test('await pauses loop', () {
+ var sc;
+ var i = 0;
+ void send() {
+ if (i == 5) {
+ sc.close();
+ } else {
+ sc.add(i++);
+ }
+ }
+
+ sc = StreamController(onListen: send, onResume: send);
+ f(s) async {
+ var r = 0;
+ await for (var i in s) {
+ r += await Future.delayed(ms * 10, () => i);
+ }
+ return r;
+ }
+
+ return f(sc.stream).then((v) {
+ expect(v, equals(10));
+ });
+ });
+}
diff --git a/tests/language_2/async_star/basic_test.dart b/tests/language_2/async_star/basic_test.dart
new file mode 100644
index 0000000..73a956d
--- /dev/null
+++ b/tests/language_2/async_star/basic_test.dart
@@ -0,0 +1,153 @@
+// 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 'package:async_helper/async_minitest.dart';
+
+import 'utils.dart';
+
+class NotAStream {
+ listen(oData, {onError, onDone, cancelOnError}) {
+ fail('Not implementing Stream.');
+ }
+}
+
+StreamTransformer getErrors =
+ StreamTransformer.fromHandlers(handleData: (data, sink) {
+ fail('Unexpected value');
+}, handleError: (e, s, sink) {
+ sink.add(e);
+}, handleDone: (sink) {
+ sink.close();
+});
+
+// Obscuring identity function.
+id(x) {
+ try {
+ if (x != null) throw x;
+ } catch (e) {
+ return e;
+ }
+ return null;
+}
+
+main() {
+ test('empty', () {
+ f() async* {}
+ return f().toList().then((v) {
+ expect(v, equals([]));
+ });
+ });
+
+ test('single', () {
+ f() async* {
+ yield 42;
+ }
+
+ return f().toList().then((v) {
+ expect(v, equals([42]));
+ });
+ });
+
+ test('call delays', () {
+ var list = [];
+ f() async* {
+ list.add(1);
+ yield 2;
+ }
+
+ var res = f().forEach(list.add);
+ list.add(0);
+ return res.whenComplete(() {
+ expect(list, equals([0, 1, 2]));
+ });
+ });
+
+ test('throws', () {
+ f() async* {
+ yield 1;
+ throw 2;
+ }
+
+ var completer = Completer();
+ var list = [];
+ f().listen(list.add,
+ onError: (v) => list.add('$v'), onDone: completer.complete);
+ return completer.future.whenComplete(() {
+ expect(list, equals([1, '2']));
+ });
+ });
+
+ test('multiple', () {
+ f() async* {
+ for (int i = 0; i < 10; i++) {
+ yield i;
+ }
+ }
+
+ return expectList(f(), List.generate(10, id));
+ });
+
+ test('allows await', () {
+ f() async* {
+ var x = await Future.value(42);
+ yield x;
+ x = await Future.value(42);
+ }
+
+ return expectList(f(), [42]);
+ });
+
+ test('allows await in loop', () {
+ f() async* {
+ for (int i = 0; i < 10; i++) {
+ yield await i;
+ }
+ }
+
+ return expectList(f(), List.generate(10, id));
+ });
+
+ test('allows yield*', () {
+ f() async* {
+ yield* Stream.fromIterable([1, 2, 3]);
+ }
+
+ return expectList(f(), [1, 2, 3]);
+ });
+
+ test('allows yield* of async*', () {
+ f(n) async* {
+ yield n;
+ if (n == 0) return;
+ yield* f(n - 1);
+ yield n;
+ }
+
+ return expectList(f(3), [3, 2, 1, 0, 1, 2, 3]);
+ });
+
+ test('Cannot yield* non-stream', () {
+ f(Object s) async* {
+ yield* s;
+ }
+
+ return f(42).transform(getErrors).single.then((v) {
+ // Not implementing Stream.
+ expect(v is Error, isTrue);
+ });
+ });
+
+ test('Cannot yield* non-stream 2', () {
+ f(Object s) async* {
+ yield* s;
+ }
+
+ return f(NotAStream()).transform(getErrors).single.then((v) {
+ // Not implementing Stream.
+ expect(v is Error, isTrue);
+ });
+ });
+}
diff --git a/tests/language_2/async_star/cancel_test.dart b/tests/language_2/async_star/cancel_test.dart
new file mode 100644
index 0000000..18c2787
--- /dev/null
+++ b/tests/language_2/async_star/cancel_test.dart
@@ -0,0 +1,142 @@
+// 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 'package:async_helper/async_minitest.dart';
+
+import 'utils.dart';
+
+main() {
+ // Stream.take(n) automatically cancels after seeing the n'th value.
+ test('cancels at yield', () {
+ Completer exits = Completer();
+ var list = [];
+ f() async* {
+ try {
+ list.add(0);
+ list.add(1);
+ yield null;
+ list.add(2);
+ } finally {
+ exits.complete(3);
+ }
+ }
+
+ // No events must be fired synchronously in response to a listen.
+ var subscription = f().listen((v) {
+ fail('Received event $v');
+ }, onDone: () {
+ fail('Received done');
+ });
+ // No events must be delivered after a cancel.
+ subscription.cancel();
+ return exits.future.then((v) {
+ expect(v, equals(3));
+ expect(list, equals([0, 1]));
+ });
+ });
+
+ test('does cancel eventually', () {
+ var exits = Completer();
+ var list = [];
+ f() async* {
+ int i = 0;
+ try {
+ while (true) yield i++;
+ } finally {
+ list.add('a');
+ exits.complete(i);
+ }
+ }
+
+ return expectList(f().take(5), [0, 1, 2, 3, 4])
+ .then((_) => exits.future)
+ .then((v) {
+ expect(v, greaterThan(4));
+ expect(list, ['a']);
+ });
+ });
+
+ group('at index', () {
+ f() async* {
+ try {
+ yield await Future.microtask(() => 1);
+ } finally {
+ try {
+ yield await Future.microtask(() => 2);
+ } finally {
+ yield await Future.microtask(() => 3);
+ }
+ }
+ }
+
+ test('- all, sanity check', () {
+ return expectList(f(), [1, 2, 3]);
+ });
+ test('after end', () {
+ return expectList(f().take(4), [1, 2, 3]);
+ });
+ test('at end', () {
+ return expectList(f().take(3), [1, 2, 3]);
+ });
+ test('before end', () {
+ return expectList(f().take(2), [1, 2]);
+ });
+ test('early', () {
+ return expectList(f().take(1), [1]);
+ });
+ test('at start', () {
+ return expectList(f().take(0), []);
+ });
+ });
+
+ test('regression-fugl/fisk', () {
+ var res = [];
+ fisk() async* {
+ res.add('+fisk');
+ try {
+ for (int i = 0; i < 2; i++) {
+ yield await Future.microtask(() => i);
+ }
+ } finally {
+ res.add('-fisk');
+ }
+ }
+
+ fugl(int count) async {
+ res.add('fisk $count');
+ try {
+ await for (int i in fisk().take(count)) res.add(i);
+ } finally {
+ res.add('done');
+ }
+ }
+
+ return fugl(3)
+ .whenComplete(() => fugl(2))
+ .whenComplete(() => fugl(1))
+ .whenComplete(() {
+ expect(res, [
+ 'fisk 3',
+ '+fisk',
+ 0,
+ 1,
+ '-fisk',
+ 'done',
+ 'fisk 2',
+ '+fisk',
+ 0,
+ 1,
+ '-fisk',
+ 'done',
+ 'fisk 1',
+ '+fisk',
+ 0,
+ '-fisk',
+ 'done',
+ ]);
+ });
+ });
+}
diff --git a/tests/language_2/async_star/cancel_while_paused_at_yield_test.dart b/tests/language_2/async_star/cancel_while_paused_at_yield_test.dart
new file mode 100644
index 0000000..af7e846
--- /dev/null
+++ b/tests/language_2/async_star/cancel_while_paused_at_yield_test.dart
@@ -0,0 +1,42 @@
+// 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 'package:async_helper/async_minitest.dart';
+
+import 'utils.dart';
+
+main() {
+ test('canceling while paused at yield', () {
+ var list = [];
+ var sync = Sync();
+ f() async* {
+ list.add('*1');
+ yield 1;
+ await sync.wait();
+ sync.release();
+ list.add('*2');
+ yield 2;
+ list.add('*3');
+ }
+
+ var stream = f();
+ // TODO(jmesserly): added workaround for:
+ // https://github.com/dart-lang/dev_compiler/issues/269
+ var sub = stream.listen((x) => list.add(x));
+ return sync.wait().whenComplete(() {
+ expect(list, equals(['*1', 1]));
+ sub.pause();
+ return sync.wait();
+ }).whenComplete(() {
+ expect(list, equals(['*1', 1, '*2']));
+ sub.cancel();
+ return Future.delayed(ms * 200, () {
+ // Should not have yielded 2 or added *3 while paused.
+ expect(list, equals(['*1', 1, '*2']));
+ });
+ });
+ });
+}
diff --git a/tests/language_2/async_star/loops_test.dart b/tests/language_2/async_star/loops_test.dart
new file mode 100644
index 0000000..8d6df7c
--- /dev/null
+++ b/tests/language_2/async_star/loops_test.dart
@@ -0,0 +1,100 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:async_helper/async_minitest.dart';
+
+import 'utils.dart';
+
+main() {
+ test('simple yield', () {
+ f() async* {
+ for (int i = 0; i < 3; i++) {
+ yield i;
+ }
+ }
+
+ return expectList(f(), [0, 1, 2]);
+ });
+
+ test('yield in double loop', () {
+ f() async* {
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 2; j++) {
+ yield i * 2 + j;
+ }
+ }
+ }
+
+ return expectList(f(), [0, 1, 2, 3, 4, 5]);
+ });
+
+ test('yield in try body', () {
+ var list = [];
+ f() async* {
+ for (int i = 0; i < 3; i++) {
+ try {
+ yield i;
+ } finally {
+ list.add('$i');
+ }
+ }
+ }
+
+ return expectList(f(), [0, 1, 2]).whenComplete(() {
+ expect(list, equals(['0', '1', '2']));
+ });
+ });
+
+ test('yield in catch', () {
+ var list = [];
+ f() async* {
+ for (int i = 0; i < 3; i++) {
+ try {
+ throw i;
+ } catch (e) {
+ yield e;
+ } finally {
+ list.add('$i');
+ }
+ }
+ }
+
+ return expectList(f(), [0, 1, 2]).whenComplete(() {
+ expect(list, equals(['0', '1', '2']));
+ });
+ });
+
+ test('yield in finally', () {
+ var list = [];
+ f() async* {
+ for (int i = 0; i < 3; i++) {
+ try {
+ throw i;
+ } finally {
+ yield i;
+ list.add('$i');
+ continue;
+ }
+ }
+ }
+
+ return expectList(f(), [0, 1, 2]).whenComplete(() {
+ expect(list, equals(['0', '1', '2']));
+ });
+ });
+
+ test('keep yielding after cancel', () {
+ f() async* {
+ for (int i = 0; i < 10; i++) {
+ try {
+ yield i;
+ } finally {
+ continue;
+ }
+ }
+ }
+
+ return expectList(f().take(3), [0, 1, 2]);
+ });
+}
diff --git a/tests/language_2/async_star/pause_test2.dart b/tests/language_2/async_star/pause_test2.dart
new file mode 100644
index 0000000..a240d3d
--- /dev/null
+++ b/tests/language_2/async_star/pause_test2.dart
@@ -0,0 +1,99 @@
+// 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 'package:async_helper/async_minitest.dart';
+
+import 'utils.dart';
+
+main() {
+ test('pauses execution at yield for at least a microtask', () {
+ var list = [];
+ f() async* {
+ list.add(1);
+ yield 2;
+ list.add(3);
+ yield 4;
+ list.add(5);
+ }
+
+ var done = Completer();
+ var sub = f().listen((v) {
+ if (v == 2) {
+ expect(list, equals([1]));
+ } else if (v == 4) {
+ expect(list, equals([1, 3]));
+ } else {
+ fail('Unexpected value $v');
+ }
+ }, onDone: () {
+ expect(list, equals([1, 3, 5]));
+ done.complete();
+ });
+ return done.future;
+ });
+
+ test('pause stops execution at yield', () {
+ var list = [];
+ f() async* {
+ list.add(1);
+ yield 2;
+ list.add(3);
+ yield 4;
+ list.add(5);
+ }
+
+ var done = Completer();
+ var sub;
+ sub = f().listen((v) {
+ if (v == 2) {
+ expect(list, equals([1]));
+ sub.pause();
+ Timer(ms * 300, () {
+ expect(list.length, lessThan(3));
+ sub.resume();
+ });
+ } else if (v == 4) {
+ expect(list, equals([1, 3]));
+ } else {
+ fail('Unexpected value $v');
+ }
+ }, onDone: () {
+ expect(list, equals([1, 3, 5]));
+ done.complete();
+ });
+ return done.future;
+ });
+
+ test('pause stops execution at yield 2', () {
+ var list = [];
+ f() async* {
+ int i = 0;
+ while (true) {
+ yield i;
+ list.add(i);
+ i++;
+ }
+ }
+
+ int expected = 0;
+ var done = Completer();
+ var sub;
+ sub = f().listen((v) {
+ expect(v, equals(expected++));
+ if (v % 5 == 0) {
+ sub.pause(Future.delayed(ms * 300));
+ } else if (v == 17) {
+ sub.cancel();
+ done.complete();
+ }
+ }, onDone: () {
+ fail('Unexpected done!');
+ });
+ return done.future.whenComplete(() {
+ expect(list.length == 18 || list.length == 19, isTrue);
+ });
+ });
+}
diff --git a/tests/language_2/async_star/utils.dart b/tests/language_2/async_star/utils.dart
new file mode 100644
index 0000000..dfd97de
--- /dev/null
+++ b/tests/language_2/async_star/utils.dart
@@ -0,0 +1,43 @@
+// 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 'package:async_helper/async_minitest.dart';
+
+const ms = const Duration(milliseconds: 1);
+
+/// Allows two asynchronous executions to synchronize.
+///
+/// Calling [wait] and waiting for the returned future to complete will wait for
+/// the other executions to call [wait] again. At that point, the waiting
+/// execution is allowed to continue (the returned future completes), and the
+/// more resent call to [wait] is now the waiting execution.
+class Sync {
+ Completer _completer = null;
+ // Release whoever is currently waiting and start waiting yourself.
+ Future wait([v]) {
+ if (_completer != null) _completer.complete(v);
+ _completer = Completer();
+ return _completer.future;
+ }
+
+ // Release whoever is currently waiting.
+ void release([v]) {
+ if (_completer != null) {
+ _completer.complete(v);
+ _completer = null;
+ }
+ }
+}
+
+expectList(stream, list) {
+ return stream.toList().then((v) {
+ expect(v, equals(list));
+ });
+}
+
+mkStream(int n) async* {
+ for (int i = 0; i < n; i++) yield i;
+}
diff --git a/tests/language_2/async_star/yield_expressions_test.dart b/tests/language_2/async_star/yield_expressions_test.dart
new file mode 100644
index 0000000..fe3578e
--- /dev/null
+++ b/tests/language_2/async_star/yield_expressions_test.dart
@@ -0,0 +1,177 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:async_helper/async_minitest.dart';
+
+import 'utils.dart';
+
+main() {
+ test('local variable', () {
+ f() async* {
+ var x = 42;
+ yield x;
+ }
+
+ return expectList(f(), [42]);
+ });
+
+ test('constant variable', () {
+ f() async* {
+ const x = 42;
+ yield x;
+ }
+
+ return expectList(f(), [42]);
+ });
+
+ test('function call', () {
+ g() => 42;
+ f() async* {
+ yield g();
+ }
+
+ return expectList(f(), [42]);
+ });
+
+ test('unary operator', () {
+ f() async* {
+ var x = -42;
+ yield -x;
+ }
+
+ return expectList(f(), [42]);
+ });
+
+ test('binary operator', () {
+ f() async* {
+ var x = 21;
+ yield x + x;
+ }
+
+ return expectList(f(), [42]);
+ });
+
+ test('ternary operator', () {
+ f() async* {
+ var x = 21;
+ yield x == 21 ? x + x : x;
+ }
+
+ return expectList(f(), [42]);
+ });
+
+ test('suffix post-increment', () {
+ f() async* {
+ var x = 42;
+ yield x++;
+ }
+
+ return expectList(f(), [42]);
+ });
+
+ test('suffix pre-increment', () {
+ f() async* {
+ var x = 41;
+ yield ++x;
+ }
+
+ return expectList(f(), [42]);
+ });
+
+ test('assignment', () {
+ f() async* {
+ var x = 37;
+ yield x = 42;
+ }
+
+ return expectList(f(), [42]);
+ });
+
+ test('assignment op', () {
+ f() async* {
+ var x = 41;
+ yield x += 1;
+ }
+
+ return expectList(f(), [42]);
+ });
+
+ test('await', () {
+ f() async* {
+ yield await Future.value(42);
+ }
+
+ return expectList(f(), [42]);
+ });
+
+ test('index operator', () {
+ f() async* {
+ var x = [42];
+ yield x[0];
+ }
+
+ return expectList(f(), [42]);
+ });
+
+ test('function expression block', () {
+ var o = Object();
+ f() async* {
+ yield () {
+ return o;
+ };
+ }
+
+ return f().first.then((v) {
+ expect(v(), same(o));
+ });
+ });
+
+ test('function expression arrow', () {
+ var o = Object();
+ f() async* {
+ yield () => o;
+ }
+
+ return f().first.then((v) {
+ expect(v(), same(o));
+ });
+ });
+
+ test('function expression block async', () {
+ var o = Object();
+ f() async* {
+ yield () async {
+ return o;
+ };
+ }
+
+ return f().first.then((v) => v()).then((v) {
+ expect(v, same(o));
+ });
+ });
+
+ test('function expression arrow async', () {
+ var o = Object();
+ f() async* {
+ yield () async => o;
+ }
+
+ return f().first.then((v) => v()).then((v) {
+ expect(v, same(o));
+ });
+ });
+
+ test('function expression block async*', () {
+ var o = Object();
+ f() async* {
+ yield () async* {
+ yield o;
+ };
+ }
+
+ return f().first.then((v) => v().first).then((v) {
+ expect(v, same(o));
+ });
+ });
+}
diff --git a/tests/language_2/async_star/yield_statement_context_test.dart b/tests/language_2/async_star/yield_statement_context_test.dart
new file mode 100644
index 0000000..7320f02
--- /dev/null
+++ b/tests/language_2/async_star/yield_statement_context_test.dart
@@ -0,0 +1,207 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:async_helper/async_minitest.dart';
+
+import 'utils.dart';
+
+void main() {
+ test('plain', () {
+ f() async* {
+ yield 0;
+ }
+
+ return expectList(f(), [0]);
+ });
+
+ test('if-then-else', () {
+ f(b) async* {
+ if (b)
+ yield 0;
+ else
+ yield 1;
+ }
+
+ return expectList(f(true), [0]).whenComplete(() {
+ expectList(f(false), [1]);
+ });
+ });
+
+ test('block', () {
+ f() async* {
+ yield 0;
+ {
+ yield 1;
+ }
+ yield 2;
+ }
+
+ return expectList(f(), [0, 1, 2]);
+ });
+
+ test('labeled', () {
+ f() async* {
+ label1:
+ yield 0;
+ }
+
+ return expectList(f(), [0]);
+ });
+
+ test('two labels on same line', () {
+ f() async* {
+ // DO NOT RUN dartfmt on this file. The labels should be on the same.
+ // line. Originally VM issue #2238.
+ label1: label2: yield 0;
+ }
+
+ return expectList(f(), [0]);
+ });
+
+ test('for-loop', () {
+ f() async* {
+ for (int i = 0; i < 3; i++) yield i;
+ }
+
+ return expectList(f(), [0, 1, 2]);
+ });
+
+ test('for-in-loop', () {
+ f() async* {
+ for (var i in [0, 1, 2]) yield i;
+ }
+
+ return expectList(f(), [0, 1, 2]);
+ });
+
+ test('await for-in-loop', () {
+ f() async* {
+ await for (var i in Stream.fromIterable([0, 1, 2])) yield i;
+ }
+
+ return expectList(f(), [0, 1, 2]);
+ });
+
+ test('while-loop', () {
+ f() async* {
+ int i = 0;
+ while (i < 3) yield i++;
+ }
+
+ return expectList(f(), [0, 1, 2]);
+ });
+
+ test('do-while-loop', () {
+ f() async* {
+ int i = 0;
+ do yield i++; while (i < 3);
+ }
+
+ return expectList(f(), [0, 1, 2]);
+ });
+
+ test('try-catch-finally', () {
+ f() async* {
+ try {
+ yield 0;
+ } catch (e) {
+ yield 1;
+ } finally {
+ yield 2;
+ }
+ }
+
+ return expectList(f(), [0, 2]);
+ });
+
+ test('try-catch-finally 2', () {
+ f() async* {
+ try {
+ yield throw 0;
+ } catch (e) {
+ yield 1;
+ } finally {
+ yield 2;
+ }
+ }
+
+ return expectList(f(), [1, 2]);
+ });
+
+ test('switch-case', () {
+ f(v) async* {
+ switch (v) {
+ case 0:
+ yield 0;
+ continue label1;
+ label1:
+ case 1:
+ yield 1;
+ break;
+ default:
+ yield 2;
+ }
+ }
+
+ return expectList(f(0), [0, 1]).whenComplete(() {
+ return expectList(f(1), [1]);
+ }).whenComplete(() {
+ return expectList(f(2), [2]);
+ });
+ });
+
+ test('dead-code return', () {
+ f() async* {
+ return;
+ yield 1;
+ }
+
+ return expectList(f(), []);
+ });
+
+ test('dead-code throw', () {
+ f() async* {
+ try {
+ throw 0;
+ yield 1;
+ } catch (_) {}
+ }
+
+ return expectList(f(), []);
+ });
+
+ test('dead-code break', () {
+ f() async* {
+ while (true) {
+ break;
+ yield 1;
+ }
+ }
+
+ return expectList(f(), []);
+ });
+
+ test('dead-code break 2', () {
+ f() async* {
+ label:
+ {
+ break label;
+ yield 1;
+ }
+ }
+
+ return expectList(f(), []);
+ });
+
+ test('dead-code continue', () {
+ f() async* {
+ do {
+ continue;
+ yield 1;
+ } while (false);
+ }
+
+ return expectList(f(), []);
+ });
+}
diff --git a/tests/language_2/language_2_kernel.status b/tests/language_2/language_2_kernel.status
index 3910863..dce25e7 100644
--- a/tests/language_2/language_2_kernel.status
+++ b/tests/language_2/language_2_kernel.status
@@ -113,10 +113,6 @@
[ $mode == debug && $runtime == vm && ($compiler == app_jitk || $compiler == dartk || $compiler == dartkb) ]
optimize/deopt_inlined_function_lazy_test: Skip
-[ $mode == debug && $hot_reload && ($compiler == dartk || $compiler == dartkb) ]
-async_star/async_star2_test/01: Crash
-async_star/async_star2_test/05: Crash
-
[ $mode == debug && ($compiler == dartk || $compiler == dartkb) && ($hot_reload || $hot_reload_rollback) ]
enum/duplicate_test/02: Crash # Issue 34606
enum/duplicate_test/none: Crash # Issue 34606
@@ -142,10 +138,4 @@
symbol/conflict_test: Slow
[ ($compiler == dartk || $compiler == dartkb) && ($hot_reload || $hot_reload_rollback) ]
-async_star/async_star2_test/01: Skip # Timeout
-async_star/async_star2_test/02: Skip # Timeout
-async_star/async_star2_test/03: Skip # Timeout
-async_star/async_star2_test/04: Skip # Timeout
-async_star/async_star2_test/05: Skip # Timeout
-async_star/async_star2_test/none: Skip # Timeout
type_constants_test/none: Skip # Deferred libraries and hot reload.
diff --git a/tests/language_2/regress/regress40066_test.dart b/tests/language_2/regress/regress40066_test.dart
new file mode 100644
index 0000000..caa08a4
--- /dev/null
+++ b/tests/language_2/regress/regress40066_test.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+class A<T> {
+ foo(T x) {
+ print('T = $T');
+ print('x.runtimeType = ${x.runtimeType}');
+ print('x is T = ${x is T}');
+ }
+}
+
+typedef IntFunc = void Function(int);
+typedef StringFunc = void Function(String);
+
+void main() {
+ void inner<S>(S y) {}
+
+ IntFunc innerOfInt = inner;
+ A a = new A<IntFunc>();
+ a.foo(innerOfInt);
+
+ StringFunc innerOfString = inner;
+ Expect.throwsTypeError(() {
+ a.foo(innerOfString);
+ });
+}
diff --git a/tests/lib/wasm/basic_test.dart b/tests/lib/wasm/basic_test.dart
new file mode 100644
index 0000000..b6dfaa9
--- /dev/null
+++ b/tests/lib/wasm/basic_test.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that we can load a wasm module, find a function, and call it.
+
+import "package:expect/expect.dart";
+import "dart:wasm";
+import "dart:typed_data";
+
+void main() {
+ // int64_t square(int64_t n) { return n * n; }
+ var data = Uint8List.fromList([
+ 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60,
+ 0x01, 0x7e, 0x01, 0x7e, 0x03, 0x02, 0x01, 0x00, 0x04, 0x05, 0x01, 0x70,
+ 0x01, 0x01, 0x01, 0x05, 0x03, 0x01, 0x00, 0x02, 0x06, 0x08, 0x01, 0x7f,
+ 0x01, 0x41, 0x80, 0x88, 0x04, 0x0b, 0x07, 0x13, 0x02, 0x06, 0x6d, 0x65,
+ 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00, 0x06, 0x73, 0x71, 0x75, 0x61, 0x72,
+ 0x65, 0x00, 0x00, 0x0a, 0x09, 0x01, 0x07, 0x00, 0x20, 0x00, 0x20, 0x00,
+ 0x7e, 0x0b,
+ ]);
+
+ var inst = WasmModule(data).instantiate(WasmImports());
+ var fn = inst.lookupFunction<Int64 Function(Int64)>("square");
+ int n = fn.call([1234]);
+
+ Expect.equals(1234 * 1234, n);
+}
diff --git a/tests/lib/wasm/corrupted_error_test.dart b/tests/lib/wasm/corrupted_error_test.dart
new file mode 100644
index 0000000..fcc4085
--- /dev/null
+++ b/tests/lib/wasm/corrupted_error_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test error thrown when the wasm module is corrupted.
+
+import "package:expect/expect.dart";
+import "dart:wasm";
+import "dart:typed_data";
+
+void main() {
+ var data = Uint8List.fromList([
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60, 0x01, 0x7e, 0x01, 0x7e,
+ 0x07, 0x13, 0x02, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00,
+ 0x06, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x00, 0x00, 0x00, 0x20, 0x00,
+ 0x7e, 0x0b,
+ ]);
+
+ Expect.throwsArgumentError(() => WasmModule(data));
+}
diff --git a/tests/lib/wasm/fn_call_error_test.dart b/tests/lib/wasm/fn_call_error_test.dart
new file mode 100644
index 0000000..932afa3
--- /dev/null
+++ b/tests/lib/wasm/fn_call_error_test.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test error thrown when a function is called with the wrong args.
+
+import "package:expect/expect.dart";
+import "dart:wasm";
+import "dart:typed_data";
+
+void main() {
+ // int64_t square(int64_t n) { return n * n; }
+ var data = Uint8List.fromList([
+ 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60,
+ 0x01, 0x7e, 0x01, 0x7e, 0x03, 0x02, 0x01, 0x00, 0x04, 0x05, 0x01, 0x70,
+ 0x01, 0x01, 0x01, 0x05, 0x03, 0x01, 0x00, 0x02, 0x06, 0x08, 0x01, 0x7f,
+ 0x01, 0x41, 0x80, 0x88, 0x04, 0x0b, 0x07, 0x13, 0x02, 0x06, 0x6d, 0x65,
+ 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00, 0x06, 0x73, 0x71, 0x75, 0x61, 0x72,
+ 0x65, 0x00, 0x00, 0x0a, 0x09, 0x01, 0x07, 0x00, 0x20, 0x00, 0x20, 0x00,
+ 0x7e, 0x0b,
+ ]);
+
+ var inst = WasmModule(data).instantiate(WasmImports());
+ var fn = inst.lookupFunction<Int64 Function(Int64)>("square");
+
+ Expect.throwsArgumentError(() => fn.call([]));
+ Expect.throwsArgumentError(() => fn.call([1, 2, 3]));
+ Expect.throwsArgumentError(() => fn.call([1.23]));
+}
diff --git a/tests/lib/wasm/fn_import_error_test.dart b/tests/lib/wasm/fn_import_error_test.dart
new file mode 100644
index 0000000..40466fb
--- /dev/null
+++ b/tests/lib/wasm/fn_import_error_test.dart
@@ -0,0 +1,60 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test errors thrown by function imports.
+
+import "package:expect/expect.dart";
+import "dart:wasm";
+import "dart:typed_data";
+
+void main() {
+ // This module expects a function import like:
+ // int64_t someFn(int32_t a, int64_t b, float c, double d);
+ var data = Uint8List.fromList([
+ 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0c, 0x02, 0x60,
+ 0x04, 0x7f, 0x7e, 0x7d, 0x7c, 0x01, 0x7e, 0x60, 0x00, 0x00, 0x02, 0x0e,
+ 0x01, 0x03, 0x65, 0x6e, 0x76, 0x06, 0x73, 0x6f, 0x6d, 0x65, 0x46, 0x6e,
+ 0x00, 0x00, 0x03, 0x02, 0x01, 0x01, 0x04, 0x05, 0x01, 0x70, 0x01, 0x01,
+ 0x01, 0x05, 0x03, 0x01, 0x00, 0x02, 0x06, 0x08, 0x01, 0x7f, 0x01, 0x41,
+ 0x80, 0x88, 0x04, 0x0b, 0x07, 0x11, 0x02, 0x06, 0x6d, 0x65, 0x6d, 0x6f,
+ 0x72, 0x79, 0x02, 0x00, 0x04, 0x62, 0x6c, 0x61, 0x68, 0x00, 0x01, 0x0a,
+ 0x1d, 0x01, 0x1b, 0x00, 0x41, 0x01, 0x42, 0x02, 0x43, 0x00, 0x00, 0x40,
+ 0x40, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x10, 0x80,
+ 0x80, 0x80, 0x80, 0x00, 0x1a, 0x0b,
+ ]);
+
+ var mod = WasmModule(data);
+ var imp = WasmImports()
+ ..addFunction<Int64 Function(Int32, Int64, Float, Double)>(
+ "env", "someFn", (num a, num b, num c, num d) => 123);
+ mod.instantiate(imp);
+
+ imp = WasmImports();
+ Expect.throwsArgumentError(() => mod.instantiate(imp));
+
+ imp = WasmImports()
+ ..addFunction<Int64 Function(Int32)>("env", "someFn", (num a) => 123);
+ Expect.throwsArgumentError(() => mod.instantiate(imp));
+
+ imp = WasmImports()
+ ..addFunction<Double Function(Int32, Int64, Float, Double)>(
+ "env", "someFn", (num a, num b, num c, num d) => 123);
+ Expect.throwsArgumentError(() => mod.instantiate(imp));
+
+ imp = WasmImports()
+ ..addFunction<Int64 Function(Int32, Int64, Float, Float)>(
+ "env", "someFn", (num a, num b, num c, num d) => 123);
+ Expect.throwsArgumentError(() => mod.instantiate(imp));
+
+ Expect.throwsArgumentError(() => WasmImports()
+ ..addFunction<dynamic Function(Int32, Int64, Float, Double)>(
+ "env", "someFn", (num a, num b, num c, num d) => 123));
+
+ Expect.throwsArgumentError(() => WasmImports()
+ ..addFunction<Int64 Function(Int32, Int64, dynamic, Double)>(
+ "env", "someFn", (num a, num b, num c, num d) => 123));
+
+ imp = WasmImports()..addGlobal<Int64>("env", "someFn", 123, false);
+ Expect.throwsArgumentError(() => mod.instantiate(imp));
+}
diff --git a/tests/lib/wasm/fn_import_exception_test.dart b/tests/lib/wasm/fn_import_exception_test.dart
new file mode 100644
index 0000000..73298d9
--- /dev/null
+++ b/tests/lib/wasm/fn_import_exception_test.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test throwing exceptions from an imported function.
+
+import "package:expect/expect.dart";
+import "dart:wasm";
+import "dart:typed_data";
+
+void main() {
+ // int64_t fn(int64_t x) { return throwIfNegative(x); }
+ var data = Uint8List.fromList([
+ 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60,
+ 0x01, 0x7e, 0x01, 0x7e, 0x02, 0x17, 0x01, 0x03, 0x65, 0x6e, 0x76, 0x0f,
+ 0x74, 0x68, 0x72, 0x6f, 0x77, 0x49, 0x66, 0x4e, 0x65, 0x67, 0x61, 0x74,
+ 0x69, 0x76, 0x65, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x04, 0x05, 0x01,
+ 0x70, 0x01, 0x01, 0x01, 0x05, 0x03, 0x01, 0x00, 0x02, 0x06, 0x08, 0x01,
+ 0x7f, 0x01, 0x41, 0x80, 0x88, 0x04, 0x0b, 0x07, 0x0f, 0x02, 0x06, 0x6d,
+ 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00, 0x02, 0x66, 0x6e, 0x00, 0x01,
+ 0x0a, 0x0c, 0x01, 0x0a, 0x00, 0x20, 0x00, 0x10, 0x80, 0x80, 0x80, 0x80,
+ 0x00, 0x0b,
+ ]);
+
+ dynamic override = null;
+ var inst = WasmModule(data).instantiate(WasmImports()
+ ..addMemory("env", "memory", WasmMemory(256, 1024))
+ ..addGlobal<Int32>("env", "__memory_base", 1024, false)
+ ..addFunction<Int64 Function(Int64)>("env", "throwIfNegative", (int x) {
+ if (x < 0) {
+ throw Exception(x);
+ }
+ if (override != null) {
+ return override;
+ }
+ return x;
+ }));
+ var fn = inst.lookupFunction<Int64 Function(Int64)>("fn");
+
+ Expect.equals(123, fn.call([123]));
+ Expect.throws(() => fn.call([-456]), (Exception e) => "$e".contains("-456"));
+
+ override = "Not an integer";
+ Expect.throwsArgumentError(() => fn.call([789]));
+ override = 0.123;
+ Expect.throwsArgumentError(() => fn.call([789]));
+}
diff --git a/tests/lib/wasm/fn_import_test.dart b/tests/lib/wasm/fn_import_test.dart
new file mode 100644
index 0000000..a9f9bdb
--- /dev/null
+++ b/tests/lib/wasm/fn_import_test.dart
@@ -0,0 +1,37 @@
+// 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.
+
+// Test that we can load a wasm module, find a function, and call it.
+
+import "package:expect/expect.dart";
+import "dart:wasm";
+import "dart:typed_data";
+
+void main() {
+ // void reportStuff() { report(123, 456); }
+ var data = Uint8List.fromList([
+ 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x09, 0x02, 0x60,
+ 0x02, 0x7e, 0x7e, 0x00, 0x60, 0x00, 0x00, 0x02, 0x0e, 0x01, 0x03, 0x65,
+ 0x6e, 0x76, 0x06, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x00, 0x00, 0x03,
+ 0x02, 0x01, 0x01, 0x04, 0x05, 0x01, 0x70, 0x01, 0x01, 0x01, 0x05, 0x03,
+ 0x01, 0x00, 0x02, 0x06, 0x08, 0x01, 0x7f, 0x01, 0x41, 0x80, 0x88, 0x04,
+ 0x0b, 0x07, 0x18, 0x02, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x02,
+ 0x00, 0x0b, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x74, 0x75, 0x66,
+ 0x66, 0x00, 0x01, 0x0a, 0x10, 0x01, 0x0e, 0x00, 0x42, 0xfb, 0x00, 0x42,
+ 0xc8, 0x03, 0x10, 0x80, 0x80, 0x80, 0x80, 0x00, 0x0b,
+ ]);
+
+ int report_x = -1;
+ int report_y = -1;
+
+ var inst = WasmModule(data).instantiate(WasmImports()
+ ..addFunction<Void Function(Int64, Int64)>("env", "report", (int x, int y) {
+ report_x = x;
+ report_y = y;
+ }));
+ var fn = inst.lookupFunction<Void Function()>("reportStuff");
+ fn.call([]);
+ Expect.equals(report_x, 123);
+ Expect.equals(report_y, 456);
+}
diff --git a/tests/lib/wasm/fn_mismatch_error_test.dart b/tests/lib/wasm/fn_mismatch_error_test.dart
new file mode 100644
index 0000000..413260e
--- /dev/null
+++ b/tests/lib/wasm/fn_mismatch_error_test.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test error thrown when the loaded function can't be found.
+
+import "package:expect/expect.dart";
+import "dart:wasm";
+import "dart:typed_data";
+
+void main() {
+ // int64_t square(int64_t n) { return n * n; }
+ var data = Uint8List.fromList([
+ 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60,
+ 0x01, 0x7e, 0x01, 0x7e, 0x03, 0x02, 0x01, 0x00, 0x04, 0x05, 0x01, 0x70,
+ 0x01, 0x01, 0x01, 0x05, 0x03, 0x01, 0x00, 0x02, 0x06, 0x08, 0x01, 0x7f,
+ 0x01, 0x41, 0x80, 0x88, 0x04, 0x0b, 0x07, 0x13, 0x02, 0x06, 0x6d, 0x65,
+ 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00, 0x06, 0x73, 0x71, 0x75, 0x61, 0x72,
+ 0x65, 0x00, 0x00, 0x0a, 0x09, 0x01, 0x07, 0x00, 0x20, 0x00, 0x20, 0x00,
+ 0x7e, 0x0b,
+ ]);
+
+ var inst = WasmModule(data).instantiate(WasmImports());
+ Expect.isNotNull(inst.lookupFunction<Int64 Function(Int64)>("square"));
+ Expect.throwsArgumentError(
+ () => inst.lookupFunction<Int64 Function(Int64)>("blah"));
+ Expect.throwsArgumentError(
+ () => inst.lookupFunction<Int64 Function()>("square"));
+ Expect.throwsArgumentError(
+ () => inst.lookupFunction<Int64 Function(Int64, Int64)>("square"));
+ Expect.throwsArgumentError(
+ () => inst.lookupFunction<Void Function(Int64)>("square"));
+ Expect.throwsArgumentError(
+ () => inst.lookupFunction<Void Function(dynamic)>("square"));
+ Expect.throwsArgumentError(
+ () => inst.lookupFunction<Int64 Function(Float)>("square"));
+ Expect.throwsArgumentError(
+ () => inst.lookupFunction<Float Function(Int64)>("square"));
+}
diff --git a/tests/lib/wasm/hello_world_test.dart b/tests/lib/wasm/hello_world_test.dart
new file mode 100644
index 0000000..c4441e3
--- /dev/null
+++ b/tests/lib/wasm/hello_world_test.dart
@@ -0,0 +1,205 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test for hello world built using emscripten with WASI.
+
+import "package:expect/expect.dart";
+import "dart:wasm";
+import "dart:typed_data";
+
+void main() {
+ // Hello world module generated by emscripten+WASI. Exports a function like
+ // `void _start()`, and prints using `int fd_write(int, int, int, int)`.
+ var data = Uint8List.fromList([
+ 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x33, 0x09, 0x60,
+ 0x03, 0x7f, 0x7f, 0x7f, 0x01, 0x7f, 0x60, 0x04, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x01, 0x7f, 0x60, 0x00, 0x00, 0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f, 0x60,
+ 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x03, 0x7f, 0x7e, 0x7f, 0x01, 0x7e, 0x60,
+ 0x00, 0x01, 0x7f, 0x60, 0x01, 0x7f, 0x00, 0x60, 0x03, 0x7f, 0x7f, 0x7f,
+ 0x00, 0x02, 0x1a, 0x01, 0x0d, 0x77, 0x61, 0x73, 0x69, 0x5f, 0x75, 0x6e,
+ 0x73, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x08, 0x66, 0x64, 0x5f, 0x77, 0x72,
+ 0x69, 0x74, 0x65, 0x00, 0x01, 0x03, 0x0f, 0x0e, 0x03, 0x04, 0x00, 0x03,
+ 0x02, 0x07, 0x05, 0x04, 0x03, 0x06, 0x02, 0x02, 0x08, 0x00, 0x04, 0x05,
+ 0x01, 0x70, 0x01, 0x04, 0x04, 0x05, 0x06, 0x01, 0x01, 0x80, 0x02, 0x80,
+ 0x02, 0x06, 0x09, 0x01, 0x7f, 0x01, 0x41, 0xc0, 0x95, 0xc0, 0x02, 0x0b,
+ 0x07, 0x2e, 0x04, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00,
+ 0x11, 0x5f, 0x5f, 0x77, 0x61, 0x73, 0x6d, 0x5f, 0x63, 0x61, 0x6c, 0x6c,
+ 0x5f, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x00, 0x05, 0x04, 0x6d, 0x61, 0x69,
+ 0x6e, 0x00, 0x04, 0x06, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x0b,
+ 0x09, 0x09, 0x01, 0x00, 0x41, 0x01, 0x0b, 0x03, 0x08, 0x0e, 0x07, 0x0a,
+ 0xae, 0x0c, 0x0e, 0xbf, 0x01, 0x01, 0x05, 0x7f, 0x41, 0x80, 0x08, 0x21,
+ 0x04, 0x02, 0x40, 0x20, 0x01, 0x28, 0x02, 0x10, 0x22, 0x02, 0x04, 0x7f,
+ 0x20, 0x02, 0x05, 0x20, 0x01, 0x10, 0x02, 0x0d, 0x01, 0x20, 0x01, 0x28,
+ 0x02, 0x10, 0x0b, 0x20, 0x01, 0x28, 0x02, 0x14, 0x22, 0x05, 0x6b, 0x20,
+ 0x00, 0x49, 0x04, 0x40, 0x20, 0x01, 0x41, 0x80, 0x08, 0x20, 0x00, 0x20,
+ 0x01, 0x28, 0x02, 0x24, 0x11, 0x00, 0x00, 0x0f, 0x0b, 0x02, 0x40, 0x20,
+ 0x01, 0x2c, 0x00, 0x4b, 0x41, 0x00, 0x48, 0x0d, 0x00, 0x20, 0x00, 0x21,
+ 0x03, 0x03, 0x40, 0x20, 0x03, 0x22, 0x02, 0x45, 0x0d, 0x01, 0x20, 0x02,
+ 0x41, 0x7f, 0x6a, 0x22, 0x03, 0x41, 0x80, 0x08, 0x6a, 0x2d, 0x00, 0x00,
+ 0x41, 0x0a, 0x47, 0x0d, 0x00, 0x0b, 0x20, 0x01, 0x41, 0x80, 0x08, 0x20,
+ 0x02, 0x20, 0x01, 0x28, 0x02, 0x24, 0x11, 0x00, 0x00, 0x22, 0x03, 0x20,
+ 0x02, 0x49, 0x0d, 0x01, 0x20, 0x00, 0x20, 0x02, 0x6b, 0x21, 0x00, 0x20,
+ 0x02, 0x41, 0x80, 0x08, 0x6a, 0x21, 0x04, 0x20, 0x01, 0x28, 0x02, 0x14,
+ 0x21, 0x05, 0x20, 0x02, 0x21, 0x06, 0x0b, 0x20, 0x05, 0x20, 0x04, 0x20,
+ 0x00, 0x10, 0x03, 0x1a, 0x20, 0x01, 0x20, 0x01, 0x28, 0x02, 0x14, 0x20,
+ 0x00, 0x6a, 0x36, 0x02, 0x14, 0x20, 0x00, 0x20, 0x06, 0x6a, 0x21, 0x03,
+ 0x0b, 0x20, 0x03, 0x0b, 0x59, 0x01, 0x01, 0x7f, 0x20, 0x00, 0x20, 0x00,
+ 0x2d, 0x00, 0x4a, 0x22, 0x01, 0x41, 0x7f, 0x6a, 0x20, 0x01, 0x72, 0x3a,
+ 0x00, 0x4a, 0x20, 0x00, 0x28, 0x02, 0x00, 0x22, 0x01, 0x41, 0x08, 0x71,
+ 0x04, 0x40, 0x20, 0x00, 0x20, 0x01, 0x41, 0x20, 0x72, 0x36, 0x02, 0x00,
+ 0x41, 0x7f, 0x0f, 0x0b, 0x20, 0x00, 0x42, 0x00, 0x37, 0x02, 0x04, 0x20,
+ 0x00, 0x20, 0x00, 0x28, 0x02, 0x2c, 0x22, 0x01, 0x36, 0x02, 0x1c, 0x20,
+ 0x00, 0x20, 0x01, 0x36, 0x02, 0x14, 0x20, 0x00, 0x20, 0x01, 0x20, 0x00,
+ 0x28, 0x02, 0x30, 0x6a, 0x36, 0x02, 0x10, 0x41, 0x00, 0x0b, 0x82, 0x04,
+ 0x01, 0x03, 0x7f, 0x20, 0x02, 0x41, 0x80, 0xc0, 0x00, 0x4f, 0x04, 0x40,
+ 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0x10, 0x0d, 0x20, 0x00, 0x0f, 0x0b,
+ 0x20, 0x00, 0x20, 0x02, 0x6a, 0x21, 0x03, 0x02, 0x40, 0x20, 0x00, 0x20,
+ 0x01, 0x73, 0x41, 0x03, 0x71, 0x45, 0x04, 0x40, 0x02, 0x40, 0x20, 0x02,
+ 0x41, 0x01, 0x48, 0x04, 0x40, 0x20, 0x00, 0x21, 0x02, 0x0c, 0x01, 0x0b,
+ 0x20, 0x00, 0x41, 0x03, 0x71, 0x45, 0x04, 0x40, 0x20, 0x00, 0x21, 0x02,
+ 0x0c, 0x01, 0x0b, 0x20, 0x00, 0x21, 0x02, 0x03, 0x40, 0x20, 0x02, 0x20,
+ 0x01, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, 0x01, 0x41, 0x01, 0x6a,
+ 0x21, 0x01, 0x20, 0x02, 0x41, 0x01, 0x6a, 0x22, 0x02, 0x20, 0x03, 0x4f,
+ 0x0d, 0x01, 0x20, 0x02, 0x41, 0x03, 0x71, 0x0d, 0x00, 0x0b, 0x0b, 0x02,
+ 0x40, 0x20, 0x03, 0x41, 0x7c, 0x71, 0x22, 0x04, 0x41, 0xc0, 0x00, 0x49,
+ 0x0d, 0x00, 0x20, 0x02, 0x20, 0x04, 0x41, 0x40, 0x6a, 0x22, 0x05, 0x4b,
+ 0x0d, 0x00, 0x03, 0x40, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x00, 0x36,
+ 0x02, 0x00, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x04, 0x36, 0x02, 0x04,
+ 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x08, 0x36, 0x02, 0x08, 0x20, 0x02,
+ 0x20, 0x01, 0x28, 0x02, 0x0c, 0x36, 0x02, 0x0c, 0x20, 0x02, 0x20, 0x01,
+ 0x28, 0x02, 0x10, 0x36, 0x02, 0x10, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02,
+ 0x14, 0x36, 0x02, 0x14, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x18, 0x36,
+ 0x02, 0x18, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x1c, 0x36, 0x02, 0x1c,
+ 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x20, 0x36, 0x02, 0x20, 0x20, 0x02,
+ 0x20, 0x01, 0x28, 0x02, 0x24, 0x36, 0x02, 0x24, 0x20, 0x02, 0x20, 0x01,
+ 0x28, 0x02, 0x28, 0x36, 0x02, 0x28, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02,
+ 0x2c, 0x36, 0x02, 0x2c, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x30, 0x36,
+ 0x02, 0x30, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x34, 0x36, 0x02, 0x34,
+ 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x38, 0x36, 0x02, 0x38, 0x20, 0x02,
+ 0x20, 0x01, 0x28, 0x02, 0x3c, 0x36, 0x02, 0x3c, 0x20, 0x01, 0x41, 0x40,
+ 0x6b, 0x21, 0x01, 0x20, 0x02, 0x41, 0x40, 0x6b, 0x22, 0x02, 0x20, 0x05,
+ 0x4d, 0x0d, 0x00, 0x0b, 0x0b, 0x20, 0x02, 0x20, 0x04, 0x4f, 0x0d, 0x01,
+ 0x03, 0x40, 0x20, 0x02, 0x20, 0x01, 0x28, 0x02, 0x00, 0x36, 0x02, 0x00,
+ 0x20, 0x01, 0x41, 0x04, 0x6a, 0x21, 0x01, 0x20, 0x02, 0x41, 0x04, 0x6a,
+ 0x22, 0x02, 0x20, 0x04, 0x49, 0x0d, 0x00, 0x0b, 0x0c, 0x01, 0x0b, 0x20,
+ 0x03, 0x41, 0x04, 0x49, 0x04, 0x40, 0x20, 0x00, 0x21, 0x02, 0x0c, 0x01,
+ 0x0b, 0x20, 0x03, 0x41, 0x7c, 0x6a, 0x22, 0x04, 0x20, 0x00, 0x49, 0x04,
+ 0x40, 0x20, 0x00, 0x21, 0x02, 0x0c, 0x01, 0x0b, 0x20, 0x00, 0x21, 0x02,
+ 0x03, 0x40, 0x20, 0x02, 0x20, 0x01, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00,
+ 0x20, 0x02, 0x20, 0x01, 0x2d, 0x00, 0x01, 0x3a, 0x00, 0x01, 0x20, 0x02,
+ 0x20, 0x01, 0x2d, 0x00, 0x02, 0x3a, 0x00, 0x02, 0x20, 0x02, 0x20, 0x01,
+ 0x2d, 0x00, 0x03, 0x3a, 0x00, 0x03, 0x20, 0x01, 0x41, 0x04, 0x6a, 0x21,
+ 0x01, 0x20, 0x02, 0x41, 0x04, 0x6a, 0x22, 0x02, 0x20, 0x04, 0x4d, 0x0d,
+ 0x00, 0x0b, 0x0b, 0x20, 0x02, 0x20, 0x03, 0x49, 0x04, 0x40, 0x03, 0x40,
+ 0x20, 0x02, 0x20, 0x01, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, 0x01,
+ 0x41, 0x01, 0x6a, 0x21, 0x01, 0x20, 0x02, 0x41, 0x01, 0x6a, 0x22, 0x02,
+ 0x20, 0x03, 0x47, 0x0d, 0x00, 0x0b, 0x0b, 0x20, 0x00, 0x0b, 0x06, 0x00,
+ 0x10, 0x0c, 0x41, 0x00, 0x0b, 0x03, 0x00, 0x01, 0x0b, 0x7e, 0x01, 0x03,
+ 0x7f, 0x23, 0x00, 0x41, 0x10, 0x6b, 0x22, 0x01, 0x24, 0x00, 0x20, 0x01,
+ 0x41, 0x0a, 0x3a, 0x00, 0x0f, 0x02, 0x40, 0x20, 0x00, 0x28, 0x02, 0x10,
+ 0x22, 0x02, 0x45, 0x04, 0x40, 0x20, 0x00, 0x10, 0x02, 0x0d, 0x01, 0x20,
+ 0x00, 0x28, 0x02, 0x10, 0x21, 0x02, 0x0b, 0x02, 0x40, 0x20, 0x00, 0x28,
+ 0x02, 0x14, 0x22, 0x03, 0x20, 0x02, 0x4f, 0x0d, 0x00, 0x20, 0x00, 0x2c,
+ 0x00, 0x4b, 0x41, 0x0a, 0x46, 0x0d, 0x00, 0x20, 0x00, 0x20, 0x03, 0x41,
+ 0x01, 0x6a, 0x36, 0x02, 0x14, 0x20, 0x03, 0x41, 0x0a, 0x3a, 0x00, 0x00,
+ 0x0c, 0x01, 0x0b, 0x20, 0x00, 0x20, 0x01, 0x41, 0x0f, 0x6a, 0x41, 0x01,
+ 0x20, 0x00, 0x28, 0x02, 0x24, 0x11, 0x00, 0x00, 0x41, 0x01, 0x47, 0x0d,
+ 0x00, 0x20, 0x01, 0x2d, 0x00, 0x0f, 0x1a, 0x0b, 0x20, 0x01, 0x41, 0x10,
+ 0x6a, 0x24, 0x00, 0x0b, 0x04, 0x00, 0x42, 0x00, 0x0b, 0x04, 0x00, 0x41,
+ 0x00, 0x0b, 0x31, 0x01, 0x01, 0x7f, 0x20, 0x00, 0x21, 0x02, 0x20, 0x02,
+ 0x02, 0x7f, 0x20, 0x01, 0x28, 0x02, 0x4c, 0x41, 0x7f, 0x4c, 0x04, 0x40,
+ 0x20, 0x02, 0x20, 0x01, 0x10, 0x01, 0x0c, 0x01, 0x0b, 0x20, 0x02, 0x20,
+ 0x01, 0x10, 0x01, 0x0b, 0x22, 0x01, 0x46, 0x04, 0x40, 0x20, 0x00, 0x0f,
+ 0x0b, 0x20, 0x01, 0x0b, 0x62, 0x01, 0x03, 0x7f, 0x41, 0x80, 0x08, 0x21,
+ 0x00, 0x03, 0x40, 0x20, 0x00, 0x22, 0x01, 0x41, 0x04, 0x6a, 0x21, 0x00,
+ 0x20, 0x01, 0x28, 0x02, 0x00, 0x22, 0x02, 0x41, 0x7f, 0x73, 0x20, 0x02,
+ 0x41, 0xff, 0xfd, 0xfb, 0x77, 0x6a, 0x71, 0x41, 0x80, 0x81, 0x82, 0x84,
+ 0x78, 0x71, 0x45, 0x0d, 0x00, 0x0b, 0x02, 0x40, 0x20, 0x02, 0x41, 0xff,
+ 0x01, 0x71, 0x45, 0x04, 0x40, 0x20, 0x01, 0x21, 0x00, 0x0c, 0x01, 0x0b,
+ 0x03, 0x40, 0x20, 0x01, 0x2d, 0x00, 0x01, 0x21, 0x02, 0x20, 0x01, 0x41,
+ 0x01, 0x6a, 0x22, 0x00, 0x21, 0x01, 0x20, 0x02, 0x0d, 0x00, 0x0b, 0x0b,
+ 0x20, 0x00, 0x41, 0x80, 0x08, 0x6b, 0x0b, 0x0c, 0x00, 0x02, 0x7f, 0x41,
+ 0x00, 0x41, 0x00, 0x10, 0x04, 0x0b, 0x1a, 0x0b, 0x66, 0x01, 0x02, 0x7f,
+ 0x41, 0x90, 0x08, 0x28, 0x02, 0x00, 0x22, 0x00, 0x28, 0x02, 0x4c, 0x41,
+ 0x00, 0x4e, 0x04, 0x7f, 0x41, 0x01, 0x05, 0x20, 0x01, 0x0b, 0x1a, 0x02,
+ 0x40, 0x41, 0x7f, 0x41, 0x00, 0x10, 0x0a, 0x22, 0x01, 0x20, 0x01, 0x20,
+ 0x00, 0x10, 0x09, 0x47, 0x1b, 0x41, 0x00, 0x48, 0x0d, 0x00, 0x02, 0x40,
+ 0x20, 0x00, 0x2d, 0x00, 0x4b, 0x41, 0x0a, 0x46, 0x0d, 0x00, 0x20, 0x00,
+ 0x28, 0x02, 0x14, 0x22, 0x01, 0x20, 0x00, 0x28, 0x02, 0x10, 0x4f, 0x0d,
+ 0x00, 0x20, 0x00, 0x20, 0x01, 0x41, 0x01, 0x6a, 0x36, 0x02, 0x14, 0x20,
+ 0x01, 0x41, 0x0a, 0x3a, 0x00, 0x00, 0x0c, 0x01, 0x0b, 0x20, 0x00, 0x10,
+ 0x06, 0x0b, 0x0b, 0x3d, 0x01, 0x01, 0x7f, 0x20, 0x02, 0x04, 0x40, 0x03,
+ 0x40, 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0x41, 0x80, 0xc0, 0x00, 0x20,
+ 0x02, 0x41, 0x80, 0xc0, 0x00, 0x49, 0x1b, 0x22, 0x03, 0x10, 0x03, 0x21,
+ 0x00, 0x20, 0x01, 0x41, 0x80, 0x40, 0x6b, 0x21, 0x01, 0x20, 0x00, 0x41,
+ 0x80, 0x40, 0x6b, 0x21, 0x00, 0x20, 0x02, 0x20, 0x03, 0x6b, 0x22, 0x02,
+ 0x0d, 0x00, 0x0b, 0x0b, 0x0b, 0xb1, 0x02, 0x01, 0x06, 0x7f, 0x23, 0x00,
+ 0x41, 0x20, 0x6b, 0x22, 0x03, 0x24, 0x00, 0x20, 0x03, 0x20, 0x00, 0x28,
+ 0x02, 0x1c, 0x22, 0x04, 0x36, 0x02, 0x10, 0x20, 0x00, 0x28, 0x02, 0x14,
+ 0x21, 0x05, 0x20, 0x03, 0x20, 0x02, 0x36, 0x02, 0x1c, 0x20, 0x03, 0x20,
+ 0x01, 0x36, 0x02, 0x18, 0x20, 0x03, 0x20, 0x05, 0x20, 0x04, 0x6b, 0x22,
+ 0x01, 0x36, 0x02, 0x14, 0x20, 0x01, 0x20, 0x02, 0x6a, 0x21, 0x06, 0x41,
+ 0x02, 0x21, 0x05, 0x20, 0x03, 0x41, 0x10, 0x6a, 0x21, 0x01, 0x03, 0x40,
+ 0x02, 0x40, 0x02, 0x7f, 0x20, 0x06, 0x02, 0x7f, 0x20, 0x00, 0x28, 0x02,
+ 0x3c, 0x20, 0x01, 0x20, 0x05, 0x20, 0x03, 0x41, 0x0c, 0x6a, 0x10, 0x00,
+ 0x04, 0x40, 0x20, 0x03, 0x41, 0x7f, 0x36, 0x02, 0x0c, 0x41, 0x7f, 0x0c,
+ 0x01, 0x0b, 0x20, 0x03, 0x28, 0x02, 0x0c, 0x0b, 0x22, 0x04, 0x46, 0x04,
+ 0x40, 0x20, 0x00, 0x20, 0x00, 0x28, 0x02, 0x2c, 0x22, 0x01, 0x36, 0x02,
+ 0x1c, 0x20, 0x00, 0x20, 0x01, 0x36, 0x02, 0x14, 0x20, 0x00, 0x20, 0x01,
+ 0x20, 0x00, 0x28, 0x02, 0x30, 0x6a, 0x36, 0x02, 0x10, 0x20, 0x02, 0x0c,
+ 0x01, 0x0b, 0x20, 0x04, 0x41, 0x7f, 0x4a, 0x0d, 0x01, 0x20, 0x00, 0x41,
+ 0x00, 0x36, 0x02, 0x1c, 0x20, 0x00, 0x42, 0x00, 0x37, 0x03, 0x10, 0x20,
+ 0x00, 0x20, 0x00, 0x28, 0x02, 0x00, 0x41, 0x20, 0x72, 0x36, 0x02, 0x00,
+ 0x41, 0x00, 0x20, 0x05, 0x41, 0x02, 0x46, 0x0d, 0x00, 0x1a, 0x20, 0x02,
+ 0x20, 0x01, 0x28, 0x02, 0x04, 0x6b, 0x0b, 0x21, 0x04, 0x20, 0x03, 0x41,
+ 0x20, 0x6a, 0x24, 0x00, 0x20, 0x04, 0x0f, 0x0b, 0x20, 0x01, 0x41, 0x08,
+ 0x6a, 0x20, 0x01, 0x20, 0x04, 0x20, 0x01, 0x28, 0x02, 0x04, 0x22, 0x07,
+ 0x4b, 0x22, 0x08, 0x1b, 0x22, 0x01, 0x20, 0x04, 0x20, 0x07, 0x41, 0x00,
+ 0x20, 0x08, 0x1b, 0x6b, 0x22, 0x07, 0x20, 0x01, 0x28, 0x02, 0x00, 0x6a,
+ 0x36, 0x02, 0x00, 0x20, 0x01, 0x20, 0x01, 0x28, 0x02, 0x04, 0x20, 0x07,
+ 0x6b, 0x36, 0x02, 0x04, 0x20, 0x06, 0x20, 0x04, 0x6b, 0x21, 0x06, 0x20,
+ 0x05, 0x20, 0x08, 0x6b, 0x21, 0x05, 0x0c, 0x00, 0x00, 0x0b, 0x00, 0x0b,
+ 0x0b, 0x4d, 0x06, 0x00, 0x41, 0x80, 0x08, 0x0b, 0x12, 0x68, 0x65, 0x6c,
+ 0x6c, 0x6f, 0x2c, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0x00, 0x00,
+ 0x00, 0x18, 0x04, 0x00, 0x41, 0x98, 0x08, 0x0b, 0x01, 0x05, 0x00, 0x41,
+ 0xa4, 0x08, 0x0b, 0x01, 0x01, 0x00, 0x41, 0xbc, 0x08, 0x0b, 0x0e, 0x02,
+ 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xb8, 0x04, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x41, 0xd4, 0x08, 0x0b, 0x01, 0x01, 0x00, 0x41, 0xe3, 0x08,
+ 0x0b, 0x05, 0x0a, 0xff, 0xff, 0xff, 0xff,
+ ]);
+
+ WasmMemory mem = null;
+ String out = "";
+ var getI32 = (int p) {
+ // Read a little-endian I32.
+ int n = 0;
+ for (var i = p + 3; i >= p; --i) {
+ n *= 256;
+ n += mem[i];
+ }
+ return n;
+ };
+ var inst = WasmModule(data).instantiate(WasmImports()
+ ..addFunction<Int32 Function(Int32, Int32, Int32, Int32)>(
+ "wasi_unstable", "fd_write",
+ (int fd, int iovs, int iovs_len, int unused) {
+ // iovs points to an array of length iovs_len. Each element is two I32s,
+ // a char* and a length.
+ String o = "";
+ for (var i = 0; i < iovs_len; ++i) {
+ var str = getI32(iovs + 8 * i);
+ var len = getI32(iovs + 4 + 8 * i);
+ for (var j = 0; j < len; ++j) {
+ o += String.fromCharCode(mem[str + j]);
+ }
+ }
+ out += o;
+ return o.length;
+ }));
+ mem = inst.memory;
+
+ var fn = inst.lookupFunction<Void Function()>("_start");
+ fn.call([]);
+ Expect.equals("hello, world!\n", out);
+}
diff --git a/tests/lib/wasm/import_error_test.dart b/tests/lib/wasm/import_error_test.dart
new file mode 100644
index 0000000..a06a3a9
--- /dev/null
+++ b/tests/lib/wasm/import_error_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test errors thrown by WasmImports.
+
+import "package:expect/expect.dart";
+import "dart:wasm";
+import "dart:typed_data";
+
+void main() {
+ var imp = WasmImports();
+ imp.addGlobal<Int64>("env", "x", 123, false);
+ imp.addGlobal<Double>("env", "y", 4.56, true);
+ Expect.throwsArgumentError(() => imp.addGlobal<int>("env", "a", 1, true));
+ Expect.throwsArgumentError(() => imp.addGlobal<double>("env", "b", 2, true));
+ Expect.throwsArgumentError(() => imp.addGlobal<dynamic>("env", "c", 3, true));
+}
diff --git a/tests/lib/wasm/memory_error_test.dart b/tests/lib/wasm/memory_error_test.dart
new file mode 100644
index 0000000..e866bf0
--- /dev/null
+++ b/tests/lib/wasm/memory_error_test.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test errors thrown by WasmMemory.
+
+import "package:expect/expect.dart";
+import "dart:wasm";
+import "dart:typed_data";
+
+void main() {
+ Expect.throwsArgumentError(() => WasmMemory(1000000000));
+ var mem = WasmMemory(1000);
+ Expect.throwsArgumentError(() => mem.grow(1000000000));
+}
diff --git a/tests/lib/wasm/memory_test.dart b/tests/lib/wasm/memory_test.dart
new file mode 100644
index 0000000..52d12c3
--- /dev/null
+++ b/tests/lib/wasm/memory_test.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that we can create a WasmMemory, edit it, and grow it.
+
+import "package:expect/expect.dart";
+import "dart:wasm";
+import "dart:typed_data";
+
+void main() {
+ var mem = WasmMemory(1000);
+ Expect.equals(1000, mem.lengthInPages);
+ Expect.equals(1000 * WasmMemory.kPageSizeInBytes, mem.lengthInBytes);
+
+ mem[123] = 45;
+ Expect.equals(45, mem[123]);
+
+ mem.grow(100);
+ Expect.equals(1100, mem.lengthInPages);
+ Expect.equals(1100 * WasmMemory.kPageSizeInBytes, mem.lengthInBytes);
+ Expect.equals(45, mem[123]);
+
+ Expect.throwsArgumentError(() => WasmMemory(1000000000));
+ Expect.throwsArgumentError(() => mem.grow(1000000000));
+}
diff --git a/tests/lib/wasm/numerics_test.dart b/tests/lib/wasm/numerics_test.dart
new file mode 100644
index 0000000..8651caa
--- /dev/null
+++ b/tests/lib/wasm/numerics_test.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test numeric types.
+
+import "package:expect/expect.dart";
+import "dart:wasm";
+import "dart:typed_data";
+
+void main() {
+ // int64_t addI64(int64_t x, int64_t y) { return x + y; }
+ // int32_t addI32(int32_t x, int32_t y) { return x + y; }
+ // double addF64(double x, double y) { return x + y; }
+ // float addF32(float x, float y) { return x + y; }
+ var data = Uint8List.fromList([
+ 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x19, 0x04, 0x60,
+ 0x02, 0x7e, 0x7e, 0x01, 0x7e, 0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f, 0x60,
+ 0x02, 0x7c, 0x7c, 0x01, 0x7c, 0x60, 0x02, 0x7d, 0x7d, 0x01, 0x7d, 0x03,
+ 0x05, 0x04, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x01, 0x70, 0x01, 0x01,
+ 0x01, 0x05, 0x03, 0x01, 0x00, 0x02, 0x06, 0x08, 0x01, 0x7f, 0x01, 0x41,
+ 0x80, 0x88, 0x04, 0x0b, 0x07, 0x2e, 0x05, 0x06, 0x6d, 0x65, 0x6d, 0x6f,
+ 0x72, 0x79, 0x02, 0x00, 0x06, 0x61, 0x64, 0x64, 0x49, 0x36, 0x34, 0x00,
+ 0x00, 0x06, 0x61, 0x64, 0x64, 0x49, 0x33, 0x32, 0x00, 0x01, 0x06, 0x61,
+ 0x64, 0x64, 0x46, 0x36, 0x34, 0x00, 0x02, 0x06, 0x61, 0x64, 0x64, 0x46,
+ 0x33, 0x32, 0x00, 0x03, 0x0a, 0x21, 0x04, 0x07, 0x00, 0x20, 0x01, 0x20,
+ 0x00, 0x7c, 0x0b, 0x07, 0x00, 0x20, 0x01, 0x20, 0x00, 0x6a, 0x0b, 0x07,
+ 0x00, 0x20, 0x00, 0x20, 0x01, 0xa0, 0x0b, 0x07, 0x00, 0x20, 0x00, 0x20,
+ 0x01, 0x92, 0x0b,
+ ]);
+
+ var inst = WasmModule(data).instantiate(WasmImports());
+ var addI64 = inst.lookupFunction<Int64 Function(Int64, Int64)>("addI64");
+ var addI32 = inst.lookupFunction<Int32 Function(Int32, Int32)>("addI32");
+ var addF64 = inst.lookupFunction<Double Function(Double, Double)>("addF64");
+ var addF32 = inst.lookupFunction<Float Function(Float, Float)>("addF32");
+
+ int i64 = addI64.call([0x123456789ABCDEF, 0xFEDCBA987654321]);
+ Expect.equals(0x1111111111111110, i64);
+
+ int i32 = addI32.call([0xABCDEF, 0xFEDCBA]);
+ Expect.equals(0x1aaaaa9, i32);
+
+ double f64 = addF64.call([1234.5678, 8765.4321]);
+ Expect.approxEquals(9999.9999, f64, 1e-6);
+
+ double f32 = addF32.call([1234.5678, 8765.4321]);
+ Expect.approxEquals(9999.9999, f32, 1e-3);
+}
diff --git a/tests/lib/wasm/void_test.dart b/tests/lib/wasm/void_test.dart
new file mode 100644
index 0000000..fe3bd94
--- /dev/null
+++ b/tests/lib/wasm/void_test.dart
@@ -0,0 +1,34 @@
+// 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.
+
+// Test functions with void return type, and functions that take no args.
+
+import "package:expect/expect.dart";
+import "dart:wasm";
+import "dart:typed_data";
+
+void main() {
+ // int64_t x = 0;
+ // void set(int64_t a, int64_t b) { x = a + b; }
+ // int64_t get() { return x; }
+ var data = Uint8List.fromList([
+ 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x02, 0x60,
+ 0x02, 0x7e, 0x7e, 0x00, 0x60, 0x00, 0x01, 0x7e, 0x03, 0x03, 0x02, 0x00,
+ 0x01, 0x04, 0x05, 0x01, 0x70, 0x01, 0x01, 0x01, 0x05, 0x03, 0x01, 0x00,
+ 0x02, 0x06, 0x08, 0x01, 0x7f, 0x01, 0x41, 0x90, 0x88, 0x04, 0x0b, 0x07,
+ 0x16, 0x03, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00, 0x03,
+ 0x73, 0x65, 0x74, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00, 0x01, 0x0a,
+ 0x1e, 0x02, 0x10, 0x00, 0x41, 0x00, 0x20, 0x01, 0x20, 0x00, 0x7c, 0x37,
+ 0x03, 0x80, 0x88, 0x80, 0x80, 0x00, 0x0b, 0x0b, 0x00, 0x41, 0x00, 0x29,
+ 0x03, 0x80, 0x88, 0x80, 0x80, 0x00, 0x0b, 0x0b, 0x0f, 0x01, 0x00, 0x41,
+ 0x80, 0x08, 0x0b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ ]);
+
+ var inst = WasmModule(data).instantiate(WasmImports());
+ var setFn = inst.lookupFunction<Void Function(Int64, Int64)>("set");
+ var getFn = inst.lookupFunction<Int64 Function()>("get");
+ Expect.isNull(setFn.call([123, 456]));
+ int n = getFn.call([]);
+ Expect.equals(123 + 456, n);
+}
diff --git a/tools/VERSION b/tools/VERSION
index bc4e037..0f79813 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -33,7 +33,7 @@
MAJOR 2
MINOR 8
PATCH 0
-PRERELEASE 2
+PRERELEASE 3
PRERELEASE_PATCH 0
ABI_VERSION 27
OLDEST_SUPPORTED_ABI_VERSION 27