// 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 file.

import 'package:js_runtime/shared/embedded_names.dart';
import 'package:kernel/ast.dart' as ir;

import '../common.dart';
import '../common/names.dart';
import '../compiler.dart';
import '../constants/expressions.dart';
import '../constants/values.dart';
import '../elements/resolution_types.dart';
import '../elements/elements.dart';
import '../elements/entities.dart';
import '../elements/modelx.dart';
import '../elements/types.dart';
import '../js/js.dart' as js;
import '../js_backend/backend_helpers.dart';
import '../js_backend/js_backend.dart';
import '../kernel/kernel.dart';
import '../kernel/kernel_debug.dart';
import '../native/native.dart' as native;
import '../resolution/tree_elements.dart';
import '../tree/tree.dart' as ast;
import '../types/masks.dart';
import '../types/types.dart';
import '../universe/call_structure.dart';
import '../universe/selector.dart';
import '../universe/side_effects.dart';
import '../world.dart';
import 'graph_builder.dart';
import 'jump_handler.dart' show SwitchCaseJumpHandler;
import 'locals_handler.dart';
import 'types.dart';

/// Interface that translates between Kernel IR nodes and entities.
abstract class KernelWorldBuilder {
  /// Returns the [DartType] corresponding to [type].
  DartType getDartType(ir.DartType type);

  /// Returns the list of [DartType]s corresponding to [types].
  List<DartType> getDartTypes(List<ir.DartType> types);

  /// Returns the [InterfaceType] corresponding to [type].
  InterfaceType getInterfaceType(ir.InterfaceType type);

  /// Return the [InterfaceType] corresponding to the [cls] with the given
  /// [typeArguments].
  InterfaceType createInterfaceType(
      ir.Class cls, List<ir.DartType> typeArguments);

  /// Returns the [CallStructure] corresponding to the [arguments].
  CallStructure getCallStructure(ir.Arguments arguments);

  /// Returns the [Selector] corresponding to the invocation or getter/setter
  /// access of [node].
  Selector getSelector(ir.Expression node);

  /// Returns the [FunctionEntity] corresponding to the generative or factory
  /// constructor [node].
  FunctionEntity getConstructor(ir.Member node);

  /// Returns the [MemberEntity] corresponding to the member [node].
  MemberEntity getMember(ir.Member node);

  /// Returns the [FunctionEntity] corresponding to the procedure [node].
  FunctionEntity getMethod(ir.Procedure node);

  /// Returns the [FieldEntity] corresponding to the field [node].
  FieldEntity getField(ir.Field node);

  /// Returns the [ClassEntity] corresponding to the class [node].
  ClassEntity getClass(ir.Class node);

  /// Returns the [Local] corresponding to the [node]. The node must be either
  /// a [ir.FunctionDeclaration] or [ir.FunctionExpression].
  Local getLocalFunction(ir.Node node);

  /// Returns the [Name] corresponding to [name].
  Name getName(ir.Name name);

  /// Returns `true` is [node] has a `@Native(...)` annotation.
  bool isNativeClass(ir.Class node);

  /// Return `true` if [node] is the `dart:_foreign_helper` library.
  bool isForeignLibrary(ir.Library node);

  /// Computes the native behavior for reading the native [field].
  native.NativeBehavior getNativeBehaviorForFieldLoad(ir.Field field);

  /// Computes the native behavior for writing to the native [field].
  native.NativeBehavior getNativeBehaviorForFieldStore(ir.Field field);

  /// Computes the native behavior for calling [procedure].
  native.NativeBehavior getNativeBehaviorForMethod(ir.Procedure procedure);

  /// Computes the [native.NativeBehavior] for a call to the [JS] function.
  native.NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node);

  /// Computes the [native.NativeBehavior] for a call to the [JS_BUILTIN]
  /// function.
  native.NativeBehavior getNativeBehaviorForJsBuiltinCall(
      ir.StaticInvocation node);

  /// Computes the [native.NativeBehavior] for a call to the
  /// [JS_EMBEDDED_GLOBAL] function.
  native.NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall(
      ir.StaticInvocation node);

  /// Compute the kind of foreign helper function called by [node], if any.
  ForeignKind getForeignKind(ir.StaticInvocation node);

  /// Computes the [InterfaceType] referenced by a call to the
  /// [JS_INTERCEPTOR_CONSTANT] function, if any.
  InterfaceType getInterfaceTypeForJsInterceptorCall(ir.StaticInvocation node);
}

/// A helper class that abstracts all accesses of the AST from Kernel nodes.
///
/// The goal is to remove all need for the AST from the Kernel SSA builder.
class KernelAstAdapter implements KernelWorldBuilder {
  final Kernel kernel;
  final JavaScriptBackend _backend;
  final Map<ir.Node, ast.Node> _nodeToAst;
  final Map<ir.Node, Element> _nodeToElement;
  final Map<ir.VariableDeclaration, SyntheticLocal> _syntheticLocals =
      <ir.VariableDeclaration, SyntheticLocal>{};
  // TODO(efortuna): In an ideal world the TreeNodes should be some common
  // interface we create for both ir.Statements and ir.SwitchCase (the
  // ContinueSwitchStatement's target is a SwitchCase) rather than general
  // TreeNode. Talking to Asger about this.
  final Map<ir.TreeNode, KernelJumpTarget> _jumpTargets =
      <ir.TreeNode, KernelJumpTarget>{};
  DartTypeConverter _typeConverter;
  ResolvedAst _resolvedAst;

  /// Sometimes for resolution the resolved AST element needs to change (for
  /// example, if we're inlining, or if we're in a constructor, but then also
  /// constructing the field values). We keep track of this with a stack.
  final List<ResolvedAst> _resolvedAstStack = <ResolvedAst>[];

