Version 2.16.0-152.0.dev

Merge commit '2766add19a274cef9eb0c763fa3627026fd9b923' into 'dev'
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/type_info.dart b/pkg/_fe_analyzer_shared/lib/src/parser/type_info.dart
index d599819..9e76440 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/type_info.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/type_info.dart
@@ -251,6 +251,18 @@
 
   assert(typeParamOrArg == noTypeParamOrArg);
   next = next.next!;
+
+  // TODO(scheglov) This is a hack to partially fix.
+  // https://github.com/dart-lang/sdk/issues/47951
+  if (optional('?', next) &&
+      optional('super', next.next!) &&
+      optional('.', next.next!.next!)) {
+    return simpleNullableType;
+  }
+  if (optional('super', next) && optional('.', next.next!)) {
+    return simpleType;
+  }
+
   if (optional('.', next)) {
     next = next.next!;
     if (isValidTypeReference(next)) {
diff --git a/pkg/analyzer/lib/src/summary2/informative_data.dart b/pkg/analyzer/lib/src/summary2/informative_data.dart
index c592b1f..aa69ec9 100644
--- a/pkg/analyzer/lib/src/summary2/informative_data.dart
+++ b/pkg/analyzer/lib/src/summary2/informative_data.dart
@@ -1370,6 +1370,9 @@
       } else if (notDefault is FunctionTypedFormalParameter) {
         _writeTypeParameters(notDefault.typeParameters);
         _writeFormalParameters(notDefault.parameters);
+      } else if (notDefault is SuperFormalParameter) {
+        _writeTypeParameters(notDefault.typeParameters);
+        _writeFormalParameters(notDefault.parameters);
       } else {
         _writeTypeParameters(null);
         _writeFormalParameters(null);
diff --git a/pkg/analyzer/test/generated/utilities_test.dart b/pkg/analyzer/test/generated/utilities_test.dart
index cd93433..dfaa5e0 100644
--- a/pkg/analyzer/test/generated/utilities_test.dart
+++ b/pkg/analyzer/test/generated/utilities_test.dart
@@ -1644,7 +1644,6 @@
     );
   }
 
