// Copyright (c) 2015, 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.

library dart2js.resolution.constructors;

import '../common.dart';
import '../common/resolution.dart' show Feature;
import '../compiler.dart' show Compiler;
import '../constants/constructors.dart'
    show
        GenerativeConstantConstructor,
        RedirectingGenerativeConstantConstructor;
import '../constants/expressions.dart';
import '../dart_types.dart';
import '../elements/elements.dart';
import '../elements/modelx.dart'
    show
        ConstructorElementX,
        ErroneousConstructorElementX,
        ErroneousElementX,
        ErroneousFieldElementX,
        FieldElementX,
        InitializingFormalElementX,
        ParameterElementX;
import '../tree/tree.dart';
import '../util/util.dart' show Link;
import '../universe/call_structure.dart' show CallStructure;
import '../universe/use.dart' show StaticUse;

import 'members.dart' show lookupInScope, ResolverVisitor;
import 'registry.dart' show ResolutionRegistry;
import 'resolution_common.dart' show CommonResolverVisitor;
import 'resolution_result.dart';

class InitializerResolver {
  final ResolverVisitor visitor;
  final ConstructorElementX constructor;
  final FunctionExpression functionNode;
  final Map<FieldElement, Node> initialized = <FieldElement, Node>{};
  final Map<FieldElement, ConstantExpression> fieldInitializers =
      <FieldElement, ConstantExpression>{};
  Link<Node> initializers;
  bool hasSuper = false;
  bool isValidAsConstant = true;

  bool get isConst => constructor.isConst;

  InitializerResolver(this.visitor, this.constructor, this.functionNode);

  ResolutionRegistry get registry => visitor.registry;

  DiagnosticReporter get reporter => visitor.reporter;

  bool isFieldInitializer(SendSet node) {
    if (node.selector.asIdentifier() == null) return false;
    if (node.receiver == null) return true;
    if (node.receiver.asIdentifier() == null) return false;
    return node.receiver.asIdentifier().isThis();
  }

  reportDuplicateInitializerError(
      Element field, Node init, Spannable existing) {
    reporter.reportError(
        reporter.createMessage(
            init, MessageKind.DUPLICATE_INITIALIZER, {'fieldName': field.name}),
        <DiagnosticMessage>[
          reporter.createMessage(existing, MessageKind.ALREADY_INITIALIZED,
              {'fieldName': field.name}),
        ]);
    isValidAsConstant = false;
  }

  void checkForDuplicateInitializers(FieldElementX field, Node init) {
    // [field] can be null if it could not be resolved.
    if (field == null) return;
    if (initialized.containsKey(field)) {
      reportDuplicateInitializerError(field, init, initialized[field]);
    } else if (field.isFinal) {
      field.parseNode(visitor.resolution.parsingContext);
      Expression initializer = field.initializer;
      if (initializer != null) {
        reportDuplicateInitializerError(
            field,
            init,
            reporter.withCurrentElement(
                field, () => reporter.spanFromSpannable(initializer)));
      }
    }
    initialized[field] = init;
  }

  void resolveFieldInitializer(SendSet init) {
    // init is of the form [this.]field = value.
    final Node selector = init.selector;
    final String name = selector.asIdentifier().source;
    // Lookup target field.
    Element target;
    FieldElement field;
    if (isFieldInitializer(init)) {
      target = constructor.enclosingClass.lookupLocalMember(name);
      if (target == null) {
        reporter.reportErrorMessage(
            selector, MessageKind.CANNOT_RESOLVE, {'name': name});
        target = new ErroneousFieldElementX(
            selector.asIdentifier(), constructor.enclosingClass);
      } else if (target.kind != ElementKind.FIELD) {
        reporter.reportErrorMessage(
            selector, MessageKind.NOT_A_FIELD, {'fieldName': name});
        target = new ErroneousFieldElementX(
            selector.asIdentifier(), constructor.enclosingClass);
      } else if (!target.isInstanceMember) {
        reporter.reportErrorMessage(
            selector, MessageKind.INIT_STATIC_FIELD, {'fieldName': name});
      } else {
        field = target;
      }
    } else {
      reporter.reportErrorMessage(
          init, MessageKind.INVALID_RECEIVER_IN_INITIALIZER);
    }
    if (target != null) {
      registry.useElement(init, target);
      checkForDuplicateInitializers(target, init);
    }
    if (field != null) {
      registry.registerStaticUse(new StaticUse.fieldInit(field));
    }
    // Resolve initializing value.
    ResolutionResult result = visitor.visitInStaticContext(init.arguments.head,
        inConstantInitializer: isConst);
    if (isConst) {
      if (result.isConstant && field != null) {
        // TODO(johnniwinther): Report error if `result.constant` is `null`.
        fieldInitializers[field] = result.constant;
      } else {
        isValidAsConstant = false;
      }
    }
  }

