Remove ElementCreatorMixin from JsKernelToElementMap

Change-Id: I2ff9014305177a1f0060626062fadf8276b74979
Reviewed-on: https://dart-review.googlesource.com/74400
Reviewed-by: Stephen Adams <sra@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/compiler/lib/src/ir/element_map.dart b/pkg/compiler/lib/src/ir/element_map.dart
index 16de410..250c391 100644
--- a/pkg/compiler/lib/src/ir/element_map.dart
+++ b/pkg/compiler/lib/src/ir/element_map.dart
@@ -53,6 +53,10 @@
   /// Returns the [CallStructure] corresponding to the [arguments].
   CallStructure getCallStructure(ir.Arguments arguments);
 
+  /// Returns the [TypeVariableEntity] corresponding to the type parameter
+  /// [node].
+  TypeVariableEntity getTypeVariable(ir.TypeParameter node);
+
   CommonElements get commonElements;
   DiagnosticReporter get reporter;
   InterfaceType getThisType(IndexedClass cls);
diff --git a/pkg/compiler/lib/src/ir/visitors.dart b/pkg/compiler/lib/src/ir/visitors.dart
index 5c0ab85..3e97494 100644
--- a/pkg/compiler/lib/src/ir/visitors.dart
+++ b/pkg/compiler/lib/src/ir/visitors.dart
@@ -507,3 +507,116 @@
     }
   }
 }
+
+/// Visitor that converts kernel dart types into [DartType].
+class DartTypeConverter extends ir.DartTypeVisitor<DartType> {
+  final IrToElementMap elementMap;
+  final Map<ir.TypeParameter, DartType> currentFunctionTypeParameters =
+      <ir.TypeParameter, DartType>{};
+  bool topLevel = true;
+
+  DartTypeConverter(this.elementMap);
+
+  DartType convert(ir.DartType type) {
+    topLevel = true;
+    return type.accept(this);
+  }
+
+  /// Visit a inner type.
+  DartType visitType(ir.DartType type) {
+    topLevel = false;
+    return type.accept(this);
+  }
+
+  InterfaceType visitSupertype(ir.Supertype node) {
+    ClassEntity cls = elementMap.getClass(node.classNode);
+    return new InterfaceType(cls, visitTypes(node.typeArguments));
+  }
+
+  List<DartType> visitTypes(List<ir.DartType> types) {
+    topLevel = false;
+    return new List.generate(
+        types.length, (int index) => types[index].accept(this));
+  }
+
+  @override
+  DartType visitTypeParameterType(ir.TypeParameterType node) {
+    DartType typeParameter = currentFunctionTypeParameters[node.parameter];
+    if (typeParameter != null) {
+      return typeParameter;
+    }
+    if (node.parameter.parent is ir.Typedef) {
+      // Typedefs are only used in type literals so we never need their type
+      // variables.
+      return const DynamicType();
+    }
+    return new TypeVariableType(elementMap.getTypeVariable(node.parameter));
+  }
+
+  @override
+  DartType visitFunctionType(ir.FunctionType node) {
+    int index = 0;
+    List<FunctionTypeVariable> typeVariables;
+    for (ir.TypeParameter typeParameter in node.typeParameters) {
+      FunctionTypeVariable typeVariable = new FunctionTypeVariable(index);
+      currentFunctionTypeParameters[typeParameter] = typeVariable;
+      typeVariables ??= <FunctionTypeVariable>[];
+      typeVariables.add(typeVariable);
+      index++;
+    }
+    if (typeVariables != null) {
+      for (int index = 0; index < typeVariables.length; index++) {
+        typeVariables[index].bound =
+            node.typeParameters[index].bound.accept(this);
+      }
+    }
+
+    FunctionType type = new FunctionType(
+        visitType(node.returnType),
+        visitTypes(node.positionalParameters
+            .take(node.requiredParameterCount)
+            .toList()),
+        visitTypes(node.positionalParameters
+            .skip(node.requiredParameterCount)
+            .toList()),
+        node.namedParameters.map((n) => n.name).toList(),
+        node.namedParameters.map((n) => visitType(n.type)).toList(),
+        typeVariables ?? const <FunctionTypeVariable>[]);
+    for (ir.TypeParameter typeParameter in node.typeParameters) {
+      currentFunctionTypeParameters.remove(typeParameter);
+    }
+    return type;
+  }
+
+  @override
+  DartType visitInterfaceType(ir.InterfaceType node) {
+    ClassEntity cls = elementMap.getClass(node.classNode);
+    if (cls.name == 'FutureOr' &&
+        cls.library == elementMap.commonElements.asyncLibrary) {
+      return new FutureOrType(visitTypes(node.typeArguments).single);
+    }
+    return new InterfaceType(cls, visitTypes(node.typeArguments));
+  }
+
+  @override
+  DartType visitVoidType(ir.VoidType node) {
+    return const VoidType();
+  }
+
+  @override
+  DartType visitDynamicType(ir.DynamicType node) {
+    return const DynamicType();
+  }
+
+  @override
+  DartType visitInvalidType(ir.InvalidType node) {
+    // Root uses such a `o is Unresolved` and `o as Unresolved` must be special
+    // cased in the builder, nested invalid types are treated as `dynamic`.
+    return const DynamicType();
+  }
+
+  @override
+  DartType visitBottomType(ir.BottomType node) {
+    return elementMap.commonElements.nullType;
+  }
+}
diff --git a/pkg/compiler/lib/src/js_model/element_map_impl.dart b/pkg/compiler/lib/src/js_model/element_map_impl.dart
index 0cafcf5..ccce835 100644
--- a/pkg/compiler/lib/src/js_model/element_map_impl.dart
+++ b/pkg/compiler/lib/src/js_model/element_map_impl.dart
@@ -46,20 +46,28 @@
 }
 
 class JsKernelToElementMap extends KernelToElementMapBase
