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

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

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

Powered by Google App Engine
This is Rietveld 408576698