[cfe] Create SourceConstructorBuilder through fragments

Change-Id: I78e40b1c5cd80e9e32a0c96f99ec9c9a172ad8e4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/385580
Reviewed-by: Jens Johansen <jensj@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/front_end/lib/src/fragment/fragment.dart b/pkg/front_end/lib/src/fragment/fragment.dart
index 6239b0e..3eeda4f 100644
--- a/pkg/front_end/lib/src/fragment/fragment.dart
+++ b/pkg/front_end/lib/src/fragment/fragment.dart
@@ -16,6 +16,7 @@
 import '../builder/type_builder.dart';
 import '../source/name_scheme.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';
@@ -586,3 +587,70 @@
   @override
   String toString() => '$runtimeType($name,$fileUri,$charOffset)';
 }
+
+class ConstructorFragment implements Fragment {
+  final String name;
+  final Uri fileUri;
+  final int startCharOffset;
+  final int charOffset;
+  final int charOpenParenOffset;
+  final int charEndOffset;
+  final int modifiers;
+  final List<MetadataBuilder>? metadata;
+  final OmittedTypeBuilder returnType;
+  final List<NominalVariableBuilder>? typeParameters;
+  final List<FormalParameterBuilder>? formals;
+  final Reference? constructorReference;
+  final Reference? tearOffReference;
+  final NameScheme nameScheme;
+  final String? nativeMethodName;
+  final bool forAbstractClassOrMixin;
+  Token? _beginInitializers;
+
+  AbstractSourceConstructorBuilder? _builder;
+
+  ConstructorFragment(
+      {required this.name,
+      required this.fileUri,
+      required this.startCharOffset,
+      required this.charOffset,
+      required this.charOpenParenOffset,
+      required this.charEndOffset,
+      required this.modifiers,
+      required this.metadata,
+      required this.returnType,
+      required this.typeParameters,
+      required this.formals,
+      required this.constructorReference,
+      required this.tearOffReference,
+      required this.nameScheme,
+      required this.nativeMethodName,
+      required this.forAbstractClassOrMixin,
+      required Token? beginInitializers})
+      : _beginInitializers = beginInitializers;
+
+  Token? get beginInitializers {
+    Token? result = _beginInitializers;
+    // Ensure that we don't hold onto the token.
+    _beginInitializers = null;
+    return result;
+  }
+
+  @override
+  AbstractSourceConstructorBuilder get builder {
+    assert(
+        _builder != null, // Coverage-ignore(suite): Not run.
+        "Builder has not been computed for $this.");
+    return _builder!;
+  }
+
+  void set builder(AbstractSourceConstructorBuilder value) {
+    assert(
+        _builder == null, // Coverage-ignore(suite): Not run.
+        "Builder has already been computed for $this.");
+    _builder = value;
+  }
+
+  @override
+  String toString() => '$runtimeType($name,$fileUri,$charOffset)';
+}
diff --git a/pkg/front_end/lib/src/kernel/constructor_tearoff_lowering.dart b/pkg/front_end/lib/src/kernel/constructor_tearoff_lowering.dart
index 3a45c11..4e48cf9 100644
--- a/pkg/front_end/lib/src/kernel/constructor_tearoff_lowering.dart
+++ b/pkg/front_end/lib/src/kernel/constructor_tearoff_lowering.dart
@@ -30,8 +30,7 @@
       (forceCreateLowering ||
           compilationUnit.loader.target.backendTarget
               .isConstructorTearOffLoweringEnabled)) {
-    return _createTearOffProcedure(
-        compilationUnit, tearOffName, fileUri, fileOffset, reference);
+    return _createTearOffProcedure(tearOffName, fileUri, fileOffset, reference);
   }
   return null;
 }
@@ -50,8 +49,7 @@
   if (forceCreateLowering ||
       compilationUnit
           .loader.target.backendTarget.isFactoryTearOffLoweringEnabled) {
-    return _createTearOffProcedure(
-        compilationUnit, tearOffName, fileUri, fileOffset, reference);
+    return _createTearOffProcedure(tearOffName, fileUri, fileOffset, reference);
   }
   return null;
 }
