Version 3.0.0-78.0.dev

Merge 81b137d8fe7c68fd524605c0f3e62800faca7ea6 into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e013bd1..b81eedb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -30,6 +30,9 @@
     ways instead, possibly with a StackOverflowError.
   - Removed the deprecated [`NoSuchMethodError`][] default constructor.
     Use the [`NoSuchMethodError.withInvocation`][] named constructor instead.
+  - Removed the deprecated [`BidirectionalIterator`][] class.
+    Existing bidirectional iterators can still work, they just don't have
+    a shared supertype locking them to a specific name for moving backwards.
 
 [#49529]: https://github.com/dart-lang/sdk/issues/49529
 [`List.filled`]: https://api.dart.dev/stable/2.18.6/dart-core/List/List.filled.html
@@ -54,6 +57,7 @@
 [`NullThrownError`]: https://api.dart.dev/dev/2.19.0-430.0.dev/dart-core/NullThrownError-class.html
 [`AbstractClassInstantiationError`]: https://api.dart.dev/stable/2.18.3/dart-core/AbstractClassInstantiationError-class.html
 [`CyclicInitializationError`]: https://api.dart.dev/dev/2.19.0-430.0.dev/dart-core/CyclicInitializationError-class.html
+[`BidirectionalIterator`]: https://api.dart.dev/dev/2.19.0-430.0.dev/dart-core/BidirectionalIterator-class.html
 
 #### `dart:async`
 
@@ -68,7 +72,7 @@
 #### `dart:developer`
 
 - **Breaking change** [#49529][]:
-  - Removed the deprecated [`MAX_USER_TAGS`][] constant. 
+  - Removed the deprecated [`MAX_USER_TAGS`][] constant.
     Use [`maxUserTags`][] instead.
 - Callbacks passed to `registerExtension` will be run in the zone from which
   they are registered.
diff --git a/benchmarks/ObjectHash/dart/ObjectHash.dart b/benchmarks/ObjectHash/dart/ObjectHash.dart
index 67ad018..5f70d44 100644
--- a/benchmarks/ObjectHash/dart/ObjectHash.dart
+++ b/benchmarks/ObjectHash/dart/ObjectHash.dart
@@ -28,7 +28,7 @@
 class Node5Hash extends Node5 {
   // This is the main subject of the benchmark - a typical use of `Object.hash`.
   @override
-  int get hashCode => Object.hash(item1, item2, item3, item4, item5);
+  int get hashCode => Object.hash(item1, item2, item3, item4, item5, 0);
 }
 
 class Node5Manual extends Node5 {
@@ -36,7 +36,7 @@
   // `hashCode` calls.
   @override
   int get hashCode => _SystemHash.hash5(item1.hashCode, item2.hashCode,
-      item3.hashCode, item4.hashCode, item5.hashCode);
+      item3.hashCode, item4.hashCode, item5.hashCode, 0);
 }
 
 class Node5List extends Node5 {
@@ -190,10 +190,11 @@
   check(Object.hash(a6, a7, a1, a2, a3), Object.hash(a6, a7, a1, a2, a3));
   check(Object.hash(a7, a1, a2, a3, a4), Object.hash(a7, a1, a2, a3, a4));
 
-  check(_SystemHash.hash2(1, 2), _SystemHash.hash2(1, 2));
-  check(_SystemHash.hash3(1, 2, 3), _SystemHash.hash3(1, 2, 3));
-  check(_SystemHash.hash4(1, 2, 3, 4), _SystemHash.hash4(1, 2, 3, 4));
-  check(_SystemHash.hash5(1, 2, 3, 4, 5), _SystemHash.hash5(1, 2, 3, 4, 5));
+  check(_SystemHash.hash2(1, 2, 0), _SystemHash.hash2(1, 2, 0));
+  check(_SystemHash.hash3(1, 2, 3, 0), _SystemHash.hash3(1, 2, 3, 0));
+  check(_SystemHash.hash4(1, 2, 3, 4, 0), _SystemHash.hash4(1, 2, 3, 4, 0));
+  check(
+      _SystemHash.hash5(1, 2, 3, 4, 5, 0), _SystemHash.hash5(1, 2, 3, 4, 5, 0));
 
   // Pollute hashAll argument type.
   check(Object.hashAll({}), Object.hashAll([]));
@@ -217,14 +218,14 @@
     return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
   }
 
-  static int hash2(int v1, int v2, [int seed = 0]) {
+  static int hash2(int v1, int v2, int seed) {
     int hash = seed;
     hash = combine(hash, v1);
     hash = combine(hash, v2);
     return finish(hash);
   }
 
-  static int hash3(int v1, int v2, int v3, [int seed = 0]) {
+  static int hash3(int v1, int v2, int v3, int seed) {
     int hash = seed;
     hash = combine(hash, v1);
     hash = combine(hash, v2);
@@ -232,7 +233,7 @@
     return finish(hash);
   }
 
-  static int hash4(int v1, int v2, int v3, int v4, [int seed = 0]) {
+  static int hash4(int v1, int v2, int v3, int v4, int seed) {
     int hash = seed;
     hash = combine(hash, v1);
     hash = combine(hash, v2);
@@ -241,7 +242,7 @@
     return finish(hash);
   }
 
-  static int hash5(int v1, int v2, int v3, int v4, int v5, [int seed = 0]) {
+  static int hash5(int v1, int v2, int v3, int v4, int v5, int seed) {
     int hash = seed;
     hash = combine(hash, v1);
     hash = combine(hash, v2);
diff --git a/pkg/front_end/lib/src/compute_platform_binaries_location.dart b/pkg/front_end/lib/src/compute_platform_binaries_location.dart
index c273b4c..9a3c0f4 100644
--- a/pkg/front_end/lib/src/compute_platform_binaries_location.dart
+++ b/pkg/front_end/lib/src/compute_platform_binaries_location.dart
@@ -64,6 +64,17 @@
       return "vm_platform_strong.dill";
     case 'none':
       return "vm_platform_strong.dill";
+    case 'wasm':
+      switch (nnbdMode) {
+        case NnbdMode.Strong:
+          return 'dart2wasm_outline.dill';
+        //TODO(johnniwinther): Support using the full dill.
+        //return 'dart2wasm_platform.dill';
+        case NnbdMode.Weak:
+        case NnbdMode.Agnostic:
+          break;
+      }
+      break;
     default:
       break;
   }
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index c675951..a9f1337 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -8347,8 +8347,37 @@
     // TODO(cstefantsova): Handle the case of secondIdentifier != null
     handleIdentifier(firstIdentifier, IdentifierContext.typeReference);
     Object? resolvedIdentifier = pop();
+
     if (resolvedIdentifier is TypeUseGenerator) {
       TypeDeclarationBuilder typeDeclaration = resolvedIdentifier.declaration;
+
+      if (typeDeclaration is TypeAliasBuilder) {
+        if (typeArguments == null ||
+            typeArguments.length ==
+                typeDeclaration.typedef.typeParameters.length) {
+          TypeDeclarationBuilder? unaliasedTypeDeclaration =
+              typeDeclaration.unaliasDeclaration(typeArguments);
+          List<TypeBuilder>? unaliasedTypeArguments =
+              typeDeclaration.unaliasTypeArguments(typeArguments);
+          if (unaliasedTypeDeclaration == null) {
+            // TODO(cstefantsova): Make sure an error is reported elsewhere.
+            push(new DummyPattern(firstIdentifier.charOffset));
+            return;
+          } else {
+            typeDeclaration = unaliasedTypeDeclaration;
+            typeArguments = unaliasedTypeArguments;
+          }
+        } else {
+          addProblem(
+              fasta.templateTypeArgumentMismatch
+                  .withArguments(typeDeclaration.typedef.typeParameters.length),
+              firstIdentifier.charOffset,
+              noLength);
+          push(new DummyPattern(firstIdentifier.charOffset));
+          return;
+        }
+      }
+
       if (typeDeclaration is ClassBuilder) {
         List<DartType>? builtTypeArguments;
         if (typeArguments != null) {
@@ -8359,7 +8388,13 @@
                   .add(typeBuilder.build(libraryBuilder, TypeUse.typeArgument));
             }
           } else {
-            // TODO(cstefantsova): Report an error.
+            addProblem(
+                fasta.templateTypeArgumentMismatch
+                    .withArguments(typeDeclaration.cls.typeParameters.length),
+                firstIdentifier.charOffset,
+                noLength);
+            push(new DummyPattern(firstIdentifier.charOffset));
+            return;
           }
         }
         push(new ObjectPattern(
@@ -8368,7 +8403,7 @@
             builtTypeArguments,
             firstIdentifier.offset));
       } else {
-        // TODO(cstefantsova): Handle this case.
+        // TODO(cstefantsova): Handle other possibilities.
         push(new DummyPattern(firstIdentifier.charOffset));
       }
     } else {
diff --git a/pkg/front_end/test/fasta/testing/suite.dart b/pkg/front_end/test/fasta/testing/suite.dart
index 517597e..fd10997 100644
--- a/pkg/front_end/test/fasta/testing/suite.dart
+++ b/pkg/front_end/test/fasta/testing/suite.dart
@@ -17,6 +17,7 @@
 import 'package:compiler/src/kernel/dart2js_target.dart';
 import 'package:compiler/src/options.dart' as dart2jsOptions
     show CompilerOptions;
+import 'package:dart2wasm/target.dart';
 import 'package:dev_compiler/src/kernel/target.dart';
 import 'package:front_end/src/api_prototype/compiler_options.dart'
     show
@@ -866,7 +867,8 @@
         case "none":
         case "dart2js":
         case "dartdevc":
-          // TODO(johnniwinther): Support running dart2js and/or dartdevc.
+        case "wasm":
+          // TODO(johnniwinther): Support running dart2js, dartdevc and/or wasm.
           return pass(result);
         default:
           throw new ArgumentError(
@@ -2198,6 +2200,9 @@
     case "dartdevc":
       target = new TestDevCompilerTarget(targetFlags);
       break;
+    case "wasm":
+      target = new TestWasmTarget(targetFlags);
+      break;
     default:
       throw new ArgumentError(
           "Unsupported test target '${folderOptions.target}'.");
@@ -2559,6 +2564,13 @@
   TestVmTarget(this.flags) : super(flags);
 }
 
+class TestWasmTarget extends WasmTarget with TestTarget, TestTargetMixin {
+  @override
+  final TestTargetFlags flags;
+
+  TestWasmTarget(this.flags);
+}
+
 class EnsureNoErrors
     extends Step<ComponentResult, ComponentResult, FastaContext> {
   const EnsureNoErrors();
diff --git a/pkg/front_end/testcases/dart2wasm/folder.options b/pkg/front_end/testcases/dart2wasm/folder.options
new file mode 100644
index 0000000..fb4023e
--- /dev/null
+++ b/pkg/front_end/testcases/dart2wasm/folder.options
@@ -0,0 +1 @@
+--target=wasm
\ No newline at end of file
diff --git a/pkg/front_end/testcases/dart2wasm/for_in.dart b/pkg/front_end/testcases/dart2wasm/for_in.dart
new file mode 100644
index 0000000..9a9f97c
--- /dev/null
+++ b/pkg/front_end/testcases/dart2wasm/for_in.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2023, 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.
+
+method(Iterable<int> iterable) {
+  for (int i in iterable) {
+    print(i);
+  }
+}
+
+asyncMethod(Stream<int> stream) async {
+  await for (int i in stream) {
+    print(i);
+  }
+}
diff --git a/pkg/front_end/testcases/dart2wasm/for_in.dart.strong.expect b/pkg/front_end/testcases/dart2wasm/for_in.dart.strong.expect
new file mode 100644
index 0000000..adc675c
--- /dev/null
+++ b/pkg/front_end/testcases/dart2wasm/for_in.dart.strong.expect
@@ -0,0 +1,15 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:async" as asy;
+
+static method method(core::Iterable<core::int> iterable) → dynamic {
+  for (core::int i in iterable) {
+    core::print(i);
+  }
+}
+static method asyncMethod(asy::Stream<core::int> stream) → dynamic async /* futureValueType= dynamic */ {
+  await for (core::int i in stream) {
+    core::print(i);
+  }
+}
diff --git a/pkg/front_end/testcases/dart2wasm/for_in.dart.strong.transformed.expect b/pkg/front_end/testcases/dart2wasm/for_in.dart.strong.transformed.expect
new file mode 100644
index 0000000..134a29e
--- /dev/null
+++ b/pkg/front_end/testcases/dart2wasm/for_in.dart.strong.transformed.expect
@@ -0,0 +1,38 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:async" as asy;
+
+static method method(core::Iterable<core::int> iterable) → dynamic {
+  {
+    core::Iterator<core::int> #forIterator = iterable.{core::Iterable::iterator}{core::Iterator<core::int>};
+    for (; #forIterator.{core::Iterator::moveNext}(){() → core::bool}; ) {
+      core::int i = #forIterator.{core::Iterator::current}{core::int};
+      {
+        core::print(i);
+      }
+    }
+  }
+}
+static method asyncMethod(asy::Stream<core::int> stream) → dynamic async /* futureValueType= dynamic */ {
+  {
+    asy::_StreamIterator<core::int> #forIterator = new asy::_StreamIterator::•<core::int>(stream);
+    core::bool #jumpSentinel = #C1;
+    try {
+      for (; #jumpSentinel = await #forIterator.{asy::_StreamIterator::moveNext}(){() → asy::Future<core::bool>}; ) {
+        core::int i = #forIterator.{asy::_StreamIterator::current}{core::int};
+        {
+          core::print(i);
+        }
+      }
+    }
+    finally {
+      if(#jumpSentinel)
+        await #forIterator.{asy::_StreamIterator::cancel}(){() → asy::Future<dynamic>};
+    }
+  }
+}
+
+constants  {
+  #C1 = false
+}
diff --git a/pkg/front_end/testcases/dart2wasm/for_in.dart.textual_outline.expect b/pkg/front_end/testcases/dart2wasm/for_in.dart.textual_outline.expect
new file mode 100644
index 0000000..e85a911
--- /dev/null
+++ b/pkg/front_end/testcases/dart2wasm/for_in.dart.textual_outline.expect
@@ -0,0 +1,2 @@
+method(Iterable<int> iterable) {}
+asyncMethod(Stream<int> stream) async {}
diff --git a/pkg/front_end/testcases/dart2wasm/for_in.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/dart2wasm/for_in.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..ae78206
--- /dev/null
+++ b/pkg/front_end/testcases/dart2wasm/for_in.dart.textual_outline_modelled.expect
@@ -0,0 +1,2 @@
+asyncMethod(Stream<int> stream) async {}
+method(Iterable<int> iterable) {}
diff --git a/pkg/front_end/testcases/dart2wasm/yield.dart b/pkg/front_end/testcases/dart2wasm/yield.dart
new file mode 100644
index 0000000..57782eb
--- /dev/null
+++ b/pkg/front_end/testcases/dart2wasm/yield.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2023, 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.
+
+Iterable<int> method(Iterable<int> iterable) sync* {
+  yield 1;
+  yield 2;
+  yield* iterable;
+}
+
+Stream<int> asyncMethod(Stream<int> stream) async* {
+  yield 1;
+  yield 2;
+  yield* stream;
+}
diff --git a/pkg/front_end/testcases/dart2wasm/yield.dart.strong.expect b/pkg/front_end/testcases/dart2wasm/yield.dart.strong.expect
new file mode 100644
index 0000000..3ca9d81
--- /dev/null
+++ b/pkg/front_end/testcases/dart2wasm/yield.dart.strong.expect
@@ -0,0 +1,15 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:async" as asy;
+
+static method method(core::Iterable<core::int> iterable) → core::Iterable<core::int> sync* {
+  yield 1;
+  yield 2;
+  yield* iterable;
+}
+static method asyncMethod(asy::Stream<core::int> stream) → asy::Stream<core::int> async* {
+  yield 1;
+  yield 2;
+  yield* stream;
+}
diff --git a/pkg/front_end/testcases/dart2wasm/yield.dart.strong.transformed.expect b/pkg/front_end/testcases/dart2wasm/yield.dart.strong.transformed.expect
new file mode 100644
index 0000000..07a0c80
--- /dev/null
+++ b/pkg/front_end/testcases/dart2wasm/yield.dart.strong.transformed.expect
@@ -0,0 +1,78 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:async" as asy;
+
+static method method(core::Iterable<core::int> iterable) → core::Iterable<core::int> sync* {
+  yield 1;
+  yield 2;
+  yield* iterable;
+}
+static method asyncMethod(asy::Stream<core::int> stream) → asy::Stream<core::int> {
+  asy::StreamController<core::Object?> #controller = asy::StreamController::•<core::Object?>();
+  () → asy::Future<void> #body = () → asy::Future<void> async /* futureValueType= void */ {
+    asy::Completer<core::bool> #completer = asy::Completer::•<core::bool>();
+    #controller.{asy::StreamController::add}(#completer){(core::Object?) → void};
+    await #completer.{asy::Completer::future}{() → asy::Future<core::bool>};
+    {
+      {
+        #controller.{asy::StreamController::add}(1){(core::Object?) → void};
+        #completer = asy::Completer::•<core::bool>();
+        #controller.{asy::StreamController::add}(#completer){(core::Object?) → void};
+        await #completer.{asy::Completer::future}{() → asy::Future<core::bool>};
+      }
+      {
+        #controller.{asy::StreamController::add}(2){(core::Object?) → void};
+        #completer = asy::Completer::•<core::bool>();
+        #controller.{asy::StreamController::add}(#completer){(core::Object?) → void};
+        await #completer.{asy::Completer::future}{() → asy::Future<core::bool>};
+      }
+      {
+        asy::_StreamIterator<core::int> #forIterator = new asy::_StreamIterator::•<core::int>(stream);
+        core::bool #jumpSentinel = #C1;
+        try {
+          for (; #jumpSentinel = await #forIterator.{asy::_StreamIterator::moveNext}(){() → asy::Future<core::bool>}; ) {
+            core::int #awaitForVar = #forIterator.{asy::_StreamIterator::current}{core::int};
+            {
+              #controller.{asy::StreamController::add}(#awaitForVar){(core::Object?) → void};
+              #completer = asy::Completer::•<core::bool>();
+              #controller.{asy::StreamController::add}(#completer){(core::Object?) → void};
+              await #completer.{asy::Completer::future}{() → asy::Future<core::bool>};
+            }
+          }
+        }
+        finally {
+          if(#jumpSentinel)
+            await #forIterator.{asy::_StreamIterator::cancel}(){() → asy::Future<dynamic>};
+        }
+      }
+    }
+    #controller.{asy::StreamController::close}(){() → asy::Future<dynamic>};
+  };
+  core::bool #isFirst = #C2;
+  core::bool #isEven = #C1;
+  #controller.{asy::StreamController::add}(#C3){(core::Object?) → void};
+  return #controller.{asy::StreamController::stream}{() → asy::Stream<core::Object?>}.{asy::Stream::asyncMap}<core::Object?>((core::Object? value) → FutureOr<core::Object?> async /* futureValueType= core::Object? */ {
+    if(#isFirst) {
+      #body(){() → asy::Future<void>};
+      return #C3;
+    }
+    if(value is asy::Completer<core::bool>)
+      value.{asy::Completer::complete}(#C2){([FutureOr<core::bool>?]) → void};
+    return value;
+  }){((core::Object?) → FutureOr<core::Object?>) → asy::Stream<core::Object?>}.{asy::Stream::where}((core::Object? value) → core::Object? {
+    if(#isFirst) {
+      #isFirst = #C1;
+      return #C1;
+    }
+    core::bool keep = #isEven;
+    #isEven = !#isEven;
+    return keep;
+  }){((core::Object?) → core::bool) → asy::Stream<core::Object?>}.{asy::Stream::cast}<core::int>(){() → asy::Stream<core::int>};
+}
+
+constants  {
+  #C1 = false
+  #C2 = true
+  #C3 = null
+}
diff --git a/pkg/front_end/testcases/dart2wasm/yield.dart.textual_outline.expect b/pkg/front_end/testcases/dart2wasm/yield.dart.textual_outline.expect
new file mode 100644
index 0000000..b93b8f2
--- /dev/null
+++ b/pkg/front_end/testcases/dart2wasm/yield.dart.textual_outline.expect
@@ -0,0 +1,2 @@
+Iterable<int> method(Iterable<int> iterable) sync* {}
+Stream<int> asyncMethod(Stream<int> stream) async* {}
diff --git a/pkg/front_end/testcases/dart2wasm/yield.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/dart2wasm/yield.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..b93b8f2
--- /dev/null
+++ b/pkg/front_end/testcases/dart2wasm/yield.dart.textual_outline_modelled.expect
@@ -0,0 +1,2 @@
+Iterable<int> method(Iterable<int> iterable) sync* {}
+Stream<int> asyncMethod(Stream<int> stream) async* {}
diff --git a/pkg/front_end/testcases/general/error_export_from_dill/main.dart.strong.expect b/pkg/front_end/testcases/general/error_export_from_dill/main.dart.strong.expect
index 67410f4..af63181 100644
--- a/pkg/front_end/testcases/general/error_export_from_dill/main.dart.strong.expect
+++ b/pkg/front_end/testcases/general/error_export_from_dill/main.dart.strong.expect
@@ -121,7 +121,6 @@
   core::int,
   core::Invocation,
   core::Iterable,
-  core::BidirectionalIterator,
   core::Iterator,
   core::List,
   core::Map,
diff --git a/pkg/front_end/testcases/general/error_export_from_dill/main.dart.strong.transformed.expect b/pkg/front_end/testcases/general/error_export_from_dill/main.dart.strong.transformed.expect
index 28e4d78..a01af77 100644
--- a/pkg/front_end/testcases/general/error_export_from_dill/main.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/error_export_from_dill/main.dart.strong.transformed.expect
@@ -117,7 +117,6 @@
   core::int,
   core::Invocation,
   core::Iterable,
-  core::BidirectionalIterator,
   core::Iterator,
   core::List,
   core::Map,
diff --git a/pkg/front_end/testcases/general/error_export_from_dill/main.dart.weak.expect b/pkg/front_end/testcases/general/error_export_from_dill/main.dart.weak.expect
index 67410f4..af63181 100644
--- a/pkg/front_end/testcases/general/error_export_from_dill/main.dart.weak.expect
+++ b/pkg/front_end/testcases/general/error_export_from_dill/main.dart.weak.expect
@@ -121,7 +121,6 @@
   core::int,
   core::Invocation,
   core::Iterable,
-  core::BidirectionalIterator,
   core::Iterator,
   core::List,
   core::Map,
diff --git a/pkg/front_end/testcases/general/error_export_from_dill/main.dart.weak.outline.expect b/pkg/front_end/testcases/general/error_export_from_dill/main.dart.weak.outline.expect
index ed19572..a1ec656 100644
--- a/pkg/front_end/testcases/general/error_export_from_dill/main.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/general/error_export_from_dill/main.dart.weak.outline.expect
@@ -56,7 +56,6 @@
   core::int,
   core::Invocation,
   core::Iterable,
-  core::BidirectionalIterator,
   core::Iterator,
   core::List,
   core::Map,
diff --git a/pkg/front_end/testcases/general/error_export_from_dill/main.dart.weak.transformed.expect b/pkg/front_end/testcases/general/error_export_from_dill/main.dart.weak.transformed.expect
index 28e4d78..a01af77 100644
--- a/pkg/front_end/testcases/general/error_export_from_dill/main.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general/error_export_from_dill/main.dart.weak.transformed.expect
@@ -117,7 +117,6 @@
   core::int,
   core::Invocation,
   core::Iterable,
-  core::BidirectionalIterator,
   core::Iterator,
   core::List,
   core::Map,
diff --git a/pkg/front_end/testcases/incremental/export_core.yaml.world.2.expect b/pkg/front_end/testcases/incremental/export_core.yaml.world.2.expect
index b9a075c..65de26d 100644
--- a/pkg/front_end/testcases/incremental/export_core.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental/export_core.yaml.world.2.expect
@@ -11,7 +11,6 @@
   core::Comparator,
   core::ArgumentError,
   core::AssertionError,
-  core::BidirectionalIterator,
   core::BigInt,
   core::Comparable,
   core::ConcurrentModificationError,
diff --git a/pkg/front_end/testcases/incremental/export_core.yaml.world.3.expect b/pkg/front_end/testcases/incremental/export_core.yaml.world.3.expect
index 79de28b..835e454 100644
--- a/pkg/front_end/testcases/incremental/export_core.yaml.world.3.expect
+++ b/pkg/front_end/testcases/incremental/export_core.yaml.world.3.expect
@@ -11,7 +11,6 @@
   core::Comparator,
   core::ArgumentError,
   core::AssertionError,
-  core::BidirectionalIterator,
   core::BigInt,
   core::Comparable,
   core::ConcurrentModificationError,
diff --git a/pkg/front_end/testcases/patterns/object_pattern_errors.dart b/pkg/front_end/testcases/patterns/object_pattern_errors.dart
new file mode 100644
index 0000000..ca53cfd
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/object_pattern_errors.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2022, 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 {}
+
+typedef B<X> = A;
+
+test(dynamic x) {
+  if (x case A<int>()) {} // Error.
+  if (x case B()) {} // Ok: the type argument is inferred.
+  if (x case B<int>()) {} // Ok.
+  if (x case B<String, num>()) {} // Error.
+}
diff --git a/pkg/front_end/testcases/patterns/object_pattern_errors.dart.strong.expect b/pkg/front_end/testcases/patterns/object_pattern_errors.dart.strong.expect
new file mode 100644
index 0000000..12565fa
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/object_pattern_errors.dart.strong.expect
@@ -0,0 +1,35 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/patterns/object_pattern_errors.dart:10:14: Error: Expected 0 type arguments.
+//   if (x case A<int>()) {} // Error.
+//              ^
+//
+// pkg/front_end/testcases/patterns/object_pattern_errors.dart:13:14: Error: Expected 1 type arguments.
+//   if (x case B<String, num>()) {} // Error.
+//              ^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef B<unrelated X extends core::Object? = dynamic> = self::A;
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+}
+static method test(dynamic x) → dynamic {
+  final dynamic #t1 = x;
+  final dynamic #t2 = x;
+  final dynamic #t3 = #t2;
+  if(#t3 is self::A) {
+  }
+  final dynamic #t4 = x;
+  final dynamic #t5 = #t4;
+  if(#t5 is self::A) {
+  }
+  final dynamic #t6 = x;
+}
+static method _#B#new#tearOff<unrelated X extends core::Object? = dynamic>() → self::A
+  return new self::A::•();
diff --git a/pkg/front_end/testcases/patterns/object_pattern_errors.dart.strong.transformed.expect b/pkg/front_end/testcases/patterns/object_pattern_errors.dart.strong.transformed.expect
new file mode 100644
index 0000000..12565fa
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/object_pattern_errors.dart.strong.transformed.expect
@@ -0,0 +1,35 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/patterns/object_pattern_errors.dart:10:14: Error: Expected 0 type arguments.
+//   if (x case A<int>()) {} // Error.
+//              ^
+//
+// pkg/front_end/testcases/patterns/object_pattern_errors.dart:13:14: Error: Expected 1 type arguments.
+//   if (x case B<String, num>()) {} // Error.
+//              ^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef B<unrelated X extends core::Object? = dynamic> = self::A;
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+}
+static method test(dynamic x) → dynamic {
+  final dynamic #t1 = x;
+  final dynamic #t2 = x;
+  final dynamic #t3 = #t2;
+  if(#t3 is self::A) {
+  }
+  final dynamic #t4 = x;
+  final dynamic #t5 = #t4;
+  if(#t5 is self::A) {
+  }
+  final dynamic #t6 = x;
+}
+static method _#B#new#tearOff<unrelated X extends core::Object? = dynamic>() → self::A
+  return new self::A::•();
diff --git a/pkg/front_end/testcases/patterns/object_pattern_errors.dart.textual_outline.expect b/pkg/front_end/testcases/patterns/object_pattern_errors.dart.textual_outline.expect
new file mode 100644
index 0000000..7570659
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/object_pattern_errors.dart.textual_outline.expect
@@ -0,0 +1,4 @@
+class A {}
+
+typedef B<X> = A;
+test(dynamic x) {}
diff --git a/pkg/front_end/testcases/patterns/object_pattern_errors.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/patterns/object_pattern_errors.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..ec8e681
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/object_pattern_errors.dart.textual_outline_modelled.expect
@@ -0,0 +1,4 @@
+class A {}
+
+test(dynamic x) {}
+typedef B<X> = A;
diff --git a/pkg/front_end/testcases/patterns/object_pattern_errors.dart.weak.expect b/pkg/front_end/testcases/patterns/object_pattern_errors.dart.weak.expect
new file mode 100644
index 0000000..12565fa
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/object_pattern_errors.dart.weak.expect
@@ -0,0 +1,35 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/patterns/object_pattern_errors.dart:10:14: Error: Expected 0 type arguments.
+//   if (x case A<int>()) {} // Error.
+//              ^
+//
+// pkg/front_end/testcases/patterns/object_pattern_errors.dart:13:14: Error: Expected 1 type arguments.
+//   if (x case B<String, num>()) {} // Error.
+//              ^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef B<unrelated X extends core::Object? = dynamic> = self::A;
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+}
+static method test(dynamic x) → dynamic {
+  final dynamic #t1 = x;
+  final dynamic #t2 = x;
+  final dynamic #t3 = #t2;
+  if(#t3 is self::A) {
+  }
+  final dynamic #t4 = x;
+  final dynamic #t5 = #t4;
+  if(#t5 is self::A) {
+  }
+  final dynamic #t6 = x;
+}
+static method _#B#new#tearOff<unrelated X extends core::Object? = dynamic>() → self::A
+  return new self::A::•();
diff --git a/pkg/front_end/testcases/patterns/object_pattern_errors.dart.weak.modular.expect b/pkg/front_end/testcases/patterns/object_pattern_errors.dart.weak.modular.expect
new file mode 100644
index 0000000..12565fa
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/object_pattern_errors.dart.weak.modular.expect
@@ -0,0 +1,35 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/patterns/object_pattern_errors.dart:10:14: Error: Expected 0 type arguments.
+//   if (x case A<int>()) {} // Error.
+//              ^
+//
+// pkg/front_end/testcases/patterns/object_pattern_errors.dart:13:14: Error: Expected 1 type arguments.
+//   if (x case B<String, num>()) {} // Error.
+//              ^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef B<unrelated X extends core::Object? = dynamic> = self::A;
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+}
+static method test(dynamic x) → dynamic {
+  final dynamic #t1 = x;
+  final dynamic #t2 = x;
+  final dynamic #t3 = #t2;
+  if(#t3 is self::A) {
+  }
+  final dynamic #t4 = x;
+  final dynamic #t5 = #t4;
+  if(#t5 is self::A) {
+  }
+  final dynamic #t6 = x;
+}
+static method _#B#new#tearOff<unrelated X extends core::Object? = dynamic>() → self::A
+  return new self::A::•();
diff --git a/pkg/front_end/testcases/patterns/object_pattern_errors.dart.weak.outline.expect b/pkg/front_end/testcases/patterns/object_pattern_errors.dart.weak.outline.expect
new file mode 100644
index 0000000..292f781
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/object_pattern_errors.dart.weak.outline.expect
@@ -0,0 +1,13 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef B<unrelated X extends core::Object? = dynamic> = self::A;
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    ;
+}
+static method test(dynamic x) → dynamic
+  ;
+static method _#B#new#tearOff<unrelated X extends core::Object? = dynamic>() → self::A
+  return new self::A::•();
diff --git a/pkg/front_end/testcases/patterns/object_pattern_errors.dart.weak.transformed.expect b/pkg/front_end/testcases/patterns/object_pattern_errors.dart.weak.transformed.expect
new file mode 100644
index 0000000..12565fa
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/object_pattern_errors.dart.weak.transformed.expect
@@ -0,0 +1,35 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/patterns/object_pattern_errors.dart:10:14: Error: Expected 0 type arguments.
+//   if (x case A<int>()) {} // Error.
+//              ^
+//
+// pkg/front_end/testcases/patterns/object_pattern_errors.dart:13:14: Error: Expected 1 type arguments.
+//   if (x case B<String, num>()) {} // Error.
+//              ^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef B<unrelated X extends core::Object? = dynamic> = self::A;
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+}
+static method test(dynamic x) → dynamic {
+  final dynamic #t1 = x;
+  final dynamic #t2 = x;
+  final dynamic #t3 = #t2;
+  if(#t3 is self::A) {
+  }
+  final dynamic #t4 = x;
+  final dynamic #t5 = #t4;
+  if(#t5 is self::A) {
+  }
+  final dynamic #t6 = x;
+}
+static method _#B#new#tearOff<unrelated X extends core::Object? = dynamic>() → self::A
+  return new self::A::•();
diff --git a/pkg/front_end/testcases/patterns/typedef_in_object_pattern.dart b/pkg/front_end/testcases/patterns/typedef_in_object_pattern.dart
new file mode 100644
index 0000000..763547b
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/typedef_in_object_pattern.dart
@@ -0,0 +1,52 @@
+// Copyright (c) 2022, 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 {
+  int foo;
+
+  A(this.foo);
+}
+
+typedef B = A;
+
+class C<X, Y> {
+  X x;
+  Y y;
+
+  C(this.x, this.y);
+}
+
+typedef D<X> = C<X, X>;
+
+test1(dynamic x) {
+  if (x case B(:var foo)) {
+    return foo;
+  } else {
+    return null;
+  }
+}
+
+test2(dynamic x) {
+  if (x case D<String>(:var x)) {
+    return x;
+  } else {
+    return null;
+  }
+}
+
+main() {
+  expectEquals(0, test1(new A(0)));
+  expectEquals(1, test1(new B(1)));
+  expectEquals(null, test1(null));
+
+  expectEquals("one", test2(new C("one", "two")));
+  expectEquals("one", test2(new D("one", "two")));
+  expectEquals(null, test2(null));
+}
+
+expectEquals(x, y) {
+  if (x != y) {
+    throw "Expected ${x} to be equal to ${y}.";
+  }
+}
diff --git a/pkg/front_end/testcases/patterns/typedef_in_object_pattern.dart.strong.expect b/pkg/front_end/testcases/patterns/typedef_in_object_pattern.dart.strong.expect
new file mode 100644
index 0000000..e6c5ae8
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/typedef_in_object_pattern.dart.strong.expect
@@ -0,0 +1,70 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef B = self::A;
+typedef D<X extends core::Object? = dynamic> = self::C<X%, X%>;
+class A extends core::Object {
+  field core::int foo;
+  constructor •(core::int foo) → self::A
+    : self::A::foo = foo, super core::Object::•()
+    ;
+}
+class C<X extends core::Object? = dynamic, Y extends core::Object? = dynamic> extends core::Object {
+  covariant-by-class field self::C::X% x;
+  covariant-by-class field self::C::Y% y;
+  constructor •(self::C::X% x, self::C::Y% y) → self::C<self::C::X%, self::C::Y%>
+    : self::C::x = x, self::C::y = y, super core::Object::•()
+    ;
+}
+static method test1(dynamic x) → dynamic {
+  final dynamic #t1 = x;
+  final core::bool #t2 = true;
+  final dynamic #t3 = #t1;
+  if(#t3 is self::A) {
+    final core::int #t4 = #t3{self::A}.{self::A::foo}{core::int};
+    #t2 = false;
+    {
+      dynamic foo = #t4;
+      {
+        return foo;
+      }
+    }
+  }
+  if(#t2) {
+    return null;
+  }
+}
+static method test2(dynamic x) → dynamic {
+  final dynamic #t5 = x;
+  final core::bool #t6 = true;
+  final dynamic #t7 = #t5;
+  if(#t7 is self::C<core::String, core::String>) {
+    final core::String #t8 = #t7{self::C<core::String, core::String>}.{self::C::x}{core::String};
+    #t6 = false;
+    {
+      dynamic x = #t8;
+      {
+        return x;
+      }
+    }
+  }
+  if(#t6) {
+    return null;
+  }
+}
+static method main() → dynamic {
+  self::expectEquals(0, self::test1(new self::A::•(0)));
+  self::expectEquals(1, self::test1(new self::A::•(1)));
+  self::expectEquals(null, self::test1(null));
+  self::expectEquals("one", self::test2(new self::C::•<core::String, core::String>("one", "two")));
+  self::expectEquals("one", self::test2(new self::C::•<core::String, core::String>("one", "two")));
+  self::expectEquals(null, self::test2(null));
+}
+static method expectEquals(dynamic x, dynamic y) → dynamic {
+  if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
+    throw "Expected ${x} to be equal to ${y}.";
+  }
+}
+static method _#D#new#tearOff<X extends core::Object? = dynamic>(self::_#D#new#tearOff::X% x, self::_#D#new#tearOff::X% y) → self::C<self::_#D#new#tearOff::X%, self::_#D#new#tearOff::X%>
+  return new self::C::•<self::_#D#new#tearOff::X%, self::_#D#new#tearOff::X%>(x, y);
diff --git a/pkg/front_end/testcases/patterns/typedef_in_object_pattern.dart.strong.transformed.expect b/pkg/front_end/testcases/patterns/typedef_in_object_pattern.dart.strong.transformed.expect
new file mode 100644
index 0000000..e6c5ae8
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/typedef_in_object_pattern.dart.strong.transformed.expect
@@ -0,0 +1,70 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef B = self::A;
+typedef D<X extends core::Object? = dynamic> = self::C<X%, X%>;
+class A extends core::Object {
+  field core::int foo;
+  constructor •(core::int foo) → self::A
+    : self::A::foo = foo, super core::Object::•()
+    ;
+}
+class C<X extends core::Object? = dynamic, Y extends core::Object? = dynamic> extends core::Object {
+  covariant-by-class field self::C::X% x;
+  covariant-by-class field self::C::Y% y;
+  constructor •(self::C::X% x, self::C::Y% y) → self::C<self::C::X%, self::C::Y%>
+    : self::C::x = x, self::C::y = y, super core::Object::•()
+    ;
+}
+static method test1(dynamic x) → dynamic {
+  final dynamic #t1 = x;
+  final core::bool #t2 = true;
+  final dynamic #t3 = #t1;
+  if(#t3 is self::A) {
+    final core::int #t4 = #t3{self::A}.{self::A::foo}{core::int};
+    #t2 = false;
+    {
+      dynamic foo = #t4;
+      {
+        return foo;
+      }
+    }
+  }
+  if(#t2) {
+    return null;
+  }
+}
+static method test2(dynamic x) → dynamic {
+  final dynamic #t5 = x;
+  final core::bool #t6 = true;
+  final dynamic #t7 = #t5;
+  if(#t7 is self::C<core::String, core::String>) {
+    final core::String #t8 = #t7{self::C<core::String, core::String>}.{self::C::x}{core::String};
+    #t6 = false;
+    {
+      dynamic x = #t8;
+      {
+        return x;
+      }
+    }
+  }
+  if(#t6) {
+    return null;
+  }
+}
+static method main() → dynamic {
+  self::expectEquals(0, self::test1(new self::A::•(0)));
+  self::expectEquals(1, self::test1(new self::A::•(1)));
+  self::expectEquals(null, self::test1(null));
+  self::expectEquals("one", self::test2(new self::C::•<core::String, core::String>("one", "two")));
+  self::expectEquals("one", self::test2(new self::C::•<core::String, core::String>("one", "two")));
+  self::expectEquals(null, self::test2(null));
+}
+static method expectEquals(dynamic x, dynamic y) → dynamic {
+  if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
+    throw "Expected ${x} to be equal to ${y}.";
+  }
+}
+static method _#D#new#tearOff<X extends core::Object? = dynamic>(self::_#D#new#tearOff::X% x, self::_#D#new#tearOff::X% y) → self::C<self::_#D#new#tearOff::X%, self::_#D#new#tearOff::X%>
+  return new self::C::•<self::_#D#new#tearOff::X%, self::_#D#new#tearOff::X%>(x, y);
diff --git a/pkg/front_end/testcases/patterns/typedef_in_object_pattern.dart.textual_outline.expect b/pkg/front_end/testcases/patterns/typedef_in_object_pattern.dart.textual_outline.expect
new file mode 100644
index 0000000..c4cc6de
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/typedef_in_object_pattern.dart.textual_outline.expect
@@ -0,0 +1,18 @@
+class A {
+  int foo;
+  A(this.foo);
+}
+
+typedef B = A;
+
+class C<X, Y> {
+  X x;
+  Y y;
+  C(this.x, this.y);
+}
+
+typedef D<X> = C<X, X>;
+test1(dynamic x) {}
+test2(dynamic x) {}
+main() {}
+expectEquals(x, y) {}
diff --git a/pkg/front_end/testcases/patterns/typedef_in_object_pattern.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/patterns/typedef_in_object_pattern.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..33e21fff
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/typedef_in_object_pattern.dart.textual_outline_modelled.expect
@@ -0,0 +1,17 @@
+class A {
+  A(this.foo);
+  int foo;
+}
+
+class C<X, Y> {
+  C(this.x, this.y);
+  X x;
+  Y y;
+}
+
+expectEquals(x, y) {}
+main() {}
+test1(dynamic x) {}
+test2(dynamic x) {}
+typedef B = A;
+typedef D<X> = C<X, X>;
diff --git a/pkg/front_end/testcases/patterns/typedef_in_object_pattern.dart.weak.expect b/pkg/front_end/testcases/patterns/typedef_in_object_pattern.dart.weak.expect
new file mode 100644
index 0000000..e6c5ae8
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/typedef_in_object_pattern.dart.weak.expect
@@ -0,0 +1,70 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef B = self::A;
+typedef D<X extends core::Object? = dynamic> = self::C<X%, X%>;
+class A extends core::Object {
+  field core::int foo;
+  constructor •(core::int foo) → self::A
+    : self::A::foo = foo, super core::Object::•()
+    ;
+}
+class C<X extends core::Object? = dynamic, Y extends core::Object? = dynamic> extends core::Object {
+  covariant-by-class field self::C::X% x;
+  covariant-by-class field self::C::Y% y;
+  constructor •(self::C::X% x, self::C::Y% y) → self::C<self::C::X%, self::C::Y%>
+    : self::C::x = x, self::C::y = y, super core::Object::•()
+    ;
+}
+static method test1(dynamic x) → dynamic {
+  final dynamic #t1 = x;
+  final core::bool #t2 = true;
+  final dynamic #t3 = #t1;
+  if(#t3 is self::A) {
+    final core::int #t4 = #t3{self::A}.{self::A::foo}{core::int};
+    #t2 = false;
+    {
+      dynamic foo = #t4;
+      {
+        return foo;
+      }
+    }
+  }
+  if(#t2) {
+    return null;
+  }
+}
+static method test2(dynamic x) → dynamic {
+  final dynamic #t5 = x;
+  final core::bool #t6 = true;
+  final dynamic #t7 = #t5;
+  if(#t7 is self::C<core::String, core::String>) {
+    final core::String #t8 = #t7{self::C<core::String, core::String>}.{self::C::x}{core::String};
+    #t6 = false;
+    {
+      dynamic x = #t8;
+      {
+        return x;
+      }
+    }
+  }
+  if(#t6) {
+    return null;
+  }
+}
+static method main() → dynamic {
+  self::expectEquals(0, self::test1(new self::A::•(0)));
+  self::expectEquals(1, self::test1(new self::A::•(1)));
+  self::expectEquals(null, self::test1(null));
+  self::expectEquals("one", self::test2(new self::C::•<core::String, core::String>("one", "two")));
+  self::expectEquals("one", self::test2(new self::C::•<core::String, core::String>("one", "two")));
+  self::expectEquals(null, self::test2(null));
+}
+static method expectEquals(dynamic x, dynamic y) → dynamic {
+  if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
+    throw "Expected ${x} to be equal to ${y}.";
+  }
+}
+static method _#D#new#tearOff<X extends core::Object? = dynamic>(self::_#D#new#tearOff::X% x, self::_#D#new#tearOff::X% y) → self::C<self::_#D#new#tearOff::X%, self::_#D#new#tearOff::X%>
+  return new self::C::•<self::_#D#new#tearOff::X%, self::_#D#new#tearOff::X%>(x, y);
diff --git a/pkg/front_end/testcases/patterns/typedef_in_object_pattern.dart.weak.modular.expect b/pkg/front_end/testcases/patterns/typedef_in_object_pattern.dart.weak.modular.expect
new file mode 100644
index 0000000..e6c5ae8
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/typedef_in_object_pattern.dart.weak.modular.expect
@@ -0,0 +1,70 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef B = self::A;
+typedef D<X extends core::Object? = dynamic> = self::C<X%, X%>;
+class A extends core::Object {
+  field core::int foo;
+  constructor •(core::int foo) → self::A
+    : self::A::foo = foo, super core::Object::•()
+    ;
+}
+class C<X extends core::Object? = dynamic, Y extends core::Object? = dynamic> extends core::Object {
+  covariant-by-class field self::C::X% x;
+  covariant-by-class field self::C::Y% y;
+  constructor •(self::C::X% x, self::C::Y% y) → self::C<self::C::X%, self::C::Y%>
+    : self::C::x = x, self::C::y = y, super core::Object::•()
+    ;
+}
+static method test1(dynamic x) → dynamic {
+  final dynamic #t1 = x;
+  final core::bool #t2 = true;
+  final dynamic #t3 = #t1;
+  if(#t3 is self::A) {
+    final core::int #t4 = #t3{self::A}.{self::A::foo}{core::int};
+    #t2 = false;
+    {
+      dynamic foo = #t4;
+      {
+        return foo;
+      }
+    }
+  }
+  if(#t2) {
+    return null;
+  }
+}
+static method test2(dynamic x) → dynamic {
+  final dynamic #t5 = x;
+  final core::bool #t6 = true;
+  final dynamic #t7 = #t5;
+  if(#t7 is self::C<core::String, core::String>) {
+    final core::String #t8 = #t7{self::C<core::String, core::String>}.{self::C::x}{core::String};
+    #t6 = false;
+    {
+      dynamic x = #t8;
+      {
+        return x;
+      }
+    }
+  }
+  if(#t6) {
+    return null;
+  }
+}
+static method main() → dynamic {
+  self::expectEquals(0, self::test1(new self::A::•(0)));
+  self::expectEquals(1, self::test1(new self::A::•(1)));
+  self::expectEquals(null, self::test1(null));
+  self::expectEquals("one", self::test2(new self::C::•<core::String, core::String>("one", "two")));
+  self::expectEquals("one", self::test2(new self::C::•<core::String, core::String>("one", "two")));
+  self::expectEquals(null, self::test2(null));
+}
+static method expectEquals(dynamic x, dynamic y) → dynamic {
+  if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
+    throw "Expected ${x} to be equal to ${y}.";
+  }
+}
+static method _#D#new#tearOff<X extends core::Object? = dynamic>(self::_#D#new#tearOff::X% x, self::_#D#new#tearOff::X% y) → self::C<self::_#D#new#tearOff::X%, self::_#D#new#tearOff::X%>
+  return new self::C::•<self::_#D#new#tearOff::X%, self::_#D#new#tearOff::X%>(x, y);
diff --git a/pkg/front_end/testcases/patterns/typedef_in_object_pattern.dart.weak.outline.expect b/pkg/front_end/testcases/patterns/typedef_in_object_pattern.dart.weak.outline.expect
new file mode 100644
index 0000000..09ecd76
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/typedef_in_object_pattern.dart.weak.outline.expect
@@ -0,0 +1,27 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef B = self::A;
+typedef D<X extends core::Object? = dynamic> = self::C<X%, X%>;
+class A extends core::Object {
+  field core::int foo;
+  constructor •(core::int foo) → self::A
+    ;
+}
+class C<X extends core::Object? = dynamic, Y extends core::Object? = dynamic> extends core::Object {
+  covariant-by-class field self::C::X% x;
+  covariant-by-class field self::C::Y% y;
+  constructor •(self::C::X% x, self::C::Y% y) → self::C<self::C::X%, self::C::Y%>
+    ;
+}
+static method test1(dynamic x) → dynamic
+  ;
+static method test2(dynamic x) → dynamic
+  ;
+static method main() → dynamic
+  ;
+static method expectEquals(dynamic x, dynamic y) → dynamic
+  ;
+static method _#D#new#tearOff<X extends core::Object? = dynamic>(self::_#D#new#tearOff::X% x, self::_#D#new#tearOff::X% y) → self::C<self::_#D#new#tearOff::X%, self::_#D#new#tearOff::X%>
+  return new self::C::•<self::_#D#new#tearOff::X%, self::_#D#new#tearOff::X%>(x, y);
diff --git a/pkg/front_end/testcases/patterns/typedef_in_object_pattern.dart.weak.transformed.expect b/pkg/front_end/testcases/patterns/typedef_in_object_pattern.dart.weak.transformed.expect
new file mode 100644
index 0000000..e6c5ae8
--- /dev/null
+++ b/pkg/front_end/testcases/patterns/typedef_in_object_pattern.dart.weak.transformed.expect
@@ -0,0 +1,70 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef B = self::A;
+typedef D<X extends core::Object? = dynamic> = self::C<X%, X%>;
+class A extends core::Object {
+  field core::int foo;
+  constructor •(core::int foo) → self::A
+    : self::A::foo = foo, super core::Object::•()
+    ;
+}
+class C<X extends core::Object? = dynamic, Y extends core::Object? = dynamic> extends core::Object {
+  covariant-by-class field self::C::X% x;
+  covariant-by-class field self::C::Y% y;
+  constructor •(self::C::X% x, self::C::Y% y) → self::C<self::C::X%, self::C::Y%>
+    : self::C::x = x, self::C::y = y, super core::Object::•()
+    ;
+}
+static method test1(dynamic x) → dynamic {
+  final dynamic #t1 = x;
+  final core::bool #t2 = true;
+  final dynamic #t3 = #t1;
+  if(#t3 is self::A) {
+    final core::int #t4 = #t3{self::A}.{self::A::foo}{core::int};
+    #t2 = false;
+    {
+      dynamic foo = #t4;
+      {
+        return foo;
+      }
+    }
+  }
+  if(#t2) {
+    return null;
+  }
+}
+static method test2(dynamic x) → dynamic {
+  final dynamic #t5 = x;
+  final core::bool #t6 = true;
+  final dynamic #t7 = #t5;
+  if(#t7 is self::C<core::String, core::String>) {
+    final core::String #t8 = #t7{self::C<core::String, core::String>}.{self::C::x}{core::String};
+    #t6 = false;
+    {
+      dynamic x = #t8;
+      {
+        return x;
+      }
+    }
+  }
+  if(#t6) {
+    return null;
+  }
+}
+static method main() → dynamic {
+  self::expectEquals(0, self::test1(new self::A::•(0)));
+  self::expectEquals(1, self::test1(new self::A::•(1)));
+  self::expectEquals(null, self::test1(null));
+  self::expectEquals("one", self::test2(new self::C::•<core::String, core::String>("one", "two")));
+  self::expectEquals("one", self::test2(new self::C::•<core::String, core::String>("one", "two")));
+  self::expectEquals(null, self::test2(null));
+}
+static method expectEquals(dynamic x, dynamic y) → dynamic {
+  if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
+    throw "Expected ${x} to be equal to ${y}.";
+  }
+}
+static method _#D#new#tearOff<X extends core::Object? = dynamic>(self::_#D#new#tearOff::X% x, self::_#D#new#tearOff::X% y) → self::C<self::_#D#new#tearOff::X%, self::_#D#new#tearOff::X%>
+  return new self::C::•<self::_#D#new#tearOff::X%, self::_#D#new#tearOff::X%>(x, y);
diff --git a/pkg/front_end/testing.json b/pkg/front_end/testing.json
index 42f39cc..c3dd6ae 100644
--- a/pkg/front_end/testing.json
+++ b/pkg/front_end/testing.json
@@ -44,6 +44,7 @@
         "/testcases/.*_part[0-9]*\\.dart$",
         "/testcases/.*_lib[0-9]*\\.dart$",
         "/testcases/dartino/",
