Version 2.14.0-125.0.dev
Merge commit '8c4dcce5aa0c662ad9e61c55c96549bab164600a' into 'dev'
diff --git a/pkg/front_end/lib/src/fasta/builder/enum_builder.dart b/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
index cf7f639..f05be5b 100644
--- a/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
@@ -16,6 +16,8 @@
Expression,
Field,
FieldInitializer,
+ InstanceAccessKind,
+ InstanceGet,
IntLiteral,
InterfaceType,
ListLiteral,
@@ -436,8 +438,15 @@
nameFieldBuilder.build(libraryBuilder);
Field nameField = nameFieldBuilder.field;
ProcedureBuilder toStringBuilder = firstMemberNamed("toString");
- toStringBuilder.body = new ReturnStatement(
- new PropertyGet(new ThisExpression(), nameField.name, nameField));
+ if (libraryBuilder
+ .loader.target.backendTarget.supportsNewMethodInvocationEncoding) {
+ toStringBuilder.body = new ReturnStatement(new InstanceGet(
+ InstanceAccessKind.Instance, new ThisExpression(), nameField.name,
+ interfaceTarget: nameField, resultType: nameField.type));
+ } else {
+ toStringBuilder.body = new ReturnStatement(
+ new PropertyGet(new ThisExpression(), nameField.name, nameField));
+ }
List<Expression> values = <Expression>[];
if (enumConstantInfos != null) {
for (EnumConstantInfo enumConstantInfo in enumConstantInfos) {
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index ad072b3..6bb19ed 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -2947,12 +2947,12 @@
expression ??= new FunctionInvocation(
target.isNullableCallFunction
? FunctionAccessKind.Nullable
- : (inferredFunctionType == unknownFunction
+ : (identical(inferredFunctionType, unknownFunction)
? FunctionAccessKind.Function
: FunctionAccessKind.FunctionType),
receiver,
arguments,
- functionType: inferredFunctionType == unknownFunction
+ functionType: identical(inferredFunctionType, unknownFunction)
? null
: inferredFunctionType)
..fileOffset = fileOffset;
diff --git a/pkg/front_end/testcases/none/issue46003.dart b/pkg/front_end/testcases/none/issue46003.dart
new file mode 100644
index 0000000..b0b7271
--- /dev/null
+++ b/pkg/front_end/testcases/none/issue46003.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE.md file.
+
+class A {
+ final Function() foo;
+ A(this.foo);
+
+ void bar() {
+ foo();
+
+ Function() x = foo;
+ x();
+
+ void Function() y = foo;
+ y();
+ }
+}
+
+main() {
+ A(() {}).bar();
+}
diff --git a/pkg/front_end/testcases/none/issue46003.dart.strong.expect b/pkg/front_end/testcases/none/issue46003.dart.strong.expect
new file mode 100644
index 0000000..cbdc1a0
--- /dev/null
+++ b/pkg/front_end/testcases/none/issue46003.dart.strong.expect
@@ -0,0 +1,20 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ final field () → dynamic foo;
+ constructor •(() → dynamic foo) → self::A
+ : self::A::foo = foo, super core::Object::•()
+ ;
+ method bar() → void {
+ this.{self::A::foo}{() → dynamic}(){() → dynamic};
+ () → dynamic x = this.{self::A::foo}{() → dynamic};
+ x(){() → dynamic};
+ () → void y = this.{self::A::foo}{() → dynamic};
+ y(){() → void};
+ }
+}
+static method main() → dynamic {
+ new self::A::•(() → Null {}).{self::A::bar}(){() → void};
+}
diff --git a/pkg/front_end/testcases/none/issue46003.dart.strong.transformed.expect b/pkg/front_end/testcases/none/issue46003.dart.strong.transformed.expect
new file mode 100644
index 0000000..cbdc1a0
--- /dev/null
+++ b/pkg/front_end/testcases/none/issue46003.dart.strong.transformed.expect
@@ -0,0 +1,20 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ final field () → dynamic foo;
+ constructor •(() → dynamic foo) → self::A
+ : self::A::foo = foo, super core::Object::•()
+ ;
+ method bar() → void {
+ this.{self::A::foo}{() → dynamic}(){() → dynamic};
+ () → dynamic x = this.{self::A::foo}{() → dynamic};
+ x(){() → dynamic};
+ () → void y = this.{self::A::foo}{() → dynamic};
+ y(){() → void};
+ }
+}
+static method main() → dynamic {
+ new self::A::•(() → Null {}).{self::A::bar}(){() → void};
+}
diff --git a/pkg/front_end/testcases/none/issue46003.dart.textual_outline.expect b/pkg/front_end/testcases/none/issue46003.dart.textual_outline.expect
new file mode 100644
index 0000000..71689d1
--- /dev/null
+++ b/pkg/front_end/testcases/none/issue46003.dart.textual_outline.expect
@@ -0,0 +1,7 @@
+class A {
+ final Function() foo;
+ A(this.foo);
+ void bar() {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/none/issue46003.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/none/issue46003.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..68ea14c
--- /dev/null
+++ b/pkg/front_end/testcases/none/issue46003.dart.textual_outline_modelled.expect
@@ -0,0 +1,7 @@
+class A {
+ A(this.foo);
+ final Function() foo;
+ void bar() {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/none/issue46003.dart.weak.expect b/pkg/front_end/testcases/none/issue46003.dart.weak.expect
new file mode 100644
index 0000000..cbdc1a0
--- /dev/null
+++ b/pkg/front_end/testcases/none/issue46003.dart.weak.expect
@@ -0,0 +1,20 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ final field () → dynamic foo;
+ constructor •(() → dynamic foo) → self::A
+ : self::A::foo = foo, super core::Object::•()
+ ;
+ method bar() → void {
+ this.{self::A::foo}{() → dynamic}(){() → dynamic};
+ () → dynamic x = this.{self::A::foo}{() → dynamic};
+ x(){() → dynamic};
+ () → void y = this.{self::A::foo}{() → dynamic};
+ y(){() → void};
+ }
+}
+static method main() → dynamic {
+ new self::A::•(() → Null {}).{self::A::bar}(){() → void};
+}
diff --git a/pkg/front_end/testcases/none/issue46003.dart.weak.outline.expect b/pkg/front_end/testcases/none/issue46003.dart.weak.outline.expect
new file mode 100644
index 0000000..f30d3b1
--- /dev/null
+++ b/pkg/front_end/testcases/none/issue46003.dart.weak.outline.expect
@@ -0,0 +1,13 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ final field () → dynamic foo;
+ constructor •(() → dynamic foo) → self::A
+ ;
+ method bar() → void
+ ;
+}
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/none/issue46003.dart.weak.transformed.expect b/pkg/front_end/testcases/none/issue46003.dart.weak.transformed.expect
new file mode 100644
index 0000000..cbdc1a0
--- /dev/null
+++ b/pkg/front_end/testcases/none/issue46003.dart.weak.transformed.expect
@@ -0,0 +1,20 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ final field () → dynamic foo;
+ constructor •(() → dynamic foo) → self::A
+ : self::A::foo = foo, super core::Object::•()
+ ;
+ method bar() → void {
+ this.{self::A::foo}{() → dynamic}(){() → dynamic};
+ () → dynamic x = this.{self::A::foo}{() → dynamic};
+ x(){() → dynamic};
+ () → void y = this.{self::A::foo}{() → dynamic};
+ y(){() → void};
+ }
+}
+static method main() → dynamic {
+ new self::A::•(() → Null {}).{self::A::bar}(){() → void};
+}
diff --git a/pkg/test_runner/test/experiment_test.dart b/pkg/test_runner/test/experiment_test.dart
new file mode 100644
index 0000000..1dffb4a
--- /dev/null
+++ b/pkg/test_runner/test/experiment_test.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that the experiment in the 'SharedOptions' comment is passed by the
+// test runner.
+
+import 'dart:io';
+
+import 'package:expect/expect.dart';
+
+// SharedOptions=--enable-experiment=test-experiment
+main() {
+ Expect.isTrue(Platform.executableArguments
+ .contains("--enable-experiment=test-experiment"));
+}
diff --git a/runtime/tests/concurrency/run_stress_test_shards.dart b/runtime/tests/concurrency/run_stress_test_shards.dart
index e719c4a..3157880 100644
--- a/runtime/tests/concurrency/run_stress_test_shards.dart
+++ b/runtime/tests/concurrency/run_stress_test_shards.dart
@@ -124,13 +124,24 @@
final shards = int.parse(options['shards']);
final shard = int.parse(options['shard']) - 1;
- final thisShardsConfigurations = [];
- for (int i = 0; i < configurations.length; i++) {
- if ((i % shards) == shard) {
- thisShardsConfigurations.add(configurations[i]);
+ // Tasks will eventually be killed if they do not have any output for some
+ // time. So we'll explicitly print something every 4 minutes.
+ final sw = Stopwatch()..start();
+ final timer = Timer.periodic(const Duration(minutes: 4), (_) {
+ print('[${sw.elapsed}] ... still working ...');
+ });
+
+ try {
+ final thisShardsConfigurations = [];
+ for (int i = 0; i < configurations.length; i++) {
+ if ((i % shards) == shard) {
+ thisShardsConfigurations.add(configurations[i]);
+ }
}
- }
- for (final config in thisShardsConfigurations) {
- await config.runTest();
+ for (final config in thisShardsConfigurations) {
+ await config.runTest();
+ }
+ } finally {
+ timer.cancel();
}
}
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index 1f688e0..0795592 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -6438,6 +6438,17 @@
__ b(deopt, CS);
}
}
+
+static bool CanBePairOfImmediateOperands(Value* value,
+ compiler::Operand* low,
+ compiler::Operand* high) {
+ int64_t imm;
+ if (value->BindsToConstant() && compiler::HasIntegerValue(value->BoundConstant(), &imm)) {
+ return compiler::Operand::CanHold(Utils::Low32Bits(imm), low) &&
+ compiler::Operand::CanHold(Utils::High32Bits(imm), high);
+ }
+ return false;
+}
LocationSummary* BinaryInt64OpInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
@@ -6447,8 +6458,17 @@
LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
summary->set_in(0, Location::Pair(Location::RequiresRegister(),
Location::RequiresRegister()));
- summary->set_in(1, Location::Pair(Location::RequiresRegister(),
- Location::RequiresRegister()));
+
+ compiler::Operand o;
+ if (CanBePairOfImmediateOperands(right(), &o, &o) &&
+ (op_kind() == Token::kBIT_AND || op_kind() == Token::kBIT_OR ||
+ op_kind() == Token::kBIT_XOR || op_kind() == Token::kADD ||
+ op_kind() == Token::kSUB)) {
+ summary->set_in(1, Location::Constant(right()->definition()->AsConstant()));
+ } else {
+ summary->set_in(1, Location::Pair(Location::RequiresRegister(),
+ Location::RequiresRegister()));
+ }
summary->set_out(0, Location::Pair(Location::RequiresRegister(),
Location::RequiresRegister()));
if (op_kind() == Token::kMUL) {
@@ -6461,15 +6481,22 @@
PairLocation* left_pair = locs()->in(0).AsPairLocation();
Register left_lo = left_pair->At(0).reg();
Register left_hi = left_pair->At(1).reg();
- PairLocation* right_pair = locs()->in(1).AsPairLocation();
- Register right_lo = right_pair->At(0).reg();
- Register right_hi = right_pair->At(1).reg();
PairLocation* out_pair = locs()->out(0).AsPairLocation();
Register out_lo = out_pair->At(0).reg();
Register out_hi = out_pair->At(1).reg();
ASSERT(!can_overflow());
ASSERT(!CanDeoptimize());
+ compiler::Operand right_lo, right_hi;
+ if (locs()->in(1).IsConstant()) {
+ const bool ok = CanBePairOfImmediateOperands(right(), &right_lo, &right_hi);
+ RELEASE_ASSERT(ok);
+ } else {
+ PairLocation* right_pair = locs()->in(1).AsPairLocation();
+ right_lo = compiler::Operand(right_pair->At(0).reg());
+ right_hi = compiler::Operand(right_pair->At(1).reg());
+ }
+
switch (op_kind()) {
case Token::kBIT_AND: {
__ and_(out_lo, left_lo, compiler::Operand(right_lo));
@@ -6497,12 +6524,15 @@
break;
}
case Token::kMUL: {
+ PairLocation* right_pair = locs()->in(1).AsPairLocation();
+ Register right_lo_reg = right_pair->At(0).reg();
+ Register right_hi_reg = right_pair->At(1).reg();
// Compute 64-bit a * b as:
// a_l * b_l + (a_h * b_l + a_l * b_h) << 32
Register temp = locs()->temp(0).reg();
- __ mul(temp, left_lo, right_hi);
- __ mla(out_hi, left_hi, right_lo, temp);
- __ umull(out_lo, temp, left_lo, right_lo);
+ __ mul(temp, left_lo, right_hi_reg);
+ __ mla(out_hi, left_hi, right_lo_reg, temp);
+ __ umull(out_lo, temp, left_lo, right_lo_reg);
__ add(out_hi, out_hi, compiler::Operand(temp));
break;
}
diff --git a/tests/language/generic_methods/generic_invocation_all_types_test.dart b/tests/language/generic_methods/generic_invocation_all_types_test.dart
new file mode 100644
index 0000000..bad31e8
--- /dev/null
+++ b/tests/language/generic_methods/generic_invocation_all_types_test.dart
@@ -0,0 +1,50 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This test verifies that `f<T, U>(0)` is properly parsed as a generic
+// invocation, for all type syntaxes that may appear as T and U.
+
+// Note: it doesn't really matter what we import here; it's just a handy library
+// that has declares a types so that we can refer a type via a prefix.
+import 'dart:async' as prefix;
+
+import '../syntax_helper.dart';
+
+class C extends SyntaxTracker {
+ C([Object? x = absent, Object? y = absent])
+ : super('new C${SyntaxTracker.args(x, y)}');
+}
+
+/// Helper function to work around the fact that not all types can be expressed
+/// as type literals.
+Type typeOf<T>() => T;
+
+main() {
+ SyntaxTracker.known[C] = 'C';
+ SyntaxTracker.known[typeOf<C?>()] = 'C?';
+ SyntaxTracker.known[prefix.Zone] = 'prefix.Zone';
+ SyntaxTracker.known[typeOf<prefix.Zone?>()] = 'prefix.Zone?';
+ SyntaxTracker.known[dynamic] = 'dynamic';
+ SyntaxTracker.known[typeOf<List<C>>()] = 'List<C>';
+ SyntaxTracker.known[typeOf<List<C>?>()] = 'List<C>?';
+ SyntaxTracker.known[typeOf<void Function()>()] = 'void Function()';
+ SyntaxTracker.known[typeOf<void Function()?>()] = 'void Function()?';
+ checkSyntax(f(f<C, C>(0)), 'f(f<C, C>(0))');
+ checkSyntax(f(f<C?, C>(0)), 'f(f<C?, C>(0))');
+ checkSyntax(f(f<dynamic, C>(0)), 'f(f<dynamic, C>(0))');
+ checkSyntax(f(f<prefix.Zone, C>(0)), 'f(f<prefix.Zone, C>(0))');
+ checkSyntax(f(f<prefix.Zone?, C>(0)), 'f(f<prefix.Zone?, C>(0))');
+ checkSyntax(f(f<List<C>, C>(0)), 'f(f<List<C>, C>(0))');
+ checkSyntax(f(f<List<C>?, C>(0)), 'f(f<List<C>?, C>(0))');
+ checkSyntax(f(f<void Function(), C>(0)), 'f(f<void Function(), C>(0))');
+ checkSyntax(f(f<void Function()?, C>(0)), 'f(f<void Function()?, C>(0))');
+ checkSyntax(f(f<C, C?>(0)), 'f(f<C, C?>(0))');
+ checkSyntax(f(f<C, dynamic>(0)), 'f(f<C, dynamic>(0))');
+ checkSyntax(f(f<C, prefix.Zone>(0)), 'f(f<C, prefix.Zone>(0))');
+ checkSyntax(f(f<C, prefix.Zone?>(0)), 'f(f<C, prefix.Zone?>(0))');
+ checkSyntax(f(f<C, List<C>>(0)), 'f(f<C, List<C>>(0))');
+ checkSyntax(f(f<C, List<C>?>(0)), 'f(f<C, List<C>?>(0))');
+ checkSyntax(f(f<C, void Function()>(0)), 'f(f<C, void Function()>(0))');
+ checkSyntax(f(f<C, void Function()?>(0)), 'f(f<C, void Function()?>(0))');
+}
diff --git a/tests/language/generic_methods/non_generic_invocation_all_first_types_test.dart b/tests/language/generic_methods/non_generic_invocation_all_first_types_test.dart
new file mode 100644
index 0000000..a384927
--- /dev/null
+++ b/tests/language/generic_methods/non_generic_invocation_all_first_types_test.dart
@@ -0,0 +1,71 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This test verifies that `f<EXPR,b>(x)` is properly parsed as a pair of
+// expressions separated by a `,`, for all types of expressions that may appear
+// as EXPR that can't be parsed as types.
+
+import '../syntax_helper.dart';
+
+class C extends SyntaxTracker {
+ C([Object? x = absent, Object? y = absent])
+ : super('new C${SyntaxTracker.args(x, y)}');
+
+ C.syntax(String s) : super(s);
+}
+
+class ThisTest extends C {
+ ThisTest() : super.syntax('this');
+
+ void test() {
+ checkSyntax(f(x < this, C > (x)), 'f((x < this), (C > x))');
+ // Note: SyntaxTracker can't see the parens around `this` in the line below
+ checkSyntax(f(x < (this), C > (x)), 'f((x < this), (C > x))');
+ }
+}
+
+main() {
+ SyntaxTracker.known[C] = 'C';
+ SyntaxTracker.known[#x] = '#x';
+ checkSyntax(
+ f(x < x.getter.getter, C > (x)), 'f((x < x.getter.getter), (C > x))');
+ checkSyntax(f(x < C(), C > (x)), 'f((x < new C()), (C > x))');
+ checkSyntax(f(x < new C(), C > (x)), 'f((x < new C()), (C > x))');
+ checkSyntax(f(x < f(), C > (x)), 'f((x < f()), (C > x))');
+ checkSyntax(f(x < x.method(), C > (x)), 'f((x < x.method()), (C > x))');
+ checkSyntax(f(x < x[0](), C > (x)), 'f((x < x[0]()), (C > x))');
+ checkSyntax(f(x < #x, C > (x)), 'f((x < #x), (C > x))');
+ checkSyntax(f(x < null, C > (x)), 'f((x < null), (C > x))');
+ checkSyntax(f(x < 0, C > (x)), 'f((x < 0), (C > x))');
+ checkSyntax(f(x < 0.5, C > (x)), 'f((x < 0.5), (C > x))');
+ checkSyntax(f(x < [], C > (x)), 'f((x < []), (C > x))');
+ checkSyntax(f(x < [0], C > (x)), 'f((x < [0]), (C > x))');
+ checkSyntax(f(x < {}, C > (x)), 'f((x < {}), (C > x))');
+ checkSyntax(f(x < {0}, C > (x)), 'f((x < {0}), (C > x))');
+ checkSyntax(f(x < {0: 0}, C > (x)), 'f((x < { 0: 0 }), (C > x))');
+ checkSyntax(f(x < true, C > (x)), 'f((x < true), (C > x))');
+ checkSyntax(f(x < "s", C > (x)), 'f((x < "s"), (C > x))');
+ checkSyntax(f(x < r"s", C > (x)), 'f((x < "s"), (C > x))');
+ checkSyntax(f(x < x[0], C > (x)), 'f((x < x[0]), (C > x))');
+ // Note: SyntaxTracker can't see the `!` in the line below
+ checkSyntax(f(x < x!, C > (x)), 'f((x < x), (C > x))');
+ // Note: SyntaxTracker can't see the parens around `x` in the line below
+ checkSyntax(f(x < (x), C > (x)), 'f((x < x), (C > x))');
+ checkSyntax(f(x < -x, C > (x)), 'f((x < (-x)), (C > x))');
+ checkSyntax(f(x < !true, C > (x)), 'f((x < false), (C > x))');
+ checkSyntax(f(x < !(true), C > (x)), 'f((x < false), (C > x))');
+ checkSyntax(f(x < ~x, C > (x)), 'f((x < (~x)), (C > x))');
+ checkSyntax(f(x < x * x, C > (x)), 'f((x < (x * x)), (C > x))');
+ checkSyntax(f(x < x / x, C > (x)), 'f((x < (x / x)), (C > x))');
+ checkSyntax(f(x < x ~/ x, C > (x)), 'f((x < (x ~/ x)), (C > x))');
+ checkSyntax(f(x < x % x, C > (x)), 'f((x < (x % x)), (C > x))');
+ checkSyntax(f(x < x + x, C > (x)), 'f((x < (x + x)), (C > x))');
+ checkSyntax(f(x < x - x, C > (x)), 'f((x < (x - x)), (C > x))');
+ checkSyntax(f(x < x << x, C > (x)), 'f((x < (x << x)), (C > x))');
+ checkSyntax(f(x < x >> x, C > (x)), 'f((x < (x >> x)), (C > x))');
+ checkSyntax(f(x < x & x, C > (x)), 'f((x < (x & x)), (C > x))');
+ checkSyntax(f(x < x ^ x, C > (x)), 'f((x < (x ^ x)), (C > x))');
+ checkSyntax(f(x < x | x, C > (x)), 'f((x < (x | x)), (C > x))');
+ ThisTest().test();
+}
diff --git a/tests/language/generic_methods/non_generic_invocation_all_second_types_test.dart b/tests/language/generic_methods/non_generic_invocation_all_second_types_test.dart
new file mode 100644
index 0000000..d59058d
--- /dev/null
+++ b/tests/language/generic_methods/non_generic_invocation_all_second_types_test.dart
@@ -0,0 +1,85 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This test verifies that `f<a,EXPR>(x)` is properly parsed as a pair of
+// expressions separated by a `,`, for all types of expressions that may appear
+// as EXPR that can't be parsed as types.
+
+import '../syntax_helper.dart';
+
+class C extends SyntaxTracker {
+ C([Object? x = absent, Object? y = absent])
+ : super('new C${SyntaxTracker.args(x, y)}');
+
+ C.syntax(String s) : super(s);
+
+ Object? operator >(Object? other) =>
+ SyntaxTracker('(${syntax(this)} > ${syntax(other)})');
+}
+
+class ThisTest extends C {
+ ThisTest() : super.syntax('this');
+
+ void test() {
+ checkSyntax(f(x < C, this > (x)), 'f((x < C), (this > x))');
+ // Note: SyntaxTracker can't see the parens around `this` in the line below
+ checkSyntax(f(x < C, (this) > (x)), 'f((x < C), (this > x))');
+ }
+}
+
+class SuperTest extends C {
+ SuperTest() : super.syntax('super');
+
+ void test() {
+ checkSyntax(f(x < C, super > (x)), 'f((x < C), (super > x))');
+ }
+}
+
+main() {
+ const y = 123;
+ SyntaxTracker.known[C] = 'C';
+ SyntaxTracker.known[#x] = '#x';
+ SyntaxTracker.known[y] = 'y';
+ checkSyntax(
+ f(x < C, x.getter.getter > (x)), 'f((x < C), (x.getter.getter > x))');
+ checkSyntax(f(x < C, C() > (x)), 'f((x < C), (new C() > x))');
+ checkSyntax(f(x < C, new C() > (x)), 'f((x < C), (new C() > x))');
+ checkSyntax(f(x < C, f() > (x)), 'f((x < C), (f() > x))');
+ checkSyntax(f(x < C, x.method() > (x)), 'f((x < C), (x.method() > x))');
+ checkSyntax(f(x < C, x[0]() > (x)), 'f((x < C), (x[0]() > x))');
+ checkSyntax(f(x < C, #x > (x)), 'f((x < C), (#x > x))');
+ checkSyntax(f(x < C, null > (x)), 'f((x < C), (null > x))');
+ checkSyntax(f(x < C, 0 > (y)), 'f((x < C), false)');
+ checkSyntax(f(x < C, 0.5 > (y)), 'f((x < C), false)');
+ checkSyntax(f(x < C, [] > (x)), 'f((x < C), ([] > x))');
+ checkSyntax(f(x < C, [0] > (x)), 'f((x < C), ([0] > x))');
+ checkSyntax(f(x < C, {} > (x)), 'f((x < C), ({} > x))');
+ checkSyntax(f(x < C, {0} > (x)), 'f((x < C), ({0} > x))');
+ checkSyntax(f(x < C, {0: 0} > (x)), 'f((x < C), ({ 0: 0 } > x))');
+ checkSyntax(f(x < C, true > (x)), 'f((x < C), (true > x))');
+ checkSyntax(f(x < C, "s" > (x)), 'f((x < C), ("s" > x))');
+ checkSyntax(f(x < C, r"s" > (x)), 'f((x < C), ("s" > x))');
+ checkSyntax(f(x < C, x[0] > (x)), 'f((x < C), (x[0] > x))');
+ // Note: SyntaxTracker can't see the `!` in the line below
+ checkSyntax(f(x < C, x! > (x)), 'f((x < C), (x > x))');
+ // Note: SyntaxTracker can't see the parens around `x` in the line below
+ checkSyntax(f(x < C, (x) > (x)), 'f((x < C), (x > x))');
+ checkSyntax(f(x < C, -x > (x)), 'f((x < C), ((-x) > x))');
+ checkSyntax(f(x < C, !true > (x)), 'f((x < C), (false > x))');
+ checkSyntax(f(x < C, !(true) > (x)), 'f((x < C), (false > x))');
+ checkSyntax(f(x < C, ~x > (x)), 'f((x < C), ((~x) > x))');
+ checkSyntax(f(x < C, x * x > (x)), 'f((x < C), ((x * x) > x))');
+ checkSyntax(f(x < C, x / x > (x)), 'f((x < C), ((x / x) > x))');
+ checkSyntax(f(x < C, x ~/ x > (x)), 'f((x < C), ((x ~/ x) > x))');
+ checkSyntax(f(x < C, x % x > (x)), 'f((x < C), ((x % x) > x))');
+ checkSyntax(f(x < C, x + x > (x)), 'f((x < C), ((x + x) > x))');
+ checkSyntax(f(x < C, x - x > (x)), 'f((x < C), ((x - x) > x))');
+ checkSyntax(f(x < C, x << x > (x)), 'f((x < C), ((x << x) > x))');
+ checkSyntax(f(x < C, x >> x > (x)), 'f((x < C), ((x >> x) > x))');
+ checkSyntax(f(x < C, x & x > (x)), 'f((x < C), ((x & x) > x))');
+ checkSyntax(f(x < C, x ^ x > (x)), 'f((x < C), ((x ^ x) > x))');
+ checkSyntax(f(x < C, x | x > (x)), 'f((x < C), ((x | x) > x))');
+ ThisTest().test();
+ SuperTest().test();
+}
diff --git a/tests/language/string/overflow_test.dart b/tests/language/string/overflow_test.dart
index 8b01e19..f93428a 100644
--- a/tests/language/string/overflow_test.dart
+++ b/tests/language/string/overflow_test.dart
@@ -9,13 +9,15 @@
main() {
String a = "a";
- for (; a.length < 256 * 1024 * 1024;) a = a + a;
var exception_thrown = false;
try {
- var concat = "$a$a$a$a$a$a$a$a";
+ while (true) {
+ a = "$a$a";
+ }
} on OutOfMemoryError catch (exc) {
exception_thrown = true;
}
Expect.isTrue(exception_thrown);
+ Expect.isTrue(a.startsWith('aaaaa') && a.length > 1024);
}
diff --git a/tests/language/syntax_helper.dart b/tests/language/syntax_helper.dart
index 7cf4147..586edc0 100644
--- a/tests/language/syntax_helper.dart
+++ b/tests/language/syntax_helper.dart
@@ -51,7 +51,7 @@
'(${[x, y].where((v) => v is! Absent).join(', ')})';
static String typeArgs(Type T, Type U) =>
- T.toString() == 'dynamic' ? '' : '<${syntax(T)}, ${syntax(U)}>';
+ T == dynamic && U == dynamic ? '' : '<${syntax(T)}, ${syntax(U)}>';
/// Simple objects with known syntactic representations. Tests can add to
/// this map.
diff --git a/tests/language_2/generic_methods/generic_invocation_all_types_test.dart b/tests/language_2/generic_methods/generic_invocation_all_types_test.dart
new file mode 100644
index 0000000..f37efda
--- /dev/null
+++ b/tests/language_2/generic_methods/generic_invocation_all_types_test.dart
@@ -0,0 +1,38 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This test verifies that `f<T, U>(0)` is properly parsed as a generic
+// invocation, for all type syntaxes that may appear as T and U.
+
+// Note: it doesn't really matter what we import here; it's just a handy library
+// that has declares a types so that we can refer a type via a prefix.
+import 'dart:async' as prefix;
+
+import '../syntax_helper.dart';
+
+class C extends SyntaxTracker {
+ C([Object x = absent, Object y = absent])
+ : super('new C${SyntaxTracker.args(x, y)}');
+}
+
+/// Helper function to work around the fact that not all types can be expressed
+/// as type literals.
+Type typeOf<T>() => T;
+
+main() {
+ SyntaxTracker.known[C] = 'C';
+ SyntaxTracker.known[prefix.Zone] = 'prefix.Zone';
+ SyntaxTracker.known[dynamic] = 'dynamic';
+ SyntaxTracker.known[typeOf<List<C>>()] = 'List<C>';
+ SyntaxTracker.known[typeOf<void Function()>()] = 'void Function()';
+ checkSyntax(f(f<C, C>(0)), 'f(f<C, C>(0))');
+ checkSyntax(f(f<dynamic, C>(0)), 'f(f<dynamic, C>(0))');
+ checkSyntax(f(f<prefix.Zone, C>(0)), 'f(f<prefix.Zone, C>(0))');
+ checkSyntax(f(f<List<C>, C>(0)), 'f(f<List<C>, C>(0))');
+ checkSyntax(f(f<void Function(), C>(0)), 'f(f<void Function(), C>(0))');
+ checkSyntax(f(f<C, dynamic>(0)), 'f(f<C, dynamic>(0))');
+ checkSyntax(f(f<C, prefix.Zone>(0)), 'f(f<C, prefix.Zone>(0))');
+ checkSyntax(f(f<C, List<C>>(0)), 'f(f<C, List<C>>(0))');
+ checkSyntax(f(f<C, void Function()>(0)), 'f(f<C, void Function()>(0))');
+}
diff --git a/tests/language_2/generic_methods/non_generic_invocation_all_first_types_test.dart b/tests/language_2/generic_methods/non_generic_invocation_all_first_types_test.dart
new file mode 100644
index 0000000..59a76a8
--- /dev/null
+++ b/tests/language_2/generic_methods/non_generic_invocation_all_first_types_test.dart
@@ -0,0 +1,69 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This test verifies that `f<EXPR,b>(x)` is properly parsed as a pair of
+// expressions separated by a `,`, for all types of expressions that may appear
+// as EXPR that can't be parsed as types.
+
+import '../syntax_helper.dart';
+
+class C extends SyntaxTracker {
+ C([Object x = absent, Object y = absent])
+ : super('new C${SyntaxTracker.args(x, y)}');
+
+ C.syntax(String s) : super(s);
+}
+
+class ThisTest extends C {
+ ThisTest() : super.syntax('this');
+
+ void test() {
+ checkSyntax(f(x < this, C > (x)), 'f((x < this), (C > x))');
+ // Note: SyntaxTracker can't see the parens around `this` in the line below
+ checkSyntax(f(x < (this), C > (x)), 'f((x < this), (C > x))');
+ }
+}
+
+main() {
+ SyntaxTracker.known[C] = 'C';
+ SyntaxTracker.known[#x] = '#x';
+ checkSyntax(
+ f(x < x.getter.getter, C > (x)), 'f((x < x.getter.getter), (C > x))');
+ checkSyntax(f(x < C(), C > (x)), 'f((x < new C()), (C > x))');
+ checkSyntax(f(x < new C(), C > (x)), 'f((x < new C()), (C > x))');
+ checkSyntax(f(x < f(), C > (x)), 'f((x < f()), (C > x))');
+ checkSyntax(f(x < x.method(), C > (x)), 'f((x < x.method()), (C > x))');
+ checkSyntax(f(x < x[0](), C > (x)), 'f((x < x[0]()), (C > x))');
+ checkSyntax(f(x < #x, C > (x)), 'f((x < #x), (C > x))');
+ checkSyntax(f(x < null, C > (x)), 'f((x < null), (C > x))');
+ checkSyntax(f(x < 0, C > (x)), 'f((x < 0), (C > x))');
+ checkSyntax(f(x < 0.5, C > (x)), 'f((x < 0.5), (C > x))');
+ checkSyntax(f(x < [], C > (x)), 'f((x < []), (C > x))');
+ checkSyntax(f(x < [0], C > (x)), 'f((x < [0]), (C > x))');
+ checkSyntax(f(x < {}, C > (x)), 'f((x < {}), (C > x))');
+ checkSyntax(f(x < {0}, C > (x)), 'f((x < {0}), (C > x))');
+ checkSyntax(f(x < {0: 0}, C > (x)), 'f((x < { 0: 0 }), (C > x))');
+ checkSyntax(f(x < true, C > (x)), 'f((x < true), (C > x))');
+ checkSyntax(f(x < "s", C > (x)), 'f((x < "s"), (C > x))');
+ checkSyntax(f(x < r"s", C > (x)), 'f((x < "s"), (C > x))');
+ checkSyntax(f(x < x[0], C > (x)), 'f((x < x[0]), (C > x))');
+ // Note: SyntaxTracker can't see the parens around `x` in the line below
+ checkSyntax(f(x < (x), C > (x)), 'f((x < x), (C > x))');
+ checkSyntax(f(x < -x, C > (x)), 'f((x < (-x)), (C > x))');
+ checkSyntax(f(x < !true, C > (x)), 'f((x < false), (C > x))');
+ checkSyntax(f(x < !(true), C > (x)), 'f((x < false), (C > x))');
+ checkSyntax(f(x < ~x, C > (x)), 'f((x < (~x)), (C > x))');
+ checkSyntax(f(x < x * x, C > (x)), 'f((x < (x * x)), (C > x))');
+ checkSyntax(f(x < x / x, C > (x)), 'f((x < (x / x)), (C > x))');
+ checkSyntax(f(x < x ~/ x, C > (x)), 'f((x < (x ~/ x)), (C > x))');
+ checkSyntax(f(x < x % x, C > (x)), 'f((x < (x % x)), (C > x))');
+ checkSyntax(f(x < x + x, C > (x)), 'f((x < (x + x)), (C > x))');
+ checkSyntax(f(x < x - x, C > (x)), 'f((x < (x - x)), (C > x))');
+ checkSyntax(f(x < x << x, C > (x)), 'f((x < (x << x)), (C > x))');
+ checkSyntax(f(x < x >> x, C > (x)), 'f((x < (x >> x)), (C > x))');
+ checkSyntax(f(x < x & x, C > (x)), 'f((x < (x & x)), (C > x))');
+ checkSyntax(f(x < x ^ x, C > (x)), 'f((x < (x ^ x)), (C > x))');
+ checkSyntax(f(x < x | x, C > (x)), 'f((x < (x | x)), (C > x))');
+ ThisTest().test();
+}
diff --git a/tests/language_2/generic_methods/non_generic_invocation_all_second_types_test.dart b/tests/language_2/generic_methods/non_generic_invocation_all_second_types_test.dart
new file mode 100644
index 0000000..2036af2
--- /dev/null
+++ b/tests/language_2/generic_methods/non_generic_invocation_all_second_types_test.dart
@@ -0,0 +1,83 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This test verifies that `f<a,EXPR>(x)` is properly parsed as a pair of
+// expressions separated by a `,`, for all types of expressions that may appear
+// as EXPR that can't be parsed as types.
+
+import '../syntax_helper.dart';
+
+class C extends SyntaxTracker {
+ C([Object x = absent, Object y = absent])
+ : super('new C${SyntaxTracker.args(x, y)}');
+
+ C.syntax(String s) : super(s);
+
+ Object operator >(Object other) =>
+ SyntaxTracker('(${syntax(this)} > ${syntax(other)})');
+}
+
+class ThisTest extends C {
+ ThisTest() : super.syntax('this');
+
+ void test() {
+ checkSyntax(f(x < C, this > (x)), 'f((x < C), (this > x))');
+ // Note: SyntaxTracker can't see the parens around `this` in the line below
+ checkSyntax(f(x < C, (this) > (x)), 'f((x < C), (this > x))');
+ }
+}
+
+class SuperTest extends C {
+ SuperTest() : super.syntax('super');
+
+ void test() {
+ checkSyntax(f(x < C, super > (x)), 'f((x < C), (super > x))');
+ }
+}
+
+main() {
+ const y = 123;
+ SyntaxTracker.known[C] = 'C';
+ SyntaxTracker.known[#x] = '#x';
+ SyntaxTracker.known[y] = 'y';
+ checkSyntax(
+ f(x < C, x.getter.getter > (x)), 'f((x < C), (x.getter.getter > x))');
+ checkSyntax(f(x < C, C() > (x)), 'f((x < C), (new C() > x))');
+ checkSyntax(f(x < C, new C() > (x)), 'f((x < C), (new C() > x))');
+ checkSyntax(f(x < C, f() > (x)), 'f((x < C), (f() > x))');
+ checkSyntax(f(x < C, x.method() > (x)), 'f((x < C), (x.method() > x))');
+ checkSyntax(f(x < C, x[0]() > (x)), 'f((x < C), (x[0]() > x))');
+ checkSyntax(f(x < C, #x > (x)), 'f((x < C), (#x > x))');
+ checkSyntax(f(x < C, null > (x)), 'f((x < C), (null > x))');
+ checkSyntax(f(x < C, 0 > (y)), 'f((x < C), false)');
+ checkSyntax(f(x < C, 0.5 > (y)), 'f((x < C), false)');
+ checkSyntax(f(x < C, [] > (x)), 'f((x < C), ([] > x))');
+ checkSyntax(f(x < C, [0] > (x)), 'f((x < C), ([0] > x))');
+ checkSyntax(f(x < C, {} > (x)), 'f((x < C), ({} > x))');
+ checkSyntax(f(x < C, {0} > (x)), 'f((x < C), ({0} > x))');
+ checkSyntax(f(x < C, {0: 0} > (x)), 'f((x < C), ({ 0: 0 } > x))');
+ checkSyntax(f(x < C, true > (x)), 'f((x < C), (true > x))');
+ checkSyntax(f(x < C, "s" > (x)), 'f((x < C), ("s" > x))');
+ checkSyntax(f(x < C, r"s" > (x)), 'f((x < C), ("s" > x))');
+ checkSyntax(f(x < C, x[0] > (x)), 'f((x < C), (x[0] > x))');
+ // Note: SyntaxTracker can't see the parens around `x` in the line below
+ checkSyntax(f(x < C, (x) > (x)), 'f((x < C), (x > x))');
+ checkSyntax(f(x < C, -x > (x)), 'f((x < C), ((-x) > x))');
+ checkSyntax(f(x < C, !true > (x)), 'f((x < C), (false > x))');
+ checkSyntax(f(x < C, !(true) > (x)), 'f((x < C), (false > x))');
+ checkSyntax(f(x < C, ~x > (x)), 'f((x < C), ((~x) > x))');
+ checkSyntax(f(x < C, x * x > (x)), 'f((x < C), ((x * x) > x))');
+ checkSyntax(f(x < C, x / x > (x)), 'f((x < C), ((x / x) > x))');
+ checkSyntax(f(x < C, x ~/ x > (x)), 'f((x < C), ((x ~/ x) > x))');
+ checkSyntax(f(x < C, x % x > (x)), 'f((x < C), ((x % x) > x))');
+ checkSyntax(f(x < C, x + x > (x)), 'f((x < C), ((x + x) > x))');
+ checkSyntax(f(x < C, x - x > (x)), 'f((x < C), ((x - x) > x))');
+ checkSyntax(f(x < C, x << x > (x)), 'f((x < C), ((x << x) > x))');
+ checkSyntax(f(x < C, x >> x > (x)), 'f((x < C), ((x >> x) > x))');
+ checkSyntax(f(x < C, x & x > (x)), 'f((x < C), ((x & x) > x))');
+ checkSyntax(f(x < C, x ^ x > (x)), 'f((x < C), ((x ^ x) > x))');
+ checkSyntax(f(x < C, x | x > (x)), 'f((x < C), ((x | x) > x))');
+ ThisTest().test();
+ SuperTest().test();
+}
diff --git a/tests/language_2/string/overflow_test.dart b/tests/language_2/string/overflow_test.dart
index ad58981..ad4a332 100644
--- a/tests/language_2/string/overflow_test.dart
+++ b/tests/language_2/string/overflow_test.dart
@@ -11,13 +11,15 @@
main() {
String a = "a";
- for (; a.length < 256 * 1024 * 1024;) a = a + a;
var exception_thrown = false;
try {
- var concat = "$a$a$a$a$a$a$a$a";
+ while (true) {
+ a = "$a$a";
+ }
} on OutOfMemoryError catch (exc) {
exception_thrown = true;
}
Expect.isTrue(exception_thrown);
+ Expect.isTrue(a.startsWith('aaaaa') && a.length > 1024);
}
diff --git a/tests/language_2/syntax_helper.dart b/tests/language_2/syntax_helper.dart
index 1c65097..bf6f995 100644
--- a/tests/language_2/syntax_helper.dart
+++ b/tests/language_2/syntax_helper.dart
@@ -51,7 +51,7 @@
'(${[x, y].where((v) => v is! Absent).join(', ')})';
static String typeArgs(Type T, Type U) =>
- T.toString() == 'dynamic' ? '' : '<${syntax(T)}, ${syntax(U)}>';
+ T == dynamic && U == dynamic ? '' : '<${syntax(T)}, ${syntax(U)}>';
/// Simple objects with known syntactic representations. Tests can add to
/// this map.
diff --git a/tools/VERSION b/tools/VERSION
index a47d6f5..83dfa8e 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 14
PATCH 0
-PRERELEASE 124
+PRERELEASE 125
PRERELEASE_PATCH 0
\ No newline at end of file