  KernelAstAdapter(this.kernel, this._backend, this._resolvedAst,
      this._nodeToAst, this._nodeToElement) {
    KernelJumpTarget.index = 0;
    // TODO(het): Maybe just use all of the kernel maps directly?
    for (FieldElement fieldElement in kernel.fields.keys) {
      _nodeToElement[kernel.fields[fieldElement]] = fieldElement;
    }
    for (FunctionElement functionElement in kernel.functions.keys) {
      _nodeToElement[kernel.functions[functionElement]] = functionElement;
    }
    for (ClassElement classElement in kernel.classes.keys) {
      _nodeToElement[kernel.classes[classElement]] = classElement;
    }
    for (LibraryElement libraryElement in kernel.libraries.keys) {
      _nodeToElement[kernel.libraries[libraryElement]] = libraryElement;
    }
    for (LocalFunctionElement localFunction in kernel.localFunctions.keys) {
      _nodeToElement[kernel.localFunctions[localFunction]] = localFunction;
    }
    for (TypeVariableElement typeVariable in kernel.typeParameters.keys) {
      _nodeToElement[kernel.typeParameters[typeVariable]] = typeVariable;
    }
    _typeConverter = new DartTypeConverter(this);
  }

  /// Push the existing resolved AST on the stack and shift the current resolved
  /// AST to the AST that this kernel node points to.
  void pushResolvedAst(ir.Node node) {
    _resolvedAstStack.add(_resolvedAst);
    _resolvedAst = (getElement(node) as AstElement).resolvedAst;
  }

  /// Pop the resolved AST stack to reset it to the previous resolved AST node.
  void popResolvedAstStack() {
    assert(_resolvedAstStack.isNotEmpty);
    _resolvedAst = _resolvedAstStack.removeLast();
  }

  Compiler get _compiler => _backend.compiler;
  TreeElements get elements => _resolvedAst.elements;
  DiagnosticReporter get reporter => _compiler.reporter;
  Element get _target => _resolvedAst.element;

  GlobalTypeInferenceResults get _globalInferenceResults =>
      _compiler.globalInference.results;

  GlobalTypeInferenceElementResult _resultOf(Element e) =>
      _globalInferenceResults
          .resultOf(e is ConstructorBodyElementX ? e.constructor : e);

  ConstantValue getConstantForSymbol(ir.SymbolLiteral node) {
    if (kernel.syntheticNodes.contains(node)) {
      return _backend.constantSystem.createSymbol(_compiler, node.value);
    }
    ast.Node astNode = getNode(node);
    ConstantValue constantValue = _backend.constants
        .getConstantValueForNode(astNode, _resolvedAst.elements);
    assert(invariant(astNode, constantValue != null,
        message: 'No constant computed for $node'));
    return constantValue;
  }

  // TODO(johnniwinther): Use the more precise functions below.
  Element getElement(ir.Node node) {
    Element result = _nodeToElement[node];
    assert(invariant(CURRENT_ELEMENT_SPANNABLE, result != null,
        message: "No element found for $node."));
    return result;
  }

  ConstructorElement getConstructor(ir.Member node) =>
      getElement(node).declaration;

  MemberElement getMember(ir.Member node) => getElement(node).declaration;

  MethodElement getMethod(ir.Procedure node) => getElement(node).declaration;

  FieldElement getField(ir.Field node) => getElement(node).declaration;

  ClassElement getClass(ir.Class node) => getElement(node).declaration;

  LocalFunctionElement getLocalFunction(ir.Node node) => getElement(node);

  ast.Node getNode(ir.Node node) {
    ast.Node result = _nodeToAst[node];
    assert(invariant(CURRENT_ELEMENT_SPANNABLE, result != null,
        message: "No node found for $node"));
    return result;
  }

  ast.Node getNodeOrNull(ir.Node node) {
    return _nodeToAst[node];
  }

  void assertNodeIsSynthetic(ir.Node node) {
    assert(invariant(
        CURRENT_ELEMENT_SPANNABLE, kernel.syntheticNodes.contains(node),
        message: "No synthetic marker found for $node"));
  }

  Local getLocal(ir.VariableDeclaration variable) {
    // If this is a synthetic local, return the synthetic local
    if (variable.name == null) {
      return _syntheticLocals.putIfAbsent(
          variable, () => new SyntheticLocal("x", null));
    }
    return getElement(variable) as LocalElement;
  }

  bool getCanThrow(ir.Node procedure, ClosedWorld closedWorld) {
    FunctionElement function = getElement(procedure);
    return !closedWorld.getCannotThrow(function);
  }

  TypeMask returnTypeOf(ir.Member node) {
    return TypeMaskFactory.inferredReturnTypeForElement(
        getElement(node), _globalInferenceResults);
  }

  SideEffects getSideEffects(ir.Node node, ClosedWorld closedWorld) {
    return closedWorld.getSideEffectsOfElement(getElement(node));
  }

  CallStructure getCallStructure(ir.Arguments arguments) {
    int argumentCount = arguments.positional.length + arguments.named.length;
    List<String> namedArguments = arguments.named.map((e) => e.name).toList();
    return new CallStructure(argumentCount, namedArguments);
  }

  FunctionSignature getFunctionSignature(ir.FunctionNode function) {
    return getElement(function).asFunctionElement().functionSignature;
  }

  Name getName(ir.Name name) {
    return new Name(
        name.name, name.isPrivate ? getElement(name.library) : null);
  }

  ir.Field getFieldFromElement(FieldElement field) {
    return kernel.fields[field];
  }

  Selector getSelector(ir.Expression node) {
    if (node is ir.PropertyGet) return getGetterSelector(node);
    if (node is ir.PropertySet) return getSetterSelector(node);
    if (node is ir.InvocationExpression) return getInvocationSelector(node);
    _compiler.reporter.internalError(getNode(node),
        "Can only get the selector for a property get or an invocation.");
    return null;
  }