  InterfaceType getSuperOrThisLookupTarget(Node diagnosticNode,
      {bool isSuperCall}) {
    if (isSuperCall) {
      // Calculate correct lookup target and constructor name.
      if (constructor.enclosingClass.isObject) {
        reporter.reportErrorMessage(
            diagnosticNode, MessageKind.SUPER_INITIALIZER_IN_OBJECT);
        isValidAsConstant = false;
      } else {
        return constructor.enclosingClass.supertype;
      }
    }
    return constructor.enclosingClass.thisType;
  }

  ResolutionResult resolveSuperOrThisForSend(Send node) {
    // Resolve the selector and the arguments.
    ArgumentsResult argumentsResult = visitor.inStaticContext(() {
      // TODO(johnniwinther): Remove this when [SendStructure] is used directly.
      visitor.resolveSelector(node, null);
      return visitor.resolveArguments(node.argumentsNode);
    }, inConstantInitializer: isConst);

    bool isSuperCall = Initializers.isSuperConstructorCall(node);
    InterfaceType targetType =
        getSuperOrThisLookupTarget(node, isSuperCall: isSuperCall);
    ClassElement lookupTarget = targetType.element;
    String constructorName =
        visitor.getRedirectingThisOrSuperConstructorName(node).text;
    ConstructorElement foundConstructor =
        findConstructor(constructor.library, lookupTarget, constructorName);

    final String className = lookupTarget.name;
    CallStructure callStructure = argumentsResult.callStructure;
    ConstructorElement calledConstructor = verifyThatConstructorMatchesCall(
        node, foundConstructor, callStructure, className,
        constructorName: constructorName,
        isThisCall: !isSuperCall,
        isImplicitSuperCall: false);
    // TODO(johnniwinther): Remove this when information is pulled from an
    // [InitializerStructure].
    registry.useElement(node, calledConstructor);
    if (!calledConstructor.isError) {
      registry.registerStaticUse(new StaticUse.superConstructorInvoke(
          calledConstructor, callStructure));
    }
    if (isConst) {
      if (isValidAsConstant &&
          calledConstructor.isConst &&
          argumentsResult.isValidAsConstant) {
        List<ConstantExpression> arguments = argumentsResult.constantArguments;
        return new ConstantResult(
            node,
            new ConstructedConstantExpression(
                targetType, calledConstructor, callStructure, arguments),
            element: calledConstructor);
      } else {
        isValidAsConstant = false;
      }
    }
    return new ResolutionResult.forElement(calledConstructor);
  }

  ConstructedConstantExpression resolveImplicitSuperConstructorSend() {
    // If the class has a super resolve the implicit super call.
    ClassElement classElement = constructor.enclosingClass;
    ClassElement superClass = classElement.superclass;
    if (!classElement.isObject) {
      assert(superClass != null);
      assert(superClass.isResolved);

      InterfaceType targetType =
          getSuperOrThisLookupTarget(functionNode, isSuperCall: true);
      ClassElement lookupTarget = targetType.element;
      ConstructorElement calledConstructor =
          findConstructor(constructor.library, lookupTarget, '');

      final String className = lookupTarget.name;
      CallStructure callStructure = CallStructure.NO_ARGS;
      ConstructorElement result = verifyThatConstructorMatchesCall(
          functionNode, calledConstructor, callStructure, className,
          isImplicitSuperCall: true);
      if (!result.isError) {
        registry.registerStaticUse(
            new StaticUse.constructorInvoke(calledConstructor, callStructure));
      }

      if (isConst && isValidAsConstant) {
        return new ConstructedConstantExpression(targetType, result,
            CallStructure.NO_ARGS, const <ConstantExpression>[]);
      }
    }
    return null;
  }

  ConstructorElement reportAndCreateErroneousConstructor(
      Spannable diagnosticNode, String name, MessageKind kind, Map arguments) {
    isValidAsConstant = false;
    reporter.reportErrorMessage(diagnosticNode, kind, arguments);
    return new ErroneousConstructorElementX(
        kind, arguments, name, visitor.currentClass);
  }

