// Copyright (c) 2016, 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.md file.

import 'dart:async';
import 'dart:collection' show Queue;

import 'package:kernel/ast.dart' as ir;
import 'package:kernel/verifier.dart' show CheckParentPointers;

import '../common.dart';
import '../common/names.dart';
import '../compiler.dart' show Compiler;
import '../constants/expressions.dart'
    show ConstantExpression, TypeConstantExpression;
import '../dart_types.dart'
    show DartType, FunctionType, InterfaceType, TypeKind, TypeVariableType;
import '../diagnostics/messages.dart' show MessageKind;
import '../diagnostics/spannable.dart' show Spannable;
import '../elements/elements.dart'
    show
        ClassElement,
        ConstructorElement,
        Element,
        ExportElement,
        FieldElement,
        FunctionElement,
        ImportElement,
        LibraryElement,
        LocalFunctionElement,
        MetadataAnnotation,
        MixinApplicationElement,
        TypeVariableElement;
import '../elements/modelx.dart' show ErroneousFieldElementX;
import '../tree/tree.dart' show FunctionExpression, Node;
import 'constant_visitor.dart';
import 'kernel_visitor.dart' show IrFunction, KernelVisitor;

typedef void WorkAction();

class WorkItem {
  final Element element;
  final WorkAction action;

  WorkItem(this.element, this.action);
}

class Kernel {
  final Compiler compiler;

  final Map<LibraryElement, ir.Library> libraries =
      <LibraryElement, ir.Library>{};

  final Map<ClassElement, ir.Class> classes = <ClassElement, ir.Class>{};

  final Map<FunctionElement, ir.Member> functions =
      <FunctionElement, ir.Member>{};

  final Map<LocalFunctionElement, ir.Node> localFunctions =
      <LocalFunctionElement, ir.Node>{};

  final Map<FieldElement, ir.Field> fields = <FieldElement, ir.Field>{};

  final Map<TypeVariableElement, ir.TypeParameter> typeParameters =
      <TypeVariableElement, ir.TypeParameter>{};

  final Map<TypeVariableElement, ir.TypeParameter> factoryTypeParameters =
      <TypeVariableElement, ir.TypeParameter>{};

  final Set<ir.TreeNode> checkedNodes = new Set<ir.TreeNode>();

  final Map<LibraryElement, Map<String, int>> mixinApplicationNamesByLibrary =
      <LibraryElement, Map<String, int>>{};

  final Map<ir.Node, Element> nodeToElement = <ir.Node, Element>{};
  final Map<ir.Node, Node> nodeToAst = <ir.Node, Node>{};
  final Map<ir.Node, Node> nodeToAstOperator = <ir.Node, Node>{};
  // Synthetic nodes are nodes we generated that do not correspond to
  // [ast.Node]s. A node should be in one of nodeToAst or syntheticNodes but not
  // both.
  final Set<ir.Node> syntheticNodes = new Set<ir.Node>();

  final Map<ir.Node, ConstantExpression> parameterInitializerNodeToConstant =
      <ir.Node, ConstantExpression>{};

  /// FIFO queue of work that needs to be completed before the returned AST
  /// nodes are correct.
  final Queue<WorkItem> workQueue = new Queue<WorkItem>();

  Kernel(this.compiler);

  void addWork(Element element, WorkAction action) {
    workQueue.addLast(new WorkItem(element, action));
  }

  void checkMember(Element key, ir.TreeNode value) {
    if (!checkedNodes.add(value)) return;
    if (value.parent == null) {
      internalError(key, "Missing parent on IR node.");
    }
    try {
      CheckParentPointers.check(value);
    } catch (e, s) {
      internalError(key, "$e\n$s");
    }
  }

  void checkLibrary(Element key, ir.Library library) {
    if (!checkedNodes.add(library)) return;
    CheckParentPointers.check(library);
  }

