Version 2.13.0-91.0.dev

Merge commit 'e0f45c2cdf3fed270ffbcf23b28cf0ad09c38337' into 'dev'
diff --git a/pkg/analyzer/lib/src/error/dead_code_verifier.dart b/pkg/analyzer/lib/src/error/dead_code_verifier.dart
index eea542d..ec56191 100644
--- a/pkg/analyzer/lib/src/error/dead_code_verifier.dart
+++ b/pkg/analyzer/lib/src/error/dead_code_verifier.dart
@@ -568,6 +568,11 @@
     if (flowAnalysis == null) return;
     flowAnalysis.checkUnreachableNode(node);
 
+    // If the first dead node is not `null`, even if this new new node is
+    // unreachable, we can ignore it as it is part of the same dead code
+    // range anyway.
+    if (_firstDeadNode != null) return;
+
     var flow = flowAnalysis.flow;
     if (flow == null) return;
 
@@ -580,7 +585,6 @@
       }
     }
 
-    if (_firstDeadNode != null) return;
     _firstDeadNode = node;
   }
 
diff --git a/pkg/front_end/lib/src/fasta/builder/constructor_reference_builder.dart b/pkg/front_end/lib/src/fasta/builder/constructor_reference_builder.dart
index 824d08f..79ece35 100644
--- a/pkg/front_end/lib/src/fasta/builder/constructor_reference_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/constructor_reference_builder.dart
@@ -67,6 +67,10 @@
       }
     } else {
       declaration = scope.lookup(name, charOffset, fileUri);
+      if (declaration is TypeAliasBuilder) {
+        TypeAliasBuilder aliasBuilder = declaration;
+        declaration = aliasBuilder.unaliasDeclaration(typeArguments);
+      }
     }
     if (declaration is ClassBuilder) {
       target = declaration.findConstructorOrFactory(
diff --git a/pkg/front_end/lib/src/fasta/fasta_codes_cfe_generated.dart b/pkg/front_end/lib/src/fasta/fasta_codes_cfe_generated.dart
index a145ee7..127d61d 100644
--- a/pkg/front_end/lib/src/fasta/fasta_codes_cfe_generated.dart
+++ b/pkg/front_end/lib/src/fasta/fasta_codes_cfe_generated.dart
@@ -4730,6 +4730,43 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<
+        Message Function(
+            String name, DartType _type, bool isNonNullableByDefault)>
+    templateUndefinedExtensionMethod = const Template<
+            Message Function(
+                String name, DartType _type, bool isNonNullableByDefault)>(
+        messageTemplate:
+            r"""The method '#name' isn't defined for the extension '#type'.""",
+        tipTemplate:
+            r"""Try correcting the name to the name of an existing method, or defining a method name '#name'.""",
+        withArguments: _withArgumentsUndefinedExtensionMethod);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<
+    Message Function(String name, DartType _type,
+        bool isNonNullableByDefault)> codeUndefinedExtensionMethod = const Code<
+    Message Function(String name, DartType _type, bool isNonNullableByDefault)>(
+  "UndefinedExtensionMethod",
+);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsUndefinedExtensionMethod(
+    String name, DartType _type, bool isNonNullableByDefault) {
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  TypeLabeler labeler = new TypeLabeler(isNonNullableByDefault);
+  List<Object> typeParts = labeler.labelType(_type);
+  String type = typeParts.join();
+  return new Message(codeUndefinedExtensionMethod,
+      message:
+          """The method '${name}' isn't defined for the extension '${type}'.""" +
+              labeler.originMessages,
+      tip: """Try correcting the name to the name of an existing method, or defining a method name '${name}'.""",
+      arguments: {'name': name, 'type': _type});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
     Message Function(
         String name,
         DartType _type,
diff --git a/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart b/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
index 3ea1788..06bdd72 100644
--- a/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
@@ -54,6 +54,8 @@
 
 import 'inference_visitor.dart';
 
+import 'type_labeler.dart';
+
 /// Computes the return type of a (possibly factory) constructor.
 InterfaceType computeConstructorReturnType(
     Member constructor, CoreTypes coreTypes) {
@@ -4303,6 +4305,30 @@
       // TODO(dmitryas): Remove the following line and implement
       // BinaryPrinter.visitExtensionType when it's available.
       return onType.accept(v);
+    } else if (v is TypeLabeler) {
+      // TODO(dmitryas): Move this guarded code into
+      // TypeLabeler.visitExtensionType when it's available.
+      TypeLabeler typeLabeler = v as TypeLabeler;
+      typeLabeler.result.add(typeLabeler.nameForEntity(
+          extensionNode,
+          extensionNode.name,
+          extensionNode.enclosingLibrary.importUri,
+          extensionNode.enclosingLibrary.fileUri));
+      if (typeArguments.isNotEmpty) {
+        typeLabeler.result.add("<");
+        bool first = true;
+        for (DartType typeArg in typeArguments) {
+          if (!first) typeLabeler.result.add(", ");
+          typeArg.accept(typeLabeler);
+          first = false;
+        }
+        typeLabeler.result.add(">");
+      }
+      typeLabeler.addNullability(declaredNullability);
+      // The following line is needed to supply the return value and make the
+      // compiler happy. It should go away once ExtensionType is moved to
+      // ast.dart.
+      return null;
     }
     // TODO(dmitryas): Change this to `v.visitExtensionType(this)` when
     // ExtensionType is moved to ast.dart.
@@ -4363,7 +4389,7 @@
 
   @override
   String toString() {
-    return "ExtensionType(${toStringInternal})";
+    return "ExtensionType(${toStringInternal()})";
   }
 
   @override
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 a7282a4..b450ab3 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
@@ -868,6 +868,41 @@
     return inferredTypes;
   }
 
+  /// Returns extension member declared immediately for [receiverType].
+  ///
+  /// If none is found, [defaultTarget] is returned.
+  ObjectAccessTarget _findDirectExtensionMember(
+      ExtensionType receiverType, Name name, int fileOffset,
+      {ObjectAccessTarget defaultTarget}) {
+    Member targetMethod;
+    Member targetTearoff;
+    for (ExtensionMemberDescriptor descriptor
+        in receiverType.extensionNode.members) {
+      if (descriptor.name == name) {
+        switch (descriptor.kind) {
+          case ExtensionMemberKind.Method:
+            targetMethod = descriptor.member.asMember;
+            break;
+          case ExtensionMemberKind.TearOff:
+            targetTearoff = descriptor.member.asMember;
+            break;
+          default:
+            unhandled("${descriptor.kind}", "findInterfaceMember", fileOffset,
+                library.fileUri);
+        }
+      }
+    }
+    if (targetMethod != null) {
+      return new ObjectAccessTarget.extensionMember(
+          targetMethod,
+          targetTearoff ?? targetMethod,
+          ProcedureKind.Method,
+          receiverType.typeArguments);
+    } else {
+      return defaultTarget;
+    }
+  }
+
   /// Returns the extension member access by the given [name] for a receiver
   /// with the static [receiverType].
   ///
@@ -1104,6 +1139,10 @@
       target = isReceiverTypePotentiallyNullable
           ? const ObjectAccessTarget.nullableCallFunction()
           : const ObjectAccessTarget.callFunction();
+    } else if (library.enableExtensionTypesInLibrary &&
+        receiverBound is ExtensionType) {
+      target = _findDirectExtensionMember(receiverBound, name, fileOffset,
+          defaultTarget: const ObjectAccessTarget.missing());
     } else {
       target = const ObjectAccessTarget.missing();
     }
@@ -4069,7 +4108,9 @@
           receiverType,
           name,
           extensionAccessCandidates,
-          templateUndefinedMethod,
+          receiverType is ExtensionType
+              ? templateUndefinedExtensionMethod
+              : templateUndefinedMethod,
           templateAmbiguousExtensionMethod);
     }
   }
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart b/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart
index 7b37c14..172476b 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart
@@ -17,6 +17,8 @@
 import 'package:kernel/src/hierarchy_based_type_environment.dart'
     show HierarchyBasedTypeEnvironment;
 