  /// Checks that [lookedupConstructor] is valid as a target for the super/this
  /// constructor call using with the given [callStructure].
  ///
  /// If [lookedupConstructor] is valid it is returned, otherwise an error is
  /// reported and an [ErroneousConstructorElement] is returned.
  ConstructorElement verifyThatConstructorMatchesCall(
      Node node,
      ConstructorElement lookedupConstructor,
      CallStructure callStructure,
      String className,
      {String constructorName: '',
      bool isImplicitSuperCall: false,
      bool isThisCall: false}) {
    Element result = lookedupConstructor;
    if (lookedupConstructor == null) {
      String fullConstructorName =
          Elements.constructorNameForDiagnostics(className, constructorName);
      MessageKind kind = isImplicitSuperCall
          ? MessageKind.CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT
          : MessageKind.CANNOT_RESOLVE_CONSTRUCTOR;
      result = reportAndCreateErroneousConstructor(node, constructorName, kind,
          {'constructorName': fullConstructorName});
    } else if (!lookedupConstructor.isGenerativeConstructor) {
      MessageKind kind = isThisCall
          ? MessageKind.THIS_CALL_TO_FACTORY
          : MessageKind.SUPER_CALL_TO_FACTORY;
      result =
          reportAndCreateErroneousConstructor(node, constructorName, kind, {});
    } else {
      lookedupConstructor.computeType(visitor.resolution);
      if (!callStructure
          .signatureApplies(lookedupConstructor.functionSignature)) {
        MessageKind kind = isImplicitSuperCall
            ? MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT
            : MessageKind.NO_MATCHING_CONSTRUCTOR;
        result = reportAndCreateErroneousConstructor(
            node, constructorName, kind, {});
      } else if (constructor.isConst && !lookedupConstructor.isConst) {
        MessageKind kind = isImplicitSuperCall
            ? MessageKind.CONST_CALLS_NON_CONST_FOR_IMPLICIT
            : MessageKind.CONST_CALLS_NON_CONST;
        result = reportAndCreateErroneousConstructor(
            node, constructorName, kind, {});
      }
    }
    return result;
  }

