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

Side by Side Diff: frog/leg/resolver.dart

Issue 9873021: Move frog/leg to lib/compiler/implementation. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 8 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 | Annotate | Revision Log
« no previous file with comments | « frog/leg/operations.dart ('k') | frog/leg/scanner/array_based_scanner.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 interface TreeElements {
6 Element operator[](Node node);
7 Selector getSelector(Send send);
8 }
9
10 class TreeElementMapping implements TreeElements {
11 Map<Node, Element> map;
12 Map<Send, Selector> selectors;
13 TreeElementMapping()
14 : map = new LinkedHashMap<Node, Element>(),
15 selectors = new LinkedHashMap<Send, Selector>();
16
17 operator []=(Node node, Element element) => map[node] = element;
18 operator [](Node node) => map[node];
19 void remove(Node node) { map.remove(node); }
20
21 void setSelector(Send send, Selector selector) {
22 selectors[send] = selector;
23 }
24
25 Selector getSelector(Send send) => selectors[send];
26 }
27
28 class ResolverTask extends CompilerTask {
29 Queue<ClassElement> toResolve;
30
31 // Caches the elements of analyzed constructors to make them available
32 // for inlining in later tasks.
33 Map<FunctionElement, TreeElements> constructorElements;
34
35 ResolverTask(Compiler compiler)
36 : super(compiler), toResolve = new Queue<ClassElement>(),
37 constructorElements = new Map<FunctionElement, TreeElements>();
38
39 String get name() => 'Resolver';
40
41 TreeElements resolve(Element element) {
42 return measure(() {
43 switch (element.kind) {
44 case ElementKind.GENERATIVE_CONSTRUCTOR:
45 case ElementKind.FUNCTION:
46 case ElementKind.GETTER:
47 case ElementKind.SETTER:
48 return resolveMethodElement(element);
49
50 case ElementKind.FIELD:
51 return resolveField(element);
52
53 case ElementKind.PARAMETER:
54 case ElementKind.FIELD_PARAMETER:
55 return resolveParameter(element);
56
57 default:
58 compiler.unimplemented(
59 "resolver", node: element.parseNode(compiler));
60 }
61 });
62 }
63
64 SourceString getConstructorName(Send node) {
65 if (node.receiver !== null) {
66 return node.selector.asIdentifier().source;
67 } else {
68 return const SourceString('');
69 }
70 }
71
72 FunctionElement lookupConstructor(ClassElement classElement, Send send,
73 [noConstructor(Element)]) {
74 final SourceString constructorName = getConstructorName(send);
75 final SourceString className = classElement.name;
76 return classElement.lookupConstructor(className,
77 constructorName,
78 noConstructor);
79 }
80
81 FunctionElement resolveConstructorRedirection(FunctionElement constructor) {
82 FunctionExpression node = constructor.parseNode(compiler);
83 // A synthetic constructor does not have a node.
84 if (node === null) return null;
85 if (node.initializers === null) return null;
86 Link<Node> initializers = node.initializers.nodes;
87 if (!initializers.isEmpty() &&
88 Initializers.isConstructorRedirect(initializers.head)) {
89 return lookupConstructor(constructor.enclosingElement, initializers.head);
90 }
91 return null;
92 }
93
94 void resolveRedirectingConstructor(InitializerResolver resolver,
95 Node node,
96 FunctionElement constructor,
97 FunctionElement redirection) {
98 Set<FunctionElement> seen = new Set<FunctionElement>();
99 seen.add(constructor);
100 while (redirection !== null) {
101 if (seen.contains(redirection)) {
102 resolver.visitor.error(node, MessageKind.REDIRECTING_CONSTRUCTOR_CYCLE);
103 return;
104 }
105 seen.add(redirection);
106 redirection = resolveConstructorRedirection(redirection);
107 }
108 }
109
110 TreeElements resolveMethodElement(FunctionElement element) {
111 return compiler.withCurrentElement(element, () {
112 bool isConstructor = element.kind === ElementKind.GENERATIVE_CONSTRUCTOR;
113 if (constructorElements.containsKey(element)) {
114 assert(isConstructor);
115 TreeElements elements = constructorElements[element];
116 if (elements !== null) return elements;
117 }
118 FunctionExpression tree = element.parseNode(compiler);
119 if (isConstructor) {
120 resolveConstructorImplementation(element, tree);
121 }
122 ResolverVisitor visitor = new ResolverVisitor(compiler, element);
123 visitor.useElement(tree, element);
124 visitor.setupFunction(tree, element);
125
126 if (tree.initializers != null) {
127 if (!isConstructor) {
128 error(tree, MessageKind.FUNCTION_WITH_INITIALIZER);
129 }
130 InitializerResolver resolver = new InitializerResolver(visitor);
131 FunctionElement redirection =
132 resolver.resolveInitializers(element, tree);
133 if (redirection !== null) {
134 resolveRedirectingConstructor(resolver, tree, element, redirection);
135 }
136 }
137 visitor.visit(tree.body);
138
139 // Resolve the type annotations encountered in the method.
140 while (!toResolve.isEmpty()) {
141 ClassElement classElement = toResolve.removeFirst();
142 classElement.ensureResolved(compiler);
143 }
144 if (isConstructor) {
145 constructorElements[element] = visitor.mapping;
146 }
147 return visitor.mapping;
148 });
149 }
150
151 void resolveConstructorImplementation(FunctionElement constructor,
152 FunctionExpression node) {
153 assert(constructor.defaultImplementation === constructor);
154 ClassElement intrface = constructor.enclosingElement;
155 if (!intrface.isInterface()) return;
156 Type defaultType = intrface.defaultClass;
157 if (defaultType === null) {
158 error(node, MessageKind.NO_DEFAULT_CLASS, [intrface.name]);
159 }
160 ClassElement defaultClass = defaultType.element;
161 defaultClass.ensureResolved(compiler);
162 if (defaultClass.isInterface()) {
163 error(node, MessageKind.CANNOT_INSTANTIATE_INTERFACE,
164 [defaultClass.name]);
165 }
166 // We have now established the following:
167 // [intrface] is an interface, let's say "MyInterface".
168 // [defaultClass] is a class, let's say "MyClass".
169
170 // First look up the constructor named "MyInterface.name".
171 constructor.defaultImplementation =
172 defaultClass.lookupConstructor(constructor.name);
173
174 // If that fails, try looking up "MyClass.name".
175 if (constructor.defaultImplementation === null) {
176 SourceString name =
177 new SourceString(constructor.name.slowToString().replaceFirst(
178 intrface.name.slowToString(),
179 defaultClass.name.slowToString()));
180 constructor.defaultImplementation = defaultClass.lookupConstructor(name);
181
182 if (constructor.defaultImplementation === null) {
183 // We failed find a constrcutor named either
184 // "MyInterface.name" or "MyClass.name".
185 error(node, MessageKind.CANNOT_FIND_CONSTRUCTOR2,
186 [constructor.name, name]);
187 }
188 }
189 }
190
191 TreeElements resolveField(Element element) {
192 Node tree = element.parseNode(compiler);
193 ResolverVisitor visitor = new ResolverVisitor(compiler, element);
194 initializerDo(tree, visitor.visit);
195 return visitor.mapping;
196 }
197
198 TreeElements resolveParameter(Element element) {
199 Node tree = element.parseNode(compiler);
200 ResolverVisitor visitor =
201 new ResolverVisitor(compiler, element.enclosingElement);
202 initializerDo(tree, visitor.visit);
203 return visitor.mapping;
204 }
205
206 Type resolveType(ClassElement element) {
207 if (element.isResolved) return element.type;
208 return measure(() {
209 ClassNode tree = element.parseNode(compiler);
210 ClassResolverVisitor visitor =
211 new ClassResolverVisitor(compiler, element.getLibrary(), element);
212 visitor.visit(tree);
213 element.isResolved = true;
214 return element.type;
215 });
216 }
217
218 FunctionParameters resolveSignature(FunctionElement element) {
219 return measure(() => SignatureResolver.analyze(compiler, element));
220 }
221
222 error(Node node, MessageKind kind, [arguments = const []]) {
223 ResolutionError message = new ResolutionError(kind, arguments);
224 compiler.reportError(node, message);
225 }
226 }
227
228 class InitializerResolver {
229 final ResolverVisitor visitor;
230 final Map<SourceString, Node> initialized;
231 Link<Node> initializers;
232 bool hasSuper;
233
234 InitializerResolver(this.visitor)
235 : initialized = new Map<SourceString, Node>(), hasSuper = false;
236
237 error(Node node, MessageKind kind, [arguments = const []]) {
238 visitor.error(node, kind, arguments);
239 }
240
241 warning(Node node, MessageKind kind, [arguments = const []]) {
242 visitor.warning(node, kind, arguments);
243 }
244
245 bool isFieldInitializer(SendSet node) {
246 if (node.selector.asIdentifier() == null) return false;
247 if (node.receiver == null) return true;
248 if (node.receiver.asIdentifier() == null) return false;
249 return node.receiver.asIdentifier().isThis();
250 }
251
252 void resolveFieldInitializer(FunctionElement constructor, SendSet init) {
253 // init is of the form [this.]field = value.
254 final Node selector = init.selector;
255 final SourceString name = selector.asIdentifier().source;
256 // Lookup target field.
257 Element target;
258 if (isFieldInitializer(init)) {
259 final ClassElement classElement = constructor.enclosingElement;
260 target = classElement.lookupLocalMember(name);
261 if (target === null) {
262 error(selector, MessageKind.CANNOT_RESOLVE, [name]);
263 } else if (target.kind != ElementKind.FIELD) {
264 error(selector, MessageKind.NOT_A_FIELD, [name]);
265 } else if (!target.isInstanceMember()) {
266 error(selector, MessageKind.INIT_STATIC_FIELD, [name]);
267 }
268 } else {
269 error(init, MessageKind.INVALID_RECEIVER_IN_INITIALIZER);
270 }
271 visitor.useElement(init, target);
272 // Check for duplicate initializers.
273 if (initialized.containsKey(name)) {
274 error(init, MessageKind.DUPLICATE_INITIALIZER, [name]);
275 warning(initialized[name], MessageKind.ALREADY_INITIALIZED, [name]);
276 }
277 initialized[name] = init;
278 // Resolve initializing value.
279 visitor.visitInStaticContext(init.arguments.head);
280 }
281
282 Element resolveSuperOrThis(FunctionElement constructor,
283 FunctionExpression functionNode,
284 Send call) {
285 noConstructor(e) {
286 if (e !== null) error(call, MessageKind.NO_CONSTRUCTOR, [e.name, e.kind]);
287 }
288
289 ClassElement lookupTarget = constructor.enclosingElement;
290 bool validTarget = true;
291 FunctionElement result;
292 if (Initializers.isSuperConstructorCall(call)) {
293 // Check for invalid initializers.
294 if (hasSuper) {
295 error(call, MessageKind.DUPLICATE_SUPER_INITIALIZER);
296 }
297 hasSuper = true;
298 // Calculate correct lookup target and constructor name.
299 if (lookupTarget.name == Types.OBJECT) {
300 error(call, MessageKind.SUPER_INITIALIZER_IN_OBJECT);
301 } else {
302 lookupTarget = lookupTarget.supertype.element;
303 }
304 } else if (Initializers.isConstructorRedirect(call)) {
305 // Check that there is no body (Language specification 7.5.1).
306 if (functionNode.hasBody()) {
307 error(functionNode, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_BODY);
308 }
309 // Check that there are no other initializers.
310 if (!initializers.tail.isEmpty()) {
311 error(call, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER);
312 }
313 } else {
314 visitor.error(call, MessageKind.CONSTRUCTOR_CALL_EXPECTED);
315 validTarget = false;
316 }
317
318 if (validTarget) {
319 // Resolve the arguments, and make sure the call gets a selector
320 // by calling handleArguments.
321 visitor.inStaticContext( () => visitor.handleArguments(call) );
322 // Lookup constructor and try to match it to the selector.
323 ResolverTask resolver = visitor.compiler.resolver;
324 result = resolver.lookupConstructor(lookupTarget, call);
325 if (result === null) {
326 SourceString constructorName = resolver.getConstructorName(call);
327 String className = lookupTarget.name.slowToString();
328 String name = (constructorName === const SourceString(''))
329 ? className
330 : "$className.${constructorName.slowToString()}";
331 error(call, MessageKind.CANNOT_RESOLVE_CONSTRUCTOR, [name]);
332 } else {
333 final Compiler compiler = visitor.compiler;
334 Selector selector = visitor.mapping.getSelector(call);
335 FunctionParameters parameters = result.computeParameters(compiler);
336 // TODO(karlklose): support optional arguments.
337 if (!selector.applies(parameters)) {
338 error(call, MessageKind.NO_MATCHING_CONSTRUCTOR);
339 }
340 }
341 visitor.useElement(call, result);
342 }
343 return result;
344 }
345
346 FunctionElement resolveRedirection(FunctionElement constructor,
347 FunctionExpression functionNode) {
348 if (functionNode.initializers === null) return null;
349 Link<Node> link = functionNode.initializers.nodes;
350 if (!link.isEmpty() && Initializers.isConstructorRedirect(link.head)) {
351 return resolveSuperOrThis(constructor, functionNode, link.head);
352 }
353 return null;
354 }
355
356 /**
357 * Resolve all initializers of this constructor. In the case of a redirecting
358 * constructor, the resolved constructor's function element is returned.
359 */
360 FunctionElement resolveInitializers(FunctionElement constructor,
361 FunctionExpression functionNode) {
362 if (functionNode.initializers === null) return null;
363 initializers = functionNode.initializers.nodes;
364 FunctionElement result;
365 for (Link<Node> link = initializers;
366 !link.isEmpty();
367 link = link.tail) {
368 if (link.head.asSendSet() != null) {
369 final SendSet init = link.head.asSendSet();
370 resolveFieldInitializer(constructor, init);
371 } else if (link.head.asSend() !== null) {
372 final Send call = link.head.asSend();
373 result = resolveSuperOrThis(constructor, functionNode, call);
374 } else {
375 error(link.head, MessageKind.INVALID_INITIALIZER);
376 }
377 }
378 return result;
379 }
380 }
381
382 class CommonResolverVisitor<R> extends AbstractVisitor<R> {
383 final Compiler compiler;
384
385 CommonResolverVisitor(Compiler this.compiler);
386
387 R visitNode(Node node) {
388 cancel(node, 'internal error');
389 }
390
391 R visitEmptyStatement(Node node) => null;
392
393 /** Convenience method for visiting nodes that may be null. */
394 R visit(Node node) => (node == null) ? null : node.accept(this);
395
396 void error(Node node, MessageKind kind, [arguments = const []]) {
397 ResolutionError message = new ResolutionError(kind, arguments);
398 compiler.reportError(node, message);
399 }
400
401 void warning(Node node, MessageKind kind, [arguments = const []]) {
402 ResolutionWarning message = new ResolutionWarning(kind, arguments);
403 compiler.reportWarning(node, message);
404 }
405
406 void cancel(Node node, String message) {
407 compiler.cancel(message, node: node);
408 }
409
410 void internalError(Node node, String message) {
411 compiler.internalError(message, node: node);
412 }
413
414 void unimplemented(Node node, String message) {
415 compiler.unimplemented(message, node: node);
416 }
417 }
418
419 interface LabelScope {
420 LabelScope get outer();
421 LabelElement lookup(String label);
422 }
423
424 class LabeledStatementLabelScope implements LabelScope {
425 final LabelScope outer;
426 final LabelElement label;
427 LabeledStatementLabelScope(this.outer, this.label);
428 LabelElement lookup(String labelName) {
429 if (this.label.labelName == labelName) return label;
430 return outer.lookup(labelName);
431 }
432 }
433
434 class SwitchLabelScope implements LabelScope {
435 final LabelScope outer;
436 final Map<String, LabelElement> caseLabels;
437
438 SwitchLabelScope(this.outer, this.caseLabels);
439
440 LabelElement lookup(String labelName) {
441 LabelElement result = caseLabels[labelName];
442 if (result !== null) return result;
443 return outer.lookup(labelName);
444 }
445 }
446
447 class EmptyLabelScope implements LabelScope {
448 const EmptyLabelScope();
449 LabelElement lookup(String label) => null;
450 LabelScope get outer() {
451 throw 'internal error: empty label scope has no outer';
452 }
453 }
454
455 class StatementScope {
456 LabelScope labels;
457 Link<TargetElement> breakTargetStack;
458 Link<TargetElement> continueTargetStack;
459 // Used to provide different numbers to statements if one is inside the other.
460 // Can be used to make otherwise duplicate labels unique.
461 int nestingLevel = 0;
462
463 StatementScope()
464 : labels = const EmptyLabelScope(),
465 breakTargetStack = const EmptyLink<TargetElement>(),
466 continueTargetStack = const EmptyLink<TargetElement>();
467
468 LabelElement lookupLabel(String label) {
469 return labels.lookup(label);
470 }
471 TargetElement currentBreakTarget() =>
472 breakTargetStack.isEmpty() ? null : breakTargetStack.head;
473
474 TargetElement currentContinueTarget() =>
475 continueTargetStack.isEmpty() ? null : continueTargetStack.head;
476
477 void enterLabelScope(LabelElement element) {
478 labels = new LabeledStatementLabelScope(labels, element);
479 nestingLevel++;
480 }
481
482 void exitLabelScope() {
483 nestingLevel--;
484 labels = labels.outer;
485 }
486
487 void enterLoop(TargetElement element) {
488 breakTargetStack = breakTargetStack.prepend(element);
489 continueTargetStack = continueTargetStack.prepend(element);
490 nestingLevel++;
491 }
492
493 void exitLoop() {
494 nestingLevel--;
495 breakTargetStack = breakTargetStack.tail;
496 continueTargetStack = continueTargetStack.tail;
497 }
498
499 void enterSwitch(TargetElement breakElement,
500 Map<String, LabelElement> continueElements) {
501 breakTargetStack = breakTargetStack.prepend(breakElement);
502 labels = new SwitchLabelScope(labels, continueElements);
503 nestingLevel++;
504 }
505
506 void exitSwitch() {
507 nestingLevel--;
508 breakTargetStack = breakTargetStack.tail;
509 labels = labels.outer;
510 }
511 }
512
513 class ResolverVisitor extends CommonResolverVisitor<Element> {
514 final TreeElementMapping mapping;
515 final Element enclosingElement;
516 bool inInstanceContext;
517 Scope context;
518 ClassElement currentClass;
519 bool typeRequired = false;
520 StatementScope statementScope;
521 int allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION;
522
523 ResolverVisitor(Compiler compiler, Element element)
524 : this.mapping = new TreeElementMapping(),
525 this.enclosingElement = element,
526 inInstanceContext = element.isInstanceMember()
527 || element.isGenerativeConstructor(),
528 this.context = element.isMember()
529 ? new ClassScope(element.enclosingElement, element.getLibrary())
530 : new TopScope(element.getLibrary()),
531 this.currentClass = element.isMember() ? element.enclosingElement : null,
532 this.statementScope = new StatementScope(),
533 super(compiler);
534
535 Element lookup(Node node, SourceString name) {
536 Element result = context.lookup(name);
537 if (!inInstanceContext && result != null && result.isInstanceMember()) {
538 error(node, MessageKind.NO_INSTANCE_AVAILABLE, [node]);
539 }
540 return result;
541 }
542
543 // Create, or reuse an already created, statement element for a statement.
544 TargetElement getOrCreateTargetElement(Node statement) {
545 TargetElement element = mapping[statement];
546 if (element === null) {
547 element = new TargetElement(statement,
548 statementScope.nestingLevel,
549 enclosingElement);
550 mapping[statement] = element;
551 }
552 return element;
553 }
554
555 inStaticContext(action()) {
556 bool wasInstanceContext = inInstanceContext;
557 inInstanceContext = false;
558 var result = action();
559 inInstanceContext = wasInstanceContext;
560 return result;
561 }
562
563 visitInStaticContext(Node node) {
564 inStaticContext(() => visit(node));
565 }
566
567 Element visitIdentifier(Identifier node) {
568 if (node.isThis()) {
569 if (!inInstanceContext) {
570 error(node, MessageKind.NO_INSTANCE_AVAILABLE, [node]);
571 }
572 return null;
573 } else if (node.isSuper()) {
574 if (!inInstanceContext) error(node, MessageKind.NO_SUPER_IN_STATIC);
575 if ((ElementCategory.SUPER & allowedCategory) == 0) {
576 error(node, MessageKind.INVALID_USE_OF_SUPER);
577 }
578 return null;
579 } else {
580 Element element = lookup(node, node.source);
581 if (element === null) {
582 if (!inInstanceContext) error(node, MessageKind.CANNOT_RESOLVE, [node]);
583 } else {
584 if ((element.kind.category & allowedCategory) == 0) {
585 // TODO(ahe): Improve error message. Need UX input.
586 error(node, MessageKind.GENERIC, ["is not an expression $element"]);
587 }
588 }
589 return useElement(node, element);
590 }
591 }
592
593 visitTypeAnnotation(TypeAnnotation node) {
594 Send send = node.typeName.asSend();
595 Element element;
596 if (send !== null) {
597 if (typeRequired) {
598 element = resolveSend(send);
599 } else {
600 // Not calling resolveSend as it will emit an error instead of
601 // a warning if the type is bogus.
602 // TODO(ahe): Change resolveSend so it can emit a warning when needed.
603 return null;
604 }
605 } else {
606 element = context.lookup(node.typeName.asIdentifier().source);
607 }
608 if (element === null) {
609 if (typeRequired) {
610 error(node, MessageKind.CANNOT_RESOLVE_TYPE, [node.typeName]);
611 } else {
612 warning(node, MessageKind.CANNOT_RESOLVE_TYPE, [node.typeName]);
613 }
614 } else if (!element.impliesType()) {
615 if (typeRequired) {
616 error(node, MessageKind.NOT_A_TYPE, [node.typeName]);
617 } else {
618 warning(node, MessageKind.NOT_A_TYPE, [node.typeName]);
619 }
620 } else {
621 if (element.isClass()) {
622 // TODO(ngeoffray): Should we also resolve typedef?
623 ClassElement cls = element;
624 compiler.resolver.toResolve.add(element);
625 }
626 // TODO(ahe): This should be a Type.
627 useElement(node, element);
628 }
629 return element;
630 }
631
632 Element defineElement(Node node, Element element,
633 [bool doAddToScope = true]) {
634 compiler.ensure(element !== null);
635 mapping[node] = element;
636 if (doAddToScope) {
637 Element existing = context.add(element);
638 if (existing != element) {
639 error(node, MessageKind.DUPLICATE_DEFINITION, [node]);
640 }
641 }
642 return element;
643 }
644
645 Element useElement(Node node, Element element) {
646 if (element === null) return null;
647 return mapping[node] = element;
648 }
649
650 void setupFunction(FunctionExpression node, FunctionElement function) {
651 context = new MethodScope(context, function);
652 // Put the parameters in scope.
653 FunctionParameters functionParameters =
654 function.computeParameters(compiler);
655 Link<Node> parameterNodes = node.parameters.nodes;
656 functionParameters.forEachParameter((Element element) {
657 if (element == functionParameters.optionalParameters.head) {
658 NodeList nodes = parameterNodes.head;
659 parameterNodes = nodes.nodes;
660 }
661 VariableDefinitions variableDefinitions = parameterNodes.head;
662 Node parameterNode = variableDefinitions.definitions.nodes.head;
663 initializerDo(parameterNode, (n) => n.accept(this));
664 // Field parameters (this.x) are not visible inside the constructor. The
665 // fields they reference are visible, but must be resolved independently.
666 if (element.kind == ElementKind.FIELD_PARAMETER) {
667 useElement(parameterNode, element);
668 } else {
669 defineElement(variableDefinitions.definitions.nodes.head, element);
670 }
671 parameterNodes = parameterNodes.tail;
672 });
673 }
674
675 Element visitClassNode(ClassNode node) {
676 cancel(node, "shouldn't be called");
677 }
678
679 visitIn(Node node, Scope scope) {
680 context = scope;
681 Element element = visit(node);
682 context = context.parent;
683 return element;
684 }
685
686 /**
687 * Introduces new default targets for break and continue
688 * before visiting the body of the loop
689 */
690 visitLoopBodyIn(Node loop, Node body, Scope scope) {
691 TargetElement element = getOrCreateTargetElement(loop);
692 statementScope.enterLoop(element);
693 visitIn(body, scope);
694 statementScope.exitLoop();
695 if (!element.isTarget) {
696 mapping.remove(loop);
697 }
698 }
699
700 visitBlock(Block node) {
701 visitIn(node.statements, new BlockScope(context));
702 }
703
704 visitDoWhile(DoWhile node) {
705 visitLoopBodyIn(node, node.body, new BlockScope(context));
706 visit(node.condition);
707 }
708
709 visitEmptyStatement(EmptyStatement node) { }
710
711 visitExpressionStatement(ExpressionStatement node) {
712 visit(node.expression);
713 }
714
715 visitFor(For node) {
716 Scope scope = new BlockScope(context);
717 visitIn(node.initializer, scope);
718 visitIn(node.condition, scope);
719 visitIn(node.update, scope);
720 visitLoopBodyIn(node, node.body, scope);
721 }
722
723 visitFunctionDeclaration(FunctionDeclaration node) {
724 assert(node.function.name !== null);
725 visit(node.function);
726 FunctionElement functionElement = mapping[node.function];
727 // TODO(floitsch): this might lead to two errors complaining about
728 // shadowing.
729 defineElement(node, functionElement);
730 }
731
732 visitFunctionExpression(FunctionExpression node) {
733 visit(node.returnType);
734 SourceString name;
735 if (node.name === null) {
736 name = const SourceString("");
737 } else {
738 name = node.name.asIdentifier().source;
739 }
740 FunctionElement enclosing = new FunctionElement.node(
741 name, node, ElementKind.FUNCTION, new Modifiers.empty(),
742 context.element);
743 setupFunction(node, enclosing);
744 defineElement(node, enclosing, doAddToScope: node.name !== null);
745
746 // Run the body in a fresh statement scope.
747 StatementScope oldScope = statementScope;
748 statementScope = new StatementScope();
749 visit(node.body);
750 statementScope = oldScope;
751
752 context = context.parent;
753 }
754
755 visitIf(If node) {
756 visit(node.condition);
757 visit(node.thenPart);
758 visit(node.elsePart);
759 }
760
761 static bool isLogicalOperator(Identifier op) {
762 String str = op.source.stringValue;
763 return (str === '&&' || str == '||' || str == '!');
764 }
765
766 Element resolveSend(Send node) {
767 if (node.receiver === null) {
768 return node.selector.accept(this);
769 }
770 var oldCategory = allowedCategory;
771 allowedCategory |=
772 ElementCategory.CLASS | ElementCategory.PREFIX | ElementCategory.SUPER;
773 Element resolvedReceiver = visit(node.receiver);
774 allowedCategory = oldCategory;
775
776 Element target;
777 SourceString name = node.selector.asIdentifier().source;
778 if (name.stringValue === 'this') {
779 error(node.selector, MessageKind.GENERIC, ["expected an identifier"]);
780 } else if (node.isSuperCall) {
781 if (node.isOperator) {
782 if (isUserDefinableOperator(name.stringValue)) {
783 name = Elements.constructOperatorName(const SourceString('operator'),
784 name);
785 } else {
786 error(node.selector, MessageKind.ILLEGAL_SUPER_SEND, [name]);
787 }
788 }
789 if (!inInstanceContext) {
790 error(node.receiver, MessageKind.NO_INSTANCE_AVAILABLE, [name]);
791 return null;
792 }
793 if (currentClass.supertype === null) {
794 // This is just to guard against internal errors, so no need
795 // for a real error message.
796 error(node.receiver, MessageKind.GENERIC, ["Object has no superclass"]);
797 }
798 target = currentClass.lookupSuperMember(name);
799 // [target] may be null which means invoking noSuchMethod on
800 // super.
801 } else if (resolvedReceiver === null) {
802 return null;
803 } else if (resolvedReceiver.kind === ElementKind.CLASS) {
804 ClassElement receiverClass = resolvedReceiver;
805 target = receiverClass.ensureResolved(compiler).lookupLocalMember(name);
806 if (target === null) {
807 error(node, MessageKind.METHOD_NOT_FOUND, [receiverClass.name, name]);
808 } else if (target.isInstanceMember()) {
809 error(node, MessageKind.MEMBER_NOT_STATIC, [receiverClass.name, name]);
810 }
811 } else if (resolvedReceiver.kind === ElementKind.PREFIX) {
812 PrefixElement prefix = resolvedReceiver;
813 target = prefix.lookupLocalMember(name);
814 if (target == null) {
815 error(node, MessageKind.NO_SUCH_LIBRARY_MEMBER, [prefix.name, name]);
816 }
817 }
818 return target;
819 }
820
821 resolveTypeTest(Node argument) {
822 TypeAnnotation node = argument.asTypeAnnotation();
823 if (node == null) {
824 node = argument.asSend().receiver;
825 }
826 resolveTypeRequired(node);
827 }
828
829 void handleArguments(Send node) {
830 int count = 0;
831 List<SourceString> namedArguments = <SourceString>[];
832 bool seenNamedArgument = false;
833 for (Link<Node> link = node.argumentsNode.nodes;
834 !link.isEmpty();
835 link = link.tail) {
836 count++;
837 Expression argument = link.head;
838 visit(argument);
839 if (argument.asNamedArgument() != null) {
840 seenNamedArgument = true;
841 NamedArgument named = argument;
842 namedArguments.add(named.name.source);
843 } else if (seenNamedArgument) {
844 error(argument, MessageKind.INVALID_ARGUMENT_AFTER_NAMED);
845 }
846 }
847 mapping.setSelector(node, new Invocation(count, namedArguments));
848 }
849
850 visitSend(Send node) {
851 Element target = resolveSend(node);
852 if (node.isOperator) {
853 Operator op = node.selector.asOperator();
854 if (op.source.stringValue === 'is') {
855 resolveTypeTest(node.arguments.head);
856 assert(node.arguments.tail.isEmpty());
857 mapping.setSelector(node, Selector.BINARY_OPERATOR);
858 } else if (node.arguments.isEmpty()) {
859 assert(op.token.kind !== PLUS_TOKEN);
860 mapping.setSelector(node, Selector.UNARY_OPERATOR);
861 } else {
862 visit(node.argumentsNode);
863 mapping.setSelector(node, Selector.BINARY_OPERATOR);
864 }
865 } else if (node.isIndex) {
866 visit(node.argumentsNode);
867 assert(node.arguments.tail.isEmpty());
868 mapping.setSelector(node, Selector.INDEX);
869 } else if (node.isPropertyAccess) {
870 mapping.setSelector(node, Selector.GETTER);
871 } else {
872 handleArguments(node);
873 }
874 if (target != null && target.kind == ElementKind.ABSTRACT_FIELD) {
875 AbstractFieldElement field = target;
876 target = field.getter;
877 }
878 // TODO(ngeoffray): Warn if target is null and the send is
879 // unqualified.
880 useElement(node, target);
881 if (node.isPropertyAccess) return target;
882 }
883
884 visitSendSet(SendSet node) {
885 Element target = resolveSend(node);
886 Element setter = null;
887 Element getter = null;
888 if (target != null && target.kind == ElementKind.ABSTRACT_FIELD) {
889 AbstractFieldElement field = target;
890 setter = field.setter;
891 getter = field.getter;
892 } else {
893 setter = target;
894 getter = target;
895 }
896 // TODO(ngeoffray): Check if the target can be assigned.
897 Identifier op = node.assignmentOperator;
898 bool needsGetter = op.source.stringValue !== '=';
899 Selector selector;
900 if (needsGetter) {
901 if (node.isIndex) {
902 selector = Selector.INDEX_AND_INDEX_SET;
903 } else {
904 selector = Selector.GETTER_AND_SETTER;
905 }
906 useElement(node.selector, getter);
907 } else if (node.isIndex) {
908 selector = Selector.INDEX_SET;
909 } else {
910 selector = Selector.SETTER;
911 }
912 visit(node.argumentsNode);
913 mapping.setSelector(node, selector);
914 // TODO(ngeoffray): Warn if target is null and the send is
915 // unqualified.
916 return useElement(node, setter);
917 }
918
919 visitLiteralInt(LiteralInt node) {
920 }
921
922 visitLiteralDouble(LiteralDouble node) {
923 }
924
925 visitLiteralBool(LiteralBool node) {
926 }
927
928 visitLiteralString(LiteralString node) {
929 }
930
931 visitLiteralNull(LiteralNull node) {
932 }
933
934 visitStringJuxtaposition(StringJuxtaposition node) {
935 node.visitChildren(this);
936 }
937
938 visitNodeList(NodeList node) {
939 for (Link<Node> link = node.nodes; !link.isEmpty(); link = link.tail) {
940 visit(link.head);
941 }
942 }
943
944 visitOperator(Operator node) {
945 unimplemented(node, 'operator');
946 }
947
948 visitReturn(Return node) {
949 visit(node.expression);
950 }
951
952 visitThrow(Throw node) {
953 visit(node.expression);
954 }
955
956 visitVariableDefinitions(VariableDefinitions node) {
957 visit(node.type);
958 VariableDefinitionsVisitor visitor =
959 new VariableDefinitionsVisitor(compiler, node, this,
960 ElementKind.VARIABLE);
961 visitor.visit(node.definitions);
962 }
963
964 visitWhile(While node) {
965 visit(node.condition);
966 visitLoopBodyIn(node, node.body, new BlockScope(context));
967 }
968
969 visitParenthesizedExpression(ParenthesizedExpression node) {
970 visit(node.expression);
971 }
972
973 visitNewExpression(NewExpression node) {
974 Node selector = node.send.selector;
975
976 FunctionElement constructor = resolveConstructor(node);
977 handleArguments(node.send);
978 if (constructor === null) return null;
979 // TODO(karlklose): handle optional arguments.
980 if (node.send.argumentCount() != constructor.parameterCount(compiler)) {
981 // TODO(ngeoffray): resolution error with wrong number of
982 // parameters. We cannot do this rigth now because of the
983 // List constructor.
984 }
985 useElement(node.send, constructor);
986 return null;
987 }
988
989 FunctionElement resolveConstructor(NewExpression node) {
990 FunctionElement constructor =
991 node.accept(new ConstructorResolver(compiler, this));
992 if (constructor === null) {
993 Element resolved = resolveTypeRequired(node.send.selector);
994 if (resolved !== null && resolved.kind === ElementKind.TYPE_VARIABLE) {
995 error(node, WarningKind.TYPE_VARIABLE_AS_CONSTRUCTOR);
996 return null;
997 } else {
998 error(node.send, MessageKind.CANNOT_FIND_CONSTRUCTOR, [node.send]);
999 }
1000 }
1001 return constructor;
1002 }
1003
1004 Element resolveTypeRequired(Node node) {
1005 bool old = typeRequired;
1006 typeRequired = true;
1007 Element element = visit(node);
1008 typeRequired = old;
1009 return element;
1010 }
1011
1012 visitModifiers(Modifiers node) {
1013 // TODO(ngeoffray): Implement this.
1014 unimplemented(node, 'modifiers');
1015 }
1016
1017 visitLiteralList(LiteralList node) {
1018 visit(node.elements);
1019 }
1020
1021 visitConditional(Conditional node) {
1022 node.visitChildren(this);
1023 }
1024
1025 visitStringInterpolation(StringInterpolation node) {
1026 node.visitChildren(this);
1027 }
1028
1029 visitStringInterpolationPart(StringInterpolationPart node) {
1030 node.visitChildren(this);
1031 }
1032
1033 visitBreakStatement(BreakStatement node) {
1034 TargetElement target;
1035 if (node.target === null) {
1036 target = statementScope.currentBreakTarget();
1037 if (target === null) {
1038 error(node, MessageKind.NO_BREAK_TARGET);
1039 return;
1040 }
1041 target.isBreakTarget = true;
1042 } else {
1043 String labelName = node.target.source.slowToString();
1044 LabelElement label = statementScope.lookupLabel(labelName);
1045 if (label === null) {
1046 error(node.target, MessageKind.UNBOUND_LABEL, [labelName]);
1047 return;
1048 }
1049 target = label.target;
1050 if (!target.statement.isValidBreakTarget()) {
1051 error(node.target, MessageKind.INVALID_BREAK, [labelName]);
1052 return;
1053 }
1054 label.setBreakTarget();
1055 mapping[node.target] = label;
1056 }
1057 mapping[node] = target;
1058 }
1059
1060 visitContinueStatement(ContinueStatement node) {
1061 TargetElement target;
1062 if (node.target === null) {
1063 target = statementScope.currentContinueTarget();
1064 if (target === null) {
1065 error(node, MessageKind.NO_CONTINUE_TARGET);
1066 return;
1067 }
1068 target.isContinueTarget = true;
1069 } else {
1070 String labelName = node.target.source.slowToString();
1071 LabelElement label = statementScope.lookupLabel(labelName);
1072 if (label === null) {
1073 error(node.target, MessageKind.UNBOUND_LABEL, [labelName]);
1074 return;
1075 }
1076 target = label.target;
1077 if (!target.statement.isValidContinueTarget()) {
1078 error(node.target, MessageKind.INVALID_CONTINUE, [labelName]);
1079 }
1080 label.setContinueTarget();
1081 }
1082 mapping[node] = target;
1083 }
1084
1085 visitForInStatement(ForInStatement node) {
1086 visit(node.expression);
1087 Scope scope = new BlockScope(context);
1088 Node declaration = node.declaredIdentifier;
1089 visitIn(declaration, scope);
1090 visitLoopBodyIn(node, node.body, scope);
1091
1092 // TODO(lrn): Also allow a single identifier.
1093 if ((declaration is !Send || declaration.asSend().selector is !Identifier)
1094 && (declaration is !VariableDefinitions ||
1095 !declaration.asVariableDefinitions().definitions.nodes.tail.isEmpty()))
1096 {
1097 // The variable declaration is either not an identifier, not a
1098 // declaration, or it's declaring more than one variable.
1099 error(node.declaredIdentifier, MessageKind.INVALID_FOR_IN, []);
1100 }
1101 }
1102
1103 visitLabeledStatement(LabeledStatement node) {
1104 String labelName = node.label.source.slowToString();
1105 LabelElement existingElement = statementScope.lookupLabel(labelName);
1106 if (existingElement !== null) {
1107 warning(node.label, MessageKind.DUPLICATE_LABEL, [labelName]);
1108 warning(existingElement.label, MessageKind.EXISTING_LABEL, [labelName]);
1109 }
1110 Node body = node.getBody();
1111 TargetElement targetElement = getOrCreateTargetElement(body);
1112
1113 LabelElement element = targetElement.addLabel(node.label, labelName);
1114 statementScope.enterLabelScope(element);
1115 visit(node.statement);
1116 statementScope.exitLabelScope();
1117 if (element.isTarget) {
1118 mapping[node.label] = element;
1119 } else {
1120 warning(node.label, MessageKind.UNUSED_LABEL, [labelName]);
1121 }
1122 if (!targetElement.isTarget && mapping[body] === targetElement) {
1123 // If the body is itself a break or continue for another target, it
1124 // might have updated its mapping to the target it actually does target.
1125 mapping.remove(body);
1126 }
1127 }
1128
1129 visitLiteralMap(LiteralMap node) {
1130 node.visitChildren(this);
1131 }
1132
1133 visitLiteralMapEntry(LiteralMapEntry node) {
1134 node.visitChildren(this);
1135 }
1136
1137 visitNamedArgument(NamedArgument node) {
1138 visit(node.expression);
1139 }
1140
1141 visitSwitchStatement(SwitchStatement node) {
1142 node.expression.accept(this);
1143
1144 TargetElement breakElement = getOrCreateTargetElement(node);
1145 Map<String, LabelElement> continueLabels = <LabelElement>{};
1146 Link<Node> cases = node.cases.nodes;
1147 while (!cases.isEmpty()) {
1148 SwitchCase switchCase = cases.head;
1149 if (switchCase.label !== null) {
1150 Identifier labelIdentifier = switchCase.label;
1151 String labelName = labelIdentifier.source.slowToString();
1152
1153 LabelElement existingElement = continueLabels[labelName];
1154 if (existingElement !== null) {
1155 // It's an error if the same label occurs twice in the same switch.
1156 warning(labelIdentifier, MessageKind.DUPLICATE_LABEL, [labelName]);
1157 error(existingElement.label, MessageKind.EXISTING_LABEL, [labelName]);
1158 } else {
1159 // It's only a warning if it shadows another label.
1160 existingElement = statementScope.lookupLabel(labelName);
1161 if (existingElement !== null) {
1162 warning(labelIdentifier, MessageKind.DUPLICATE_LABEL, [labelName]);
1163 warning(existingElement.label,
1164 MessageKind.EXISTING_LABEL, [labelName]);
1165 }
1166 }
1167
1168 TargetElement TargetElement =
1169 new TargetElement(switchCase,
1170 statementScope.nestingLevel,
1171 enclosingElement);
1172 mapping[switchCase] = TargetElement;
1173
1174 LabelElement label =
1175 new LabelElement(labelIdentifier, labelName,
1176 TargetElement, enclosingElement);
1177 mapping[labelIdentifier] = label;
1178 continueLabels[labelName] = label;
1179 }
1180 cases = cases.tail;
1181 if (switchCase.defaultKeyword !== null && !cases.isEmpty()) {
1182 error(switchCase, MessageKind.INVALID_CASE_DEFAULT);
1183 }
1184 }
1185 statementScope.enterSwitch(breakElement, continueLabels);
1186 node.cases.accept(this);
1187 statementScope.exitSwitch();
1188
1189 // Clean-up unused labels
1190 continueLabels.forEach((String key, LabelElement label) {
1191 TargetElement TargetElement = label.target;
1192 SwitchCase switchCase = TargetElement.statement;
1193 if (!label.isContinueTarget) {
1194 mapping.remove(switchCase);
1195 mapping.remove(label.label);
1196 }
1197 });
1198 }
1199
1200 visitSwitchCase(SwitchCase node) {
1201 // The label was handled in [visitSwitchStatement(SwitchStatement)].
1202 node.expressions.accept(this);
1203 visitIn(node.statements, new BlockScope(context));
1204 }
1205
1206 visitTryStatement(TryStatement node) {
1207 visit(node.tryBlock);
1208 if (node.catchBlocks.isEmpty() && node.finallyBlock == null) {
1209 // TODO(ngeoffray): The precise location is
1210 // node.getEndtoken.next. Adjust when issue #1581 is fixed.
1211 error(node, MessageKind.NO_CATCH_NOR_FINALLY);
1212 }
1213 visit(node.catchBlocks);
1214 visit(node.finallyBlock);
1215 }
1216
1217 visitCatchBlock(CatchBlock node) {
1218 Scope scope = new BlockScope(context);
1219 if (node.formals.isEmpty()) {
1220 error(node, MessageKind.EMPTY_CATCH_DECLARATION);
1221 } else if (!node.formals.nodes.tail.isEmpty()
1222 && !node.formals.nodes.tail.tail.isEmpty()) {
1223 for (Node extra in node.formals.nodes.tail.tail) {
1224 error(extra, MessageKind.EXTRA_CATCH_DECLARATION);
1225 }
1226 }
1227 visitIn(node.formals, scope);
1228 visitIn(node.block, scope);
1229 }
1230
1231 visitTypedef(Typedef node) {
1232 unimplemented(node, 'typedef');
1233 }
1234 }
1235
1236 class ClassResolverVisitor extends CommonResolverVisitor<Type> {
1237 Scope context;
1238 ClassElement classElement;
1239
1240 ClassResolverVisitor(Compiler compiler, LibraryElement library,
1241 ClassElement this.classElement)
1242 : context = new TopScope(library),
1243 super(compiler);
1244
1245 Type visitClassNode(ClassNode node) {
1246 compiler.ensure(classElement !== null);
1247 compiler.ensure(!classElement.isResolved);
1248 final Link<Node> parameters =
1249 node.typeParameters !== null ? node.typeParameters.nodes
1250 : const EmptyLink<TypeVariable>();
1251 // Create types and elements for type variable.
1252 for (Link<Node> link = parameters; !link.isEmpty(); link = link.tail) {
1253 TypeVariable typeNode = link.head;
1254 SourceString variableName = typeNode.name.source;
1255 TypeVariableType variableType = new TypeVariableType(variableName);
1256 TypeVariableElement variableElement =
1257 new TypeVariableElement(variableName, classElement, node,
1258 variableType);
1259 variableType.element = variableElement;
1260 classElement.typeParameters[variableName] = variableElement;
1261 context = new TypeVariablesScope(context, classElement);
1262 }
1263 // Resolve the bounds of type variables.
1264 for (Link<Node> link = parameters; !link.isEmpty(); link = link.tail) {
1265 TypeVariable typeNode = link.head;
1266 SourceString variableName = typeNode.name.source;
1267 TypeVariableElement variableElement =
1268 classElement.typeParameters[variableName];
1269 if (typeNode.bound !== null) {
1270 Type boundType = visit(typeNode.bound);
1271 if (boundType !== null && boundType.element == variableElement) {
1272 warning(node, MessageKind.CYCLIC_TYPE_VARIABLE,
1273 [variableElement.name]);
1274 } else if (boundType !== null) {
1275 variableElement.bound = boundType;
1276 } else {
1277 variableElement.bound = compiler.objectClass.computeType(compiler);
1278 }
1279 }
1280 }
1281 // Find super type.
1282 Type supertype = visit(node.superclass);
1283 if (supertype !== null && supertype.element.isExtendable()) {
1284 classElement.supertype = supertype;
1285 if (isBlackListed(supertype)) {
1286 error(node.superclass, MessageKind.CANNOT_EXTEND, [supertype]);
1287 }
1288 } else if (supertype !== null) {
1289 error(node.superclass, MessageKind.TYPE_NAME_EXPECTED);
1290 }
1291 if (classElement.name != Types.OBJECT && classElement.supertype === null) {
1292 ClassElement objectElement = context.lookup(Types.OBJECT);
1293 if (objectElement !== null && !objectElement.isResolved) {
1294 compiler.resolver.toResolve.add(objectElement);
1295 } else if (objectElement === null){
1296 error(node, MessageKind.CANNOT_RESOLVE_TYPE, [Types.OBJECT]);
1297 }
1298 classElement.supertype = new SimpleType(Types.OBJECT, objectElement);
1299 }
1300 if (node.defaultClause !== null) {
1301 classElement.defaultClass = visit(node.defaultClause);
1302 }
1303 for (Link<Node> link = node.interfaces.nodes;
1304 !link.isEmpty();
1305 link = link.tail) {
1306 Type interfaceType = visit(link.head);
1307 if (interfaceType !== null && interfaceType.element.isExtendable()) {
1308 classElement.interfaces =
1309 classElement.interfaces.prepend(interfaceType);
1310 if (isBlackListed(interfaceType)) {
1311 error(link.head, MessageKind.CANNOT_IMPLEMENT, [interfaceType]);
1312 }
1313 } else {
1314 error(link.head, MessageKind.TYPE_NAME_EXPECTED);
1315 }
1316 }
1317 calculateAllSupertypes(classElement, new Set<ClassElement>());
1318 addDefaultConstructorIfNeeded(classElement);
1319 return classElement.computeType(compiler);
1320 }
1321
1322 Type visitTypeAnnotation(TypeAnnotation node) {
1323 return visit(node.typeName);
1324 }
1325
1326 Type visitIdentifier(Identifier node) {
1327 Element element = context.lookup(node.source);
1328 if (element === null) {
1329 error(node, MessageKind.CANNOT_RESOLVE_TYPE, [node]);
1330 return null;
1331 } else if (!element.impliesType() && !element.isTypeVariable()) {
1332 error(node, MessageKind.NOT_A_TYPE, [node]);
1333 return null;
1334 } else {
1335 if (element.isClass()) {
1336 compiler.resolver.toResolve.add(element);
1337 }
1338 if (element.isTypeVariable()) {
1339 TypeVariableElement variableElement = element;
1340 return variableElement.type;
1341 } else if (element.isTypedef()) {
1342 compiler.unimplemented('visitIdentifier for typedefs');
1343 } else {
1344 // TODO(ngeoffray): Use type variables.
1345 return element.computeType(compiler);
1346 }
1347 }
1348 return null;
1349 }
1350
1351 Type visitSend(Send node) {
1352 Identifier prefix = node.receiver.asIdentifier();
1353 if (prefix === null) {
1354 error(node.receiver, MessageKind.NOT_A_PREFIX, [node.receiver]);
1355 return null;
1356 }
1357 Element element = context.lookup(prefix.source);
1358 if (element === null || element.kind !== ElementKind.PREFIX) {
1359 error(node.receiver, MessageKind.NOT_A_PREFIX, [node.receiver]);
1360 return null;
1361 }
1362 PrefixElement prefixElement = element;
1363 Identifier selector = node.selector.asIdentifier();
1364 var e = prefixElement.lookupLocalMember(selector.source);
1365 if (e === null || !e.impliesType()) {
1366 error(node.selector, MessageKind.CANNOT_RESOLVE_TYPE, [node.selector]);
1367 return null;
1368 }
1369 return e.computeType(compiler);
1370 }
1371
1372 Link<Type> getOrCalculateAllSupertypes(ClassElement classElement,
1373 [Set<ClassElement> seen]) {
1374 Link<Type> allSupertypes = classElement.allSupertypes;
1375 if (allSupertypes !== null) return allSupertypes;
1376 if (seen === null) {
1377 seen = new Set<ClassElement>();
1378 }
1379 if (seen.contains(classElement)) {
1380 error(classElement.parseNode(compiler),
1381 MessageKind.CYCLIC_CLASS_HIERARCHY,
1382 [classElement.name]);
1383 classElement.allSupertypes = const EmptyLink<Type>();
1384 } else {
1385 classElement.ensureResolved(compiler);
1386 calculateAllSupertypes(classElement, seen);
1387 }
1388 return classElement.allSupertypes;
1389 }
1390
1391 void calculateAllSupertypes(ClassElement classElement,
1392 Set<ClassElement> seen) {
1393 // TODO(karlklose): substitute type variables.
1394 // TODO(karlklose): check if type arguments match, if a classelement occurs
1395 // more than once in the supertypes.
1396 if (classElement.allSupertypes !== null) return;
1397 final Type supertype = classElement.supertype;
1398 if (seen.contains(classElement)) {
1399 error(classElement.parseNode(compiler),
1400 MessageKind.CYCLIC_CLASS_HIERARCHY,
1401 [classElement.name]);
1402 classElement.allSupertypes = const EmptyLink<Type>();
1403 } else if (supertype != null) {
1404 seen.add(classElement);
1405 Link<Type> superSupertypes =
1406 getOrCalculateAllSupertypes(supertype.element, seen);
1407 Link<Type> supertypes = new Link<Type>(supertype, superSupertypes);
1408 for (Link<Type> interfaces = classElement.interfaces;
1409 !interfaces.isEmpty();
1410 interfaces = interfaces.tail) {
1411 Element element = interfaces.head.element;
1412 Link<Type> interfaceSupertypes =
1413 getOrCalculateAllSupertypes(element, seen);
1414 supertypes = supertypes.reversePrependAll(interfaceSupertypes);
1415 supertypes = supertypes.prepend(interfaces.head);
1416 }
1417 seen.remove(classElement);
1418 classElement.allSupertypes = supertypes;
1419 } else {
1420 classElement.allSupertypes = const EmptyLink<Type>();
1421 }
1422 }
1423
1424 /**
1425 * Add a synthetic nullary constructor if there are no other
1426 * constructors.
1427 */
1428 void addDefaultConstructorIfNeeded(ClassElement element) {
1429 if (element.constructors.length != 0) return;
1430 SynthesizedConstructorElement constructor =
1431 new SynthesizedConstructorElement(element);
1432 element.constructors[element.name] = constructor;
1433 Type returnType = compiler.types.voidType;
1434 constructor.type = new FunctionType(returnType, const EmptyLink<Type>(),
1435 constructor);
1436 constructor.cachedNode =
1437 new FunctionExpression(new Identifier(element.position()),
1438 new NodeList.empty(),
1439 new Block(new NodeList.empty()),
1440 null, null, null, null);
1441 }
1442
1443 isBlackListed(Type type) {
1444 LibraryElement lib = classElement.getLibrary();
1445 return
1446 lib !== compiler.coreLibrary &&
1447 lib !== compiler.coreImplLibrary &&
1448 lib !== compiler.jsHelperLibrary &&
1449 (type.element === compiler.dynamicClass ||
1450 type.element === compiler.boolClass ||
1451 type.element === compiler.numClass ||
1452 type.element === compiler.intClass ||
1453 type.element === compiler.doubleClass ||
1454 type.element === compiler.stringClass ||
1455 type.element === compiler.nullClass ||
1456 type.element === compiler.functionClass);
1457 }
1458 }
1459
1460 class VariableDefinitionsVisitor extends CommonResolverVisitor<SourceString> {
1461 VariableDefinitions definitions;
1462 ResolverVisitor resolver;
1463 ElementKind kind;
1464 VariableListElement variables;
1465
1466 VariableDefinitionsVisitor(Compiler compiler,
1467 this.definitions, this.resolver, this.kind)
1468 : super(compiler)
1469 {
1470 variables = new VariableListElement.node(
1471 definitions, ElementKind.VARIABLE_LIST, resolver.context.element);
1472 }
1473
1474 SourceString visitSendSet(SendSet node) {
1475 assert(node.arguments.tail.isEmpty()); // Sanity check
1476 resolver.visit(node.arguments.head);
1477 return visit(node.selector);
1478 }
1479
1480 SourceString visitIdentifier(Identifier node) => node.source;
1481
1482 visitNodeList(NodeList node) {
1483 for (Link<Node> link = node.nodes; !link.isEmpty(); link = link.tail) {
1484 SourceString name = visit(link.head);
1485 VariableElement element = new VariableElement(
1486 name, variables, kind, resolver.context.element, node: link.head);
1487 resolver.defineElement(link.head, element);
1488 }
1489 }
1490 }
1491
1492 class SignatureResolver extends CommonResolverVisitor<Element> {
1493 final Element enclosingElement;
1494 Link<Element> optionalParameters = const EmptyLink<Element>();
1495 int optionalParameterCount = 0;
1496 Node currentDefinitions;
1497
1498 SignatureResolver(Compiler compiler, this.enclosingElement) : super(compiler);
1499
1500 Element visitNodeList(NodeList node) {
1501 // This must be a list of optional arguments.
1502 if (node.beginToken.stringValue !== '[') {
1503 internalError(node, "expected optional parameters");
1504 }
1505 LinkBuilder<Element> elements = analyzeNodes(node.nodes);
1506 optionalParameterCount = elements.length;
1507 optionalParameters = elements.toLink();
1508 return null;
1509 }
1510
1511 Element visitVariableDefinitions(VariableDefinitions node) {
1512 resolveType(node.type);
1513
1514 Link<Node> definitions = node.definitions.nodes;
1515 if (definitions.isEmpty()) {
1516 cancel(node, 'internal error: no parameter definition');
1517 return null;
1518 }
1519 if (!definitions.tail.isEmpty()) {
1520 cancel(definitions.tail.head, 'internal error: extra definition');
1521 return null;
1522 }
1523 Node definition = definitions.head;
1524 if (definition is NodeList) {
1525 cancel(node, 'optional parameters are not implemented');
1526 }
1527
1528 if (currentDefinitions != null) {
1529 cancel(node, 'function type parameters not supported');
1530 }
1531 currentDefinitions = node;
1532 Element element = definition.accept(this);
1533 currentDefinitions = null;
1534 return element;
1535 }
1536
1537 Element visitIdentifier(Identifier node) {
1538 Element variables = new VariableListElement.node(currentDefinitions,
1539 ElementKind.VARIABLE_LIST, enclosingElement);
1540 return new VariableElement(node.source, variables,
1541 ElementKind.PARAMETER, enclosingElement, node: node);
1542 }
1543
1544 // The only valid [Send] can be in constructors and must be of the form
1545 // [:this.x:] (where [:x:] represents an instance field).
1546 FieldParameterElement visitSend(Send node) {
1547 FieldParameterElement element;
1548 if (node.receiver.asIdentifier() === null ||
1549 !node.receiver.asIdentifier().isThis()) {
1550 error(node, MessageKind.INVALID_PARAMETER, []);
1551 } else if (enclosingElement.kind !== ElementKind.GENERATIVE_CONSTRUCTOR) {
1552 error(node, MessageKind.FIELD_PARAMETER_NOT_ALLOWED, []);
1553 } else {
1554 if (node.selector.asIdentifier() == null) {
1555 cancel(node,
1556 'internal error: unimplemented receiver on parameter send');
1557 }
1558 SourceString name = node.selector.asIdentifier().source;
1559 Element fieldElement = currentClass.lookupLocalMember(name);
1560 if (fieldElement === null || fieldElement.kind !== ElementKind.FIELD) {
1561 error(node, MessageKind.NOT_A_FIELD, [name]);
1562 } else if (!fieldElement.isInstanceMember()) {
1563 error(node, MessageKind.NOT_INSTANCE_FIELD, [name]);
1564 }
1565 Element variables = new VariableListElement.node(currentDefinitions,
1566 ElementKind.VARIABLE_LIST, enclosingElement);
1567 element = new FieldParameterElement(node.selector.asIdentifier().source,
1568 fieldElement, variables, enclosingElement, node);
1569 }
1570 return element;
1571 }
1572
1573 Element visitSendSet(SendSet node) {
1574 Element element;
1575 if (node.receiver != null) {
1576 element = visitSend(node);
1577 } else if (node.selector.asIdentifier() != null) {
1578 Element variables = new VariableListElement.node(currentDefinitions,
1579 ElementKind.VARIABLE_LIST, enclosingElement);
1580 element = new VariableElement(node.selector.asIdentifier().source,
1581 variables, ElementKind.PARAMETER, enclosingElement, node: node);
1582 }
1583 // Visit the value. The compile time constant handler will
1584 // make sure it's a compile time constant.
1585 resolveExpression(node.arguments.head);
1586 compiler.enqueue(new WorkItem.toCompile(element));
1587 return element;
1588 }
1589
1590 Element visitFunctionExpression(FunctionExpression node) {
1591 // This is a function typed parameter.
1592 // TODO(ahe): Resolve the function type.
1593 return visit(node.name);
1594 }
1595
1596 LinkBuilder<Element> analyzeNodes(Link<Node> link) {
1597 LinkBuilder<Element> elements = new LinkBuilder<Element>();
1598 for (; !link.isEmpty(); link = link.tail) {
1599 Element element = link.head.accept(this);
1600 if (element != null) {
1601 elements.addLast(element);
1602 } else {
1603 // If parameter is null, the current node should be the last,
1604 // and a list of optional named parameters.
1605 if (!link.tail.isEmpty() || (link.head is !NodeList)) {
1606 internalError(link.head, "expected optional parameters");
1607 }
1608 }
1609 }
1610 return elements;
1611 }
1612
1613 static FunctionParameters analyze(Compiler compiler,
1614 FunctionElement element) {
1615 FunctionExpression node = element.parseNode(compiler);
1616 SignatureResolver visitor = new SignatureResolver(compiler, element);
1617 Link<Node> nodes = node.parameters.nodes;
1618 LinkBuilder<Element> parameters = visitor.analyzeNodes(nodes);
1619 return new FunctionParameters(parameters.toLink(),
1620 visitor.optionalParameters,
1621 parameters.length,
1622 visitor.optionalParameterCount);
1623 }
1624
1625 // TODO(ahe): This is temporary.
1626 void resolveExpression(Node node) {
1627 if (node == null) return;
1628 node.accept(new ResolverVisitor(compiler, enclosingElement));
1629 }
1630
1631 // TODO(ahe): This is temporary.
1632 void resolveType(Node node) {
1633 if (node == null) return;
1634 node.accept(new ResolverVisitor(compiler, enclosingElement));
1635 }
1636
1637 // TODO(ahe): This is temporary.
1638 ClassElement get currentClass() {
1639 return enclosingElement.isMember()
1640 ? enclosingElement.enclosingElement : null;
1641 }
1642 }
1643
1644 class ConstructorResolver extends CommonResolverVisitor<Element> {
1645 final ResolverVisitor resolver;
1646 ConstructorResolver(Compiler compiler, this.resolver) : super(compiler);
1647
1648 visitNode(Node node) {
1649 throw 'not supported';
1650 }
1651
1652 visitNewExpression(NewExpression node) {
1653 Node selector = node.send.selector;
1654 Element e = visit(selector);
1655 if (e !== null && e.kind === ElementKind.CLASS) {
1656 ClassElement cls = e;
1657 cls.ensureResolved(compiler);
1658 compiler.resolver.toResolve.add(cls);
1659 if (cls.isInterface() && (cls.defaultClass === null)) {
1660 error(selector, MessageKind.CANNOT_INSTANTIATE_INTERFACE, [cls.name]);
1661 }
1662 e = cls.lookupConstructor(cls.name);
1663 }
1664 return e;
1665 }
1666
1667 visitTypeAnnotation(TypeAnnotation node) {
1668 // TODO(ahe): Do not ignore type arguments.
1669 return visit(node.typeName);
1670 }
1671
1672 visitSend(Send node) {
1673 Element e = visit(node.receiver);
1674 if (e === null) return null; // TODO(ahe): Return erroneous element.
1675
1676 Identifier name = node.selector.asIdentifier();
1677 if (name === null) internalError(node.selector, 'unexpected node');
1678
1679 if (e.kind === ElementKind.CLASS) {
1680 ClassElement cls = e;
1681 cls.ensureResolved(compiler);
1682 compiler.resolver.toResolve.add(cls);
1683 if (cls.isInterface() && (cls.defaultClass === null)) {
1684 error(node.receiver, MessageKind.CANNOT_INSTANTIATE_INTERFACE,
1685 [cls.name]);
1686 }
1687 SourceString constructorName =
1688 Elements.constructConstructorName(cls.name, name.source);
1689 FunctionElement constructor = cls.lookupConstructor(constructorName);
1690 if (constructor === null) {
1691 error(name, MessageKind.CANNOT_FIND_CONSTRUCTOR, [name]);
1692 }
1693 e = constructor;
1694 } else if (e.kind === ElementKind.PREFIX) {
1695 PrefixElement prefix = e;
1696 e = prefix.lookupLocalMember(name.source);
1697 if (e === null) {
1698 error(name, MessageKind.CANNOT_RESOLVE, [name]);
1699 // TODO(ahe): Return erroneous element.
1700 } else if (e.kind !== ElementKind.CLASS) {
1701 error(node, MessageKind.NOT_A_TYPE, [name]);
1702 }
1703 } else {
1704 internalError(node.receiver, 'unexpected element $e');
1705 }
1706 return e;
1707 }
1708
1709 Element visitIdentifier(Identifier node) {
1710 SourceString name = node.source;
1711 Element e = resolver.lookup(node, name);
1712 if (e === null) {
1713 error(node, MessageKind.CANNOT_RESOLVE, [name]);
1714 // TODO(ahe): Return erroneous element.
1715 } else if (e.kind === ElementKind.TYPEDEF) {
1716 error(node, MessageKind.CANNOT_INSTANTIATE_TYPEDEF, [name]);
1717 } else if (e.kind !== ElementKind.CLASS && e.kind !== ElementKind.PREFIX) {
1718 error(node, MessageKind.NOT_A_TYPE, [name]);
1719 }
1720 return e;
1721 }
1722 }
1723
1724 class Scope {
1725 final Element element;
1726 final Scope parent;
1727
1728 Scope(this.parent, this.element);
1729 abstract Element add(Element element);
1730 abstract Element lookup(SourceString name);
1731 }
1732
1733 class TypeVariablesScope extends Scope {
1734 TypeVariablesScope(parent, ClassElement element) : super(parent, element);
1735 Element add(Element element) {
1736 throw "Cannot add element to TypeVariableScope";
1737 }
1738 Element lookup(SourceString name) {
1739 ClassElement cls = element;
1740 Element result = cls.lookupTypeParameter(name);
1741 if (result !== null) return result;
1742 if (parent !== null) return parent.lookup(name);
1743 }
1744 }
1745
1746 class MethodScope extends Scope {
1747 final Map<SourceString, Element> elements;
1748
1749 MethodScope(Scope parent, Element element)
1750 : super(parent, element), this.elements = new Map<SourceString, Element>();
1751
1752 Element lookup(SourceString name) {
1753 Element element = elements[name];
1754 if (element !== null) return element;
1755 return parent.lookup(name);
1756 }
1757
1758 Element add(Element element) {
1759 if (elements.containsKey(element.name)) return elements[element.name];
1760 elements[element.name] = element;
1761 return element;
1762 }
1763 }
1764
1765 class BlockScope extends MethodScope {
1766 BlockScope(Scope parent) : super(parent, parent.element);
1767 }
1768
1769 class ClassScope extends Scope {
1770 ClassScope(ClassElement element, LibraryElement library)
1771 : super(new TopScope(library), element);
1772
1773 Element lookup(SourceString name) {
1774 ClassElement cls = element;
1775 Element result = cls.lookupLocalMember(name);
1776 if (result !== null) return result;
1777 result = cls.lookupTypeParameter(name);
1778 if (result !== null) return result;
1779 result = parent.lookup(name);
1780 if (result != null) return result;
1781 return cls.lookupSuperMember(name);
1782 }
1783
1784 Element add(Element element) {
1785 throw "Cannot add an element in a class scope";
1786 }
1787 }
1788
1789 class TopScope extends Scope {
1790 LibraryElement get library() => element;
1791
1792 TopScope(LibraryElement library) : super(null, library);
1793 Element lookup(SourceString name) {
1794 return library.find(name);
1795 }
1796
1797 Element add(Element element) {
1798 throw "Cannot add an element in the top scope";
1799 }
1800 }
OLDNEW
« no previous file with comments | « frog/leg/operations.dart ('k') | frog/leg/scanner/array_based_scanner.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698