Version 2.19.0-276.0.dev

Merge 76b615b80d24fcceb87e602626a163e829cb2995 into dev
diff --git a/DEPS b/DEPS
index d86fdec..cc97cb7 100644
--- a/DEPS
+++ b/DEPS
@@ -111,7 +111,7 @@
   # For more details, see https://github.com/dart-lang/sdk/issues/30164.
   "dart_style_rev": "49bc3ff32b5578b6e19f8fd376d668130941ee29", # manually rev'd
 
-  "dartdoc_rev": "71545cdf2e5cc4ac3c8e81cbff3e1c91c6516f38",
+  "dartdoc_rev": "9908cf86dd66bce43cd4953cd1010766b01aae2b",
   "devtools_rev": "b21cd59f1f6bb60cacd59ba39e376d2a50d82f74",
   "ffi_rev": "fb5f2667826c0900e551d19101052f84e35f41bf",
   "file_rev": "b2e31cb6ef40b223701dbfa0b907fe58468484d7",
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_key_to_constructors.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_key_to_constructors.dart
index b74156e..3e8a7fd 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_key_to_constructors.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_key_to_constructors.dart
@@ -25,94 +25,11 @@
     var node = this.node;
     var parent = node.parent;
     if (node is ClassDeclaration) {
-      // The lint is on the name of the class when there are no constructors.
-      var targetLocation =
-          utils.prepareNewConstructorLocation(resolvedResult.session, node);
-      if (targetLocation == null) {
-        return;
-      }
-      var keyType = await _getKeyType();
-      if (keyType == null) {
-        return;
-      }
-      var className = node.name.lexeme;
-      var constructors = node.declaredElement?.supertype?.constructors;
-      if (constructors == null) {
-        return;
-      }
-
-      var canBeConst = _canBeConst(node, constructors);
-      await builder.addDartFileEdit(file, (builder) {
-        builder.addInsertion(targetLocation.offset, (builder) {
-          builder.write(targetLocation.prefix);
-          if (canBeConst) {
-            builder.write('const ');
-          }
-          builder.write(className);
-          builder.write('({');
-          if (libraryElement.featureSet.isEnabled(Feature.super_parameters)) {
-            builder.write('super.key});');
-          } else {
-            builder.writeType(keyType);
-            builder.write(' key}) : super(key: key);');
-          }
-          builder.write(targetLocation.suffix);
-        });
-      });
+      await _computeClassDeclaration(builder, node);
+    } else if (node is ConstructorDeclaration) {
+      await _computeConstructorDeclaration(builder, node);
     } else if (parent is ConstructorDeclaration) {
-      // The lint is on a constructor when that constructor doesn't have a `key`
-      // parameter.
-      var keyType = await _getKeyType();
-      if (keyType == null) {
-        return;
-      }
-      var superParameters =
-          libraryElement.featureSet.isEnabled(Feature.super_parameters);
-
-      void writeKey(DartEditBuilder builder) {
-        if (superParameters) {
-          builder.write('super.key');
-        } else {
-          builder.writeType(keyType);
-          builder.write(' key');
-        }
-      }
-
-      var parameterList = parent.parameters;
-      var parameters = parameterList.parameters;
-      if (parameters.isEmpty) {
-        // There are no parameters, so add the first parameter.
-        await builder.addDartFileEdit(file, (builder) {
-          builder.addInsertion(parameterList.leftParenthesis.end, (builder) {
-            builder.write('{');
-            writeKey(builder);
-            builder.write('}');
-          });
-          _updateSuper(builder, parent, superParameters);
-        });
-        return;
-      }
-      var leftDelimiter = parameterList.leftDelimiter;
-      if (leftDelimiter == null) {
-        // There are no named parameters, so add the delimiters.
-        await builder.addDartFileEdit(file, (builder) {
-          builder.addInsertion(parameters.last.end, (builder) {
-            builder.write(', {');
-            writeKey(builder);
-            builder.write('}');
-          });
-          _updateSuper(builder, parent, superParameters);
-        });
-      } else if (leftDelimiter.type == TokenType.OPEN_CURLY_BRACKET) {
-        // There are other named parameters, so add the new named parameter.
-        await builder.addDartFileEdit(file, (builder) {
-          builder.addInsertion(leftDelimiter.end, (builder) {
-            writeKey(builder);
-            builder.write(', ');
-          });
-          _updateSuper(builder, parent, superParameters);
-        });
-      }
+      await _computeConstructorDeclaration(builder, parent);
     }
   }
 
@@ -142,6 +59,101 @@
     return true;
   }
 
+  /// The lint is on the name of the class when there are no constructors.
+  Future<void> _computeClassDeclaration(
+      ChangeBuilder builder, ClassDeclaration node) async {
+    var targetLocation =
+        utils.prepareNewConstructorLocation(resolvedResult.session, node);
+    if (targetLocation == null) {
+      return;
+    }
+    var keyType = await _getKeyType();
+    if (keyType == null) {
+      return;
+    }
+    var className = node.name.lexeme;
+    var constructors = node.declaredElement?.supertype?.constructors;
+    if (constructors == null) {
+      return;
+    }
+
+    var canBeConst = _canBeConst(node, constructors);
+    await builder.addDartFileEdit(file, (builder) {
+      builder.addInsertion(targetLocation.offset, (builder) {
+        builder.write(targetLocation.prefix);
+        if (canBeConst) {
+          builder.write('const ');
+        }
+        builder.write(className);
+        builder.write('({');
+        if (libraryElement.featureSet.isEnabled(Feature.super_parameters)) {
+          builder.write('super.key});');
+        } else {
+          builder.writeType(keyType);
+          builder.write(' key}) : super(key: key);');
+        }
+        builder.write(targetLocation.suffix);
+      });
+    });
+  }
+
+  /// The lint is on a constructor when that constructor doesn't have a `key`
+  /// parameter.
+  Future<void> _computeConstructorDeclaration(
+      ChangeBuilder builder, ConstructorDeclaration node) async {
+    var keyType = await _getKeyType();
+    if (keyType == null) {
+      return;
+    }
+    var superParameters =
+        libraryElement.featureSet.isEnabled(Feature.super_parameters);
+
+    void writeKey(DartEditBuilder builder) {
+      if (superParameters) {
+        builder.write('super.key');
+      } else {
+        builder.writeType(keyType);
+        builder.write(' key');
+      }
+    }
+
+    var parameterList = node.parameters;
+    var parameters = parameterList.parameters;
+    if (parameters.isEmpty) {
+      // There are no parameters, so add the first parameter.
+      await builder.addDartFileEdit(file, (builder) {
+        builder.addInsertion(parameterList.leftParenthesis.end, (builder) {
+          builder.write('{');
+          writeKey(builder);
+          builder.write('}');
+        });
+        _updateSuper(builder, node, superParameters);
+      });
+      return;
+    }
+    var leftDelimiter = parameterList.leftDelimiter;
+    if (leftDelimiter == null) {
+      // There are no named parameters, so add the delimiters.
+      await builder.addDartFileEdit(file, (builder) {
+        builder.addInsertion(parameters.last.end, (builder) {
+          builder.write(', {');
+          writeKey(builder);
+          builder.write('}');
+        });
+        _updateSuper(builder, node, superParameters);
+      });
+    } else if (leftDelimiter.type == TokenType.OPEN_CURLY_BRACKET) {
+      // There are other named parameters, so add the new named parameter.
+      await builder.addDartFileEdit(file, (builder) {
+        builder.addInsertion(leftDelimiter.end, (builder) {
+          writeKey(builder);
+          builder.write(', ');
+        });
+        _updateSuper(builder, node, superParameters);
+      });
+    }
+  }
+
   /// Return the type for the class `Key`.
   Future<DartType?> _getKeyType() async {
     var keyClass = await sessionHelper.getClass(flutter.widgetsUri, 'Key');
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_key_to_constructors_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_key_to_constructors_test.dart
index 6eabd61..becec30 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_key_to_constructors_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_key_to_constructors_test.dart
@@ -368,6 +368,40 @@
 ''');
   }
 
+  Future<void> test_namedConstructor_namedParameters_withSuper_assert() async {
+    await resolveTestCode('''
+import 'package:flutter/material.dart';
+
+class MyWidget extends StatelessWidget {
+  MyWidget.named({required String s}) : assert(s.isNotEmpty), super();
+}
+''');
+    await assertHasFix('''
+import 'package:flutter/material.dart';
+
+class MyWidget extends StatelessWidget {
+  MyWidget.named({super.key, required String s}) : assert(s.isNotEmpty);
+}
+''');
+  }
+
+  Future<void> test_namedConstructor_noParameters_withoutSuper() async {
+    await resolveTestCode('''
+import 'package:flutter/material.dart';
+
+class MyWidget extends StatelessWidget {
+  MyWidget.named();
+}
+''');
+    await assertHasFix('''
+import 'package:flutter/material.dart';
+
+class MyWidget extends StatelessWidget {
+  MyWidget.named({super.key});
+}
+''');
+  }
+
   Future<void> test_super_not_constant() async {
     await resolveTestCode('''
 import 'package:flutter/material.dart';
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index ae640e2..710e64c 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -10347,7 +10347,7 @@
   Token leftParenthesis;
 
   /// The syntactic elements used to compute the fields of the record.
-  final NodeListImpl<Expression> _fields = NodeListImpl._();
+  final NodeListImpl<ExpressionImpl> _fields = NodeListImpl._();
 
   @override
   Token rightParenthesis;
@@ -10356,7 +10356,7 @@
   RecordLiteralImpl(
       {required this.constKeyword,
       required this.leftParenthesis,
-      required List<Expression> fields,
+      required List<ExpressionImpl> fields,
       required this.rightParenthesis}) {
     _fields._initialize(this, fields);
   }
@@ -10368,7 +10368,7 @@
   Token get endToken => rightParenthesis;
 
   @override
-  NodeList<Expression> get fields => _fields;
+  NodeList<ExpressionImpl> get fields => _fields;
 
   @override
   bool get isConst => constKeyword != null || inConstantContext;
diff --git a/pkg/analyzer/lib/src/dart/element/scope.dart b/pkg/analyzer/lib/src/dart/element/scope.dart
index be08afa..ce6320a 100644
--- a/pkg/analyzer/lib/src/dart/element/scope.dart
+++ b/pkg/analyzer/lib/src/dart/element/scope.dart
@@ -165,8 +165,12 @@
             final reference = exportedReference.reference;
             if (combinators.allows(reference.name)) {
               final element = elementFactory.elementOfReference(reference)!;
-              _add(element,
-                  _isFromDeprecatedExport(importedLibrary, exportedReference));
+              if (_shouldAdd(importedLibrary, element)) {
+                _add(
+                  element,
+                  _isFromDeprecatedExport(importedLibrary, exportedReference),
+                );
+              }
             }
           }
           if (import.prefix is DeferredImportElementPrefix) {
@@ -192,14 +196,6 @@
   }
 
   void _add(Element element, bool isFromDeprecatedExport) {
-    // TODO(scheglov) Remove when `records` feature is enabled by default.
-    if (element is ClassElementImpl &&
-        element.isDartCoreRecord &&
-        !_container.featureSet.isEnabled(Feature.records) &&
-        Feature.records.status != FeatureStatus.current) {
-      return;
-    }
-
     if (element is PropertyAccessorElement && element.isSetter) {
       _addTo(element, isFromDeprecatedExport, isSetter: true);
     } else {
@@ -267,6 +263,22 @@
     );
   }
 