@@ -68,8 +66,7 @@
     Reference? reference) {
   MemberName tearOffName = new MemberName(
       libraryBuilder.libraryName, typedefTearOffName(typedefName, name));
-  return _createTearOffProcedure(
-      libraryBuilder, tearOffName, fileUri, fileOffset, reference);
+  return _createTearOffProcedure(tearOffName, fileUri, fileOffset, reference);
 }
 
 /// Creates the parameters and body for [tearOff] based on
@@ -276,7 +273,7 @@
 
 /// Creates the synthesized [Procedure] node for a tear off lowering by the
 /// given [name].
-Procedure _createTearOffProcedure(SourceLibraryBuilder libraryBuilder,
+Procedure _createTearOffProcedure(
     MemberName tearOffName, Uri fileUri, int fileOffset, Reference? reference) {
   Procedure tearOff = new Procedure(
       dummyName, ProcedureKind.Method, new FunctionNode(null),
diff --git a/pkg/front_end/lib/src/source/offset_map.dart b/pkg/front_end/lib/src/source/offset_map.dart
index 6c06b5e..e565841 100644
--- a/pkg/front_end/lib/src/source/offset_map.dart
+++ b/pkg/front_end/lib/src/source/offset_map.dart
@@ -26,6 +26,7 @@
   final Map<int, DeclarationFragment> _declarationFragments = {};
   final Map<int, FieldFragment> _fields = {};
   final Map<int, SourceFunctionBuilder> _constructors = {};
+  final Map<int, ConstructorFragment> _constructorFragments = {};
   final Map<int, MethodFragment> _procedures = {};
   final Map<int, LibraryPart> _parts = {};
   final Map<int, Import> _imports = {};
@@ -102,12 +103,12 @@
   }
 
   void registerPrimaryConstructor(
-      Token beginToken, SourceFunctionBuilder builder) {
-    _constructors[beginToken.charOffset] = builder;
+      Token beginToken, ConstructorFragment builder) {
+    _constructorFragments[beginToken.charOffset] = builder;
   }
 
   SourceFunctionBuilder lookupPrimaryConstructor(Token beginToken) {
-    return _checkBuilder(_constructors[beginToken.charOffset],
+    return _checkBuilder(_constructorFragments[beginToken.charOffset]?.builder,
         '<primary-constructor>', beginToken.charOffset);
   }
 
@@ -116,8 +117,16 @@
     _constructors[identifier.nameOffset] = builder;
   }
 
+  void registerConstructorFragment(
+      Identifier identifier, ConstructorFragment fragment) {
+    _constructorFragments[identifier.nameOffset] = fragment;
+  }
+
   SourceFunctionBuilder lookupConstructor(Identifier identifier) {
-    return _checkBuilder(_constructors[identifier.nameOffset], identifier.name,
+    return _checkBuilder(
+        _constructors[identifier.nameOffset] ??
+            _constructorFragments[identifier.nameOffset]?.builder,
+        identifier.name,
         identifier.nameOffset);
   }
 
diff --git a/pkg/front_end/lib/src/source/source_builder_factory.dart b/pkg/front_end/lib/src/source/source_builder_factory.dart
index c491aa8..38e1760 100644
--- a/pkg/front_end/lib/src/source/source_builder_factory.dart
+++ b/pkg/front_end/lib/src/source/source_builder_factory.dart
@@ -57,7 +57,6 @@
 import 'name_scheme.dart';
 import 'offset_map.dart';
 import 'source_class_builder.dart' show SourceClassBuilder;
-import 'source_constructor_builder.dart';
 import 'source_enum_builder.dart';
 import 'source_factory_builder.dart';
 import 'source_function_builder.dart';
@@ -126,6 +125,8 @@
 
   final List<MethodFragment> _nativeMethodFragments = [];
 
+  final List<ConstructorFragment> _nativeConstructorFragments = [];
+
   final LibraryName libraryName;
 
   final LookupScope _compilationUnitScope;
@@ -1693,7 +1694,7 @@
       String? nativeMethodName,
       {Token? beginInitializers,
       required bool forAbstractClassOrMixin}) {
-    SourceFunctionBuilder builder = _addConstructor(
+    ConstructorFragment fragment = _addConstructor(
         metadata,
         modifiers,
         constructorName,
@@ -1705,8 +1706,9 @@
         charEndOffset,
         nativeMethodName,
         beginInitializers: beginInitializers,
-        forAbstractClassOrMixin: forAbstractClassOrMixin);
-    offsetMap.registerConstructor(identifier, builder);
+        forAbstractClassOrMixin: forAbstractClassOrMixin,
+        isConst: modifiers & constMask != 0);
+    offsetMap.registerConstructorFragment(identifier, fragment);
   }
 
   @override
@@ -1726,7 +1728,7 @@
     List<NominalVariableBuilder>? typeVariables =
         nominalVariableCopy?.newVariableBuilders;
 
-    SourceFunctionBuilder builder = _addConstructor(
+    ConstructorFragment builder = _addConstructor(
         null,
         isConst ? constMask : 0,
         constructorName,
@@ -1741,6 +1743,7 @@
         charOffset,
         /* nativeMethodName = */
         null,
+        isConst: isConst,
         forAbstractClassOrMixin: false);
     offsetMap.registerPrimaryConstructor(beginToken, builder);
   }
@@ -1768,7 +1771,7 @@
         false));
   }
 