  void processWorkQueue() {
    while (workQueue.isNotEmpty) {
      WorkItem work = workQueue.removeFirst();
      work.action();
    }
    assert(() {
      libraries.forEach(checkLibrary);
      classes.forEach(checkMember);
      functions.forEach(checkMember);
      fields.forEach(checkMember);
      return true;
    });
  }

  ir.Name irName(String name, Element element) {
    ir.Library irLibrary = null;
    if (name.startsWith("_")) {
      ClassElement cls = element.enclosingClass;
      if (cls != null && cls.isMixinApplication) {
        MixinApplicationElement mixinApplication = cls;
        element = mixinApplication.mixin;
      }
      irLibrary = libraryToIr(element.library);
    }
    return new ir.Name(name, irLibrary);
  }

  Future<ir.Library> loadLibrary(Uri uri) async {
    return libraryToIr(await compiler.libraryLoader.loadLibrary(uri));
  }

  ir.Library libraryToIr(LibraryElement library) {
    library = library.declaration;
    return libraries.putIfAbsent(library, () {
      String name = library.hasLibraryName ? library.libraryName : null;
      ir.Library libraryNode = new ir.Library(library.canonicalUri,
          name: name, classes: null, procedures: null, fields: null);
      addWork(library, () {
        Queue<ir.Class> classes = new Queue<ir.Class>();
        Queue<ir.Member> members = new Queue<ir.Member>();
        library.implementation.forEachLocalMember((Element e) {
          if (e.isClass) {
            classes.addFirst(classToIr(e));
          } else if (e.isFunction || e.isAccessor) {
            members.addFirst(functionToIr(e));
          } else if (e.isField) {
            members.addFirst(fieldToIr(e));
          } else if (e.isTypedef) {
            // Ignored, typedefs are unaliased on use.
          } else {
            internalError(e, "Unhandled library member: $e");
          }
        });
        // The elements were inserted in reverse order as forEachLocalMember
        // above gives them in reversed order.
        classes.forEach(libraryNode.addClass);
        members.forEach(libraryNode.addMember);
      });
      return libraryNode;
    });
  }

  /// Compute a name for [cls]. We want to have unique names in a library, but
  /// mixin applications can lead to multiple classes with the same name. So
  /// for those we append `#` and a number.
  String computeName(ClassElement cls) {
    String name = cls.name;
    if (!cls.isUnnamedMixinApplication) return name;
    Map<String, int> mixinApplicationNames = mixinApplicationNamesByLibrary
        .putIfAbsent(cls.library.implementation, () => <String, int>{});
    int count = mixinApplicationNames.putIfAbsent(name, () => 0);
    mixinApplicationNames[name] = count + 1;
    return "$name#$count";
  }

  ir.Class classToIr(ClassElement cls) {
    cls = cls.declaration;
    return classes.putIfAbsent(cls, () {
      cls.ensureResolved(compiler.resolution);
      compiler.enqueuer.resolution.emptyDeferredQueueForTesting();
      String name = computeName(cls);
      ir.Class classNode = new ir.Class(
          name: name,
          isAbstract: cls.isAbstract,
          typeParameters: null,
          implementedTypes: null,
          constructors: null,
          procedures: null,
          fields: null);
      addWork(cls, () {
        if (cls.supertype != null) {
          classNode.supertype = supertypeToIr(cls.supertype);
        }
        if (cls.isMixinApplication) {
          MixinApplicationElement mixinApplication = cls;
          classNode.mixedInType = supertypeToIr(mixinApplication.mixinType);
        }
        classNode.parent = libraryToIr(cls.library);
        if (cls.isUnnamedMixinApplication) {
          classNode.enclosingLibrary.addClass(classNode);
        }
        cls.implementation
            .forEachMember((ClassElement enclosingClass, Element member) {
          if (member.enclosingClass.declaration != cls) {
            // TODO(het): figure out why impact_test triggers this
            //internalError(cls, "`$member` isn't mine.");
          } else if (member.isConstructor) {
            ConstructorElement constructor = member;
            ir.Member memberNode = functionToIr(member);
            if (!constructor.isRedirectingFactory) {
              classNode.addMember(memberNode);
            }
          } else if (member.isFunction || member.isAccessor) {
            classNode.addMember(functionToIr(member));
          } else if (member.isField) {
            classNode.addMember(fieldToIr(member));
          } else {
            internalError(member, "Unhandled class member: $member");
          }
        });
        classNode.typeParameters.addAll(typeVariablesToIr(cls.typeVariables));
        for (ir.Supertype supertype
            in supertypesToIr(cls.interfaces.reverse().toList())) {
          if (supertype != classNode.mixedInType) {
            classNode.implementedTypes.add(supertype);
          }
        }
        addWork(cls, () {
          addDefaultInstanceFieldInitializers(classNode);
        });
      });
      addWork(cls.declaration, () {
        for (MetadataAnnotation metadata in cls.declaration.metadata) {
          classNode.addAnnotation(
              const ConstantVisitor().visit(metadata.constant, this));
        }
      });
      return classNode;
    });
  }