+        "/testcases/dart2wasm/",
         "/testcases/expression/"
       ]
     },
@@ -79,6 +80,7 @@
         "/testcases/.*_part[0-9]*\\.dart$",
         "/testcases/.*_lib[0-9]*\\.dart$",
         "/testcases/dartino/",
+        "/testcases/dart2wasm/",
         "/testcases/expression/"
       ]
     },
@@ -96,6 +98,7 @@
         "/testcases/.*_part[0-9]*\\.dart$",
         "/testcases/.*_lib[0-9]*\\.dart$",
         "/testcases/dartino/",
+        "/testcases/dart2wasm/",
         "/testcases/expression/"
       ]
     },
diff --git a/runtime/tools/dartfuzz/gen_type_table.dart b/runtime/tools/dartfuzz/gen_type_table.dart
index 2c2a189..400fefd 100644
--- a/runtime/tools/dartfuzz/gen_type_table.dart
+++ b/runtime/tools/dartfuzz/gen_type_table.dart
@@ -1394,7 +1394,6 @@
           (classElement.name == 'StackTrace') ||
           (classElement.name == 'NoSuchMethodError') ||
           (classElement.name == 'Comparable') ||
-          (classElement.name == 'BidirectionalIterator') ||
           (classElement.name == 'Iterator') ||
           (classElement.name == 'Stopwatch') ||
           (classElement.name == 'Finalizer') ||