+  bool _shouldAdd(LibraryElementImpl importedLibrary, Element element) {
+    // It is an error for the identifier `Record`, denoting the `Record` class
+    // from `dart:core`, where that import scope name is only imported from
+    // platform libraries, to appear in a library whose language version is
+    // less than `v`; assuming that `v` is the language version in which
+    // records are released.
+    if (!_container.featureSet.isEnabled(Feature.records)) {
+      if (importedLibrary.isInSdk &&
+          element is ClassElementImpl &&
+          element.isDartCoreRecord) {
+        return false;
+      }
+    }
+    return true;
+  }
+
   static void _addElement(
     Set<Element> conflictingElements,
     Element element,
diff --git a/pkg/analyzer/lib/src/dart/resolver/record_literal_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/record_literal_resolver.dart
index f22a407..9612b79 100644
--- a/pkg/analyzer/lib/src/dart/resolver/record_literal_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/record_literal_resolver.dart
@@ -29,7 +29,7 @@
   void reportDuplicateFieldDefinitions(RecordLiteralImpl node) {
     var usedNames = <String, NamedExpression>{};
     for (var field in node.fields) {
-      if (field is NamedExpression) {
+      if (field is NamedExpressionImpl) {
         var name = field.name.label.name;
         var previousField = usedNames[name];
         if (previousField != null) {
@@ -53,7 +53,7 @@
       }
     }
     for (var field in fields) {
-      if (field is NamedExpression) {
+      if (field is NamedExpressionImpl) {
         var nameNode = field.name.label;
         var name = nameNode.name;
         if (name.startsWith('_')) {
@@ -96,7 +96,7 @@
     final namedFields = <RecordTypeNamedFieldImpl>[];
     for (final field in node.fields) {
       final fieldType = field.typeOrThrow;
-      if (field is NamedExpression) {
+      if (field is NamedExpressionImpl) {
         namedFields.add(
           RecordTypeNamedFieldImpl(
             name: field.name.label.name,
@@ -123,9 +123,17 @@
     );
   }
 
-  void _resolveField(Expression field, DartType? contextType) {
+  void _resolveField(ExpressionImpl field, DartType? contextType) {
     _resolver.analyzeExpression(field, contextType);
-    _resolver.popRewrite();
+    field = _resolver.popRewrite()!;
+
+    // Implicit cast from `dynamic`.
+    if (contextType != null && field.typeOrThrow.isDynamic) {
+      field.staticType = contextType;
+      if (field is NamedExpressionImpl) {
+        field.expression.staticType = contextType;
+      }
+    }
   }
 
   void _resolveFields(RecordLiteralImpl node, DartType? contextType) {
@@ -133,7 +141,7 @@
       var index = 0;
       for (final field in node.fields) {
         DartType? fieldContextType;
-        if (field is NamedExpression) {
+        if (field is NamedExpressionImpl) {
           final name = field.name.label.name;
           fieldContextType = contextType.namedField(name)?.type;
         } else {
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index d31654b..46bf913 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -2556,16 +2556,12 @@
       );
     }
 
-    var elements = popTypedList<Expression>(count) ?? const [];
-    List<Expression> expressions = <Expression>[];
-    for (var elem in elements) {
-      expressions.add(elem);
-    }
+    var fields = popTypedList<ExpressionImpl>(count) ?? const [];
 
     push(RecordLiteralImpl(
       constKeyword: constKeyword,
       leftParenthesis: token,
-      fields: expressions,
+      fields: fields,
       rightParenthesis: token.endGroup!,
     ));
   }
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart b/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
index 3103fcf..aee911d 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
@@ -1011,7 +1011,7 @@
 
   RecordLiteralImpl _readRecordLiteral() {
     var flags = _readByte();
-    var fields = _readNodeList<Expression>();
+    var fields = _readNodeList<ExpressionImpl>();
     var node = RecordLiteralImpl(
       constKeyword: AstBinaryFlags.isConst(flags) ? Tokens.const_() : null,
       leftParenthesis: Tokens.openParenthesis(),
diff --git a/pkg/analyzer/test/src/dart/resolution/property_access_test.dart b/pkg/analyzer/test/src/dart/resolution/property_access_test.dart
index 3cd60c2..8254049 100644
--- a/pkg/analyzer/test/src/dart/resolution/property_access_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/property_access_test.dart
@@ -376,6 +376,35 @@
 ''');
   }
 
+  test_ofRecordType_namedField_language218() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+final r = (foo: 42);
+''');
+
+    await assertNoErrorsInCode('''
+// @dart = 2.18
+import 'a.dart';
+void f() {
+  r.foo;
+}
+''');
+
+    final node = findNode.propertyAccess('foo;');
+    assertResolvedNodeText(node, r'''
+PropertyAccess
+  target: SimpleIdentifier
+    token: r
+    staticElement: package:test/a.dart::@getter::r
+    staticType: ({int foo})
+  operator: .
+  propertyName: SimpleIdentifier
+    token: foo
+    staticElement: <null>
+    staticType: int
+  staticType: int
+''');
+  }
+
   test_ofRecordType_namedField_nullAware() async {
     await assertNoErrorsInCode('''
 void f(({int foo})? r) {
@@ -620,6 +649,35 @@
 ''');
   }
 
+  test_ofRecordType_positionalField_language218() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+final r = (0, 'bar');
+''');
+
+    await assertNoErrorsInCode(r'''
+// @dart = 2.18
+import 'a.dart';
+void f() {
+  r.$0;
+}
+''');
+
+    final node = findNode.propertyAccess(r'$0;');
+    assertResolvedNodeText(node, r'''
+PropertyAccess
+  target: SimpleIdentifier
+    token: r
+    staticElement: package:test/a.dart::@getter::r
+    staticType: (int, String)
+  operator: .
+  propertyName: SimpleIdentifier
+    token: $0
+    staticElement: <null>
+    staticType: int
+  staticType: int
+''');
+  }
+
   test_ofRecordType_positionalField_letterDollarZero() async {
     await assertErrorsInCode(r'''
 void f((int, String) r) {
diff --git a/pkg/analyzer/test/src/dart/resolution/record_literal_test.dart b/pkg/analyzer/test/src/dart/resolution/record_literal_test.dart
index e3917f2..0a62154 100644
--- a/pkg/analyzer/test/src/dart/resolution/record_literal_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/record_literal_test.dart
@@ -14,6 +14,177 @@
 
 @reflectiveTest
 class RecordLiteralTest extends PubPackageResolutionTest {
+  test_field_rewrite_named() async {
+    await assertNoErrorsInCode(r'''
+void f((int, String) r) {
+  (f1: r.$0, );
+}
+''');
+
+    final node = findNode.recordLiteral('(f1');
+    assertResolvedNodeText(node, r'''
+RecordLiteral
+  leftParenthesis: (
+  fields
+    NamedExpression
+      name: Label
+        label: SimpleIdentifier
+          token: f1
+          staticElement: <null>
+          staticType: null
+        colon: :
+      expression: PropertyAccess
+        target: SimpleIdentifier
+          token: r
+          staticElement: self::@function::f::@parameter::r
+          staticType: (int, String)
+        operator: .
+        propertyName: SimpleIdentifier
+          token: $0
+          staticElement: <null>
+          staticType: int
+        staticType: int
+  rightParenthesis: )
+  staticType: ({int f1})
+''');
+  }
+
+  test_field_rewrite_positional() async {
+    await assertNoErrorsInCode(r'''
+void f((int, String) r) {
+  (r.$0, );
+}
+''');
+
+    final node = findNode.recordLiteral('(r');
+    assertResolvedNodeText(node, r'''
+RecordLiteral
+  leftParenthesis: (
+  fields
+    PropertyAccess
+      target: SimpleIdentifier
+        token: r
+        staticElement: self::@function::f::@parameter::r
+        staticType: (int, String)
+      operator: .
+      propertyName: SimpleIdentifier
+        token: $0
+        staticElement: <null>
+        staticType: int
+      staticType: int
+  rightParenthesis: )
+  staticType: (int)
+''');
+  }
+
+  test_hasContext_implicitCallReference_named() async {
+    await assertNoErrorsInCode(r'''
+class A {
+  void call() {}
+}
+
+final a = A();
+final ({void Function() f1}) x = (f1: a);
+''');
+
+    final node = findNode.recordLiteral('(f1');
+    assertResolvedNodeText(node, r'''
+RecordLiteral
+  leftParenthesis: (
+  fields
+    NamedExpression
+      name: Label
+        label: SimpleIdentifier
+          token: f1
+          staticElement: <null>
+          staticType: null
+        colon: :
+      expression: ImplicitCallReference
+        expression: SimpleIdentifier
+          token: a
+          staticElement: self::@getter::a
+          staticType: A
+        staticElement: self::@class::A::@method::call
+        staticType: void Function()
+  rightParenthesis: )
+  staticType: ({void Function() f1})
+''');
+  }
+
+  test_hasContext_implicitCallReference_positional() async {
+    await assertNoErrorsInCode(r'''
+class A {
+  void call() {}
+}
+
+final a = A();
+final (void Function(), ) x = (a, );
+''');
+
+    final node = findNode.recordLiteral('(a');
+    assertResolvedNodeText(node, r'''
+RecordLiteral
+  leftParenthesis: (
+  fields
+    ImplicitCallReference
+      expression: SimpleIdentifier
+        token: a
+        staticElement: self::@getter::a
+        staticType: A
+      staticElement: self::@class::A::@method::call
+      staticType: void Function()
+  rightParenthesis: )
+  staticType: (void Function())
+''');
+  }
+
+  test_hasContext_implicitCast_fromDynamic_named() async {
+    await assertNoErrorsInCode(r'''
+final dynamic a = 0;
+final ({int f1}) x = (f1: a);
+''');
+
+    final node = findNode.recordLiteral('(f1');
+    assertResolvedNodeText(node, r'''
+RecordLiteral
+  leftParenthesis: (
+  fields
+    NamedExpression
+      name: Label
+        label: SimpleIdentifier
+          token: f1
+          staticElement: <null>
+          staticType: null
+        colon: :
+      expression: SimpleIdentifier
+        token: a
+        staticElement: self::@getter::a
+        staticType: int
+  rightParenthesis: )
+  staticType: ({int f1})
+''');
+  }
+
+  test_hasContext_implicitCast_fromDynamic_positional() async {
+    await assertNoErrorsInCode(r'''
+final dynamic a = 0;
+final (int, ) x = (a, );
+''');
+
+    final node = findNode.recordLiteral('(a');
+    assertResolvedNodeText(node, r'''
+RecordLiteral
+  leftParenthesis: (
+  fields
+    SimpleIdentifier
+      token: a
+      staticElement: self::@getter::a
+      staticType: int
+  rightParenthesis: )
+  staticType: (int)
+''');
+  }
+
   test_hasContext_mixed() async {
     await assertNoErrorsInCode(r'''
 class A1 {}
diff --git a/pkg/analyzer/test/src/diagnostics/undefined_class_test.dart b/pkg/analyzer/test/src/diagnostics/undefined_class_test.dart
index ee4beab..2749200 100644
--- a/pkg/analyzer/test/src/diagnostics/undefined_class_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/undefined_class_test.dart
@@ -215,7 +215,6 @@
   }
 
   test_Record_language218() async {
-    // TODO(scheglov) Update when `records` feature is enabled by default.
     await assertErrorsInCode('''
 // @dart = 2.18
 void f(Record r) {}
@@ -224,6 +223,18 @@
     ]);
   }
 
+  test_Record_language218_exported() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+export 'dart:core' show Record;
+''');
+
+    await assertNoErrorsInCode('''
+// @dart = 2.18
+import 'a.dart';
+void f(Record r) {}
+''');
+  }
+
   test_variableDeclaration() async {
     await assertErrorsInCode('''
 f() { C c; }
diff --git a/pkg/analyzer/test/src/summary/resolved_ast_printer.dart b/pkg/analyzer/test/src/summary/resolved_ast_printer.dart
index 0bb1ab0..ae02e70 100644
--- a/pkg/analyzer/test/src/summary/resolved_ast_printer.dart
+++ b/pkg/analyzer/test/src/summary/resolved_ast_printer.dart
@@ -924,6 +924,16 @@
     _withIndent(() {
       _writeNamedChildEntities(node);
       _writeParameterElement(node);
+      // Types of the node and its expression must be the same.
+      if (node.expression.staticType != node.staticType) {
+        final nodeType = node.staticType;
+        final expressionType = node.expression.staticType;
+        fail(
+          'Must be the same:\n'
+          'nodeType: $nodeType\n'
+          'expressionType: $expressionType',
+        );
+      }
     });
   }
 
diff --git a/pkg/compiler/lib/src/js_backend/field_naming_mixin.dart b/pkg/compiler/lib/src/js_backend/field_naming_mixin.dart
index e710d15..b49b75a 100644
--- a/pkg/compiler/lib/src/js_backend/field_naming_mixin.dart
+++ b/pkg/compiler/lib/src/js_backend/field_naming_mixin.dart
@@ -21,7 +21,7 @@
     }
 
     _FieldNamingScope names;
-    if (element is JRecordField) {
+    if (element is JContextField) {
       names = _FieldNamingScope.forBox(element.box, fieldRegistry);
     } else {
       ClassEntity cls = element.enclosingClass;
diff --git a/pkg/compiler/lib/src/js_model/closure.dart b/pkg/compiler/lib/src/js_model/closure.dart
index dc2d401..deb2c1f 100644
--- a/pkg/compiler/lib/src/js_model/closure.dart
+++ b/pkg/compiler/lib/src/js_model/closure.dart
@@ -20,7 +20,7 @@
 import 'js_world_builder_interfaces.dart' show JsClosedWorldBuilder;
 
 export 'closure_migrated.dart'
-    show AnonymousClosureLocal, JClosureField, JRecordField;
+    show AnonymousClosureLocal, JClosureField, JContextField;
 
 class ClosureDataImpl implements ClosureData {
   /// Tag used for identifying serialized [ClosureData] objects in a
@@ -339,15 +339,15 @@
       ClosureRtiNeed rtiNeed,
       List<FunctionEntity> callMethods) {
     void processModel(MemberEntity member, ClosureScopeModel model) {
-      Map<ir.VariableDeclaration, migrated.JRecordField> allBoxedVariables =
-          _elementMap.makeRecordContainer(model.scopeInfo!, member);
+      Map<ir.VariableDeclaration, migrated.JContextField> allBoxedVariables =
+          _elementMap.makeContextContainer(model.scopeInfo!, member);
       _scopeMap[member] = JsScopeInfo.from(
           allBoxedVariables, model.scopeInfo!, member.enclosingClass);
 
       model.capturedScopesMap
           .forEach((ir.Node node, KernelCapturedScope scope) {
-        Map<ir.VariableDeclaration, migrated.JRecordField> boxedVariables =
-            _elementMap.makeRecordContainer(scope, member);
+        Map<ir.VariableDeclaration, migrated.JContextField> boxedVariables =
+            _elementMap.makeContextContainer(scope, member);
         _updateScopeBasedOnRtiNeed(scope, rtiNeed, member);
 
         if (scope is KernelCapturedLoopScope) {
@@ -424,7 +424,7 @@
       MemberEntity member,
       ir.FunctionNode node,
       KernelScopeInfo info,
-      Map<ir.VariableDeclaration, migrated.JRecordField> boxedVariables,
+      Map<ir.VariableDeclaration, migrated.JContextField> boxedVariables,
       ClosureRtiNeed rtiNeed,
       {required bool createSignatureMethod}) {
     _updateScopeBasedOnRtiNeed(info, rtiNeed, member);
@@ -461,9 +461,9 @@
   @override
   final Local? thisLocal;
 
-  final Map<ir.VariableDeclaration, migrated.JRecordField> _boxedVariables;
+  final Map<ir.VariableDeclaration, migrated.JContextField> _boxedVariables;
 
-  Map<Local, migrated.JRecordField>? _boxedVariablesCache;
+  Map<Local, migrated.JContextField>? _boxedVariablesCache;
 
   JsScopeInfo.internal(
       this._localsUsedInTryOrSync, this.thisLocal, this._boxedVariables);
@@ -478,9 +478,9 @@
       if (_boxedVariables.isEmpty) {
         _boxedVariablesCache = const {};
       } else {
-        final cache = <Local, migrated.JRecordField>{};
+        final cache = <Local, migrated.JContextField>{};
         _boxedVariables.forEach(
-            (ir.VariableDeclaration node, migrated.JRecordField field) {
+            (ir.VariableDeclaration node, migrated.JContextField field) {
           cache[localsMap.getLocalVariable(node)] = field;
         });
         _boxedVariablesCache = cache;
@@ -529,9 +529,9 @@
     Iterable<ir.VariableDeclaration> localsUsedInTryOrSync =
         source.readTreeNodes<ir.VariableDeclaration>();
     Local? thisLocal = source.readLocalOrNull();
-    Map<ir.VariableDeclaration, migrated.JRecordField> boxedVariables =
-        source.readTreeNodeMap<ir.VariableDeclaration, migrated.JRecordField>(
-            () => source.readMember() as migrated.JRecordField);
+    Map<ir.VariableDeclaration, migrated.JContextField> boxedVariables =
+        source.readTreeNodeMap<ir.VariableDeclaration, migrated.JContextField>(
+            () => source.readMember() as migrated.JContextField);
     source.end(tag);
     if (boxedVariables.isEmpty) boxedVariables = const {};
     return JsScopeInfo.internal(
@@ -575,9 +575,9 @@
     Iterable<ir.VariableDeclaration> localsUsedInTryOrSync =
         source.readTreeNodes<ir.VariableDeclaration>();
     Local? thisLocal = source.readLocalOrNull();
-    Map<ir.VariableDeclaration, migrated.JRecordField> boxedVariables =
-        source.readTreeNodeMap<ir.VariableDeclaration, migrated.JRecordField>(
-            () => source.readMember() as migrated.JRecordField);
+    Map<ir.VariableDeclaration, migrated.JContextField> boxedVariables =
+        source.readTreeNodeMap<ir.VariableDeclaration, migrated.JContextField>(
+            () => source.readMember() as migrated.JContextField);
     Local? context = source.readLocalOrNull();
     source.end(tag);
     return JsCapturedScope.internal(
@@ -620,9 +620,9 @@
     Iterable<ir.VariableDeclaration> localsUsedInTryOrSync =
         source.readTreeNodes<ir.VariableDeclaration>();
     Local? thisLocal = source.readLocalOrNull();
-    Map<ir.VariableDeclaration, migrated.JRecordField> boxedVariables =
-        source.readTreeNodeMap<ir.VariableDeclaration, migrated.JRecordField>(
-            () => source.readMember() as migrated.JRecordField);
+    Map<ir.VariableDeclaration, migrated.JContextField> boxedVariables =
+        source.readTreeNodeMap<ir.VariableDeclaration, migrated.JContextField>(
+            () => source.readMember() as migrated.JContextField);
     Local? context = source.readLocalOrNull();
     List<ir.VariableDeclaration> boxedLoopVariables =
         source.readTreeNodes<ir.VariableDeclaration>();
@@ -688,7 +688,7 @@
   JsClosureClassInfo.internal(
       Iterable<ir.VariableDeclaration> localsUsedInTryOrSync,
       this.thisLocal,
-      Map<ir.VariableDeclaration, migrated.JRecordField> boxedVariables,
+      Map<ir.VariableDeclaration, migrated.JContextField> boxedVariables,
       this.callMethod,
       this.signatureMethod,
       this._closureEntity,
@@ -702,7 +702,7 @@
   JsClosureClassInfo.fromScopeInfo(
       this.closureClassEntity,
       ir.FunctionNode closureSourceNode,
-      Map<ir.VariableDeclaration, migrated.JRecordField> boxedVariables,
+      Map<ir.VariableDeclaration, migrated.JContextField> boxedVariables,
       KernelScopeInfo info,
       ClassEntity? enclosingClass,
       this._closureEntity,
@@ -718,9 +718,9 @@
     Iterable<ir.VariableDeclaration> localsUsedInTryOrSync =
         source.readTreeNodes<ir.VariableDeclaration>();
     Local? thisLocal = source.readLocalOrNull();
-    Map<ir.VariableDeclaration, migrated.JRecordField> boxedVariables =
-        source.readTreeNodeMap<ir.VariableDeclaration, migrated.JRecordField>(
-            () => source.readMember() as migrated.JRecordField);
+    Map<ir.VariableDeclaration, migrated.JContextField> boxedVariables =
+        source.readTreeNodeMap<ir.VariableDeclaration, migrated.JContextField>(
+            () => source.readMember() as migrated.JContextField);
     JFunction callMethod = source.readMember() as JFunction;
     JSignatureMethod? signatureMethod =
         source.readMemberOrNull() as JSignatureMethod?;
@@ -800,7 +800,7 @@
   void registerFieldForBoxedVariable(
       ir.VariableDeclaration node, JField field) {
     assert(_boxedVariablesCache == null);
-    _boxedVariables[node] = field as migrated.JRecordField;
+    _boxedVariables[node] = field as migrated.JContextField;
   }
 
   void _ensureFieldToLocalsMap(KernelToLocalsMap localsMap) {
diff --git a/pkg/compiler/lib/src/js_model/closure_migrated.dart b/pkg/compiler/lib/src/js_model/closure_migrated.dart
index 26a8c2f..2959ff3 100644
--- a/pkg/compiler/lib/src/js_model/closure_migrated.dart
+++ b/pkg/compiler/lib/src/js_model/closure_migrated.dart
@@ -19,31 +19,29 @@
 import 'element_map_migrated.dart';
 import 'elements.dart';
 import 'env.dart';
-import 'jrecord_field_interface.dart';
 
 /// A container for variables declared in a particular scope that are accessed
 /// elsewhere.
-// TODO(johnniwinther): Don't implement JClass. This isn't actually a
-// class.
-class JRecord extends JClass {
-  /// Tag used for identifying serialized [JRecord] objects in a
-  /// debugging data stream.
-  static const String tag = 'record';
+// TODO(johnniwinther): Don't implement JClass. This isn't actually a class.
+class JContext extends JClass {
+  /// Tag used for identifying serialized [JContext] objects in a debugging data
+  /// stream.
+  static const String tag = 'context';
 
-  JRecord(LibraryEntity library, String name)
+  JContext(LibraryEntity library, String name)
       : super(library as JLibrary, name, isAbstract: false);
 
-  factory JRecord.readFromDataSource(DataSourceReader source) {
+  factory JContext.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     JLibrary library = source.readLibrary() as JLibrary;
     String name = source.readString();
     source.end(tag);
-    return JRecord(library, name);
+    return JContext(library, name);
   }
 
   @override
   void writeToDataSink(DataSinkWriter sink) {
-    sink.writeEnum(JClassKind.record);
+    sink.writeEnum(JClassKind.context);
     sink.begin(tag);
     sink.writeLibrary(library);
     sink.writeString(name);
@@ -54,36 +52,36 @@
   bool get isClosure => false;
 
   @override
-  String toString() => '${jsElementPrefix}record_container($name)';
+  String toString() => '${jsElementPrefix}context($name)';
 }
 
-/// A variable that has been "boxed" to prevent name shadowing with the
-/// original variable and ensure that this variable is updated/read with the
-/// most recent value.
-class JRecordField extends JField implements JRecordFieldInterface {
-  /// Tag used for identifying serialized [JRecordField] objects in a
-  /// debugging data stream.
-  static const String tag = 'record-field';
+/// A variable that has been "boxed" to prevent name shadowing with the original
+/// variable and ensure that this variable is updated/read with the most recent
+/// value.
+class JContextField extends JField {
+  /// Tag used for identifying serialized [JContextField] objects in a debugging
+  /// data stream.
+  static const String tag = 'context-field';
 
   final BoxLocal box;
 
-  JRecordField(String name, this.box, {required bool isConst})
+  JContextField(String name, this.box, {required bool isConst})
       : super(box.container.library as JLibrary, box.container as JClass,
             Name(name, box.container.library.canonicalUri),
             isStatic: false, isAssignable: true, isConst: isConst);
 
-  factory JRecordField.readFromDataSource(DataSourceReader source) {
+  factory JContextField.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     String name = source.readString();
     final enclosingClass = source.readClass() as JClass;
     bool isConst = source.readBool();
     source.end(tag);
-    return JRecordField(name, BoxLocal(enclosingClass), isConst: isConst);
+    return JContextField(name, BoxLocal(enclosingClass), isConst: isConst);
   }
 
   @override
   void writeToDataSink(DataSinkWriter sink) {
-    sink.writeEnum(JMemberKind.recordField);
+    sink.writeEnum(JMemberKind.contextField);
     sink.begin(tag);
     sink.writeString(name);
     sink.writeClass(enclosingClass!);
@@ -227,10 +225,10 @@
   void registerFieldForBoxedVariable(ir.VariableDeclaration node, JField field);
 }
 
-class RecordClassData implements JClassData {
-  /// Tag used for identifying serialized [RecordClassData] objects in a
+class ContextClassData implements JClassData {
+  /// Tag used for identifying serialized [ContextClassData] objects in a
   /// debugging data stream.
-  static const String tag = 'record-class-data';
+  static const String tag = 'context-class-data';
 
   @override
   final ClassDefinition definition;
@@ -244,22 +242,22 @@
   @override
   final InterfaceType? supertype;
 
-  RecordClassData(
+  ContextClassData(
       this.definition, this.thisType, this.supertype, this.orderedTypeSet);
 
-  factory RecordClassData.readFromDataSource(DataSourceReader source) {
+  factory ContextClassData.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     ClassDefinition definition = ClassDefinition.readFromDataSource(source);
     InterfaceType thisType = source.readDartType() as InterfaceType;
     InterfaceType supertype = source.readDartType() as InterfaceType;
     OrderedTypeSet orderedTypeSet = OrderedTypeSet.readFromDataSource(source);
     source.end(tag);
-    return RecordClassData(definition, thisType, supertype, orderedTypeSet);
+    return ContextClassData(definition, thisType, supertype, orderedTypeSet);
   }
 
   @override
   void writeToDataSink(DataSinkWriter sink) {
-    sink.writeEnum(JClassDataKind.record);
+    sink.writeEnum(JClassDataKind.context);
     sink.begin(tag);
     definition.writeToDataSink(sink);
     sink.writeDartType(thisType!);
@@ -296,7 +294,7 @@
   List<Variance> getVariances() => [];
 }
 
-class ClosureClassData extends RecordClassData {
+class ClosureClassData extends ContextClassData {
   /// Tag used for identifying serialized [ClosureClassData] objects in a
   /// debugging data stream.
   static const String tag = 'closure-class-data';
diff --git a/pkg/compiler/lib/src/js_model/element_map.dart b/pkg/compiler/lib/src/js_model/element_map.dart
index 99d2abd..7651af7 100644
--- a/pkg/compiler/lib/src/js_model/element_map.dart
+++ b/pkg/compiler/lib/src/js_model/element_map.dart
@@ -161,10 +161,10 @@
   /// Returns the constructor body entity corresponding to [function].
   JGeneratorBody getGeneratorBody(FunctionEntity function);
 
-  /// Make a record to ensure variables that are are declared in one scope and
-  /// modified in another get their values updated correctly.
+  /// Make a mapping from closed-over variables to the context fields where they
+  /// are stored.
   @override
-  Map<ir.VariableDeclaration, JRecordField> makeRecordContainer(
+  Map<ir.VariableDeclaration, JContextField> makeContextContainer(
       KernelScopeInfo info, MemberEntity member);
 
   /// Returns a provider for static types for [member].
diff --git a/pkg/compiler/lib/src/js_model/element_map_impl.dart b/pkg/compiler/lib/src/js_model/element_map_impl.dart
index fe5706c..aaad54a 100644
--- a/pkg/compiler/lib/src/js_model/element_map_impl.dart
+++ b/pkg/compiler/lib/src/js_model/element_map_impl.dart
@@ -366,7 +366,7 @@
       if (env.cls != null) {
         classMap[env.cls!] = cls;
       }
-      if (cls is! closureMigrated.JRecord &&
+      if (cls is! closureMigrated.JContext &&
           cls is! closureMigrated.JClosureClass) {
         // Synthesized classes are not part of the library environment.
         libraries.getEnv(cls.library).registerClass(cls.name, env);
@@ -1730,13 +1730,13 @@
     _injectedClassMembers[cls]?.forEach(f);
   }
 
-  JRecordField _constructRecordFieldEntry(
+  JContextField _constructContextFieldEntry(
       InterfaceType? memberThisType,
       ir.VariableDeclaration variable,
       BoxLocal boxLocal,
       Map<Name, MemberEntity> memberMap) {
-    JRecordField boxedField =
-        JRecordField(variable.name!, boxLocal, isConst: variable.isConst);
+    JContextField boxedField =
+        JContextField(variable.name!, boxLocal, isConst: variable.isConst);
     members.register(
         boxedField,
         closureMigrated.ClosureFieldData(
@@ -1748,36 +1748,36 @@
     return boxedField;
   }
 
-  /// Make a container controlling access to records, that is, variables that
+  /// Make a container controlling access to contexts, that is, variables that
   /// are accessed in different scopes. This function creates the container
   /// and returns a map of locals to the corresponding records created.
   @override
-  Map<ir.VariableDeclaration, JRecordField> makeRecordContainer(
+  Map<ir.VariableDeclaration, JContextField> makeContextContainer(
       KernelScopeInfo info, MemberEntity member) {
-    Map<ir.VariableDeclaration, JRecordField> boxedFields = {};
+    Map<ir.VariableDeclaration, JContextField> boxedFields = {};
     if (info.boxedVariables.isNotEmpty) {
       NodeBox box = info.capturedVariablesAccessor!;
 
       Map<Name, IndexedMember> memberMap = {};
-      closureMigrated.JRecord container =
-          closureMigrated.JRecord(member.library, box.name);
+      closureMigrated.JContext container =
+          closureMigrated.JContext(member.library, box.name);
       BoxLocal boxLocal = BoxLocal(container);
       InterfaceType thisType =
           types.interfaceType(container, const <DartType>[]);
       InterfaceType supertype = commonElements.objectType;
-      JClassData containerData = closureMigrated.RecordClassData(
-          RecordContainerDefinition(getMemberDefinition(member).location),
+      JClassData containerData = closureMigrated.ContextClassData(
+          ContextContainerDefinition(getMemberDefinition(member).location),
           thisType,
           supertype,
           getOrderedTypeSet(supertype.element as IndexedClass)
               .extendClass(types, thisType));
-      classes.register(container, containerData, RecordEnv(memberMap));
+      classes.register(container, containerData, ContextEnv(memberMap));
 
       InterfaceType? memberThisType = member.enclosingClass != null
           ? elementEnvironment.getThisType(member.enclosingClass!)
           : null;
       for (ir.VariableDeclaration variable in info.boxedVariables) {
-        boxedFields[variable] = _constructRecordFieldEntry(
+        boxedFields[variable] = _constructContextFieldEntry(
             memberThisType, variable, boxLocal, memberMap);
       }
     }
@@ -1810,7 +1810,7 @@
       MemberEntity member,
       ir.FunctionNode node,
       JLibrary enclosingLibrary,
-      Map<ir.VariableDeclaration, JRecordField> recordFieldsVisibleInScope,
+      Map<ir.VariableDeclaration, JContextField> contextFieldsVisibleInScope,
       KernelScopeInfo info,
       InterfaceType supertype,
       {required bool createSignatureMethod}) {
@@ -1873,14 +1873,14 @@
     JsClosureClassInfo closureClassInfo = JsClosureClassInfo.fromScopeInfo(
         classEntity,
         node,
-        <ir.VariableDeclaration, JRecordField>{},
+        <ir.VariableDeclaration, JContextField>{},
         info,
         member.enclosingClass,
         closureEntity,
         closureEntityNode,
         info.hasThisLocal ? ThisLocal(member.enclosingClass!) : null);
     _buildClosureClassFields(closureClassInfo, member, memberThisType, info,
-        recordFieldsVisibleInScope, memberMap);
+        contextFieldsVisibleInScope, memberMap);
 
     if (createSignatureMethod) {
       _constructSignatureMethod(closureClassInfo, memberMap, node,
@@ -1908,7 +1908,7 @@
       MemberEntity member,
       InterfaceType? memberThisType,
       KernelScopeInfo info,
-      Map<ir.VariableDeclaration, JRecordField> recordFieldsVisibleInScope,
+      Map<ir.VariableDeclaration, JContextField> contextFieldsVisibleInScope,
       Map<Name, MemberEntity> memberMap) {
     // TODO(efortuna): Limit field number usage to when we need to distinguish
     // between two variables with the same name from different scopes.
@@ -1922,14 +1922,14 @@
 
     for (ir.Node variable in info.freeVariables) {
       if (variable is ir.VariableDeclaration) {
-        if (recordFieldsVisibleInScope.containsKey(variable)) {
+        if (contextFieldsVisibleInScope.containsKey(variable)) {
           bool constructedField = _constructClosureFieldForRecord(
               variable,
               closureClassInfo,
               memberThisType,
               memberMap,
               variable,
-              recordFieldsVisibleInScope,
+              contextFieldsVisibleInScope,
               fieldNumber);
           if (constructedField) fieldNumber++;
         }
@@ -1956,7 +1956,7 @@
       // Make a corresponding field entity in this closure class for the
       // free variables in the KernelScopeInfo.freeVariable.
       if (variable is ir.VariableDeclaration) {
-        if (!recordFieldsVisibleInScope.containsKey(variable)) {
+        if (!contextFieldsVisibleInScope.containsKey(variable)) {
           closureClassInfo.registerFieldForVariable(
               variable,
               _constructClosureField(
@@ -1998,11 +1998,11 @@
     }
   }
 
-  /// Records point to one or more local variables declared in another scope
+  /// Contexts point to one or more local variables declared in another scope
   /// that are captured in a scope. Access to those variables goes entirely
-  /// through the record container, so we only create a field for the *record*
+  /// through the context container, so we only create a field for the *context*
   /// holding [capturedLocal] and not the individual local variables accessed
-  /// through the record. Records, by definition, are not mutable (though the
+  /// through the context. Contexts, by definition, are not mutable (though the
   /// locals they contain may be). Returns `true` if we constructed a new field
   /// in the closure class.
   bool _constructClosureFieldForRecord(
@@ -2011,20 +2011,20 @@
       InterfaceType? memberThisType,
       Map<Name, MemberEntity> memberMap,
       ir.TreeNode sourceNode,
-      Map<ir.VariableDeclaration, JRecordField> recordFieldsVisibleInScope,
+      Map<ir.VariableDeclaration, JContextField> contextFieldsVisibleInScope,
       int fieldNumber) {
-    JRecordField recordField = recordFieldsVisibleInScope[capturedLocal]!;
+    JContextField contextField = contextFieldsVisibleInScope[capturedLocal]!;
 
     // Don't construct a new field if the box that holds this local already has
     // a field in the closure class.
-    if (closureClassInfo.hasFieldForLocal(recordField.box)) {
+    if (closureClassInfo.hasFieldForLocal(contextField.box)) {
       closureClassInfo.registerFieldForBoxedVariable(
-          capturedLocal, recordField);
+          capturedLocal, contextField);
       return false;
     }
 
     final closureField = JClosureField(
-        '_box_$fieldNumber', closureClassInfo, recordField.box.name,
+        '_box_$fieldNumber', closureClassInfo, contextField.box.name,
         isConst: true, isAssignable: false);
 
     members.register<IndexedField, JFieldData>(
@@ -2034,8 +2034,8 @@
                 MemberKind.closureField, sourceNode),
             memberThisType));
     memberMap[closureField.memberName] = closureField;
-    closureClassInfo.registerFieldForLocal(recordField.box, closureField);
-    closureClassInfo.registerFieldForBoxedVariable(capturedLocal, recordField);
+    closureClassInfo.registerFieldForLocal(contextField.box, closureField);
+    closureClassInfo.registerFieldForBoxedVariable(capturedLocal, contextField);
     return true;
   }
 
diff --git a/pkg/compiler/lib/src/js_model/element_map_interfaces.dart b/pkg/compiler/lib/src/js_model/element_map_interfaces.dart
index f7367f9..a6261bc 100644
--- a/pkg/compiler/lib/src/js_model/element_map_interfaces.dart
+++ b/pkg/compiler/lib/src/js_model/element_map_interfaces.dart
@@ -32,7 +32,7 @@
   MemberDefinition getMemberDefinition(MemberEntity member);
   ConstantValue getRequiredSentinelConstantValue();
 
-  Map<ir.VariableDeclaration, JRecordField> makeRecordContainer(
+  Map<ir.VariableDeclaration, JContextField> makeContextContainer(
       KernelScopeInfo info, MemberEntity member);
   NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node);
 }
diff --git a/pkg/compiler/lib/src/js_model/element_map_migrated.dart b/pkg/compiler/lib/src/js_model/element_map_migrated.dart
index 1794774..0f76e82 100644
--- a/pkg/compiler/lib/src/js_model/element_map_migrated.dart
+++ b/pkg/compiler/lib/src/js_model/element_map_migrated.dart
@@ -344,9 +344,9 @@
 enum ClassKind {
   regular,
   closure,
-  // TODO(efortuna, johnniwinther): Record is not a class, but is
+  // TODO(efortuna, johnniwinther): Context is not a class, but is
   // masquerading as one currently for consistency with the old element model.
-  record,
+  context,
 }
 
 /// Definition information for a [ClassEntity].
@@ -369,8 +369,8 @@
         return RegularClassDefinition.readFromDataSource(source);
       case ClassKind.closure:
         return ClosureClassDefinition.readFromDataSource(source);
-      case ClassKind.record:
-        return RecordContainerDefinition.readFromDataSource(source);
+      case ClassKind.context:
+        return ContextContainerDefinition.readFromDataSource(source);
     }
   }
 
@@ -451,40 +451,40 @@
   String toString() => 'ClosureClassDefinition(kind:$kind,location:$location)';
 }
 
-class RecordContainerDefinition implements ClassDefinition {
-  /// Tag used for identifying serialized [RecordContainerDefinition] objects in
+class ContextContainerDefinition implements ClassDefinition {
+  /// Tag used for identifying serialized [ContextContainerDefinition] objects in
   /// a debugging data stream.
-  static const String tag = 'record-definition';
+  static const String tag = 'context-definition';
 
   @override
   final SourceSpan location;
 
-  RecordContainerDefinition(this.location);
+  ContextContainerDefinition(this.location);
 
-  factory RecordContainerDefinition.readFromDataSource(
+  factory ContextContainerDefinition.readFromDataSource(
       DataSourceReader source) {
     source.begin(tag);
     SourceSpan location = source.readSourceSpan();
     source.end(tag);
-    return RecordContainerDefinition(location);
+    return ContextContainerDefinition(location);
   }
 
   @override
   void writeToDataSink(DataSinkWriter sink) {
-    sink.writeEnum(ClassKind.record);
+    sink.writeEnum(ClassKind.context);
     sink.begin(tag);
     sink.writeSourceSpan(location);
     sink.end(tag);
   }
 
   @override
-  ClassKind get kind => ClassKind.record;
+  ClassKind get kind => ClassKind.context;
 
   @override
   ir.Node get node =>
-      throw UnsupportedError('RecordContainerDefinition.node for $location');
+      throw UnsupportedError('ContextContainerDefinition.node for $location');
 
   @override
   String toString() =>
-      'RecordContainerDefinition(kind:$kind,location:$location)';
+      'ContextContainerDefinition(kind:$kind,location:$location)';
 }
diff --git a/pkg/compiler/lib/src/js_model/elements.dart b/pkg/compiler/lib/src/js_model/elements.dart
index 44ec959..e60daa6 100644
--- a/pkg/compiler/lib/src/js_model/elements.dart
+++ b/pkg/compiler/lib/src/js_model/elements.dart
@@ -53,7 +53,7 @@
 }
 
 /// Enum used for identifying [JClass] subclasses in serialization.
-enum JClassKind { node, closure, record }
+enum JClassKind { node, closure, context }
 
 class JClass extends IndexedClass with ClassHierarchyNodesMapKey {
   /// Tag used for identifying serialized [JClass] objects in a
@@ -83,8 +83,8 @@
         return JClass(library, name, isAbstract: isAbstract);
       case JClassKind.closure:
         return JClosureClass.readFromDataSource(source);
-      case JClassKind.record:
-        return JRecord.readFromDataSource(source);
+      case JClassKind.context:
+        return JContext.readFromDataSource(source);
     }
   }
 
@@ -118,7 +118,7 @@
   closureCallMethod,
   generatorBody,
   signatureMethod,
-  recordField,
+  contextField,
 }
 
 abstract class JMember extends IndexedMember {
@@ -159,8 +159,8 @@
         return JGeneratorBody.readFromDataSource(source);
       case JMemberKind.signatureMethod:
         return JSignatureMethod.readFromDataSource(source);
-      case JMemberKind.recordField:
-        return JRecordField.readFromDataSource(source);
+      case JMemberKind.contextField:
+        return JContextField.readFromDataSource(source);
     }
   }
 
diff --git a/pkg/compiler/lib/src/js_model/env.dart b/pkg/compiler/lib/src/js_model/env.dart
index 5e712fa..78281c4 100644
--- a/pkg/compiler/lib/src/js_model/env.dart
+++ b/pkg/compiler/lib/src/js_model/env.dart
@@ -21,7 +21,7 @@
 import 'closure_migrated.dart'
     show
         ClosureClassData,
-        RecordClassData,
+        ContextClassData,
         ClosureFunctionData,
         ClosureFieldData;
 import 'element_map_interfaces.dart' show JsToElementMap, JsKernelToElementMap;
@@ -178,7 +178,7 @@
 }
 
 /// Enum used for identifying [JClassEnv] subclasses in serialization.
-enum JClassEnvKind { node, closure, record }
+enum JClassEnvKind { node, closure, context }
 
 /// Member data for a class.
 abstract class JClassEnv {
@@ -190,8 +190,8 @@
         return JClassEnvImpl.readFromDataSource(source);
       case JClassEnvKind.closure:
         return ClosureClassEnv.readFromDataSource(source);
-      case JClassEnvKind.record:
-        return RecordEnv.readFromDataSource(source);
+      case JClassEnvKind.context:
+        return ContextEnv.readFromDataSource(source);
     }
   }
 
@@ -315,26 +315,26 @@
   }
 }
 
-class RecordEnv implements JClassEnv {
-  /// Tag used for identifying serialized [RecordEnv] objects in a
-  /// debugging data stream.
-  static const String tag = 'record-env';
+class ContextEnv implements JClassEnv {
+  /// Tag used for identifying serialized [ContextEnv] objects in a debugging
+  /// data stream.
+  static const String tag = 'context-env';
 
   final Map<Name, IndexedMember> _memberMap;
 
-  RecordEnv(this._memberMap);
+  ContextEnv(this._memberMap);
 
-  factory RecordEnv.readFromDataSource(DataSourceReader source) {
+  factory ContextEnv.readFromDataSource(DataSourceReader source) {
     source.begin(tag);
     Map<Name, IndexedMember> _memberMap =
         source.readNameMap(() => source.readMember() as IndexedMember)!;
     source.end(tag);
-    return RecordEnv(_memberMap);
+    return ContextEnv(_memberMap);
   }
 
   @override
   void writeToDataSink(DataSinkWriter sink) {
-    sink.writeEnum(JClassEnvKind.record);
+    sink.writeEnum(JClassEnvKind.context);
     sink.begin(tag);
     sink.writeNameMap(
         _memberMap, (IndexedMember member) => sink.writeMember(member));
@@ -378,7 +378,7 @@
   ir.Class? get cls => null;
 }
 
-class ClosureClassEnv extends RecordEnv {
+class ClosureClassEnv extends ContextEnv {
   /// Tag used for identifying serialized [ClosureClassEnv] objects in a
   /// debugging data stream.
   static const String tag = 'closure-class-env';
@@ -404,7 +404,7 @@
 }
 
 /// Enum used for identifying [JClassData] subclasses in serialization.
-enum JClassDataKind { node, closure, record }
+enum JClassDataKind { node, closure, context }
 
 abstract class JClassData {
   /// Deserializes a [JClassData] object from [source].
@@ -415,8 +415,8 @@
         return JClassDataImpl.readFromDataSource(source);
       case JClassDataKind.closure:
         return ClosureClassData.readFromDataSource(source);
-      case JClassDataKind.record:
-        return RecordClassData.readFromDataSource(source);
+      case JClassDataKind.context:
+        return ContextClassData.readFromDataSource(source);
     }
   }
 
diff --git a/pkg/compiler/lib/src/js_model/jrecord_field_interface.dart b/pkg/compiler/lib/src/js_model/jrecord_field_interface.dart
deleted file mode 100644
index 17f3bd0..0000000
--- a/pkg/compiler/lib/src/js_model/jrecord_field_interface.dart
+++ /dev/null
@@ -1,6 +0,0 @@
-// 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.
-
-// TODO(48820): delete this class once migration is complete.
-abstract class JRecordFieldInterface {}
diff --git a/pkg/compiler/lib/src/js_model/js_world_builder.dart b/pkg/compiler/lib/src/js_model/js_world_builder.dart
index 612444e..c22ccfc 100644
--- a/pkg/compiler/lib/src/js_model/js_world_builder.dart
+++ b/pkg/compiler/lib/src/js_model/js_world_builder.dart
@@ -321,7 +321,7 @@
       MemberEntity member,
       ir.FunctionNode originalClosureFunctionNode,
       JLibrary enclosingLibrary,
-      Map<ir.VariableDeclaration, JRecordField> boxedVariables,
+      Map<ir.VariableDeclaration, JContextField> boxedVariables,
       KernelScopeInfo info,
       {bool createSignatureMethod}) {
     ClassEntity superclass =
diff --git a/pkg/compiler/lib/src/js_model/js_world_builder_interfaces.dart b/pkg/compiler/lib/src/js_model/js_world_builder_interfaces.dart
index 52b8965..b20aa18 100644
--- a/pkg/compiler/lib/src/js_model/js_world_builder_interfaces.dart
+++ b/pkg/compiler/lib/src/js_model/js_world_builder_interfaces.dart
@@ -14,7 +14,7 @@
       MemberEntity member,
       ir.FunctionNode originalClosureFunctionNode,
       JLibrary enclosingLibrary,
-      Map<ir.VariableDeclaration, JRecordField> boxedVariables,
+      Map<ir.VariableDeclaration, JContextField> boxedVariables,
       KernelScopeInfo info,
       {required bool createSignatureMethod});
 }
diff --git a/pkg/compiler/lib/src/ssa/locals_handler.dart b/pkg/compiler/lib/src/ssa/locals_handler.dart
index ca2fe43..7017849 100644
--- a/pkg/compiler/lib/src/ssa/locals_handler.dart
+++ b/pkg/compiler/lib/src/ssa/locals_handler.dart
@@ -15,7 +15,7 @@
 import '../io/source_information.dart';
 import '../js_backend/native_data.dart';
 import '../js_backend/interceptor_data.dart';
-import '../js_model/closure.dart' show JRecordField, JClosureField;
+import '../js_model/closure.dart' show JContextField, JClosureField;
 import '../js_model/locals.dart' show GlobalLocalsMap, JLocal;
 import '../world_interfaces.dart' show JClosedWorld;
 
@@ -384,7 +384,7 @@
       // accessed through a closure-field.
       // Calling [readLocal] makes sure we generate the correct code to get
       // the box.
-      if (redirect is JRecordField) {
+      if (redirect is JContextField) {
         localBox = redirect.box;
       }
       assert(localBox != null);
@@ -452,7 +452,7 @@
       FieldEntity redirect = redirectionMapping[local];
       assert(redirect != null);
       BoxLocal localBox;
-      if (redirect is JRecordField) {
+      if (redirect is JContextField) {
         localBox = redirect.box;
       }
       assert(localBox != null);
diff --git a/pkg/compiler/lib/src/universe/member_usage.dart b/pkg/compiler/lib/src/universe/member_usage.dart
index d9321e7..48b022d 100644
--- a/pkg/compiler/lib/src/universe/member_usage.dart
+++ b/pkg/compiler/lib/src/universe/member_usage.dart
@@ -7,7 +7,7 @@
 import '../common.dart';
 import '../constants/values.dart';
 import '../elements/entities.dart';
-import '../js_model/jrecord_field_interface.dart' show JRecordFieldInterface;
+import '../js_model/closure_migrated.dart' show JContextField;
 import '../serialization/serialization.dart';
 import '../util/enumset.dart';
 import 'call_structure.dart';
@@ -64,7 +64,7 @@
       } else if (member.isInstanceMember) {
         return EnumSet.fromValues(Access.values);
       } else {
-        assert(member is JRecordFieldInterface, "Unexpected member: $member");
+        assert(member is JContextField, "Unexpected member: $member");
         return EnumSet();
       }
     }
diff --git a/pkg/compiler/lib/src/universe/use.dart b/pkg/compiler/lib/src/universe/use.dart
index 0bda473..3d62eaf 100644
--- a/pkg/compiler/lib/src/universe/use.dart
+++ b/pkg/compiler/lib/src/universe/use.dart
@@ -22,7 +22,7 @@
 import '../elements/entities.dart';
 import '../inferrer/abstract_value_domain.dart';
 import '../serialization/serialization.dart';
-import '../js_model/jrecord_field_interface.dart' show JRecordFieldInterface;
+import '../js_model/closure_migrated.dart' show JContextField;
 import '../util/util.dart' show equalElements, Hashing;
 import 'call_structure.dart' show CallStructure;
 import 'selector.dart' show Selector;
@@ -622,7 +622,7 @@
   /// Read access of an instance field or boxed field [element].
   factory StaticUse.fieldGet(FieldEntity element) {
     assert(
-        element.isInstanceMember || element is JRecordFieldInterface,
+        element.isInstanceMember || element is JContextField,
         failedAt(element,
             "Field init element $element must be an instance or boxed field."));
     return StaticUse.internal(element, StaticUseKind.INSTANCE_FIELD_GET);
@@ -631,7 +631,7 @@
   /// Write access of an instance field or boxed field [element].
   factory StaticUse.fieldSet(FieldEntity element) {
     assert(
-        element.isInstanceMember || element is JRecordFieldInterface,
+        element.isInstanceMember || element is JContextField,
         failedAt(element,
             "Field init element $element must be an instance or boxed field."));
     return StaticUse.internal(element, StaticUseKind.INSTANCE_FIELD_SET);
diff --git a/pkg/dart2wasm/lib/constants.dart b/pkg/dart2wasm/lib/constants.dart
index a2f327e..4ba4963 100644
--- a/pkg/dart2wasm/lib/constants.dart
+++ b/pkg/dart2wasm/lib/constants.dart
@@ -780,7 +780,7 @@
 
   @override
   ConstantInfo? visitTypeLiteralConstant(TypeLiteralConstant constant) {
-    DartType type = constant.type;
+    DartType type = types.normalize(constant.type);
 
     ClassInfo info = translator.classInfo[types.classForType(type)]!;
     translator.functions.allocateClass(info.classId);
diff --git a/pkg/dart2wasm/lib/types.dart b/pkg/dart2wasm/lib/types.dart
index 20da36b..3eb2fed 100644
--- a/pkg/dart2wasm/lib/types.dart
+++ b/pkg/dart2wasm/lib/types.dart
@@ -114,7 +114,9 @@
       for (InterfaceType subtype in subtypes) {
         interfaceTypeEnvironment._add(subtype);
         List<DartType>? typeArguments = translator.hierarchy
-            .getTypeArgumentsAsInstanceOf(subtype, superclass);
+            .getTypeArgumentsAsInstanceOf(subtype, superclass)
+            ?.map(normalize)
+            .toList();
         ClassInfo subclassInfo = translator.classInfo[subtype.classNode]!;
         Map<int, List<DartType>> substitutionMap =
             subtypeMap[subclassInfo.classId] ??= {};
@@ -311,6 +313,57 @@
     _makeTypeList(codeGen, type.typeArguments);
   }
 
+  DartType normalizeFutureOrType(FutureOrType type) {
+    final s = normalize(type.typeArgument);
+
+    // `coreTypes.isTope` and `coreTypes.isObject` take into account the
+    // normalization rules of `futureOr`.
+    if (coreTypes.isTop(type) || coreTypes.isObject(type)) {
+      return s;
+    } else if (s is NeverType) {
+      return InterfaceType(coreTypes.futureClass, Nullability.nonNullable,
+          const [const NeverType.nonNullable()]);
+    } else if (s is NullType) {
+      return InterfaceType(coreTypes.futureClass, Nullability.nullable,
+          const [const NullType()]);
+    }
+
+    // The type is normalized, and remains a `FutureOr` so now we normalize its
+    // nullability.
+    final declaredNullability = s.nullability == Nullability.nullable
+        ? Nullability.nonNullable
+        : type.declaredNullability;
+    return FutureOrType(s, declaredNullability);
+  }
+
+  /// Normalizes a Dart type. Many rules are already applied for us, but some we
+  /// have to apply manually, particularly to [FutureOr].
+  DartType normalize(DartType type) {
+    if (type is InterfaceType) {
+      return InterfaceType(type.classNode, type.nullability,
+          type.typeArguments.map(normalize).toList());
+    } else if (type is FunctionType) {
+      return FunctionType(type.positionalParameters.map(normalize).toList(),
+          normalize(type.returnType), type.nullability,
+          namedParameters: type.namedParameters
+              .map((namedType) => NamedType(
+                  namedType.name, normalize(namedType.type),
+                  isRequired: namedType.isRequired))
+              .toList(),
+          typeParameters: type.typeParameters
+              .map((typeParameter) => TypeParameter(
+                  typeParameter.name,
+                  normalize(typeParameter.bound),
+                  normalize(typeParameter.defaultType)))
+              .toList(),
+          requiredParameterCount: type.requiredParameterCount);
+    } else if (type is FutureOrType) {
+      return normalizeFutureOrType(type);
+    } else {
+      return type;
+    }
+  }
+
   void _makeFutureOrType(CodeGenerator codeGen, FutureOrType type) {
     w.Instructions b = codeGen.b;
     w.DefinedFunction function = codeGen.function;
@@ -382,6 +435,8 @@
   /// TODO(joshualitt): Refactor this logic to remove the dependency on
   /// CodeGenerator.
   w.ValueType makeType(CodeGenerator codeGen, DartType type) {
+    // Always ensure type is normalized before making a type.
+    type = normalize(type);
     w.Instructions b = codeGen.b;
     if (_isTypeConstant(type)) {
       translator.constants.instantiateConstant(
diff --git a/runtime/vm/app_snapshot.cc b/runtime/vm/app_snapshot.cc
index 9a80a2a..7b3726e 100644
--- a/runtime/vm/app_snapshot.cc
+++ b/runtime/vm/app_snapshot.cc
@@ -4124,7 +4124,7 @@
     }
 #endif
     WriteFromTo(type);
-    s->WriteUnsigned(type->untag()->flags_);
+    s->WriteUnsigned(type->untag()->flags());
   }
 };
 #endif  // !DART_PRECOMPILED_RUNTIME
@@ -4153,7 +4153,7 @@
       Deserializer::InitializeHeader(type, kTypeCid, Type::InstanceSize(),
                                      mark_canonical);
       d.ReadFromTo(type);
-      type->untag()->flags_ = d.ReadUnsigned();
+      type->untag()->set_flags(d.ReadUnsigned());
     }
   }
 
@@ -4235,8 +4235,8 @@
   void WriteFunctionType(Serializer* s, FunctionTypePtr type) {
     AutoTraceObject(type);
     WriteFromTo(type);
-    ASSERT(Utils::IsUint(8, type->untag()->flags_));
-    s->Write<uint8_t>(type->untag()->flags_);
+    ASSERT(Utils::IsUint(8, type->untag()->flags()));
+    s->Write<uint8_t>(type->untag()->flags());
     s->Write<uint32_t>(type->untag()->packed_parameter_counts_);
     s->Write<uint16_t>(type->untag()->packed_type_parameter_counts_);
   }
@@ -4267,7 +4267,7 @@
       Deserializer::InitializeHeader(
           type, kFunctionTypeCid, FunctionType::InstanceSize(), mark_canonical);
       d.ReadFromTo(type);
-      type->untag()->flags_ = d.Read<uint8_t>();
+      type->untag()->set_flags(d.Read<uint8_t>());
       type->untag()->packed_parameter_counts_ = d.Read<uint32_t>();
       type->untag()->packed_type_parameter_counts_ = d.Read<uint16_t>();
     }
@@ -4351,8 +4351,8 @@
   void WriteRecordType(Serializer* s, RecordTypePtr type) {
     AutoTraceObject(type);
     WriteFromTo(type);
-    ASSERT(Utils::IsUint(8, type->untag()->flags_));
-    s->Write<uint8_t>(type->untag()->flags_);
+    ASSERT(Utils::IsUint(8, type->untag()->flags()));
+    s->Write<uint8_t>(type->untag()->flags());
   }
 };
 #endif  // !DART_PRECOMPILED_RUNTIME
@@ -4380,7 +4380,7 @@
       Deserializer::InitializeHeader(
           type, kRecordTypeCid, RecordType::InstanceSize(), mark_canonical);
       d.ReadFromTo(type);
-      type->untag()->flags_ = d.Read<uint8_t>();
+      type->untag()->set_flags(d.Read<uint8_t>());
     }
   }
 
@@ -4556,8 +4556,8 @@
     s->Write<int32_t>(type->untag()->parameterized_class_id_);
     s->Write<uint8_t>(type->untag()->base_);
     s->Write<uint8_t>(type->untag()->index_);
-    ASSERT(Utils::IsUint(8, type->untag()->flags_));
-    s->Write<uint8_t>(type->untag()->flags_);
+    ASSERT(Utils::IsUint(8, type->untag()->flags()));
+    s->Write<uint8_t>(type->untag()->flags());
   }
 };
 #endif  // !DART_PRECOMPILED_RUNTIME
@@ -4590,7 +4590,7 @@
       type->untag()->parameterized_class_id_ = d.Read<int32_t>();
       type->untag()->base_ = d.Read<uint8_t>();
       type->untag()->index_ = d.Read<uint8_t>();
-      type->untag()->flags_ = d.Read<uint8_t>();
+      type->untag()->set_flags(d.Read<uint8_t>());
     }
   }
 
diff --git a/runtime/vm/compiler/assembler/assembler_arm.cc b/runtime/vm/compiler/assembler/assembler_arm.cc
index db372c1..7587b27 100644
--- a/runtime/vm/compiler/assembler/assembler_arm.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm.cc
@@ -1704,38 +1704,6 @@
   }
 }
 
-// Preserves object and value registers.
-void Assembler::StoreIntoObjectFilter(Register object,
-                                      Register value,
-                                      Label* label,
-                                      CanBeSmi value_can_be_smi,
-                                      BarrierFilterMode how_to_jump) {
-  COMPILE_ASSERT((target::ObjectAlignment::kNewObjectAlignmentOffset ==
-                  target::kWordSize) &&
-                 (target::ObjectAlignment::kOldObjectAlignmentOffset == 0));
-  // For the value we are only interested in the new/old bit and the tag bit.
-  // And the new bit with the tag bit. The resulting bit will be 0 for a Smi.
-  if (value_can_be_smi == kValueCanBeSmi) {
-    and_(
-        IP, value,
-        Operand(value, LSL, target::ObjectAlignment::kObjectAlignmentLog2 - 1));
-    // And the result with the negated space bit of the object.
-    bic(IP, IP, Operand(object));
-  } else {
-#if defined(DEBUG)
-    Label okay;
-    BranchIfNotSmi(value, &okay);
-    Stop("Unexpected Smi!");
-    Bind(&okay);
-#endif
-    bic(IP, value, Operand(object));
-  }
-  tst(IP, Operand(target::ObjectAlignment::kNewObjectAlignmentOffset));
-  if (how_to_jump != kNoJump) {
-    b(label, how_to_jump == kJumpToNoUpdate ? EQ : NE);
-  }
-}
-
 Register UseRegister(Register reg, RegList* used) {
   ASSERT(reg != THR);
   ASSERT(reg != SP);
@@ -1782,7 +1750,7 @@
   // Compare UntaggedObject::StorePointer.
   Label done;
   if (can_be_smi == kValueCanBeSmi) {
-    BranchIfSmi(value, &done);
+    BranchIfSmi(value, &done, kNearJump);
   }
   const bool preserve_lr = lr_state().LRContainsReturnAddress();
   if (preserve_lr) {
@@ -1853,7 +1821,7 @@
   // Compare UntaggedObject::StorePointer.
   Label done;
   if (can_be_smi == kValueCanBeSmi) {
-    BranchIfSmi(value, &done);
+    BranchIfSmi(value, &done, kNearJump);
   }
   const bool preserve_lr = lr_state().LRContainsReturnAddress();
   if (preserve_lr) {
@@ -1915,13 +1883,14 @@
   // reachable via a constant pool, so it doesn't matter if it is not traced via
   // 'object'.
   Label done;
-  StoreIntoObjectFilter(object, value, &done, kValueCanBeSmi, kJumpToNoUpdate);
-
+  BranchIfSmi(value, &done, kNearJump);
+  ldrb(TMP, FieldAddress(value, target::Object::tags_offset()));
+  tst(TMP, Operand(1 << target::UntaggedObject::kNewBit));
+  b(&done, ZERO);
   ldrb(TMP, FieldAddress(object, target::Object::tags_offset()));
   tst(TMP, Operand(1 << target::UntaggedObject::kOldAndNotRememberedBit));
   b(&done, ZERO);
-
-  Stop("Store buffer update is required");
+  Stop("Write barrier is required");
   Bind(&done);
 #endif  // defined(DEBUG)
   // No store buffer update.
@@ -1998,16 +1967,6 @@
   strd(value_even, value_odd, begin, -2 * target::kWordSize, LS);
   b(&init_loop, CC);
   str(value_even, Address(begin, -2 * target::kWordSize), HI);
-#if defined(DEBUG)
-  Label done;
-  StoreIntoObjectFilter(object, value_even, &done, kValueCanBeSmi,
-                        kJumpToNoUpdate);
-  StoreIntoObjectFilter(object, value_odd, &done, kValueCanBeSmi,
-                        kJumpToNoUpdate);
-  Stop("Store buffer update is required");
-  Bind(&done);
-#endif  // defined(DEBUG)
-  // No store buffer update.
 }
 
 void Assembler::InitializeFieldsNoBarrierUnrolled(Register object,
@@ -2026,16 +1985,6 @@
     str(value_even, Address(base, current_offset));
     current_offset += target::kWordSize;
   }
-#if defined(DEBUG)
-  Label done;
-  StoreIntoObjectFilter(object, value_even, &done, kValueCanBeSmi,
-                        kJumpToNoUpdate);
-  StoreIntoObjectFilter(object, value_odd, &done, kValueCanBeSmi,
-                        kJumpToNoUpdate);
-  Stop("Store buffer update is required");
-  Bind(&done);
-#endif  // defined(DEBUG)
-  // No store buffer update.
 }
 
 void Assembler::StoreIntoSmiField(const Address& dest, Register value) {
diff --git a/runtime/vm/compiler/assembler/assembler_arm.h b/runtime/vm/compiler/assembler/assembler_arm.h
index a8d45d3..25d2c63 100644
--- a/runtime/vm/compiler/assembler/assembler_arm.h
+++ b/runtime/vm/compiler/assembler/assembler_arm.h
@@ -1645,27 +1645,6 @@
   int32_t EncodeTstOffset(int32_t offset, int32_t inst);
   int32_t DecodeTstOffset(int32_t inst);
 
-  enum BarrierFilterMode {
-    // Filter falls through into the barrier update code. Target label
-    // is a "after-store" label.
-    kJumpToNoUpdate,
-
-    // Filter falls through to the "after-store" code. Target label
-    // is barrier update code label.
-    kJumpToBarrier,
-
-    // Filter falls through into the conditional barrier update code and does
-    // not jump. Target label is unused. The barrier should run if the NE
-    // condition is set.
-    kNoJump
-  };
-
-  void StoreIntoObjectFilter(Register object,
-                             Register value,
-                             Label* label,
-                             CanBeSmi can_be_smi,
-                             BarrierFilterMode barrier_filter_mode);
-
   friend class dart::FlowGraphCompiler;
   std::function<void(Condition, Register)>
       generate_invoke_write_barrier_wrapper_;
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.cc b/runtime/vm/compiler/assembler/assembler_arm64.cc
index 61117e1..e7956e4 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm64.cc
@@ -994,43 +994,6 @@
 #endif
 }
 
-// Preserves object and value registers.
-void Assembler::StoreIntoObjectFilter(Register object,
-                                      Register value,
-                                      Label* label,
-                                      CanBeSmi value_can_be_smi,
-                                      BarrierFilterMode how_to_jump) {
-  COMPILE_ASSERT((target::ObjectAlignment::kNewObjectAlignmentOffset ==
-                  target::kWordSize) &&
-                 (target::ObjectAlignment::kOldObjectAlignmentOffset == 0));
-
-  // Write-barrier triggers if the value is in the new space (has bit set) and
-  // the object is in the old space (has bit cleared).
-  if (value_can_be_smi == kValueIsNotSmi) {
-#if defined(DEBUG)
-    Label okay;
-    BranchIfNotSmi(value, &okay);
-    Stop("Unexpected Smi!");
-    Bind(&okay);
-#endif
-    // To check that, we compute value & ~object and skip the write barrier
-    // if the bit is not set. We can't destroy the object.
-    bic(TMP, value, Operand(object));
-  } else {
-    // For the value we are only interested in the new/old bit and the tag bit.
-    // And the new bit with the tag bit. The resulting bit will be 0 for a Smi.
-    and_(TMP, value,
-         Operand(value, LSL, target::ObjectAlignment::kNewObjectBitPosition));
-    // And the result with the negated space bit of the object.
-    bic(TMP, TMP, Operand(object));
-  }
-  if (how_to_jump == kJumpToNoUpdate) {
-    tbz(label, TMP, target::ObjectAlignment::kNewObjectBitPosition);
-  } else {
-    tbnz(label, TMP, target::ObjectAlignment::kNewObjectBitPosition);
-  }
-}
-
 void Assembler::StoreIntoObjectOffset(Register object,
                                       int32_t offset,
                                       Register value,
@@ -1220,13 +1183,12 @@
   // reachable via a constant pool, so it doesn't matter if it is not traced via
   // 'object'.
   Label done;
-  StoreIntoObjectFilter(object, value, &done, kValueCanBeSmi, kJumpToNoUpdate);
-
+  BranchIfSmi(value, &done, kNearJump);
+  ldr(TMP, FieldAddress(value, target::Object::tags_offset()), kUnsignedByte);
+  tbz(&done, TMP, target::UntaggedObject::kNewBit);
   ldr(TMP, FieldAddress(object, target::Object::tags_offset()), kUnsignedByte);
-  tsti(TMP, Immediate(1 << target::UntaggedObject::kOldAndNotRememberedBit));
-  b(&done, ZERO);
-
-  Stop("Store buffer update is required");
+  tbz(&done, TMP, target::UntaggedObject::kOldAndNotRememberedBit);
+  Stop("Write barrier is required");
   Bind(&done);
 #endif  // defined(DEBUG)
   // No store buffer update.
@@ -1246,13 +1208,12 @@
   // reachable via a constant pool, so it doesn't matter if it is not traced via
   // 'object'.
   Label done;
-  StoreIntoObjectFilter(object, value, &done, kValueCanBeSmi, kJumpToNoUpdate);
-
+  BranchIfSmi(value, &done, kNearJump);
+  ldr(TMP, FieldAddress(value, target::Object::tags_offset()), kUnsignedByte);
+  tbz(&done, TMP, target::UntaggedObject::kNewBit);
   ldr(TMP, FieldAddress(object, target::Object::tags_offset()), kUnsignedByte);
-  tsti(TMP, Immediate(1 << target::UntaggedObject::kOldAndNotRememberedBit));
-  b(&done, ZERO);
-
-  Stop("Store buffer update is required");
+  tbz(&done, TMP, target::UntaggedObject::kOldAndNotRememberedBit);
+  Stop("Write barrier is required");
   Bind(&done);
 #endif  // defined(DEBUG)
   // No store buffer update.
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.h b/runtime/vm/compiler/assembler/assembler_arm64.h
index 58d8a84..a06a0a9 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.h
+++ b/runtime/vm/compiler/assembler/assembler_arm64.h
@@ -2982,22 +2982,6 @@
     Emit(encoding);
   }
 
-  enum BarrierFilterMode {
-    // Filter falls through into the barrier update code. Target label
-    // is a "after-store" label.
-    kJumpToNoUpdate,
-
-    // Filter falls through to the "after-store" code. Target label
-    // is barrier update code label.
-    kJumpToBarrier,
-  };
-
-  void StoreIntoObjectFilter(Register object,
-                             Register value,
-                             Label* label,
-                             CanBeSmi can_be_smi,
-                             BarrierFilterMode barrier_filter_mode);
-
   friend class dart::FlowGraphCompiler;
   std::function<void(Register reg)> generate_invoke_write_barrier_wrapper_;
   std::function<void()> generate_invoke_array_write_barrier_;
diff --git a/runtime/vm/compiler/assembler/assembler_ia32.cc b/runtime/vm/compiler/assembler/assembler_ia32.cc
index 6ef1b78..d25fd16 100644
--- a/runtime/vm/compiler/assembler/assembler_ia32.cc
+++ b/runtime/vm/compiler/assembler/assembler_ia32.cc
@@ -2086,16 +2086,15 @@
   // reachable via a constant pool, so it doesn't matter if it is not traced via
   // 'object'.
   Label done;
-  pushl(value);
-  StoreIntoObjectFilter(object, value, &done, kValueCanBeSmi, kJumpToNoUpdate);
-
+  BranchIfSmi(value, &done, kNearJump);
+  testb(FieldAddress(value, target::Object::tags_offset()),
+        Immediate(1 << target::UntaggedObject::kNewBit));
+  j(ZERO, &done, Assembler::kNearJump);
   testb(FieldAddress(object, target::Object::tags_offset()),
         Immediate(1 << target::UntaggedObject::kOldAndNotRememberedBit));
   j(ZERO, &done, Assembler::kNearJump);
-
-  Stop("Store buffer update is required");
+  Stop("Write barrier is required");
   Bind(&done);
-  popl(value);
 #endif  // defined(DEBUG)
   // No store buffer update.
 }
diff --git a/runtime/vm/compiler/assembler/assembler_riscv.cc b/runtime/vm/compiler/assembler/assembler_riscv.cc
index ea90057..f7d20b5 100644
--- a/runtime/vm/compiler/assembler/assembler_riscv.cc
+++ b/runtime/vm/compiler/assembler/assembler_riscv.cc
@@ -3144,15 +3144,14 @@
   // reachable via a constant pool, so it doesn't matter if it is not traced via
   // 'object'.
   Label done;
-  beq(object, value, &done, kNearJump);
   BranchIfSmi(value, &done, kNearJump);
-  lbu(TMP, FieldAddress(object, target::Object::tags_offset()));
   lbu(TMP2, FieldAddress(value, target::Object::tags_offset()));
-  srli(TMP, TMP, target::UntaggedObject::kBarrierOverlapShift);
-  and_(TMP, TMP, TMP2);
-  andi(TMP, TMP, target::UntaggedObject::kGenerationalBarrierMask);
-  beqz(TMP, &done, kNearJump);
-  Stop("Store buffer update is required");
+  andi(TMP2, TMP2, 1 << target::UntaggedObject::kNewBit);
+  beqz(TMP2, &done, kNearJump);
+  lbu(TMP2, FieldAddress(object, target::Object::tags_offset()));
+  andi(TMP2, TMP2, 1 << target::UntaggedObject::kOldAndNotRememberedBit);
+  beqz(TMP2, &done, kNearJump);
+  Stop("Write barrier is required");
   Bind(&done);
 #endif
 }
@@ -3178,15 +3177,14 @@
   // reachable via a constant pool, so it doesn't matter if it is not traced via
   // 'object'.
   Label done;
-  beq(object, value, &done, kNearJump);
   BranchIfSmi(value, &done, kNearJump);
-  lbu(TMP, FieldAddress(object, target::Object::tags_offset()));
   lbu(TMP2, FieldAddress(value, target::Object::tags_offset()));
-  srli(TMP, TMP, target::UntaggedObject::kBarrierOverlapShift);
-  and_(TMP, TMP, TMP2);
-  andi(TMP, TMP, target::UntaggedObject::kGenerationalBarrierMask);
-  beqz(TMP, &done, kNearJump);
-  Stop("Store buffer update is required");
+  andi(TMP2, TMP2, 1 << target::UntaggedObject::kNewBit);
+  beqz(TMP2, &done, kNearJump);
+  lbu(TMP2, FieldAddress(object, target::Object::tags_offset()));
+  andi(TMP2, TMP2, 1 << target::UntaggedObject::kOldAndNotRememberedBit);
+  beqz(TMP2, &done, kNearJump);
+  Stop("Write barrier is required");
   Bind(&done);
 #endif
 }
diff --git a/runtime/vm/compiler/assembler/assembler_riscv.h b/runtime/vm/compiler/assembler/assembler_riscv.h
index 598fe65..64a11f4 100644
--- a/runtime/vm/compiler/assembler/assembler_riscv.h
+++ b/runtime/vm/compiler/assembler/assembler_riscv.h
@@ -1478,22 +1478,6 @@
   // Note: the function never clobbers TMP, TMP2 scratch registers.
   void LoadObjectHelper(Register dst, const Object& obj, bool is_unique);
 
-  enum BarrierFilterMode {
-    // Filter falls through into the barrier update code. Target label
-    // is a "after-store" label.
-    kJumpToNoUpdate,
-
-    // Filter falls through to the "after-store" code. Target label
-    // is barrier update code label.
-    kJumpToBarrier,
-  };
-
-  void StoreIntoObjectFilter(Register object,
-                             Register value,
-                             Label* label,
-                             CanBeSmi can_be_smi,
-                             BarrierFilterMode barrier_filter_mode);
-
   friend class dart::FlowGraphCompiler;
   std::function<void(Register reg)> generate_invoke_write_barrier_wrapper_;
   std::function<void()> generate_invoke_array_write_barrier_;
diff --git a/runtime/vm/compiler/assembler/assembler_x64.cc b/runtime/vm/compiler/assembler/assembler_x64.cc
index 199b126..f98805b 100644
--- a/runtime/vm/compiler/assembler/assembler_x64.cc
+++ b/runtime/vm/compiler/assembler/assembler_x64.cc
@@ -1434,44 +1434,6 @@
 #endif
 }
 
-// Destroys the value register.
-void Assembler::StoreIntoObjectFilter(Register object,
-                                      Register value,
-                                      Label* label,
-                                      CanBeSmi can_be_smi,
-                                      BarrierFilterMode how_to_jump) {
-  COMPILE_ASSERT((target::ObjectAlignment::kNewObjectAlignmentOffset ==
-                  target::kWordSize) &&
-                 (target::ObjectAlignment::kOldObjectAlignmentOffset == 0));
-
-  if (can_be_smi == kValueIsNotSmi) {
-#if defined(DEBUG)
-    Label okay;
-    BranchIfNotSmi(value, &okay);
-    Stop("Unexpected Smi!");
-    Bind(&okay);
-#endif
-    // Write-barrier triggers if the value is in the new space (has bit set) and
-    // the object is in the old space (has bit cleared).
-    // To check that we could compute value & ~object and skip the write barrier
-    // if the bit is not set. However we can't destroy the object.
-    // However to preserve the object we compute negated expression
-    // ~value | object instead and skip the write barrier if the bit is set.
-    notl(value);
-    orl(value, object);
-    testl(value, Immediate(target::ObjectAlignment::kNewObjectAlignmentOffset));
-  } else {
-    ASSERT(kHeapObjectTag == 1);
-    // Detect value being ...1001 and object being ...0001.
-    andl(value, Immediate(0xf));
-    leal(value, Address(value, object, TIMES_2, 0x15));
-    testl(value, Immediate(0x1f));
-  }
-  Condition condition = how_to_jump == kJumpToNoUpdate ? NOT_ZERO : ZERO;
-  JumpDistance distance = how_to_jump == kJumpToNoUpdate ? kNearJump : kFarJump;
-  j(condition, label, distance);
-}
-
 void Assembler::StoreIntoObject(Register object,
                                 const Address& dest,
                                 Register value,
@@ -1515,8 +1477,7 @@
   // Compare UntaggedObject::StorePointer.
   Label done;
   if (can_be_smi == kValueCanBeSmi) {
-    testq(value, Immediate(kSmiTagMask));
-    j(ZERO, &done, kNearJump);
+    BranchIfSmi(value, &done, kNearJump);
   }
   movb(ByteRegisterOf(TMP),
        FieldAddress(object, target::Object::tags_offset()));
@@ -1582,8 +1543,7 @@
   // Compare UntaggedObject::StorePointer.
   Label done;
   if (can_be_smi == kValueCanBeSmi) {
-    testq(value, Immediate(kSmiTagMask));
-    j(ZERO, &done, kNearJump);
+    BranchIfSmi(value, &done, kNearJump);
   }
   movb(ByteRegisterOf(TMP),
        FieldAddress(object, target::Object::tags_offset()));
@@ -1621,16 +1581,15 @@
   // reachable via a constant pool, so it doesn't matter if it is not traced via
   // 'object'.
   Label done;
-  pushq(value);
-  StoreIntoObjectFilter(object, value, &done, kValueCanBeSmi, kJumpToNoUpdate);
-
+  BranchIfSmi(value, &done, kNearJump);
+  testb(FieldAddress(value, target::Object::tags_offset()),
+        Immediate(1 << target::UntaggedObject::kNewBit));
+  j(ZERO, &done, Assembler::kNearJump);
   testb(FieldAddress(object, target::Object::tags_offset()),
         Immediate(1 << target::UntaggedObject::kOldAndNotRememberedBit));
   j(ZERO, &done, Assembler::kNearJump);
-
-  Stop("Store buffer update is required");
+  Stop("Write barrier is required");
   Bind(&done);
-  popq(value);
 #endif  // defined(DEBUG)
   // No store buffer update.
 }
@@ -1651,16 +1610,15 @@
   // reachable via a constant pool, so it doesn't matter if it is not traced via
   // 'object'.
   Label done;
-  pushq(value);
-  StoreIntoObjectFilter(object, value, &done, kValueCanBeSmi, kJumpToNoUpdate);
-
+  BranchIfSmi(value, &done, kNearJump);
+  testb(FieldAddress(value, target::Object::tags_offset()),
+        Immediate(1 << target::UntaggedObject::kNewBit));
+  j(ZERO, &done, Assembler::kNearJump);
   testb(FieldAddress(object, target::Object::tags_offset()),
         Immediate(1 << target::UntaggedObject::kOldAndNotRememberedBit));
   j(ZERO, &done, Assembler::kNearJump);
-
-  Stop("Store buffer update is required");
+  Stop("Write barrier is required");
   Bind(&done);
-  popq(value);
 #endif  // defined(DEBUG)
   // No store buffer update.
 }
diff --git a/runtime/vm/compiler/assembler/assembler_x64.h b/runtime/vm/compiler/assembler/assembler_x64.h
index a9c45e6..3b4eb27 100644
--- a/runtime/vm/compiler/assembler/assembler_x64.h
+++ b/runtime/vm/compiler/assembler/assembler_x64.h
@@ -1491,11 +1491,6 @@
     kJumpToBarrier,
   };
 
-  void StoreIntoObjectFilter(Register object,
-                             Register value,
-                             Label* label,
-                             CanBeSmi can_be_smi,
-                             BarrierFilterMode barrier_filter_mode);
   void StoreIntoArrayBarrier(Register object,
                              Register slot,
                              Register value,
diff --git a/runtime/vm/compiler/runtime_api.cc b/runtime/vm/compiler/runtime_api.cc
index 0ae58f0..10ecb9e 100644
--- a/runtime/vm/compiler/runtime_api.cc
+++ b/runtime/vm/compiler/runtime_api.cc
@@ -360,6 +360,8 @@
 
 const word UntaggedObject::kCanonicalBit = dart::UntaggedObject::kCanonicalBit;
 
+const word UntaggedObject::kNewBit = dart::UntaggedObject::kNewBit;
+
 const word UntaggedObject::kOldAndNotRememberedBit =
     dart::UntaggedObject::kOldAndNotRememberedBit;
 
diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h
index 7afa8c7..e9324ae 100644
--- a/runtime/vm/compiler/runtime_api.h
+++ b/runtime/vm/compiler/runtime_api.h
@@ -411,6 +411,7 @@
  public:
   static const word kCardRememberedBit;
   static const word kCanonicalBit;
+  static const word kNewBit;
   static const word kOldAndNotRememberedBit;
   static const word kOldAndNotMarkedBit;
   static const word kImmutableBit;
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index e7070ee..a86369e 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -17414,10 +17414,8 @@
                                      Code::ContainsCompressedPointers());
     NoSafepointScope no_safepoint;
     result ^= raw;
+    result.set_state_bits(0);
     result.set_pointer_offsets_length(pointer_offsets_length);
-    result.set_is_optimized(false);
-    result.set_is_force_optimized(false);
-    result.set_is_alive(false);
 #if defined(INCLUDE_IL_PRINTER)
     result.set_comments(Comments::New(0));
 #endif
@@ -20336,19 +20334,19 @@
 }
 
 void AbstractType::set_flags(uint32_t value) const {
-  StoreNonPointer(&untag()->flags_, value);
+  untag()->set_flags(value);
 }
 
 void AbstractType::set_type_state(UntaggedAbstractType::TypeState value) const {
   ASSERT(!IsCanonical());
   set_flags(
-      UntaggedAbstractType::TypeStateBits::update(value, untag()->flags_));
+      UntaggedAbstractType::TypeStateBits::update(value, untag()->flags()));
 }
 
 void AbstractType::set_nullability(Nullability value) const {
   ASSERT(!IsCanonical());
   set_flags(UntaggedAbstractType::NullabilityBits::update(
-      static_cast<uint8_t>(value), untag()->flags_));
+      static_cast<uint8_t>(value), untag()->flags()));
 }
 
 bool AbstractType::IsEquivalent(const Instance& other,
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index fec8db2..7d45ed5 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -8197,7 +8197,7 @@
 
   Nullability nullability() const {
     return static_cast<Nullability>(
-        UntaggedAbstractType::NullabilityBits::decode(untag()->flags_));
+        UntaggedAbstractType::NullabilityBits::decode(untag()->flags()));
   }
   // Returns true if type has '?' nullability suffix, or it is a
   // built-in type which is always nullable (Null, dynamic or void).
@@ -8493,7 +8493,7 @@
 
   UntaggedAbstractType::TypeState type_state() const {
     return static_cast<UntaggedAbstractType::TypeState>(
-        UntaggedAbstractType::TypeStateBits::decode(untag()->flags_));
+        UntaggedAbstractType::TypeStateBits::decode(untag()->flags()));
   }
   void set_flags(uint32_t value) const;
   void set_type_state(UntaggedAbstractType::TypeState value) const;
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 60b40e0..15975c6 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -2613,10 +2613,15 @@
   // Accessed from generated code.
   std::atomic<uword> type_test_stub_entry_point_;
   // Accessed from generated code.
-  uint32_t flags_;
+  std::atomic<uint32_t> flags_;
   COMPRESSED_POINTER_FIELD(CodePtr, type_test_stub)
   VISIT_FROM(type_test_stub)
 
+  uint32_t flags() const { return flags_.load(std::memory_order_relaxed); }
+  void set_flags(uint32_t value) {
+    flags_.store(value, std::memory_order_relaxed);
+  }
+
  public:
   enum TypeState {
     kAllocated,                // Initial state.
@@ -2625,13 +2630,13 @@
     kFinalizedUninstantiated,  // Uninstantiated type ready for use.
   };
 
-  using NullabilityBits = BitField<decltype(flags_), uint8_t, 0, 2>;
+  using NullabilityBits = BitField<uint32_t, uint8_t, 0, 2>;
   static constexpr intptr_t kNullabilityMask = NullabilityBits::mask();
 
   static constexpr intptr_t kTypeStateShift = NullabilityBits::kNextBit;
   static constexpr intptr_t kTypeStateBits = 2;
   using TypeStateBits =
-      BitField<decltype(flags_), uint8_t, kTypeStateShift, kTypeStateBits>;
+      BitField<uint32_t, uint8_t, kTypeStateShift, kTypeStateBits>;
 
  private:
   RAW_HEAP_OBJECT_IMPLEMENTATION(AbstractType);
@@ -2643,7 +2648,7 @@
 class UntaggedType : public UntaggedAbstractType {
  public:
   static constexpr intptr_t kTypeClassIdShift = TypeStateBits::kNextBit;
-  using TypeClassIdBits = BitField<decltype(flags_),
+  using TypeClassIdBits = BitField<uint32_t,
                                    ClassIdTagType,
                                    kTypeClassIdShift,
                                    sizeof(ClassIdTagType) * kBitsPerByte>;
@@ -2658,10 +2663,10 @@
   CompressedObjectPtr* to_snapshot(Snapshot::Kind kind) { return to(); }
 
   ClassIdTagType type_class_id() const {
-    return TypeClassIdBits::decode(flags_);
+    return TypeClassIdBits::decode(flags());
   }
   void set_type_class_id(ClassIdTagType value) {
-    flags_ = TypeClassIdBits::update(value, flags_);
+    set_flags(TypeClassIdBits::update(value, flags()));
   }
 
   friend class compiler::target::UntaggedType;
diff --git a/tests/modular/issue38703/main.dart b/tests/modular/issue38703/main.dart
index 076b9f1..e14eaf1 100644
--- a/tests/modular/issue38703/main.dart
+++ b/tests/modular/issue38703/main.dart
@@ -4,5 +4,5 @@
 const Map<Key, String> m = {someKey: "PASSED"};
 
 main() {
-  Expect.equals(m[someKey], "PASSED");
+  Expect.equals("PASSED", m[someKey]);
 }
diff --git a/tools/VERSION b/tools/VERSION
index 3799845..08d79d8 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 19
 PATCH 0
-PRERELEASE 275
+PRERELEASE 276
 PRERELEASE_PATCH 0