  Selector getInvocationSelector(ir.InvocationExpression invocation) {
    Name name = getName(invocation.name);
    SelectorKind kind;
    if (Elements.isOperatorName(invocation.name.name)) {
      if (name == Names.INDEX_NAME || name == Names.INDEX_SET_NAME) {
        kind = SelectorKind.INDEX;
      } else {
        kind = SelectorKind.OPERATOR;
      }
    } else {
      kind = SelectorKind.CALL;
    }

    CallStructure callStructure = getCallStructure(invocation.arguments);
    return new Selector(kind, name, callStructure);
  }

  Selector getGetterSelector(ir.PropertyGet getter) {
    ir.Name irName = getter.name;
    Name name = new Name(
        irName.name, irName.isPrivate ? getElement(irName.library) : null);
    return new Selector.getter(name);
  }

  Selector getSetterSelector(ir.PropertySet setter) {
    ir.Name irName = setter.name;
    Name name = new Name(
        irName.name, irName.isPrivate ? getElement(irName.library) : null);
    return new Selector.setter(name);
  }

  TypeMask typeOfInvocation(ir.MethodInvocation send, ClosedWorld closedWorld) {
    ast.Node operatorNode = kernel.nodeToAstOperator[send];
    if (operatorNode != null) {
      return _resultOf(_target).typeOfOperator(operatorNode);
    }
    if (send.name.name == '[]=') {
      return closedWorld.commonMasks.dynamicType;
    }
    return _resultOf(_target).typeOfSend(getNode(send));
  }

  TypeMask typeOfGet(ir.PropertyGet getter) {
    return _resultOf(_target).typeOfSend(getNode(getter));
  }

  TypeMask typeOfSet(ir.PropertySet setter, ClosedWorld closedWorld) {
    return closedWorld.commonMasks.dynamicType;
  }

  TypeMask typeOfSend(ir.Expression send) {
    assert(send is ir.InvocationExpression || send is ir.PropertyGet);
    return _resultOf(_target).typeOfSend(getNode(send));
  }

  TypeMask typeOfListLiteral(
      Element owner, ir.ListLiteral listLiteral, ClosedWorld closedWorld) {
    ast.Node node = getNodeOrNull(listLiteral);
    if (node == null) {
      assertNodeIsSynthetic(listLiteral);
      return closedWorld.commonMasks.growableListType;
    }
    return _resultOf(owner).typeOfListLiteral(getNode(listLiteral)) ??
        closedWorld.commonMasks.dynamicType;
  }

  TypeMask typeOfIterator(ir.ForInStatement forInStatement) {
    return _resultOf(_target).typeOfIterator(getNode(forInStatement));
  }

  TypeMask typeOfIteratorCurrent(ir.ForInStatement forInStatement) {
    return _resultOf(_target).typeOfIteratorCurrent(getNode(forInStatement));
  }

  TypeMask typeOfIteratorMoveNext(ir.ForInStatement forInStatement) {
    return _resultOf(_target).typeOfIteratorMoveNext(getNode(forInStatement));
  }

  bool isJsIndexableIterator(
      ir.ForInStatement forInStatement, ClosedWorld closedWorld) {
    TypeMask mask = typeOfIterator(forInStatement);
    return mask != null &&
        mask.satisfies(_backend.helpers.jsIndexableClass, closedWorld) &&
        // String is indexable but not iterable.
        !mask.satisfies(_backend.helpers.jsStringClass, closedWorld);
  }

  bool isFixedLength(TypeMask mask, ClosedWorld closedWorld) {
    if (mask.isContainer && (mask as ContainerTypeMask).length != null) {
      // A container on which we have inferred the length.
      return true;
    }
    // TODO(sra): Recognize any combination of fixed length indexables.
    if (mask.containsOnly(closedWorld.backendClasses.fixedListImplementation) ||
        mask.containsOnly(closedWorld.backendClasses.constListImplementation) ||
        mask.containsOnlyString(closedWorld) ||
        closedWorld.commonMasks.isTypedArray(mask)) {
      return true;
    }
    return false;
  }

  TypeMask inferredIndexType(ir.ForInStatement forInStatement) {
    return TypeMaskFactory.inferredTypeForSelector(new Selector.index(),
        typeOfIterator(forInStatement), _globalInferenceResults);
  }

  TypeMask inferredTypeOf(ir.Member node) {
    return TypeMaskFactory.inferredTypeForElement(
        getElement(node), _globalInferenceResults);
  }

  TypeMask selectorTypeOf(Selector selector, TypeMask mask) {
    return TypeMaskFactory.inferredTypeForSelector(
        selector, mask, _globalInferenceResults);
  }

  TypeMask typeFromNativeBehavior(
      native.NativeBehavior nativeBehavior, ClosedWorld closedWorld) {
    return TypeMaskFactory.fromNativeBehavior(nativeBehavior, closedWorld);
  }

  ConstantValue getConstantFor(ir.Node node) {
    // Some `null`s are not mapped when they correspond to errors, e.g. missing
    // `const` initializers.
    if (node is ir.NullLiteral) return new NullConstantValue();

    ConstantValue constantValue =
        _backend.constants.getConstantValueForNode(getNode(node), elements);
    assert(invariant(getNode(node), constantValue != null,
        message: 'No constant computed for $node'));
    return constantValue;
  }