  /**
   * Resolve all initializers of this constructor. In the case of a redirecting
   * constructor, the resolved constructor's function element is returned.
   */
  ConstructorElement resolveInitializers() {
    Map<dynamic /*String|int*/, ConstantExpression> defaultValues =
        <dynamic /*String|int*/, ConstantExpression>{};
    ConstructedConstantExpression constructorInvocation;
    // Keep track of all "this.param" parameters specified for constructor so
    // that we can ensure that fields are initialized only once.
    FunctionSignature functionParameters = constructor.functionSignature;
    functionParameters.forEachParameter((ParameterElementX element) {
      if (isConst) {
        if (element.isOptional) {
          if (element.constantCache == null) {
            // TODO(johnniwinther): Remove this when all constant expressions
            // can be computed during resolution.
            isValidAsConstant = false;
          } else {
            ConstantExpression defaultValue = element.constant;
            if (defaultValue != null) {
              if (element.isNamed) {
                defaultValues[element.name] = defaultValue;
              } else {
                int index =
                    element.functionDeclaration.parameters.indexOf(element);
                defaultValues[index] = defaultValue;
              }
            } else {
              isValidAsConstant = false;
            }
          }
        }
      }
      if (element.isInitializingFormal) {
        InitializingFormalElementX initializingFormal = element;
        FieldElement field = initializingFormal.fieldElement;
        checkForDuplicateInitializers(field, element.initializer);
        if (isConst) {
          if (element.isNamed) {
            fieldInitializers[field] = new NamedArgumentReference(element.name);
          } else {
            int index = element.functionDeclaration.parameters.indexOf(element);
            fieldInitializers[field] = new PositionalArgumentReference(index);
          }
        } else {
          isValidAsConstant = false;
        }
      }
    });

    if (functionNode.initializers == null) {
      initializers = const Link<Node>();
    } else {
      initializers = functionNode.initializers.nodes;
    }
    bool resolvedSuper = false;
    for (Link<Node> link = initializers; !link.isEmpty; link = link.tail) {
      if (link.head.asSendSet() != null) {
        final SendSet init = link.head.asSendSet();
        resolveFieldInitializer(init);
      } else if (link.head.asSend() != null) {
        final Send call = link.head.asSend();
        if (call.argumentsNode == null) {
          reporter.reportErrorMessage(
              link.head, MessageKind.INVALID_INITIALIZER);
          continue;
        }
        if (Initializers.isSuperConstructorCall(call)) {
          if (resolvedSuper) {
            reporter.reportErrorMessage(
                call, MessageKind.DUPLICATE_SUPER_INITIALIZER);
          }
          ResolutionResult result = resolveSuperOrThisForSend(call);
          if (isConst) {
            if (result.isConstant) {
              constructorInvocation = result.constant;
            } else {
              isValidAsConstant = false;
            }
          }
          resolvedSuper = true;
        } else if (Initializers.isConstructorRedirect(call)) {
          // Check that there is no body (Language specification 7.5.1).  If the
          // constructor is also const, we already reported an error in
          // [resolveMethodElement].
          if (functionNode.hasBody && !constructor.isConst) {
            reporter.reportErrorMessage(
                functionNode, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_BODY);
          }
          // Check that there are no other initializers.
          if (!initializers.tail.isEmpty) {
            reporter.reportErrorMessage(
                call, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER);
          } else {
            constructor.isRedirectingGenerative = true;
          }
          // Check that there are no field initializing parameters.
          FunctionSignature signature = constructor.functionSignature;
          signature.forEachParameter((ParameterElement parameter) {
            if (parameter.isInitializingFormal) {
              Node node = parameter.node;
              reporter.reportErrorMessage(
                  node, MessageKind.INITIALIZING_FORMAL_NOT_ALLOWED);
              isValidAsConstant = false;
            }
          });
          ResolutionResult result = resolveSuperOrThisForSend(call);
          if (isConst) {
            if (result.isConstant) {
              constructorInvocation = result.constant;
            } else {
              isValidAsConstant = false;
            }
            if (isConst && isValidAsConstant) {
              constructor.constantConstructor =
                  new RedirectingGenerativeConstantConstructor(
                      defaultValues, constructorInvocation);
            }
          }
          return result.element;
        } else {
          reporter.reportErrorMessage(
              call, MessageKind.CONSTRUCTOR_CALL_EXPECTED);
          return null;
        }
      } else {
        reporter.reportErrorMessage(link.head, MessageKind.INVALID_INITIALIZER);
      }
    }
    if (!resolvedSuper) {
      constructorInvocation = resolveImplicitSuperConstructorSend();
    }
    if (isConst && isValidAsConstant) {
      constructor.constantConstructor = new GenerativeConstantConstructor(
          constructor.enclosingClass.thisType,
          defaultValues,
          fieldInitializers,
          constructorInvocation);
    }
    return null; // If there was no redirection always return null.
  }
}

class ConstructorResolver extends CommonResolverVisitor<ConstructorResult> {
  final ResolverVisitor resolver;
  final bool inConstContext;

  ConstructorResolver(Compiler compiler, this.resolver,
      {bool this.inConstContext: false})
      : super(compiler);

  ResolutionRegistry get registry => resolver.registry;

  visitNode(Node node) {
    throw 'not supported';
  }

  ConstructorResult reportAndCreateErroneousConstructorElement(
      Spannable diagnosticNode,
      ConstructorResultKind resultKind,
      DartType type,
      Element enclosing,
      String name,
      MessageKind kind,
      Map arguments,
      {bool isError: false,
      bool missingConstructor: false,
      List<DiagnosticMessage> infos: const <DiagnosticMessage>[]}) {
    if (missingConstructor) {
      registry.registerFeature(Feature.THROW_NO_SUCH_METHOD);
    } else {
      registry.registerFeature(Feature.THROW_RUNTIME_ERROR);
    }
    DiagnosticMessage message =
        reporter.createMessage(diagnosticNode, kind, arguments);
    if (isError || inConstContext) {
      reporter.reportError(message, infos);
    } else {
      reporter.reportWarning(message, infos);
    }
    ErroneousElement error =
        new ErroneousConstructorElementX(kind, arguments, name, enclosing);
    if (type == null) {
      type = new MalformedType(error, null);
    }
    return new ConstructorResult.forError(resultKind, error, type);
  }