  /// Adds initializers to instance fields that are have no initializer and are
  /// not initialized by all constructors in the class.
  ///
  /// This is more or less copied directly from `ast_from_analyzer.dart` in
  /// dartk.
  void addDefaultInstanceFieldInitializers(ir.Class node) {
    List<ir.Field> uninitializedFields = new List<ir.Field>();
    for (ir.Field field in node.fields) {
      if (field.initializer != null || field.isStatic) continue;
      uninitializedFields.add(field);
    }
    if (uninitializedFields.isEmpty) return;
    constructorLoop:
    for (ir.Constructor constructor in node.constructors) {
      Set<ir.Field> remainingFields = uninitializedFields.toSet();
      for (ir.Initializer initializer in constructor.initializers) {
        if (initializer is ir.FieldInitializer) {
          remainingFields.remove(initializer.field);
        } else if (initializer is ir.RedirectingInitializer) {
          // The target constructor will be checked in another iteration.
          continue constructorLoop;
        }
      }
      for (ir.Field field in remainingFields) {
        if (field.initializer == null) {
          field.initializer = new ir.NullLiteral()..parent = field;
        }
      }
    }
  }

  bool hasHierarchyProblem(ClassElement cls) => cls.hasIncompleteHierarchy;

  ir.InterfaceType interfaceTypeToIr(InterfaceType type) {
    ir.Class cls = classToIr(type.element);
    if (type.typeArguments.isEmpty) {
      return cls.rawType;
    } else {
      return new ir.InterfaceType(cls, typesToIr(type.typeArguments));
    }
  }

  ir.Supertype supertypeToIr(InterfaceType type) {
    ir.Class cls = classToIr(type.element);
    if (type.typeArguments.isEmpty) {
      return cls.asRawSupertype;
    } else {
      return new ir.Supertype(cls, typesToIr(type.typeArguments));
    }
  }

  ir.FunctionType functionTypeToIr(FunctionType type) {
    List<ir.TypeParameter> typeParameters = <ir.TypeParameter>[];
    int requiredParameterCount = type.parameterTypes.length;
    List<ir.DartType> positionalParameters =
        new List<ir.DartType>.from(typesToIr(type.parameterTypes))
          ..addAll(typesToIr(type.optionalParameterTypes));
    List<ir.NamedType> namedParameters = new List<ir.NamedType>.generate(
        type.namedParameters.length,
        (i) => new ir.NamedType(
            type.namedParameters[i], typeToIr(type.namedParameterTypes[i])));
    ir.DartType returnType = typeToIr(type.returnType);

    return new ir.FunctionType(positionalParameters, returnType,
        namedParameters: namedParameters,
        typeParameters: typeParameters,
        requiredParameterCount: requiredParameterCount);
  }

  ir.TypeParameterType typeVariableTypeToIr(TypeVariableType type) {
    return new ir.TypeParameterType(typeVariableToIr(type.element));
  }