-    with
-        JsElementCreatorMixin,
-        // TODO(johnniwinther): Avoid mixing in [ElementCreatorMixin]. The
-        // codegen world should be a strict subset of the resolution world and
-        // creating elements for IR nodes should therefore not be needed.
-        // Currently some are created purely for testing (like
-        // `element == commonElements.foo`, where 'foo' might not be live).
-        // Others are created because we do a
-        // `elementEnvironment.forEachLibraryMember(...)` call on each emitted
-        // library.
-        ElementCreatorMixin
-    implements
-        KernelToWorldBuilder,
-        JsToElementMap {
+    with JsElementCreatorMixin
+    implements KernelToWorldBuilder, JsToElementMap {
+  Map<ir.Library, IndexedLibrary> libraryMap = <ir.Library, IndexedLibrary>{};
+  Map<ir.Class, IndexedClass> classMap = <ir.Class, IndexedClass>{};
+  Map<ir.Typedef, IndexedTypedef> typedefMap = <ir.Typedef, IndexedTypedef>{};
+
+  /// Map from [ir.TypeParameter] nodes to the corresponding
+  /// [TypeVariableEntity].
+  ///
+  /// Normally the type variables are [IndexedTypeVariable]s, but for type
+  /// parameters on local function (in the frontend) these are _not_ since
+  /// their type declaration is neither a class nor a member. In the backend,
+  /// these type parameters belong to the call-method and are therefore indexed.
+  Map<ir.TypeParameter, TypeVariableEntity> typeVariableMap =
+      <ir.TypeParameter, TypeVariableEntity>{};
+  Map<ir.Member, IndexedConstructor> constructorMap =
+      <ir.Member, IndexedConstructor>{};
+  Map<ir.Procedure, IndexedFunction> methodMap =
+      <ir.Procedure, IndexedFunction>{};
+  Map<ir.Field, IndexedField> fieldMap = <ir.Field, IndexedField>{};
+  Map<ir.TreeNode, Local> localFunctionMap = <ir.TreeNode, Local>{};
+
   /// Map from members to the call methods created for their nested closures.
   Map<MemberEntity, List<FunctionEntity>> _nestedClosureMap =
       <MemberEntity, List<FunctionEntity>>{};
@@ -166,11 +174,13 @@
       }
       IndexedTypeVariable newTypeVariable = createTypeVariable(
           newTypeDeclaration, oldTypeVariable.name, oldTypeVariable.index);
-      typeVariables.register<IndexedTypeVariable, TypeVariableData>(
-          newTypeVariable, oldTypeVariableData.copy());
+      typeVariableMap[oldTypeVariableData.node] =
+          typeVariables.register<IndexedTypeVariable, TypeVariableData>(
+              newTypeVariable, oldTypeVariableData.copy());
       assert(newTypeVariable.typeVariableIndex ==
           oldTypeVariable.typeVariableIndex);
     }