  ConstructorResult resolveConstructor(PrefixElement prefix, InterfaceType type,
      Node diagnosticNode, String constructorName) {
    ClassElement cls = type.element;
    cls.ensureResolved(resolution);
    ConstructorElement constructor = findConstructor(
        resolver.enclosingElement.library, cls, constructorName);
    if (constructor == null) {
      MessageKind kind = constructorName.isEmpty
          ? MessageKind.CANNOT_FIND_UNNAMED_CONSTRUCTOR
          : MessageKind.CANNOT_FIND_CONSTRUCTOR;
      return reportAndCreateErroneousConstructorElement(
          diagnosticNode,
          ConstructorResultKind.UNRESOLVED_CONSTRUCTOR,
          type,
          cls,
          constructorName,
          kind,
          {'className': cls.name, 'constructorName': constructorName},
          missingConstructor: true);
    } else if (inConstContext && !constructor.isConst) {
      reporter.reportErrorMessage(
          diagnosticNode, MessageKind.CONSTRUCTOR_IS_NOT_CONST);
      return new ConstructorResult(
          ConstructorResultKind.NON_CONSTANT, prefix, constructor, type);
    } else {
      if (cls.isEnumClass && resolver.currentClass != cls) {
        return reportAndCreateErroneousConstructorElement(
            diagnosticNode,
            ConstructorResultKind.INVALID_TYPE,
            type,
            cls,
            constructorName,
            MessageKind.CANNOT_INSTANTIATE_ENUM,
            {'enumName': cls.name},
            isError: true);
      }
      if (constructor.isGenerativeConstructor) {
        if (cls.isAbstract) {
          reporter.reportWarningMessage(
              diagnosticNode, MessageKind.ABSTRACT_CLASS_INSTANTIATION);
          registry.registerFeature(Feature.ABSTRACT_CLASS_INSTANTIATION);
          return new ConstructorResult(
              ConstructorResultKind.ABSTRACT, prefix, constructor, type);
        } else {
          return new ConstructorResult(
              ConstructorResultKind.GENERATIVE, prefix, constructor, type);
        }
      } else {
        assert(invariant(diagnosticNode, constructor.isFactoryConstructor,
            message: "Unexpected constructor $constructor."));
        return new ConstructorResult(
            ConstructorResultKind.FACTORY, prefix, constructor, type);
      }
    }
  }

  ConstructorResult visitNewExpression(NewExpression node) {
    Node selector = node.send.selector;
    ConstructorResult result = visit(selector);
    assert(invariant(selector, result != null,
        message: 'No result returned for $selector.'));
    return finishConstructorReference(result, node.send.selector, node);
  }

  /// Finishes resolution of a constructor reference and records the
  /// type of the constructed instance on [expression].
  ConstructorResult finishConstructorReference(
      ConstructorResult result, Node diagnosticNode, Node expression) {
    assert(invariant(diagnosticNode, result != null,
        message: 'No result returned for $diagnosticNode.'));

    if (result.kind != null) {
      resolver.registry.setType(expression, result.type);
      return result;
    }

    // Find the unnamed constructor if the reference resolved to a
    // class.
    if (result.type != null) {
      // The unnamed constructor may not exist, so [e] may become unresolved.
      result =
          resolveConstructor(result.prefix, result.type, diagnosticNode, '');
    } else {
      Element element = result.element;
      if (element.isMalformed) {
        result = constructorResultForErroneous(diagnosticNode, element);
      } else {
        result = reportAndCreateErroneousConstructorElement(
            diagnosticNode,
            ConstructorResultKind.INVALID_TYPE,
            null,
            element,
            element.name,
            MessageKind.NOT_A_TYPE,
            {'node': diagnosticNode});
      }
    }
    resolver.registry.setType(expression, result.type);
    return result;
  }

  ConstructorResult visitTypeAnnotation(TypeAnnotation node) {
    // This is not really resolving a type-annotation, but the name of the
    // constructor. Therefore we allow deferred types.
    DartType type = resolver.resolveTypeAnnotation(node,
        malformedIsError: inConstContext, deferredIsMalformed: false);
    Send send = node.typeName.asSend();
    PrefixElement prefix;
    if (send != null) {
      // The type name is of the form [: prefix . identifier :].
      String name = send.receiver.asIdentifier().source;
      Element element = lookupInScope(reporter, send, resolver.scope, name);
      if (element != null && element.isPrefix) {
        prefix = element;
      }
    }
    return constructorResultForType(node, type, prefix: prefix);
  }