  List<ir.DartType> typesToIr(List<DartType> types) {
    List<ir.DartType> result = new List<ir.DartType>(types.length);
    for (int i = 0; i < types.length; i++) {
      result[i] = typeToIr(types[i]);
    }
    return result;
  }

  List<ir.Supertype> supertypesToIr(List<DartType> types) {
    List<ir.Supertype> result = new List<ir.Supertype>(types.length);
    for (int i = 0; i < types.length; i++) {
      result[i] = supertypeToIr(types[i]);
    }
    return result;
  }

  ir.DartType typeToIr(DartType type) {
    switch (type.kind) {
      case TypeKind.FUNCTION:
        return functionTypeToIr(type);

      case TypeKind.INTERFACE:
        return interfaceTypeToIr(type);

      case TypeKind.TYPEDEF:
        type.computeUnaliased(compiler.resolution);
        return typeToIr(type.unaliased);

      case TypeKind.TYPE_VARIABLE:
        return typeVariableTypeToIr(type);

      case TypeKind.MALFORMED_TYPE:
        return const ir.InvalidType();

      case TypeKind.DYNAMIC:
        return const ir.DynamicType();

      case TypeKind.VOID:
        return const ir.VoidType();
    }
  }

  ir.DartType typeLiteralToIr(TypeConstantExpression constant) {
    return typeToIr(constant.type);
  }

  void setParent(ir.Member member, Element element) {
    if (element.isLocal) {
      member.parent = elementToIr(element.enclosingElement);
    } else if (element.isTopLevel) {
      member.parent = elementToIr(element.library);
    } else if (element.isClassMember) {
      member.parent = elementToIr(element.enclosingClass);
    } else {
      member.parent = elementToIr(element.enclosingElement);
    }
  }

  bool isNativeMethod(FunctionElement element) {
    // This method is a (modified) copy of the same method in
    // `pkg/compiler/lib/src/native/enqueue.dart`.
    if (!compiler.backend.canLibraryUseNative(element.library)) return false;
    return compiler.reporter.withCurrentElement(element, () {
      FunctionExpression functionExpression =
          element.node?.asFunctionExpression();
      if (functionExpression == null) return false;
      Node body = functionExpression.body;
      if (body == null) return false;
      if (identical(body.getBeginToken().stringValue, 'native')) return true;
      return false;
    });
  }

  ir.Member functionToIr(FunctionElement function) {
    if (function.isDeferredLoaderGetter) {
      internalError(function, "Deferred loader.");
    }
    if (function.isLocal) {
      internalError(function, "Local function.");
    }
    if (isSyntheticError(function)) {
      internalError(function, "Synthetic error function: $function.");
    }
    function = function.declaration;
    return functions.putIfAbsent(function, () {
      compiler.resolution.ensureResolved(function);
      compiler.enqueuer.resolution.emptyDeferredQueueForTesting();
      function = function.implementation;
      ir.Member member;
      ir.Constructor constructor;
      ir.Procedure procedure;
      ir.Name name = irName(function.name, function);
      bool isNative = isNativeMethod(function);
      if (function.isGenerativeConstructor) {
        member = constructor = new ir.Constructor(null,
            name: name,
            isConst: function.isConst,
            isExternal: isNative || function.isExternal,
            initializers: null);
      } else {
        member = procedure = new ir.Procedure(name, null, null,
            isAbstract: function.isAbstract,
            isStatic: function.isStatic ||
                function.isTopLevel ||
                function.isFactoryConstructor,
            isExternal: isNative || function.isExternal,
            isConst: false); // TODO(ahe): When is this true?
      }
      addWork(function, () {
        setParent(member, function);
        KernelVisitor visitor =
            new KernelVisitor(function, function.treeElements, this);
        beginFactoryScope(function);
        IrFunction irFunction = visitor.buildFunction();
        // TODO(ahe): Add addFunction/set function to [ir.Procedure].
        irFunction.node.parent = member;
        if (irFunction.isConstructor) {
          assert(irFunction.kind == null);
          constructor.function = irFunction.node;
          constructor.initializers = irFunction.initializers;
          // TODO(ahe): Add setInitializers to [ir.Constructor].
          for (ir.Initializer initializer in irFunction.initializers) {
            initializer.parent = constructor;
          }
        } else {
          assert(irFunction.kind != null);
          procedure.function = irFunction.node;
          procedure.kind = irFunction.kind;
        }
        endFactoryScope(function);
        irFunction.node.typeParameters
            .addAll(typeVariablesToIr(function.typeVariables));
        member.transformerFlags = visitor.transformerFlags;
        assert(() {
          visitor.locals.forEach(checkMember);
          return true;
        });
      });
      addWork(function.declaration, () {
        for (MetadataAnnotation metadata in function.declaration.metadata) {
          member.addAnnotation(
              const ConstantVisitor().visit(metadata.constant, this));
        }
      });
      return member;
    });
  }