  ConstantValue getConstantForParameterDefaultValue(ir.Node defaultExpression) {
    // TODO(27394): Evaluate constant expressions in ir.Node domain.
    // In the interim, expand the Constantifier and do this:
    //
    //     ConstantExpression constantExpression =
    //         defaultExpression.accept(new Constantifier(this));
    //     assert(constantExpression != null);
    ConstantExpression constantExpression =
        kernel.parameterInitializerNodeToConstant[defaultExpression];
    if (constantExpression == null) return null;
    return _backend.constants.getConstantValue(constantExpression);
  }

  ConstantValue getConstantForType(ir.DartType irType) {
    ResolutionDartType type = getDartType(irType);
    return _backend.constantSystem.createType(_compiler, type.asRaw());
  }

  bool isIntercepted(ir.Node node) {
    Selector selector = getSelector(node);
    return _backend.isInterceptedSelector(selector);
  }

  bool isInterceptedSelector(Selector selector) {
    return _backend.isInterceptedSelector(selector);
  }

  // Is the member a lazy initialized static or top-level member?
  bool isLazyStatic(ir.Member member) {
    if (member is ir.Field) {
      FieldElement field = _nodeToElement[member];
      return field.constant == null;
    }
    return false;
  }

  LibraryElement get jsHelperLibrary => _backend.helpers.jsHelperLibrary;

  KernelJumpTarget getJumpTarget(ir.TreeNode node,
      {bool isContinueTarget: false}) {
    return _jumpTargets.putIfAbsent(node, () {
      if (node is ir.LabeledStatement &&
          _jumpTargets.containsKey((node as ir.LabeledStatement).body)) {
        return _jumpTargets[(node as ir.LabeledStatement).body];
      }
      return new KernelJumpTarget(node, this,
          makeContinueLabel: isContinueTarget);
    });
  }

  ir.Class get mapLiteralClass =>
      kernel.classes[_backend.helpers.mapLiteralClass];

  ir.Procedure get mapLiteralConstructor =>
      kernel.functions[_backend.helpers.mapLiteralConstructor];

  ir.Procedure get mapLiteralConstructorEmpty =>
      kernel.functions[_backend.helpers.mapLiteralConstructorEmpty];

  ir.Procedure get mapLiteralUntypedEmptyMaker =>
      kernel.functions[_backend.helpers.mapLiteralUntypedEmptyMaker];

  ir.Procedure get exceptionUnwrapper =>
      kernel.functions[_backend.helpers.exceptionUnwrapper];

  TypeMask get exceptionUnwrapperType =>
      TypeMaskFactory.inferredReturnTypeForElement(
          _backend.helpers.exceptionUnwrapper, _globalInferenceResults);

  ir.Procedure get traceFromException =>
      kernel.functions[_backend.helpers.traceFromException];

  TypeMask get traceFromExceptionType =>
      TypeMaskFactory.inferredReturnTypeForElement(
          _backend.helpers.traceFromException, _globalInferenceResults);

  ir.Procedure get streamIteratorConstructor =>
      kernel.functions[_backend.helpers.streamIteratorConstructor];

  TypeMask get streamIteratorConstructorType =>
      TypeMaskFactory.inferredReturnTypeForElement(
          _backend.helpers.streamIteratorConstructor, _globalInferenceResults);

  ir.Procedure get fallThroughError =>
      kernel.functions[_backend.helpers.fallThroughError];

  TypeMask get fallThroughErrorType =>
      TypeMaskFactory.inferredReturnTypeForElement(
          _backend.helpers.fallThroughError, _globalInferenceResults);

  ir.Procedure get mapLiteralUntypedMaker =>
      kernel.functions[_backend.helpers.mapLiteralUntypedMaker];

  MemberElement get jsIndexableLength => _backend.helpers.jsIndexableLength;

  ir.Procedure get checkConcurrentModificationError =>
      kernel.functions[_backend.helpers.checkConcurrentModificationError];

  TypeMask get checkConcurrentModificationErrorReturnType =>
      TypeMaskFactory.inferredReturnTypeForElement(
          _backend.helpers.checkConcurrentModificationError,
          _globalInferenceResults);

  ir.Procedure get checkSubtype =>
      kernel.functions[_backend.helpers.checkSubtype];

  ir.Procedure get checkSubtypeOfRuntimeType =>
      kernel.functions[_backend.helpers.checkSubtypeOfRuntimeType];

  ir.Procedure get throwTypeError =>
      kernel.functions[_backend.helpers.throwTypeError];

  TypeMask get throwTypeErrorType =>
      TypeMaskFactory.inferredReturnTypeForElement(
          _backend.helpers.throwTypeError, _globalInferenceResults);

  ir.Procedure get assertHelper =>
      kernel.functions[_backend.helpers.assertHelper];

  TypeMask get assertHelperReturnType =>
      TypeMaskFactory.inferredReturnTypeForElement(
          _backend.helpers.assertHelper, _globalInferenceResults);

  ir.Procedure get assertTest => kernel.functions[_backend.helpers.assertTest];

  TypeMask get assertTestReturnType =>
      TypeMaskFactory.inferredReturnTypeForElement(
          _backend.helpers.assertTest, _globalInferenceResults);

  ir.Procedure get assertThrow =>
      kernel.functions[_backend.helpers.assertThrow];

  ir.Procedure get setRuntimeTypeInfo =>
      kernel.functions[_backend.helpers.setRuntimeTypeInfo];

  TypeMask get assertThrowReturnType =>
      TypeMaskFactory.inferredReturnTypeForElement(
          _backend.helpers.assertThrow, _globalInferenceResults);

  ir.Procedure get runtimeTypeToString =>
      kernel.functions[_backend.helpers.runtimeTypeToString];

  ir.Procedure get createRuntimeType =>
      kernel.functions[_backend.helpers.createRuntimeType];

  TypeMask get createRuntimeTypeReturnType =>
      TypeMaskFactory.inferredReturnTypeForElement(
          _backend.helpers.createRuntimeType, _globalInferenceResults);

