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