+    //typeVariableMap.keys.forEach((n) => print(n.parent));
     // TODO(johnniwinther): We should close the environment in the beginning of
     // this constructor but currently we need the [MemberEntity] to query if the
     // member is live, thus potentially creating the [MemberEntity] in the
@@ -179,11 +189,6 @@
   }
 
   @override
-  Entity getClosure(ir.FunctionDeclaration node) {
-    throw new UnsupportedError('JsKernelToElementMap.getClosure');
-  }
-
-  @override
   void forEachNestedClosure(
       MemberEntity member, void f(FunctionEntity closure)) {
     assert(checkFamily(member));
@@ -239,8 +244,6 @@
     return cls;
   }
 
-  // TODO(johnniwinther): Reinsert these when [ElementCreatorMixin] is no longer
-  // mixed in.
   @override
   FieldEntity getFieldInternal(ir.Field node) {
     FieldEntity field = fieldMap[node];
@@ -263,6 +266,40 @@
   }
 
   @override
+  TypeVariableEntity getTypeVariableInternal(ir.TypeParameter node) {
+    TypeVariableEntity typeVariable = typeVariableMap[node];
+    if (typeVariable == null) {
+      if (node.parent is ir.FunctionNode) {
+        ir.FunctionNode func = node.parent;
+        int index = func.typeParameters.indexOf(node);
+        if (func.parent is ir.Constructor) {
+          ir.Constructor constructor = func.parent;
+          ir.Class cls = constructor.enclosingClass;
+          typeVariableMap[node] =
+              typeVariable = getTypeVariableInternal(cls.typeParameters[index]);
+        } else if (func.parent is ir.Procedure) {
+          ir.Procedure procedure = func.parent;
+          if (procedure.kind == ir.ProcedureKind.Factory) {
+            ir.Class cls = procedure.enclosingClass;
+            typeVariableMap[node] = typeVariable =
+                getTypeVariableInternal(cls.typeParameters[index]);
+          }
+        }
+      }
+    }
+    assert(typeVariable != null,
+        "No type variable entity for $node on ${node.parent is ir.FunctionNode ? node.parent.parent : node.parent}");
+    return typeVariable;
+  }
+
+  @override
+  TypedefEntity getTypedefInternal(ir.Typedef node) {
+    TypedefEntity typedef = typedefMap[node];
+    assert(typedef != null, "No typedef entity for $node");
+    return typedef;
+  }
+
+  @override
   FunctionEntity getConstructorBody(ir.Constructor node) {
     ConstructorEntity constructor = getConstructor(node);
     return _getConstructorBody(node, constructor);
diff --git a/pkg/compiler/lib/src/kernel/element_map_impl.dart b/pkg/compiler/lib/src/kernel/element_map_impl.dart
index 72d76ae..4e66347 100644
--- a/pkg/compiler/lib/src/kernel/element_map_impl.dart
+++ b/pkg/compiler/lib/src/kernel/element_map_impl.dart
@@ -751,6 +751,20 @@
         argumentCount, namedArguments, arguments.types.length);
   }
 