  ir.Class get objectClass =>
      kernel.classes[_compiler.commonElements.objectClass];

  ir.Class get futureClass =>
      kernel.classes[_compiler.commonElements.futureClass];

  TypeMask makeSubtypeOfObject(ClosedWorld closedWorld) =>
      new TypeMask.subclass(_compiler.commonElements.objectClass, closedWorld);

  ir.Procedure get currentIsolate =>
      kernel.functions[_backend.helpers.currentIsolate];

  ir.Procedure get callInIsolate =>
      kernel.functions[_backend.helpers.callInIsolate];

  bool isInForeignLibrary(ir.Member member) =>
      _backend.isForeign(getElement(member));

  native.NativeBehavior getNativeBehavior(ir.Node node) {
    return elements.getNativeData(getNode(node));
  }

  js.Name getNameForJsGetName(ir.Node argument, ConstantValue constant) {
    int index = _extractEnumIndexFromConstantValue(
        constant, _backend.helpers.jsGetNameEnum);
    if (index == null) return null;
    return _backend.namer
        .getNameForJsGetName(getNode(argument), JsGetName.values[index]);
  }

  js.Template getJsBuiltinTemplate(ConstantValue constant) {
    int index = _extractEnumIndexFromConstantValue(
        constant, _backend.helpers.jsBuiltinEnum);
    if (index == null) return null;
    return _backend.emitter.builtinTemplateFor(JsBuiltin.values[index]);
  }

  int _extractEnumIndexFromConstantValue(
      ConstantValue constant, Element classElement) {
    if (constant is ConstructedConstantValue) {
      if (constant.type.element == classElement) {
        assert(constant.fields.length == 1);
        ConstantValue indexConstant = constant.fields.values.single;
        if (indexConstant is IntConstantValue) {
          return indexConstant.primitiveValue;
        }
      }
    }
    return null;
  }

  ResolutionDartType getDartType(ir.DartType type) {
    return _typeConverter.convert(type);
  }

  ResolutionDartType getDartTypeIfValid(ir.DartType type) {
    if (type is ir.InvalidType) return null;
    return _typeConverter.convert(type);
  }

  List<ResolutionDartType> getDartTypes(List<ir.DartType> types) {
    return types.map(getDartType).toList();
  }

  ResolutionInterfaceType getDartTypeOfListLiteral(ir.ListLiteral list) {
    ast.Node node = getNodeOrNull(list);
    if (node != null) return elements.getType(node);
    assertNodeIsSynthetic(list);
    return _compiler.commonElements.listType(getDartType(list.typeArgument));
  }

  ResolutionInterfaceType getDartTypeOfMapLiteral(ir.MapLiteral literal) {
    ast.Node node = getNodeOrNull(literal);
    if (node != null) return elements.getType(node);
    assertNodeIsSynthetic(literal);
    return _compiler.commonElements
        .mapType(getDartType(literal.keyType), getDartType(literal.valueType));
  }

  ResolutionDartType getFunctionReturnType(ir.FunctionNode node) {
    if (node.returnType is ir.InvalidType) return const ResolutionDynamicType();
    return getDartType(node.returnType);
  }

  /// Computes the function type corresponding the signature of [node].
  ResolutionFunctionType getFunctionType(ir.FunctionNode node) {
    ResolutionDartType returnType = getFunctionReturnType(node);
    List<ResolutionDartType> parameterTypes = <ResolutionDartType>[];
    List<ResolutionDartType> optionalParameterTypes = <ResolutionDartType>[];
    for (ir.VariableDeclaration variable in node.positionalParameters) {
      if (parameterTypes.length == node.requiredParameterCount) {
        optionalParameterTypes.add(getDartType(variable.type));
      } else {
        parameterTypes.add(getDartType(variable.type));
      }
    }
    List<String> namedParameters = <String>[];
    List<ResolutionDartType> namedParameterTypes = <ResolutionDartType>[];
    List<ir.VariableDeclaration> sortedNamedParameters =
        node.namedParameters.toList()..sort((a, b) => a.name.compareTo(b.name));
    for (ir.VariableDeclaration variable in sortedNamedParameters) {
      namedParameters.add(variable.name);
      namedParameterTypes.add(getDartType(variable.type));
    }
    return new ResolutionFunctionType.synthesized(returnType, parameterTypes,
        optionalParameterTypes, namedParameters, namedParameterTypes);
  }

  ResolutionInterfaceType getInterfaceType(ir.InterfaceType type) =>
      getDartType(type);

  ResolutionInterfaceType createInterfaceType(
      ir.Class cls, List<ir.DartType> typeArguments) {
    return new ResolutionInterfaceType(
        getClass(cls), getDartTypes(typeArguments));
  }

  /// Converts [annotations] into a list of [ConstantExpression]s.
  List<ConstantExpression> getMetadata(List<ir.Expression> annotations) {
    List<ConstantExpression> metadata = <ConstantExpression>[];
    annotations.forEach((ir.Expression node) {
      ConstantExpression constant = node.accept(new Constantifier(this));
      if (constant == null) {
        throw new UnsupportedError(
            'No constant for ${DebugPrinter.prettyPrint(node)}');
      }
      metadata.add(constant);
    });
    return metadata;
  }

  /// Compute the kind of foreign helper function called by [node], if any.
  ForeignKind getForeignKind(ir.StaticInvocation node) {
    if (isForeignLibrary(node.target.enclosingLibrary)) {
      switch (node.target.name.name) {
        case BackendHelpers.JS:
          return ForeignKind.JS;
        case BackendHelpers.JS_BUILTIN:
          return ForeignKind.JS_BUILTIN;
        case BackendHelpers.JS_EMBEDDED_GLOBAL:
          return ForeignKind.JS_EMBEDDED_GLOBAL;
        case BackendHelpers.JS_INTERCEPTOR_CONSTANT:
          return ForeignKind.JS_INTERCEPTOR_CONSTANT;
      }
    }
    return ForeignKind.NONE;
  }

