[cfe] Create fields through SourcePropertyBuilder

Change-Id: I20c9dd7baa705aba77d90b94ba0a46ed64eb02ec
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/403600
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
diff --git a/pkg/front_end/lib/src/base/incremental_compiler.dart b/pkg/front_end/lib/src/base/incremental_compiler.dart
index f2ffaeb..ca404aa 100644
--- a/pkg/front_end/lib/src/base/incremental_compiler.dart
+++ b/pkg/front_end/lib/src/base/incremental_compiler.dart
@@ -73,7 +73,6 @@
 import '../builder/builder.dart' show Builder;
 import '../builder/declaration_builders.dart'
     show ClassBuilder, ExtensionBuilder, ExtensionTypeDeclarationBuilder;
-import '../builder/field_builder.dart' show FieldBuilder;
 import '../builder/library_builder.dart'
     show CompilationUnit, LibraryBuilder, SourceCompilationUnit;
 import '../builder/member_builder.dart' show MemberBuilder;
@@ -741,7 +740,9 @@
       if (sourceBuilder == null) {
         sourceBuilder = sourceLibraryBuilder.exportNameSpace
             .lookupLocalMember(name, setter: false);
-        if (sourceBuilder is FieldBuilder && sourceBuilder.isAssignable) {
+        if (sourceBuilder is MemberBuilder &&
+            sourceBuilder.isField &&
+            sourceBuilder.isAssignable) {
           // Assignable fields can be lowered into a getter and setter.
           return;
         }
diff --git a/pkg/front_end/lib/src/base/scope.dart b/pkg/front_end/lib/src/base/scope.dart
index 38b029d0..45bb794 100644
--- a/pkg/front_end/lib/src/base/scope.dart
+++ b/pkg/front_end/lib/src/base/scope.dart
@@ -688,6 +688,14 @@
   bool get isAbstract => false;
 
   @override
+  // Coverage-ignore(suite): Not run.
+  bool get isFinal => false;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  bool get isSynthesized => false;
+
+  @override
   bool get isConflictingSetter => false;
 
   @override
@@ -1503,8 +1511,9 @@
       return _hasPatchAnnotation(self.metadata);
     } else if (self is SourceMethodBuilder) {
       return _hasPatchAnnotation(self.metadata);
-    } else if (self is SourceExtensionTypeDeclarationBuilder) {
-      // Coverage-ignore-block(suite): Not run.
+    }
+    // Coverage-ignore(suite): Not run.
+    else if (self is SourceExtensionTypeDeclarationBuilder) {
       return _hasPatchAnnotation(self.metadata);
     }
     return false;
diff --git a/pkg/front_end/lib/src/builder/builder_mixins.dart b/pkg/front_end/lib/src/builder/builder_mixins.dart
index 68bd1c3..2817a14 100644
--- a/pkg/front_end/lib/src/builder/builder_mixins.dart
+++ b/pkg/front_end/lib/src/builder/builder_mixins.dart
@@ -10,7 +10,6 @@
 import '../base/scope.dart';
 import 'builder.dart';
 import 'declaration_builders.dart';
-import 'field_builder.dart';
 import 'library_builder.dart';
 import 'member_builder.dart';
 import 'nullability_builder.dart';
@@ -96,16 +95,16 @@
     if (builder == null && setter) {
       // When looking up setters, we include assignable fields.
       builder = lookupLocalMember(name.text, setter: false, required: required);
-      if (builder is! FieldBuilder || !builder.isAssignable) {
+      if (builder is! MemberBuilder ||
+          !builder.isField ||
+          !builder.isAssignable) {
         builder = null;
       }
     }
     if (builder != null) {
       if (name.isPrivate && libraryBuilder.library != name.library) {
         builder = null;
-      } else if (builder is FieldBuilder &&
-          !builder.isStatic &&
-          !builder.isExternal) {
+      } else if (builder.isField && !builder.isStatic && !builder.isExternal) {
         // Non-external extension instance fields are invalid.
         builder = null;
       } else if (builder.isDuplicate) {
diff --git a/pkg/front_end/lib/src/builder/formal_parameter_builder.dart b/pkg/front_end/lib/src/builder/formal_parameter_builder.dart
index 774db86..1d984b3 100644
--- a/pkg/front_end/lib/src/builder/formal_parameter_builder.dart
+++ b/pkg/front_end/lib/src/builder/formal_parameter_builder.dart
@@ -19,13 +19,13 @@
 import '../source/builder_factory.dart';
 import '../source/constructor_declaration.dart';
 import '../source/source_factory_builder.dart';
-import '../source/source_field_builder.dart';
 import '../source/source_library_builder.dart';
 import 'builder.dart';
 import 'constructor_builder.dart';
 import 'declaration_builders.dart';
 import 'member_builder.dart';
 import 'omitted_type_builder.dart';
+import 'property_builder.dart';
 import 'type_builder.dart';
 import 'variable_builder.dart';
 
@@ -229,7 +229,7 @@
       ClassHierarchyBase hierarchy) {
     String fieldName = isWildcardLoweredFormalParameter(name) ? '_' : name;
     Builder? fieldBuilder = declarationBuilder.lookupLocalMember(fieldName);
-    if (fieldBuilder is SourceFieldBuilder) {
+    if (fieldBuilder is PropertyBuilder && fieldBuilder.isField) {
       DartType fieldType = fieldBuilder.inferType(hierarchy);
       fieldType = constructorDeclaration.substituteFieldType(fieldType);
       type.registerInferredType(fieldType);
diff --git a/pkg/front_end/lib/src/builder/invalid_type_declaration_builder.dart b/pkg/front_end/lib/src/builder/invalid_type_declaration_builder.dart
index b4dc83d..fb8ec6e 100644
--- a/pkg/front_end/lib/src/builder/invalid_type_declaration_builder.dart
+++ b/pkg/front_end/lib/src/builder/invalid_type_declaration_builder.dart
@@ -28,7 +28,7 @@
 
   @override
   // Coverage-ignore(suite): Not run.
-  Uri? get fileUri => message.uri;
+  Uri get fileUri => message.uri!;
 
   @override
   DartType buildAliasedType(
diff --git a/pkg/front_end/lib/src/builder/member_builder.dart b/pkg/front_end/lib/src/builder/member_builder.dart
index 98af57c..0c5c795 100644
--- a/pkg/front_end/lib/src/builder/member_builder.dart
+++ b/pkg/front_end/lib/src/builder/member_builder.dart
@@ -186,6 +186,7 @@
   Uri get fileUri => memberBuilder.fileUri;
 
   @override
+  // Coverage-ignore(suite): Not run.
   bool get isExtensionTypeMember => memberBuilder.isExtensionTypeMember;
 
   @override
@@ -206,6 +207,7 @@
   bool get isDuplicate => memberBuilder.isDuplicate;
 
   @override
+  // Coverage-ignore(suite): Not run.
   bool get isField => memberBuilder.isField;
 
   @override
@@ -231,9 +233,11 @@
   bool get isSynthesized => false;
 
   @override
+  // Coverage-ignore(suite): Not run.
   bool get isInternalImplementation => false;
 
   @override
+  // Coverage-ignore(suite): Not run.
   bool get isNoSuchMethodForwarder => false;
 
   @override
diff --git a/pkg/front_end/lib/src/builder/property_builder.dart b/pkg/front_end/lib/src/builder/property_builder.dart
new file mode 100644
index 0000000..fe65c62
--- /dev/null
+++ b/pkg/front_end/lib/src/builder/property_builder.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2025, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:kernel/ast.dart';
+import 'package:kernel/class_hierarchy.dart';
+
+import 'member_builder.dart';
+
+abstract class PropertyBuilder implements MemberBuilder {
+  bool get hasInitializer;
+
+  @override
+  Uri get fileUri;
+
+  bool get isExtensionTypeDeclaredInstanceField;
+
+  bool get isLate;
+
+  bool get isFinal;
+
+  abstract DartType fieldType;
+
+  DartType inferType(ClassHierarchyBase hierarchy);
+
+  /// Builds the field initializers for each field used to encode this field
+  /// using the [fileOffset] for the created nodes and [value] as the initial
+  /// field value.
+  List<Initializer> buildInitializer(int fileOffset, Expression value,
+      {required bool isSynthetic});
+
+  /// Creates the AST node for this field as the default initializer.
+  void buildImplicitDefaultValue();
+
+  /// Create the [Initializer] for the implicit initialization of this field
+  /// in a constructor.
+  Initializer buildImplicitInitializer();
+
+  Initializer buildErroneousInitializer(Expression effect, Expression value,
+      {required int fileOffset});
+}
diff --git a/pkg/front_end/lib/src/fragment/field.dart b/pkg/front_end/lib/src/fragment/field.dart
index 0648f15..93694e2 100644
--- a/pkg/front_end/lib/src/fragment/field.dart
+++ b/pkg/front_end/lib/src/fragment/field.dart
@@ -4,7 +4,7 @@
 
 part of 'fragment.dart';
 
-class FieldFragment implements Fragment {
+class FieldFragment implements Fragment, Inferable, InferredTypeListener {
   @override
   final String name;
 
@@ -21,7 +21,9 @@
   // fields.
   final bool isPrimaryConstructorField;
 
-  SourceFieldBuilder? _builder;
+  SourcePropertyBuilder? _builder;
+
+  late final _FieldEncoding _encoding;
 
   FieldFragment(
       {required this.name,
@@ -59,6 +61,7 @@
     return result;
   }
 
+  // Coverage-ignore(suite): Not run.
   Token? get constInitializerToken {
     Token? result = _constInitializerToken;
     // Ensure that we don't hold onto the token.
@@ -67,16 +70,377 @@
   }
 
   @override
-  SourceFieldBuilder get builder {
+  SourcePropertyBuilder get builder {
     assert(_builder != null, "Builder has not been computed for $this.");
     return _builder!;
   }
 
-  void set builder(SourceFieldBuilder value) {
+  void set builder(SourcePropertyBuilder value) {
     assert(_builder == null, "Builder has already been computed for $this.");
     _builder = value;
+
+    SourceLibraryBuilder libraryBuilder = builder.libraryBuilder;
+
+    bool isAbstract = modifiers.isAbstract;
+    bool isExternal = modifiers.isExternal;
+    bool isInstanceMember = builder.isDeclarationInstanceMember;
+    bool isExtensionMember = builder.isExtensionMember;
+    bool isExtensionTypeMember = builder.isExtensionTypeMember;
+
+    // If in mixed mode, late lowerings cannot use `null` as a sentinel on
+    // non-nullable fields since they can be assigned from legacy code.
+    late_lowering.IsSetStrategy isSetStrategy =
+        late_lowering.computeIsSetStrategy(libraryBuilder);
+    if (isAbstract || isExternal) {
+      _encoding = new AbstractOrExternalFieldEncoding(this,
+          isExtensionInstanceMember: isExtensionMember && isInstanceMember,
+          isExtensionTypeInstanceMember:
+              isExtensionTypeMember && isInstanceMember,
+          isAbstract: isAbstract,
+          isExternal: isExternal);
+    } else if (isExtensionTypeMember && isInstanceMember) {
+      if (isPrimaryConstructorField) {
+        _encoding = new RepresentationFieldEncoding(this);
+      } else {
+        // Field on a extension type. Encode as abstract.
+        // TODO(johnniwinther): Should we have an erroneous flag on such
+        // members?
+        _encoding = new AbstractOrExternalFieldEncoding(this,
+            isExtensionInstanceMember: isExtensionMember && isInstanceMember,
+            isExtensionTypeInstanceMember:
+                isExtensionTypeMember && isInstanceMember,
+            isAbstract: true,
+            isExternal: false,
+            isForcedExtension: true);
+      }
+    } else if (isLate &&
+        libraryBuilder.loader.target.backendTarget.isLateFieldLoweringEnabled(
+            hasInitializer: hasInitializer,
+            isFinal: isFinal,
+            isStatic: !isInstanceMember)) {
+      if (hasInitializer) {
+        if (isFinal) {
+          _encoding = new LateFinalFieldWithInitializerEncoding(this,
+              isSetStrategy: isSetStrategy);
+        } else {
+          _encoding = new LateFieldWithInitializerEncoding(this,
+              isSetStrategy: isSetStrategy);
+        }
+      } else {
+        if (isFinal) {
+          _encoding = new LateFinalFieldWithoutInitializerEncoding(this,
+              isSetStrategy: isSetStrategy);
+        } else {
+          _encoding = new LateFieldWithoutInitializerEncoding(this,
+              isSetStrategy: isSetStrategy);
+        }
+      }
+    } else if (libraryBuilder
+            .loader.target.backendTarget.useStaticFieldLowering &&
+        !isInstanceMember &&
+        !modifiers.isConst &&
+        hasInitializer) {
+      if (isFinal) {
+        _encoding = new LateFinalFieldWithInitializerEncoding(this,
+            isSetStrategy: isSetStrategy);
+      } else {
+        _encoding = new LateFieldWithInitializerEncoding(this,
+            isSetStrategy: isSetStrategy);
+      }
+    } else {
+      _encoding = new RegularFieldEncoding(this, isEnumElement: false);
+    }
+
+    type.registerInferredTypeListener(this);
+    Token? token = initializerToken;
+    if (type is InferableTypeBuilder) {
+      if (!modifiers.hasInitializer && _isStatic) {
+        // A static field without type and initializer will always be inferred
+        // to have type `dynamic`.
+        type.registerInferredType(const DynamicType());
+      } else {
+        // A field with no type and initializer or an instance field without
+        // type and initializer need to have the type inferred.
+        _encoding.type =
+            new InferredType.fromFieldFragmentInitializer(this, token);
+        type.registerInferable(this);
+      }
+    }
   }
 
+  BodyBuilderContext createBodyBuilderContext() {
+    return new _FieldFragmentBodyBuilderContext(
+        this, builder.libraryBuilder, builder.declarationBuilder,
+        isDeclarationInstanceMember: builder.isDeclarationInstanceMember);
+  }
+
+  /// Registers that a `super` call has occurred in the initializer of this
+  /// field.
+  void registerSuperCall() {
+    _encoding.registerSuperCall();
+  }
+
+  void buildOutlineNode(SourceLibraryBuilder libraryBuilder,
+      NameScheme nameScheme, BuildNodesCallback f, FieldReference references,
+      {required List<TypeParameter>? classTypeParameters}) {
+    _encoding.buildOutlineNode(libraryBuilder, nameScheme, references,
+        isAbstractOrExternal: modifiers.isAbstract || modifiers.isExternal,
+        classTypeParameters: classTypeParameters);
+    if (type is! InferableTypeBuilder) {
+      fieldType = type.build(libraryBuilder, TypeUse.fieldType);
+    }
+    _encoding.registerMembers(f);
+  }
+
+  Iterable<Reference> getExportedMemberReferences(FieldReference references) {
+    return [
+      references.getterReference!,
+      if (hasSetter) references.setterReference!
+    ];
+  }
+
+  shared.Expression? _initializerExpression;
+
+  // Coverage-ignore(suite): Not run.
+  shared.Expression? get initializerExpression => _initializerExpression;
+
+  void buildOutlineExpressions(
+      ClassHierarchy classHierarchy,
+      SourceLibraryBuilder libraryBuilder,
+      DeclarationBuilder? declarationBuilder,
+      LookupScope parentScope,
+      List<Annotatable> annotatables,
+      {required bool isClassInstanceMember,
+      required bool createFileUriExpression}) {
+    BodyBuilderContext bodyBuilderContext = createBodyBuilderContext();
+    for (Annotatable annotatable in annotatables) {
+      _buildMetadataForOutlineExpressions(libraryBuilder, parentScope,
+          bodyBuilderContext, annotatable, metadata,
+          fileUri: fileUri, createFileUriExpression: createFileUriExpression);
+    }
+    // For modular compilation we need to include initializers of all const
+    // fields and all non-static final fields in classes with const constructors
+    // into the outline.
+    if ((modifiers.isConst ||
+            (isFinal &&
+                isClassInstanceMember &&
+                (declarationBuilder as SourceClassBuilder)
+                    .declaresConstConstructor)) &&
+        _constInitializerToken != null) {
+      Token initializerToken = _constInitializerToken!;
+      LookupScope scope = declarationBuilder?.scope ?? libraryBuilder.scope;
+      BodyBuilder bodyBuilder = libraryBuilder.loader
+          .createBodyBuilderForOutlineExpression(
+              libraryBuilder, createBodyBuilderContext(), scope, fileUri);
+      bodyBuilder.constantContext = modifiers.isConst
+          ? ConstantContext.inferred
+          : ConstantContext.required;
+      Expression initializer = bodyBuilder.typeInferrer
+          .inferFieldInitializer(bodyBuilder, fieldType,
+              bodyBuilder.parseFieldInitializer(initializerToken))
+          .expression;
+      buildBody(classHierarchy.coreTypes, initializer);
+      bodyBuilder.performBacklogComputations();
+      if (computeSharedExpressionForTesting) {
+        // Coverage-ignore-block(suite): Not run.
+        _initializerExpression = parseFieldInitializer(libraryBuilder.loader,
+            initializerToken, libraryBuilder.importUri, fileUri, scope);
+      }
+    }
+    _constInitializerToken = null;
+  }
+
+  void checkTypes(SourceLibraryBuilder libraryBuilder,
+      TypeEnvironment typeEnvironment, SourcePropertyBuilder? setterBuilder,
+      {required bool isAbstract, required bool isExternal}) {
+    libraryBuilder.checkTypesInField(typeEnvironment,
+        isInstanceMember: builder.isDeclarationInstanceMember,
+        isLate: isLate,
+        isExternal: isExternal,
+        hasInitializer: hasInitializer,
+        fieldType: fieldType,
+        name: name,
+        nameLength: name.length,
+        nameOffset: nameOffset,
+        fileUri: fileUri);
+  }
+
+  void ensureTypes(
+      ClassMembersBuilder membersBuilder,
+      Set<ClassMember>? getterOverrideDependencies,
+      Set<ClassMember>? setterOverrideDependencies) {
+    if (getterOverrideDependencies != null ||
+        setterOverrideDependencies != null) {
+      membersBuilder.inferFieldType(
+          builder.declarationBuilder as SourceClassBuilder,
+          type,
+          [...?getterOverrideDependencies, ...?setterOverrideDependencies],
+          name: name,
+          fileUri: fileUri,
+          nameOffset: nameOffset,
+          nameLength: name.length,
+          isAssignable: hasSetter);
+    } else {
+      type.build(builder.libraryBuilder, TypeUse.fieldType,
+          hierarchy: membersBuilder.hierarchyBuilder);
+    }
+  }
+
+  void checkVariance(
+      SourceClassBuilder sourceClassBuilder, TypeEnvironment typeEnvironment) {
+    sourceClassBuilder.checkVarianceInField(typeEnvironment,
+        fieldType: fieldType,
+        isInstanceMember: !_isStatic,
+        hasSetter: hasSetter,
+        isCovariantByDeclaration: modifiers.isCovariant,
+        fileUri: fileUri,
+        fileOffset: nameOffset);
+  }
+
+  int computeDefaultTypes(ComputeDefaultTypeContext context) {
+    if (type is! OmittedTypeBuilder) {
+      context.reportInboundReferenceIssuesForType(type);
+      context.recursivelyReportGenericFunctionTypesAsBoundsForType(type);
+    }
+    return 0;
+  }
+
+  Member get readTarget => _encoding.readTarget;
+
+  Member? get writeTarget => _encoding.writeTarget;
+
+  /// Whether the body of this field has been built.
+  ///
+  /// Constant fields have their initializer built in the outline so we avoid
+  /// building them twice as part of the non-outline build.
+  bool hasBodyBeenBuilt = false;
+
+  /// Builds the body of this field using [initializer] as the initializer
+  /// expression.
+  void buildBody(CoreTypes coreTypes, Expression? initializer) {
+    assert(!hasBodyBeenBuilt, "Body has already been built for $this.");
+    hasBodyBeenBuilt = true;
+    if (!modifiers.hasInitializer &&
+        initializer != null &&
+        initializer is! NullLiteral &&
+        // Coverage-ignore(suite): Not run.
+        !modifiers.isConst &&
+        // Coverage-ignore(suite): Not run.
+        !modifiers.isFinal) {
+      internalProblem(
+          messageInternalProblemAlreadyInitialized, nameOffset, fileUri);
+    }
+    _encoding.createBodies(coreTypes, initializer);
+  }
+
+  DartType get fieldType => _encoding.type;
+
+  @override
+  void inferTypes(ClassHierarchyBase hierarchy) {
+    inferType(hierarchy);
+  }
+
+  DartType inferType(ClassHierarchyBase hierarchy) {
+    if (fieldType is! InferredType) {
+      // We have already inferred a type.
+      return fieldType;
+    }
+
+    return builder.libraryBuilder.loader
+        .withUriForCrashReporting(fileUri, nameOffset, () {
+      InferredType implicitFieldType = fieldType as InferredType;
+      DartType inferredType = implicitFieldType.computeType(hierarchy);
+      if (fieldType is InferredType) {
+        // `fieldType` may have changed if a circularity was detected when
+        // [inferredType] was computed.
+        type.registerInferredType(inferredType);
+
+        // TODO(johnniwinther): Isn't this handled in the [fieldType] setter?
+        IncludesTypeParametersNonCovariantly? needsCheckVisitor;
+        DeclarationBuilder? declarationBuilder = builder.declarationBuilder;
+        if (declarationBuilder is ClassBuilder) {
+          Class enclosingClass = declarationBuilder.cls;
+          if (enclosingClass.typeParameters.isNotEmpty) {
+            needsCheckVisitor = new IncludesTypeParametersNonCovariantly(
+                enclosingClass.typeParameters,
+                // We are checking the field type as if it is the type of the
+                // parameter of the implicit setter and this is a contravariant
+                // position.
+                initialVariance: Variance.contravariant);
+          }
+        }
+        if (needsCheckVisitor != null) {
+          if (fieldType.accept(needsCheckVisitor)) {
+            _encoding.setCovariantByClass();
+          }
+        }
+      }
+      return fieldType;
+    });
+  }
+
+  void set fieldType(DartType value) {
+    _encoding.type = value;
+    DeclarationBuilder? declarationBuilder = builder.declarationBuilder;
+    // TODO(johnniwinther): Should this be `hasSetter`?
+    if (!isFinal && !modifiers.isConst && declarationBuilder is ClassBuilder) {
+      Class enclosingClass = declarationBuilder.cls;
+      if (enclosingClass.typeParameters.isNotEmpty) {
+        IncludesTypeParametersNonCovariantly needsCheckVisitor =
+            new IncludesTypeParametersNonCovariantly(
+                enclosingClass.typeParameters,
+                // We are checking the field type as if it is the type of the
+                // parameter of the implicit setter and this is a contravariant
+                // position.
+                initialVariance: Variance.contravariant);
+        if (value.accept(needsCheckVisitor)) {
+          _encoding.setCovariantByClass();
+        }
+      }
+    }
+  }
+
+  Initializer buildErroneousInitializer(Expression effect, Expression value,
+      {required int fileOffset}) {
+    return _encoding.buildErroneousInitializer(effect, value,
+        fileOffset: fileOffset);
+  }
+
+  void buildImplicitDefaultValue() {
+    _encoding.buildImplicitDefaultValue();
+  }
+
+  Initializer buildImplicitInitializer() {
+    return _encoding.buildImplicitInitializer();
+  }
+
+  List<Initializer> buildInitializer(int fileOffset, Expression value,
+      {required bool isSynthetic}) {
+    return _encoding.createInitializer(fileOffset, value,
+        isSynthetic: isSynthetic);
+  }
+
+  bool get hasInitializer => modifiers.hasInitializer;
+
+  bool get isExtensionTypeDeclaredInstanceField =>
+      builder.isExtensionTypeInstanceMember && !isPrimaryConstructorField;
+
+  bool get isFinal => modifiers.isFinal;
+
+  bool get isLate => modifiers.isLate;
+
+  bool get _isStatic =>
+      modifiers.isStatic || builder.declarationBuilder == null;
+
   @override
   String toString() => '$runtimeType($name,$fileUri,$nameOffset)';
+
+  @override
+  void onInferredType(DartType type) {
+    fieldType = type;
+  }
+
+  List<ClassMember> get localMembers => _encoding.localMembers;
+
+  List<ClassMember> get localSetters => _encoding.localSetters;
 }
diff --git a/pkg/front_end/lib/src/fragment/field/body_builder_context.dart b/pkg/front_end/lib/src/fragment/field/body_builder_context.dart
new file mode 100644
index 0000000..a79fcb5
--- /dev/null
+++ b/pkg/front_end/lib/src/fragment/field/body_builder_context.dart
@@ -0,0 +1,74 @@
+// Copyright (c) 2025, 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.
+
+part of '../fragment.dart';
+
+class _FieldFragmentBodyBuilderContext extends BodyBuilderContext {
+  final FieldFragment _fragment;
+
+  _FieldFragmentBodyBuilderContext(
+      this._fragment,
+      SourceLibraryBuilder libraryBuilder,
+      DeclarationBuilder? declarationBuilder,
+      {required bool isDeclarationInstanceMember})
+      : super(libraryBuilder, declarationBuilder,
+            isDeclarationInstanceMember: isDeclarationInstanceMember);
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  LocalScope computeFormalParameterInitializerScope(LocalScope parent) {
+    /// Initializer formals or super parameters cannot occur in getters so
+    /// we don't need to create a new scope.
+    return parent;
+  }
+
+  @override
+  bool get isLateField => _fragment.modifiers.isLate;
+
+  @override
+  bool get isAbstractField => _fragment.modifiers.isAbstract;
+
+  @override
+  bool get isExternalField => _fragment.modifiers.isExternal;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  int get memberNameOffset => _fragment.nameOffset;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  int get memberNameLength => _fragment.name.length;
+
+  @override
+  InstanceTypeParameterAccessState get instanceTypeParameterAccessState {
+    if (_fragment.builder.isExtensionMember && !isExternalField) {
+      return InstanceTypeParameterAccessState.Invalid;
+    } else {
+      return super.instanceTypeParameterAccessState;
+    }
+  }
+
+  @override
+  void registerSuperCall() {
+    _fragment.registerSuperCall();
+  }
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  AugmentSuperTarget? get augmentSuperTarget {
+    if (_fragment.builder.isAugmentation) {
+      return _fragment.builder.augmentSuperTarget;
+    }
+    return null;
+  }
+
+  @override
+  ConstantContext get constantContext {
+    return _fragment.modifiers.isConst
+        ? ConstantContext.inferred
+        : !_fragment._isStatic && declarationDeclaresConstConstructor
+            ? ConstantContext.required
+            : ConstantContext.none;
+  }
+}
diff --git a/pkg/front_end/lib/src/fragment/field/class_member.dart b/pkg/front_end/lib/src/fragment/field/class_member.dart
new file mode 100644
index 0000000..8d0daa0
--- /dev/null
+++ b/pkg/front_end/lib/src/fragment/field/class_member.dart
@@ -0,0 +1,339 @@
+// Copyright (c) 2025, 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.
+
+part of '../fragment.dart';
+
+class _FieldClassMember implements ClassMember {
+  final SourcePropertyBuilder _builder;
+  final FieldFragment _fragment;
+
+  @override
+  final bool forSetter;
+
+  Covariance? _covariance;
+
+  _FieldClassMember(this._builder, this._fragment, {required this.forSetter});
+
+  @override
+  int get charOffset => _fragment.nameOffset;
+
+  @override
+  DeclarationBuilder get declarationBuilder => _builder.declarationBuilder!;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  List<ClassMember> get declarations =>
+      throw new UnsupportedError('$runtimeType.declarations');
+
+  @override
+  Uri get fileUri => _fragment.fileUri;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  String get fullName {
+    String className = declarationBuilder.fullNameForErrors;
+    return "${className}.${fullNameForErrors}";
+  }
+
+  @override
+  String get fullNameForErrors => _builder.fullNameForErrors;
+
+  @override
+  Covariance getCovariance(ClassMembersBuilder membersBuilder) {
+    return _covariance ??= forSetter
+        ? new Covariance.fromMember(getMember(membersBuilder),
+            forSetter: forSetter)
+        : const Covariance.empty();
+  }
+
+  @override
+  Member getMember(ClassMembersBuilder membersBuilder) {
+    _builder.ensureTypes(membersBuilder);
+    return forSetter ? _builder.writeTarget! : _builder.readTarget!;
+  }
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  MemberResult getMemberResult(ClassMembersBuilder membersBuilder) {
+    if (isStatic) {
+      return new StaticMemberResult(getMember(membersBuilder), memberKind,
+          isDeclaredAsField: true,
+          fullName: '${declarationBuilder.name}.${_builder.memberName.text}');
+    } else if (_builder.isExtensionTypeMember) {
+      ExtensionTypeDeclaration extensionTypeDeclaration =
+          (declarationBuilder as ExtensionTypeDeclarationBuilder)
+              .extensionTypeDeclaration;
+      Member member = getTearOff(membersBuilder) ?? getMember(membersBuilder);
+      return new ExtensionTypeMemberResult(
+          extensionTypeDeclaration, member, memberKind, name,
+          isDeclaredAsField: true);
+    } else {
+      return new TypeDeclarationInstanceMemberResult(
+          getMember(membersBuilder), memberKind,
+          isDeclaredAsField: true);
+    }
+  }
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  Member? getTearOff(ClassMembersBuilder membersBuilder) => null;
+
+  @override
+  bool get hasDeclarations => false;
+
+  @override
+  void inferType(ClassMembersBuilder membersBuilder) {
+    _builder.ensureTypes(membersBuilder);
+  }
+
+  @override
+  ClassMember get interfaceMember => this;
+
+  @override
+  // TODO(johnniwinther): This should not be determined by the builder. A
+  // property can have a non-abstract getter and an abstract setter or the
+  // reverse. With augmentations, abstract introductory declarations might even
+  // be implemented by augmentations.
+  bool get isAbstract => _fragment.modifiers.isAbstract;
+
+  @override
+  bool get isDuplicate => _builder.isDuplicate;
+
+  @override
+  bool get isExtensionTypeMember => _builder.isExtensionTypeMember;
+
+  @override
+  bool get isField => true;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  bool get isGetter => false; //!forSetter;
+
+  @override
+  bool get isInternalImplementation => false;
+
+  @override
+  bool get isNoSuchMethodForwarder => false;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  bool isObjectMember(ClassBuilder objectClass) {
+    return declarationBuilder == objectClass;
+  }
+
+  @override
+  bool get isProperty => true;
+
+  @override
+  bool isSameDeclaration(ClassMember other) {
+    return other is _FieldClassMember && _builder == other._builder;
+  }
+
+  @override
+  bool get isSetter => false; //forSetter;
+
+  @override
+  bool get isSourceDeclaration => true;
+
+  @override
+  bool get isStatic => _fragment.modifiers.isStatic;
+
+  @override
+  bool get isSynthesized => false;
+
+  @override
+  ClassMemberKind get memberKind =>
+      forSetter ? ClassMemberKind.Setter : ClassMemberKind.Getter;
+
+  @override
+  Name get name => _builder.memberName;
+
+  @override
+  void registerOverrideDependency(Set<ClassMember> overriddenMembers) {
+    if (forSetter) {
+      _builder.registerSetterOverrideDependency(overriddenMembers);
+    } else {
+      _builder.registerGetterOverrideDependency(overriddenMembers);
+    }
+  }
+
+  @override
+  String toString() => '$runtimeType($fullName,forSetter=${forSetter})';
+}
+
+class _SynthesizedFieldClassMember implements ClassMember {
+  final SourcePropertyBuilder _builder;
+  final _SynthesizedFieldMemberKind _kind;
+
+  final Member _member;
+
+  final Name _name;
+
+  Covariance? _covariance;
+
+  @override
+  final ClassMemberKind memberKind;
+
+  _SynthesizedFieldClassMember(
+      this._builder, this._member, this._name, this._kind, this.memberKind);
+
+  @override
+  bool get isInternalImplementation => _kind.isInternalImplementation;
+
+  @override
+  Member getMember(ClassMembersBuilder membersBuilder) {
+    _builder.ensureTypes(membersBuilder);
+    return _member;
+  }
+
+  @override
+  Member? getTearOff(ClassMembersBuilder membersBuilder) {
+    // Ensure field type is computed.
+    getMember(membersBuilder);
+    return null;
+  }
+
+  @override
+  Covariance getCovariance(ClassMembersBuilder membersBuilder) {
+    return _covariance ??= new Covariance.fromMember(getMember(membersBuilder),
+        forSetter: forSetter);
+  }
+
+  @override
+  MemberResult getMemberResult(ClassMembersBuilder membersBuilder) {
+    return new TypeDeclarationInstanceMemberResult(
+        getMember(membersBuilder), memberKind,
+        isDeclaredAsField: _builder.isField);
+  }
+
+  @override
+  void inferType(ClassMembersBuilder membersBuilder) {
+    _builder.ensureTypes(membersBuilder);
+  }
+
+  @override
+  void registerOverrideDependency(Set<ClassMember> overriddenMembers) {
+    if (forSetter) {
+      _builder.registerSetterOverrideDependency(overriddenMembers);
+    } else {
+      _builder.registerGetterOverrideDependency(overriddenMembers);
+    }
+  }
+
+  @override
+  bool get isSourceDeclaration => true;
+
+  @override
+  bool get forSetter => memberKind == ClassMemberKind.Setter;
+
+  @override
+  bool get isProperty => memberKind != ClassMemberKind.Method;
+
+  @override
+  DeclarationBuilder get declarationBuilder => _builder.declarationBuilder!;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  bool isObjectMember(ClassBuilder objectClass) {
+    return declarationBuilder == objectClass;
+  }
+
+  @override
+  bool get isDuplicate => _builder.isDuplicate;
+
+  @override
+  bool get isStatic => _builder.isStatic;
+
+  @override
+  bool get isField => _member is Field;
+
+  @override
+  bool get isSetter {
+    Member procedure = _member;
+    return procedure is Procedure && procedure.kind == ProcedureKind.Setter;
+  }
+
+  @override
+  bool get isGetter {
+    Member procedure = _member;
+    return procedure is Procedure && procedure.kind == ProcedureKind.Getter;
+  }
+
+  @override
+  Name get name => _name;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  String get fullName {
+    String suffix = isSetter ? "=" : "";
+    String className = declarationBuilder.fullNameForErrors;
+    return "${className}.${fullNameForErrors}$suffix";
+  }
+
+  @override
+  String get fullNameForErrors => _builder.fullNameForErrors;
+
+  @override
+  Uri get fileUri => _builder.fileUri;
+
+  @override
+  int get charOffset => _builder.fileOffset;
+
+  @override
+  bool get isAbstract => _member.isAbstract;
+
+  @override
+  bool get isSynthesized => false;
+
+  @override
+  bool get hasDeclarations => false;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  List<ClassMember> get declarations =>
+      throw new UnsupportedError("$runtimeType.declarations");
+
+  @override
+  ClassMember get interfaceMember => this;
+
+  @override
+  bool isSameDeclaration(ClassMember other) {
+    if (identical(this, other)) return true;
+    return other is _SynthesizedFieldClassMember &&
+        _builder == other._builder &&
+        _kind == other._kind;
+  }
+
+  @override
+  bool get isNoSuchMethodForwarder => false;
+
+  @override
+  String toString() => '_SynthesizedFieldClassMember('
+      '$_builder,$_member,$_kind,forSetter=${forSetter})';
+
+  @override
+  bool get isExtensionTypeMember => _builder.isExtensionTypeMember;
+}
+
+enum _SynthesizedFieldMemberKind {
+  /// A `isSet` field used for late lowering.
+  LateIsSet(isInternalImplementation: true),
+
+  /// A field used for the value of a late lowered field.
+  LateField(isInternalImplementation: true),
+
+  /// A getter or setter used for late lowering.
+  LateGetterSetter(isInternalImplementation: false),
+
+  /// A getter or setter used for abstract or external fields.
+  AbstractExternalGetterSetter(isInternalImplementation: false),
+
+  /// A getter for an extension type declaration representation field.
+  RepresentationField(isInternalImplementation: false),
+  ;
+
+  final bool isInternalImplementation;
+
+  const _SynthesizedFieldMemberKind({required this.isInternalImplementation});
+}
diff --git a/pkg/front_end/lib/src/fragment/field/encoding.dart b/pkg/front_end/lib/src/fragment/field/encoding.dart
new file mode 100644
index 0000000..4aaf45d
--- /dev/null
+++ b/pkg/front_end/lib/src/fragment/field/encoding.dart
@@ -0,0 +1,1326 @@
+// Copyright (c) 2025, 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.
+
+part of '../fragment.dart';
+
+/// Strategy pattern for creating different encodings of a declared field.
+///
+/// This is used to provide lowerings for late fields using synthesized getters
+/// and setters.
+sealed class _FieldEncoding {
+  /// Creates the members necessary for this field encoding.
+  ///
+  /// This method is called for both outline and full compilation so the created
+  /// members should be without body. The member bodies are created through
+  /// [createBodies].
+  void buildOutlineNode(SourceLibraryBuilder libraryBuilder,
+      NameScheme nameScheme, FieldReference references,
+      {required bool isAbstractOrExternal,
+      required List<TypeParameter>? classTypeParameters});
+
+  /// Calls [f] for each member needed for this field encoding.
+  void registerMembers(BuildNodesCallback f);
+
+  /// Creates the bodies needed for the field encoding using [initializer] as
+  /// the declared initializer expression.
+  ///
+  /// This method is not called for fields in outlines unless their are constant
+  /// or part of a const constructor.
+  void createBodies(CoreTypes coreTypes, Expression? initializer);
+
+  /// The type of the declared field.
+  abstract DartType type;
+
+  List<Initializer> createInitializer(int fileOffset, Expression value,
+      {required bool isSynthetic});
+
+  /// Creates the AST node for this field as the default initializer.
+  void buildImplicitDefaultValue();
+
+  /// Create the [Initializer] for the implicit initialization of this field
+  /// in a constructor.
+  Initializer buildImplicitInitializer();
+
+  Initializer buildErroneousInitializer(Expression effect, Expression value,
+      {required int fileOffset});
+
+  /// Registers that the (implicit) setter associated with this field needs to
+  /// contain a runtime type check to deal with generic covariance.
+  void setCovariantByClass();
+
+  /// Returns the field that holds the field value at runtime.
+  Field get field;
+
+  /// The [Member] built during [SourceFieldBuilder.buildOutlineExpressions].
+  Member get builtMember;
+
+  /// Returns the members that holds the field annotations.
+  Iterable<Annotatable> get annotatables;
+
+  /// Returns the member used to read the field value.
+  Member get readTarget;
+
+  /// Returns the reference used to read the field value.
+  Reference get readTargetReference;
+
+  /// Returns the member used to write to the field.
+  Member? get writeTarget;
+
+  /// Returns the reference used to write to the field.
+  Reference? get writeTargetReference;
+
+  /// Returns the references to the generated members that are visible through
+  /// exports.
+  ///
+  /// This is the getter reference, and, if available, the setter reference.
+  Iterable<Reference> get exportedReferenceMembers;
+
+  /// Returns a list of the field, getters and methods created by this field
+  /// encoding.
+  List<ClassMember> get localMembers;
+
+  /// Returns a list of the setters created by this field encoding.
+  List<ClassMember> get localSetters;
+
+  /// Registers that a `super` call has occurred in the initializer of this
+  /// field.
+  void registerSuperCall();
+}
+
+class RegularFieldEncoding implements _FieldEncoding {
+  final FieldFragment _fragment;
+  final bool isEnumElement;
+  Field? _field;
+  DartType _type = const DynamicType();
+
+  RegularFieldEncoding(this._fragment, {required this.isEnumElement}) {}
+
+  @override
+  DartType get type => _type;
+
+  @override
+  void set type(DartType value) {
+    _type = value;
+    _field?.type = value;
+  }
+
+  @override
+  void createBodies(CoreTypes coreTypes, Expression? initializer) {
+    if (initializer != null) {
+      _field!.initializer = initializer..parent = _field;
+    }
+  }
+
+  @override
+  List<Initializer> createInitializer(int fileOffset, Expression value,
+      {required bool isSynthetic}) {
+    return <Initializer>[
+      new FieldInitializer(_field!, value)
+        ..fileOffset = fileOffset
+        ..isSynthetic = isSynthetic
+    ];
+  }
+
+  @override
+  void buildOutlineNode(SourceLibraryBuilder libraryBuilder,
+      NameScheme nameScheme, FieldReference references,
+      {required bool isAbstractOrExternal,
+      required List<TypeParameter>? classTypeParameters}) {
+    bool isImmutable = _fragment.modifiers.isLate
+        ? (_fragment.modifiers.isFinal && _fragment.hasInitializer)
+        : (_fragment.modifiers.isFinal || _fragment.modifiers.isConst);
+    _field = isImmutable
+        ? new Field.immutable(dummyName,
+            type: _type,
+            isFinal: _fragment.modifiers.isFinal,
+            isConst: _fragment.modifiers.isConst,
+            isLate: _fragment.modifiers.isLate,
+            fileUri: _fragment.fileUri,
+            fieldReference: references.fieldReference,
+            getterReference: references.fieldGetterReference,
+            isEnumElement: isEnumElement)
+        : new Field.mutable(dummyName,
+            type: _type,
+            isFinal: _fragment.modifiers.isFinal,
+            isLate: _fragment.modifiers.isLate,
+            fileUri: _fragment.fileUri,
+            fieldReference: references.fieldReference,
+            getterReference: references.fieldGetterReference,
+            setterReference: references.fieldSetterReference);
+    nameScheme
+        .getFieldMemberName(FieldNameType.Field, _fragment.name,
+            isSynthesized: false)
+        .attachMember(_field!);
+    _field!
+      ..fileOffset = _fragment.nameOffset
+      ..fileEndOffset = _fragment.endOffset;
+    _field!..isCovariantByDeclaration = _fragment.modifiers.isCovariant;
+    if (_fragment.builder.isExtensionMember) {
+      _field!
+        ..isStatic = true
+        ..isExtensionMember = true;
+    } else if (_fragment.builder.isExtensionTypeMember) {
+      _field!
+        ..isStatic = _fragment.builder.isStatic
+        ..isExtensionTypeMember = true;
+    } else {
+      bool isInstanceMember =
+          !_fragment.builder.isStatic && !_fragment.builder.isTopLevel;
+      _field!
+        ..isStatic = !isInstanceMember
+        ..isExtensionMember = false;
+    }
+    _field!.isLate = _fragment.modifiers.isLate;
+  }
+
+  @override
+  void registerMembers(BuildNodesCallback f) {
+    f(
+        member: _field!,
+        kind: _fragment.builder.isExtensionMember ||
+                _fragment.builder.isExtensionTypeMember
+            ? BuiltMemberKind.ExtensionField
+            : BuiltMemberKind.Field);
+  }
+
+  @override
+  void setCovariantByClass() {
+    if (_field!.hasSetter) {
+      _field!.isCovariantByClass = true;
+    }
+  }
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  Field get field => _field!;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  Member get builtMember => _field!;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  Iterable<Annotatable> get annotatables => [_field!];
+
+  @override
+  Member get readTarget => _field!;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  Reference get readTargetReference => _field!.getterReference;
+
+  @override
+  Member get writeTarget => _field!;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  Reference? get writeTargetReference => _field!.setterReference;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  Iterable<Reference> get exportedReferenceMembers => [
+        _field!.getterReference,
+        if (_field!.hasSetter) _field!.setterReference!
+      ];
+
+  @override
+  List<ClassMember> get localMembers => <ClassMember>[
+        new _FieldClassMember(_fragment.builder, _fragment, forSetter: false)
+      ];
+
+  @override
+  List<ClassMember> get localSetters => _fragment.hasSetter
+      ? [new _FieldClassMember(_fragment.builder, _fragment, forSetter: true)]
+      : const [];
+
+  @override
+  void buildImplicitDefaultValue() {
+    _field!.initializer = new NullLiteral()..parent = _field;
+  }
+
+  @override
+  Initializer buildImplicitInitializer() {
+    return new FieldInitializer(_field!, new NullLiteral())..isSynthetic = true;
+  }
+
+  @override
+  Initializer buildErroneousInitializer(Expression effect, Expression value,
+      {required int fileOffset}) {
+    return new ShadowInvalidFieldInitializer(type, value, effect)
+      ..fileOffset = fileOffset;
+  }
+
+  @override
+  void registerSuperCall() {
+    _field!.transformerFlags |= TransformerFlag.superCalls;
+  }
+}
+
+abstract class AbstractLateFieldEncoding implements _FieldEncoding {
+  final FieldFragment _fragment;
+  DartType? _type;
+  Field? _field;
+  Field? _lateIsSetField;
+  Procedure? _lateGetter;
+  Procedure? _lateSetter;
+
+  // If `true`, an isSet field is used even when the type of the field is
+  // not potentially nullable.
+  //
+  // This is used to force use isSet fields in mixed mode encoding since
+  // we cannot trust non-nullable fields to be initialized with non-null values.
+  final late_lowering.IsSetStrategy _isSetStrategy;
+  late_lowering.IsSetEncoding? _isSetEncoding;
+
+  // If `true`, the is-set field was register before the type was known to be
+  // nullable or non-nullable. In this case we do not try to remove it from
+  // the generated AST to avoid inconsistency between the class hierarchy used
+  // during and after inference.
+  //
+  // This is also used to force use isSet fields in mixed mode encoding since
+  // we cannot trust non-nullable fields to be initialized with non-null values.
+  bool _forceIncludeIsSetField;
+
+  AbstractLateFieldEncoding(this._fragment,
+      {required late_lowering.IsSetStrategy isSetStrategy})
+      : _isSetStrategy = isSetStrategy,
+        _forceIncludeIsSetField =
+            isSetStrategy == late_lowering.IsSetStrategy.forceUseIsSetField {}
+
+  late_lowering.IsSetEncoding get isSetEncoding {
+    assert(_type != null,
+        "Type has not been computed for field ${_fragment.name}.");
+    return _isSetEncoding ??=
+        late_lowering.computeIsSetEncoding(_type!, _isSetStrategy);
+  }
+
+  @override
+  void createBodies(CoreTypes coreTypes, Expression? initializer) {
+    assert(_type != null,
+        "Type has not been computed for field ${_fragment.name}.");
+    if (isSetEncoding == late_lowering.IsSetEncoding.useSentinel) {
+      _field!.initializer = new StaticInvocation(coreTypes.createSentinelMethod,
+          new Arguments([], types: [_type!])..fileOffset = _fragment.nameOffset)
+        ..fileOffset = _fragment.nameOffset
+        ..parent = _field;
+    } else {
+      _field!.initializer = new NullLiteral()
+        ..fileOffset = _fragment.nameOffset
+        ..parent = _field;
+    }
+    if (_lateIsSetField != null) {
+      _lateIsSetField!.initializer = new BoolLiteral(false)
+        ..fileOffset = _fragment.nameOffset
+        ..parent = _lateIsSetField;
+    }
+    _lateGetter!.function.body =
+        _createGetterBody(coreTypes, _fragment.name, initializer)
+          ..parent = _lateGetter!.function;
+    // The initializer is copied from [_field] to [_lateGetter] so we copy the
+    // transformer flags to reflect whether the getter contains super calls.
+    _lateGetter!.transformerFlags = _field!.transformerFlags;
+
+    if (_lateSetter != null) {
+      _lateSetter!.function.body = _createSetterBody(coreTypes, _fragment.name,
+          _lateSetter!.function.positionalParameters.first)
+        ..parent = _lateSetter!.function;
+    }
+  }
+
+  @override
+  List<Initializer> createInitializer(int fileOffset, Expression value,
+      {required bool isSynthetic}) {
+    List<Initializer> initializers = <Initializer>[];
+    if (_lateIsSetField != null) {
+      initializers.add(new FieldInitializer(
+          _lateIsSetField!, new BoolLiteral(true)..fileOffset = fileOffset)
+        ..fileOffset = fileOffset
+        ..isSynthetic = isSynthetic);
+    }
+    initializers.add(new FieldInitializer(_field!, value)
+      ..fileOffset = fileOffset
+      ..isSynthetic = isSynthetic);
+    return initializers;
+  }
+
+  /// Creates an [Expression] that reads [_field].
+  ///
+  /// If [needsPromotion] is `true`, the field will be read through a `let`
+  /// expression that promotes the expression to [_type]. This is needed for a
+  /// sound encoding of fields with type parameter type of undetermined
+  /// nullability.
+  Expression _createFieldRead({bool needsPromotion = false}) {
+    assert(_type != null,
+        "Type has not been computed for field ${_fragment.name}.");
+    if (needsPromotion) {
+      VariableDeclaration variable = new VariableDeclaration.forValue(
+          _createFieldGet(_field!),
+          type: _type!.withDeclaredNullability(Nullability.nullable))
+        ..fileOffset = _fragment.nameOffset;
+      return new Let(variable,
+          new VariableGet(variable, _type)..fileOffset = _fragment.nameOffset);
+    } else {
+      return _createFieldGet(_field!);
+    }
+  }
+
+  /// Creates an [Expression] that reads [field].
+  Expression _createFieldGet(Field field) {
+    if (field.isStatic) {
+      return new StaticGet(field)..fileOffset = _fragment.nameOffset;
+    } else {
+      // No substitution needed for the result type, since any type parameters
+      // in there are also in scope at the access site.
+      return new InstanceGet(InstanceAccessKind.Instance,
+          new ThisExpression()..fileOffset = _fragment.nameOffset, field.name,
+          interfaceTarget: field, resultType: field.type)
+        ..fileOffset = _fragment.nameOffset;
+    }
+  }
+
+  /// Creates an [Expression] that writes [value] to [field].
+  Expression _createFieldSet(Field field, Expression value) {
+    if (field.isStatic) {
+      return new StaticSet(field, value)..fileOffset = _fragment.nameOffset;
+    } else {
+      return new InstanceSet(
+          InstanceAccessKind.Instance,
+          new ThisExpression()..fileOffset = _fragment.nameOffset,
+          field.name,
+          value,
+          interfaceTarget: field)
+        ..fileOffset = _fragment.nameOffset;
+    }
+  }
+
+  Statement _createGetterBody(
+      CoreTypes coreTypes, String name, Expression? initializer);
+
+  Procedure? _createSetter(Uri fileUri, int charOffset, Reference? reference,
+      {required bool isCovariantByDeclaration}) {
+    VariableDeclaration parameter =
+        new VariableDeclaration("${_fragment.name}#param")
+          ..isCovariantByDeclaration = isCovariantByDeclaration
+          ..fileOffset = _fragment.nameOffset;
+    return new Procedure(
+        dummyName,
+        ProcedureKind.Setter,
+        new FunctionNode(null,
+            positionalParameters: [parameter], returnType: const VoidType())
+          ..fileOffset = charOffset
+          ..fileEndOffset = _fragment.endOffset,
+        fileUri: fileUri,
+        reference: reference)
+      ..fileOffset = charOffset
+      ..fileEndOffset = _fragment.endOffset;
+  }
+
+  Statement _createSetterBody(
+      CoreTypes coreTypes, String name, VariableDeclaration parameter);
+
+  @override
+  DartType get type {
+    assert(_type != null,
+        "Type has not been computed for field ${_fragment.name}.");
+    return _type!;
+  }
+
+  /// Updates the field/getter/setter types of [_field], [_lateGetter] and
+  /// [_lateSetter] to match the value of [_type].
+  ///
+  /// This allows for creating the members and computing the type in arbitrary
+  /// order.
+  void _updateMemberTypes() {
+    DartType? type = _type;
+    Field? field = _field;
+    if (type != null && type is! InferredType && field != null) {
+      field.type = type.withDeclaredNullability(Nullability.nullable);
+      _lateGetter!.function.returnType = type;
+      _lateSetter?.function.positionalParameters.single.type = type;
+      if (!type.isPotentiallyNullable && !_forceIncludeIsSetField) {
+        // We only need the is-set field if the field is potentially nullable.
+        //  Otherwise we use `null` to signal that the field is uninitialized.
+        _lateIsSetField = null;
+      }
+    }
+  }
+
+  @override
+  void set type(DartType value) {
+    assert(_type == null || _type is InferredType,
+        "Type has already been computed for field ${_fragment.name}.");
+    _type = value;
+    _updateMemberTypes();
+  }
+
+  @override
+  void setCovariantByClass() {
+    if (_field!.hasSetter) {
+      _field!.isCovariantByClass = true;
+    }
+    _lateSetter?.function.positionalParameters.single.isCovariantByClass = true;
+  }
+
+  @override
+  Field get field => _field!;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  Member get builtMember => _field!;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  Iterable<Annotatable> get annotatables {
+    List<Annotatable> list = [_lateGetter!];
+    if (_lateSetter != null) {
+      list.add(_lateSetter!);
+    }
+    return list;
+  }
+
+  @override
+  Member get readTarget => _lateGetter!;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  Reference get readTargetReference => _lateGetter!.reference;
+
+  @override
+  Member? get writeTarget => _lateSetter;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  Reference? get writeTargetReference => _lateSetter?.reference;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  Iterable<Reference> get exportedReferenceMembers {
+    if (_lateSetter != null) {
+      return [_lateGetter!.reference, _lateSetter!.reference];
+    }
+    return [_lateGetter!.reference];
+  }
+
+  @override
+  void buildOutlineNode(SourceLibraryBuilder libraryBuilder,
+      NameScheme nameScheme, FieldReference references,
+      {required bool isAbstractOrExternal,
+      required List<TypeParameter>? classTypeParameters}) {
+    _field = new Field.mutable(dummyName,
+        fileUri: _fragment.fileUri,
+        fieldReference: references.fieldReference,
+        getterReference: references.fieldGetterReference,
+        setterReference: references.fieldSetterReference)
+      ..fileOffset = _fragment.nameOffset
+      ..fileEndOffset = _fragment.endOffset
+      ..isInternalImplementation = true;
+    nameScheme
+        .getFieldMemberName(FieldNameType.Field, _fragment.name,
+            isSynthesized: true)
+        .attachMember(_field!);
+    switch (_isSetStrategy) {
+      case late_lowering.IsSetStrategy.useSentinelOrNull:
+      case late_lowering.IsSetStrategy.forceUseSentinel:
+        // [_lateIsSetField] is never needed.
+        break;
+      case late_lowering.IsSetStrategy.forceUseIsSetField:
+      case late_lowering.IsSetStrategy.useIsSetFieldOrNull:
+        _lateIsSetField = new Field.mutable(dummyName,
+            fileUri: _fragment.fileUri,
+            fieldReference: references.lateIsSetFieldReference,
+            getterReference: references.lateIsSetGetterReference,
+            setterReference: references.lateIsSetSetterReference)
+          ..fileOffset = _fragment.nameOffset
+          ..fileEndOffset = _fragment.endOffset
+          ..isInternalImplementation = true;
+        nameScheme
+            .getFieldMemberName(FieldNameType.IsSetField, _fragment.name,
+                isSynthesized: true)
+            .attachMember(_lateIsSetField!);
+        break;
+    }
+    _lateGetter = new Procedure(
+        dummyName,
+        ProcedureKind.Getter,
+        new FunctionNode(null)
+          ..fileOffset = _fragment.nameOffset
+          ..fileEndOffset = _fragment.endOffset,
+        fileUri: _fragment.fileUri,
+        reference: references.lateGetterReference)
+      ..fileOffset = _fragment.nameOffset
+      ..fileEndOffset = _fragment.endOffset;
+    nameScheme
+        .getFieldMemberName(FieldNameType.Getter, _fragment.name,
+            isSynthesized: true)
+        .attachMember(_lateGetter!);
+    _lateSetter = _createSetter(
+        _fragment.fileUri, _fragment.nameOffset, references.lateSetterReference,
+        isCovariantByDeclaration: _fragment.modifiers.isCovariant);
+    if (_lateSetter != null) {
+      nameScheme
+          .getFieldMemberName(FieldNameType.Setter, _fragment.name,
+              isSynthesized: true)
+          .attachMember(_lateSetter!);
+    }
+
+    bool isInstanceMember =
+        !_fragment.builder.isStatic && !_fragment.builder.isTopLevel;
+    bool isExtensionMember = _fragment.builder.isExtensionMember;
+    bool isExtensionTypeMember = _fragment.builder.isExtensionTypeMember;
+    if (isExtensionMember) {
+      _field!
+        ..isStatic = true
+        ..isExtensionMember = isExtensionMember;
+      isInstanceMember = false;
+    } else if (isExtensionTypeMember) {
+      // Coverage-ignore-block(suite): Not run.
+      _field!
+        ..isStatic = _fragment.builder.isStatic
+        ..isExtensionTypeMember = true;
+    } else {
+      _field!
+        ..isStatic = !isInstanceMember
+        ..isExtensionMember = false;
+    }
+    if (_lateIsSetField != null) {
+      _lateIsSetField!
+        ..isStatic = !isInstanceMember
+        ..isExtensionMember = isExtensionMember
+        ..isExtensionTypeMember = isExtensionTypeMember
+        ..type = libraryBuilder.loader
+            .createCoreType('bool', Nullability.nonNullable);
+    }
+    _lateGetter!
+      ..isStatic = !isInstanceMember
+      ..isExtensionMember = isExtensionMember
+      ..isExtensionTypeMember = isExtensionTypeMember;
+    if (_lateSetter != null) {
+      _lateSetter!
+        ..isStatic = !isInstanceMember
+        ..isExtensionMember = isExtensionMember
+        ..isExtensionTypeMember = isExtensionTypeMember;
+    }
+    _updateMemberTypes();
+  }
+
+  @override
+  void registerMembers(BuildNodesCallback f) {
+    f(
+        member: _field!,
+        kind: _fragment.builder.isExtensionMember ||
+                _fragment.builder.isExtensionTypeMember
+            ? BuiltMemberKind.ExtensionField
+            : BuiltMemberKind.Field);
+    if (_lateIsSetField != null) {
+      _forceIncludeIsSetField = true;
+      f(member: _lateIsSetField!, kind: BuiltMemberKind.LateIsSetField);
+    }
+    f(member: _lateGetter!, kind: BuiltMemberKind.LateGetter);
+    if (_lateSetter != null) {
+      f(member: _lateSetter!, kind: BuiltMemberKind.LateSetter);
+    }
+  }
+
+  @override
+  List<ClassMember> get localMembers {
+    List<ClassMember> list = [
+      new _SynthesizedFieldClassMember(_fragment.builder, field, field.name,
+          _SynthesizedFieldMemberKind.LateField, ClassMemberKind.Getter),
+      new _SynthesizedFieldClassMember(
+          _fragment.builder,
+          _lateGetter!,
+          _fragment.builder.memberName,
+          _SynthesizedFieldMemberKind.LateGetterSetter,
+          ClassMemberKind.Getter)
+    ];
+    if (_lateIsSetField != null) {
+      list.add(new _SynthesizedFieldClassMember(
+          _fragment.builder,
+          _lateIsSetField!,
+          _lateIsSetField!.name,
+          _SynthesizedFieldMemberKind.LateIsSet,
+          ClassMemberKind.Getter));
+    }
+    return list;
+  }
+
+  @override
+  List<ClassMember> get localSetters {
+    List<ClassMember> list = [
+      new _SynthesizedFieldClassMember(_fragment.builder, field, field.name,
+          _SynthesizedFieldMemberKind.LateField, ClassMemberKind.Setter),
+    ];
+    if (_lateIsSetField != null) {
+      list.add(new _SynthesizedFieldClassMember(
+          _fragment.builder,
+          _lateIsSetField!,
+          _lateIsSetField!.name,
+          _SynthesizedFieldMemberKind.LateIsSet,
+          ClassMemberKind.Setter));
+    }
+    if (_lateSetter != null) {
+      list.add(new _SynthesizedFieldClassMember(
+          _fragment.builder,
+          _lateSetter!,
+          _fragment.builder.memberName,
+          _SynthesizedFieldMemberKind.LateGetterSetter,
+          ClassMemberKind.Setter));
+    }
+    return list;
+  }
+
+  @override
+  void registerSuperCall() {
+    _field!.transformerFlags |= TransformerFlag.superCalls;
+  }
+}
+
+mixin NonFinalLate on AbstractLateFieldEncoding {
+  @override
+  Statement _createSetterBody(
+      CoreTypes coreTypes, String name, VariableDeclaration parameter) {
+    assert(_type != null, "Type has not been computed for field $name.");
+    return late_lowering.createSetterBody(
+        coreTypes, _fragment.nameOffset, name, parameter, _type!,
+        shouldReturnValue: false,
+        createVariableWrite: (Expression value) =>
+            _createFieldSet(_field!, value),
+        createIsSetWrite: (Expression value) =>
+            _createFieldSet(_lateIsSetField!, value),
+        isSetEncoding: isSetEncoding);
+  }
+}
+
+mixin LateWithoutInitializer on AbstractLateFieldEncoding {
+  @override
+  Statement _createGetterBody(
+      CoreTypes coreTypes, String name, Expression? initializer) {
+    assert(_type != null, "Type has not been computed for field $name.");
+    return late_lowering.createGetterBodyWithoutInitializer(
+        coreTypes, _fragment.nameOffset, name, type,
+        createVariableRead: _createFieldRead,
+        createIsSetRead: () => _createFieldGet(_lateIsSetField!),
+        isSetEncoding: isSetEncoding,
+        forField: true);
+  }
+
+  @override
+  void buildImplicitDefaultValue() {
+    throw new UnsupportedError("$runtimeType.buildImplicitDefaultValue");
+  }
+
+  @override
+  Initializer buildImplicitInitializer() {
+    throw new UnsupportedError("$runtimeType.buildImplicitInitializer");
+  }
+
+  @override
+  Initializer buildErroneousInitializer(Expression effect, Expression value,
+      {required int fileOffset}) {
+    throw new UnsupportedError("$runtimeType.buildDuplicatedInitializer");
+  }
+}
+
+class LateFieldWithoutInitializerEncoding extends AbstractLateFieldEncoding
+    with NonFinalLate, LateWithoutInitializer {
+  LateFieldWithoutInitializerEncoding(super._fragment,
+      {required super.isSetStrategy});
+}
+
+class LateFieldWithInitializerEncoding extends AbstractLateFieldEncoding
+    with NonFinalLate {
+  LateFieldWithInitializerEncoding(super._fragment,
+      {required super.isSetStrategy});
+
+  @override
+  Statement _createGetterBody(
+      CoreTypes coreTypes, String name, Expression? initializer) {
+    assert(_type != null, "Type has not been computed for field $name.");
+    return late_lowering.createGetterWithInitializer(
+        coreTypes, _fragment.nameOffset, name, _type!, initializer!,
+        createVariableRead: _createFieldRead,
+        createVariableWrite: (Expression value) =>
+            _createFieldSet(_field!, value),
+        createIsSetRead: () => _createFieldGet(_lateIsSetField!),
+        createIsSetWrite: (Expression value) =>
+            _createFieldSet(_lateIsSetField!, value),
+        isSetEncoding: isSetEncoding);
+  }
+
+  @override
+  void buildImplicitDefaultValue() {
+    throw new UnsupportedError("$runtimeType.buildImplicitDefaultValue");
+  }
+
+  @override
+  Initializer buildImplicitInitializer() {
+    throw new UnsupportedError("$runtimeType.buildImplicitInitializer");
+  }
+
+  @override
+  Initializer buildErroneousInitializer(Expression effect, Expression value,
+      {required int fileOffset}) {
+    throw new UnsupportedError("$runtimeType.buildDuplicatedInitializer");
+  }
+}
+
+class LateFinalFieldWithoutInitializerEncoding extends AbstractLateFieldEncoding
+    with LateWithoutInitializer {
+  LateFinalFieldWithoutInitializerEncoding(super._fragment,
+      {required super.isSetStrategy});
+
+  @override
+  Statement _createSetterBody(
+      CoreTypes coreTypes, String name, VariableDeclaration parameter) {
+    assert(_type != null, "Type has not been computed for field $name.");
+    return late_lowering.createSetterBodyFinal(
+        coreTypes, _fragment.nameOffset, name, parameter, type,
+        shouldReturnValue: false,
+        createVariableRead: () => _createFieldGet(_field!),
+        createVariableWrite: (Expression value) =>
+            _createFieldSet(_field!, value),
+        createIsSetRead: () => _createFieldGet(_lateIsSetField!),
+        createIsSetWrite: (Expression value) =>
+            _createFieldSet(_lateIsSetField!, value),
+        isSetEncoding: isSetEncoding,
+        forField: true);
+  }
+}
+
+class LateFinalFieldWithInitializerEncoding extends AbstractLateFieldEncoding {
+  LateFinalFieldWithInitializerEncoding(super._fragment,
+      {required super.isSetStrategy});
+
+  @override
+  Statement _createGetterBody(
+      CoreTypes coreTypes, String name, Expression? initializer) {
+    assert(_type != null, "Type has not been computed for field $name.");
+    return late_lowering.createGetterWithInitializerWithRecheck(
+        coreTypes, _fragment.nameOffset, name, _type!, initializer!,
+        createVariableRead: _createFieldRead,
+        createVariableWrite: (Expression value) =>
+            _createFieldSet(_field!, value),
+        createIsSetRead: () => _createFieldGet(_lateIsSetField!),
+        createIsSetWrite: (Expression value) =>
+            _createFieldSet(_lateIsSetField!, value),
+        isSetEncoding: isSetEncoding,
+        forField: true);
+  }
+
+  @override
+  Procedure? _createSetter(Uri fileUri, int charOffset, Reference? reference,
+          {required bool isCovariantByDeclaration}) =>
+      null;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  Statement _createSetterBody(
+          CoreTypes coreTypes, String name, VariableDeclaration parameter) =>
+      throw new UnsupportedError(
+          '$runtimeType._createSetterBody is not supported.');
+
+  @override
+  void buildImplicitDefaultValue() {
+    throw new UnsupportedError("$runtimeType.buildImplicitDefaultValue");
+  }
+
+  @override
+  Initializer buildImplicitInitializer() {
+    throw new UnsupportedError("$runtimeType.buildImplicitInitializer");
+  }
+
+  @override
+  Initializer buildErroneousInitializer(Expression effect, Expression value,
+      {required int fileOffset}) {
+    throw new UnsupportedError("$runtimeType.buildDuplicatedInitializer");
+  }
+}
+
+class AbstractOrExternalFieldEncoding implements _FieldEncoding {
+  final FieldFragment _fragment;
+  final bool isAbstract;
+  final bool isExternal;
+  final bool _isExtensionInstanceMember;
+  final bool _isExtensionTypeInstanceMember;
+
+  Procedure? _getter;
+  Procedure? _setter;
+  DartType? _type;
+
+  AbstractOrExternalFieldEncoding(this._fragment,
+      {required bool isExtensionInstanceMember,
+      required bool isExtensionTypeInstanceMember,
+      required this.isAbstract,
+      required this.isExternal,
+      bool isForcedExtension = false})
+      : _isExtensionInstanceMember =
+            (isExternal || isForcedExtension) && isExtensionInstanceMember,
+        _isExtensionTypeInstanceMember =
+            (isExternal || isForcedExtension) && isExtensionTypeInstanceMember;
+
+  @override
+  DartType get type {
+    assert(_type != null,
+        "Type has not been computed for field ${_fragment.name}.");
+    return _type!;
+  }
+
+  /// Updates the getter/setter types of [_getter] and [_setter] to match the
+  /// value of [_type].
+  ///
+  /// This allows for creating the members and computing the type in arbitrary
+  /// order.
+  void _updateMemberTypes() {
+    Procedure? getter = _getter;
+    Procedure? setter = _setter;
+    DartType? type = _type;
+    if (type != null && type is! InferredType && getter != null) {
+      if (_isExtensionInstanceMember || _isExtensionTypeInstanceMember) {
+        DartType thisParameterType;
+        List<TypeParameter> typeParameters;
+        if (_isExtensionInstanceMember) {
+          SourceExtensionBuilder extensionBuilder =
+              _fragment.builder.parent as SourceExtensionBuilder;
+          thisParameterType = extensionBuilder.extension.onType;
+          typeParameters = extensionBuilder.extension.typeParameters;
+        } else {
+          SourceExtensionTypeDeclarationBuilder
+              extensionTypeDeclarationBuilder =
+              _fragment.builder.parent as SourceExtensionTypeDeclarationBuilder;
+          thisParameterType = extensionTypeDeclarationBuilder
+              .extensionTypeDeclaration.declaredRepresentationType;
+          typeParameters = extensionTypeDeclarationBuilder
+              .extensionTypeDeclaration.typeParameters;
+        }
+        if (typeParameters.isNotEmpty) {
+          FreshTypeParameters getterTypeParameters =
+              getFreshTypeParameters(typeParameters);
+          getter.function.positionalParameters.first.type =
+              getterTypeParameters.substitute(thisParameterType);
+          getter.function.returnType = getterTypeParameters.substitute(type);
+          getter.function.typeParameters =
+              getterTypeParameters.freshTypeParameters;
+          setParents(getterTypeParameters.freshTypeParameters, getter.function);
+
+          if (setter != null) {
+            FreshTypeParameters setterTypeParameters =
+                getFreshTypeParameters(typeParameters);
+            setter.function.positionalParameters.first.type =
+                setterTypeParameters.substitute(thisParameterType);
+            setter.function.positionalParameters[1].type =
+                setterTypeParameters.substitute(type);
+            setter.function.typeParameters =
+                setterTypeParameters.freshTypeParameters;
+            setParents(
+                setterTypeParameters.freshTypeParameters, setter.function);
+          }
+        } else {
+          getter.function.returnType = type;
+          setter?.function.positionalParameters[1].type = type;
+          getter.function.positionalParameters.first.type = thisParameterType;
+          setter?.function.positionalParameters.first.type = thisParameterType;
+        }
+      } else {
+        getter.function.returnType = type;
+        if (setter != null) {
+          if (setter.kind == ProcedureKind.Method) {
+            // Coverage-ignore-block(suite): Not run.
+            setter.function.positionalParameters[1].type = type;
+          } else {
+            setter.function.positionalParameters.first.type = type;
+          }
+        }
+      }
+    }
+  }
+
+  @override
+  void set type(DartType value) {
+    assert(_type == null || _type is InferredType,
+        "Type has already been computed for field ${_fragment.name}.");
+    _type = value;
+    _updateMemberTypes();
+  }
+
+  @override
+  void createBodies(CoreTypes coreTypes, Expression? initializer) {
+    // TODO(johnniwinther): Enable this assert.
+    //assert(initializer != null);
+  }
+
+  @override
+  List<Initializer> createInitializer(int fileOffset, Expression value,
+      {required bool isSynthetic}) {
+    throw new UnsupportedError('ExternalFieldEncoding.createInitializer');
+  }
+
+  @override
+  void buildOutlineNode(SourceLibraryBuilder libraryBuilder,
+      NameScheme nameScheme, FieldReference references,
+      {required bool isAbstractOrExternal,
+      required List<TypeParameter>? classTypeParameters}) {
+    if (_isExtensionInstanceMember || _isExtensionTypeInstanceMember) {
+      _getter = new Procedure(
+          dummyName,
+          ProcedureKind.Method,
+          new FunctionNode(null, positionalParameters: [
+            new VariableDeclaration(syntheticThisName)
+              ..fileOffset = _fragment.nameOffset
+              ..isLowered = true
+          ]),
+          fileUri: _fragment.fileUri,
+          reference: references.fieldGetterReference)
+        ..fileOffset = _fragment.nameOffset
+        ..fileEndOffset = _fragment.endOffset;
+      nameScheme
+          .getProcedureMemberName(ProcedureKind.Getter, _fragment.name)
+          .attachMember(_getter!);
+      if (!_fragment.modifiers.isFinal) {
+        VariableDeclaration parameter =
+            new VariableDeclaration("#externalFieldValue", isSynthesized: true)
+              ..isCovariantByDeclaration = _fragment.modifiers.isCovariant
+              ..fileOffset = _fragment.nameOffset;
+        _setter = new Procedure(
+            dummyName,
+            ProcedureKind.Method,
+            new FunctionNode(null,
+                positionalParameters: [
+                  new VariableDeclaration(syntheticThisName)
+                    ..fileOffset = _fragment.nameOffset
+                    ..isLowered = true,
+                  parameter
+                ],
+                returnType: const VoidType())
+              ..fileOffset = _fragment.nameOffset
+              ..fileEndOffset = _fragment.endOffset,
+            fileUri: _fragment.fileUri,
+            reference: references.fieldSetterReference)
+          ..fileOffset = _fragment.nameOffset
+          ..fileEndOffset = _fragment.endOffset;
+        nameScheme
+            .getProcedureMemberName(ProcedureKind.Setter, _fragment.name)
+            .attachMember(_setter!);
+      }
+    } else {
+      _getter = new Procedure(
+          dummyName, ProcedureKind.Getter, new FunctionNode(null),
+          fileUri: _fragment.fileUri,
+          reference: references.fieldGetterReference)
+        ..fileOffset = _fragment.nameOffset
+        ..fileEndOffset = _fragment.endOffset;
+      nameScheme
+          .getFieldMemberName(FieldNameType.Getter, _fragment.name,
+              isSynthesized: true)
+          .attachMember(_getter!);
+      if (!_fragment.modifiers.isFinal) {
+        VariableDeclaration parameter =
+            new VariableDeclaration("#externalFieldValue", isSynthesized: true)
+              ..isCovariantByDeclaration = _fragment.modifiers.isCovariant
+              ..fileOffset = _fragment.nameOffset;
+        _setter = new Procedure(
+            dummyName,
+            ProcedureKind.Setter,
+            new FunctionNode(null,
+                positionalParameters: [parameter], returnType: const VoidType())
+              ..fileOffset = _fragment.nameOffset
+              ..fileEndOffset = _fragment.endOffset,
+            fileUri: _fragment.fileUri,
+            reference: references.fieldSetterReference)
+          ..fileOffset = _fragment.nameOffset
+          ..fileEndOffset = _fragment.endOffset;
+        nameScheme
+            .getFieldMemberName(FieldNameType.Setter, _fragment.name,
+                isSynthesized: true)
+            .attachMember(_setter!);
+      }
+    }
+
+    bool isExtensionMember = _fragment.builder.isExtensionMember;
+    bool isExtensionTypeMember = _fragment.builder.isExtensionTypeMember;
+    bool isInstanceMember = !isExtensionMember &&
+        !isExtensionTypeMember &&
+        !_fragment.builder.isStatic &&
+        !_fragment.builder.isTopLevel;
+    _getter!
+      ..isConst = _fragment.modifiers.isConst
+      ..isStatic = !isInstanceMember
+      ..isExtensionMember = isExtensionMember
+      ..isExtensionTypeMember = isExtensionTypeMember
+      ..isAbstract = isAbstract && !isExternal
+      ..isExternal = isExternal;
+
+    _setter
+      ?..isStatic = !isInstanceMember
+      ..isExtensionMember = isExtensionMember
+      ..isExtensionTypeMember = isExtensionTypeMember
+      ..isAbstract = isAbstract && !isExternal
+      ..isExternal = isExternal;
+
+    _updateMemberTypes();
+  }
+
+  @override
+  void registerMembers(BuildNodesCallback f) {
+    BuiltMemberKind getterMemberKind;
+    if (_fragment.builder.isExtensionMember) {
+      getterMemberKind = BuiltMemberKind.ExtensionGetter;
+    } else if (_fragment.builder.isExtensionTypeMember) {
+      getterMemberKind = BuiltMemberKind.ExtensionTypeGetter;
+    } else {
+      getterMemberKind = BuiltMemberKind.Method;
+    }
+    f(member: _getter!, kind: getterMemberKind);
+    if (_setter != null) {
+      BuiltMemberKind setterMemberKind;
+      if (_fragment.builder.isExtensionMember) {
+        setterMemberKind = BuiltMemberKind.ExtensionSetter;
+      } else if (_fragment.builder.isExtensionTypeMember) {
+        setterMemberKind = BuiltMemberKind.ExtensionTypeSetter;
+      } else {
+        setterMemberKind = BuiltMemberKind.Method;
+      }
+      f(member: _setter!, kind: setterMemberKind);
+    }
+  }
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  void setCovariantByClass() {
+    _setter!.function.positionalParameters.first.isCovariantByClass = true;
+  }
+
+  @override
+  Field get field {
+    throw new UnsupportedError("ExternalFieldEncoding.field");
+  }
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  Member get builtMember => _getter!;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  Iterable<Annotatable> get annotatables {
+    List<Annotatable> list = [_getter!];
+    if (_setter != null) {
+      list.add(_setter!);
+    }
+    return list;
+  }
+
+  @override
+  Member get readTarget => _getter!;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  Reference get readTargetReference => _getter!.reference;
+
+  @override
+  Member? get writeTarget => _setter;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  Reference? get writeTargetReference => _setter?.reference;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  Iterable<Reference> get exportedReferenceMembers {
+    if (_setter != null) {
+      return [_getter!.reference, _setter!.reference];
+    }
+    return [_getter!.reference];
+  }
+
+  @override
+  List<ClassMember> get localMembers => <ClassMember>[
+        new _SynthesizedFieldClassMember(
+            _fragment.builder,
+            _getter!,
+            _fragment.builder.memberName,
+            _SynthesizedFieldMemberKind.AbstractExternalGetterSetter,
+            ClassMemberKind.Getter)
+      ];
+
+  @override
+  List<ClassMember> get localSetters => _setter != null
+      ? <ClassMember>[
+          new _SynthesizedFieldClassMember(
+              _fragment.builder,
+              _setter!,
+              _fragment.builder.memberName,
+              _SynthesizedFieldMemberKind.AbstractExternalGetterSetter,
+              ClassMemberKind.Setter)
+        ]
+      : const <ClassMember>[];
+
+  @override
+  void buildImplicitDefaultValue() {
+    throw new UnsupportedError("$runtimeType.buildImplicitDefaultValue");
+  }
+
+  @override
+  Initializer buildImplicitInitializer() {
+    throw new UnsupportedError("$runtimeType.buildImplicitInitializer");
+  }
+
+  @override
+  Initializer buildErroneousInitializer(Expression effect, Expression value,
+      {required int fileOffset}) {
+    return new ShadowInvalidFieldInitializer(type, value, effect)
+      ..fileOffset = fileOffset;
+  }
+
+  @override
+  void registerSuperCall() {
+    throw new UnsupportedError(
+        "Unexpected call to ${runtimeType}.registerSuperCall().");
+  }
+}
+
+/// The encoding of an extension type declaration representation field.
+class RepresentationFieldEncoding implements _FieldEncoding {
+  final FieldFragment _fragment;
+
+  late Procedure _getter;
+  DartType? _type;
+
+  RepresentationFieldEncoding(this._fragment);
+  @override
+  DartType get type {
+    assert(_type != null,
+        "Type has not been computed for field ${_fragment.name}.");
+    return _type!;
+  }
+
+  @override
+  void set type(DartType value) {
+    assert(
+        _type == null ||
+            // Coverage-ignore(suite): Not run.
+            _type is InferredType,
+        "Type has already been computed for field ${_fragment.name}.");
+    _type = value;
+    if (value is! InferredType) {
+      _getter.function.returnType = value;
+    }
+  }
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  void createBodies(CoreTypes coreTypes, Expression? initializer) {
+    // TODO(johnniwinther): Enable this assert.
+    //assert(initializer != null);
+  }
+
+  @override
+  List<Initializer> createInitializer(int fileOffset, Expression value,
+      {required bool isSynthetic}) {
+    return <Initializer>[
+      new ExtensionTypeRepresentationFieldInitializer(_getter, value)
+    ];
+  }
+
+  @override
+  void buildOutlineNode(SourceLibraryBuilder libraryBuilder,
+      NameScheme nameScheme, FieldReference references,
+      {required bool isAbstractOrExternal,
+      required List<TypeParameter>? classTypeParameters}) {
+    _getter = new Procedure(
+        dummyName, ProcedureKind.Getter, new FunctionNode(null),
+        fileUri: _fragment.fileUri, reference: references.fieldGetterReference)
+      ..stubKind = ProcedureStubKind.RepresentationField
+      ..fileOffset = _fragment.nameOffset
+      ..fileEndOffset = _fragment.endOffset;
+    nameScheme
+        .getFieldMemberName(FieldNameType.RepresentationField, _fragment.name,
+            isSynthesized: true)
+        .attachMember(_getter);
+    _getter..isConst = _fragment.modifiers.isConst;
+    _getter
+      ..isStatic = false
+      ..isExtensionMember = false
+      ..isExtensionTypeMember = true
+      ..isAbstract = true
+      ..isExternal = false;
+  }
+
+  @override
+  void registerMembers(BuildNodesCallback f) {
+    f(member: _getter, kind: BuiltMemberKind.ExtensionTypeRepresentationField);
+  }
+
+  @override
+  void setCovariantByClass() {
+    throw new UnsupportedError("$runtimeType.setGenericCovariantImpl");
+  }
+
+  @override
+  Field get field {
+    throw new UnsupportedError("$runtimeType.field");
+  }
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  Member get builtMember => _getter;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  Iterable<Annotatable> get annotatables => [_getter];
+
+  @override
+  Member get readTarget => _getter;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  Reference get readTargetReference => _getter.reference;
+
+  @override
+  Member? get writeTarget => null;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  Reference? get writeTargetReference => null;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  Iterable<Reference> get exportedReferenceMembers => [_getter.reference];
+
+  @override
+  List<ClassMember> get localMembers => [
+        new _SynthesizedFieldClassMember(
+            _fragment.builder,
+            _getter,
+            _fragment.builder.memberName,
+            _SynthesizedFieldMemberKind.RepresentationField,
+            ClassMemberKind.Getter)
+      ];
+
+  @override
+  List<ClassMember> get localSetters => const [];
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  void buildImplicitDefaultValue() {
+    // Not needed.
+  }
+
+  @override
+  Initializer buildImplicitInitializer() {
+    return new ExtensionTypeRepresentationFieldInitializer(
+        _getter, new NullLiteral());
+  }
+
+  @override
+  Initializer buildErroneousInitializer(Expression effect, Expression value,
+      {required int fileOffset}) {
+    return new ShadowInvalidFieldInitializer(type, value, effect)
+      ..fileOffset = fileOffset;
+  }
+
+  @override
+  void registerSuperCall() {
+    throw new UnsupportedError(
+        "Unexpected call to ${runtimeType}.registerSuperCall().");
+  }
+}
diff --git a/pkg/front_end/lib/src/fragment/fragment.dart b/pkg/front_end/lib/src/fragment/fragment.dart
index 4fd060f..3b3a131 100644
--- a/pkg/front_end/lib/src/fragment/fragment.dart
+++ b/pkg/front_end/lib/src/fragment/fragment.dart
@@ -2,16 +2,22 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:_fe_analyzer_shared/src/metadata/expressions.dart' as shared;
 import 'package:_fe_analyzer_shared/src/parser/member_kind.dart';
 import 'package:_fe_analyzer_shared/src/scanner/scanner.dart' show Token;
 import 'package:kernel/ast.dart';
 import 'package:kernel/class_hierarchy.dart';
+import 'package:kernel/core_types.dart';
 import 'package:kernel/transformations/flags.dart';
 import 'package:kernel/type_algebra.dart';
 import 'package:kernel/type_environment.dart';
 
+import '../api_prototype/codes.dart';
+import '../api_prototype/lowering_predicates.dart';
+import '../base/constant_context.dart';
 import '../base/local_scope.dart';
 import '../base/modifiers.dart';
+import '../base/problems.dart';
 import '../base/scope.dart';
 import '../builder/builder.dart';
 import '../builder/constructor_reference_builder.dart';
@@ -19,27 +25,32 @@
 import '../builder/formal_parameter_builder.dart';
 import '../builder/metadata_builder.dart';
 import '../builder/mixin_application_builder.dart';
+import '../builder/named_type_builder.dart';
 import '../builder/omitted_type_builder.dart';
 import '../builder/type_builder.dart';
+import '../kernel/body_builder.dart';
 import '../kernel/body_builder_context.dart';
 import '../kernel/hierarchy/class_member.dart';
 import '../kernel/hierarchy/members_builder.dart';
+import '../kernel/implicit_field_type.dart';
 import '../kernel/internal_ast.dart';
+import '../kernel/late_lowering.dart' as late_lowering;
+import '../kernel/macro/metadata.dart' hide FieldReference;
+import '../kernel/member_covariance.dart';
 import '../kernel/type_algorithms.dart';
 import '../source/name_scheme.dart';
-import '../source/source_property_builder.dart';
 import '../source/source_class_builder.dart';
 import '../source/source_constructor_builder.dart';
 import '../source/source_enum_builder.dart';
 import '../source/source_extension_builder.dart';
 import '../source/source_extension_type_declaration_builder.dart';
 import '../source/source_factory_builder.dart';
-import '../source/source_field_builder.dart';
 import '../source/source_function_builder.dart';
 import '../source/source_library_builder.dart';
 import '../source/source_loader.dart';
 import '../source/source_member_builder.dart';
 import '../source/source_method_builder.dart';
+import '../source/source_property_builder.dart';
 import '../source/source_type_alias_builder.dart';
 import '../source/type_parameter_scope_builder.dart';
 import '../type_inference/type_inference_engine.dart';
@@ -52,6 +63,9 @@
 part 'extension_type.dart';
 part 'factory.dart';
 part 'field.dart';
+part 'field/body_builder_context.dart';
+part 'field/class_member.dart';
+part 'field/encoding.dart';
 part 'function.dart';
 part 'getter.dart';
 part 'method.dart';
diff --git a/pkg/front_end/lib/src/fragment/getter.dart b/pkg/front_end/lib/src/fragment/getter.dart
index 5097931..96e7659 100644
--- a/pkg/front_end/lib/src/fragment/getter.dart
+++ b/pkg/front_end/lib/src/fragment/getter.dart
@@ -133,11 +133,9 @@
   }
 
   void buildOutlineNode(SourceLibraryBuilder libraryBuilder,
-      NameScheme nameScheme, BuildNodesCallback f,
-      {required Reference getterReference,
-      required List<TypeParameter>? classTypeParameters}) {
-    _encoding.buildOutlineNode(libraryBuilder, nameScheme, f,
-        getterReference: getterReference,
+      NameScheme nameScheme, BuildNodesCallback f, GetterReference references,
+      {required List<TypeParameter>? classTypeParameters}) {
+    _encoding.buildOutlineNode(libraryBuilder, nameScheme, f, references,
         isAbstractOrExternal: modifiers.isAbstract || modifiers.isExternal,
         classTypeParameters: classTypeParameters);
   }
@@ -161,6 +159,9 @@
         createFileUriExpression: createFileUriExpression);
   }
 
+  Iterable<Reference> getExportedMemberReferences(GetterReference references) =>
+      [references.getterReference];
+
   BodyBuilderContext createBodyBuilderContext() {
     return new _GetterFragmentBodyBuilderContext(
         this, builder.libraryBuilder, builder.declarationBuilder,
@@ -175,20 +176,20 @@
     return _encoding.computeDefaultTypes(context);
   }
 
-  void ensureTypes(
-      ClassMembersBuilder membersBuilder,
-      SourceClassBuilder enclosingClassBuilder,
+  void ensureTypes(ClassMembersBuilder membersBuilder,
       Set<ClassMember>? getterOverrideDependencies) {
     if (getterOverrideDependencies != null) {
       membersBuilder.inferGetterType(
-          enclosingClassBuilder, returnType, getterOverrideDependencies,
+          builder.declarationBuilder as SourceClassBuilder,
+          returnType,
+          getterOverrideDependencies,
           name: name,
           fileUri: fileUri,
           nameOffset: nameOffset,
           nameLength: name.length);
     }
     _encoding.ensureTypes(
-        enclosingClassBuilder.libraryBuilder, membersBuilder.hierarchyBuilder);
+        builder.libraryBuilder, membersBuilder.hierarchyBuilder);
   }
 
   void checkTypes(SourceLibraryBuilder libraryBuilder,
@@ -269,9 +270,8 @@
   Procedure get readTarget;
 
   void buildOutlineNode(SourceLibraryBuilder libraryBuilder,
-      NameScheme nameScheme, BuildNodesCallback f,
-      {required Reference getterReference,
-      required bool isAbstractOrExternal,
+      NameScheme nameScheme, BuildNodesCallback f, GetterReference references,
+      {required bool isAbstractOrExternal,
       required List<TypeParameter>? classTypeParameters});
 
   void buildOutlineExpressions(
@@ -328,9 +328,8 @@
 
   @override
   void buildOutlineNode(SourceLibraryBuilder libraryBuilder,
-      NameScheme nameScheme, BuildNodesCallback f,
-      {required Reference getterReference,
-      required bool isAbstractOrExternal,
+      NameScheme nameScheme, BuildNodesCallback f, GetterReference references,
+      {required bool isAbstractOrExternal,
       List<TypeParameter>? classTypeParameters}) {
     FunctionNode function = new FunctionNode(
         isAbstractOrExternal ? null : new EmptyStatement(),
@@ -349,7 +348,7 @@
         nameScheme.getProcedureMemberName(ProcedureKind.Getter, _fragment.name);
     Procedure procedure = _procedure = new Procedure(
         memberName.name, ProcedureKind.Getter, function,
-        reference: getterReference, fileUri: _fragment.fileUri)
+        reference: references.getterReference, fileUri: _fragment.fileUri)
       ..fileStartOffset = _fragment.startOffset
       ..fileOffset = _fragment.nameOffset
       ..fileEndOffset = _fragment.endOffset
@@ -556,9 +555,8 @@
 
   @override
   void buildOutlineNode(SourceLibraryBuilder libraryBuilder,
-      NameScheme nameScheme, BuildNodesCallback f,
-      {required Reference getterReference,
-      required bool isAbstractOrExternal,
+      NameScheme nameScheme, BuildNodesCallback f, GetterReference references,
+      {required bool isAbstractOrExternal,
       required List<TypeParameter>? classTypeParameters}) {
     List<TypeParameter>? typeParameters;
     if (_clonedDeclarationTypeParameters != null) {
@@ -589,7 +587,7 @@
         nameScheme.getProcedureMemberName(ProcedureKind.Getter, _fragment.name);
     Procedure procedure = _procedure = new Procedure(
         memberName.name, ProcedureKind.Method, function,
-        reference: getterReference, fileUri: _fragment.fileUri)
+        reference: references.getterReference, fileUri: _fragment.fileUri)
       ..fileStartOffset = _fragment.startOffset
       ..fileOffset = _fragment.nameOffset
       ..fileEndOffset = _fragment.endOffset
diff --git a/pkg/front_end/lib/src/fragment/setter.dart b/pkg/front_end/lib/src/fragment/setter.dart
index 952b59e..d28c135 100644
--- a/pkg/front_end/lib/src/fragment/setter.dart
+++ b/pkg/front_end/lib/src/fragment/setter.dart
@@ -125,11 +125,9 @@
   }
 
   void buildOutlineNode(SourceLibraryBuilder libraryBuilder,
-      NameScheme nameScheme, BuildNodesCallback f,
-      {required Reference setterReference,
-      required List<TypeParameter>? classTypeParameters}) {
-    _encoding.buildOutlineNode(libraryBuilder, nameScheme, f,
-        setterReference: setterReference,
+      NameScheme nameScheme, BuildNodesCallback f, SetterReference references,
+      {required List<TypeParameter>? classTypeParameters}) {
+    _encoding.buildOutlineNode(libraryBuilder, nameScheme, f, references,
         isAbstractOrExternal: modifiers.isAbstract || modifiers.isExternal,
         classTypeParameters: classTypeParameters);
   }
@@ -153,20 +151,23 @@
         createFileUriExpression: createFileUriExpression);
   }
 
-  void ensureTypes(
-      ClassMembersBuilder membersBuilder,
-      SourceClassBuilder enclosingClassBuilder,
+  Iterable<Reference> getExportedMemberReferences(SetterReference references) =>
+      [references.setterReference];
+
+  void ensureTypes(ClassMembersBuilder membersBuilder,
       Set<ClassMember>? setterOverrideDependencies) {
     if (setterOverrideDependencies != null) {
       membersBuilder.inferSetterType(
-          enclosingClassBuilder, declaredFormals, setterOverrideDependencies,
+          builder.declarationBuilder as SourceClassBuilder,
+          declaredFormals,
+          setterOverrideDependencies,
           name: name,
           fileUri: fileUri,
           nameOffset: nameOffset,
           nameLength: name.length);
     }
     _encoding.ensureTypes(
-        enclosingClassBuilder.libraryBuilder, membersBuilder.hierarchyBuilder);
+        builder.libraryBuilder, membersBuilder.hierarchyBuilder);
   }
 
   void checkTypes(
@@ -266,9 +267,8 @@
   Procedure get writeTarget;
 
   void buildOutlineNode(SourceLibraryBuilder libraryBuilder,
-      NameScheme nameScheme, BuildNodesCallback f,
-      {required Reference setterReference,
-      required bool isAbstractOrExternal,
+      NameScheme nameScheme, BuildNodesCallback f, SetterReference references,
+      {required bool isAbstractOrExternal,
       required List<TypeParameter>? classTypeParameters});
 
   void buildOutlineExpressions(
@@ -353,9 +353,8 @@
 
   @override
   void buildOutlineNode(SourceLibraryBuilder libraryBuilder,
-      NameScheme nameScheme, BuildNodesCallback f,
-      {required Reference setterReference,
-      required bool isAbstractOrExternal,
+      NameScheme nameScheme, BuildNodesCallback f, SetterReference references,
+      {required bool isAbstractOrExternal,
       List<TypeParameter>? classTypeParameters}) {
     FunctionNode function = new FunctionNode(
         isAbstractOrExternal ? null : new EmptyStatement(),
@@ -385,7 +384,7 @@
         nameScheme.getProcedureMemberName(ProcedureKind.Setter, _fragment.name);
     Procedure procedure = _procedure = new Procedure(
         memberName.name, ProcedureKind.Setter, function,
-        reference: setterReference, fileUri: _fragment.fileUri)
+        reference: references.setterReference, fileUri: _fragment.fileUri)
       ..fileStartOffset = _fragment.startOffset
       ..fileOffset = _fragment.nameOffset
       ..fileEndOffset = _fragment.endOffset
@@ -580,9 +579,8 @@
 
   @override
   void buildOutlineNode(SourceLibraryBuilder libraryBuilder,
-      NameScheme nameScheme, BuildNodesCallback f,
-      {required Reference setterReference,
-      required bool isAbstractOrExternal,
+      NameScheme nameScheme, BuildNodesCallback f, SetterReference references,
+      {required bool isAbstractOrExternal,
       required List<TypeParameter>? classTypeParameters}) {
     List<TypeParameter>? typeParameters;
     if (_clonedDeclarationTypeParameters != null) {
@@ -630,7 +628,7 @@
         nameScheme.getProcedureMemberName(ProcedureKind.Setter, _fragment.name);
     Procedure procedure = _procedure = new Procedure(
         memberName.name, ProcedureKind.Method, function,
-        reference: setterReference, fileUri: _fragment.fileUri)
+        reference: references.setterReference, fileUri: _fragment.fileUri)
       ..fileStartOffset = _fragment.startOffset
       ..fileOffset = _fragment.nameOffset
       ..fileEndOffset = _fragment.endOffset
diff --git a/pkg/front_end/lib/src/kernel/body_builder.dart b/pkg/front_end/lib/src/kernel/body_builder.dart
index 920295e..8dd7677 100644
--- a/pkg/front_end/lib/src/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/kernel/body_builder.dart
@@ -73,6 +73,7 @@
 import '../builder/nullability_builder.dart';
 import '../builder/omitted_type_builder.dart';
 import '../builder/prefix_builder.dart';
+import '../builder/property_builder.dart';
 import '../builder/record_type_builder.dart';
 import '../builder/type_builder.dart';
 import '../builder/variable_builder.dart';
@@ -91,9 +92,9 @@
         templateLocalVariableUsedBeforeDeclaredContext;
 import '../codes/cfe_codes.dart' as cfe;
 import '../dill/dill_library_builder.dart' show DillLibraryBuilder;
+import '../fragment/fragment.dart';
 import '../source/diet_parser.dart';
 import '../source/offset_map.dart';
-import '../source/source_field_builder.dart';
 import '../source/source_library_builder.dart';
 import '../source/source_member_builder.dart';
 import '../source/stack_listener_impl.dart'
@@ -977,16 +978,16 @@
       ]));
       Expression? initializer = pop() as Expression?;
       Identifier identifier = pop() as Identifier;
-      SourceFieldBuilder fieldBuilder = offsetMap.lookupField(identifier);
+      FieldFragment fieldFragment = offsetMap.lookupField(identifier);
       if (initializer != null) {
-        if (!fieldBuilder.hasBodyBeenBuilt) {
+        if (!fieldFragment.hasBodyBeenBuilt) {
           initializer = typeInferrer
-              .inferFieldInitializer(this, fieldBuilder.builtType, initializer)
+              .inferFieldInitializer(this, fieldFragment.fieldType, initializer)
               .expression;
-          fieldBuilder.buildBody(coreTypes, initializer);
+          fieldFragment.buildBody(coreTypes, initializer);
         }
-      } else if (!fieldBuilder.hasBodyBeenBuilt) {
-        fieldBuilder.buildBody(coreTypes, null);
+      } else if (!fieldFragment.hasBodyBeenBuilt) {
+        fieldFragment.buildBody(coreTypes, null);
       }
     }
     assert(checkState(
@@ -9070,7 +9071,7 @@
   }
 
   Initializer buildDuplicatedInitializer(
-      SourceFieldBuilder fieldBuilder,
+      PropertyBuilder fieldBuilder,
       Expression value,
       String name,
       int offset,
@@ -9105,7 +9106,9 @@
     if (builder?.next != null) {
       // Duplicated name, already reported.
       while (builder != null) {
-        if (builder.next == null && builder is SourceFieldBuilder) {
+        if (builder.next == null &&
+            builder is PropertyBuilder &&
+            builder.isField) {
           // Assume the first field has been initialized.
           _context.registerInitializedField(builder);
         }
@@ -9122,7 +9125,8 @@
             ),
             fieldNameOffset)
       ];
-    } else if (builder is SourceFieldBuilder &&
+    } else if (builder is PropertyBuilder &&
+        builder.isField &&
         builder.isDeclarationInstanceMember) {
       if (builder.isExtensionTypeDeclaredInstanceField) {
         // Operating on an invalid field. Don't report anything though
diff --git a/pkg/front_end/lib/src/kernel/body_builder_context.dart b/pkg/front_end/lib/src/kernel/body_builder_context.dart
index 684fe4c..511db32 100644
--- a/pkg/front_end/lib/src/kernel/body_builder_context.dart
+++ b/pkg/front_end/lib/src/kernel/body_builder_context.dart
@@ -15,6 +15,7 @@
 import '../builder/formal_parameter_builder.dart';
 import '../builder/library_builder.dart';
 import '../builder/named_type_builder.dart';
+import '../builder/property_builder.dart';
 import '../builder/type_builder.dart';
 import '../dill/dill_class_builder.dart';
 import '../source/constructor_declaration.dart';
@@ -50,6 +51,10 @@
         _declarationContext = new BodyBuilderDeclarationContext(
             libraryBuilder, declarationBuilder);
 
+  /// Returns `true` if the enclosing declaration declares a const constructor.
+  bool get declarationDeclaresConstConstructor =>
+      _declarationContext.declaresConstConstructor;
+
   /// Returns the file offset of the name of the member whose body is being
   /// built.
   ///
@@ -282,7 +287,7 @@
 
   /// Registers that the field [builder] has been initialized in generative
   /// constructor whose body is being built.
-  void registerInitializedField(SourceFieldBuilder builder) {
+  void registerInitializedField(PropertyBuilder builder) {
     throw new UnsupportedError('${runtimeType}.registerInitializedField');
   }
 
@@ -748,15 +753,19 @@
             isDeclarationInstanceMember: _member.isDeclarationInstanceMember);
 
   @override
+  // Coverage-ignore(suite): Not run.
   bool get isLateField => _member.isLate;
 
   @override
+  // Coverage-ignore(suite): Not run.
   bool get isAbstractField => _member.isAbstract;
 
   @override
+  // Coverage-ignore(suite): Not run.
   bool get isExternalField => _member.isExternal;
 
   @override
+  // Coverage-ignore(suite): Not run.
   InstanceTypeParameterAccessState get instanceTypeParameterAccessState {
     if (_member.isExtensionMember && !_member.isExternal) {
       return InstanceTypeParameterAccessState.Invalid;
@@ -766,6 +775,7 @@
   }
 
   @override
+  // Coverage-ignore(suite): Not run.
   ConstantContext get constantContext {
     return _member.isConst
         ? ConstantContext.inferred
@@ -852,7 +862,7 @@
   }
 
   @override
-  void registerInitializedField(SourceFieldBuilder builder) {
+  void registerInitializedField(PropertyBuilder builder) {
     _member.registerInitializedField(builder);
   }
 
diff --git a/pkg/front_end/lib/src/kernel/expression_generator.dart b/pkg/front_end/lib/src/kernel/expression_generator.dart
index 48cb7cf..4e77f1b 100644
--- a/pkg/front_end/lib/src/kernel/expression_generator.dart
+++ b/pkg/front_end/lib/src/kernel/expression_generator.dart
@@ -1979,6 +1979,10 @@
       } else if (getterBuilder.isField) {
         assert(!getterBuilder.isStatic);
         MemberBuilder memberBuilder = getterBuilder as MemberBuilder;
+        assert(
+            memberBuilder.invokeTarget is Procedure?,
+            "Unexpected invoke target ${memberBuilder.invokeTarget} "
+            "(${memberBuilder.invokeTarget.runtimeType}) on ${memberBuilder}.");
         readTarget = memberBuilder.invokeTarget as Procedure?;
       } else {
         return unhandled(
diff --git a/pkg/front_end/lib/src/kernel/hierarchy/class_member.dart b/pkg/front_end/lib/src/kernel/hierarchy/class_member.dart
index 2c280dd..b2849dc 100644
--- a/pkg/front_end/lib/src/kernel/hierarchy/class_member.dart
+++ b/pkg/front_end/lib/src/kernel/hierarchy/class_member.dart
@@ -170,6 +170,8 @@
   @override
   DartType getMemberType(
       ClassMembersBuilder membersBuilder, TypeDeclarationType thisType) {
+    assert(member.getterType is FunctionType,
+        "Unexpected member type for $member (${member.runtimeType}).");
     FunctionType type = member.getterType as FunctionType;
     if (type.typeParameters.isNotEmpty) {
       // Coverage-ignore-block(suite): Not run.
diff --git a/pkg/front_end/lib/src/kernel/implicit_field_type.dart b/pkg/front_end/lib/src/kernel/implicit_field_type.dart
index 8cb4666..5a9646c 100644
--- a/pkg/front_end/lib/src/kernel/implicit_field_type.dart
+++ b/pkg/front_end/lib/src/kernel/implicit_field_type.dart
@@ -11,10 +11,14 @@
 import '../base/constant_context.dart';
 import '../base/problems.dart' show unsupported;
 import '../builder/builder.dart';
+import '../builder/declaration_builders.dart';
 import '../builder/inferable_type_builder.dart';
 import '../codes/cfe_codes.dart';
+import '../fragment/fragment.dart';
+import '../source/source_class_builder.dart';
 import '../source/source_enum_builder.dart';
 import '../source/source_field_builder.dart';
+import '../source/source_library_builder.dart';
 import '../type_inference/type_inferrer.dart';
 import 'body_builder.dart';
 import 'body_builder_context.dart';
@@ -29,6 +33,10 @@
           SourceFieldBuilder fieldBuilder, Token? initializerToken) =
       _ImplicitFieldTypeRoot;
 
+  factory InferredType.fromFieldFragmentInitializer(
+          FieldFragment fieldFragment, Token? initializerToken) =
+      _ImplicitFieldFragmentTypeRoot;
+
   factory InferredType.fromInferableTypeUse(InferableTypeUse inferableTypeUse) =
       _InferredTypeUse;
 
@@ -114,6 +122,7 @@
   @override
   DartType computeType(ClassHierarchyBase hierarchy) {
     if (isStarted) {
+      // Coverage-ignore-block(suite): Not run.
       fieldBuilder.libraryBuilder.addProblem(
           templateCantInferTypeDueToCircularity
               .withArguments(fieldBuilder.name),
@@ -131,7 +140,9 @@
         parent.elementBuilders.contains(fieldBuilder)) {
       inferredType = parent.buildElement(
           fieldBuilder, parent.libraryBuilder.loader.coreTypes);
-    } else if (initializerToken != null) {
+    }
+    // Coverage-ignore(suite): Not run.
+    else if (initializerToken != null) {
       InterfaceType? enclosingClassThisType = fieldBuilder.classBuilder == null
           ? null
           : fieldBuilder.libraryBuilder.loader.typeInferenceEngine.coreTypes
@@ -143,10 +154,7 @@
               fieldBuilder.fileUri,
               enclosingClassThisType,
               fieldBuilder.libraryBuilder,
-              fieldBuilder
-                  .dataForTesting
-                  // Coverage-ignore(suite): Not run.
-                  ?.inferenceData);
+              fieldBuilder.dataForTesting?.inferenceData);
       BodyBuilderContext bodyBuilderContext =
           fieldBuilder.createBodyBuilderContext();
       BodyBuilder bodyBuilder = fieldBuilder.libraryBuilder.loader
@@ -195,6 +203,116 @@
   String toString() => 'ImplicitFieldType(${toStringInternal()})';
 }
 
+class _ImplicitFieldFragmentTypeRoot extends InferredType {
+  final FieldFragment _fieldFragment;
+
+  Token? initializerToken;
+  bool isStarted = false;
+
+  _ImplicitFieldFragmentTypeRoot(this._fieldFragment, this.initializerToken)
+      : super._();
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  Uri get fileUri => _fieldFragment.fileUri;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  int get charOffset => _fieldFragment.nameOffset;
+
+  @override
+  DartType inferType(ClassHierarchyBase hierarchy) {
+    return _fieldFragment.inferType(hierarchy);
+  }
+
+  @override
+  DartType computeType(ClassHierarchyBase hierarchy) {
+    if (isStarted) {
+      _fieldFragment.builder.libraryBuilder.addProblem(
+          templateCantInferTypeDueToCircularity
+              .withArguments(_fieldFragment.name),
+          _fieldFragment.nameOffset,
+          _fieldFragment.name.length,
+          _fieldFragment.fileUri);
+      DartType type = const InvalidType();
+      _fieldFragment.type.registerInferredType(type);
+      return type;
+    }
+    isStarted = true;
+    DartType? inferredType;
+    SourceLibraryBuilder libraryBuilder = _fieldFragment.builder.libraryBuilder;
+    DeclarationBuilder? declarationBuilder =
+        _fieldFragment.builder.declarationBuilder;
+    if (declarationBuilder is SourceEnumBuilder &&
+        declarationBuilder.elementBuilders.contains(_fieldFragment.builder)) {
+      // Coverage-ignore-block(suite): Not run.
+      inferredType = declarationBuilder.buildElement(
+          // TODO(johnniwinther): Create a EnumElementFragment to avoid this.
+          _fieldFragment.builder as SourceFieldBuilder,
+          libraryBuilder.loader.coreTypes);
+    } else if (initializerToken != null) {
+      InterfaceType? enclosingClassThisType = declarationBuilder
+              is SourceClassBuilder
+          ? libraryBuilder.loader.typeInferenceEngine.coreTypes
+              .thisInterfaceType(
+                  declarationBuilder.cls, libraryBuilder.library.nonNullable)
+          : null;
+      TypeInferrer typeInferrer =
+          libraryBuilder.loader.typeInferenceEngine.createTopLevelTypeInferrer(
+              _fieldFragment.fileUri,
+              enclosingClassThisType,
+              libraryBuilder,
+              _fieldFragment
+                  .builder
+                  .dataForTesting
+                  // Coverage-ignore(suite): Not run.
+                  ?.inferenceData);
+      BodyBuilderContext bodyBuilderContext =
+          _fieldFragment.createBodyBuilderContext();
+      BodyBuilder bodyBuilder = libraryBuilder.loader.createBodyBuilderForField(
+          libraryBuilder,
+          bodyBuilderContext,
+          declarationBuilder?.scope ?? libraryBuilder.scope,
+          typeInferrer,
+          _fieldFragment.fileUri);
+      bodyBuilder.constantContext = _fieldFragment.modifiers.isConst
+          ? ConstantContext.inferred
+          : ConstantContext.none;
+      bodyBuilder.inFieldInitializer = true;
+      bodyBuilder.inLateFieldInitializer = _fieldFragment.modifiers.isLate;
+      Expression initializer =
+          bodyBuilder.parseFieldInitializer(initializerToken!);
+      initializerToken = null;
+
+      inferredType =
+          typeInferrer.inferImplicitFieldType(bodyBuilder, initializer);
+    } else {
+      inferredType = const DynamicType();
+    }
+    return inferredType;
+  }
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  void toTextInternal(AstPrinter printer) {
+    printer.write('<implicit-field-type:$_fieldFragment>');
+  }
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  bool equals(Object other, Assumptions? assumptions) {
+    if (identical(this, other)) return true;
+    return other is _ImplicitFieldFragmentTypeRoot &&
+        _fieldFragment == other._fieldFragment;
+  }
+
+  @override
+  int get hashCode => _fieldFragment.hashCode;
+
+  @override
+  String toString() => 'ImplicitFieldType(${toStringInternal()})';
+}
+
 class _InferredTypeUse extends InferredType {
   final InferableTypeUse inferableTypeUse;
 
diff --git a/pkg/front_end/lib/src/kernel/kernel_target.dart b/pkg/front_end/lib/src/kernel/kernel_target.dart
index 05953dc..7386f7c 100644
--- a/pkg/front_end/lib/src/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/kernel/kernel_target.dart
@@ -47,13 +47,13 @@
 import '../base/uri_translator.dart' show UriTranslator;
 import '../builder/builder.dart';
 import '../builder/declaration_builders.dart';
-import '../builder/field_builder.dart';
 import '../builder/library_builder.dart';
 import '../builder/member_builder.dart';
 import '../builder/name_iterator.dart';
 import '../builder/named_type_builder.dart';
 import '../builder/nullability_builder.dart';
 import '../builder/procedure_builder.dart';
+import '../builder/property_builder.dart';
 import '../builder/type_builder.dart';
 import '../dill/dill_target.dart' show DillTarget;
 import '../source/class_declaration.dart';
@@ -62,13 +62,13 @@
 import '../source/source_class_builder.dart' show SourceClassBuilder;
 import '../source/source_constructor_builder.dart';
 import '../source/source_extension_type_declaration_builder.dart';
-import '../source/source_field_builder.dart';
 import '../source/source_library_builder.dart' show SourceLibraryBuilder;
 import '../source/source_loader.dart'
     show CompilationPhaseForProblemReporting, SourceLoader;
 import '../source/source_method_builder.dart';
 import '../type_inference/type_schema.dart';
 import 'benchmarker.dart' show BenchmarkPhases, Benchmarker;
+import 'cfe_verifier.dart' show verifyComponent, verifyGetStaticType;
 import 'constant_evaluator.dart' as constants
     show
         EvaluationMode,
@@ -81,7 +81,6 @@
 import 'kernel_constants.dart' show KernelConstantErrorReporter;
 import 'kernel_helper.dart';
 import 'macro/macro.dart';
-import 'cfe_verifier.dart' show verifyComponent, verifyGetStaticType;
 
 class KernelTarget {
   final Ticker ticker;
@@ -1533,14 +1532,17 @@
 
     /// Quotes below are from [Dart Programming Language Specification, 4th
     /// Edition](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-408.pdf):
-    List<SourceFieldBuilder> uninitializedFields = [];
-    List<SourceFieldBuilder> nonFinalFields = [];
-    List<SourceFieldBuilder> lateFinalFields = [];
+    List<PropertyBuilder> uninitializedFields = [];
+    List<PropertyBuilder> nonFinalFields = [];
+    List<PropertyBuilder> lateFinalFields = [];
 
-    Iterator<SourceFieldBuilder> fieldIterator =
-        classDeclaration.fullMemberIterator<SourceFieldBuilder>();
+    Iterator<PropertyBuilder> fieldIterator =
+        classDeclaration.fullMemberIterator<PropertyBuilder>();
     while (fieldIterator.moveNext()) {
-      SourceFieldBuilder fieldBuilder = fieldIterator.current;
+      PropertyBuilder fieldBuilder = fieldIterator.current;
+      if (!fieldBuilder.isField) {
+        continue;
+      }
       if (fieldBuilder.isAbstract || fieldBuilder.isExternal) {
         // Skip abstract and external fields. These are abstract/external
         // getters/setters and have no initialization.
@@ -1559,10 +1561,10 @@
       }
     }
 
-    Map<ConstructorDeclaration, Set<SourceFieldBuilder>>
+    Map<ConstructorDeclaration, Set<PropertyBuilder>>
         constructorInitializedFields = new Map.identity();
-    Set<SourceFieldBuilder>? initializedFieldBuilders = null;
-    Set<SourceFieldBuilder>? uninitializedInstanceFields;
+    Set<PropertyBuilder>? initializedFieldBuilders = null;
+    Set<PropertyBuilder>? uninitializedInstanceFields;
 
     Iterator<ConstructorDeclaration> constructorIterator =
         classDeclaration.fullConstructorIterator<ConstructorDeclaration>();
@@ -1579,14 +1581,14 @@
         nonFinalFields.clear();
       }
       if (constructor.isConst && lateFinalFields.isNotEmpty) {
-        for (FieldBuilder field in lateFinalFields) {
+        for (PropertyBuilder field in lateFinalFields) {
           classDeclaration.addProblem(
               messageConstConstructorLateFinalFieldError,
               field.fileOffset,
               noLength,
               context: [
                 messageConstConstructorLateFinalFieldCause.withLocation(
-                    constructor.fileUri!, constructor.fileOffset, noLength)
+                    constructor.fileUri, constructor.fileOffset, noLength)
               ]);
         }
         lateFinalFields.clear();
@@ -1595,23 +1597,23 @@
         // Assume that an external constructor initializes all uninitialized
         // instance fields.
         uninitializedInstanceFields ??= uninitializedFields
-            .where((SourceFieldBuilder fieldBuilder) => !fieldBuilder.isStatic)
+            .where((PropertyBuilder fieldBuilder) => !fieldBuilder.isStatic)
             .toSet();
         constructorInitializedFields[constructor] = uninitializedInstanceFields;
-        (initializedFieldBuilders ??= new Set<SourceFieldBuilder>.identity())
+        (initializedFieldBuilders ??= new Set<PropertyBuilder>.identity())
             .addAll(uninitializedInstanceFields);
       } else {
-        Set<SourceFieldBuilder> fields =
+        Set<PropertyBuilder> fields =
             constructor.takeInitializedFields() ?? const {};
         constructorInitializedFields[constructor] = fields;
-        (initializedFieldBuilders ??= new Set<SourceFieldBuilder>.identity())
+        (initializedFieldBuilders ??= new Set<PropertyBuilder>.identity())
             .addAll(fields);
       }
     }
 
     // Run through all fields that aren't initialized by any constructor, and
     // set their initializer to `null`.
-    for (SourceFieldBuilder fieldBuilder in uninitializedFields) {
+    for (PropertyBuilder fieldBuilder in uninitializedFields) {
       if (fieldBuilder.isExtensionTypeDeclaredInstanceField) continue;
       if (initializedFieldBuilders == null ||
           !initializedFieldBuilders.contains(fieldBuilder)) {
@@ -1651,11 +1653,11 @@
 
     // Run through all fields that are initialized by some constructor, and
     // make sure that all other constructors also initialize them.
-    for (MapEntry<ConstructorDeclaration, Set<FieldBuilder>> entry
+    for (MapEntry<ConstructorDeclaration, Set<PropertyBuilder>> entry
         in constructorInitializedFields.entries) {
       ConstructorDeclaration constructorBuilder = entry.key;
-      Set<FieldBuilder> fieldBuilders = entry.value;
-      for (SourceFieldBuilder fieldBuilder
+      Set<PropertyBuilder> fieldBuilders = entry.value;
+      for (PropertyBuilder fieldBuilder
           in initializedFieldBuilders!.difference(fieldBuilders)) {
         if (fieldBuilder.isExtensionTypeDeclaredInstanceField) continue;
         if (!fieldBuilder.hasInitializer && !fieldBuilder.isLate) {
@@ -1674,12 +1676,12 @@
                       .withLocation(fieldBuilder.fileUri,
                           fieldBuilder.fileOffset, fieldBuilder.name.length)
                 ]);
-          } else if (fieldBuilder.field.type is! InvalidType &&
+          } else if (fieldBuilder.fieldType is! InvalidType &&
               !fieldBuilder.isLate &&
-              fieldBuilder.field.type.isPotentiallyNonNullable) {
+              fieldBuilder.fieldType.isPotentiallyNonNullable) {
             libraryBuilder.addProblem(
                 templateFieldNonNullableNotInitializedByConstructorError
-                    .withArguments(fieldBuilder.name, fieldBuilder.field.type),
+                    .withArguments(fieldBuilder.name, fieldBuilder.fieldType),
                 constructorBuilder.fileOffset,
                 noLength,
                 constructorBuilder.fileUri,
diff --git a/pkg/front_end/lib/src/kernel/macro/introspectors.dart b/pkg/front_end/lib/src/kernel/macro/introspectors.dart
index 29679e1..afc8a18 100644
--- a/pkg/front_end/lib/src/kernel/macro/introspectors.dart
+++ b/pkg/front_end/lib/src/kernel/macro/introspectors.dart
@@ -129,8 +129,12 @@
   macro.Declaration _createMemberDeclaration(MemberBuilder memberBuilder) {
     if (memberBuilder is SourceMethodBuilder) {
       return _createMethodDeclaration(memberBuilder);
-    } else if (memberBuilder is SourcePropertyBuilder) {
+    } else if (memberBuilder is SourcePropertyBuilder &&
+        (memberBuilder.isGetter || memberBuilder.isSetter)) {
       return _createGetterDeclaration(memberBuilder);
+    } else if (memberBuilder is SourcePropertyBuilder &&
+        memberBuilder.isField) {
+      return _createFieldDeclaration(memberBuilder);
     } else if (memberBuilder is SourceFieldBuilder) {
       return _createVariableDeclaration(memberBuilder);
     } else if (memberBuilder is SourceConstructorBuilder) {
@@ -445,10 +449,8 @@
       // TODO(johnniwinther): Support typeParameters
       typeParameters: const [],
     );
-    if (builder.fileUri != null) {
-      _declarationOffsets[declaration] =
-          new UriOffset(builder.fileUri!, builder.fileOffset);
-    }
+    _declarationOffsets[declaration] =
+        new UriOffset(builder.fileUri, builder.fileOffset);
     return declaration;
   }
 
@@ -641,6 +643,64 @@
   }
 
   /// Creates the [macro.VariableDeclaration] corresponding to [builder].
+  macro.VariableDeclaration _createFieldDeclaration(
+      SourcePropertyBuilder builder) {
+    macro.ParameterizedTypeDeclaration? definingTypeDeclaration = null;
+    Builder? parent = builder.parent;
+    if (parent is ClassBuilder) {
+      definingTypeDeclaration = getClassDeclaration(parent);
+    } else if (parent is ExtensionTypeDeclarationBuilder) {
+      definingTypeDeclaration = getExtensionTypeDeclaration(parent);
+    }
+    final macro.LibraryImpl library = getLibrary(builder.libraryBuilder);
+    macro.VariableDeclaration declaration;
+    if (definingTypeDeclaration != null) {
+      // TODO(johnniwinther): Should static fields be field or variable
+      //  declarations?
+      declaration = new macro.FieldDeclarationImpl(
+          id: macro.RemoteInstance.uniqueId,
+          identifier: new MemberBuilderIdentifier(
+              memberBuilder: builder,
+              id: macro.RemoteInstance.uniqueId,
+              name: builder.name),
+          library: library,
+          // TODO: Provide metadata annotations.
+          metadata: const [],
+          definingType:
+              definingTypeDeclaration.identifier as macro.IdentifierImpl,
+          hasAbstract: builder.isAbstract,
+          hasConst: builder.isConst,
+          hasExternal: builder.isExternal,
+          hasFinal: builder.isFinal,
+          hasInitializer: builder.hasInitializer,
+          hasLate: builder.isLate,
+          hasStatic: builder.isStatic,
+          type: types.getTypeAnnotation(
+              builder.libraryBuilder, builder.typeForTesting));
+    } else {
+      declaration = new macro.VariableDeclarationImpl(
+          id: macro.RemoteInstance.uniqueId,
+          identifier: new MemberBuilderIdentifier(
+              memberBuilder: builder,
+              id: macro.RemoteInstance.uniqueId,
+              name: builder.name),
+          library: library,
+          // TODO: Provide metadata annotations.
+          metadata: const [],
+          hasConst: builder.isConst,
+          hasExternal: builder.isExternal,
+          hasFinal: builder.isFinal,
+          hasInitializer: builder.hasInitializer,
+          hasLate: builder.isLate,
+          type: types.getTypeAnnotation(
+              builder.libraryBuilder, builder.typeForTesting));
+    }
+    _declarationOffsets[declaration] =
+        new UriOffset(builder.fileUri, builder.fileOffset);
+    return declaration;
+  }
+
+  /// Creates the [macro.VariableDeclaration] corresponding to [builder].
   macro.VariableDeclaration _createVariableDeclaration(
       SourceFieldBuilder builder) {
     macro.ParameterizedTypeDeclaration? definingTypeDeclaration = null;
@@ -867,20 +927,26 @@
     if (type is macro.ClassDeclaration || type is macro.MixinDeclaration) {
       ClassBuilder classBuilder = _introspection
           ._getClassBuilder(type as macro.ParameterizedTypeDeclaration);
-      Iterator<SourceFieldBuilder> iterator =
-          classBuilder.fullMemberIterator<SourceFieldBuilder>();
+      Iterator<SourceMemberBuilder> iterator =
+          classBuilder.fullMemberIterator<SourceMemberBuilder>();
       while (iterator.moveNext()) {
-        result.add(_introspection.getMemberDeclaration(iterator.current)
-            as macro.FieldDeclaration);
+        SourceMemberBuilder memberBuilder = iterator.current;
+        if (memberBuilder.isField) {
+          result.add(_introspection.getMemberDeclaration(memberBuilder)
+              as macro.FieldDeclaration);
+        }
       }
     } else if (type is macro.ExtensionTypeDeclaration) {
       ExtensionTypeDeclarationBuilder extensionTypeDeclarationBuilder =
           _introspection._getExtensionTypeDeclarationBuilder(type);
-      Iterator<SourceFieldBuilder> iterator = extensionTypeDeclarationBuilder
-          .fullMemberIterator<SourceFieldBuilder>();
+      Iterator<SourceMemberBuilder> iterator = extensionTypeDeclarationBuilder
+          .fullMemberIterator<SourceMemberBuilder>();
       while (iterator.moveNext()) {
-        result.add(_introspection.getMemberDeclaration(iterator.current)
-            as macro.FieldDeclaration);
+        SourceMemberBuilder memberBuilder = iterator.current;
+        if (memberBuilder.isField) {
+          result.add(_introspection.getMemberDeclaration(memberBuilder)
+              as macro.FieldDeclaration);
+        }
       }
     } else {
       throw new UnsupportedError('Only introspection on classes is supported');
@@ -899,7 +965,8 @@
       while (iterator.moveNext()) {
         SourceMemberBuilder memberBuilder = iterator.current;
         if (memberBuilder is SourceMethodBuilder ||
-            memberBuilder is SourcePropertyBuilder) {
+            (memberBuilder is SourcePropertyBuilder &&
+                (memberBuilder.isGetter || memberBuilder.isSetter))) {
           result.add(_introspection.getMemberDeclaration(memberBuilder)
               as macro.MethodDeclaration);
         }
@@ -912,7 +979,8 @@
       while (iterator.moveNext()) {
         SourceMemberBuilder memberBuilder = iterator.current;
         if (memberBuilder is SourceMethodBuilder ||
-            memberBuilder is SourcePropertyBuilder) {
+            (memberBuilder is SourcePropertyBuilder &&
+                (memberBuilder.isGetter || memberBuilder.isSetter))) {
           result.add(_introspection.getMemberDeclaration(memberBuilder)
               as macro.MethodDeclaration);
         }
diff --git a/pkg/front_end/lib/src/kernel/macro/metadata.dart b/pkg/front_end/lib/src/kernel/macro/metadata.dart
index f270f6e..763aa31 100644
--- a/pkg/front_end/lib/src/kernel/macro/metadata.dart
+++ b/pkg/front_end/lib/src/kernel/macro/metadata.dart
@@ -24,8 +24,10 @@
 import '../../builder/null_type_declaration_builder.dart';
 import '../../builder/prefix_builder.dart';
 import '../../builder/procedure_builder.dart';
+import '../../builder/property_builder.dart';
 import '../../source/source_field_builder.dart';
 import '../../source/source_method_builder.dart';
+import '../../source/source_property_builder.dart';
 
 // Coverage-ignore(suite): Not run.
 final Uri dummyUri = Uri.parse('dummy:uri');
@@ -79,6 +81,11 @@
     if (element is SourceFieldBuilder) {
       return element.initializerExpression;
     }
+  } else if (reference is PropertyReference) {
+    PropertyBuilder element = reference.builder;
+    if (element is SourcePropertyBuilder) {
+      return element.initializerExpression;
+    }
   } else {
     assert(false,
         "Unexpected field reference $reference (${reference.runtimeType})");
@@ -90,6 +97,8 @@
 shared.Proto builderToProto(Builder builder, String name) {
   if (builder is FieldBuilder) {
     return new shared.FieldProto(new FieldReference(builder));
+  } else if (builder is PropertyBuilder) {
+    return new shared.FieldProto(new PropertyReference(builder));
   } else if (builder is ProcedureBuilder) {
     return new shared.FunctionProto(new FunctionReference(builder));
   } else if (builder is SourceMethodBuilder) {
@@ -353,6 +362,16 @@
 }
 
 // Coverage-ignore(suite): Not run.
+class PropertyReference extends shared.FieldReference {
+  final PropertyBuilder builder;
+
+  PropertyReference(this.builder);
+
+  @override
+  String get name => builder.name;
+}
+
+// Coverage-ignore(suite): Not run.
 class FunctionReference extends shared.FunctionReference {
   final ProcedureBuilder builder;
 
diff --git a/pkg/front_end/lib/src/source/constructor_declaration.dart b/pkg/front_end/lib/src/source/constructor_declaration.dart
index ef5edc3..17a90bc 100644
--- a/pkg/front_end/lib/src/source/constructor_declaration.dart
+++ b/pkg/front_end/lib/src/source/constructor_declaration.dart
@@ -4,9 +4,9 @@
 
 import 'package:kernel/ast.dart';
 
+import '../builder/property_builder.dart';
 import '../kernel/expression_generator_helper.dart';
 import '../type_inference/inference_results.dart';
-import 'source_field_builder.dart';
 import 'source_function_builder.dart';
 
 /// Common interface for builders for generative constructor declarations in
@@ -41,14 +41,14 @@
   ///
   /// The field can be initialized either via an initializing formal or via an
   /// entry in the constructor initializer list.
-  void registerInitializedField(SourceFieldBuilder fieldBuilder);
+  void registerInitializedField(PropertyBuilder fieldBuilder);
 
   /// Returns the fields registered as initialized by this constructor.
   ///
   /// Returns the set of fields previously registered via
   /// [registerInitializedField] and passes on the ownership of the collection
   /// to the caller.
-  Set<SourceFieldBuilder>? takeInitializedFields();
+  Set<PropertyBuilder>? takeInitializedFields();
 
   /// Substitute [fieldType] from the context of the enclosing class or
   /// extension type declaration to this constructor.
diff --git a/pkg/front_end/lib/src/source/diet_listener.dart b/pkg/front_end/lib/src/source/diet_listener.dart
index 4cb8778..50731ff 100644
--- a/pkg/front_end/lib/src/source/diet_listener.dart
+++ b/pkg/front_end/lib/src/source/diet_listener.dart
@@ -45,7 +45,6 @@
 import '../type_inference/type_inferrer.dart' show TypeInferrer;
 import 'diet_parser.dart';
 import 'offset_map.dart';
-import 'source_field_builder.dart';
 import 'source_library_builder.dart' show SourceLibraryBuilder;
 import 'stack_listener_impl.dart';
 
@@ -932,13 +931,14 @@
     if (names == null || currentClassIsParserRecovery) return;
 
     Identifier first = names.first!;
-    SourceFieldBuilder declaration = _offsetMap.lookupField(first);
+    FieldFragment fragment = _offsetMap.lookupField(first);
     // TODO(paulberry): don't re-parse the field if we've already parsed it
     // for type inference.
     _parseFields(
         _offsetMap,
-        createListener(declaration.createBodyBuilderContext(), memberScope,
-            inferenceDataForTesting: declaration
+        createListener(fragment.createBodyBuilderContext(), memberScope,
+            inferenceDataForTesting: fragment
+                .builder
                 .dataForTesting
                 // Coverage-ignore(suite): Not run.
                 ?.inferenceData),
diff --git a/pkg/front_end/lib/src/source/offset_map.dart b/pkg/front_end/lib/src/source/offset_map.dart
index 8dd2b27..5ff7097 100644
--- a/pkg/front_end/lib/src/source/offset_map.dart
+++ b/pkg/front_end/lib/src/source/offset_map.dart
@@ -14,7 +14,6 @@
 import '../builder/declaration_builders.dart';
 import '../codes/cfe_codes.dart';
 import '../fragment/fragment.dart';
-import 'source_field_builder.dart';
 
 /// Map from offsets of directives and declarations to the objects the define.
 ///
@@ -99,9 +98,9 @@
     _fields[identifier.nameOffset] = fragment;
   }
 
-  SourceFieldBuilder lookupField(Identifier identifier) {
-    return _checkBuilder(_fields[identifier.nameOffset]?.builder,
-        identifier.name, identifier.nameOffset);
+  FieldFragment lookupField(Identifier identifier) {
+    return _checkFragment(
+        _fields[identifier.nameOffset], identifier.name, identifier.nameOffset);
   }
 
   void registerPrimaryConstructor(
diff --git a/pkg/front_end/lib/src/source/source_class_builder.dart b/pkg/front_end/lib/src/source/source_class_builder.dart
index 54f06f6..ddfb129 100644
--- a/pkg/front_end/lib/src/source/source_class_builder.dart
+++ b/pkg/front_end/lib/src/source/source_class_builder.dart
@@ -48,7 +48,6 @@
 import 'source_builder_mixins.dart';
 import 'source_constructor_builder.dart';
 import 'source_factory_builder.dart';
-import 'source_field_builder.dart';
 import 'source_library_builder.dart';
 import 'source_loader.dart';
 import 'source_member_builder.dart';
@@ -1037,21 +1036,26 @@
     return supertype;
   }
 
-  void checkVarianceInField(SourceFieldBuilder fieldBuilder,
-      TypeEnvironment typeEnvironment, List<TypeParameter> typeParameters) {
-    for (TypeParameter typeParameter in typeParameters) {
-      Variance fieldVariance =
-          computeVariance(typeParameter, fieldBuilder.fieldType);
-      if (fieldBuilder.isClassInstanceMember) {
-        reportVariancePositionIfInvalid(fieldVariance, typeParameter,
-            fieldBuilder.fileUri, fieldBuilder.fileOffset);
-      }
-      if (fieldBuilder.isClassInstanceMember &&
-          fieldBuilder.isAssignable &&
-          !fieldBuilder.isCovariantByDeclaration) {
-        fieldVariance = Variance.contravariant.combine(fieldVariance);
-        reportVariancePositionIfInvalid(fieldVariance, typeParameter,
-            fieldBuilder.fileUri, fieldBuilder.fileOffset);
+  void checkVarianceInField(TypeEnvironment typeEnvironment,
+      {required DartType fieldType,
+      required bool isInstanceMember,
+      required bool hasSetter,
+      required bool isCovariantByDeclaration,
+      required Uri fileUri,
+      required int fileOffset}) {
+    List<TypeParameter> typeParameters = cls.typeParameters;
+    if (typeParameters.isNotEmpty) {
+      for (TypeParameter typeParameter in typeParameters) {
+        Variance fieldVariance = computeVariance(typeParameter, fieldType);
+        if (isInstanceMember) {
+          reportVariancePositionIfInvalid(
+              fieldVariance, typeParameter, fileUri, fileOffset);
+        }
+        if (isInstanceMember && hasSetter && !isCovariantByDeclaration) {
+          fieldVariance = Variance.contravariant.combine(fieldVariance);
+          reportVariancePositionIfInvalid(
+              fieldVariance, typeParameter, fileUri, fileOffset);
+        }
       }
     }
   }
diff --git a/pkg/front_end/lib/src/source/source_constructor_builder.dart b/pkg/front_end/lib/src/source/source_constructor_builder.dart
index 78a0e8b..f8f08fc 100644
--- a/pkg/front_end/lib/src/source/source_constructor_builder.dart
+++ b/pkg/front_end/lib/src/source/source_constructor_builder.dart
@@ -30,6 +30,7 @@
 import '../builder/member_builder.dart';
 import '../builder/metadata_builder.dart';
 import '../builder/omitted_type_builder.dart';
+import '../builder/property_builder.dart';
 import '../builder/type_builder.dart';
 import '../kernel/body_builder.dart' show BodyBuilder;
 import '../kernel/body_builder_context.dart';
@@ -51,7 +52,6 @@
 import 'source_class_builder.dart';
 import 'source_enum_builder.dart';
 import 'source_extension_type_declaration_builder.dart';
-import 'source_field_builder.dart';
 import 'source_function_builder.dart';
 import 'source_library_builder.dart' show SourceLibraryBuilder;
 import 'source_loader.dart'
@@ -396,6 +396,14 @@
   @override
   // Coverage-ignore(suite): Not run.
   bool get isProperty => false;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  bool get isFinal => false;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  bool get isSynthesized => false;
 }
 
 class DeclaredSourceConstructorBuilder
@@ -405,7 +413,7 @@
   @override
   late final Procedure? _constructorTearOff;
 
-  Set<SourceFieldBuilder>? _initializedFields;
+  Set<PropertyBuilder>? _initializedFields;
 
   DeclaredSourceConstructorBuilder? actualOrigin;
 
@@ -1000,7 +1008,7 @@
   }
 
   @override
-  void registerInitializedField(SourceFieldBuilder fieldBuilder) {
+  void registerInitializedField(PropertyBuilder fieldBuilder) {
     if (isAugmenting) {
       origin.registerInitializedField(fieldBuilder);
     } else {
@@ -1009,8 +1017,8 @@
   }
 
   @override
-  Set<SourceFieldBuilder>? takeInitializedFields() {
-    Set<SourceFieldBuilder>? result = _initializedFields;
+  Set<PropertyBuilder>? takeInitializedFields() {
+    Set<PropertyBuilder>? result = _initializedFields;
     _initializedFields = null;
     return result;
   }
@@ -1127,6 +1135,14 @@
 
   @override
   // Coverage-ignore(suite): Not run.
+  bool get isFinal => false;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  bool get isSynthesized => true;
+
+  @override
+  // Coverage-ignore(suite): Not run.
   bool get isAbstract => false;
 
   @override
@@ -1302,7 +1318,7 @@
   @override
   late final Procedure? _constructorTearOff;
 
-  Set<SourceFieldBuilder>? _initializedFields;
+  Set<PropertyBuilder>? _initializedFields;
 
   @override
   List<Initializer> initializers = [];
@@ -1542,13 +1558,13 @@
   }
 
   @override
-  void registerInitializedField(SourceFieldBuilder fieldBuilder) {
+  void registerInitializedField(PropertyBuilder fieldBuilder) {
     (_initializedFields ??= {}).add(fieldBuilder);
   }
 
   @override
-  Set<SourceFieldBuilder>? takeInitializedFields() {
-    Set<SourceFieldBuilder>? result = _initializedFields;
+  Set<PropertyBuilder>? takeInitializedFields() {
+    Set<PropertyBuilder>? result = _initializedFields;
     _initializedFields = null;
     return result;
   }
diff --git a/pkg/front_end/lib/src/source/source_extension_type_declaration_builder.dart b/pkg/front_end/lib/src/source/source_extension_type_declaration_builder.dart
index 020afb8..3ce7584 100644
--- a/pkg/front_end/lib/src/source/source_extension_type_declaration_builder.dart
+++ b/pkg/front_end/lib/src/source/source_extension_type_declaration_builder.dart
@@ -35,9 +35,9 @@
 import 'source_builder_mixins.dart';
 import 'source_constructor_builder.dart';
 import 'source_factory_builder.dart';
-import 'source_field_builder.dart';
 import 'source_library_builder.dart';
 import 'source_member_builder.dart';
+import 'source_property_builder.dart';
 import 'type_parameter_scope_builder.dart';
 
 class SourceExtensionTypeDeclarationBuilder
@@ -90,8 +90,6 @@
 
   FieldFragment? _representationFieldFragment;
 
-  SourceFieldBuilder? _representationFieldBuilder;
-
   final IndexedContainer? indexedContainer;
 
   Nullability? _nullability;
@@ -155,13 +153,8 @@
   @override
   bool get isAugment => _modifiers.isAugment;
 
-  SourceFieldBuilder? get representationFieldBuilder {
-    if (_representationFieldBuilder == null) {
-      _representationFieldBuilder = _representationFieldFragment?.builder;
-      _representationFieldFragment = null;
-    }
-    return _representationFieldBuilder;
-  }
+  SourcePropertyBuilder? get representationFieldBuilder =>
+      _representationFieldFragment?.builder;
 
   @override
   void buildScopes(LibraryBuilder coreLibrary) {
@@ -187,7 +180,7 @@
 
   @override
   TypeBuilder? get declaredRepresentationTypeBuilder =>
-      representationFieldBuilder?.type;
+      _representationFieldFragment?.type;
 
   @override
   SourceExtensionTypeDeclarationBuilder get origin => _origin ?? this;
@@ -347,8 +340,8 @@
 
     DartType representationType;
     String representationName;
-    if (representationFieldBuilder != null) {
-      TypeBuilder typeBuilder = representationFieldBuilder!.type;
+    if (_representationFieldFragment != null) {
+      TypeBuilder typeBuilder = _representationFieldFragment!.type;
       if (typeBuilder.isExplicit) {
         if (_checkRepresentationDependency(typeBuilder, this, {this}, {})) {
           representationType = const InvalidType();
@@ -373,16 +366,16 @@
           if (isBottom(representationType)) {
             libraryBuilder.addProblem(
                 messageExtensionTypeRepresentationTypeBottom,
-                representationFieldBuilder!.fileOffset,
-                representationFieldBuilder!.name.length,
-                representationFieldBuilder!.fileUri);
+                _representationFieldFragment!.nameOffset,
+                _representationFieldFragment!.name.length,
+                _representationFieldFragment!.fileUri);
             representationType = const InvalidType();
           }
         }
       } else {
         representationType = const DynamicType();
       }
-      representationName = representationFieldBuilder!.name;
+      representationName = _representationFieldFragment!.name;
     } else {
       representationType = const InvalidType();
       representationName = '#';
@@ -436,9 +429,9 @@
             }
             libraryBuilder.addProblem(
                 messageCyclicRepresentationDependency,
-                representationFieldBuilder!.type.charOffset!,
+                _representationFieldFragment!.type.charOffset!,
                 noLength,
-                representationFieldBuilder!.type.fileUri,
+                _representationFieldFragment!.type.fileUri,
                 context: context);
             return true;
           } else {
diff --git a/pkg/front_end/lib/src/source/source_factory_builder.dart b/pkg/front_end/lib/src/source/source_factory_builder.dart
index 234e348..d7f73c8 100644
--- a/pkg/front_end/lib/src/source/source_factory_builder.dart
+++ b/pkg/front_end/lib/src/source/source_factory_builder.dart
@@ -182,6 +182,14 @@
   // Coverage-ignore(suite): Not run.
   bool get isProperty => false;
 
+  @override
+  // Coverage-ignore(suite): Not run.
+  bool get isFinal => false;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  bool get isSynthesized => false;
+
   Procedure get _procedure =>
       isAugmenting ? origin._procedure : _procedureInternal;
 
diff --git a/pkg/front_end/lib/src/source/source_field_builder.dart b/pkg/front_end/lib/src/source/source_field_builder.dart
index 342417e..9bb0e96 100644
--- a/pkg/front_end/lib/src/source/source_field_builder.dart
+++ b/pkg/front_end/lib/src/source/source_field_builder.dart
@@ -22,6 +22,7 @@
 import '../builder/member_builder.dart';
 import '../builder/metadata_builder.dart';
 import '../builder/omitted_type_builder.dart';
+import '../builder/property_builder.dart';
 import '../builder/type_builder.dart';
 import '../codes/cfe_codes.dart' show messageInternalProblemAlreadyInitialized;
 import '../kernel/body_builder.dart' show BodyBuilder;
@@ -45,7 +46,7 @@
 import 'source_member_builder.dart';
 
 class SourceFieldBuilder extends SourceMemberBuilderImpl
-    implements FieldBuilder, InferredTypeListener, Inferable {
+    implements FieldBuilder, InferredTypeListener, Inferable, PropertyBuilder {
   @override
   final SourceLibraryBuilder libraryBuilder;
 
@@ -81,6 +82,7 @@
 
   final bool isPrimaryConstructorField;
 
+  @override
   final bool isSynthesized;
 
   /// If `true`, this field builder is for the field corresponding to an enum
@@ -131,6 +133,7 @@
     late_lowering.IsSetStrategy isSetStrategy =
         late_lowering.computeIsSetStrategy(libraryBuilder);
     if (isAbstract || isExternal) {
+      // Coverage-ignore-block(suite): Not run.
       assert(fieldReference == null);
       assert(lateIsSetFieldReference == null);
       assert(lateIsSetGetterReference == null);
@@ -152,7 +155,9 @@
           isFinal: isFinal,
           isCovariantByDeclaration: isCovariantByDeclaration);
     } else if (nameScheme.isExtensionTypeMember &&
+        // Coverage-ignore(suite): Not run.
         nameScheme.isInstanceMember) {
+      // Coverage-ignore-block(suite): Not run.
       assert(fieldReference == null);
       assert(fieldSetterReference == null);
       assert(lateIsSetFieldReference == null);
@@ -183,10 +188,12 @@
             isForcedExtension: true);
       }
     } else if (isLate &&
+        // Coverage-ignore(suite): Not run.
         libraryBuilder.loader.target.backendTarget.isLateFieldLoweringEnabled(
             hasInitializer: hasInitializer,
             isFinal: isFinal,
             isStatic: !isInstanceMember)) {
+      // Coverage-ignore-block(suite): Not run.
       assert(!isEnumElement, "Unexpected late enum element");
       if (hasInitializer) {
         if (isFinal) {
@@ -265,7 +272,9 @@
             .loader.target.backendTarget.useStaticFieldLowering &&
         !isInstanceMember &&
         !isConst &&
+        // Coverage-ignore(suite): Not run.
         hasInitializer) {
+      // Coverage-ignore-block(suite): Not run.
       assert(!isEnumElement, "Unexpected non-const enum element");
       if (isFinal) {
         _fieldEncoding = new LateFinalFieldWithInitializerEncoding(
@@ -325,7 +334,10 @@
     }
 
     if (type is InferableTypeBuilder) {
-      if (!hasInitializer && isStatic) {
+      if (!hasInitializer &&
+          // Coverage-ignore(suite): Not run.
+          isStatic) {
+        // Coverage-ignore-block(suite): Not run.
         // A static field without type and initializer will always be inferred
         // to have type `dynamic`.
         type.registerInferredType(const DynamicType());
@@ -351,6 +363,7 @@
   bool get isProperty => true;
 
   @override
+  // Coverage-ignore(suite): Not run.
   bool get isAugmentation => modifiers.isAugment;
 
   @override
@@ -359,22 +372,28 @@
   @override
   bool get isAbstract => modifiers.isAbstract;
 
+  @override
+  // Coverage-ignore(suite): Not run.
   bool get isExtensionTypeDeclaredInstanceField =>
       isExtensionTypeInstanceMember && !isPrimaryConstructorField;
 
   @override
   bool get isConst => modifiers.isConst;
 
+  @override
   bool get isFinal => modifiers.isFinal;
 
   @override
   bool get isStatic => modifiers.isStatic;
 
   @override
+  // Coverage-ignore(suite): Not run.
   bool get isAugment => modifiers.isAugment;
 
   @override
-  Builder get parent => declarationBuilder ?? libraryBuilder;
+  Builder get parent =>
+      declarationBuilder ?? // Coverage-ignore(suite): Not run.
+      libraryBuilder;
 
   @override
   Name get memberName => _memberName.name;
@@ -382,6 +401,7 @@
   bool _typeEnsured = false;
   Set<ClassMember>? _overrideDependencies;
 
+  // Coverage-ignore(suite): Not run.
   void registerOverrideDependency(Set<ClassMember> overriddenMembers) {
     assert(
         overriddenMembers.every((overriddenMember) =>
@@ -394,6 +414,7 @@
   void _ensureType(ClassMembersBuilder membersBuilder) {
     if (_typeEnsured) return;
     if (_overrideDependencies != null) {
+      // Coverage-ignore-block(suite): Not run.
       membersBuilder.inferFieldType(declarationBuilder as SourceClassBuilder,
           type, _overrideDependencies!,
           name: fullNameForErrors,
@@ -412,10 +433,12 @@
   @override
   bool get isField => true;
 
+  @override
   bool get isLate => modifiers.isLate;
 
   bool get isCovariantByDeclaration => modifiers.isCovariant;
 
+  @override
   bool get hasInitializer => modifiers.hasInitializer;
 
   /// Builds the body of this field using [initializer] as the initializer
@@ -425,6 +448,7 @@
     hasBodyBeenBuilt = true;
     if (!hasInitializer &&
         initializer != null &&
+        // Coverage-ignore(suite): Not run.
         initializer is! NullLiteral &&
         // Coverage-ignore(suite): Not run.
         !isConst &&
@@ -436,26 +460,28 @@
     _fieldEncoding.createBodies(coreTypes, initializer);
   }
 
-  /// Builds the field initializers for each field used to encode this field
-  /// using the [fileOffset] for the created nodes and [value] as the initial
-  /// field value.
+  @override
+  // Coverage-ignore(suite): Not run.
   List<Initializer> buildInitializer(int fileOffset, Expression value,
       {required bool isSynthetic}) {
     return _fieldEncoding.createInitializer(fileOffset, value,
         isSynthetic: isSynthetic);
   }
 
-  /// Creates the AST node for this field as the default initializer.
+  @override
+  // Coverage-ignore(suite): Not run.
   void buildImplicitDefaultValue() {
     _fieldEncoding.buildImplicitDefaultValue();
   }
 
-  /// Create the [Initializer] for the implicit initialization of this field
-  /// in a constructor.
+  @override
+  // Coverage-ignore(suite): Not run.
   Initializer buildImplicitInitializer() {
     return _fieldEncoding.buildImplicitInitializer();
   }
 
+  @override
+  // Coverage-ignore(suite): Not run.
   Initializer buildErroneousInitializer(Expression effect, Expression value,
       {required int fileOffset}) {
     return _fieldEncoding.buildErroneousInitializer(effect, value,
@@ -465,6 +491,7 @@
   @override
   bool get isAssignable {
     if (isConst) return false;
+    // Coverage-ignore(suite): Not run.
     if (isFinal) {
       if (isLate) {
         return !hasInitializer;
@@ -485,6 +512,7 @@
   Reference get readTargetReference => _fieldEncoding.readTargetReference;
 
   @override
+  // Coverage-ignore(suite): Not run.
   Member? get writeTarget {
     return isAssignable ? _fieldEncoding.writeTarget : null;
   }
@@ -501,6 +529,7 @@
   Reference get invokeTargetReference => _fieldEncoding.readTargetReference;
 
   @override
+  // Coverage-ignore(suite): Not run.
   Iterable<Reference> get exportedMemberReferences =>
       _fieldEncoding.exportedReferenceMembers;
 
@@ -535,18 +564,21 @@
           createBodyBuilderContext(),
           libraryBuilder,
           fileUri,
-          declarationBuilder?.scope ?? libraryBuilder.scope);
+          declarationBuilder?.scope ?? // Coverage-ignore(suite): Not run.
+              libraryBuilder.scope);
     }
 
     // For modular compilation we need to include initializers of all const
     // fields and all non-static final fields in classes with const constructors
     // into the outline.
     if ((isConst ||
+            // Coverage-ignore(suite): Not run.
             (isFinal &&
                 !isStatic &&
                 isClassMember &&
                 classBuilder!.declaresConstConstructor)) &&
         _constInitializerToken != null) {
+      // Coverage-ignore-block(suite): Not run.
       Token initializerToken = _constInitializerToken!;
       LookupScope scope = declarationBuilder?.scope ?? libraryBuilder.scope;
       BodyBuilder bodyBuilder = libraryBuilder.loader
@@ -561,7 +593,6 @@
       buildBody(classHierarchy.coreTypes, initializer);
       bodyBuilder.performBacklogComputations();
       if (computeSharedExpressionForTesting) {
-        // Coverage-ignore-block(suite): Not run.
         _initializerExpression = parseFieldInitializer(libraryBuilder.loader,
             initializerToken, libraryBuilder.importUri, fileUri, scope);
       }
@@ -575,11 +606,17 @@
   // Coverage-ignore(suite): Not run.
   bool get hasOutlineExpressionsBuilt => _constInitializerToken == null;
 
+  @override
   DartType get fieldType => _fieldEncoding.type;
 
+  @override
   void set fieldType(DartType value) {
     _fieldEncoding.type = value;
-    if (!isFinal && !isConst && parent is ClassBuilder) {
+    if (!isFinal &&
+        !isConst &&
+        // Coverage-ignore(suite): Not run.
+        parent is ClassBuilder) {
+      // Coverage-ignore-block(suite): Not run.
       Class enclosingClass = classBuilder!.cls;
       if (enclosingClass.typeParameters.isNotEmpty) {
         IncludesTypeParametersNonCovariantly needsCheckVisitor =
@@ -601,8 +638,10 @@
     inferType(hierarchy);
   }
 
+  @override
   DartType inferType(ClassHierarchyBase hierarchy) {
     if (fieldType is! InferredType) {
+      // Coverage-ignore-block(suite): Not run.
       // We have already inferred a type.
       return fieldType;
     }
@@ -630,6 +669,7 @@
         }
         if (needsCheckVisitor != null) {
           if (fieldType.accept(needsCheckVisitor)) {
+            // Coverage-ignore-block(suite): Not run.
             _fieldEncoding.setGenericCovariantImpl();
           }
         }
@@ -643,6 +683,7 @@
     fieldType = type;
   }
 
+  // Coverage-ignore(suite): Not run.
   DartType get builtType => fieldType;
 
   List<ClassMember>? _localMembers;
@@ -670,14 +711,28 @@
   @override
   void checkVariance(
       SourceClassBuilder sourceClassBuilder, TypeEnvironment typeEnvironment) {
-    sourceClassBuilder.checkVarianceInField(
-        this, typeEnvironment, sourceClassBuilder.cls.typeParameters);
+    sourceClassBuilder.checkVarianceInField(typeEnvironment,
+        fieldType: fieldType,
+        isInstanceMember: isClassInstanceMember,
+        hasSetter: isAssignable,
+        isCovariantByDeclaration: isCovariantByDeclaration,
+        fileUri: fileUri,
+        fileOffset: fileOffset);
   }
 
   @override
   void checkTypes(SourceLibraryBuilder library, NameSpace nameSpace,
       TypeEnvironment typeEnvironment) {
-    library.checkTypesInField(this, typeEnvironment);
+    library.checkTypesInField(typeEnvironment,
+        isInstanceMember: isDeclarationInstanceMember,
+        isLate: isLate,
+        isExternal: isExternal,
+        hasInitializer: hasInitializer,
+        fieldType: fieldType,
+        name: name,
+        nameLength: name.length,
+        nameOffset: fileOffset,
+        fileUri: fileUri);
   }
 
   @override
@@ -793,7 +848,9 @@
             fieldReference: fieldReference,
             getterReference: getterReference,
             isEnumElement: isEnumElement)
-        : new Field.mutable(dummyName,
+        :
+        // Coverage-ignore(suite): Not run.
+        new Field.mutable(dummyName,
             isFinal: isFinal,
             isLate: isLate,
             fileUri: fileUri,
@@ -824,6 +881,7 @@
   }
 
   @override
+  // Coverage-ignore(suite): Not run.
   List<Initializer> createInitializer(int fileOffset, Expression value,
       {required bool isSynthetic}) {
     return <Initializer>[
@@ -838,16 +896,19 @@
       SourceLibraryBuilder libraryBuilder, SourceFieldBuilder fieldBuilder) {
     _field..isCovariantByDeclaration = fieldBuilder.isCovariantByDeclaration;
     if (fieldBuilder.isExtensionMember) {
+      // Coverage-ignore-block(suite): Not run.
       _field
         ..isStatic = true
         ..isExtensionMember = true;
     } else if (fieldBuilder.isExtensionTypeMember) {
+      // Coverage-ignore-block(suite): Not run.
       _field
         ..isStatic = fieldBuilder.isStatic
         ..isExtensionTypeMember = true;
     } else {
-      bool isInstanceMember =
-          !fieldBuilder.isStatic && !fieldBuilder.isTopLevel;
+      bool isInstanceMember = !fieldBuilder.isStatic &&
+          // Coverage-ignore(suite): Not run.
+          !fieldBuilder.isTopLevel;
       _field
         ..isStatic = !isInstanceMember
         ..isExtensionMember = false;
@@ -867,6 +928,7 @@
   }
 
   @override
+  // Coverage-ignore(suite): Not run.
   void setGenericCovariantImpl() {
     if (_field.hasSetter) {
       _field.isCovariantByClass = true;
@@ -890,6 +952,7 @@
   Reference get readTargetReference => _field.getterReference;
 
   @override
+  // Coverage-ignore(suite): Not run.
   Member get writeTarget => _field;
 
   @override
@@ -897,6 +960,7 @@
   Reference? get writeTargetReference => _field.setterReference;
 
   @override
+  // Coverage-ignore(suite): Not run.
   Iterable<Reference> get exportedReferenceMembers =>
       [_field.getterReference, if (_field.hasSetter) _field.setterReference!];
 
@@ -909,22 +973,27 @@
   @override
   List<ClassMember> getLocalSetters(SourceFieldBuilder fieldBuilder) =>
       fieldBuilder.isAssignable
-          ? <ClassMember>[
+          ?
+          // Coverage-ignore(suite): Not run.
+          <ClassMember>[
               new SourceFieldMember(fieldBuilder, ClassMemberKind.Setter)
             ]
           : const <ClassMember>[];
 
   @override
+  // Coverage-ignore(suite): Not run.
   void buildImplicitDefaultValue() {
     _field.initializer = new NullLiteral()..parent = _field;
   }
 
   @override
+  // Coverage-ignore(suite): Not run.
   Initializer buildImplicitInitializer() {
     return new FieldInitializer(_field, new NullLiteral())..isSynthetic = true;
   }
 
   @override
+  // Coverage-ignore(suite): Not run.
   Initializer buildErroneousInitializer(Expression effect, Expression value,
       {required int fileOffset}) {
     return new ShadowInvalidFieldInitializer(type, value, effect)
@@ -944,11 +1013,13 @@
   SourceFieldMember(this.memberBuilder, this.memberKind);
 
   @override
+  // Coverage-ignore(suite): Not run.
   void inferType(ClassMembersBuilder membersBuilder) {
     memberBuilder._ensureType(membersBuilder);
   }
 
   @override
+  // Coverage-ignore(suite): Not run.
   void registerOverrideDependency(Set<ClassMember> overriddenMembers) {
     memberBuilder.registerOverrideDependency(overriddenMembers);
   }
@@ -968,6 +1039,7 @@
   }
 
   @override
+  // Coverage-ignore(suite): Not run.
   Covariance getCovariance(ClassMembersBuilder membersBuilder) {
     return _covariance ??= forSetter
         ? new Covariance.fromMember(getMember(membersBuilder),
@@ -976,6 +1048,7 @@
   }
 
   @override
+  // Coverage-ignore(suite): Not run.
   bool get isSourceDeclaration => true;
 
   @override
@@ -983,10 +1056,13 @@
 
   @override
   bool isSameDeclaration(ClassMember other) {
-    return other is SourceFieldMember && memberBuilder == other.memberBuilder;
+    return other is SourceFieldMember &&
+        // Coverage-ignore(suite): Not run.
+        memberBuilder == other.memberBuilder;
   }
 }
 
+// Coverage-ignore(suite): Not run.
 abstract class AbstractLateFieldEncoding implements FieldEncoding {
   final String name;
   final int fileOffset;
@@ -1264,14 +1340,12 @@
   Member get readTarget => _lateGetter;
 
   @override
-  // Coverage-ignore(suite): Not run.
   Reference get readTargetReference => _lateGetter.reference;
 
   @override
   Member? get writeTarget => _lateSetter;
 
   @override
-  // Coverage-ignore(suite): Not run.
   Reference? get writeTargetReference => _lateSetter?.reference;
 
   @override
@@ -1294,7 +1368,6 @@
         ..isExtensionMember = isExtensionMember;
       isInstanceMember = false;
     } else if (isExtensionTypeMember) {
-      // Coverage-ignore-block(suite): Not run.
       _field
         ..isStatic = fieldBuilder.isStatic
         ..isExtensionTypeMember = true;
@@ -1399,6 +1472,7 @@
 
 mixin NonFinalLate on AbstractLateFieldEncoding {
   @override
+  // Coverage-ignore(suite): Not run.
   Statement _createSetterBody(
       CoreTypes coreTypes, String name, VariableDeclaration parameter) {
     assert(_type != null, "Type has not been computed for field $name.");
@@ -1415,6 +1489,7 @@
 
 mixin LateWithoutInitializer on AbstractLateFieldEncoding {
   @override
+  // Coverage-ignore(suite): Not run.
   Statement _createGetterBody(
       CoreTypes coreTypes, String name, Expression? initializer) {
     assert(_type != null, "Type has not been computed for field $name.");
@@ -1443,6 +1518,7 @@
   }
 }
 
+// Coverage-ignore(suite): Not run.
 class LateFieldWithoutInitializerEncoding extends AbstractLateFieldEncoding
     with NonFinalLate, LateWithoutInitializer {
   LateFieldWithoutInitializerEncoding(
@@ -1463,6 +1539,7 @@
       required super.isSetStrategy});
 }
 
+// Coverage-ignore(suite): Not run.
 class LateFieldWithInitializerEncoding extends AbstractLateFieldEncoding
     with NonFinalLate {
   LateFieldWithInitializerEncoding(
@@ -1514,6 +1591,7 @@
   }
 }
 
+// Coverage-ignore(suite): Not run.
 class LateFinalFieldWithoutInitializerEncoding extends AbstractLateFieldEncoding
     with LateWithoutInitializer {
   LateFinalFieldWithoutInitializerEncoding(
@@ -1551,6 +1629,7 @@
   }
 }
 
+// Coverage-ignore(suite): Not run.
 class LateFinalFieldWithInitializerEncoding extends AbstractLateFieldEncoding {
   LateFinalFieldWithInitializerEncoding(
       {required super.name,
@@ -1591,7 +1670,6 @@
       null;
 
   @override
-  // Coverage-ignore(suite): Not run.
   Statement _createSetterBody(
           CoreTypes coreTypes, String name, VariableDeclaration parameter) =>
       throw new UnsupportedError(
@@ -1614,6 +1692,7 @@
   }
 }
 
+// Coverage-ignore(suite): Not run.
 class _SynthesizedFieldClassMember implements ClassMember {
   final SourceFieldBuilder fieldBuilder;
   final _SynthesizedFieldMemberKind _kind;
@@ -1683,7 +1762,6 @@
   DeclarationBuilder get declarationBuilder => fieldBuilder.declarationBuilder!;
 
   @override
-  // Coverage-ignore(suite): Not run.
   bool isObjectMember(ClassBuilder objectClass) {
     return declarationBuilder == objectClass;
   }
@@ -1713,7 +1791,6 @@
   Name get name => _name;
 
   @override
-  // Coverage-ignore(suite): Not run.
   String get fullName {
     String suffix = isSetter ? "=" : "";
     String className = declarationBuilder.fullNameForErrors;
@@ -1739,7 +1816,6 @@
   bool get hasDeclarations => false;
 
   @override
-  // Coverage-ignore(suite): Not run.
   List<ClassMember> get declarations =>
       throw new UnsupportedError("$runtimeType.declarations");
 
@@ -1765,6 +1841,7 @@
   bool get isExtensionTypeMember => fieldBuilder.isExtensionTypeMember;
 }
 
+// Coverage-ignore(suite): Not run.
 class AbstractOrExternalFieldEncoding implements FieldEncoding {
   final SourceFieldBuilder _fieldBuilder;
   final bool isAbstract;
@@ -1935,7 +2012,6 @@
         Procedure? setter = _setter;
         if (setter != null) {
           if (setter.kind == ProcedureKind.Method) {
-            // Coverage-ignore-block(suite): Not run.
             setter.function.positionalParameters[1].type = value;
           } else {
             setter.function.positionalParameters.first.type = value;
@@ -2010,7 +2086,6 @@
   }
 
   @override
-  // Coverage-ignore(suite): Not run.
   void setGenericCovariantImpl() {
     _setter!.function.positionalParameters.first.isCovariantByClass = true;
   }
@@ -2036,14 +2111,12 @@
   Member get readTarget => _getter;
 
   @override
-  // Coverage-ignore(suite): Not run.
   Reference get readTargetReference => _getter.reference;
 
   @override
   Member? get writeTarget => _setter;
 
   @override
-  // Coverage-ignore(suite): Not run.
   Reference? get writeTargetReference => _setter?.reference;
 
   @override
@@ -2098,6 +2171,7 @@
   }
 }
 
+// Coverage-ignore(suite): Not run.
 /// The encoding of an extension type declaration representation field.
 class RepresentationFieldEncoding implements FieldEncoding {
   final SourceFieldBuilder _fieldBuilder;
@@ -2134,10 +2208,7 @@
 
   @override
   void set type(DartType value) {
-    assert(
-        _type == null ||
-            // Coverage-ignore(suite): Not run.
-            _type is InferredType,
+    assert(_type == null || _type is InferredType,
         "Type has already been computed for field ${_fieldBuilder.name}.");
     _type = value;
     if (value is! InferredType) {
@@ -2146,7 +2217,6 @@
   }
 
   @override
-  // Coverage-ignore(suite): Not run.
   void createBodies(CoreTypes coreTypes, Expression? initializer) {
     // TODO(johnniwinther): Enable this assert.
     //assert(initializer != null);
@@ -2198,19 +2268,15 @@
   Member get readTarget => _getter;
 
   @override
-  // Coverage-ignore(suite): Not run.
   Reference get readTargetReference => _getter.reference;
 
   @override
-  // Coverage-ignore(suite): Not run.
   Member? get writeTarget => null;
 
   @override
-  // Coverage-ignore(suite): Not run.
   Reference? get writeTargetReference => null;
 
   @override
-  // Coverage-ignore(suite): Not run.
   Iterable<Reference> get exportedReferenceMembers => [_getter.reference];
 
   @override
@@ -2230,7 +2296,6 @@
       const <ClassMember>[];
 
   @override
-  // Coverage-ignore(suite): Not run.
   void buildImplicitDefaultValue() {
     // Not needed.
   }
diff --git a/pkg/front_end/lib/src/source/source_library_builder.dart b/pkg/front_end/lib/src/source/source_library_builder.dart
index 0b046cd..85f0fb2 100644
--- a/pkg/front_end/lib/src/source/source_library_builder.dart
+++ b/pkg/front_end/lib/src/source/source_library_builder.dart
@@ -70,7 +70,6 @@
 import 'source_extension_builder.dart';
 import 'source_extension_type_declaration_builder.dart';
 import 'source_factory_builder.dart';
-import 'source_field_builder.dart';
 import 'source_loader.dart'
     show CompilationPhaseForProblemReporting, SourceLoader;
 import 'source_member_builder.dart';
@@ -874,7 +873,7 @@
       while (memberIterator.moveNext()) {
         SourceMemberBuilder member = memberIterator.current;
         if (member.isStatic) continue;
-        if (member is SourceFieldBuilder) {
+        if (member.isField) {
           if (member.isSynthesized) continue;
           PropertyNonPromotabilityReason? reason = fieldPromotability.addField(
               classInfo, member, member.name,
@@ -882,7 +881,7 @@
               isAbstract: member.isAbstract,
               isExternal: member.isExternal);
           if (reason != null) {
-            individualPropertyReasons[member.readTarget] = reason;
+            individualPropertyReasons[member.readTarget!] = reason;
           }
         } else if (member.isGetter) {
           if (member.isSynthetic) continue;
@@ -1655,26 +1654,33 @@
     addProblem(message, fileOffset, noLength, fileUri, context: context);
   }
 
-  void checkTypesInField(
-      SourceFieldBuilder fieldBuilder, TypeEnvironment typeEnvironment) {
+  void checkTypesInField(TypeEnvironment typeEnvironment,
+      {required bool isInstanceMember,
+      required bool isLate,
+      required bool isExternal,
+      required bool hasInitializer,
+      required DartType fieldType,
+      required String name,
+      required int nameLength,
+      required int nameOffset,
+      required Uri fileUri}) {
     // Check that the field has an initializer if its type is potentially
     // non-nullable.
 
     // Only static and top-level fields are checked here.  Instance fields are
     // checked elsewhere.
-    DartType fieldType = fieldBuilder.fieldType;
-    if (!fieldBuilder.isDeclarationInstanceMember &&
-        !fieldBuilder.isLate &&
-        !fieldBuilder.isExternal &&
+    if (!isInstanceMember &&
+        !isLate &&
+        !isExternal &&
         fieldType is! InvalidType &&
         fieldType.isPotentiallyNonNullable &&
-        !fieldBuilder.hasInitializer) {
+        !hasInitializer) {
       addProblem(
           templateFieldNonNullableWithoutInitializerError.withArguments(
-              fieldBuilder.name, fieldBuilder.fieldType),
-          fieldBuilder.fileOffset,
-          fieldBuilder.name.length,
-          fieldBuilder.fileUri);
+              name, fieldType),
+          nameOffset,
+          nameLength,
+          fileUri);
     }
   }
 
@@ -2212,8 +2218,8 @@
 
 /// This class examines all the [Class]es in a library and determines which
 /// fields are promotable within that library.
-class _FieldPromotability
-    extends FieldPromotability<Class, SourceFieldBuilder, SourceMemberBuilder> {
+class _FieldPromotability extends FieldPromotability<Class, SourceMemberBuilder,
+    SourceMemberBuilder> {
   @override
   Iterable<Class> getSuperclasses(Class class_,
       {required bool ignoreImplements}) {
@@ -2253,7 +2259,7 @@
   /// see [individualPropertyReasons].
   final Map<
       String,
-      FieldNameNonPromotabilityInfo<Class, SourceFieldBuilder,
+      FieldNameNonPromotabilityInfo<Class, SourceMemberBuilder,
           SourceMemberBuilder>> fieldNameInfo;
 
   /// Map whose keys are the members that a property get might resolve to, and
diff --git a/pkg/front_end/lib/src/source/source_member_builder.dart b/pkg/front_end/lib/src/source/source_member_builder.dart
index 1f9ef75..43a412c 100644
--- a/pkg/front_end/lib/src/source/source_member_builder.dart
+++ b/pkg/front_end/lib/src/source/source_member_builder.dart
@@ -28,6 +28,14 @@
   @override
   SourceLibraryBuilder get libraryBuilder;
 
+  @override
+  Uri get fileUri;
+
+  bool get isFinal;
+
+  // TODO(johnniwinther): Avoid this or define a clear semantics.
+  bool get isSynthesized;
+
   /// Builds the core AST structures for this member as needed for the outline.
   void buildOutlineNodes(BuildNodesCallback f);
 
diff --git a/pkg/front_end/lib/src/source/source_method_builder.dart b/pkg/front_end/lib/src/source/source_method_builder.dart
index af9fad6..8b7ba28 100644
--- a/pkg/front_end/lib/src/source/source_method_builder.dart
+++ b/pkg/front_end/lib/src/source/source_method_builder.dart
@@ -118,6 +118,14 @@
   @override
   bool get isAugment => _modifiers.isAugment;
 
+  @override
+  // Coverage-ignore(suite): Not run.
+  bool get isFinal => false;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  bool get isSynthesized => false;
+
   // TODO(johnniwinther): What is this supposed to return?
   @override
   // Coverage-ignore(suite): Not run.
diff --git a/pkg/front_end/lib/src/source/source_property_builder.dart b/pkg/front_end/lib/src/source/source_property_builder.dart
index 4d2482e..fef0e3c 100644
--- a/pkg/front_end/lib/src/source/source_property_builder.dart
+++ b/pkg/front_end/lib/src/source/source_property_builder.dart
@@ -2,8 +2,10 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:_fe_analyzer_shared/src/metadata/expressions.dart' as shared;
 import 'package:kernel/ast.dart';
 import 'package:kernel/class_hierarchy.dart';
+import 'package:kernel/reference_from_index.dart';
 import 'package:kernel/type_algebra.dart';
 import 'package:kernel/type_environment.dart';
 
@@ -14,6 +16,7 @@
 import '../builder/declaration_builders.dart';
 import '../builder/formal_parameter_builder.dart';
 import '../builder/metadata_builder.dart';
+import '../builder/property_builder.dart';
 import '../builder/type_builder.dart';
 import '../fragment/fragment.dart';
 import '../kernel/augmentation_lowering.dart';
@@ -26,9 +29,11 @@
 import 'source_class_builder.dart';
 import 'source_function_builder.dart';
 import 'source_library_builder.dart';
+import 'source_loader.dart';
 import 'source_member_builder.dart';
 
-class SourcePropertyBuilder extends SourceMemberBuilderImpl {
+class SourcePropertyBuilder extends SourceMemberBuilderImpl
+    implements PropertyBuilder {
   @override
   final Uri fileUri;
 
@@ -53,13 +58,13 @@
   /// same name must be augmentations.
   // TODO(johnniwinther): Support setter and field declarations.
   // TODO(johnniwinther): Add [_augmentations] field.
+  FieldFragment? _introductoryField;
   GetterFragment? _introductoryGetable;
   SetterFragment? _introductorySetable;
 
   Modifiers _modifiers;
 
-  final Reference? _getterReference;
-  final Reference? _setterReference;
+  final PropertyReferences _references;
 
   final MemberName _memberName;
 
@@ -89,12 +94,11 @@
       required this.isStatic,
       required NameScheme nameScheme,
       required GetterFragment fragment,
-      required Reference? getterReference})
+      required PropertyReferences references})
       : _nameScheme = nameScheme,
         _introductoryGetable = fragment,
         _modifiers = fragment.modifiers,
-        _getterReference = getterReference ?? new Reference(),
-        _setterReference = null,
+        _references = references,
         _memberName = nameScheme.getDeclaredName(name);
 
   SourcePropertyBuilder.forSetter(
@@ -106,12 +110,27 @@
       required this.isStatic,
       required NameScheme nameScheme,
       required SetterFragment fragment,
-      required Reference? setterReference})
+      required PropertyReferences references})
       : _nameScheme = nameScheme,
         _introductorySetable = fragment,
         _modifiers = fragment.modifiers,
-        _getterReference = null,
-        _setterReference = setterReference ?? new Reference(),
+        _references = references,
+        _memberName = nameScheme.getDeclaredName(name);
+
+  SourcePropertyBuilder.forField(
+      {required this.fileUri,
+      required this.fileOffset,
+      required this.name,
+      required this.libraryBuilder,
+      required this.declarationBuilder,
+      required this.isStatic,
+      required NameScheme nameScheme,
+      required FieldFragment fragment,
+      required PropertyReferences references})
+      : _nameScheme = nameScheme,
+        _introductoryField = fragment,
+        _modifiers = fragment.modifiers,
+        _references = references,
         _memberName = nameScheme.getDeclaredName(name);
 
   @override
@@ -133,20 +152,27 @@
   @override
   bool get isAugment => _modifiers.isAugment;
 
+  @override
+  bool get isSynthesized => false;
+
   // TODO(johnniwinther): What is this supposed to return?
   @override
   // Coverage-ignore(suite): Not run.
   Iterable<Annotatable> get annotatables => [
         if (readTarget != null) readTarget as Annotatable,
-        if (writeTarget != null) writeTarget as Annotatable
+        if (writeTarget != null && readTarget != writeTarget)
+          writeTarget as Annotatable
       ];
 
   // TODO(johnniwinther): Remove this. This is only needed for detecting patches
   // and macro annotations and we should use the fragment directly once
   // augmentations are fragments.
   List<MetadataBuilder>? get metadata =>
-      _introductoryGetable?.metadata ?? // Coverage-ignore(suite): Not run.
-      _introductorySetable?.metadata;
+      _introductoryGetable?.metadata ??
+      _introductorySetable
+          // Coverage-ignore(suite): Not run.
+          ?.metadata ??
+      _introductoryField?.metadata;
 
   @override
   void applyAugmentation(Builder augmentation) {
@@ -344,11 +370,14 @@
 
   @override
   void buildOutlineNodes(BuildNodesCallback f) {
-    _introductoryGetable?.buildOutlineNode(libraryBuilder, _nameScheme, f,
-        getterReference: _getterReference!,
+    _introductoryField?.buildOutlineNode(
+        libraryBuilder, _nameScheme, f, _references as FieldReference,
         classTypeParameters: classBuilder?.cls.typeParameters);
-    _introductorySetable?.buildOutlineNode(libraryBuilder, _nameScheme, f,
-        setterReference: _setterReference!,
+    _introductoryGetable?.buildOutlineNode(
+        libraryBuilder, _nameScheme, f, _references as GetterReference,
+        classTypeParameters: classBuilder?.cls.typeParameters);
+    _introductorySetable?.buildOutlineNode(
+        libraryBuilder, _nameScheme, f, _references as SetterReference,
         classTypeParameters: classBuilder?.cls.typeParameters);
   }
 
@@ -360,6 +389,18 @@
     if (!hasBuiltOutlineExpressions) {
       LookupScope parentScope =
           declarationBuilder?.scope ?? libraryBuilder.scope;
+      _introductoryField?.buildOutlineExpressions(
+          classHierarchy,
+          libraryBuilder,
+          declarationBuilder,
+          parentScope,
+          [
+            readTarget as Annotatable,
+            if (writeTarget != null && readTarget != writeTarget)
+              writeTarget as Annotatable
+          ],
+          isClassInstanceMember: isClassInstanceMember,
+          createFileUriExpression: isAugmented);
       _introductoryGetable?.buildOutlineExpressions(
           classHierarchy,
           libraryBuilder,
@@ -390,6 +431,8 @@
       setterBuilder = nameSpace.lookupLocalMember(name, setter: true)
           as SourcePropertyBuilder?;
     }
+    _introductoryField?.checkTypes(library, typeEnvironment, setterBuilder,
+        isExternal: isExternal, isAbstract: isAbstract);
     _introductoryGetable?.checkTypes(library, typeEnvironment, setterBuilder,
         isExternal: isExternal, isAbstract: isAbstract);
     _introductorySetable?.checkTypes(library, typeEnvironment,
@@ -412,6 +455,7 @@
   void checkVariance(
       SourceClassBuilder sourceClassBuilder, TypeEnvironment typeEnvironment) {
     if (!isClassInstanceMember) return;
+    _introductoryField?.checkVariance(sourceClassBuilder, typeEnvironment);
     _introductoryGetable?.checkVariance(sourceClassBuilder, typeEnvironment);
     _introductorySetable?.checkVariance(sourceClassBuilder, typeEnvironment);
     List<SourcePropertyBuilder>? getterAugmentations = _getterAugmentations;
@@ -430,21 +474,24 @@
 
   @override
   Iterable<Reference> get exportedMemberReferences => [
-        if (_getterReference != null) _getterReference,
-        if (_setterReference != null) _setterReference
+        ...?_introductoryField
+            ?.getExportedMemberReferences(_references as FieldReference),
+        ...?_introductoryGetable
+            ?.getExportedMemberReferences(_references as GetterReference),
+        ...?_introductorySetable
+            ?.getExportedMemberReferences(_references as SetterReference),
       ];
 
+  // TODO(johnniwinther): Should fields and getters have an invoke target?
   @override
-  Member? get invokeTarget => null;
+  Member? get invokeTarget => readTarget;
 
   @override
   // Coverage-ignore(suite): Not run.
-  Reference? get invokeTargetReference => null;
+  Reference? get invokeTargetReference => readTargetReference;
 
   @override
-  // Coverage-ignore(suite): Not run.
-  bool get isAssignable =>
-      throw new UnsupportedError('$runtimeType.isAssignable');
+  bool get isAssignable => _introductoryField?.hasSetter ?? false;
 
   List<ClassMember>? _localMembers;
 
@@ -452,12 +499,14 @@
 
   @override
   List<ClassMember> get localMembers => _localMembers ??= [
+        ...?_introductoryField?.localMembers,
         if (_introductoryGetable != null)
           new _GetterClassMember(this, _introductoryGetable!)
       ];
 
   @override
   List<ClassMember> get localSetters => _localSetters ??= [
+        ...?_introductoryField?.localSetters,
         if (_introductorySetable != null && !isConflictingSetter)
           new _SetterClassMember(this, _introductorySetable!)
       ];
@@ -466,27 +515,33 @@
   Name get memberName => _memberName.name;
 
   @override
-  Member? get readTarget =>
-      isAugmenting ? _origin!.readTarget : _introductoryGetable?.readTarget;
+  Member? get readTarget => isAugmenting
+      ? _origin!.readTarget
+      : (_introductoryField?.readTarget ?? _introductoryGetable?.readTarget);
 
   @override
   // Coverage-ignore(suite): Not run.
   Reference? get readTargetReference =>
-      isAugmenting ? _origin!.readTargetReference : _getterReference;
+      isAugmenting ? _origin!.readTargetReference : _references.getterReference;
 
   @override
-  Member? get writeTarget =>
-      isAugmenting ? _origin!.writeTarget : _introductorySetable?.writeTarget;
+  Member? get writeTarget => isAugmenting
+      ? _origin!.writeTarget
+      : (_introductorySetable?.writeTarget ?? _introductoryField?.writeTarget);
 
   @override
   // Coverage-ignore(suite): Not run.
-  Reference? get writeTargetReference =>
-      isAugmenting ? _origin!.writeTargetReference : _setterReference;
+  Reference? get writeTargetReference => isAugmenting
+      ? _origin!.writeTargetReference
+      : _references.setterReference;
 
   @override
   int computeDefaultTypes(ComputeDefaultTypeContext context,
       {required bool inErrorRecovery}) {
     int count = 0;
+    if (_introductoryField != null) {
+      count += _introductoryField!.computeDefaultTypes(context);
+    }
     if (_introductoryGetable != null) {
       count += _introductoryGetable!.computeDefaultTypes(context);
     }
@@ -517,12 +572,20 @@
   TypeBuilder? get returnTypeForTesting =>
       _introductoryGetable?.returnType ?? _introductorySetable?.returnType;
 
+  // Coverage-ignore(suite): Not run.
+  TypeBuilder? get typeForTesting => _introductoryField?.type;
+
   @override
   bool get isAugmenting => this != origin;
 
   @override
   bool get isProperty => true;
 
+  // TODO(johnniwinther): Remove this. Maybe replace with `hasField`,
+  // `hasGetter` and `hasSetter`?
+  @override
+  bool get isField => _introductoryField != null;
+
   // TODO(johnniwinther): Remove this. Maybe replace with `hasGetter`?
   @override
   bool get isGetter => _introductoryGetable != null;
@@ -534,7 +597,7 @@
   bool _typeEnsured = false;
   Set<ClassMember>? _getterOverrideDependencies;
 
-  void _registerGetterOverrideDependency(Set<ClassMember> overriddenMembers) {
+  void registerGetterOverrideDependency(Set<ClassMember> overriddenMembers) {
     assert(
         overriddenMembers.every((overriddenMember) =>
             overriddenMember.declarationBuilder != classBuilder),
@@ -545,7 +608,7 @@
 
   Set<ClassMember>? _setterOverrideDependencies;
 
-  void _registerSetterOverrideDependency(Set<ClassMember> overriddenMembers) {
+  void registerSetterOverrideDependency(Set<ClassMember> overriddenMembers) {
     assert(
         overriddenMembers.every((overriddenMember) =>
             overriddenMember.declarationBuilder != classBuilder),
@@ -554,13 +617,15 @@
     _setterOverrideDependencies!.addAll(overriddenMembers);
   }
 
-  void _ensureTypes(ClassMembersBuilder membersBuilder) {
+  void ensureTypes(ClassMembersBuilder membersBuilder) {
     if (_typeEnsured) return;
-    _introductoryGetable?.ensureTypes(membersBuilder,
-        declarationBuilder as SourceClassBuilder, _getterOverrideDependencies);
+    _introductoryField?.ensureTypes(membersBuilder, _getterOverrideDependencies,
+        _setterOverrideDependencies);
+    _introductoryGetable?.ensureTypes(
+        membersBuilder, _getterOverrideDependencies);
+    _introductorySetable?.ensureTypes(
+        membersBuilder, _setterOverrideDependencies);
     _getterOverrideDependencies = null;
-    _introductorySetable?.ensureTypes(membersBuilder,
-        declarationBuilder as SourceClassBuilder, _setterOverrideDependencies);
     _setterOverrideDependencies = null;
     _typeEnsured = true;
   }
@@ -602,6 +667,63 @@
     }
     return setterType;
   }
+
+  @override
+  DartType get fieldType {
+    return _introductoryField!.fieldType;
+  }
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  void set fieldType(DartType value) {
+    _introductoryField!.fieldType = value;
+  }
+
+  @override
+  Initializer buildErroneousInitializer(Expression effect, Expression value,
+      {required int fileOffset}) {
+    return _introductoryField!
+        .buildErroneousInitializer(effect, value, fileOffset: fileOffset);
+  }
+
+  @override
+  void buildImplicitDefaultValue() {
+    _introductoryField!.buildImplicitDefaultValue();
+  }
+
+  @override
+  Initializer buildImplicitInitializer() {
+    return _introductoryField!.buildImplicitInitializer();
+  }
+
+  @override
+  List<Initializer> buildInitializer(int fileOffset, Expression value,
+      {required bool isSynthetic}) {
+    return _introductoryField!
+        .buildInitializer(fileOffset, value, isSynthetic: isSynthetic);
+  }
+
+  @override
+  bool get hasInitializer => _introductoryField!.hasInitializer;
+
+  @override
+  bool get isExtensionTypeDeclaredInstanceField =>
+      _introductoryField!.isExtensionTypeDeclaredInstanceField;
+
+  @override
+  bool get isFinal => _introductoryField!.isFinal;
+
+  @override
+  bool get isLate => _introductoryField!.isLate;
+
+  @override
+  DartType inferType(ClassHierarchyBase hierarchy) {
+    return _introductoryField!.inferType(hierarchy);
+  }
+
+  // Coverage-ignore(suite): Not run.
+  shared.Expression? get initializerExpression =>
+      _introductoryField?.initializerExpression;
 }
 
 class _GetterClassMember implements ClassMember {
@@ -674,7 +796,7 @@
 
   @override
   void inferType(ClassMembersBuilder membersBuilder) {
-    _builder._ensureTypes(membersBuilder);
+    _builder.ensureTypes(membersBuilder);
   }
 
   @override
@@ -741,7 +863,7 @@
 
   @override
   void registerOverrideDependency(Set<ClassMember> overriddenMembers) {
-    _builder._registerGetterOverrideDependency(overriddenMembers);
+    _builder.registerGetterOverrideDependency(overriddenMembers);
   }
 
   @override
@@ -820,7 +942,7 @@
 
   @override
   void inferType(ClassMembersBuilder membersBuilder) {
-    _builder._ensureTypes(membersBuilder);
+    _builder.ensureTypes(membersBuilder);
   }
 
   @override
@@ -886,9 +1008,332 @@
 
   @override
   void registerOverrideDependency(Set<ClassMember> overriddenMembers) {
-    _builder._registerSetterOverrideDependency(overriddenMembers);
+    _builder.registerSetterOverrideDependency(overriddenMembers);
   }
 
   @override
   String toString() => '$runtimeType($fullName,forSetter=${forSetter})';
 }
+
+abstract class PropertyReferences {
+  Reference? get getterReference;
+  Reference? get setterReference;
+}
+
+class GetterReference extends PropertyReferences {
+  Reference? _getterReference;
+
+  GetterReference._(this._getterReference);
+
+  factory GetterReference(
+      String name, NameScheme nameScheme, IndexedContainer? indexedContainer,
+      {required bool isAugmentation}) {
+    Reference? procedureReference;
+    ProcedureKind kind = ProcedureKind.Getter;
+    if (indexedContainer != null && !isAugmentation) {
+      Name nameToLookup = nameScheme.getProcedureMemberName(kind, name).name;
+      procedureReference = indexedContainer.lookupGetterReference(nameToLookup);
+    }
+    return new GetterReference._(procedureReference);
+  }
+
+  void registerReference(SourceLoader loader, Builder builder) {
+    if (_getterReference != null) {
+      loader.buildersCreatedWithReferences[_getterReference!] = builder;
+    }
+  }
+
+  @override
+  Reference get getterReference => _getterReference ??= new Reference();
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  Reference? get setterReference => null;
+}
+
+class SetterReference extends PropertyReferences {
+  Reference? _setterReference;
+
+  SetterReference._(this._setterReference);
+
+  factory SetterReference(
+      String name, NameScheme nameScheme, IndexedContainer? indexedContainer,
+      {required bool isAugmentation}) {
+    Reference? procedureReference;
+    ProcedureKind kind = ProcedureKind.Setter;
+    if (indexedContainer != null && !isAugmentation) {
+      Name nameToLookup = nameScheme.getProcedureMemberName(kind, name).name;
+      if ((nameScheme.isExtensionMember || nameScheme.isExtensionTypeMember) &&
+          nameScheme.isInstanceMember) {
+        // Extension (type) instance setters are encoded as methods.
+        procedureReference =
+            indexedContainer.lookupGetterReference(nameToLookup);
+      } else {
+        procedureReference =
+            indexedContainer.lookupSetterReference(nameToLookup);
+      }
+    }
+    return new SetterReference._(procedureReference);
+  }
+
+  void registerReference(SourceLoader loader, Builder builder) {
+    if (_setterReference != null) {
+      loader.buildersCreatedWithReferences[_setterReference!] = builder;
+    }
+  }
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  Reference? get getterReference => null;
+
+  @override
+  Reference get setterReference => _setterReference ??= new Reference();
+}
+
+abstract class FieldReference extends PropertyReferences {
+  factory FieldReference(
+      String name, NameScheme nameScheme, IndexedContainer? indexedContainer,
+      {required bool fieldIsLateWithLowering, required bool isExternal}) {
+    Reference? fieldReference;
+    Reference? fieldGetterReference;
+    Reference? fieldSetterReference;
+    Reference? lateIsSetFieldReference;
+    Reference? lateIsSetGetterReference;
+    Reference? lateIsSetSetterReference;
+    Reference? lateGetterReference;
+    Reference? lateSetterReference;
+    if (indexedContainer != null) {
+      if ((nameScheme.isExtensionMember || nameScheme.isExtensionTypeMember) &&
+          nameScheme.isInstanceMember &&
+          isExternal) {
+        /// An external extension (type) instance field is special. It is
+        /// treated as an external getter/setter pair and is therefore
+        /// encoded as a pair of top level methods using the extension
+        /// instance member naming convention.
+        fieldGetterReference = indexedContainer.lookupGetterReference(
+            nameScheme.getProcedureMemberName(ProcedureKind.Getter, name).name);
+        fieldSetterReference = indexedContainer.lookupGetterReference(
+            nameScheme.getProcedureMemberName(ProcedureKind.Setter, name).name);
+      } else if (nameScheme.isExtensionTypeMember &&
+          nameScheme.isInstanceMember) {
+        Name nameToLookup = nameScheme
+            .getFieldMemberName(FieldNameType.RepresentationField, name,
+                isSynthesized: true)
+            .name;
+        fieldGetterReference =
+            indexedContainer.lookupGetterReference(nameToLookup);
+      } else {
+        Name nameToLookup = nameScheme
+            .getFieldMemberName(FieldNameType.Field, name,
+                isSynthesized: fieldIsLateWithLowering)
+            .name;
+        fieldReference = indexedContainer.lookupFieldReference(nameToLookup);
+        fieldGetterReference =
+            indexedContainer.lookupGetterReference(nameToLookup);
+        fieldSetterReference =
+            indexedContainer.lookupSetterReference(nameToLookup);
+      }
+
+      if (fieldIsLateWithLowering) {
+        Name lateIsSetName = nameScheme
+            .getFieldMemberName(FieldNameType.IsSetField, name,
+                isSynthesized: fieldIsLateWithLowering)
+            .name;
+        lateIsSetFieldReference =
+            indexedContainer.lookupFieldReference(lateIsSetName);
+        lateIsSetGetterReference =
+            indexedContainer.lookupGetterReference(lateIsSetName);
+        lateIsSetSetterReference =
+            indexedContainer.lookupSetterReference(lateIsSetName);
+        lateGetterReference = indexedContainer.lookupGetterReference(nameScheme
+            .getFieldMemberName(FieldNameType.Getter, name,
+                isSynthesized: fieldIsLateWithLowering)
+            .name);
+        lateSetterReference = indexedContainer.lookupSetterReference(nameScheme
+            .getFieldMemberName(FieldNameType.Setter, name,
+                isSynthesized: fieldIsLateWithLowering)
+            .name);
+      }
+    }
+    if (fieldIsLateWithLowering) {
+      return new _LateFieldLoweringReference._(
+          fieldReference: fieldReference,
+          fieldGetterReference: fieldGetterReference,
+          fieldSetterReference: fieldSetterReference,
+          lateIsSetFieldReference: lateIsSetFieldReference,
+          lateIsSetGetterReference: lateIsSetGetterReference,
+          lateIsSetSetterReference: lateIsSetSetterReference,
+          lateGetterReference: lateGetterReference,
+          lateSetterReference: lateSetterReference);
+    } else {
+      return new _RegularFieldReference._(
+          fieldReference: fieldReference,
+          fieldGetterReference: fieldGetterReference,
+          fieldSetterReference: fieldSetterReference,
+          lateIsSetFieldReference: lateIsSetFieldReference,
+          lateIsSetGetterReference: lateIsSetGetterReference,
+          lateIsSetSetterReference: lateIsSetSetterReference,
+          lateGetterReference: lateGetterReference,
+          lateSetterReference: lateSetterReference);
+    }
+  }
+
+  void registerReference(SourceLoader loader, Builder builder);
+
+  Reference get fieldReference;
+  Reference get fieldGetterReference;
+  Reference get fieldSetterReference;
+  Reference get lateIsSetFieldReference;
+  Reference get lateIsSetGetterReference;
+  Reference get lateIsSetSetterReference;
+  Reference get lateGetterReference;
+  Reference get lateSetterReference;
+}
+
+class _RegularFieldReference implements FieldReference {
+  Reference? _fieldReference;
+  Reference? _fieldGetterReference;
+  Reference? _fieldSetterReference;
+  Reference? _lateIsSetFieldReference;
+  Reference? _lateIsSetGetterReference;
+  Reference? _lateIsSetSetterReference;
+  Reference? _lateGetterReference;
+  Reference? _lateSetterReference;
+
+  _RegularFieldReference._(
+      {required Reference? fieldReference,
+      required Reference? fieldGetterReference,
+      required Reference? fieldSetterReference,
+      required Reference? lateIsSetFieldReference,
+      required Reference? lateIsSetGetterReference,
+      required Reference? lateIsSetSetterReference,
+      required Reference? lateGetterReference,
+      required Reference? lateSetterReference})
+      : _fieldReference = fieldReference,
+        _fieldGetterReference = fieldGetterReference,
+        _fieldSetterReference = fieldSetterReference,
+        _lateIsSetFieldReference = lateIsSetFieldReference,
+        _lateIsSetGetterReference = lateIsSetGetterReference,
+        _lateIsSetSetterReference = lateIsSetSetterReference,
+        _lateGetterReference = lateGetterReference,
+        _lateSetterReference = lateSetterReference;
+
+  @override
+  void registerReference(SourceLoader loader, Builder builder) {
+    if (_fieldGetterReference != null) {
+      loader.buildersCreatedWithReferences[_fieldGetterReference!] = builder;
+    }
+    if (_fieldSetterReference != null) {
+      loader.buildersCreatedWithReferences[_fieldSetterReference!] = builder;
+    }
+  }
+
+  @override
+  Reference get fieldReference => _fieldReference ??= new Reference();
+
+  @override
+  Reference get fieldGetterReference =>
+      _fieldGetterReference ??= new Reference();
+
+  @override
+  Reference get fieldSetterReference =>
+      _fieldSetterReference ??= new Reference();
+
+  @override
+  Reference get lateIsSetFieldReference =>
+      _lateIsSetFieldReference ??= new Reference();
+
+  @override
+  Reference get lateIsSetGetterReference =>
+      _lateIsSetGetterReference ??= new Reference();
+
+  @override
+  Reference get lateIsSetSetterReference =>
+      _lateIsSetSetterReference ??= new Reference();
+
+  @override
+  Reference get lateGetterReference => _lateGetterReference ??= new Reference();
+
+  @override
+  Reference get lateSetterReference => _lateSetterReference ??= new Reference();
+
+  @override
+  Reference? get getterReference => fieldGetterReference;
+
+  @override
+  Reference? get setterReference => fieldSetterReference;
+}
+
+class _LateFieldLoweringReference implements FieldReference {
+  Reference? _fieldReference;
+  Reference? _fieldGetterReference;
+  Reference? _fieldSetterReference;
+  Reference? _lateIsSetFieldReference;
+  Reference? _lateIsSetGetterReference;
+  Reference? _lateIsSetSetterReference;
+  Reference? _lateGetterReference;
+  Reference? _lateSetterReference;
+
+  _LateFieldLoweringReference._(
+      {required Reference? fieldReference,
+      required Reference? fieldGetterReference,
+      required Reference? fieldSetterReference,
+      required Reference? lateIsSetFieldReference,
+      required Reference? lateIsSetGetterReference,
+      required Reference? lateIsSetSetterReference,
+      required Reference? lateGetterReference,
+      required Reference? lateSetterReference})
+      : _fieldReference = fieldReference,
+        _fieldGetterReference = fieldGetterReference,
+        _fieldSetterReference = fieldSetterReference,
+        _lateIsSetFieldReference = lateIsSetFieldReference,
+        _lateIsSetGetterReference = lateIsSetGetterReference,
+        _lateIsSetSetterReference = lateIsSetSetterReference,
+        _lateGetterReference = lateGetterReference,
+        _lateSetterReference = lateSetterReference;
+
+  @override
+  void registerReference(SourceLoader loader, Builder builder) {
+    if (_fieldGetterReference != null) {
+      loader.buildersCreatedWithReferences[_fieldGetterReference!] = builder;
+    }
+    if (_fieldSetterReference != null) {
+      loader.buildersCreatedWithReferences[_fieldSetterReference!] = builder;
+    }
+  }
+
+  @override
+  Reference get fieldReference => _fieldReference ??= new Reference();
+
+  @override
+  Reference get fieldGetterReference =>
+      _fieldGetterReference ??= new Reference();
+
+  @override
+  Reference get fieldSetterReference =>
+      _fieldSetterReference ??= new Reference();
+
+  @override
+  Reference get lateIsSetFieldReference =>
+      _lateIsSetFieldReference ??= new Reference();
+
+  @override
+  Reference get lateIsSetGetterReference =>
+      _lateIsSetGetterReference ??= new Reference();
+
+  @override
+  Reference get lateIsSetSetterReference =>
+      _lateIsSetSetterReference ??= new Reference();
+
+  @override
+  Reference get lateGetterReference => _lateGetterReference ??= new Reference();
+
+  @override
+  Reference get lateSetterReference => _lateSetterReference ??= new Reference();
+
+  @override
+  Reference? get getterReference => lateGetterReference;
+
+  @override
+  Reference? get setterReference => lateSetterReference;
+}
diff --git a/pkg/front_end/lib/src/source/synthetic_method_builder.dart b/pkg/front_end/lib/src/source/synthetic_method_builder.dart
index 3e9689c..093b352 100644
--- a/pkg/front_end/lib/src/source/synthetic_method_builder.dart
+++ b/pkg/front_end/lib/src/source/synthetic_method_builder.dart
@@ -133,6 +133,14 @@
   bool get isProperty => false;
 
   @override
+  // Coverage-ignore(suite): Not run.
+  bool get isFinal => false;
+
+  @override
+  // Coverage-ignore(suite): Not run.
+  bool get isSynthesized => true;
+
+  @override
   late final List<ClassMember> localMembers = [
     new _SyntheticMethodClassMember(this)
   ];
diff --git a/pkg/front_end/lib/src/source/type_parameter_scope_builder.dart b/pkg/front_end/lib/src/source/type_parameter_scope_builder.dart
index 6bcba25c..bc8b3d9 100644
--- a/pkg/front_end/lib/src/source/type_parameter_scope_builder.dart
+++ b/pkg/front_end/lib/src/source/type_parameter_scope_builder.dart
@@ -32,7 +32,6 @@
 import 'source_extension_builder.dart';
 import 'source_extension_type_declaration_builder.dart';
 import 'source_factory_builder.dart';
-import 'source_field_builder.dart';
 import 'source_library_builder.dart';
 import 'source_loader.dart';
 import 'source_method_builder.dart';
@@ -1481,9 +1480,6 @@
 
         final bool isInstanceMember = containerType != ContainerType.Library &&
             !fragment.modifiers.isStatic;
-        final bool isExtensionMember = containerType == ContainerType.Extension;
-        final bool isExtensionTypeMember =
-            containerType == ContainerType.ExtensionType;
 
         NameScheme nameScheme = new NameScheme(
             isInstanceMember: isInstanceMember,
@@ -1494,107 +1490,26 @@
                 : enclosingLibraryBuilder.libraryName);
         indexedContainer ??= indexedLibrary;
 
-        Reference? fieldReference;
-        Reference? fieldGetterReference;
-        Reference? fieldSetterReference;
-        Reference? lateIsSetFieldReference;
-        Reference? lateIsSetGetterReference;
-        Reference? lateIsSetSetterReference;
-        Reference? lateGetterReference;
-        Reference? lateSetterReference;
-        if (indexedContainer != null) {
-          if ((isExtensionMember || isExtensionTypeMember) &&
-              isInstanceMember &&
-              fragment.modifiers.isExternal) {
-            /// An external extension (type) instance field is special. It is
-            /// treated as an external getter/setter pair and is therefore
-            /// encoded as a pair of top level methods using the extension
-            /// instance member naming convention.
-            fieldGetterReference = indexedContainer!.lookupGetterReference(
-                nameScheme
-                    .getProcedureMemberName(ProcedureKind.Getter, name)
-                    .name);
-            fieldSetterReference = indexedContainer!.lookupGetterReference(
-                nameScheme
-                    .getProcedureMemberName(ProcedureKind.Setter, name)
-                    .name);
-          } else if (isExtensionTypeMember && isInstanceMember) {
-            Name nameToLookup = nameScheme
-                .getFieldMemberName(FieldNameType.RepresentationField, name,
-                    isSynthesized: true)
-                .name;
-            fieldGetterReference =
-                indexedContainer!.lookupGetterReference(nameToLookup);
-          } else {
-            Name nameToLookup = nameScheme
-                .getFieldMemberName(FieldNameType.Field, name,
-                    isSynthesized: fieldIsLateWithLowering)
-                .name;
-            fieldReference =
-                indexedContainer!.lookupFieldReference(nameToLookup);
-            fieldGetterReference =
-                indexedContainer!.lookupGetterReference(nameToLookup);
-            fieldSetterReference =
-                indexedContainer!.lookupSetterReference(nameToLookup);
-          }
+        FieldReference references = new FieldReference(
+            name, nameScheme, indexedContainer,
+            fieldIsLateWithLowering: fieldIsLateWithLowering,
+            isExternal: fragment.modifiers.isExternal);
 
-          if (fieldIsLateWithLowering) {
-            Name lateIsSetName = nameScheme
-                .getFieldMemberName(FieldNameType.IsSetField, name,
-                    isSynthesized: fieldIsLateWithLowering)
-                .name;
-            lateIsSetFieldReference =
-                indexedContainer!.lookupFieldReference(lateIsSetName);
-            lateIsSetGetterReference =
-                indexedContainer!.lookupGetterReference(lateIsSetName);
-            lateIsSetSetterReference =
-                indexedContainer!.lookupSetterReference(lateIsSetName);
-            lateGetterReference = indexedContainer!.lookupGetterReference(
-                nameScheme
-                    .getFieldMemberName(FieldNameType.Getter, name,
-                        isSynthesized: fieldIsLateWithLowering)
-                    .name);
-            lateSetterReference = indexedContainer!.lookupSetterReference(
-                nameScheme
-                    .getFieldMemberName(FieldNameType.Setter, name,
-                        isSynthesized: fieldIsLateWithLowering)
-                    .name);
-          }
-        }
-        SourceFieldBuilder fieldBuilder = new SourceFieldBuilder(
-            metadata: fragment.metadata,
-            type: fragment.type,
-            name: name,
-            modifiers: fragment.modifiers,
-            isTopLevel: fragment.isTopLevel,
-            isPrimaryConstructorField: fragment.isPrimaryConstructorField,
-            libraryBuilder: enclosingLibraryBuilder,
-            declarationBuilder: declarationBuilder,
-            fileUri: fragment.fileUri,
-            nameOffset: fragment.nameOffset,
-            endOffset: fragment.endOffset,
-            nameScheme: nameScheme,
-            fieldReference: fieldReference,
-            fieldGetterReference: fieldGetterReference,
-            fieldSetterReference: fieldSetterReference,
-            lateIsSetFieldReference: lateIsSetFieldReference,
-            lateIsSetGetterReference: lateIsSetGetterReference,
-            lateIsSetSetterReference: lateIsSetSetterReference,
-            lateGetterReference: lateGetterReference,
-            lateSetterReference: lateSetterReference,
-            initializerToken: fragment.initializerToken,
-            constInitializerToken: fragment.constInitializerToken);
-        fragment.builder = fieldBuilder;
-        builders.add(new _AddBuilder(fragment.name, fieldBuilder,
+        SourcePropertyBuilder propertyBuilder =
+            new SourcePropertyBuilder.forField(
+                fileUri: fragment.fileUri,
+                fileOffset: fragment.nameOffset,
+                name: name,
+                libraryBuilder: enclosingLibraryBuilder,
+                declarationBuilder: declarationBuilder,
+                isStatic: fragment.modifiers.isStatic,
+                nameScheme: nameScheme,
+                fragment: fragment,
+                references: references);
+        fragment.builder = propertyBuilder;
+        builders.add(new _AddBuilder(fragment.name, propertyBuilder,
             fragment.fileUri, fragment.nameOffset));
-        if (fieldGetterReference != null) {
-          loader.buildersCreatedWithReferences[fieldGetterReference] =
-              fieldBuilder;
-        }
-        if (fieldSetterReference != null) {
-          loader.buildersCreatedWithReferences[fieldSetterReference] =
-              fieldBuilder;
-        }
+        references.registerReference(loader, propertyBuilder);
       case GetterFragment():
         String name = fragment.name;
         final bool isInstanceMember = containerType != ContainerType.Library &&
@@ -1604,7 +1519,7 @@
           List<NominalParameterBuilder>? typeParameters,
           List<FormalParameterBuilder>? formals
         ) = _createTypeParametersAndFormals(
-            declarationBuilder, null, null, unboundNominalParameters,
+            declarationBuilder, unboundNominalParameters,
             isInstanceMember: isInstanceMember,
             fileUri: fragment.fileUri,
             nameOffset: fragment.nameOffset);
@@ -1621,19 +1536,15 @@
                 ? new LibraryName(indexedLibrary.library.reference)
                 : enclosingLibraryBuilder.libraryName);
 
-        Reference? procedureReference;
         indexedContainer ??= indexedLibrary;
 
         bool isAugmentation = enclosingLibraryBuilder.isAugmenting &&
             fragment.modifiers.isAugment;
 
-        ProcedureKind kind = ProcedureKind.Getter;
-        if (indexedContainer != null && !isAugmentation) {
-          Name nameToLookup =
-              nameScheme.getProcedureMemberName(kind, name).name;
-          procedureReference =
-              indexedContainer!.lookupGetterReference(nameToLookup);
-        }
+        GetterReference references = new GetterReference(
+            name, nameScheme, indexedContainer,
+            isAugmentation: isAugmentation);
+
         SourcePropertyBuilder propertyBuilder =
             new SourcePropertyBuilder.forGetter(
                 fileUri: fragment.fileUri,
@@ -1644,14 +1555,11 @@
                 isStatic: fragment.modifiers.isStatic,
                 fragment: fragment,
                 nameScheme: nameScheme,
-                getterReference: procedureReference);
+                references: references);
         fragment.setBuilder(propertyBuilder, typeParameters, formals);
         builders.add(new _AddBuilder(fragment.name, propertyBuilder,
             fragment.fileUri, fragment.nameOffset));
-        if (procedureReference != null) {
-          loader.buildersCreatedWithReferences[procedureReference] =
-              propertyBuilder;
-        }
+        references.registerReference(loader, propertyBuilder);
       case SetterFragment():
         String name = fragment.name;
         final bool isInstanceMember = containerType != ContainerType.Library &&
@@ -1661,7 +1569,7 @@
           List<NominalParameterBuilder>? typeParameters,
           List<FormalParameterBuilder>? formals
         ) = _createTypeParametersAndFormals(
-            declarationBuilder, null, null, unboundNominalParameters,
+            declarationBuilder, unboundNominalParameters,
             isInstanceMember: isInstanceMember,
             fileUri: fragment.fileUri,
             nameOffset: fragment.nameOffset);
@@ -1670,10 +1578,6 @@
             problemReporting, typeParameters,
             ownerName: name, allowNameConflict: true);
 
-        final bool isExtensionMember = containerType == ContainerType.Extension;
-        final bool isExtensionTypeMember =
-            containerType == ContainerType.ExtensionType;
-
         NameScheme nameScheme = new NameScheme(
             containerName: containerName,
             containerType: containerType,
@@ -1682,26 +1586,15 @@
                 ? new LibraryName(indexedLibrary.library.reference)
                 : enclosingLibraryBuilder.libraryName);
 
-        Reference? procedureReference;
         indexedContainer ??= indexedLibrary;
 
         bool isAugmentation = enclosingLibraryBuilder.isAugmenting &&
             fragment.modifiers.isAugment;
 
-        ProcedureKind kind = ProcedureKind.Setter;
-        if (indexedContainer != null && !isAugmentation) {
-          Name nameToLookup =
-              nameScheme.getProcedureMemberName(kind, name).name;
-          if ((isExtensionMember || isExtensionTypeMember) &&
-              isInstanceMember) {
-            // Extension (type) instance setters are encoded as methods.
-            procedureReference =
-                indexedContainer!.lookupGetterReference(nameToLookup);
-          } else {
-            procedureReference =
-                indexedContainer!.lookupSetterReference(nameToLookup);
-          }
-        }
+        SetterReference references = new SetterReference(
+            name, nameScheme, indexedContainer,
+            isAugmentation: isAugmentation);
+
         SourcePropertyBuilder propertyBuilder =
             new SourcePropertyBuilder.forSetter(
                 fileUri: fragment.fileUri,
@@ -1712,14 +1605,11 @@
                 isStatic: fragment.modifiers.isStatic,
                 fragment: fragment,
                 nameScheme: nameScheme,
-                setterReference: procedureReference);
+                references: references);
         fragment.setBuilder(propertyBuilder, typeParameters, formals);
         builders.add(new _AddBuilder(fragment.name, propertyBuilder,
             fragment.fileUri, fragment.nameOffset));
-        if (procedureReference != null) {
-          loader.buildersCreatedWithReferences[procedureReference] =
-              propertyBuilder;
-        }
+        references.registerReference(loader, propertyBuilder);
         if (conflictingSetter) {
           propertyBuilder.isConflictingSetter = true;
         }
@@ -1732,7 +1622,7 @@
           List<NominalParameterBuilder>? typeParameters,
           List<FormalParameterBuilder>? formals
         ) = _createTypeParametersAndFormals(
-            declarationBuilder, null, null, unboundNominalParameters,
+            declarationBuilder, unboundNominalParameters,
             isInstanceMember: isInstanceMember,
             fileUri: fragment.fileUri,
             nameOffset: fragment.nameOffset);
@@ -2605,14 +2495,13 @@
 (
   List<NominalParameterBuilder>? typeParameters,
   List<FormalParameterBuilder>? formals
-) _createTypeParametersAndFormals(
-    DeclarationBuilder? declarationBuilder,
-    List<NominalParameterBuilder>? typeParameters,
-    List<FormalParameterBuilder>? formals,
+) _createTypeParametersAndFormals(DeclarationBuilder? declarationBuilder,
     List<NominalParameterBuilder> _unboundNominalVariables,
     {required bool isInstanceMember,
     required Uri fileUri,
     required int nameOffset}) {
+  List<NominalParameterBuilder>? typeParameters;
+  List<FormalParameterBuilder>? formals;
   if (isInstanceMember) {
     switch (declarationBuilder) {
       case ExtensionBuilder():
@@ -2624,13 +2513,7 @@
                     InstanceTypeParameterAccessState.Allowed);
 
         if (nominalVariableCopy != null) {
-          if (typeParameters != null) {
-            // Coverage-ignore-block(suite): Not run.
-            typeParameters = nominalVariableCopy.newParameterBuilders
-              ..addAll(typeParameters);
-          } else {
-            typeParameters = nominalVariableCopy.newParameterBuilders;
-          }
+          typeParameters = nominalVariableCopy.newParameterBuilders;
         }
 
         TypeBuilder thisType = declarationBuilder.onType;
@@ -2647,10 +2530,6 @@
               isExtensionThis: true,
               hasImmediatelyDeclaredInitializer: false)
         ];
-        if (formals != null) {
-          // Coverage-ignore-block(suite): Not run.
-          synthesizedFormals.addAll(formals);
-        }
         formals = synthesizedFormals;
       case ExtensionTypeDeclarationBuilder():
         NominalParameterCopy? nominalVariableCopy =
@@ -2661,13 +2540,7 @@
                     InstanceTypeParameterAccessState.Allowed);
 
         if (nominalVariableCopy != null) {
-          if (typeParameters != null) {
-            // Coverage-ignore-block(suite): Not run.
-            typeParameters = nominalVariableCopy.newParameterBuilders
-              ..addAll(typeParameters);
-          } else {
-            typeParameters = nominalVariableCopy.newParameterBuilders;
-          }
+          typeParameters = nominalVariableCopy.newParameterBuilders;
         }
 
         TypeBuilder thisType =
@@ -2699,10 +2572,6 @@
               isExtensionThis: true,
               hasImmediatelyDeclaredInitializer: false)
         ];
-        if (formals != null) {
-          // Coverage-ignore-block(suite): Not run.
-          synthesizedFormals.addAll(formals);
-        }
         formals = synthesizedFormals;
       case ClassFragment():
       case MixinFragment():
diff --git a/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart b/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart
index 2927ddd..6c87506 100644
--- a/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart
+++ b/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart
@@ -38,7 +38,6 @@
 import '../kernel/kernel_helper.dart';
 import '../kernel/type_algorithms.dart' show hasAnyTypeParameters;
 import '../source/source_constructor_builder.dart';
-import '../source/source_field_builder.dart';
 import '../source/source_library_builder.dart'
     show FieldNonPromotabilityInfo, SourceLibraryBuilder;
 import '../source/source_member_builder.dart';
@@ -4416,16 +4415,16 @@
       // libraries, so just don't generate a context message.
       return const [];
     }
-    FieldNameNonPromotabilityInfo<Class, SourceFieldBuilder,
+    FieldNameNonPromotabilityInfo<Class, SourceMemberBuilder,
             SourceMemberBuilder>? fieldNameInfo =
         fieldNonPromotabilityInfo.fieldNameInfo[reason.propertyName];
     List<LocatedMessage> messages = [];
     if (fieldNameInfo != null) {
-      for (SourceFieldBuilder field in fieldNameInfo.conflictingFields) {
+      for (SourceMemberBuilder field in fieldNameInfo.conflictingFields) {
         messages.add(templateFieldNotPromotedBecauseConflictingField
             .withArguments(
                 reason.propertyName,
-                field.readTarget.enclosingClass!.name,
+                field.readTarget!.enclosingClass!.name,
                 NonPromotionDocumentationLink.conflictingNonPromotableField.url)
             .withLocation(field.fileUri, field.fileOffset, noLength));
       }
@@ -4435,7 +4434,7 @@
                 reason.propertyName,
                 getter.readTarget!.enclosingClass!.name,
                 NonPromotionDocumentationLink.conflictingGetter.url)
-            .withLocation(getter.fileUri!, getter.fileOffset, noLength));
+            .withLocation(getter.fileUri, getter.fileOffset, noLength));
       }
       for (Class nsmClass in fieldNameInfo.conflictingNsmClasses) {
         messages.add(templateFieldNotPromotedBecauseConflictingNsmForwarder
diff --git a/pkg/front_end/test/coverage_suite_expected.dart b/pkg/front_end/test/coverage_suite_expected.dart
index aea19d9..6f7e123 100644
--- a/pkg/front_end/test/coverage_suite_expected.dart
+++ b/pkg/front_end/test/coverage_suite_expected.dart
@@ -208,9 +208,9 @@
     hitCount: 260,
     missCount: 0,
   ),
-  // 99.38931297709924%.
+  // 99.38837920489296%.
   "package:front_end/src/base/scope.dart": (
-    hitCount: 651,
+    hitCount: 650,
     missCount: 4,
   ),
   // 100.0%.
@@ -245,7 +245,7 @@
   ),
   // 100.0%.
   "package:front_end/src/builder/builder_mixins.dart": (
-    hitCount: 44,
+    hitCount: 45,
     missCount: 0,
   ),
   // 100.0%.
@@ -290,7 +290,7 @@
   ),
   // 100.0%.
   "package:front_end/src/builder/formal_parameter_builder.dart": (
-    hitCount: 169,
+    hitCount: 170,
     missCount: 0,
   ),
   // 100.0%.
@@ -325,7 +325,7 @@
   ),
   // 100.0%.
   "package:front_end/src/builder/member_builder.dart": (
-    hitCount: 97,
+    hitCount: 89,
     missCount: 0,
   ),
   // 100.0%.
@@ -505,12 +505,27 @@
   ),
   // 100.0%.
   "package:front_end/src/fragment/field.dart": (
-    hitCount: 22,
+    hitCount: 300,
+    missCount: 0,
+  ),
+  // 100.0%.
+  "package:front_end/src/fragment/field/body_builder_context.dart": (
+    hitCount: 30,
+    missCount: 0,
+  ),
+  // 100.0%.
+  "package:front_end/src/fragment/field/class_member.dart": (
+    hitCount: 157,
+    missCount: 0,
+  ),
+  // 100.0%.
+  "package:front_end/src/fragment/field/encoding.dart": (
+    hitCount: 995,
     missCount: 0,
   ),
   // 100.0%.
   "package:front_end/src/fragment/getter.dart": (
-    hitCount: 533,
+    hitCount: 541,
     missCount: 0,
   ),
   // 100.0%.
@@ -535,7 +550,7 @@
   ),
   // 100.0%.
   "package:front_end/src/fragment/setter.dart": (
-    hitCount: 553,
+    hitCount: 561,
     missCount: 0,
   ),
   // 100.0%.
@@ -560,12 +575,12 @@
   ),
   // 100.0%.
   "package:front_end/src/kernel/body_builder.dart": (
-    hitCount: 7180,
+    hitCount: 7182,
     missCount: 0,
   ),
   // 100.0%.
   "package:front_end/src/kernel/body_builder_context.dart": (
-    hitCount: 343,
+    hitCount: 324,
     missCount: 0,
   ),
   // 100.0%.
@@ -620,7 +635,7 @@
   ),
   // 100.0%.
   "package:front_end/src/kernel/expression_generator.dart": (
-    hitCount: 2519,
+    hitCount: 2522,
     missCount: 0,
   ),
   // 100.0%.
@@ -640,7 +655,7 @@
   ),
   // 100.0%.
   "package:front_end/src/kernel/hierarchy/class_member.dart": (
-    hitCount: 386,
+    hitCount: 389,
     missCount: 0,
   ),
   // 100.0%.
@@ -680,7 +695,7 @@
   ),
   // 100.0%.
   "package:front_end/src/kernel/implicit_field_type.dart": (
-    hitCount: 93,
+    hitCount: 97,
     missCount: 0,
   ),
   // 100.0%.
@@ -710,7 +725,7 @@
   ),
   // 100.0%.
   "package:front_end/src/kernel/kernel_target.dart": (
-    hitCount: 1078,
+    hitCount: 1076,
     missCount: 0,
   ),
   // 100.0%.
@@ -850,7 +865,7 @@
   ),
   // 100.0%.
   "package:front_end/src/source/diet_listener.dart": (
-    hitCount: 659,
+    hitCount: 660,
     missCount: 0,
   ),
   // 100.0%.
@@ -865,7 +880,7 @@
   ),
   // 100.0%.
   "package:front_end/src/source/offset_map.dart": (
-    hitCount: 151,
+    hitCount: 150,
     missCount: 0,
   ),
   // 100.0%.
@@ -890,7 +905,7 @@
   ),
   // 100.0%.
   "package:front_end/src/source/source_class_builder.dart": (
-    hitCount: 1282,
+    hitCount: 1276,
     missCount: 0,
   ),
   // 100.0%.
@@ -916,7 +931,7 @@
   // 100.0%.
   "package:front_end/src/source/source_extension_type_declaration_builder.dart":
       (
-    hitCount: 508,
+    hitCount: 504,
     missCount: 0,
   ),
   // 100.0%.
@@ -926,7 +941,7 @@
   ),
   // 100.0%.
   "package:front_end/src/source/source_field_builder.dart": (
-    hitCount: 1269,
+    hitCount: 268,
     missCount: 0,
   ),
   // 100.0%.
@@ -936,7 +951,7 @@
   ),
   // 100.0%.
   "package:front_end/src/source/source_library_builder.dart": (
-    hitCount: 1265,
+    hitCount: 1254,
     missCount: 0,
   ),
   // 100.0%.
@@ -956,7 +971,7 @@
   ),
   // 100.0%.
   "package:front_end/src/source/source_property_builder.dart": (
-    hitCount: 540,
+    hitCount: 769,
     missCount: 0,
   ),
   // 100.0%.
@@ -976,7 +991,7 @@
   ),
   // 100.0%.
   "package:front_end/src/source/type_parameter_scope_builder.dart": (
-    hitCount: 1533,
+    hitCount: 1489,
     missCount: 0,
   ),
   // 100.0%.
diff --git a/pkg/front_end/test/macros/application/macro_application_test.dart b/pkg/front_end/test/macros/application/macro_application_test.dart
index 4c297b9..16dd38a 100644
--- a/pkg/front_end/test/macros/application/macro_application_test.dart
+++ b/pkg/front_end/test/macros/application/macro_application_test.dart
@@ -11,6 +11,7 @@
 import 'package:front_end/src/api_prototype/experimental_flags.dart';
 import 'package:front_end/src/builder/field_builder.dart';
 import 'package:front_end/src/builder/member_builder.dart';
+import 'package:front_end/src/builder/property_builder.dart';
 import 'package:front_end/src/kernel/macro/macro.dart';
 import 'package:front_end/src/kernel/macro/offset_checker.dart';
 import 'package:front_end/src/macros/macro_serializer.dart';
@@ -125,6 +126,9 @@
   if (memberBuilder is FieldBuilder) {
     // Only show annotations for the field or getter.
     return memberBuilder.readTarget == member;
+  } else if (memberBuilder is PropertyBuilder && memberBuilder.isField) {
+    // Only show annotations for the field or getter.
+    return memberBuilder.readTarget == member;
   } else if (member is Procedure && member.isSetter) {
     return memberBuilder.writeTarget == member;
   } else if (member is Procedure && member.isGetter) {
diff --git a/pkg/front_end/test/testing/suite.dart b/pkg/front_end/test/testing/suite.dart
index 861e58c..891f3f0 100644
--- a/pkg/front_end/test/testing/suite.dart
+++ b/pkg/front_end/test/testing/suite.dart
@@ -1128,7 +1128,8 @@
           a.libraries[i], b.libraries[i],
           strategy: const Strategy());
       if (!result.isEquivalent) {
-        print(result.toString());
+        print('Original component and new component are not equivalent:\n'
+            '$result');
         return false;
       }
     }