+  ParameterStructure getParameterStructure(ir.FunctionNode node,
+      // TODO(johnniwinther): Remove this when type arguments are passed to
+      // constructors like calling a generic method.
+      {bool includeTypeParameters: true}) {
+    // TODO(johnniwinther): Cache the computed function type.
+    int requiredParameters = node.requiredParameterCount;
+    int positionalParameters = node.positionalParameters.length;
+    int typeParameters = node.typeParameters.length;
+    List<String> namedParameters =
+        node.namedParameters.map((p) => p.name).toList()..sort();
+    return new ParameterStructure(requiredParameters, positionalParameters,
+        namedParameters, includeTypeParameters ? typeParameters : 0);
+  }
+
   Selector getSelector(ir.Expression node) {
     // TODO(efortuna): This is screaming for a common interface between
     // PropertyGet and SuperPropertyGet (and same for *Get). Talk to kernel
@@ -1257,52 +1271,61 @@
   }
 
   FunctionEntity getMethodInternal(ir.Procedure node) {
-    return methodMap[node] ??= _getMethodCreate(node);
-  }
-
-  FunctionEntity _getMethodCreate(ir.Procedure node) {
-    assert(
-        !envIsClosed,
-        "Environment of $this is closed. Trying to create "
-        "function for $node.");
-    LibraryEntity library;
-    ClassEntity enclosingClass;
-    if (node.enclosingClass != null) {
-      enclosingClass = getClassInternal(node.enclosingClass);
-      library = enclosingClass.library;
-    } else {
-      library = getLibraryInternal(node.enclosingLibrary);
+    IndexedFunction function = methodMap[node];
+    if (function == null) {
+      assert(
+          !envIsClosed,
+          "Environment of $this is closed. Trying to create "
+          "function for $node.");
+      LibraryEntity library;
+      ClassEntity enclosingClass;
+      if (node.enclosingClass != null) {
+        enclosingClass = getClassInternal(node.enclosingClass);
+        library = enclosingClass.library;
+      } else {
+        library = getLibraryInternal(node.enclosingLibrary);
+      }
+      Name name = getName(node.name);
+      bool isStatic = node.isStatic;
+      bool isExternal = node.isExternal;
+      // TODO(johnniwinther): Remove `&& !node.isExternal` when #31233 is fixed.
+      bool isAbstract = node.isAbstract && !node.isExternal;
+      AsyncMarker asyncMarker = getAsyncMarker(node.function);
+      switch (node.kind) {
+        case ir.ProcedureKind.Factory:
+          throw new UnsupportedError("Cannot create method from factory.");
+        case ir.ProcedureKind.Getter:
+          function = createGetter(library, enclosingClass, name, asyncMarker,
+              isStatic: isStatic,
+              isExternal: isExternal,
+              isAbstract: isAbstract);
+          break;
+        case ir.ProcedureKind.Method:
+        case ir.ProcedureKind.Operator:
+          function = createMethod(library, enclosingClass, name,
+              getParameterStructure(node.function), asyncMarker,
+              isStatic: isStatic,
+              isExternal: isExternal,
+              isAbstract: isAbstract);
+          break;
+        case ir.ProcedureKind.Setter:
+          assert(asyncMarker == AsyncMarker.SYNC);
+          function = createSetter(library, enclosingClass, name.setter,
+              isStatic: isStatic,
+              isExternal: isExternal,
+              isAbstract: isAbstract);
+          break;
+      }
+      members.register<IndexedFunction, FunctionData>(
+          function,
+          new FunctionDataImpl(node, node.function,
+              new RegularMemberDefinition(function, node)));
+      methodMap[node] = function;
+      for (ir.TypeParameter typeParameter in node.function.typeParameters) {
+        getTypeVariable(typeParameter);
+      }
     }
-    Name name = getName(node.name);
-    bool isStatic = node.isStatic;
-    bool isExternal = node.isExternal;
-    // TODO(johnniwinther): Remove `&& !node.isExternal` when #31233 is fixed.
-    bool isAbstract = node.isAbstract && !node.isExternal;
-    AsyncMarker asyncMarker = getAsyncMarker(node.function);
-    IndexedFunction function;
-    switch (node.kind) {
-      case ir.ProcedureKind.Factory:
-        throw new UnsupportedError("Cannot create method from factory.");
-      case ir.ProcedureKind.Getter:
-        function = createGetter(library, enclosingClass, name, asyncMarker,
-            isStatic: isStatic, isExternal: isExternal, isAbstract: isAbstract);
-        break;
-      case ir.ProcedureKind.Method:
-      case ir.ProcedureKind.Operator:
-        function = createMethod(library, enclosingClass, name,
-            getParameterStructure(node.function), asyncMarker,
-            isStatic: isStatic, isExternal: isExternal, isAbstract: isAbstract);
-        break;
-      case ir.ProcedureKind.Setter:
-        assert(asyncMarker == AsyncMarker.SYNC);
-        function = createSetter(library, enclosingClass, name.setter,
-            isStatic: isStatic, isExternal: isExternal, isAbstract: isAbstract);
-        break;
-    }
-    return members.register<IndexedFunction, FunctionData>(
-        function,
-        new FunctionDataImpl(
-            node, node.function, new RegularMemberDefinition(function, node)));
+    return function;
   }
 
   FieldEntity getFieldInternal(ir.Field node) {
@@ -1332,20 +1355,6 @@
         new FieldDataImpl(node, new RegularMemberDefinition(field, node)));
   }
 