  /// Return `true` if [node] is the `dart:_foreign_helper` library.
  bool isForeignLibrary(ir.Library node) {
    return node.importUri == BackendHelpers.DART_FOREIGN_HELPER;
  }

  /// Looks up [typeName] for use in the spec-string of a `JS` called.
  // TODO(johnniwinther): Use this in [native.NativeBehavior] instead of calling
  // the `ForeignResolver`.
  // TODO(johnniwinther): Cache the result to avoid redundant lookups?
  native.TypeLookup _typeLookup({bool resolveAsRaw: true}) {
    return (String typeName) {
      ResolutionDartType findIn(Uri uri) {
        LibraryElement library = _compiler.libraryLoader.lookupLibrary(uri);
        if (library != null) {
          Element element = library.find(typeName);
          if (element != null && element.isClass) {
            ClassElement cls = element;
            // TODO(johnniwinther): Align semantics.
            return resolveAsRaw ? cls.rawType : cls.thisType;
          }
        }
        return null;
      }

      ResolutionDartType type = findIn(Uris.dart_core);
      type ??= findIn(BackendHelpers.DART_JS_HELPER);
      type ??= findIn(BackendHelpers.DART_INTERCEPTORS);
      type ??= findIn(BackendHelpers.DART_ISOLATE_HELPER);
      type ??= findIn(Uris.dart_collection);
      type ??= findIn(Uris.dart_html);
      type ??= findIn(Uris.dart_svg);
      type ??= findIn(Uris.dart_web_audio);
      type ??= findIn(Uris.dart_web_gl);
      return type;
    };
  }

  String _getStringArgument(ir.StaticInvocation node, int index) {
    return node.arguments.positional[index].accept(new Stringifier());
  }

  /// Computes the [native.NativeBehavior] for a call to the [JS] function.
  // TODO(johnniwinther): Cache this for later use.
  native.NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node) {
    if (node.arguments.positional.length < 2 ||
        node.arguments.named.isNotEmpty) {
      reporter.reportErrorMessage(
          CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS);
      return new native.NativeBehavior();
    }
    String specString = _getStringArgument(node, 0);
    if (specString == null) {
      reporter.reportErrorMessage(
          CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_FIRST);
      return new native.NativeBehavior();
    }

    String codeString = _getStringArgument(node, 1);
    if (codeString == null) {
      reporter.reportErrorMessage(
          CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_SECOND);
      return new native.NativeBehavior();
    }

    return native.NativeBehavior.ofJsCall(
        specString,
        codeString,
        _typeLookup(resolveAsRaw: true),
        CURRENT_ELEMENT_SPANNABLE,
        reporter,
        _compiler.commonElements);
  }

  /// Computes the [native.NativeBehavior] for a call to the [JS_BUILTIN]
  /// function.
  // TODO(johnniwinther): Cache this for later use.
  native.NativeBehavior getNativeBehaviorForJsBuiltinCall(
      ir.StaticInvocation node) {
    if (node.arguments.positional.length < 1) {
      reporter.internalError(
          CURRENT_ELEMENT_SPANNABLE, "JS builtin expression has no type.");
      return new native.NativeBehavior();
    }
    if (node.arguments.positional.length < 2) {
      reporter.internalError(
          CURRENT_ELEMENT_SPANNABLE, "JS builtin is missing name.");
      return new native.NativeBehavior();
    }
    String specString = _getStringArgument(node, 0);
    if (specString == null) {
      reporter.internalError(
          CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument.");
      return new native.NativeBehavior();
    }
    return native.NativeBehavior.ofJsBuiltinCall(
        specString,
        _typeLookup(resolveAsRaw: true),
        CURRENT_ELEMENT_SPANNABLE,
        reporter,
        _compiler.commonElements);
  }

  /// Computes the [native.NativeBehavior] for a call to the
  /// [JS_EMBEDDED_GLOBAL] function.
  // TODO(johnniwinther): Cache this for later use.
  native.NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall(
      ir.StaticInvocation node) {
    if (node.arguments.positional.length < 1) {
      reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
          "JS embedded global expression has no type.");
      return new native.NativeBehavior();
    }
    if (node.arguments.positional.length < 2) {
      reporter.internalError(
          CURRENT_ELEMENT_SPANNABLE, "JS embedded global is missing name.");
      return new native.NativeBehavior();
    }
    if (node.arguments.positional.length > 2 ||
        node.arguments.named.isNotEmpty) {
      reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
          "JS embedded global has more than 2 arguments.");
      return new native.NativeBehavior();
    }
    String specString = _getStringArgument(node, 0);
    if (specString == null) {
      reporter.internalError(
          CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument.");
      return new native.NativeBehavior();
    }
    return native.NativeBehavior.ofJsEmbeddedGlobalCall(
        specString,
        _typeLookup(resolveAsRaw: true),
        CURRENT_ELEMENT_SPANNABLE,
        reporter,
        _compiler.commonElements);
  }

  /// Computes the [InterfaceType] referenced by a call to the
  /// [JS_INTERCEPTOR_CONSTANT] function, if any.
  InterfaceType getInterfaceTypeForJsInterceptorCall(ir.StaticInvocation node) {
    if (node.arguments.positional.length != 1 ||
        node.arguments.named.isNotEmpty) {
      reporter.reportErrorMessage(CURRENT_ELEMENT_SPANNABLE,
          MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT);
    }
    ir.Node argument = node.arguments.positional.first;
    if (argument is ir.TypeLiteral && argument.type is ir.InterfaceType) {
      return getInterfaceType(argument.type);
    }
    return null;
  }

  /// Returns `true` is [node] has a `@Native(...)` annotation.
  // TODO(johnniwinther): Cache this for later use.
  bool isNativeClass(ir.Class node) {
    for (ir.Expression annotation in node.annotations) {
      if (annotation is ir.ConstructorInvocation) {
        ConstructorElement target = getElement(annotation.target).declaration;
        if (target.enclosingClass ==
            _compiler.commonElements.nativeAnnotationClass) {
          return true;
        }
      }
    }
    return false;
  }

  /// Computes the native behavior for reading the native [field].
  // TODO(johnniwinther): Cache this for later use.
  native.NativeBehavior getNativeBehaviorForFieldLoad(ir.Field field) {
    ResolutionDartType type = getDartType(field.type);
    List<ConstantExpression> metadata = getMetadata(field.annotations);
    return native.NativeBehavior.ofFieldLoad(CURRENT_ELEMENT_SPANNABLE, type,
        metadata, _typeLookup(resolveAsRaw: false), _compiler,
        isJsInterop: false);
  }

  /// Computes the native behavior for writing to the native [field].
  // TODO(johnniwinther): Cache this for later use.
  native.NativeBehavior getNativeBehaviorForFieldStore(ir.Field field) {
    ResolutionDartType type = getDartType(field.type);
    return native.NativeBehavior.ofFieldStore(type, _compiler.resolution);
  }

  /// Computes the native behavior for calling [procedure].
  // TODO(johnniwinther): Cache this for later use.
  native.NativeBehavior getNativeBehaviorForMethod(ir.Procedure procedure) {
    ResolutionDartType type = getFunctionType(procedure.function);
    List<ConstantExpression> metadata = getMetadata(procedure.annotations);
    return native.NativeBehavior.ofMethod(CURRENT_ELEMENT_SPANNABLE, type,
        metadata, _typeLookup(resolveAsRaw: false), _compiler,
        isJsInterop: false);
  }

  MemberEntity getConstructorBodyEntity(ir.Constructor constructor) {
    AstElement element = getElement(constructor);
    MemberEntity constructorBody =
        ConstructorBodyElementX.createFromResolvedAst(element.resolvedAst);
    assert(constructorBody != null);
    return constructorBody;
  }
}