diff --git a/sdk/lib/core/iterable.dart b/sdk/lib/core/iterable.dart
index 1960f29..be89448 100644
--- a/sdk/lib/core/iterable.dart
+++ b/sdk/lib/core/iterable.dart
@@ -822,22 +822,3 @@
   /// Helper function used as default _generator function.
   static int _id(int n) => n;
 }
-
-/// An [Iterator] that allows moving backwards as well as forwards.
-///
-/// Deprecation note: This interface has turned out to not be
-/// valuable as a general reusable interface. There is still only
-/// one class implementing it, [RuneIterator], and at least one other
-/// bidirectional iterator preferred a different name than `movePrevious`
-/// for the other direction.
-/// As such, this interface does not carry its own weight, and will be
-/// removed in a later release.
-@Deprecated("Use the implementing class directly")
-abstract class BidirectionalIterator<E> implements Iterator<E> {
-  /// Move back to the previous element.
-  ///
-  /// Returns true and updates [current] if successful. Returns false
-  /// and updates [current] to an implementation defined state if there is no
-  /// previous element
-  bool movePrevious();
-}
diff --git a/sdk/lib/core/object.dart b/sdk/lib/core/object.dart
index 8f2c5a6..ef55aec 100644
--- a/sdk/lib/core/object.dart
+++ b/sdk/lib/core/object.dart
@@ -556,7 +556,7 @@
       sum = (sum + objectHash) & mask;
       count += 1;
     }