  /// Adds the type parameters of the enclosing class of [function] to
  /// [factoryTypeParameters]. This serves as a local scope for type variables
  /// resolved inside the factory.
  ///
  /// This method solves the problem that a factory method really is a generic
  /// method that has its own type parameters, one for each type parameter in
  /// the enclosing class.
  void beginFactoryScope(FunctionElement function) {
    assert(factoryTypeParameters.isEmpty);
    if (!function.isFactoryConstructor) return;
    ClassElement cls = function.enclosingClass;
    for (DartType type in cls.typeVariables) {
      if (type.isTypeVariable) {
        TypeVariableElement variable = type.element;
        factoryTypeParameters[variable] =
            new ir.TypeParameter(variable.name, null);
      }
    }
    for (DartType type in cls.typeVariables) {
      if (type.isTypeVariable) {
        TypeVariableElement variable = type.element;
        factoryTypeParameters[variable].bound = typeToIr(variable.bound);
      }
    }
  }

  /// Ends the local scope started by [beginFactoryScope].
  void endFactoryScope(FunctionElement function) {
    factoryTypeParameters.clear();
  }

  ir.Field fieldToIr(FieldElement field) {
    if (isSyntheticError(field)) {
      internalError(field, "Synthetic error field: $field.");
    }
    field = field.declaration;
    return fields.putIfAbsent(field, () {
      compiler.resolution.ensureResolved(field);
      compiler.enqueuer.resolution.emptyDeferredQueueForTesting();
      field = field.implementation;
      ir.DartType type =
          field.isMalformed ? const ir.InvalidType() : typeToIr(field.type);
      ir.Field fieldNode = new ir.Field(irName(field.memberName.text, field),
          type: type,
          initializer: null,
          isFinal: field.isFinal,
          isStatic: field.isStatic || field.isTopLevel,
          isConst: field.isConst);
      addWork(field, () {
        setParent(fieldNode, field);
        if (!field.isMalformed) {
          if (field.initializer != null) {
            KernelVisitor visitor =
                new KernelVisitor(field, field.treeElements, this);
            fieldNode.initializer = visitor.buildInitializer()
              ..parent = fieldNode;
          } else if (!field.isInstanceMember) {
            fieldNode.initializer = new ir.NullLiteral()..parent = fieldNode;
          }
        }
      });
      addWork(field.declaration, () {
        for (MetadataAnnotation metadata in field.declaration.metadata) {
          fieldNode.addAnnotation(
              const ConstantVisitor().visit(metadata.constant, this));
        }
      });
      return fieldNode;
    });
  }