-  SourceFunctionBuilder _addConstructor(
+  ConstructorFragment _addConstructor(
       List<MetadataBuilder>? metadata,
       int modifiers,
       String constructorName,
@@ -1780,6 +1783,7 @@
       int charEndOffset,
       String? nativeMethodName,
       {Token? beginInitializers,
+      required bool isConst,
       required bool forAbstractClassOrMixin}) {
     ContainerType containerType = _declarationFragments.current.containerType;
     ContainerName? containerName = _declarationFragments.current.containerName;
@@ -1804,71 +1808,47 @@
           .getConstructorMemberName(constructorName, isTearOff: true)
           .name);
     }
-    AbstractSourceConstructorBuilder constructorBuilder;
 
-    if (_declarationFragments.current.kind ==
-        DeclarationFragmentKind.extensionTypeDeclaration) {
-      constructorBuilder = new SourceExtensionTypeConstructorBuilder(
-          metadata,
-          modifiers & ~abstractMask,
-          addInferableType(),
-          constructorName,
-          typeVariables,
-          formals,
-          _parent,
-          _compilationUnit.fileUri,
-          startCharOffset,
-          charOffset,
-          charOpenParenOffset,
-          charEndOffset,
-          constructorReference,
-          tearOffReference,
-          nameScheme,
-          nativeMethodName: nativeMethodName,
-          forAbstractClassOrEnumOrMixin: forAbstractClassOrMixin);
-    } else {
-      constructorBuilder = new DeclaredSourceConstructorBuilder(
-          metadata,
-          modifiers & ~abstractMask,
-          addInferableType(),
-          constructorName,
-          typeVariables,
-          formals,
-          _parent,
-          _compilationUnit.fileUri,
-          startCharOffset,
-          charOffset,
-          charOpenParenOffset,
-          charEndOffset,
-          constructorReference,
-          tearOffReference,
-          nameScheme,
-          nativeMethodName: nativeMethodName,
-          forAbstractClassOrEnumOrMixin: forAbstractClassOrMixin);
-    }
+    ConstructorFragment fragment = new ConstructorFragment(
+        name: constructorName,
+        fileUri: _compilationUnit.fileUri,
+        startCharOffset: startCharOffset,
+        charOffset: charOffset,
+        charOpenParenOffset: charOpenParenOffset,
+        charEndOffset: charEndOffset,
+        modifiers: modifiers & ~abstractMask,
+        metadata: metadata,
+        returnType: addInferableType(),
+        typeParameters: typeVariables,
+        formals: formals,
+        constructorReference: constructorReference,
+        tearOffReference: tearOffReference,
+        nameScheme: nameScheme,
+        nativeMethodName: nativeMethodName,
+        forAbstractClassOrMixin: forAbstractClassOrMixin,
+        beginInitializers: isConst || libraryFeatures.superParameters.isEnabled
+
+            // const constructors will have their initializers compiled and
+            // written into the outline. In case of super-parameters language
+            // feature, the super initializers are required to infer the types
+            // of super parameters.
+            // TODO(johnniwinther): Avoid using a dummy token to ensure building
+            // of constant constructors in the outline phase.
+            ? (beginInitializers ?? new Token.eof(-1))
+            : null);
+
     _nominalParameterNameSpaces.pop().addTypeVariables(
         _problemReporting, typeVariables,
-        ownerName: constructorBuilder.name, allowNameConflict: true);
+        ownerName: constructorName, allowNameConflict: true);
     // TODO(johnniwinther): There is no way to pass the tear off reference here.