-    return SystemHash.hash2(sum, count);
+    return SystemHash.hash2(sum, count, 0);
   }
 }
 
diff --git a/sdk/lib/core/string.dart b/sdk/lib/core/string.dart
index 694ce73..b4c8078 100644
--- a/sdk/lib/core/string.dart
+++ b/sdk/lib/core/string.dart
@@ -799,7 +799,7 @@
 }
 
 /// [Iterator] for reading runes (integer Unicode code points) of a Dart string.
-class RuneIterator implements BidirectionalIterator<int> {
+class RuneIterator implements Iterator<int> {
   /// String being iterated.
   final String string;
 
@@ -906,6 +906,10 @@
     return string.substring(_position, _nextPosition);
   }
 
+  /// Move to the next code point.
+  ///
+  /// Returns `true` and updates [current] if there is a next code point.
+  /// Returns `false` otherwise, and then there is no current code point.
   bool moveNext() {
     _position = _nextPosition;
     if (_position == string.length) {
@@ -927,6 +931,10 @@
     return true;
   }
 
+  /// Move back to the previous code point.
+  ///
+  /// Returns `true` and updates [current] if there is a previous code point.
+  /// Returns `false` otherwise, and then there is no current code point.
   bool movePrevious() {
     _nextPosition = _position;
     if (_position == 0) {
diff --git a/sdk/lib/internal/internal.dart b/sdk/lib/internal/internal.dart
index c94a35c..5df7ecd 100644
--- a/sdk/lib/internal/internal.dart
+++ b/sdk/lib/internal/internal.dart
@@ -178,7 +178,6 @@
 ///
 /// TODO(lrn): Consider specializing this code per platform,
 /// so the VM can use its 64-bit integers directly.
-@Since("2.11")
 class SystemHash {
   static int combine(int hash, int value) {
     hash = 0x1fffffff & (hash + value);
@@ -192,14 +191,14 @@
     return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
   }
 
-  static int hash2(int v1, int v2, [@Since("2.14") int seed = 0]) {
+  static int hash2(int v1, int v2, int seed) {
     int hash = seed;
     hash = combine(hash, v1);
     hash = combine(hash, v2);
     return finish(hash);
   }
 
-  static int hash3(int v1, int v2, int v3, [@Since("2.14") int seed = 0]) {
+  static int hash3(int v1, int v2, int v3, int seed) {
     int hash = seed;
     hash = combine(hash, v1);
     hash = combine(hash, v2);
@@ -207,8 +206,7 @@
     return finish(hash);
   }
 
-  static int hash4(int v1, int v2, int v3, int v4,
-      [@Since("2.14") int seed = 0]) {
+  static int hash4(int v1, int v2, int v3, int v4, int seed) {
     int hash = seed;
     hash = combine(hash, v1);
     hash = combine(hash, v2);
@@ -217,8 +215,7 @@
     return finish(hash);
   }
 
-  static int hash5(int v1, int v2, int v3, int v4, int v5,
-      [@Since("2.14") int seed = 0]) {
+  static int hash5(int v1, int v2, int v3, int v4, int v5, int seed) {
     int hash = seed;
     hash = combine(hash, v1);
     hash = combine(hash, v2);
@@ -228,8 +225,7 @@
     return finish(hash);
   }
 
-  static int hash6(int v1, int v2, int v3, int v4, int v5, int v6,
-      [@Since("2.14") int seed = 0]) {
+  static int hash6(int v1, int v2, int v3, int v4, int v5, int v6, int seed) {
     int hash = seed;
     hash = combine(hash, v1);
     hash = combine(hash, v2);
@@ -240,8 +236,8 @@
     return finish(hash);
   }
 
-  static int hash7(int v1, int v2, int v3, int v4, int v5, int v6, int v7,
-      [@Since("2.14") int seed = 0]) {
+  static int hash7(
+      int v1, int v2, int v3, int v4, int v5, int v6, int v7, int seed) {
     int hash = seed;
     hash = combine(hash, v1);
     hash = combine(hash, v2);
@@ -253,9 +249,8 @@
     return finish(hash);
   }
 
-  static int hash8(
-      int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8,
-      [@Since("2.14") int seed = 0]) {
+  static int hash8(int v1, int v2, int v3, int v4, int v5, int v6, int v7,
+      int v8, int seed) {
     int hash = seed;
     hash = combine(hash, v1);
     hash = combine(hash, v2);
@@ -268,9 +263,8 @@
     return finish(hash);
   }
 
-  static int hash9(
-      int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8, int v9,
-      [@Since("2.14") int seed = 0]) {
+  static int hash9(int v1, int v2, int v3, int v4, int v5, int v6, int v7,
+      int v8, int v9, int seed) {
     int hash = seed;
     hash = combine(hash, v1);
     hash = combine(hash, v2);
@@ -285,8 +279,7 @@
   }
 
   static int hash10(int v1, int v2, int v3, int v4, int v5, int v6, int v7,
-      int v8, int v9, int v10,
-      [@Since("2.14") int seed = 0]) {
+      int v8, int v9, int v10, int seed) {
     int hash = seed;
     hash = combine(hash, v1);
     hash = combine(hash, v2);
@@ -301,10 +294,8 @@
     return finish(hash);
   }
 
-  @Since("2.14")
   static int hash11(int v1, int v2, int v3, int v4, int v5, int v6, int v7,
-      int v8, int v9, int v10, int v11,
-      [int seed = 0]) {
+      int v8, int v9, int v10, int v11, int seed) {
     int hash = seed;
     hash = combine(hash, v1);
     hash = combine(hash, v2);
@@ -320,10 +311,8 @@
     return finish(hash);
   }
 
-  @Since("2.14")
   static int hash12(int v1, int v2, int v3, int v4, int v5, int v6, int v7,
-      int v8, int v9, int v10, int v11, int v12,
-      [int seed = 0]) {
+      int v8, int v9, int v10, int v11, int v12, int seed) {
     int hash = seed;
     hash = combine(hash, v1);
     hash = combine(hash, v2);
@@ -340,10 +329,8 @@
     return finish(hash);
   }
 
-  @Since("2.14")
   static int hash13(int v1, int v2, int v3, int v4, int v5, int v6, int v7,
-      int v8, int v9, int v10, int v11, int v12, int v13,
-      [int seed = 0]) {
+      int v8, int v9, int v10, int v11, int v12, int v13, int seed) {
     int hash = seed;
     hash = combine(hash, v1);
     hash = combine(hash, v2);
@@ -361,10 +348,8 @@
     return finish(hash);
   }
 
-  @Since("2.14")
   static int hash14(int v1, int v2, int v3, int v4, int v5, int v6, int v7,
-      int v8, int v9, int v10, int v11, int v12, int v13, int v14,
-      [int seed = 0]) {
+      int v8, int v9, int v10, int v11, int v12, int v13, int v14, int seed) {
     int hash = seed;
     hash = combine(hash, v1);
     hash = combine(hash, v2);
@@ -383,10 +368,23 @@
     return finish(hash);
   }
 
-  @Since("2.14")
-  static int hash15(int v1, int v2, int v3, int v4, int v5, int v6, int v7,
-      int v8, int v9, int v10, int v11, int v12, int v13, int v14, int v15,
-      [int seed = 0]) {
+  static int hash15(
+      int v1,
+      int v2,
+      int v3,
+      int v4,
+      int v5,
+      int v6,
+      int v7,
+      int v8,
+      int v9,
+      int v10,
+      int v11,
+      int v12,
+      int v13,
+      int v14,
+      int v15,
+      int seed) {
     int hash = seed;
     hash = combine(hash, v1);
     hash = combine(hash, v2);
@@ -406,7 +404,6 @@
     return finish(hash);
   }
 
-  @Since("2.14")
   static int hash16(
       int v1,
       int v2,
@@ -424,7 +421,7 @@
       int v14,
       int v15,
       int v16,
-      [int seed = 0]) {
+      int seed) {
     int hash = seed;
     hash = combine(hash, v1);
     hash = combine(hash, v2);
@@ -445,7 +442,6 @@
     return finish(hash);
   }
 
-  @Since("2.14")
   static int hash17(
       int v1,
       int v2,
@@ -464,7 +460,7 @@
       int v15,
       int v16,
       int v17,
-      [int seed = 0]) {
+      int seed) {
     int hash = seed;
     hash = combine(hash, v1);
     hash = combine(hash, v2);
@@ -486,7 +482,6 @@
     return finish(hash);
   }
 
-  @Since("2.14")
   static int hash18(
       int v1,
       int v2,
@@ -506,7 +501,7 @@
       int v16,
       int v17,
       int v18,
-      [int seed = 0]) {
+      int seed) {
     int hash = seed;
     hash = combine(hash, v1);
     hash = combine(hash, v2);
@@ -529,7 +524,6 @@
     return finish(hash);
   }
 
-  @Since("2.14")
   static int hash19(
       int v1,
       int v2,
@@ -550,7 +544,7 @@
       int v17,
       int v18,
       int v19,
-      [int seed = 0]) {
+      int seed) {
     int hash = seed;
     hash = combine(hash, v1);
     hash = combine(hash, v2);
@@ -574,7 +568,6 @@
     return finish(hash);
   }
 
-  @Since("2.14")
   static int hash20(
       int v1,
       int v2,
@@ -596,7 +589,7 @@
       int v18,
       int v19,
       int v20,
-      [int seed = 0]) {
+      int seed) {
     int hash = seed;
     hash = combine(hash, v1);
     hash = combine(hash, v2);
@@ -644,14 +637,12 @@
 }
 
 /// Sentinel values that should never be exposed outside of platform libraries.
-@Since("2.14")
 class SentinelValue {
   final int id;
   const SentinelValue(this.id);
 }
 
 /// A default value to use when only one sentinel is needed.
-@Since("2.14")
 const Object sentinelValue = const SentinelValue(0);
 
 /// Given an [instance] of some generic type [T], and [extract], a first-class
diff --git a/sdk/lib/math/point.dart b/sdk/lib/math/point.dart
index baf18c2..80a4bbd 100644
--- a/sdk/lib/math/point.dart
+++ b/sdk/lib/math/point.dart
@@ -36,7 +36,7 @@
   bool operator ==(Object other) =>
       other is Point && x == other.x && y == other.y;
 
-  int get hashCode => SystemHash.hash2(x.hashCode, y.hashCode);
+  int get hashCode => SystemHash.hash2(x.hashCode, y.hashCode, 0);
 
   /// Add [other] to `this`, as if both points were vectors.
   ///
diff --git a/sdk/lib/math/rectangle.dart b/sdk/lib/math/rectangle.dart
index fd7d783..93cab78 100644
--- a/sdk/lib/math/rectangle.dart
+++ b/sdk/lib/math/rectangle.dart
@@ -49,7 +49,7 @@
       bottom == other.bottom;
 
   int get hashCode => SystemHash.hash4(
-      left.hashCode, top.hashCode, right.hashCode, bottom.hashCode);
+      left.hashCode, top.hashCode, right.hashCode, bottom.hashCode, 0);
 
   /// Computes the intersection of `this` and [other].
   ///
diff --git a/tools/VERSION b/tools/VERSION
index f4537254..fe75ebb 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 3
 MINOR 0
 PATCH 0
-PRERELEASE 77
+PRERELEASE 78
 PRERELEASE_PATCH 0