  ir.TypeParameter typeVariableToIr(TypeVariableElement variable) {
    variable = variable.declaration;
    ir.TypeParameter parameter = factoryTypeParameters[variable];
    if (parameter != null) return parameter;
    return typeParameters.putIfAbsent(variable, () {
      ir.TypeParameter parameter = new ir.TypeParameter(variable.name, null);
      addWork(variable, () {
        if (variable.typeDeclaration.isClass) {
          ClassElement cls = variable.typeDeclaration;
          cls.ensureResolved(compiler.resolution);
          parameter.parent = classToIr(cls);
        } else {
          FunctionElement method = variable.typeDeclaration;
          parameter.parent = functionToIr(method).function;
        }
        parameter.bound = typeToIr(variable.bound);
      });
      return parameter;
    });
  }

  List<ir.TypeParameter> typeVariablesToIr(List<DartType> variables) {
    List<ir.TypeParameter> result =
        new List<ir.TypeParameter>(variables.length);
    for (int i = 0; i < variables.length; i++) {
      TypeVariableType type = variables[i];
      result[i] = typeVariableToIr(type.element);
    }
    return result;
  }

  ir.TreeNode elementToIr(Element element) {
    if (element.isLibrary) return libraryToIr(element);
    if (element.isClass) return classToIr(element);
    if (element.isFunction || element.isAccessor) return functionToIr(element);
    if (element.isField) return fieldToIr(element);
    throw "unhandled element: $element";
  }

  void debugMessage(Spannable spannable, String message) {
    compiler.reporter
        .reportHintMessage(spannable, MessageKind.GENERIC, {'text': message});
  }

  void internalError(Spannable spannable, String message) {
    compiler.reporter.internalError(spannable, message);
    throw message;
  }

  forEachLibraryElement(f(LibraryElement library)) {
    return compiler.libraryLoader.libraries.forEach(f);
  }

  ConstructorTarget computeEffectiveTarget(
      ConstructorElement constructor, DartType type) {
    constructor = constructor.implementation;
    Set<ConstructorElement> seen = new Set<ConstructorElement>();
    functionToIr(constructor);
    while (constructor != constructor.effectiveTarget) {
      type = constructor.computeEffectiveTargetType(type);
      if (constructor.isGenerativeConstructor) break;
      if (!seen.add(constructor)) break;
      constructor = constructor.effectiveTarget.implementation;
      if (isSyntheticError(constructor)) break;
      functionToIr(constructor);
    }
    return new ConstructorTarget(constructor, type);
  }

  /// Compute all the dependencies on the library with [uri] (including the
  /// library itself). This is useful for creating a Kernel IR `Program`.
  List<ir.Library> libraryDependencies(Uri uri) {
    List<ir.Library> result = <ir.Library>[];
    Queue<LibraryElement> notProcessed = new Queue<LibraryElement>();
    Set<LibraryElement> seen = new Set<LibraryElement>();
    LibraryElement library = compiler.libraryLoader.lookupLibrary(uri);
    void processLater(LibraryElement library) {
      if (library != null) {
        notProcessed.addLast(library);
      }
    }

    processLater(library);
    seen.add(library);
    LibraryElement core =
        compiler.libraryLoader.lookupLibrary(Uri.parse("dart:core"));
    if (seen.add(core)) {
      // `dart:core` is implicitly imported by most libraries, and for some
      // reason not included in `library.imports` below.
      processLater(core);
    }
    while (notProcessed.isNotEmpty) {
      LibraryElement library = notProcessed.removeFirst();
      ir.Library irLibrary = libraryToIr(library);
      for (ImportElement import in library.imports) {
        if (seen.add(import.importedLibrary)) {
          processLater(import.importedLibrary);
        }
      }
      for (ExportElement export in library.exports) {
        if (seen.add(export.exportedLibrary)) {
          processLater(export.exportedLibrary);
        }
      }
      for (ImportElement import in library.implementation.imports) {
        if (seen.add(import.importedLibrary)) {
          processLater(import.importedLibrary);
        }
      }
      for (ExportElement export in library.implementation.exports) {
        if (seen.add(export.exportedLibrary)) {
          processLater(export.exportedLibrary);
        }
      }
      if (irLibrary != null) {
        result.add(irLibrary);
      }
    }
    processWorkQueue();
    return result;
  }