-  ParameterStructure getParameterStructure(ir.FunctionNode node,
-      // TODO(johnniwinther): Remove this when type arguments are passed to
-      // constructors like calling a generic method.
-      {bool includeTypeParameters: true}) {
-    // TODO(johnniwinther): Cache the computed function type.
-    int requiredParameters = node.requiredParameterCount;
-    int positionalParameters = node.positionalParameters.length;
-    int typeParameters = node.typeParameters.length;
-    List<String> namedParameters =
-        node.namedParameters.map((p) => p.name).toList()..sort();
-    return new ParameterStructure(requiredParameters, positionalParameters,
-        namedParameters, includeTypeParameters ? typeParameters : 0);
-  }
-
   IndexedLibrary createLibrary(String name, Uri canonicalUri);
 
   IndexedClass createClass(LibraryEntity library, String name,
@@ -2039,119 +2048,6 @@
   }
 }
 
-/// Visitor that converts kernel dart types into [DartType].
-class DartTypeConverter extends ir.DartTypeVisitor<DartType> {
-  final KernelToElementMapBase elementMap;
-  final Map<ir.TypeParameter, DartType> currentFunctionTypeParameters =
-      <ir.TypeParameter, DartType>{};
-  bool topLevel = true;
-
-  DartTypeConverter(this.elementMap);
-
-  DartType convert(ir.DartType type) {
-    topLevel = true;
-    return type.accept(this);
-  }
-
-  /// Visit a inner type.
-  DartType visitType(ir.DartType type) {
-    topLevel = false;
-    return type.accept(this);
-  }
-
-  InterfaceType visitSupertype(ir.Supertype node) {
-    ClassEntity cls = elementMap.getClass(node.classNode);
-    return new InterfaceType(cls, visitTypes(node.typeArguments));
-  }
-
-  List<DartType> visitTypes(List<ir.DartType> types) {
-    topLevel = false;
-    return new List.generate(
-        types.length, (int index) => types[index].accept(this));
-  }
-
-  @override
-  DartType visitTypeParameterType(ir.TypeParameterType node) {
-    DartType typeParameter = currentFunctionTypeParameters[node.parameter];
-    if (typeParameter != null) {
-      return typeParameter;
-    }
-    if (node.parameter.parent is ir.Typedef) {
-      // Typedefs are only used in type literals so we never need their type
-      // variables.
-      return const DynamicType();
-    }
-    return new TypeVariableType(elementMap.getTypeVariable(node.parameter));
-  }
-
-  @override
-  DartType visitFunctionType(ir.FunctionType node) {
-    int index = 0;
-    List<FunctionTypeVariable> typeVariables;
-    for (ir.TypeParameter typeParameter in node.typeParameters) {
-      FunctionTypeVariable typeVariable = new FunctionTypeVariable(index);
-      currentFunctionTypeParameters[typeParameter] = typeVariable;
-      typeVariables ??= <FunctionTypeVariable>[];
-      typeVariables.add(typeVariable);
-      index++;
-    }
-    if (typeVariables != null) {
-      for (int index = 0; index < typeVariables.length; index++) {
-        typeVariables[index].bound =
-            node.typeParameters[index].bound.accept(this);
-      }
-    }
-
-    FunctionType type = new FunctionType(
-        visitType(node.returnType),
-        visitTypes(node.positionalParameters
-            .take(node.requiredParameterCount)
-            .toList()),
-        visitTypes(node.positionalParameters
-            .skip(node.requiredParameterCount)
-            .toList()),
-        node.namedParameters.map((n) => n.name).toList(),
-        node.namedParameters.map((n) => visitType(n.type)).toList(),
-        typeVariables ?? const <FunctionTypeVariable>[]);
-    for (ir.TypeParameter typeParameter in node.typeParameters) {
-      currentFunctionTypeParameters.remove(typeParameter);
-    }
-    return type;
-  }
-
-  @override
-  DartType visitInterfaceType(ir.InterfaceType node) {
-    ClassEntity cls = elementMap.getClass(node.classNode);
-    if (cls.name == 'FutureOr' &&
-        cls.library == elementMap.commonElements.asyncLibrary) {
-      return new FutureOrType(visitTypes(node.typeArguments).single);
-    }
-    return new InterfaceType(cls, visitTypes(node.typeArguments));
-  }
-
-  @override
-  DartType visitVoidType(ir.VoidType node) {
-    return const VoidType();
-  }
-
-  @override
-  DartType visitDynamicType(ir.DynamicType node) {
-    return const DynamicType();
-  }
-
-  @override
-  DartType visitInvalidType(ir.InvalidType node) {
-    // Root uses such a `o is Unresolved` and `o as Unresolved` must be special
-    // cased in the builder, nested invalid types are treated as `dynamic`.
-    return const DynamicType();
-  }
-
-  @override
-  DartType visitBottomType(ir.BottomType node) {
-    return elementMap.commonElements.nullType;
-  }
-}
-
 /// [native.BehaviorBuilder] for kernel based elements.
 class KernelBehaviorBuilder extends native.BehaviorBuilder {
   final ElementEnvironment elementEnvironment;
diff --git a/pkg/compiler/lib/src/ssa/kernel_impact.dart b/pkg/compiler/lib/src/ssa/kernel_impact.dart
index 75b41d1..a1d6c47 100644
--- a/pkg/compiler/lib/src/ssa/kernel_impact.dart
+++ b/pkg/compiler/lib/src/ssa/kernel_impact.dart
@@ -812,6 +812,13 @@
   void visitTypeLiteral(ir.TypeLiteral node) {
     impactBuilder.registerTypeUse(
         new TypeUse.typeLiteral(elementMap.getDartType(node.type)));
+    if (node.type is ir.FunctionType) {
+      ir.FunctionType functionType = node.type;
+      assert(functionType.typedef != null);
+      // TODO(johnniwinther): Can we avoid the typedef type altogether?
+      // We need to ensure that the typedef is live.
+      elementMap.getTypedefType(functionType.typedef);
+    }
   }
 
   @override