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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/resolution/members.dart

Issue 692513002: Remove old dart2js code. (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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 part of resolution;
6
7 abstract class TreeElements {
8 AnalyzableElement get analyzedElement;
9 Iterable<Node> get superUses;
10
11 /// Iterables of the dependencies that this [TreeElement] records of
12 /// [analyzedElement].
13 Iterable<Element> get allElements;
14 void forEachConstantNode(f(Node n, ConstantExpression c));
15
16 /// A set of additional dependencies. See [registerDependency] below.
17 Iterable<Element> get otherDependencies;
18
19 Element operator[](Node node);
20
21 // TODO(johnniwinther): Investigate whether [Node] could be a [Send].
22 Selector getSelector(Node node);
23 Selector getGetterSelectorInComplexSendSet(SendSet node);
24 Selector getOperatorSelectorInComplexSendSet(SendSet node);
25 DartType getType(Node node);
26 void setSelector(Node node, Selector selector);
27 void setGetterSelectorInComplexSendSet(SendSet node, Selector selector);
28 void setOperatorSelectorInComplexSendSet(SendSet node, Selector selector);
29
30 /// Returns the for-in loop variable for [node].
31 Element getForInVariable(ForIn node);
32 Selector getIteratorSelector(ForIn node);
33 Selector getMoveNextSelector(ForIn node);
34 Selector getCurrentSelector(ForIn node);
35 void setIteratorSelector(ForIn node, Selector selector);
36 void setMoveNextSelector(ForIn node, Selector selector);
37 void setCurrentSelector(ForIn node, Selector selector);
38 void setConstant(Node node, ConstantExpression constant);
39 ConstantExpression getConstant(Node node);
40 bool isAssert(Send send);
41
42 /// Returns the [FunctionElement] defined by [node].
43 FunctionElement getFunctionDefinition(FunctionExpression node);
44
45 /// Returns target constructor for the redirecting factory body [node].
46 ConstructorElement getRedirectingTargetConstructor(
47 RedirectingFactoryBody node);
48
49 /**
50 * Returns [:true:] if [node] is a type literal.
51 *
52 * Resolution marks this by setting the type on the node to be the
53 * type that the literal refers to.
54 */
55 bool isTypeLiteral(Send node);
56
57 /// Returns the type that the type literal [node] refers to.
58 DartType getTypeLiteralType(Send node);
59
60 /// Register additional dependencies required by [analyzedElement].
61 /// For example, elements that are used by a backend.
62 void registerDependency(Element element);
63
64 /// Returns a list of nodes that potentially mutate [element] anywhere in its
65 /// scope.
66 List<Node> getPotentialMutations(VariableElement element);
67
68 /// Returns a list of nodes that potentially mutate [element] in [node].
69 List<Node> getPotentialMutationsIn(Node node, VariableElement element);
70
71 /// Returns a list of nodes that potentially mutate [element] in a closure.
72 List<Node> getPotentialMutationsInClosure(VariableElement element);
73
74 /// Returns a list of nodes that access [element] within a closure in [node].
75 List<Node> getAccessesByClosureIn(Node node, VariableElement element);
76
77 /// Returns the jump target defined by [node].
78 JumpTarget getTargetDefinition(Node node);
79
80 /// Returns the jump target of the [node].
81 JumpTarget getTargetOf(GotoStatement node);
82
83 /// Returns the label defined by [node].
84 LabelDefinition getLabelDefinition(Label node);
85
86 /// Returns the label that [node] targets.
87 LabelDefinition getTargetLabel(GotoStatement node);
88 }
89
90 class TreeElementMapping implements TreeElements {
91 final AnalyzableElement analyzedElement;
92 Map<Spannable, Selector> _selectors;
93 Map<Node, DartType> _types;
94 Setlet<Node> _superUses;
95 Setlet<Element> _otherDependencies;
96 Map<Node, ConstantExpression> _constants;
97 Map<VariableElement, List<Node>> _potentiallyMutated;
98 Map<Node, Map<VariableElement, List<Node>>> _potentiallyMutatedIn;
99 Map<VariableElement, List<Node>> _potentiallyMutatedInClosure;
100 Map<Node, Map<VariableElement, List<Node>>> _accessedByClosureIn;
101 Setlet<Element> _elements;
102 Setlet<Send> _asserts;
103
104 /// Map from nodes to the targets they define.
105 Map<Node, JumpTarget> _definedTargets;
106
107 /// Map from goto statements to their targets.
108 Map<GotoStatement, JumpTarget> _usedTargets;
109
110 /// Map from labels to their label definition.
111 Map<Label, LabelDefinition> _definedLabels;
112
113 /// Map from labeled goto statements to the labels they target.
114 Map<GotoStatement, LabelDefinition> _targetLabels;
115
116 final int hashCode = ++_hashCodeCounter;
117 static int _hashCodeCounter = 0;
118
119 TreeElementMapping(this.analyzedElement);
120
121 operator []=(Node node, Element element) {
122 assert(invariant(node, () {
123 FunctionExpression functionExpression = node.asFunctionExpression();
124 if (functionExpression != null) {
125 return !functionExpression.modifiers.isExternal;
126 }
127 return true;
128 }));
129 // TODO(johnniwinther): Simplify this invariant to use only declarations in
130 // [TreeElements].
131 assert(invariant(node, () {
132 if (!element.isErroneous && analyzedElement != null && element.isPatch) {
133 return analyzedElement.implementationLibrary.isPatch;
134 }
135 return true;
136 }));
137 // TODO(ahe): Investigate why the invariant below doesn't hold.
138 // assert(invariant(node,
139 // getTreeElement(node) == element ||
140 // getTreeElement(node) == null,
141 // message: '${getTreeElement(node)}; $element'));
142
143 if (_elements == null) {
144 _elements = new Setlet<Element>();
145 }
146 _elements.add(element);
147 setTreeElement(node, element);
148 }
149
150 operator [](Node node) => getTreeElement(node);
151
152 void setType(Node node, DartType type) {
153 if (_types == null) {
154 _types = new Maplet<Node, DartType>();
155 }
156 _types[node] = type;
157 }
158
159 DartType getType(Node node) => _types != null ? _types[node] : null;
160
161 Iterable<Node> get superUses {
162 return _superUses != null ? _superUses : const <Node>[];
163 }
164
165 void addSuperUse(Node node) {
166 if (_superUses == null) {
167 _superUses = new Setlet<Node>();
168 }
169 _superUses.add(node);
170 }
171
172 Selector _getSelector(Spannable node) {
173 return _selectors != null ? _selectors[node] : null;
174 }
175
176 void _setSelector(Spannable node, Selector selector) {
177 if (_selectors == null) {
178 _selectors = new Maplet<Spannable, Selector>();
179 }
180 _selectors[node] = selector;
181 }
182
183 void setSelector(Node node, Selector selector) {
184 _setSelector(node, selector);
185 }
186
187 Selector getSelector(Node node) => _getSelector(node);
188
189 int getSelectorCount() => _selectors == null ? 0 : _selectors.length;
190
191 void setGetterSelectorInComplexSendSet(SendSet node, Selector selector) {
192 _setSelector(node.selector, selector);
193 }
194
195 Selector getGetterSelectorInComplexSendSet(SendSet node) {
196 return _getSelector(node.selector);
197 }
198
199 void setOperatorSelectorInComplexSendSet(SendSet node, Selector selector) {
200 _setSelector(node.assignmentOperator, selector);
201 }
202
203 Selector getOperatorSelectorInComplexSendSet(SendSet node) {
204 return _getSelector(node.assignmentOperator);
205 }
206
207 // The following methods set selectors on the "for in" node. Since
208 // we're using three selectors, we need to use children of the node,
209 // and we arbitrarily choose which ones.
210
211 void setIteratorSelector(ForIn node, Selector selector) {
212 _setSelector(node, selector);
213 }
214
215 Selector getIteratorSelector(ForIn node) {
216 return _getSelector(node);
217 }
218
219 void setMoveNextSelector(ForIn node, Selector selector) {
220 _setSelector(node.forToken, selector);
221 }
222
223 Selector getMoveNextSelector(ForIn node) {
224 return _getSelector(node.forToken);
225 }
226
227 void setCurrentSelector(ForIn node, Selector selector) {
228 _setSelector(node.inToken, selector);
229 }
230
231 Selector getCurrentSelector(ForIn node) {
232 return _getSelector(node.inToken);
233 }
234
235 Element getForInVariable(ForIn node) {
236 return this[node];
237 }
238
239 void setConstant(Node node, ConstantExpression constant) {
240 if (_constants == null) {
241 _constants = new Maplet<Node, ConstantExpression>();
242 }
243 _constants[node] = constant;
244 }
245
246 ConstantExpression getConstant(Node node) {
247 return _constants != null ? _constants[node] : null;
248 }
249
250 bool isTypeLiteral(Send node) {
251 return getType(node) != null;
252 }
253
254 DartType getTypeLiteralType(Send node) {
255 return getType(node);
256 }
257
258 void registerDependency(Element element) {
259 if (element == null) return;
260 if (_otherDependencies == null) {
261 _otherDependencies = new Setlet<Element>();
262 }
263 _otherDependencies.add(element.implementation);
264 }
265
266 Iterable<Element> get otherDependencies {
267 return _otherDependencies != null ? _otherDependencies : const <Element>[];
268 }
269
270 List<Node> getPotentialMutations(VariableElement element) {
271 if (_potentiallyMutated == null) return const <Node>[];
272 List<Node> mutations = _potentiallyMutated[element];
273 if (mutations == null) return const <Node>[];
274 return mutations;
275 }
276
277 void registerPotentialMutation(VariableElement element, Node mutationNode) {
278 if (_potentiallyMutated == null) {
279 _potentiallyMutated = new Maplet<VariableElement, List<Node>>();
280 }
281 _potentiallyMutated.putIfAbsent(element, () => <Node>[]).add(mutationNode);
282 }
283
284 List<Node> getPotentialMutationsIn(Node node, VariableElement element) {
285 if (_potentiallyMutatedIn == null) return const <Node>[];
286 Map<VariableElement, List<Node>> mutationsIn = _potentiallyMutatedIn[node];
287 if (mutationsIn == null) return const <Node>[];
288 List<Node> mutations = mutationsIn[element];
289 if (mutations == null) return const <Node>[];
290 return mutations;
291 }
292
293 void registerPotentialMutationIn(Node contextNode, VariableElement element,
294 Node mutationNode) {
295 if (_potentiallyMutatedIn == null) {
296 _potentiallyMutatedIn =
297 new Maplet<Node, Map<VariableElement, List<Node>>>();
298 }
299 Map<VariableElement, List<Node>> mutationMap =
300 _potentiallyMutatedIn.putIfAbsent(contextNode,
301 () => new Maplet<VariableElement, List<Node>>());
302 mutationMap.putIfAbsent(element, () => <Node>[]).add(mutationNode);
303 }
304
305 List<Node> getPotentialMutationsInClosure(VariableElement element) {
306 if (_potentiallyMutatedInClosure == null) return const <Node>[];
307 List<Node> mutations = _potentiallyMutatedInClosure[element];
308 if (mutations == null) return const <Node>[];
309 return mutations;
310 }
311
312 void registerPotentialMutationInClosure(VariableElement element,
313 Node mutationNode) {
314 if (_potentiallyMutatedInClosure == null) {
315 _potentiallyMutatedInClosure = new Maplet<VariableElement, List<Node>>();
316 }
317 _potentiallyMutatedInClosure.putIfAbsent(
318 element, () => <Node>[]).add(mutationNode);
319 }
320
321 List<Node> getAccessesByClosureIn(Node node, VariableElement element) {
322 if (_accessedByClosureIn == null) return const <Node>[];
323 Map<VariableElement, List<Node>> accessesIn = _accessedByClosureIn[node];
324 if (accessesIn == null) return const <Node>[];
325 List<Node> accesses = accessesIn[element];
326 if (accesses == null) return const <Node>[];
327 return accesses;
328 }
329
330 void setAccessedByClosureIn(Node contextNode, VariableElement element,
331 Node accessNode) {
332 if (_accessedByClosureIn == null) {
333 _accessedByClosureIn = new Map<Node, Map<VariableElement, List<Node>>>();
334 }
335 Map<VariableElement, List<Node>> accessMap =
336 _accessedByClosureIn.putIfAbsent(contextNode,
337 () => new Maplet<VariableElement, List<Node>>());
338 accessMap.putIfAbsent(element, () => <Node>[]).add(accessNode);
339 }
340
341 String toString() => 'TreeElementMapping($analyzedElement)';
342
343 Iterable<Element> get allElements {
344 return _elements != null ? _elements : const <Element>[];
345 }
346
347 void forEachConstantNode(f(Node n, ConstantExpression c)) {
348 if (_constants != null) {
349 _constants.forEach(f);
350 }
351 }
352
353 void setAssert(Send node) {
354 if (_asserts == null) {
355 _asserts = new Setlet<Send>();
356 }
357 _asserts.add(node);
358 }
359
360 bool isAssert(Send node) {
361 return _asserts != null && _asserts.contains(node);
362 }
363
364 FunctionElement getFunctionDefinition(FunctionExpression node) {
365 return this[node];
366 }
367
368 ConstructorElement getRedirectingTargetConstructor(
369 RedirectingFactoryBody node) {
370 return this[node];
371 }
372
373 void defineTarget(Node node, JumpTarget target) {
374 if (_definedTargets == null) {
375 _definedTargets = new Maplet<Node, JumpTarget>();
376 }
377 _definedTargets[node] = target;
378 }
379
380 void undefineTarget(Node node) {
381 if (_definedTargets != null) {
382 _definedTargets.remove(node);
383 if (_definedTargets.isEmpty) {
384 _definedTargets = null;
385 }
386 }
387 }
388
389 JumpTarget getTargetDefinition(Node node) {
390 return _definedTargets != null ? _definedTargets[node] : null;
391 }
392
393 void registerTargetOf(GotoStatement node, JumpTarget target) {
394 if (_usedTargets == null) {
395 _usedTargets = new Maplet<GotoStatement, JumpTarget>();
396 }
397 _usedTargets[node] = target;
398 }
399
400 JumpTarget getTargetOf(GotoStatement node) {
401 return _usedTargets != null ? _usedTargets[node] : null;
402 }
403
404 void defineLabel(Label label, LabelDefinition target) {
405 if (_definedLabels == null) {
406 _definedLabels = new Maplet<Label, LabelDefinition>();
407 }
408 _definedLabels[label] = target;
409 }
410
411 void undefineLabel(Label label) {
412 if (_definedLabels != null) {
413 _definedLabels.remove(label);
414 if (_definedLabels.isEmpty) {
415 _definedLabels = null;
416 }
417 }
418 }
419
420 LabelDefinition getLabelDefinition(Label label) {
421 return _definedLabels != null ? _definedLabels[label] : null;
422 }
423
424 void registerTargetLabel(GotoStatement node, LabelDefinition label) {
425 assert(node.target != null);
426 if (_targetLabels == null) {
427 _targetLabels = new Maplet<GotoStatement, LabelDefinition>();
428 }
429 _targetLabels[node] = label;
430 }
431
432 LabelDefinition getTargetLabel(GotoStatement node) {
433 assert(node.target != null);
434 return _targetLabels != null ? _targetLabels[node] : null;
435 }
436 }
437
438 class ResolverTask extends CompilerTask {
439 final ConstantCompiler constantCompiler;
440
441 ResolverTask(Compiler compiler, this.constantCompiler) : super(compiler);
442
443 String get name => 'Resolver';
444
445 TreeElements resolve(Element element) {
446 return measure(() {
447 if (Elements.isErroneousElement(element)) return null;
448
449 processMetadata([result]) {
450 for (MetadataAnnotation metadata in element.metadata) {
451 metadata.ensureResolved(compiler);
452 }
453 return result;
454 }
455
456 ElementKind kind = element.kind;
457 if (identical(kind, ElementKind.GENERATIVE_CONSTRUCTOR) ||
458 identical(kind, ElementKind.FUNCTION) ||
459 identical(kind, ElementKind.GETTER) ||
460 identical(kind, ElementKind.SETTER)) {
461 return processMetadata(resolveMethodElement(element));
462 }
463
464 if (identical(kind, ElementKind.FIELD)) {
465 return processMetadata(resolveField(element));
466 }
467 if (element.isClass) {
468 ClassElement cls = element;
469 cls.ensureResolved(compiler);
470 return processMetadata();
471 } else if (element.isTypedef) {
472 TypedefElement typdef = element;
473 return processMetadata(resolveTypedef(typdef));
474 }
475
476 compiler.unimplemented(element, "resolve($element)");
477 });
478 }
479
480 void resolveRedirectingConstructor(InitializerResolver resolver,
481 Node node,
482 FunctionElement constructor,
483 FunctionElement redirection) {
484 assert(invariant(node, constructor.isImplementation,
485 message: 'Redirecting constructors must be resolved on implementation '
486 'elements.'));
487 Setlet<FunctionElement> seen = new Setlet<FunctionElement>();
488 seen.add(constructor);
489 while (redirection != null) {
490 // Ensure that we follow redirections through implementation elements.
491 redirection = redirection.implementation;
492 if (seen.contains(redirection)) {
493 resolver.visitor.error(node, MessageKind.REDIRECTING_CONSTRUCTOR_CYCLE);
494 return;
495 }
496 seen.add(redirection);
497 redirection = resolver.visitor.resolveConstructorRedirection(redirection);
498 }
499 }
500
501 void checkMatchingPatchParameters(FunctionElement origin,
502 Link<Element> originParameters,
503 Link<Element> patchParameters) {
504 while (!originParameters.isEmpty) {
505 ParameterElementX originParameter = originParameters.head;
506 ParameterElementX patchParameter = patchParameters.head;
507 // TODO(johnniwinther): Remove the conditional patching when we never
508 // resolve the same method twice.
509 if (!originParameter.isPatched) {
510 originParameter.applyPatch(patchParameter);
511 } else {
512 assert(invariant(origin, originParameter.patch == patchParameter,
513 message: "Inconsistent repatch of $originParameter."));
514 }
515 DartType originParameterType = originParameter.computeType(compiler);
516 DartType patchParameterType = patchParameter.computeType(compiler);
517 if (originParameterType != patchParameterType) {
518 compiler.reportError(
519 originParameter.parseNode(compiler),
520 MessageKind.PATCH_PARAMETER_TYPE_MISMATCH,
521 {'methodName': origin.name,
522 'parameterName': originParameter.name,
523 'originParameterType': originParameterType,
524 'patchParameterType': patchParameterType});
525 compiler.reportInfo(patchParameter,
526 MessageKind.PATCH_POINT_TO_PARAMETER,
527 {'parameterName': patchParameter.name});
528 } else {
529 // Hack: Use unparser to test parameter equality. This only works
530 // because we are restricting patch uses and the approach cannot be used
531 // elsewhere.
532
533 // The node contains the type, so there is a potential overlap.
534 // Therefore we only check the text if the types are identical.
535 String originParameterText =
536 originParameter.parseNode(compiler).toString();
537 String patchParameterText =
538 patchParameter.parseNode(compiler).toString();
539 if (originParameterText != patchParameterText
540 // We special case the list constructor because of the
541 // optional parameter.
542 && origin != compiler.unnamedListConstructor) {
543 compiler.reportError(
544 originParameter.parseNode(compiler),
545 MessageKind.PATCH_PARAMETER_MISMATCH,
546 {'methodName': origin.name,
547 'originParameter': originParameterText,
548 'patchParameter': patchParameterText});
549 compiler.reportInfo(patchParameter,
550 MessageKind.PATCH_POINT_TO_PARAMETER,
551 {'parameterName': patchParameter.name});
552 }
553 }
554
555 originParameters = originParameters.tail;
556 patchParameters = patchParameters.tail;
557 }
558 }
559
560 void checkMatchingPatchSignatures(FunctionElement origin,
561 FunctionElement patch) {
562 // TODO(johnniwinther): Show both origin and patch locations on errors.
563 FunctionExpression originTree = origin.node;
564 FunctionSignature originSignature = origin.functionSignature;
565 FunctionExpression patchTree = patch.node;
566 FunctionSignature patchSignature = patch.functionSignature;
567
568 if (originSignature.type.returnType != patchSignature.type.returnType) {
569 compiler.withCurrentElement(patch, () {
570 Node errorNode =
571 patchTree.returnType != null ? patchTree.returnType : patchTree;
572 error(errorNode, MessageKind.PATCH_RETURN_TYPE_MISMATCH,
573 {'methodName': origin.name,
574 'originReturnType': originSignature.type.returnType,
575 'patchReturnType': patchSignature.type.returnType});
576 });
577 }
578 if (originSignature.requiredParameterCount !=
579 patchSignature.requiredParameterCount) {
580 compiler.withCurrentElement(patch, () {
581 error(patchTree,
582 MessageKind.PATCH_REQUIRED_PARAMETER_COUNT_MISMATCH,
583 {'methodName': origin.name,
584 'originParameterCount': originSignature.requiredParameterCount,
585 'patchParameterCount': patchSignature.requiredParameterCount});
586 });
587 } else {
588 checkMatchingPatchParameters(origin,
589 originSignature.requiredParameters,
590 patchSignature.requiredParameters);
591 }
592 if (originSignature.optionalParameterCount != 0 &&
593 patchSignature.optionalParameterCount != 0) {
594 if (originSignature.optionalParametersAreNamed !=
595 patchSignature.optionalParametersAreNamed) {
596 compiler.withCurrentElement(patch, () {
597 error(patchTree,
598 MessageKind.PATCH_OPTIONAL_PARAMETER_NAMED_MISMATCH,
599 {'methodName': origin.name});
600 });
601 }
602 }
603 if (originSignature.optionalParameterCount !=
604 patchSignature.optionalParameterCount) {
605 compiler.withCurrentElement(patch, () {
606 error(patchTree,
607 MessageKind.PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH,
608 {'methodName': origin.name,
609 'originParameterCount': originSignature.optionalParameterCount,
610 'patchParameterCount': patchSignature.optionalParameterCount});
611 });
612 } else {
613 checkMatchingPatchParameters(origin,
614 originSignature.optionalParameters,
615 patchSignature.optionalParameters);
616 }
617 }
618
619 TreeElements resolveMethodElement(FunctionElementX element) {
620 assert(invariant(element, element.isDeclaration));
621 return compiler.withCurrentElement(element, () {
622 bool isConstructor =
623 identical(element.kind, ElementKind.GENERATIVE_CONSTRUCTOR);
624 if (compiler.enqueuer.resolution.hasBeenResolved(element)) {
625 // TODO(karlklose): Remove the check for [isConstructor]. [elememts]
626 // should never be non-null, not even for constructors.
627 assert(invariant(element, element.isConstructor,
628 message: 'Non-constructor element $element '
629 'has already been analyzed.'));
630 return element.resolvedAst.elements;
631 }
632 if (element.isSynthesized) {
633 if (isConstructor) {
634 ResolutionRegistry registry =
635 new ResolutionRegistry(compiler, element);
636 ConstructorElement constructor = element.asFunctionElement();
637 ConstructorElement target = constructor.definingConstructor;
638 // Ensure the signature of the synthesized element is
639 // resolved. This is the only place where the resolver is
640 // seeing this element.
641 element.computeSignature(compiler);
642 if (!target.isErroneous) {
643 registry.registerStaticUse(target);
644 registry.registerImplicitSuperCall(target);
645 }
646 return registry.mapping;
647 } else {
648 assert(element.isDeferredLoaderGetter);
649 return _ensureTreeElements(element);
650 }
651 }
652 element.parseNode(compiler);
653 element.computeType(compiler);
654 if (element.isPatched) {
655 FunctionElementX patch = element.patch;
656 compiler.withCurrentElement(patch, () {
657 patch.parseNode(compiler);
658 patch.computeType(compiler);
659 });
660 checkMatchingPatchSignatures(element, patch);
661 element = patch;
662 }
663 return compiler.withCurrentElement(element, () {
664 FunctionExpression tree = element.node;
665 if (tree.modifiers.isExternal) {
666 error(tree, MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION);
667 return null;
668 }
669 if (isConstructor || element.isFactoryConstructor) {
670 if (tree.returnType != null) {
671 error(tree, MessageKind.CONSTRUCTOR_WITH_RETURN_TYPE);
672 }
673 if (element.modifiers.isConst &&
674 tree.hasBody() &&
675 !tree.isRedirectingFactory) {
676 compiler.reportError(tree, MessageKind.CONST_CONSTRUCTOR_HAS_BODY);
677 }
678 }
679
680 ResolverVisitor visitor = visitorFor(element);
681 ResolutionRegistry registry = visitor.registry;
682 registry.defineFunction(tree, element);
683 visitor.setupFunction(tree, element);
684
685 if (isConstructor && !element.isForwardingConstructor) {
686 // Even if there is no initializer list we still have to do the
687 // resolution in case there is an implicit super constructor call.
688 InitializerResolver resolver = new InitializerResolver(visitor);
689 FunctionElement redirection =
690 resolver.resolveInitializers(element, tree);
691 if (redirection != null) {
692 resolveRedirectingConstructor(resolver, tree, element, redirection);
693 }
694 } else if (element.isForwardingConstructor) {
695 // Initializers will be checked on the original constructor.
696 } else if (tree.initializers != null) {
697 error(tree, MessageKind.FUNCTION_WITH_INITIALIZER);
698 }
699
700 if (!compiler.analyzeSignaturesOnly || tree.isRedirectingFactory) {
701 // We need to analyze the redirecting factory bodies to ensure that
702 // we can analyze compile-time constants.
703 visitor.visit(tree.body);
704 }
705
706 // Get the resolution tree and check that the resolved
707 // function doesn't use 'super' if it is mixed into another
708 // class. This is the part of the 'super' mixin check that
709 // happens when a function is resolved after the mixin
710 // application has been performed.
711 TreeElements resolutionTree = registry.mapping;
712 ClassElement enclosingClass = element.enclosingClass;
713 if (enclosingClass != null) {
714 // TODO(johnniwinther): Find another way to obtain mixin uses.
715 Iterable<MixinApplicationElement> mixinUses =
716 compiler.world.allMixinUsesOf(enclosingClass);
717 ClassElement mixin = enclosingClass;
718 for (MixinApplicationElement mixinApplication in mixinUses) {
719 checkMixinSuperUses(resolutionTree, mixinApplication, mixin);
720 }
721 }
722 return resolutionTree;
723 });
724 });
725 }
726
727 /// Creates a [ResolverVisitor] for resolving an AST in context of [element].
728 /// If [useEnclosingScope] is `true` then the initial scope of the visitor
729 /// does not include inner scope of [element].
730 ///
731 /// This method should only be used by this library (or tests of
732 /// this library).
733 ResolverVisitor visitorFor(Element element, {bool useEnclosingScope: false}) {
734 return new ResolverVisitor(compiler, element,
735 new ResolutionRegistry(compiler, element),
736 useEnclosingScope: useEnclosingScope);
737 }
738
739 TreeElements resolveField(FieldElementX element) {
740 VariableDefinitions tree = element.parseNode(compiler);
741 if(element.modifiers.isStatic && element.isTopLevel) {
742 error(element.modifiers.getStatic(),
743 MessageKind.TOP_LEVEL_VARIABLE_DECLARED_STATIC);
744 }
745 ResolverVisitor visitor = visitorFor(element);
746 ResolutionRegistry registry = visitor.registry;
747 // TODO(johnniwinther): Maybe remove this when placeholderCollector migrates
748 // to the backend ast.
749 registry.defineElement(tree.definitions.nodes.head, element);
750 // TODO(johnniwinther): Share the resolved type between all variables
751 // declared in the same declaration.
752 if (tree.type != null) {
753 element.variables.type = visitor.resolveTypeAnnotation(tree.type);
754 } else {
755 element.variables.type = const DynamicType();
756 }
757
758 Expression initializer = element.initializer;
759 Modifiers modifiers = element.modifiers;
760 if (initializer != null) {
761 // TODO(johnniwinther): Avoid analyzing initializers if
762 // [Compiler.analyzeSignaturesOnly] is set.
763 visitor.visit(initializer);
764 } else if (modifiers.isConst) {
765 compiler.reportError(element, MessageKind.CONST_WITHOUT_INITIALIZER);
766 } else if (modifiers.isFinal && !element.isInstanceMember) {
767 compiler.reportError(element, MessageKind.FINAL_WITHOUT_INITIALIZER);
768 } else {
769 registry.registerInstantiatedClass(compiler.nullClass);
770 }
771
772 if (Elements.isStaticOrTopLevelField(element)) {
773 visitor.addDeferredAction(element, () {
774 if (element.modifiers.isConst) {
775 constantCompiler.compileConstant(element);
776 } else {
777 constantCompiler.compileVariable(element);
778 }
779 });
780 if (initializer != null) {
781 if (!element.modifiers.isConst) {
782 // TODO(johnniwinther): Determine the const-ness eagerly to avoid
783 // unnecessary registrations.
784 registry.registerLazyField();
785 }
786 }
787 }
788
789 // Perform various checks as side effect of "computing" the type.
790 element.computeType(compiler);
791
792 return registry.mapping;
793 }
794
795 DartType resolveTypeAnnotation(Element element, TypeAnnotation annotation) {
796 DartType type = resolveReturnType(element, annotation);
797 if (type.isVoid) {
798 error(annotation, MessageKind.VOID_NOT_ALLOWED);
799 }
800 return type;
801 }
802
803 DartType resolveReturnType(Element element, TypeAnnotation annotation) {
804 if (annotation == null) return const DynamicType();
805 DartType result = visitorFor(element).resolveTypeAnnotation(annotation);
806 if (result == null) {
807 // TODO(karklose): warning.
808 return const DynamicType();
809 }
810 return result;
811 }
812
813 void resolveRedirectionChain(ConstructorElementX constructor,
814 Spannable node) {
815 ConstructorElementX target = constructor;
816 InterfaceType targetType;
817 List<Element> seen = new List<Element>();
818 // Follow the chain of redirections and check for cycles.
819 while (target.isRedirectingFactory) {
820 if (target.internalEffectiveTarget != null) {
821 // We found a constructor that already has been processed.
822 targetType = target.effectiveTargetType;
823 assert(invariant(target, targetType != null,
824 message: 'Redirection target type has not been computed for '
825 '$target'));
826 target = target.internalEffectiveTarget;
827 break;
828 }
829
830 Element nextTarget = target.immediateRedirectionTarget;
831 if (seen.contains(nextTarget)) {
832 error(node, MessageKind.CYCLIC_REDIRECTING_FACTORY);
833 break;
834 }
835 seen.add(target);
836 target = nextTarget;
837 }
838
839 if (targetType == null) {
840 assert(!target.isRedirectingFactory);
841 targetType = target.enclosingClass.thisType;
842 }
843
844 // [target] is now the actual target of the redirections. Run through
845 // the constructors again and set their [redirectionTarget], so that we
846 // do not have to run the loop for these constructors again. Furthermore,
847 // compute [redirectionTargetType] for each factory by computing the
848 // substitution of the target type with respect to the factory type.
849 while (!seen.isEmpty) {
850 ConstructorElementX factory = seen.removeLast();
851
852 // [factory] must already be analyzed but the [TreeElements] might not
853 // have been stored in the enqueuer cache yet.
854 // TODO(johnniwinther): Store [TreeElements] in the cache before
855 // resolution of the element.
856 TreeElements treeElements = factory.treeElements;
857 assert(invariant(node, treeElements != null,
858 message: 'No TreeElements cached for $factory.'));
859 FunctionExpression functionNode = factory.parseNode(compiler);
860 RedirectingFactoryBody redirectionNode = functionNode.body;
861 InterfaceType factoryType = treeElements.getType(redirectionNode);
862
863 targetType = targetType.substByContext(factoryType);
864 factory.effectiveTarget = target;
865 factory.effectiveTargetType = targetType;
866 }
867 }
868
869 /**
870 * Load and resolve the supertypes of [cls].
871 *
872 * Warning: do not call this method directly. It should only be
873 * called by [resolveClass] and [ClassSupertypeResolver].
874 */
875 void loadSupertypes(BaseClassElementX cls, Spannable from) {
876 compiler.withCurrentElement(cls, () => measure(() {
877 if (cls.supertypeLoadState == STATE_DONE) return;
878 if (cls.supertypeLoadState == STATE_STARTED) {
879 compiler.reportError(from, MessageKind.CYCLIC_CLASS_HIERARCHY,
880 {'className': cls.name});
881 cls.supertypeLoadState = STATE_DONE;
882 cls.hasIncompleteHierarchy = true;
883 cls.allSupertypesAndSelf =
884 compiler.objectClass.allSupertypesAndSelf.extendClass(
885 cls.computeType(compiler));
886 cls.supertype = cls.allSupertypes.head;
887 assert(invariant(from, cls.supertype != null,
888 message: 'Missing supertype on cyclic class $cls.'));
889 cls.interfaces = const Link<DartType>();
890 return;
891 }
892 cls.supertypeLoadState = STATE_STARTED;
893 compiler.withCurrentElement(cls, () {
894 // TODO(ahe): Cache the node in cls.
895 cls.parseNode(compiler).accept(
896 new ClassSupertypeResolver(compiler, cls));
897 if (cls.supertypeLoadState != STATE_DONE) {
898 cls.supertypeLoadState = STATE_DONE;
899 }
900 });
901 }));
902 }
903
904 // TODO(johnniwinther): Remove this queue when resolution has been split into
905 // syntax and semantic resolution.
906 TypeDeclarationElement currentlyResolvedTypeDeclaration;
907 Queue<ClassElement> pendingClassesToBeResolved = new Queue<ClassElement>();
908 Queue<ClassElement> pendingClassesToBePostProcessed =
909 new Queue<ClassElement>();
910
911 /// Resolve [element] using [resolveTypeDeclaration].
912 ///
913 /// This methods ensure that class declarations encountered through type
914 /// annotations during the resolution of [element] are resolved after
915 /// [element] has been resolved.
916 // TODO(johnniwinther): Encapsulate this functionality in a
917 // 'TypeDeclarationResolver'.
918 _resolveTypeDeclaration(TypeDeclarationElement element,
919 resolveTypeDeclaration()) {
920 return compiler.withCurrentElement(element, () {
921 return measure(() {
922 TypeDeclarationElement previousResolvedTypeDeclaration =
923 currentlyResolvedTypeDeclaration;
924 currentlyResolvedTypeDeclaration = element;
925 var result = resolveTypeDeclaration();
926 if (previousResolvedTypeDeclaration == null) {
927 do {
928 while (!pendingClassesToBeResolved.isEmpty) {
929 pendingClassesToBeResolved.removeFirst().ensureResolved(compiler);
930 }
931 while (!pendingClassesToBePostProcessed.isEmpty) {
932 _postProcessClassElement(
933 pendingClassesToBePostProcessed.removeFirst());
934 }
935 } while (!pendingClassesToBeResolved.isEmpty);
936 assert(pendingClassesToBeResolved.isEmpty);
937 assert(pendingClassesToBePostProcessed.isEmpty);
938 }
939 currentlyResolvedTypeDeclaration = previousResolvedTypeDeclaration;
940 return result;
941 });
942 });
943 }
944
945 /**
946 * Resolve the class [element].
947 *
948 * Before calling this method, [element] was constructed by the
949 * scanner and most fields are null or empty. This method fills in
950 * these fields and also ensure that the supertypes of [element] are
951 * resolved.
952 *
953 * Warning: Do not call this method directly. Instead use
954 * [:element.ensureResolved(compiler):].
955 */
956 TreeElements resolveClass(BaseClassElementX element) {
957 return _resolveTypeDeclaration(element, () {
958 // TODO(johnniwinther): Store the mapping in the resolution enqueuer.
959 ResolutionRegistry registry = new ResolutionRegistry(compiler, element);
960 resolveClassInternal(element, registry);
961 return element.treeElements;
962 });
963 }
964
965 void _ensureClassWillBeResolved(ClassElement element) {
966 if (currentlyResolvedTypeDeclaration == null) {
967 element.ensureResolved(compiler);
968 } else {
969 pendingClassesToBeResolved.add(element);
970 }
971 }
972
973 void resolveClassInternal(BaseClassElementX element,
974 ResolutionRegistry registry) {
975 if (!element.isPatch) {
976 compiler.withCurrentElement(element, () => measure(() {
977 assert(element.resolutionState == STATE_NOT_STARTED);
978 element.resolutionState = STATE_STARTED;
979 Node tree = element.parseNode(compiler);
980 loadSupertypes(element, tree);
981
982 ClassResolverVisitor visitor =
983 new ClassResolverVisitor(compiler, element, registry);
984 visitor.visit(tree);
985 element.resolutionState = STATE_DONE;
986 compiler.onClassResolved(element);
987 pendingClassesToBePostProcessed.add(element);
988 }));
989 if (element.isPatched) {
990 // Ensure handling patch after origin.
991 element.patch.ensureResolved(compiler);
992 }
993 } else { // Handle patch classes:
994 element.resolutionState = STATE_STARTED;
995 // Ensure handling origin before patch.
996 element.origin.ensureResolved(compiler);
997 // Ensure that the type is computed.
998 element.computeType(compiler);
999 // Copy class hierarchy from origin.
1000 element.supertype = element.origin.supertype;
1001 element.interfaces = element.origin.interfaces;
1002 element.allSupertypesAndSelf = element.origin.allSupertypesAndSelf;
1003 // Stepwise assignment to ensure invariant.
1004 element.supertypeLoadState = STATE_STARTED;
1005 element.supertypeLoadState = STATE_DONE;
1006 element.resolutionState = STATE_DONE;
1007 // TODO(johnniwinther): Check matching type variables and
1008 // empty extends/implements clauses.
1009 }
1010 }
1011
1012 void _postProcessClassElement(BaseClassElementX element) {
1013 for (MetadataAnnotation metadata in element.metadata) {
1014 metadata.ensureResolved(compiler);
1015 if (!element.isProxy &&
1016 metadata.constant.value == compiler.proxyConstant) {
1017 element.isProxy = true;
1018 }
1019 }
1020
1021 // Force resolution of metadata on non-instance members since they may be
1022 // inspected by the backend while emitting. Metadata on instance members is
1023 // handled as a result of processing instantiated class members in the
1024 // enqueuer.
1025 // TODO(ahe): Avoid this eager resolution.
1026 element.forEachMember((_, Element member) {
1027 if (!member.isInstanceMember) {
1028 compiler.withCurrentElement(member, () {
1029 for (MetadataAnnotation metadata in member.metadata) {
1030 metadata.ensureResolved(compiler);
1031 }
1032 });
1033 }
1034 });
1035
1036 computeClassMember(element, Compiler.CALL_OPERATOR_NAME);
1037 }
1038
1039 void computeClassMembers(ClassElement element) {
1040 MembersCreator.computeAllClassMembers(compiler, element);
1041 }
1042
1043 void computeClassMember(ClassElement element, String name) {
1044 MembersCreator.computeClassMembersByName(compiler, element, name);
1045 }
1046
1047 void checkClass(ClassElement element) {
1048 computeClassMembers(element);
1049 if (element.isMixinApplication) {
1050 checkMixinApplication(element);
1051 } else {
1052 checkClassMembers(element);
1053 }
1054 }
1055
1056 void checkMixinApplication(MixinApplicationElementX mixinApplication) {
1057 Modifiers modifiers = mixinApplication.modifiers;
1058 int illegalFlags = modifiers.flags & ~Modifiers.FLAG_ABSTRACT;
1059 if (illegalFlags != 0) {
1060 Modifiers illegalModifiers = new Modifiers.withFlags(null, illegalFlags);
1061 compiler.reportError(
1062 modifiers,
1063 MessageKind.ILLEGAL_MIXIN_APPLICATION_MODIFIERS,
1064 {'modifiers': illegalModifiers});
1065 }
1066
1067 // In case of cyclic mixin applications, the mixin chain will have
1068 // been cut. If so, we have already reported the error to the
1069 // user so we just return from here.
1070 ClassElement mixin = mixinApplication.mixin;
1071 if (mixin == null) return;
1072
1073 // Check that we're not trying to use Object as a mixin.
1074 if (mixin.superclass == null) {
1075 compiler.reportError(mixinApplication,
1076 MessageKind.ILLEGAL_MIXIN_OBJECT);
1077 // Avoid reporting additional errors for the Object class.
1078 return;
1079 }
1080
1081 // Check that the mixed in class has Object as its superclass.
1082 if (!mixin.superclass.isObject) {
1083 compiler.reportError(mixin, MessageKind.ILLEGAL_MIXIN_SUPERCLASS);
1084 }
1085
1086 // Check that the mixed in class doesn't have any constructors and
1087 // make sure we aren't mixing in methods that use 'super'.
1088 mixin.forEachLocalMember((AstElement member) {
1089 if (member.isGenerativeConstructor && !member.isSynthesized) {
1090 compiler.reportError(member, MessageKind.ILLEGAL_MIXIN_CONSTRUCTOR);
1091 } else {
1092 // Get the resolution tree and check that the resolved member
1093 // doesn't use 'super'. This is the part of the 'super' mixin
1094 // check that happens when a function is resolved before the
1095 // mixin application has been performed.
1096 // TODO(johnniwinther): Obtain the [TreeElements] for [member]
1097 // differently.
1098 if (compiler.enqueuer.resolution.hasBeenResolved(member)) {
1099 checkMixinSuperUses(
1100 member.resolvedAst.elements,
1101 mixinApplication,
1102 mixin);
1103 }
1104 }
1105 });
1106 }
1107
1108 void checkMixinSuperUses(TreeElements resolutionTree,
1109 MixinApplicationElement mixinApplication,
1110 ClassElement mixin) {
1111 // TODO(johnniwinther): Avoid the use of [TreeElements] here.
1112 if (resolutionTree == null) return;
1113 Iterable<Node> superUses = resolutionTree.superUses;
1114 if (superUses.isEmpty) return;
1115 compiler.reportError(mixinApplication,
1116 MessageKind.ILLEGAL_MIXIN_WITH_SUPER,
1117 {'className': mixin.name});
1118 // Show the user the problematic uses of 'super' in the mixin.
1119 for (Node use in superUses) {
1120 compiler.reportInfo(
1121 use,
1122 MessageKind.ILLEGAL_MIXIN_SUPER_USE);
1123 }
1124 }
1125
1126 void checkClassMembers(ClassElement cls) {
1127 assert(invariant(cls, cls.isDeclaration));
1128 if (cls.isObject) return;
1129 // TODO(johnniwinther): Should this be done on the implementation element as
1130 // well?
1131 List<Element> constConstructors = <Element>[];
1132 List<Element> nonFinalInstanceFields = <Element>[];
1133 cls.forEachMember((holder, member) {
1134 compiler.withCurrentElement(member, () {
1135 // Perform various checks as side effect of "computing" the type.
1136 member.computeType(compiler);
1137
1138 // Check modifiers.
1139 if (member.isFunction && member.modifiers.isFinal) {
1140 compiler.reportError(
1141 member, MessageKind.ILLEGAL_FINAL_METHOD_MODIFIER);
1142 }
1143 if (member.isConstructor) {
1144 final mismatchedFlagsBits =
1145 member.modifiers.flags &
1146 (Modifiers.FLAG_STATIC | Modifiers.FLAG_ABSTRACT);
1147 if (mismatchedFlagsBits != 0) {
1148 final mismatchedFlags =
1149 new Modifiers.withFlags(null, mismatchedFlagsBits);
1150 compiler.reportError(
1151 member,
1152 MessageKind.ILLEGAL_CONSTRUCTOR_MODIFIERS,
1153 {'modifiers': mismatchedFlags});
1154 }
1155 if (member.modifiers.isConst) {
1156 constConstructors.add(member);
1157 }
1158 }
1159 if (member.isField) {
1160 if (member.modifiers.isConst && !member.modifiers.isStatic) {
1161 compiler.reportError(
1162 member, MessageKind.ILLEGAL_CONST_FIELD_MODIFIER);
1163 }
1164 if (!member.modifiers.isStatic && !member.modifiers.isFinal) {
1165 nonFinalInstanceFields.add(member);
1166 }
1167 }
1168 checkAbstractField(member);
1169 checkUserDefinableOperator(member);
1170 });
1171 });
1172 if (!constConstructors.isEmpty && !nonFinalInstanceFields.isEmpty) {
1173 Spannable span = constConstructors.length > 1
1174 ? cls : constConstructors[0];
1175 compiler.reportError(span,
1176 MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS,
1177 {'className': cls.name});
1178 if (constConstructors.length > 1) {
1179 for (Element constructor in constConstructors) {
1180 compiler.reportInfo(constructor,
1181 MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_CONSTRUCTOR);
1182 }
1183 }
1184 for (Element field in nonFinalInstanceFields) {
1185 compiler.reportInfo(field,
1186 MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_FIELD);
1187 }
1188 }
1189 }
1190
1191 void checkAbstractField(Element member) {
1192 // Only check for getters. The test can only fail if there is both a setter
1193 // and a getter with the same name, and we only need to check each abstract
1194 // field once, so we just ignore setters.
1195 if (!member.isGetter) return;
1196
1197 // Find the associated abstract field.
1198 ClassElement classElement = member.enclosingClass;
1199 Element lookupElement = classElement.lookupLocalMember(member.name);
1200 if (lookupElement == null) {
1201 compiler.internalError(member,
1202 "No abstract field for accessor");
1203 } else if (!identical(lookupElement.kind, ElementKind.ABSTRACT_FIELD)) {
1204 compiler.internalError(member,
1205 "Inaccessible abstract field for accessor");
1206 }
1207 AbstractFieldElement field = lookupElement;
1208
1209 FunctionElementX getter = field.getter;
1210 if (getter == null) return;
1211 FunctionElementX setter = field.setter;
1212 if (setter == null) return;
1213 int getterFlags = getter.modifiers.flags | Modifiers.FLAG_ABSTRACT;
1214 int setterFlags = setter.modifiers.flags | Modifiers.FLAG_ABSTRACT;
1215 if (!identical(getterFlags, setterFlags)) {
1216 final mismatchedFlags =
1217 new Modifiers.withFlags(null, getterFlags ^ setterFlags);
1218 compiler.reportError(
1219 field.getter,
1220 MessageKind.GETTER_MISMATCH,
1221 {'modifiers': mismatchedFlags});
1222 compiler.reportError(
1223 field.setter,
1224 MessageKind.SETTER_MISMATCH,
1225 {'modifiers': mismatchedFlags});
1226 }
1227 }
1228
1229 void checkUserDefinableOperator(Element member) {
1230 FunctionElement function = member.asFunctionElement();
1231 if (function == null) return;
1232 String value = member.name;
1233 if (value == null) return;
1234 if (!(isUserDefinableOperator(value) || identical(value, 'unary-'))) return;
1235
1236 bool isMinus = false;
1237 int requiredParameterCount;
1238 MessageKind messageKind;
1239 if (identical(value, 'unary-')) {
1240 isMinus = true;
1241 messageKind = MessageKind.MINUS_OPERATOR_BAD_ARITY;
1242 requiredParameterCount = 0;
1243 } else if (isMinusOperator(value)) {
1244 isMinus = true;
1245 messageKind = MessageKind.MINUS_OPERATOR_BAD_ARITY;
1246 requiredParameterCount = 1;
1247 } else if (isUnaryOperator(value)) {
1248 messageKind = MessageKind.UNARY_OPERATOR_BAD_ARITY;
1249 requiredParameterCount = 0;
1250 } else if (isBinaryOperator(value)) {
1251 messageKind = MessageKind.BINARY_OPERATOR_BAD_ARITY;
1252 requiredParameterCount = 1;
1253 if (identical(value, '==')) checkOverrideHashCode(member);
1254 } else if (isTernaryOperator(value)) {
1255 messageKind = MessageKind.TERNARY_OPERATOR_BAD_ARITY;
1256 requiredParameterCount = 2;
1257 } else {
1258 compiler.internalError(function,
1259 'Unexpected user defined operator $value');
1260 }
1261 checkArity(function, requiredParameterCount, messageKind, isMinus);
1262 }
1263
1264 void checkOverrideHashCode(FunctionElement operatorEquals) {
1265 if (operatorEquals.isAbstract) return;
1266 ClassElement cls = operatorEquals.enclosingClass;
1267 Element hashCodeImplementation =
1268 cls.lookupLocalMember('hashCode');
1269 if (hashCodeImplementation != null) return;
1270 compiler.reportHint(
1271 operatorEquals, MessageKind.OVERRIDE_EQUALS_NOT_HASH_CODE,
1272 {'class': cls.name});
1273 }
1274
1275 void checkArity(FunctionElement function,
1276 int requiredParameterCount, MessageKind messageKind,
1277 bool isMinus) {
1278 FunctionExpression node = function.node;
1279 FunctionSignature signature = function.functionSignature;
1280 if (signature.requiredParameterCount != requiredParameterCount) {
1281 Node errorNode = node;
1282 if (node.parameters != null) {
1283 if (isMinus ||
1284 signature.requiredParameterCount < requiredParameterCount) {
1285 // If there are too few parameters, point to the whole parameter list.
1286 // For instance
1287 //
1288 // int operator +() {}
1289 // ^^
1290 //
1291 // int operator []=(value) {}
1292 // ^^^^^^^
1293 //
1294 // For operator -, always point the whole parameter list, like
1295 //
1296 // int operator -(a, b) {}
1297 // ^^^^^^
1298 //
1299 // instead of
1300 //
1301 // int operator -(a, b) {}
1302 // ^
1303 //
1304 // since the correction might not be to remove 'b' but instead to
1305 // remove 'a, b'.
1306 errorNode = node.parameters;
1307 } else {
1308 errorNode = node.parameters.nodes.skip(requiredParameterCount).head;
1309 }
1310 }
1311 compiler.reportError(
1312 errorNode, messageKind, {'operatorName': function.name});
1313 }
1314 if (signature.optionalParameterCount != 0) {
1315 Node errorNode =
1316 node.parameters.nodes.skip(signature.requiredParameterCount).head;
1317 if (signature.optionalParametersAreNamed) {
1318 compiler.reportError(
1319 errorNode,
1320 MessageKind.OPERATOR_NAMED_PARAMETERS,
1321 {'operatorName': function.name});
1322 } else {
1323 compiler.reportError(
1324 errorNode,
1325 MessageKind.OPERATOR_OPTIONAL_PARAMETERS,
1326 {'operatorName': function.name});
1327 }
1328 }
1329 }
1330
1331 reportErrorWithContext(Element errorneousElement,
1332 MessageKind errorMessage,
1333 Element contextElement,
1334 MessageKind contextMessage) {
1335 compiler.reportError(
1336 errorneousElement,
1337 errorMessage,
1338 {'memberName': contextElement.name,
1339 'className': contextElement.enclosingClass.name});
1340 compiler.reportInfo(contextElement, contextMessage);
1341 }
1342
1343
1344 FunctionSignature resolveSignature(FunctionElementX element) {
1345 MessageKind defaultValuesError = null;
1346 if (element.isFactoryConstructor) {
1347 FunctionExpression body = element.parseNode(compiler);
1348 if (body.isRedirectingFactory) {
1349 defaultValuesError = MessageKind.REDIRECTING_FACTORY_WITH_DEFAULT;
1350 }
1351 }
1352 return compiler.withCurrentElement(element, () {
1353 FunctionExpression node =
1354 compiler.parser.measure(() => element.parseNode(compiler));
1355 return measure(() => SignatureResolver.analyze(
1356 compiler, node.parameters, node.returnType, element,
1357 new ResolutionRegistry(compiler, element),
1358 defaultValuesError: defaultValuesError,
1359 createRealParameters: true));
1360 });
1361 }
1362
1363 TreeElements resolveTypedef(TypedefElementX element) {
1364 if (element.isResolved) return element.treeElements;
1365 compiler.world.allTypedefs.add(element);
1366 return _resolveTypeDeclaration(element, () {
1367 ResolutionRegistry registry = new ResolutionRegistry(compiler, element);
1368 return compiler.withCurrentElement(element, () {
1369 return measure(() {
1370 assert(element.resolutionState == STATE_NOT_STARTED);
1371 element.resolutionState = STATE_STARTED;
1372 Typedef node =
1373 compiler.parser.measure(() => element.parseNode(compiler));
1374 TypedefResolverVisitor visitor =
1375 new TypedefResolverVisitor(compiler, element, registry);
1376 visitor.visit(node);
1377 element.resolutionState = STATE_DONE;
1378 return registry.mapping;
1379 });
1380 });
1381 });
1382 }
1383
1384 void resolveMetadataAnnotation(MetadataAnnotationX annotation) {
1385 compiler.withCurrentElement(annotation.annotatedElement, () => measure(() {
1386 assert(annotation.resolutionState == STATE_NOT_STARTED);
1387 annotation.resolutionState = STATE_STARTED;
1388
1389 Node node = annotation.parseNode(compiler);
1390 Element annotatedElement = annotation.annotatedElement;
1391 AnalyzableElement context = annotatedElement.analyzableElement;
1392 ClassElement classElement = annotatedElement.enclosingClass;
1393 if (classElement != null) {
1394 // The annotation is resolved in the scope of [classElement].
1395 classElement.ensureResolved(compiler);
1396 }
1397 assert(invariant(node, context != null,
1398 message: "No context found for metadata annotation "
1399 "on $annotatedElement."));
1400 ResolverVisitor visitor = visitorFor(context, useEnclosingScope: true);
1401 ResolutionRegistry registry = visitor.registry;
1402 node.accept(visitor);
1403 // TODO(johnniwinther): Avoid passing the [TreeElements] to
1404 // [compileMetadata].
1405 annotation.constant =
1406 constantCompiler.compileMetadata(annotation, node, registry.mapping);
1407 // TODO(johnniwinther): Register the relation between the annotation
1408 // and the annotated element instead. This will allow the backend to
1409 // retrieve the backend constant and only register metadata on the
1410 // elements for which it is needed. (Issue 17732).
1411 registry.registerMetadataConstant(annotation, annotatedElement);
1412 annotation.resolutionState = STATE_DONE;
1413 }));
1414 }
1415
1416 error(Spannable node, MessageKind kind, [arguments = const {}]) {
1417 // TODO(ahe): Make non-fatal.
1418 compiler.reportFatalError(node, kind, arguments);
1419 }
1420
1421 Link<MetadataAnnotation> resolveMetadata(Element element,
1422 VariableDefinitions node) {
1423 LinkBuilder<MetadataAnnotation> metadata =
1424 new LinkBuilder<MetadataAnnotation>();
1425 for (Metadata annotation in node.metadata.nodes) {
1426 ParameterMetadataAnnotation metadataAnnotation =
1427 new ParameterMetadataAnnotation(annotation);
1428 metadataAnnotation.annotatedElement = element;
1429 metadata.addLast(metadataAnnotation.ensureResolved(compiler));
1430 }
1431 return metadata.toLink();
1432 }
1433 }
1434
1435 class InitializerResolver {
1436 final ResolverVisitor visitor;
1437 final Map<Element, Node> initialized;
1438 Link<Node> initializers;
1439 bool hasSuper;
1440
1441 InitializerResolver(this.visitor)
1442 : initialized = new Map<Element, Node>(), hasSuper = false;
1443
1444 ResolutionRegistry get registry => visitor.registry;
1445
1446 error(Node node, MessageKind kind, [arguments = const {}]) {
1447 visitor.error(node, kind, arguments);
1448 }
1449
1450 warning(Node node, MessageKind kind, [arguments = const {}]) {
1451 visitor.warning(node, kind, arguments);
1452 }
1453
1454 bool isFieldInitializer(SendSet node) {
1455 if (node.selector.asIdentifier() == null) return false;
1456 if (node.receiver == null) return true;
1457 if (node.receiver.asIdentifier() == null) return false;
1458 return node.receiver.asIdentifier().isThis();
1459 }
1460
1461 reportDuplicateInitializerError(Element field, Node init, Node existing) {
1462 visitor.compiler.reportError(
1463 init,
1464 MessageKind.DUPLICATE_INITIALIZER, {'fieldName': field.name});
1465 visitor.compiler.reportInfo(
1466 existing,
1467 MessageKind.ALREADY_INITIALIZED, {'fieldName': field.name});
1468 }
1469
1470 void checkForDuplicateInitializers(FieldElementX field, Node init) {
1471 // [field] can be null if it could not be resolved.
1472 if (field == null) return;
1473 String name = field.name;
1474 if (initialized.containsKey(field)) {
1475 reportDuplicateInitializerError(field, init, initialized[field]);
1476 } else if (field.isFinal) {
1477 field.parseNode(visitor.compiler);
1478 Expression initializer = field.initializer;
1479 if (initializer != null) {
1480 reportDuplicateInitializerError(field, init, initializer);
1481 }
1482 }
1483 initialized[field] = init;
1484 }
1485
1486 void resolveFieldInitializer(FunctionElement constructor, SendSet init) {
1487 // init is of the form [this.]field = value.
1488 final Node selector = init.selector;
1489 final String name = selector.asIdentifier().source;
1490 // Lookup target field.
1491 Element target;
1492 if (isFieldInitializer(init)) {
1493 target = constructor.enclosingClass.lookupLocalMember(name);
1494 if (target == null) {
1495 error(selector, MessageKind.CANNOT_RESOLVE, {'name': name});
1496 } else if (target.kind != ElementKind.FIELD) {
1497 error(selector, MessageKind.NOT_A_FIELD, {'fieldName': name});
1498 } else if (!target.isInstanceMember) {
1499 error(selector, MessageKind.INIT_STATIC_FIELD, {'fieldName': name});
1500 }
1501 } else {
1502 error(init, MessageKind.INVALID_RECEIVER_IN_INITIALIZER);
1503 }
1504 registry.useElement(init, target);
1505 registry.registerStaticUse(target);
1506 checkForDuplicateInitializers(target, init);
1507 // Resolve initializing value.
1508 visitor.visitInStaticContext(init.arguments.head);
1509 }
1510
1511 ClassElement getSuperOrThisLookupTarget(FunctionElement constructor,
1512 bool isSuperCall,
1513 Node diagnosticNode) {
1514 ClassElement lookupTarget = constructor.enclosingClass;
1515 if (isSuperCall) {
1516 // Calculate correct lookup target and constructor name.
1517 if (identical(lookupTarget, visitor.compiler.objectClass)) {
1518 error(diagnosticNode, MessageKind.SUPER_INITIALIZER_IN_OBJECT);
1519 } else {
1520 return lookupTarget.supertype.element;
1521 }
1522 }
1523 return lookupTarget;
1524 }
1525
1526 Element resolveSuperOrThisForSend(FunctionElement constructor,
1527 FunctionExpression functionNode,
1528 Send call) {
1529 // Resolve the selector and the arguments.
1530 ResolverTask resolver = visitor.compiler.resolver;
1531 visitor.inStaticContext(() {
1532 visitor.resolveSelector(call, null);
1533 visitor.resolveArguments(call.argumentsNode);
1534 });
1535 Selector selector = registry.getSelector(call);
1536 bool isSuperCall = Initializers.isSuperConstructorCall(call);
1537
1538 ClassElement lookupTarget = getSuperOrThisLookupTarget(constructor,
1539 isSuperCall,
1540 call);
1541 Selector constructorSelector =
1542 visitor.getRedirectingThisOrSuperConstructorSelector(call);
1543 FunctionElement calledConstructor =
1544 lookupTarget.lookupConstructor(constructorSelector);
1545
1546 final bool isImplicitSuperCall = false;
1547 final String className = lookupTarget.name;
1548 verifyThatConstructorMatchesCall(constructor,
1549 calledConstructor,
1550 selector,
1551 isImplicitSuperCall,
1552 call,
1553 className,
1554 constructorSelector);
1555
1556 registry.useElement(call, calledConstructor);
1557 registry.registerStaticUse(calledConstructor);
1558 return calledConstructor;
1559 }
1560
1561 void resolveImplicitSuperConstructorSend(FunctionElement constructor,
1562 FunctionExpression functionNode) {
1563 // If the class has a super resolve the implicit super call.
1564 ClassElement classElement = constructor.enclosingClass;
1565 ClassElement superClass = classElement.superclass;
1566 if (classElement != visitor.compiler.objectClass) {
1567 assert(superClass != null);
1568 assert(superClass.resolutionState == STATE_DONE);
1569 String constructorName = '';
1570 Selector callToMatch = new Selector.call(
1571 constructorName,
1572 classElement.library,
1573 0);
1574
1575 final bool isSuperCall = true;
1576 ClassElement lookupTarget = getSuperOrThisLookupTarget(constructor,
1577 isSuperCall,
1578 functionNode);
1579 Selector constructorSelector = new Selector.callDefaultConstructor(
1580 visitor.enclosingElement.library);
1581 Element calledConstructor = lookupTarget.lookupConstructor(
1582 constructorSelector);
1583
1584 final String className = lookupTarget.name;
1585 final bool isImplicitSuperCall = true;
1586 verifyThatConstructorMatchesCall(constructor,
1587 calledConstructor,
1588 callToMatch,
1589 isImplicitSuperCall,
1590 functionNode,
1591 className,
1592 constructorSelector);
1593 registry.registerImplicitSuperCall(calledConstructor);
1594 registry.registerStaticUse(calledConstructor);
1595 }
1596 }
1597
1598 void verifyThatConstructorMatchesCall(
1599 FunctionElement caller,
1600 FunctionElement lookedupConstructor,
1601 Selector call,
1602 bool isImplicitSuperCall,
1603 Node diagnosticNode,
1604 String className,
1605 Selector constructorSelector) {
1606 if (lookedupConstructor == null
1607 || !lookedupConstructor.isGenerativeConstructor) {
1608 String fullConstructorName = Elements.constructorNameForDiagnostics(
1609 className,
1610 constructorSelector.name);
1611 MessageKind kind = isImplicitSuperCall
1612 ? MessageKind.CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT
1613 : MessageKind.CANNOT_RESOLVE_CONSTRUCTOR;
1614 visitor.compiler.reportError(
1615 diagnosticNode, kind, {'constructorName': fullConstructorName});
1616 } else {
1617 lookedupConstructor.computeSignature(visitor.compiler);
1618 if (!call.applies(lookedupConstructor, visitor.compiler.world)) {
1619 MessageKind kind = isImplicitSuperCall
1620 ? MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT
1621 : MessageKind.NO_MATCHING_CONSTRUCTOR;
1622 visitor.compiler.reportError(diagnosticNode, kind);
1623 } else if (caller.isConst
1624 && !lookedupConstructor.isConst) {
1625 visitor.compiler.reportError(
1626 diagnosticNode, MessageKind.CONST_CALLS_NON_CONST);
1627 }
1628 }
1629 }
1630
1631 /**
1632 * Resolve all initializers of this constructor. In the case of a redirecting
1633 * constructor, the resolved constructor's function element is returned.
1634 */
1635 FunctionElement resolveInitializers(FunctionElement constructor,
1636 FunctionExpression functionNode) {
1637 // Keep track of all "this.param" parameters specified for constructor so
1638 // that we can ensure that fields are initialized only once.
1639 FunctionSignature functionParameters = constructor.functionSignature;
1640 functionParameters.forEachParameter((ParameterElement element) {
1641 if (element.isInitializingFormal) {
1642 InitializingFormalElement initializingFormal = element;
1643 checkForDuplicateInitializers(initializingFormal.fieldElement,
1644 element.initializer);
1645 }
1646 });
1647
1648 if (functionNode.initializers == null) {
1649 initializers = const Link<Node>();
1650 } else {
1651 initializers = functionNode.initializers.nodes;
1652 }
1653 FunctionElement result;
1654 bool resolvedSuper = false;
1655 for (Link<Node> link = initializers; !link.isEmpty; link = link.tail) {
1656 if (link.head.asSendSet() != null) {
1657 final SendSet init = link.head.asSendSet();
1658 resolveFieldInitializer(constructor, init);
1659 } else if (link.head.asSend() != null) {
1660 final Send call = link.head.asSend();
1661 if (call.argumentsNode == null) {
1662 error(link.head, MessageKind.INVALID_INITIALIZER);
1663 continue;
1664 }
1665 if (Initializers.isSuperConstructorCall(call)) {
1666 if (resolvedSuper) {
1667 error(call, MessageKind.DUPLICATE_SUPER_INITIALIZER);
1668 }
1669 resolveSuperOrThisForSend(constructor, functionNode, call);
1670 resolvedSuper = true;
1671 } else if (Initializers.isConstructorRedirect(call)) {
1672 // Check that there is no body (Language specification 7.5.1). If the
1673 // constructor is also const, we already reported an error in
1674 // [resolveMethodElement].
1675 if (functionNode.hasBody() && !constructor.isConst) {
1676 error(functionNode, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_BODY);
1677 }
1678 // Check that there are no other initializers.
1679 if (!initializers.tail.isEmpty) {
1680 error(call, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER);
1681 }
1682 // Check that there are no field initializing parameters.
1683 Compiler compiler = visitor.compiler;
1684 FunctionSignature signature = constructor.functionSignature;
1685 signature.forEachParameter((ParameterElement parameter) {
1686 if (parameter.isInitializingFormal) {
1687 Node node = parameter.node;
1688 error(node, MessageKind.INITIALIZING_FORMAL_NOT_ALLOWED);
1689 }
1690 });
1691 return resolveSuperOrThisForSend(constructor, functionNode, call);
1692 } else {
1693 visitor.error(call, MessageKind.CONSTRUCTOR_CALL_EXPECTED);
1694 return null;
1695 }
1696 } else {
1697 error(link.head, MessageKind.INVALID_INITIALIZER);
1698 }
1699 }
1700 if (!resolvedSuper) {
1701 resolveImplicitSuperConstructorSend(constructor, functionNode);
1702 }
1703 return null; // If there was no redirection always return null.
1704 }
1705 }
1706
1707 class CommonResolverVisitor<R> extends Visitor<R> {
1708 final Compiler compiler;
1709
1710 CommonResolverVisitor(Compiler this.compiler);
1711
1712 R visitNode(Node node) {
1713 internalError(node,
1714 'internal error: Unhandled node: ${node.getObjectDescription()}');
1715 return null;
1716 }
1717
1718 R visitEmptyStatement(Node node) => null;
1719
1720 /** Convenience method for visiting nodes that may be null. */
1721 R visit(Node node) => (node == null) ? null : node.accept(this);
1722
1723 void error(Spannable node, MessageKind kind, [Map arguments = const {}]) {
1724 compiler.reportFatalError(node, kind, arguments);
1725 }
1726
1727 void warning(Spannable node, MessageKind kind, [Map arguments = const {}]) {
1728 compiler.reportWarning(node, kind, arguments);
1729 }
1730
1731 void internalError(Spannable node, message) {
1732 compiler.internalError(node, message);
1733 }
1734
1735 void addDeferredAction(Element element, DeferredAction action) {
1736 compiler.enqueuer.resolution.addDeferredAction(element, action);
1737 }
1738 }
1739
1740 abstract class LabelScope {
1741 LabelScope get outer;
1742 LabelDefinition lookup(String label);
1743 }
1744
1745 class LabeledStatementLabelScope implements LabelScope {
1746 final LabelScope outer;
1747 final Map<String, LabelDefinition> labels;
1748 LabeledStatementLabelScope(this.outer, this.labels);
1749 LabelDefinition lookup(String labelName) {
1750 LabelDefinition label = labels[labelName];
1751 if (label != null) return label;
1752 return outer.lookup(labelName);
1753 }
1754 }
1755
1756 class SwitchLabelScope implements LabelScope {
1757 final LabelScope outer;
1758 final Map<String, LabelDefinition> caseLabels;
1759
1760 SwitchLabelScope(this.outer, this.caseLabels);
1761
1762 LabelDefinition lookup(String labelName) {
1763 LabelDefinition result = caseLabels[labelName];
1764 if (result != null) return result;
1765 return outer.lookup(labelName);
1766 }
1767 }
1768
1769 class EmptyLabelScope implements LabelScope {
1770 const EmptyLabelScope();
1771 LabelDefinition lookup(String label) => null;
1772 LabelScope get outer {
1773 throw 'internal error: empty label scope has no outer';
1774 }
1775 }
1776
1777 class StatementScope {
1778 LabelScope labels;
1779 Link<JumpTarget> breakTargetStack;
1780 Link<JumpTarget> continueTargetStack;
1781 // Used to provide different numbers to statements if one is inside the other.
1782 // Can be used to make otherwise duplicate labels unique.
1783 int nestingLevel = 0;
1784
1785 StatementScope()
1786 : labels = const EmptyLabelScope(),
1787 breakTargetStack = const Link<JumpTarget>(),
1788 continueTargetStack = const Link<JumpTarget>();
1789
1790 LabelDefinition lookupLabel(String label) {
1791 return labels.lookup(label);
1792 }
1793
1794 JumpTarget currentBreakTarget() =>
1795 breakTargetStack.isEmpty ? null : breakTargetStack.head;
1796
1797 JumpTarget currentContinueTarget() =>
1798 continueTargetStack.isEmpty ? null : continueTargetStack.head;
1799
1800 void enterLabelScope(Map<String, LabelDefinition> elements) {
1801 labels = new LabeledStatementLabelScope(labels, elements);
1802 nestingLevel++;
1803 }
1804
1805 void exitLabelScope() {
1806 nestingLevel--;
1807 labels = labels.outer;
1808 }
1809
1810 void enterLoop(JumpTarget element) {
1811 breakTargetStack = breakTargetStack.prepend(element);
1812 continueTargetStack = continueTargetStack.prepend(element);
1813 nestingLevel++;
1814 }
1815
1816 void exitLoop() {
1817 nestingLevel--;
1818 breakTargetStack = breakTargetStack.tail;
1819 continueTargetStack = continueTargetStack.tail;
1820 }
1821
1822 void enterSwitch(JumpTarget breakElement,
1823 Map<String, LabelDefinition> continueElements) {
1824 breakTargetStack = breakTargetStack.prepend(breakElement);
1825 labels = new SwitchLabelScope(labels, continueElements);
1826 nestingLevel++;
1827 }
1828
1829 void exitSwitch() {
1830 nestingLevel--;
1831 breakTargetStack = breakTargetStack.tail;
1832 labels = labels.outer;
1833 }
1834 }
1835
1836 class TypeResolver {
1837 final Compiler compiler;
1838
1839 TypeResolver(this.compiler);
1840
1841 /// Tries to resolve the type name as an element.
1842 Element resolveTypeName(Identifier prefixName,
1843 Identifier typeName,
1844 Scope scope,
1845 {bool deferredIsMalformed: true}) {
1846 Element element;
1847 bool deferredTypeAnnotation = false;
1848 if (prefixName != null) {
1849 Element prefixElement =
1850 lookupInScope(compiler, prefixName, scope, prefixName.source);
1851 if (prefixElement != null && prefixElement.isPrefix) {
1852 // The receiver is a prefix. Lookup in the imported members.
1853 PrefixElement prefix = prefixElement;
1854 element = prefix.lookupLocalMember(typeName.source);
1855 // TODO(17260, sigurdm): The test for DartBackend is there because
1856 // dart2dart outputs malformed types with prefix.
1857 if (element != null &&
1858 prefix.isDeferred &&
1859 deferredIsMalformed &&
1860 compiler.backend is! DartBackend) {
1861 element = new ErroneousElementX(MessageKind.DEFERRED_TYPE_ANNOTATION,
1862 {'node': typeName},
1863 element.name,
1864 element);
1865 }
1866 } else {
1867 // The caller of this method will create the ErroneousElement for
1868 // the MalformedType.
1869 element = null;
1870 }
1871 } else {
1872 String stringValue = typeName.source;
1873 element = lookupInScope(compiler, typeName, scope, typeName.source);
1874 }
1875 return element;
1876 }
1877
1878 DartType resolveTypeAnnotation(MappingVisitor visitor, TypeAnnotation node,
1879 {bool malformedIsError: false,
1880 bool deferredIsMalformed: true}) {
1881 ResolutionRegistry registry = visitor.registry;
1882
1883 Identifier typeName;
1884 DartType type;
1885
1886 DartType checkNoTypeArguments(DartType type) {
1887 List<DartType> arguments = new List<DartType>();
1888 bool hasTypeArgumentMismatch = resolveTypeArguments(
1889 visitor, node, const <DartType>[], arguments);
1890 if (hasTypeArgumentMismatch) {
1891 return new MalformedType(
1892 new ErroneousElementX(MessageKind.TYPE_ARGUMENT_COUNT_MISMATCH,
1893 {'type': node}, typeName.source, visitor.enclosingElement),
1894 type, arguments);
1895 }
1896 return type;
1897 }
1898
1899 Identifier prefixName;
1900 Send send = node.typeName.asSend();
1901 if (send != null) {
1902 // The type name is of the form [: prefix . identifier :].
1903 prefixName = send.receiver.asIdentifier();
1904 typeName = send.selector.asIdentifier();
1905 } else {
1906 typeName = node.typeName.asIdentifier();
1907 if (identical(typeName.source, 'void')) {
1908 type = const VoidType();
1909 checkNoTypeArguments(type);
1910 registry.useType(node, type);
1911 return type;
1912 } else if (identical(typeName.source, 'dynamic')) {
1913 type = const DynamicType();
1914 checkNoTypeArguments(type);
1915 registry.useType(node, type);
1916 return type;
1917 }
1918 }
1919
1920 Element element = resolveTypeName(prefixName, typeName, visitor.scope,
1921 deferredIsMalformed: deferredIsMalformed);
1922
1923 DartType reportFailureAndCreateType(MessageKind messageKind,
1924 Map messageArguments,
1925 {DartType userProvidedBadType,
1926 Element erroneousElement}) {
1927 if (malformedIsError) {
1928 visitor.error(node, messageKind, messageArguments);
1929 } else {
1930 registry.registerThrowRuntimeError();
1931 visitor.warning(node, messageKind, messageArguments);
1932 }
1933 if (erroneousElement == null) {
1934 erroneousElement = new ErroneousElementX(
1935 messageKind, messageArguments, typeName.source,
1936 visitor.enclosingElement);
1937 }
1938 List<DartType> arguments = <DartType>[];
1939 resolveTypeArguments(visitor, node, const <DartType>[], arguments);
1940 return new MalformedType(erroneousElement,
1941 userProvidedBadType, arguments);
1942 }
1943
1944 // Try to construct the type from the element.
1945 if (element == null) {
1946 type = reportFailureAndCreateType(
1947 MessageKind.CANNOT_RESOLVE_TYPE, {'typeName': node.typeName});
1948 } else if (element.isAmbiguous) {
1949 AmbiguousElement ambiguous = element;
1950 type = reportFailureAndCreateType(
1951 ambiguous.messageKind, ambiguous.messageArguments);
1952 ambiguous.diagnose(registry.mapping.analyzedElement, compiler);
1953 } else if (element.isErroneous) {
1954 ErroneousElement erroneousElement = element;
1955 type = reportFailureAndCreateType(
1956 erroneousElement.messageKind, erroneousElement.messageArguments,
1957 erroneousElement: erroneousElement);
1958 } else if (!element.impliesType) {
1959 type = reportFailureAndCreateType(
1960 MessageKind.NOT_A_TYPE, {'node': node.typeName});
1961 } else {
1962 bool addTypeVariableBoundsCheck = false;
1963 if (element.isClass) {
1964 ClassElement cls = element;
1965 // TODO(johnniwinther): [_ensureClassWillBeResolved] should imply
1966 // [computeType].
1967 compiler.resolver._ensureClassWillBeResolved(cls);
1968 element.computeType(compiler);
1969 List<DartType> arguments = <DartType>[];
1970 bool hasTypeArgumentMismatch = resolveTypeArguments(
1971 visitor, node, cls.typeVariables, arguments);
1972 if (hasTypeArgumentMismatch) {
1973 type = new BadInterfaceType(cls.declaration,
1974 new InterfaceType.forUserProvidedBadType(cls.declaration,
1975 arguments));
1976 } else {
1977 if (arguments.isEmpty) {
1978 type = cls.rawType;
1979 } else {
1980 type = new InterfaceType(cls.declaration, arguments.toList(growable: false));
1981 addTypeVariableBoundsCheck = true;
1982 }
1983 }
1984 } else if (element.isTypedef) {
1985 TypedefElement typdef = element;
1986 // TODO(johnniwinther): [ensureResolved] should imply [computeType].
1987 typdef.ensureResolved(compiler);
1988 element.computeType(compiler);
1989 List<DartType> arguments = <DartType>[];
1990 bool hasTypeArgumentMismatch = resolveTypeArguments(
1991 visitor, node, typdef.typeVariables, arguments);
1992 if (hasTypeArgumentMismatch) {
1993 type = new BadTypedefType(typdef,
1994 new TypedefType.forUserProvidedBadType(typdef, arguments));
1995 } else {
1996 if (arguments.isEmpty) {
1997 type = typdef.rawType;
1998 } else {
1999 type = new TypedefType(typdef, arguments.toList(growable: false));
2000 addTypeVariableBoundsCheck = true;
2001 }
2002 }
2003 } else if (element.isTypeVariable) {
2004 Element outer =
2005 visitor.enclosingElement.outermostEnclosingMemberOrTopLevel;
2006 bool isInFactoryConstructor =
2007 outer != null && outer.isFactoryConstructor;
2008 if (!outer.isClass &&
2009 !outer.isTypedef &&
2010 !isInFactoryConstructor &&
2011 Elements.isInStaticContext(visitor.enclosingElement)) {
2012 registry.registerThrowRuntimeError();
2013 type = reportFailureAndCreateType(
2014 MessageKind.TYPE_VARIABLE_WITHIN_STATIC_MEMBER,
2015 {'typeVariableName': node},
2016 userProvidedBadType: element.computeType(compiler));
2017 } else {
2018 type = element.computeType(compiler);
2019 }
2020 type = checkNoTypeArguments(type);
2021 } else {
2022 compiler.internalError(node,
2023 "Unexpected element kind ${element.kind}.");
2024 }
2025 if (addTypeVariableBoundsCheck) {
2026 registry.registerTypeVariableBoundCheck();
2027 visitor.addDeferredAction(
2028 visitor.enclosingElement,
2029 () => checkTypeVariableBounds(node, type));
2030 }
2031 }
2032 registry.useType(node, type);
2033 return type;
2034 }
2035
2036 /// Checks the type arguments of [type] against the type variable bounds.
2037 void checkTypeVariableBounds(TypeAnnotation node, GenericType type) {
2038 void checkTypeVariableBound(_, DartType typeArgument,
2039 TypeVariableType typeVariable,
2040 DartType bound) {
2041 if (!compiler.types.isSubtype(typeArgument, bound)) {
2042 compiler.reportWarning(node,
2043 MessageKind.INVALID_TYPE_VARIABLE_BOUND,
2044 {'typeVariable': typeVariable,
2045 'bound': bound,
2046 'typeArgument': typeArgument,
2047 'thisType': type.element.thisType});
2048 }
2049 };
2050
2051 compiler.types.checkTypeVariableBounds(type, checkTypeVariableBound);
2052 }
2053
2054 /**
2055 * Resolves the type arguments of [node] and adds these to [arguments].
2056 *
2057 * Returns [: true :] if the number of type arguments did not match the
2058 * number of type variables.
2059 */
2060 bool resolveTypeArguments(MappingVisitor visitor,
2061 TypeAnnotation node,
2062 List<DartType> typeVariables,
2063 List<DartType> arguments) {
2064 if (node.typeArguments == null) {
2065 return false;
2066 }
2067 int expectedVariables = typeVariables.length;
2068 int index = 0;
2069 bool typeArgumentCountMismatch = false;
2070 for (Link<Node> typeArguments = node.typeArguments.nodes;
2071 !typeArguments.isEmpty;
2072 typeArguments = typeArguments.tail, index++) {
2073 if (index > expectedVariables - 1) {
2074 visitor.warning(
2075 typeArguments.head, MessageKind.ADDITIONAL_TYPE_ARGUMENT);
2076 typeArgumentCountMismatch = true;
2077 }
2078 DartType argType = resolveTypeAnnotation(visitor, typeArguments.head);
2079 // TODO(karlklose): rewrite to not modify [arguments].
2080 arguments.add(argType);
2081 }
2082 if (index < expectedVariables) {
2083 visitor.warning(node.typeArguments,
2084 MessageKind.MISSING_TYPE_ARGUMENT);
2085 typeArgumentCountMismatch = true;
2086 }
2087 return typeArgumentCountMismatch;
2088 }
2089 }
2090
2091 /**
2092 * Common supertype for resolver visitors that record resolutions in a
2093 * [ResolutionRegistry].
2094 */
2095 abstract class MappingVisitor<T> extends CommonResolverVisitor<T> {
2096 final ResolutionRegistry registry;
2097 final TypeResolver typeResolver;
2098 /// The current enclosing element for the visited AST nodes.
2099 Element get enclosingElement;
2100 /// The current scope of the visitor.
2101 Scope get scope;
2102
2103 MappingVisitor(Compiler compiler, ResolutionRegistry this.registry)
2104 : typeResolver = new TypeResolver(compiler),
2105 super(compiler);
2106
2107 /// Add [element] to the current scope and check for duplicate definitions.
2108 void addToScope(Element element) {
2109 Element existing = scope.add(element);
2110 if (existing != element) {
2111 reportDuplicateDefinition(element.name, element, existing);
2112 }
2113 }
2114
2115 /// Register [node] as the definition of [element].
2116 void defineLocalVariable(Node node, LocalVariableElement element) {
2117 invariant(node, element != null);
2118 registry.defineElement(node, element);
2119 }
2120
2121 void reportDuplicateDefinition(String name,
2122 Spannable definition,
2123 Spannable existing) {
2124 compiler.reportError(definition,
2125 MessageKind.DUPLICATE_DEFINITION, {'name': name});
2126 compiler.reportInfo(existing,
2127 MessageKind.EXISTING_DEFINITION, {'name': name});
2128 }
2129 }
2130
2131 /**
2132 * Core implementation of resolution.
2133 *
2134 * Do not subclass or instantiate this class outside this library
2135 * except for testing.
2136 */
2137 class ResolverVisitor extends MappingVisitor<ResolutionResult> {
2138 /**
2139 * The current enclosing element for the visited AST nodes.
2140 *
2141 * This field is updated when nested closures are visited.
2142 */
2143 Element enclosingElement;
2144 bool inInstanceContext;
2145 bool inCheckContext;
2146 bool inCatchBlock;
2147
2148 Scope scope;
2149 ClassElement currentClass;
2150 ExpressionStatement currentExpressionStatement;
2151 bool sendIsMemberAccess = false;
2152 StatementScope statementScope;
2153 int allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION
2154 | ElementCategory.IMPLIES_TYPE;
2155
2156 /**
2157 * Record of argument nodes to JS_INTERCEPTOR_CONSTANT for deferred
2158 * processing.
2159 */
2160 Set<Node> argumentsToJsInterceptorConstant = null;
2161
2162 /// When visiting the type declaration of the variable in a [ForIn] loop,
2163 /// the initializer of the variable is implicit and we should not emit an
2164 /// error when verifying that all final variables are initialized.
2165 bool allowFinalWithoutInitializer = false;
2166
2167 /// The nodes for which variable access and mutation must be registered in
2168 /// order to determine when the static type of variables types is promoted.
2169 Link<Node> promotionScope = const Link<Node>();
2170
2171 bool isPotentiallyMutableTarget(Element target) {
2172 if (target == null) return false;
2173 return (target.isVariable || target.isParameter) &&
2174 !(target.isFinal || target.isConst);
2175 }
2176
2177 // TODO(ahe): Find a way to share this with runtime implementation.
2178 static final RegExp symbolValidationPattern =
2179 new RegExp(r'^(?:[a-zA-Z$][a-zA-Z$0-9_]*\.)*(?:[a-zA-Z$][a-zA-Z$0-9_]*=?|'
2180 r'-|'
2181 r'unary-|'
2182 r'\[\]=|'
2183 r'~|'
2184 r'==|'
2185 r'\[\]|'
2186 r'\*|'
2187 r'/|'
2188 r'%|'
2189 r'~/|'
2190 r'\+|'
2191 r'<<|'
2192 r'>>|'
2193 r'>=|'
2194 r'>|'
2195 r'<=|'
2196 r'<|'
2197 r'&|'
2198 r'\^|'
2199 r'\|'
2200 r')$');
2201
2202 ResolverVisitor(Compiler compiler,
2203 Element element,
2204 ResolutionRegistry registry,
2205 {bool useEnclosingScope: false})
2206 : this.enclosingElement = element,
2207 // When the element is a field, we are actually resolving its
2208 // initial value, which should not have access to instance
2209 // fields.
2210 inInstanceContext = (element.isInstanceMember && !element.isField)
2211 || element.isGenerativeConstructor,
2212 this.currentClass = element.isClassMember ? element.enclosingClass
2213 : null,
2214 this.statementScope = new StatementScope(),
2215 scope = useEnclosingScope
2216 ? Scope.buildEnclosingScope(element) : element.buildScope(),
2217 // The type annotations on a typedef do not imply type checks.
2218 // TODO(karlklose): clean this up (dartbug.com/8870).
2219 inCheckContext = compiler.enableTypeAssertions &&
2220 !element.isLibrary &&
2221 !element.isTypedef &&
2222 !element.enclosingElement.isTypedef,
2223 inCatchBlock = false,
2224 super(compiler, registry);
2225
2226 Element reportLookupErrorIfAny(Element result, Node node, String name) {
2227 if (!Elements.isUnresolved(result)) {
2228 if (!inInstanceContext && result.isInstanceMember) {
2229 compiler.reportError(
2230 node, MessageKind.NO_INSTANCE_AVAILABLE, {'name': name});
2231 return new ErroneousElementX(MessageKind.NO_INSTANCE_AVAILABLE,
2232 {'name': name},
2233 name, enclosingElement);
2234 } else if (result.isAmbiguous) {
2235 AmbiguousElement ambiguous = result;
2236 compiler.reportError(
2237 node, ambiguous.messageKind, ambiguous.messageArguments);
2238 ambiguous.diagnose(enclosingElement, compiler);
2239 return new ErroneousElementX(ambiguous.messageKind,
2240 ambiguous.messageArguments,
2241 name, enclosingElement);
2242 }
2243 }
2244 return result;
2245 }
2246
2247 // Create, or reuse an already created, target element for a statement.
2248 JumpTarget getOrDefineTarget(Node statement) {
2249 JumpTarget element = registry.getTargetDefinition(statement);
2250 if (element == null) {
2251 element = new JumpTargetX(statement,
2252 statementScope.nestingLevel,
2253 enclosingElement);
2254 registry.defineTarget(statement, element);
2255 }
2256 return element;
2257 }
2258
2259 doInCheckContext(action()) {
2260 bool wasInCheckContext = inCheckContext;
2261 inCheckContext = true;
2262 var result = action();
2263 inCheckContext = wasInCheckContext;
2264 return result;
2265 }
2266
2267 inStaticContext(action()) {
2268 bool wasInstanceContext = inInstanceContext;
2269 inInstanceContext = false;
2270 var result = action();
2271 inInstanceContext = wasInstanceContext;
2272 return result;
2273 }
2274
2275 doInPromotionScope(Node node, action()) {
2276 promotionScope = promotionScope.prepend(node);
2277 var result = action();
2278 promotionScope = promotionScope.tail;
2279 return result;
2280 }
2281
2282 visitInStaticContext(Node node) {
2283 inStaticContext(() => visit(node));
2284 }
2285
2286 ErroneousElement warnAndCreateErroneousElement(Node node,
2287 String name,
2288 MessageKind kind,
2289 [Map arguments = const {}]) {
2290 compiler.reportWarning(node, kind, arguments);
2291 return new ErroneousElementX(kind, arguments, name, enclosingElement);
2292 }
2293
2294 ResolutionResult visitIdentifier(Identifier node) {
2295 if (node.isThis()) {
2296 if (!inInstanceContext) {
2297 error(node, MessageKind.NO_INSTANCE_AVAILABLE, {'name': node});
2298 }
2299 return null;
2300 } else if (node.isSuper()) {
2301 if (!inInstanceContext) error(node, MessageKind.NO_SUPER_IN_STATIC);
2302 if ((ElementCategory.SUPER & allowedCategory) == 0) {
2303 error(node, MessageKind.INVALID_USE_OF_SUPER);
2304 }
2305 return null;
2306 } else {
2307 String name = node.source;
2308 Element element = lookupInScope(compiler, node, scope, name);
2309 if (Elements.isUnresolved(element) && name == 'dynamic') {
2310 // TODO(johnniwinther): Remove this hack when we can return more complex
2311 // objects than [Element] from this method.
2312 element = compiler.typeClass;
2313 // Set the type to be `dynamic` to mark that this is a type literal.
2314 registry.setType(node, const DynamicType());
2315 }
2316 element = reportLookupErrorIfAny(element, node, node.source);
2317 if (element == null) {
2318 if (!inInstanceContext) {
2319 element = warnAndCreateErroneousElement(
2320 node, node.source, MessageKind.CANNOT_RESOLVE,
2321 {'name': node});
2322 registry.registerThrowNoSuchMethod();
2323 }
2324 } else if (element.isErroneous) {
2325 // Use the erroneous element.
2326 } else {
2327 if ((element.kind.category & allowedCategory) == 0) {
2328 // TODO(ahe): Improve error message. Need UX input.
2329 error(node, MessageKind.GENERIC,
2330 {'text': "is not an expression $element"});
2331 }
2332 }
2333 if (!Elements.isUnresolved(element) && element.isClass) {
2334 ClassElement classElement = element;
2335 classElement.ensureResolved(compiler);
2336 }
2337 return new ElementResult(registry.useElement(node, element));
2338 }
2339 }
2340
2341 ResolutionResult visitTypeAnnotation(TypeAnnotation node) {
2342 DartType type = resolveTypeAnnotation(node);
2343 if (inCheckContext) {
2344 registry.registerIsCheck(type);
2345 }
2346 return new TypeResult(type);
2347 }
2348
2349 bool isNamedConstructor(Send node) => node.receiver != null;
2350
2351 Selector getRedirectingThisOrSuperConstructorSelector(Send node) {
2352 if (isNamedConstructor(node)) {
2353 String constructorName = node.selector.asIdentifier().source;
2354 return new Selector.callConstructor(
2355 constructorName,
2356 enclosingElement.library);
2357 } else {
2358 return new Selector.callDefaultConstructor(
2359 enclosingElement.library);
2360 }
2361 }
2362
2363 FunctionElement resolveConstructorRedirection(FunctionElementX constructor) {
2364 FunctionExpression node = constructor.parseNode(compiler);
2365
2366 // A synthetic constructor does not have a node.
2367 if (node == null) return null;
2368 if (node.initializers == null) return null;
2369 Link<Node> initializers = node.initializers.nodes;
2370 if (!initializers.isEmpty &&
2371 Initializers.isConstructorRedirect(initializers.head)) {
2372 Selector selector =
2373 getRedirectingThisOrSuperConstructorSelector(initializers.head);
2374 final ClassElement classElement = constructor.enclosingClass;
2375 return classElement.lookupConstructor(selector);
2376 }
2377 return null;
2378 }
2379
2380 void setupFunction(FunctionExpression node, FunctionElement function) {
2381 Element enclosingElement = function.enclosingElement;
2382 if (node.modifiers.isStatic &&
2383 enclosingElement.kind != ElementKind.CLASS) {
2384 compiler.reportError(node, MessageKind.ILLEGAL_STATIC);
2385 }
2386
2387 scope = new MethodScope(scope, function);
2388 // Put the parameters in scope.
2389 FunctionSignature functionParameters = function.functionSignature;
2390 Link<Node> parameterNodes = (node.parameters == null)
2391 ? const Link<Node>() : node.parameters.nodes;
2392 functionParameters.forEachParameter((ParameterElement element) {
2393 // TODO(karlklose): should be a list of [FormalElement]s, but the actual
2394 // implementation uses [Element].
2395 Link<Element> optionals = functionParameters.optionalParameters;
2396 if (!optionals.isEmpty && element == optionals.head) {
2397 NodeList nodes = parameterNodes.head;
2398 parameterNodes = nodes.nodes;
2399 }
2400 visit(element.initializer);
2401 VariableDefinitions variableDefinitions = parameterNodes.head;
2402 Node parameterNode = variableDefinitions.definitions.nodes.head;
2403 // Field parameters (this.x) are not visible inside the constructor. The
2404 // fields they reference are visible, but must be resolved independently.
2405 if (element.isInitializingFormal) {
2406 registry.useElement(parameterNode, element);
2407 } else {
2408 LocalParameterElement parameterElement = element;
2409 defineLocalVariable(parameterNode, parameterElement);
2410 addToScope(parameterElement);
2411 }
2412 parameterNodes = parameterNodes.tail;
2413 });
2414 addDeferredAction(enclosingElement, () {
2415 functionParameters.forEachOptionalParameter((Element parameter) {
2416 compiler.resolver.constantCompiler.compileConstant(parameter);
2417 });
2418 });
2419 if (inCheckContext) {
2420 functionParameters.forEachParameter((ParameterElement element) {
2421 registry.registerIsCheck(element.type);
2422 });
2423 }
2424 }
2425
2426 visitCascade(Cascade node) {
2427 visit(node.expression);
2428 }
2429
2430 visitCascadeReceiver(CascadeReceiver node) {
2431 visit(node.expression);
2432 }
2433
2434 visitClassNode(ClassNode node) {
2435 internalError(node, "shouldn't be called");
2436 }
2437
2438 visitIn(Node node, Scope nestedScope) {
2439 Scope oldScope = scope;
2440 scope = nestedScope;
2441 ResolutionResult result = visit(node);
2442 scope = oldScope;
2443 return result;
2444 }
2445
2446 /**
2447 * Introduces new default targets for break and continue
2448 * before visiting the body of the loop
2449 */
2450 visitLoopBodyIn(Loop loop, Node body, Scope bodyScope) {
2451 JumpTarget element = getOrDefineTarget(loop);
2452 statementScope.enterLoop(element);
2453 visitIn(body, bodyScope);
2454 statementScope.exitLoop();
2455 if (!element.isTarget) {
2456 registry.undefineTarget(loop);
2457 }
2458 }
2459
2460 visitBlock(Block node) {
2461 visitIn(node.statements, new BlockScope(scope));
2462 }
2463
2464 visitDoWhile(DoWhile node) {
2465 visitLoopBodyIn(node, node.body, new BlockScope(scope));
2466 visit(node.condition);
2467 }
2468
2469 visitEmptyStatement(EmptyStatement node) { }
2470
2471 visitExpressionStatement(ExpressionStatement node) {
2472 ExpressionStatement oldExpressionStatement = currentExpressionStatement;
2473 currentExpressionStatement = node;
2474 visit(node.expression);
2475 currentExpressionStatement = oldExpressionStatement;
2476 }
2477
2478 visitFor(For node) {
2479 Scope blockScope = new BlockScope(scope);
2480 visitIn(node.initializer, blockScope);
2481 visitIn(node.condition, blockScope);
2482 visitIn(node.update, blockScope);
2483 visitLoopBodyIn(node, node.body, blockScope);
2484 }
2485
2486 visitFunctionDeclaration(FunctionDeclaration node) {
2487 assert(node.function.name != null);
2488 visitFunctionExpression(node.function, inFunctionDeclaration: true);
2489 }
2490
2491
2492 /// Process a local function declaration or an anonymous function expression.
2493 ///
2494 /// [inFunctionDeclaration] is `true` when the current node is the immediate
2495 /// child of a function declaration.
2496 ///
2497 /// This is used to distinguish local function declarations from anonymous
2498 /// function expressions.
2499 visitFunctionExpression(FunctionExpression node,
2500 {bool inFunctionDeclaration: false}) {
2501 bool doAddToScope = inFunctionDeclaration;
2502 if (!inFunctionDeclaration && node.name != null) {
2503 compiler.reportError(
2504 node.name,
2505 MessageKind.NAMED_FUNCTION_EXPRESSION,
2506 {'name': node.name});
2507 }
2508 visit(node.returnType);
2509 String name;
2510 if (node.name == null) {
2511 name = "";
2512 } else {
2513 name = node.name.asIdentifier().source;
2514 }
2515 LocalFunctionElementX function = new LocalFunctionElementX(
2516 name, node, ElementKind.FUNCTION, Modifiers.EMPTY,
2517 enclosingElement);
2518 function.functionSignatureCache =
2519 SignatureResolver.analyze(compiler, node.parameters, node.returnType,
2520 function, registry, createRealParameters: true);
2521 registry.defineFunction(node, function);
2522 if (doAddToScope) {
2523 addToScope(function);
2524 }
2525 Scope oldScope = scope; // The scope is modified by [setupFunction].
2526 setupFunction(node, function);
2527
2528 Element previousEnclosingElement = enclosingElement;
2529 enclosingElement = function;
2530 // Run the body in a fresh statement scope.
2531 StatementScope oldStatementScope = statementScope;
2532 statementScope = new StatementScope();
2533 visit(node.body);
2534 statementScope = oldStatementScope;
2535
2536 scope = oldScope;
2537 enclosingElement = previousEnclosingElement;
2538
2539 registry.registerClosure(function);
2540 registry.registerInstantiatedClass(compiler.functionClass);
2541 }
2542
2543 visitIf(If node) {
2544 doInPromotionScope(node.condition.expression, () => visit(node.condition));
2545 doInPromotionScope(node.thenPart,
2546 () => visitIn(node.thenPart, new BlockScope(scope)));
2547 visitIn(node.elsePart, new BlockScope(scope));
2548 }
2549
2550 ResolutionResult resolveSend(Send node) {
2551 Selector selector = resolveSelector(node, null);
2552 if (node.isSuperCall) registry.registerSuperUse(node);
2553
2554 if (node.receiver == null) {
2555 // If this send is of the form "assert(expr);", then
2556 // this is an assertion.
2557 if (selector.isAssert) {
2558 if (selector.argumentCount != 1) {
2559 error(node.selector,
2560 MessageKind.WRONG_NUMBER_OF_ARGUMENTS_FOR_ASSERT,
2561 {'argumentCount': selector.argumentCount});
2562 } else if (selector.namedArgumentCount != 0) {
2563 error(node.selector,
2564 MessageKind.ASSERT_IS_GIVEN_NAMED_ARGUMENTS,
2565 {'argumentCount': selector.namedArgumentCount});
2566 }
2567 registry.registerAssert(node);
2568 return const AssertResult();
2569 }
2570
2571 return node.selector.accept(this);
2572 }
2573
2574 var oldCategory = allowedCategory;
2575 allowedCategory |= ElementCategory.PREFIX | ElementCategory.SUPER;
2576 ResolutionResult resolvedReceiver = visit(node.receiver);
2577 allowedCategory = oldCategory;
2578
2579 Element target;
2580 String name = node.selector.asIdentifier().source;
2581 if (identical(name, 'this')) {
2582 // TODO(ahe): Why is this using GENERIC?
2583 error(node.selector, MessageKind.GENERIC,
2584 {'text': "expected an identifier"});
2585 } else if (node.isSuperCall) {
2586 if (node.isOperator) {
2587 if (isUserDefinableOperator(name)) {
2588 name = selector.name;
2589 } else {
2590 error(node.selector, MessageKind.ILLEGAL_SUPER_SEND, {'name': name});
2591 }
2592 }
2593 if (!inInstanceContext) {
2594 error(node.receiver, MessageKind.NO_INSTANCE_AVAILABLE, {'name': name});
2595 return null;
2596 }
2597 if (currentClass.supertype == null) {
2598 // This is just to guard against internal errors, so no need
2599 // for a real error message.
2600 error(node.receiver, MessageKind.GENERIC,
2601 {'text': "Object has no superclass"});
2602 }
2603 // TODO(johnniwinther): Ensure correct behavior if currentClass is a
2604 // patch.
2605 target = currentClass.lookupSuperSelector(selector);
2606 // [target] may be null which means invoking noSuchMethod on
2607 // super.
2608 if (target == null) {
2609 target = warnAndCreateErroneousElement(
2610 node, name, MessageKind.NO_SUCH_SUPER_MEMBER,
2611 {'className': currentClass, 'memberName': name});
2612 // We still need to register the invocation, because we might
2613 // call [:super.noSuchMethod:] which calls
2614 // [JSInvocationMirror._invokeOn].
2615 registry.registerDynamicInvocation(selector);
2616 registry.registerSuperNoSuchMethod();
2617 }
2618 } else if (resolvedReceiver == null ||
2619 Elements.isUnresolved(resolvedReceiver.element)) {
2620 return null;
2621 } else if (resolvedReceiver.element.isClass) {
2622 ClassElement receiverClass = resolvedReceiver.element;
2623 receiverClass.ensureResolved(compiler);
2624 if (node.isOperator) {
2625 // When the resolved receiver is a class, we can have two cases:
2626 // 1) a static send: C.foo, or
2627 // 2) an operator send, where the receiver is a class literal: 'C + 1'.
2628 // The following code that looks up the selector on the resolved
2629 // receiver will treat the second as the invocation of a static operator
2630 // if the resolved receiver is not null.
2631 return null;
2632 }
2633 MembersCreator.computeClassMembersByName(
2634 compiler, receiverClass.declaration, name);
2635 target = receiverClass.lookupLocalMember(name);
2636 if (target == null || target.isInstanceMember) {
2637 registry.registerThrowNoSuchMethod();
2638 // TODO(johnniwinther): With the simplified [TreeElements] invariant,
2639 // try to resolve injected elements if [currentClass] is in the patch
2640 // library of [receiverClass].
2641
2642 // TODO(karlklose): this should be reported by the caller of
2643 // [resolveSend] to select better warning messages for getters and
2644 // setters.
2645 MessageKind kind = (target == null)
2646 ? MessageKind.MEMBER_NOT_FOUND
2647 : MessageKind.MEMBER_NOT_STATIC;
2648 return new ElementResult(warnAndCreateErroneousElement(
2649 node, name, kind,
2650 {'className': receiverClass.name, 'memberName': name}));
2651 } else if (isPrivateName(name) &&
2652 target.library != enclosingElement.library) {
2653 registry.registerThrowNoSuchMethod();
2654 return new ElementResult(warnAndCreateErroneousElement(
2655 node, name, MessageKind.PRIVATE_ACCESS,
2656 {'libraryName': target.library.getLibraryOrScriptName(),
2657 'name': name}));
2658 }
2659 } else if (resolvedReceiver.element.isPrefix) {
2660 PrefixElement prefix = resolvedReceiver.element;
2661 target = prefix.lookupLocalMember(name);
2662 if (Elements.isUnresolved(target)) {
2663 registry.registerThrowNoSuchMethod();
2664 return new ElementResult(warnAndCreateErroneousElement(
2665 node, name, MessageKind.NO_SUCH_LIBRARY_MEMBER,
2666 {'libraryName': prefix.name, 'memberName': name}));
2667 } else if (target.isAmbiguous) {
2668 registry.registerThrowNoSuchMethod();
2669 AmbiguousElement ambiguous = target;
2670 target = warnAndCreateErroneousElement(node, name,
2671 ambiguous.messageKind,
2672 ambiguous.messageArguments);
2673 ambiguous.diagnose(enclosingElement, compiler);
2674 return new ElementResult(target);
2675 } else if (target.kind == ElementKind.CLASS) {
2676 ClassElement classElement = target;
2677 classElement.ensureResolved(compiler);
2678 }
2679 }
2680 return new ElementResult(target);
2681 }
2682
2683 static Selector computeSendSelector(Send node,
2684 LibraryElement library,
2685 Element element) {
2686 // First determine if this is part of an assignment.
2687 bool isSet = node.asSendSet() != null;
2688
2689 if (node.isIndex) {
2690 return isSet ? new Selector.indexSet() : new Selector.index();
2691 }
2692
2693 if (node.isOperator) {
2694 String source = node.selector.asOperator().source;
2695 String string = source;
2696 if (identical(string, '!') ||
2697 identical(string, '&&') || identical(string, '||') ||
2698 identical(string, 'is') || identical(string, 'as') ||
2699 identical(string, '?') ||
2700 identical(string, '>>>')) {
2701 return null;
2702 }
2703 String op = source;
2704 if (!isUserDefinableOperator(source)) {
2705 op = Elements.mapToUserOperatorOrNull(source);
2706 }
2707 if (op == null) {
2708 // Unsupported operator. An error has been reported during parsing.
2709 return new Selector.call(
2710 source, library, node.argumentsNode.slowLength(), []);
2711 }
2712 return node.arguments.isEmpty
2713 ? new Selector.unaryOperator(op)
2714 : new Selector.binaryOperator(op);
2715 }
2716
2717 Identifier identifier = node.selector.asIdentifier();
2718 if (node.isPropertyAccess) {
2719 assert(!isSet);
2720 return new Selector.getter(identifier.source, library);
2721 } else if (isSet) {
2722 return new Selector.setter(identifier.source, library);
2723 }
2724
2725 // Compute the arity and the list of named arguments.
2726 int arity = 0;
2727 List<String> named = <String>[];
2728 for (Link<Node> link = node.argumentsNode.nodes;
2729 !link.isEmpty;
2730 link = link.tail) {
2731 Expression argument = link.head;
2732 NamedArgument namedArgument = argument.asNamedArgument();
2733 if (namedArgument != null) {
2734 named.add(namedArgument.name.source);
2735 }
2736 arity++;
2737 }
2738
2739 if (element != null && element.isConstructor) {
2740 return new Selector.callConstructor(
2741 element.name, library, arity, named);
2742 }
2743
2744 // If we're invoking a closure, we do not have an identifier.
2745 return (identifier == null)
2746 ? new Selector.callClosure(arity, named)
2747 : new Selector.call(identifier.source, library, arity, named);
2748 }
2749
2750 Selector resolveSelector(Send node, Element element) {
2751 LibraryElement library = enclosingElement.library;
2752 Selector selector = computeSendSelector(node, library, element);
2753 if (selector != null) registry.setSelector(node, selector);
2754 return selector;
2755 }
2756
2757 void resolveArguments(NodeList list) {
2758 if (list == null) return;
2759 bool oldSendIsMemberAccess = sendIsMemberAccess;
2760 sendIsMemberAccess = false;
2761 Map<String, Node> seenNamedArguments = new Map<String, Node>();
2762 for (Link<Node> link = list.nodes; !link.isEmpty; link = link.tail) {
2763 Expression argument = link.head;
2764 visit(argument);
2765 NamedArgument namedArgument = argument.asNamedArgument();
2766 if (namedArgument != null) {
2767 String source = namedArgument.name.source;
2768 if (seenNamedArguments.containsKey(source)) {
2769 reportDuplicateDefinition(
2770 source,
2771 argument,
2772 seenNamedArguments[source]);
2773 } else {
2774 seenNamedArguments[source] = namedArgument;
2775 }
2776 } else if (!seenNamedArguments.isEmpty) {
2777 error(argument, MessageKind.INVALID_ARGUMENT_AFTER_NAMED);
2778 }
2779 }
2780 sendIsMemberAccess = oldSendIsMemberAccess;
2781 }
2782
2783 ResolutionResult visitSend(Send node) {
2784 bool oldSendIsMemberAccess = sendIsMemberAccess;
2785 sendIsMemberAccess = node.isPropertyAccess || node.isCall;
2786 ResolutionResult result;
2787 if (node.isLogicalAnd) {
2788 result = doInPromotionScope(node.receiver, () => resolveSend(node));
2789 } else {
2790 result = resolveSend(node);
2791 }
2792 sendIsMemberAccess = oldSendIsMemberAccess;
2793
2794 Element target = result != null ? result.element : null;
2795
2796 if (target != null
2797 && target == compiler.mirrorSystemGetNameFunction
2798 && !compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(enclosingElement)) {
2799 compiler.reportHint(
2800 node.selector, MessageKind.STATIC_FUNCTION_BLOAT,
2801 {'class': compiler.mirrorSystemClass.name,
2802 'name': compiler.mirrorSystemGetNameFunction.name});
2803 }
2804
2805 if (!Elements.isUnresolved(target)) {
2806 if (target.isAbstractField) {
2807 AbstractFieldElement field = target;
2808 target = field.getter;
2809 if (target == null && !inInstanceContext) {
2810 registry.registerThrowNoSuchMethod();
2811 target =
2812 warnAndCreateErroneousElement(node.selector, field.name,
2813 MessageKind.CANNOT_RESOLVE_GETTER);
2814 }
2815 } else if (target.isTypeVariable) {
2816 ClassElement cls = target.enclosingClass;
2817 assert(enclosingElement.enclosingClass == cls);
2818 registry.registerClassUsingVariableExpression(cls);
2819 registry.registerTypeVariableExpression();
2820 // Set the type of the node to [Type] to mark this send as a
2821 // type variable expression.
2822 registry.registerTypeLiteral(node, target.computeType(compiler));
2823 } else if (target.impliesType && (!sendIsMemberAccess || node.isCall)) {
2824 // Set the type of the node to [Type] to mark this send as a
2825 // type literal.
2826 DartType type;
2827
2828 // TODO(johnniwinther): Remove this hack when we can pass more complex
2829 // information between methods than resolved elements.
2830 if (target == compiler.typeClass && node.receiver == null) {
2831 // Potentially a 'dynamic' type literal.
2832 type = registry.getType(node.selector);
2833 }
2834 if (type == null) {
2835 type = target.computeType(compiler);
2836 }
2837 registry.registerTypeLiteral(node, type);
2838
2839 // Don't try to make constants of calls to type literals.
2840 if (!node.isCall) {
2841 analyzeConstant(node);
2842 } else {
2843 // The node itself is not a constant but we register the selector (the
2844 // identifier that refers to the class/typedef) as a constant.
2845 analyzeConstant(node.selector);
2846 }
2847 }
2848 if (isPotentiallyMutableTarget(target)) {
2849 if (enclosingElement != target.enclosingElement) {
2850 for (Node scope in promotionScope) {
2851 registry.setAccessedByClosureIn(scope, target, node);
2852 }
2853 }
2854 }
2855 }
2856
2857 bool resolvedArguments = false;
2858 if (node.isOperator) {
2859 String operatorString = node.selector.asOperator().source;
2860 if (identical(operatorString, 'is')) {
2861 // TODO(johnniwinther): Use seen type tests to avoid registration of
2862 // mutation/access to unpromoted variables.
2863 DartType type =
2864 resolveTypeAnnotation(node.typeAnnotationFromIsCheckOrCast);
2865 if (type != null) {
2866 registry.registerIsCheck(type);
2867 }
2868 resolvedArguments = true;
2869 } else if (identical(operatorString, 'as')) {
2870 DartType type = resolveTypeAnnotation(node.arguments.head);
2871 if (type != null) {
2872 registry.registerAsCheck(type);
2873 }
2874 resolvedArguments = true;
2875 } else if (identical(operatorString, '&&')) {
2876 doInPromotionScope(node.arguments.head,
2877 () => resolveArguments(node.argumentsNode));
2878 resolvedArguments = true;
2879 }
2880 }
2881
2882 if (!resolvedArguments) {
2883 resolveArguments(node.argumentsNode);
2884 }
2885
2886 // If the selector is null, it means that we will not be generating
2887 // code for this as a send.
2888 Selector selector = registry.getSelector(node);
2889 if (selector == null) return null;
2890
2891 if (node.isCall) {
2892 if (Elements.isUnresolved(target) ||
2893 target.isGetter ||
2894 target.isField ||
2895 Elements.isClosureSend(node, target)) {
2896 // If we don't know what we're calling or if we are calling a getter,
2897 // we need to register that fact that we may be calling a closure
2898 // with the same arguments.
2899 Selector call = new Selector.callClosureFrom(selector);
2900 registry.registerDynamicInvocation(call);
2901 } else if (target.impliesType) {
2902 // We call 'call()' on a Type instance returned from the reference to a
2903 // class or typedef literal. We do not need to register this call as a
2904 // dynamic invocation, because we statically know what the target is.
2905 } else {
2906 if (target is FunctionElement) {
2907 FunctionElement function = target;
2908 function.computeSignature(compiler);
2909 }
2910 if (!selector.applies(target, compiler.world)) {
2911 registry.registerThrowNoSuchMethod();
2912 if (node.isSuperCall) {
2913 // Similar to what we do when we can't find super via selector
2914 // in [resolveSend] above, we still need to register the invocation,
2915 // because we might call [:super.noSuchMethod:] which calls
2916 // [JSInvocationMirror._invokeOn].
2917 registry.registerDynamicInvocation(selector);
2918 registry.registerSuperNoSuchMethod();
2919 }
2920 }
2921 }
2922
2923 if (target != null && target.isForeign(compiler.backend)) {
2924 if (selector.name == 'JS') {
2925 registry.registerJsCall(node, this);
2926 } else if (selector.name == 'JS_EMBEDDED_GLOBAL') {
2927 registry.registerJsEmbeddedGlobalCall(node, this);
2928 } else if (selector.name == 'JS_INTERCEPTOR_CONSTANT') {
2929 if (!node.argumentsNode.isEmpty) {
2930 Node argument = node.argumentsNode.nodes.head;
2931 if (argumentsToJsInterceptorConstant == null) {
2932 argumentsToJsInterceptorConstant = new Set<Node>();
2933 }
2934 argumentsToJsInterceptorConstant.add(argument);
2935 }
2936 }
2937 }
2938 }
2939
2940 registry.useElement(node, target);
2941 registerSend(selector, target);
2942 if (node.isPropertyAccess && Elements.isStaticOrTopLevelFunction(target)) {
2943 registry.registerGetOfStaticFunction(target.declaration);
2944 }
2945 return node.isPropertyAccess ? new ElementResult(target) : null;
2946 }
2947
2948 /// Callback for native enqueuer to parse a type. Returns [:null:] on error.
2949 DartType resolveTypeFromString(Node node, String typeName) {
2950 Element element = lookupInScope(compiler, node,
2951 scope, typeName);
2952 if (element == null) return null;
2953 if (element is! ClassElement) return null;
2954 ClassElement cls = element;
2955 cls.ensureResolved(compiler);
2956 return cls.computeType(compiler);
2957 }
2958
2959 ResolutionResult visitSendSet(SendSet node) {
2960 bool oldSendIsMemberAccess = sendIsMemberAccess;
2961 sendIsMemberAccess = node.isPropertyAccess || node.isCall;
2962 ResolutionResult result = resolveSend(node);
2963 sendIsMemberAccess = oldSendIsMemberAccess;
2964 Element target = result != null ? result.element : null;
2965 Element setter = target;
2966 Element getter = target;
2967 String operatorName = node.assignmentOperator.source;
2968 String source = operatorName;
2969 bool isComplex = !identical(source, '=');
2970 if (!(result is AssertResult || Elements.isUnresolved(target))) {
2971 if (target.isAbstractField) {
2972 AbstractFieldElement field = target;
2973 setter = field.setter;
2974 getter = field.getter;
2975 if (setter == null && !inInstanceContext) {
2976 setter = warnAndCreateErroneousElement(
2977 node.selector, field.name, MessageKind.CANNOT_RESOLVE_SETTER);
2978 registry.registerThrowNoSuchMethod();
2979 }
2980 if (isComplex && getter == null && !inInstanceContext) {
2981 getter = warnAndCreateErroneousElement(
2982 node.selector, field.name, MessageKind.CANNOT_RESOLVE_GETTER);
2983 registry.registerThrowNoSuchMethod();
2984 }
2985 } else if (target.impliesType) {
2986 setter = warnAndCreateErroneousElement(
2987 node.selector, target.name, MessageKind.ASSIGNING_TYPE);
2988 registry.registerThrowNoSuchMethod();
2989 } else if (target.isFinal ||
2990 target.isConst ||
2991 (target.isFunction &&
2992 Elements.isStaticOrTopLevelFunction(target) &&
2993 !target.isSetter)) {
2994 if (target.isFunction) {
2995 setter = warnAndCreateErroneousElement(
2996 node.selector, target.name, MessageKind.ASSIGNING_METHOD);
2997 } else {
2998 setter = warnAndCreateErroneousElement(
2999 node.selector, target.name, MessageKind.CANNOT_RESOLVE_SETTER);
3000 }
3001 registry.registerThrowNoSuchMethod();
3002 }
3003 if (isPotentiallyMutableTarget(target)) {
3004 registry.registerPotentialMutation(target, node);
3005 if (enclosingElement != target.enclosingElement) {
3006 registry.registerPotentialMutationInClosure(target, node);
3007 }
3008 for (Node scope in promotionScope) {
3009 registry.registerPotentialMutationIn(scope, target, node);
3010 }
3011 }
3012 }
3013
3014 resolveArguments(node.argumentsNode);
3015
3016 Selector selector = registry.getSelector(node);
3017 if (isComplex) {
3018 Selector getterSelector;
3019 if (selector.isSetter) {
3020 getterSelector = new Selector.getterFrom(selector);
3021 } else {
3022 assert(selector.isIndexSet);
3023 getterSelector = new Selector.index();
3024 }
3025 registerSend(getterSelector, getter);
3026 registry.setGetterSelectorInComplexSendSet(node, getterSelector);
3027 if (node.isSuperCall) {
3028 getter = currentClass.lookupSuperSelector(getterSelector);
3029 if (getter == null) {
3030 target = warnAndCreateErroneousElement(
3031 node, selector.name, MessageKind.NO_SUCH_SUPER_MEMBER,
3032 {'className': currentClass, 'memberName': selector.name});
3033 registry.registerSuperNoSuchMethod();
3034 }
3035 }
3036 registry.useElement(node.selector, getter);
3037
3038 // Make sure we include the + and - operators if we are using
3039 // the ++ and -- ones. Also, if op= form is used, include op itself.
3040 void registerBinaryOperator(String name) {
3041 Selector binop = new Selector.binaryOperator(name);
3042 registry.registerDynamicInvocation(binop);
3043 registry.setOperatorSelectorInComplexSendSet(node, binop);
3044 }
3045 if (identical(source, '++')) {
3046 registerBinaryOperator('+');
3047 registry.registerInstantiatedClass(compiler.intClass);
3048 } else if (identical(source, '--')) {
3049 registerBinaryOperator('-');
3050 registry.registerInstantiatedClass(compiler.intClass);
3051 } else if (source.endsWith('=')) {
3052 registerBinaryOperator(Elements.mapToUserOperator(operatorName));
3053 }
3054 }
3055
3056 registerSend(selector, setter);
3057 return new ElementResult(registry.useElement(node, setter));
3058 }
3059
3060 void registerSend(Selector selector, Element target) {
3061 if (target == null || target.isInstanceMember) {
3062 if (selector.isGetter) {
3063 registry.registerDynamicGetter(selector);
3064 } else if (selector.isSetter) {
3065 registry.registerDynamicSetter(selector);
3066 } else {
3067 registry.registerDynamicInvocation(selector);
3068 }
3069 } else if (Elements.isStaticOrTopLevel(target)) {
3070 // Avoid registration of type variables since they are not analyzable but
3071 // instead resolved through their enclosing type declaration.
3072 if (!target.isTypeVariable) {
3073 // [target] might be the implementation element and only declaration
3074 // elements may be registered.
3075 registry.registerStaticUse(target.declaration);
3076 }
3077 }
3078 }
3079
3080 visitLiteralInt(LiteralInt node) {
3081 registry.registerInstantiatedClass(compiler.intClass);
3082 }
3083
3084 visitLiteralDouble(LiteralDouble node) {
3085 registry.registerInstantiatedClass(compiler.doubleClass);
3086 }
3087
3088 visitLiteralBool(LiteralBool node) {
3089 registry.registerInstantiatedClass(compiler.boolClass);
3090 }
3091
3092 visitLiteralString(LiteralString node) {
3093 registry.registerInstantiatedClass(compiler.stringClass);
3094 }
3095
3096 visitLiteralNull(LiteralNull node) {
3097 registry.registerInstantiatedClass(compiler.nullClass);
3098 }
3099
3100 visitLiteralSymbol(LiteralSymbol node) {
3101 registry.registerInstantiatedClass(compiler.symbolClass);
3102 registry.registerStaticUse(compiler.symbolConstructor.declaration);
3103 registry.registerConstSymbol(node.slowNameString);
3104 if (!validateSymbol(node, node.slowNameString, reportError: false)) {
3105 compiler.reportError(node,
3106 MessageKind.UNSUPPORTED_LITERAL_SYMBOL,
3107 {'value': node.slowNameString});
3108 }
3109 analyzeConstant(node);
3110 }
3111
3112 visitStringJuxtaposition(StringJuxtaposition node) {
3113 registry.registerInstantiatedClass(compiler.stringClass);
3114 node.visitChildren(this);
3115 }
3116
3117 visitNodeList(NodeList node) {
3118 for (Link<Node> link = node.nodes; !link.isEmpty; link = link.tail) {
3119 visit(link.head);
3120 }
3121 }
3122
3123 visitOperator(Operator node) {
3124 internalError(node, 'operator');
3125 }
3126
3127 visitRethrow(Rethrow node) {
3128 if (!inCatchBlock) {
3129 error(node, MessageKind.THROW_WITHOUT_EXPRESSION);
3130 }
3131 }
3132
3133 visitReturn(Return node) {
3134 Node expression = node.expression;
3135 if (expression != null &&
3136 enclosingElement.isGenerativeConstructor) {
3137 // It is a compile-time error if a return statement of the form
3138 // `return e;` appears in a generative constructor. (Dart Language
3139 // Specification 13.12.)
3140 compiler.reportError(expression,
3141 MessageKind.CANNOT_RETURN_FROM_CONSTRUCTOR);
3142 }
3143 visit(node.expression);
3144 }
3145
3146 visitRedirectingFactoryBody(RedirectingFactoryBody node) {
3147 final isSymbolConstructor = enclosingElement == compiler.symbolConstructor;
3148 if (!enclosingElement.isFactoryConstructor) {
3149 compiler.reportError(
3150 node, MessageKind.FACTORY_REDIRECTION_IN_NON_FACTORY);
3151 compiler.reportHint(
3152 enclosingElement, MessageKind.MISSING_FACTORY_KEYWORD);
3153 }
3154 ConstructorElementX constructor = enclosingElement;
3155 bool isConstConstructor = constructor.isConst;
3156 ConstructorElement redirectionTarget = resolveRedirectingFactory(
3157 node, inConstContext: isConstConstructor);
3158 constructor.immediateRedirectionTarget = redirectionTarget;
3159 registry.setRedirectingTargetConstructor(node, redirectionTarget);
3160 if (Elements.isUnresolved(redirectionTarget)) {
3161 registry.registerThrowNoSuchMethod();
3162 return;
3163 } else {
3164 if (isConstConstructor &&
3165 !redirectionTarget.isConst) {
3166 compiler.reportError(node, MessageKind.CONSTRUCTOR_IS_NOT_CONST);
3167 }
3168 if (redirectionTarget == constructor) {
3169 compiler.reportError(node, MessageKind.CYCLIC_REDIRECTING_FACTORY);
3170 return;
3171 }
3172 }
3173
3174 // Check that the target constructor is type compatible with the
3175 // redirecting constructor.
3176 ClassElement targetClass = redirectionTarget.enclosingClass;
3177 InterfaceType type = registry.getType(node);
3178 FunctionType targetType = redirectionTarget.computeType(compiler)
3179 .subst(type.typeArguments, targetClass.typeVariables);
3180 FunctionType constructorType = constructor.computeType(compiler);
3181 bool isSubtype = compiler.types.isSubtype(targetType, constructorType);
3182 if (!isSubtype) {
3183 warning(node, MessageKind.NOT_ASSIGNABLE,
3184 {'fromType': targetType, 'toType': constructorType});
3185 }
3186
3187 FunctionSignature targetSignature =
3188 redirectionTarget.computeSignature(compiler);
3189 FunctionSignature constructorSignature =
3190 constructor.computeSignature(compiler);
3191 if (!targetSignature.isCompatibleWith(constructorSignature)) {
3192 assert(!isSubtype);
3193 registry.registerThrowNoSuchMethod();
3194 }
3195
3196 // Register a post process to check for cycles in the redirection chain and
3197 // set the actual generative constructor at the end of the chain.
3198 addDeferredAction(constructor, () {
3199 compiler.resolver.resolveRedirectionChain(constructor, node);
3200 });
3201
3202 registry.registerStaticUse(redirectionTarget);
3203 // TODO(johnniwinther): Register the effective target type instead.
3204 registry.registerInstantiatedClass(
3205 redirectionTarget.enclosingClass.declaration);
3206 if (isSymbolConstructor) {
3207 registry.registerSymbolConstructor();
3208 }
3209 }
3210
3211 visitThrow(Throw node) {
3212 registry.registerThrowExpression();
3213 visit(node.expression);
3214 }
3215
3216 visitVariableDefinitions(VariableDefinitions node) {
3217 DartType type;
3218 if (node.type != null) {
3219 type = resolveTypeAnnotation(node.type);
3220 } else {
3221 type = const DynamicType();
3222 }
3223 VariableList variables = new VariableList.node(node, type);
3224 VariableDefinitionsVisitor visitor =
3225 new VariableDefinitionsVisitor(compiler, node, this, variables);
3226
3227 Modifiers modifiers = node.modifiers;
3228 void reportExtraModifier(String modifier) {
3229 Node modifierNode;
3230 for (Link<Node> nodes = modifiers.nodes.nodes;
3231 !nodes.isEmpty;
3232 nodes = nodes.tail) {
3233 if (modifier == nodes.head.asIdentifier().source) {
3234 modifierNode = nodes.head;
3235 break;
3236 }
3237 }
3238 assert(modifierNode != null);
3239 compiler.reportError(modifierNode, MessageKind.EXTRANEOUS_MODIFIER,
3240 {'modifier': modifier});
3241 }
3242 if (modifiers.isFinal && (modifiers.isConst || modifiers.isVar)) {
3243 reportExtraModifier('final');
3244 }
3245 if (modifiers.isVar && (modifiers.isConst || node.type != null)) {
3246 reportExtraModifier('var');
3247 }
3248 if (enclosingElement.isFunction) {
3249 if (modifiers.isAbstract) {
3250 reportExtraModifier('abstract');
3251 }
3252 if (modifiers.isStatic) {
3253 reportExtraModifier('static');
3254 }
3255 }
3256 if (node.metadata != null) {
3257 variables.metadata =
3258 compiler.resolver.resolveMetadata(enclosingElement, node);
3259 }
3260 visitor.visit(node.definitions);
3261 }
3262
3263 visitWhile(While node) {
3264 visit(node.condition);
3265 visitLoopBodyIn(node, node.body, new BlockScope(scope));
3266 }
3267
3268 visitParenthesizedExpression(ParenthesizedExpression node) {
3269 bool oldSendIsMemberAccess = sendIsMemberAccess;
3270 sendIsMemberAccess = false;
3271 visit(node.expression);
3272 sendIsMemberAccess = oldSendIsMemberAccess;
3273 }
3274
3275 ResolutionResult visitNewExpression(NewExpression node) {
3276 Node selector = node.send.selector;
3277 FunctionElement constructor = resolveConstructor(node);
3278 final bool isSymbolConstructor = constructor == compiler.symbolConstructor;
3279 final bool isMirrorsUsedConstant =
3280 node.isConst && (constructor == compiler.mirrorsUsedConstructor);
3281 Selector callSelector = resolveSelector(node.send, constructor);
3282 resolveArguments(node.send.argumentsNode);
3283 registry.useElement(node.send, constructor);
3284 if (Elements.isUnresolved(constructor)) {
3285 return new ElementResult(constructor);
3286 }
3287 constructor.computeSignature(compiler);
3288 if (!callSelector.applies(constructor, compiler.world)) {
3289 registry.registerThrowNoSuchMethod();
3290 }
3291
3292 // [constructor] might be the implementation element
3293 // and only declaration elements may be registered.
3294 registry.registerStaticUse(constructor.declaration);
3295 ClassElement cls = constructor.enclosingClass;
3296 InterfaceType type = registry.getType(node);
3297 if (node.isConst && type.containsTypeVariables) {
3298 compiler.reportError(node.send.selector,
3299 MessageKind.TYPE_VARIABLE_IN_CONSTANT);
3300 }
3301 // TODO(johniwinther): Avoid registration of `type` in face of redirecting
3302 // factory constructors.
3303 registry.registerInstantiatedType(type);
3304 if (constructor.isFactoryConstructor && !type.typeArguments.isEmpty) {
3305 registry.registerFactoryWithTypeArguments();
3306 }
3307 if (constructor.isGenerativeConstructor && cls.isAbstract) {
3308 warning(node, MessageKind.ABSTRACT_CLASS_INSTANTIATION);
3309 registry.registerAbstractClassInstantiation();
3310 }
3311
3312 if (isSymbolConstructor) {
3313 if (node.isConst) {
3314 Node argumentNode = node.send.arguments.head;
3315 ConstantExpression constant =
3316 compiler.resolver.constantCompiler.compileNode(
3317 argumentNode, registry.mapping);
3318 ConstantValue name = constant.value;
3319 if (!name.isString) {
3320 DartType type = name.computeType(compiler);
3321 compiler.reportError(argumentNode, MessageKind.STRING_EXPECTED,
3322 {'type': type});
3323 } else {
3324 StringConstantValue stringConstant = name;
3325 String nameString = stringConstant.toDartString().slowToString();
3326 if (validateSymbol(argumentNode, nameString)) {
3327 registry.registerConstSymbol(nameString);
3328 }
3329 }
3330 } else {
3331 if (!compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(
3332 enclosingElement)) {
3333 compiler.reportHint(
3334 node.newToken, MessageKind.NON_CONST_BLOAT,
3335 {'name': compiler.symbolClass.name});
3336 }
3337 registry.registerNewSymbol();
3338 }
3339 } else if (isMirrorsUsedConstant) {
3340 compiler.mirrorUsageAnalyzerTask.validate(node, registry.mapping);
3341 }
3342 if (node.isConst) {
3343 analyzeConstant(node);
3344 }
3345
3346 return null;
3347 }
3348
3349 void checkConstMapKeysDontOverrideEquals(Spannable spannable,
3350 MapConstantValue map) {
3351 for (ConstantValue key in map.keys) {
3352 if (!key.isObject) continue;
3353 ObjectConstantValue objectConstant = key;
3354 DartType keyType = objectConstant.type;
3355 ClassElement cls = keyType.element;
3356 if (cls == compiler.stringClass) continue;
3357 Element equals = cls.lookupMember('==');
3358 if (equals.enclosingClass != compiler.objectClass) {
3359 compiler.reportError(spannable,
3360 MessageKind.CONST_MAP_KEY_OVERRIDES_EQUALS,
3361 {'type': keyType});
3362 }
3363 }
3364 }
3365
3366 void analyzeConstant(Node node) {
3367 addDeferredAction(enclosingElement, () {
3368 ConstantExpression constant =
3369 compiler.resolver.constantCompiler.compileNode(
3370 node, registry.mapping);
3371
3372 ConstantValue value = constant.value;
3373 if (value.isMap) {
3374 checkConstMapKeysDontOverrideEquals(node, value);
3375 }
3376
3377 // The type constant that is an argument to JS_INTERCEPTOR_CONSTANT names
3378 // a class that will be instantiated outside the program by attaching a
3379 // native class dispatch record referencing the interceptor.
3380 if (argumentsToJsInterceptorConstant != null &&
3381 argumentsToJsInterceptorConstant.contains(node)) {
3382 if (value.isType) {
3383 TypeConstantValue typeConstant = value;
3384 if (typeConstant.representedType is InterfaceType) {
3385 registry.registerInstantiatedType(typeConstant.representedType);
3386 } else {
3387 compiler.reportError(node,
3388 MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT);
3389 }
3390 } else {
3391 compiler.reportError(node,
3392 MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT);
3393 }
3394 }
3395 });
3396 }
3397
3398 bool validateSymbol(Node node, String name, {bool reportError: true}) {
3399 if (name.isEmpty) return true;
3400 if (name.startsWith('_')) {
3401 if (reportError) {
3402 compiler.reportError(node, MessageKind.PRIVATE_IDENTIFIER,
3403 {'value': name});
3404 }
3405 return false;
3406 }
3407 if (!symbolValidationPattern.hasMatch(name)) {
3408 if (reportError) {
3409 compiler.reportError(node, MessageKind.INVALID_SYMBOL,
3410 {'value': name});
3411 }
3412 return false;
3413 }
3414 return true;
3415 }
3416
3417 /**
3418 * Try to resolve the constructor that is referred to by [node].
3419 * Note: this function may return an ErroneousFunctionElement instead of
3420 * [:null:], if there is no corresponding constructor, class or library.
3421 */
3422 ConstructorElement resolveConstructor(NewExpression node) {
3423 return node.accept(new ConstructorResolver(compiler, this));
3424 }
3425
3426 ConstructorElement resolveRedirectingFactory(RedirectingFactoryBody node,
3427 {bool inConstContext: false}) {
3428 return node.accept(new ConstructorResolver(compiler, this,
3429 inConstContext: inConstContext));
3430 }
3431
3432 DartType resolveTypeAnnotation(TypeAnnotation node,
3433 {bool malformedIsError: false,
3434 bool deferredIsMalformed: true}) {
3435 DartType type = typeResolver.resolveTypeAnnotation(
3436 this, node, malformedIsError: malformedIsError,
3437 deferredIsMalformed: deferredIsMalformed);
3438 if (inCheckContext) {
3439 registry.registerIsCheck(type);
3440 registry.registerRequiredType(type, enclosingElement);
3441 }
3442 return type;
3443 }
3444
3445 visitModifiers(Modifiers node) {
3446 internalError(node, 'modifiers');
3447 }
3448
3449 visitLiteralList(LiteralList node) {
3450 bool oldSendIsMemberAccess = sendIsMemberAccess;
3451 sendIsMemberAccess = false;
3452
3453 NodeList arguments = node.typeArguments;
3454 DartType typeArgument;
3455 if (arguments != null) {
3456 Link<Node> nodes = arguments.nodes;
3457 if (nodes.isEmpty) {
3458 // The syntax [: <>[] :] is not allowed.
3459 error(arguments, MessageKind.MISSING_TYPE_ARGUMENT);
3460 } else {
3461 typeArgument = resolveTypeAnnotation(nodes.head);
3462 for (nodes = nodes.tail; !nodes.isEmpty; nodes = nodes.tail) {
3463 warning(nodes.head, MessageKind.ADDITIONAL_TYPE_ARGUMENT);
3464 resolveTypeAnnotation(nodes.head);
3465 }
3466 }
3467 }
3468 DartType listType;
3469 if (typeArgument != null) {
3470 if (node.isConst && typeArgument.containsTypeVariables) {
3471 compiler.reportError(arguments.nodes.head,
3472 MessageKind.TYPE_VARIABLE_IN_CONSTANT);
3473 }
3474 listType = new InterfaceType(compiler.listClass, [typeArgument]);
3475 } else {
3476 compiler.listClass.computeType(compiler);
3477 listType = compiler.listClass.rawType;
3478 }
3479 registry.setType(node, listType);
3480 registry.registerInstantiatedType(listType);
3481 registry.registerRequiredType(listType, enclosingElement);
3482 visit(node.elements);
3483 if (node.isConst) {
3484 analyzeConstant(node);
3485 }
3486
3487 sendIsMemberAccess = false;
3488 }
3489
3490 visitConditional(Conditional node) {
3491 doInPromotionScope(node.condition, () => visit(node.condition));
3492 doInPromotionScope(node.thenExpression, () => visit(node.thenExpression));
3493 visit(node.elseExpression);
3494 }
3495
3496 visitStringInterpolation(StringInterpolation node) {
3497 registry.registerInstantiatedClass(compiler.stringClass);
3498 registry.registerStringInterpolation();
3499 node.visitChildren(this);
3500 }
3501
3502 visitStringInterpolationPart(StringInterpolationPart node) {
3503 registerImplicitInvocation('toString', 0);
3504 node.visitChildren(this);
3505 }
3506
3507 visitBreakStatement(BreakStatement node) {
3508 JumpTarget target;
3509 if (node.target == null) {
3510 target = statementScope.currentBreakTarget();
3511 if (target == null) {
3512 error(node, MessageKind.NO_BREAK_TARGET);
3513 return;
3514 }
3515 target.isBreakTarget = true;
3516 } else {
3517 String labelName = node.target.source;
3518 LabelDefinition label = statementScope.lookupLabel(labelName);
3519 if (label == null) {
3520 error(node.target, MessageKind.UNBOUND_LABEL, {'labelName': labelName});
3521 return;
3522 }
3523 target = label.target;
3524 if (!target.statement.isValidBreakTarget()) {
3525 error(node.target, MessageKind.INVALID_BREAK);
3526 return;
3527 }
3528 label.setBreakTarget();
3529 registry.useLabel(node, label);
3530 }
3531 registry.registerTargetOf(node, target);
3532 }
3533
3534 visitContinueStatement(ContinueStatement node) {
3535 JumpTarget target;
3536 if (node.target == null) {
3537 target = statementScope.currentContinueTarget();
3538 if (target == null) {
3539 error(node, MessageKind.NO_CONTINUE_TARGET);
3540 return;
3541 }
3542 target.isContinueTarget = true;
3543 } else {
3544 String labelName = node.target.source;
3545 LabelDefinition label = statementScope.lookupLabel(labelName);
3546 if (label == null) {
3547 error(node.target, MessageKind.UNBOUND_LABEL, {'labelName': labelName});
3548 return;
3549 }
3550 target = label.target;
3551 if (!target.statement.isValidContinueTarget()) {
3552 error(node.target, MessageKind.INVALID_CONTINUE);
3553 }
3554 label.setContinueTarget();
3555 registry.useLabel(node, label);
3556 }
3557 registry.registerTargetOf(node, target);
3558 }
3559
3560 registerImplicitInvocation(String name, int arity) {
3561 Selector selector = new Selector.call(name, null, arity);
3562 registry.registerDynamicInvocation(selector);
3563 }
3564
3565 visitForIn(ForIn node) {
3566 LibraryElement library = enclosingElement.library;
3567 registry.setIteratorSelector(node, compiler.iteratorSelector);
3568 registry.registerDynamicGetter(compiler.iteratorSelector);
3569 registry.setCurrentSelector(node, compiler.currentSelector);
3570 registry.registerDynamicGetter(compiler.currentSelector);
3571 registry.setMoveNextSelector(node, compiler.moveNextSelector);
3572 registry.registerDynamicInvocation(compiler.moveNextSelector);
3573
3574 visit(node.expression);
3575 Scope blockScope = new BlockScope(scope);
3576 Node declaration = node.declaredIdentifier;
3577
3578 bool oldAllowFinalWithoutInitializer = allowFinalWithoutInitializer;
3579 allowFinalWithoutInitializer = true;
3580 visitIn(declaration, blockScope);
3581 allowFinalWithoutInitializer = oldAllowFinalWithoutInitializer;
3582
3583 Send send = declaration.asSend();
3584 VariableDefinitions variableDefinitions =
3585 declaration.asVariableDefinitions();
3586 Element loopVariable;
3587 Selector loopVariableSelector;
3588 if (send != null) {
3589 loopVariable = registry.getDefinition(send);
3590 Identifier identifier = send.selector.asIdentifier();
3591 if (identifier == null) {
3592 compiler.reportError(send.selector, MessageKind.INVALID_FOR_IN);
3593 } else {
3594 loopVariableSelector = new Selector.setter(identifier.source, library);
3595 }
3596 if (send.receiver != null) {
3597 compiler.reportError(send.receiver, MessageKind.INVALID_FOR_IN);
3598 }
3599 } else if (variableDefinitions != null) {
3600 Link<Node> nodes = variableDefinitions.definitions.nodes;
3601 if (!nodes.tail.isEmpty) {
3602 compiler.reportError(nodes.tail.head, MessageKind.INVALID_FOR_IN);
3603 }
3604 Node first = nodes.head;
3605 Identifier identifier = first.asIdentifier();
3606 if (identifier == null) {
3607 compiler.reportError(first, MessageKind.INVALID_FOR_IN);
3608 } else {
3609 loopVariableSelector = new Selector.setter(identifier.source, library);
3610 loopVariable = registry.getDefinition(identifier);
3611 }
3612 } else {
3613 compiler.reportError(declaration, MessageKind.INVALID_FOR_IN);
3614 }
3615 if (loopVariableSelector != null) {
3616 registry.setSelector(declaration, loopVariableSelector);
3617 registerSend(loopVariableSelector, loopVariable);
3618 } else {
3619 // The selector may only be null if we reported an error.
3620 assert(invariant(declaration, compiler.compilationFailed));
3621 }
3622 if (loopVariable != null) {
3623 // loopVariable may be null if it could not be resolved.
3624 registry.setForInVariable(node, loopVariable);
3625 }
3626 visitLoopBodyIn(node, node.body, blockScope);
3627 }
3628
3629 visitLabel(Label node) {
3630 // Labels are handled by their containing statements/cases.
3631 }
3632
3633 visitLabeledStatement(LabeledStatement node) {
3634 Statement body = node.statement;
3635 JumpTarget targetElement = getOrDefineTarget(body);
3636 Map<String, LabelDefinition> labelElements = <String, LabelDefinition>{};
3637 for (Label label in node.labels) {
3638 String labelName = label.labelName;
3639 if (labelElements.containsKey(labelName)) continue;
3640 LabelDefinition element = targetElement.addLabel(label, labelName);
3641 labelElements[labelName] = element;
3642 }
3643 statementScope.enterLabelScope(labelElements);
3644 visit(node.statement);
3645 statementScope.exitLabelScope();
3646 labelElements.forEach((String labelName, LabelDefinition element) {
3647 if (element.isTarget) {
3648 registry.defineLabel(element.label, element);
3649 } else {
3650 warning(element.label, MessageKind.UNUSED_LABEL,
3651 {'labelName': labelName});
3652 }
3653 });
3654 if (!targetElement.isTarget) {
3655 registry.undefineTarget(body);
3656 }
3657 }
3658
3659 visitLiteralMap(LiteralMap node) {
3660 bool oldSendIsMemberAccess = sendIsMemberAccess;
3661 sendIsMemberAccess = false;
3662
3663 NodeList arguments = node.typeArguments;
3664 DartType keyTypeArgument;
3665 DartType valueTypeArgument;
3666 if (arguments != null) {
3667 Link<Node> nodes = arguments.nodes;
3668 if (nodes.isEmpty) {
3669 // The syntax [: <>{} :] is not allowed.
3670 error(arguments, MessageKind.MISSING_TYPE_ARGUMENT);
3671 } else {
3672 keyTypeArgument = resolveTypeAnnotation(nodes.head);
3673 nodes = nodes.tail;
3674 if (nodes.isEmpty) {
3675 warning(arguments, MessageKind.MISSING_TYPE_ARGUMENT);
3676 } else {
3677 valueTypeArgument = resolveTypeAnnotation(nodes.head);
3678 for (nodes = nodes.tail; !nodes.isEmpty; nodes = nodes.tail) {
3679 warning(nodes.head, MessageKind.ADDITIONAL_TYPE_ARGUMENT);
3680 resolveTypeAnnotation(nodes.head);
3681 }
3682 }
3683 }
3684 }
3685 DartType mapType;
3686 if (valueTypeArgument != null) {
3687 mapType = new InterfaceType(compiler.mapClass,
3688 [keyTypeArgument, valueTypeArgument]);
3689 } else {
3690 compiler.mapClass.computeType(compiler);
3691 mapType = compiler.mapClass.rawType;
3692 }
3693 if (node.isConst && mapType.containsTypeVariables) {
3694 compiler.reportError(arguments,
3695 MessageKind.TYPE_VARIABLE_IN_CONSTANT);
3696 }
3697 registry.setType(node, mapType);
3698 registry.registerInstantiatedType(mapType);
3699 if (node.isConst) {
3700 registry.registerConstantMap();
3701 }
3702 registry.registerRequiredType(mapType, enclosingElement);
3703 node.visitChildren(this);
3704 if (node.isConst) {
3705 analyzeConstant(node);
3706 }
3707
3708 sendIsMemberAccess = false;
3709 }
3710
3711 visitLiteralMapEntry(LiteralMapEntry node) {
3712 node.visitChildren(this);
3713 }
3714
3715 visitNamedArgument(NamedArgument node) {
3716 visit(node.expression);
3717 }
3718
3719 DartType typeOfConstant(ConstantValue constant) {
3720 if (constant.isInt) return compiler.intClass.rawType;
3721 if (constant.isBool) return compiler.boolClass.rawType;
3722 if (constant.isDouble) return compiler.doubleClass.rawType;
3723 if (constant.isString) return compiler.stringClass.rawType;
3724 if (constant.isNull) return compiler.nullClass.rawType;
3725 if (constant.isFunction) return compiler.functionClass.rawType;
3726 assert(constant.isObject);
3727 ObjectConstantValue objectConstant = constant;
3728 return objectConstant.type;
3729 }
3730
3731 bool overridesEquals(DartType type) {
3732 ClassElement cls = type.element;
3733 Element equals = cls.lookupMember('==');
3734 return equals.enclosingClass != compiler.objectClass;
3735 }
3736
3737 void checkCaseExpressions(SwitchStatement node) {
3738 JumpTarget breakElement = getOrDefineTarget(node);
3739 Map<String, LabelDefinition> continueLabels = <String, LabelDefinition>{};
3740
3741 Link<Node> cases = node.cases.nodes;
3742 CaseMatch firstCase = null;
3743 DartType firstCaseType = null;
3744 bool hasReportedProblem = false;
3745
3746 for (Link<Node> cases = node.cases.nodes;
3747 !cases.isEmpty;
3748 cases = cases.tail) {
3749 SwitchCase switchCase = cases.head;
3750
3751 for (Node labelOrCase in switchCase.labelsAndCases) {
3752 CaseMatch caseMatch = labelOrCase.asCaseMatch();
3753 if (caseMatch == null) continue;
3754
3755 // Analyze the constant.
3756 ConstantExpression constant =
3757 registry.getConstant(caseMatch.expression);
3758 assert(invariant(node, constant != null,
3759 message: 'No constant computed for $node'));
3760
3761 DartType caseType = typeOfConstant(constant.value);
3762
3763 if (firstCaseType == null) {
3764 firstCase = caseMatch;
3765 firstCaseType = caseType;
3766
3767 // We only report the bad type on the first class element. All others
3768 // get a "type differs" error.
3769 if (caseType.element == compiler.doubleClass) {
3770 compiler.reportError(node,
3771 MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS,
3772 {'type': "double"});
3773 } else if (caseType.element == compiler.functionClass) {
3774 compiler.reportError(node, MessageKind.SWITCH_CASE_FORBIDDEN,
3775 {'type': "Function"});
3776 } else if (constant.value.isObject && overridesEquals(caseType)) {
3777 compiler.reportError(firstCase.expression,
3778 MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS,
3779 {'type': caseType});
3780 }
3781 } else {
3782 if (caseType != firstCaseType) {
3783 if (!hasReportedProblem) {
3784 compiler.reportError(
3785 node,
3786 MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL,
3787 {'type': firstCaseType});
3788 compiler.reportInfo(
3789 firstCase.expression,
3790 MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL_CASE,
3791 {'type': firstCaseType});
3792 hasReportedProblem = true;
3793 }
3794 compiler.reportInfo(
3795 caseMatch.expression,
3796 MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL_CASE,
3797 {'type': caseType});
3798 }
3799 }
3800 }
3801 }
3802 }
3803
3804 visitSwitchStatement(SwitchStatement node) {
3805 node.expression.accept(this);
3806
3807 JumpTarget breakElement = getOrDefineTarget(node);
3808 Map<String, LabelDefinition> continueLabels = <String, LabelDefinition>{};
3809 Link<Node> cases = node.cases.nodes;
3810 while (!cases.isEmpty) {
3811 SwitchCase switchCase = cases.head;
3812 for (Node labelOrCase in switchCase.labelsAndCases) {
3813 CaseMatch caseMatch = labelOrCase.asCaseMatch();
3814 if (caseMatch != null) {
3815 analyzeConstant(caseMatch.expression);
3816 continue;
3817 }
3818 Label label = labelOrCase;
3819 String labelName = label.labelName;
3820
3821 LabelDefinition existingElement = continueLabels[labelName];
3822 if (existingElement != null) {
3823 // It's an error if the same label occurs twice in the same switch.
3824 compiler.reportError(
3825 label,
3826 MessageKind.DUPLICATE_LABEL, {'labelName': labelName});
3827 compiler.reportInfo(
3828 existingElement.label,
3829 MessageKind.EXISTING_LABEL, {'labelName': labelName});
3830 } else {
3831 // It's only a warning if it shadows another label.
3832 existingElement = statementScope.lookupLabel(labelName);
3833 if (existingElement != null) {
3834 compiler.reportWarning(
3835 label,
3836 MessageKind.DUPLICATE_LABEL, {'labelName': labelName});
3837 compiler.reportInfo(
3838 existingElement.label,
3839 MessageKind.EXISTING_LABEL, {'labelName': labelName});
3840 }
3841 }
3842
3843 JumpTarget targetElement = getOrDefineTarget(switchCase);
3844 LabelDefinition labelElement = targetElement.addLabel(label, labelName);
3845 registry.defineLabel(label, labelElement);
3846 continueLabels[labelName] = labelElement;
3847 }
3848 cases = cases.tail;
3849 // Test that only the last case, if any, is a default case.
3850 if (switchCase.defaultKeyword != null && !cases.isEmpty) {
3851 error(switchCase, MessageKind.INVALID_CASE_DEFAULT);
3852 }
3853 }
3854
3855 addDeferredAction(enclosingElement, () {
3856 checkCaseExpressions(node);
3857 });
3858
3859 statementScope.enterSwitch(breakElement, continueLabels);
3860 node.cases.accept(this);
3861 statementScope.exitSwitch();
3862
3863 // Clean-up unused labels.
3864 continueLabels.forEach((String key, LabelDefinition label) {
3865 if (!label.isContinueTarget) {
3866 JumpTarget targetElement = label.target;
3867 SwitchCase switchCase = targetElement.statement;
3868 registry.undefineTarget(switchCase);
3869 registry.undefineLabel(label.label);
3870 }
3871 });
3872 // TODO(15575): We should warn if we can detect a fall through
3873 // error.
3874 registry.registerFallThroughError();
3875 }
3876
3877 visitSwitchCase(SwitchCase node) {
3878 node.labelsAndCases.accept(this);
3879 visitIn(node.statements, new BlockScope(scope));
3880 }
3881
3882 visitCaseMatch(CaseMatch node) {
3883 visit(node.expression);
3884 }
3885
3886 visitTryStatement(TryStatement node) {
3887 visit(node.tryBlock);
3888 if (node.catchBlocks.isEmpty && node.finallyBlock == null) {
3889 error(node.getEndToken().next, MessageKind.NO_CATCH_NOR_FINALLY);
3890 }
3891 visit(node.catchBlocks);
3892 visit(node.finallyBlock);
3893 }
3894
3895 visitCatchBlock(CatchBlock node) {
3896 registry.registerCatchStatement();
3897 // Check that if catch part is present, then
3898 // it has one or two formal parameters.
3899 VariableDefinitions exceptionDefinition;
3900 VariableDefinitions stackTraceDefinition;
3901 if (node.formals != null) {
3902 Link<Node> formalsToProcess = node.formals.nodes;
3903 if (formalsToProcess.isEmpty) {
3904 error(node, MessageKind.EMPTY_CATCH_DECLARATION);
3905 } else {
3906 exceptionDefinition = formalsToProcess.head.asVariableDefinitions();
3907 formalsToProcess = formalsToProcess.tail;
3908 if (!formalsToProcess.isEmpty) {
3909 stackTraceDefinition = formalsToProcess.head.asVariableDefinitions();
3910 formalsToProcess = formalsToProcess.tail;
3911 if (!formalsToProcess.isEmpty) {
3912 for (Node extra in formalsToProcess) {
3913 error(extra, MessageKind.EXTRA_CATCH_DECLARATION);
3914 }
3915 }
3916 registry.registerStackTraceInCatch();
3917 }
3918 }
3919
3920 // Check that the formals aren't optional and that they have no
3921 // modifiers or type.
3922 for (Link<Node> link = node.formals.nodes;
3923 !link.isEmpty;
3924 link = link.tail) {
3925 // If the formal parameter is a node list, it means that it is a
3926 // sequence of optional parameters.
3927 NodeList nodeList = link.head.asNodeList();
3928 if (nodeList != null) {
3929 error(nodeList, MessageKind.OPTIONAL_PARAMETER_IN_CATCH);
3930 } else {
3931 VariableDefinitions declaration = link.head;
3932 for (Node modifier in declaration.modifiers.nodes) {
3933 error(modifier, MessageKind.PARAMETER_WITH_MODIFIER_IN_CATCH);
3934 }
3935 TypeAnnotation type = declaration.type;
3936 if (type != null) {
3937 error(type, MessageKind.PARAMETER_WITH_TYPE_IN_CATCH);
3938 }
3939 }
3940 }
3941 }
3942
3943 Scope blockScope = new BlockScope(scope);
3944 doInCheckContext(() => visitIn(node.type, blockScope));
3945 visitIn(node.formals, blockScope);
3946 var oldInCatchBlock = inCatchBlock;
3947 inCatchBlock = true;
3948 visitIn(node.block, blockScope);
3949 inCatchBlock = oldInCatchBlock;
3950
3951 if (node.type != null && exceptionDefinition != null) {
3952 DartType exceptionType = registry.getType(node.type);
3953 Node exceptionVariable = exceptionDefinition.definitions.nodes.head;
3954 VariableElementX exceptionElement =
3955 registry.getDefinition(exceptionVariable);
3956 exceptionElement.variables.type = exceptionType;
3957 }
3958 if (stackTraceDefinition != null) {
3959 Node stackTraceVariable = stackTraceDefinition.definitions.nodes.head;
3960 VariableElementX stackTraceElement =
3961 registry.getDefinition(stackTraceVariable);
3962 registry.registerInstantiatedClass(compiler.stackTraceClass);
3963 stackTraceElement.variables.type = compiler.stackTraceClass.rawType;
3964 }
3965 }
3966
3967 visitTypedef(Typedef node) {
3968 internalError(node, 'typedef');
3969 }
3970 }
3971
3972 class TypeDefinitionVisitor extends MappingVisitor<DartType> {
3973 Scope scope;
3974 final TypeDeclarationElement enclosingElement;
3975 TypeDeclarationElement get element => enclosingElement;
3976
3977 TypeDefinitionVisitor(Compiler compiler,
3978 TypeDeclarationElement element,
3979 ResolutionRegistry registry)
3980 : this.enclosingElement = element,
3981 scope = Scope.buildEnclosingScope(element),
3982 super(compiler, registry);
3983
3984 DartType get objectType => compiler.objectClass.rawType;
3985
3986 void resolveTypeVariableBounds(NodeList node) {
3987 if (node == null) return;
3988
3989 Setlet<String> nameSet = new Setlet<String>();
3990 // Resolve the bounds of type variables.
3991 Iterator<DartType> types = element.typeVariables.iterator;
3992 Link<Node> nodeLink = node.nodes;
3993 while (!nodeLink.isEmpty) {
3994 types.moveNext();
3995 TypeVariableType typeVariable = types.current;
3996 String typeName = typeVariable.name;
3997 TypeVariable typeNode = nodeLink.head;
3998 registry.useType(typeNode, typeVariable);
3999 if (nameSet.contains(typeName)) {
4000 error(typeNode, MessageKind.DUPLICATE_TYPE_VARIABLE_NAME,
4001 {'typeVariableName': typeName});
4002 }
4003 nameSet.add(typeName);
4004
4005 TypeVariableElementX variableElement = typeVariable.element;
4006 if (typeNode.bound != null) {
4007 DartType boundType = typeResolver.resolveTypeAnnotation(
4008 this, typeNode.bound);
4009 variableElement.boundCache = boundType;
4010
4011 void checkTypeVariableBound() {
4012 Link<TypeVariableElement> seenTypeVariables =
4013 const Link<TypeVariableElement>();
4014 seenTypeVariables = seenTypeVariables.prepend(variableElement);
4015 DartType bound = boundType;
4016 while (bound.isTypeVariable) {
4017 TypeVariableElement element = bound.element;
4018 if (seenTypeVariables.contains(element)) {
4019 if (identical(element, variableElement)) {
4020 // Only report an error on the checked type variable to avoid
4021 // generating multiple errors for the same cyclicity.
4022 warning(typeNode.name, MessageKind.CYCLIC_TYPE_VARIABLE,
4023 {'typeVariableName': variableElement.name});
4024 }
4025 break;
4026 }
4027 seenTypeVariables = seenTypeVariables.prepend(element);
4028 bound = element.bound;
4029 }
4030 }
4031 addDeferredAction(element, checkTypeVariableBound);
4032 } else {
4033 variableElement.boundCache = objectType;
4034 }
4035 nodeLink = nodeLink.tail;
4036 }
4037 assert(!types.moveNext());
4038 }
4039 }
4040
4041 class TypedefResolverVisitor extends TypeDefinitionVisitor {
4042 TypedefElementX get element => enclosingElement;
4043
4044 TypedefResolverVisitor(Compiler compiler,
4045 TypedefElement typedefElement,
4046 ResolutionRegistry registry)
4047 : super(compiler, typedefElement, registry);
4048
4049 visitTypedef(Typedef node) {
4050 TypedefType type = element.computeType(compiler);
4051 scope = new TypeDeclarationScope(scope, element);
4052 resolveTypeVariableBounds(node.typeParameters);
4053
4054 FunctionSignature signature = SignatureResolver.analyze(
4055 compiler, node.formals, node.returnType, element, registry,
4056 defaultValuesError: MessageKind.TYPEDEF_FORMAL_WITH_DEFAULT);
4057 element.functionSignature = signature;
4058
4059 scope = new MethodScope(scope, element);
4060 signature.forEachParameter(addToScope);
4061
4062 element.alias = signature.type;
4063
4064 void checkCyclicReference() {
4065 element.checkCyclicReference(compiler);
4066 }
4067 addDeferredAction(element, checkCyclicReference);
4068 }
4069 }
4070
4071 // TODO(johnniwinther): Replace with a traversal on the AST when the type
4072 // annotations in typedef alias are stored in a [TreeElements] mapping.
4073 class TypedefCyclicVisitor extends DartTypeVisitor {
4074 final Compiler compiler;
4075 final TypedefElementX element;
4076 bool hasCyclicReference = false;
4077
4078 Link<TypedefElement> seenTypedefs = const Link<TypedefElement>();
4079
4080 int seenTypedefsCount = 0;
4081
4082 Link<TypeVariableElement> seenTypeVariables =
4083 const Link<TypeVariableElement>();
4084
4085 TypedefCyclicVisitor(Compiler this.compiler, TypedefElement this.element);
4086
4087 visitType(DartType type, _) {
4088 // Do nothing.
4089 }
4090
4091 visitTypedefType(TypedefType type, _) {
4092 TypedefElementX typedefElement = type.element;
4093 if (seenTypedefs.contains(typedefElement)) {
4094 if (!hasCyclicReference && identical(element, typedefElement)) {
4095 // Only report an error on the checked typedef to avoid generating
4096 // multiple errors for the same cyclicity.
4097 hasCyclicReference = true;
4098 if (seenTypedefsCount == 1) {
4099 // Direct cyclicity.
4100 compiler.reportError(element,
4101 MessageKind.CYCLIC_TYPEDEF,
4102 {'typedefName': element.name});
4103 } else if (seenTypedefsCount == 2) {
4104 // Cyclicity through one other typedef.
4105 compiler.reportError(element,
4106 MessageKind.CYCLIC_TYPEDEF_ONE,
4107 {'typedefName': element.name,
4108 'otherTypedefName': seenTypedefs.head.name});
4109 } else {
4110 // Cyclicity through more than one other typedef.
4111 for (TypedefElement cycle in seenTypedefs) {
4112 if (!identical(typedefElement, cycle)) {
4113 compiler.reportError(element,
4114 MessageKind.CYCLIC_TYPEDEF_ONE,
4115 {'typedefName': element.name,
4116 'otherTypedefName': cycle.name});
4117 }
4118 }
4119 }
4120 ErroneousElementX erroneousElement = new ErroneousElementX(
4121 MessageKind.CYCLIC_TYPEDEF,
4122 {'typedefName': element.name},
4123 element.name, element);
4124 element.alias =
4125 new MalformedType(erroneousElement, typedefElement.alias);
4126 element.hasBeenCheckedForCycles = true;
4127 }
4128 } else {
4129 seenTypedefs = seenTypedefs.prepend(typedefElement);
4130 seenTypedefsCount++;
4131 type.visitChildren(this, null);
4132 typedefElement.alias.accept(this, null);
4133 seenTypedefs = seenTypedefs.tail;
4134 seenTypedefsCount--;
4135 }
4136 }
4137
4138 visitFunctionType(FunctionType type, _) {
4139 type.visitChildren(this, null);
4140 }
4141
4142 visitInterfaceType(InterfaceType type, _) {
4143 type.visitChildren(this, null);
4144 }
4145
4146 visitTypeVariableType(TypeVariableType type, _) {
4147 TypeVariableElement typeVariableElement = type.element;
4148 if (seenTypeVariables.contains(typeVariableElement)) {
4149 // Avoid running in cycles on cyclic type variable bounds.
4150 // Cyclicity is reported elsewhere.
4151 return;
4152 }
4153 seenTypeVariables = seenTypeVariables.prepend(typeVariableElement);
4154 typeVariableElement.bound.accept(this, null);
4155 seenTypeVariables = seenTypeVariables.tail;
4156 }
4157 }
4158
4159 /**
4160 * The implementation of [ResolverTask.resolveClass].
4161 *
4162 * This visitor has to be extra careful as it is building the basic
4163 * element information, and cannot safely look at other elements as
4164 * this may lead to cycles.
4165 *
4166 * This visitor can assume that the supertypes have already been
4167 * resolved, but it cannot call [ResolverTask.resolveClass] directly
4168 * or indirectly (through [ClassElement.ensureResolved]) for any other
4169 * types.
4170 */
4171 class ClassResolverVisitor extends TypeDefinitionVisitor {
4172 BaseClassElementX get element => enclosingElement;
4173
4174 ClassResolverVisitor(Compiler compiler,
4175 ClassElement classElement,
4176 ResolutionRegistry registry)
4177 : super(compiler, classElement, registry);
4178
4179 DartType visitClassNode(ClassNode node) {
4180 invariant(node, element != null);
4181 invariant(element, element.resolutionState == STATE_STARTED,
4182 message: () => 'cyclic resolution of class $element');
4183
4184 InterfaceType type = element.computeType(compiler);
4185 scope = new TypeDeclarationScope(scope, element);
4186 // TODO(ahe): It is not safe to call resolveTypeVariableBounds yet.
4187 // As a side-effect, this may get us back here trying to
4188 // resolve this class again.
4189 resolveTypeVariableBounds(node.typeParameters);
4190
4191 // Setup the supertype for the element (if there is a cycle in the
4192 // class hierarchy, it has already been set to Object).
4193 if (element.supertype == null && node.superclass != null) {
4194 MixinApplication superMixin = node.superclass.asMixinApplication();
4195 if (superMixin != null) {
4196 DartType supertype = resolveSupertype(element, superMixin.superclass);
4197 Link<Node> link = superMixin.mixins.nodes;
4198 while (!link.isEmpty) {
4199 supertype = applyMixin(supertype,
4200 checkMixinType(link.head), link.head);
4201 link = link.tail;
4202 }
4203 element.supertype = supertype;
4204 } else {
4205 element.supertype = resolveSupertype(element, node.superclass);
4206 }
4207 }
4208 // If the super type isn't specified, we provide a default. The language
4209 // specifies [Object] but the backend can pick a specific 'implementation'
4210 // of Object - the JavaScript backend chooses between Object and
4211 // Interceptor.
4212 if (element.supertype == null) {
4213 ClassElement superElement = registry.defaultSuperclass(element);
4214 // Avoid making the superclass (usually Object) extend itself.
4215 if (element != superElement) {
4216 if (superElement == null) {
4217 compiler.internalError(node,
4218 "Cannot resolve default superclass for $element.");
4219 } else {
4220 superElement.ensureResolved(compiler);
4221 }
4222 element.supertype = superElement.computeType(compiler);
4223 }
4224 }
4225
4226 if (element.interfaces == null) {
4227 element.interfaces = resolveInterfaces(node.interfaces, node.superclass);
4228 } else {
4229 assert(invariant(element, element.hasIncompleteHierarchy));
4230 }
4231 calculateAllSupertypes(element);
4232
4233 if (!element.hasConstructor) {
4234 Element superMember = element.superclass.localLookup('');
4235 if (superMember == null || !superMember.isGenerativeConstructor) {
4236 MessageKind kind = MessageKind.CANNOT_FIND_CONSTRUCTOR;
4237 Map arguments = {'constructorName': ''};
4238 // TODO(ahe): Why is this a compile-time error? Or if it is an error,
4239 // why do we bother to registerThrowNoSuchMethod below?
4240 compiler.reportError(node, kind, arguments);
4241 superMember = new ErroneousElementX(
4242 kind, arguments, '', element);
4243 registry.registerThrowNoSuchMethod();
4244 } else {
4245 ConstructorElement superConstructor = superMember;
4246 Selector callToMatch = new Selector.call("", element.library, 0);
4247 superConstructor.computeSignature(compiler);
4248 if (!callToMatch.applies(superConstructor, compiler.world)) {
4249 MessageKind kind = MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT;
4250 compiler.reportError(node, kind);
4251 superMember = new ErroneousElementX(kind, {}, '', element);
4252 }
4253 }
4254 FunctionElement constructor =
4255 new SynthesizedConstructorElementX.forDefault(superMember, element);
4256 element.setDefaultConstructor(constructor, compiler);
4257 }
4258 return element.computeType(compiler);
4259 }
4260
4261 /// Resolves the mixed type for [mixinNode] and checks that the the mixin type
4262 /// is a valid, non-blacklisted interface type. The mixin type is returned.
4263 DartType checkMixinType(TypeAnnotation mixinNode) {
4264 DartType mixinType = resolveType(mixinNode);
4265 if (isBlackListed(mixinType)) {
4266 compiler.reportError(mixinNode,
4267 MessageKind.CANNOT_MIXIN, {'type': mixinType});
4268 } else if (mixinType.isTypeVariable) {
4269 compiler.reportError(mixinNode, MessageKind.CLASS_NAME_EXPECTED);
4270 } else if (mixinType.isMalformed) {
4271 compiler.reportError(mixinNode, MessageKind.CANNOT_MIXIN_MALFORMED,
4272 {'className': element.name, 'malformedType': mixinType});
4273 }
4274 return mixinType;
4275 }
4276
4277 DartType visitNamedMixinApplication(NamedMixinApplication node) {
4278 invariant(node, element != null);
4279 invariant(element, element.resolutionState == STATE_STARTED,
4280 message: () => 'cyclic resolution of class $element');
4281
4282 if (identical(node.classKeyword.stringValue, 'typedef')) {
4283 // TODO(aprelev@gmail.com): Remove this deprecation diagnostic
4284 // together with corresponding TODO in parser.dart.
4285 compiler.reportWarning(node.classKeyword,
4286 MessageKind.DEPRECATED_TYPEDEF_MIXIN_SYNTAX);
4287 }
4288
4289 InterfaceType type = element.computeType(compiler);
4290 scope = new TypeDeclarationScope(scope, element);
4291 resolveTypeVariableBounds(node.typeParameters);
4292
4293 // Generate anonymous mixin application elements for the
4294 // intermediate mixin applications (excluding the last).
4295 DartType supertype = resolveSupertype(element, node.superclass);
4296 Link<Node> link = node.mixins.nodes;
4297 while (!link.tail.isEmpty) {
4298 supertype = applyMixin(supertype, checkMixinType(link.head), link.head);
4299 link = link.tail;
4300 }
4301 doApplyMixinTo(element, supertype, checkMixinType(link.head));
4302 return element.computeType(compiler);
4303 }
4304
4305 DartType applyMixin(DartType supertype, DartType mixinType, Node node) {
4306 String superName = supertype.name;
4307 String mixinName = mixinType.name;
4308 MixinApplicationElementX mixinApplication = new MixinApplicationElementX(
4309 "${superName}+${mixinName}",
4310 element.compilationUnit,
4311 compiler.getNextFreeClassId(),
4312 node,
4313 new Modifiers.withFlags(new NodeList.empty(), Modifiers.FLAG_ABSTRACT));
4314 // Create synthetic type variables for the mixin application.
4315 List<DartType> typeVariables = <DartType>[];
4316 element.typeVariables.forEach((TypeVariableType type) {
4317 TypeVariableElementX typeVariableElement = new TypeVariableElementX(
4318 type.name, mixinApplication, type.element.node);
4319 TypeVariableType typeVariable = new TypeVariableType(typeVariableElement);
4320 typeVariables.add(typeVariable);
4321 });
4322 // Setup bounds on the synthetic type variables.
4323 List<DartType> link = typeVariables;
4324 int index = 0;
4325 element.typeVariables.forEach((TypeVariableType type) {
4326 TypeVariableType typeVariable = typeVariables[index++];
4327 TypeVariableElementX typeVariableElement = typeVariable.element;
4328 typeVariableElement.typeCache = typeVariable;
4329 typeVariableElement.boundCache =
4330 type.element.bound.subst(typeVariables, element.typeVariables);
4331 });
4332 // Setup this and raw type for the mixin application.
4333 mixinApplication.computeThisAndRawType(compiler, typeVariables);
4334 // Substitute in synthetic type variables in super and mixin types.
4335 supertype = supertype.subst(typeVariables, element.typeVariables);
4336 mixinType = mixinType.subst(typeVariables, element.typeVariables);
4337
4338 doApplyMixinTo(mixinApplication, supertype, mixinType);
4339 mixinApplication.resolutionState = STATE_DONE;
4340 mixinApplication.supertypeLoadState = STATE_DONE;
4341 // Replace the synthetic type variables by the original type variables in
4342 // the returned type (which should be the type actually extended).
4343 InterfaceType mixinThisType = mixinApplication.computeType(compiler);
4344 return mixinThisType.subst(element.typeVariables,
4345 mixinThisType.typeArguments);
4346 }
4347
4348 bool isDefaultConstructor(FunctionElement constructor) {
4349 return constructor.name == '' &&
4350 constructor.computeSignature(compiler).parameterCount == 0;
4351 }
4352
4353 FunctionElement createForwardingConstructor(ConstructorElement target,
4354 ClassElement enclosing) {
4355 return new SynthesizedConstructorElementX(
4356 target.name, target, enclosing, false);
4357 }
4358
4359 void doApplyMixinTo(MixinApplicationElementX mixinApplication,
4360 DartType supertype,
4361 DartType mixinType) {
4362 Node node = mixinApplication.parseNode(compiler);
4363
4364 if (mixinApplication.supertype != null) {
4365 // [supertype] is not null if there was a cycle.
4366 assert(invariant(node, compiler.compilationFailed));
4367 supertype = mixinApplication.supertype;
4368 assert(invariant(node, supertype.element == compiler.objectClass));
4369 } else {
4370 mixinApplication.supertype = supertype;
4371 }
4372
4373 // Named mixin application may have an 'implements' clause.
4374 NamedMixinApplication namedMixinApplication =
4375 node.asNamedMixinApplication();
4376 Link<DartType> interfaces = (namedMixinApplication != null)
4377 ? resolveInterfaces(namedMixinApplication.interfaces,
4378 namedMixinApplication.superclass)
4379 : const Link<DartType>();
4380
4381 // The class that is the result of a mixin application implements
4382 // the interface of the class that was mixed in so always prepend
4383 // that to the interface list.
4384 if (mixinApplication.interfaces == null) {
4385 if (mixinType.isInterfaceType) {
4386 // Avoid malformed types in the interfaces.
4387 interfaces = interfaces.prepend(mixinType);
4388 }
4389 mixinApplication.interfaces = interfaces;
4390 } else {
4391 assert(invariant(mixinApplication,
4392 mixinApplication.hasIncompleteHierarchy));
4393 }
4394
4395 ClassElement superclass = supertype.element;
4396 if (mixinType.kind != TypeKind.INTERFACE) {
4397 mixinApplication.hasIncompleteHierarchy = true;
4398 mixinApplication.allSupertypesAndSelf = superclass.allSupertypesAndSelf;
4399 return;
4400 }
4401
4402 assert(mixinApplication.mixinType == null);
4403 mixinApplication.mixinType = resolveMixinFor(mixinApplication, mixinType);
4404
4405 // Create forwarding constructors for constructor defined in the superclass
4406 // because they are now hidden by the mixin application.
4407 superclass.forEachLocalMember((Element member) {
4408 if (!member.isGenerativeConstructor) return;
4409 FunctionElement forwarder =
4410 createForwardingConstructor(member, mixinApplication);
4411 if (isPrivateName(member.name) &&
4412 mixinApplication.library != superclass.library) {
4413 // Do not create a forwarder to the super constructor, because the mixin
4414 // application is in a different library than the constructor in the
4415 // super class and it is not possible to call that constructor from the
4416 // library using the mixin application.
4417 return;
4418 }
4419 mixinApplication.addConstructor(forwarder);
4420 });
4421 calculateAllSupertypes(mixinApplication);
4422 }
4423
4424 InterfaceType resolveMixinFor(MixinApplicationElement mixinApplication,
4425 DartType mixinType) {
4426 ClassElement mixin = mixinType.element;
4427 mixin.ensureResolved(compiler);
4428
4429 // Check for cycles in the mixin chain.
4430 ClassElement previous = mixinApplication; // For better error messages.
4431 ClassElement current = mixin;
4432 while (current != null && current.isMixinApplication) {
4433 MixinApplicationElement currentMixinApplication = current;
4434 if (currentMixinApplication == mixinApplication) {
4435 compiler.reportError(
4436 mixinApplication, MessageKind.ILLEGAL_MIXIN_CYCLE,
4437 {'mixinName1': current.name, 'mixinName2': previous.name});
4438 // We have found a cycle in the mixin chain. Return null as
4439 // the mixin for this application to avoid getting into
4440 // infinite recursion when traversing members.
4441 return null;
4442 }
4443 previous = current;
4444 current = currentMixinApplication.mixin;
4445 }
4446 registry.registerMixinUse(mixinApplication, mixin);
4447 return mixinType;
4448 }
4449
4450 DartType resolveType(TypeAnnotation node) {
4451 return typeResolver.resolveTypeAnnotation(this, node);
4452 }
4453
4454 DartType resolveSupertype(ClassElement cls, TypeAnnotation superclass) {
4455 DartType supertype = resolveType(superclass);
4456 if (supertype != null) {
4457 if (identical(supertype.kind, TypeKind.MALFORMED_TYPE)) {
4458 compiler.reportError(superclass, MessageKind.CANNOT_EXTEND_MALFORMED,
4459 {'className': element.name, 'malformedType': supertype});
4460 return objectType;
4461 } else if (!identical(supertype.kind, TypeKind.INTERFACE)) {
4462 compiler.reportError(superclass.typeName,
4463 MessageKind.CLASS_NAME_EXPECTED);
4464 return objectType;
4465 } else if (isBlackListed(supertype)) {
4466 compiler.reportError(superclass, MessageKind.CANNOT_EXTEND,
4467 {'type': supertype});
4468 return objectType;
4469 }
4470 }
4471 return supertype;
4472 }
4473
4474 Link<DartType> resolveInterfaces(NodeList interfaces, Node superclass) {
4475 Link<DartType> result = const Link<DartType>();
4476 if (interfaces == null) return result;
4477 for (Link<Node> link = interfaces.nodes; !link.isEmpty; link = link.tail) {
4478 DartType interfaceType = resolveType(link.head);
4479 if (interfaceType != null) {
4480 if (identical(interfaceType.kind, TypeKind.MALFORMED_TYPE)) {
4481 compiler.reportError(superclass,
4482 MessageKind.CANNOT_IMPLEMENT_MALFORMED,
4483 {'className': element.name, 'malformedType': interfaceType});
4484 } else if (!identical(interfaceType.kind, TypeKind.INTERFACE)) {
4485 // TODO(johnniwinther): Handle dynamic.
4486 TypeAnnotation typeAnnotation = link.head;
4487 error(typeAnnotation.typeName, MessageKind.CLASS_NAME_EXPECTED);
4488 } else {
4489 if (interfaceType == element.supertype) {
4490 compiler.reportError(
4491 superclass,
4492 MessageKind.DUPLICATE_EXTENDS_IMPLEMENTS,
4493 {'type': interfaceType});
4494 compiler.reportError(
4495 link.head,
4496 MessageKind.DUPLICATE_EXTENDS_IMPLEMENTS,
4497 {'type': interfaceType});
4498 }
4499 if (result.contains(interfaceType)) {
4500 compiler.reportError(
4501 link.head,
4502 MessageKind.DUPLICATE_IMPLEMENTS,
4503 {'type': interfaceType});
4504 }
4505 result = result.prepend(interfaceType);
4506 if (isBlackListed(interfaceType)) {
4507 error(link.head, MessageKind.CANNOT_IMPLEMENT,
4508 {'type': interfaceType});
4509 }
4510 }
4511 }
4512 }
4513 return result;
4514 }
4515
4516 /**
4517 * Compute the list of all supertypes.
4518 *
4519 * The elements of this list are ordered as follows: first the supertype that
4520 * the class extends, then the implemented interfaces, and then the supertypes
4521 * of these. The class [Object] appears only once, at the end of the list.
4522 *
4523 * For example, for a class `class C extends S implements I1, I2`, we compute
4524 * supertypes(C) = [S, I1, I2] ++ supertypes(S) ++ supertypes(I1)
4525 * ++ supertypes(I2),
4526 * where ++ stands for list concatenation.
4527 *
4528 * This order makes sure that if a class implements an interface twice with
4529 * different type arguments, the type used in the most specific class comes
4530 * first.
4531 */
4532 void calculateAllSupertypes(BaseClassElementX cls) {
4533 if (cls.allSupertypesAndSelf != null) return;
4534 final DartType supertype = cls.supertype;
4535 if (supertype != null) {
4536 OrderedTypeSetBuilder allSupertypes = new OrderedTypeSetBuilder(cls);
4537 // TODO(15296): Collapse these iterations to one when the order is not
4538 // needed.
4539 allSupertypes.add(compiler, supertype);
4540 for (Link<DartType> interfaces = cls.interfaces;
4541 !interfaces.isEmpty;
4542 interfaces = interfaces.tail) {
4543 allSupertypes.add(compiler, interfaces.head);
4544 }
4545
4546 addAllSupertypes(allSupertypes, supertype);
4547 for (Link<DartType> interfaces = cls.interfaces;
4548 !interfaces.isEmpty;
4549 interfaces = interfaces.tail) {
4550 addAllSupertypes(allSupertypes, interfaces.head);
4551 }
4552 allSupertypes.add(compiler, cls.computeType(compiler));
4553 cls.allSupertypesAndSelf = allSupertypes.toTypeSet();
4554 } else {
4555 assert(identical(cls, compiler.objectClass));
4556 cls.allSupertypesAndSelf =
4557 new OrderedTypeSet.singleton(cls.computeType(compiler));
4558 }
4559 }
4560
4561 /**
4562 * Adds [type] and all supertypes of [type] to [allSupertypes] while
4563 * substituting type variables.
4564 */
4565 void addAllSupertypes(OrderedTypeSetBuilder allSupertypes,
4566 InterfaceType type) {
4567 ClassElement classElement = type.element;
4568 Link<DartType> supertypes = classElement.allSupertypes;
4569 assert(invariant(element, supertypes != null,
4570 message: "Supertypes not computed on $classElement "
4571 "during resolution of $element"));
4572 while (!supertypes.isEmpty) {
4573 DartType supertype = supertypes.head;
4574 allSupertypes.add(compiler, supertype.substByContext(type));
4575 supertypes = supertypes.tail;
4576 }
4577 }
4578
4579 isBlackListed(DartType type) {
4580 LibraryElement lib = element.library;
4581 return
4582 !identical(lib, compiler.coreLibrary) &&
4583 !compiler.backend.isBackendLibrary(lib) &&
4584 (type.isDynamic ||
4585 identical(type.element, compiler.boolClass) ||
4586 identical(type.element, compiler.numClass) ||
4587 identical(type.element, compiler.intClass) ||
4588 identical(type.element, compiler.doubleClass) ||
4589 identical(type.element, compiler.stringClass) ||
4590 identical(type.element, compiler.nullClass));
4591 }
4592 }
4593
4594 class ClassSupertypeResolver extends CommonResolverVisitor {
4595 Scope context;
4596 ClassElement classElement;
4597
4598 ClassSupertypeResolver(Compiler compiler, ClassElement cls)
4599 : context = Scope.buildEnclosingScope(cls),
4600 this.classElement = cls,
4601 super(compiler);
4602
4603 void loadSupertype(ClassElement element, Node from) {
4604 compiler.resolver.loadSupertypes(element, from);
4605 element.ensureResolved(compiler);
4606 }
4607
4608 void visitNodeList(NodeList node) {
4609 if (node != null) {
4610 for (Link<Node> link = node.nodes; !link.isEmpty; link = link.tail) {
4611 link.head.accept(this);
4612 }
4613 }
4614 }
4615
4616 void visitClassNode(ClassNode node) {
4617 if (node.superclass == null) {
4618 if (!identical(classElement, compiler.objectClass)) {
4619 loadSupertype(compiler.objectClass, node);
4620 }
4621 } else {
4622 node.superclass.accept(this);
4623 }
4624 visitNodeList(node.interfaces);
4625 }
4626
4627 void visitMixinApplication(MixinApplication node) {
4628 node.superclass.accept(this);
4629 visitNodeList(node.mixins);
4630 }
4631
4632 void visitNamedMixinApplication(NamedMixinApplication node) {
4633 node.superclass.accept(this);
4634 visitNodeList(node.mixins);
4635 visitNodeList(node.interfaces);
4636 }
4637
4638 void visitTypeAnnotation(TypeAnnotation node) {
4639 node.typeName.accept(this);
4640 }
4641
4642 void visitIdentifier(Identifier node) {
4643 Element element = lookupInScope(compiler, node, context, node.source);
4644 if (element != null && element.isClass) {
4645 loadSupertype(element, node);
4646 }
4647 }
4648
4649 void visitSend(Send node) {
4650 Identifier prefix = node.receiver.asIdentifier();
4651 if (prefix == null) {
4652 error(node.receiver, MessageKind.NOT_A_PREFIX, {'node': node.receiver});
4653 return;
4654 }
4655 Element element = lookupInScope(compiler, prefix, context, prefix.source);
4656 if (element == null || !identical(element.kind, ElementKind.PREFIX)) {
4657 error(node.receiver, MessageKind.NOT_A_PREFIX, {'node': node.receiver});
4658 return;
4659 }
4660 PrefixElement prefixElement = element;
4661 Identifier selector = node.selector.asIdentifier();
4662 var e = prefixElement.lookupLocalMember(selector.source);
4663 if (e == null || !e.impliesType) {
4664 error(node.selector, MessageKind.CANNOT_RESOLVE_TYPE,
4665 {'typeName': node.selector});
4666 return;
4667 }
4668 loadSupertype(e, node);
4669 }
4670 }
4671
4672 class VariableDefinitionsVisitor extends CommonResolverVisitor<Identifier> {
4673 VariableDefinitions definitions;
4674 ResolverVisitor resolver;
4675 VariableList variables;
4676
4677 VariableDefinitionsVisitor(Compiler compiler,
4678 this.definitions,
4679 this.resolver,
4680 this.variables)
4681 : super(compiler) {
4682 }
4683
4684 ResolutionRegistry get registry => resolver.registry;
4685
4686 Identifier visitSendSet(SendSet node) {
4687 assert(node.arguments.tail.isEmpty); // Sanity check
4688 Identifier identifier = node.selector;
4689 String name = identifier.source;
4690 VariableDefinitionScope scope =
4691 new VariableDefinitionScope(resolver.scope, name);
4692 resolver.visitIn(node.arguments.head, scope);
4693 if (scope.variableReferencedInInitializer) {
4694 compiler.reportError(
4695 identifier, MessageKind.REFERENCE_IN_INITIALIZATION,
4696 {'variableName': name});
4697 }
4698 return identifier;
4699 }
4700
4701 Identifier visitIdentifier(Identifier node) {
4702 // The variable is initialized to null.
4703 registry.registerInstantiatedClass(compiler.nullClass);
4704 if (definitions.modifiers.isConst) {
4705 compiler.reportError(node, MessageKind.CONST_WITHOUT_INITIALIZER);
4706 }
4707 if (definitions.modifiers.isFinal &&
4708 !resolver.allowFinalWithoutInitializer) {
4709 compiler.reportError(node, MessageKind.FINAL_WITHOUT_INITIALIZER);
4710 }
4711 return node;
4712 }
4713
4714 visitNodeList(NodeList node) {
4715 for (Link<Node> link = node.nodes; !link.isEmpty; link = link.tail) {
4716 Identifier name = visit(link.head);
4717 LocalVariableElement element = new LocalVariableElementX(
4718 name.source, resolver.enclosingElement,
4719 variables, name.token);
4720 resolver.defineLocalVariable(link.head, element);
4721 resolver.addToScope(element);
4722 if (definitions.modifiers.isConst) {
4723 compiler.enqueuer.resolution.addDeferredAction(element, () {
4724 compiler.resolver.constantCompiler.compileConstant(element);
4725 });
4726 }
4727 }
4728 }
4729 }
4730
4731 class ConstructorResolver extends CommonResolverVisitor<Element> {
4732 final ResolverVisitor resolver;
4733 bool inConstContext;
4734 DartType type;
4735
4736 ConstructorResolver(Compiler compiler, this.resolver,
4737 {bool this.inConstContext: false})
4738 : super(compiler);
4739
4740 ResolutionRegistry get registry => resolver.registry;
4741
4742 visitNode(Node node) {
4743 throw 'not supported';
4744 }
4745
4746 failOrReturnErroneousElement(Element enclosing, Node diagnosticNode,
4747 String targetName, MessageKind kind,
4748 Map arguments) {
4749 if (kind == MessageKind.CANNOT_FIND_CONSTRUCTOR) {
4750 registry.registerThrowNoSuchMethod();
4751 } else {
4752 registry.registerThrowRuntimeError();
4753 }
4754 if (inConstContext) {
4755 compiler.reportError(diagnosticNode, kind, arguments);
4756 } else {
4757 compiler.reportWarning(diagnosticNode, kind, arguments);
4758 }
4759 return new ErroneousElementX(kind, arguments, targetName, enclosing);
4760 }
4761
4762 Selector createConstructorSelector(String constructorName) {
4763 return constructorName == ''
4764 ? new Selector.callDefaultConstructor(
4765 resolver.enclosingElement.library)
4766 : new Selector.callConstructor(
4767 constructorName,
4768 resolver.enclosingElement.library);
4769 }
4770
4771 FunctionElement resolveConstructor(ClassElement cls,
4772 Node diagnosticNode,
4773 String constructorName) {
4774 cls.ensureResolved(compiler);
4775 Selector selector = createConstructorSelector(constructorName);
4776 Element result = cls.lookupConstructor(selector);
4777 if (result == null) {
4778 String fullConstructorName = Elements.constructorNameForDiagnostics(
4779 cls.name,
4780 constructorName);
4781 return failOrReturnErroneousElement(
4782 cls,
4783 diagnosticNode,
4784 fullConstructorName,
4785 MessageKind.CANNOT_FIND_CONSTRUCTOR,
4786 {'constructorName': fullConstructorName});
4787 } else if (inConstContext && !result.isConst) {
4788 error(diagnosticNode, MessageKind.CONSTRUCTOR_IS_NOT_CONST);
4789 }
4790 return result;
4791 }
4792
4793 Element visitNewExpression(NewExpression node) {
4794 inConstContext = node.isConst;
4795 Node selector = node.send.selector;
4796 Element element = visit(selector);
4797 assert(invariant(selector, element != null,
4798 message: 'No element return for $selector.'));
4799 return finishConstructorReference(element, node.send.selector, node);
4800 }
4801
4802 /// Finishes resolution of a constructor reference and records the
4803 /// type of the constructed instance on [expression].
4804 FunctionElement finishConstructorReference(Element element,
4805 Node diagnosticNode,
4806 Node expression) {
4807 assert(invariant(diagnosticNode, element != null,
4808 message: 'No element return for $diagnosticNode.'));
4809 // Find the unnamed constructor if the reference resolved to a
4810 // class.
4811 if (!Elements.isUnresolved(element) && !element.isConstructor) {
4812 if (element.isClass) {
4813 ClassElement cls = element;
4814 cls.ensureResolved(compiler);
4815 // The unnamed constructor may not exist, so [e] may become unresolved.
4816 element = resolveConstructor(cls, diagnosticNode, '');
4817 } else {
4818 element = failOrReturnErroneousElement(
4819 element, diagnosticNode, element.name, MessageKind.NOT_A_TYPE,
4820 {'node': diagnosticNode});
4821 }
4822 }
4823 if (type == null) {
4824 if (Elements.isUnresolved(element)) {
4825 type = const DynamicType();
4826 } else {
4827 type = element.enclosingClass.rawType;
4828 }
4829 }
4830 resolver.registry.setType(expression, type);
4831 return element;
4832 }
4833
4834 Element visitTypeAnnotation(TypeAnnotation node) {
4835 assert(invariant(node, type == null));
4836 // This is not really resolving a type-annotation, but the name of the
4837 // constructor. Therefore we allow deferred types.
4838 type = resolver.resolveTypeAnnotation(node,
4839 malformedIsError: inConstContext,
4840 deferredIsMalformed: false);
4841 registry.registerRequiredType(type, resolver.enclosingElement);
4842 return type.element;
4843 }
4844
4845 Element visitSend(Send node) {
4846 Element element = visit(node.receiver);
4847 assert(invariant(node.receiver, element != null,
4848 message: 'No element return for $node.receiver.'));
4849 if (Elements.isUnresolved(element)) return element;
4850 Identifier name = node.selector.asIdentifier();
4851 if (name == null) internalError(node.selector, 'unexpected node');
4852
4853 if (element.isClass) {
4854 ClassElement cls = element;
4855 cls.ensureResolved(compiler);
4856 return resolveConstructor(cls, name, name.source);
4857 } else if (element.isPrefix) {
4858 PrefixElement prefix = element;
4859 element = prefix.lookupLocalMember(name.source);
4860 element = Elements.unwrap(element, compiler, node);
4861 if (element == null) {
4862 return failOrReturnErroneousElement(
4863 resolver.enclosingElement, name,
4864 name.source,
4865 MessageKind.CANNOT_RESOLVE,
4866 {'name': name});
4867 } else if (!element.isClass) {
4868 error(node, MessageKind.NOT_A_TYPE, {'node': name});
4869 }
4870 } else {
4871 internalError(node.receiver, 'unexpected element $element');
4872 }
4873 return element;
4874 }
4875
4876 Element visitIdentifier(Identifier node) {
4877 String name = node.source;
4878 Element element = resolver.reportLookupErrorIfAny(
4879 lookupInScope(compiler, node, resolver.scope, name), node, name);
4880 registry.useElement(node, element);
4881 // TODO(johnniwinther): Change errors to warnings, cf. 11.11.1.
4882 if (element == null) {
4883 return failOrReturnErroneousElement(resolver.enclosingElement, node, name,
4884 MessageKind.CANNOT_RESOLVE,
4885 {'name': name});
4886 } else if (element.isErroneous) {
4887 return element;
4888 } else if (element.isTypedef) {
4889 error(node, MessageKind.CANNOT_INSTANTIATE_TYPEDEF,
4890 {'typedefName': name});
4891 } else if (element.isTypeVariable) {
4892 error(node, MessageKind.CANNOT_INSTANTIATE_TYPE_VARIABLE,
4893 {'typeVariableName': name});
4894 } else if (!element.isClass && !element.isPrefix) {
4895 error(node, MessageKind.NOT_A_TYPE, {'node': name});
4896 }
4897 return element;
4898 }
4899
4900 /// Assumed to be called by [resolveRedirectingFactory].
4901 Element visitRedirectingFactoryBody(RedirectingFactoryBody node) {
4902 Node constructorReference = node.constructorReference;
4903 return finishConstructorReference(visit(constructorReference),
4904 constructorReference, node);
4905 }
4906 }
4907
4908 /// Looks up [name] in [scope] and unwraps the result.
4909 Element lookupInScope(Compiler compiler, Node node,
4910 Scope scope, String name) {
4911 return Elements.unwrap(scope.lookup(name), compiler, node);
4912 }
4913
4914 TreeElements _ensureTreeElements(AnalyzableElementX element) {
4915 if (element._treeElements == null) {
4916 element._treeElements = new TreeElementMapping(element);
4917 }
4918 return element._treeElements;
4919 }
4920
4921 abstract class AnalyzableElementX implements AnalyzableElement {
4922 TreeElements _treeElements;
4923
4924 bool get hasTreeElements => _treeElements != null;
4925
4926 TreeElements get treeElements {
4927 assert(invariant(this, _treeElements !=null,
4928 message: "TreeElements have not been computed for $this."));
4929 return _treeElements;
4930 }
4931
4932 void reuseElement() {
4933 _treeElements = null;
4934 }
4935 }
4936
4937 /// The result of resolving a node.
4938 abstract class ResolutionResult {
4939 Element get element;
4940 }
4941
4942 /// The result for the resolution of a node that points to an [Element].
4943 class ElementResult implements ResolutionResult {
4944 final Element element;
4945
4946 // TODO(johnniwinther): Remove this factory constructor when `null` is never
4947 // passed as an element result.
4948 factory ElementResult(Element element) {
4949 return element != null ? new ElementResult.internal(element) : null;
4950 }
4951
4952 ElementResult.internal(this.element);
4953
4954 String toString() => 'ElementResult($element)';
4955 }
4956
4957 /// The result for the resolution of a node that points to an [DartType].
4958 class TypeResult implements ResolutionResult {
4959 final DartType type;
4960
4961 TypeResult(this.type) {
4962 assert(type != null);
4963 }
4964
4965 Element get element => type.element;
4966
4967 String toString() => 'TypeResult($type)';
4968 }
4969
4970 /// The result for the resolution of the `assert` method.
4971 class AssertResult implements ResolutionResult {
4972 const AssertResult();
4973
4974 Element get element => null;
4975
4976 String toString() => 'AssertResult()';
4977 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698