-    _addBuilder(constructorName, constructorBuilder, charOffset,
-        getterReference: constructorReference);
+    _addFragment(fragment, getterReference: constructorReference);
     if (nativeMethodName != null) {
-      _addNativeMethod(constructorBuilder);
+      _addNativeConstructorFragment(fragment);
     }
-    if (constructorBuilder.isConst) {
+    if (isConst) {
       _declarationFragments.current.declaresConstConstructor = true;
     }
-    if (constructorBuilder.isConst ||
-        libraryFeatures.superParameters.isEnabled) {
-      // const constructors will have their initializers compiled and written
-      // into the outline. In case of super-parameters language feature, the
-      // super initializers are required to infer the types of super parameters.
-      constructorBuilder.beginInitializers =
-          // TODO(johnniwinther): Avoid using a dummy token to ensure building
-          // of constant constructors in the outline phase.
-          beginInitializers ?? new Token.eof(-1);
-    }
-    return constructorBuilder;
+    return fragment;
   }
 
   @override
@@ -2129,6 +2109,10 @@
     _nativeMethodFragments.add(fragment);
   }
 
+  void _addNativeConstructorFragment(ConstructorFragment fragment) {
+    _nativeConstructorFragments.add(fragment);
+  }
+
   void _addNativeMethod(SourceFunctionBuilder method) {
     _nativeMethods.add(method);
   }
@@ -2749,6 +2733,9 @@
     for (MethodFragment fragment in _nativeMethodFragments) {
       fragment.builder.becomeNative(loader);
     }