  ConstructorResult visitSend(Send node) {
    ConstructorResult receiver = visit(node.receiver);
    assert(invariant(node.receiver, receiver != null,
        message: 'No result returned for $node.receiver.'));
    if (receiver.kind != null) {
      assert(invariant(node, receiver.element.isMalformed,
          message: "Unexpected prefix result: $receiver."));
      // We have already found an error.
      return receiver;
    }

    Identifier name = node.selector.asIdentifier();
    if (name == null) {
      reporter.internalError(node.selector, 'unexpected node');
    }

    if (receiver.type != null) {
      if (receiver.type.isInterfaceType) {
        return resolveConstructor(
            receiver.prefix, receiver.type, name, name.source);
      } else {
        // TODO(johnniwinther): Update the message for the different types.
        return reportAndCreateErroneousConstructorElement(
            name,
            ConstructorResultKind.INVALID_TYPE,
            null,
            resolver.enclosingElement,
            name.source,
            MessageKind.NOT_A_TYPE,
            {'node': name});
      }
    } else if (receiver.element.isPrefix) {
      PrefixElement prefix = receiver.element;
      Element member = prefix.lookupLocalMember(name.source);
      return constructorResultForElement(node, name.source, member,
          prefix: prefix);
    } else {
      return reporter.internalError(
          node.receiver, 'unexpected receiver $receiver');
    }
  }

  ConstructorResult visitIdentifier(Identifier node) {
    String name = node.source;
    Element element = lookupInScope(reporter, node, resolver.scope, name);
    registry.useElement(node, element);
    return constructorResultForElement(node, name, element);
  }

  /// Assumed to be called by [resolveRedirectingFactory].
  ConstructorResult visitRedirectingFactoryBody(RedirectingFactoryBody node) {
    Node constructorReference = node.constructorReference;
    return finishConstructorReference(
        visit(constructorReference), constructorReference, node);
  }

  ConstructorResult constructorResultForElement(
      Node node, String name, Element element,
      {PrefixElement prefix}) {
    element = Elements.unwrap(element, reporter, node);
    if (element == null) {
      return reportAndCreateErroneousConstructorElement(
          node,
          ConstructorResultKind.INVALID_TYPE,
          null,
          resolver.enclosingElement,
          name,
          MessageKind.CANNOT_RESOLVE,
          {'name': name});
    } else if (element.isAmbiguous) {
      AmbiguousElement ambiguous = element;
      return reportAndCreateErroneousConstructorElement(
          node,
          ConstructorResultKind.INVALID_TYPE,
          null,
          resolver.enclosingElement,
          name,
          ambiguous.messageKind,
          ambiguous.messageArguments,
          infos: ambiguous.computeInfos(resolver.enclosingElement, reporter));
    } else if (element.isMalformed) {
      return constructorResultForErroneous(node, element);
    } else if (element.isClass) {
      ClassElement cls = element;
      cls.computeType(resolution);
      return constructorResultForType(node, cls.rawType, prefix: prefix);
    } else if (element.isPrefix) {
      return new ConstructorResult.forPrefix(element);
    } else if (element.isTypedef) {
      TypedefElement typdef = element;
      typdef.ensureResolved(resolution);
      return constructorResultForType(node, typdef.rawType);
    } else if (element.isTypeVariable) {
      TypeVariableElement typeVariableElement = element;
      return constructorResultForType(node, typeVariableElement.type);
    } else {
      return reportAndCreateErroneousConstructorElement(
          node,
          ConstructorResultKind.INVALID_TYPE,
          null,
          resolver.enclosingElement,
          name,
          MessageKind.NOT_A_TYPE,
          {'node': name});
    }
  }

  ConstructorResult constructorResultForErroneous(Node node, Element error) {
    if (error is! ErroneousElementX) {
      // Parser error. The error has already been reported.
      error = new ErroneousConstructorElementX(
          MessageKind.NOT_A_TYPE, {'node': node}, error.name, error);
      registry.registerFeature(Feature.THROW_RUNTIME_ERROR);
    }
    return new ConstructorResult.forError(ConstructorResultKind.INVALID_TYPE,
        error, new MalformedType(error, null));
  }

