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

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

Issue 693183006: Revert "Move dart2js from sdk/lib/_internal/compiler to pkg/compiler" (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month 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
« no previous file with comments | « pkg/compiler/lib/src/resolution/member_impl.dart ('k') | pkg/compiler/lib/src/resolution/registry.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/resolution/members.dart
diff --git a/pkg/compiler/lib/src/resolution/members.dart b/pkg/compiler/lib/src/resolution/members.dart
deleted file mode 100644
index 937d308a4afbc195fa6be76d78d86e5b2586eeb7..0000000000000000000000000000000000000000
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ /dev/null
@@ -1,5054 +0,0 @@
-// Copyright (c) 2012, 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.
-
-part of resolution;
-
-abstract class TreeElements {
- AnalyzableElement get analyzedElement;
- Iterable<Node> get superUses;
-
- /// Iterables of the dependencies that this [TreeElement] records of
- /// [analyzedElement].
- Iterable<Element> get allElements;
- void forEachConstantNode(f(Node n, ConstantExpression c));
-
- /// A set of additional dependencies. See [registerDependency] below.
- Iterable<Element> get otherDependencies;
-
- Element operator[](Node node);
-
- // TODO(johnniwinther): Investigate whether [Node] could be a [Send].
- Selector getSelector(Node node);
- Selector getGetterSelectorInComplexSendSet(SendSet node);
- Selector getOperatorSelectorInComplexSendSet(SendSet node);
- DartType getType(Node node);
- void setSelector(Node node, Selector selector);
- void setGetterSelectorInComplexSendSet(SendSet node, Selector selector);
- void setOperatorSelectorInComplexSendSet(SendSet node, Selector selector);
-
- /// Returns the for-in loop variable for [node].
- Element getForInVariable(ForIn node);
- Selector getIteratorSelector(ForIn node);
- Selector getMoveNextSelector(ForIn node);
- Selector getCurrentSelector(ForIn node);
- void setIteratorSelector(ForIn node, Selector selector);
- void setMoveNextSelector(ForIn node, Selector selector);
- void setCurrentSelector(ForIn node, Selector selector);
- void setConstant(Node node, ConstantExpression constant);
- ConstantExpression getConstant(Node node);
- bool isAssert(Send send);
-
- /// Returns the [FunctionElement] defined by [node].
- FunctionElement getFunctionDefinition(FunctionExpression node);
-
- /// Returns target constructor for the redirecting factory body [node].
- ConstructorElement getRedirectingTargetConstructor(
- RedirectingFactoryBody node);
-
- /**
- * Returns [:true:] if [node] is a type literal.
- *
- * Resolution marks this by setting the type on the node to be the
- * type that the literal refers to.
- */
- bool isTypeLiteral(Send node);
-
- /// Returns the type that the type literal [node] refers to.
- DartType getTypeLiteralType(Send node);
-
- /// Register additional dependencies required by [analyzedElement].
- /// For example, elements that are used by a backend.
- void registerDependency(Element element);
-
- /// Returns a list of nodes that potentially mutate [element] anywhere in its
- /// scope.
- List<Node> getPotentialMutations(VariableElement element);
-
- /// Returns a list of nodes that potentially mutate [element] in [node].
- List<Node> getPotentialMutationsIn(Node node, VariableElement element);
-
- /// Returns a list of nodes that potentially mutate [element] in a closure.
- List<Node> getPotentialMutationsInClosure(VariableElement element);
-
- /// Returns a list of nodes that access [element] within a closure in [node].
- List<Node> getAccessesByClosureIn(Node node, VariableElement element);
-
- /// Returns the jump target defined by [node].
- JumpTarget getTargetDefinition(Node node);
-
- /// Returns the jump target of the [node].
- JumpTarget getTargetOf(GotoStatement node);
-
- /// Returns the label defined by [node].
- LabelDefinition getLabelDefinition(Label node);
-
- /// Returns the label that [node] targets.
- LabelDefinition getTargetLabel(GotoStatement node);
-}
-
-class TreeElementMapping implements TreeElements {
- final AnalyzableElement analyzedElement;
- Map<Spannable, Selector> _selectors;
- Map<Node, DartType> _types;
- Setlet<Node> _superUses;
- Setlet<Element> _otherDependencies;
- Map<Node, ConstantExpression> _constants;
- Map<VariableElement, List<Node>> _potentiallyMutated;
- Map<Node, Map<VariableElement, List<Node>>> _potentiallyMutatedIn;
- Map<VariableElement, List<Node>> _potentiallyMutatedInClosure;
- Map<Node, Map<VariableElement, List<Node>>> _accessedByClosureIn;
- Setlet<Element> _elements;
- Setlet<Send> _asserts;
-
- /// Map from nodes to the targets they define.
- Map<Node, JumpTarget> _definedTargets;
-
- /// Map from goto statements to their targets.
- Map<GotoStatement, JumpTarget> _usedTargets;
-
- /// Map from labels to their label definition.
- Map<Label, LabelDefinition> _definedLabels;
-
- /// Map from labeled goto statements to the labels they target.
- Map<GotoStatement, LabelDefinition> _targetLabels;
-
- final int hashCode = ++_hashCodeCounter;
- static int _hashCodeCounter = 0;
-
- TreeElementMapping(this.analyzedElement);
-
- operator []=(Node node, Element element) {
- assert(invariant(node, () {
- FunctionExpression functionExpression = node.asFunctionExpression();
- if (functionExpression != null) {
- return !functionExpression.modifiers.isExternal;
- }
- return true;
- }));
- // TODO(johnniwinther): Simplify this invariant to use only declarations in
- // [TreeElements].
- assert(invariant(node, () {
- if (!element.isErroneous && analyzedElement != null && element.isPatch) {
- return analyzedElement.implementationLibrary.isPatch;
- }
- return true;
- }));
- // TODO(ahe): Investigate why the invariant below doesn't hold.
- // assert(invariant(node,
- // getTreeElement(node) == element ||
- // getTreeElement(node) == null,
- // message: '${getTreeElement(node)}; $element'));
-
- if (_elements == null) {
- _elements = new Setlet<Element>();
- }
- _elements.add(element);
- setTreeElement(node, element);
- }
-
- operator [](Node node) => getTreeElement(node);
-
- void setType(Node node, DartType type) {
- if (_types == null) {
- _types = new Maplet<Node, DartType>();
- }
- _types[node] = type;
- }
-
- DartType getType(Node node) => _types != null ? _types[node] : null;
-
- Iterable<Node> get superUses {
- return _superUses != null ? _superUses : const <Node>[];
- }
-
- void addSuperUse(Node node) {
- if (_superUses == null) {
- _superUses = new Setlet<Node>();
- }
- _superUses.add(node);
- }
-
- Selector _getSelector(Spannable node) {
- return _selectors != null ? _selectors[node] : null;
- }
-
- void _setSelector(Spannable node, Selector selector) {
- if (_selectors == null) {
- _selectors = new Maplet<Spannable, Selector>();
- }
- _selectors[node] = selector;
- }
-
- void setSelector(Node node, Selector selector) {
- _setSelector(node, selector);
- }
-
- Selector getSelector(Node node) => _getSelector(node);
-
- int getSelectorCount() => _selectors == null ? 0 : _selectors.length;
-
- void setGetterSelectorInComplexSendSet(SendSet node, Selector selector) {
- _setSelector(node.selector, selector);
- }
-
- Selector getGetterSelectorInComplexSendSet(SendSet node) {
- return _getSelector(node.selector);
- }
-
- void setOperatorSelectorInComplexSendSet(SendSet node, Selector selector) {
- _setSelector(node.assignmentOperator, selector);
- }
-
- Selector getOperatorSelectorInComplexSendSet(SendSet node) {
- return _getSelector(node.assignmentOperator);
- }
-
- // The following methods set selectors on the "for in" node. Since
- // we're using three selectors, we need to use children of the node,
- // and we arbitrarily choose which ones.
-
- void setIteratorSelector(ForIn node, Selector selector) {
- _setSelector(node, selector);
- }
-
- Selector getIteratorSelector(ForIn node) {
- return _getSelector(node);
- }
-
- void setMoveNextSelector(ForIn node, Selector selector) {
- _setSelector(node.forToken, selector);
- }
-
- Selector getMoveNextSelector(ForIn node) {
- return _getSelector(node.forToken);
- }
-
- void setCurrentSelector(ForIn node, Selector selector) {
- _setSelector(node.inToken, selector);
- }
-
- Selector getCurrentSelector(ForIn node) {
- return _getSelector(node.inToken);
- }
-
- Element getForInVariable(ForIn node) {
- return this[node];
- }
-
- void setConstant(Node node, ConstantExpression constant) {
- if (_constants == null) {
- _constants = new Maplet<Node, ConstantExpression>();
- }
- _constants[node] = constant;
- }
-
- ConstantExpression getConstant(Node node) {
- return _constants != null ? _constants[node] : null;
- }
-
- bool isTypeLiteral(Send node) {
- return getType(node) != null;
- }
-
- DartType getTypeLiteralType(Send node) {
- return getType(node);
- }
-
- void registerDependency(Element element) {
- if (element == null) return;
- if (_otherDependencies == null) {
- _otherDependencies = new Setlet<Element>();
- }
- _otherDependencies.add(element.implementation);
- }
-
- Iterable<Element> get otherDependencies {
- return _otherDependencies != null ? _otherDependencies : const <Element>[];
- }
-
- List<Node> getPotentialMutations(VariableElement element) {
- if (_potentiallyMutated == null) return const <Node>[];
- List<Node> mutations = _potentiallyMutated[element];
- if (mutations == null) return const <Node>[];
- return mutations;
- }
-
- void registerPotentialMutation(VariableElement element, Node mutationNode) {
- if (_potentiallyMutated == null) {
- _potentiallyMutated = new Maplet<VariableElement, List<Node>>();
- }
- _potentiallyMutated.putIfAbsent(element, () => <Node>[]).add(mutationNode);
- }
-
- List<Node> getPotentialMutationsIn(Node node, VariableElement element) {
- if (_potentiallyMutatedIn == null) return const <Node>[];
- Map<VariableElement, List<Node>> mutationsIn = _potentiallyMutatedIn[node];
- if (mutationsIn == null) return const <Node>[];
- List<Node> mutations = mutationsIn[element];
- if (mutations == null) return const <Node>[];
- return mutations;
- }
-
- void registerPotentialMutationIn(Node contextNode, VariableElement element,
- Node mutationNode) {
- if (_potentiallyMutatedIn == null) {
- _potentiallyMutatedIn =
- new Maplet<Node, Map<VariableElement, List<Node>>>();
- }
- Map<VariableElement, List<Node>> mutationMap =
- _potentiallyMutatedIn.putIfAbsent(contextNode,
- () => new Maplet<VariableElement, List<Node>>());
- mutationMap.putIfAbsent(element, () => <Node>[]).add(mutationNode);
- }
-
- List<Node> getPotentialMutationsInClosure(VariableElement element) {
- if (_potentiallyMutatedInClosure == null) return const <Node>[];
- List<Node> mutations = _potentiallyMutatedInClosure[element];
- if (mutations == null) return const <Node>[];
- return mutations;
- }
-
- void registerPotentialMutationInClosure(VariableElement element,
- Node mutationNode) {
- if (_potentiallyMutatedInClosure == null) {
- _potentiallyMutatedInClosure = new Maplet<VariableElement, List<Node>>();
- }
- _potentiallyMutatedInClosure.putIfAbsent(
- element, () => <Node>[]).add(mutationNode);
- }
-
- List<Node> getAccessesByClosureIn(Node node, VariableElement element) {
- if (_accessedByClosureIn == null) return const <Node>[];
- Map<VariableElement, List<Node>> accessesIn = _accessedByClosureIn[node];
- if (accessesIn == null) return const <Node>[];
- List<Node> accesses = accessesIn[element];
- if (accesses == null) return const <Node>[];
- return accesses;
- }
-
- void setAccessedByClosureIn(Node contextNode, VariableElement element,
- Node accessNode) {
- if (_accessedByClosureIn == null) {
- _accessedByClosureIn = new Map<Node, Map<VariableElement, List<Node>>>();
- }
- Map<VariableElement, List<Node>> accessMap =
- _accessedByClosureIn.putIfAbsent(contextNode,
- () => new Maplet<VariableElement, List<Node>>());
- accessMap.putIfAbsent(element, () => <Node>[]).add(accessNode);
- }
-
- String toString() => 'TreeElementMapping($analyzedElement)';
-
- Iterable<Element> get allElements {
- return _elements != null ? _elements : const <Element>[];
- }
-
- void forEachConstantNode(f(Node n, ConstantExpression c)) {
- if (_constants != null) {
- _constants.forEach(f);
- }
- }
-
- void setAssert(Send node) {
- if (_asserts == null) {
- _asserts = new Setlet<Send>();
- }
- _asserts.add(node);
- }
-
- bool isAssert(Send node) {
- return _asserts != null && _asserts.contains(node);
- }
-
- FunctionElement getFunctionDefinition(FunctionExpression node) {
- return this[node];
- }
-
- ConstructorElement getRedirectingTargetConstructor(
- RedirectingFactoryBody node) {
- return this[node];
- }
-
- void defineTarget(Node node, JumpTarget target) {
- if (_definedTargets == null) {
- _definedTargets = new Maplet<Node, JumpTarget>();
- }
- _definedTargets[node] = target;
- }
-
- void undefineTarget(Node node) {
- if (_definedTargets != null) {
- _definedTargets.remove(node);
- if (_definedTargets.isEmpty) {
- _definedTargets = null;
- }
- }
- }
-
- JumpTarget getTargetDefinition(Node node) {
- return _definedTargets != null ? _definedTargets[node] : null;
- }
-
- void registerTargetOf(GotoStatement node, JumpTarget target) {
- if (_usedTargets == null) {
- _usedTargets = new Maplet<GotoStatement, JumpTarget>();
- }
- _usedTargets[node] = target;
- }
-
- JumpTarget getTargetOf(GotoStatement node) {
- return _usedTargets != null ? _usedTargets[node] : null;
- }
-
- void defineLabel(Label label, LabelDefinition target) {
- if (_definedLabels == null) {
- _definedLabels = new Maplet<Label, LabelDefinition>();
- }
- _definedLabels[label] = target;
- }
-
- void undefineLabel(Label label) {
- if (_definedLabels != null) {
- _definedLabels.remove(label);
- if (_definedLabels.isEmpty) {
- _definedLabels = null;
- }
- }
- }
-
- LabelDefinition getLabelDefinition(Label label) {
- return _definedLabels != null ? _definedLabels[label] : null;
- }
-
- void registerTargetLabel(GotoStatement node, LabelDefinition label) {
- assert(node.target != null);
- if (_targetLabels == null) {
- _targetLabels = new Maplet<GotoStatement, LabelDefinition>();
- }
- _targetLabels[node] = label;
- }
-
- LabelDefinition getTargetLabel(GotoStatement node) {
- assert(node.target != null);
- return _targetLabels != null ? _targetLabels[node] : null;
- }
-}
-
-class ResolverTask extends CompilerTask {
- final ConstantCompiler constantCompiler;
-
- ResolverTask(Compiler compiler, this.constantCompiler) : super(compiler);
-
- String get name => 'Resolver';
-
- TreeElements resolve(Element element) {
- return measure(() {
- if (Elements.isErroneousElement(element)) return null;
-
- processMetadata([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();
- } 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);
- }
- }
-
- void checkMatchingPatchParameters(FunctionElement origin,
- Link<Element> originParameters,
- Link<Element> patchParameters) {
- while (!originParameters.isEmpty) {
- ParameterElementX originParameter = originParameters.head;
- ParameterElementX patchParameter = patchParameters.head;
- // TODO(johnniwinther): Remove the conditional patching when we never
- // resolve the same method twice.
- if (!originParameter.isPatched) {
- originParameter.applyPatch(patchParameter);
- } else {
- assert(invariant(origin, originParameter.patch == patchParameter,
- message: "Inconsistent repatch of $originParameter."));
- }
- DartType originParameterType = originParameter.computeType(compiler);
- DartType patchParameterType = patchParameter.computeType(compiler);
- if (originParameterType != patchParameterType) {
- compiler.reportError(
- originParameter.parseNode(compiler),
- MessageKind.PATCH_PARAMETER_TYPE_MISMATCH,
- {'methodName': origin.name,
- 'parameterName': originParameter.name,
- 'originParameterType': originParameterType,
- 'patchParameterType': patchParameterType});
- compiler.reportInfo(patchParameter,
- MessageKind.PATCH_POINT_TO_PARAMETER,
- {'parameterName': patchParameter.name});
- } else {
- // Hack: Use unparser to test parameter equality. This only works
- // because we are restricting patch uses and the approach cannot be used
- // elsewhere.
-
- // The node contains the type, so there is a potential overlap.
- // Therefore we only check the text if the types are identical.
- String originParameterText =
- originParameter.parseNode(compiler).toString();
- String patchParameterText =
- patchParameter.parseNode(compiler).toString();
- if (originParameterText != patchParameterText
- // We special case the list constructor because of the
- // optional parameter.
- && origin != compiler.unnamedListConstructor) {
- compiler.reportError(
- originParameter.parseNode(compiler),
- MessageKind.PATCH_PARAMETER_MISMATCH,
- {'methodName': origin.name,
- 'originParameter': originParameterText,
- 'patchParameter': patchParameterText});
- compiler.reportInfo(patchParameter,
- MessageKind.PATCH_POINT_TO_PARAMETER,
- {'parameterName': patchParameter.name});
- }
- }
-
- originParameters = originParameters.tail;
- patchParameters = patchParameters.tail;
- }
- }
-
- void checkMatchingPatchSignatures(FunctionElement origin,
- FunctionElement patch) {
- // TODO(johnniwinther): Show both origin and patch locations on errors.
- FunctionExpression originTree = origin.node;
- FunctionSignature originSignature = origin.functionSignature;
- FunctionExpression patchTree = patch.node;
- FunctionSignature patchSignature = patch.functionSignature;
-
- if (originSignature.type.returnType != patchSignature.type.returnType) {
- compiler.withCurrentElement(patch, () {
- Node errorNode =
- patchTree.returnType != null ? patchTree.returnType : patchTree;
- error(errorNode, MessageKind.PATCH_RETURN_TYPE_MISMATCH,
- {'methodName': origin.name,
- 'originReturnType': originSignature.type.returnType,
- 'patchReturnType': patchSignature.type.returnType});
- });
- }
- if (originSignature.requiredParameterCount !=
- patchSignature.requiredParameterCount) {
- compiler.withCurrentElement(patch, () {
- error(patchTree,
- MessageKind.PATCH_REQUIRED_PARAMETER_COUNT_MISMATCH,
- {'methodName': origin.name,
- 'originParameterCount': originSignature.requiredParameterCount,
- 'patchParameterCount': patchSignature.requiredParameterCount});
- });
- } else {
- checkMatchingPatchParameters(origin,
- originSignature.requiredParameters,
- patchSignature.requiredParameters);
- }
- if (originSignature.optionalParameterCount != 0 &&
- patchSignature.optionalParameterCount != 0) {
- if (originSignature.optionalParametersAreNamed !=
- patchSignature.optionalParametersAreNamed) {
- compiler.withCurrentElement(patch, () {
- error(patchTree,
- MessageKind.PATCH_OPTIONAL_PARAMETER_NAMED_MISMATCH,
- {'methodName': origin.name});
- });
- }
- }
- if (originSignature.optionalParameterCount !=
- patchSignature.optionalParameterCount) {
- compiler.withCurrentElement(patch, () {
- error(patchTree,
- MessageKind.PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH,
- {'methodName': origin.name,
- 'originParameterCount': originSignature.optionalParameterCount,
- 'patchParameterCount': patchSignature.optionalParameterCount});
- });
- } else {
- checkMatchingPatchParameters(origin,
- originSignature.optionalParameters,
- patchSignature.optionalParameters);
- }
- }
-
- static void processAsyncMarker(Compiler compiler,
- BaseFunctionElementX element) {
- FunctionExpression functionExpression = element.node;
- AsyncModifier asyncModifier = functionExpression.asyncModifier;
- if (asyncModifier != null) {
- if (!compiler.enableAsyncAwait) {
- compiler.reportError(asyncModifier,
- MessageKind.EXPERIMENTAL_ASYNC_AWAIT,
- {'modifier': element.asyncMarker});
- } else if (!compiler.analyzeOnly) {
- compiler.reportError(asyncModifier,
- MessageKind.EXPERIMENTAL_ASYNC_AWAIT,
- {'modifier': element.asyncMarker});
- }
-
- 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 (functionExpression.body.asReturn() != null &&
- element.asyncMarker.isYielding) {
- compiler.reportError(asyncModifier,
- MessageKind.YIELDING_MODIFIER_ON_ARROW_BODY,
- {'modifier': element.asyncMarker});
- }
- }
- }
-
- TreeElements resolveMethodElement(FunctionElementX element) {
- assert(invariant(element, element.isDeclaration));
- return compiler.withCurrentElement(element, () {
- bool isConstructor =
- identical(element.kind, ElementKind.GENERATIVE_CONSTRUCTOR);
- 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 element.resolvedAst.elements;
- }
- if (element.isSynthesized) {
- if (isConstructor) {
- 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.mapping;
- } else {
- assert(element.isDeferredLoaderGetter);
- return _ensureTreeElements(element);
- }
- }
- element.parseNode(compiler);
- element.computeType(compiler);
- processAsyncMarker(compiler, element);
- if (element.isPatched) {
- FunctionElementX patch = element.patch;
- compiler.withCurrentElement(patch, () {
- patch.parseNode(compiler);
- patch.computeType(compiler);
- });
- checkMatchingPatchSignatures(element, patch);
- element = patch;
- processAsyncMarker(compiler, element);
- }
- return compiler.withCurrentElement(element, () {
- FunctionExpression tree = element.node;
- if (tree.modifiers.isExternal) {
- error(tree, MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION);
- return null;
- }
- if (isConstructor || element.isFactoryConstructor) {
- if (tree.returnType != null) {
- error(tree, MessageKind.CONSTRUCTOR_WITH_RETURN_TYPE);
- }
- if (element.modifiers.isConst &&
- tree.hasBody() &&
- !tree.isRedirectingFactory) {
- compiler.reportError(tree, MessageKind.CONST_CONSTRUCTOR_HAS_BODY);
- }
- }
-
- ResolverVisitor visitor = visitorFor(element);
- ResolutionRegistry registry = visitor.registry;
- registry.defineFunction(tree, element);
- visitor.setupFunction(tree, element);
-
- if (isConstructor && !element.isForwardingConstructor) {
- // 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);
- FunctionElement redirection =
- resolver.resolveInitializers(element, tree);
- if (redirection != null) {
- resolveRedirectingConstructor(resolver, tree, element, redirection);
- }
- } else if (element.isForwardingConstructor) {
- // Initializers will be checked on the original constructor.
- } 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);
- }
- }
- return resolutionTree;
- });
- });
- }
-
- /// 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);
- }
-
- TreeElements 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) {
- 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.mapping;
- }
-
- 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);
- 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;
- InterfaceType factoryType = treeElements.getType(redirectionNode);
-
- 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);
- if (!element.isProxy &&
- metadata.constant.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;
- }
-
- // 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)) {
- compiler.internalError(member,
- "Inaccessible abstract field for accessor");
- }
- AbstractFieldElement field = lookupElement;
-
- FunctionElementX getter = field.getter;
- if (getter == null) return;
- FunctionElementX 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));
- });
- }
-
- TreeElements resolveTypedef(TypedefElementX element) {
- if (element.isResolved) return element.treeElements;
- 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.mapping;
- });
- });
- });
- }
-
- 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 {}]) {
- // TODO(ahe): Make non-fatal.
- compiler.reportFatalError(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();
- }
-}
-
-class InitializerResolver {
- final ResolverVisitor visitor;
- final Map<Element, Node> initialized;
- Link<Node> initializers;
- bool hasSuper;
-
- InitializerResolver(this.visitor)
- : initialized = new Map<Element, Node>(), hasSuper = false;
-
- ResolutionRegistry get registry => visitor.registry;
-
- error(Node node, MessageKind kind, [arguments = const {}]) {
- visitor.error(node, kind, arguments);
- }
-
- warning(Node node, MessageKind kind, [arguments = const {}]) {
- visitor.warning(node, kind, arguments);
- }
-
- 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, Node existing) {
- visitor.compiler.reportError(
- init,
- MessageKind.DUPLICATE_INITIALIZER, {'fieldName': field.name});
- visitor.compiler.reportInfo(
- existing,
- MessageKind.ALREADY_INITIALIZED, {'fieldName': field.name});
- }
-
- void checkForDuplicateInitializers(FieldElementX field, Node init) {
- // [field] can be null if it could not be resolved.
- if (field == null) return;
- String name = field.name;
- if (initialized.containsKey(field)) {
- reportDuplicateInitializerError(field, init, initialized[field]);
- } else if (field.isFinal) {
- field.parseNode(visitor.compiler);
- Expression initializer = field.initializer;
- if (initializer != null) {
- reportDuplicateInitializerError(field, init, initializer);
- }
- }
- initialized[field] = init;
- }
-
- void resolveFieldInitializer(FunctionElement constructor, 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;
- if (isFieldInitializer(init)) {
- target = constructor.enclosingClass.lookupLocalMember(name);
- if (target == null) {
- error(selector, MessageKind.CANNOT_RESOLVE, {'name': name});
- } else if (target.kind != ElementKind.FIELD) {
- error(selector, MessageKind.NOT_A_FIELD, {'fieldName': name});
- } else if (!target.isInstanceMember) {
- error(selector, MessageKind.INIT_STATIC_FIELD, {'fieldName': name});
- }
- } else {
- error(init, MessageKind.INVALID_RECEIVER_IN_INITIALIZER);
- }
- registry.useElement(init, target);
- registry.registerStaticUse(target);
- checkForDuplicateInitializers(target, init);
- // Resolve initializing value.
- visitor.visitInStaticContext(init.arguments.head);
- }
-
- ClassElement getSuperOrThisLookupTarget(FunctionElement constructor,
- bool isSuperCall,
- Node diagnosticNode) {
- ClassElement lookupTarget = constructor.enclosingClass;
- if (isSuperCall) {
- // Calculate correct lookup target and constructor name.
- if (identical(lookupTarget, visitor.compiler.objectClass)) {
- error(diagnosticNode, MessageKind.SUPER_INITIALIZER_IN_OBJECT);
- } else {
- return lookupTarget.supertype.element;
- }
- }
- return lookupTarget;
- }
-
- Element resolveSuperOrThisForSend(FunctionElement constructor,
- FunctionExpression functionNode,
- Send call) {
- // Resolve the selector and the arguments.
- ResolverTask resolver = visitor.compiler.resolver;
- visitor.inStaticContext(() {
- visitor.resolveSelector(call, null);
- visitor.resolveArguments(call.argumentsNode);
- });
- Selector selector = registry.getSelector(call);
- bool isSuperCall = Initializers.isSuperConstructorCall(call);
-
- ClassElement lookupTarget = getSuperOrThisLookupTarget(constructor,
- isSuperCall,
- call);
- Selector constructorSelector =
- visitor.getRedirectingThisOrSuperConstructorSelector(call);
- FunctionElement calledConstructor =
- lookupTarget.lookupConstructor(constructorSelector);
-
- final bool isImplicitSuperCall = false;
- final String className = lookupTarget.name;
- verifyThatConstructorMatchesCall(constructor,
- calledConstructor,
- selector,
- isImplicitSuperCall,
- call,
- className,
- constructorSelector);
-
- registry.useElement(call, calledConstructor);
- registry.registerStaticUse(calledConstructor);
- return calledConstructor;
- }
-
- void resolveImplicitSuperConstructorSend(FunctionElement constructor,
- FunctionExpression functionNode) {
- // If the class has a super resolve the implicit super call.
- ClassElement classElement = constructor.enclosingClass;
- ClassElement superClass = classElement.superclass;
- if (classElement != visitor.compiler.objectClass) {
- assert(superClass != null);
- assert(superClass.resolutionState == STATE_DONE);
- String constructorName = '';
- Selector callToMatch = new Selector.call(
- constructorName,
- classElement.library,
- 0);
-
- final bool isSuperCall = true;
- ClassElement lookupTarget = getSuperOrThisLookupTarget(constructor,
- isSuperCall,
- functionNode);
- Selector constructorSelector = new Selector.callDefaultConstructor(
- visitor.enclosingElement.library);
- Element calledConstructor = lookupTarget.lookupConstructor(
- constructorSelector);
-
- final String className = lookupTarget.name;
- final bool isImplicitSuperCall = true;
- verifyThatConstructorMatchesCall(constructor,
- calledConstructor,
- callToMatch,
- isImplicitSuperCall,
- functionNode,
- className,
- constructorSelector);
- registry.registerImplicitSuperCall(calledConstructor);
- registry.registerStaticUse(calledConstructor);
- }
- }
-
- void verifyThatConstructorMatchesCall(
- FunctionElement caller,
- FunctionElement lookedupConstructor,
- Selector call,
- bool isImplicitSuperCall,
- Node diagnosticNode,
- String className,
- Selector constructorSelector) {
- if (lookedupConstructor == null
- || !lookedupConstructor.isGenerativeConstructor) {
- String fullConstructorName = Elements.constructorNameForDiagnostics(
- className,
- constructorSelector.name);
- MessageKind kind = isImplicitSuperCall
- ? MessageKind.CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT
- : MessageKind.CANNOT_RESOLVE_CONSTRUCTOR;
- visitor.compiler.reportError(
- diagnosticNode, kind, {'constructorName': fullConstructorName});
- } else {
- lookedupConstructor.computeSignature(visitor.compiler);
- if (!call.applies(lookedupConstructor, visitor.compiler.world)) {
- MessageKind kind = isImplicitSuperCall
- ? MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT
- : MessageKind.NO_MATCHING_CONSTRUCTOR;
- visitor.compiler.reportError(diagnosticNode, kind);
- } else if (caller.isConst
- && !lookedupConstructor.isConst) {
- visitor.compiler.reportError(
- diagnosticNode, MessageKind.CONST_CALLS_NON_CONST);
- }
- }
- }
-
- /**
- * Resolve all initializers of this constructor. In the case of a redirecting
- * constructor, the resolved constructor's function element is returned.
- */
- FunctionElement resolveInitializers(FunctionElement constructor,
- FunctionExpression functionNode) {
- // 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((ParameterElement element) {
- if (element.isInitializingFormal) {
- InitializingFormalElement initializingFormal = element;
- checkForDuplicateInitializers(initializingFormal.fieldElement,
- element.initializer);
- }
- });
-
- if (functionNode.initializers == null) {
- initializers = const Link<Node>();
- } else {
- initializers = functionNode.initializers.nodes;
- }
- FunctionElement result;
- 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(constructor, init);
- } else if (link.head.asSend() != null) {
- final Send call = link.head.asSend();
- if (call.argumentsNode == null) {
- error(link.head, MessageKind.INVALID_INITIALIZER);
- continue;
- }
- if (Initializers.isSuperConstructorCall(call)) {
- if (resolvedSuper) {
- error(call, MessageKind.DUPLICATE_SUPER_INITIALIZER);
- }
- resolveSuperOrThisForSend(constructor, functionNode, call);
- 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) {
- error(functionNode, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_BODY);
- }
- // Check that there are no other initializers.
- if (!initializers.tail.isEmpty) {
- error(call, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER);
- }
- // Check that there are no field initializing parameters.
- Compiler compiler = visitor.compiler;
- FunctionSignature signature = constructor.functionSignature;
- signature.forEachParameter((ParameterElement parameter) {
- if (parameter.isInitializingFormal) {
- Node node = parameter.node;
- error(node, MessageKind.INITIALIZING_FORMAL_NOT_ALLOWED);
- }
- });
- return resolveSuperOrThisForSend(constructor, functionNode, call);
- } else {
- visitor.error(call, MessageKind.CONSTRUCTOR_CALL_EXPECTED);
- return null;
- }
- } else {
- error(link.head, MessageKind.INVALID_INITIALIZER);
- }
- }
- if (!resolvedSuper) {
- resolveImplicitSuperConstructorSend(constructor, functionNode);
- }
- return null; // If there was no redirection always return null.
- }
-}
-
-class CommonResolverVisitor<R> extends Visitor<R> {
- final Compiler compiler;
-
- CommonResolverVisitor(Compiler this.compiler);
-
- R visitNode(Node node) {
- internalError(node,
- 'internal error: Unhandled node: ${node.getObjectDescription()}');
- return null;
- }
-
- R visitEmptyStatement(Node node) => null;
-
- /** Convenience method for visiting nodes that may be null. */
- R visit(Node node) => (node == null) ? null : node.accept(this);
-
- void error(Spannable node, MessageKind kind, [Map arguments = const {}]) {
- compiler.reportFatalError(node, kind, arguments);
- }
-
- void warning(Spannable node, MessageKind kind, [Map arguments = const {}]) {
- compiler.reportWarning(node, kind, arguments);
- }
-
- void internalError(Spannable node, message) {
- compiler.internalError(node, message);
- }
-
- void addDeferredAction(Element element, DeferredAction action) {
- compiler.enqueuer.resolution.addDeferredAction(element, action);
- }
-}
-
-abstract class LabelScope {
- LabelScope get outer;
- LabelDefinition lookup(String label);
-}
-
-class LabeledStatementLabelScope implements LabelScope {
- final LabelScope outer;
- final Map<String, LabelDefinition> labels;
- LabeledStatementLabelScope(this.outer, this.labels);
- LabelDefinition lookup(String labelName) {
- LabelDefinition label = labels[labelName];
- if (label != null) return label;
- return outer.lookup(labelName);
- }
-}
-
-class SwitchLabelScope implements LabelScope {
- final LabelScope outer;
- final Map<String, LabelDefinition> caseLabels;
-
- SwitchLabelScope(this.outer, this.caseLabels);
-
- LabelDefinition lookup(String labelName) {
- LabelDefinition result = caseLabels[labelName];
- if (result != null) return result;
- return outer.lookup(labelName);
- }
-}
-
-class EmptyLabelScope implements LabelScope {
- const EmptyLabelScope();
- LabelDefinition lookup(String label) => null;
- LabelScope get outer {
- throw 'internal error: empty label scope has no outer';
- }
-}
-
-class StatementScope {
- LabelScope labels;
- Link<JumpTarget> breakTargetStack;
- Link<JumpTarget> continueTargetStack;
- // Used to provide different numbers to statements if one is inside the other.
- // Can be used to make otherwise duplicate labels unique.
- int nestingLevel = 0;
-
- StatementScope()
- : labels = const EmptyLabelScope(),
- breakTargetStack = const Link<JumpTarget>(),
- continueTargetStack = const Link<JumpTarget>();
-
- LabelDefinition lookupLabel(String label) {
- return labels.lookup(label);
- }
-
- JumpTarget currentBreakTarget() =>
- breakTargetStack.isEmpty ? null : breakTargetStack.head;
-
- JumpTarget currentContinueTarget() =>
- continueTargetStack.isEmpty ? null : continueTargetStack.head;
-
- void enterLabelScope(Map<String, LabelDefinition> elements) {
- labels = new LabeledStatementLabelScope(labels, elements);
- nestingLevel++;
- }
-
- void exitLabelScope() {
- nestingLevel--;
- labels = labels.outer;
- }
-
- void enterLoop(JumpTarget element) {
- breakTargetStack = breakTargetStack.prepend(element);
- continueTargetStack = continueTargetStack.prepend(element);
- nestingLevel++;
- }
-
- void exitLoop() {
- nestingLevel--;
- breakTargetStack = breakTargetStack.tail;
- continueTargetStack = continueTargetStack.tail;
- }
-
- void enterSwitch(JumpTarget breakElement,
- Map<String, LabelDefinition> continueElements) {
- breakTargetStack = breakTargetStack.prepend(breakElement);
- labels = new SwitchLabelScope(labels, continueElements);
- nestingLevel++;
- }
-
- void exitSwitch() {
- nestingLevel--;
- breakTargetStack = breakTargetStack.tail;
- labels = labels.outer;
- }
-}
-
-class TypeResolver {
- final Compiler compiler;
-
- TypeResolver(this.compiler);
-
- /// Tries to resolve the type name as an element.
- Element resolveTypeName(Identifier prefixName,
- Identifier typeName,
- Scope scope,
- {bool deferredIsMalformed: true}) {
- Element element;
- bool deferredTypeAnnotation = false;
- if (prefixName != null) {
- Element prefixElement =
- lookupInScope(compiler, prefixName, scope, prefixName.source);
- if (prefixElement != null && prefixElement.isPrefix) {
- // The receiver is a prefix. Lookup in the imported members.
- PrefixElement prefix = prefixElement;
- element = prefix.lookupLocalMember(typeName.source);
- // TODO(17260, sigurdm): The test for DartBackend is there because
- // dart2dart outputs malformed types with prefix.
- if (element != null &&
- prefix.isDeferred &&
- deferredIsMalformed &&
- compiler.backend is! DartBackend) {
- element = new ErroneousElementX(MessageKind.DEFERRED_TYPE_ANNOTATION,
- {'node': typeName},
- element.name,
- element);
- }
- } else {
- // The caller of this method will create the ErroneousElement for
- // the MalformedType.
- element = null;
- }
- } else {
- String stringValue = typeName.source;
- element = lookupInScope(compiler, typeName, scope, typeName.source);
- }
- return element;
- }
-
- DartType resolveTypeAnnotation(MappingVisitor visitor, TypeAnnotation node,
- {bool malformedIsError: false,
- bool deferredIsMalformed: true}) {
- ResolutionRegistry registry = visitor.registry;
-
- Identifier typeName;
- DartType type;
-
- DartType checkNoTypeArguments(DartType type) {
- List<DartType> arguments = new List<DartType>();
- bool hasTypeArgumentMismatch = resolveTypeArguments(
- visitor, node, const <DartType>[], arguments);
- if (hasTypeArgumentMismatch) {
- return new MalformedType(
- new ErroneousElementX(MessageKind.TYPE_ARGUMENT_COUNT_MISMATCH,
- {'type': node}, typeName.source, visitor.enclosingElement),
- type, arguments);
- }
- return type;
- }
-
- Identifier prefixName;
- Send send = node.typeName.asSend();
- if (send != null) {
- // The type name is of the form [: prefix . identifier :].
- prefixName = send.receiver.asIdentifier();
- typeName = send.selector.asIdentifier();
- } else {
- typeName = node.typeName.asIdentifier();
- if (identical(typeName.source, 'void')) {
- type = const VoidType();
- checkNoTypeArguments(type);
- registry.useType(node, type);
- return type;
- } else if (identical(typeName.source, 'dynamic')) {
- type = const DynamicType();
- checkNoTypeArguments(type);
- registry.useType(node, type);
- return type;
- }
- }
-
- Element element = resolveTypeName(prefixName, typeName, visitor.scope,
- deferredIsMalformed: deferredIsMalformed);
-
- DartType reportFailureAndCreateType(MessageKind messageKind,
- Map messageArguments,
- {DartType userProvidedBadType,
- Element erroneousElement}) {
- if (malformedIsError) {
- visitor.error(node, messageKind, messageArguments);
- } else {
- registry.registerThrowRuntimeError();
- visitor.warning(node, messageKind, messageArguments);
- }
- if (erroneousElement == null) {
- erroneousElement = new ErroneousElementX(
- messageKind, messageArguments, typeName.source,
- visitor.enclosingElement);
- }
- List<DartType> arguments = <DartType>[];
- resolveTypeArguments(visitor, node, const <DartType>[], arguments);
- return new MalformedType(erroneousElement,
- userProvidedBadType, arguments);
- }
-
- // Try to construct the type from the element.
- if (element == null) {
- type = reportFailureAndCreateType(
- MessageKind.CANNOT_RESOLVE_TYPE, {'typeName': node.typeName});
- } else if (element.isAmbiguous) {
- AmbiguousElement ambiguous = element;
- type = reportFailureAndCreateType(
- ambiguous.messageKind, ambiguous.messageArguments);
- ambiguous.diagnose(registry.mapping.analyzedElement, compiler);
- } else if (element.isErroneous) {
- ErroneousElement erroneousElement = element;
- type = reportFailureAndCreateType(
- erroneousElement.messageKind, erroneousElement.messageArguments,
- erroneousElement: erroneousElement);
- } else if (!element.impliesType) {
- type = reportFailureAndCreateType(
- MessageKind.NOT_A_TYPE, {'node': node.typeName});
- } else {
- bool addTypeVariableBoundsCheck = false;
- if (element.isClass) {
- ClassElement cls = element;
- // TODO(johnniwinther): [_ensureClassWillBeResolved] should imply
- // [computeType].
- compiler.resolver._ensureClassWillBeResolved(cls);
- element.computeType(compiler);
- List<DartType> arguments = <DartType>[];
- bool hasTypeArgumentMismatch = resolveTypeArguments(
- visitor, node, cls.typeVariables, arguments);
- if (hasTypeArgumentMismatch) {
- type = new BadInterfaceType(cls.declaration,
- new InterfaceType.forUserProvidedBadType(cls.declaration,
- arguments));
- } else {
- if (arguments.isEmpty) {
- type = cls.rawType;
- } else {
- type = new InterfaceType(cls.declaration, arguments.toList(growable: false));
- addTypeVariableBoundsCheck = true;
- }
- }
- } else if (element.isTypedef) {
- TypedefElement typdef = element;
- // TODO(johnniwinther): [ensureResolved] should imply [computeType].
- typdef.ensureResolved(compiler);
- element.computeType(compiler);
- List<DartType> arguments = <DartType>[];
- bool hasTypeArgumentMismatch = resolveTypeArguments(
- visitor, node, typdef.typeVariables, arguments);
- if (hasTypeArgumentMismatch) {
- type = new BadTypedefType(typdef,
- new TypedefType.forUserProvidedBadType(typdef, arguments));
- } else {
- if (arguments.isEmpty) {
- type = typdef.rawType;
- } else {
- type = new TypedefType(typdef, arguments.toList(growable: false));
- addTypeVariableBoundsCheck = true;
- }
- }
- } else if (element.isTypeVariable) {
- Element outer =
- visitor.enclosingElement.outermostEnclosingMemberOrTopLevel;
- bool isInFactoryConstructor =
- outer != null && outer.isFactoryConstructor;
- if (!outer.isClass &&
- !outer.isTypedef &&
- !isInFactoryConstructor &&
- Elements.isInStaticContext(visitor.enclosingElement)) {
- registry.registerThrowRuntimeError();
- type = reportFailureAndCreateType(
- MessageKind.TYPE_VARIABLE_WITHIN_STATIC_MEMBER,
- {'typeVariableName': node},
- userProvidedBadType: element.computeType(compiler));
- } else {
- type = element.computeType(compiler);
- }
- type = checkNoTypeArguments(type);
- } else {
- compiler.internalError(node,
- "Unexpected element kind ${element.kind}.");
- }
- if (addTypeVariableBoundsCheck) {
- registry.registerTypeVariableBoundCheck();
- visitor.addDeferredAction(
- visitor.enclosingElement,
- () => checkTypeVariableBounds(node, type));
- }
- }
- registry.useType(node, type);
- return type;
- }
-
- /// Checks the type arguments of [type] against the type variable bounds.
- void checkTypeVariableBounds(TypeAnnotation node, GenericType type) {
- void checkTypeVariableBound(_, DartType typeArgument,
- TypeVariableType typeVariable,
- DartType bound) {
- if (!compiler.types.isSubtype(typeArgument, bound)) {
- compiler.reportWarning(node,
- MessageKind.INVALID_TYPE_VARIABLE_BOUND,
- {'typeVariable': typeVariable,
- 'bound': bound,
- 'typeArgument': typeArgument,
- 'thisType': type.element.thisType});
- }
- };
-
- compiler.types.checkTypeVariableBounds(type, checkTypeVariableBound);
- }
-
- /**
- * Resolves the type arguments of [node] and adds these to [arguments].
- *
- * Returns [: true :] if the number of type arguments did not match the
- * number of type variables.
- */
- bool resolveTypeArguments(MappingVisitor visitor,
- TypeAnnotation node,
- List<DartType> typeVariables,
- List<DartType> arguments) {
- if (node.typeArguments == null) {
- return false;
- }
- int expectedVariables = typeVariables.length;
- int index = 0;
- bool typeArgumentCountMismatch = false;
- for (Link<Node> typeArguments = node.typeArguments.nodes;
- !typeArguments.isEmpty;
- typeArguments = typeArguments.tail, index++) {
- if (index > expectedVariables - 1) {
- visitor.warning(
- typeArguments.head, MessageKind.ADDITIONAL_TYPE_ARGUMENT);
- typeArgumentCountMismatch = true;
- }
- DartType argType = resolveTypeAnnotation(visitor, typeArguments.head);
- // TODO(karlklose): rewrite to not modify [arguments].
- arguments.add(argType);
- }
- if (index < expectedVariables) {
- visitor.warning(node.typeArguments,
- MessageKind.MISSING_TYPE_ARGUMENT);
- typeArgumentCountMismatch = true;
- }
- return typeArgumentCountMismatch;
- }
-}
-
-/**
- * Common supertype for resolver visitors that record resolutions in a
- * [ResolutionRegistry].
- */
-abstract class MappingVisitor<T> extends CommonResolverVisitor<T> {
- final ResolutionRegistry registry;
- final TypeResolver typeResolver;
- /// The current enclosing element for the visited AST nodes.
- Element get enclosingElement;
- /// The current scope of the visitor.
- Scope get scope;
-
- MappingVisitor(Compiler compiler, ResolutionRegistry this.registry)
- : typeResolver = new TypeResolver(compiler),
- super(compiler);
-
- AsyncMarker get currentAsyncMarker => AsyncMarker.SYNC;
-
- /// Add [element] to the current scope and check for duplicate definitions.
- void addToScope(Element element) {
- Element existing = scope.add(element);
- if (existing != element) {
- reportDuplicateDefinition(element.name, element, existing);
- }
- }
-
- void checkLocalDefinitionName(Node node, Element element) {
- if (currentAsyncMarker != AsyncMarker.SYNC) {
- if (element.name == 'yield' ||
- element.name == 'async' ||
- element.name == 'await') {
- compiler.reportError(
- node, MessageKind.ASYNC_KEYWORD_AS_IDENTIFIER,
- {'keyword': element.name,
- 'modifier': currentAsyncMarker});
- }
- }
- }
-
- /// Register [node] as the definition of [element].
- void defineLocalVariable(Node node, LocalVariableElement element) {
- invariant(node, element != null);
- checkLocalDefinitionName(node, element);
- registry.defineElement(node, element);
- }
-
- void reportDuplicateDefinition(String name,
- Spannable definition,
- Spannable existing) {
- compiler.reportError(definition,
- MessageKind.DUPLICATE_DEFINITION, {'name': name});
- compiler.reportInfo(existing,
- MessageKind.EXISTING_DEFINITION, {'name': name});
- }
-}
-
-/**
- * Core implementation of resolution.
- *
- * Do not subclass or instantiate this class outside this library
- * except for testing.
- */
-class ResolverVisitor extends MappingVisitor<ResolutionResult> {
- /**
- * The current enclosing element for the visited AST nodes.
- *
- * This field is updated when nested closures are visited.
- */
- Element enclosingElement;
- bool inInstanceContext;
- bool inCheckContext;
- bool inCatchBlock;
-
- Scope scope;
- ClassElement currentClass;
- ExpressionStatement currentExpressionStatement;
- bool sendIsMemberAccess = false;
- StatementScope statementScope;
- int allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION
- | ElementCategory.IMPLIES_TYPE;
-
- /**
- * Record of argument nodes to JS_INTERCEPTOR_CONSTANT for deferred
- * processing.
- */
- Set<Node> argumentsToJsInterceptorConstant = null;
-
- /// When visiting the type declaration of the variable in a [ForIn] loop,
- /// the initializer of the variable is implicit and we should not emit an
- /// error when verifying that all final variables are initialized.
- bool allowFinalWithoutInitializer = false;
-
- /// The nodes for which variable access and mutation must be registered in
- /// order to determine when the static type of variables types is promoted.
- Link<Node> promotionScope = const Link<Node>();
-
- bool isPotentiallyMutableTarget(Element target) {
- if (target == null) return false;
- return (target.isVariable || target.isParameter) &&
- !(target.isFinal || target.isConst);
- }
-
- // TODO(ahe): Find a way to share this with runtime implementation.
- static final RegExp symbolValidationPattern =
- new RegExp(r'^(?:[a-zA-Z$][a-zA-Z$0-9_]*\.)*(?:[a-zA-Z$][a-zA-Z$0-9_]*=?|'
- r'-|'
- r'unary-|'
- r'\[\]=|'
- r'~|'
- r'==|'
- r'\[\]|'
- r'\*|'
- r'/|'
- r'%|'
- r'~/|'
- r'\+|'
- r'<<|'
- r'>>|'
- r'>=|'
- r'>|'
- r'<=|'
- r'<|'
- r'&|'
- r'\^|'
- r'\|'
- r')$');
-
- ResolverVisitor(Compiler compiler,
- Element element,
- ResolutionRegistry registry,
- {bool useEnclosingScope: false})
- : this.enclosingElement = element,
- // When the element is a field, we are actually resolving its
- // initial value, which should not have access to instance
- // fields.
- inInstanceContext = (element.isInstanceMember && !element.isField)
- || element.isGenerativeConstructor,
- this.currentClass = element.isClassMember ? element.enclosingClass
- : null,
- this.statementScope = new StatementScope(),
- scope = useEnclosingScope
- ? Scope.buildEnclosingScope(element) : element.buildScope(),
- // The type annotations on a typedef do not imply type checks.
- // TODO(karlklose): clean this up (dartbug.com/8870).
- inCheckContext = compiler.enableTypeAssertions &&
- !element.isLibrary &&
- !element.isTypedef &&
- !element.enclosingElement.isTypedef,
- inCatchBlock = false,
- super(compiler, registry);
-
- AsyncMarker get currentAsyncMarker {
- if (enclosingElement is FunctionElement) {
- FunctionElement function = enclosingElement;
- return function.asyncMarker;
- }
- return AsyncMarker.SYNC;
- }
-
- Element reportLookupErrorIfAny(Element result, Node node, String name) {
- if (!Elements.isUnresolved(result)) {
- if (!inInstanceContext && result.isInstanceMember) {
- compiler.reportError(
- node, MessageKind.NO_INSTANCE_AVAILABLE, {'name': name});
- return new ErroneousElementX(MessageKind.NO_INSTANCE_AVAILABLE,
- {'name': name},
- name, enclosingElement);
- } else if (result.isAmbiguous) {
- AmbiguousElement ambiguous = result;
- compiler.reportError(
- node, ambiguous.messageKind, ambiguous.messageArguments);
- ambiguous.diagnose(enclosingElement, compiler);
- return new ErroneousElementX(ambiguous.messageKind,
- ambiguous.messageArguments,
- name, enclosingElement);
- }
- }
- return result;
- }
-
- // Create, or reuse an already created, target element for a statement.
- JumpTarget getOrDefineTarget(Node statement) {
- JumpTarget element = registry.getTargetDefinition(statement);
- if (element == null) {
- element = new JumpTargetX(statement,
- statementScope.nestingLevel,
- enclosingElement);
- registry.defineTarget(statement, element);
- }
- return element;
- }
-
- doInCheckContext(action()) {
- bool wasInCheckContext = inCheckContext;
- inCheckContext = true;
- var result = action();
- inCheckContext = wasInCheckContext;
- return result;
- }
-
- inStaticContext(action()) {
- bool wasInstanceContext = inInstanceContext;
- inInstanceContext = false;
- var result = action();
- inInstanceContext = wasInstanceContext;
- return result;
- }
-
- doInPromotionScope(Node node, action()) {
- promotionScope = promotionScope.prepend(node);
- var result = action();
- promotionScope = promotionScope.tail;
- return result;
- }
-
- visitInStaticContext(Node node) {
- inStaticContext(() => visit(node));
- }
-
- ErroneousElement warnAndCreateErroneousElement(Node node,
- String name,
- MessageKind kind,
- [Map arguments = const {}]) {
- compiler.reportWarning(node, kind, arguments);
- return new ErroneousElementX(kind, arguments, name, enclosingElement);
- }
-
- ResolutionResult visitIdentifier(Identifier node) {
- if (node.isThis()) {
- if (!inInstanceContext) {
- error(node, MessageKind.NO_INSTANCE_AVAILABLE, {'name': node});
- }
- return null;
- } else if (node.isSuper()) {
- if (!inInstanceContext) error(node, MessageKind.NO_SUPER_IN_STATIC);
- if ((ElementCategory.SUPER & allowedCategory) == 0) {
- error(node, MessageKind.INVALID_USE_OF_SUPER);
- }
- return null;
- } else {
- String name = node.source;
- Element element = lookupInScope(compiler, node, scope, name);
- if (Elements.isUnresolved(element) && name == 'dynamic') {
- // TODO(johnniwinther): Remove this hack when we can return more complex
- // objects than [Element] from this method.
- element = compiler.typeClass;
- // Set the type to be `dynamic` to mark that this is a type literal.
- registry.setType(node, const DynamicType());
- }
- element = reportLookupErrorIfAny(element, node, node.source);
- if (element == null) {
- if (!inInstanceContext) {
- element = warnAndCreateErroneousElement(
- node, node.source, MessageKind.CANNOT_RESOLVE,
- {'name': node});
- registry.registerThrowNoSuchMethod();
- }
- } else if (element.isErroneous) {
- // Use the erroneous element.
- } else {
- if ((element.kind.category & allowedCategory) == 0) {
- // TODO(ahe): Improve error message. Need UX input.
- error(node, MessageKind.GENERIC,
- {'text': "is not an expression $element"});
- }
- }
- if (!Elements.isUnresolved(element) && element.isClass) {
- ClassElement classElement = element;
- classElement.ensureResolved(compiler);
- }
- return new ElementResult(registry.useElement(node, element));
- }
- }
-
- ResolutionResult visitTypeAnnotation(TypeAnnotation node) {
- DartType type = resolveTypeAnnotation(node);
- if (inCheckContext) {
- registry.registerIsCheck(type);
- }
- return new TypeResult(type);
- }
-
- bool isNamedConstructor(Send node) => node.receiver != null;
-
- Selector getRedirectingThisOrSuperConstructorSelector(Send node) {
- if (isNamedConstructor(node)) {
- String constructorName = node.selector.asIdentifier().source;
- return new Selector.callConstructor(
- constructorName,
- enclosingElement.library);
- } else {
- return new Selector.callDefaultConstructor(
- enclosingElement.library);
- }
- }
-
- FunctionElement resolveConstructorRedirection(FunctionElementX constructor) {
- FunctionExpression node = constructor.parseNode(compiler);
-
- // A synthetic constructor does not have a node.
- if (node == null) return null;
- if (node.initializers == null) return null;
- Link<Node> initializers = node.initializers.nodes;
- if (!initializers.isEmpty &&
- Initializers.isConstructorRedirect(initializers.head)) {
- Selector selector =
- getRedirectingThisOrSuperConstructorSelector(initializers.head);
- final ClassElement classElement = constructor.enclosingClass;
- return classElement.lookupConstructor(selector);
- }
- return null;
- }
-
- void setupFunction(FunctionExpression node, FunctionElement function) {
- Element enclosingElement = function.enclosingElement;
- if (node.modifiers.isStatic &&
- enclosingElement.kind != ElementKind.CLASS) {
- compiler.reportError(node, MessageKind.ILLEGAL_STATIC);
- }
-
- scope = new MethodScope(scope, function);
- // Put the parameters in scope.
- FunctionSignature functionParameters = function.functionSignature;
- Link<Node> parameterNodes = (node.parameters == null)
- ? const Link<Node>() : node.parameters.nodes;
- functionParameters.forEachParameter((ParameterElement element) {
- // TODO(karlklose): should be a list of [FormalElement]s, but the actual
- // implementation uses [Element].
- Link<Element> optionals = functionParameters.optionalParameters;
- if (!optionals.isEmpty && element == optionals.head) {
- NodeList nodes = parameterNodes.head;
- parameterNodes = nodes.nodes;
- }
- visit(element.initializer);
- VariableDefinitions variableDefinitions = parameterNodes.head;
- Node parameterNode = variableDefinitions.definitions.nodes.head;
- // Field parameters (this.x) are not visible inside the constructor. The
- // fields they reference are visible, but must be resolved independently.
- if (element.isInitializingFormal) {
- registry.useElement(parameterNode, element);
- } else {
- LocalParameterElement parameterElement = element;
- defineLocalVariable(parameterNode, parameterElement);
- addToScope(parameterElement);
- }
- parameterNodes = parameterNodes.tail;
- });
- addDeferredAction(enclosingElement, () {
- functionParameters.forEachOptionalParameter((Element parameter) {
- compiler.resolver.constantCompiler.compileConstant(parameter);
- });
- });
- if (inCheckContext) {
- functionParameters.forEachParameter((ParameterElement element) {
- registry.registerIsCheck(element.type);
- });
- }
- }
-
- visitCascade(Cascade node) {
- visit(node.expression);
- }
-
- visitCascadeReceiver(CascadeReceiver node) {
- visit(node.expression);
- }
-
- visitClassNode(ClassNode node) {
- internalError(node, "shouldn't be called");
- }
-
- visitIn(Node node, Scope nestedScope) {
- Scope oldScope = scope;
- scope = nestedScope;
- ResolutionResult result = visit(node);
- scope = oldScope;
- return result;
- }
-
- /**
- * Introduces new default targets for break and continue
- * before visiting the body of the loop
- */
- visitLoopBodyIn(Loop loop, Node body, Scope bodyScope) {
- JumpTarget element = getOrDefineTarget(loop);
- statementScope.enterLoop(element);
- visitIn(body, bodyScope);
- statementScope.exitLoop();
- if (!element.isTarget) {
- registry.undefineTarget(loop);
- }
- }
-
- visitBlock(Block node) {
- visitIn(node.statements, new BlockScope(scope));
- }
-
- visitDoWhile(DoWhile node) {
- visitLoopBodyIn(node, node.body, new BlockScope(scope));
- visit(node.condition);
- }
-
- visitEmptyStatement(EmptyStatement node) { }
-
- visitExpressionStatement(ExpressionStatement node) {
- ExpressionStatement oldExpressionStatement = currentExpressionStatement;
- currentExpressionStatement = node;
- visit(node.expression);
- currentExpressionStatement = oldExpressionStatement;
- }
-
- visitFor(For node) {
- Scope blockScope = new BlockScope(scope);
- visitIn(node.initializer, blockScope);
- visitIn(node.condition, blockScope);
- visitIn(node.update, blockScope);
- visitLoopBodyIn(node, node.body, blockScope);
- }
-
- visitFunctionDeclaration(FunctionDeclaration node) {
- assert(node.function.name != null);
- visitFunctionExpression(node.function, inFunctionDeclaration: true);
- }
-
-
- /// Process a local function declaration or an anonymous function expression.
- ///
- /// [inFunctionDeclaration] is `true` when the current node is the immediate
- /// child of a function declaration.
- ///
- /// This is used to distinguish local function declarations from anonymous
- /// function expressions.
- visitFunctionExpression(FunctionExpression node,
- {bool inFunctionDeclaration: false}) {
- bool doAddToScope = inFunctionDeclaration;
- if (!inFunctionDeclaration && node.name != null) {
- compiler.reportError(
- node.name,
- MessageKind.NAMED_FUNCTION_EXPRESSION,
- {'name': node.name});
- }
- visit(node.returnType);
- String name;
- if (node.name == null) {
- name = "";
- } else {
- name = node.name.asIdentifier().source;
- }
- LocalFunctionElementX function = new LocalFunctionElementX(
- name, node, ElementKind.FUNCTION, Modifiers.EMPTY,
- enclosingElement);
- function.functionSignatureCache =
- SignatureResolver.analyze(compiler, node.parameters, node.returnType,
- function, registry, createRealParameters: true);
- ResolverTask.processAsyncMarker(compiler, function);
- checkLocalDefinitionName(node, function);
- registry.defineFunction(node, function);
- if (doAddToScope) {
- addToScope(function);
- }
- Scope oldScope = scope; // The scope is modified by [setupFunction].
- setupFunction(node, function);
-
- Element previousEnclosingElement = enclosingElement;
- enclosingElement = function;
- // Run the body in a fresh statement scope.
- StatementScope oldStatementScope = statementScope;
- statementScope = new StatementScope();
- visit(node.body);
- statementScope = oldStatementScope;
-
- scope = oldScope;
- enclosingElement = previousEnclosingElement;
-
- registry.registerClosure(function);
- registry.registerInstantiatedClass(compiler.functionClass);
- }
-
- visitIf(If node) {
- doInPromotionScope(node.condition.expression, () => visit(node.condition));
- doInPromotionScope(node.thenPart,
- () => visitIn(node.thenPart, new BlockScope(scope)));
- visitIn(node.elsePart, new BlockScope(scope));
- }
-
- ResolutionResult resolveSend(Send node) {
- Selector selector = resolveSelector(node, null);
- if (node.isSuperCall) registry.registerSuperUse(node);
-
- if (node.receiver == null) {
- // If this send is of the form "assert(expr);", then
- // this is an assertion.
- if (selector.isAssert) {
- if (selector.argumentCount != 1) {
- error(node.selector,
- MessageKind.WRONG_NUMBER_OF_ARGUMENTS_FOR_ASSERT,
- {'argumentCount': selector.argumentCount});
- } else if (selector.namedArgumentCount != 0) {
- error(node.selector,
- MessageKind.ASSERT_IS_GIVEN_NAMED_ARGUMENTS,
- {'argumentCount': selector.namedArgumentCount});
- }
- registry.registerAssert(node);
- return const AssertResult();
- }
-
- return node.selector.accept(this);
- }
-
- var oldCategory = allowedCategory;
- allowedCategory |= ElementCategory.PREFIX | ElementCategory.SUPER;
- ResolutionResult resolvedReceiver = visit(node.receiver);
- allowedCategory = oldCategory;
-
- Element target;
- String name = node.selector.asIdentifier().source;
- if (identical(name, 'this')) {
- // TODO(ahe): Why is this using GENERIC?
- error(node.selector, MessageKind.GENERIC,
- {'text': "expected an identifier"});
- } else if (node.isSuperCall) {
- if (node.isOperator) {
- if (isUserDefinableOperator(name)) {
- name = selector.name;
- } else {
- error(node.selector, MessageKind.ILLEGAL_SUPER_SEND, {'name': name});
- }
- }
- if (!inInstanceContext) {
- error(node.receiver, MessageKind.NO_INSTANCE_AVAILABLE, {'name': name});
- return null;
- }
- if (currentClass.supertype == null) {
- // This is just to guard against internal errors, so no need
- // for a real error message.
- error(node.receiver, MessageKind.GENERIC,
- {'text': "Object has no superclass"});
- }
- // TODO(johnniwinther): Ensure correct behavior if currentClass is a
- // patch.
- target = currentClass.lookupSuperSelector(selector);
- // [target] may be null which means invoking noSuchMethod on
- // super.
- if (target == null) {
- target = warnAndCreateErroneousElement(
- node, name, MessageKind.NO_SUCH_SUPER_MEMBER,
- {'className': currentClass, 'memberName': name});
- // We still need to register the invocation, because we might
- // call [:super.noSuchMethod:] which calls
- // [JSInvocationMirror._invokeOn].
- registry.registerDynamicInvocation(selector);
- registry.registerSuperNoSuchMethod();
- }
- } else if (resolvedReceiver == null ||
- Elements.isUnresolved(resolvedReceiver.element)) {
- return null;
- } else if (resolvedReceiver.element.isClass) {
- ClassElement receiverClass = resolvedReceiver.element;
- receiverClass.ensureResolved(compiler);
- if (node.isOperator) {
- // When the resolved receiver is a class, we can have two cases:
- // 1) a static send: C.foo, or
- // 2) an operator send, where the receiver is a class literal: 'C + 1'.
- // The following code that looks up the selector on the resolved
- // receiver will treat the second as the invocation of a static operator
- // if the resolved receiver is not null.
- return null;
- }
- MembersCreator.computeClassMembersByName(
- compiler, receiverClass.declaration, name);
- target = receiverClass.lookupLocalMember(name);
- if (target == null || target.isInstanceMember) {
- registry.registerThrowNoSuchMethod();
- // TODO(johnniwinther): With the simplified [TreeElements] invariant,
- // try to resolve injected elements if [currentClass] is in the patch
- // library of [receiverClass].
-
- // TODO(karlklose): this should be reported by the caller of
- // [resolveSend] to select better warning messages for getters and
- // setters.
- MessageKind kind = (target == null)
- ? MessageKind.MEMBER_NOT_FOUND
- : MessageKind.MEMBER_NOT_STATIC;
- return new ElementResult(warnAndCreateErroneousElement(
- node, name, kind,
- {'className': receiverClass.name, 'memberName': name}));
- } else if (isPrivateName(name) &&
- target.library != enclosingElement.library) {
- registry.registerThrowNoSuchMethod();
- return new ElementResult(warnAndCreateErroneousElement(
- node, name, MessageKind.PRIVATE_ACCESS,
- {'libraryName': target.library.getLibraryOrScriptName(),
- 'name': name}));
- }
- } else if (resolvedReceiver.element.isPrefix) {
- PrefixElement prefix = resolvedReceiver.element;
- target = prefix.lookupLocalMember(name);
- if (Elements.isUnresolved(target)) {
- registry.registerThrowNoSuchMethod();
- return new ElementResult(warnAndCreateErroneousElement(
- node, name, MessageKind.NO_SUCH_LIBRARY_MEMBER,
- {'libraryName': prefix.name, 'memberName': name}));
- } else if (target.isAmbiguous) {
- registry.registerThrowNoSuchMethod();
- AmbiguousElement ambiguous = target;
- target = warnAndCreateErroneousElement(node, name,
- ambiguous.messageKind,
- ambiguous.messageArguments);
- ambiguous.diagnose(enclosingElement, compiler);
- return new ElementResult(target);
- } else if (target.kind == ElementKind.CLASS) {
- ClassElement classElement = target;
- classElement.ensureResolved(compiler);
- }
- }
- return new ElementResult(target);
- }
-
- static Selector computeSendSelector(Send node,
- LibraryElement library,
- Element element) {
- // First determine if this is part of an assignment.
- bool isSet = node.asSendSet() != null;
-
- if (node.isIndex) {
- return isSet ? new Selector.indexSet() : new Selector.index();
- }
-
- if (node.isOperator) {
- String source = node.selector.asOperator().source;
- String string = source;
- if (identical(string, '!') ||
- identical(string, '&&') || identical(string, '||') ||
- identical(string, 'is') || identical(string, 'as') ||
- identical(string, '?') ||
- identical(string, '>>>')) {
- return null;
- }
- String op = source;
- if (!isUserDefinableOperator(source)) {
- op = Elements.mapToUserOperatorOrNull(source);
- }
- if (op == null) {
- // Unsupported operator. An error has been reported during parsing.
- return new Selector.call(
- source, library, node.argumentsNode.slowLength(), []);
- }
- return node.arguments.isEmpty
- ? new Selector.unaryOperator(op)
- : new Selector.binaryOperator(op);
- }
-
- Identifier identifier = node.selector.asIdentifier();
- if (node.isPropertyAccess) {
- assert(!isSet);
- return new Selector.getter(identifier.source, library);
- } else if (isSet) {
- return new Selector.setter(identifier.source, library);
- }
-
- // Compute the arity and the list of named arguments.
- int arity = 0;
- List<String> named = <String>[];
- for (Link<Node> link = node.argumentsNode.nodes;
- !link.isEmpty;
- link = link.tail) {
- Expression argument = link.head;
- NamedArgument namedArgument = argument.asNamedArgument();
- if (namedArgument != null) {
- named.add(namedArgument.name.source);
- }
- arity++;
- }
-
- if (element != null && element.isConstructor) {
- return new Selector.callConstructor(
- element.name, library, arity, named);
- }
-
- // If we're invoking a closure, we do not have an identifier.
- return (identifier == null)
- ? new Selector.callClosure(arity, named)
- : new Selector.call(identifier.source, library, arity, named);
- }
-
- Selector resolveSelector(Send node, Element element) {
- LibraryElement library = enclosingElement.library;
- Selector selector = computeSendSelector(node, library, element);
- if (selector != null) registry.setSelector(node, selector);
- return selector;
- }
-
- void resolveArguments(NodeList list) {
- if (list == null) return;
- bool oldSendIsMemberAccess = sendIsMemberAccess;
- sendIsMemberAccess = false;
- Map<String, Node> seenNamedArguments = new Map<String, Node>();
- for (Link<Node> link = list.nodes; !link.isEmpty; link = link.tail) {
- Expression argument = link.head;
- visit(argument);
- NamedArgument namedArgument = argument.asNamedArgument();
- if (namedArgument != null) {
- String source = namedArgument.name.source;
- if (seenNamedArguments.containsKey(source)) {
- reportDuplicateDefinition(
- source,
- argument,
- seenNamedArguments[source]);
- } else {
- seenNamedArguments[source] = namedArgument;
- }
- } else if (!seenNamedArguments.isEmpty) {
- error(argument, MessageKind.INVALID_ARGUMENT_AFTER_NAMED);
- }
- }
- sendIsMemberAccess = oldSendIsMemberAccess;
- }
-
- ResolutionResult visitSend(Send node) {
- bool oldSendIsMemberAccess = sendIsMemberAccess;
- sendIsMemberAccess = node.isPropertyAccess || node.isCall;
- ResolutionResult result;
- if (node.isLogicalAnd) {
- result = doInPromotionScope(node.receiver, () => resolveSend(node));
- } else {
- result = resolveSend(node);
- }
- sendIsMemberAccess = oldSendIsMemberAccess;
-
- Element target = result != null ? result.element : null;
-
- if (target != null
- && target == compiler.mirrorSystemGetNameFunction
- && !compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(enclosingElement)) {
- compiler.reportHint(
- node.selector, MessageKind.STATIC_FUNCTION_BLOAT,
- {'class': compiler.mirrorSystemClass.name,
- 'name': compiler.mirrorSystemGetNameFunction.name});
- }
-
- if (!Elements.isUnresolved(target)) {
- if (target.isAbstractField) {
- AbstractFieldElement field = target;
- target = field.getter;
- if (target == null && !inInstanceContext) {
- registry.registerThrowNoSuchMethod();
- target =
- warnAndCreateErroneousElement(node.selector, field.name,
- MessageKind.CANNOT_RESOLVE_GETTER);
- }
- } else if (target.isTypeVariable) {
- ClassElement cls = target.enclosingClass;
- assert(enclosingElement.enclosingClass == cls);
- registry.registerClassUsingVariableExpression(cls);
- registry.registerTypeVariableExpression();
- // Set the type of the node to [Type] to mark this send as a
- // type variable expression.
- registry.registerTypeLiteral(node, target.computeType(compiler));
- } else if (target.impliesType && (!sendIsMemberAccess || node.isCall)) {
- // Set the type of the node to [Type] to mark this send as a
- // type literal.
- DartType type;
-
- // TODO(johnniwinther): Remove this hack when we can pass more complex
- // information between methods than resolved elements.
- if (target == compiler.typeClass && node.receiver == null) {
- // Potentially a 'dynamic' type literal.
- type = registry.getType(node.selector);
- }
- if (type == null) {
- type = target.computeType(compiler);
- }
- registry.registerTypeLiteral(node, type);
-
- // Don't try to make constants of calls to type literals.
- if (!node.isCall) {
- analyzeConstant(node);
- } else {
- // The node itself is not a constant but we register the selector (the
- // identifier that refers to the class/typedef) as a constant.
- analyzeConstant(node.selector);
- }
- }
- if (isPotentiallyMutableTarget(target)) {
- if (enclosingElement != target.enclosingElement) {
- for (Node scope in promotionScope) {
- registry.setAccessedByClosureIn(scope, target, node);
- }
- }
- }
- }
-
- bool resolvedArguments = false;
- if (node.isOperator) {
- String operatorString = node.selector.asOperator().source;
- if (identical(operatorString, 'is')) {
- // TODO(johnniwinther): Use seen type tests to avoid registration of
- // mutation/access to unpromoted variables.
- DartType type =
- resolveTypeAnnotation(node.typeAnnotationFromIsCheckOrCast);
- if (type != null) {
- registry.registerIsCheck(type);
- }
- resolvedArguments = true;
- } else if (identical(operatorString, 'as')) {
- DartType type = resolveTypeAnnotation(node.arguments.head);
- if (type != null) {
- registry.registerAsCheck(type);
- }
- resolvedArguments = true;
- } else if (identical(operatorString, '&&')) {
- doInPromotionScope(node.arguments.head,
- () => resolveArguments(node.argumentsNode));
- resolvedArguments = true;
- }
- }
-
- if (!resolvedArguments) {
- resolveArguments(node.argumentsNode);
- }
-
- // If the selector is null, it means that we will not be generating
- // code for this as a send.
- Selector selector = registry.getSelector(node);
- if (selector == null) return null;
-
- if (node.isCall) {
- if (Elements.isUnresolved(target) ||
- target.isGetter ||
- target.isField ||
- Elements.isClosureSend(node, target)) {
- // If we don't know what we're calling or if we are calling a getter,
- // we need to register that fact that we may be calling a closure
- // with the same arguments.
- Selector call = new Selector.callClosureFrom(selector);
- registry.registerDynamicInvocation(call);
- } else if (target.impliesType) {
- // We call 'call()' on a Type instance returned from the reference to a
- // class or typedef literal. We do not need to register this call as a
- // dynamic invocation, because we statically know what the target is.
- } else {
- if (target is FunctionElement) {
- FunctionElement function = target;
- function.computeSignature(compiler);
- }
- if (!selector.applies(target, compiler.world)) {
- registry.registerThrowNoSuchMethod();
- if (node.isSuperCall) {
- // Similar to what we do when we can't find super via selector
- // in [resolveSend] above, we still need to register the invocation,
- // because we might call [:super.noSuchMethod:] which calls
- // [JSInvocationMirror._invokeOn].
- registry.registerDynamicInvocation(selector);
- registry.registerSuperNoSuchMethod();
- }
- }
- }
-
- if (target != null && target.isForeign(compiler.backend)) {
- if (selector.name == 'JS') {
- registry.registerJsCall(node, this);
- } else if (selector.name == 'JS_EMBEDDED_GLOBAL') {
- registry.registerJsEmbeddedGlobalCall(node, this);
- } else if (selector.name == 'JS_INTERCEPTOR_CONSTANT') {
- if (!node.argumentsNode.isEmpty) {
- Node argument = node.argumentsNode.nodes.head;
- if (argumentsToJsInterceptorConstant == null) {
- argumentsToJsInterceptorConstant = new Set<Node>();
- }
- argumentsToJsInterceptorConstant.add(argument);
- }
- }
- }
- }
-
- registry.useElement(node, target);
- registerSend(selector, target);
- if (node.isPropertyAccess && Elements.isStaticOrTopLevelFunction(target)) {
- registry.registerGetOfStaticFunction(target.declaration);
- }
- return node.isPropertyAccess ? new ElementResult(target) : null;
- }
-
- /// Callback for native enqueuer to parse a type. Returns [:null:] on error.
- DartType resolveTypeFromString(Node node, String typeName) {
- Element element = lookupInScope(compiler, node,
- scope, typeName);
- if (element == null) return null;
- if (element is! ClassElement) return null;
- ClassElement cls = element;
- cls.ensureResolved(compiler);
- return cls.computeType(compiler);
- }
-
- ResolutionResult visitSendSet(SendSet node) {
- bool oldSendIsMemberAccess = sendIsMemberAccess;
- sendIsMemberAccess = node.isPropertyAccess || node.isCall;
- ResolutionResult result = resolveSend(node);
- sendIsMemberAccess = oldSendIsMemberAccess;
- Element target = result != null ? result.element : null;
- Element setter = target;
- Element getter = target;
- String operatorName = node.assignmentOperator.source;
- String source = operatorName;
- bool isComplex = !identical(source, '=');
- if (!(result is AssertResult || Elements.isUnresolved(target))) {
- if (target.isAbstractField) {
- AbstractFieldElement field = target;
- setter = field.setter;
- getter = field.getter;
- if (setter == null && !inInstanceContext) {
- setter = warnAndCreateErroneousElement(
- node.selector, field.name, MessageKind.CANNOT_RESOLVE_SETTER);
- registry.registerThrowNoSuchMethod();
- }
- if (isComplex && getter == null && !inInstanceContext) {
- getter = warnAndCreateErroneousElement(
- node.selector, field.name, MessageKind.CANNOT_RESOLVE_GETTER);
- registry.registerThrowNoSuchMethod();
- }
- } else if (target.impliesType) {
- setter = warnAndCreateErroneousElement(
- node.selector, target.name, MessageKind.ASSIGNING_TYPE);
- registry.registerThrowNoSuchMethod();
- } else if (target.isFinal ||
- target.isConst ||
- (target.isFunction &&
- Elements.isStaticOrTopLevelFunction(target) &&
- !target.isSetter)) {
- if (target.isFunction) {
- setter = warnAndCreateErroneousElement(
- node.selector, target.name, MessageKind.ASSIGNING_METHOD);
- } else {
- setter = warnAndCreateErroneousElement(
- node.selector, target.name, MessageKind.CANNOT_RESOLVE_SETTER);
- }
- registry.registerThrowNoSuchMethod();
- }
- if (isPotentiallyMutableTarget(target)) {
- registry.registerPotentialMutation(target, node);
- if (enclosingElement != target.enclosingElement) {
- registry.registerPotentialMutationInClosure(target, node);
- }
- for (Node scope in promotionScope) {
- registry.registerPotentialMutationIn(scope, target, node);
- }
- }
- }
-
- resolveArguments(node.argumentsNode);
-
- Selector selector = registry.getSelector(node);
- if (isComplex) {
- Selector getterSelector;
- if (selector.isSetter) {
- getterSelector = new Selector.getterFrom(selector);
- } else {
- assert(selector.isIndexSet);
- getterSelector = new Selector.index();
- }
- registerSend(getterSelector, getter);
- registry.setGetterSelectorInComplexSendSet(node, getterSelector);
- if (node.isSuperCall) {
- getter = currentClass.lookupSuperSelector(getterSelector);
- if (getter == null) {
- target = warnAndCreateErroneousElement(
- node, selector.name, MessageKind.NO_SUCH_SUPER_MEMBER,
- {'className': currentClass, 'memberName': selector.name});
- registry.registerSuperNoSuchMethod();
- }
- }
- registry.useElement(node.selector, getter);
-
- // Make sure we include the + and - operators if we are using
- // the ++ and -- ones. Also, if op= form is used, include op itself.
- void registerBinaryOperator(String name) {
- Selector binop = new Selector.binaryOperator(name);
- registry.registerDynamicInvocation(binop);
- registry.setOperatorSelectorInComplexSendSet(node, binop);
- }
- if (identical(source, '++')) {
- registerBinaryOperator('+');
- registry.registerInstantiatedClass(compiler.intClass);
- } else if (identical(source, '--')) {
- registerBinaryOperator('-');
- registry.registerInstantiatedClass(compiler.intClass);
- } else if (source.endsWith('=')) {
- registerBinaryOperator(Elements.mapToUserOperator(operatorName));
- }
- }
-
- registerSend(selector, setter);
- return new ElementResult(registry.useElement(node, setter));
- }
-
- void registerSend(Selector selector, Element target) {
- if (target == null || target.isInstanceMember) {
- if (selector.isGetter) {
- registry.registerDynamicGetter(selector);
- } else if (selector.isSetter) {
- registry.registerDynamicSetter(selector);
- } else {
- registry.registerDynamicInvocation(selector);
- }
- } else if (Elements.isStaticOrTopLevel(target)) {
- // Avoid registration of type variables since they are not analyzable but
- // instead resolved through their enclosing type declaration.
- if (!target.isTypeVariable) {
- // [target] might be the implementation element and only declaration
- // elements may be registered.
- registry.registerStaticUse(target.declaration);
- }
- }
- }
-
- visitLiteralInt(LiteralInt node) {
- registry.registerInstantiatedClass(compiler.intClass);
- }
-
- visitLiteralDouble(LiteralDouble node) {
- registry.registerInstantiatedClass(compiler.doubleClass);
- }
-
- visitLiteralBool(LiteralBool node) {
- registry.registerInstantiatedClass(compiler.boolClass);
- }
-
- visitLiteralString(LiteralString node) {
- registry.registerInstantiatedClass(compiler.stringClass);
- }
-
- visitLiteralNull(LiteralNull node) {
- registry.registerInstantiatedClass(compiler.nullClass);
- }
-
- visitLiteralSymbol(LiteralSymbol node) {
- registry.registerInstantiatedClass(compiler.symbolClass);
- registry.registerStaticUse(compiler.symbolConstructor.declaration);
- registry.registerConstSymbol(node.slowNameString);
- if (!validateSymbol(node, node.slowNameString, reportError: false)) {
- compiler.reportError(node,
- MessageKind.UNSUPPORTED_LITERAL_SYMBOL,
- {'value': node.slowNameString});
- }
- analyzeConstant(node);
- }
-
- visitStringJuxtaposition(StringJuxtaposition node) {
- registry.registerInstantiatedClass(compiler.stringClass);
- node.visitChildren(this);
- }
-
- visitNodeList(NodeList node) {
- for (Link<Node> link = node.nodes; !link.isEmpty; link = link.tail) {
- visit(link.head);
- }
- }
-
- visitOperator(Operator node) {
- internalError(node, 'operator');
- }
-
- visitRethrow(Rethrow node) {
- if (!inCatchBlock) {
- error(node, MessageKind.THROW_WITHOUT_EXPRESSION);
- }
- }
-
- visitReturn(Return node) {
- Node expression = node.expression;
- if (expression != null &&
- enclosingElement.isGenerativeConstructor) {
- // It is a compile-time error if a return statement of the form
- // `return e;` appears in a generative constructor. (Dart Language
- // Specification 13.12.)
- compiler.reportError(expression,
- MessageKind.CANNOT_RETURN_FROM_CONSTRUCTOR);
- }
- visit(node.expression);
- }
-
- visitYield(Yield node) {
- compiler.streamClass.ensureResolved(compiler);
- compiler.iterableClass.ensureResolved(compiler);
- visit(node.expression);
- }
-
- visitRedirectingFactoryBody(RedirectingFactoryBody node) {
- final isSymbolConstructor = enclosingElement == compiler.symbolConstructor;
- if (!enclosingElement.isFactoryConstructor) {
- compiler.reportError(
- node, MessageKind.FACTORY_REDIRECTION_IN_NON_FACTORY);
- compiler.reportHint(
- enclosingElement, MessageKind.MISSING_FACTORY_KEYWORD);
- }
- ConstructorElementX constructor = enclosingElement;
- bool isConstConstructor = constructor.isConst;
- ConstructorElement redirectionTarget = resolveRedirectingFactory(
- node, inConstContext: isConstConstructor);
- constructor.immediateRedirectionTarget = redirectionTarget;
- registry.setRedirectingTargetConstructor(node, redirectionTarget);
- if (Elements.isUnresolved(redirectionTarget)) {
- registry.registerThrowNoSuchMethod();
- return;
- } else {
- if (isConstConstructor &&
- !redirectionTarget.isConst) {
- compiler.reportError(node, MessageKind.CONSTRUCTOR_IS_NOT_CONST);
- }
- if (redirectionTarget == constructor) {
- compiler.reportError(node, MessageKind.CYCLIC_REDIRECTING_FACTORY);
- return;
- }
- }
-
- // Check that the target constructor is type compatible with the
- // redirecting constructor.
- ClassElement targetClass = redirectionTarget.enclosingClass;
- InterfaceType type = registry.getType(node);
- FunctionType targetType = redirectionTarget.computeType(compiler)
- .subst(type.typeArguments, targetClass.typeVariables);
- FunctionType constructorType = constructor.computeType(compiler);
- bool isSubtype = compiler.types.isSubtype(targetType, constructorType);
- if (!isSubtype) {
- warning(node, MessageKind.NOT_ASSIGNABLE,
- {'fromType': targetType, 'toType': constructorType});
- }
-
- FunctionSignature targetSignature =
- redirectionTarget.computeSignature(compiler);
- FunctionSignature constructorSignature =
- constructor.computeSignature(compiler);
- if (!targetSignature.isCompatibleWith(constructorSignature)) {
- assert(!isSubtype);
- registry.registerThrowNoSuchMethod();
- }
-
- // Register a post process to check for cycles in the redirection chain and
- // set the actual generative constructor at the end of the chain.
- addDeferredAction(constructor, () {
- compiler.resolver.resolveRedirectionChain(constructor, node);
- });
-
- registry.registerStaticUse(redirectionTarget);
- // TODO(johnniwinther): Register the effective target type instead.
- registry.registerInstantiatedClass(
- redirectionTarget.enclosingClass.declaration);
- if (isSymbolConstructor) {
- registry.registerSymbolConstructor();
- }
- }
-
- visitThrow(Throw node) {
- registry.registerThrowExpression();
- visit(node.expression);
- }
-
- visitAwait(Await node) {
- compiler.futureClass.ensureResolved(compiler);
- visit(node.expression);
- }
-
- visitVariableDefinitions(VariableDefinitions node) {
- DartType type;
- if (node.type != null) {
- type = resolveTypeAnnotation(node.type);
- } else {
- type = const DynamicType();
- }
- VariableList variables = new VariableList.node(node, type);
- VariableDefinitionsVisitor visitor =
- new VariableDefinitionsVisitor(compiler, node, this, variables);
-
- Modifiers modifiers = node.modifiers;
- void reportExtraModifier(String modifier) {
- Node modifierNode;
- for (Link<Node> nodes = modifiers.nodes.nodes;
- !nodes.isEmpty;
- nodes = nodes.tail) {
- if (modifier == nodes.head.asIdentifier().source) {
- modifierNode = nodes.head;
- break;
- }
- }
- assert(modifierNode != null);
- compiler.reportError(modifierNode, MessageKind.EXTRANEOUS_MODIFIER,
- {'modifier': modifier});
- }
- if (modifiers.isFinal && (modifiers.isConst || modifiers.isVar)) {
- reportExtraModifier('final');
- }
- if (modifiers.isVar && (modifiers.isConst || node.type != null)) {
- reportExtraModifier('var');
- }
- if (enclosingElement.isFunction) {
- if (modifiers.isAbstract) {
- reportExtraModifier('abstract');
- }
- if (modifiers.isStatic) {
- reportExtraModifier('static');
- }
- }
- if (node.metadata != null) {
- variables.metadata =
- compiler.resolver.resolveMetadata(enclosingElement, node);
- }
- visitor.visit(node.definitions);
- }
-
- visitWhile(While node) {
- visit(node.condition);
- visitLoopBodyIn(node, node.body, new BlockScope(scope));
- }
-
- visitParenthesizedExpression(ParenthesizedExpression node) {
- bool oldSendIsMemberAccess = sendIsMemberAccess;
- sendIsMemberAccess = false;
- visit(node.expression);
- sendIsMemberAccess = oldSendIsMemberAccess;
- }
-
- ResolutionResult visitNewExpression(NewExpression node) {
- Node selector = node.send.selector;
- FunctionElement constructor = resolveConstructor(node);
- final bool isSymbolConstructor = constructor == compiler.symbolConstructor;
- final bool isMirrorsUsedConstant =
- node.isConst && (constructor == compiler.mirrorsUsedConstructor);
- Selector callSelector = resolveSelector(node.send, constructor);
- resolveArguments(node.send.argumentsNode);
- registry.useElement(node.send, constructor);
- if (Elements.isUnresolved(constructor)) {
- return new ElementResult(constructor);
- }
- constructor.computeSignature(compiler);
- if (!callSelector.applies(constructor, compiler.world)) {
- registry.registerThrowNoSuchMethod();
- }
-
- // [constructor] might be the implementation element
- // and only declaration elements may be registered.
- registry.registerStaticUse(constructor.declaration);
- ClassElement cls = constructor.enclosingClass;
- InterfaceType type = registry.getType(node);
- if (node.isConst && type.containsTypeVariables) {
- compiler.reportError(node.send.selector,
- MessageKind.TYPE_VARIABLE_IN_CONSTANT);
- }
- // TODO(johniwinther): Avoid registration of `type` in face of redirecting
- // factory constructors.
- registry.registerInstantiatedType(type);
- if (constructor.isFactoryConstructor && !type.typeArguments.isEmpty) {
- registry.registerFactoryWithTypeArguments();
- }
- if (constructor.isGenerativeConstructor && cls.isAbstract) {
- warning(node, MessageKind.ABSTRACT_CLASS_INSTANTIATION);
- registry.registerAbstractClassInstantiation();
- }
-
- if (isSymbolConstructor) {
- if (node.isConst) {
- Node argumentNode = node.send.arguments.head;
- ConstantExpression constant =
- compiler.resolver.constantCompiler.compileNode(
- argumentNode, registry.mapping);
- ConstantValue name = constant.value;
- if (!name.isString) {
- DartType type = name.computeType(compiler);
- compiler.reportError(argumentNode, MessageKind.STRING_EXPECTED,
- {'type': type});
- } else {
- StringConstantValue stringConstant = name;
- String nameString = stringConstant.toDartString().slowToString();
- if (validateSymbol(argumentNode, nameString)) {
- registry.registerConstSymbol(nameString);
- }
- }
- } else {
- if (!compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(
- enclosingElement)) {
- compiler.reportHint(
- node.newToken, MessageKind.NON_CONST_BLOAT,
- {'name': compiler.symbolClass.name});
- }
- registry.registerNewSymbol();
- }
- } else if (isMirrorsUsedConstant) {
- compiler.mirrorUsageAnalyzerTask.validate(node, registry.mapping);
- }
- if (node.isConst) {
- analyzeConstant(node);
- }
-
- return null;
- }
-
- void checkConstMapKeysDontOverrideEquals(Spannable spannable,
- MapConstantValue map) {
- for (ConstantValue key in map.keys) {
- if (!key.isObject) continue;
- ObjectConstantValue objectConstant = key;
- DartType keyType = objectConstant.type;
- ClassElement cls = keyType.element;
- if (cls == compiler.stringClass) continue;
- Element equals = cls.lookupMember('==');
- if (equals.enclosingClass != compiler.objectClass) {
- compiler.reportError(spannable,
- MessageKind.CONST_MAP_KEY_OVERRIDES_EQUALS,
- {'type': keyType});
- }
- }
- }
-
- void analyzeConstant(Node node) {
- addDeferredAction(enclosingElement, () {
- ConstantExpression constant =
- compiler.resolver.constantCompiler.compileNode(
- node, registry.mapping);
-
- ConstantValue value = constant.value;
- if (value.isMap) {
- checkConstMapKeysDontOverrideEquals(node, value);
- }
-
- // The type constant that is an argument to JS_INTERCEPTOR_CONSTANT names
- // a class that will be instantiated outside the program by attaching a
- // native class dispatch record referencing the interceptor.
- if (argumentsToJsInterceptorConstant != null &&
- argumentsToJsInterceptorConstant.contains(node)) {
- if (value.isType) {
- TypeConstantValue typeConstant = value;
- if (typeConstant.representedType is InterfaceType) {
- registry.registerInstantiatedType(typeConstant.representedType);
- } else {
- compiler.reportError(node,
- MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT);
- }
- } else {
- compiler.reportError(node,
- MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT);
- }
- }
- });
- }
-
- bool validateSymbol(Node node, String name, {bool reportError: true}) {
- if (name.isEmpty) return true;
- if (name.startsWith('_')) {
- if (reportError) {
- compiler.reportError(node, MessageKind.PRIVATE_IDENTIFIER,
- {'value': name});
- }
- return false;
- }
- if (!symbolValidationPattern.hasMatch(name)) {
- if (reportError) {
- compiler.reportError(node, MessageKind.INVALID_SYMBOL,
- {'value': name});
- }
- return false;
- }
- return true;
- }
-
- /**
- * Try to resolve the constructor that is referred to by [node].
- * Note: this function may return an ErroneousFunctionElement instead of
- * [:null:], if there is no corresponding constructor, class or library.
- */
- ConstructorElement resolveConstructor(NewExpression node) {
- return node.accept(new ConstructorResolver(compiler, this));
- }
-
- ConstructorElement resolveRedirectingFactory(RedirectingFactoryBody node,
- {bool inConstContext: false}) {
- return node.accept(new ConstructorResolver(compiler, this,
- inConstContext: inConstContext));
- }
-
- DartType resolveTypeAnnotation(TypeAnnotation node,
- {bool malformedIsError: false,
- bool deferredIsMalformed: true}) {
- DartType type = typeResolver.resolveTypeAnnotation(
- this, node, malformedIsError: malformedIsError,
- deferredIsMalformed: deferredIsMalformed);
- if (inCheckContext) {
- registry.registerIsCheck(type);
- registry.registerRequiredType(type, enclosingElement);
- }
- return type;
- }
-
- visitModifiers(Modifiers node) {
- internalError(node, 'modifiers');
- }
-
- visitLiteralList(LiteralList node) {
- bool oldSendIsMemberAccess = sendIsMemberAccess;
- sendIsMemberAccess = false;
-
- NodeList arguments = node.typeArguments;
- DartType typeArgument;
- if (arguments != null) {
- Link<Node> nodes = arguments.nodes;
- if (nodes.isEmpty) {
- // The syntax [: <>[] :] is not allowed.
- error(arguments, MessageKind.MISSING_TYPE_ARGUMENT);
- } else {
- typeArgument = resolveTypeAnnotation(nodes.head);
- for (nodes = nodes.tail; !nodes.isEmpty; nodes = nodes.tail) {
- warning(nodes.head, MessageKind.ADDITIONAL_TYPE_ARGUMENT);
- resolveTypeAnnotation(nodes.head);
- }
- }
- }
- DartType listType;
- if (typeArgument != null) {
- if (node.isConst && typeArgument.containsTypeVariables) {
- compiler.reportError(arguments.nodes.head,
- MessageKind.TYPE_VARIABLE_IN_CONSTANT);
- }
- listType = new InterfaceType(compiler.listClass, [typeArgument]);
- } else {
- compiler.listClass.computeType(compiler);
- listType = compiler.listClass.rawType;
- }
- registry.setType(node, listType);
- registry.registerInstantiatedType(listType);
- registry.registerRequiredType(listType, enclosingElement);
- visit(node.elements);
- if (node.isConst) {
- analyzeConstant(node);
- }
-
- sendIsMemberAccess = false;
- }
-
- visitConditional(Conditional node) {
- doInPromotionScope(node.condition, () => visit(node.condition));
- doInPromotionScope(node.thenExpression, () => visit(node.thenExpression));
- visit(node.elseExpression);
- }
-
- visitStringInterpolation(StringInterpolation node) {
- registry.registerInstantiatedClass(compiler.stringClass);
- registry.registerStringInterpolation();
- node.visitChildren(this);
- }
-
- visitStringInterpolationPart(StringInterpolationPart node) {
- registerImplicitInvocation('toString', 0);
- node.visitChildren(this);
- }
-
- visitBreakStatement(BreakStatement node) {
- JumpTarget target;
- if (node.target == null) {
- target = statementScope.currentBreakTarget();
- if (target == null) {
- error(node, MessageKind.NO_BREAK_TARGET);
- return;
- }
- target.isBreakTarget = true;
- } else {
- String labelName = node.target.source;
- LabelDefinition label = statementScope.lookupLabel(labelName);
- if (label == null) {
- error(node.target, MessageKind.UNBOUND_LABEL, {'labelName': labelName});
- return;
- }
- target = label.target;
- if (!target.statement.isValidBreakTarget()) {
- error(node.target, MessageKind.INVALID_BREAK);
- return;
- }
- label.setBreakTarget();
- registry.useLabel(node, label);
- }
- registry.registerTargetOf(node, target);
- }
-
- visitContinueStatement(ContinueStatement node) {
- JumpTarget target;
- if (node.target == null) {
- target = statementScope.currentContinueTarget();
- if (target == null) {
- error(node, MessageKind.NO_CONTINUE_TARGET);
- return;
- }
- target.isContinueTarget = true;
- } else {
- String labelName = node.target.source;
- LabelDefinition label = statementScope.lookupLabel(labelName);
- if (label == null) {
- error(node.target, MessageKind.UNBOUND_LABEL, {'labelName': labelName});
- return;
- }
- target = label.target;
- if (!target.statement.isValidContinueTarget()) {
- error(node.target, MessageKind.INVALID_CONTINUE);
- }
- label.setContinueTarget();
- registry.useLabel(node, label);
- }
- registry.registerTargetOf(node, target);
- }
-
- registerImplicitInvocation(String name, int arity) {
- Selector selector = new Selector.call(name, null, arity);
- registry.registerDynamicInvocation(selector);
- }
-
- visitForIn(ForIn node) {
- LibraryElement library = enclosingElement.library;
- registry.setIteratorSelector(node, compiler.iteratorSelector);
- registry.registerDynamicGetter(compiler.iteratorSelector);
- registry.setCurrentSelector(node, compiler.currentSelector);
- registry.registerDynamicGetter(compiler.currentSelector);
- registry.setMoveNextSelector(node, compiler.moveNextSelector);
- registry.registerDynamicInvocation(compiler.moveNextSelector);
-
- visit(node.expression);
- Scope blockScope = new BlockScope(scope);
- Node declaration = node.declaredIdentifier;
-
- bool oldAllowFinalWithoutInitializer = allowFinalWithoutInitializer;
- allowFinalWithoutInitializer = true;
- visitIn(declaration, blockScope);
- allowFinalWithoutInitializer = oldAllowFinalWithoutInitializer;
-
- Send send = declaration.asSend();
- VariableDefinitions variableDefinitions =
- declaration.asVariableDefinitions();
- Element loopVariable;
- Selector loopVariableSelector;
- if (send != null) {
- loopVariable = registry.getDefinition(send);
- Identifier identifier = send.selector.asIdentifier();
- if (identifier == null) {
- compiler.reportError(send.selector, MessageKind.INVALID_FOR_IN);
- } else {
- loopVariableSelector = new Selector.setter(identifier.source, library);
- }
- if (send.receiver != null) {
- compiler.reportError(send.receiver, MessageKind.INVALID_FOR_IN);
- }
- } else if (variableDefinitions != null) {
- Link<Node> nodes = variableDefinitions.definitions.nodes;
- if (!nodes.tail.isEmpty) {
- compiler.reportError(nodes.tail.head, MessageKind.INVALID_FOR_IN);
- }
- Node first = nodes.head;
- Identifier identifier = first.asIdentifier();
- if (identifier == null) {
- compiler.reportError(first, MessageKind.INVALID_FOR_IN);
- } else {
- loopVariableSelector = new Selector.setter(identifier.source, library);
- loopVariable = registry.getDefinition(identifier);
- }
- } else {
- compiler.reportError(declaration, MessageKind.INVALID_FOR_IN);
- }
- if (loopVariableSelector != null) {
- registry.setSelector(declaration, loopVariableSelector);
- registerSend(loopVariableSelector, loopVariable);
- } else {
- // The selector may only be null if we reported an error.
- assert(invariant(declaration, compiler.compilationFailed));
- }
- if (loopVariable != null) {
- // loopVariable may be null if it could not be resolved.
- registry.setForInVariable(node, loopVariable);
- }
- visitLoopBodyIn(node, node.body, blockScope);
- }
-
- visitLabel(Label node) {
- // Labels are handled by their containing statements/cases.
- }
-
- visitLabeledStatement(LabeledStatement node) {
- Statement body = node.statement;
- JumpTarget targetElement = getOrDefineTarget(body);
- Map<String, LabelDefinition> labelElements = <String, LabelDefinition>{};
- for (Label label in node.labels) {
- String labelName = label.labelName;
- if (labelElements.containsKey(labelName)) continue;
- LabelDefinition element = targetElement.addLabel(label, labelName);
- labelElements[labelName] = element;
- }
- statementScope.enterLabelScope(labelElements);
- visit(node.statement);
- statementScope.exitLabelScope();
- labelElements.forEach((String labelName, LabelDefinition element) {
- if (element.isTarget) {
- registry.defineLabel(element.label, element);
- } else {
- warning(element.label, MessageKind.UNUSED_LABEL,
- {'labelName': labelName});
- }
- });
- if (!targetElement.isTarget) {
- registry.undefineTarget(body);
- }
- }
-
- visitLiteralMap(LiteralMap node) {
- bool oldSendIsMemberAccess = sendIsMemberAccess;
- sendIsMemberAccess = false;
-
- NodeList arguments = node.typeArguments;
- DartType keyTypeArgument;
- DartType valueTypeArgument;
- if (arguments != null) {
- Link<Node> nodes = arguments.nodes;
- if (nodes.isEmpty) {
- // The syntax [: <>{} :] is not allowed.
- error(arguments, MessageKind.MISSING_TYPE_ARGUMENT);
- } else {
- keyTypeArgument = resolveTypeAnnotation(nodes.head);
- nodes = nodes.tail;
- if (nodes.isEmpty) {
- warning(arguments, MessageKind.MISSING_TYPE_ARGUMENT);
- } else {
- valueTypeArgument = resolveTypeAnnotation(nodes.head);
- for (nodes = nodes.tail; !nodes.isEmpty; nodes = nodes.tail) {
- warning(nodes.head, MessageKind.ADDITIONAL_TYPE_ARGUMENT);
- resolveTypeAnnotation(nodes.head);
- }
- }
- }
- }
- DartType mapType;
- if (valueTypeArgument != null) {
- mapType = new InterfaceType(compiler.mapClass,
- [keyTypeArgument, valueTypeArgument]);
- } else {
- compiler.mapClass.computeType(compiler);
- mapType = compiler.mapClass.rawType;
- }
- if (node.isConst && mapType.containsTypeVariables) {
- compiler.reportError(arguments,
- MessageKind.TYPE_VARIABLE_IN_CONSTANT);
- }
- registry.setType(node, mapType);
- registry.registerInstantiatedType(mapType);
- if (node.isConst) {
- registry.registerConstantMap();
- }
- registry.registerRequiredType(mapType, enclosingElement);
- node.visitChildren(this);
- if (node.isConst) {
- analyzeConstant(node);
- }
-
- sendIsMemberAccess = false;
- }
-
- visitLiteralMapEntry(LiteralMapEntry node) {
- node.visitChildren(this);
- }
-
- visitNamedArgument(NamedArgument node) {
- visit(node.expression);
- }
-
- DartType typeOfConstant(ConstantValue constant) {
- if (constant.isInt) return compiler.intClass.rawType;
- if (constant.isBool) return compiler.boolClass.rawType;
- if (constant.isDouble) return compiler.doubleClass.rawType;
- if (constant.isString) return compiler.stringClass.rawType;
- if (constant.isNull) return compiler.nullClass.rawType;
- if (constant.isFunction) return compiler.functionClass.rawType;
- assert(constant.isObject);
- ObjectConstantValue objectConstant = constant;
- return objectConstant.type;
- }
-
- bool overridesEquals(DartType type) {
- ClassElement cls = type.element;
- Element equals = cls.lookupMember('==');
- return equals.enclosingClass != compiler.objectClass;
- }
-
- void checkCaseExpressions(SwitchStatement node) {
- JumpTarget breakElement = getOrDefineTarget(node);
- Map<String, LabelDefinition> continueLabels = <String, LabelDefinition>{};
-
- Link<Node> cases = node.cases.nodes;
- CaseMatch firstCase = null;
- DartType firstCaseType = null;
- bool hasReportedProblem = false;
-
- for (Link<Node> cases = node.cases.nodes;
- !cases.isEmpty;
- cases = cases.tail) {
- SwitchCase switchCase = cases.head;
-
- for (Node labelOrCase in switchCase.labelsAndCases) {
- CaseMatch caseMatch = labelOrCase.asCaseMatch();
- if (caseMatch == null) continue;
-
- // Analyze the constant.
- ConstantExpression constant =
- registry.getConstant(caseMatch.expression);
- assert(invariant(node, constant != null,
- message: 'No constant computed for $node'));
-
- DartType caseType = typeOfConstant(constant.value);
-
- if (firstCaseType == null) {
- firstCase = caseMatch;
- firstCaseType = caseType;
-
- // We only report the bad type on the first class element. All others
- // get a "type differs" error.
- if (caseType.element == compiler.doubleClass) {
- compiler.reportError(node,
- MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS,
- {'type': "double"});
- } else if (caseType.element == compiler.functionClass) {
- compiler.reportError(node, MessageKind.SWITCH_CASE_FORBIDDEN,
- {'type': "Function"});
- } else if (constant.value.isObject && overridesEquals(caseType)) {
- compiler.reportError(firstCase.expression,
- MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS,
- {'type': caseType});
- }
- } else {
- if (caseType != firstCaseType) {
- if (!hasReportedProblem) {
- compiler.reportError(
- node,
- MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL,
- {'type': firstCaseType});
- compiler.reportInfo(
- firstCase.expression,
- MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL_CASE,
- {'type': firstCaseType});
- hasReportedProblem = true;
- }
- compiler.reportInfo(
- caseMatch.expression,
- MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL_CASE,
- {'type': caseType});
- }
- }
- }
- }
- }
-
- visitSwitchStatement(SwitchStatement node) {
- node.expression.accept(this);
-
- JumpTarget breakElement = getOrDefineTarget(node);
- Map<String, LabelDefinition> continueLabels = <String, LabelDefinition>{};
- Link<Node> cases = node.cases.nodes;
- while (!cases.isEmpty) {
- SwitchCase switchCase = cases.head;
- for (Node labelOrCase in switchCase.labelsAndCases) {
- CaseMatch caseMatch = labelOrCase.asCaseMatch();
- if (caseMatch != null) {
- analyzeConstant(caseMatch.expression);
- continue;
- }
- Label label = labelOrCase;
- String labelName = label.labelName;
-
- LabelDefinition existingElement = continueLabels[labelName];
- if (existingElement != null) {
- // It's an error if the same label occurs twice in the same switch.
- compiler.reportError(
- label,
- MessageKind.DUPLICATE_LABEL, {'labelName': labelName});
- compiler.reportInfo(
- existingElement.label,
- MessageKind.EXISTING_LABEL, {'labelName': labelName});
- } else {
- // It's only a warning if it shadows another label.
- existingElement = statementScope.lookupLabel(labelName);
- if (existingElement != null) {
- compiler.reportWarning(
- label,
- MessageKind.DUPLICATE_LABEL, {'labelName': labelName});
- compiler.reportInfo(
- existingElement.label,
- MessageKind.EXISTING_LABEL, {'labelName': labelName});
- }
- }
-
- JumpTarget targetElement = getOrDefineTarget(switchCase);
- LabelDefinition labelElement = targetElement.addLabel(label, labelName);
- registry.defineLabel(label, labelElement);
- continueLabels[labelName] = labelElement;
- }
- cases = cases.tail;
- // Test that only the last case, if any, is a default case.
- if (switchCase.defaultKeyword != null && !cases.isEmpty) {
- error(switchCase, MessageKind.INVALID_CASE_DEFAULT);
- }
- }
-
- addDeferredAction(enclosingElement, () {
- checkCaseExpressions(node);
- });
-
- statementScope.enterSwitch(breakElement, continueLabels);
- node.cases.accept(this);
- statementScope.exitSwitch();
-
- // Clean-up unused labels.
- continueLabels.forEach((String key, LabelDefinition label) {
- if (!label.isContinueTarget) {
- JumpTarget targetElement = label.target;
- SwitchCase switchCase = targetElement.statement;
- registry.undefineTarget(switchCase);
- registry.undefineLabel(label.label);
- }
- });
- // TODO(15575): We should warn if we can detect a fall through
- // error.
- registry.registerFallThroughError();
- }
-
- visitSwitchCase(SwitchCase node) {
- node.labelsAndCases.accept(this);
- visitIn(node.statements, new BlockScope(scope));
- }
-
- visitCaseMatch(CaseMatch node) {
- visit(node.expression);
- }
-
- visitTryStatement(TryStatement node) {
- visit(node.tryBlock);
- if (node.catchBlocks.isEmpty && node.finallyBlock == null) {
- error(node.getEndToken().next, MessageKind.NO_CATCH_NOR_FINALLY);
- }
- visit(node.catchBlocks);
- visit(node.finallyBlock);
- }
-
- visitCatchBlock(CatchBlock node) {
- registry.registerCatchStatement();
- // Check that if catch part is present, then
- // it has one or two formal parameters.
- VariableDefinitions exceptionDefinition;
- VariableDefinitions stackTraceDefinition;
- if (node.formals != null) {
- Link<Node> formalsToProcess = node.formals.nodes;
- if (formalsToProcess.isEmpty) {
- error(node, MessageKind.EMPTY_CATCH_DECLARATION);
- } else {
- exceptionDefinition = formalsToProcess.head.asVariableDefinitions();
- formalsToProcess = formalsToProcess.tail;
- if (!formalsToProcess.isEmpty) {
- stackTraceDefinition = formalsToProcess.head.asVariableDefinitions();
- formalsToProcess = formalsToProcess.tail;
- if (!formalsToProcess.isEmpty) {
- for (Node extra in formalsToProcess) {
- error(extra, MessageKind.EXTRA_CATCH_DECLARATION);
- }
- }
- registry.registerStackTraceInCatch();
- }
- }
-
- // Check that the formals aren't optional and that they have no
- // modifiers or type.
- for (Link<Node> link = node.formals.nodes;
- !link.isEmpty;
- link = link.tail) {
- // If the formal parameter is a node list, it means that it is a
- // sequence of optional parameters.
- NodeList nodeList = link.head.asNodeList();
- if (nodeList != null) {
- error(nodeList, MessageKind.OPTIONAL_PARAMETER_IN_CATCH);
- } else {
- VariableDefinitions declaration = link.head;
- for (Node modifier in declaration.modifiers.nodes) {
- error(modifier, MessageKind.PARAMETER_WITH_MODIFIER_IN_CATCH);
- }
- TypeAnnotation type = declaration.type;
- if (type != null) {
- error(type, MessageKind.PARAMETER_WITH_TYPE_IN_CATCH);
- }
- }
- }
- }
-
- Scope blockScope = new BlockScope(scope);
- doInCheckContext(() => visitIn(node.type, blockScope));
- visitIn(node.formals, blockScope);
- var oldInCatchBlock = inCatchBlock;
- inCatchBlock = true;
- visitIn(node.block, blockScope);
- inCatchBlock = oldInCatchBlock;
-
- if (node.type != null && exceptionDefinition != null) {
- DartType exceptionType = registry.getType(node.type);
- Node exceptionVariable = exceptionDefinition.definitions.nodes.head;
- VariableElementX exceptionElement =
- registry.getDefinition(exceptionVariable);
- exceptionElement.variables.type = exceptionType;
- }
- if (stackTraceDefinition != null) {
- Node stackTraceVariable = stackTraceDefinition.definitions.nodes.head;
- VariableElementX stackTraceElement =
- registry.getDefinition(stackTraceVariable);
- registry.registerInstantiatedClass(compiler.stackTraceClass);
- stackTraceElement.variables.type = compiler.stackTraceClass.rawType;
- }
- }
-
- visitTypedef(Typedef node) {
- internalError(node, 'typedef');
- }
-}
-
-class TypeDefinitionVisitor extends MappingVisitor<DartType> {
- Scope scope;
- final TypeDeclarationElement enclosingElement;
- TypeDeclarationElement get element => enclosingElement;
-
- TypeDefinitionVisitor(Compiler compiler,
- TypeDeclarationElement element,
- ResolutionRegistry registry)
- : this.enclosingElement = element,
- scope = Scope.buildEnclosingScope(element),
- super(compiler, registry);
-
- DartType get objectType => compiler.objectClass.rawType;
-
- void resolveTypeVariableBounds(NodeList node) {
- if (node == null) return;
-
- Setlet<String> nameSet = new Setlet<String>();
- // Resolve the bounds of type variables.
- Iterator<DartType> types = element.typeVariables.iterator;
- Link<Node> nodeLink = node.nodes;
- while (!nodeLink.isEmpty) {
- types.moveNext();
- TypeVariableType typeVariable = types.current;
- String typeName = typeVariable.name;
- TypeVariable typeNode = nodeLink.head;
- registry.useType(typeNode, typeVariable);
- if (nameSet.contains(typeName)) {
- error(typeNode, MessageKind.DUPLICATE_TYPE_VARIABLE_NAME,
- {'typeVariableName': typeName});
- }
- nameSet.add(typeName);
-
- TypeVariableElementX variableElement = typeVariable.element;
- if (typeNode.bound != null) {
- DartType boundType = typeResolver.resolveTypeAnnotation(
- this, typeNode.bound);
- variableElement.boundCache = boundType;
-
- void checkTypeVariableBound() {
- Link<TypeVariableElement> seenTypeVariables =
- const Link<TypeVariableElement>();
- seenTypeVariables = seenTypeVariables.prepend(variableElement);
- DartType bound = boundType;
- while (bound.isTypeVariable) {
- TypeVariableElement element = bound.element;
- if (seenTypeVariables.contains(element)) {
- if (identical(element, variableElement)) {
- // Only report an error on the checked type variable to avoid
- // generating multiple errors for the same cyclicity.
- warning(typeNode.name, MessageKind.CYCLIC_TYPE_VARIABLE,
- {'typeVariableName': variableElement.name});
- }
- break;
- }
- seenTypeVariables = seenTypeVariables.prepend(element);
- bound = element.bound;
- }
- }
- addDeferredAction(element, checkTypeVariableBound);
- } else {
- variableElement.boundCache = objectType;
- }
- nodeLink = nodeLink.tail;
- }
- assert(!types.moveNext());
- }
-}
-
-class TypedefResolverVisitor extends TypeDefinitionVisitor {
- TypedefElementX get element => enclosingElement;
-
- TypedefResolverVisitor(Compiler compiler,
- TypedefElement typedefElement,
- ResolutionRegistry registry)
- : super(compiler, typedefElement, registry);
-
- visitTypedef(Typedef node) {
- TypedefType type = element.computeType(compiler);
- scope = new TypeDeclarationScope(scope, element);
- resolveTypeVariableBounds(node.typeParameters);
-
- FunctionSignature signature = SignatureResolver.analyze(
- compiler, node.formals, node.returnType, element, registry,
- defaultValuesError: MessageKind.TYPEDEF_FORMAL_WITH_DEFAULT);
- element.functionSignature = signature;
-
- scope = new MethodScope(scope, element);
- signature.forEachParameter(addToScope);
-
- element.alias = signature.type;
-
- void checkCyclicReference() {
- element.checkCyclicReference(compiler);
- }
- addDeferredAction(element, checkCyclicReference);
- }
-}
-
-// TODO(johnniwinther): Replace with a traversal on the AST when the type
-// annotations in typedef alias are stored in a [TreeElements] mapping.
-class TypedefCyclicVisitor extends DartTypeVisitor {
- final Compiler compiler;
- final TypedefElementX element;
- bool hasCyclicReference = false;
-
- Link<TypedefElement> seenTypedefs = const Link<TypedefElement>();
-
- int seenTypedefsCount = 0;
-
- Link<TypeVariableElement> seenTypeVariables =
- const Link<TypeVariableElement>();
-
- TypedefCyclicVisitor(Compiler this.compiler, TypedefElement this.element);
-
- visitType(DartType type, _) {
- // Do nothing.
- }
-
- visitTypedefType(TypedefType type, _) {
- TypedefElementX typedefElement = type.element;
- if (seenTypedefs.contains(typedefElement)) {
- if (!hasCyclicReference && identical(element, typedefElement)) {
- // Only report an error on the checked typedef to avoid generating
- // multiple errors for the same cyclicity.
- hasCyclicReference = true;
- if (seenTypedefsCount == 1) {
- // Direct cyclicity.
- compiler.reportError(element,
- MessageKind.CYCLIC_TYPEDEF,
- {'typedefName': element.name});
- } else if (seenTypedefsCount == 2) {
- // Cyclicity through one other typedef.
- compiler.reportError(element,
- MessageKind.CYCLIC_TYPEDEF_ONE,
- {'typedefName': element.name,
- 'otherTypedefName': seenTypedefs.head.name});
- } else {
- // Cyclicity through more than one other typedef.
- for (TypedefElement cycle in seenTypedefs) {
- if (!identical(typedefElement, cycle)) {
- compiler.reportError(element,
- MessageKind.CYCLIC_TYPEDEF_ONE,
- {'typedefName': element.name,
- 'otherTypedefName': cycle.name});
- }
- }
- }
- ErroneousElementX erroneousElement = new ErroneousElementX(
- MessageKind.CYCLIC_TYPEDEF,
- {'typedefName': element.name},
- element.name, element);
- element.alias =
- new MalformedType(erroneousElement, typedefElement.alias);
- element.hasBeenCheckedForCycles = true;
- }
- } else {
- seenTypedefs = seenTypedefs.prepend(typedefElement);
- seenTypedefsCount++;
- type.visitChildren(this, null);
- typedefElement.alias.accept(this, null);
- seenTypedefs = seenTypedefs.tail;
- seenTypedefsCount--;
- }
- }
-
- visitFunctionType(FunctionType type, _) {
- type.visitChildren(this, null);
- }
-
- visitInterfaceType(InterfaceType type, _) {
- type.visitChildren(this, null);
- }
-
- visitTypeVariableType(TypeVariableType type, _) {
- TypeVariableElement typeVariableElement = type.element;
- if (seenTypeVariables.contains(typeVariableElement)) {
- // Avoid running in cycles on cyclic type variable bounds.
- // Cyclicity is reported elsewhere.
- return;
- }
- seenTypeVariables = seenTypeVariables.prepend(typeVariableElement);
- typeVariableElement.bound.accept(this, null);
- seenTypeVariables = seenTypeVariables.tail;
- }
-}
-
-/**
- * The implementation of [ResolverTask.resolveClass].
- *
- * This visitor has to be extra careful as it is building the basic
- * element information, and cannot safely look at other elements as
- * this may lead to cycles.
- *
- * This visitor can assume that the supertypes have already been
- * resolved, but it cannot call [ResolverTask.resolveClass] directly
- * or indirectly (through [ClassElement.ensureResolved]) for any other
- * types.
- */
-class ClassResolverVisitor extends TypeDefinitionVisitor {
- BaseClassElementX get element => enclosingElement;
-
- ClassResolverVisitor(Compiler compiler,
- ClassElement classElement,
- ResolutionRegistry registry)
- : super(compiler, classElement, registry);
-
- DartType visitClassNode(ClassNode node) {
- invariant(node, element != null);
- invariant(element, element.resolutionState == STATE_STARTED,
- message: () => 'cyclic resolution of class $element');
-
- InterfaceType type = element.computeType(compiler);
- scope = new TypeDeclarationScope(scope, element);
- // TODO(ahe): It is not safe to call resolveTypeVariableBounds yet.
- // As a side-effect, this may get us back here trying to
- // resolve this class again.
- resolveTypeVariableBounds(node.typeParameters);
-
- // Setup the supertype for the element (if there is a cycle in the
- // class hierarchy, it has already been set to Object).
- if (element.supertype == null && node.superclass != null) {
- MixinApplication superMixin = node.superclass.asMixinApplication();
- if (superMixin != null) {
- DartType supertype = resolveSupertype(element, superMixin.superclass);
- Link<Node> link = superMixin.mixins.nodes;
- while (!link.isEmpty) {
- supertype = applyMixin(supertype,
- checkMixinType(link.head), link.head);
- link = link.tail;
- }
- element.supertype = supertype;
- } else {
- element.supertype = resolveSupertype(element, node.superclass);
- }
- }
- // If the super type isn't specified, we provide a default. The language
- // specifies [Object] but the backend can pick a specific 'implementation'
- // of Object - the JavaScript backend chooses between Object and
- // Interceptor.
- if (element.supertype == null) {
- ClassElement superElement = registry.defaultSuperclass(element);
- // Avoid making the superclass (usually Object) extend itself.
- if (element != superElement) {
- if (superElement == null) {
- compiler.internalError(node,
- "Cannot resolve default superclass for $element.");
- } else {
- superElement.ensureResolved(compiler);
- }
- element.supertype = superElement.computeType(compiler);
- }
- }
-
- if (element.interfaces == null) {
- element.interfaces = resolveInterfaces(node.interfaces, node.superclass);
- } else {
- assert(invariant(element, element.hasIncompleteHierarchy));
- }
- calculateAllSupertypes(element);
-
- if (!element.hasConstructor) {
- Element superMember = element.superclass.localLookup('');
- if (superMember == null || !superMember.isGenerativeConstructor) {
- MessageKind kind = MessageKind.CANNOT_FIND_CONSTRUCTOR;
- Map arguments = {'constructorName': ''};
- // TODO(ahe): Why is this a compile-time error? Or if it is an error,
- // why do we bother to registerThrowNoSuchMethod below?
- compiler.reportError(node, kind, arguments);
- superMember = new ErroneousElementX(
- kind, arguments, '', element);
- registry.registerThrowNoSuchMethod();
- } else {
- ConstructorElement superConstructor = superMember;
- Selector callToMatch = new Selector.call("", element.library, 0);
- superConstructor.computeSignature(compiler);
- if (!callToMatch.applies(superConstructor, compiler.world)) {
- MessageKind kind = MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT;
- compiler.reportError(node, kind);
- superMember = new ErroneousElementX(kind, {}, '', element);
- }
- }
- FunctionElement constructor =
- new SynthesizedConstructorElementX.forDefault(superMember, element);
- element.setDefaultConstructor(constructor, compiler);
- }
- return element.computeType(compiler);
- }
-
- /// Resolves the mixed type for [mixinNode] and checks that the the mixin type
- /// is a valid, non-blacklisted interface type. The mixin type is returned.
- DartType checkMixinType(TypeAnnotation mixinNode) {
- DartType mixinType = resolveType(mixinNode);
- if (isBlackListed(mixinType)) {
- compiler.reportError(mixinNode,
- MessageKind.CANNOT_MIXIN, {'type': mixinType});
- } else if (mixinType.isTypeVariable) {
- compiler.reportError(mixinNode, MessageKind.CLASS_NAME_EXPECTED);
- } else if (mixinType.isMalformed) {
- compiler.reportError(mixinNode, MessageKind.CANNOT_MIXIN_MALFORMED,
- {'className': element.name, 'malformedType': mixinType});
- }
- return mixinType;
- }
-
- DartType visitNamedMixinApplication(NamedMixinApplication node) {
- invariant(node, element != null);
- invariant(element, element.resolutionState == STATE_STARTED,
- message: () => 'cyclic resolution of class $element');
-
- if (identical(node.classKeyword.stringValue, 'typedef')) {
- // TODO(aprelev@gmail.com): Remove this deprecation diagnostic
- // together with corresponding TODO in parser.dart.
- compiler.reportWarning(node.classKeyword,
- MessageKind.DEPRECATED_TYPEDEF_MIXIN_SYNTAX);
- }
-
- InterfaceType type = element.computeType(compiler);
- scope = new TypeDeclarationScope(scope, element);
- resolveTypeVariableBounds(node.typeParameters);
-
- // Generate anonymous mixin application elements for the
- // intermediate mixin applications (excluding the last).
- DartType supertype = resolveSupertype(element, node.superclass);
- Link<Node> link = node.mixins.nodes;
- while (!link.tail.isEmpty) {
- supertype = applyMixin(supertype, checkMixinType(link.head), link.head);
- link = link.tail;
- }
- doApplyMixinTo(element, supertype, checkMixinType(link.head));
- return element.computeType(compiler);
- }
-
- DartType applyMixin(DartType supertype, DartType mixinType, Node node) {
- String superName = supertype.name;
- String mixinName = mixinType.name;
- MixinApplicationElementX mixinApplication = new MixinApplicationElementX(
- "${superName}+${mixinName}",
- element.compilationUnit,
- compiler.getNextFreeClassId(),
- node,
- new Modifiers.withFlags(new NodeList.empty(), Modifiers.FLAG_ABSTRACT));
- // Create synthetic type variables for the mixin application.
- List<DartType> typeVariables = <DartType>[];
- element.typeVariables.forEach((TypeVariableType type) {
- TypeVariableElementX typeVariableElement = new TypeVariableElementX(
- type.name, mixinApplication, type.element.node);
- TypeVariableType typeVariable = new TypeVariableType(typeVariableElement);
- typeVariables.add(typeVariable);
- });
- // Setup bounds on the synthetic type variables.
- List<DartType> link = typeVariables;
- int index = 0;
- element.typeVariables.forEach((TypeVariableType type) {
- TypeVariableType typeVariable = typeVariables[index++];
- TypeVariableElementX typeVariableElement = typeVariable.element;
- typeVariableElement.typeCache = typeVariable;
- typeVariableElement.boundCache =
- type.element.bound.subst(typeVariables, element.typeVariables);
- });
- // Setup this and raw type for the mixin application.
- mixinApplication.computeThisAndRawType(compiler, typeVariables);
- // Substitute in synthetic type variables in super and mixin types.
- supertype = supertype.subst(typeVariables, element.typeVariables);
- mixinType = mixinType.subst(typeVariables, element.typeVariables);
-
- doApplyMixinTo(mixinApplication, supertype, mixinType);
- mixinApplication.resolutionState = STATE_DONE;
- mixinApplication.supertypeLoadState = STATE_DONE;
- // Replace the synthetic type variables by the original type variables in
- // the returned type (which should be the type actually extended).
- InterfaceType mixinThisType = mixinApplication.computeType(compiler);
- return mixinThisType.subst(element.typeVariables,
- mixinThisType.typeArguments);
- }
-
- bool isDefaultConstructor(FunctionElement constructor) {
- return constructor.name == '' &&
- constructor.computeSignature(compiler).parameterCount == 0;
- }
-
- FunctionElement createForwardingConstructor(ConstructorElement target,
- ClassElement enclosing) {
- return new SynthesizedConstructorElementX(
- target.name, target, enclosing, false);
- }
-
- void doApplyMixinTo(MixinApplicationElementX mixinApplication,
- DartType supertype,
- DartType mixinType) {
- Node node = mixinApplication.parseNode(compiler);
-
- if (mixinApplication.supertype != null) {
- // [supertype] is not null if there was a cycle.
- assert(invariant(node, compiler.compilationFailed));
- supertype = mixinApplication.supertype;
- assert(invariant(node, supertype.element == compiler.objectClass));
- } else {
- mixinApplication.supertype = supertype;
- }
-
- // Named mixin application may have an 'implements' clause.
- NamedMixinApplication namedMixinApplication =
- node.asNamedMixinApplication();
- Link<DartType> interfaces = (namedMixinApplication != null)
- ? resolveInterfaces(namedMixinApplication.interfaces,
- namedMixinApplication.superclass)
- : const Link<DartType>();
-
- // The class that is the result of a mixin application implements
- // the interface of the class that was mixed in so always prepend
- // that to the interface list.
- if (mixinApplication.interfaces == null) {
- if (mixinType.isInterfaceType) {
- // Avoid malformed types in the interfaces.
- interfaces = interfaces.prepend(mixinType);
- }
- mixinApplication.interfaces = interfaces;
- } else {
- assert(invariant(mixinApplication,
- mixinApplication.hasIncompleteHierarchy));
- }
-
- ClassElement superclass = supertype.element;
- if (mixinType.kind != TypeKind.INTERFACE) {
- mixinApplication.hasIncompleteHierarchy = true;
- mixinApplication.allSupertypesAndSelf = superclass.allSupertypesAndSelf;
- return;
- }
-
- assert(mixinApplication.mixinType == null);
- mixinApplication.mixinType = resolveMixinFor(mixinApplication, mixinType);
-
- // Create forwarding constructors for constructor defined in the superclass
- // because they are now hidden by the mixin application.
- superclass.forEachLocalMember((Element member) {
- if (!member.isGenerativeConstructor) return;
- FunctionElement forwarder =
- createForwardingConstructor(member, mixinApplication);
- if (isPrivateName(member.name) &&
- mixinApplication.library != superclass.library) {
- // Do not create a forwarder to the super constructor, because the mixin
- // application is in a different library than the constructor in the
- // super class and it is not possible to call that constructor from the
- // library using the mixin application.
- return;
- }
- mixinApplication.addConstructor(forwarder);
- });
- calculateAllSupertypes(mixinApplication);
- }
-
- InterfaceType resolveMixinFor(MixinApplicationElement mixinApplication,
- DartType mixinType) {
- ClassElement mixin = mixinType.element;
- mixin.ensureResolved(compiler);
-
- // Check for cycles in the mixin chain.
- ClassElement previous = mixinApplication; // For better error messages.
- ClassElement current = mixin;
- while (current != null && current.isMixinApplication) {
- MixinApplicationElement currentMixinApplication = current;
- if (currentMixinApplication == mixinApplication) {
- compiler.reportError(
- mixinApplication, MessageKind.ILLEGAL_MIXIN_CYCLE,
- {'mixinName1': current.name, 'mixinName2': previous.name});
- // We have found a cycle in the mixin chain. Return null as
- // the mixin for this application to avoid getting into
- // infinite recursion when traversing members.
- return null;
- }
- previous = current;
- current = currentMixinApplication.mixin;
- }
- registry.registerMixinUse(mixinApplication, mixin);
- return mixinType;
- }
-
- DartType resolveType(TypeAnnotation node) {
- return typeResolver.resolveTypeAnnotation(this, node);
- }
-
- DartType resolveSupertype(ClassElement cls, TypeAnnotation superclass) {
- DartType supertype = resolveType(superclass);
- if (supertype != null) {
- if (identical(supertype.kind, TypeKind.MALFORMED_TYPE)) {
- compiler.reportError(superclass, MessageKind.CANNOT_EXTEND_MALFORMED,
- {'className': element.name, 'malformedType': supertype});
- return objectType;
- } else if (!identical(supertype.kind, TypeKind.INTERFACE)) {
- compiler.reportError(superclass.typeName,
- MessageKind.CLASS_NAME_EXPECTED);
- return objectType;
- } else if (isBlackListed(supertype)) {
- compiler.reportError(superclass, MessageKind.CANNOT_EXTEND,
- {'type': supertype});
- return objectType;
- }
- }
- return supertype;
- }
-
- Link<DartType> resolveInterfaces(NodeList interfaces, Node superclass) {
- Link<DartType> result = const Link<DartType>();
- if (interfaces == null) return result;
- for (Link<Node> link = interfaces.nodes; !link.isEmpty; link = link.tail) {
- DartType interfaceType = resolveType(link.head);
- if (interfaceType != null) {
- if (identical(interfaceType.kind, TypeKind.MALFORMED_TYPE)) {
- compiler.reportError(superclass,
- MessageKind.CANNOT_IMPLEMENT_MALFORMED,
- {'className': element.name, 'malformedType': interfaceType});
- } else if (!identical(interfaceType.kind, TypeKind.INTERFACE)) {
- // TODO(johnniwinther): Handle dynamic.
- TypeAnnotation typeAnnotation = link.head;
- error(typeAnnotation.typeName, MessageKind.CLASS_NAME_EXPECTED);
- } else {
- if (interfaceType == element.supertype) {
- compiler.reportError(
- superclass,
- MessageKind.DUPLICATE_EXTENDS_IMPLEMENTS,
- {'type': interfaceType});
- compiler.reportError(
- link.head,
- MessageKind.DUPLICATE_EXTENDS_IMPLEMENTS,
- {'type': interfaceType});
- }
- if (result.contains(interfaceType)) {
- compiler.reportError(
- link.head,
- MessageKind.DUPLICATE_IMPLEMENTS,
- {'type': interfaceType});
- }
- result = result.prepend(interfaceType);
- if (isBlackListed(interfaceType)) {
- error(link.head, MessageKind.CANNOT_IMPLEMENT,
- {'type': interfaceType});
- }
- }
- }
- }
- return result;
- }
-
- /**
- * Compute the list of all supertypes.
- *
- * The elements of this list are ordered as follows: first the supertype that
- * the class extends, then the implemented interfaces, and then the supertypes
- * of these. The class [Object] appears only once, at the end of the list.
- *
- * For example, for a class `class C extends S implements I1, I2`, we compute
- * supertypes(C) = [S, I1, I2] ++ supertypes(S) ++ supertypes(I1)
- * ++ supertypes(I2),
- * where ++ stands for list concatenation.
- *
- * This order makes sure that if a class implements an interface twice with
- * different type arguments, the type used in the most specific class comes
- * first.
- */
- void calculateAllSupertypes(BaseClassElementX cls) {
- if (cls.allSupertypesAndSelf != null) return;
- final DartType supertype = cls.supertype;
- if (supertype != null) {
- OrderedTypeSetBuilder allSupertypes = new OrderedTypeSetBuilder(cls);
- // TODO(15296): Collapse these iterations to one when the order is not
- // needed.
- allSupertypes.add(compiler, supertype);
- for (Link<DartType> interfaces = cls.interfaces;
- !interfaces.isEmpty;
- interfaces = interfaces.tail) {
- allSupertypes.add(compiler, interfaces.head);
- }
-
- addAllSupertypes(allSupertypes, supertype);
- for (Link<DartType> interfaces = cls.interfaces;
- !interfaces.isEmpty;
- interfaces = interfaces.tail) {
- addAllSupertypes(allSupertypes, interfaces.head);
- }
- allSupertypes.add(compiler, cls.computeType(compiler));
- cls.allSupertypesAndSelf = allSupertypes.toTypeSet();
- } else {
- assert(identical(cls, compiler.objectClass));
- cls.allSupertypesAndSelf =
- new OrderedTypeSet.singleton(cls.computeType(compiler));
- }
- }
-
- /**
- * Adds [type] and all supertypes of [type] to [allSupertypes] while
- * substituting type variables.
- */
- void addAllSupertypes(OrderedTypeSetBuilder allSupertypes,
- InterfaceType type) {
- ClassElement classElement = type.element;
- Link<DartType> supertypes = classElement.allSupertypes;
- assert(invariant(element, supertypes != null,
- message: "Supertypes not computed on $classElement "
- "during resolution of $element"));
- while (!supertypes.isEmpty) {
- DartType supertype = supertypes.head;
- allSupertypes.add(compiler, supertype.substByContext(type));
- supertypes = supertypes.tail;
- }
- }
-
- isBlackListed(DartType type) {
- LibraryElement lib = element.library;
- return
- !identical(lib, compiler.coreLibrary) &&
- !compiler.backend.isBackendLibrary(lib) &&
- (type.isDynamic ||
- identical(type.element, compiler.boolClass) ||
- identical(type.element, compiler.numClass) ||
- identical(type.element, compiler.intClass) ||
- identical(type.element, compiler.doubleClass) ||
- identical(type.element, compiler.stringClass) ||
- identical(type.element, compiler.nullClass));
- }
-}
-
-class ClassSupertypeResolver extends CommonResolverVisitor {
- Scope context;
- ClassElement classElement;
-
- ClassSupertypeResolver(Compiler compiler, ClassElement cls)
- : context = Scope.buildEnclosingScope(cls),
- this.classElement = cls,
- super(compiler);
-
- void loadSupertype(ClassElement element, Node from) {
- compiler.resolver.loadSupertypes(element, from);
- element.ensureResolved(compiler);
- }
-
- void visitNodeList(NodeList node) {
- if (node != null) {
- for (Link<Node> link = node.nodes; !link.isEmpty; link = link.tail) {
- link.head.accept(this);
- }
- }
- }
-
- void visitClassNode(ClassNode node) {
- if (node.superclass == null) {
- if (!identical(classElement, compiler.objectClass)) {
- loadSupertype(compiler.objectClass, node);
- }
- } else {
- node.superclass.accept(this);
- }
- visitNodeList(node.interfaces);
- }
-
- void visitMixinApplication(MixinApplication node) {
- node.superclass.accept(this);
- visitNodeList(node.mixins);
- }
-
- void visitNamedMixinApplication(NamedMixinApplication node) {
- node.superclass.accept(this);
- visitNodeList(node.mixins);
- visitNodeList(node.interfaces);
- }
-
- void visitTypeAnnotation(TypeAnnotation node) {
- node.typeName.accept(this);
- }
-
- void visitIdentifier(Identifier node) {
- Element element = lookupInScope(compiler, node, context, node.source);
- if (element != null && element.isClass) {
- loadSupertype(element, node);
- }
- }
-
- void visitSend(Send node) {
- Identifier prefix = node.receiver.asIdentifier();
- if (prefix == null) {
- error(node.receiver, MessageKind.NOT_A_PREFIX, {'node': node.receiver});
- return;
- }
- Element element = lookupInScope(compiler, prefix, context, prefix.source);
- if (element == null || !identical(element.kind, ElementKind.PREFIX)) {
- error(node.receiver, MessageKind.NOT_A_PREFIX, {'node': node.receiver});
- return;
- }
- PrefixElement prefixElement = element;
- Identifier selector = node.selector.asIdentifier();
- var e = prefixElement.lookupLocalMember(selector.source);
- if (e == null || !e.impliesType) {
- error(node.selector, MessageKind.CANNOT_RESOLVE_TYPE,
- {'typeName': node.selector});
- return;
- }
- loadSupertype(e, node);
- }
-}
-
-class VariableDefinitionsVisitor extends CommonResolverVisitor<Identifier> {
- VariableDefinitions definitions;
- ResolverVisitor resolver;
- VariableList variables;
-
- VariableDefinitionsVisitor(Compiler compiler,
- this.definitions,
- this.resolver,
- this.variables)
- : super(compiler) {
- }
-
- ResolutionRegistry get registry => resolver.registry;
-
- Identifier visitSendSet(SendSet node) {
- assert(node.arguments.tail.isEmpty); // Sanity check
- Identifier identifier = node.selector;
- String name = identifier.source;
- VariableDefinitionScope scope =
- new VariableDefinitionScope(resolver.scope, name);
- resolver.visitIn(node.arguments.head, scope);
- if (scope.variableReferencedInInitializer) {
- compiler.reportError(
- identifier, MessageKind.REFERENCE_IN_INITIALIZATION,
- {'variableName': name});
- }
- return identifier;
- }
-
- Identifier visitIdentifier(Identifier node) {
- // The variable is initialized to null.
- registry.registerInstantiatedClass(compiler.nullClass);
- if (definitions.modifiers.isConst) {
- compiler.reportError(node, MessageKind.CONST_WITHOUT_INITIALIZER);
- }
- if (definitions.modifiers.isFinal &&
- !resolver.allowFinalWithoutInitializer) {
- compiler.reportError(node, MessageKind.FINAL_WITHOUT_INITIALIZER);
- }
- return node;
- }
-
- visitNodeList(NodeList node) {
- for (Link<Node> link = node.nodes; !link.isEmpty; link = link.tail) {
- Identifier name = visit(link.head);
- LocalVariableElement element = new LocalVariableElementX(
- name.source, resolver.enclosingElement,
- variables, name.token);
- resolver.defineLocalVariable(link.head, element);
- resolver.addToScope(element);
- if (definitions.modifiers.isConst) {
- compiler.enqueuer.resolution.addDeferredAction(element, () {
- compiler.resolver.constantCompiler.compileConstant(element);
- });
- }
- }
- }
-}
-
-class ConstructorResolver extends CommonResolverVisitor<Element> {
- final ResolverVisitor resolver;
- bool inConstContext;
- DartType type;
-
- ConstructorResolver(Compiler compiler, this.resolver,
- {bool this.inConstContext: false})
- : super(compiler);
-
- ResolutionRegistry get registry => resolver.registry;
-
- visitNode(Node node) {
- throw 'not supported';
- }
-
- failOrReturnErroneousElement(Element enclosing, Node diagnosticNode,
- String targetName, MessageKind kind,
- Map arguments) {
- if (kind == MessageKind.CANNOT_FIND_CONSTRUCTOR) {
- registry.registerThrowNoSuchMethod();
- } else {
- registry.registerThrowRuntimeError();
- }
- if (inConstContext) {
- compiler.reportError(diagnosticNode, kind, arguments);
- } else {
- compiler.reportWarning(diagnosticNode, kind, arguments);
- }
- return new ErroneousElementX(kind, arguments, targetName, enclosing);
- }
-
- Selector createConstructorSelector(String constructorName) {
- return constructorName == ''
- ? new Selector.callDefaultConstructor(
- resolver.enclosingElement.library)
- : new Selector.callConstructor(
- constructorName,
- resolver.enclosingElement.library);
- }
-
- FunctionElement resolveConstructor(ClassElement cls,
- Node diagnosticNode,
- String constructorName) {
- cls.ensureResolved(compiler);
- Selector selector = createConstructorSelector(constructorName);
- Element result = cls.lookupConstructor(selector);
- if (result == null) {
- String fullConstructorName = Elements.constructorNameForDiagnostics(
- cls.name,
- constructorName);
- return failOrReturnErroneousElement(
- cls,
- diagnosticNode,
- fullConstructorName,
- MessageKind.CANNOT_FIND_CONSTRUCTOR,
- {'constructorName': fullConstructorName});
- } else if (inConstContext && !result.isConst) {
- error(diagnosticNode, MessageKind.CONSTRUCTOR_IS_NOT_CONST);
- }
- return result;
- }
-
- Element visitNewExpression(NewExpression node) {
- inConstContext = node.isConst;
- Node selector = node.send.selector;
- 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].
- 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 (!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 {
- element = failOrReturnErroneousElement(
- element, diagnosticNode, element.name, MessageKind.NOT_A_TYPE,
- {'node': diagnosticNode});
- }
- }
- if (type == null) {
- if (Elements.isUnresolved(element)) {
- type = const DynamicType();
- } else {
- type = element.enclosingClass.rawType;
- }
- }
- resolver.registry.setType(expression, type);
- return element;
- }
-
- 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.
- type = resolver.resolveTypeAnnotation(node,
- malformedIsError: inConstContext,
- deferredIsMalformed: false);
- registry.registerRequiredType(type, resolver.enclosingElement);
- return type.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 (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 failOrReturnErroneousElement(
- resolver.enclosingElement, name,
- name.source,
- MessageKind.CANNOT_RESOLVE,
- {'name': name});
- } else if (!element.isClass) {
- error(node, MessageKind.NOT_A_TYPE, {'node': name});
- }
- } else {
- internalError(node.receiver, 'unexpected element $element');
- }
- return element;
- }
-
- 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.
- if (element == null) {
- return failOrReturnErroneousElement(resolver.enclosingElement, node, name,
- MessageKind.CANNOT_RESOLVE,
- {'name': name});
- } else if (element.isErroneous) {
- return element;
- } else if (element.isTypedef) {
- error(node, MessageKind.CANNOT_INSTANTIATE_TYPEDEF,
- {'typedefName': name});
- } else if (element.isTypeVariable) {
- error(node, MessageKind.CANNOT_INSTANTIATE_TYPE_VARIABLE,
- {'typeVariableName': name});
- } else if (!element.isClass && !element.isPrefix) {
- error(node, MessageKind.NOT_A_TYPE, {'node': name});
- }
- return element;
- }
-
- /// Assumed to be called by [resolveRedirectingFactory].
- Element visitRedirectingFactoryBody(RedirectingFactoryBody node) {
- Node constructorReference = node.constructorReference;
- return finishConstructorReference(visit(constructorReference),
- constructorReference, node);
- }
-}
-
-/// Looks up [name] in [scope] and unwraps the result.
-Element lookupInScope(Compiler compiler, Node node,
- Scope scope, String name) {
- return Elements.unwrap(scope.lookup(name), compiler, node);
-}
-
-TreeElements _ensureTreeElements(AnalyzableElementX element) {
- if (element._treeElements == null) {
- element._treeElements = new TreeElementMapping(element);
- }
- return element._treeElements;
-}
-
-abstract class AnalyzableElementX implements AnalyzableElement {
- TreeElements _treeElements;
-
- bool get hasTreeElements => _treeElements != null;
-
- TreeElements get treeElements {
- assert(invariant(this, _treeElements !=null,
- message: "TreeElements have not been computed for $this."));
- return _treeElements;
- }
-
- void reuseElement() {
- _treeElements = null;
- }
-}
-
-/// The result of resolving a node.
-abstract class ResolutionResult {
- Element get element;
-}
-
-/// The result for the resolution of a node that points to an [Element].
-class ElementResult implements ResolutionResult {
- final Element element;
-
- // TODO(johnniwinther): Remove this factory constructor when `null` is never
- // passed as an element result.
- factory ElementResult(Element element) {
- return element != null ? new ElementResult.internal(element) : null;
- }
-
- ElementResult.internal(this.element);
-
- String toString() => 'ElementResult($element)';
-}
-
-/// The result for the resolution of a node that points to an [DartType].
-class TypeResult implements ResolutionResult {
- final DartType type;
-
- TypeResult(this.type) {
- assert(type != null);
- }
-
- Element get element => type.element;
-
- String toString() => 'TypeResult($type)';
-}
-
-/// The result for the resolution of the `assert` method.
-class AssertResult implements ResolutionResult {
- const AssertResult();
-
- Element get element => null;
-
- String toString() => 'AssertResult()';
-}
« no previous file with comments | « pkg/compiler/lib/src/resolution/member_impl.dart ('k') | pkg/compiler/lib/src/resolution/registry.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698