+    for (ConstructorFragment fragment in _nativeConstructorFragments) {
+      fragment.builder.becomeNative(loader);
+    }
     return _nativeMethods.length;
   }
 
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 a1d980c..a46b88c 100644
--- a/pkg/front_end/lib/src/source/source_constructor_builder.dart
+++ b/pkg/front_end/lib/src/source/source_constructor_builder.dart
@@ -79,6 +79,12 @@
     extends SourceFunctionBuilderImpl
     implements SourceConstructorBuilder, Inferable, ConstructorDeclaration {
   @override
+  final SourceLibraryBuilder libraryBuilder;
+
+  @override
+  final DeclarationBuilder declarationBuilder;
+
+  @override
   final OmittedTypeBuilder returnType;
 
   final int charOpenParenOffset;
@@ -94,13 +100,15 @@
       String name,
       List<NominalVariableBuilder>? typeVariables,
       List<FormalParameterBuilder>? formals,
-      SourceLibraryBuilder compilationUnit,
+      this.libraryBuilder,
+      this.declarationBuilder,
       Uri fileUri,
       int charOffset,
       this.charOpenParenOffset,
-      String? nativeMethodName)
+      String? nativeMethodName,
+      this.beginInitializers)
       : super(metadata, modifiers, name, typeVariables, formals,
-            compilationUnit, fileUri, charOffset, nativeMethodName) {
+            declarationBuilder, fileUri, charOffset, nativeMethodName) {
     if (formals != null) {
       for (FormalParameterBuilder formal in formals) {
         if (formal.isInitializingFormal || formal.isSuperInitializingFormal) {
@@ -111,9 +119,6 @@
   }
 
   @override
-  DeclarationBuilder get declarationBuilder => super.declarationBuilder!;
-
-  @override
   bool get isConstructor => true;
 
   @override
@@ -405,7 +410,8 @@
       String name,
       List<NominalVariableBuilder>? typeVariables,
       this.formals,
-      SourceLibraryBuilder compilationUnit,
+      SourceLibraryBuilder libraryBuilder,
+      DeclarationBuilder declarationBuilder,
       Uri fileUri,
       int startCharOffset,
       int charOffset,
@@ -416,6 +422,7 @@
       NameScheme nameScheme,
       {String? nativeMethodName,
       required bool forAbstractClassOrEnumOrMixin,
+      required Token? beginInitializers,
       bool isSynthetic = false})
       : _hasSuperInitializingFormals =
             formals?.any((formal) => formal.isSuperInitializingFormal) ?? false,
@@ -427,11 +434,13 @@
             name,
             typeVariables,
             formals,
-            compilationUnit,
+            libraryBuilder,
+            declarationBuilder,
             fileUri,
             charOffset,
             charOpenParenOffset,
-            nativeMethodName) {
+            nativeMethodName,
+            beginInitializers) {
     _constructor = new Constructor(new FunctionNode(null),
         name: dummyName,
         fileUri: fileUri,
@@ -445,8 +454,8 @@
         .attachMember(_constructor);
     _constructorTearOff = createConstructorTearOffProcedure(
         nameScheme.getConstructorMemberName(name, isTearOff: true),
-        compilationUnit,
-        compilationUnit.fileUri,
+        libraryBuilder,
+        fileUri,
         charOffset,
         tearOffReference,
         forAbstractClassOrEnumOrMixin: forAbstractClassOrEnumOrMixin);
@@ -1149,7 +1158,8 @@
       String name,
       List<NominalVariableBuilder>? typeVariables,
       List<FormalParameterBuilder>? formals,
-      SourceLibraryBuilder compilationUnit,
+      SourceLibraryBuilder libraryBuilder,
+      SourceExtensionTypeDeclarationBuilder declarationBuilder,
       Uri fileUri,
       int startCharOffset,
       int charOffset,
@@ -1159,7 +1169,8 @@
       Reference? tearOffReference,
       NameScheme nameScheme,
       {String? nativeMethodName,
-      required bool forAbstractClassOrEnumOrMixin})
+      required bool forAbstractClassOrEnumOrMixin,
+      required Token? beginInitializers})
       : _memberName = nameScheme.getDeclaredName(name),
         super(
             metadata,
@@ -1168,14 +1179,16 @@
             name,
             typeVariables,
             formals,
-            compilationUnit,
+            libraryBuilder,
+            declarationBuilder,
             fileUri,
             charOffset,
             charOpenParenOffset,
-            nativeMethodName) {
+            nativeMethodName,
+            beginInitializers) {
     _constructor = new Procedure(
         dummyName, ProcedureKind.Method, new FunctionNode(null),
-        fileUri: compilationUnit.fileUri, reference: constructorReference)
+        fileUri: fileUri, reference: constructorReference)
       ..fileOffset = charOffset
       ..fileEndOffset = charEndOffset;
     nameScheme