  ConstructorResult constructorResultForType(Node node, DartType type,
      {PrefixElement prefix}) {
    String name = type.name;
    if (type.isMalformed) {
      return new ConstructorResult.forError(
          ConstructorResultKind.INVALID_TYPE, type.element, type);
    } else if (type.isInterfaceType) {
      return new ConstructorResult.forType(prefix, type);
    } else if (type.isTypedef) {
      return reportAndCreateErroneousConstructorElement(
          node,
          ConstructorResultKind.INVALID_TYPE,
          type,
          resolver.enclosingElement,
          name,
          MessageKind.CANNOT_INSTANTIATE_TYPEDEF,
          {'typedefName': name});
    } else if (type.isTypeVariable) {
      return reportAndCreateErroneousConstructorElement(
          node,
          ConstructorResultKind.INVALID_TYPE,
          type,
          resolver.enclosingElement,
          name,
          MessageKind.CANNOT_INSTANTIATE_TYPE_VARIABLE,
          {'typeVariableName': name});
    }
    return reporter.internalError(node, "Unexpected constructor type $type");
  }
}

/// The kind of constructor found by the [ConstructorResolver].
enum ConstructorResultKind {
  /// A generative or redirecting generative constructor.
  GENERATIVE,

  /// A factory or redirecting factory constructor.
  FACTORY,

  /// A generative or redirecting generative constructor on an abstract class.
  ABSTRACT,

  /// No constructor was found because the type was invalid, for instance
  /// unresolved, an enum class, a type variable, a typedef or a non-type.
  INVALID_TYPE,

  /// No constructor of the sought name was found on the class.
  UNRESOLVED_CONSTRUCTOR,

  /// A non-constant constructor was found for a const constructor invocation.
  NON_CONSTANT,
}

/// The (partial) result of the resolution of a new expression used in
/// [ConstructorResolver].
class ConstructorResult {
  /// The prefix used to access the constructor. For instance `prefix` in `new
  /// prefix.Class.constructorName()`.
  final PrefixElement prefix;

  /// The kind of the found constructor.
  final ConstructorResultKind kind;

  /// The currently found element. Since [ConstructorResult] is used for partial
  /// results, this might be a [PrefixElement], a [ClassElement], a
  /// [ConstructorElement] or in the negative cases an [ErroneousElement].
  final Element element;

  /// The type of the new expression. For instance `Foo<String>` in
  /// `new prefix.Foo<String>.constructorName()`.
  final DartType type;

  /// Creates a fully resolved constructor access where [element] is resolved
  /// to a constructor and [type] to an interface type.
  ConstructorResult(this.kind, this.prefix, ConstructorElement this.element,
      InterfaceType this.type);

  /// Creates a fully resolved constructor access where [element] is an
  /// [ErroneousElement].
  // TODO(johnniwinther): Do we still need the prefix for cases like
  // `new deferred.Class.unresolvedConstructor()` ?
  ConstructorResult.forError(
      this.kind, ErroneousElement this.element, this.type)
      : prefix = null;

  /// Creates a constructor access that is partially resolved to a prefix. For
  /// instance `prefix` of `new prefix.Class()`.
  ConstructorResult.forPrefix(this.element)
      : prefix = null,
        kind = null,
        type = null;

  /// Creates a constructor access that is partially resolved to a type. For
  /// instance `Foo<String>` of `new Foo<String>.constructorName()`.
  ConstructorResult.forType(this.prefix, this.type)
      : kind = null,
        element = null;

  bool get isDeferred => prefix != null && prefix.isDeferred;

  String toString() {
    StringBuffer sb = new StringBuffer();
    sb.write('ConstructorResult(');
    if (kind != null) {
      sb.write('kind=$kind,');
      if (prefix != null) {
        sb.write('prefix=$prefix,');
      }
      sb.write('element=$element,');
      sb.write('type=$type');
    } else if (element != null) {
      sb.write('element=$element');
    } else {
      if (prefix != null) {
        sb.write('prefix=$prefix,');
      }
      sb.write('type=$type');
    }
    sb.write(')');
    return sb.toString();
  }
}

/// Lookup the [constructorName] constructor in [cls] and normalize the result
/// with respect to privacy and patching.
ConstructorElement findConstructor(
    LibraryElement currentLibrary, ClassElement cls, String constructorName) {
  if (Name.isPrivateName(constructorName) &&
      currentLibrary.library != cls.library) {
    // TODO(johnniwinther): Report a special error on unaccessible private
    // constructors.
    return null;
  }
  // TODO(johnniwinther): Use [Name] for lookup.
  ConstructorElement constructor = cls.lookupConstructor(constructorName);
  if (constructor != null) {
    constructor = constructor.declaration;
  }
  return constructor;
}