/// Kinds of foreign functions.
enum ForeignKind {
  JS,
  JS_BUILTIN,
  JS_EMBEDDED_GLOBAL,
  JS_INTERCEPTOR_CONSTANT,
  NONE,
}

/// Visitor that converts kernel dart types into [ResolutionDartType].
class DartTypeConverter extends ir.DartTypeVisitor<ResolutionDartType> {
  final KernelAstAdapter astAdapter;
  bool topLevel = true;

  DartTypeConverter(this.astAdapter);

  ResolutionDartType convert(ir.DartType type) {
    topLevel = true;
    return type.accept(this);
  }

  /// Visit a inner type.
  ResolutionDartType visitType(ir.DartType type) {
    topLevel = false;
    return type.accept(this);
  }

  List<ResolutionDartType> visitTypes(List<ir.DartType> types) {
    topLevel = false;
    return new List.generate(
        types.length, (int index) => types[index].accept(this));
  }

  @override
  ResolutionDartType visitTypeParameterType(ir.TypeParameterType node) {
    if (node.parameter.parent is ir.Class) {
      ir.Class cls = node.parameter.parent;
      int index = cls.typeParameters.indexOf(node.parameter);
      ClassElement classElement = astAdapter.getElement(cls);
      return classElement.typeVariables[index];
    } else if (node.parameter.parent is ir.FunctionNode) {
      ir.FunctionNode func = node.parameter.parent;
      int index = func.typeParameters.indexOf(node.parameter);
      Element element = astAdapter.getElement(func);
      if (element.isConstructor) {
        ClassElement classElement = element.enclosingClass;
        return classElement.typeVariables[index];
      } else {
        GenericElement genericElement = element;
        return genericElement.typeVariables[index];
      }
    }
    throw new UnsupportedError('Unsupported type parameter type node $node.');
  }

  @override
  ResolutionDartType visitFunctionType(ir.FunctionType node) {
    return new ResolutionFunctionType.synthesized(
        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());
  }

  @override
  ResolutionDartType visitInterfaceType(ir.InterfaceType node) {
    ClassElement cls = astAdapter.getElement(node.classNode);
    return new ResolutionInterfaceType(cls, visitTypes(node.typeArguments));
  }

  @override
  ResolutionDartType visitVoidType(ir.VoidType node) {
    return const ResolutionVoidType();
  }

  @override
  ResolutionDartType visitDynamicType(ir.DynamicType node) {
    return const ResolutionDynamicType();
  }

  @override
  ResolutionDartType visitInvalidType(ir.InvalidType node) {
    if (topLevel) {
      throw new UnimplementedError(
          "Outermost invalid types not currently supported");
    }
    // Nested invalid types are treated as `dynamic`.
    return const ResolutionDynamicType();
  }
}

/// Visitor that converts string literals and concatenations of string literals
/// into the string value.
class Stringifier extends ir.ExpressionVisitor<String> {
  @override
  String visitStringLiteral(ir.StringLiteral node) => node.value;

  @override
  String visitStringConcatenation(ir.StringConcatenation node) {
    StringBuffer sb = new StringBuffer();
    for (ir.Expression expression in node.expressions) {
      String value = expression.accept(this);
      if (value == null) return null;
      sb.write(value);
    }
    return sb.toString();
  }
}

/// Visitor that converts a kernel constant expression into a
/// [ConstantExpression].
class Constantifier extends ir.ExpressionVisitor<ConstantExpression> {
  final KernelAstAdapter astAdapter;

