Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(78)

Unified Diff: pkg/compiler/lib/src/resolution/resolution_common.dart

Issue 1286993004: Split resolution into several libraries. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/compiler/lib/src/resolution/resolution_common.dart
diff --git a/pkg/compiler/lib/src/resolution/resolution_common.dart b/pkg/compiler/lib/src/resolution/resolution_common.dart
index 0f1a7784a4b65d976028c1acf95e1ae3e6e7fef5..67974330fcc28a1527e749345202ae0f364aeda5 100644
--- a/pkg/compiler/lib/src/resolution/resolution_common.dart
+++ b/pkg/compiler/lib/src/resolution/resolution_common.dart
@@ -2,968 +2,25 @@
// 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.
-part of resolution;
-
-class ResolverTask extends CompilerTask {
- final ConstantCompiler constantCompiler;
-
- ResolverTask(Compiler compiler, this.constantCompiler) : super(compiler);
-
- String get name => 'Resolver';
-
- WorldImpact resolve(Element element) {
- return measure(() {
- if (Elements.isErroneous(element)) {
- // TODO(johnniwinther): Add a predicate for this.
- assert(invariant(element, element is! ErroneousElement,
- message: "Element $element expected to have parse errors."));
- _ensureTreeElements(element);
- return const WorldImpact();
- }
-
- WorldImpact processMetadata([WorldImpact result]) {
- for (MetadataAnnotation metadata in element.metadata) {
- metadata.ensureResolved(compiler);
- }
- return result;
- }
-
- ElementKind kind = element.kind;
- if (identical(kind, ElementKind.GENERATIVE_CONSTRUCTOR) ||
- identical(kind, ElementKind.FUNCTION) ||
- identical(kind, ElementKind.GETTER) ||
- identical(kind, ElementKind.SETTER)) {
- return processMetadata(resolveMethodElement(element));
- }
-
- if (identical(kind, ElementKind.FIELD)) {
- return processMetadata(resolveField(element));
- }
- if (element.isClass) {
- ClassElement cls = element;
- cls.ensureResolved(compiler);
- return processMetadata(const WorldImpact());
- } else if (element.isTypedef) {
- TypedefElement typdef = element;
- return processMetadata(resolveTypedef(typdef));
- }
-
- compiler.unimplemented(element, "resolve($element)");
- });
- }
-
- void resolveRedirectingConstructor(InitializerResolver resolver,
- Node node,
- FunctionElement constructor,
- FunctionElement redirection) {
- assert(invariant(node, constructor.isImplementation,
- message: 'Redirecting constructors must be resolved on implementation '
- 'elements.'));
- Setlet<FunctionElement> seen = new Setlet<FunctionElement>();
- seen.add(constructor);
- while (redirection != null) {
- // Ensure that we follow redirections through implementation elements.
- redirection = redirection.implementation;
- if (seen.contains(redirection)) {
- resolver.visitor.error(node, MessageKind.REDIRECTING_CONSTRUCTOR_CYCLE);
- return;
- }
- seen.add(redirection);
- redirection = resolver.visitor.resolveConstructorRedirection(redirection);
- }
- }
-
- static void processAsyncMarker(Compiler compiler,
- BaseFunctionElementX element,
- ResolutionRegistry registry) {
- FunctionExpression functionExpression = element.node;
- AsyncModifier asyncModifier = functionExpression.asyncModifier;
- if (asyncModifier != null) {
-
- if (asyncModifier.isAsynchronous) {
- element.asyncMarker = asyncModifier.isYielding
- ? AsyncMarker.ASYNC_STAR : AsyncMarker.ASYNC;
- } else {
- element.asyncMarker = AsyncMarker.SYNC_STAR;
- }
- if (element.isAbstract) {
- compiler.reportError(asyncModifier,
- MessageKind.ASYNC_MODIFIER_ON_ABSTRACT_METHOD,
- {'modifier': element.asyncMarker});
- } else if (element.isConstructor) {
- compiler.reportError(asyncModifier,
- MessageKind.ASYNC_MODIFIER_ON_CONSTRUCTOR,
- {'modifier': element.asyncMarker});
- } else {
- if (element.isSetter) {
- compiler.reportError(asyncModifier,
- MessageKind.ASYNC_MODIFIER_ON_SETTER,
- {'modifier': element.asyncMarker});
-
- }
- if (functionExpression.body.asReturn() != null &&
- element.asyncMarker.isYielding) {
- compiler.reportError(asyncModifier,
- MessageKind.YIELDING_MODIFIER_ON_ARROW_BODY,
- {'modifier': element.asyncMarker});
- }
- }
- registry.registerAsyncMarker(element);
- switch (element.asyncMarker) {
- case AsyncMarker.ASYNC:
- compiler.futureClass.ensureResolved(compiler);
- break;
- case AsyncMarker.ASYNC_STAR:
- compiler.streamClass.ensureResolved(compiler);
- break;
- case AsyncMarker.SYNC_STAR:
- compiler.iterableClass.ensureResolved(compiler);
- break;
- }
- }
- }
-
- bool _isNativeClassOrExtendsNativeClass(ClassElement classElement) {
- assert(classElement != null);
- while (classElement != null) {
- if (classElement.isNative) return true;
- classElement = classElement.superclass;
- }
- return false;
- }
-
- WorldImpact resolveMethodElementImplementation(
- FunctionElement element, FunctionExpression tree) {
- return compiler.withCurrentElement(element, () {
- if (element.isExternal && tree.hasBody()) {
- error(element,
- MessageKind.EXTERNAL_WITH_BODY,
- {'functionName': element.name});
- }
- if (element.isConstructor) {
- if (tree.returnType != null) {
- error(tree, MessageKind.CONSTRUCTOR_WITH_RETURN_TYPE);
- }
- if (element.isConst &&
- tree.hasBody() &&
- !tree.isRedirectingFactory) {
- error(tree, MessageKind.CONST_CONSTRUCTOR_HAS_BODY);
- }
- }
-
- ResolverVisitor visitor = visitorFor(element);
- ResolutionRegistry registry = visitor.registry;
- registry.defineFunction(tree, element);
- visitor.setupFunction(tree, element);
- processAsyncMarker(compiler, element, registry);
-
- if (element.isGenerativeConstructor) {
- // Even if there is no initializer list we still have to do the
- // resolution in case there is an implicit super constructor call.
- InitializerResolver resolver =
- new InitializerResolver(visitor, element, tree);
- FunctionElement redirection = resolver.resolveInitializers();
- if (redirection != null) {
- resolveRedirectingConstructor(resolver, tree, element, redirection);
- }
- } else if (tree.initializers != null) {
- error(tree, MessageKind.FUNCTION_WITH_INITIALIZER);
- }
-
- if (!compiler.analyzeSignaturesOnly || tree.isRedirectingFactory) {
- // We need to analyze the redirecting factory bodies to ensure that
- // we can analyze compile-time constants.
- visitor.visit(tree.body);
- }
-
- // Get the resolution tree and check that the resolved
- // function doesn't use 'super' if it is mixed into another
- // class. This is the part of the 'super' mixin check that
- // happens when a function is resolved after the mixin
- // application has been performed.
- TreeElements resolutionTree = registry.mapping;
- ClassElement enclosingClass = element.enclosingClass;
- if (enclosingClass != null) {
- // TODO(johnniwinther): Find another way to obtain mixin uses.
- Iterable<MixinApplicationElement> mixinUses =
- compiler.world.allMixinUsesOf(enclosingClass);
- ClassElement mixin = enclosingClass;
- for (MixinApplicationElement mixinApplication in mixinUses) {
- checkMixinSuperUses(resolutionTree, mixinApplication, mixin);
- }
- }
-
- // TODO(9631): support noSuchMethod on native classes.
- if (Elements.isInstanceMethod(element) &&
- element.name == Compiler.NO_SUCH_METHOD &&
- _isNativeClassOrExtendsNativeClass(enclosingClass)) {
- error(tree, MessageKind.NO_SUCH_METHOD_IN_NATIVE);
- }
-
- return registry.worldImpact;
- });
-
- }
-
- WorldImpact resolveMethodElement(FunctionElementX element) {
- assert(invariant(element, element.isDeclaration));
- return compiler.withCurrentElement(element, () {
- if (compiler.enqueuer.resolution.hasBeenResolved(element)) {
- // TODO(karlklose): Remove the check for [isConstructor]. [elememts]
- // should never be non-null, not even for constructors.
- assert(invariant(element, element.isConstructor,
- message: 'Non-constructor element $element '
- 'has already been analyzed.'));
- return const WorldImpact();
- }
- if (element.isSynthesized) {
- if (element.isGenerativeConstructor) {
- ResolutionRegistry registry =
- new ResolutionRegistry(compiler, element);
- ConstructorElement constructor = element.asFunctionElement();
- ConstructorElement target = constructor.definingConstructor;
- // Ensure the signature of the synthesized element is
- // resolved. This is the only place where the resolver is
- // seeing this element.
- element.computeSignature(compiler);
- if (!target.isErroneous) {
- registry.registerStaticUse(target);
- registry.registerImplicitSuperCall(target);
- }
- return registry.worldImpact;
- } else {
- assert(element.isDeferredLoaderGetter || element.isErroneous);
- _ensureTreeElements(element);
- return const WorldImpact();
- }
- } else {
- element.parseNode(compiler);
- element.computeType(compiler);
- FunctionElementX implementation = element;
- if (element.isExternal) {
- implementation = compiler.backend.resolveExternalFunction(element);
- }
- return resolveMethodElementImplementation(
- implementation, implementation.node);
- }
- });
- }
-
- /// Creates a [ResolverVisitor] for resolving an AST in context of [element].
- /// If [useEnclosingScope] is `true` then the initial scope of the visitor
- /// does not include inner scope of [element].
- ///
- /// This method should only be used by this library (or tests of
- /// this library).
- ResolverVisitor visitorFor(Element element, {bool useEnclosingScope: false}) {
- return new ResolverVisitor(compiler, element,
- new ResolutionRegistry(compiler, element),
- useEnclosingScope: useEnclosingScope);
- }
-
- WorldImpact resolveField(FieldElementX element) {
- VariableDefinitions tree = element.parseNode(compiler);
- if(element.modifiers.isStatic && element.isTopLevel) {
- error(element.modifiers.getStatic(),
- MessageKind.TOP_LEVEL_VARIABLE_DECLARED_STATIC);
- }
- ResolverVisitor visitor = visitorFor(element);
- ResolutionRegistry registry = visitor.registry;
- // TODO(johnniwinther): Maybe remove this when placeholderCollector migrates
- // to the backend ast.
- registry.defineElement(tree.definitions.nodes.head, element);
- // TODO(johnniwinther): Share the resolved type between all variables
- // declared in the same declaration.
- if (tree.type != null) {
- element.variables.type = visitor.resolveTypeAnnotation(tree.type);
- } else {
- element.variables.type = const DynamicType();
- }
-
- Expression initializer = element.initializer;
- Modifiers modifiers = element.modifiers;
- if (initializer != null) {
- // TODO(johnniwinther): Avoid analyzing initializers if
- // [Compiler.analyzeSignaturesOnly] is set.
- visitor.visit(initializer);
- } else if (modifiers.isConst) {
- compiler.reportError(element, MessageKind.CONST_WITHOUT_INITIALIZER);
- } else if (modifiers.isFinal && !element.isInstanceMember) {
- compiler.reportError(element, MessageKind.FINAL_WITHOUT_INITIALIZER);
- } else {
- registry.registerInstantiatedClass(compiler.nullClass);
- }
-
- if (Elements.isStaticOrTopLevelField(element)) {
- visitor.addDeferredAction(element, () {
- if (element.modifiers.isConst) {
- element.constant = constantCompiler.compileConstant(element);
- } else {
- constantCompiler.compileVariable(element);
- }
- });
- if (initializer != null) {
- if (!element.modifiers.isConst) {
- // TODO(johnniwinther): Determine the const-ness eagerly to avoid
- // unnecessary registrations.
- registry.registerLazyField();
- }
- }
- }
-
- // Perform various checks as side effect of "computing" the type.
- element.computeType(compiler);
-
- return registry.worldImpact;
- }
-
- DartType resolveTypeAnnotation(Element element, TypeAnnotation annotation) {
- DartType type = resolveReturnType(element, annotation);
- if (type.isVoid) {
- error(annotation, MessageKind.VOID_NOT_ALLOWED);
- }
- return type;
- }
-
- DartType resolveReturnType(Element element, TypeAnnotation annotation) {
- if (annotation == null) return const DynamicType();
- DartType result = visitorFor(element).resolveTypeAnnotation(annotation);
- if (result == null) {
- // TODO(karklose): warning.
- return const DynamicType();
- }
- return result;
- }
-
- void resolveRedirectionChain(ConstructorElementX constructor,
- Spannable node) {
- ConstructorElementX target = constructor;
- InterfaceType targetType;
- List<Element> seen = new List<Element>();
- // Follow the chain of redirections and check for cycles.
- while (target.isRedirectingFactory) {
- if (target.internalEffectiveTarget != null) {
- // We found a constructor that already has been processed.
- targetType = target.effectiveTargetType;
- assert(invariant(target, targetType != null,
- message: 'Redirection target type has not been computed for '
- '$target'));
- target = target.internalEffectiveTarget;
- break;
- }
-
- Element nextTarget = target.immediateRedirectionTarget;
- if (seen.contains(nextTarget)) {
- error(node, MessageKind.CYCLIC_REDIRECTING_FACTORY);
- targetType = target.enclosingClass.thisType;
- break;
- }
- seen.add(target);
- target = nextTarget;
- }
-
- if (targetType == null) {
- assert(!target.isRedirectingFactory);
- targetType = target.enclosingClass.thisType;
- }
-
- // [target] is now the actual target of the redirections. Run through
- // the constructors again and set their [redirectionTarget], so that we
- // do not have to run the loop for these constructors again. Furthermore,
- // compute [redirectionTargetType] for each factory by computing the
- // substitution of the target type with respect to the factory type.
- while (!seen.isEmpty) {
- ConstructorElementX factory = seen.removeLast();
-
- // [factory] must already be analyzed but the [TreeElements] might not
- // have been stored in the enqueuer cache yet.
- // TODO(johnniwinther): Store [TreeElements] in the cache before
- // resolution of the element.
- TreeElements treeElements = factory.treeElements;
- assert(invariant(node, treeElements != null,
- message: 'No TreeElements cached for $factory.'));
- FunctionExpression functionNode = factory.parseNode(compiler);
- RedirectingFactoryBody redirectionNode = functionNode.body;
- DartType factoryType = treeElements.getType(redirectionNode);
- if (!factoryType.isDynamic) {
- targetType = targetType.substByContext(factoryType);
- }
- factory.effectiveTarget = target;
- factory.effectiveTargetType = targetType;
- }
- }
-
- /**
- * Load and resolve the supertypes of [cls].
- *
- * Warning: do not call this method directly. It should only be
- * called by [resolveClass] and [ClassSupertypeResolver].
- */
- void loadSupertypes(BaseClassElementX cls, Spannable from) {
- compiler.withCurrentElement(cls, () => measure(() {
- if (cls.supertypeLoadState == STATE_DONE) return;
- if (cls.supertypeLoadState == STATE_STARTED) {
- compiler.reportError(from, MessageKind.CYCLIC_CLASS_HIERARCHY,
- {'className': cls.name});
- cls.supertypeLoadState = STATE_DONE;
- cls.hasIncompleteHierarchy = true;
- cls.allSupertypesAndSelf =
- compiler.objectClass.allSupertypesAndSelf.extendClass(
- cls.computeType(compiler));
- cls.supertype = cls.allSupertypes.head;
- assert(invariant(from, cls.supertype != null,
- message: 'Missing supertype on cyclic class $cls.'));
- cls.interfaces = const Link<DartType>();
- return;
- }
- cls.supertypeLoadState = STATE_STARTED;
- compiler.withCurrentElement(cls, () {
- // TODO(ahe): Cache the node in cls.
- cls.parseNode(compiler).accept(
- new ClassSupertypeResolver(compiler, cls));
- if (cls.supertypeLoadState != STATE_DONE) {
- cls.supertypeLoadState = STATE_DONE;
- }
- });
- }));
- }
-
- // TODO(johnniwinther): Remove this queue when resolution has been split into
- // syntax and semantic resolution.
- TypeDeclarationElement currentlyResolvedTypeDeclaration;
- Queue<ClassElement> pendingClassesToBeResolved = new Queue<ClassElement>();
- Queue<ClassElement> pendingClassesToBePostProcessed =
- new Queue<ClassElement>();
-
- /// Resolve [element] using [resolveTypeDeclaration].
- ///
- /// This methods ensure that class declarations encountered through type
- /// annotations during the resolution of [element] are resolved after
- /// [element] has been resolved.
- // TODO(johnniwinther): Encapsulate this functionality in a
- // 'TypeDeclarationResolver'.
- _resolveTypeDeclaration(TypeDeclarationElement element,
- resolveTypeDeclaration()) {
- return compiler.withCurrentElement(element, () {
- return measure(() {
- TypeDeclarationElement previousResolvedTypeDeclaration =
- currentlyResolvedTypeDeclaration;
- currentlyResolvedTypeDeclaration = element;
- var result = resolveTypeDeclaration();
- if (previousResolvedTypeDeclaration == null) {
- do {
- while (!pendingClassesToBeResolved.isEmpty) {
- pendingClassesToBeResolved.removeFirst().ensureResolved(compiler);
- }
- while (!pendingClassesToBePostProcessed.isEmpty) {
- _postProcessClassElement(
- pendingClassesToBePostProcessed.removeFirst());
- }
- } while (!pendingClassesToBeResolved.isEmpty);
- assert(pendingClassesToBeResolved.isEmpty);
- assert(pendingClassesToBePostProcessed.isEmpty);
- }
- currentlyResolvedTypeDeclaration = previousResolvedTypeDeclaration;
- return result;
- });
- });
- }
-
- /**
- * Resolve the class [element].
- *
- * Before calling this method, [element] was constructed by the
- * scanner and most fields are null or empty. This method fills in
- * these fields and also ensure that the supertypes of [element] are
- * resolved.
- *
- * Warning: Do not call this method directly. Instead use
- * [:element.ensureResolved(compiler):].
- */
- TreeElements resolveClass(BaseClassElementX element) {
- return _resolveTypeDeclaration(element, () {
- // TODO(johnniwinther): Store the mapping in the resolution enqueuer.
- ResolutionRegistry registry = new ResolutionRegistry(compiler, element);
- resolveClassInternal(element, registry);
- return element.treeElements;
- });
- }
-
- void _ensureClassWillBeResolved(ClassElement element) {
- if (currentlyResolvedTypeDeclaration == null) {
- element.ensureResolved(compiler);
- } else {
- pendingClassesToBeResolved.add(element);
- }
- }
-
- void resolveClassInternal(BaseClassElementX element,
- ResolutionRegistry registry) {
- if (!element.isPatch) {
- compiler.withCurrentElement(element, () => measure(() {
- assert(element.resolutionState == STATE_NOT_STARTED);
- element.resolutionState = STATE_STARTED;
- Node tree = element.parseNode(compiler);
- loadSupertypes(element, tree);
-
- ClassResolverVisitor visitor =
- new ClassResolverVisitor(compiler, element, registry);
- visitor.visit(tree);
- element.resolutionState = STATE_DONE;
- compiler.onClassResolved(element);
- pendingClassesToBePostProcessed.add(element);
- }));
- if (element.isPatched) {
- // Ensure handling patch after origin.
- element.patch.ensureResolved(compiler);
- }
- } else { // Handle patch classes:
- element.resolutionState = STATE_STARTED;
- // Ensure handling origin before patch.
- element.origin.ensureResolved(compiler);
- // Ensure that the type is computed.
- element.computeType(compiler);
- // Copy class hierarchy from origin.
- element.supertype = element.origin.supertype;
- element.interfaces = element.origin.interfaces;
- element.allSupertypesAndSelf = element.origin.allSupertypesAndSelf;
- // Stepwise assignment to ensure invariant.
- element.supertypeLoadState = STATE_STARTED;
- element.supertypeLoadState = STATE_DONE;
- element.resolutionState = STATE_DONE;
- // TODO(johnniwinther): Check matching type variables and
- // empty extends/implements clauses.
- }
- }
-
- void _postProcessClassElement(BaseClassElementX element) {
- for (MetadataAnnotation metadata in element.metadata) {
- metadata.ensureResolved(compiler);
- ConstantValue value =
- compiler.constants.getConstantValue(metadata.constant);
- if (!element.isProxy && value == compiler.proxyConstant) {
- element.isProxy = true;
- }
- }
-
- // Force resolution of metadata on non-instance members since they may be
- // inspected by the backend while emitting. Metadata on instance members is
- // handled as a result of processing instantiated class members in the
- // enqueuer.
- // TODO(ahe): Avoid this eager resolution.
- element.forEachMember((_, Element member) {
- if (!member.isInstanceMember) {
- compiler.withCurrentElement(member, () {
- for (MetadataAnnotation metadata in member.metadata) {
- metadata.ensureResolved(compiler);
- }
- });
- }
- });
-
- computeClassMember(element, Compiler.CALL_OPERATOR_NAME);
- }
-
- void computeClassMembers(ClassElement element) {
- MembersCreator.computeAllClassMembers(compiler, element);
- }
-
- void computeClassMember(ClassElement element, String name) {
- MembersCreator.computeClassMembersByName(compiler, element, name);
- }
-
- void checkClass(ClassElement element) {
- computeClassMembers(element);
- if (element.isMixinApplication) {
- checkMixinApplication(element);
- } else {
- checkClassMembers(element);
- }
- }
-
- void checkMixinApplication(MixinApplicationElementX mixinApplication) {
- Modifiers modifiers = mixinApplication.modifiers;
- int illegalFlags = modifiers.flags & ~Modifiers.FLAG_ABSTRACT;
- if (illegalFlags != 0) {
- Modifiers illegalModifiers = new Modifiers.withFlags(null, illegalFlags);
- compiler.reportError(
- modifiers,
- MessageKind.ILLEGAL_MIXIN_APPLICATION_MODIFIERS,
- {'modifiers': illegalModifiers});
- }
-
- // In case of cyclic mixin applications, the mixin chain will have
- // been cut. If so, we have already reported the error to the
- // user so we just return from here.
- ClassElement mixin = mixinApplication.mixin;
- if (mixin == null) return;
-
- // Check that we're not trying to use Object as a mixin.
- if (mixin.superclass == null) {
- compiler.reportError(mixinApplication,
- MessageKind.ILLEGAL_MIXIN_OBJECT);
- // Avoid reporting additional errors for the Object class.
- return;
- }
-
- if (mixin.isEnumClass) {
- // Mixing in an enum has already caused a compile-time error.
- return;
- }
-
- // Check that the mixed in class has Object as its superclass.
- if (!mixin.superclass.isObject) {
- compiler.reportError(mixin, MessageKind.ILLEGAL_MIXIN_SUPERCLASS);
- }
-
- // Check that the mixed in class doesn't have any constructors and
- // make sure we aren't mixing in methods that use 'super'.
- mixin.forEachLocalMember((AstElement member) {
- if (member.isGenerativeConstructor && !member.isSynthesized) {
- compiler.reportError(member, MessageKind.ILLEGAL_MIXIN_CONSTRUCTOR);
- } else {
- // Get the resolution tree and check that the resolved member
- // doesn't use 'super'. This is the part of the 'super' mixin
- // check that happens when a function is resolved before the
- // mixin application has been performed.
- // TODO(johnniwinther): Obtain the [TreeElements] for [member]
- // differently.
- if (compiler.enqueuer.resolution.hasBeenResolved(member)) {
- checkMixinSuperUses(
- member.resolvedAst.elements,
- mixinApplication,
- mixin);
- }
- }
- });
- }
-
- void checkMixinSuperUses(TreeElements resolutionTree,
- MixinApplicationElement mixinApplication,
- ClassElement mixin) {
- // TODO(johnniwinther): Avoid the use of [TreeElements] here.
- if (resolutionTree == null) return;
- Iterable<Node> superUses = resolutionTree.superUses;
- if (superUses.isEmpty) return;
- compiler.reportError(mixinApplication,
- MessageKind.ILLEGAL_MIXIN_WITH_SUPER,
- {'className': mixin.name});
- // Show the user the problematic uses of 'super' in the mixin.
- for (Node use in superUses) {
- compiler.reportInfo(
- use,
- MessageKind.ILLEGAL_MIXIN_SUPER_USE);
- }
- }
-
- void checkClassMembers(ClassElement cls) {
- assert(invariant(cls, cls.isDeclaration));
- if (cls.isObject) return;
- // TODO(johnniwinther): Should this be done on the implementation element as
- // well?
- List<Element> constConstructors = <Element>[];
- List<Element> nonFinalInstanceFields = <Element>[];
- cls.forEachMember((holder, member) {
- compiler.withCurrentElement(member, () {
- // Perform various checks as side effect of "computing" the type.
- member.computeType(compiler);
-
- // Check modifiers.
- if (member.isFunction && member.modifiers.isFinal) {
- compiler.reportError(
- member, MessageKind.ILLEGAL_FINAL_METHOD_MODIFIER);
- }
- if (member.isConstructor) {
- final mismatchedFlagsBits =
- member.modifiers.flags &
- (Modifiers.FLAG_STATIC | Modifiers.FLAG_ABSTRACT);
- if (mismatchedFlagsBits != 0) {
- final mismatchedFlags =
- new Modifiers.withFlags(null, mismatchedFlagsBits);
- compiler.reportError(
- member,
- MessageKind.ILLEGAL_CONSTRUCTOR_MODIFIERS,
- {'modifiers': mismatchedFlags});
- }
- if (member.modifiers.isConst) {
- constConstructors.add(member);
- }
- }
- if (member.isField) {
- if (member.modifiers.isConst && !member.modifiers.isStatic) {
- compiler.reportError(
- member, MessageKind.ILLEGAL_CONST_FIELD_MODIFIER);
- }
- if (!member.modifiers.isStatic && !member.modifiers.isFinal) {
- nonFinalInstanceFields.add(member);
- }
- }
- checkAbstractField(member);
- checkUserDefinableOperator(member);
- });
- });
- if (!constConstructors.isEmpty && !nonFinalInstanceFields.isEmpty) {
- Spannable span = constConstructors.length > 1
- ? cls : constConstructors[0];
- compiler.reportError(span,
- MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS,
- {'className': cls.name});
- if (constConstructors.length > 1) {
- for (Element constructor in constConstructors) {
- compiler.reportInfo(constructor,
- MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_CONSTRUCTOR);
- }
- }
- for (Element field in nonFinalInstanceFields) {
- compiler.reportInfo(field,
- MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_FIELD);
- }
- }
- }
-
- void checkAbstractField(Element member) {
- // Only check for getters. The test can only fail if there is both a setter
- // and a getter with the same name, and we only need to check each abstract
- // field once, so we just ignore setters.
- if (!member.isGetter) return;
-
- // Find the associated abstract field.
- ClassElement classElement = member.enclosingClass;
- Element lookupElement = classElement.lookupLocalMember(member.name);
- if (lookupElement == null) {
- compiler.internalError(member,
- "No abstract field for accessor");
- } else if (!identical(lookupElement.kind, ElementKind.ABSTRACT_FIELD)) {
- if (lookupElement.isErroneous || lookupElement.isAmbiguous) return;
- compiler.internalError(member,
- "Inaccessible abstract field for accessor");
- }
- AbstractFieldElement field = lookupElement;
-
- GetterElementX getter = field.getter;
- if (getter == null) return;
- SetterElementX setter = field.setter;
- if (setter == null) return;
- int getterFlags = getter.modifiers.flags | Modifiers.FLAG_ABSTRACT;
- int setterFlags = setter.modifiers.flags | Modifiers.FLAG_ABSTRACT;
- if (!identical(getterFlags, setterFlags)) {
- final mismatchedFlags =
- new Modifiers.withFlags(null, getterFlags ^ setterFlags);
- compiler.reportError(
- field.getter,
- MessageKind.GETTER_MISMATCH,
- {'modifiers': mismatchedFlags});
- compiler.reportError(
- field.setter,
- MessageKind.SETTER_MISMATCH,
- {'modifiers': mismatchedFlags});
- }
- }
-
- void checkUserDefinableOperator(Element member) {
- FunctionElement function = member.asFunctionElement();
- if (function == null) return;
- String value = member.name;
- if (value == null) return;
- if (!(isUserDefinableOperator(value) || identical(value, 'unary-'))) return;
-
- bool isMinus = false;
- int requiredParameterCount;
- MessageKind messageKind;
- if (identical(value, 'unary-')) {
- isMinus = true;
- messageKind = MessageKind.MINUS_OPERATOR_BAD_ARITY;
- requiredParameterCount = 0;
- } else if (isMinusOperator(value)) {
- isMinus = true;
- messageKind = MessageKind.MINUS_OPERATOR_BAD_ARITY;
- requiredParameterCount = 1;
- } else if (isUnaryOperator(value)) {
- messageKind = MessageKind.UNARY_OPERATOR_BAD_ARITY;
- requiredParameterCount = 0;
- } else if (isBinaryOperator(value)) {
- messageKind = MessageKind.BINARY_OPERATOR_BAD_ARITY;
- requiredParameterCount = 1;
- if (identical(value, '==')) checkOverrideHashCode(member);
- } else if (isTernaryOperator(value)) {
- messageKind = MessageKind.TERNARY_OPERATOR_BAD_ARITY;
- requiredParameterCount = 2;
- } else {
- compiler.internalError(function,
- 'Unexpected user defined operator $value');
- }
- checkArity(function, requiredParameterCount, messageKind, isMinus);
- }
-
- void checkOverrideHashCode(FunctionElement operatorEquals) {
- if (operatorEquals.isAbstract) return;
- ClassElement cls = operatorEquals.enclosingClass;
- Element hashCodeImplementation =
- cls.lookupLocalMember('hashCode');
- if (hashCodeImplementation != null) return;
- compiler.reportHint(
- operatorEquals, MessageKind.OVERRIDE_EQUALS_NOT_HASH_CODE,
- {'class': cls.name});
- }
-
- void checkArity(FunctionElement function,
- int requiredParameterCount, MessageKind messageKind,
- bool isMinus) {
- FunctionExpression node = function.node;
- FunctionSignature signature = function.functionSignature;
- if (signature.requiredParameterCount != requiredParameterCount) {
- Node errorNode = node;
- if (node.parameters != null) {
- if (isMinus ||
- signature.requiredParameterCount < requiredParameterCount) {
- // If there are too few parameters, point to the whole parameter list.
- // For instance
- //
- // int operator +() {}
- // ^^
- //
- // int operator []=(value) {}
- // ^^^^^^^
- //
- // For operator -, always point the whole parameter list, like
- //
- // int operator -(a, b) {}
- // ^^^^^^
- //
- // instead of
- //
- // int operator -(a, b) {}
- // ^
- //
- // since the correction might not be to remove 'b' but instead to
- // remove 'a, b'.
- errorNode = node.parameters;
- } else {
- errorNode = node.parameters.nodes.skip(requiredParameterCount).head;
- }
- }
- compiler.reportError(
- errorNode, messageKind, {'operatorName': function.name});
- }
- if (signature.optionalParameterCount != 0) {
- Node errorNode =
- node.parameters.nodes.skip(signature.requiredParameterCount).head;
- if (signature.optionalParametersAreNamed) {
- compiler.reportError(
- errorNode,
- MessageKind.OPERATOR_NAMED_PARAMETERS,
- {'operatorName': function.name});
- } else {
- compiler.reportError(
- errorNode,
- MessageKind.OPERATOR_OPTIONAL_PARAMETERS,
- {'operatorName': function.name});
- }
- }
- }
-
- reportErrorWithContext(Element errorneousElement,
- MessageKind errorMessage,
- Element contextElement,
- MessageKind contextMessage) {
- compiler.reportError(
- errorneousElement,
- errorMessage,
- {'memberName': contextElement.name,
- 'className': contextElement.enclosingClass.name});
- compiler.reportInfo(contextElement, contextMessage);
- }
-
-
- FunctionSignature resolveSignature(FunctionElementX element) {
- MessageKind defaultValuesError = null;
- if (element.isFactoryConstructor) {
- FunctionExpression body = element.parseNode(compiler);
- if (body.isRedirectingFactory) {
- defaultValuesError = MessageKind.REDIRECTING_FACTORY_WITH_DEFAULT;
- }
- }
- return compiler.withCurrentElement(element, () {
- FunctionExpression node =
- compiler.parser.measure(() => element.parseNode(compiler));
- return measure(() => SignatureResolver.analyze(
- compiler, node.parameters, node.returnType, element,
- new ResolutionRegistry(compiler, element),
- defaultValuesError: defaultValuesError,
- createRealParameters: true));
- });
- }
-
- WorldImpact resolveTypedef(TypedefElementX element) {
- if (element.isResolved) return const WorldImpact();
- compiler.world.allTypedefs.add(element);
- return _resolveTypeDeclaration(element, () {
- ResolutionRegistry registry = new ResolutionRegistry(compiler, element);
- return compiler.withCurrentElement(element, () {
- return measure(() {
- assert(element.resolutionState == STATE_NOT_STARTED);
- element.resolutionState = STATE_STARTED;
- Typedef node =
- compiler.parser.measure(() => element.parseNode(compiler));
- TypedefResolverVisitor visitor =
- new TypedefResolverVisitor(compiler, element, registry);
- visitor.visit(node);
- element.resolutionState = STATE_DONE;
- return registry.worldImpact;
- });
- });
- });
- }
-
- void resolveMetadataAnnotation(MetadataAnnotationX annotation) {
- compiler.withCurrentElement(annotation.annotatedElement, () => measure(() {
- assert(annotation.resolutionState == STATE_NOT_STARTED);
- annotation.resolutionState = STATE_STARTED;
-
- Node node = annotation.parseNode(compiler);
- Element annotatedElement = annotation.annotatedElement;
- AnalyzableElement context = annotatedElement.analyzableElement;
- ClassElement classElement = annotatedElement.enclosingClass;
- if (classElement != null) {
- // The annotation is resolved in the scope of [classElement].
- classElement.ensureResolved(compiler);
- }
- assert(invariant(node, context != null,
- message: "No context found for metadata annotation "
- "on $annotatedElement."));
- ResolverVisitor visitor = visitorFor(context, useEnclosingScope: true);
- ResolutionRegistry registry = visitor.registry;
- node.accept(visitor);
- // TODO(johnniwinther): Avoid passing the [TreeElements] to
- // [compileMetadata].
- annotation.constant =
- constantCompiler.compileMetadata(annotation, node, registry.mapping);
- // TODO(johnniwinther): Register the relation between the annotation
- // and the annotated element instead. This will allow the backend to
- // retrieve the backend constant and only register metadata on the
- // elements for which it is needed. (Issue 17732).
- registry.registerMetadataConstant(annotation, annotatedElement);
- annotation.resolutionState = STATE_DONE;
- }));
- }
-
- error(Spannable node, MessageKind kind, [arguments = const {}]) {
- compiler.reportError(node, kind, arguments);
- }
-
- Link<MetadataAnnotation> resolveMetadata(Element element,
- VariableDefinitions node) {
- LinkBuilder<MetadataAnnotation> metadata =
- new LinkBuilder<MetadataAnnotation>();
- for (Metadata annotation in node.metadata.nodes) {
- ParameterMetadataAnnotation metadataAnnotation =
- new ParameterMetadataAnnotation(annotation);
- metadataAnnotation.annotatedElement = element;
- metadata.addLast(metadataAnnotation.ensureResolved(compiler));
- }
- return metadata.toLink();
- }
-}
+library dart2js.resolution.common;
+
+import '../common/tasks.dart' show
+ DeferredAction;
+import '../compiler.dart' show
+ Compiler;
+import '../diagnostics/messages.dart' show
+ MessageKind;
+import '../diagnostics/spannable.dart' show
+ Spannable;
+import '../elements/elements.dart';
+import '../tree/tree.dart';
+
+import 'registry.dart' show
+ ResolutionRegistry;
+import 'scope.dart' show
+ Scope;
+import 'type_resolver.dart' show
+ TypeResolver;
class CommonResolverVisitor<R> extends Visitor<R> {
final Compiler compiler;

Powered by Google App Engine
This is Rietveld 408576698