+import '../kernel/internal_ast.dart' show ExtensionType;
+
 import 'standard_bounds.dart' show TypeSchemaStandardBounds;
 
 import 'type_constraint_gatherer.dart' show TypeConstraintGatherer;
@@ -363,12 +365,52 @@
   IsSubtypeOf performNullabilityAwareSubtypeCheck(
       DartType subtype, DartType supertype) {
     if (subtype is UnknownType) return const IsSubtypeOf.always();
+
+    // For now, extension types are only related to themselves, top types, and
+    // bottom types.
+    // TODO(dmitryas): Implement subtyping rules for extension types.
+    if (subtype is ExtensionType) {
+      if (coreTypes.isTop(supertype)) {
+        return const IsSubtypeOf.always();
+      } else if (supertype is ExtensionType &&
+          subtype.extensionNode == supertype.extensionNode) {
+        assert(subtype.typeArguments.length == supertype.typeArguments.length);
+        IsSubtypeOf result = const IsSubtypeOf.always();
+        for (int i = 0; i < subtype.typeArguments.length; ++i) {
+          result.and(performNullabilityAwareMutualSubtypesCheck(
+              subtype.typeArguments[i], supertype.typeArguments[i]));
+        }
+        return result;
+      } else {
+        return const IsSubtypeOf.never();
+      }
+    }
+
     DartType unwrappedSupertype = supertype;
     while (unwrappedSupertype is FutureOrType) {
       unwrappedSupertype = (unwrappedSupertype as FutureOrType).typeArgument;
     }
     if (unwrappedSupertype is UnknownType) {
       return const IsSubtypeOf.always();
+    } else if (unwrappedSupertype is ExtensionType) {
+      // For now, extension types are only related to themselves, top types, and
+      // bottom types.
+      // TODO(dmitryas): Implement subtyping rules for extension types.
+      if (coreTypes.isBottom(subtype)) {
+        return const IsSubtypeOf.always();
+      } else if (subtype is ExtensionType &&
+          subtype.extensionNode == unwrappedSupertype.extensionNode) {
+        assert(subtype.typeArguments.length ==
+            unwrappedSupertype.typeArguments.length);
+        IsSubtypeOf result = const IsSubtypeOf.always();
+        for (int i = 0; i < subtype.typeArguments.length; ++i) {
+          result.and(performNullabilityAwareMutualSubtypesCheck(
+              subtype.typeArguments[i], unwrappedSupertype.typeArguments[i]));
+        }
+        return result;
+      } else {
+        return const IsSubtypeOf.never();
+      }
     }
     return super.performNullabilityAwareSubtypeCheck(subtype, supertype);
   }
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index 8e24091..9c120af 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -772,6 +772,8 @@
 TypedefNullableType/analyzerCode: Fail
 TypedefTypeVariableNotConstructor/analyzerCode: Fail # Feature not yet enabled by default.
 TypedefTypeVariableNotConstructor/example: Fail # Feature not yet enabled by default.