@@ -1183,8 +1196,8 @@
         .attachMember(_constructor);
     _constructorTearOff = createConstructorTearOffProcedure(
         nameScheme.getConstructorMemberName(name, isTearOff: true),
-        compilationUnit,
-        compilationUnit.fileUri,
+        libraryBuilder,
+        fileUri,
         charOffset,
         tearOffReference,
         forAbstractClassOrEnumOrMixin: forAbstractClassOrEnumOrMixin,
diff --git a/pkg/front_end/lib/src/source/source_enum_builder.dart b/pkg/front_end/lib/src/source/source_enum_builder.dart
index 2429e3b..1345804 100644
--- a/pkg/front_end/lib/src/source/source_enum_builder.dart
+++ b/pkg/front_end/lib/src/source/source_enum_builder.dart
@@ -369,6 +369,7 @@
               /* typeParameters = */ null,
               /* formals = */ [],
               libraryBuilder,
+              this,
               fileUri,
               charOffset,
               charOffset,
@@ -382,12 +383,11 @@
                   containerType: ContainerType.Class,
                   libraryName: libraryName),
               forAbstractClassOrEnumOrMixin: true,
-              isSynthetic: true);
-      // Trick the constructor to be built during the outline phase.
-      // TODO(johnniwinther): Avoid relying on [beginInitializers] to ensure
-      // building constructors creation during the outline phase.
-      synthesizedDefaultConstructorBuilder!.beginInitializers =
-          new Token.eof(-1);
+              isSynthetic: true,
+              // Trick the constructor to be built during the outline phase.
+              // TODO(johnniwinther): Avoid relying on [beginInitializers] to
+              // ensure building constructors creation during the outline phase.
+              beginInitializers: new Token.eof(-1));
       synthesizedDefaultConstructorBuilder!
           .registerInitializedField(valuesBuilder);
       nameSpace.addConstructor("", synthesizedDefaultConstructorBuilder!);
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 6b5cd46..23e0200 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
@@ -19,6 +19,7 @@
 import 'name_scheme.dart';
 import 'source_builder_factory.dart';
 import 'source_class_builder.dart';
+import 'source_constructor_builder.dart';
 import 'source_enum_builder.dart';
 import 'source_extension_builder.dart';
 import 'source_extension_type_declaration_builder.dart';
@@ -408,6 +409,54 @@
         fragment.builder = procedureBuilder;
         builders.add(new _AddBuilder(fragment.name, procedureBuilder,
             fragment.fileUri, fragment.charOffset));
+      case ConstructorFragment():
+        AbstractSourceConstructorBuilder constructorBuilder;
+        if (declarationBuilder is SourceExtensionTypeDeclarationBuilder) {
+          constructorBuilder = new SourceExtensionTypeConstructorBuilder(
+              fragment.metadata,
+              fragment.modifiers,
+              fragment.returnType,
+              fragment.name,
+              fragment.typeParameters,
+              fragment.formals,
+              enclosingLibraryBuilder,
+              declarationBuilder,
+              fragment.fileUri,
+              fragment.startCharOffset,
+              fragment.charOffset,
+              fragment.charOpenParenOffset,
+              fragment.charEndOffset,
+              fragment.constructorReference,
+              fragment.tearOffReference,
+              fragment.nameScheme,
+              nativeMethodName: fragment.nativeMethodName,
+              forAbstractClassOrEnumOrMixin: fragment.forAbstractClassOrMixin,
+              beginInitializers: fragment.beginInitializers);
+        } else {
+          constructorBuilder = new DeclaredSourceConstructorBuilder(
+              fragment.metadata,
+              fragment.modifiers,
+              fragment.returnType,
+              fragment.name,
+              fragment.typeParameters,
+              fragment.formals,
+              enclosingLibraryBuilder,
+              declarationBuilder!,
+              fragment.fileUri,
+              fragment.startCharOffset,
+              fragment.charOffset,
+              fragment.charOpenParenOffset,
+              fragment.charEndOffset,
+              fragment.constructorReference,
+              fragment.tearOffReference,
+              fragment.nameScheme,
+              nativeMethodName: fragment.nativeMethodName,
+              forAbstractClassOrEnumOrMixin: fragment.forAbstractClassOrMixin,
+              beginInitializers: fragment.beginInitializers);
+        }
+        fragment.builder = constructorBuilder;
+        builders.add(new _AddBuilder(fragment.name, constructorBuilder,
+            fragment.fileUri, fragment.charOffset));
     }
   }
 }