-  @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/47951')
   void test_superFormalParameter() {
     var findNode = _parseStringToFindNode(r'''
 class A {
@@ -1666,7 +1665,6 @@
     );
   }
 
-  @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/47741')
   void test_superFormalParameter_functionTyped() {
     var findNode = _parseStringToFindNode(r'''
 class A {
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index b5fdd89..7a39830 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -1453,7 +1453,6 @@
 ''');
   }
 
-  @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/47951')
   test_class_constructor_parameters_super_explicitType_function() async {
     var library = await checkLibrary('''
 class A {
@@ -1492,7 +1491,6 @@
 ''');
   }
 
-  @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/47951')
   test_class_constructor_parameters_super_explicitType_interface() async {
     var library = await checkLibrary('''
 class A {
@@ -1518,13 +1516,45 @@
         constructors
           @47
             parameters
-              requiredPositional final super.a @49
+              requiredPositional final super.a @59
                 type: int
                 superConstructorParameter: a@18
             superConstructor: self::@class::A::@constructor::•
 ''');
   }
 
+  test_class_constructor_parameters_super_explicitType_interface_nullable() async {
+    var library = await checkLibrary('''
+class A {
+  A(num? a);
+}
+
+class B extends A {
+  B(int? super.a);
+}
+''');
+    checkElementText(library, r'''
+library
+  definingUnit
+    classes
+      class A @6
+        constructors
+          @12
+            parameters
+              requiredPositional a @19
+                type: num?
+      class B @32
+        supertype: A
+        constructors
+          @48
+            parameters
+              requiredPositional final super.a @61
+                type: int?
+                superConstructorParameter: a@19
+            superConstructor: self::@class::A::@constructor::•
+''');
+  }
+
   test_class_constructor_parameters_super_invalid_topFunction() async {
     var library = await checkLibrary('''
 void f(super.a) {}
diff --git a/pkg/front_end/lib/src/fasta/builder/class_builder.dart b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
index d545175..c6b977b 100644
--- a/pkg/front_end/lib/src/fasta/builder/class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
@@ -39,7 +39,6 @@
 import '../names.dart' show noSuchMethodName;
 import '../problems.dart' show internalProblem, unhandled;
 import '../scope.dart';
-import '../source/source_constructor_builder.dart';
 import '../source/source_factory_builder.dart';
 import '../source/source_library_builder.dart' show SourceLibraryBuilder;
 import '../source/source_loader.dart';
@@ -47,10 +46,8 @@
 import '../type_inference/type_schema.dart' show UnknownType;
 import '../util/helpers.dart' show DelayedActionPerformer;
 import 'builder.dart';
-import 'constructor_builder.dart';
 import 'constructor_reference_builder.dart';
 import 'declaration_builder.dart';
-import 'field_builder.dart';
 import 'function_builder.dart';
 import 'library_builder.dart';
 import 'member_builder.dart';
@@ -89,8 +86,6 @@
   @override
   Uri get fileUri;
 
-  ClassBuilder? get patchForTesting;
-
   bool get isAbstract;
 
   bool get isMacro;
@@ -120,13 +115,6 @@
 
   void forEach(void f(String name, Builder builder));
 
-  void forEachDeclaredField(
-      void Function(String name, FieldBuilder fieldBuilder) f);
-
-  void forEachDeclaredConstructor(
-      void Function(String name, ConstructorBuilder constructorBuilder)
-          callback);
-
   /// The [Class] built by this builder.
   ///
   /// For a patch class the origin class is returned.
@@ -259,16 +247,12 @@
   ClassBuilder? actualOrigin;
 
   @override
-  ClassBuilder? get patchForTesting => _patchBuilder;
-
-  @override
   bool isNullClass = false;
 
   InterfaceType? _legacyRawType;
   InterfaceType? _nullableRawType;
   InterfaceType? _nonNullableRawType;
   InterfaceType? _thisType;
-  ClassBuilder? _patchBuilder;
 
   ClassBuilderImpl(
       List<MetadataBuilder>? metadata,
@@ -319,14 +303,6 @@
           includeInjectedConstructors: includeInjectedConstructors);
     } else {
       constructors.forEach(f);
-      if (includeInjectedConstructors) {
-        _patchBuilder?.constructors
-            .forEach((String name, MemberBuilder builder) {
-          if (!builder.isPatch) {
-            f(name, builder);
-          }
-        });
-      }
     }
   }
 
@@ -416,57 +392,6 @@
   }
 
   @override
-  void forEachDeclaredField(
-      void Function(String name, FieldBuilder fieldBuilder) callback) {
-    void callbackFilteringFieldBuilders(String name, Builder builder) {
-      if (builder is FieldBuilder) {
-        callback(name, builder);
-      }
-    }
-
-    // Currently, fields can't be patched, but can be injected.  When the fields
-    // will be made available for patching, the following code should iterate
-    // first over the fields from the patch and then -- over the fields in the
-    // original declaration, filtering out the patched fields.  For now, the
-    // assert checks that the names of the fields from the original declaration
-    // and from the patch don't intersect.
-    assert(
-        _patchBuilder == null ||
-            _patchBuilder!.scope.localMembers
-                .where((b) => b is FieldBuilder)
-                .map((b) => (b as FieldBuilder).name)
-                .toSet()
-                .intersection(scope.localMembers
-                    .where((b) => b is FieldBuilder)
-                    .map((b) => (b as FieldBuilder).name)
-                    .toSet())
-                .isEmpty,
-        "Detected an attempt to patch a field.");
-    _patchBuilder?.scope.forEach(callbackFilteringFieldBuilders);
-    scope.forEach(callbackFilteringFieldBuilders);
-  }
-
-  @override
-  void forEachDeclaredConstructor(
-      void Function(
-              String name, DeclaredSourceConstructorBuilder constructorBuilder)
-          callback) {
-    Set<String> visitedConstructorNames = {};
-    void callbackFilteringFieldBuilders(String name, Builder builder) {
-      if (builder is DeclaredSourceConstructorBuilder &&
-          visitedConstructorNames.add(builder.name)) {
-        callback(name, builder);
-      }
-    }
-
-    // Constructors can be patched, so iterate first over constructors in the
-    // patch, and then over constructors in the original declaration skipping
-    // those with the names that are in the patch.
-    _patchBuilder?.constructors.forEach(callbackFilteringFieldBuilders);
-    constructors.forEach(callbackFilteringFieldBuilders);
-  }
-
-  @override
   Builder? lookupLocalMember(String name,
       {bool setter: false, bool required: false}) {
     Builder? builder = scope.lookupLocalMember(name, setter: setter);
@@ -819,55 +744,6 @@
   }
 
   @override
-  void applyPatch(Builder patch) {
-    if (patch is ClassBuilder) {
-      patch.actualOrigin = this;
-      _patchBuilder = patch;
-      // TODO(ahe): Complain if `patch.supertype` isn't null.
-      scope.forEachLocalMember((String name, Builder member) {
-        Builder? memberPatch =
-            patch.scope.lookupLocalMember(name, setter: false);
-        if (memberPatch != null) {
-          member.applyPatch(memberPatch);
-        }
-      });
-      scope.forEachLocalSetter((String name, Builder member) {
-        Builder? memberPatch =
-            patch.scope.lookupLocalMember(name, setter: true);
-        if (memberPatch != null) {
-          member.applyPatch(memberPatch);
-        }
-      });
-      constructors.local.forEach((String name, Builder member) {
-        Builder? memberPatch = patch.constructors.local[name];
-        if (memberPatch != null) {
-          member.applyPatch(memberPatch);
-        }
-      });
-
-      int originLength = typeVariables?.length ?? 0;
-      int patchLength = patch.typeVariables?.length ?? 0;
-      if (originLength != patchLength) {
-        patch.addProblem(messagePatchClassTypeVariablesMismatch,
-            patch.charOffset, noLength, context: [
-          messagePatchClassOrigin.withLocation(fileUri, charOffset, noLength)
-        ]);
-      } else if (typeVariables != null) {
-        int count = 0;
-        for (TypeVariableBuilder t in patch.typeVariables!) {
-          typeVariables![count++].applyPatch(t);
-        }
-      }
-    } else {
-      library.addProblem(messagePatchDeclarationMismatch, patch.charOffset,
-          noLength, patch.fileUri, context: [
-        messagePatchDeclarationOrigin.withLocation(
-            fileUri, charOffset, noLength)
-      ]);
-    }
-  }
-
-  @override
   FunctionType? computeRedirecteeType(
       RedirectingFactoryBuilder factory, TypeEnvironment typeEnvironment) {
     ConstructorReferenceBuilder redirectionTarget = factory.redirectionTarget;
diff --git a/pkg/front_end/lib/src/fasta/builder/field_builder.dart b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
index 725b34c..a5fd7b7 100644
--- a/pkg/front_end/lib/src/fasta/builder/field_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
@@ -5,46 +5,9 @@
 library fasta.field_builder;
 
 import 'package:kernel/ast.dart';
-import 'package:kernel/core_types.dart';
 
 import 'member_builder.dart';
-import 'metadata_builder.dart';
-import 'type_builder.dart';
 
 abstract class FieldBuilder implements MemberBuilder {
   Field get field;
-
-  List<MetadataBuilder>? get metadata;
-
-  TypeBuilder? get type;
-
-  bool get isCovariantByDeclaration;
-
-  bool get isLate;
-
-  bool get hasInitializer;
-
-  /// Whether the body of this field has been built.
-  ///
-  /// Constant fields have their initializer built in the outline so we avoid
-  /// building them twice as part of the non-outline build.
-  bool get hasBodyBeenBuilt;
-
-  /// Builds the body of this field using [initializer] as the initializer
-  /// expression.
-  void buildBody(CoreTypes coreTypes, Expression? initializer);
-
-  /// Builds the field initializers for each field used to encode this field
-  /// using the [fileOffset] for the created nodes and [value] as the initial
-  /// field value.
-  List<Initializer> buildInitializer(int fileOffset, Expression value,
-      {required bool isSynthetic});
-
-  bool get isEligibleForInference;
-
-  DartType get builtType;
-
-  DartType inferType();
-
-  DartType get fieldType;
 }
diff --git a/pkg/front_end/lib/src/fasta/builder/formal_parameter_builder.dart b/pkg/front_end/lib/src/fasta/builder/formal_parameter_builder.dart
index 1503956..eefc5d1 100644
--- a/pkg/front_end/lib/src/fasta/builder/formal_parameter_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/formal_parameter_builder.dart
@@ -22,12 +22,12 @@
 import '../modifier.dart';
 import '../scope.dart' show Scope;
 import '../source/source_factory_builder.dart';
+import '../source/source_field_builder.dart';
 import '../source/source_library_builder.dart';
 import '../util/helpers.dart' show DelayedActionPerformer;
 import 'builder.dart';
 import 'class_builder.dart';
 import 'constructor_builder.dart';
-import 'field_builder.dart';
 import 'library_builder.dart';
 import 'metadata_builder.dart';
 import 'modifier_builder.dart';
@@ -197,7 +197,7 @@
 
   void finalizeInitializingFormal(ClassBuilder classBuilder) {
     Builder? fieldBuilder = classBuilder.lookupLocalMember(name);
-    if (fieldBuilder is FieldBuilder) {
+    if (fieldBuilder is SourceFieldBuilder) {
       variable!.type = fieldBuilder.inferType();
     } else {
       variable!.type = const DynamicType();
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart
index f3046a7..21cde4c 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart
@@ -9,6 +9,7 @@
 
 import '../builder/builder.dart';
 import '../builder/constructor_builder.dart';
+import '../builder/field_builder.dart';
 import '../builder/member_builder.dart';
 
 import '../builder/procedure_builder.dart';
@@ -89,7 +90,8 @@
           : const <ClassMember>[];
 }
 
-class DillFieldBuilder extends DillMemberBuilder {
+class DillFieldBuilder extends DillMemberBuilder implements FieldBuilder {
+  @override
   final Field field;
 
   DillFieldBuilder(this.field, Builder parent) : super(field, parent);
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 6ecde36..ed6468b 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -88,6 +88,7 @@
 import '../source/source_constructor_builder.dart';
 import '../source/source_enum_builder.dart';
 import '../source/source_factory_builder.dart';
+import '../source/source_field_builder.dart';
 import '../source/source_function_builder.dart';
 import '../source/source_library_builder.dart' show SourceLibraryBuilder;
 import '../source/source_procedure_builder.dart';
@@ -790,7 +791,7 @@
     debugEvent("finishFields");
     assert(checkState(null, [/*field count*/ ValueKinds.Integer]));
     int count = pop() as int;
-    List<FieldBuilder> fields = <FieldBuilder>[];
+    List<SourceFieldBuilder> fields = [];
     for (int i = 0; i < count; i++) {
       assert(checkState(null, [
         ValueKinds.FieldInitializerOrNull,
@@ -806,9 +807,9 @@
       } else {
         declaration = libraryBuilder.lookupLocalMember(name, required: true)!;
       }
-      FieldBuilder fieldBuilder;
+      SourceFieldBuilder fieldBuilder;
       if (declaration.isField && declaration.next == null) {
-        fieldBuilder = declaration as FieldBuilder;
+        fieldBuilder = declaration as SourceFieldBuilder;
       } else {
         continue;
       }
@@ -3122,8 +3123,8 @@
                 classBuilder!.declaresConstConstructor
             ? ConstantContext.required
             : ConstantContext.none;
-    if (member is FieldBuilder) {
-      FieldBuilder fieldBuilder = member as FieldBuilder;
+    if (member is SourceFieldBuilder) {
+      SourceFieldBuilder fieldBuilder = member as SourceFieldBuilder;
       inLateFieldInitializer = fieldBuilder.isLate;
       if (fieldBuilder.isAbstract) {
         addProblem(
@@ -6855,7 +6856,8 @@
                 name.length),
             fieldNameOffset)
       ];
-    } else if (builder is FieldBuilder && builder.isDeclarationInstanceMember) {
+    } else if (builder is SourceFieldBuilder &&
+        builder.isDeclarationInstanceMember) {
       initializedFields ??= <String, int>{};
       if (initializedFields!.containsKey(name)) {
         return <Initializer>[
@@ -6922,7 +6924,7 @@
                 uri,
                 context: [
                   fasta.messageInitializingFormalTypeMismatchField.withLocation(
-                      builder.fileUri!, builder.charOffset, noLength)
+                      builder.fileUri, builder.charOffset, noLength)
                 ]);
           }
         }
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
index f2a6f7f..0073678 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -1020,11 +1020,12 @@
 
     /// Quotes below are from [Dart Programming Language Specification, 4th
     /// Edition](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-408.pdf):
-    List<FieldBuilder> uninitializedFields = <FieldBuilder>[];
-    List<FieldBuilder> nonFinalFields = <FieldBuilder>[];
-    List<FieldBuilder> lateFinalFields = <FieldBuilder>[];
+    List<SourceFieldBuilder> uninitializedFields = [];
+    List<SourceFieldBuilder> nonFinalFields = [];
+    List<SourceFieldBuilder> lateFinalFields = [];
 
-    builder.forEachDeclaredField((String name, FieldBuilder fieldBuilder) {
+    builder
+        .forEachDeclaredField((String name, SourceFieldBuilder fieldBuilder) {
       if (fieldBuilder.isAbstract || fieldBuilder.isExternal) {
         // Skip abstract and external fields. These are abstract/external
         // getters/setters and have no initialization.
@@ -1043,11 +1044,11 @@
         // declared towards the beginning of the file) come last in the list.
         // To report errors on the first definition of a field, we need to
         // iterate until that last element.
-        FieldBuilder earliest = fieldBuilder;
+        SourceFieldBuilder earliest = fieldBuilder;
         Builder current = fieldBuilder;
         while (current.next != null) {
           current = current.next!;
-          if (current is FieldBuilder && !fieldBuilder.hasInitializer) {
+          if (current is SourceFieldBuilder && !fieldBuilder.hasInitializer) {
             earliest = current;
           }
         }
@@ -1131,7 +1132,7 @@
               constructor.fileOffset, noLength,
               context: nonFinalFields
                   .map((field) => messageConstConstructorNonFinalFieldCause
-                      .withLocation(field.fileUri!, field.charOffset, noLength))
+                      .withLocation(field.fileUri, field.charOffset, noLength))
                   .toList());
           nonFinalFields.clear();
         }
@@ -1152,9 +1153,9 @@
       }
     }
 
-    Map<ConstructorBuilder, Set<FieldBuilder>> constructorInitializedFields =
-        new Map<ConstructorBuilder, Set<FieldBuilder>>.identity();
-    Set<FieldBuilder>? initializedFields = null;
+    Map<ConstructorBuilder, Set<SourceFieldBuilder>>
+        constructorInitializedFields = new Map.identity();
+    Set<SourceFieldBuilder>? initializedFields = null;
 
     builder.forEachDeclaredConstructor(
         (String name, DeclaredSourceConstructorBuilder constructorBuilder) {
@@ -1179,15 +1180,17 @@
         }
       }
       if (!isRedirecting) {
-        Set<FieldBuilder> fields = earliest.takeInitializedFields() ?? const {};
+        Set<SourceFieldBuilder> fields =
+            earliest.takeInitializedFields() ?? const {};
         constructorInitializedFields[earliest] = fields;
-        (initializedFields ??= new Set<FieldBuilder>.identity()).addAll(fields);
+        (initializedFields ??= new Set<SourceFieldBuilder>.identity())
+            .addAll(fields);
       }
     });
 
     // Run through all fields that aren't initialized by any constructor, and
     // set their initializer to `null`.
-    for (FieldBuilder fieldBuilder in uninitializedFields) {
+    for (SourceFieldBuilder fieldBuilder in uninitializedFields) {
       if (initializedFields == null ||
           !initializedFields!.contains(fieldBuilder)) {
         bool uninitializedFinalOrNonNullableFieldIsError =
@@ -1197,7 +1200,7 @@
           if (fieldBuilder.isFinal &&
               uninitializedFinalOrNonNullableFieldIsError) {
             String uri = '${fieldBuilder.library.importUri}';
-            String file = fieldBuilder.fileUri!.pathSegments.last;
+            String file = fieldBuilder.fileUri.pathSegments.last;
             if (uri == 'dart:html' ||
                 uri == 'dart:svg' ||
                 uri == 'dart:_native_typed_data' ||
@@ -1235,7 +1238,7 @@
     // make sure that all other constructors also initialize them.
     constructorInitializedFields.forEach((ConstructorBuilder constructorBuilder,
         Set<FieldBuilder> fieldBuilders) {
-      for (FieldBuilder fieldBuilder
+      for (SourceFieldBuilder fieldBuilder
           in initializedFields!.difference(fieldBuilders)) {
         if (!fieldBuilder.hasInitializer && !fieldBuilder.isLate) {
           FieldInitializer initializer =
@@ -1253,7 +1256,7 @@
                 context: [
                   templateMissingImplementationCause
                       .withArguments(fieldBuilder.name)
-                      .withLocation(fieldBuilder.fileUri!,
+                      .withLocation(fieldBuilder.fileUri,
                           fieldBuilder.charOffset, fieldBuilder.name.length)
                 ]);
           } else if (fieldBuilder.field.type is! InvalidType &&
@@ -1271,7 +1274,7 @@
                   context: [
                     templateMissingImplementationCause
                         .withArguments(fieldBuilder.name)
-                        .withLocation(fieldBuilder.fileUri!,
+                        .withLocation(fieldBuilder.fileUri,
                             fieldBuilder.charOffset, fieldBuilder.name.length)
                   ]);
             }
@@ -1293,14 +1296,14 @@
     // it's so.
     assert(() {
       Set<String> patchFieldNames = {};
-      builder.forEachDeclaredField((String name, FieldBuilder fieldBuilder) {
+      builder
+          .forEachDeclaredField((String name, SourceFieldBuilder fieldBuilder) {
         patchFieldNames.add(NameScheme.createFieldName(
           FieldNameType.Field,
           name,
           isInstanceMember: fieldBuilder.isClassInstanceMember,
           className: builder.name,
-          isSynthesized:
-              fieldBuilder is SourceFieldBuilder && fieldBuilder.isLateLowered,
+          isSynthesized: fieldBuilder.isLateLowered,
         ));
       });
       builder.forEach((String name, Builder builder) {
diff --git a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
index c9eacac..e645c59 100644
--- a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
@@ -98,6 +98,8 @@
   @override
   final bool isMacro;
 
+  SourceClassBuilder? _patchBuilder;
+
   SourceClassBuilder(
       List<MetadataBuilder>? metadata,
       int modifiers,
@@ -125,6 +127,8 @@
     actualCls.hasConstConstructor = declaresConstConstructor;
   }
 
+  SourceClassBuilder? get patchForTesting => _patchBuilder;
+
   @override
   Class get cls => origin.actualCls;
 
@@ -310,6 +314,123 @@
     return false;
   }
 
+  @override
+  void forEachConstructor(void Function(String, MemberBuilder) f,
+      {bool includeInjectedConstructors: false}) {
+    if (isPatch) {
+      actualOrigin!.forEachConstructor(f,
+          includeInjectedConstructors: includeInjectedConstructors);
+    } else {
+      constructors.forEach(f);
+      if (includeInjectedConstructors) {
+        _patchBuilder?.constructors
+            .forEach((String name, MemberBuilder builder) {
+          if (!builder.isPatch) {
+            f(name, builder);
+          }
+        });
+      }
+    }
+  }
+
+  void forEachDeclaredField(
+      void Function(String name, SourceFieldBuilder fieldBuilder) callback) {
+    void callbackFilteringFieldBuilders(String name, Builder builder) {
+      if (builder is SourceFieldBuilder) {
+        callback(name, builder);
+      }
+    }
+
+    // Currently, fields can't be patched, but can be injected.  When the fields
+    // will be made available for patching, the following code should iterate
+    // first over the fields from the patch and then -- over the fields in the
+    // original declaration, filtering out the patched fields.  For now, the
+    // assert checks that the names of the fields from the original declaration
+    // and from the patch don't intersect.
+    assert(
+        _patchBuilder == null ||
+            _patchBuilder!.scope.localMembers
+                .where((b) => b is SourceFieldBuilder)
+                .map((b) => (b as SourceFieldBuilder).name)
+                .toSet()
+                .intersection(scope.localMembers
+                    .where((b) => b is SourceFieldBuilder)
+                    .map((b) => (b as SourceFieldBuilder).name)
+                    .toSet())
+                .isEmpty,
+        "Detected an attempt to patch a field.");
+    _patchBuilder?.scope.forEach(callbackFilteringFieldBuilders);
+    scope.forEach(callbackFilteringFieldBuilders);
+  }
+
+  void forEachDeclaredConstructor(
+      void Function(
+              String name, DeclaredSourceConstructorBuilder constructorBuilder)
+          callback) {
+    Set<String> visitedConstructorNames = {};
+    void callbackFilteringFieldBuilders(String name, Builder builder) {
+      if (builder is DeclaredSourceConstructorBuilder &&
+          visitedConstructorNames.add(builder.name)) {
+        callback(name, builder);
+      }
+    }
+
+    // Constructors can be patched, so iterate first over constructors in the
+    // patch, and then over constructors in the original declaration skipping
+    // those with the names that are in the patch.
+    _patchBuilder?.constructors.forEach(callbackFilteringFieldBuilders);
+    constructors.forEach(callbackFilteringFieldBuilders);
+  }
+
+  @override
+  void applyPatch(Builder patch) {
+    if (patch is SourceClassBuilder) {
+      patch.actualOrigin = this;
+      _patchBuilder = patch;
+      // TODO(ahe): Complain if `patch.supertype` isn't null.
+      scope.forEachLocalMember((String name, Builder member) {
+        Builder? memberPatch =
+            patch.scope.lookupLocalMember(name, setter: false);
+        if (memberPatch != null) {
+          member.applyPatch(memberPatch);
+        }
+      });
+      scope.forEachLocalSetter((String name, Builder member) {
+        Builder? memberPatch =
+            patch.scope.lookupLocalMember(name, setter: true);
+        if (memberPatch != null) {
+          member.applyPatch(memberPatch);
+        }
+      });
+      constructors.local.forEach((String name, Builder member) {
+        Builder? memberPatch = patch.constructors.local[name];
+        if (memberPatch != null) {
+          member.applyPatch(memberPatch);
+        }
+      });
+
+      int originLength = typeVariables?.length ?? 0;
+      int patchLength = patch.typeVariables?.length ?? 0;
+      if (originLength != patchLength) {
+        patch.addProblem(messagePatchClassTypeVariablesMismatch,
+            patch.charOffset, noLength, context: [
+          messagePatchClassOrigin.withLocation(fileUri, charOffset, noLength)
+        ]);
+      } else if (typeVariables != null) {
+        int count = 0;
+        for (TypeVariableBuilder t in patch.typeVariables!) {
+          typeVariables![count++].applyPatch(t);
+        }
+      }
+    } else {
+      library.addProblem(messagePatchDeclarationMismatch, patch.charOffset,
+          noLength, patch.fileUri, context: [
+        messagePatchDeclarationOrigin.withLocation(
+            fileUri, charOffset, noLength)
+      ]);
+    }
+  }
+
   TypeBuilder checkSupertype(TypeBuilder supertype) {
     if (typeVariables == null) return supertype;
     Message? message;
diff --git a/pkg/front_end/lib/src/fasta/source/source_constructor_builder.dart b/pkg/front_end/lib/src/fasta/source/source_constructor_builder.dart
index d6c3ae4..cb8ee92 100644
--- a/pkg/front_end/lib/src/fasta/source/source_constructor_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_constructor_builder.dart
@@ -10,7 +10,6 @@
 import '../builder/builder.dart';
 import '../builder/class_builder.dart';
 import '../builder/constructor_builder.dart';
-import '../builder/field_builder.dart';
 import '../builder/formal_parameter_builder.dart';
 import '../builder/library_builder.dart';
 import '../builder/member_builder.dart';
@@ -46,6 +45,7 @@
 import '../type_inference/type_inferrer.dart';
 import '../type_inference/type_schema.dart';
 import '../util/helpers.dart' show DelayedActionPerformer;
+import 'source_field_builder.dart';
 import 'source_function_builder.dart';
 
 abstract class SourceConstructorBuilder
@@ -56,7 +56,7 @@
   final Constructor _constructor;
   final Procedure? _constructorTearOff;
 
-  Set<FieldBuilder>? _initializedFields;
+  Set<SourceFieldBuilder>? _initializedFields;
 
   final int charOpenParenOffset;
 
@@ -656,7 +656,7 @@
   ///
   /// The field can be initialized either via an initializing formal or via an
   /// entry in the constructor initializer list.
-  void registerInitializedField(FieldBuilder fieldBuilder) {
+  void registerInitializedField(SourceFieldBuilder fieldBuilder) {
     (_initializedFields ??= {}).add(fieldBuilder);
   }
 
@@ -665,8 +665,8 @@
   /// Returns the set of fields previously registered via
   /// [registerInitializedField] and passes on the ownership of the collection
   /// to the caller.
-  Set<FieldBuilder>? takeInitializedFields() {
-    Set<FieldBuilder>? result = _initializedFields;
+  Set<SourceFieldBuilder>? takeInitializedFields() {
+    Set<SourceFieldBuilder>? result = _initializedFields;
     _initializedFields = null;
     return result;
   }
diff --git a/pkg/front_end/lib/src/fasta/source/source_enum_builder.dart b/pkg/front_end/lib/src/fasta/source/source_enum_builder.dart
index 216861b..9dc50e7 100644
--- a/pkg/front_end/lib/src/fasta/source/source_enum_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_enum_builder.dart
@@ -255,7 +255,7 @@
           referencesFromIndexed.lookupSetterReference(valuesName);
     }
 
-    FieldBuilder valuesBuilder = new SourceFieldBuilder(
+    SourceFieldBuilder valuesBuilder = new SourceFieldBuilder(
         /* metadata = */ null,
         listType,
         "values",
@@ -546,9 +546,9 @@
         if (enumConstantInfo != null) {
           String constant = enumConstantInfo.name;
           Builder declaration = firstMemberNamed(constant)!;
-          FieldBuilder field;
+          SourceFieldBuilder field;
           if (declaration.isField) {
-            field = declaration as FieldBuilder;
+            field = declaration as SourceFieldBuilder;
           } else {
             continue;
           }
@@ -604,9 +604,7 @@
                   bodyBuilder.typeInferrer.inferFieldInitializer(
                       bodyBuilder, const UnknownType(), initializer);
               initializer = inferenceResult.expression;
-              if (field is SourceFieldBuilder) {
-                field.fieldType = inferenceResult.inferredType;
-              }
+              field.fieldType = inferenceResult.inferredType;
             }
             field.buildBody(classHierarchy.coreTypes, initializer);
           }
diff --git a/pkg/front_end/lib/src/fasta/source/source_field_builder.dart b/pkg/front_end/lib/src/fasta/source/source_field_builder.dart
index d864cd8..377b82c 100644
--- a/pkg/front_end/lib/src/fasta/source/source_field_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_field_builder.dart
@@ -47,17 +47,18 @@
 
   late FieldEncoding _fieldEncoding;
 
-  @override
   final List<MetadataBuilder>? metadata;
 
-  @override
   final TypeBuilder? type;
 
   Token? _constInitializerToken;
 
   bool hadTypesInferred = false;
 
-  @override
+  /// Whether the body of this field has been built.
+  ///
+  /// Constant fields have their initializer built in the outline so we avoid
+  /// building them twice as part of the non-outline build.
   bool hasBodyBeenBuilt = false;
 
   // TODO(johnniwinther): [parent] is not trust-worthy for determining
@@ -291,16 +292,14 @@
   @override
   bool get isField => true;
 
-  @override
   bool get isLate => (modifiers & lateMask) != 0;
 
-  @override
   bool get isCovariantByDeclaration => (modifiers & covariantMask) != 0;
 
-  @override
   bool get hasInitializer => (modifiers & hasInitializerMask) != 0;
 
-  @override
+  /// Builds the body of this field using [initializer] as the initializer
+  /// expression.
   void buildBody(CoreTypes coreTypes, Expression? initializer) {
     assert(!hasBodyBeenBuilt);
     hasBodyBeenBuilt = true;
@@ -315,14 +314,15 @@
     _fieldEncoding.createBodies(coreTypes, initializer);
   }
 
-  @override
+  /// Builds the field initializers for each field used to encode this field
+  /// using the [fileOffset] for the created nodes and [value] as the initial
+  /// field value.
   List<Initializer> buildInitializer(int fileOffset, Expression value,
       {required bool isSynthetic}) {
     return _fieldEncoding.createInitializer(fileOffset, value,
         isSynthetic: isSynthetic);
   }
 
-  @override
   bool get isEligibleForInference {
     return type == null && (hasInitializer || isClassInstanceMember);
   }
@@ -425,7 +425,6 @@
     _constInitializerToken = null;
   }
 
-  @override
   DartType get fieldType => _fieldEncoding.type;
 
   void set fieldType(DartType value) {
@@ -447,7 +446,6 @@
     }
   }
 
-  @override
   DartType inferType() {
     SourceLibraryBuilder library = this.library;
     if (fieldType is! ImplicitFieldType) {
@@ -486,7 +484,6 @@
     return fieldType;
   }
 
-  @override
   DartType get builtType => fieldType;
 
   List<ClassMember>? _localMembers;
diff --git a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
index 4070f2c..9aa1463 100644
--- a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
@@ -213,7 +213,7 @@
   /// the error message is the corresponding value in the map.
   Map<String, String?>? unserializableExports;
 
-  List<FieldBuilder>? _implicitlyTypedFields;
+  List<SourceFieldBuilder>? _implicitlyTypedFields;
 
   /// The language version of this library as defined by the language version
   /// of the package it belongs to, if present, or the current language version
@@ -1310,7 +1310,7 @@
         (library.problemsAsJson ??= <String>[])
             .addAll(part.library.problemsAsJson!);
       }
-      List<FieldBuilder> partImplicitlyTypedFields = [];
+      List<SourceFieldBuilder> partImplicitlyTypedFields = [];
       part.collectImplicitlyTypedFields(partImplicitlyTypedFields);
       if (partImplicitlyTypedFields.isNotEmpty) {
         if (_implicitlyTypedFields == null) {
@@ -3697,9 +3697,9 @@
             count += computeDefaultTypesForVariables(member.typeVariables,
                 inErrorRecovery: issues.isNotEmpty);
           } else {
-            assert(member is FieldBuilder,
+            assert(member is SourceFieldBuilder,
                 "Unexpected class member $member (${member.runtimeType}).");
-            TypeBuilder? fieldType = (member as FieldBuilder).type;
+            TypeBuilder? fieldType = (member as SourceFieldBuilder).type;
             if (fieldType != null) {
               List<NonSimplicityIssue> issues =
                   getInboundReferenceIssuesInType(fieldType);
@@ -3763,7 +3763,7 @@
             reportIssues(issues);
             count += computeDefaultTypesForVariables(member.typeVariables,
                 inErrorRecovery: issues.isNotEmpty);
-          } else if (member is FieldBuilder) {
+          } else if (member is SourceFieldBuilder) {
             if (member.type != null) {
               _recursivelyReportGenericFunctionTypesAsBoundsForType(
                   member.type);
@@ -3773,7 +3773,7 @@
                 "Unexpected extension member $member (${member.runtimeType}).");
           }
         });
-      } else if (declaration is FieldBuilder) {
+      } else if (declaration is SourceFieldBuilder) {
         if (declaration.type != null) {
           List<NonSimplicityIssue> issues =
               getInboundReferenceIssuesInType(declaration.type);
@@ -4046,10 +4046,10 @@
   }
 
   void checkTypesInField(
-      FieldBuilder fieldBuilder, TypeEnvironment typeEnvironment) {
+      SourceFieldBuilder fieldBuilder, TypeEnvironment typeEnvironment) {
     // Check the bounds in the field's type.
     checkBoundsInType(fieldBuilder.fieldType, typeEnvironment,
-        fieldBuilder.fileUri!, fieldBuilder.charOffset,
+        fieldBuilder.fileUri, fieldBuilder.charOffset,
         allowSuperBounded: true);
 
     // Check that the field has an initializer if its type is potentially
@@ -4532,7 +4532,7 @@
     Iterator<Builder> iterator = this.iterator;
     while (iterator.moveNext()) {
       Builder declaration = iterator.current;
-      if (declaration is FieldBuilder) {
+      if (declaration is SourceFieldBuilder) {
         checkTypesInField(declaration, typeEnvironment);
       } else if (declaration is SourceProcedureBuilder) {
         checkTypesInFunctionBuilder(declaration, typeEnvironment);
@@ -4776,8 +4776,8 @@
     }
   }
 
-  void registerImplicitlyTypedField(FieldBuilder fieldBuilder) {
-    (_implicitlyTypedFields ??= <FieldBuilder>[]).add(fieldBuilder);
+  void registerImplicitlyTypedField(SourceFieldBuilder fieldBuilder) {
+    (_implicitlyTypedFields ??= <SourceFieldBuilder>[]).add(fieldBuilder);
   }
 
   void collectImplicitlyTypedFields(
diff --git a/pkg/front_end/lib/src/fasta/source/source_loader.dart b/pkg/front_end/lib/src/fasta/source/source_loader.dart
index 2b0ad49..2d2cac8 100644
--- a/pkg/front_end/lib/src/fasta/source/source_loader.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart
@@ -1992,7 +1992,7 @@
     typeInferenceEngine.prepareTopLevel(coreTypes, hierarchy);
     membersBuilder.computeTypes();
 
-    List<FieldBuilder> allImplicitlyTypedFields = <FieldBuilder>[];
+    List<SourceFieldBuilder> allImplicitlyTypedFields = [];
     for (SourceLibraryBuilder library in sourceLibraryBuilders) {
       library.collectImplicitlyTypedFields(allImplicitlyTypedFields);
     }
diff --git a/pkg/front_end/testcases/super_parameters/default_values.dart.strong.expect b/pkg/front_end/testcases/super_parameters/default_values.dart.strong.expect
index d27a628..29ffdbc 100644
--- a/pkg/front_end/testcases/super_parameters/default_values.dart.strong.expect
+++ b/pkg/front_end/testcases/super_parameters/default_values.dart.strong.expect
@@ -2,13 +2,10 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/super_parameters/default_values.dart:51:11: Error: Expected ']' before this.
+// pkg/front_end/testcases/super_parameters/default_values.dart:51:17: Error: The parameter 'x' can't have a value of 'null' because of its type 'int', but the implicit default value is 'null'.
+// Try adding either an explicit non-'null' default value or the 'required' modifier.
 //   C5([int super.x]); // Error.
-//           ^^^^^
-//
-// pkg/front_end/testcases/super_parameters/default_values.dart:61:10: Error: Expected ']' before this.
-//   C6([int? super.x]); // Ok.
-//          ^
+//                 ^
 //
 import self as self;
 import "dart:core" as core;
@@ -68,8 +65,8 @@
     ;
 }
 class C5 extends self::S5 {
-  constructor •([dynamic int = #C4]) → self::C5
-    : super self::S5::•()
+  constructor •([core::int x = #C4]) → self::C5
+    : super self::S5::•(x)
     ;
 }
 class S6 extends core::Object {
@@ -80,8 +77,8 @@
 }
 class C6 extends self::S6 {
   field core::int? b = null;
-  constructor •([dynamic int = #C4]) → self::C6
-    : super self::S6::•()
+  constructor •([core::int? x = #C4]) → self::C6
+    : super self::S6::•(x)
     ;
 }
 class S7 extends core::Object {
diff --git a/pkg/front_end/testcases/super_parameters/default_values.dart.strong.transformed.expect b/pkg/front_end/testcases/super_parameters/default_values.dart.strong.transformed.expect
index d27a628..29ffdbc 100644
--- a/pkg/front_end/testcases/super_parameters/default_values.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/super_parameters/default_values.dart.strong.transformed.expect
@@ -2,13 +2,10 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/super_parameters/default_values.dart:51:11: Error: Expected ']' before this.
+// pkg/front_end/testcases/super_parameters/default_values.dart:51:17: Error: The parameter 'x' can't have a value of 'null' because of its type 'int', but the implicit default value is 'null'.
+// Try adding either an explicit non-'null' default value or the 'required' modifier.
 //   C5([int super.x]); // Error.
-//           ^^^^^
-//
-// pkg/front_end/testcases/super_parameters/default_values.dart:61:10: Error: Expected ']' before this.
-//   C6([int? super.x]); // Ok.
-//          ^
+//                 ^
 //
 import self as self;
 import "dart:core" as core;
@@ -68,8 +65,8 @@
     ;
 }
 class C5 extends self::S5 {
-  constructor •([dynamic int = #C4]) → self::C5
-    : super self::S5::•()
+  constructor •([core::int x = #C4]) → self::C5
+    : super self::S5::•(x)
     ;
 }
 class S6 extends core::Object {
@@ -80,8 +77,8 @@
 }
 class C6 extends self::S6 {
   field core::int? b = null;
-  constructor •([dynamic int = #C4]) → self::C6
-    : super self::S6::•()
+  constructor •([core::int? x = #C4]) → self::C6
+    : super self::S6::•(x)
     ;
 }
 class S7 extends core::Object {
diff --git a/pkg/front_end/testcases/super_parameters/default_values.dart.weak.expect b/pkg/front_end/testcases/super_parameters/default_values.dart.weak.expect
index d27a628..29ffdbc 100644
--- a/pkg/front_end/testcases/super_parameters/default_values.dart.weak.expect
+++ b/pkg/front_end/testcases/super_parameters/default_values.dart.weak.expect
@@ -2,13 +2,10 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/super_parameters/default_values.dart:51:11: Error: Expected ']' before this.
+// pkg/front_end/testcases/super_parameters/default_values.dart:51:17: Error: The parameter 'x' can't have a value of 'null' because of its type 'int', but the implicit default value is 'null'.
+// Try adding either an explicit non-'null' default value or the 'required' modifier.
 //   C5([int super.x]); // Error.
-//           ^^^^^
-//
-// pkg/front_end/testcases/super_parameters/default_values.dart:61:10: Error: Expected ']' before this.
-//   C6([int? super.x]); // Ok.
-//          ^
+//                 ^
 //
 import self as self;
 import "dart:core" as core;
@@ -68,8 +65,8 @@
     ;
 }
 class C5 extends self::S5 {
-  constructor •([dynamic int = #C4]) → self::C5
-    : super self::S5::•()
+  constructor •([core::int x = #C4]) → self::C5
+    : super self::S5::•(x)
     ;
 }
 class S6 extends core::Object {
@@ -80,8 +77,8 @@
 }
 class C6 extends self::S6 {
   field core::int? b = null;
-  constructor •([dynamic int = #C4]) → self::C6
-    : super self::S6::•()
+  constructor •([core::int? x = #C4]) → self::C6
+    : super self::S6::•(x)
     ;
 }
 class S7 extends core::Object {
diff --git a/pkg/front_end/testcases/super_parameters/default_values.dart.weak.modular.expect b/pkg/front_end/testcases/super_parameters/default_values.dart.weak.modular.expect
index d27a628..29ffdbc 100644
--- a/pkg/front_end/testcases/super_parameters/default_values.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/super_parameters/default_values.dart.weak.modular.expect
@@ -2,13 +2,10 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/super_parameters/default_values.dart:51:11: Error: Expected ']' before this.
+// pkg/front_end/testcases/super_parameters/default_values.dart:51:17: Error: The parameter 'x' can't have a value of 'null' because of its type 'int', but the implicit default value is 'null'.
+// Try adding either an explicit non-'null' default value or the 'required' modifier.
 //   C5([int super.x]); // Error.
-//           ^^^^^
-//
-// pkg/front_end/testcases/super_parameters/default_values.dart:61:10: Error: Expected ']' before this.
-//   C6([int? super.x]); // Ok.
-//          ^
+//                 ^
 //
 import self as self;
 import "dart:core" as core;
@@ -68,8 +65,8 @@
     ;
 }
 class C5 extends self::S5 {
-  constructor •([dynamic int = #C4]) → self::C5
-    : super self::S5::•()
+  constructor •([core::int x = #C4]) → self::C5
+    : super self::S5::•(x)
     ;
 }
 class S6 extends core::Object {
@@ -80,8 +77,8 @@
 }
 class C6 extends self::S6 {
   field core::int? b = null;
-  constructor •([dynamic int = #C4]) → self::C6
-    : super self::S6::•()
+  constructor •([core::int? x = #C4]) → self::C6
+    : super self::S6::•(x)
     ;
 }
 class S7 extends core::Object {
diff --git a/pkg/front_end/testcases/super_parameters/default_values.dart.weak.outline.expect b/pkg/front_end/testcases/super_parameters/default_values.dart.weak.outline.expect
index 9cb4ff2..aca3fd0 100644
--- a/pkg/front_end/testcases/super_parameters/default_values.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/super_parameters/default_values.dart.weak.outline.expect
@@ -2,13 +2,10 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/super_parameters/default_values.dart:51:11: Error: Expected ']' before this.
+// pkg/front_end/testcases/super_parameters/default_values.dart:51:17: Error: The parameter 'x' can't have a value of 'null' because of its type 'int', but the implicit default value is 'null'.
+// Try adding either an explicit non-'null' default value or the 'required' modifier.
 //   C5([int super.x]); // Error.
-//           ^^^^^
-//
-// pkg/front_end/testcases/super_parameters/default_values.dart:61:10: Error: Expected ']' before this.
-//   C6([int? super.x]); // Ok.
-//          ^
+//                 ^
 //
 import self as self;
 import "dart:core" as core;
@@ -59,7 +56,7 @@
     ;
 }
 class C5 extends self::S5 {
-  constructor •([dynamic int]) → self::C5
+  constructor •([core::int x]) → self::C5
     ;
 }
 class S6 extends core::Object {
@@ -69,7 +66,7 @@
 }
 class C6 extends self::S6 {
   field core::int? b;
-  constructor •([dynamic int]) → self::C6
+  constructor •([core::int? x]) → self::C6
     ;
 }
 class S7 extends core::Object {
diff --git a/pkg/front_end/testcases/super_parameters/default_values.dart.weak.transformed.expect b/pkg/front_end/testcases/super_parameters/default_values.dart.weak.transformed.expect
index d27a628..29ffdbc 100644
--- a/pkg/front_end/testcases/super_parameters/default_values.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/super_parameters/default_values.dart.weak.transformed.expect
@@ -2,13 +2,10 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/super_parameters/default_values.dart:51:11: Error: Expected ']' before this.
+// pkg/front_end/testcases/super_parameters/default_values.dart:51:17: Error: The parameter 'x' can't have a value of 'null' because of its type 'int', but the implicit default value is 'null'.
+// Try adding either an explicit non-'null' default value or the 'required' modifier.
 //   C5([int super.x]); // Error.
-//           ^^^^^
-//
-// pkg/front_end/testcases/super_parameters/default_values.dart:61:10: Error: Expected ']' before this.
-//   C6([int? super.x]); // Ok.
-//          ^
+//                 ^
 //
 import self as self;
 import "dart:core" as core;
@@ -68,8 +65,8 @@
     ;
 }
 class C5 extends self::S5 {
-  constructor •([dynamic int = #C4]) → self::C5
-    : super self::S5::•()
+  constructor •([core::int x = #C4]) → self::C5
+    : super self::S5::•(x)
     ;
 }
 class S6 extends core::Object {
@@ -80,8 +77,8 @@
 }
 class C6 extends self::S6 {
   field core::int? b = null;
-  constructor •([dynamic int = #C4]) → self::C6
-    : super self::S6::•()
+  constructor •([core::int? x = #C4]) → self::C6
+    : super self::S6::•(x)
     ;
 }
 class S7 extends core::Object {
diff --git a/pkg/vm/bin/compare_il.dart b/pkg/vm/bin/compare_il.dart
index 5b9caa3..7545b08 100644
--- a/pkg/vm/bin/compare_il.dart
+++ b/pkg/vm/bin/compare_il.dart
@@ -29,13 +29,14 @@
   final graphs = _loadGraphs(ilFile, rename);
   final tests = await _loadTestCases(testFile);
 
-  Map<String, FlowGraph> findMatchingGraphs(String name) {
-    final suffix = '_${rename(name)}';
+  Map<String, FlowGraph> findMatchingGraphs(String name, String? closureName) {
+    final closureSuffix = closureName != null ? '_${rename(closureName)}' : '';
+    final suffix = '_${rename(name)}${closureSuffix}';
     return graphs.entries.firstWhere((f) => f.key.contains(suffix)).value;
   }
 
   for (var test in tests) {
-    test.run(findMatchingGraphs(test.name));
+    test.run(findMatchingGraphs(test.name, test.closureName));
   }
 
   exit(0); // Success.
@@ -43,6 +44,7 @@
 
 class TestCase {
   final String name;
+  final String? closureName;
   final String phasesFilter;
   final LibraryMirror library;
 
@@ -51,13 +53,16 @@
 
   TestCase({
     required this.name,
+    this.closureName,
     required this.phasesFilter,
     required this.library,
   });
 
+  late final fullName = name + (closureName != null ? '_$closureName' : '');
+
   void run(Map<String, FlowGraph> graphs) {
-    print('matching IL (${phases.join(', ')}) for $name');
-    library.invoke(MirrorSystem.getSymbol('matchIL\$$name'),
+    print('matching IL (${phases.join(', ')}) for $fullName');
+    library.invoke(MirrorSystem.getSymbol('matchIL\$$fullName'),
         phases.map((phase) => graphs[phase]!).toList());
     print('... ok');
   }
@@ -104,20 +109,35 @@
       .firstWhereOrNull((p) => p.name == name);
 
   final cases = LinkedHashSet<TestCase>(
-    equals: (a, b) => a.name == b.name,
-    hashCode: (a) => a.name.hashCode,
+    equals: (a, b) => a.fullName == b.fullName,
+    hashCode: (a) => a.fullName.hashCode,
   );
 
   void processDeclaration(DeclarationMirror decl) {
-    final p = getPragma(decl, 'vm:testing:print-flow-graph');
+    TestCase? testCase;
+    pragma? p = getPragma(decl, 'vm:testing:print-flow-graph');
     if (p != null) {
       final name = MirrorSystem.getName(decl.simpleName);
-      final added = cases.add(TestCase(
+      testCase = TestCase(
         name: name,
         phasesFilter: (p.options as String?) ?? 'AllocateRegisters',
         library: library,
-      ));
-      if (!added) throw 'duplicate test case with name $name';
+      );
+    }
+    p = getPragma(decl, 'vm:testing:match-inner-flow-graph');
+    if (p != null) {
+      final name = MirrorSystem.getName(decl.simpleName);
+      final closureName = p.options as String;
+      testCase = TestCase(
+        name: name,
+        closureName: closureName,
+        phasesFilter: 'AllocateRegisters',
+        library: library,
+      );
+    }
+    if (testCase != null) {
+      final added = cases.add(testCase);
+      if (!added) throw 'duplicate test case with name ${testCase.fullName}';
     }
   }
 
diff --git a/runtime/docs/infra/il_tests.md b/runtime/docs/infra/il_tests.md
index 94c4500..c8c2b40 100644
--- a/runtime/docs/infra/il_tests.md
+++ b/runtime/docs/infra/il_tests.md
@@ -36,6 +36,10 @@
 
 Actual matching is done by the `pkg/vm/tool/compare_il` script.
 
+In order to test IL of the inner (local) function, use
+`@pragma('vm:testing:match-inner-flow-graph', 'inner name')`.
+Specifying a particular phase is not supported for inner closures.
+
 ## Example
 
 ```dart
@@ -54,4 +58,15 @@
     ]),
   ]);
 }
-```
\ No newline at end of file
+
+@pragma('vm:testing:match-inner-flow-graph', 'bar')
+void foo() {
+  @pragma('vm:testing:print-flow-graph')
+  bar() {
+  }
+}
+
+void matchIL$foo_bar(FlowGraph graph) {
+  // Test IL of local bar() in foo().
+}
+```
diff --git a/runtime/tests/vm/dart/typed_data_aot_not_inlining_il_test.dart b/runtime/tests/vm/dart/typed_data_aot_not_inlining_il_test.dart
new file mode 100644
index 0000000..4b50aea
--- /dev/null
+++ b/runtime/tests/vm/dart/typed_data_aot_not_inlining_il_test.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This test asserts that we are not inlining accesses to typed data interfaces
+// (e.g. Uint8List) if there are instantiated 3rd party classes (e.g.
+// UnmodifiableUint8ListView).
+
+import 'dart:typed_data';
+import 'package:vm/testing/il_matchers.dart';
+
+createThirdPartyUint8List() => UnmodifiableUint8ListView(Uint8List(10));
+
+@pragma('vm:never-inline')
+@pragma('vm:testing:print-flow-graph')
+void foo(Uint8List list, int from) {
+  if (from >= list.length) {
+    list[from];
+  }
+}
+
+void matchIL$foo(FlowGraph graph) {
+  graph.match([
+    match.block('Graph'),
+    match.block('Function', [
+      'list' << match.Parameter(index: 0),
+      'from' << match.Parameter(index: 1),
+      'v13' << match.LoadClassId('list'),
+      match.PushArgument('list'),
+      match.DispatchTableCall('v13', selector_name: 'get:length'),
+      match.Branch(match.RelationalOp(match.any, match.any, kind: '>='),
+          ifTrue: 'B3'),
+    ]),
+    'B3' <<
+        match.block('Target', [
+          'v15' << match.LoadClassId('list'),
+          match.PushArgument('list'),
+          match.PushArgument(/* BoxInt64(Parameter) or Parameter */),
+          match.DispatchTableCall('v15', selector_name: '[]'),
+        ]),
+  ]);
+}
+
+void main() {
+  foo(int.parse('1') == 1 ? createThirdPartyUint8List() : Uint8List(1),
+      int.parse('0'));
+}
diff --git a/runtime/tests/vm/dart/typed_data_aot_regress43534_il_test.dart b/runtime/tests/vm/dart/typed_data_aot_regress43534_il_test.dart
new file mode 100644
index 0000000..50fe78c
--- /dev/null
+++ b/runtime/tests/vm/dart/typed_data_aot_regress43534_il_test.dart
@@ -0,0 +1,35 @@
+// 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:typed_data';
+import 'package:vm/testing/il_matchers.dart';
+
+@pragma('vm:never-inline')
+void callWith<T>(void Function(T arg) fun, T arg) {
+  fun(arg);
+}
+
+@pragma('vm:testing:match-inner-flow-graph', 'foo')
+void main() {
+  @pragma('vm:testing:print-flow-graph')
+  foo(Uint8List list) {
+    if (list[0] != 0) throw 'a';
+  }
+
+  callWith<Uint8List>(foo, Uint8List(10));
+}
+
+void matchIL$main(FlowGraph graph) {}
+
+void matchIL$main_foo(FlowGraph graph) {
+  graph.match([
+    match.block('Graph'),
+    match.block('Function', [
+      match.LoadField(),
+      match.GenericCheckBound(),
+      match.LoadUntagged(),
+      match.LoadIndexed(),
+    ]),
+  ]);
+}
diff --git a/runtime/tests/vm/dart_2/typed_data_aot_not_inlining_il_test.dart b/runtime/tests/vm/dart_2/typed_data_aot_not_inlining_il_test.dart
new file mode 100644
index 0000000..4b50aea
--- /dev/null
+++ b/runtime/tests/vm/dart_2/typed_data_aot_not_inlining_il_test.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This test asserts that we are not inlining accesses to typed data interfaces
+// (e.g. Uint8List) if there are instantiated 3rd party classes (e.g.
+// UnmodifiableUint8ListView).
+
+import 'dart:typed_data';
+import 'package:vm/testing/il_matchers.dart';
+
+createThirdPartyUint8List() => UnmodifiableUint8ListView(Uint8List(10));
+
+@pragma('vm:never-inline')
+@pragma('vm:testing:print-flow-graph')
+void foo(Uint8List list, int from) {
+  if (from >= list.length) {
+    list[from];
+  }
+}
+
+void matchIL$foo(FlowGraph graph) {
+  graph.match([
+    match.block('Graph'),
+    match.block('Function', [
+      'list' << match.Parameter(index: 0),
+      'from' << match.Parameter(index: 1),
+      'v13' << match.LoadClassId('list'),
+      match.PushArgument('list'),
+      match.DispatchTableCall('v13', selector_name: 'get:length'),
+      match.Branch(match.RelationalOp(match.any, match.any, kind: '>='),
+          ifTrue: 'B3'),
+    ]),
+    'B3' <<
+        match.block('Target', [
+          'v15' << match.LoadClassId('list'),
+          match.PushArgument('list'),
+          match.PushArgument(/* BoxInt64(Parameter) or Parameter */),
+          match.DispatchTableCall('v15', selector_name: '[]'),
+        ]),
+  ]);
+}
+
+void main() {
+  foo(int.parse('1') == 1 ? createThirdPartyUint8List() : Uint8List(1),
+      int.parse('0'));
+}
diff --git a/runtime/tests/vm/dart_2/typed_data_aot_regress43534_il_test.dart b/runtime/tests/vm/dart_2/typed_data_aot_regress43534_il_test.dart
new file mode 100644
index 0000000..50fe78c
--- /dev/null
+++ b/runtime/tests/vm/dart_2/typed_data_aot_regress43534_il_test.dart
@@ -0,0 +1,35 @@
+// 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:typed_data';
+import 'package:vm/testing/il_matchers.dart';
+
+@pragma('vm:never-inline')
+void callWith<T>(void Function(T arg) fun, T arg) {
+  fun(arg);
+}
+
+@pragma('vm:testing:match-inner-flow-graph', 'foo')
+void main() {
+  @pragma('vm:testing:print-flow-graph')
+  foo(Uint8List list) {
+    if (list[0] != 0) throw 'a';
+  }
+
+  callWith<Uint8List>(foo, Uint8List(10));
+}
+
+void matchIL$main(FlowGraph graph) {}
+
+void matchIL$main_foo(FlowGraph graph) {
+  graph.match([
+    match.block('Graph'),
+    match.block('Function', [
+      match.LoadField(),
+      match.GenericCheckBound(),
+      match.LoadUntagged(),
+      match.LoadIndexed(),
+    ]),
+  ]);
+}
diff --git a/runtime/vm/compiler/backend/flow_graph.cc b/runtime/vm/compiler/backend/flow_graph.cc
index 1dbf213..22ff2d3 100644
--- a/runtime/vm/compiler/backend/flow_graph.cc
+++ b/runtime/vm/compiler/backend/flow_graph.cc
@@ -1954,136 +1954,153 @@
   }
 }
 
-static void UnboxPhi(PhiInstr* phi, bool is_aot) {
-  Representation unboxed = phi->representation();
+namespace {
+class PhiUnboxingHeuristic : public ValueObject {
+ public:
+  explicit PhiUnboxingHeuristic(FlowGraph* flow_graph)
+      : worklist_(flow_graph, 10) {}
 
-  switch (phi->Type()->ToCid()) {
-    case kDoubleCid:
-      if (CanUnboxDouble()) {
-        unboxed = kUnboxedDouble;
-      }
-      break;
-    case kFloat32x4Cid:
-      if (ShouldInlineSimd()) {
-        unboxed = kUnboxedFloat32x4;
-      }
-      break;
-    case kInt32x4Cid:
-      if (ShouldInlineSimd()) {
-        unboxed = kUnboxedInt32x4;
-      }
-      break;
-    case kFloat64x2Cid:
-      if (ShouldInlineSimd()) {
-        unboxed = kUnboxedFloat64x2;
-      }
-      break;
-  }
+  void Process(PhiInstr* phi) {
+    Representation unboxed = phi->representation();
 
-  // If all the inputs are unboxed, leave the Phi unboxed.
-  if ((unboxed == kTagged) && phi->Type()->IsInt()) {
-    bool should_unbox = true;
-    Representation new_representation = kTagged;
-    for (intptr_t i = 0; i < phi->InputCount(); i++) {
-      Definition* input = phi->InputAt(i)->definition();
-      if (input->representation() != kUnboxedInt64 &&
-          input->representation() != kUnboxedInt32 &&
-          input->representation() != kUnboxedUint32 && !(input == phi)) {
-        should_unbox = false;
+    switch (phi->Type()->ToCid()) {
+      case kDoubleCid:
+        if (CanUnboxDouble()) {
+          unboxed = kUnboxedDouble;
+        }
         break;
-      }
-
-      if (new_representation == kTagged) {
-        new_representation = input->representation();
-      } else if (new_representation != input->representation()) {
-        new_representation = kNoRepresentation;
-      }
-    }
-    if (should_unbox) {
-      unboxed = new_representation != kNoRepresentation
-                    ? new_representation
-                    : RangeUtils::Fits(phi->range(),
-                                       RangeBoundary::kRangeBoundaryInt32)
-                          ? kUnboxedInt32
-                          : kUnboxedInt64;
-    }
-  }
-
-  if ((unboxed == kTagged) && phi->Type()->IsInt() &&
-      !phi->Type()->can_be_sentinel()) {
-    // Conservatively unbox phis that:
-    //   - are proven to be of type Int;
-    //   - fit into 64bits range;
-    //   - have either constants or Box() operations as inputs;
-    //   - have at least one Box() operation as an input;
-    //   - are used in at least 1 Unbox() operation.
-    bool should_unbox = false;
-    for (intptr_t i = 0; i < phi->InputCount(); i++) {
-      Definition* input = phi->InputAt(i)->definition();
-      if (input->IsBox()) {
-        should_unbox = true;
-      } else if (!input->IsConstant()) {
-        should_unbox = false;
+      case kFloat32x4Cid:
+        if (ShouldInlineSimd()) {
+          unboxed = kUnboxedFloat32x4;
+        }
         break;
-      }
+      case kInt32x4Cid:
+        if (ShouldInlineSimd()) {
+          unboxed = kUnboxedInt32x4;
+        }
+        break;
+      case kFloat64x2Cid:
+        if (ShouldInlineSimd()) {
+          unboxed = kUnboxedFloat64x2;
+        }
+        break;
     }
 
-    if (should_unbox) {
-      // We checked inputs. Check if phi is used in at least one unbox
-      // operation.
-      bool has_unboxed_use = false;
-      for (Value* use = phi->input_use_list(); use != NULL;
-           use = use->next_use()) {
-        Instruction* instr = use->instruction();
-        if (instr->IsUnbox()) {
-          has_unboxed_use = true;
+    // If all the inputs are unboxed, leave the Phi unboxed.
+    if ((unboxed == kTagged) && phi->Type()->IsInt()) {
+      bool should_unbox = true;
+      Representation new_representation = kTagged;
+      for (auto input : phi->inputs()) {
+        if (input == phi) continue;
+
+        if (!IsUnboxedInteger(input->representation())) {
+          should_unbox = false;
           break;
-        } else if (IsUnboxedInteger(
-                       instr->RequiredInputRepresentation(use->use_index()))) {
-          has_unboxed_use = true;
-          break;
+        }
+
+        if (new_representation == kTagged) {
+          new_representation = input->representation();
+        } else if (new_representation != input->representation()) {
+          new_representation = kNoRepresentation;
         }
       }
 
-      if (!has_unboxed_use) {
-        should_unbox = false;
+      if (should_unbox) {
+        unboxed =
+            new_representation != kNoRepresentation ? new_representation
+            : RangeUtils::Fits(phi->range(), RangeBoundary::kRangeBoundaryInt32)
+                ? kUnboxedInt32
+                : kUnboxedInt64;
       }
     }
 
-    if (should_unbox) {
-      unboxed =
-          RangeUtils::Fits(phi->range(), RangeBoundary::kRangeBoundaryInt32)
-              ? kUnboxedInt32
-              : kUnboxedInt64;
-    }
-  }
-
+    // Decide if it is worth to unbox an integer phi.
+    if ((unboxed == kTagged) && phi->Type()->IsInt() &&
+        !phi->Type()->can_be_sentinel()) {
 #if defined(TARGET_ARCH_IS_64_BIT)
-  // In AOT mode on 64-bit platforms always unbox integer typed phis (similar
-  // to how we treat doubles and other boxed numeric types).
-  // In JIT mode only unbox phis which are not fully known to be Smi.
-  if ((unboxed == kTagged) && phi->Type()->IsInt() &&
-      !phi->Type()->can_be_sentinel() &&
-      (is_aot || phi->Type()->ToCid() != kSmiCid)) {
-    unboxed = kUnboxedInt64;
-  }
-#endif
+      // In AOT mode on 64-bit platforms always unbox integer typed phis
+      // (similar to how we treat doubles and other boxed numeric types).
+      // In JIT mode only unbox phis which are not fully known to be Smi.
+      if (is_aot_ || phi->Type()->ToCid() != kSmiCid) {
+        unboxed = kUnboxedInt64;
+      }
+#else
+      // If we are on a 32-bit platform check if there are unboxed values
+      // flowing into the phi and the phi value itself is flowing into an
+      // unboxed operation prefer to keep it unboxed.
+      // We use this heuristic instead of eagerly unboxing all the phis
+      // because we are concerned about the code size and register pressure.
+      const bool has_unboxed_incomming_value = HasUnboxedIncommingValue(phi);
+      const bool flows_into_unboxed_use = FlowsIntoUnboxedUse(phi);
 
-  phi->set_representation(unboxed);
-}
+      if (has_unboxed_incomming_value && flows_into_unboxed_use) {
+        unboxed =
+            RangeUtils::Fits(phi->range(), RangeBoundary::kRangeBoundaryInt32)
+                ? kUnboxedInt32
+                : kUnboxedInt64;
+      }
+#endif
+    }
+
+    phi->set_representation(unboxed);
+  }
+
+ private:
+  // Returns |true| iff there is an unboxed definition among all potential
+  // definitions that can flow into the |phi|.
+  // This function looks through phis.
+  bool HasUnboxedIncommingValue(PhiInstr* phi) {
+    worklist_.Clear();
+    worklist_.Add(phi);
+    for (intptr_t i = 0; i < worklist_.definitions().length(); i++) {
+      const auto defn = worklist_.definitions()[i];
+      for (auto input : defn->inputs()) {
+        if (IsUnboxedInteger(input->representation()) || input->IsBox()) {
+          return true;
+        } else if (input->IsPhi()) {
+          worklist_.Add(input);
+        }
+      }
+    }
+    return false;
+  }
+
+  // Returns |true| iff |phi| potentially flows into an unboxed use.
+  // This function looks through phis.
+  bool FlowsIntoUnboxedUse(PhiInstr* phi) {
+    worklist_.Clear();
+    worklist_.Add(phi);
+    for (intptr_t i = 0; i < worklist_.definitions().length(); i++) {
+      const auto defn = worklist_.definitions()[i];
+      for (auto use : defn->input_uses()) {
+        if (IsUnboxedInteger(use->instruction()->RequiredInputRepresentation(
+                use->use_index())) ||
+            use->instruction()->IsUnbox()) {
+          return true;
+        } else if (auto phi_use = use->instruction()->AsPhi()) {
+          worklist_.Add(phi_use);
+        }
+      }
+    }
+    return false;
+  }
+
+  const bool is_aot_ = CompilerState::Current().is_aot();
+  DefinitionWorklist worklist_;
+};
+}  // namespace
 
 void FlowGraph::SelectRepresentations() {
-  const auto is_aot = CompilerState::Current().is_aot();
-
   // First we decide for each phi if it is beneficial to unbox it. If so, we
   // change it's `phi->representation()`
+  PhiUnboxingHeuristic phi_unboxing_heuristic(this);
   for (BlockIterator block_it = reverse_postorder_iterator(); !block_it.Done();
        block_it.Advance()) {
     JoinEntryInstr* join_entry = block_it.Current()->AsJoinEntry();
     if (join_entry != NULL) {
       for (PhiIterator it(join_entry); !it.Done(); it.Advance()) {
         PhiInstr* phi = it.Current();
-        UnboxPhi(phi, is_aot);
+        phi_unboxing_heuristic.Process(phi);
       }
     }
   }
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index c261131..719d0d9 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -62,7 +62,6 @@
 class Range;
 class RangeAnalysis;
 class RangeBoundary;
-class SuccessorsIterable;
 class TypeUsageInfo;
 class UnboxIntegerInstr;
 
@@ -769,6 +768,64 @@
 typedef ZoneGrowableArray<Value*> InputsArray;
 typedef ZoneGrowableArray<PushArgumentInstr*> PushArgumentsArray;
 
+template <typename Trait>
+class InstructionIndexedPropertyIterable {
+ public:
+  struct Iterator {
+    const Instruction* instr;
+    intptr_t index;
+
+    decltype(Trait::At(instr, index)) operator*() const {
+      return Trait::At(instr, index);
+    }
+    Iterator& operator++() {
+      index++;
+      return *this;
+    }
+
+    bool operator==(const Iterator& other) {
+      return instr == other.instr && index == other.index;
+    }
+
+    bool operator!=(const Iterator& other) { return !(*this == other); }
+  };
+
+  explicit InstructionIndexedPropertyIterable(const Instruction* instr)
+      : instr_(instr) {}
+
+  Iterator begin() const { return {instr_, 0}; }
+  Iterator end() const { return {instr_, Trait::Length(instr_)}; }
+
+ private:
+  const Instruction* instr_;
+};
+
+class ValueListIterable {
+ public:
+  struct Iterator {
+    Value* value;
+
+    Value* operator*() const { return value; }
+
+    Iterator& operator++() {
+      value = value->next_use();
+      return *this;
+    }
+
+    bool operator==(const Iterator& other) { return value == other.value; }
+
+    bool operator!=(const Iterator& other) { return !(*this == other); }
+  };
+
+  explicit ValueListIterable(Value* value) : value_(value) {}
+
+  Iterator begin() const { return {value_}; }
+  Iterator end() const { return {nullptr}; }
+
+ private:
+  Value* value_;
+};
+
 class Instruction : public ZoneAllocated {
  public:
 #define DECLARE_TAG(type, attrs) k##type,
@@ -828,6 +885,20 @@
     RawSetInputAt(i, value);
   }
 
+  struct InputsTrait {
+    static Definition* At(const Instruction* instr, intptr_t index) {
+      return instr->InputAt(index)->definition();
+    }
+
+    static intptr_t Length(const Instruction* instr) {
+      return instr->InputCount();
+    }
+  };
+
+  using InputsIterable = InstructionIndexedPropertyIterable<InputsTrait>;
+
+  InputsIterable inputs() { return InputsIterable(this); }
+
   // Remove all inputs (including in the environment) from their
   // definition's use lists.
   void UnuseAllInputs();
@@ -917,7 +988,22 @@
   virtual intptr_t SuccessorCount() const;
   virtual BlockEntryInstr* SuccessorAt(intptr_t index) const;
 
-  inline SuccessorsIterable successors() const;
+  struct SuccessorsTrait {
+    static BlockEntryInstr* At(const Instruction* instr, intptr_t index) {
+      return instr->SuccessorAt(index);
+    }
+
+    static intptr_t Length(const Instruction* instr) {
+      return instr->SuccessorCount();
+    }
+  };
+
+  using SuccessorsIterable =
+      InstructionIndexedPropertyIterable<SuccessorsTrait>;
+
+  inline SuccessorsIterable successors() const {
+    return SuccessorsIterable(this);
+  }
 
   void Goto(JoinEntryInstr* entry);
 
@@ -2297,6 +2383,10 @@
   Value* env_use_list() const { return env_use_list_; }
   void set_env_use_list(Value* head) { env_use_list_ = head; }
 
+  ValueListIterable input_uses() const {
+    return ValueListIterable(input_use_list_);
+  }
+
   void AddInputUse(Value* value) { Value::AddToList(value, &input_use_list_); }
   void AddEnvUse(Value* value) { Value::AddToList(value, &env_use_list_); }
 
@@ -4384,9 +4474,13 @@
       const compiler::TableSelector* selector);
 
   DECLARE_INSTRUCTION(DispatchTableCall)
+  DECLARE_ATTRIBUTES(selector_name())
 
   const Function& interface_target() const { return interface_target_; }
   const compiler::TableSelector* selector() const { return selector_; }
+  const char* selector_name() const {
+    return String::Handle(interface_target().name()).ToCString();
+  }
 
   Value* class_id() const { return InputAt(InputCount() - 1); }
 
@@ -9764,37 +9858,6 @@
   return (constant == nullptr) || constant->value().ptr() == value.ptr();
 }
 
-class SuccessorsIterable {
- public:
-  struct Iterator {
-    const Instruction* instr;
-    intptr_t index;
-
-    BlockEntryInstr* operator*() const { return instr->SuccessorAt(index); }
-    Iterator& operator++() {
-      index++;
-      return *this;
-    }
-
-    bool operator==(const Iterator& other) {
-      return instr == other.instr && index == other.index;
-    }
-
-    bool operator!=(const Iterator& other) { return !(*this == other); }
-  };
-
-  explicit SuccessorsIterable(const Instruction* instr) : instr_(instr) {}
-
-  Iterator begin() const { return {instr_, 0}; }
-  Iterator end() const { return {instr_, instr_->SuccessorCount()}; }
-
- private:
-  const Instruction* instr_;
-};
-
-SuccessorsIterable Instruction::successors() const {
-  return SuccessorsIterable(this);
-}
 
 }  // namespace dart
 
diff --git a/runtime/vm/compiler/backend/il_test_helper.cc b/runtime/vm/compiler/backend/il_test_helper.cc
index 5d332bc..caa35ac 100644
--- a/runtime/vm/compiler/backend/il_test_helper.cc
+++ b/runtime/vm/compiler/backend/il_test_helper.cc
@@ -94,10 +94,6 @@
 
 FlowGraph* TestPipeline::RunPasses(
     std::initializer_list<CompilerPass::Id> passes) {
-  // The table dispatch transformation needs a precompiler, which is not
-  // available in the test pipeline.
-  SetFlagScope<bool> sfs(&FLAG_use_table_dispatch, false);
-
   auto thread = Thread::Current();
   auto zone = thread->zone();
   const bool optimized = true;
diff --git a/runtime/vm/compiler/backend/loops_test.cc b/runtime/vm/compiler/backend/loops_test.cc
index 1722f3b..dec8c01 100644
--- a/runtime/vm/compiler/backend/loops_test.cc
+++ b/runtime/vm/compiler/backend/loops_test.cc
@@ -387,15 +387,7 @@
   const char* expected =
       "  [0\n"
       "  LIN(9223372036854775806 + 1 * i)\n"  // phi
-#if !defined(TARGET_ARCH_IS_64_BIT)
-      "  LIN(9223372036854775806 + 1 * i)\n"  // (un)boxing
-      "  LIN(9223372036854775806 + 1 * i)\n"
-      "  LIN(9223372036854775806 + 1 * i)\n"
-#endif                                        // !defined(TARGET_ARCH_IS_64_BIT)
       "  LIN(9223372036854775807 + 1 * i)\n"  // add
-#if !defined(TARGET_ARCH_IS_64_BIT)
-      "  LIN(9223372036854775807 + 1 * i)\n"  // unbox
-#endif                                        // !defined(TARGET_ARCH_IS_64_BIT)
       "  ]\n";
   EXPECT_STREQ(expected, ComputeInduction(thread, script_chars));
 }
@@ -434,15 +426,7 @@
   const char* expected =
       "  [0\n"
       "  LIN(-9223372036854775807 + -1 * i)\n"  // phi
-#if !defined(TARGET_ARCH_IS_64_BIT)
-      "  LIN(-9223372036854775807 + -1 * i)\n"  // (un)boxing
-      "  LIN(-9223372036854775807 + -1 * i)\n"
-      "  LIN(-9223372036854775807 + -1 * i)\n"
-#endif  // !defined(TARGET_ARCH_IS_64_BIT)
       "  LIN(-9223372036854775808 + -1 * i)\n"  // sub
-#if !defined(TARGET_ARCH_IS_64_BIT)
-      "  LIN(-9223372036854775808 + -1 * i)\n"  // unbox
-#endif  // !defined(TARGET_ARCH_IS_64_BIT)
       "  ]\n";
   EXPECT_STREQ(expected, ComputeInduction(thread, script_chars));
 }
diff --git a/runtime/vm/compiler/backend/typed_data_aot_test.cc b/runtime/vm/compiler/backend/typed_data_aot_test.cc
index 557139a..1087c72 100644
--- a/runtime/vm/compiler/backend/typed_data_aot_test.cc
+++ b/runtime/vm/compiler/backend/typed_data_aot_test.cc
@@ -85,62 +85,6 @@
   EXPECT(load_indexed->InputAt(0)->definition() == load_untagged);
 }
 
-// This test asserts that we are not inlining accesses to typed data interfaces
-// (e.g. Uint8List) if there are instantiated 3rd party classes (e.g.
-// UnmodifiableUint8ListView).
-ISOLATE_UNIT_TEST_CASE(IRTest_TypedDataAOT_NotInlining) {
-  const char* kScript =
-      R"(
-      import 'dart:typed_data';
-
-      createThirdPartyUint8List() => UnmodifiableUint8ListView(Uint8List(10));
-
-      void foo(Uint8List list, int from) {
-        if (from >= list.length) {
-          list[from];
-        }
-      }
-      )";
-
-  const auto& root_library = Library::Handle(LoadTestScript(kScript));
-
-  // Firstly we ensure a non internal/external/view Uint8List is allocated.
-  Invoke(root_library, "createThirdPartyUint8List");
-
-  // Now we ensure that we don't perform the inlining of the `list[from]`
-  // access.
-  const auto& function = Function::Handle(GetFunction(root_library, "foo"));
-  TestPipeline pipeline(function, CompilerPass::kAOT);
-  FlowGraph* flow_graph = pipeline.RunPasses({});
-
-  auto entry = flow_graph->graph_entry()->normal_entry();
-  EXPECT(entry != nullptr);
-
-  InstanceCallInstr* length_call = nullptr;
-  PushArgumentInstr* pusharg1 = nullptr;
-  PushArgumentInstr* pusharg2 = nullptr;
-  InstanceCallInstr* index_get_call = nullptr;
-
-  ILMatcher cursor(flow_graph, entry);
-  RELEASE_ASSERT(cursor.TryMatch({
-      kMoveGlob,
-      {kMatchAndMoveInstanceCall, &length_call},
-      kMoveGlob,
-      kMatchAndMoveBranchTrue,
-      kMoveGlob,
-      {kMatchAndMovePushArgument, &pusharg1},
-      {kMatchAndMovePushArgument, &pusharg2},
-      {kMatchAndMoveInstanceCall, &index_get_call},
-      kMoveGlob,
-      kMatchReturn,
-  }));
-
-  EXPECT(length_call->Selector() == Symbols::GetLength().ptr());
-  EXPECT(pusharg1->InputAt(0)->definition()->IsParameter());
-  EXPECT(pusharg2->InputAt(0)->definition()->IsParameter());
-  EXPECT(index_get_call->Selector() == Symbols::IndexToken().ptr());
-}
-
 // This test asserts that we are inlining get:length, [] and []= for all typed
 // data interfaces.  It also ensures that the asserted IR actually works by
 // exercising it.
@@ -448,51 +392,6 @@
   }
 }
 
-ISOLATE_UNIT_TEST_CASE(IRTest_TypedDataAOT_Regress43534) {
-  const char* kScript =
-      R"(
-      import 'dart:typed_data';
-
-      @pragma('vm:never-inline')
-      void callWith<T>(void Function(T arg) fun, T arg) {
-        fun(arg);
-      }
-
-      void test() {
-        callWith<Uint8List>((Uint8List list) {
-          if (list[0] != 0) throw 'a';
-        }, Uint8List(10));
-      }
-      )";
-
-  const auto& root_library = Library::Handle(LoadTestScript(kScript));
-  Invoke(root_library, "test");
-  const auto& test_function =
-      Function::Handle(GetFunction(root_library, "test"));
-
-  const auto& function = Function::Handle(
-      ClosureFunctionsCache::GetUniqueInnerClosure(test_function));
-  RELEASE_ASSERT(function.IsFunction());
-
-  TestPipeline pipeline(function, CompilerPass::kAOT);
-  FlowGraph* flow_graph = pipeline.RunPasses({});
-
-  auto entry = flow_graph->graph_entry()->normal_entry();
-  EXPECT(entry != nullptr);
-  ILMatcher cursor(flow_graph, entry, /*trace=*/true);
-  RELEASE_ASSERT(cursor.TryMatch(
-      {
-          kMatchAndMoveLoadField,
-          kMatchAndMoveGenericCheckBound,
-          kMatchAndMoveLoadUntagged,
-          kMatchAndMoveLoadIndexed,
-          kMatchAndMoveBranchFalse,
-          kMoveGlob,
-          kMatchReturn,
-      },
-      kMoveGlob));
-}
-
 #endif  // defined(DART_PRECOMPILER)
 
 }  // namespace dart
diff --git a/tools/VERSION b/tools/VERSION
index 777b780..8faa73f 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 16
 PATCH 0
-PRERELEASE 151
+PRERELEASE 152
 PRERELEASE_PATCH 0
\ No newline at end of file