+UndefinedExtensionMethod/analyzerCode: Fail
+UndefinedExtensionMethod/example: Fail
 UnexpectedToken/part_wrapped_script1: Fail
 UnexpectedToken/script1: Fail
 UnmatchedToken/part_wrapped_script1: Fail
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index cc8fb0d..36d6bcc 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -3491,6 +3491,10 @@
       c + 0;
     }
 
+UndefinedExtensionMethod:
+  template: "The method '#name' isn't defined for the extension '#type'."
+  tip: "Try correcting the name to the name of an existing method, or defining a method name '#name'."
+
 AmbiguousExtensionMethod:
   template: "The method '#name' is defined in multiple extensions for '#type' and neither is more specific."
   tip: "Try using an explicit extension application of the wanted extension or hiding unwanted extensions from scope."
diff --git a/pkg/front_end/testcases/extension_types/simple_method_resolution.dart b/pkg/front_end/testcases/extension_types/simple_method_resolution.dart
new file mode 100644
index 0000000..0406a33
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/simple_method_resolution.dart
@@ -0,0 +1,20 @@
+// 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.
+
+class A {
+  void foo() {}
+}
+
+extension E on A {
+  void bar() => foo();
+}
+
+test(A a, E e) {
+  a.foo(); // Ok.
+  a.bar(); // Ok.
+  e.foo(); // Error.
+  e.bar(); // Ok.
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.strong.expect b/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.strong.expect
new file mode 100644
index 0000000..207f18f
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.strong.expect
@@ -0,0 +1,36 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extension_types/simple_method_resolution.dart:16:5: Error: The method 'foo' isn't defined for the extension 'E'.
+// Try correcting the name to the name of an existing method, or defining a method name 'foo'.
+//   e.foo(); // Error.
+//     ^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+  method foo() → void {}
+}
+extension E on self::A {
+  method bar = self::E|bar;
+  tearoff bar = self::E|get#bar;
+}
+static method E|bar(lowered final self::A #this) → void
+  return #this.{self::A::foo}();
+static method E|get#bar(lowered final self::A #this) → () → void
+  return () → void => self::E|bar(#this);
+static method test(self::A a, self::E e) → dynamic {
+  a.{self::A::foo}();
+  self::E|bar(a);
+  invalid-expression "pkg/front_end/testcases/extension_types/simple_method_resolution.dart:16:5: Error: The method 'foo' isn't defined for the extension 'E'.
+Try correcting the name to the name of an existing method, or defining a method name 'foo'.
+  e.foo(); // Error.
+    ^^^";
+  self::E|bar(e);
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.strong.transformed.expect b/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.strong.transformed.expect
new file mode 100644
index 0000000..207f18f
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.strong.transformed.expect
@@ -0,0 +1,36 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extension_types/simple_method_resolution.dart:16:5: Error: The method 'foo' isn't defined for the extension 'E'.
+// Try correcting the name to the name of an existing method, or defining a method name 'foo'.
+//   e.foo(); // Error.
+//     ^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+  method foo() → void {}
+}
+extension E on self::A {
+  method bar = self::E|bar;
+  tearoff bar = self::E|get#bar;
+}
+static method E|bar(lowered final self::A #this) → void
+  return #this.{self::A::foo}();
+static method E|get#bar(lowered final self::A #this) → () → void
+  return () → void => self::E|bar(#this);
+static method test(self::A a, self::E e) → dynamic {
+  a.{self::A::foo}();
+  self::E|bar(a);
+  invalid-expression "pkg/front_end/testcases/extension_types/simple_method_resolution.dart:16:5: Error: The method 'foo' isn't defined for the extension 'E'.
+Try correcting the name to the name of an existing method, or defining a method name 'foo'.
+  e.foo(); // Error.
+    ^^^";
+  self::E|bar(e);
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.textual_outline.expect b/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.textual_outline.expect
new file mode 100644
index 0000000..d2f4abf
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.textual_outline.expect
@@ -0,0 +1,10 @@
+class A {
+  void foo() {}
+}
+
+extension E on A {
+  void bar() => foo();
+}
+
+test(A a, E e) {}
+main() {}
diff --git a/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..00002ee
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.textual_outline_modelled.expect
@@ -0,0 +1,10 @@
+class A {
+  void foo() {}
+}
+
+extension E on A {
+  void bar() => foo();
+}
+
+main() {}
+test(A a, E e) {}
diff --git a/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.weak.expect b/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.weak.expect
new file mode 100644
index 0000000..207f18f
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.weak.expect
@@ -0,0 +1,36 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extension_types/simple_method_resolution.dart:16:5: Error: The method 'foo' isn't defined for the extension 'E'.
+// Try correcting the name to the name of an existing method, or defining a method name 'foo'.
+//   e.foo(); // Error.
+//     ^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+  method foo() → void {}
+}
+extension E on self::A {
+  method bar = self::E|bar;
+  tearoff bar = self::E|get#bar;
+}
+static method E|bar(lowered final self::A #this) → void
+  return #this.{self::A::foo}();
+static method E|get#bar(lowered final self::A #this) → () → void
+  return () → void => self::E|bar(#this);
+static method test(self::A a, self::E e) → dynamic {
+  a.{self::A::foo}();
+  self::E|bar(a);
+  invalid-expression "pkg/front_end/testcases/extension_types/simple_method_resolution.dart:16:5: Error: The method 'foo' isn't defined for the extension 'E'.
+Try correcting the name to the name of an existing method, or defining a method name 'foo'.
+  e.foo(); // Error.
+    ^^^";
+  self::E|bar(e);
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.weak.outline.expect b/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.weak.outline.expect
new file mode 100644
index 0000000..e77d076
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.weak.outline.expect
@@ -0,0 +1,22 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    ;
+  method foo() → void
+    ;
+}
+extension E on self::A {
+  method bar = self::E|bar;
+  tearoff bar = self::E|get#bar;
+}
+static method E|bar(lowered final self::A #this) → void
+  ;
+static method E|get#bar(lowered final self::A #this) → () → void
+  return () → void => self::E|bar(#this);
+static method test(self::A a, self::E e) → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.weak.transformed.expect b/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.weak.transformed.expect
new file mode 100644
index 0000000..207f18f
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/simple_method_resolution.dart.weak.transformed.expect
@@ -0,0 +1,36 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extension_types/simple_method_resolution.dart:16:5: Error: The method 'foo' isn't defined for the extension 'E'.
+// Try correcting the name to the name of an existing method, or defining a method name 'foo'.
+//   e.foo(); // Error.
+//     ^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+  method foo() → void {}
+}
+extension E on self::A {
+  method bar = self::E|bar;
+  tearoff bar = self::E|get#bar;
+}
+static method E|bar(lowered final self::A #this) → void
+  return #this.{self::A::foo}();
+static method E|get#bar(lowered final self::A #this) → () → void
+  return () → void => self::E|bar(#this);
+static method test(self::A a, self::E e) → dynamic {
+  a.{self::A::foo}();
+  self::E|bar(a);
+  invalid-expression "pkg/front_end/testcases/extension_types/simple_method_resolution.dart:16:5: Error: The method 'foo' isn't defined for the extension 'E'.
+Try correcting the name to the name of an existing method, or defining a method name 'foo'.
+  e.foo(); // Error.
+    ^^^";
+  self::E|bar(e);
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/issue45051.dart b/pkg/front_end/testcases/nonfunction_type_aliases/issue45051.dart
new file mode 100644
index 0000000..4f2e02f
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/issue45051.dart
@@ -0,0 +1,17 @@
+// 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.
+
+class A {
+  factory A() = BAlias;
+  factory A.named() = BAlias.named;
+}
+
+typedef BAlias = B;
+
+class B implements A {
+  B();
+  B.named();
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/issue45051.dart.strong.expect b/pkg/front_end/testcases/nonfunction_type_aliases/issue45051.dart.strong.expect
new file mode 100644
index 0000000..435aedb
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/issue45051.dart.strong.expect
@@ -0,0 +1,21 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef BAlias = self::B;
+class A extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::A::•, self::A::named]/*isLegacy*/;
+  static factory •() → self::A
+    let dynamic #redirecting_factory = self::B::• in invalid-expression;
+  static factory named() → self::A
+    let dynamic #redirecting_factory = self::B::named in invalid-expression;
+}
+class B extends core::Object implements self::A {
+  constructor •() → self::B
+    : super core::Object::•()
+    ;
+  constructor named() → self::B
+    : super core::Object::•()
+    ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/issue45051.dart.strong.transformed.expect b/pkg/front_end/testcases/nonfunction_type_aliases/issue45051.dart.strong.transformed.expect
new file mode 100644
index 0000000..b58ffcf
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/issue45051.dart.strong.transformed.expect
@@ -0,0 +1,21 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef BAlias = self::B;
+class A extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::A::•, self::A::named]/*isLegacy*/;
+  static factory •() → self::A
+    let Never #redirecting_factory = self::B::• in invalid-expression;
+  static factory named() → self::A
+    let Never #redirecting_factory = self::B::named in invalid-expression;
+}
+class B extends core::Object implements self::A {
+  constructor •() → self::B
+    : super core::Object::•()
+    ;
+  constructor named() → self::B
+    : super core::Object::•()
+    ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/issue45051.dart.textual_outline.expect b/pkg/front_end/testcases/nonfunction_type_aliases/issue45051.dart.textual_outline.expect
new file mode 100644
index 0000000..08b1c6f
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/issue45051.dart.textual_outline.expect
@@ -0,0 +1,10 @@
+class A {
+  factory A() = BAlias;
+  factory A.named() = BAlias.named;
+}
+typedef BAlias = B;
+class B implements A {
+  B();
+  B.named();
+}
+main() {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/issue45051.dart.weak.expect b/pkg/front_end/testcases/nonfunction_type_aliases/issue45051.dart.weak.expect
new file mode 100644
index 0000000..435aedb
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/issue45051.dart.weak.expect
@@ -0,0 +1,21 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef BAlias = self::B;
+class A extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::A::•, self::A::named]/*isLegacy*/;
+  static factory •() → self::A
+    let dynamic #redirecting_factory = self::B::• in invalid-expression;
+  static factory named() → self::A
+    let dynamic #redirecting_factory = self::B::named in invalid-expression;
+}
+class B extends core::Object implements self::A {
+  constructor •() → self::B
+    : super core::Object::•()
+    ;
+  constructor named() → self::B
+    : super core::Object::•()
+    ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/issue45051.dart.weak.outline.expect b/pkg/front_end/testcases/nonfunction_type_aliases/issue45051.dart.weak.outline.expect
new file mode 100644
index 0000000..65b2862
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/issue45051.dart.weak.outline.expect
@@ -0,0 +1,20 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef BAlias = self::B;
+class A extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::A::•, self::A::named]/*isLegacy*/;
+  static factory •() → self::A
+    let dynamic #redirecting_factory = self::B::• in invalid-expression;
+  static factory named() → self::A
+    let dynamic #redirecting_factory = self::B::named in invalid-expression;
+}
+class B extends core::Object implements self::A {
+  constructor •() → self::B
+    ;
+  constructor named() → self::B
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/issue45051.dart.weak.transformed.expect b/pkg/front_end/testcases/nonfunction_type_aliases/issue45051.dart.weak.transformed.expect
new file mode 100644
index 0000000..b58ffcf
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/issue45051.dart.weak.transformed.expect
@@ -0,0 +1,21 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef BAlias = self::B;
+class A extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::A::•, self::A::named]/*isLegacy*/;
+  static factory •() → self::A
+    let Never #redirecting_factory = self::B::• in invalid-expression;
+  static factory named() → self::A
+    let Never #redirecting_factory = self::B::named in invalid-expression;
+}
+class B extends core::Object implements self::A {
+  constructor •() → self::B
+    : super core::Object::•()
+    ;
+  constructor named() → self::B
+    : super core::Object::•()
+    ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/outline.status b/pkg/front_end/testcases/outline.status
index 4be494f..63e873f 100644
--- a/pkg/front_end/testcases/outline.status
+++ b/pkg/front_end/testcases/outline.status
@@ -3,6 +3,7 @@
 # BSD-style license that can be found in the LICENSE.md file.
 
 extension_types/simple: ExpectationFileMismatchSerialized
+extension_types/simple_method_resolution: ExpectationFileMismatchSerialized
 general/abstract_members: TypeCheckError
 general/bug30695: TypeCheckError
 general/covariant_field: TypeCheckError
diff --git a/pkg/front_end/testcases/strong.status b/pkg/front_end/testcases/strong.status
index ba90386..757cc84 100644
--- a/pkg/front_end/testcases/strong.status
+++ b/pkg/front_end/testcases/strong.status
@@ -7,6 +7,7 @@
 # strong-mode enabled.
 
 extension_types/simple: ExpectationFileMismatchSerialized # Expected.
+extension_types/simple_method_resolution: ExpectationFileMismatchSerialized # Expected.
 late_lowering/covariant_late_field: TypeCheckError
 nnbd/covariant_late_field: TypeCheckError
 nnbd/getter_vs_setter_type: TypeCheckError
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index b106449..bd4dc72 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -8,6 +8,7 @@
 
 dartdevc/private_covariant: TextSerializationFailure
 extension_types/simple: ExpectationFileMismatchSerialized # Expected.
+extension_types/simple_method_resolution: ExpectationFileMismatchSerialized # Expected.
 extensions/call_methods: TypeCheckError
 extensions/extension_setter_error: TypeCheckError
 extensions/instance_access_of_static: RuntimeError
diff --git a/pkg/front_end/testcases/textual_outline.status b/pkg/front_end/testcases/textual_outline.status
index a9e5f3e..6fef290 100644
--- a/pkg/front_end/testcases/textual_outline.status
+++ b/pkg/front_end/testcases/textual_outline.status
@@ -127,6 +127,7 @@
 nnbd_mixed/null_safety_invalid_language_version: FormatterCrash
 nonfunction_type_aliases/issue41501: FormatterCrash
 nonfunction_type_aliases/issue42446: FormatterCrash
+nonfunction_type_aliases/issue45051: FormatterCrash
 rasta/bad_redirection: FormatterCrash
 rasta/issue_000032: FormatterCrash
 rasta/issue_000034: FormatterCrash
diff --git a/pkg/front_end/testcases/weak.status b/pkg/front_end/testcases/weak.status
index 6c4e1c1..1087328 100644
--- a/pkg/front_end/testcases/weak.status
+++ b/pkg/front_end/testcases/weak.status
@@ -11,6 +11,7 @@
 # regress/utf_16_le_content.crash: Crash # semi fuzz fails but isn't currently enabled by default.
 
 extension_types/simple: ExpectationFileMismatchSerialized # Expected.
+extension_types/simple_method_resolution: ExpectationFileMismatchSerialized # Expected.
 extensions/call_methods: TypeCheckError
 extensions/extension_setter_error: TypeCheckError
 extensions/instance_access_of_static: RuntimeError
diff --git a/pkg/kernel/lib/naive_type_checker.dart b/pkg/kernel/lib/naive_type_checker.dart
index 080ccf8..449a9a3 100644
--- a/pkg/kernel/lib/naive_type_checker.dart
+++ b/pkg/kernel/lib/naive_type_checker.dart
@@ -111,6 +111,12 @@
   /// Check if [subtype] is subtype of [supertype] after applying
   /// type parameter [substitution].
   bool _isSubtypeOf(DartType subtype, DartType supertype) {
+    // TODO(dmitryas): Remove this when ExtensionType is in ast.dart.
+    if (!_isKnownDartTypeImplementation(subtype) ||
+        !_isKnownDartTypeImplementation(supertype)) {
+      return true;
+    }
+
     if (subtype is InvalidType || supertype is InvalidType) {
       return true;
     }
@@ -299,3 +305,16 @@
     failures.reportFailure(where, message);
   }
 }
+
+bool _isKnownDartTypeImplementation(DartType type) {
+  return type is DynamicType ||
+      type is FunctionType ||
+      type is FutureOrType ||
+      type is InterfaceType ||
+      type is InvalidType ||
+      type is NeverType ||
+      type is NullType ||
+      type is TypeParameterType ||
+      type is TypedefType ||
+      type is VoidType;
+}
diff --git a/runtime/tests/vm/dart/regress_flutter76919_test.dart b/runtime/tests/vm/dart/regress_flutter76919_test.dart
new file mode 100644
index 0000000..669641a
--- /dev/null
+++ b/runtime/tests/vm/dart/regress_flutter76919_test.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for https://github.com/flutter/flutter/issues/76919
+// Verifies that we don't try to strengthen an environmentless assertion
+// with a class check in AOT mode which crashes AOT compiler.
+
+import 'dart:typed_data';
+import 'package:expect/expect.dart';
+
+class C<E, L extends List<E>> {
+  final L list;
+
+  C(this.list);
+
+  @pragma('vm:never-inline')
+  E operator [](int index) => list[index];
+
+  @pragma('vm:never-inline')
+  void operator []=(int index, E value) {
+    // We emit AssertAssignable(value, E) on entry.
+    // Speculative compilation of this line produces CheckSmi(value)
+    list[index] = value;
+  }
+}
+
+void main(List<String> args) {
+  final v = C<int, Uint8List>(Uint8List(1));
+  v[0] = 1;
+  Expect.equals(1, v[0]);
+}
diff --git a/runtime/tests/vm/dart_2/regress_flutter76919_test.dart b/runtime/tests/vm/dart_2/regress_flutter76919_test.dart
new file mode 100644
index 0000000..669641a
--- /dev/null
+++ b/runtime/tests/vm/dart_2/regress_flutter76919_test.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for https://github.com/flutter/flutter/issues/76919
+// Verifies that we don't try to strengthen an environmentless assertion
+// with a class check in AOT mode which crashes AOT compiler.
+
+import 'dart:typed_data';
+import 'package:expect/expect.dart';
+
+class C<E, L extends List<E>> {
+  final L list;
+
+  C(this.list);
+
+  @pragma('vm:never-inline')
+  E operator [](int index) => list[index];
+
+  @pragma('vm:never-inline')
+  void operator []=(int index, E value) {
+    // We emit AssertAssignable(value, E) on entry.
+    // Speculative compilation of this line produces CheckSmi(value)
+    list[index] = value;
+  }
+}
+
+void main(List<String> args) {
+  final v = C<int, Uint8List>(Uint8List(1));
+  v[0] = 1;
+  Expect.equals(1, v[0]);
+}
diff --git a/runtime/vm/compiler/backend/type_propagator.cc b/runtime/vm/compiler/backend/type_propagator.cc
index fd01d69..dce6e90 100644
--- a/runtime/vm/compiler/backend/type_propagator.cc
+++ b/runtime/vm/compiler/backend/type_propagator.cc
@@ -48,6 +48,7 @@
 FlowGraphTypePropagator::FlowGraphTypePropagator(FlowGraph* flow_graph)
     : FlowGraphVisitor(flow_graph->reverse_postorder()),
       flow_graph_(flow_graph),
+      is_aot_(CompilerState::Current().is_aot()),
       visited_blocks_(new (flow_graph->zone())
                           BitVector(flow_graph->zone(),
                                     flow_graph->reverse_postorder().length())),
@@ -119,7 +120,13 @@
 
   const intptr_t rollback_point = rollback_.length();
 
-  StrengthenAsserts(block);
+  if (!is_aot_) {
+    // Don't try to strengthen asserts with class checks in AOT mode, this is a
+    // speculative optimization which only really makes sense in JIT mode.
+    // It is also written to expect environments to be attached to
+    // AssertAssignable instructions, which is not always a case in AOT mode.
+    StrengthenAsserts(block);
+  }
 
   block->Accept(this);
 
diff --git a/runtime/vm/compiler/backend/type_propagator.h b/runtime/vm/compiler/backend/type_propagator.h
index 5c27420..435ef4a 100644
--- a/runtime/vm/compiler/backend/type_propagator.h
+++ b/runtime/vm/compiler/backend/type_propagator.h
@@ -77,6 +77,7 @@
   Zone* zone() const { return flow_graph_->zone(); }
 
   FlowGraph* flow_graph_;
+  const bool is_aot_;
 
   BitVector* visited_blocks_;
 
diff --git a/runtime/vm/compiler/backend/type_propagator_test.cc b/runtime/vm/compiler/backend/type_propagator_test.cc
index 1090bc9..60d58c4 100644
--- a/runtime/vm/compiler/backend/type_propagator_test.cc
+++ b/runtime/vm/compiler/backend/type_propagator_test.cc
@@ -491,4 +491,53 @@
   }
 }
 
+// Verifies that Propagate does not crash when running in AOT mode on a graph
+// which contains both AssertAssignable and a CheckClass/Smi after
+// EliminateEnvironments was called.
+ISOLATE_UNIT_TEST_CASE(TypePropagator_RegressFlutter76919) {
+  CompilerState S(thread, /*is_aot=*/true, /*is_optimizing=*/true);
+
+  FlowGraphBuilderHelper H;
+
+  // Add a variable into the scope which would provide static type for the
+  // parameter.
+  LocalVariable* v0_var =
+      new LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
+                        String::Handle(Symbols::New(thread, "v0")),
+                        AbstractType::ZoneHandle(Type::DynamicType()));
+  v0_var->set_type_check_mode(LocalVariable::kTypeCheckedByCaller);
+  H.flow_graph()->parsed_function().scope()->AddVariable(v0_var);
+
+  auto normal_entry = H.flow_graph()->graph_entry()->normal_entry();
+
+  // We are going to build the following graph:
+  //
+  // B0[graph_entry]:
+  // B1[function_entry]:
+  //   v0 <- Parameter(0)
+  //   AssertAssignable(v0, 'int')
+  //   CheckSmi(v0)
+  //   Return(v0)
+
+  {
+    BlockBuilder builder(H.flow_graph(), normal_entry);
+    Definition* v0 = builder.AddParameter(0, 0, /*with_frame=*/true, kTagged);
+    auto null_value = builder.AddNullDefinition();
+    builder.AddDefinition(new AssertAssignableInstr(
+        InstructionSource(), new Value(v0),
+        new Value(
+            H.flow_graph()->GetConstant(Type::ZoneHandle(Type::IntType()))),
+        new Value(null_value), new Value(null_value), Symbols::Value(),
+        S.GetNextDeoptId()));
+    builder.AddInstruction(new CheckSmiInstr(new Value(v0), S.GetNextDeoptId(),
+                                             InstructionSource()));
+    builder.AddReturn(new Value(v0));
+  }
+
+  H.FinishGraph();
+
+  H.flow_graph()->EliminateEnvironments();
+  FlowGraphTypePropagator::Propagate(H.flow_graph());  // Should not crash.
+}
+
 }  // namespace dart
diff --git a/sdk/lib/_internal/vm/lib/typed_data_patch.dart b/sdk/lib/_internal/vm/lib/typed_data_patch.dart
index d608ab6..b0c18d5 100644
--- a/sdk/lib/_internal/vm/lib/typed_data_patch.dart
+++ b/sdk/lib/_internal/vm/lib/typed_data_patch.dart
@@ -150,13 +150,7 @@
     return -1;
   }
 
-  List<int> operator +(List<int> other) {
-    int totalLength = this.length + other.length;
-    return <int>[]
-      ..length = totalLength
-      ..setRange(0, this.length, this)
-      ..setRange(this.length, totalLength, other);
-  }
+  List<int> operator +(List<int> other) => [...this, ...other];
 
   bool contains(Object? element) {
     var len = this.length;
@@ -506,13 +500,7 @@
     return -1;
   }
 
-  List<double> operator +(List<double> other) {
-    int totalLength = this.length + other.length;
-    return <double>[]
-      ..length = totalLength
-      ..setRange(0, this.length, this)
-      ..setRange(this.length, totalLength, other);
-  }
+  List<double> operator +(List<double> other) => [...this, ...other];
 
   bool contains(Object? element) {
     var len = this.length;
@@ -868,13 +856,7 @@
     return -1;
   }
 
-  List<Float32x4> operator +(List<Float32x4> other) {
-    int totalLength = this.length + other.length;
-    return <Float32x4>[]
-      ..length = totalLength
-      ..setRange(0, this.length, this)
-      ..setRange(this.length, totalLength, other);
-  }
+  List<Float32x4> operator +(List<Float32x4> other) => [...this, ...other];
 
   bool contains(Object? element) {
     var len = this.length;
@@ -1228,13 +1210,7 @@
     return -1;
   }
 
-  List<Int32x4> operator +(List<Int32x4> other) {
-    int totalLength = this.length + other.length;
-    return <Int32x4>[]
-      ..length = totalLength
-      ..setRange(0, this.length, this)
-      ..setRange(this.length, totalLength, other);
-  }
+  List<Int32x4> operator +(List<Int32x4> other) => [...this, ...other];
 
   bool contains(Object? element) {
     var len = this.length;
@@ -1587,13 +1563,7 @@
     return -1;
   }
 
-  List<Float64x2> operator +(List<Float64x2> other) {
-    int totalLength = this.length + other.length;
-    return <Float64x2>[]
-      ..length = totalLength
-      ..setRange(0, this.length, this)
-      ..setRange(this.length, totalLength, other);
-  }
+  List<Float64x2> operator +(List<Float64x2> other) => [...this, ...other];
 
   bool contains(Object? element) {
     var len = this.length;
diff --git a/tests/lib/typed_data/regression_45140_test.dart b/tests/lib/typed_data/regression_45140_test.dart
new file mode 100644
index 0000000..864ce45
--- /dev/null
+++ b/tests/lib/typed_data/regression_45140_test.dart
@@ -0,0 +1,63 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:math' show Random;
+import 'dart:typed_data';
+import 'package:expect/expect.dart';
+
+void main() {
+  var r = Random();
+  int genInt() => r.nextInt(256);
+  double genDbl() => r.nextDouble();
+  Int32x4 genIx4() => Int32x4(genInt(), genInt(), genInt(), genInt());
+  Float32x4 genFx4() => Float32x4(genDbl(), genDbl(), genDbl(), genDbl());
+  Float64x2 genDx2() => Float64x2(genDbl(), genDbl());
+
+  test("Uint8List", (n) => Uint8List(n)..fill(genInt));
+  test("Uint16List", (n) => Uint16List(n)..fill(genInt));
+  test("Uint32List", (n) => Uint32List(n)..fill(genInt));
+  test("Int8List", (n) => Int8List(n)..fill(genInt));
+  test("Int16List", (n) => Int16List(n)..fill(genInt));
+  test("Int32List", (n) => Int32List(n)..fill(genInt));
+  test("Uint8ClampedList", (n) => Uint8ClampedList(n)..fill(genInt));
+  test("Float32List", (n) => Float32List(n)..fill(genDbl));
+  test("Float64List", (n) => Float64List(n)..fill(genDbl));
+  test("Int32x4List", (n) => Int32x4List(n)..fill(genIx4));
+  test("Float32x4List", (n) => Float32x4List(n)..fill(genFx4));
+  test("Float64x2List", (n) => Float64x2List(n)..fill(genDx2));
+}
+
+void test<T>(String name, List<T> create(int n)) {
+  var l1 = create(17);
+  var l2 = create(13);
+  List<T> l3;
+  try {
+    // Shouldn't throw:
+    l3 = l1 + l2;
+  } catch (e) {
+    // Until we change Expect.fail to return Never.
+    Expect.fail("$name: $e") as Never;
+  }
+  Expect.equals(30, l3.length);
+  if (0 is T || 0.0 is T) {
+    // Int32x4 etc. do not support `==`.
+    Expect.listEquals(l1, l3.sublist(0, 17), "$name first");
+    Expect.listEquals(l2, l3.sublist(17), "$name second");
+  }
+  // Result is growable, shouldn't throw.
+  try {
+    l3.add(l3.first);
+  } catch (e) {
+    Expect.fail("$name: $e");
+  }
+}
+
+// Fill a list with (random) generated values.
+extension<T> on List<T> {
+  void fill(T gen()) {
+    for (var i = 0; i < length; i++) {
+      this[i] = gen();
+    }
+  }
+}
diff --git a/tools/VERSION b/tools/VERSION
index d620660..f121dd3 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 13
 PATCH 0
-PRERELEASE 90
+PRERELEASE 91
 PRERELEASE_PATCH 0
\ No newline at end of file