Remove Declaration.prepareTopLevelInference

Change-Id: I3c31cdf200c77749e4465be99d832b65be4a775d
Reviewed-on: https://dart-review.googlesource.com/57508
Reviewed-by: Kevin Millikin <kmillikin@google.com>
Commit-Queue: Peter von der Ahé <ahe@google.com>
diff --git a/pkg/front_end/lib/src/fasta/builder/class_builder.dart b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
index f787b69..1fc5bc5 100644
--- a/pkg/front_end/lib/src/fasta/builder/class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
@@ -226,4 +226,6 @@
   }
 
   int get typeVariablesCount;
+
+  void prepareTopLevelInference() {}
 }
diff --git a/pkg/front_end/lib/src/fasta/builder/declaration.dart b/pkg/front_end/lib/src/fasta/builder/declaration.dart
index f68699e..d340033 100644
--- a/pkg/front_end/lib/src/fasta/builder/declaration.dart
+++ b/pkg/front_end/lib/src/fasta/builder/declaration.dart
@@ -76,7 +76,5 @@
   /// return the number of constructors resolved.
   int resolveConstructors(covariant Declaration parent) => 0;
 
-  void prepareTopLevelInference(covariant library, covariant currentClass) {}
-
   void instrumentTopLevelInference(covariant instrumentation) {}
 }
diff --git a/pkg/front_end/lib/src/fasta/builder/field_builder.dart b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
index 054a552..8e780a5 100644
--- a/pkg/front_end/lib/src/fasta/builder/field_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
@@ -28,4 +28,6 @@
   bool get isField => true;
 
   bool get hasTypeInferredFromInitializer;
+
+  void prepareTopLevelInference() {}
 }
diff --git a/pkg/front_end/lib/src/fasta/builder/library_builder.dart b/pkg/front_end/lib/src/fasta/builder/library_builder.dart
index 8d73995..7e81d10 100644
--- a/pkg/front_end/lib/src/fasta/builder/library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/library_builder.dart
@@ -67,6 +67,8 @@
   @override
   R get target;
 
+  bool get disableTypeInference => true;
+
   Uri get uri;
 
   Declaration addBuilder(String name, Declaration declaration, int charOffset);
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index b5eced7..fad4a2d 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -117,6 +117,7 @@
 abstract class BodyBuilder<Expression, Statement, Arguments>
     extends ScopeListener<JumpTarget>
     implements ExpressionGeneratorHelper<Expression, Statement, Arguments> {
+  // TODO(ahe): Rename [library] to 'part'.
   @override
   final KernelLibraryBuilder library;
 
@@ -148,6 +149,7 @@
   // https://github.com/dart-lang/sdk/issues/28989.
   final bool ignoreMainInGetMainClosure;
 
+  // TODO(ahe): Consider renaming [uri] to 'partUri'.
   @override
   final Uri uri;
 
@@ -210,9 +212,9 @@
   Map<String, int> initializedFields;
 
   BodyBuilder(
-      KernelLibraryBuilder library,
+      this.library,
       this.member,
-      Scope scope,
+      this.enclosingScope,
       this.formalParameterScope,
       this.hierarchy,
       this.coreTypes,
@@ -220,9 +222,7 @@
       this.isInstanceMember,
       this.uri,
       this._typeInferrer)
-      : enclosingScope = scope,
-        library = library,
-        enableNative =
+      : enableNative =
             library.loader.target.backendTarget.enableNative(library.uri),
         stringExpectedAfterNative =
             library.loader.target.backendTarget.nativeExtensionExpectsString,
@@ -231,7 +231,38 @@
         needsImplicitSuperInitializer =
             coreTypes?.objectClass != classBuilder?.cls,
         typePromoter = _typeInferrer?.typePromoter,
-        super(scope);
+        super(enclosingScope);
+
+  BodyBuilder.withParents(
+      KernelFieldBuilder field,
+      KernelLibraryBuilder part,
+      KernelClassBuilder classBuilder,
+      ClassHierarchy hierarchy,
+      CoreTypes coreTypes,
+      TypeInferrer typeInferrer)
+      : this(
+            part,
+            field,
+            classBuilder?.scope ?? field.library.scope,
+            null,
+            hierarchy,
+            coreTypes,
+            classBuilder,
+            field.isInstanceMember,
+            field.fileUri,
+            typeInferrer);
+
+  BodyBuilder.forField(KernelFieldBuilder field, ClassHierarchy hierarchy,
+      CoreTypes coreTypes, TypeInferrer typeInferrer)
+      : this.withParents(
+            field,
+            field.parent is KernelClassBuilder
+                ? field.parent.parent
+                : field.parent,
+            field.parent is KernelClassBuilder ? field.parent : null,
+            hierarchy,
+            coreTypes,
+            typeInferrer);
 
   bool get hasParserError => recoverableErrors.isNotEmpty;
 
@@ -766,6 +797,14 @@
     return toExpression(fakeReturn.expression);
   }
 