  /// Returns true if [element] is synthesized to recover or represent a
  /// semantic error, for example, missing, duplicated, or ambiguous elements.
  /// However, returns false for elements that have an unrecoverable syntax
  /// error. Both kinds of element will return true from [Element.isMalformed],
  /// but they must be handled differently. For example, a static call to
  /// synthetic error element should be compiled to [ir.InvalidExpression],
  /// whereas a static call to a method which has a syntax error should be
  /// compiled to a static call to the method. The method itself will have a
  /// method body that is [ir.InvalidStatement].
  bool isSyntheticError(Element element) {
    if (element.isAmbiguous) return true;
    if (element.isError) return true;
    if (element.isField && element is ErroneousFieldElementX) {
      return true;
    }
    return false;
  }

  ir.Constructor getDartCoreConstructor(
      String className, String constructorName) {
    LibraryElement library =
        compiler.libraryLoader.lookupLibrary(Uris.dart_core);
    ClassElement cls = library.implementation.localLookup(className);
    assert(invariant(CURRENT_ELEMENT_SPANNABLE, cls != null,
        message: 'dart:core class $className not found.'));
    ConstructorElement constructor = cls.lookupConstructor(constructorName);
    assert(invariant(CURRENT_ELEMENT_SPANNABLE, constructor != null,
        message: "Constructor '$constructorName' not found "
            "in class '$className'."));
    return functionToIr(constructor);
  }

  ir.Procedure getDartCoreMethod(String name) {
    LibraryElement library =
        compiler.libraryLoader.lookupLibrary(Uris.dart_core);
    Element function = library.implementation.localLookup(name);
    assert(invariant(CURRENT_ELEMENT_SPANNABLE, function != null,
        message: "dart:core method '$name' not found."));
    return functionToIr(function);
  }

  ir.Procedure getMalformedTypeErrorBuilder() {
    return getDartCoreMethod('_malformedTypeError');
  }

  ir.Procedure getUnresolvedConstructorBuilder() {
    return getDartCoreMethod('_unresolvedConstructorError');
  }

  ir.Procedure getUnresolvedStaticGetterBuilder() {
    return getDartCoreMethod('_unresolvedStaticGetterError');
  }

  ir.Procedure getUnresolvedStaticSetterBuilder() {
    return getDartCoreMethod('_unresolvedStaticSetterError');
  }

  ir.Procedure getUnresolvedStaticMethodBuilder() {
    return getDartCoreMethod('_unresolvedStaticMethodError');
  }

  ir.Procedure getUnresolvedTopLevelGetterBuilder() {
    return getDartCoreMethod('_unresolvedTopLevelGetterError');
  }

  ir.Procedure getUnresolvedTopLevelSetterBuilder() {
    return getDartCoreMethod('_unresolvedTopLevelSetterError');
  }

  ir.Procedure getUnresolvedTopLevelMethodBuilder() {
    return getDartCoreMethod('_unresolvedTopLevelMethodError');
  }

  ir.Procedure getUnresolvedSuperGetterBuilder() {
    return getDartCoreMethod('_unresolvedSuperGetterError');
  }

  ir.Procedure getUnresolvedSuperSetterBuilder() {
    return getDartCoreMethod('_unresolvedSuperSetterError');
  }

  ir.Procedure getUnresolvedSuperMethodBuilder() {
    return getDartCoreMethod('_unresolvedSuperMethodError');
  }

  ir.Procedure getGenericNoSuchMethodBuilder() {
    return getDartCoreMethod('_genericNoSuchMethod');
  }

  ir.Constructor getFallThroughErrorConstructor() {
    return getDartCoreConstructor('FallThroughError', '');
  }
}

class ConstructorTarget {
  final ConstructorElement element;
  final DartType type;

  ConstructorTarget(this.element, this.type);

  String toString() => "ConstructorTarget($element, $type)";
}
