| Index: pkg/compiler/lib/src/resolution/constructors.dart
|
| diff --git a/pkg/compiler/lib/src/resolution/constructors.dart b/pkg/compiler/lib/src/resolution/constructors.dart
|
| index 4a80a021b84a5111e626a9b55baac2338ca97b74..cff366c5327ee36d067c8a8e54f20122f607e92c 100644
|
| --- a/pkg/compiler/lib/src/resolution/constructors.dart
|
| +++ b/pkg/compiler/lib/src/resolution/constructors.dart
|
| @@ -415,9 +415,10 @@ class InitializerResolver {
|
| }
|
| }
|
|
|
| -class ConstructorResolver extends CommonResolverVisitor<ConstructorResult> {
|
| +class ConstructorResolver extends CommonResolverVisitor<Element> {
|
| final ResolverVisitor resolver;
|
| - final bool inConstContext;
|
| + bool inConstContext;
|
| + DartType type;
|
|
|
| ConstructorResolver(Compiler compiler, this.resolver,
|
| {bool this.inConstContext: false})
|
| @@ -429,10 +430,8 @@ class ConstructorResolver extends CommonResolverVisitor<ConstructorResult> {
|
| throw 'not supported';
|
| }
|
|
|
| - ConstructorResult reportAndCreateErroneousConstructorElement(
|
| + ErroneousConstructorElementX failOrReturnErroneousConstructorElement(
|
| Spannable diagnosticNode,
|
| - ConstructorResultKind resultKind,
|
| - DartType type,
|
| Element enclosing,
|
| String name,
|
| MessageKind kind,
|
| @@ -449,276 +448,171 @@ class ConstructorResolver extends CommonResolverVisitor<ConstructorResult> {
|
| } else {
|
| compiler.reportWarning(diagnosticNode, kind, arguments);
|
| }
|
| - ErroneousElement error = new ErroneousConstructorElementX(
|
| + return new ErroneousConstructorElementX(
|
| kind, arguments, name, enclosing);
|
| - if (type == null) {
|
| - type = new MalformedType(error, null);
|
| - }
|
| - return new ConstructorResult(resultKind, error, type);
|
| }
|
|
|
| - ConstructorResult resolveConstructor(
|
| - InterfaceType type,
|
| - Node diagnosticNode,
|
| - String constructorName) {
|
| - ClassElement cls = type.element;
|
| + FunctionElement resolveConstructor(ClassElement cls,
|
| + Node diagnosticNode,
|
| + String constructorName) {
|
| cls.ensureResolved(compiler);
|
| - ConstructorElement constructor = cls.lookupConstructor(constructorName);
|
| + Element result = cls.lookupConstructor(constructorName);
|
| // TODO(johnniwinther): Use [Name] for lookup.
|
| if (Name.isPrivateName(constructorName) &&
|
| resolver.enclosingElement.library != cls.library) {
|
| - constructor = null;
|
| + result = null;
|
| }
|
| - if (constructor == null) {
|
| - String fullConstructorName =
|
| - Elements.constructorNameForDiagnostics(cls.name, constructorName);
|
| - return reportAndCreateErroneousConstructorElement(
|
| + if (result == null) {
|
| + String fullConstructorName = Elements.constructorNameForDiagnostics(
|
| + cls.name,
|
| + constructorName);
|
| + return failOrReturnErroneousConstructorElement(
|
| diagnosticNode,
|
| - ConstructorResultKind.UNRESOLVED_CONSTRUCTOR, type,
|
| cls, constructorName,
|
| MessageKind.CANNOT_FIND_CONSTRUCTOR,
|
| {'constructorName': fullConstructorName},
|
| missingConstructor: true);
|
| - } else if (inConstContext && !constructor.isConst) {
|
| - compiler.reportError(
|
| - diagnosticNode, MessageKind.CONSTRUCTOR_IS_NOT_CONST);
|
| - return new ConstructorResult(
|
| - ConstructorResultKind.NON_CONSTANT, constructor, type);
|
| - } else {
|
| - if (constructor.isGenerativeConstructor) {
|
| - if (cls.isAbstract) {
|
| - compiler.reportWarning(
|
| - diagnosticNode, MessageKind.ABSTRACT_CLASS_INSTANTIATION);
|
| - registry.registerAbstractClassInstantiation();
|
| - return new ConstructorResult(
|
| - ConstructorResultKind.ABSTRACT, constructor, type);
|
| - } else {
|
| - return new ConstructorResult(
|
| - ConstructorResultKind.GENERATIVE, constructor, type);
|
| - }
|
| - } else {
|
| - assert(invariant(diagnosticNode, constructor.isFactoryConstructor,
|
| - message: "Unexpected constructor $constructor."));
|
| - return new ConstructorResult(
|
| - ConstructorResultKind.FACTORY, constructor, type);
|
| - }
|
| + } else if (inConstContext && !result.isConst) {
|
| + error(diagnosticNode, MessageKind.CONSTRUCTOR_IS_NOT_CONST);
|
| }
|
| + return result;
|
| }
|
|
|
| - ConstructorResult visitNewExpression(NewExpression node) {
|
| + Element visitNewExpression(NewExpression node) {
|
| + inConstContext = node.isConst;
|
| 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);
|
| + Element element = visit(selector);
|
| + assert(invariant(selector, element != null,
|
| + message: 'No element return for $selector.'));
|
| + return finishConstructorReference(element, 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;
|
| - }
|
| -
|
| + FunctionElement finishConstructorReference(Element element,
|
| + Node diagnosticNode,
|
| + Node expression) {
|
| + assert(invariant(diagnosticNode, element != null,
|
| + message: 'No element return for $diagnosticNode.'));
|
| // 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.type, diagnosticNode, '');
|
| - } else {
|
| - Element element = result.element;
|
| - if (element.isErroneous) {
|
| - result = constructorResultForErroneous(diagnosticNode, element);
|
| + if (!Elements.isUnresolved(element) && !element.isConstructor) {
|
| + if (element.isClass) {
|
| + ClassElement cls = element;
|
| + cls.ensureResolved(compiler);
|
| + // The unnamed constructor may not exist, so [e] may become unresolved.
|
| + element = resolveConstructor(cls, diagnosticNode, '');
|
| } else {
|
| - result = reportAndCreateErroneousConstructorElement(
|
| + element = failOrReturnErroneousConstructorElement(
|
| diagnosticNode,
|
| - ConstructorResultKind.INVALID_TYPE, null,
|
| element, element.name,
|
| MessageKind.NOT_A_TYPE, {'node': diagnosticNode});
|
| }
|
| + } else if (element.isErroneous && element is! ErroneousElementX) {
|
| + // Parser error. The error has already been reported.
|
| + element = new ErroneousConstructorElementX(
|
| + MessageKind.NOT_A_TYPE, {'node': diagnosticNode},
|
| + element.name, element);
|
| + registry.registerThrowRuntimeError();
|
| + }
|
| +
|
| + if (type == null) {
|
| + if (Elements.isUnresolved(element)) {
|
| + type = const DynamicType();
|
| + } else {
|
| + type = element.enclosingClass.rawType;
|
| + }
|
| }
|
| - resolver.registry.setType(expression, result.type);
|
| - return result;
|
| + resolver.registry.setType(expression, type);
|
| + return element;
|
| }
|
|
|
| - ConstructorResult visitTypeAnnotation(TypeAnnotation node) {
|
| + Element visitTypeAnnotation(TypeAnnotation node) {
|
| + assert(invariant(node, type == null));
|
| // 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);
|
| + type = resolver.resolveTypeAnnotation(node,
|
| + malformedIsError: inConstContext,
|
| + deferredIsMalformed: false);
|
| registry.registerRequiredType(type, resolver.enclosingElement);
|
| - return constructorResultForType(node, type);
|
| + return type.element;
|
| }
|
|
|
| - ConstructorResult visitSend(Send node) {
|
| - ConstructorResult receiver = visit(node.receiver);
|
| - assert(invariant(node.receiver, receiver != null,
|
| - message: 'No result returned for $node.receiver.'));
|
| - //if (Elements.isUnresolved(element)) return element;
|
| -
|
| + Element visitSend(Send node) {
|
| + Element element = visit(node.receiver);
|
| + assert(invariant(node.receiver, element != null,
|
| + message: 'No element return for $node.receiver.'));
|
| + if (Elements.isUnresolved(element)) return element;
|
| Identifier name = node.selector.asIdentifier();
|
| if (name == null) internalError(node.selector, 'unexpected node');
|
|
|
| - if (receiver.type != null) {
|
| - if (receiver.type.isInterfaceType) {
|
| - return resolveConstructor(receiver.type, name, name.source);
|
| - } else {
|
| - // TODO(johnniwinther): Update the message for the different types.
|
| - return reportAndCreateErroneousConstructorElement(
|
| + if (element.isClass) {
|
| + ClassElement cls = element;
|
| + cls.ensureResolved(compiler);
|
| + return resolveConstructor(cls, name, name.source);
|
| + } else if (element.isPrefix) {
|
| + PrefixElement prefix = element;
|
| + element = prefix.lookupLocalMember(name.source);
|
| + element = Elements.unwrap(element, compiler, node);
|
| + if (element == null) {
|
| + return failOrReturnErroneousConstructorElement(
|
| + name,
|
| + resolver.enclosingElement, name.source,
|
| + MessageKind.CANNOT_RESOLVE, {'name': name});
|
| + } else if (!element.isClass) {
|
| + return failOrReturnErroneousConstructorElement(
|
| name,
|
| - ConstructorResultKind.INVALID_TYPE, null,
|
| resolver.enclosingElement, name.source,
|
| - MessageKind.NOT_A_TYPE, {'node': name});
|
| + MessageKind.NOT_A_TYPE, {'node': name},
|
| + isError: true);
|
| }
|
| - } else if (receiver.element.isPrefix) {
|
| - PrefixElement prefix = receiver.element;
|
| - Element member = prefix.lookupLocalMember(name.source);
|
| - return constructorResultForElement(node, name.source, member);
|
| } else {
|
| - return internalError(node.receiver, 'unexpected receiver $receiver');
|
| + internalError(node.receiver, 'unexpected element $element');
|
| }
|
| + return element;
|
| }
|
|
|
| - ConstructorResult visitIdentifier(Identifier node) {
|
| + Element visitIdentifier(Identifier node) {
|
| String name = node.source;
|
| Element element = resolver.reportLookupErrorIfAny(
|
| lookupInScope(compiler, node, resolver.scope, name), node, name);
|
| registry.useElement(node, element);
|
| // TODO(johnniwinther): Change errors to warnings, cf. 11.11.1.
|
| - 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) {
|
| - element = Elements.unwrap(element, compiler, node);
|
| if (element == null) {
|
| - return reportAndCreateErroneousConstructorElement(
|
| + return failOrReturnErroneousConstructorElement(
|
| node,
|
| - ConstructorResultKind.INVALID_TYPE, null,
|
| resolver.enclosingElement, name,
|
| MessageKind.CANNOT_RESOLVE,
|
| {'name': name});
|
| } else if (element.isErroneous) {
|
| - return constructorResultForErroneous(node, element);
|
| - } else if (element.isClass) {
|
| - ClassElement cls = element;
|
| - cls.computeType(compiler);
|
| - return constructorResultForType(node, cls.rawType);
|
| - } else if (element.isPrefix) {
|
| - return new ConstructorResult.forElement(element);
|
| + return element;
|
| } else if (element.isTypedef) {
|
| - TypedefElement typdef = element;
|
| - typdef.ensureResolved(compiler);
|
| - return constructorResultForType(node, typdef.rawType);
|
| - } else if (element.isTypeVariable) {
|
| - TypeVariableElement typeVariableElement = element;
|
| - return constructorResultForType(node, typeVariableElement.type);
|
| - } else {
|
| - return reportAndCreateErroneousConstructorElement(
|
| + element = failOrReturnErroneousConstructorElement(
|
| 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.registerThrowRuntimeError();
|
| - }
|
| - return new ConstructorResult(
|
| - ConstructorResultKind.INVALID_TYPE,
|
| - error,
|
| - new MalformedType(error, null));
|
| - }
|
| -
|
| - ConstructorResult constructorResultForType(
|
| - Node node,
|
| - DartType type) {
|
| - String name = type.name;
|
| - if (type.isMalformed) {
|
| - return new ConstructorResult(
|
| - ConstructorResultKind.INVALID_TYPE, type.element, type);
|
| - } else if (type.isInterfaceType) {
|
| - return new ConstructorResult.forType(type);
|
| - } else if (type.isTypedef) {
|
| - return reportAndCreateErroneousConstructorElement(
|
| + MessageKind.CANNOT_INSTANTIATE_TYPEDEF, {'typedefName': name},
|
| + isError: true);
|
| + } else if (element.isTypeVariable) {
|
| + element = failOrReturnErroneousConstructorElement(
|
| node,
|
| - ConstructorResultKind.INVALID_TYPE, type,
|
| resolver.enclosingElement, name,
|
| - MessageKind.CANNOT_INSTANTIATE_TYPEDEF, {'typedefName': name});
|
| - } else if (type.isTypeVariable) {
|
| - return reportAndCreateErroneousConstructorElement(
|
| + MessageKind.CANNOT_INSTANTIATE_TYPE_VARIABLE,
|
| + {'typeVariableName': name},
|
| + isError: true);
|
| + } else if (!element.isClass && !element.isPrefix) {
|
| + element = failOrReturnErroneousConstructorElement(
|
| node,
|
| - ConstructorResultKind.INVALID_TYPE, type,
|
| resolver.enclosingElement, name,
|
| - MessageKind.CANNOT_INSTANTIATE_TYPE_VARIABLE,
|
| - {'typeVariableName': name});
|
| + MessageKind.NOT_A_TYPE, {'node': name},
|
| + isError: true);
|
| }
|
| - internalError(node, "Unexpected constructor type $type");
|
| - return null;
|
| + return element;
|
| }
|
|
|
| -}
|
| -
|
| -enum ConstructorResultKind {
|
| - GENERATIVE,
|
| - FACTORY,
|
| - ABSTRACT,
|
| - INVALID_TYPE,
|
| - UNRESOLVED_CONSTRUCTOR,
|
| - NON_CONSTANT,
|
| -}
|
| -
|
| -class ConstructorResult {
|
| - final ConstructorResultKind kind;
|
| - final Element element;
|
| - final DartType type;
|
| -
|
| - ConstructorResult(this.kind, this.element, this.type);
|
| -
|
| - ConstructorResult.forElement(this.element)
|
| - : kind = null,
|
| - type = null;
|
| -
|
| - ConstructorResult.forType(this.type)
|
| - : kind = null,
|
| - element = null;
|
| -
|
| - String toString() {
|
| - StringBuffer sb = new StringBuffer();
|
| - sb.write('ConstructorResult(');
|
| - if (kind != null) {
|
| - sb.write('kind=$kind,');
|
| - sb.write('element=$element,');
|
| - sb.write('type=$type');
|
| - } else if (element != null) {
|
| - sb.write('element=$element');
|
| - } else {
|
| - sb.write('type=$type');
|
| - }
|
| - sb.write(')');
|
| - return sb.toString();
|
| + /// Assumed to be called by [resolveRedirectingFactory].
|
| + Element visitRedirectingFactoryBody(RedirectingFactoryBody node) {
|
| + Node constructorReference = node.constructorReference;
|
| + return finishConstructorReference(visit(constructorReference),
|
| + constructorReference, node);
|
| }
|
| }
|
|
|