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

Side by Side Diff: pkg/compiler/lib/src/resolution/resolution_common.dart

Issue 1152963003: Split resolution/members.dart into several parts. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of resolution; 5 part of resolution;
6 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 SendStructure getSendStructure(Send send);
22
23 // TODO(johnniwinther): Investigate whether [Node] could be a [Send].
24 Selector getSelector(Node node);
25 Selector getGetterSelectorInComplexSendSet(SendSet node);
26 Selector getOperatorSelectorInComplexSendSet(SendSet node);
27 DartType getType(Node node);
28 void setSelector(Node node, Selector selector);
29 void setGetterSelectorInComplexSendSet(SendSet node, Selector selector);
30 void setOperatorSelectorInComplexSendSet(SendSet node, Selector selector);
31
32 /// Returns the for-in loop variable for [node].
33 Element getForInVariable(ForIn node);
34 Selector getIteratorSelector(ForIn node);
35 Selector getMoveNextSelector(ForIn node);
36 Selector getCurrentSelector(ForIn node);
37 void setIteratorSelector(ForIn node, Selector selector);
38 void setMoveNextSelector(ForIn node, Selector selector);
39 void setCurrentSelector(ForIn node, Selector selector);
40 void setConstant(Node node, ConstantExpression constant);
41 ConstantExpression getConstant(Node node);
42 bool isAssert(Send send);
43
44 /// Returns the [FunctionElement] defined by [node].
45 FunctionElement getFunctionDefinition(FunctionExpression node);
46
47 /// Returns target constructor for the redirecting factory body [node].
48 ConstructorElement getRedirectingTargetConstructor(
49 RedirectingFactoryBody node);
50
51 /**
52 * Returns [:true:] if [node] is a type literal.
53 *
54 * Resolution marks this by setting the type on the node to be the
55 * type that the literal refers to.
56 */
57 bool isTypeLiteral(Send node);
58
59 /// Returns the type that the type literal [node] refers to.
60 DartType getTypeLiteralType(Send node);
61
62 /// Register additional dependencies required by [analyzedElement].
63 /// For example, elements that are used by a backend.
64 void registerDependency(Element element);
65
66 /// Returns a list of nodes that potentially mutate [element] anywhere in its
67 /// scope.
68 List<Node> getPotentialMutations(VariableElement element);
69
70 /// Returns a list of nodes that potentially mutate [element] in [node].
71 List<Node> getPotentialMutationsIn(Node node, VariableElement element);
72
73 /// Returns a list of nodes that potentially mutate [element] in a closure.
74 List<Node> getPotentialMutationsInClosure(VariableElement element);
75
76 /// Returns a list of nodes that access [element] within a closure in [node].
77 List<Node> getAccessesByClosureIn(Node node, VariableElement element);
78
79 /// Returns the jump target defined by [node].
80 JumpTarget getTargetDefinition(Node node);
81
82 /// Returns the jump target of the [node].
83 JumpTarget getTargetOf(GotoStatement node);
84
85 /// Returns the label defined by [node].
86 LabelDefinition getLabelDefinition(Label node);
87
88 /// Returns the label that [node] targets.
89 LabelDefinition getTargetLabel(GotoStatement node);
90 }
91
92 class TreeElementMapping implements TreeElements {
93 final AnalyzableElement analyzedElement;
94 Map<Spannable, Selector> _selectors;
95 Map<Node, DartType> _types;
96 Setlet<Node> _superUses;
97 Setlet<Element> _otherDependencies;
98 Map<Node, ConstantExpression> _constants;
99 Map<VariableElement, List<Node>> _potentiallyMutated;
100 Map<Node, Map<VariableElement, List<Node>>> _potentiallyMutatedIn;
101 Map<VariableElement, List<Node>> _potentiallyMutatedInClosure;
102 Map<Node, Map<VariableElement, List<Node>>> _accessedByClosureIn;
103 Setlet<Element> _elements;
104 Setlet<Send> _asserts;
105 Maplet<Send, SendStructure> _sendStructureMap;
106
107 /// Map from nodes to the targets they define.
108 Map<Node, JumpTarget> _definedTargets;
109
110 /// Map from goto statements to their targets.
111 Map<GotoStatement, JumpTarget> _usedTargets;
112
113 /// Map from labels to their label definition.
114 Map<Label, LabelDefinition> _definedLabels;
115
116 /// Map from labeled goto statements to the labels they target.
117 Map<GotoStatement, LabelDefinition> _targetLabels;
118
119 final int hashCode = ++_hashCodeCounter;
120 static int _hashCodeCounter = 0;
121
122 TreeElementMapping(this.analyzedElement);
123
124 operator []=(Node node, Element element) {
125 // TODO(johnniwinther): Simplify this invariant to use only declarations in
126 // [TreeElements].
127 assert(invariant(node, () {
128 if (!element.isErroneous && analyzedElement != null && element.isPatch) {
129 return analyzedElement.implementationLibrary.isPatch;
130 }
131 return true;
132 }));
133 // TODO(ahe): Investigate why the invariant below doesn't hold.
134 // assert(invariant(node,
135 // getTreeElement(node) == element ||
136 // getTreeElement(node) == null,
137 // message: '${getTreeElement(node)}; $element'));
138
139 if (_elements == null) {
140 _elements = new Setlet<Element>();
141 }
142 _elements.add(element);
143 setTreeElement(node, element);
144 }
145
146 operator [](Node node) => getTreeElement(node);
147
148 SendStructure getSendStructure(Send send) {
149 if (_sendStructureMap == null) return null;
150 return _sendStructureMap[send];
151 }
152
153 void setSendStructure(Send send, SendStructure sendStructure) {
154 if (_sendStructureMap == null) {
155 _sendStructureMap = new Maplet<Send, SendStructure>();
156 }
157 _sendStructureMap[send] = sendStructure;
158 }
159
160 void setType(Node node, DartType type) {
161 if (_types == null) {
162 _types = new Maplet<Node, DartType>();
163 }
164 _types[node] = type;
165 }
166
167 DartType getType(Node node) => _types != null ? _types[node] : null;
168
169 Iterable<Node> get superUses {
170 return _superUses != null ? _superUses : const <Node>[];
171 }
172
173 void addSuperUse(Node node) {
174 if (_superUses == null) {
175 _superUses = new Setlet<Node>();
176 }
177 _superUses.add(node);
178 }
179
180 Selector _getSelector(Spannable node) {
181 return _selectors != null ? _selectors[node] : null;
182 }
183
184 void _setSelector(Spannable node, Selector selector) {
185 if (_selectors == null) {
186 _selectors = new Maplet<Spannable, Selector>();
187 }
188 _selectors[node] = selector;
189 }
190
191 void setSelector(Node node, Selector selector) {
192 _setSelector(node, selector);
193 }
194
195 Selector getSelector(Node node) => _getSelector(node);
196
197 int getSelectorCount() => _selectors == null ? 0 : _selectors.length;
198
199 void setGetterSelectorInComplexSendSet(SendSet node, Selector selector) {
200 _setSelector(node.selector, selector);
201 }
202
203 Selector getGetterSelectorInComplexSendSet(SendSet node) {
204 return _getSelector(node.selector);
205 }
206
207 void setOperatorSelectorInComplexSendSet(SendSet node, Selector selector) {
208 _setSelector(node.assignmentOperator, selector);
209 }
210
211 Selector getOperatorSelectorInComplexSendSet(SendSet node) {
212 return _getSelector(node.assignmentOperator);
213 }
214
215 // The following methods set selectors on the "for in" node. Since
216 // we're using three selectors, we need to use children of the node,
217 // and we arbitrarily choose which ones.
218
219 void setIteratorSelector(ForIn node, Selector selector) {
220 _setSelector(node, selector);
221 }
222
223 Selector getIteratorSelector(ForIn node) {
224 return _getSelector(node);
225 }
226
227 void setMoveNextSelector(ForIn node, Selector selector) {
228 _setSelector(node.forToken, selector);
229 }
230
231 Selector getMoveNextSelector(ForIn node) {
232 return _getSelector(node.forToken);
233 }
234
235 void setCurrentSelector(ForIn node, Selector selector) {
236 _setSelector(node.inToken, selector);
237 }
238
239 Selector getCurrentSelector(ForIn node) {
240 return _getSelector(node.inToken);
241 }
242
243 Element getForInVariable(ForIn node) {
244 return this[node];
245 }
246
247 void setConstant(Node node, ConstantExpression constant) {
248 if (_constants == null) {
249 _constants = new Maplet<Node, ConstantExpression>();
250 }
251 _constants[node] = constant;
252 }
253
254 ConstantExpression getConstant(Node node) {
255 return _constants != null ? _constants[node] : null;
256 }
257
258 bool isTypeLiteral(Send node) {
259 return getType(node) != null;
260 }
261
262 DartType getTypeLiteralType(Send node) {
263 return getType(node);
264 }
265
266 void registerDependency(Element element) {
267 if (element == null) return;
268 if (_otherDependencies == null) {
269 _otherDependencies = new Setlet<Element>();
270 }
271 _otherDependencies.add(element.implementation);
272 }
273
274 Iterable<Element> get otherDependencies {
275 return _otherDependencies != null ? _otherDependencies : const <Element>[];
276 }
277
278 List<Node> getPotentialMutations(VariableElement element) {
279 if (_potentiallyMutated == null) return const <Node>[];
280 List<Node> mutations = _potentiallyMutated[element];
281 if (mutations == null) return const <Node>[];
282 return mutations;
283 }
284
285 void registerPotentialMutation(VariableElement element, Node mutationNode) {
286 if (_potentiallyMutated == null) {
287 _potentiallyMutated = new Maplet<VariableElement, List<Node>>();
288 }
289 _potentiallyMutated.putIfAbsent(element, () => <Node>[]).add(mutationNode);
290 }
291
292 List<Node> getPotentialMutationsIn(Node node, VariableElement element) {
293 if (_potentiallyMutatedIn == null) return const <Node>[];
294 Map<VariableElement, List<Node>> mutationsIn = _potentiallyMutatedIn[node];
295 if (mutationsIn == null) return const <Node>[];
296 List<Node> mutations = mutationsIn[element];
297 if (mutations == null) return const <Node>[];
298 return mutations;
299 }
300
301 void registerPotentialMutationIn(Node contextNode, VariableElement element,
302 Node mutationNode) {
303 if (_potentiallyMutatedIn == null) {
304 _potentiallyMutatedIn =
305 new Maplet<Node, Map<VariableElement, List<Node>>>();
306 }
307 Map<VariableElement, List<Node>> mutationMap =
308 _potentiallyMutatedIn.putIfAbsent(contextNode,
309 () => new Maplet<VariableElement, List<Node>>());
310 mutationMap.putIfAbsent(element, () => <Node>[]).add(mutationNode);
311 }
312
313 List<Node> getPotentialMutationsInClosure(VariableElement element) {
314 if (_potentiallyMutatedInClosure == null) return const <Node>[];
315 List<Node> mutations = _potentiallyMutatedInClosure[element];
316 if (mutations == null) return const <Node>[];
317 return mutations;
318 }
319
320 void registerPotentialMutationInClosure(VariableElement element,
321 Node mutationNode) {
322 if (_potentiallyMutatedInClosure == null) {
323 _potentiallyMutatedInClosure = new Maplet<VariableElement, List<Node>>();
324 }
325 _potentiallyMutatedInClosure.putIfAbsent(
326 element, () => <Node>[]).add(mutationNode);
327 }
328
329 List<Node> getAccessesByClosureIn(Node node, VariableElement element) {
330 if (_accessedByClosureIn == null) return const <Node>[];
331 Map<VariableElement, List<Node>> accessesIn = _accessedByClosureIn[node];
332 if (accessesIn == null) return const <Node>[];
333 List<Node> accesses = accessesIn[element];
334 if (accesses == null) return const <Node>[];
335 return accesses;
336 }
337
338 void setAccessedByClosureIn(Node contextNode, VariableElement element,
339 Node accessNode) {
340 if (_accessedByClosureIn == null) {
341 _accessedByClosureIn = new Map<Node, Map<VariableElement, List<Node>>>();
342 }
343 Map<VariableElement, List<Node>> accessMap =
344 _accessedByClosureIn.putIfAbsent(contextNode,
345 () => new Maplet<VariableElement, List<Node>>());
346 accessMap.putIfAbsent(element, () => <Node>[]).add(accessNode);
347 }
348
349 String toString() => 'TreeElementMapping($analyzedElement)';
350
351 Iterable<Element> get allElements {
352 return _elements != null ? _elements : const <Element>[];
353 }
354
355 void forEachConstantNode(f(Node n, ConstantExpression c)) {
356 if (_constants != null) {
357 _constants.forEach(f);
358 }
359 }
360
361 void setAssert(Send node) {
362 if (_asserts == null) {
363 _asserts = new Setlet<Send>();
364 }
365 _asserts.add(node);
366 }
367
368 bool isAssert(Send node) {
369 return _asserts != null && _asserts.contains(node);
370 }
371
372 FunctionElement getFunctionDefinition(FunctionExpression node) {
373 return this[node];
374 }
375
376 ConstructorElement getRedirectingTargetConstructor(
377 RedirectingFactoryBody node) {
378 return this[node];
379 }
380
381 void defineTarget(Node node, JumpTarget target) {
382 if (_definedTargets == null) {
383 _definedTargets = new Maplet<Node, JumpTarget>();
384 }
385 _definedTargets[node] = target;
386 }
387
388 void undefineTarget(Node node) {
389 if (_definedTargets != null) {
390 _definedTargets.remove(node);
391 if (_definedTargets.isEmpty) {
392 _definedTargets = null;
393 }
394 }
395 }
396
397 JumpTarget getTargetDefinition(Node node) {
398 return _definedTargets != null ? _definedTargets[node] : null;
399 }
400
401 void registerTargetOf(GotoStatement node, JumpTarget target) {
402 if (_usedTargets == null) {
403 _usedTargets = new Maplet<GotoStatement, JumpTarget>();
404 }
405 _usedTargets[node] = target;
406 }
407
408 JumpTarget getTargetOf(GotoStatement node) {
409 return _usedTargets != null ? _usedTargets[node] : null;
410 }
411
412 void defineLabel(Label label, LabelDefinition target) {
413 if (_definedLabels == null) {
414 _definedLabels = new Maplet<Label, LabelDefinition>();
415 }
416 _definedLabels[label] = target;
417 }
418
419 void undefineLabel(Label label) {
420 if (_definedLabels != null) {
421 _definedLabels.remove(label);
422 if (_definedLabels.isEmpty) {
423 _definedLabels = null;
424 }
425 }
426 }
427
428 LabelDefinition getLabelDefinition(Label label) {
429 return _definedLabels != null ? _definedLabels[label] : null;
430 }
431
432 void registerTargetLabel(GotoStatement node, LabelDefinition label) {
433 assert(node.target != null);
434 if (_targetLabels == null) {
435 _targetLabels = new Maplet<GotoStatement, LabelDefinition>();
436 }
437 _targetLabels[node] = label;
438 }
439
440 LabelDefinition getTargetLabel(GotoStatement node) {
441 assert(node.target != null);
442 return _targetLabels != null ? _targetLabels[node] : null;
443 }
444 }
445
446 class ResolverTask extends CompilerTask { 7 class ResolverTask extends CompilerTask {
447 final ConstantCompiler constantCompiler; 8 final ConstantCompiler constantCompiler;
448 9
449 ResolverTask(Compiler compiler, this.constantCompiler) : super(compiler); 10 ResolverTask(Compiler compiler, this.constantCompiler) : super(compiler);
450 11
451 String get name => 'Resolver'; 12 String get name => 'Resolver';
452 13
453 TreeElements resolve(Element element) { 14 TreeElements resolve(Element element) {
454 return measure(() { 15 return measure(() {
455 if (Elements.isErroneous(element)) return null; 16 if (Elements.isErroneous(element)) return null;
(...skipping 933 matching lines...) Expand 10 before | Expand all | Expand 10 after
1389 for (Metadata annotation in node.metadata.nodes) { 950 for (Metadata annotation in node.metadata.nodes) {
1390 ParameterMetadataAnnotation metadataAnnotation = 951 ParameterMetadataAnnotation metadataAnnotation =
1391 new ParameterMetadataAnnotation(annotation); 952 new ParameterMetadataAnnotation(annotation);
1392 metadataAnnotation.annotatedElement = element; 953 metadataAnnotation.annotatedElement = element;
1393 metadata.addLast(metadataAnnotation.ensureResolved(compiler)); 954 metadata.addLast(metadataAnnotation.ensureResolved(compiler));
1394 } 955 }
1395 return metadata.toLink(); 956 return metadata.toLink();
1396 } 957 }
1397 } 958 }
1398 959
1399 class InitializerResolver {
1400 final ResolverVisitor visitor;
1401 final Map<Element, Node> initialized;
1402 Link<Node> initializers;
1403 bool hasSuper;
1404
1405 InitializerResolver(this.visitor)
1406 : initialized = new Map<Element, Node>(), hasSuper = false;
1407
1408 ResolutionRegistry get registry => visitor.registry;
1409
1410 error(Node node, MessageKind kind, [arguments = const {}]) {
1411 visitor.error(node, kind, arguments);
1412 }
1413
1414 warning(Node node, MessageKind kind, [arguments = const {}]) {
1415 visitor.warning(node, kind, arguments);
1416 }
1417
1418 bool isFieldInitializer(SendSet node) {
1419 if (node.selector.asIdentifier() == null) return false;
1420 if (node.receiver == null) return true;
1421 if (node.receiver.asIdentifier() == null) return false;
1422 return node.receiver.asIdentifier().isThis();
1423 }
1424
1425 reportDuplicateInitializerError(Element field, Node init, Node existing) {
1426 visitor.compiler.reportError(
1427 init,
1428 MessageKind.DUPLICATE_INITIALIZER, {'fieldName': field.name});
1429 visitor.compiler.reportInfo(
1430 existing,
1431 MessageKind.ALREADY_INITIALIZED, {'fieldName': field.name});
1432 }
1433
1434 void checkForDuplicateInitializers(FieldElementX field, Node init) {
1435 // [field] can be null if it could not be resolved.
1436 if (field == null) return;
1437 String name = field.name;
1438 if (initialized.containsKey(field)) {
1439 reportDuplicateInitializerError(field, init, initialized[field]);
1440 } else if (field.isFinal) {
1441 field.parseNode(visitor.compiler);
1442 Expression initializer = field.initializer;
1443 if (initializer != null) {
1444 reportDuplicateInitializerError(field, init, initializer);
1445 }
1446 }
1447 initialized[field] = init;
1448 }
1449
1450 void resolveFieldInitializer(FunctionElement constructor, SendSet init) {
1451 // init is of the form [this.]field = value.
1452 final Node selector = init.selector;
1453 final String name = selector.asIdentifier().source;
1454 // Lookup target field.
1455 Element target;
1456 if (isFieldInitializer(init)) {
1457 target = constructor.enclosingClass.lookupLocalMember(name);
1458 if (target == null) {
1459 error(selector, MessageKind.CANNOT_RESOLVE, {'name': name});
1460 target = new ErroneousFieldElementX(
1461 selector.asIdentifier(), constructor.enclosingClass);
1462 } else if (target.kind != ElementKind.FIELD) {
1463 error(selector, MessageKind.NOT_A_FIELD, {'fieldName': name});
1464 target = new ErroneousFieldElementX(
1465 selector.asIdentifier(), constructor.enclosingClass);
1466 } else if (!target.isInstanceMember) {
1467 error(selector, MessageKind.INIT_STATIC_FIELD, {'fieldName': name});
1468 }
1469 } else {
1470 error(init, MessageKind.INVALID_RECEIVER_IN_INITIALIZER);
1471 }
1472 registry.useElement(init, target);
1473 registry.registerStaticUse(target);
1474 checkForDuplicateInitializers(target, init);
1475 // Resolve initializing value.
1476 visitor.visitInStaticContext(init.arguments.head);
1477 }
1478
1479 ClassElement getSuperOrThisLookupTarget(FunctionElement constructor,
1480 bool isSuperCall,
1481 Node diagnosticNode) {
1482 ClassElement lookupTarget = constructor.enclosingClass;
1483 if (isSuperCall) {
1484 // Calculate correct lookup target and constructor name.
1485 if (identical(lookupTarget, visitor.compiler.objectClass)) {
1486 error(diagnosticNode, MessageKind.SUPER_INITIALIZER_IN_OBJECT);
1487 } else {
1488 return lookupTarget.supertype.element;
1489 }
1490 }
1491 return lookupTarget;
1492 }
1493
1494 Element resolveSuperOrThisForSend(FunctionElement constructor,
1495 FunctionExpression functionNode,
1496 Send call) {
1497 // Resolve the selector and the arguments.
1498 ResolverTask resolver = visitor.compiler.resolver;
1499 visitor.inStaticContext(() {
1500 visitor.resolveSelector(call, null);
1501 visitor.resolveArguments(call.argumentsNode);
1502 });
1503 Selector selector = registry.getSelector(call);
1504 bool isSuperCall = Initializers.isSuperConstructorCall(call);
1505
1506 ClassElement lookupTarget = getSuperOrThisLookupTarget(constructor,
1507 isSuperCall,
1508 call);
1509 Selector constructorSelector =
1510 visitor.getRedirectingThisOrSuperConstructorSelector(call);
1511 FunctionElement calledConstructor =
1512 lookupTarget.lookupConstructor(constructorSelector.name);
1513
1514 final bool isImplicitSuperCall = false;
1515 final String className = lookupTarget.name;
1516 verifyThatConstructorMatchesCall(constructor,
1517 calledConstructor,
1518 selector.callStructure,
1519 isImplicitSuperCall,
1520 call,
1521 className,
1522 constructorSelector);
1523
1524 registry.useElement(call, calledConstructor);
1525 registry.registerStaticUse(calledConstructor);
1526 return calledConstructor;
1527 }
1528
1529 void resolveImplicitSuperConstructorSend(FunctionElement constructor,
1530 FunctionExpression functionNode) {
1531 // If the class has a super resolve the implicit super call.
1532 ClassElement classElement = constructor.enclosingClass;
1533 ClassElement superClass = classElement.superclass;
1534 if (classElement != visitor.compiler.objectClass) {
1535 assert(superClass != null);
1536 assert(superClass.resolutionState == STATE_DONE);
1537
1538 final bool isSuperCall = true;
1539 ClassElement lookupTarget = getSuperOrThisLookupTarget(constructor,
1540 isSuperCall,
1541 functionNode);
1542 Selector constructorSelector = new Selector.callDefaultConstructor();
1543 Element calledConstructor = lookupTarget.lookupConstructor(
1544 constructorSelector.name);
1545
1546 final String className = lookupTarget.name;
1547 final bool isImplicitSuperCall = true;
1548 verifyThatConstructorMatchesCall(constructor,
1549 calledConstructor,
1550 CallStructure.NO_ARGS,
1551 isImplicitSuperCall,
1552 functionNode,
1553 className,
1554 constructorSelector);
1555 registry.registerImplicitSuperCall(calledConstructor);
1556 registry.registerStaticUse(calledConstructor);
1557 }
1558 }
1559
1560 void verifyThatConstructorMatchesCall(
1561 FunctionElement caller,
1562 ConstructorElementX lookedupConstructor,
1563 CallStructure call,
1564 bool isImplicitSuperCall,
1565 Node diagnosticNode,
1566 String className,
1567 Selector constructorSelector) {
1568 if (lookedupConstructor == null
1569 || !lookedupConstructor.isGenerativeConstructor) {
1570 String fullConstructorName = Elements.constructorNameForDiagnostics(
1571 className,
1572 constructorSelector.name);
1573 MessageKind kind = isImplicitSuperCall
1574 ? MessageKind.CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT
1575 : MessageKind.CANNOT_RESOLVE_CONSTRUCTOR;
1576 visitor.compiler.reportError(
1577 diagnosticNode, kind, {'constructorName': fullConstructorName});
1578 } else {
1579 lookedupConstructor.computeSignature(visitor.compiler);
1580 if (!call.signatureApplies(lookedupConstructor)) {
1581 MessageKind kind = isImplicitSuperCall
1582 ? MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT
1583 : MessageKind.NO_MATCHING_CONSTRUCTOR;
1584 visitor.compiler.reportError(diagnosticNode, kind);
1585 } else if (caller.isConst
1586 && !lookedupConstructor.isConst) {
1587 visitor.compiler.reportError(
1588 diagnosticNode, MessageKind.CONST_CALLS_NON_CONST);
1589 }
1590 }
1591 }
1592
1593 /**
1594 * Resolve all initializers of this constructor. In the case of a redirecting
1595 * constructor, the resolved constructor's function element is returned.
1596 */
1597 ConstructorElement resolveInitializers(ConstructorElementX constructor,
1598 FunctionExpression functionNode) {
1599 // Keep track of all "this.param" parameters specified for constructor so
1600 // that we can ensure that fields are initialized only once.
1601 FunctionSignature functionParameters = constructor.functionSignature;
1602 functionParameters.forEachParameter((ParameterElement element) {
1603 if (element.isInitializingFormal) {
1604 InitializingFormalElement initializingFormal = element;
1605 checkForDuplicateInitializers(initializingFormal.fieldElement,
1606 element.initializer);
1607 }
1608 });
1609
1610 if (functionNode.initializers == null) {
1611 initializers = const Link<Node>();
1612 } else {
1613 initializers = functionNode.initializers.nodes;
1614 }
1615 bool resolvedSuper = false;
1616 for (Link<Node> link = initializers; !link.isEmpty; link = link.tail) {
1617 if (link.head.asSendSet() != null) {
1618 final SendSet init = link.head.asSendSet();
1619 resolveFieldInitializer(constructor, init);
1620 } else if (link.head.asSend() != null) {
1621 final Send call = link.head.asSend();
1622 if (call.argumentsNode == null) {
1623 error(link.head, MessageKind.INVALID_INITIALIZER);
1624 continue;
1625 }
1626 if (Initializers.isSuperConstructorCall(call)) {
1627 if (resolvedSuper) {
1628 error(call, MessageKind.DUPLICATE_SUPER_INITIALIZER);
1629 }
1630 resolveSuperOrThisForSend(constructor, functionNode, call);
1631 resolvedSuper = true;
1632 } else if (Initializers.isConstructorRedirect(call)) {
1633 // Check that there is no body (Language specification 7.5.1). If the
1634 // constructor is also const, we already reported an error in
1635 // [resolveMethodElement].
1636 if (functionNode.hasBody() && !constructor.isConst) {
1637 error(functionNode, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_BODY);
1638 }
1639 // Check that there are no other initializers.
1640 if (!initializers.tail.isEmpty) {
1641 error(call, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER);
1642 } else {
1643 constructor.isRedirectingGenerative = true;
1644 }
1645 // Check that there are no field initializing parameters.
1646 Compiler compiler = visitor.compiler;
1647 FunctionSignature signature = constructor.functionSignature;
1648 signature.forEachParameter((ParameterElement parameter) {
1649 if (parameter.isInitializingFormal) {
1650 Node node = parameter.node;
1651 error(node, MessageKind.INITIALIZING_FORMAL_NOT_ALLOWED);
1652 }
1653 });
1654 return resolveSuperOrThisForSend(constructor, functionNode, call);
1655 } else {
1656 visitor.error(call, MessageKind.CONSTRUCTOR_CALL_EXPECTED);
1657 return null;
1658 }
1659 } else {
1660 error(link.head, MessageKind.INVALID_INITIALIZER);
1661 }
1662 }
1663 if (!resolvedSuper) {
1664 resolveImplicitSuperConstructorSend(constructor, functionNode);
1665 }
1666 return null; // If there was no redirection always return null.
1667 }
1668 }
1669
1670 class CommonResolverVisitor<R> extends Visitor<R> { 960 class CommonResolverVisitor<R> extends Visitor<R> {
1671 final Compiler compiler; 961 final Compiler compiler;
1672 962
1673 CommonResolverVisitor(Compiler this.compiler); 963 CommonResolverVisitor(Compiler this.compiler);
1674 964
1675 R visitNode(Node node) { 965 R visitNode(Node node) {
1676 internalError(node, 966 internalError(node,
1677 'internal error: Unhandled node: ${node.getObjectDescription()}'); 967 'internal error: Unhandled node: ${node.getObjectDescription()}');
1678 return null; 968 return null;
1679 } 969 }
(...skipping 13 matching lines...) Expand all
1693 983
1694 void internalError(Spannable node, message) { 984 void internalError(Spannable node, message) {
1695 compiler.internalError(node, message); 985 compiler.internalError(node, message);
1696 } 986 }
1697 987
1698 void addDeferredAction(Element element, DeferredAction action) { 988 void addDeferredAction(Element element, DeferredAction action) {
1699 compiler.enqueuer.resolution.addDeferredAction(element, action); 989 compiler.enqueuer.resolution.addDeferredAction(element, action);
1700 } 990 }
1701 } 991 }
1702 992
1703 abstract class LabelScope {
1704 LabelScope get outer;
1705 LabelDefinition lookup(String label);
1706 }
1707
1708 class LabeledStatementLabelScope implements LabelScope {
1709 final LabelScope outer;
1710 final Map<String, LabelDefinition> labels;
1711 LabeledStatementLabelScope(this.outer, this.labels);
1712 LabelDefinition lookup(String labelName) {
1713 LabelDefinition label = labels[labelName];
1714 if (label != null) return label;
1715 return outer.lookup(labelName);
1716 }
1717 }
1718
1719 class SwitchLabelScope implements LabelScope {
1720 final LabelScope outer;
1721 final Map<String, LabelDefinition> caseLabels;
1722
1723 SwitchLabelScope(this.outer, this.caseLabels);
1724
1725 LabelDefinition lookup(String labelName) {
1726 LabelDefinition result = caseLabels[labelName];
1727 if (result != null) return result;
1728 return outer.lookup(labelName);
1729 }
1730 }
1731
1732 class EmptyLabelScope implements LabelScope {
1733 const EmptyLabelScope();
1734 LabelDefinition lookup(String label) => null;
1735 LabelScope get outer {
1736 throw 'internal error: empty label scope has no outer';
1737 }
1738 }
1739
1740 class StatementScope {
1741 LabelScope labels;
1742 Link<JumpTarget> breakTargetStack;
1743 Link<JumpTarget> continueTargetStack;
1744 // Used to provide different numbers to statements if one is inside the other.
1745 // Can be used to make otherwise duplicate labels unique.
1746 int nestingLevel = 0;
1747
1748 StatementScope()
1749 : labels = const EmptyLabelScope(),
1750 breakTargetStack = const Link<JumpTarget>(),
1751 continueTargetStack = const Link<JumpTarget>();
1752
1753 LabelDefinition lookupLabel(String label) {
1754 return labels.lookup(label);
1755 }
1756
1757 JumpTarget currentBreakTarget() =>
1758 breakTargetStack.isEmpty ? null : breakTargetStack.head;
1759
1760 JumpTarget currentContinueTarget() =>
1761 continueTargetStack.isEmpty ? null : continueTargetStack.head;
1762
1763 void enterLabelScope(Map<String, LabelDefinition> elements) {
1764 labels = new LabeledStatementLabelScope(labels, elements);
1765 nestingLevel++;
1766 }
1767
1768 void exitLabelScope() {
1769 nestingLevel--;
1770 labels = labels.outer;
1771 }
1772
1773 void enterLoop(JumpTarget element) {
1774 breakTargetStack = breakTargetStack.prepend(element);
1775 continueTargetStack = continueTargetStack.prepend(element);
1776 nestingLevel++;
1777 }
1778
1779 void exitLoop() {
1780 nestingLevel--;
1781 breakTargetStack = breakTargetStack.tail;
1782 continueTargetStack = continueTargetStack.tail;
1783 }
1784
1785 void enterSwitch(JumpTarget breakElement,
1786 Map<String, LabelDefinition> continueElements) {
1787 breakTargetStack = breakTargetStack.prepend(breakElement);
1788 labels = new SwitchLabelScope(labels, continueElements);
1789 nestingLevel++;
1790 }
1791
1792 void exitSwitch() {
1793 nestingLevel--;
1794 breakTargetStack = breakTargetStack.tail;
1795 labels = labels.outer;
1796 }
1797 }
1798
1799 class TypeResolver {
1800 final Compiler compiler;
1801
1802 TypeResolver(this.compiler);
1803
1804 /// Tries to resolve the type name as an element.
1805 Element resolveTypeName(Identifier prefixName,
1806 Identifier typeName,
1807 Scope scope,
1808 {bool deferredIsMalformed: true}) {
1809 Element element;
1810 bool deferredTypeAnnotation = false;
1811 if (prefixName != null) {
1812 Element prefixElement =
1813 lookupInScope(compiler, prefixName, scope, prefixName.source);
1814 if (prefixElement != null && prefixElement.isPrefix) {
1815 // The receiver is a prefix. Lookup in the imported members.
1816 PrefixElement prefix = prefixElement;
1817 element = prefix.lookupLocalMember(typeName.source);
1818 // TODO(17260, sigurdm): The test for DartBackend is there because
1819 // dart2dart outputs malformed types with prefix.
1820 if (element != null &&
1821 prefix.isDeferred &&
1822 deferredIsMalformed &&
1823 compiler.backend is! DartBackend) {
1824 element = new ErroneousElementX(MessageKind.DEFERRED_TYPE_ANNOTATION,
1825 {'node': typeName},
1826 element.name,
1827 element);
1828 }
1829 } else {
1830 // The caller of this method will create the ErroneousElement for
1831 // the MalformedType.
1832 element = null;
1833 }
1834 } else {
1835 String stringValue = typeName.source;
1836 element = lookupInScope(compiler, typeName, scope, typeName.source);
1837 }
1838 return element;
1839 }
1840
1841 DartType resolveTypeAnnotation(MappingVisitor visitor, TypeAnnotation node,
1842 {bool malformedIsError: false,
1843 bool deferredIsMalformed: true}) {
1844 ResolutionRegistry registry = visitor.registry;
1845
1846 Identifier typeName;
1847 DartType type;
1848
1849 DartType checkNoTypeArguments(DartType type) {
1850 List<DartType> arguments = new List<DartType>();
1851 bool hasTypeArgumentMismatch = resolveTypeArguments(
1852 visitor, node, const <DartType>[], arguments);
1853 if (hasTypeArgumentMismatch) {
1854 return new MalformedType(
1855 new ErroneousElementX(MessageKind.TYPE_ARGUMENT_COUNT_MISMATCH,
1856 {'type': node}, typeName.source, visitor.enclosingElement),
1857 type, arguments);
1858 }
1859 return type;
1860 }
1861
1862 Identifier prefixName;
1863 Send send = node.typeName.asSend();
1864 if (send != null) {
1865 // The type name is of the form [: prefix . identifier :].
1866 prefixName = send.receiver.asIdentifier();
1867 typeName = send.selector.asIdentifier();
1868 } else {
1869 typeName = node.typeName.asIdentifier();
1870 if (identical(typeName.source, 'void')) {
1871 type = const VoidType();
1872 checkNoTypeArguments(type);
1873 registry.useType(node, type);
1874 return type;
1875 } else if (identical(typeName.source, 'dynamic')) {
1876 type = const DynamicType();
1877 checkNoTypeArguments(type);
1878 registry.useType(node, type);
1879 return type;
1880 }
1881 }
1882
1883 Element element = resolveTypeName(prefixName, typeName, visitor.scope,
1884 deferredIsMalformed: deferredIsMalformed);
1885
1886 DartType reportFailureAndCreateType(MessageKind messageKind,
1887 Map messageArguments,
1888 {DartType userProvidedBadType,
1889 Element erroneousElement}) {
1890 if (malformedIsError) {
1891 visitor.error(node, messageKind, messageArguments);
1892 } else {
1893 registry.registerThrowRuntimeError();
1894 visitor.warning(node, messageKind, messageArguments);
1895 }
1896 if (erroneousElement == null) {
1897 registry.registerThrowRuntimeError();
1898 erroneousElement = new ErroneousElementX(
1899 messageKind, messageArguments, typeName.source,
1900 visitor.enclosingElement);
1901 }
1902 List<DartType> arguments = <DartType>[];
1903 resolveTypeArguments(visitor, node, const <DartType>[], arguments);
1904 return new MalformedType(erroneousElement,
1905 userProvidedBadType, arguments);
1906 }
1907
1908 // Try to construct the type from the element.
1909 if (element == null) {
1910 type = reportFailureAndCreateType(
1911 MessageKind.CANNOT_RESOLVE_TYPE, {'typeName': node.typeName});
1912 } else if (element.isAmbiguous) {
1913 AmbiguousElement ambiguous = element;
1914 type = reportFailureAndCreateType(
1915 ambiguous.messageKind, ambiguous.messageArguments);
1916 ambiguous.diagnose(registry.mapping.analyzedElement, compiler);
1917 } else if (element.isErroneous) {
1918 if (element is ErroneousElement) {
1919 type = reportFailureAndCreateType(
1920 element.messageKind, element.messageArguments,
1921 erroneousElement: element);
1922 } else {
1923 type = const DynamicType();
1924 }
1925 } else if (!element.impliesType) {
1926 type = reportFailureAndCreateType(
1927 MessageKind.NOT_A_TYPE, {'node': node.typeName});
1928 } else {
1929 bool addTypeVariableBoundsCheck = false;
1930 if (element.isClass) {
1931 ClassElement cls = element;
1932 // TODO(johnniwinther): [_ensureClassWillBeResolved] should imply
1933 // [computeType].
1934 compiler.resolver._ensureClassWillBeResolved(cls);
1935 element.computeType(compiler);
1936 List<DartType> arguments = <DartType>[];
1937 bool hasTypeArgumentMismatch = resolveTypeArguments(
1938 visitor, node, cls.typeVariables, arguments);
1939 if (hasTypeArgumentMismatch) {
1940 type = new BadInterfaceType(cls.declaration,
1941 new InterfaceType.forUserProvidedBadType(cls.declaration,
1942 arguments));
1943 } else {
1944 if (arguments.isEmpty) {
1945 type = cls.rawType;
1946 } else {
1947 type = new InterfaceType(cls.declaration, arguments.toList(growable: false));
1948 addTypeVariableBoundsCheck = true;
1949 }
1950 }
1951 } else if (element.isTypedef) {
1952 TypedefElement typdef = element;
1953 // TODO(johnniwinther): [ensureResolved] should imply [computeType].
1954 typdef.ensureResolved(compiler);
1955 element.computeType(compiler);
1956 List<DartType> arguments = <DartType>[];
1957 bool hasTypeArgumentMismatch = resolveTypeArguments(
1958 visitor, node, typdef.typeVariables, arguments);
1959 if (hasTypeArgumentMismatch) {
1960 type = new BadTypedefType(typdef,
1961 new TypedefType.forUserProvidedBadType(typdef, arguments));
1962 } else {
1963 if (arguments.isEmpty) {
1964 type = typdef.rawType;
1965 } else {
1966 type = new TypedefType(typdef, arguments.toList(growable: false));
1967 addTypeVariableBoundsCheck = true;
1968 }
1969 }
1970 } else if (element.isTypeVariable) {
1971 Element outer =
1972 visitor.enclosingElement.outermostEnclosingMemberOrTopLevel;
1973 bool isInFactoryConstructor =
1974 outer != null && outer.isFactoryConstructor;
1975 if (!outer.isClass &&
1976 !outer.isTypedef &&
1977 !Elements.hasAccessToTypeVariables(visitor.enclosingElement)) {
1978 registry.registerThrowRuntimeError();
1979 type = reportFailureAndCreateType(
1980 MessageKind.TYPE_VARIABLE_WITHIN_STATIC_MEMBER,
1981 {'typeVariableName': node},
1982 userProvidedBadType: element.computeType(compiler));
1983 } else {
1984 type = element.computeType(compiler);
1985 }
1986 type = checkNoTypeArguments(type);
1987 } else {
1988 compiler.internalError(node,
1989 "Unexpected element kind ${element.kind}.");
1990 }
1991 if (addTypeVariableBoundsCheck) {
1992 registry.registerTypeVariableBoundCheck();
1993 visitor.addDeferredAction(
1994 visitor.enclosingElement,
1995 () => checkTypeVariableBounds(node, type));
1996 }
1997 }
1998 registry.useType(node, type);
1999 return type;
2000 }
2001
2002 /// Checks the type arguments of [type] against the type variable bounds.
2003 void checkTypeVariableBounds(TypeAnnotation node, GenericType type) {
2004 void checkTypeVariableBound(_, DartType typeArgument,
2005 TypeVariableType typeVariable,
2006 DartType bound) {
2007 if (!compiler.types.isSubtype(typeArgument, bound)) {
2008 compiler.reportWarning(node,
2009 MessageKind.INVALID_TYPE_VARIABLE_BOUND,
2010 {'typeVariable': typeVariable,
2011 'bound': bound,
2012 'typeArgument': typeArgument,
2013 'thisType': type.element.thisType});
2014 }
2015 };
2016
2017 compiler.types.checkTypeVariableBounds(type, checkTypeVariableBound);
2018 }
2019
2020 /**
2021 * Resolves the type arguments of [node] and adds these to [arguments].
2022 *
2023 * Returns [: true :] if the number of type arguments did not match the
2024 * number of type variables.
2025 */
2026 bool resolveTypeArguments(MappingVisitor visitor,
2027 TypeAnnotation node,
2028 List<DartType> typeVariables,
2029 List<DartType> arguments) {
2030 if (node.typeArguments == null) {
2031 return false;
2032 }
2033 int expectedVariables = typeVariables.length;
2034 int index = 0;
2035 bool typeArgumentCountMismatch = false;
2036 for (Link<Node> typeArguments = node.typeArguments.nodes;
2037 !typeArguments.isEmpty;
2038 typeArguments = typeArguments.tail, index++) {
2039 if (index > expectedVariables - 1) {
2040 visitor.warning(
2041 typeArguments.head, MessageKind.ADDITIONAL_TYPE_ARGUMENT);
2042 typeArgumentCountMismatch = true;
2043 }
2044 DartType argType = resolveTypeAnnotation(visitor, typeArguments.head);
2045 // TODO(karlklose): rewrite to not modify [arguments].
2046 arguments.add(argType);
2047 }
2048 if (index < expectedVariables) {
2049 visitor.warning(node.typeArguments,
2050 MessageKind.MISSING_TYPE_ARGUMENT);
2051 typeArgumentCountMismatch = true;
2052 }
2053 return typeArgumentCountMismatch;
2054 }
2055 }
2056
2057 /** 993 /**
2058 * Common supertype for resolver visitors that record resolutions in a 994 * Common supertype for resolver visitors that record resolutions in a
2059 * [ResolutionRegistry]. 995 * [ResolutionRegistry].
2060 */ 996 */
2061 abstract class MappingVisitor<T> extends CommonResolverVisitor<T> { 997 abstract class MappingVisitor<T> extends CommonResolverVisitor<T> {
2062 final ResolutionRegistry registry; 998 final ResolutionRegistry registry;
2063 final TypeResolver typeResolver; 999 final TypeResolver typeResolver;
2064 /// The current enclosing element for the visited AST nodes. 1000 /// The current enclosing element for the visited AST nodes.
2065 Element get enclosingElement; 1001 Element get enclosingElement;
2066 /// The current scope of the visitor. 1002 /// The current scope of the visitor.
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
2104 1040
2105 void reportDuplicateDefinition(String name, 1041 void reportDuplicateDefinition(String name,
2106 Spannable definition, 1042 Spannable definition,
2107 Spannable existing) { 1043 Spannable existing) {
2108 compiler.reportError(definition, 1044 compiler.reportError(definition,
2109 MessageKind.DUPLICATE_DEFINITION, {'name': name}); 1045 MessageKind.DUPLICATE_DEFINITION, {'name': name});
2110 compiler.reportInfo(existing, 1046 compiler.reportInfo(existing,
2111 MessageKind.EXISTING_DEFINITION, {'name': name}); 1047 MessageKind.EXISTING_DEFINITION, {'name': name});
2112 } 1048 }
2113 } 1049 }
2114
2115 /**
2116 * Core implementation of resolution.
2117 *
2118 * Do not subclass or instantiate this class outside this library
2119 * except for testing.
2120 */
2121 class ResolverVisitor extends MappingVisitor<ResolutionResult> {
2122 /**
2123 * The current enclosing element for the visited AST nodes.
2124 *
2125 * This field is updated when nested closures are visited.
2126 */
2127 Element enclosingElement;
2128
2129 /// Whether we are in a context where `this` is accessible (this will be false
2130 /// in static contexts, factory methods, and field initializers).
2131 bool inInstanceContext;
2132 bool inCheckContext;
2133 bool inCatchBlock;
2134
2135 Scope scope;
2136 ClassElement currentClass;
2137 ExpressionStatement currentExpressionStatement;
2138 bool sendIsMemberAccess = false;
2139 StatementScope statementScope;
2140 int allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION
2141 | ElementCategory.IMPLIES_TYPE;
2142
2143 /**
2144 * Record of argument nodes to JS_INTERCEPTOR_CONSTANT for deferred
2145 * processing.
2146 */
2147 Set<Node> argumentsToJsInterceptorConstant = null;
2148
2149 /// When visiting the type declaration of the variable in a [ForIn] loop,
2150 /// the initializer of the variable is implicit and we should not emit an
2151 /// error when verifying that all final variables are initialized.
2152 bool allowFinalWithoutInitializer = false;
2153
2154 /// The nodes for which variable access and mutation must be registered in
2155 /// order to determine when the static type of variables types is promoted.
2156 Link<Node> promotionScope = const Link<Node>();
2157
2158 bool isPotentiallyMutableTarget(Element target) {
2159 if (target == null) return false;
2160 return (target.isVariable || target.isParameter) &&
2161 !(target.isFinal || target.isConst);
2162 }
2163
2164 // TODO(ahe): Find a way to share this with runtime implementation.
2165 static final RegExp symbolValidationPattern =
2166 new RegExp(r'^(?:[a-zA-Z$][a-zA-Z$0-9_]*\.)*(?:[a-zA-Z$][a-zA-Z$0-9_]*=?|'
2167 r'-|'
2168 r'unary-|'
2169 r'\[\]=|'
2170 r'~|'
2171 r'==|'
2172 r'\[\]|'
2173 r'\*|'
2174 r'/|'
2175 r'%|'
2176 r'~/|'
2177 r'\+|'
2178 r'<<|'
2179 r'>>|'
2180 r'>=|'
2181 r'>|'
2182 r'<=|'
2183 r'<|'
2184 r'&|'
2185 r'\^|'
2186 r'\|'
2187 r')$');
2188
2189 ResolverVisitor(Compiler compiler,
2190 Element element,
2191 ResolutionRegistry registry,
2192 {bool useEnclosingScope: false})
2193 : this.enclosingElement = element,
2194 // When the element is a field, we are actually resolving its
2195 // initial value, which should not have access to instance
2196 // fields.
2197 inInstanceContext = (element.isInstanceMember && !element.isField)
2198 || element.isGenerativeConstructor,
2199 this.currentClass = element.isClassMember ? element.enclosingClass
2200 : null,
2201 this.statementScope = new StatementScope(),
2202 scope = useEnclosingScope
2203 ? Scope.buildEnclosingScope(element) : element.buildScope(),
2204 // The type annotations on a typedef do not imply type checks.
2205 // TODO(karlklose): clean this up (dartbug.com/8870).
2206 inCheckContext = compiler.enableTypeAssertions &&
2207 !element.isLibrary &&
2208 !element.isTypedef &&
2209 !element.enclosingElement.isTypedef,
2210 inCatchBlock = false,
2211 super(compiler, registry);
2212
2213 AsyncMarker get currentAsyncMarker {
2214 if (enclosingElement is FunctionElement) {
2215 FunctionElement function = enclosingElement;
2216 return function.asyncMarker;
2217 }
2218 return AsyncMarker.SYNC;
2219 }
2220
2221 Element reportLookupErrorIfAny(Element result, Node node, String name) {
2222 if (!Elements.isUnresolved(result)) {
2223 if (!inInstanceContext && result.isInstanceMember) {
2224 compiler.reportError(
2225 node, MessageKind.NO_INSTANCE_AVAILABLE, {'name': name});
2226 return new ErroneousElementX(MessageKind.NO_INSTANCE_AVAILABLE,
2227 {'name': name},
2228 name, enclosingElement);
2229 } else if (result.isAmbiguous) {
2230 AmbiguousElement ambiguous = result;
2231 compiler.reportError(
2232 node, ambiguous.messageKind, ambiguous.messageArguments);
2233 ambiguous.diagnose(enclosingElement, compiler);
2234 return new ErroneousElementX(ambiguous.messageKind,
2235 ambiguous.messageArguments,
2236 name, enclosingElement);
2237 }
2238 }
2239 return result;
2240 }
2241
2242 // Create, or reuse an already created, target element for a statement.
2243 JumpTarget getOrDefineTarget(Node statement) {
2244 JumpTarget element = registry.getTargetDefinition(statement);
2245 if (element == null) {
2246 element = new JumpTargetX(statement,
2247 statementScope.nestingLevel,
2248 enclosingElement);
2249 registry.defineTarget(statement, element);
2250 }
2251 return element;
2252 }
2253
2254 doInCheckContext(action()) {
2255 bool wasInCheckContext = inCheckContext;
2256 inCheckContext = true;
2257 var result = action();
2258 inCheckContext = wasInCheckContext;
2259 return result;
2260 }
2261
2262 inStaticContext(action()) {
2263 bool wasInstanceContext = inInstanceContext;
2264 inInstanceContext = false;
2265 var result = action();
2266 inInstanceContext = wasInstanceContext;
2267 return result;
2268 }
2269
2270 doInPromotionScope(Node node, action()) {
2271 promotionScope = promotionScope.prepend(node);
2272 var result = action();
2273 promotionScope = promotionScope.tail;
2274 return result;
2275 }
2276
2277 visitInStaticContext(Node node) {
2278 inStaticContext(() => visit(node));
2279 }
2280
2281 ErroneousElement reportAndCreateErroneousElement(
2282 Node node,
2283 String name,
2284 MessageKind kind,
2285 Map arguments,
2286 {bool isError: false}) {
2287 if (isError) {
2288 compiler.reportError(node, kind, arguments);
2289 } else {
2290 compiler.reportWarning(node, kind, arguments);
2291 }
2292 // TODO(ahe): Use [allowedCategory] to synthesize a more precise subclass
2293 // of [ErroneousElementX]. For example, [ErroneousFieldElementX],
2294 // [ErroneousConstructorElementX], etc.
2295 return new ErroneousElementX(kind, arguments, name, enclosingElement);
2296 }
2297
2298 ResolutionResult visitIdentifier(Identifier node) {
2299 if (node.isThis()) {
2300 if (!inInstanceContext) {
2301 error(node, MessageKind.NO_INSTANCE_AVAILABLE, {'name': node});
2302 }
2303 return null;
2304 } else if (node.isSuper()) {
2305 if (!inInstanceContext) {
2306 error(node, MessageKind.NO_SUPER_IN_STATIC);
2307 }
2308 if ((ElementCategory.SUPER & allowedCategory) == 0) {
2309 error(node, MessageKind.INVALID_USE_OF_SUPER);
2310 }
2311 return null;
2312 } else {
2313 String name = node.source;
2314 Element element = lookupInScope(compiler, node, scope, name);
2315 if (Elements.isUnresolved(element) && name == 'dynamic') {
2316 // TODO(johnniwinther): Remove this hack when we can return more complex
2317 // objects than [Element] from this method.
2318 element = compiler.typeClass;
2319 // Set the type to be `dynamic` to mark that this is a type literal.
2320 registry.setType(node, const DynamicType());
2321 }
2322 element = reportLookupErrorIfAny(element, node, node.source);
2323 if (element == null) {
2324 if (!inInstanceContext) {
2325 // We report an error within initializers because `this` is implicitly
2326 // accessed when unqualified identifiers are not resolved. For
2327 // details, see section 16.14.3 of the spec (2nd edition):
2328 // An unqualified invocation `i` of the form `id(a1, ...)`
2329 // ...
2330 // If `i` does not occur inside a top level or static function, `i`
2331 // is equivalent to `this.id(a1 , ...)`.
2332 bool inInitializer = enclosingElement.isGenerativeConstructor ||
2333 (enclosingElement.isInstanceMember && enclosingElement.isField);
2334 MessageKind kind;
2335 Map arguments = {'name': name};
2336 if (inInitializer) {
2337 kind = MessageKind.CANNOT_RESOLVE_IN_INITIALIZER;
2338 } else if (name == 'await') {
2339 var functionName = enclosingElement.name;
2340 if (functionName == '') {
2341 kind = MessageKind.CANNOT_RESOLVE_AWAIT_IN_CLOSURE;
2342 } else {
2343 kind = MessageKind.CANNOT_RESOLVE_AWAIT;
2344 arguments['functionName'] = functionName;
2345 }
2346 } else {
2347 kind = MessageKind.CANNOT_RESOLVE;
2348 }
2349 element = reportAndCreateErroneousElement(node, name, kind,
2350 arguments, isError: inInitializer);
2351 registry.registerThrowNoSuchMethod();
2352 }
2353 } else if (element.isErroneous) {
2354 // Use the erroneous element.
2355 } else {
2356 if ((element.kind.category & allowedCategory) == 0) {
2357 element = reportAndCreateErroneousElement(
2358 node, name, MessageKind.GENERIC,
2359 // TODO(ahe): Improve error message. Need UX input.
2360 {'text': "is not an expression $element"});
2361 }
2362 }
2363 if (!Elements.isUnresolved(element) && element.isClass) {
2364 ClassElement classElement = element;
2365 classElement.ensureResolved(compiler);
2366 }
2367 return new ElementResult(registry.useElement(node, element));
2368 }
2369 }
2370
2371 ResolutionResult visitTypeAnnotation(TypeAnnotation node) {
2372 DartType type = resolveTypeAnnotation(node);
2373 if (inCheckContext) {
2374 registry.registerIsCheck(type);
2375 }
2376 return new TypeResult(type);
2377 }
2378
2379 bool isNamedConstructor(Send node) => node.receiver != null;
2380
2381 Selector getRedirectingThisOrSuperConstructorSelector(Send node) {
2382 if (isNamedConstructor(node)) {
2383 String constructorName = node.selector.asIdentifier().source;
2384 return new Selector.callConstructor(
2385 constructorName,
2386 enclosingElement.library);
2387 } else {
2388 return new Selector.callDefaultConstructor();
2389 }
2390 }
2391
2392 FunctionElement resolveConstructorRedirection(FunctionElementX constructor) {
2393 FunctionExpression node = constructor.parseNode(compiler);
2394
2395 // A synthetic constructor does not have a node.
2396 if (node == null) return null;
2397 if (node.initializers == null) return null;
2398 Link<Node> initializers = node.initializers.nodes;
2399 if (!initializers.isEmpty &&
2400 Initializers.isConstructorRedirect(initializers.head)) {
2401 Selector selector =
2402 getRedirectingThisOrSuperConstructorSelector(initializers.head);
2403 final ClassElement classElement = constructor.enclosingClass;
2404 return classElement.lookupConstructor(selector.name);
2405 }
2406 return null;
2407 }
2408
2409 void setupFunction(FunctionExpression node, FunctionElement function) {
2410 Element enclosingElement = function.enclosingElement;
2411 if (node.modifiers.isStatic &&
2412 enclosingElement.kind != ElementKind.CLASS) {
2413 compiler.reportError(node, MessageKind.ILLEGAL_STATIC);
2414 }
2415
2416 scope = new MethodScope(scope, function);
2417 // Put the parameters in scope.
2418 FunctionSignature functionParameters = function.functionSignature;
2419 Link<Node> parameterNodes = (node.parameters == null)
2420 ? const Link<Node>() : node.parameters.nodes;
2421 functionParameters.forEachParameter((ParameterElement element) {
2422 // TODO(karlklose): should be a list of [FormalElement]s, but the actual
2423 // implementation uses [Element].
2424 List<Element> optionals = functionParameters.optionalParameters;
2425 if (!optionals.isEmpty && element == optionals.first) {
2426 NodeList nodes = parameterNodes.head;
2427 parameterNodes = nodes.nodes;
2428 }
2429 visit(element.initializer);
2430 VariableDefinitions variableDefinitions = parameterNodes.head;
2431 Node parameterNode = variableDefinitions.definitions.nodes.head;
2432 // Field parameters (this.x) are not visible inside the constructor. The
2433 // fields they reference are visible, but must be resolved independently.
2434 if (element.isInitializingFormal) {
2435 registry.useElement(parameterNode, element);
2436 } else {
2437 LocalParameterElement parameterElement = element;
2438 defineLocalVariable(parameterNode, parameterElement);
2439 addToScope(parameterElement);
2440 }
2441 parameterNodes = parameterNodes.tail;
2442 });
2443 addDeferredAction(enclosingElement, () {
2444 functionParameters.forEachOptionalParameter(
2445 (ParameterElementX parameter) {
2446 parameter.constant =
2447 compiler.resolver.constantCompiler.compileConstant(parameter);
2448 });
2449 });
2450 if (inCheckContext) {
2451 functionParameters.forEachParameter((ParameterElement element) {
2452 registry.registerIsCheck(element.type);
2453 });
2454 }
2455 }
2456
2457 visitCascade(Cascade node) {
2458 visit(node.expression);
2459 }
2460
2461 visitCascadeReceiver(CascadeReceiver node) {
2462 visit(node.expression);
2463 }
2464
2465 visitClassNode(ClassNode node) {
2466 internalError(node, "shouldn't be called");
2467 }
2468
2469 visitIn(Node node, Scope nestedScope) {
2470 Scope oldScope = scope;
2471 scope = nestedScope;
2472 ResolutionResult result = visit(node);
2473 scope = oldScope;
2474 return result;
2475 }
2476
2477 /**
2478 * Introduces new default targets for break and continue
2479 * before visiting the body of the loop
2480 */
2481 visitLoopBodyIn(Loop loop, Node body, Scope bodyScope) {
2482 JumpTarget element = getOrDefineTarget(loop);
2483 statementScope.enterLoop(element);
2484 visitIn(body, bodyScope);
2485 statementScope.exitLoop();
2486 if (!element.isTarget) {
2487 registry.undefineTarget(loop);
2488 }
2489 }
2490
2491 visitBlock(Block node) {
2492 visitIn(node.statements, new BlockScope(scope));
2493 }
2494
2495 visitDoWhile(DoWhile node) {
2496 visitLoopBodyIn(node, node.body, new BlockScope(scope));
2497 visit(node.condition);
2498 }
2499
2500 visitEmptyStatement(EmptyStatement node) { }
2501
2502 visitExpressionStatement(ExpressionStatement node) {
2503 ExpressionStatement oldExpressionStatement = currentExpressionStatement;
2504 currentExpressionStatement = node;
2505 visit(node.expression);
2506 currentExpressionStatement = oldExpressionStatement;
2507 }
2508
2509 visitFor(For node) {
2510 Scope blockScope = new BlockScope(scope);
2511 visitIn(node.initializer, blockScope);
2512 visitIn(node.condition, blockScope);
2513 visitIn(node.update, blockScope);
2514 visitLoopBodyIn(node, node.body, blockScope);
2515 }
2516
2517 visitFunctionDeclaration(FunctionDeclaration node) {
2518 assert(node.function.name != null);
2519 visitFunctionExpression(node.function, inFunctionDeclaration: true);
2520 }
2521
2522
2523 /// Process a local function declaration or an anonymous function expression.
2524 ///
2525 /// [inFunctionDeclaration] is `true` when the current node is the immediate
2526 /// child of a function declaration.
2527 ///
2528 /// This is used to distinguish local function declarations from anonymous
2529 /// function expressions.
2530 visitFunctionExpression(FunctionExpression node,
2531 {bool inFunctionDeclaration: false}) {
2532 bool doAddToScope = inFunctionDeclaration;
2533 if (!inFunctionDeclaration && node.name != null) {
2534 compiler.reportError(
2535 node.name,
2536 MessageKind.NAMED_FUNCTION_EXPRESSION,
2537 {'name': node.name});
2538 }
2539 visit(node.returnType);
2540 String name;
2541 if (node.name == null) {
2542 name = "";
2543 } else {
2544 name = node.name.asIdentifier().source;
2545 }
2546 LocalFunctionElementX function = new LocalFunctionElementX(
2547 name, node, ElementKind.FUNCTION, Modifiers.EMPTY,
2548 enclosingElement);
2549 ResolverTask.processAsyncMarker(compiler, function, registry);
2550 function.functionSignatureCache = SignatureResolver.analyze(
2551 compiler,
2552 node.parameters,
2553 node.returnType,
2554 function,
2555 registry,
2556 createRealParameters: true,
2557 isFunctionExpression: !inFunctionDeclaration);
2558 checkLocalDefinitionName(node, function);
2559 registry.defineFunction(node, function);
2560 if (doAddToScope) {
2561 addToScope(function);
2562 }
2563 Scope oldScope = scope; // The scope is modified by [setupFunction].
2564 setupFunction(node, function);
2565
2566 Element previousEnclosingElement = enclosingElement;
2567 enclosingElement = function;
2568 // Run the body in a fresh statement scope.
2569 StatementScope oldStatementScope = statementScope;
2570 statementScope = new StatementScope();
2571 visit(node.body);
2572 statementScope = oldStatementScope;
2573
2574 scope = oldScope;
2575 enclosingElement = previousEnclosingElement;
2576
2577 registry.registerClosure(function);
2578 registry.registerInstantiatedClass(compiler.functionClass);
2579 }
2580
2581 visitIf(If node) {
2582 doInPromotionScope(node.condition.expression, () => visit(node.condition));
2583 doInPromotionScope(node.thenPart,
2584 () => visitIn(node.thenPart, new BlockScope(scope)));
2585 visitIn(node.elsePart, new BlockScope(scope));
2586 }
2587
2588 ResolutionResult resolveSend(Send node) {
2589 Selector selector = resolveSelector(node, null);
2590 if (node.isSuperCall) registry.registerSuperUse(node);
2591
2592 if (node.receiver == null) {
2593 // If this send is of the form "assert(expr);", then
2594 // this is an assertion.
2595 if (selector.isAssert) {
2596 SendStructure sendStructure = const AssertStructure();
2597 if (selector.argumentCount != 1) {
2598 error(node.selector,
2599 MessageKind.WRONG_NUMBER_OF_ARGUMENTS_FOR_ASSERT,
2600 {'argumentCount': selector.argumentCount});
2601 sendStructure = const InvalidAssertStructure();
2602 } else if (selector.namedArgumentCount != 0) {
2603 error(node.selector,
2604 MessageKind.ASSERT_IS_GIVEN_NAMED_ARGUMENTS,
2605 {'argumentCount': selector.namedArgumentCount});
2606 sendStructure = const InvalidAssertStructure();
2607 }
2608 registry.registerAssert(node);
2609 registry.registerSendStructure(node, sendStructure);
2610 return const AssertResult();
2611 }
2612
2613 return node.selector.accept(this);
2614 }
2615
2616 var oldCategory = allowedCategory;
2617 allowedCategory |= ElementCategory.PREFIX | ElementCategory.SUPER;
2618
2619 bool oldSendIsMemberAccess = sendIsMemberAccess;
2620 int oldAllowedCategory = allowedCategory;
2621
2622 // Conditional sends like `e?.foo` treat the receiver as an expression. So
2623 // `C?.foo` needs to be treated like `(C).foo`, not like C.foo. Prefixes and
2624 // super are not allowed on their own in that context.
2625 if (node.isConditional) {
2626 sendIsMemberAccess = false;
2627 allowedCategory =
2628 ElementCategory.VARIABLE |
2629 ElementCategory.FUNCTION |
2630 ElementCategory.IMPLIES_TYPE;
2631 }
2632 ResolutionResult resolvedReceiver = visit(node.receiver);
2633 if (node.isConditional) {
2634 sendIsMemberAccess = oldSendIsMemberAccess;
2635 allowedCategory = oldAllowedCategory;
2636 }
2637
2638 allowedCategory = oldCategory;
2639
2640 Element target;
2641 String name = node.selector.asIdentifier().source;
2642 if (identical(name, 'this')) {
2643 // TODO(ahe): Why is this using GENERIC?
2644 error(node.selector, MessageKind.GENERIC,
2645 {'text': "expected an identifier"});
2646 return null;
2647 } else if (node.isSuperCall) {
2648 if (node.isOperator) {
2649 if (isUserDefinableOperator(name)) {
2650 name = selector.name;
2651 } else {
2652 error(node.selector, MessageKind.ILLEGAL_SUPER_SEND, {'name': name});
2653 return null;
2654 }
2655 }
2656 if (!inInstanceContext) {
2657 error(node.receiver, MessageKind.NO_INSTANCE_AVAILABLE, {'name': name});
2658 return null;
2659 }
2660 if (currentClass.supertype == null) {
2661 // This is just to guard against internal errors, so no need
2662 // for a real error message.
2663 error(node.receiver, MessageKind.GENERIC,
2664 {'text': "Object has no superclass"});
2665 return null;
2666 }
2667 // TODO(johnniwinther): Ensure correct behavior if currentClass is a
2668 // patch.
2669 target = currentClass.lookupSuperByName(selector.memberName);
2670 // [target] may be null which means invoking noSuchMethod on
2671 // super.
2672 if (target == null) {
2673 target = reportAndCreateErroneousElement(
2674 node, name, MessageKind.NO_SUCH_SUPER_MEMBER,
2675 {'className': currentClass.name, 'memberName': name});
2676 // We still need to register the invocation, because we might
2677 // call [:super.noSuchMethod:] which calls
2678 // [JSInvocationMirror._invokeOn].
2679 registry.registerDynamicInvocation(selector);
2680 registry.registerSuperNoSuchMethod();
2681 }
2682 } else if (resolvedReceiver == null ||
2683 Elements.isUnresolved(resolvedReceiver.element)) {
2684 return null;
2685 } else if (resolvedReceiver.element.isClass) {
2686 ClassElement receiverClass = resolvedReceiver.element;
2687 receiverClass.ensureResolved(compiler);
2688 if (node.isOperator) {
2689 // When the resolved receiver is a class, we can have two cases:
2690 // 1) a static send: C.foo, or
2691 // 2) an operator send, where the receiver is a class literal: 'C + 1'.
2692 // The following code that looks up the selector on the resolved
2693 // receiver will treat the second as the invocation of a static operator
2694 // if the resolved receiver is not null.
2695 return null;
2696 }
2697 MembersCreator.computeClassMembersByName(
2698 compiler, receiverClass.declaration, name);
2699 target = receiverClass.lookupLocalMember(name);
2700 if (target == null || target.isInstanceMember) {
2701 registry.registerThrowNoSuchMethod();
2702 // TODO(johnniwinther): With the simplified [TreeElements] invariant,
2703 // try to resolve injected elements if [currentClass] is in the patch
2704 // library of [receiverClass].
2705
2706 // TODO(karlklose): this should be reported by the caller of
2707 // [resolveSend] to select better warning messages for getters and
2708 // setters.
2709 MessageKind kind = (target == null)
2710 ? MessageKind.MEMBER_NOT_FOUND
2711 : MessageKind.MEMBER_NOT_STATIC;
2712 return new ElementResult(reportAndCreateErroneousElement(
2713 node, name, kind,
2714 {'className': receiverClass.name, 'memberName': name}));
2715 } else if (isPrivateName(name) &&
2716 target.library != enclosingElement.library) {
2717 registry.registerThrowNoSuchMethod();
2718 return new ElementResult(reportAndCreateErroneousElement(
2719 node, name, MessageKind.PRIVATE_ACCESS,
2720 {'libraryName': target.library.getLibraryOrScriptName(),
2721 'name': name}));
2722 }
2723 } else if (resolvedReceiver.element.isPrefix) {
2724 PrefixElement prefix = resolvedReceiver.element;
2725 target = prefix.lookupLocalMember(name);
2726 if (Elements.isUnresolved(target)) {
2727 registry.registerThrowNoSuchMethod();
2728 return new ElementResult(reportAndCreateErroneousElement(
2729 node, name, MessageKind.NO_SUCH_LIBRARY_MEMBER,
2730 {'libraryName': prefix.name, 'memberName': name}));
2731 } else if (target.isAmbiguous) {
2732 registry.registerThrowNoSuchMethod();
2733 AmbiguousElement ambiguous = target;
2734 target = reportAndCreateErroneousElement(
2735 node, name, ambiguous.messageKind, ambiguous.messageArguments);
2736 ambiguous.diagnose(enclosingElement, compiler);
2737 return new ElementResult(target);
2738 } else if (target.kind == ElementKind.CLASS) {
2739 ClassElement classElement = target;
2740 classElement.ensureResolved(compiler);
2741 }
2742 }
2743 return new ElementResult(target);
2744 }
2745
2746 static Selector computeSendSelector(Send node,
2747 LibraryElement library,
2748 Element element) {
2749 // First determine if this is part of an assignment.
2750 bool isSet = node.asSendSet() != null;
2751
2752 if (node.isIndex) {
2753 return isSet ? new Selector.indexSet() : new Selector.index();
2754 }
2755
2756 if (node.isOperator) {
2757 String source = node.selector.asOperator().source;
2758 String string = source;
2759 if (identical(string, '!') ||
2760 identical(string, '&&') || identical(string, '||') ||
2761 identical(string, 'is') || identical(string, 'as') ||
2762 identical(string, '?') || identical(string, '??') ||
2763 identical(string, '>>>')) {
2764 return null;
2765 }
2766 String op = source;
2767 if (!isUserDefinableOperator(source)) {
2768 op = Elements.mapToUserOperatorOrNull(source);
2769 }
2770 if (op == null) {
2771 // Unsupported operator. An error has been reported during parsing.
2772 return new Selector.call(
2773 source, library, node.argumentsNode.slowLength(), []);
2774 }
2775 return node.arguments.isEmpty
2776 ? new Selector.unaryOperator(op)
2777 : new Selector.binaryOperator(op);
2778 }
2779
2780 Identifier identifier = node.selector.asIdentifier();
2781 if (node.isPropertyAccess) {
2782 assert(!isSet);
2783 return new Selector.getter(identifier.source, library);
2784 } else if (isSet) {
2785 return new Selector.setter(identifier.source, library);
2786 }
2787
2788 // Compute the arity and the list of named arguments.
2789 int arity = 0;
2790 List<String> named = <String>[];
2791 for (Link<Node> link = node.argumentsNode.nodes;
2792 !link.isEmpty;
2793 link = link.tail) {
2794 Expression argument = link.head;
2795 NamedArgument namedArgument = argument.asNamedArgument();
2796 if (namedArgument != null) {
2797 named.add(namedArgument.name.source);
2798 }
2799 arity++;
2800 }
2801
2802 if (element != null && element.isConstructor) {
2803 return new Selector.callConstructor(
2804 element.name, library, arity, named);
2805 }
2806
2807 // If we're invoking a closure, we do not have an identifier.
2808 return (identifier == null)
2809 ? new Selector.callClosure(arity, named)
2810 : new Selector.call(identifier.source, library, arity, named);
2811 }
2812
2813 Selector resolveSelector(Send node, Element element) {
2814 LibraryElement library = enclosingElement.library;
2815 Selector selector = computeSendSelector(node, library, element);
2816 if (selector != null) registry.setSelector(node, selector);
2817 return selector;
2818 }
2819
2820 void resolveArguments(NodeList list) {
2821 if (list == null) return;
2822 bool oldSendIsMemberAccess = sendIsMemberAccess;
2823 sendIsMemberAccess = false;
2824 Map<String, Node> seenNamedArguments = new Map<String, Node>();
2825 for (Link<Node> link = list.nodes; !link.isEmpty; link = link.tail) {
2826 Expression argument = link.head;
2827 visit(argument);
2828 NamedArgument namedArgument = argument.asNamedArgument();
2829 if (namedArgument != null) {
2830 String source = namedArgument.name.source;
2831 if (seenNamedArguments.containsKey(source)) {
2832 reportDuplicateDefinition(
2833 source,
2834 argument,
2835 seenNamedArguments[source]);
2836 } else {
2837 seenNamedArguments[source] = namedArgument;
2838 }
2839 } else if (!seenNamedArguments.isEmpty) {
2840 error(argument, MessageKind.INVALID_ARGUMENT_AFTER_NAMED);
2841 }
2842 }
2843 sendIsMemberAccess = oldSendIsMemberAccess;
2844 }
2845
2846 void registerTypeLiteralAccess(Send node, Element target) {
2847 // Set the type of the node to [Type] to mark this send as a
2848 // type literal.
2849 DartType type;
2850
2851 // TODO(johnniwinther): Remove this hack when we can pass more complex
2852 // information between methods than resolved elements.
2853 if (target == compiler.typeClass && node.receiver == null) {
2854 // Potentially a 'dynamic' type literal.
2855 type = registry.getType(node.selector);
2856 }
2857 if (type == null) {
2858 type = target.computeType(compiler);
2859 }
2860 registry.registerTypeLiteral(node, type);
2861
2862 if (!target.isTypeVariable) {
2863 // Don't try to make constants of calls and assignments to type literals.
2864 if (!node.isCall && node.asSendSet() == null) {
2865 analyzeConstantDeferred(node, enforceConst: false);
2866 } else {
2867 // The node itself is not a constant but we register the selector (the
2868 // identifier that refers to the class/typedef) as a constant.
2869 if (node.receiver != null) {
2870 // This is a hack for the case of prefix.Type, we need to store
2871 // the element on the selector, so [analyzeConstant] can build
2872 // the type literal from the selector.
2873 registry.useElement(node.selector, target);
2874 }
2875 analyzeConstantDeferred(node.selector, enforceConst: false);
2876 }
2877 }
2878 }
2879
2880 /// Check that access to `super` is currently allowed.
2881 bool checkSuperAccess(Node node) {
2882 if (!inInstanceContext) {
2883 compiler.reportError(node, MessageKind.NO_SUPER_AVAILABLE);
2884 return false;
2885 }
2886 if (currentClass.supertype == null) {
2887 // This is just to guard against internal errors, so no need
2888 // for a real error message.
2889 compiler.reportError(node, MessageKind.GENERIC,
2890 {'text': "Object has no superclass"});
2891 return false;
2892 }
2893 registry.registerSuperUse(node);
2894 return true;
2895 }
2896
2897 /// Compute the [AccessSemantics] corresponding to a super access of [target].
2898 AccessSemantics computeSuperAccess(Spannable node, Element target) {
2899 if (target.isErroneous) {
2900 return new StaticAccess.unresolvedSuper(target);
2901 } else if (target.isGetter) {
2902 return new StaticAccess.superGetter(target);
2903 } else if (target.isSetter) {
2904 return new StaticAccess.superSetter(target);
2905 } else if (target.isField) {
2906 return new StaticAccess.superField(target);
2907 } else {
2908 assert(invariant(node, target.isFunction,
2909 message: "Unexpected super target '$target'."));
2910 return new StaticAccess.superMethod(target);
2911 }
2912 }
2913
2914 AccessSemantics computeSuperSemantics(Spannable node,
2915 Selector selector,
2916 {Name alternateName}) {
2917 Name name = selector.memberName;
2918 // TODO(johnniwinther): Ensure correct behavior if currentClass is a
2919 // patch.
2920 Element target = currentClass.lookupSuperByName(name);
2921 // [target] may be null which means invoking noSuchMethod on super.
2922 if (target == null) {
2923 Element error = reportAndCreateErroneousElement(
2924 node, name.text, MessageKind.NO_SUCH_SUPER_MEMBER,
2925 {'className': currentClass.name, 'memberName': name});
2926 if (alternateName != null) {
2927 target = currentClass.lookupSuperByName(alternateName);
2928 }
2929 if (target == null) {
2930 // If a setter wasn't resolved, use the [ErroneousElement].
2931 target = error;
2932 }
2933 // We still need to register the invocation, because we might
2934 // call [:super.noSuchMethod:] which calls [JSInvocationMirror._invokeOn].
2935 registry.registerDynamicInvocation(selector);
2936 registry.registerSuperNoSuchMethod();
2937 }
2938 return computeSuperAccess(node, target);
2939 }
2940
2941 ResolutionResult visitExpression(Node node) {
2942 bool oldSendIsMemberAccess = sendIsMemberAccess;
2943 sendIsMemberAccess = false;
2944 ResolutionResult result = visit(node);
2945 sendIsMemberAccess = oldSendIsMemberAccess;
2946 return result;
2947 }
2948
2949 ResolutionResult handleIs(Send node) {
2950 Node expression = node.receiver;
2951 visitExpression(expression);
2952
2953 // TODO(johnniwinther): Use seen type tests to avoid registration of
2954 // mutation/access to unpromoted variables.
2955
2956 Send notTypeNode = node.arguments.head.asSend();
2957 DartType type;
2958 SendStructure sendStructure;
2959 if (notTypeNode != null) {
2960 // `e is! T`.
2961 Node typeNode = notTypeNode.receiver;
2962 type = resolveTypeAnnotation(typeNode);
2963 sendStructure = new IsNotStructure(type);
2964 } else {
2965 // `e is T`.
2966 Node typeNode = node.arguments.head;
2967 type = resolveTypeAnnotation(typeNode);
2968 sendStructure = new IsStructure(type);
2969 }
2970 registry.registerIsCheck(type);
2971 registry.registerSendStructure(node, sendStructure);
2972 return null;
2973 }
2974
2975 ResolutionResult handleAs(Send node) {
2976 Node expression = node.receiver;
2977 visitExpression(expression);
2978
2979 Node typeNode = node.arguments.head;
2980 DartType type = resolveTypeAnnotation(typeNode);
2981 registry.registerAsCheck(type);
2982 registry.registerSendStructure(node, new AsStructure(type));
2983 return null;
2984 }
2985
2986 ResolutionResult handleUnresolvedUnary(Send node, String text) {
2987 Node expression = node.receiver;
2988 if (node.isSuperCall) {
2989 checkSuperAccess(node);
2990 } else {
2991 visitExpression(expression);
2992 }
2993
2994 registry.registerSendStructure(node, const InvalidUnaryStructure());
2995 return null;
2996 }
2997
2998 ResolutionResult handleUserDefinableUnary(Send node, UnaryOperator operator) {
2999 Node expression = node.receiver;
3000 Selector selector = operator.selector;
3001 // TODO(johnniwinther): Remove this when all information goes through the
3002 // [SendStructure].
3003 registry.setSelector(node, selector);
3004
3005 AccessSemantics semantics;
3006 if (node.isSuperCall) {
3007 if (checkSuperAccess(node)) {
3008 semantics = computeSuperSemantics(node, selector);
3009 // TODO(johnniwinther): Add information to [AccessSemantics] about
3010 // whether it is erroneous.
3011 if (semantics.kind == AccessKind.SUPER_METHOD) {
3012 registry.registerStaticUse(semantics.element.declaration);
3013 }
3014 // TODO(johnniwinther): Remove this when all information goes through
3015 // the [SendStructure].
3016 registry.useElement(node, semantics.element);
3017 }
3018 } else {
3019 visitExpression(expression);
3020 semantics = new DynamicAccess.dynamicProperty(expression);
3021 registry.registerDynamicInvocation(selector);
3022 }
3023 if (semantics != null) {
3024 // TODO(johnniwinther): Support invalid super access as an
3025 // [AccessSemantics].
3026 registry.registerSendStructure(node,
3027 new UnaryStructure(semantics, operator));
3028 }
3029 return null;
3030 }
3031
3032 ResolutionResult handleNot(Send node, UnaryOperator operator) {
3033 assert(invariant(node, operator.kind == UnaryOperatorKind.NOT));
3034
3035 Node expression = node.receiver;
3036 visitExpression(expression);
3037 registry.registerSendStructure(node,
3038 new NotStructure(new DynamicAccess.dynamicProperty(expression)));
3039 return null;
3040 }
3041
3042 ResolutionResult handleLogicalAnd(Send node) {
3043 Node left = node.receiver;
3044 Node right = node.arguments.head;
3045 doInPromotionScope(left, () => visitExpression(left));
3046 doInPromotionScope(right, () => visitExpression(right));
3047 registry.registerSendStructure(node, const LogicalAndStructure());
3048 return null;
3049 }
3050
3051 ResolutionResult handleLogicalOr(Send node) {
3052 Node left = node.receiver;
3053 Node right = node.arguments.head;
3054 visitExpression(left);
3055 visitExpression(right);
3056 registry.registerSendStructure(node, const LogicalOrStructure());
3057 return null;
3058 }
3059
3060 ResolutionResult handleIfNull(Send node) {
3061 Node left = node.receiver;
3062 Node right = node.arguments.head;
3063 visitExpression(left);
3064 visitExpression(right);
3065 registry.registerSendStructure(node, const IfNullStructure());
3066 return null;
3067 }
3068
3069 ResolutionResult handleUnresolvedBinary(Send node, String text) {
3070 Node left = node.receiver;
3071 Node right = node.arguments.head;
3072 if (node.isSuperCall) {
3073 checkSuperAccess(node);
3074 } else {
3075 visitExpression(left);
3076 }
3077 visitExpression(right);
3078 registry.registerSendStructure(node, const InvalidBinaryStructure());
3079 return null;
3080 }
3081
3082 ResolutionResult handleUserDefinableBinary(Send node,
3083 BinaryOperator operator) {
3084 Node left = node.receiver;
3085 Node right = node.arguments.head;
3086 AccessSemantics semantics;
3087 Selector selector;
3088 if (operator.kind == BinaryOperatorKind.INDEX) {
3089 selector = new Selector.index();
3090 } else {
3091 selector = new Selector.binaryOperator(operator.selectorName);
3092 }
3093 // TODO(johnniwinther): Remove this when all information goes through the
3094 // [SendStructure].
3095 registry.setSelector(node, selector);
3096
3097 if (node.isSuperCall) {
3098 if (checkSuperAccess(node)) {
3099 semantics = computeSuperSemantics(node, selector);
3100 // TODO(johnniwinther): Add information to [AccessSemantics] about
3101 // whether it is erroneous.
3102 if (semantics.kind == AccessKind.SUPER_METHOD) {
3103 registry.registerStaticUse(semantics.element.declaration);
3104 }
3105 // TODO(johnniwinther): Remove this when all information goes through
3106 // the [SendStructure].
3107 registry.useElement(node, semantics.element);
3108
3109 }
3110 } else {
3111 visitExpression(left);
3112 registry.registerDynamicInvocation(selector);
3113 semantics = new DynamicAccess.dynamicProperty(left);
3114 }
3115 visitExpression(right);
3116
3117 if (semantics != null) {
3118 // TODO(johnniwinther): Support invalid super access as an
3119 // [AccessSemantics].
3120 SendStructure sendStructure;
3121 switch (operator.kind) {
3122 case BinaryOperatorKind.EQ:
3123 sendStructure = new EqualsStructure(semantics);
3124 break;
3125 case BinaryOperatorKind.NOT_EQ:
3126 sendStructure = new NotEqualsStructure(semantics);
3127 break;
3128 case BinaryOperatorKind.INDEX:
3129 sendStructure = new IndexStructure(semantics);
3130 break;
3131 case BinaryOperatorKind.ADD:
3132 case BinaryOperatorKind.SUB:
3133 case BinaryOperatorKind.MUL:
3134 case BinaryOperatorKind.DIV:
3135 case BinaryOperatorKind.IDIV:
3136 case BinaryOperatorKind.MOD:
3137 case BinaryOperatorKind.SHL:
3138 case BinaryOperatorKind.SHR:
3139 case BinaryOperatorKind.GTEQ:
3140 case BinaryOperatorKind.GT:
3141 case BinaryOperatorKind.LTEQ:
3142 case BinaryOperatorKind.LT:
3143 case BinaryOperatorKind.AND:
3144 case BinaryOperatorKind.OR:
3145 case BinaryOperatorKind.XOR:
3146 sendStructure = new BinaryStructure(semantics, operator);
3147 break;
3148 case BinaryOperatorKind.LOGICAL_AND:
3149 case BinaryOperatorKind.LOGICAL_OR:
3150 case BinaryOperatorKind.IF_NULL:
3151 internalError(node, "Unexpected binary operator '${operator}'.");
3152 break;
3153 }
3154 registry.registerSendStructure(node, sendStructure);
3155 }
3156 return null;
3157 }
3158
3159 ResolutionResult visitSend(Send node) {
3160 if (node.isOperator) {
3161 String operatorText = node.selector.asOperator().source;
3162 if (operatorText == 'is') {
3163 return handleIs(node);
3164 } else if (operatorText == 'as') {
3165 return handleAs(node);
3166 } else if (node.arguments.isEmpty) {
3167 UnaryOperator operator = UnaryOperator.parse(operatorText);
3168 if (operator == null) {
3169 return handleUnresolvedUnary(node, operatorText);
3170 } else {
3171 switch (operator.kind) {
3172 case UnaryOperatorKind.NOT:
3173 return handleNot(node, operator);
3174 case UnaryOperatorKind.COMPLEMENT:
3175 case UnaryOperatorKind.NEGATE:
3176 assert(invariant(node, operator.isUserDefinable,
3177 message: "Unexpected unary operator '${operator}'."));
3178 return handleUserDefinableUnary(node, operator);
3179 }
3180 return handleUserDefinableUnary(node, operator);
3181 }
3182 } else {
3183 BinaryOperator operator = BinaryOperator.parse(operatorText);
3184 if (operator == null) {
3185 return handleUnresolvedBinary(node, operatorText);
3186 } else {
3187 switch (operator.kind) {
3188 case BinaryOperatorKind.LOGICAL_AND:
3189 return handleLogicalAnd(node);
3190 case BinaryOperatorKind.LOGICAL_OR:
3191 return handleLogicalOr(node);
3192 case BinaryOperatorKind.IF_NULL:
3193 return handleIfNull(node);
3194 case BinaryOperatorKind.EQ:
3195 case BinaryOperatorKind.NOT_EQ:
3196 case BinaryOperatorKind.INDEX:
3197 case BinaryOperatorKind.ADD:
3198 case BinaryOperatorKind.SUB:
3199 case BinaryOperatorKind.MUL:
3200 case BinaryOperatorKind.DIV:
3201 case BinaryOperatorKind.IDIV:
3202 case BinaryOperatorKind.MOD:
3203 case BinaryOperatorKind.SHL:
3204 case BinaryOperatorKind.SHR:
3205 case BinaryOperatorKind.GTEQ:
3206 case BinaryOperatorKind.GT:
3207 case BinaryOperatorKind.LTEQ:
3208 case BinaryOperatorKind.LT:
3209 case BinaryOperatorKind.AND:
3210 case BinaryOperatorKind.OR:
3211 case BinaryOperatorKind.XOR:
3212 return handleUserDefinableBinary(node, operator);
3213 }
3214 }
3215 }
3216 }
3217
3218 bool oldSendIsMemberAccess = sendIsMemberAccess;
3219 sendIsMemberAccess = node.isPropertyAccess || node.isCall;
3220
3221 ResolutionResult result = resolveSend(node);
3222 sendIsMemberAccess = oldSendIsMemberAccess;
3223
3224 Element target = result != null ? result.element : null;
3225
3226 if (target != null
3227 && target == compiler.mirrorSystemGetNameFunction
3228 && !compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(enclosingElement)) {
3229 compiler.reportHint(
3230 node.selector, MessageKind.STATIC_FUNCTION_BLOAT,
3231 {'class': compiler.mirrorSystemClass.name,
3232 'name': compiler.mirrorSystemGetNameFunction.name});
3233 }
3234
3235 if (target != null) {
3236 if (target.isErroneous) {
3237 registry.registerThrowNoSuchMethod();
3238 } else if (target.isAbstractField) {
3239 AbstractFieldElement field = target;
3240 target = field.getter;
3241 if (target == null) {
3242 if (!inInstanceContext || field.isTopLevel || field.isStatic) {
3243 registry.registerThrowNoSuchMethod();
3244 target = reportAndCreateErroneousElement(node.selector, field.name,
3245 MessageKind.CANNOT_RESOLVE_GETTER, const {});
3246 }
3247 }
3248 } else if (target.isTypeVariable) {
3249 ClassElement cls = target.enclosingClass;
3250 assert(enclosingElement.enclosingClass == cls);
3251 if (!Elements.hasAccessToTypeVariables(enclosingElement)) {
3252 compiler.reportError(node,
3253 MessageKind.TYPE_VARIABLE_WITHIN_STATIC_MEMBER,
3254 {'typeVariableName': node.selector});
3255 }
3256 registry.registerClassUsingVariableExpression(cls);
3257 registry.registerTypeVariableExpression();
3258 registerTypeLiteralAccess(node, target);
3259 } else if (target.impliesType && (!sendIsMemberAccess || node.isCall)) {
3260 registerTypeLiteralAccess(node, target);
3261 }
3262 if (isPotentiallyMutableTarget(target)) {
3263 if (enclosingElement != target.enclosingElement) {
3264 for (Node scope in promotionScope) {
3265 registry.setAccessedByClosureIn(scope, target, node);
3266 }
3267 }
3268 }
3269 }
3270
3271 bool resolvedArguments = false;
3272 resolveArguments(node.argumentsNode);
3273
3274 // If the selector is null, it means that we will not be generating
3275 // code for this as a send.
3276 Selector selector = registry.getSelector(node);
3277 if (selector == null) return null;
3278
3279 if (node.isCall) {
3280 if (Elements.isUnresolved(target) ||
3281 target.isGetter ||
3282 target.isField ||
3283 Elements.isClosureSend(node, target)) {
3284 // If we don't know what we're calling or if we are calling a getter,
3285 // we need to register that fact that we may be calling a closure
3286 // with the same arguments.
3287 Selector call = new Selector.callClosureFrom(selector);
3288 registry.registerDynamicInvocation(call);
3289 } else if (target.impliesType) {
3290 // We call 'call()' on a Type instance returned from the reference to a
3291 // class or typedef literal. We do not need to register this call as a
3292 // dynamic invocation, because we statically know what the target is.
3293 } else {
3294 if (target is FunctionElement) {
3295 FunctionElement function = target;
3296 function.computeSignature(compiler);
3297 }
3298 if (!selector.applies(target, compiler.world)) {
3299 registry.registerThrowNoSuchMethod();
3300 if (node.isSuperCall) {
3301 // Similar to what we do when we can't find super via selector
3302 // in [resolveSend] above, we still need to register the invocation,
3303 // because we might call [:super.noSuchMethod:] which calls
3304 // [JSInvocationMirror._invokeOn].
3305 registry.registerDynamicInvocation(selector);
3306 registry.registerSuperNoSuchMethod();
3307 }
3308 }
3309 }
3310
3311 if (target != null && target.isForeign(compiler.backend)) {
3312 if (selector.name == 'JS') {
3313 registry.registerJsCall(node, this);
3314 } else if (selector.name == 'JS_EMBEDDED_GLOBAL') {
3315 registry.registerJsEmbeddedGlobalCall(node, this);
3316 } else if (selector.name == 'JS_BUILTIN') {
3317 registry.registerJsBuiltinCall(node, this);
3318 } else if (selector.name == 'JS_INTERCEPTOR_CONSTANT') {
3319 if (!node.argumentsNode.isEmpty) {
3320 Node argument = node.argumentsNode.nodes.head;
3321 if (argumentsToJsInterceptorConstant == null) {
3322 argumentsToJsInterceptorConstant = new Set<Node>();
3323 }
3324 argumentsToJsInterceptorConstant.add(argument);
3325 }
3326 }
3327 }
3328 }
3329
3330 registry.useElement(node, target);
3331 registerSend(selector, target);
3332 if (node.isPropertyAccess && Elements.isStaticOrTopLevelFunction(target)) {
3333 registry.registerGetOfStaticFunction(target.declaration);
3334 }
3335 return node.isPropertyAccess ? new ElementResult(target) : null;
3336 }
3337
3338 /// Callback for native enqueuer to parse a type. Returns [:null:] on error.
3339 DartType resolveTypeFromString(Node node, String typeName) {
3340 Element element = lookupInScope(compiler, node,
3341 scope, typeName);
3342 if (element == null) return null;
3343 if (element is! ClassElement) return null;
3344 ClassElement cls = element;
3345 cls.ensureResolved(compiler);
3346 return cls.computeType(compiler);
3347 }
3348
3349 ResolutionResult visitSendSet(SendSet node) {
3350 bool oldSendIsMemberAccess = sendIsMemberAccess;
3351 sendIsMemberAccess = node.isPropertyAccess || node.isCall;
3352 ResolutionResult result = resolveSend(node);
3353 sendIsMemberAccess = oldSendIsMemberAccess;
3354 Element target = result != null ? result.element : null;
3355 Element setter = target;
3356 Element getter = target;
3357 String operatorName = node.assignmentOperator.source;
3358 String source = operatorName;
3359 bool isComplex = !identical(source, '=');
3360 if (!(result is AssertResult || Elements.isUnresolved(target))) {
3361 if (target.isAbstractField) {
3362 AbstractFieldElement field = target;
3363 setter = field.setter;
3364 getter = field.getter;
3365 if (setter == null) {
3366 if (!inInstanceContext || getter.isTopLevel || getter.isStatic) {
3367 setter = reportAndCreateErroneousElement(node.selector, field.name,
3368 MessageKind.CANNOT_RESOLVE_SETTER, const {});
3369 registry.registerThrowNoSuchMethod();
3370 }
3371 }
3372 if (isComplex && getter == null && !inInstanceContext) {
3373 getter = reportAndCreateErroneousElement(node.selector, field.name,
3374 MessageKind.CANNOT_RESOLVE_GETTER, const {});
3375 registry.registerThrowNoSuchMethod();
3376 }
3377 } else if (target.impliesType) {
3378 if (node.isIfNullAssignment) {
3379 setter = reportAndCreateErroneousElement(node.selector, target.name,
3380 MessageKind.IF_NULL_ASSIGNING_TYPE, const {});
3381 // In this case, no assignment happens, the rest of the compiler can
3382 // treat the expression `C ??= e` as if it's just reading `C`.
3383 } else {
3384 setter = reportAndCreateErroneousElement(node.selector, target.name,
3385 MessageKind.ASSIGNING_TYPE, const {});
3386 registry.registerThrowNoSuchMethod();
3387 }
3388 registerTypeLiteralAccess(node, target);
3389 } else if (target.isFinal || target.isConst) {
3390 if (Elements.isStaticOrTopLevelField(target) || target.isLocal) {
3391 setter = reportAndCreateErroneousElement(
3392 node.selector, target.name, MessageKind.CANNOT_RESOLVE_SETTER,
3393 const {});
3394 } else if (node.isSuperCall) {
3395 setter = reportAndCreateErroneousElement(
3396 node.selector, target.name, MessageKind.SETTER_NOT_FOUND_IN_SUPER,
3397 {'name': target.name, 'className': currentClass.name});
3398 registry.registerSuperNoSuchMethod();
3399 } else {
3400 // For instance fields we don't report a warning here because the type
3401 // checker will detect this as well and report a better error message
3402 // with the context of the containing class.
3403 }
3404 registry.registerThrowNoSuchMethod();
3405 } else if (target.isFunction && target.name != '[]=') {
3406 assert(!target.isSetter);
3407 if (Elements.isStaticOrTopLevelFunction(target) || target.isLocal) {
3408 setter = reportAndCreateErroneousElement(
3409 node.selector, target.name, MessageKind.ASSIGNING_METHOD,
3410 const {});
3411 } else if (node.isSuperCall) {
3412 setter = reportAndCreateErroneousElement(
3413 node.selector, target.name, MessageKind.ASSIGNING_METHOD_IN_SUPER,
3414 {'name': target.name,
3415 'superclassName': target.enclosingElement.name});
3416 registry.registerSuperNoSuchMethod();
3417 } else {
3418 // For instance methods we don't report a warning here because the
3419 // type checker will detect this as well and report a better error
3420 // message with the context of the containing class.
3421 }
3422 registry.registerThrowNoSuchMethod();
3423 }
3424 if (isPotentiallyMutableTarget(target)) {
3425 registry.registerPotentialMutation(target, node);
3426 if (enclosingElement != target.enclosingElement) {
3427 registry.registerPotentialMutationInClosure(target, node);
3428 }
3429 for (Node scope in promotionScope) {
3430 registry.registerPotentialMutationIn(scope, target, node);
3431 }
3432 }
3433 }
3434
3435 resolveArguments(node.argumentsNode);
3436
3437 Selector selector = registry.getSelector(node);
3438 if (isComplex) {
3439 Selector getterSelector;
3440 if (selector.isSetter) {
3441 getterSelector = new Selector.getterFrom(selector);
3442 } else {
3443 assert(selector.isIndexSet);
3444 getterSelector = new Selector.index();
3445 }
3446 registerSend(getterSelector, getter);
3447 registry.setGetterSelectorInComplexSendSet(node, getterSelector);
3448 if (node.isSuperCall) {
3449 getter = currentClass.lookupSuperByName(getterSelector.memberName);
3450 if (getter == null) {
3451 target = reportAndCreateErroneousElement(
3452 node, selector.name, MessageKind.NO_SUCH_SUPER_MEMBER,
3453 {'className': currentClass.name, 'memberName': selector.name});
3454 registry.registerSuperNoSuchMethod();
3455 }
3456 }
3457 registry.useElement(node.selector, getter);
3458
3459 // Make sure we include the + and - operators if we are using
3460 // the ++ and -- ones. Also, if op= form is used, include op itself.
3461 void registerBinaryOperator(String name) {
3462 Selector binop = new Selector.binaryOperator(name);
3463 registry.registerDynamicInvocation(binop);
3464 registry.setOperatorSelectorInComplexSendSet(node, binop);
3465 }
3466 if (identical(source, '++')) {
3467 registerBinaryOperator('+');
3468 registry.registerInstantiatedClass(compiler.intClass);
3469 } else if (identical(source, '--')) {
3470 registerBinaryOperator('-');
3471 registry.registerInstantiatedClass(compiler.intClass);
3472 } else if (source.endsWith('=')) {
3473 registerBinaryOperator(Elements.mapToUserOperator(operatorName));
3474 }
3475 }
3476
3477 registerSend(selector, setter);
3478 return new ElementResult(registry.useElement(node, setter));
3479 }
3480
3481 void registerSend(Selector selector, Element target) {
3482 if (target == null || target.isInstanceMember) {
3483 if (selector.isGetter) {
3484 registry.registerDynamicGetter(selector);
3485 } else if (selector.isSetter) {
3486 registry.registerDynamicSetter(selector);
3487 } else {
3488 registry.registerDynamicInvocation(selector);
3489 }
3490 } else if (Elements.isStaticOrTopLevel(target)) {
3491 // Avoid registration of type variables since they are not analyzable but
3492 // instead resolved through their enclosing type declaration.
3493 if (!target.isTypeVariable) {
3494 // [target] might be the implementation element and only declaration
3495 // elements may be registered.
3496 registry.registerStaticUse(target.declaration);
3497 }
3498 }
3499 }
3500
3501 visitLiteralInt(LiteralInt node) {
3502 registry.registerInstantiatedClass(compiler.intClass);
3503 }
3504
3505 visitLiteralDouble(LiteralDouble node) {
3506 registry.registerInstantiatedClass(compiler.doubleClass);
3507 }
3508
3509 visitLiteralBool(LiteralBool node) {
3510 registry.registerInstantiatedClass(compiler.boolClass);
3511 }
3512
3513 visitLiteralString(LiteralString node) {
3514 registry.registerInstantiatedClass(compiler.stringClass);
3515 }
3516
3517 visitLiteralNull(LiteralNull node) {
3518 registry.registerInstantiatedClass(compiler.nullClass);
3519 }
3520
3521 visitLiteralSymbol(LiteralSymbol node) {
3522 registry.registerInstantiatedClass(compiler.symbolClass);
3523 registry.registerStaticUse(compiler.symbolConstructor.declaration);
3524 registry.registerConstSymbol(node.slowNameString);
3525 if (!validateSymbol(node, node.slowNameString, reportError: false)) {
3526 compiler.reportError(node,
3527 MessageKind.UNSUPPORTED_LITERAL_SYMBOL,
3528 {'value': node.slowNameString});
3529 }
3530 analyzeConstantDeferred(node);
3531 }
3532
3533 visitStringJuxtaposition(StringJuxtaposition node) {
3534 registry.registerInstantiatedClass(compiler.stringClass);
3535 node.visitChildren(this);
3536 }
3537
3538 visitNodeList(NodeList node) {
3539 for (Link<Node> link = node.nodes; !link.isEmpty; link = link.tail) {
3540 visit(link.head);
3541 }
3542 }
3543
3544 visitOperator(Operator node) {
3545 internalError(node, 'operator');
3546 }
3547
3548 visitRethrow(Rethrow node) {
3549 if (!inCatchBlock) {
3550 error(node, MessageKind.THROW_WITHOUT_EXPRESSION);
3551 }
3552 }
3553
3554 visitReturn(Return node) {
3555 Node expression = node.expression;
3556 if (expression != null) {
3557 if (enclosingElement.isGenerativeConstructor) {
3558 // It is a compile-time error if a return statement of the form
3559 // `return e;` appears in a generative constructor. (Dart Language
3560 // Specification 13.12.)
3561 compiler.reportError(expression,
3562 MessageKind.CANNOT_RETURN_FROM_CONSTRUCTOR);
3563 } else if (!node.isArrowBody && currentAsyncMarker.isYielding) {
3564 compiler.reportError(
3565 node,
3566 MessageKind.RETURN_IN_GENERATOR,
3567 {'modifier': currentAsyncMarker});
3568 }
3569 }
3570 visit(node.expression);
3571 }
3572
3573 visitYield(Yield node) {
3574 compiler.streamClass.ensureResolved(compiler);
3575 compiler.iterableClass.ensureResolved(compiler);
3576 visit(node.expression);
3577 }
3578
3579 visitRedirectingFactoryBody(RedirectingFactoryBody node) {
3580 final isSymbolConstructor = enclosingElement == compiler.symbolConstructor;
3581 if (!enclosingElement.isFactoryConstructor) {
3582 compiler.reportError(
3583 node, MessageKind.FACTORY_REDIRECTION_IN_NON_FACTORY);
3584 compiler.reportHint(
3585 enclosingElement, MessageKind.MISSING_FACTORY_KEYWORD);
3586 }
3587 ConstructorElementX constructor = enclosingElement;
3588 bool isConstConstructor = constructor.isConst;
3589 ConstructorElement redirectionTarget = resolveRedirectingFactory(
3590 node, inConstContext: isConstConstructor);
3591 constructor.immediateRedirectionTarget = redirectionTarget;
3592
3593 Node constructorReference = node.constructorReference;
3594 if (constructorReference is Send) {
3595 constructor.redirectionDeferredPrefix =
3596 compiler.deferredLoadTask.deferredPrefixElement(constructorReference,
3597 registry.mapping);
3598 }
3599
3600 registry.setRedirectingTargetConstructor(node, redirectionTarget);
3601 if (Elements.isUnresolved(redirectionTarget)) {
3602 registry.registerThrowNoSuchMethod();
3603 return;
3604 } else {
3605 if (isConstConstructor &&
3606 !redirectionTarget.isConst) {
3607 compiler.reportError(node, MessageKind.CONSTRUCTOR_IS_NOT_CONST);
3608 }
3609 if (redirectionTarget == constructor) {
3610 compiler.reportError(node, MessageKind.CYCLIC_REDIRECTING_FACTORY);
3611 }
3612 }
3613
3614 // Check that the target constructor is type compatible with the
3615 // redirecting constructor.
3616 ClassElement targetClass = redirectionTarget.enclosingClass;
3617 InterfaceType type = registry.getType(node);
3618 FunctionType targetType = redirectionTarget.computeType(compiler)
3619 .subst(type.typeArguments, targetClass.typeVariables);
3620 FunctionType constructorType = constructor.computeType(compiler);
3621 bool isSubtype = compiler.types.isSubtype(targetType, constructorType);
3622 if (!isSubtype) {
3623 warning(node, MessageKind.NOT_ASSIGNABLE,
3624 {'fromType': targetType, 'toType': constructorType});
3625 }
3626
3627 FunctionSignature targetSignature =
3628 redirectionTarget.computeSignature(compiler);
3629 FunctionSignature constructorSignature =
3630 constructor.computeSignature(compiler);
3631 if (!targetSignature.isCompatibleWith(constructorSignature)) {
3632 assert(!isSubtype);
3633 registry.registerThrowNoSuchMethod();
3634 }
3635
3636 // Register a post process to check for cycles in the redirection chain and
3637 // set the actual generative constructor at the end of the chain.
3638 addDeferredAction(constructor, () {
3639 compiler.resolver.resolveRedirectionChain(constructor, node);
3640 });
3641
3642 registry.registerStaticUse(redirectionTarget);
3643 // TODO(johnniwinther): Register the effective target type instead.
3644 registry.registerInstantiatedClass(
3645 redirectionTarget.enclosingClass.declaration);
3646 if (isSymbolConstructor) {
3647 registry.registerSymbolConstructor();
3648 }
3649 }
3650
3651 visitThrow(Throw node) {
3652 registry.registerThrowExpression();
3653 visit(node.expression);
3654 }
3655
3656 visitAwait(Await node) {
3657 compiler.futureClass.ensureResolved(compiler);
3658 visit(node.expression);
3659 }
3660
3661 visitVariableDefinitions(VariableDefinitions node) {
3662 DartType type;
3663 if (node.type != null) {
3664 type = resolveTypeAnnotation(node.type);
3665 } else {
3666 type = const DynamicType();
3667 }
3668 VariableList variables = new VariableList.node(node, type);
3669 VariableDefinitionsVisitor visitor =
3670 new VariableDefinitionsVisitor(compiler, node, this, variables);
3671
3672 Modifiers modifiers = node.modifiers;
3673 void reportExtraModifier(String modifier) {
3674 Node modifierNode;
3675 for (Link<Node> nodes = modifiers.nodes.nodes;
3676 !nodes.isEmpty;
3677 nodes = nodes.tail) {
3678 if (modifier == nodes.head.asIdentifier().source) {
3679 modifierNode = nodes.head;
3680 break;
3681 }
3682 }
3683 assert(modifierNode != null);
3684 compiler.reportError(modifierNode, MessageKind.EXTRANEOUS_MODIFIER,
3685 {'modifier': modifier});
3686 }
3687 if (modifiers.isFinal && (modifiers.isConst || modifiers.isVar)) {
3688 reportExtraModifier('final');
3689 }
3690 if (modifiers.isVar && (modifiers.isConst || node.type != null)) {
3691 reportExtraModifier('var');
3692 }
3693 if (enclosingElement.isFunction) {
3694 if (modifiers.isAbstract) {
3695 reportExtraModifier('abstract');
3696 }
3697 if (modifiers.isStatic) {
3698 reportExtraModifier('static');
3699 }
3700 }
3701 if (node.metadata != null) {
3702 variables.metadata =
3703 compiler.resolver.resolveMetadata(enclosingElement, node);
3704 }
3705 visitor.visit(node.definitions);
3706 }
3707
3708 visitWhile(While node) {
3709 visit(node.condition);
3710 visitLoopBodyIn(node, node.body, new BlockScope(scope));
3711 }
3712
3713 visitParenthesizedExpression(ParenthesizedExpression node) {
3714 bool oldSendIsMemberAccess = sendIsMemberAccess;
3715 sendIsMemberAccess = false;
3716 var oldCategory = allowedCategory;
3717 allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION
3718 | ElementCategory.IMPLIES_TYPE;
3719 visit(node.expression);
3720 allowedCategory = oldCategory;
3721 sendIsMemberAccess = oldSendIsMemberAccess;
3722 }
3723
3724 ResolutionResult visitNewExpression(NewExpression node) {
3725 Node selector = node.send.selector;
3726 FunctionElement constructor = resolveConstructor(node);
3727 final bool isSymbolConstructor = constructor == compiler.symbolConstructor;
3728 final bool isMirrorsUsedConstant =
3729 node.isConst && (constructor == compiler.mirrorsUsedConstructor);
3730 Selector callSelector = resolveSelector(node.send, constructor);
3731 resolveArguments(node.send.argumentsNode);
3732 registry.useElement(node.send, constructor);
3733 if (Elements.isUnresolved(constructor)) {
3734 return new ElementResult(constructor);
3735 }
3736 constructor.computeSignature(compiler);
3737 if (!callSelector.applies(constructor, compiler.world)) {
3738 registry.registerThrowNoSuchMethod();
3739 }
3740
3741 // [constructor] might be the implementation element
3742 // and only declaration elements may be registered.
3743 registry.registerStaticUse(constructor.declaration);
3744 ClassElement cls = constructor.enclosingClass;
3745 if (cls.isEnumClass && currentClass != cls) {
3746 compiler.reportError(node,
3747 MessageKind.CANNOT_INSTANTIATE_ENUM,
3748 {'enumName': cls.name});
3749 }
3750
3751 InterfaceType type = registry.getType(node);
3752 if (node.isConst && type.containsTypeVariables) {
3753 compiler.reportError(node.send.selector,
3754 MessageKind.TYPE_VARIABLE_IN_CONSTANT);
3755 }
3756 // TODO(johniwinther): Avoid registration of `type` in face of redirecting
3757 // factory constructors.
3758 registry.registerInstantiatedType(type);
3759 if (constructor.isGenerativeConstructor && cls.isAbstract) {
3760 warning(node, MessageKind.ABSTRACT_CLASS_INSTANTIATION);
3761 registry.registerAbstractClassInstantiation();
3762 }
3763
3764 if (isSymbolConstructor) {
3765 if (node.isConst) {
3766 Node argumentNode = node.send.arguments.head;
3767 ConstantExpression constant =
3768 compiler.resolver.constantCompiler.compileNode(
3769 argumentNode, registry.mapping);
3770 ConstantValue name = constant.value;
3771 if (!name.isString) {
3772 DartType type = name.getType(compiler.coreTypes);
3773 compiler.reportError(argumentNode, MessageKind.STRING_EXPECTED,
3774 {'type': type});
3775 } else {
3776 StringConstantValue stringConstant = name;
3777 String nameString = stringConstant.toDartString().slowToString();
3778 if (validateSymbol(argumentNode, nameString)) {
3779 registry.registerConstSymbol(nameString);
3780 }
3781 }
3782 } else {
3783 if (!compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(
3784 enclosingElement)) {
3785 compiler.reportHint(
3786 node.newToken, MessageKind.NON_CONST_BLOAT,
3787 {'name': compiler.symbolClass.name});
3788 }
3789 registry.registerNewSymbol();
3790 }
3791 } else if (isMirrorsUsedConstant) {
3792 compiler.mirrorUsageAnalyzerTask.validate(node, registry.mapping);
3793 }
3794 if (node.isConst) {
3795 analyzeConstantDeferred(node);
3796 }
3797
3798 return null;
3799 }
3800
3801 void checkConstMapKeysDontOverrideEquals(Spannable spannable,
3802 MapConstantValue map) {
3803 for (ConstantValue key in map.keys) {
3804 if (!key.isObject) continue;
3805 ObjectConstantValue objectConstant = key;
3806 DartType keyType = objectConstant.type;
3807 ClassElement cls = keyType.element;
3808 if (cls == compiler.stringClass) continue;
3809 Element equals = cls.lookupMember('==');
3810 if (equals.enclosingClass != compiler.objectClass) {
3811 compiler.reportError(spannable,
3812 MessageKind.CONST_MAP_KEY_OVERRIDES_EQUALS,
3813 {'type': keyType});
3814 }
3815 }
3816 }
3817
3818 void analyzeConstant(Node node, {enforceConst: true}) {
3819 ConstantExpression constant =
3820 compiler.resolver.constantCompiler.compileNode(
3821 node, registry.mapping, enforceConst: enforceConst);
3822
3823 if (constant == null) {
3824 assert(invariant(node, compiler.compilationFailed));
3825 return;
3826 }
3827
3828 ConstantValue value = constant.value;
3829 if (value.isMap) {
3830 checkConstMapKeysDontOverrideEquals(node, value);
3831 }
3832
3833 // The type constant that is an argument to JS_INTERCEPTOR_CONSTANT names
3834 // a class that will be instantiated outside the program by attaching a
3835 // native class dispatch record referencing the interceptor.
3836 if (argumentsToJsInterceptorConstant != null &&
3837 argumentsToJsInterceptorConstant.contains(node)) {
3838 if (value.isType) {
3839 TypeConstantValue typeConstant = value;
3840 if (typeConstant.representedType is InterfaceType) {
3841 registry.registerInstantiatedType(typeConstant.representedType);
3842 } else {
3843 compiler.reportError(node,
3844 MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT);
3845 }
3846 } else {
3847 compiler.reportError(node,
3848 MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT);
3849 }
3850 }
3851 }
3852
3853 void analyzeConstantDeferred(Node node, {bool enforceConst: true}) {
3854 addDeferredAction(enclosingElement, () {
3855 analyzeConstant(node, enforceConst: enforceConst);
3856 });
3857 }
3858
3859 bool validateSymbol(Node node, String name, {bool reportError: true}) {
3860 if (name.isEmpty) return true;
3861 if (name.startsWith('_')) {
3862 if (reportError) {
3863 compiler.reportError(node, MessageKind.PRIVATE_IDENTIFIER,
3864 {'value': name});
3865 }
3866 return false;
3867 }
3868 if (!symbolValidationPattern.hasMatch(name)) {
3869 if (reportError) {
3870 compiler.reportError(node, MessageKind.INVALID_SYMBOL,
3871 {'value': name});
3872 }
3873 return false;
3874 }
3875 return true;
3876 }
3877
3878 /**
3879 * Try to resolve the constructor that is referred to by [node].
3880 * Note: this function may return an ErroneousFunctionElement instead of
3881 * [:null:], if there is no corresponding constructor, class or library.
3882 */
3883 ConstructorElement resolveConstructor(NewExpression node) {
3884 return node.accept(new ConstructorResolver(compiler, this));
3885 }
3886
3887 ConstructorElement resolveRedirectingFactory(RedirectingFactoryBody node,
3888 {bool inConstContext: false}) {
3889 return node.accept(new ConstructorResolver(compiler, this,
3890 inConstContext: inConstContext));
3891 }
3892
3893 DartType resolveTypeAnnotation(TypeAnnotation node,
3894 {bool malformedIsError: false,
3895 bool deferredIsMalformed: true}) {
3896 DartType type = typeResolver.resolveTypeAnnotation(
3897 this, node, malformedIsError: malformedIsError,
3898 deferredIsMalformed: deferredIsMalformed);
3899 if (inCheckContext) {
3900 registry.registerIsCheck(type);
3901 registry.registerRequiredType(type, enclosingElement);
3902 }
3903 return type;
3904 }
3905
3906 visitModifiers(Modifiers node) {
3907 internalError(node, 'modifiers');
3908 }
3909
3910 visitLiteralList(LiteralList node) {
3911 bool oldSendIsMemberAccess = sendIsMemberAccess;
3912 sendIsMemberAccess = false;
3913
3914 NodeList arguments = node.typeArguments;
3915 DartType typeArgument;
3916 if (arguments != null) {
3917 Link<Node> nodes = arguments.nodes;
3918 if (nodes.isEmpty) {
3919 // The syntax [: <>[] :] is not allowed.
3920 error(arguments, MessageKind.MISSING_TYPE_ARGUMENT);
3921 } else {
3922 typeArgument = resolveTypeAnnotation(nodes.head);
3923 for (nodes = nodes.tail; !nodes.isEmpty; nodes = nodes.tail) {
3924 warning(nodes.head, MessageKind.ADDITIONAL_TYPE_ARGUMENT);
3925 resolveTypeAnnotation(nodes.head);
3926 }
3927 }
3928 }
3929 DartType listType;
3930 if (typeArgument != null) {
3931 if (node.isConst && typeArgument.containsTypeVariables) {
3932 compiler.reportError(arguments.nodes.head,
3933 MessageKind.TYPE_VARIABLE_IN_CONSTANT);
3934 }
3935 listType = new InterfaceType(compiler.listClass, [typeArgument]);
3936 } else {
3937 compiler.listClass.computeType(compiler);
3938 listType = compiler.listClass.rawType;
3939 }
3940 registry.setType(node, listType);
3941 registry.registerInstantiatedType(listType);
3942 registry.registerRequiredType(listType, enclosingElement);
3943 visit(node.elements);
3944 if (node.isConst) {
3945 analyzeConstantDeferred(node);
3946 }
3947
3948 sendIsMemberAccess = false;
3949 }
3950
3951 visitConditional(Conditional node) {
3952 doInPromotionScope(node.condition, () => visit(node.condition));
3953 doInPromotionScope(node.thenExpression, () => visit(node.thenExpression));
3954 visit(node.elseExpression);
3955 }
3956
3957 visitStringInterpolation(StringInterpolation node) {
3958 registry.registerInstantiatedClass(compiler.stringClass);
3959 registry.registerStringInterpolation();
3960 node.visitChildren(this);
3961 }
3962
3963 visitStringInterpolationPart(StringInterpolationPart node) {
3964 registerImplicitInvocation('toString', 0);
3965 node.visitChildren(this);
3966 }
3967
3968 visitBreakStatement(BreakStatement node) {
3969 JumpTarget target;
3970 if (node.target == null) {
3971 target = statementScope.currentBreakTarget();
3972 if (target == null) {
3973 error(node, MessageKind.NO_BREAK_TARGET);
3974 return;
3975 }
3976 target.isBreakTarget = true;
3977 } else {
3978 String labelName = node.target.source;
3979 LabelDefinition label = statementScope.lookupLabel(labelName);
3980 if (label == null) {
3981 error(node.target, MessageKind.UNBOUND_LABEL, {'labelName': labelName});
3982 return;
3983 }
3984 target = label.target;
3985 if (!target.statement.isValidBreakTarget()) {
3986 error(node.target, MessageKind.INVALID_BREAK);
3987 return;
3988 }
3989 label.setBreakTarget();
3990 registry.useLabel(node, label);
3991 }
3992 registry.registerTargetOf(node, target);
3993 }
3994
3995 visitContinueStatement(ContinueStatement node) {
3996 JumpTarget target;
3997 if (node.target == null) {
3998 target = statementScope.currentContinueTarget();
3999 if (target == null) {
4000 error(node, MessageKind.NO_CONTINUE_TARGET);
4001 return;
4002 }
4003 target.isContinueTarget = true;
4004 } else {
4005 String labelName = node.target.source;
4006 LabelDefinition label = statementScope.lookupLabel(labelName);
4007 if (label == null) {
4008 error(node.target, MessageKind.UNBOUND_LABEL, {'labelName': labelName});
4009 return;
4010 }
4011 target = label.target;
4012 if (!target.statement.isValidContinueTarget()) {
4013 error(node.target, MessageKind.INVALID_CONTINUE);
4014 }
4015 label.setContinueTarget();
4016 registry.useLabel(node, label);
4017 }
4018 registry.registerTargetOf(node, target);
4019 }
4020
4021 registerImplicitInvocation(String name, int arity) {
4022 Selector selector = new Selector.call(name, null, arity);
4023 registry.registerDynamicInvocation(selector);
4024 }
4025
4026 visitAsyncForIn(AsyncForIn node) {
4027 registry.registerAsyncForIn(node);
4028 registry.setCurrentSelector(node, compiler.currentSelector);
4029 registry.registerDynamicGetter(compiler.currentSelector);
4030 registry.setMoveNextSelector(node, compiler.moveNextSelector);
4031 registry.registerDynamicInvocation(compiler.moveNextSelector);
4032
4033 visit(node.expression);
4034
4035 Scope blockScope = new BlockScope(scope);
4036 visitForInDeclaredIdentifierIn(node.declaredIdentifier, node, blockScope);
4037 visitLoopBodyIn(node, node.body, blockScope);
4038 }
4039
4040 visitSyncForIn(SyncForIn node) {
4041 registry.registerSyncForIn(node);
4042 registry.setIteratorSelector(node, compiler.iteratorSelector);
4043 registry.registerDynamicGetter(compiler.iteratorSelector);
4044 registry.setCurrentSelector(node, compiler.currentSelector);
4045 registry.registerDynamicGetter(compiler.currentSelector);
4046 registry.setMoveNextSelector(node, compiler.moveNextSelector);
4047 registry.registerDynamicInvocation(compiler.moveNextSelector);
4048
4049 visit(node.expression);
4050
4051 Scope blockScope = new BlockScope(scope);
4052 visitForInDeclaredIdentifierIn(node.declaredIdentifier, node, blockScope);
4053 visitLoopBodyIn(node, node.body, blockScope);
4054 }
4055
4056 visitForInDeclaredIdentifierIn(Node declaration, ForIn node,
4057 Scope blockScope) {
4058 LibraryElement library = enclosingElement.library;
4059
4060 bool oldAllowFinalWithoutInitializer = allowFinalWithoutInitializer;
4061 allowFinalWithoutInitializer = true;
4062 visitIn(declaration, blockScope);
4063 allowFinalWithoutInitializer = oldAllowFinalWithoutInitializer;
4064
4065 Send send = declaration.asSend();
4066 VariableDefinitions variableDefinitions =
4067 declaration.asVariableDefinitions();
4068 Element loopVariable;
4069 Selector loopVariableSelector;
4070 if (send != null) {
4071 loopVariable = registry.getDefinition(send);
4072 Identifier identifier = send.selector.asIdentifier();
4073 if (identifier == null) {
4074 compiler.reportError(send.selector, MessageKind.INVALID_FOR_IN);
4075 } else {
4076 loopVariableSelector = new Selector.setter(identifier.source, library);
4077 }
4078 if (send.receiver != null) {
4079 compiler.reportError(send.receiver, MessageKind.INVALID_FOR_IN);
4080 }
4081 } else if (variableDefinitions != null) {
4082 Link<Node> nodes = variableDefinitions.definitions.nodes;
4083 if (!nodes.tail.isEmpty) {
4084 compiler.reportError(nodes.tail.head, MessageKind.INVALID_FOR_IN);
4085 }
4086 Node first = nodes.head;
4087 Identifier identifier = first.asIdentifier();
4088 if (identifier == null) {
4089 compiler.reportError(first, MessageKind.INVALID_FOR_IN);
4090 } else {
4091 loopVariableSelector = new Selector.setter(identifier.source, library);
4092 loopVariable = registry.getDefinition(identifier);
4093 }
4094 } else {
4095 compiler.reportError(declaration, MessageKind.INVALID_FOR_IN);
4096 }
4097 if (loopVariableSelector != null) {
4098 registry.setSelector(declaration, loopVariableSelector);
4099 registerSend(loopVariableSelector, loopVariable);
4100 } else {
4101 // The selector may only be null if we reported an error.
4102 assert(invariant(declaration, compiler.compilationFailed));
4103 }
4104 if (loopVariable != null) {
4105 // loopVariable may be null if it could not be resolved.
4106 registry.setForInVariable(node, loopVariable);
4107 }
4108 }
4109
4110 visitLabel(Label node) {
4111 // Labels are handled by their containing statements/cases.
4112 }
4113
4114 visitLabeledStatement(LabeledStatement node) {
4115 Statement body = node.statement;
4116 JumpTarget targetElement = getOrDefineTarget(body);
4117 Map<String, LabelDefinition> labelElements = <String, LabelDefinition>{};
4118 for (Label label in node.labels) {
4119 String labelName = label.labelName;
4120 if (labelElements.containsKey(labelName)) continue;
4121 LabelDefinition element = targetElement.addLabel(label, labelName);
4122 labelElements[labelName] = element;
4123 }
4124 statementScope.enterLabelScope(labelElements);
4125 visit(node.statement);
4126 statementScope.exitLabelScope();
4127 labelElements.forEach((String labelName, LabelDefinition element) {
4128 if (element.isTarget) {
4129 registry.defineLabel(element.label, element);
4130 } else {
4131 warning(element.label, MessageKind.UNUSED_LABEL,
4132 {'labelName': labelName});
4133 }
4134 });
4135 if (!targetElement.isTarget) {
4136 registry.undefineTarget(body);
4137 }
4138 }
4139
4140 visitLiteralMap(LiteralMap node) {
4141 sendIsMemberAccess = false;
4142
4143 NodeList arguments = node.typeArguments;
4144 DartType keyTypeArgument;
4145 DartType valueTypeArgument;
4146 if (arguments != null) {
4147 Link<Node> nodes = arguments.nodes;
4148 if (nodes.isEmpty) {
4149 // The syntax [: <>{} :] is not allowed.
4150 error(arguments, MessageKind.MISSING_TYPE_ARGUMENT);
4151 } else {
4152 keyTypeArgument = resolveTypeAnnotation(nodes.head);
4153 nodes = nodes.tail;
4154 if (nodes.isEmpty) {
4155 warning(arguments, MessageKind.MISSING_TYPE_ARGUMENT);
4156 } else {
4157 valueTypeArgument = resolveTypeAnnotation(nodes.head);
4158 for (nodes = nodes.tail; !nodes.isEmpty; nodes = nodes.tail) {
4159 warning(nodes.head, MessageKind.ADDITIONAL_TYPE_ARGUMENT);
4160 resolveTypeAnnotation(nodes.head);
4161 }
4162 }
4163 }
4164 }
4165 DartType mapType;
4166 if (valueTypeArgument != null) {
4167 mapType = new InterfaceType(compiler.mapClass,
4168 [keyTypeArgument, valueTypeArgument]);
4169 } else {
4170 compiler.mapClass.computeType(compiler);
4171 mapType = compiler.mapClass.rawType;
4172 }
4173 if (node.isConst && mapType.containsTypeVariables) {
4174 compiler.reportError(arguments,
4175 MessageKind.TYPE_VARIABLE_IN_CONSTANT);
4176 }
4177 registry.registerMapLiteral(node, mapType, node.isConst);
4178 registry.registerRequiredType(mapType, enclosingElement);
4179 node.visitChildren(this);
4180 if (node.isConst) {
4181 analyzeConstantDeferred(node);
4182 }
4183
4184 sendIsMemberAccess = false;
4185 }
4186
4187 visitLiteralMapEntry(LiteralMapEntry node) {
4188 node.visitChildren(this);
4189 }
4190
4191 visitNamedArgument(NamedArgument node) {
4192 visit(node.expression);
4193 }
4194
4195 DartType typeOfConstant(ConstantValue constant) {
4196 if (constant.isInt) return compiler.intClass.rawType;
4197 if (constant.isBool) return compiler.boolClass.rawType;
4198 if (constant.isDouble) return compiler.doubleClass.rawType;
4199 if (constant.isString) return compiler.stringClass.rawType;
4200 if (constant.isNull) return compiler.nullClass.rawType;
4201 if (constant.isFunction) return compiler.functionClass.rawType;
4202 assert(constant.isObject);
4203 ObjectConstantValue objectConstant = constant;
4204 return objectConstant.type;
4205 }
4206
4207 bool overridesEquals(DartType type) {
4208 ClassElement cls = type.element;
4209 Element equals = cls.lookupMember('==');
4210 return equals.enclosingClass != compiler.objectClass;
4211 }
4212
4213 void checkCaseExpressions(SwitchStatement node) {
4214 CaseMatch firstCase = null;
4215 DartType firstCaseType = null;
4216 bool hasReportedProblem = false;
4217
4218 for (Link<Node> cases = node.cases.nodes;
4219 !cases.isEmpty;
4220 cases = cases.tail) {
4221 SwitchCase switchCase = cases.head;
4222
4223 for (Node labelOrCase in switchCase.labelsAndCases) {
4224 CaseMatch caseMatch = labelOrCase.asCaseMatch();
4225 if (caseMatch == null) continue;
4226
4227 // Analyze the constant.
4228 ConstantExpression constant =
4229 registry.getConstant(caseMatch.expression);
4230 assert(invariant(node, constant != null,
4231 message: 'No constant computed for $node'));
4232
4233 DartType caseType = typeOfConstant(constant.value);
4234
4235 if (firstCaseType == null) {
4236 firstCase = caseMatch;
4237 firstCaseType = caseType;
4238
4239 // We only report the bad type on the first class element. All others
4240 // get a "type differs" error.
4241 if (caseType.element == compiler.doubleClass) {
4242 compiler.reportError(node,
4243 MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS,
4244 {'type': "double"});
4245 } else if (caseType.element == compiler.functionClass) {
4246 compiler.reportError(node, MessageKind.SWITCH_CASE_FORBIDDEN,
4247 {'type': "Function"});
4248 } else if (constant.value.isObject && overridesEquals(caseType)) {
4249 compiler.reportError(firstCase.expression,
4250 MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS,
4251 {'type': caseType});
4252 }
4253 } else {
4254 if (caseType != firstCaseType) {
4255 if (!hasReportedProblem) {
4256 compiler.reportError(
4257 node,
4258 MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL,
4259 {'type': firstCaseType});
4260 compiler.reportInfo(
4261 firstCase.expression,
4262 MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL_CASE,
4263 {'type': firstCaseType});
4264 hasReportedProblem = true;
4265 }
4266 compiler.reportInfo(
4267 caseMatch.expression,
4268 MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL_CASE,
4269 {'type': caseType});
4270 }
4271 }
4272 }
4273 }
4274 }
4275
4276 visitSwitchStatement(SwitchStatement node) {
4277 node.expression.accept(this);
4278
4279 JumpTarget breakElement = getOrDefineTarget(node);
4280 Map<String, LabelDefinition> continueLabels = <String, LabelDefinition>{};
4281 Link<Node> cases = node.cases.nodes;
4282 while (!cases.isEmpty) {
4283 SwitchCase switchCase = cases.head;
4284 for (Node labelOrCase in switchCase.labelsAndCases) {
4285 CaseMatch caseMatch = labelOrCase.asCaseMatch();
4286 if (caseMatch != null) {
4287 analyzeConstantDeferred(caseMatch.expression);
4288 continue;
4289 }
4290 Label label = labelOrCase;
4291 String labelName = label.labelName;
4292
4293 LabelDefinition existingElement = continueLabels[labelName];
4294 if (existingElement != null) {
4295 // It's an error if the same label occurs twice in the same switch.
4296 compiler.reportError(
4297 label,
4298 MessageKind.DUPLICATE_LABEL, {'labelName': labelName});
4299 compiler.reportInfo(
4300 existingElement.label,
4301 MessageKind.EXISTING_LABEL, {'labelName': labelName});
4302 } else {
4303 // It's only a warning if it shadows another label.
4304 existingElement = statementScope.lookupLabel(labelName);
4305 if (existingElement != null) {
4306 compiler.reportWarning(
4307 label,
4308 MessageKind.DUPLICATE_LABEL, {'labelName': labelName});
4309 compiler.reportInfo(
4310 existingElement.label,
4311 MessageKind.EXISTING_LABEL, {'labelName': labelName});
4312 }
4313 }
4314
4315 JumpTarget targetElement = getOrDefineTarget(switchCase);
4316 LabelDefinition labelElement = targetElement.addLabel(label, labelName);
4317 registry.defineLabel(label, labelElement);
4318 continueLabels[labelName] = labelElement;
4319 }
4320 cases = cases.tail;
4321 // Test that only the last case, if any, is a default case.
4322 if (switchCase.defaultKeyword != null && !cases.isEmpty) {
4323 error(switchCase, MessageKind.INVALID_CASE_DEFAULT);
4324 }
4325 }
4326
4327 addDeferredAction(enclosingElement, () {
4328 checkCaseExpressions(node);
4329 });
4330
4331 statementScope.enterSwitch(breakElement, continueLabels);
4332 node.cases.accept(this);
4333 statementScope.exitSwitch();
4334
4335 // Clean-up unused labels.
4336 continueLabels.forEach((String key, LabelDefinition label) {
4337 if (!label.isContinueTarget) {
4338 JumpTarget targetElement = label.target;
4339 SwitchCase switchCase = targetElement.statement;
4340 registry.undefineTarget(switchCase);
4341 registry.undefineLabel(label.label);
4342 }
4343 });
4344 // TODO(15575): We should warn if we can detect a fall through
4345 // error.
4346 registry.registerFallThroughError();
4347 }
4348
4349 visitSwitchCase(SwitchCase node) {
4350 node.labelsAndCases.accept(this);
4351 visitIn(node.statements, new BlockScope(scope));
4352 }
4353
4354 visitCaseMatch(CaseMatch node) {
4355 visit(node.expression);
4356 }
4357
4358 visitTryStatement(TryStatement node) {
4359 visit(node.tryBlock);
4360 if (node.catchBlocks.isEmpty && node.finallyBlock == null) {
4361 error(node.getEndToken().next, MessageKind.NO_CATCH_NOR_FINALLY);
4362 }
4363 visit(node.catchBlocks);
4364 visit(node.finallyBlock);
4365 }
4366
4367 visitCatchBlock(CatchBlock node) {
4368 registry.registerCatchStatement();
4369 // Check that if catch part is present, then
4370 // it has one or two formal parameters.
4371 VariableDefinitions exceptionDefinition;
4372 VariableDefinitions stackTraceDefinition;
4373 if (node.formals != null) {
4374 Link<Node> formalsToProcess = node.formals.nodes;
4375 if (formalsToProcess.isEmpty) {
4376 error(node, MessageKind.EMPTY_CATCH_DECLARATION);
4377 } else {
4378 exceptionDefinition = formalsToProcess.head.asVariableDefinitions();
4379 formalsToProcess = formalsToProcess.tail;
4380 if (!formalsToProcess.isEmpty) {
4381 stackTraceDefinition = formalsToProcess.head.asVariableDefinitions();
4382 formalsToProcess = formalsToProcess.tail;
4383 if (!formalsToProcess.isEmpty) {
4384 for (Node extra in formalsToProcess) {
4385 error(extra, MessageKind.EXTRA_CATCH_DECLARATION);
4386 }
4387 }
4388 registry.registerStackTraceInCatch();
4389 }
4390 }
4391
4392 // Check that the formals aren't optional and that they have no
4393 // modifiers or type.
4394 for (Link<Node> link = node.formals.nodes;
4395 !link.isEmpty;
4396 link = link.tail) {
4397 // If the formal parameter is a node list, it means that it is a
4398 // sequence of optional parameters.
4399 NodeList nodeList = link.head.asNodeList();
4400 if (nodeList != null) {
4401 error(nodeList, MessageKind.OPTIONAL_PARAMETER_IN_CATCH);
4402 } else {
4403 VariableDefinitions declaration = link.head;
4404 for (Node modifier in declaration.modifiers.nodes) {
4405 error(modifier, MessageKind.PARAMETER_WITH_MODIFIER_IN_CATCH);
4406 }
4407 TypeAnnotation type = declaration.type;
4408 if (type != null) {
4409 error(type, MessageKind.PARAMETER_WITH_TYPE_IN_CATCH);
4410 }
4411 }
4412 }
4413 }
4414
4415 Scope blockScope = new BlockScope(scope);
4416 doInCheckContext(() => visitIn(node.type, blockScope));
4417 visitIn(node.formals, blockScope);
4418 var oldInCatchBlock = inCatchBlock;
4419 inCatchBlock = true;
4420 visitIn(node.block, blockScope);
4421 inCatchBlock = oldInCatchBlock;
4422
4423 if (node.type != null && exceptionDefinition != null) {
4424 DartType exceptionType = registry.getType(node.type);
4425 Node exceptionVariable = exceptionDefinition.definitions.nodes.head;
4426 VariableElementX exceptionElement =
4427 registry.getDefinition(exceptionVariable);
4428 exceptionElement.variables.type = exceptionType;
4429 }
4430 if (stackTraceDefinition != null) {
4431 Node stackTraceVariable = stackTraceDefinition.definitions.nodes.head;
4432 VariableElementX stackTraceElement =
4433 registry.getDefinition(stackTraceVariable);
4434 registry.registerInstantiatedClass(compiler.stackTraceClass);
4435 stackTraceElement.variables.type = compiler.stackTraceClass.rawType;
4436 }
4437 }
4438
4439 visitTypedef(Typedef node) {
4440 internalError(node, 'typedef');
4441 }
4442 }
4443
4444 class TypeDefinitionVisitor extends MappingVisitor<DartType> {
4445 Scope scope;
4446 final TypeDeclarationElement enclosingElement;
4447 TypeDeclarationElement get element => enclosingElement;
4448
4449 TypeDefinitionVisitor(Compiler compiler,
4450 TypeDeclarationElement element,
4451 ResolutionRegistry registry)
4452 : this.enclosingElement = element,
4453 scope = Scope.buildEnclosingScope(element),
4454 super(compiler, registry);
4455
4456 DartType get objectType => compiler.objectClass.rawType;
4457
4458 void resolveTypeVariableBounds(NodeList node) {
4459 if (node == null) return;
4460
4461 Setlet<String> nameSet = new Setlet<String>();
4462 // Resolve the bounds of type variables.
4463 Iterator<DartType> types = element.typeVariables.iterator;
4464 Link<Node> nodeLink = node.nodes;
4465 while (!nodeLink.isEmpty) {
4466 types.moveNext();
4467 TypeVariableType typeVariable = types.current;
4468 String typeName = typeVariable.name;
4469 TypeVariable typeNode = nodeLink.head;
4470 registry.useType(typeNode, typeVariable);
4471 if (nameSet.contains(typeName)) {
4472 error(typeNode, MessageKind.DUPLICATE_TYPE_VARIABLE_NAME,
4473 {'typeVariableName': typeName});
4474 }
4475 nameSet.add(typeName);
4476
4477 TypeVariableElementX variableElement = typeVariable.element;
4478 if (typeNode.bound != null) {
4479 DartType boundType = typeResolver.resolveTypeAnnotation(
4480 this, typeNode.bound);
4481 variableElement.boundCache = boundType;
4482
4483 void checkTypeVariableBound() {
4484 Link<TypeVariableElement> seenTypeVariables =
4485 const Link<TypeVariableElement>();
4486 seenTypeVariables = seenTypeVariables.prepend(variableElement);
4487 DartType bound = boundType;
4488 while (bound.isTypeVariable) {
4489 TypeVariableElement element = bound.element;
4490 if (seenTypeVariables.contains(element)) {
4491 if (identical(element, variableElement)) {
4492 // Only report an error on the checked type variable to avoid
4493 // generating multiple errors for the same cyclicity.
4494 warning(typeNode.name, MessageKind.CYCLIC_TYPE_VARIABLE,
4495 {'typeVariableName': variableElement.name});
4496 }
4497 break;
4498 }
4499 seenTypeVariables = seenTypeVariables.prepend(element);
4500 bound = element.bound;
4501 }
4502 }
4503 addDeferredAction(element, checkTypeVariableBound);
4504 } else {
4505 variableElement.boundCache = objectType;
4506 }
4507 nodeLink = nodeLink.tail;
4508 }
4509 assert(!types.moveNext());
4510 }
4511 }
4512
4513 class TypedefResolverVisitor extends TypeDefinitionVisitor {
4514 TypedefElementX get element => enclosingElement;
4515
4516 TypedefResolverVisitor(Compiler compiler,
4517 TypedefElement typedefElement,
4518 ResolutionRegistry registry)
4519 : super(compiler, typedefElement, registry);
4520
4521 visitTypedef(Typedef node) {
4522 TypedefType type = element.computeType(compiler);
4523 scope = new TypeDeclarationScope(scope, element);
4524 resolveTypeVariableBounds(node.typeParameters);
4525
4526 FunctionSignature signature = SignatureResolver.analyze(
4527 compiler, node.formals, node.returnType, element, registry,
4528 defaultValuesError: MessageKind.TYPEDEF_FORMAL_WITH_DEFAULT);
4529 element.functionSignature = signature;
4530
4531 scope = new MethodScope(scope, element);
4532 signature.forEachParameter(addToScope);
4533
4534 element.alias = signature.type;
4535
4536 void checkCyclicReference() {
4537 element.checkCyclicReference(compiler);
4538 }
4539 addDeferredAction(element, checkCyclicReference);
4540 }
4541 }
4542
4543 // TODO(johnniwinther): Replace with a traversal on the AST when the type
4544 // annotations in typedef alias are stored in a [TreeElements] mapping.
4545 class TypedefCyclicVisitor extends BaseDartTypeVisitor {
4546 final Compiler compiler;
4547 final TypedefElementX element;
4548 bool hasCyclicReference = false;
4549
4550 Link<TypedefElement> seenTypedefs = const Link<TypedefElement>();
4551
4552 int seenTypedefsCount = 0;
4553
4554 Link<TypeVariableElement> seenTypeVariables =
4555 const Link<TypeVariableElement>();
4556
4557 TypedefCyclicVisitor(Compiler this.compiler, TypedefElement this.element);
4558
4559 visitType(DartType type, _) {
4560 // Do nothing.
4561 }
4562
4563 visitTypedefType(TypedefType type, _) {
4564 TypedefElementX typedefElement = type.element;
4565 if (seenTypedefs.contains(typedefElement)) {
4566 if (!hasCyclicReference && identical(element, typedefElement)) {
4567 // Only report an error on the checked typedef to avoid generating
4568 // multiple errors for the same cyclicity.
4569 hasCyclicReference = true;
4570 if (seenTypedefsCount == 1) {
4571 // Direct cyclicity.
4572 compiler.reportError(element,
4573 MessageKind.CYCLIC_TYPEDEF,
4574 {'typedefName': element.name});
4575 } else if (seenTypedefsCount == 2) {
4576 // Cyclicity through one other typedef.
4577 compiler.reportError(element,
4578 MessageKind.CYCLIC_TYPEDEF_ONE,
4579 {'typedefName': element.name,
4580 'otherTypedefName': seenTypedefs.head.name});
4581 } else {
4582 // Cyclicity through more than one other typedef.
4583 for (TypedefElement cycle in seenTypedefs) {
4584 if (!identical(typedefElement, cycle)) {
4585 compiler.reportError(element,
4586 MessageKind.CYCLIC_TYPEDEF_ONE,
4587 {'typedefName': element.name,
4588 'otherTypedefName': cycle.name});
4589 }
4590 }
4591 }
4592 ErroneousElementX erroneousElement = new ErroneousElementX(
4593 MessageKind.CYCLIC_TYPEDEF,
4594 {'typedefName': element.name},
4595 element.name, element);
4596 element.alias =
4597 new MalformedType(erroneousElement, typedefElement.alias);
4598 element.hasBeenCheckedForCycles = true;
4599 }
4600 } else {
4601 seenTypedefs = seenTypedefs.prepend(typedefElement);
4602 seenTypedefsCount++;
4603 type.visitChildren(this, null);
4604 typedefElement.alias.accept(this, null);
4605 seenTypedefs = seenTypedefs.tail;
4606 seenTypedefsCount--;
4607 }
4608 }
4609
4610 visitFunctionType(FunctionType type, _) {
4611 type.visitChildren(this, null);
4612 }
4613
4614 visitInterfaceType(InterfaceType type, _) {
4615 type.visitChildren(this, null);
4616 }
4617
4618 visitTypeVariableType(TypeVariableType type, _) {
4619 TypeVariableElement typeVariableElement = type.element;
4620 if (seenTypeVariables.contains(typeVariableElement)) {
4621 // Avoid running in cycles on cyclic type variable bounds.
4622 // Cyclicity is reported elsewhere.
4623 return;
4624 }
4625 seenTypeVariables = seenTypeVariables.prepend(typeVariableElement);
4626 typeVariableElement.bound.accept(this, null);
4627 seenTypeVariables = seenTypeVariables.tail;
4628 }
4629 }
4630
4631 /**
4632 * The implementation of [ResolverTask.resolveClass].
4633 *
4634 * This visitor has to be extra careful as it is building the basic
4635 * element information, and cannot safely look at other elements as
4636 * this may lead to cycles.
4637 *
4638 * This visitor can assume that the supertypes have already been
4639 * resolved, but it cannot call [ResolverTask.resolveClass] directly
4640 * or indirectly (through [ClassElement.ensureResolved]) for any other
4641 * types.
4642 */
4643 class ClassResolverVisitor extends TypeDefinitionVisitor {
4644 BaseClassElementX get element => enclosingElement;
4645
4646 ClassResolverVisitor(Compiler compiler,
4647 ClassElement classElement,
4648 ResolutionRegistry registry)
4649 : super(compiler, classElement, registry);
4650
4651 DartType visitClassNode(ClassNode node) {
4652 if (element == null) {
4653 throw compiler.internalError(node, 'element is null');
4654 }
4655 if (element.resolutionState != STATE_STARTED) {
4656 throw compiler.internalError(element,
4657 'cyclic resolution of class $element');
4658 }
4659
4660 InterfaceType type = element.computeType(compiler);
4661 scope = new TypeDeclarationScope(scope, element);
4662 // TODO(ahe): It is not safe to call resolveTypeVariableBounds yet.
4663 // As a side-effect, this may get us back here trying to
4664 // resolve this class again.
4665 resolveTypeVariableBounds(node.typeParameters);
4666
4667 // Setup the supertype for the element (if there is a cycle in the
4668 // class hierarchy, it has already been set to Object).
4669 if (element.supertype == null && node.superclass != null) {
4670 MixinApplication superMixin = node.superclass.asMixinApplication();
4671 if (superMixin != null) {
4672 DartType supertype = resolveSupertype(element, superMixin.superclass);
4673 Link<Node> link = superMixin.mixins.nodes;
4674 while (!link.isEmpty) {
4675 supertype = applyMixin(supertype,
4676 checkMixinType(link.head), link.head);
4677 link = link.tail;
4678 }
4679 element.supertype = supertype;
4680 } else {
4681 element.supertype = resolveSupertype(element, node.superclass);
4682 }
4683 }
4684 // If the super type isn't specified, we provide a default. The language
4685 // specifies [Object] but the backend can pick a specific 'implementation'
4686 // of Object - the JavaScript backend chooses between Object and
4687 // Interceptor.
4688 if (element.supertype == null) {
4689 ClassElement superElement = registry.defaultSuperclass(element);
4690 // Avoid making the superclass (usually Object) extend itself.
4691 if (element != superElement) {
4692 if (superElement == null) {
4693 compiler.internalError(node,
4694 "Cannot resolve default superclass for $element.");
4695 } else {
4696 superElement.ensureResolved(compiler);
4697 }
4698 element.supertype = superElement.computeType(compiler);
4699 }
4700 }
4701
4702 if (element.interfaces == null) {
4703 element.interfaces = resolveInterfaces(node.interfaces, node.superclass);
4704 } else {
4705 assert(invariant(element, element.hasIncompleteHierarchy));
4706 }
4707 calculateAllSupertypes(element);
4708
4709 if (!element.hasConstructor) {
4710 Element superMember = element.superclass.localLookup('');
4711 if (superMember == null || !superMember.isGenerativeConstructor) {
4712 MessageKind kind = MessageKind.CANNOT_FIND_CONSTRUCTOR;
4713 Map arguments = {'constructorName': ''};
4714 // TODO(ahe): Why is this a compile-time error? Or if it is an error,
4715 // why do we bother to registerThrowNoSuchMethod below?
4716 compiler.reportError(node, kind, arguments);
4717 superMember = new ErroneousElementX(
4718 kind, arguments, '', element);
4719 registry.registerThrowNoSuchMethod();
4720 } else {
4721 ConstructorElement superConstructor = superMember;
4722 Selector callToMatch = new Selector.call("", element.library, 0);
4723 superConstructor.computeSignature(compiler);
4724 if (!callToMatch.applies(superConstructor, compiler.world)) {
4725 MessageKind kind = MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT;
4726 compiler.reportError(node, kind);
4727 superMember = new ErroneousElementX(kind, {}, '', element);
4728 }
4729 }
4730 FunctionElement constructor =
4731 new SynthesizedConstructorElementX.forDefault(superMember, element);
4732 if (superMember.isErroneous) {
4733 compiler.elementsWithCompileTimeErrors.add(constructor);
4734 }
4735 element.setDefaultConstructor(constructor, compiler);
4736 }
4737 return element.computeType(compiler);
4738 }
4739
4740 @override
4741 DartType visitEnum(Enum node) {
4742 if (element == null) {
4743 throw compiler.internalError(node, 'element is null');
4744 }
4745 if (element.resolutionState != STATE_STARTED) {
4746 throw compiler.internalError(element,
4747 'cyclic resolution of class $element');
4748 }
4749
4750 InterfaceType enumType = element.computeType(compiler);
4751 element.supertype = compiler.objectClass.computeType(compiler);
4752 element.interfaces = const Link<DartType>();
4753 calculateAllSupertypes(element);
4754
4755 if (node.names.nodes.isEmpty) {
4756 compiler.reportError(node,
4757 MessageKind.EMPTY_ENUM_DECLARATION,
4758 {'enumName': element.name});
4759 }
4760
4761 EnumCreator creator = new EnumCreator(compiler, element);
4762 creator.createMembers();
4763 return enumType;
4764 }
4765
4766 /// Resolves the mixed type for [mixinNode] and checks that the the mixin type
4767 /// is a valid, non-blacklisted interface type. The mixin type is returned.
4768 DartType checkMixinType(TypeAnnotation mixinNode) {
4769 DartType mixinType = resolveType(mixinNode);
4770 if (isBlackListed(mixinType)) {
4771 compiler.reportError(mixinNode,
4772 MessageKind.CANNOT_MIXIN, {'type': mixinType});
4773 } else if (mixinType.isTypeVariable) {
4774 compiler.reportError(mixinNode, MessageKind.CLASS_NAME_EXPECTED);
4775 } else if (mixinType.isMalformed) {
4776 compiler.reportError(mixinNode, MessageKind.CANNOT_MIXIN_MALFORMED,
4777 {'className': element.name, 'malformedType': mixinType});
4778 } else if (mixinType.isEnumType) {
4779 compiler.reportError(mixinNode, MessageKind.CANNOT_MIXIN_ENUM,
4780 {'className': element.name, 'enumType': mixinType});
4781 }
4782 return mixinType;
4783 }
4784
4785 DartType visitNamedMixinApplication(NamedMixinApplication node) {
4786 if (element == null) {
4787 throw compiler.internalError(node, 'element is null');
4788 }
4789 if (element.resolutionState != STATE_STARTED) {
4790 throw compiler.internalError(element,
4791 'cyclic resolution of class $element');
4792 }
4793
4794 if (identical(node.classKeyword.stringValue, 'typedef')) {
4795 // TODO(aprelev@gmail.com): Remove this deprecation diagnostic
4796 // together with corresponding TODO in parser.dart.
4797 compiler.reportWarning(node.classKeyword,
4798 MessageKind.DEPRECATED_TYPEDEF_MIXIN_SYNTAX);
4799 }
4800
4801 InterfaceType type = element.computeType(compiler);
4802 scope = new TypeDeclarationScope(scope, element);
4803 resolveTypeVariableBounds(node.typeParameters);
4804
4805 // Generate anonymous mixin application elements for the
4806 // intermediate mixin applications (excluding the last).
4807 DartType supertype = resolveSupertype(element, node.superclass);
4808 Link<Node> link = node.mixins.nodes;
4809 while (!link.tail.isEmpty) {
4810 supertype = applyMixin(supertype, checkMixinType(link.head), link.head);
4811 link = link.tail;
4812 }
4813 doApplyMixinTo(element, supertype, checkMixinType(link.head));
4814 return element.computeType(compiler);
4815 }
4816
4817 DartType applyMixin(DartType supertype, DartType mixinType, Node node) {
4818 String superName = supertype.name;
4819 String mixinName = mixinType.name;
4820 MixinApplicationElementX mixinApplication = new MixinApplicationElementX(
4821 "${superName}+${mixinName}",
4822 element.compilationUnit,
4823 compiler.getNextFreeClassId(),
4824 node,
4825 new Modifiers.withFlags(new NodeList.empty(), Modifiers.FLAG_ABSTRACT));
4826 // Create synthetic type variables for the mixin application.
4827 List<DartType> typeVariables = <DartType>[];
4828 element.typeVariables.forEach((TypeVariableType type) {
4829 TypeVariableElementX typeVariableElement = new TypeVariableElementX(
4830 type.name, mixinApplication, type.element.node);
4831 TypeVariableType typeVariable = new TypeVariableType(typeVariableElement);
4832 typeVariables.add(typeVariable);
4833 });
4834 // Setup bounds on the synthetic type variables.
4835 int index = 0;
4836 element.typeVariables.forEach((TypeVariableType type) {
4837 TypeVariableType typeVariable = typeVariables[index++];
4838 TypeVariableElementX typeVariableElement = typeVariable.element;
4839 typeVariableElement.typeCache = typeVariable;
4840 typeVariableElement.boundCache =
4841 type.element.bound.subst(typeVariables, element.typeVariables);
4842 });
4843 // Setup this and raw type for the mixin application.
4844 mixinApplication.computeThisAndRawType(compiler, typeVariables);
4845 // Substitute in synthetic type variables in super and mixin types.
4846 supertype = supertype.subst(typeVariables, element.typeVariables);
4847 mixinType = mixinType.subst(typeVariables, element.typeVariables);
4848
4849 doApplyMixinTo(mixinApplication, supertype, mixinType);
4850 mixinApplication.resolutionState = STATE_DONE;
4851 mixinApplication.supertypeLoadState = STATE_DONE;
4852 // Replace the synthetic type variables by the original type variables in
4853 // the returned type (which should be the type actually extended).
4854 InterfaceType mixinThisType = mixinApplication.computeType(compiler);
4855 return mixinThisType.subst(element.typeVariables,
4856 mixinThisType.typeArguments);
4857 }
4858
4859 bool isDefaultConstructor(FunctionElement constructor) {
4860 return constructor.name == '' &&
4861 constructor.computeSignature(compiler).parameterCount == 0;
4862 }
4863
4864 FunctionElement createForwardingConstructor(ConstructorElement target,
4865 ClassElement enclosing) {
4866 return new SynthesizedConstructorElementX.notForDefault(
4867 target.name, target, enclosing);
4868 }
4869
4870 void doApplyMixinTo(MixinApplicationElementX mixinApplication,
4871 DartType supertype,
4872 DartType mixinType) {
4873 Node node = mixinApplication.parseNode(compiler);
4874
4875 if (mixinApplication.supertype != null) {
4876 // [supertype] is not null if there was a cycle.
4877 assert(invariant(node, compiler.compilationFailed));
4878 supertype = mixinApplication.supertype;
4879 assert(invariant(node, supertype.element == compiler.objectClass));
4880 } else {
4881 mixinApplication.supertype = supertype;
4882 }
4883
4884 // Named mixin application may have an 'implements' clause.
4885 NamedMixinApplication namedMixinApplication =
4886 node.asNamedMixinApplication();
4887 Link<DartType> interfaces = (namedMixinApplication != null)
4888 ? resolveInterfaces(namedMixinApplication.interfaces,
4889 namedMixinApplication.superclass)
4890 : const Link<DartType>();
4891
4892 // The class that is the result of a mixin application implements
4893 // the interface of the class that was mixed in so always prepend
4894 // that to the interface list.
4895 if (mixinApplication.interfaces == null) {
4896 if (mixinType.isInterfaceType) {
4897 // Avoid malformed types in the interfaces.
4898 interfaces = interfaces.prepend(mixinType);
4899 }
4900 mixinApplication.interfaces = interfaces;
4901 } else {
4902 assert(invariant(mixinApplication,
4903 mixinApplication.hasIncompleteHierarchy));
4904 }
4905
4906 ClassElement superclass = supertype.element;
4907 if (mixinType.kind != TypeKind.INTERFACE) {
4908 mixinApplication.hasIncompleteHierarchy = true;
4909 mixinApplication.allSupertypesAndSelf = superclass.allSupertypesAndSelf;
4910 return;
4911 }
4912
4913 assert(mixinApplication.mixinType == null);
4914 mixinApplication.mixinType = resolveMixinFor(mixinApplication, mixinType);
4915
4916 // Create forwarding constructors for constructor defined in the superclass
4917 // because they are now hidden by the mixin application.
4918 superclass.forEachLocalMember((Element member) {
4919 if (!member.isGenerativeConstructor) return;
4920 FunctionElement forwarder =
4921 createForwardingConstructor(member, mixinApplication);
4922 if (isPrivateName(member.name) &&
4923 mixinApplication.library != superclass.library) {
4924 // Do not create a forwarder to the super constructor, because the mixin
4925 // application is in a different library than the constructor in the
4926 // super class and it is not possible to call that constructor from the
4927 // library using the mixin application.
4928 return;
4929 }
4930 mixinApplication.addConstructor(forwarder);
4931 });
4932 calculateAllSupertypes(mixinApplication);
4933 }
4934
4935 InterfaceType resolveMixinFor(MixinApplicationElement mixinApplication,
4936 DartType mixinType) {
4937 ClassElement mixin = mixinType.element;
4938 mixin.ensureResolved(compiler);
4939
4940 // Check for cycles in the mixin chain.
4941 ClassElement previous = mixinApplication; // For better error messages.
4942 ClassElement current = mixin;
4943 while (current != null && current.isMixinApplication) {
4944 MixinApplicationElement currentMixinApplication = current;
4945 if (currentMixinApplication == mixinApplication) {
4946 compiler.reportError(
4947 mixinApplication, MessageKind.ILLEGAL_MIXIN_CYCLE,
4948 {'mixinName1': current.name, 'mixinName2': previous.name});
4949 // We have found a cycle in the mixin chain. Return null as
4950 // the mixin for this application to avoid getting into
4951 // infinite recursion when traversing members.
4952 return null;
4953 }
4954 previous = current;
4955 current = currentMixinApplication.mixin;
4956 }
4957 registry.registerMixinUse(mixinApplication, mixin);
4958 return mixinType;
4959 }
4960
4961 DartType resolveType(TypeAnnotation node) {
4962 return typeResolver.resolveTypeAnnotation(this, node);
4963 }
4964
4965 DartType resolveSupertype(ClassElement cls, TypeAnnotation superclass) {
4966 DartType supertype = resolveType(superclass);
4967 if (supertype != null) {
4968 if (supertype.isMalformed) {
4969 compiler.reportError(superclass, MessageKind.CANNOT_EXTEND_MALFORMED,
4970 {'className': element.name, 'malformedType': supertype});
4971 return objectType;
4972 } else if (supertype.isEnumType) {
4973 compiler.reportError(superclass, MessageKind.CANNOT_EXTEND_ENUM,
4974 {'className': element.name, 'enumType': supertype});
4975 return objectType;
4976 } else if (!supertype.isInterfaceType) {
4977 compiler.reportError(superclass.typeName,
4978 MessageKind.CLASS_NAME_EXPECTED);
4979 return objectType;
4980 } else if (isBlackListed(supertype)) {
4981 compiler.reportError(superclass, MessageKind.CANNOT_EXTEND,
4982 {'type': supertype});
4983 return objectType;
4984 }
4985 }
4986 return supertype;
4987 }
4988
4989 Link<DartType> resolveInterfaces(NodeList interfaces, Node superclass) {
4990 Link<DartType> result = const Link<DartType>();
4991 if (interfaces == null) return result;
4992 for (Link<Node> link = interfaces.nodes; !link.isEmpty; link = link.tail) {
4993 DartType interfaceType = resolveType(link.head);
4994 if (interfaceType != null) {
4995 if (interfaceType.isMalformed) {
4996 compiler.reportError(superclass,
4997 MessageKind.CANNOT_IMPLEMENT_MALFORMED,
4998 {'className': element.name, 'malformedType': interfaceType});
4999 } else if (interfaceType.isEnumType) {
5000 compiler.reportError(superclass,
5001 MessageKind.CANNOT_IMPLEMENT_ENUM,
5002 {'className': element.name, 'enumType': interfaceType});
5003 } else if (!interfaceType.isInterfaceType) {
5004 // TODO(johnniwinther): Handle dynamic.
5005 TypeAnnotation typeAnnotation = link.head;
5006 error(typeAnnotation.typeName, MessageKind.CLASS_NAME_EXPECTED);
5007 } else {
5008 if (interfaceType == element.supertype) {
5009 compiler.reportError(
5010 superclass,
5011 MessageKind.DUPLICATE_EXTENDS_IMPLEMENTS,
5012 {'type': interfaceType});
5013 compiler.reportError(
5014 link.head,
5015 MessageKind.DUPLICATE_EXTENDS_IMPLEMENTS,
5016 {'type': interfaceType});
5017 }
5018 if (result.contains(interfaceType)) {
5019 compiler.reportError(
5020 link.head,
5021 MessageKind.DUPLICATE_IMPLEMENTS,
5022 {'type': interfaceType});
5023 }
5024 result = result.prepend(interfaceType);
5025 if (isBlackListed(interfaceType)) {
5026 error(link.head, MessageKind.CANNOT_IMPLEMENT,
5027 {'type': interfaceType});
5028 }
5029 }
5030 }
5031 }
5032 return result;
5033 }
5034
5035 /**
5036 * Compute the list of all supertypes.
5037 *
5038 * The elements of this list are ordered as follows: first the supertype that
5039 * the class extends, then the implemented interfaces, and then the supertypes
5040 * of these. The class [Object] appears only once, at the end of the list.
5041 *
5042 * For example, for a class `class C extends S implements I1, I2`, we compute
5043 * supertypes(C) = [S, I1, I2] ++ supertypes(S) ++ supertypes(I1)
5044 * ++ supertypes(I2),
5045 * where ++ stands for list concatenation.
5046 *
5047 * This order makes sure that if a class implements an interface twice with
5048 * different type arguments, the type used in the most specific class comes
5049 * first.
5050 */
5051 void calculateAllSupertypes(BaseClassElementX cls) {
5052 if (cls.allSupertypesAndSelf != null) return;
5053 final DartType supertype = cls.supertype;
5054 if (supertype != null) {
5055 OrderedTypeSetBuilder allSupertypes = new OrderedTypeSetBuilder(cls);
5056 // TODO(15296): Collapse these iterations to one when the order is not
5057 // needed.
5058 allSupertypes.add(compiler, supertype);
5059 for (Link<DartType> interfaces = cls.interfaces;
5060 !interfaces.isEmpty;
5061 interfaces = interfaces.tail) {
5062 allSupertypes.add(compiler, interfaces.head);
5063 }
5064
5065 addAllSupertypes(allSupertypes, supertype);
5066 for (Link<DartType> interfaces = cls.interfaces;
5067 !interfaces.isEmpty;
5068 interfaces = interfaces.tail) {
5069 addAllSupertypes(allSupertypes, interfaces.head);
5070 }
5071 allSupertypes.add(compiler, cls.computeType(compiler));
5072 cls.allSupertypesAndSelf = allSupertypes.toTypeSet();
5073 } else {
5074 assert(identical(cls, compiler.objectClass));
5075 cls.allSupertypesAndSelf =
5076 new OrderedTypeSet.singleton(cls.computeType(compiler));
5077 }
5078 }
5079
5080 /**
5081 * Adds [type] and all supertypes of [type] to [allSupertypes] while
5082 * substituting type variables.
5083 */
5084 void addAllSupertypes(OrderedTypeSetBuilder allSupertypes,
5085 InterfaceType type) {
5086 ClassElement classElement = type.element;
5087 Link<DartType> supertypes = classElement.allSupertypes;
5088 assert(invariant(element, supertypes != null,
5089 message: "Supertypes not computed on $classElement "
5090 "during resolution of $element"));
5091 while (!supertypes.isEmpty) {
5092 DartType supertype = supertypes.head;
5093 allSupertypes.add(compiler, supertype.substByContext(type));
5094 supertypes = supertypes.tail;
5095 }
5096 }
5097
5098 isBlackListed(DartType type) {
5099 LibraryElement lib = element.library;
5100 return
5101 !identical(lib, compiler.coreLibrary) &&
5102 !compiler.backend.isBackendLibrary(lib) &&
5103 (type.isDynamic ||
5104 identical(type.element, compiler.boolClass) ||
5105 identical(type.element, compiler.numClass) ||
5106 identical(type.element, compiler.intClass) ||
5107 identical(type.element, compiler.doubleClass) ||
5108 identical(type.element, compiler.stringClass) ||
5109 identical(type.element, compiler.nullClass));
5110 }
5111 }
5112
5113 class ClassSupertypeResolver extends CommonResolverVisitor {
5114 Scope context;
5115 ClassElement classElement;
5116
5117 ClassSupertypeResolver(Compiler compiler, ClassElement cls)
5118 : context = Scope.buildEnclosingScope(cls),
5119 this.classElement = cls,
5120 super(compiler);
5121
5122 void loadSupertype(ClassElement element, Node from) {
5123 compiler.resolver.loadSupertypes(element, from);
5124 element.ensureResolved(compiler);
5125 }
5126
5127 void visitNodeList(NodeList node) {
5128 if (node != null) {
5129 for (Link<Node> link = node.nodes; !link.isEmpty; link = link.tail) {
5130 link.head.accept(this);
5131 }
5132 }
5133 }
5134
5135 void visitClassNode(ClassNode node) {
5136 if (node.superclass == null) {
5137 if (!identical(classElement, compiler.objectClass)) {
5138 loadSupertype(compiler.objectClass, node);
5139 }
5140 } else {
5141 node.superclass.accept(this);
5142 }
5143 visitNodeList(node.interfaces);
5144 }
5145
5146 void visitEnum(Enum node) {
5147 loadSupertype(compiler.objectClass, node);
5148 }
5149
5150 void visitMixinApplication(MixinApplication node) {
5151 node.superclass.accept(this);
5152 visitNodeList(node.mixins);
5153 }
5154
5155 void visitNamedMixinApplication(NamedMixinApplication node) {
5156 node.superclass.accept(this);
5157 visitNodeList(node.mixins);
5158 visitNodeList(node.interfaces);
5159 }
5160
5161 void visitTypeAnnotation(TypeAnnotation node) {
5162 node.typeName.accept(this);
5163 }
5164
5165 void visitIdentifier(Identifier node) {
5166 Element element = lookupInScope(compiler, node, context, node.source);
5167 if (element != null && element.isClass) {
5168 loadSupertype(element, node);
5169 }
5170 }
5171
5172 void visitSend(Send node) {
5173 Identifier prefix = node.receiver.asIdentifier();
5174 if (prefix == null) {
5175 error(node.receiver, MessageKind.NOT_A_PREFIX, {'node': node.receiver});
5176 return;
5177 }
5178 Element element = lookupInScope(compiler, prefix, context, prefix.source);
5179 if (element == null || !identical(element.kind, ElementKind.PREFIX)) {
5180 error(node.receiver, MessageKind.NOT_A_PREFIX, {'node': node.receiver});
5181 return;
5182 }
5183 PrefixElement prefixElement = element;
5184 Identifier selector = node.selector.asIdentifier();
5185 var e = prefixElement.lookupLocalMember(selector.source);
5186 if (e == null || !e.impliesType) {
5187 error(node.selector, MessageKind.CANNOT_RESOLVE_TYPE,
5188 {'typeName': node.selector});
5189 return;
5190 }
5191 loadSupertype(e, node);
5192 }
5193 }
5194
5195 class VariableDefinitionsVisitor extends CommonResolverVisitor<Identifier> {
5196 VariableDefinitions definitions;
5197 ResolverVisitor resolver;
5198 VariableList variables;
5199
5200 VariableDefinitionsVisitor(Compiler compiler,
5201 this.definitions,
5202 this.resolver,
5203 this.variables)
5204 : super(compiler) {
5205 }
5206
5207 ResolutionRegistry get registry => resolver.registry;
5208
5209 Identifier visitSendSet(SendSet node) {
5210 assert(node.arguments.tail.isEmpty); // Sanity check
5211 Identifier identifier = node.selector;
5212 String name = identifier.source;
5213 VariableDefinitionScope scope =
5214 new VariableDefinitionScope(resolver.scope, name);
5215 resolver.visitIn(node.arguments.head, scope);
5216 if (scope.variableReferencedInInitializer) {
5217 compiler.reportError(
5218 identifier, MessageKind.REFERENCE_IN_INITIALIZATION,
5219 {'variableName': name});
5220 }
5221 return identifier;
5222 }
5223
5224 Identifier visitIdentifier(Identifier node) {
5225 // The variable is initialized to null.
5226 registry.registerInstantiatedClass(compiler.nullClass);
5227 if (definitions.modifiers.isConst) {
5228 compiler.reportError(node, MessageKind.CONST_WITHOUT_INITIALIZER);
5229 }
5230 if (definitions.modifiers.isFinal &&
5231 !resolver.allowFinalWithoutInitializer) {
5232 compiler.reportError(node, MessageKind.FINAL_WITHOUT_INITIALIZER);
5233 }
5234 return node;
5235 }
5236
5237 visitNodeList(NodeList node) {
5238 for (Link<Node> link = node.nodes; !link.isEmpty; link = link.tail) {
5239 Identifier name = visit(link.head);
5240 LocalVariableElementX element = new LocalVariableElementX(
5241 name.source, resolver.enclosingElement,
5242 variables, name.token);
5243 resolver.defineLocalVariable(link.head, element);
5244 resolver.addToScope(element);
5245 if (definitions.modifiers.isConst) {
5246 compiler.enqueuer.resolution.addDeferredAction(element, () {
5247 element.constant =
5248 compiler.resolver.constantCompiler.compileConstant(element);
5249 });
5250 }
5251 }
5252 }
5253 }
5254
5255 class ConstructorResolver extends CommonResolverVisitor<Element> {
5256 final ResolverVisitor resolver;
5257 bool inConstContext;
5258 DartType type;
5259
5260 ConstructorResolver(Compiler compiler, this.resolver,
5261 {bool this.inConstContext: false})
5262 : super(compiler);
5263
5264 ResolutionRegistry get registry => resolver.registry;
5265
5266 visitNode(Node node) {
5267 throw 'not supported';
5268 }
5269
5270 ErroneousConstructorElementX failOrReturnErroneousConstructorElement(
5271 Spannable diagnosticNode,
5272 Element enclosing,
5273 String name,
5274 MessageKind kind,
5275 Map arguments,
5276 {bool isError: false,
5277 bool missingConstructor: false}) {
5278 if (missingConstructor) {
5279 registry.registerThrowNoSuchMethod();
5280 } else {
5281 registry.registerThrowRuntimeError();
5282 }
5283 if (isError || inConstContext) {
5284 compiler.reportError(diagnosticNode, kind, arguments);
5285 } else {
5286 compiler.reportWarning(diagnosticNode, kind, arguments);
5287 }
5288 return new ErroneousConstructorElementX(
5289 kind, arguments, name, enclosing);
5290 }
5291
5292 FunctionElement resolveConstructor(ClassElement cls,
5293 Node diagnosticNode,
5294 String constructorName) {
5295 cls.ensureResolved(compiler);
5296 Element result = cls.lookupConstructor(constructorName);
5297 // TODO(johnniwinther): Use [Name] for lookup.
5298 if (isPrivateName(constructorName) &&
5299 resolver.enclosingElement.library != cls.library) {
5300 result = null;
5301 }
5302 if (result == null) {
5303 String fullConstructorName = Elements.constructorNameForDiagnostics(
5304 cls.name,
5305 constructorName);
5306 return failOrReturnErroneousConstructorElement(
5307 diagnosticNode,
5308 cls, constructorName,
5309 MessageKind.CANNOT_FIND_CONSTRUCTOR,
5310 {'constructorName': fullConstructorName},
5311 missingConstructor: true);
5312 } else if (inConstContext && !result.isConst) {
5313 error(diagnosticNode, MessageKind.CONSTRUCTOR_IS_NOT_CONST);
5314 }
5315 return result;
5316 }
5317
5318 Element visitNewExpression(NewExpression node) {
5319 inConstContext = node.isConst;
5320 Node selector = node.send.selector;
5321 Element element = visit(selector);
5322 assert(invariant(selector, element != null,
5323 message: 'No element return for $selector.'));
5324 return finishConstructorReference(element, node.send.selector, node);
5325 }
5326
5327 /// Finishes resolution of a constructor reference and records the
5328 /// type of the constructed instance on [expression].
5329 FunctionElement finishConstructorReference(Element element,
5330 Node diagnosticNode,
5331 Node expression) {
5332 assert(invariant(diagnosticNode, element != null,
5333 message: 'No element return for $diagnosticNode.'));
5334 // Find the unnamed constructor if the reference resolved to a
5335 // class.
5336 if (!Elements.isUnresolved(element) && !element.isConstructor) {
5337 if (element.isClass) {
5338 ClassElement cls = element;
5339 cls.ensureResolved(compiler);
5340 // The unnamed constructor may not exist, so [e] may become unresolved.
5341 element = resolveConstructor(cls, diagnosticNode, '');
5342 } else {
5343 element = failOrReturnErroneousConstructorElement(
5344 diagnosticNode,
5345 element, element.name,
5346 MessageKind.NOT_A_TYPE, {'node': diagnosticNode});
5347 }
5348 } else if (element.isErroneous && element is! ErroneousElementX) {
5349 // Parser error. The error has already been reported.
5350 element = new ErroneousConstructorElementX(
5351 MessageKind.NOT_A_TYPE, {'node': diagnosticNode},
5352 element.name, element);
5353 registry.registerThrowRuntimeError();
5354 }
5355
5356 if (type == null) {
5357 if (Elements.isUnresolved(element)) {
5358 type = const DynamicType();
5359 } else {
5360 type = element.enclosingClass.rawType;
5361 }
5362 }
5363 resolver.registry.setType(expression, type);
5364 return element;
5365 }
5366
5367 Element visitTypeAnnotation(TypeAnnotation node) {
5368 assert(invariant(node, type == null));
5369 // This is not really resolving a type-annotation, but the name of the
5370 // constructor. Therefore we allow deferred types.
5371 type = resolver.resolveTypeAnnotation(node,
5372 malformedIsError: inConstContext,
5373 deferredIsMalformed: false);
5374 registry.registerRequiredType(type, resolver.enclosingElement);
5375 return type.element;
5376 }
5377
5378 Element visitSend(Send node) {
5379 Element element = visit(node.receiver);
5380 assert(invariant(node.receiver, element != null,
5381 message: 'No element return for $node.receiver.'));
5382 if (Elements.isUnresolved(element)) return element;
5383 Identifier name = node.selector.asIdentifier();
5384 if (name == null) internalError(node.selector, 'unexpected node');
5385
5386 if (element.isClass) {
5387 ClassElement cls = element;
5388 cls.ensureResolved(compiler);
5389 return resolveConstructor(cls, name, name.source);
5390 } else if (element.isPrefix) {
5391 PrefixElement prefix = element;
5392 element = prefix.lookupLocalMember(name.source);
5393 element = Elements.unwrap(element, compiler, node);
5394 if (element == null) {
5395 return failOrReturnErroneousConstructorElement(
5396 name,
5397 resolver.enclosingElement, name.source,
5398 MessageKind.CANNOT_RESOLVE, {'name': name});
5399 } else if (!element.isClass) {
5400 return failOrReturnErroneousConstructorElement(
5401 name,
5402 resolver.enclosingElement, name.source,
5403 MessageKind.NOT_A_TYPE, {'node': name},
5404 isError: true);
5405 }
5406 } else {
5407 internalError(node.receiver, 'unexpected element $element');
5408 }
5409 return element;
5410 }
5411
5412 Element visitIdentifier(Identifier node) {
5413 String name = node.source;
5414 Element element = resolver.reportLookupErrorIfAny(
5415 lookupInScope(compiler, node, resolver.scope, name), node, name);
5416 registry.useElement(node, element);
5417 // TODO(johnniwinther): Change errors to warnings, cf. 11.11.1.
5418 if (element == null) {
5419 return failOrReturnErroneousConstructorElement(
5420 node,
5421 resolver.enclosingElement, name,
5422 MessageKind.CANNOT_RESOLVE,
5423 {'name': name});
5424 } else if (element.isErroneous) {
5425 return element;
5426 } else if (element.isTypedef) {
5427 element = failOrReturnErroneousConstructorElement(
5428 node,
5429 resolver.enclosingElement, name,
5430 MessageKind.CANNOT_INSTANTIATE_TYPEDEF, {'typedefName': name},
5431 isError: true);
5432 } else if (element.isTypeVariable) {
5433 element = failOrReturnErroneousConstructorElement(
5434 node,
5435 resolver.enclosingElement, name,
5436 MessageKind.CANNOT_INSTANTIATE_TYPE_VARIABLE,
5437 {'typeVariableName': name},
5438 isError: true);
5439 } else if (!element.isClass && !element.isPrefix) {
5440 element = failOrReturnErroneousConstructorElement(
5441 node,
5442 resolver.enclosingElement, name,
5443 MessageKind.NOT_A_TYPE, {'node': name},
5444 isError: true);
5445 }
5446 return element;
5447 }
5448
5449 /// Assumed to be called by [resolveRedirectingFactory].
5450 Element visitRedirectingFactoryBody(RedirectingFactoryBody node) {
5451 Node constructorReference = node.constructorReference;
5452 return finishConstructorReference(visit(constructorReference),
5453 constructorReference, node);
5454 }
5455 }
5456
5457 /// Looks up [name] in [scope] and unwraps the result.
5458 Element lookupInScope(Compiler compiler, Node node,
5459 Scope scope, String name) {
5460 return Elements.unwrap(scope.lookup(name), compiler, node);
5461 }
5462
5463 TreeElements _ensureTreeElements(AnalyzableElementX element) {
5464 if (element._treeElements == null) {
5465 element._treeElements = new TreeElementMapping(element);
5466 }
5467 return element._treeElements;
5468 }
5469
5470 abstract class AnalyzableElementX implements AnalyzableElement {
5471 TreeElements _treeElements;
5472
5473 bool get hasTreeElements => _treeElements != null;
5474
5475 TreeElements get treeElements {
5476 assert(invariant(this, _treeElements !=null,
5477 message: "TreeElements have not been computed for $this."));
5478 return _treeElements;
5479 }
5480
5481 void reuseElement() {
5482 _treeElements = null;
5483 }
5484 }
5485
5486 /// The result of resolving a node.
5487 abstract class ResolutionResult {
5488 Element get element;
5489 }
5490
5491 /// The result for the resolution of a node that points to an [Element].
5492 class ElementResult implements ResolutionResult {
5493 final Element element;
5494
5495 // TODO(johnniwinther): Remove this factory constructor when `null` is never
5496 // passed as an element result.
5497 factory ElementResult(Element element) {
5498 return element != null ? new ElementResult.internal(element) : null;
5499 }
5500
5501 ElementResult.internal(this.element);
5502
5503 String toString() => 'ElementResult($element)';
5504 }
5505
5506 /// The result for the resolution of a node that points to an [DartType].
5507 class TypeResult implements ResolutionResult {
5508 final DartType type;
5509
5510 TypeResult(this.type) {
5511 assert(type != null);
5512 }
5513
5514 Element get element => type.element;
5515
5516 String toString() => 'TypeResult($type)';
5517 }
5518
5519 /// The result for the resolution of the `assert` method.
5520 class AssertResult implements ResolutionResult {
5521 const AssertResult();
5522
5523 Element get element => null;
5524
5525 String toString() => 'AssertResult()';
5526 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/resolution/resolution.dart ('k') | pkg/compiler/lib/src/resolution/resolution_result.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698