  Constantifier(this.astAdapter);

  @override
  ConstantExpression visitConstructorInvocation(ir.ConstructorInvocation node) {
    ConstructorElement constructor =
        astAdapter.getElement(node.target).declaration;
    List<ResolutionDartType> typeArguments = <ResolutionDartType>[];
    for (ir.DartType type in node.arguments.types) {
      typeArguments.add(astAdapter.getDartType(type));
    }
    List<ConstantExpression> arguments = <ConstantExpression>[];
    List<String> argumentNames = <String>[];
    for (ir.Expression argument in node.arguments.positional) {
      ConstantExpression constant = argument.accept(this);
      if (constant == null) return null;
      arguments.add(constant);
    }
    for (ir.NamedExpression argument in node.arguments.named) {
      argumentNames.add(argument.name);
      ConstantExpression constant = argument.value.accept(this);
      if (constant == null) return null;
      arguments.add(constant);
    }
    return new ConstructedConstantExpression(
        constructor.enclosingClass.thisType.createInstantiation(typeArguments),
        constructor,
        new CallStructure(
            node.arguments.positional.length + argumentNames.length,
            argumentNames),
        arguments);
  }

  @override
  ConstantExpression visitStaticGet(ir.StaticGet node) {
    Element element = astAdapter.getMember(node.target);
    if (element.isField) {
      return new VariableConstantExpression(element);
    }
    astAdapter.reporter.internalError(
        CURRENT_ELEMENT_SPANNABLE, "Unexpected constant target: $element.");
    return null;
  }

  @override
  ConstantExpression visitStringLiteral(ir.StringLiteral node) {
    return new StringConstantExpression(node.value);
  }
}

class KernelJumpTarget extends JumpTarget {
  static int index = 0;

  /// Pointer to the actual executable statements that a jump target refers to.
  /// If this jump target was not initially constructed with a LabeledStatement,
  /// this value is identical to originalStatement.
  // TODO(efortuna): In an ideal world the Node should be some common
  // interface we create for both ir.Statements and ir.SwitchCase (the
  // ContinueSwitchStatement's target is a SwitchCase) rather than general
  // Node. Talking to Asger about this.
  ir.Node targetStatement;

  /// The original statement used to construct this jump target.
  /// If this jump target was not initially constructed with a LabeledStatement,
  /// this value is identical to targetStatement.
  ir.Node originalStatement;

  @override
  bool isBreakTarget = false;

  @override
  bool isContinueTarget = false;

  KernelJumpTarget(this.targetStatement, KernelAstAdapter adapter,
      {bool makeContinueLabel = false}) {
    originalStatement = targetStatement;
    this.labels = <LabelDefinition>[];
    if (targetStatement is ir.WhileStatement ||
        targetStatement is ir.DoStatement ||
        targetStatement is ir.ForStatement ||
        targetStatement is ir.ForInStatement) {
      // Currently these labels are set at resolution on the element itself.
      // Once that gets updated, this logic can change downstream.
      JumpTarget target = adapter.elements
          .getTargetDefinition(adapter.getNode(targetStatement));
      if (target != null) {
        labels.addAll(target.labels);
        isBreakTarget = target.isBreakTarget;
        isContinueTarget = target.isContinueTarget;
      }
    } else if (targetStatement is ir.LabeledStatement) {
      targetStatement = (targetStatement as ir.LabeledStatement).body;
      labels.add(
          new LabelDefinitionX(null, 'L${index++}', this)..setBreakTarget());
      isBreakTarget = true;
    }

    if (makeContinueLabel) {
      labels.add(
          new LabelDefinitionX(null, 'L${index++}', this)..setContinueTarget());
      isContinueTarget = true;
    }
  }

  @override
  LabelDefinition addLabel(ast.Label label, String labelName) {
    LabelDefinition result = new LabelDefinitionX(label, labelName, this);
    labels.add(result);
    return result;
  }

  @override
  ExecutableElement get executableContext => null;

  @override
  bool get isSwitch => targetStatement is ir.SwitchStatement;

  @override
  bool get isTarget => isBreakTarget || isContinueTarget;

  @override
  List<LabelDefinition> labels;

  @override
  String get name => 'target';

  // TODO(efortuna): In the original version, this nesting level is specified at
  // jump target construction time, by the resolver. Because these are
  // instantiated later, we don't have that information. When we move fully over
  // to the kernel model, we can pass the nesting level in KernelJumpTarget's
  // constructor.
  @override
  int get nestingLevel => 0;

  @override
  ast.Node get statement => null;

  String toString() => 'Target:$targetStatement';
}

/// Special [JumpHandler] implementation used to handle continue statements
/// targeting switch cases.
class KernelSwitchCaseJumpHandler extends SwitchCaseJumpHandler {
  KernelSwitchCaseJumpHandler(GraphBuilder builder, JumpTarget target,
      ir.SwitchStatement switchStatement, KernelAstAdapter astAdapter)
      : super(builder, target) {
    // The switch case indices must match those computed in
    // [KernelSsaBuilder.buildSwitchCaseConstants].
    // Switch indices are 1-based so we can bypass the synthetic loop when no
    // cases match simply by branching on the index (which defaults to null).
    // TODO
    int switchIndex = 1;
    for (ir.SwitchCase switchCase in switchStatement.cases) {
      JumpTarget continueTarget =
          astAdapter.getJumpTarget(switchCase, isContinueTarget: true);
      assert(continueTarget is KernelJumpTarget);
      targetIndexMap[continueTarget] = switchIndex;
      assert(builder.jumpTargets[continueTarget] == null);
      builder.jumpTargets[continueTarget] = this;
      switchIndex++;
    }
  }
}