+  Expression parseFieldInitializer(Token token) {
+    Parser parser = new Parser(this);
+    token = parser.parseExpression(parser.syntheticPreviousToken(token));
+    Expression expression = popForValue();
+    checkEmpty(token.charOffset);
+    return expression;
+  }
+
   void finishConstructor(
       KernelConstructorBuilder builder, AsyncMarker asyncModifier) {
     /// Quotes below are from [Dart Programming Language Specification, 4th
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_body_builder.dart
index f2ff3b6..9b1651a 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_body_builder.dart
@@ -40,6 +40,10 @@
       : super(library, member, scope, formalParameterScope, hierarchy,
             coreTypes, classBuilder, isInstanceMember, uri, typeInferrer);
 
+  KernelBodyBuilder.forField(ModifierBuilder member, ClassHierarchy hierarchy,
+      CoreTypes coreTypes, TypeInferrer typeInferrer)
+      : super.forField(member, hierarchy, coreTypes, typeInferrer);
+
   @override
   void enterThenForTypePromotion(Expression condition) {
     typePromoter.enterThen(condition);
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_field_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_field_builder.dart
index 27516bf..873d0f0 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_field_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_field_builder.dart
@@ -4,28 +4,27 @@
 
 library fasta.kernel_field_builder;
 
-import 'package:front_end/src/base/instrumentation.dart'
-    show Instrumentation, InstrumentationValueForType;
-
 import 'package:kernel/ast.dart'
     show DartType, Expression, Field, Name, NullLiteral;
 
-import '../../scanner/token.dart' show Token;
+import '../../base/instrumentation.dart'
+    show Instrumentation, InstrumentationValueForType;
 
-import '../builder/class_builder.dart' show ClassBuilder;
+import '../../scanner/token.dart' show Token;
 
 import '../fasta_codes.dart' show messageInternalProblemAlreadyInitialized;
 
-import '../parser/parser.dart' show Parser;
-
 import '../problems.dart' show internalProblem;
 
-import '../source/source_library_builder.dart' show SourceLibraryBuilder;
-
 import 'kernel_body_builder.dart' show KernelBodyBuilder;
 
 import 'kernel_builder.dart'
-    show Declaration, FieldBuilder, KernelTypeBuilder, MetadataBuilder;
+    show
+        Declaration,
+        FieldBuilder,
+        KernelTypeBuilder,
+        LibraryBuilder,
+        MetadataBuilder;
 
 import 'kernel_shadow_ast.dart' show ShadowField;
 
@@ -61,7 +60,7 @@
   bool get isEligibleForInference =>
       type == null && (hasInitializer || isInstanceMember);
 
-  Field build(SourceLibraryBuilder library) {
+  Field build(LibraryBuilder library) {
     field.name ??= new Name(name, library.target);
     if (type != null) {
       field.type = type.build(library);
@@ -86,35 +85,20 @@
   Field get target => field;
 
   @override
-  void prepareTopLevelInference(
-      SourceLibraryBuilder library, ClassBuilder currentClass) {
-    if (isEligibleForInference) {
-      var memberScope =
-          currentClass == null ? library.scope : currentClass.scope;
-      var typeInferenceEngine = library.loader.typeInferenceEngine;
-      var typeInferrer = typeInferenceEngine.createTopLevelTypeInferrer(
-          field.enclosingClass?.thisType, field);
-      if (hasInitializer) {
-        KernelBodyBuilder bodyBuilder = new KernelBodyBuilder(
-            library,
-            this,
-            memberScope,
-            null,
-            typeInferenceEngine.classHierarchy,
-            typeInferenceEngine.coreTypes,
-            currentClass,
-            isInstanceMember,
-            library.fileUri,
-            typeInferrer);
-        Parser parser = new Parser(bodyBuilder);
-        Token token = parser
-            .parseExpression(
-                parser.syntheticPreviousToken(initializerTokenForInference))
-            .next;
-        Expression expression = bodyBuilder.popForValue();
-        bodyBuilder.checkEmpty(token.charOffset);
-        initializer = expression;
-      }
+  void prepareTopLevelInference() {
+    if (!isEligibleForInference) return;
+    var typeInferenceEngine = library.loader.typeInferenceEngine;
+    var typeInferrer = typeInferenceEngine.createTopLevelTypeInferrer(
+        field.enclosingClass?.thisType, field);
+    if (hasInitializer) {
+      initializer = new KernelBodyBuilder.forField(
+              this,
+              // TODO(ahe): Why can't we use the loader's classHierarchy and
+              // coreTypes?
+              typeInferenceEngine.classHierarchy,
+              typeInferenceEngine.coreTypes,
+              typeInferrer)
+          .parseFieldInitializer(initializerTokenForInference);
     }
   }
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
index 2e03b94..5a912e3 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -252,15 +252,9 @@
       loader.resolveConstructors();
       component =
           link(new List<Library>.from(loader.libraries), nameRoot: nameRoot);
-      if (metadataCollector != null) {
-        component.addMetadataRepository(metadataCollector.repository);
-      }
       computeCoreTypes();
       loader.computeHierarchy();
-      if (!loader.target.disableTypeInference) {
-        loader.prepareTopLevelInference(myClasses);
-        loader.performTopLevelInference(myClasses);
-      }
+      loader.performTopLevelInference(myClasses);
       loader.checkOverrides(myClasses);
       loader.checkAbstractMembers(myClasses);
       loader.addNoSuchMethodForwarders(myClasses);
@@ -397,6 +391,10 @@
       }
     }
 
+    if (metadataCollector != null) {
+      component.addMetadataRepository(metadataCollector.repository);
+    }
+
     ticker.logMs("Linked component");
     return component;
   }
diff --git a/pkg/front_end/lib/src/fasta/loader.dart b/pkg/front_end/lib/src/fasta/loader.dart
index f1d940a..d2e21c5 100644
--- a/pkg/front_end/lib/src/fasta/loader.dart
+++ b/pkg/front_end/lib/src/fasta/loader.dart
@@ -32,6 +32,8 @@
 
 import 'ticker.dart' show Ticker;
 
+import 'type_inference/type_inference_engine.dart' show TypeInferenceEngine;
+
 abstract class Loader<L> {
   final Map<Uri, LibraryBuilder> builders = <Uri, LibraryBuilder>{};
 
@@ -73,6 +75,8 @@
 
   Template<SummaryTemplate> get outlineSummaryTemplate;
 
+  TypeInferenceEngine get typeInferenceEngine => null;
+
   /// Look up a library builder by the name [uri], or if such doesn't
   /// exist, create one. The canonical URI of the library is [uri], and its
   /// actual location is [fileUri].
diff --git a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
index 3a6d2f1..ebb30da 100644
--- a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
@@ -23,9 +23,9 @@
 
 import '../kernel/kernel_builder.dart'
     show
-        ClassBuilder,
         ConstructorReferenceBuilder,
         Declaration,
+        FieldBuilder,
         KernelClassBuilder,
         KernelFieldBuilder,
         KernelFunctionBuilder,
@@ -42,8 +42,6 @@
 
 import '../problems.dart' show unexpected, unhandled;
 
-import 'source_library_builder.dart' show SourceLibraryBuilder;
-
 ShadowClass initializeClass(
     ShadowClass cls,
     List<TypeVariableBuilder> typeVariables,
@@ -100,7 +98,11 @@
     ShadowClass.setBuilder(this.cls, this);
   }
 
-  Class get cls => origin.actualCls;
+  @override
+  ShadowClass get cls => origin.actualCls;
+
+  @override
+  KernelLibraryBuilder get library => super.library;
 
   Class build(KernelLibraryBuilder library, LibraryBuilder coreLibrary) {
     void buildBuilders(String name, Declaration declaration) {
@@ -201,11 +203,13 @@
   }
 
   @override
-  void prepareTopLevelInference(
-      SourceLibraryBuilder library, ClassBuilder currentClass) {
-    scope.forEach((name, declaration) {
-      declaration.prepareTopLevelInference(library, this);
+  void prepareTopLevelInference() {
+    scope.forEach((String name, Declaration declaration) {
+      if (declaration is FieldBuilder) {
+        declaration.prepareTopLevelInference();
+      }
     });
+    cls.setupApiMembers(library.loader.interfaceResolver);
   }
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
index 2124101..8e28bcc 100644
--- a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
@@ -89,6 +89,7 @@
 
   /// Indicates whether type inference (and type promotion) should be disabled
   /// for this library.
+  @override
   final bool disableTypeInference;
 
   String documentationComment;
@@ -724,18 +725,6 @@
   }
 
   @override
-  void prepareTopLevelInference(
-      SourceLibraryBuilder library, ClassBuilder currentClass) {
-    forEach((String name, Declaration member) {
-      if (member is ClassBuilder) {
-        // Classes are handled separately, in class hierarchy order.
-        return;
-      }
-      member.prepareTopLevelInference(library, currentClass);
-    });
-  }
-
-  @override
   void instrumentTopLevelInference(Instrumentation instrumentation) {
     forEach((String name, Declaration member) {
       member.instrumentTopLevelInference(instrumentation);
diff --git a/pkg/front_end/lib/src/fasta/source/source_loader.dart b/pkg/front_end/lib/src/fasta/source/source_loader.dart
index 68dffd5..7d6952a 100644
--- a/pkg/front_end/lib/src/fasta/source/source_loader.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart
@@ -37,6 +37,7 @@
         ClassBuilder,
         Declaration,
         EnumBuilder,
+        FieldBuilder,
         LibraryBuilder,
         NamedTypeBuilder,
         TypeBuilder;
@@ -115,6 +116,7 @@
   ClassHierarchy hierarchy;
   CoreTypes coreTypes;
 
+  @override
   TypeInferenceEngine typeInferenceEngine;
 
   InterfaceResolver interfaceResolver;
@@ -722,11 +724,13 @@
         new ShadowTypeInferenceEngine(instrumentation, target.strongMode);
   }
 
-  /// Performs the first phase of top level initializer inference, which
-  /// consists of creating kernel objects for all fields and top level variables
-  /// that might be subject to type inference, and records dependencies between
-  /// them.
-  void prepareTopLevelInference(List<SourceClassBuilder> sourceClasses) {
+  void performTopLevelInference(List<SourceClassBuilder> sourceClasses) {
+    if (target.disableTypeInference) return;
+
+    /// The first phase of top level initializer inference, which consists of
+    /// creating kernel objects for all fields and top level variables that
+    /// might be subject to type inference, and records dependencies between
+    /// them.
     typeInferenceEngine.prepareTopLevel(coreTypes, hierarchy);
     interfaceResolver = new InterfaceResolver(
         typeInferenceEngine,
@@ -735,30 +739,38 @@
         target.strongMode);
     builders.forEach((Uri uri, LibraryBuilder library) {
       if (library.loader == this) {
-        library.prepareTopLevelInference(library, null);
+        library.forEach((String name, Declaration member) {
+          if (member is FieldBuilder) {
+            member.prepareTopLevelInference();
+          }
+        });
       }
     });
-    // Note: we need to create a list before iterating, since calling
-    // builder.prepareTopLevelInference causes further class hierarchy queries
-    // to be made which would otherwise result in a concurrent modification
-    // exception.
-    orderedClasses = hierarchy
-        .getOrderedClasses(sourceClasses.map((builder) => builder.target))
-        .map((class_) => ShadowClass.getClassInferenceInfo(class_).builder)
-        .toList();
-    for (var builder in orderedClasses) {
-      ShadowClass class_ = builder.target;
-      builder.prepareTopLevelInference(builder.library, builder);
-      class_.setupApiMembers(interfaceResolver);
+    {
+      // Note: we need to create a list before iterating, since calling
+      // builder.prepareTopLevelInference causes further class hierarchy
+      // queries to be made which would otherwise result in a concurrent
+      // modification exception.
+      List<Class> classes = new List<Class>(sourceClasses.length);
+      for (int i = 0; i < sourceClasses.length; i++) {
+        classes[i] = sourceClasses[i].target;
+      }
+      List<ClassBuilder> result = new List<ClassBuilder>(sourceClasses.length);
+      int i = 0;
+      for (Class cls in hierarchy.getOrderedClasses(classes)) {
+        result[i++] = ShadowClass.getClassInferenceInfo(cls).builder;
+      }
+      orderedClasses = result;
+    }
+    for (ClassBuilder cls in orderedClasses) {
+      cls.prepareTopLevelInference();
     }
     typeInferenceEngine.isTypeInferencePrepared = true;
     ticker.logMs("Prepared top level inference");
-  }
 
-  /// Performs the second phase of top level initializer inference, which is to
-  /// visit fields and top level variables in topologically-sorted order and
-  /// assign their types.
-  void performTopLevelInference(List<SourceClassBuilder> sourceClasses) {
+    /// The second phase of top level initializer inference, which is to visit
+    /// fields and top level variables in topologically-sorted order and assign
+    /// their types.
     typeInferenceEngine.finishTopLevelFields();
     List<Class> changedClasses = new List<Class>();
     for (var builder in orderedClasses) {