Version 2.14.0-50.0.dev
Merge commit '0aaf26d265e5ff4ef6d66e508fc83de92f97690c' into 'dev'
diff --git a/pkg/front_end/test/fasta/types/kernel_type_parser_test.dart b/pkg/front_end/test/fasta/types/kernel_type_parser_test.dart
index 8ccfba3..e9d5c00 100644
--- a/pkg/front_end/test/fasta/types/kernel_type_parser_test.dart
+++ b/pkg/front_end/test/fasta/types/kernel_type_parser_test.dart
@@ -38,6 +38,9 @@
class ExtendedGenericClass<X>;
extension Extension on ExtendedClass;
extension GenericExtension<Y> on ExtendedGenericClass<Y>;
+extension TopExtension on dynamic;
+extension GenericTopExtension<Z> on dynamic;
+class ExtendedSubclass extends ExtendedClass;
""";
const String expectedSdk = """
@@ -89,10 +92,16 @@
}
class ExtendedGenericClass<X extends self::Object? = dynamic> extends self::Object {
}
+class ExtendedSubclass extends self::ExtendedClass {
+}
extension Extension on self::ExtendedClass {
}
extension GenericExtension<Y extends self::Object? = dynamic> on self::ExtendedGenericClass<Y%> {
}
+extension TopExtension on dynamic {
+}
+extension GenericTopExtension<Z extends self::Object? = dynamic> on dynamic {
+}
""";
Component parseSdk(Uri uri, TypeParserEnvironment environment) {
diff --git a/pkg/front_end/test/fasta/types/shared_type_tests.dart b/pkg/front_end/test/fasta/types/shared_type_tests.dart
index e7c03bc..f219fb6 100644
--- a/pkg/front_end/test/fasta/types/shared_type_tests.dart
+++ b/pkg/front_end/test/fasta/types/shared_type_tests.dart
@@ -1042,5 +1042,32 @@
isSubtype("List<int?>?", "List<int?>?");
isSubtype("T & int?", "T & int?", typeParameters: "T extends Object?");
isSubtype("T? & int?", "T? & int?", typeParameters: "T extends Object");
+
+ // Tests for extension types.
+ isSubtype("Never", "Extension");
+ isSubtype("Never", "GenericExtension<Never>");
+ isSubtype("Extension", "dynamic");
+ isSubtype("Extension", "void");
+ isSubtype("Extension", "Object?");
+ isSubtype("Extension", "FutureOr<dynamic>");
+ isSubtype("GenericExtension<dynamic>", "dynamic");
+ isSubtype("GenericExtension<dynamic>", "void");
+ isSubtype("GenericExtension<dynamic>", "Object?");
+ isSubtype("GenericExtension<dynamic>", "FutureOr<dynamic>");
+ isSubtype("dynamic", "TopExtension");
+ isSubtype("void", "TopExtension");
+ isSubtype("Object?", "TopExtension");
+ isSubtype("FutureOr<dynamic>", "TopExtension");
+ isSubtype("num", "TopExtension");
+ isSubtype("dynamic", "GenericTopExtension<String>");
+ isSubtype("void", "GenericTopExtension<String>");
+ isSubtype("Object?", "GenericTopExtension<String>");
+ isSubtype("FutureOr<dynamic>", "GenericTopExtension<String>");
+ isSubtype("num", "GenericTopExtension<String>");
+ isNotSubtype("Extension", "ExtendedClass");
+ isNotSubtype("GenericExtension<num>", "ExtendedGenericClass<num>");
+ isSubtype("ExtendedClass", "Extension");
+ isSubtype("ExtendedGenericClass<num>", "GenericExtension<num>");
+ isSubtype("ExtendedSubclass", "Extension");
}
}
diff --git a/pkg/front_end/testcases/extension_types/issue45775.dart.strong.expect b/pkg/front_end/testcases/extension_types/issue45775.dart.strong.expect
index f5b3d09..4e10ba8 100644
--- a/pkg/front_end/testcases/extension_types/issue45775.dart.strong.expect
+++ b/pkg/front_end/testcases/extension_types/issue45775.dart.strong.expect
@@ -1,12 +1,4 @@
library /*isNonNullableByDefault*/;
-//
-// Problems in library:
-//
-// pkg/front_end/testcases/extension_types/issue45775.dart:10:13: Error: A value of type 'Foo' can't be assigned to a variable of type 'Bar'.
-// - 'Foo' is from 'pkg/front_end/testcases/extension_types/issue45775.dart'.
-// Bar bar = Foo();
-// ^
-//
import self as self;
import "dart:core" as core;
@@ -18,8 +10,5 @@
extension Bar on self::Foo {
}
static method main() → void {
- self::Bar bar = let final Never #t1 = invalid-expression "pkg/front_end/testcases/extension_types/issue45775.dart:10:13: Error: A value of type 'Foo' can't be assigned to a variable of type 'Bar'.
- - 'Foo' is from 'pkg/front_end/testcases/extension_types/issue45775.dart'.
- Bar bar = Foo();
- ^" in new self::Foo::•() as{TypeError,ForNonNullableByDefault} self::Bar;
+ self::Bar bar = new self::Foo::•();
}
diff --git a/pkg/front_end/testcases/extension_types/issue45775.dart.weak.expect b/pkg/front_end/testcases/extension_types/issue45775.dart.weak.expect
index f5b3d09..4e10ba8 100644
--- a/pkg/front_end/testcases/extension_types/issue45775.dart.weak.expect
+++ b/pkg/front_end/testcases/extension_types/issue45775.dart.weak.expect
@@ -1,12 +1,4 @@
library /*isNonNullableByDefault*/;
-//
-// Problems in library:
-//
-// pkg/front_end/testcases/extension_types/issue45775.dart:10:13: Error: A value of type 'Foo' can't be assigned to a variable of type 'Bar'.
-// - 'Foo' is from 'pkg/front_end/testcases/extension_types/issue45775.dart'.
-// Bar bar = Foo();
-// ^
-//
import self as self;
import "dart:core" as core;
@@ -18,8 +10,5 @@
extension Bar on self::Foo {
}
static method main() → void {
- self::Bar bar = let final Never #t1 = invalid-expression "pkg/front_end/testcases/extension_types/issue45775.dart:10:13: Error: A value of type 'Foo' can't be assigned to a variable of type 'Bar'.
- - 'Foo' is from 'pkg/front_end/testcases/extension_types/issue45775.dart'.
- Bar bar = Foo();
- ^" in new self::Foo::•() as{TypeError,ForNonNullableByDefault} self::Bar;
+ self::Bar bar = new self::Foo::•();
}
diff --git a/pkg/kernel/lib/src/types.dart b/pkg/kernel/lib/src/types.dart
index 47c4b89..abb2a35 100644
--- a/pkg/kernel/lib/src/types.dart
+++ b/pkg/kernel/lib/src/types.dart
@@ -447,7 +447,6 @@
@override
IsSubtypeOf isExtensionRelated(
ExtensionType s, InterfaceType t, Types types) {
- // TODO(dmitryas): Use with the actual subtyping rules for extension types.
return const IsSubtypeOf.never();
}
}
@@ -628,7 +627,6 @@
@override
IsSubtypeOf isExtensionRelated(ExtensionType s, FunctionType t, Types types) {
- // TODO(dmitryas): Use with the actual subtyping rules for extension types.
return const IsSubtypeOf.never();
}
}
@@ -715,7 +713,6 @@
@override
IsSubtypeOf isExtensionRelated(
ExtensionType s, TypeParameterType t, Types types) {
- // TODO(dmitryas): Use with the actual subtyping rules for extension types.
return const IsSubtypeOf.never();
}
}
@@ -767,8 +764,7 @@
@override
IsSubtypeOf isExtensionRelated(ExtensionType s, TypedefType t, Types types) {
- // TODO(dmitryas): Use with the actual subtyping rules for extension types.
- return const IsSubtypeOf.never();
+ return types.performNullabilityAwareSubtypeCheck(s, t.unalias);
}
}
@@ -900,8 +896,9 @@
@override
IsSubtypeOf isExtensionRelated(ExtensionType s, FutureOrType t, Types types) {
- // TODO(dmitryas): Use with the actual subtyping rules for extension types.
- return const IsSubtypeOf.never();
+ // Rule 11.
+ return types.performNullabilityAwareSubtypeCheck(
+ s, t.typeArgument.withDeclaredNullability(t.nullability));
}
}
@@ -966,7 +963,6 @@
@override
IsSubtypeOf isExtensionRelated(
ExtensionType s, TypeParameterType t, Types types) {
- // TODO(dmitryas): Use with the actual subtyping rules for extension types.
return const IsSubtypeOf.never();
}
}
@@ -1022,7 +1018,6 @@
@override
IsSubtypeOf isExtensionRelated(ExtensionType s, NullType t, Types types) {
- // TODO(dmitryas): Use with the actual subtyping rules for extension types.
return const IsSubtypeOf.never();
}
}
@@ -1077,7 +1072,6 @@
@override
IsSubtypeOf isExtensionRelated(ExtensionType s, NeverType t, Types types) {
- // TODO(dmitryas): Use with the actual subtyping rules for extension types.
return const IsSubtypeOf.never();
}
}
@@ -1087,62 +1081,54 @@
@override
IsSubtypeOf isDynamicRelated(DynamicType s, ExtensionType t, Types types) {
- // TODO(dmitryas): Use with the actual subtyping rules for extension types.
- return const IsSubtypeOf.never();
+ return types.performNullabilityAwareSubtypeCheck(s, t.onType);
}
@override
IsSubtypeOf isVoidRelated(VoidType s, ExtensionType t, Types types) {
- // TODO(dmitryas): Use with the actual subtyping rules for extension types.
- return const IsSubtypeOf.never();
+ return types.performNullabilityAwareSubtypeCheck(s, t.onType);
}
@override
IsSubtypeOf isInterfaceRelated(
InterfaceType s, ExtensionType t, Types types) {
- // TODO(dmitryas): Use with the actual subtyping rules for extension types.
- return const IsSubtypeOf.never();
+ return types.performNullabilityAwareSubtypeCheck(s, t.onType);
}
@override
IsSubtypeOf isIntersectionRelated(
TypeParameterType intersection, ExtensionType t, Types types) {
- // TODO(dmitryas): Use with the actual subtyping rules for extension types.
- return const IsSubtypeOf.never();
+ return types.performNullabilityAwareSubtypeCheck(intersection, t.onType);
}
@override
IsSubtypeOf isFunctionRelated(FunctionType s, ExtensionType t, Types types) {
- // TODO(dmitryas): Use with the actual subtyping rules for extension types.
- return const IsSubtypeOf.never();
+ return types.performNullabilityAwareSubtypeCheck(s, t.onType);
}
@override
IsSubtypeOf isFutureOrRelated(FutureOrType s, ExtensionType t, Types types) {
- // TODO(dmitryas): Use with the actual subtyping rules for extension types.
- return const IsSubtypeOf.never();
+ return types.performNullabilityAwareSubtypeCheck(s, t.onType);
}
@override
IsSubtypeOf isTypeParameterRelated(
TypeParameterType s, ExtensionType t, Types types) {
- // TODO(dmitryas): Use with the actual subtyping rules for extension types.
- return const IsSubtypeOf.never();
+ return types.performNullabilityAwareSubtypeCheck(s, t.onType);
}
@override
IsSubtypeOf isTypedefRelated(TypedefType s, ExtensionType t, Types types) {
- // TODO(dmitryas): Use with the actual subtyping rules for extension types.
- return const IsSubtypeOf.never();
+ return types.performNullabilityAwareSubtypeCheck(s, t.onType);
}
@override
IsSubtypeOf isExtensionRelated(
ExtensionType s, ExtensionType t, Types types) {
- // TODO(dmitryas): Use with the actual subtyping rules for extension types.
if (s.extension != t.extension) {
return const IsSubtypeOf.never();
}
+ // TODO(dmitryas): Check if subtyping or mutual subtyping should be used.
return types
.areTypeArgumentsOfSubtypeKernel(
s.typeArguments, t.typeArguments, t.extension.typeParameters)
diff --git a/pkg/kernel/lib/testing/type_parser_environment.dart b/pkg/kernel/lib/testing/type_parser_environment.dart
index 262ae20..8b1cbe0 100644
--- a/pkg/kernel/lib/testing/type_parser_environment.dart
+++ b/pkg/kernel/lib/testing/type_parser_environment.dart
@@ -327,6 +327,9 @@
} else if (declaration is Typedef) {
return new TypedefType(declaration,
interpretParsedNullability(node.parsedNullability), kernelArguments);
+ } else if (declaration is Extension) {
+ return new ExtensionType(declaration,
+ interpretParsedNullability(node.parsedNullability), kernelArguments);
} else {
throw "Unhandled ${declaration.runtimeType}";
}
@@ -380,7 +383,7 @@
..addAll(parameters);
{
TypeParserEnvironment environment = parameterEnvironment.environment;
- InterfaceType onType =
+ DartType onType =
node.onType?.accept<Node, TypeParserEnvironment>(this, environment);
ext.onType = onType;
}
diff --git a/runtime/vm/compiler/backend/flow_graph.cc b/runtime/vm/compiler/backend/flow_graph.cc
index 27bc58a..ead29a0 100644
--- a/runtime/vm/compiler/backend/flow_graph.cc
+++ b/runtime/vm/compiler/backend/flow_graph.cc
@@ -948,7 +948,7 @@
//
// The algorithm is described in Georgiadis, Tarjan, and Werneck's
// "Finding Dominators in Practice".
- // See http://www.cs.princeton.edu/~rwerneck/dominators/ .
+ // https://renatowerneck.files.wordpress.com/2016/06/gtw06-dominators.pdf
// All arrays are maps between preorder basic-block numbers.
intptr_t size = parent_.length();
@@ -1115,7 +1115,10 @@
ASSERT(IsCompiledForOsr());
if (auto join = block->AsJoinEntry()) {
const intptr_t local_phi_count = variable_count() + join->stack_depth();
- for (intptr_t i = variable_count(); i < local_phi_count; ++i) {
+ // Never insert more phi's than that we had osr variables.
+ const intptr_t osr_phi_count =
+ Utils::Minimum(local_phi_count, osr_variable_count());
+ for (intptr_t i = variable_count(); i < osr_phi_count; ++i) {
if (join->phis() == nullptr || (*join->phis())[i] == nullptr) {
join->InsertPhi(i, local_phi_count)->mark_alive();
}
@@ -1150,15 +1153,23 @@
// These phis are synthetic since they are not driven by live variable
// analysis, but merely serve the purpose of merging stack slots from
// parameters and other predecessors at the block in which OSR occurred.
+ // The original definition could flow into a join via multiple predecessors
+ // but with the same definition, not requiring a phi. However, with an OSR
+ // entry in a different block, phis are required to merge the OSR variable
+ // and original definition where there was no phi. Therefore, we need
+ // synthetic phis in all (reachable) blocks, not just in the first join.
if (IsCompiledForOsr()) {
- AddSyntheticPhis(entry->osr_entry()->last_instruction()->SuccessorAt(0));
- for (intptr_t i = 0, n = entry->dominated_blocks().length(); i < n; ++i) {
- AddSyntheticPhis(entry->dominated_blocks()[i]);
+ for (intptr_t i = 0, n = preorder().length(); i < n; ++i) {
+ AddSyntheticPhis(preorder()[i]);
}
}
RenameRecursive(entry, &env, live_phis, variable_liveness,
inlining_parameters);
+
+#if defined(DEBUG)
+ ValidatePhis();
+#endif // defined(DEBUG)
}
void FlowGraph::PopulateEnvironmentFromFunctionEntry(
@@ -1595,6 +1606,46 @@
}
}
+#if defined(DEBUG)
+void FlowGraph::ValidatePhis() {
+ if (!FLAG_prune_dead_locals) {
+ // We can only check if dead locals are pruned.
+ return;
+ }
+
+ for (intptr_t i = 0, n = preorder().length(); i < n; ++i) {
+ BlockEntryInstr* block_entry = preorder()[i];
+ Instruction* last_instruction = block_entry->last_instruction();
+
+ if ((last_instruction->SuccessorCount() == 1) &&
+ last_instruction->SuccessorAt(0)->IsJoinEntry()) {
+ JoinEntryInstr* successor =
+ last_instruction->SuccessorAt(0)->AsJoinEntry();
+ if (successor->phis() != NULL) {
+ for (intptr_t j = 0; j < successor->phis()->length(); ++j) {
+ PhiInstr* phi = (*successor->phis())[j];
+ if (phi == nullptr) {
+ // We have no phi node for the this variable.
+ // Double check we do not have a different value in our env.
+ // If we do, we would have needed a phi-node in the successsor.
+ ASSERT(last_instruction->env() != nullptr);
+ Definition* current_definition =
+ last_instruction->env()->ValueAt(j)->definition();
+ ASSERT(successor->env() != nullptr);
+ Definition* successor_definition =
+ successor->env()->ValueAt(j)->definition();
+ if (!current_definition->IsConstant() &&
+ !successor_definition->IsConstant()) {
+ ASSERT(current_definition == successor_definition);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+#endif // defined(DEBUG)
+
void FlowGraph::RemoveDeadPhis(GrowableArray<PhiInstr*>* live_phis) {
// Augment live_phis with those that have implicit real used at
// potentially throwing instructions if there is a try-catch in this graph.
diff --git a/runtime/vm/compiler/backend/flow_graph.h b/runtime/vm/compiler/backend/flow_graph.h
index 7a7caa1..dbbd124 100644
--- a/runtime/vm/compiler/backend/flow_graph.h
+++ b/runtime/vm/compiler/backend/flow_graph.h
@@ -490,6 +490,10 @@
GrowableArray<PhiInstr*>* live_phis,
VariableLivenessAnalysis* variable_liveness,
ZoneGrowableArray<Definition*>* inlining_parameters);
+#if defined(DEBUG)
+ // Validates no phis are missing on join entry instructions.
+ void ValidatePhis();
+#endif // defined(DEBUG)
void PopulateEnvironmentFromFunctionEntry(
FunctionEntryInstr* function_entry,
diff --git a/tests/language/vm/regress_45260_test.dart b/tests/language/vm/regress_45260_test.dart
new file mode 100644
index 0000000..17991e3
--- /dev/null
+++ b/tests/language/vm/regress_45260_test.dart
@@ -0,0 +1,51 @@
+// 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.
+//
+// VMOptions=--optimization-counter-threshold=5 --deterministic
+
+import 'package:expect/expect.dart';
+
+List<List<List<List<int>>>> toNestedList() {
+ final list = [
+ for (var i0 = 0; i0 < 2; i0++)
+ [
+ for (var i1 = 0; i1 < 2; i1++)
+ [
+ for (var i2 = 0; i2 < 2; i2++)
+ [
+ for (var i3 = 0; i3 < 2; i3++)
+ 1000 * i0 + 100 * i1 + 10 * i2 + i3
+ ]
+ ]
+ ]
+ ];
+ return list;
+}
+
+const expectedList = [
+ [
+ [
+ [0000, 0001],
+ [0010, 0011],
+ ],
+ [
+ [0100, 0101],
+ [0110, 0111],
+ ]
+ ],
+ [
+ [
+ [1000, 1001],
+ [1010, 1011],
+ ],
+ [
+ [1100, 1101],
+ [1110, 1111],
+ ]
+ ]
+];
+
+void main() {
+ Expect.deepEquals(expectedList, toNestedList());
+}
diff --git a/tests/language_2/vm/regress_45260_test.dart b/tests/language_2/vm/regress_45260_test.dart
new file mode 100644
index 0000000..17991e3
--- /dev/null
+++ b/tests/language_2/vm/regress_45260_test.dart
@@ -0,0 +1,51 @@
+// 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.
+//
+// VMOptions=--optimization-counter-threshold=5 --deterministic
+
+import 'package:expect/expect.dart';
+
+List<List<List<List<int>>>> toNestedList() {
+ final list = [
+ for (var i0 = 0; i0 < 2; i0++)
+ [
+ for (var i1 = 0; i1 < 2; i1++)
+ [
+ for (var i2 = 0; i2 < 2; i2++)
+ [
+ for (var i3 = 0; i3 < 2; i3++)
+ 1000 * i0 + 100 * i1 + 10 * i2 + i3
+ ]
+ ]
+ ]
+ ];
+ return list;
+}
+
+const expectedList = [
+ [
+ [
+ [0000, 0001],
+ [0010, 0011],
+ ],
+ [
+ [0100, 0101],
+ [0110, 0111],
+ ]
+ ],
+ [
+ [
+ [1000, 1001],
+ [1010, 1011],
+ ],
+ [
+ [1100, 1101],
+ [1110, 1111],
+ ]
+ ]
+];
+
+void main() {
+ Expect.deepEquals(expectedList, toNestedList());
+}
diff --git a/tools/VERSION b/tools/VERSION
index 968abde..cc9e6ba 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 14
PATCH 0
-PRERELEASE 49
+PRERELEASE 50
PRERELEASE_PATCH 0
\ No newline at end of file