OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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 library dart2js.resolution; | 5 library dart2js.resolution; |
6 | 6 |
7 import 'dart:collection' show Queue; | 7 import 'dart:collection' show Queue; |
8 | 8 |
9 import '../common.dart'; | 9 import '../common.dart'; |
10 import '../common/names.dart' show Identifiers; | 10 import '../common/names.dart' show Identifiers; |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
75 CommonElements get commonElements => resolution.commonElements; | 75 CommonElements get commonElements => resolution.commonElements; |
76 ParsingContext get parsingContext => resolution.parsingContext; | 76 ParsingContext get parsingContext => resolution.parsingContext; |
77 CompilerOptions get options => resolution.options; | 77 CompilerOptions get options => resolution.options; |
78 ResolutionEnqueuer get enqueuer => resolution.enqueuer; | 78 ResolutionEnqueuer get enqueuer => resolution.enqueuer; |
79 OpenWorld get world => enqueuer.worldBuilder; | 79 OpenWorld get world => enqueuer.worldBuilder; |
80 | 80 |
81 ResolutionImpact resolve(Element element) { | 81 ResolutionImpact resolve(Element element) { |
82 return measure(() { | 82 return measure(() { |
83 if (Elements.isMalformed(element)) { | 83 if (Elements.isMalformed(element)) { |
84 // TODO(johnniwinther): Add a predicate for this. | 84 // TODO(johnniwinther): Add a predicate for this. |
85 assert(invariant(element, element is! ErroneousElement, | 85 assert( |
86 message: "Element $element expected to have parse errors.")); | 86 element is! ErroneousElement, |
| 87 failedAt( |
| 88 element, "Element $element expected to have parse errors.")); |
87 _ensureTreeElements(element); | 89 _ensureTreeElements(element); |
88 return const ResolutionImpact(); | 90 return const ResolutionImpact(); |
89 } | 91 } |
90 | 92 |
91 WorldImpact processMetadata([WorldImpact result]) { | 93 WorldImpact processMetadata([WorldImpact result]) { |
92 for (MetadataAnnotation metadata in element.implementation.metadata) { | 94 for (MetadataAnnotation metadata in element.implementation.metadata) { |
93 metadata.ensureResolved(resolution); | 95 metadata.ensureResolved(resolution); |
94 } | 96 } |
95 return result; | 97 return result; |
96 } | 98 } |
(...skipping 16 matching lines...) Expand all Loading... |
113 TypedefElement typdef = element; | 115 TypedefElement typdef = element; |
114 return processMetadata(resolveTypedef(typdef)); | 116 return processMetadata(resolveTypedef(typdef)); |
115 } | 117 } |
116 | 118 |
117 reporter.internalError(element, "resolve($element) not implemented."); | 119 reporter.internalError(element, "resolve($element) not implemented."); |
118 }); | 120 }); |
119 } | 121 } |
120 | 122 |
121 void resolveRedirectingConstructor(InitializerResolver resolver, Node node, | 123 void resolveRedirectingConstructor(InitializerResolver resolver, Node node, |
122 FunctionElement constructor, FunctionElement redirection) { | 124 FunctionElement constructor, FunctionElement redirection) { |
123 assert(invariant(node, constructor.isImplementation, | 125 assert( |
124 message: 'Redirecting constructors must be resolved on implementation ' | 126 constructor.isImplementation, |
| 127 failedAt( |
| 128 node, |
| 129 'Redirecting constructors must be resolved on implementation ' |
125 'elements.')); | 130 'elements.')); |
126 Setlet<FunctionElement> seen = new Setlet<FunctionElement>(); | 131 Setlet<FunctionElement> seen = new Setlet<FunctionElement>(); |
127 seen.add(constructor); | 132 seen.add(constructor); |
128 while (redirection != null) { | 133 while (redirection != null) { |
129 // Ensure that we follow redirections through implementation elements. | 134 // Ensure that we follow redirections through implementation elements. |
130 redirection = redirection.implementation; | 135 redirection = redirection.implementation; |
131 if (redirection.isError) { | 136 if (redirection.isError) { |
132 break; | 137 break; |
133 } | 138 } |
134 if (seen.contains(redirection)) { | 139 if (seen.contains(redirection)) { |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
286 } | 291 } |
287 | 292 |
288 resolution.target.resolveNativeMember(element, registry.impactBuilder); | 293 resolution.target.resolveNativeMember(element, registry.impactBuilder); |
289 | 294 |
290 return registry.impactBuilder; | 295 return registry.impactBuilder; |
291 }); | 296 }); |
292 } | 297 } |
293 | 298 |
294 /// Returns `true` if [element] has been processed by the resolution enqueuer. | 299 /// Returns `true` if [element] has been processed by the resolution enqueuer. |
295 bool _hasBeenProcessed(MemberElement element) { | 300 bool _hasBeenProcessed(MemberElement element) { |
296 assert(invariant(element, element == element.analyzableElement.declaration, | 301 assert(element == element.analyzableElement.declaration, |
297 message: "Unexpected element $element")); | 302 failedAt(element, "Unexpected element $element")); |
298 return enqueuer.processedEntities.contains(element); | 303 return enqueuer.processedEntities.contains(element); |
299 } | 304 } |
300 | 305 |
301 WorldImpact resolveMethodElement(FunctionElementX element) { | 306 WorldImpact resolveMethodElement(FunctionElementX element) { |
302 assert(invariant(element, element.isDeclaration)); | 307 assert(element.isDeclaration, failedAt(element)); |
303 return reporter.withCurrentElement(element, () { | 308 return reporter.withCurrentElement(element, () { |
304 if (_hasBeenProcessed(element)) { | 309 if (_hasBeenProcessed(element)) { |
305 // TODO(karlklose): Remove the check for [isConstructor]. [elememts] | 310 // TODO(karlklose): Remove the check for [isConstructor]. [elememts] |
306 // should never be non-null, not even for constructors. | 311 // should never be non-null, not even for constructors. |
307 assert(invariant(element, element.isConstructor, | 312 assert( |
308 message: 'Non-constructor element $element ' | 313 element.isConstructor, |
309 'has already been analyzed.')); | 314 failedAt(element, |
| 315 'Non-constructor element $element has already been analyzed.')); |
310 return const ResolutionImpact(); | 316 return const ResolutionImpact(); |
311 } | 317 } |
312 if (element.isSynthesized) { | 318 if (element.isSynthesized) { |
313 if (element.isGenerativeConstructor) { | 319 if (element.isGenerativeConstructor) { |
314 ResolutionRegistry registry = | 320 ResolutionRegistry registry = |
315 new ResolutionRegistry(this.target, _ensureTreeElements(element)); | 321 new ResolutionRegistry(this.target, _ensureTreeElements(element)); |
316 ConstructorElement constructor = element.asFunctionElement(); | 322 ConstructorElement constructor = element.asFunctionElement(); |
317 ConstructorElement target = constructor.definingConstructor; | 323 ConstructorElement target = constructor.definingConstructor; |
318 // Ensure the signature of the synthesized element is | 324 // Ensure the signature of the synthesized element is |
319 // resolved. This is the only place where the resolver is | 325 // resolved. This is the only place where the resolver is |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
374 } | 380 } |
375 ResolverVisitor visitor = visitorFor(element); | 381 ResolverVisitor visitor = visitorFor(element); |
376 ResolutionRegistry registry = visitor.registry; | 382 ResolutionRegistry registry = visitor.registry; |
377 // TODO(johnniwinther): Maybe remove this when placeholderCollector | 383 // TODO(johnniwinther): Maybe remove this when placeholderCollector |
378 // migrates to the backend ast. | 384 // migrates to the backend ast. |
379 registry.defineElement(element.definition, element); | 385 registry.defineElement(element.definition, element); |
380 // TODO(johnniwinther): Share the resolved type between all variables | 386 // TODO(johnniwinther): Share the resolved type between all variables |
381 // declared in the same declaration. | 387 // declared in the same declaration. |
382 if (tree.type != null) { | 388 if (tree.type != null) { |
383 ResolutionDartType type = visitor.resolveTypeAnnotation(tree.type); | 389 ResolutionDartType type = visitor.resolveTypeAnnotation(tree.type); |
384 assert(invariant( | 390 assert( |
385 element, | |
386 element.variables.type == null || | 391 element.variables.type == null || |
387 // Crude check but we have no equivalence relation that | 392 // Crude check but we have no equivalence relation that |
388 // equates malformed types, like matching creations of type | 393 // equates malformed types, like matching creations of type |
389 // `Foo<Unresolved>`. | 394 // `Foo<Unresolved>`. |
390 element.variables.type.toString() == type.toString(), | 395 element.variables.type.toString() == type.toString(), |
391 message: "Unexpected type computed for $element. " | 396 failedAt( |
| 397 element, |
| 398 "Unexpected type computed for $element. " |
392 "Was ${element.variables.type}, computed $type.")); | 399 "Was ${element.variables.type}, computed $type.")); |
393 element.variables.type = type; | 400 element.variables.type = type; |
394 } else if (element.variables.type == null) { | 401 } else if (element.variables.type == null) { |
395 // Only assign the dynamic type if the element has no known type. This | 402 // Only assign the dynamic type if the element has no known type. This |
396 // happens for enum fields where the type is known but is not in the | 403 // happens for enum fields where the type is known but is not in the |
397 // synthesized AST. | 404 // synthesized AST. |
398 element.variables.type = const ResolutionDynamicType(); | 405 element.variables.type = const ResolutionDynamicType(); |
399 } else { | 406 } else { |
400 registry.registerCheckedModeCheck(element.variables.type); | 407 registry.registerCheckedModeCheck(element.variables.type); |
401 } | 408 } |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
453 reporter.reportErrorMessage(annotation, MessageKind.VOID_NOT_ALLOWED); | 460 reporter.reportErrorMessage(annotation, MessageKind.VOID_NOT_ALLOWED); |
454 } | 461 } |
455 return type; | 462 return type; |
456 } | 463 } |
457 | 464 |
458 ResolutionDartType _resolveReturnType( | 465 ResolutionDartType _resolveReturnType( |
459 Element element, TypeAnnotation annotation) { | 466 Element element, TypeAnnotation annotation) { |
460 if (annotation == null) return const ResolutionDynamicType(); | 467 if (annotation == null) return const ResolutionDynamicType(); |
461 ResolutionDartType result = | 468 ResolutionDartType result = |
462 visitorFor(element).resolveTypeAnnotation(annotation); | 469 visitorFor(element).resolveTypeAnnotation(annotation); |
463 assert(invariant(annotation, result != null, | 470 assert(result != null, |
464 message: "No type computed for $annotation.")); | 471 failedAt(annotation, "No type computed for $annotation.")); |
465 if (result == null) { | 472 if (result == null) { |
466 // TODO(karklose): warning. | 473 // TODO(karklose): warning. |
467 return const ResolutionDynamicType(); | 474 return const ResolutionDynamicType(); |
468 } | 475 } |
469 return result; | 476 return result; |
470 } | 477 } |
471 | 478 |
472 void resolveRedirectionChain(ConstructorElement constructor, Spannable node) { | 479 void resolveRedirectionChain(ConstructorElement constructor, Spannable node) { |
473 ConstructorElement target = constructor; | 480 ConstructorElement target = constructor; |
474 ResolutionDartType targetType; | 481 ResolutionDartType targetType; |
475 List<ConstructorElement> seen = new List<ConstructorElement>(); | 482 List<ConstructorElement> seen = new List<ConstructorElement>(); |
476 bool isMalformed = false; | 483 bool isMalformed = false; |
477 // Follow the chain of redirections and check for cycles. | 484 // Follow the chain of redirections and check for cycles. |
478 while (target.isRedirectingFactory) { | 485 while (target.isRedirectingFactory) { |
479 if (target.hasEffectiveTarget) { | 486 if (target.hasEffectiveTarget) { |
480 // We found a constructor that already has been processed. | 487 // We found a constructor that already has been processed. |
481 // TODO(johnniwinther): Should `effectiveTargetType` be part of the | 488 // TODO(johnniwinther): Should `effectiveTargetType` be part of the |
482 // interface? | 489 // interface? |
483 targetType = | 490 targetType = |
484 target.computeEffectiveTargetType(target.enclosingClass.thisType); | 491 target.computeEffectiveTargetType(target.enclosingClass.thisType); |
485 assert(invariant(target, targetType != null, | 492 assert( |
486 message: 'Redirection target type has not been computed for ' | 493 targetType != null, |
487 '$target')); | 494 failedAt(target, |
| 495 'Redirection target type has not been computed for $target')); |
488 target = target.effectiveTarget; | 496 target = target.effectiveTarget; |
489 break; | 497 break; |
490 } | 498 } |
491 | 499 |
492 Element nextTarget = target.immediateRedirectionTarget; | 500 Element nextTarget = target.immediateRedirectionTarget; |
493 | 501 |
494 if (seen.contains(nextTarget)) { | 502 if (seen.contains(nextTarget)) { |
495 reporter.reportErrorMessage( | 503 reporter.reportErrorMessage( |
496 node, MessageKind.CYCLIC_REDIRECTING_FACTORY); | 504 node, MessageKind.CYCLIC_REDIRECTING_FACTORY); |
497 targetType = target.enclosingClass.thisType; | 505 targetType = target.enclosingClass.thisType; |
(...skipping 17 matching lines...) Expand all Loading... |
515 } | 523 } |
516 | 524 |
517 // [target] is now the actual target of the redirections. Run through | 525 // [target] is now the actual target of the redirections. Run through |
518 // the constructors again and set their [redirectionTarget], so that we | 526 // the constructors again and set their [redirectionTarget], so that we |
519 // do not have to run the loop for these constructors again. Furthermore, | 527 // do not have to run the loop for these constructors again. Furthermore, |
520 // compute [redirectionTargetType] for each factory by computing the | 528 // compute [redirectionTargetType] for each factory by computing the |
521 // substitution of the target type with respect to the factory type. | 529 // substitution of the target type with respect to the factory type. |
522 while (!seen.isEmpty) { | 530 while (!seen.isEmpty) { |
523 ConstructorElementX factory = seen.removeLast(); | 531 ConstructorElementX factory = seen.removeLast(); |
524 ResolvedAst resolvedAst = factory.resolvedAst; | 532 ResolvedAst resolvedAst = factory.resolvedAst; |
525 assert(invariant(node, resolvedAst != null, | 533 assert( |
526 message: 'No ResolvedAst for $factory.')); | 534 resolvedAst != null, failedAt(node, 'No ResolvedAst for $factory.')); |
527 RedirectingFactoryBody redirectionNode = resolvedAst.body; | 535 RedirectingFactoryBody redirectionNode = resolvedAst.body; |
528 ResolutionDartType factoryType = | 536 ResolutionDartType factoryType = |
529 resolvedAst.elements.getType(redirectionNode); | 537 resolvedAst.elements.getType(redirectionNode); |
530 if (!factoryType.isDynamic) { | 538 if (!factoryType.isDynamic) { |
531 targetType = targetType.substByContext(factoryType); | 539 targetType = targetType.substByContext(factoryType); |
532 } | 540 } |
533 factory.setEffectiveTarget(target, targetType, isMalformed: isMalformed); | 541 factory.setEffectiveTarget(target, targetType, isMalformed: isMalformed); |
534 } | 542 } |
535 } | 543 } |
536 | 544 |
537 /** | 545 /** |
538 * Load and resolve the supertypes of [cls]. | 546 * Load and resolve the supertypes of [cls]. |
539 * | 547 * |
540 * Warning: do not call this method directly. It should only be | 548 * Warning: do not call this method directly. It should only be |
541 * called by [resolveClass] and [ClassSupertypeResolver]. | 549 * called by [resolveClass] and [ClassSupertypeResolver]. |
542 */ | 550 */ |
543 void loadSupertypes(BaseClassElementX cls, Spannable from) { | 551 void loadSupertypes(BaseClassElementX cls, Spannable from) { |
544 measure(() { | 552 measure(() { |
545 if (cls.supertypeLoadState == STATE_DONE) return; | 553 if (cls.supertypeLoadState == STATE_DONE) return; |
546 if (cls.supertypeLoadState == STATE_STARTED) { | 554 if (cls.supertypeLoadState == STATE_STARTED) { |
547 reporter.reportErrorMessage( | 555 reporter.reportErrorMessage( |
548 from, MessageKind.CYCLIC_CLASS_HIERARCHY, {'className': cls.name}); | 556 from, MessageKind.CYCLIC_CLASS_HIERARCHY, {'className': cls.name}); |
549 cls.supertypeLoadState = STATE_DONE; | 557 cls.supertypeLoadState = STATE_DONE; |
550 cls.hasIncompleteHierarchy = true; | 558 cls.hasIncompleteHierarchy = true; |
551 ClassElement objectClass = commonElements.objectClass; | 559 ClassElement objectClass = commonElements.objectClass; |
552 cls.allSupertypesAndSelf = objectClass.allSupertypesAndSelf | 560 cls.allSupertypesAndSelf = objectClass.allSupertypesAndSelf |
553 .extendClass(cls.computeType(resolution)); | 561 .extendClass(cls.computeType(resolution)); |
554 cls.supertype = cls.allSupertypes.head; | 562 cls.supertype = cls.allSupertypes.head; |
555 assert(invariant(from, cls.supertype != null, | 563 assert(cls.supertype != null, |
556 message: 'Missing supertype on cyclic class $cls.')); | 564 failedAt(from, 'Missing supertype on cyclic class $cls.')); |
557 cls.interfaces = const Link<ResolutionDartType>(); | 565 cls.interfaces = const Link<ResolutionDartType>(); |
558 return; | 566 return; |
559 } | 567 } |
560 cls.supertypeLoadState = STATE_STARTED; | 568 cls.supertypeLoadState = STATE_STARTED; |
561 reporter.withCurrentElement(cls, () { | 569 reporter.withCurrentElement(cls, () { |
562 // TODO(ahe): Cache the node in cls. | 570 // TODO(ahe): Cache the node in cls. |
563 cls | 571 cls |
564 .parseNode(parsingContext) | 572 .parseNode(parsingContext) |
565 .accept(new ClassSupertypeResolver(resolution, cls)); | 573 .accept(new ClassSupertypeResolver(resolution, cls)); |
566 if (cls.supertypeLoadState != STATE_DONE) { | 574 if (cls.supertypeLoadState != STATE_DONE) { |
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
796 // Show the user the problematic uses of 'super' in the mixin. | 804 // Show the user the problematic uses of 'super' in the mixin. |
797 List<DiagnosticMessage> infos = <DiagnosticMessage>[]; | 805 List<DiagnosticMessage> infos = <DiagnosticMessage>[]; |
798 for (SourceSpan use in superUses) { | 806 for (SourceSpan use in superUses) { |
799 infos.add( | 807 infos.add( |
800 reporter.createMessage(use, MessageKind.ILLEGAL_MIXIN_SUPER_USE)); | 808 reporter.createMessage(use, MessageKind.ILLEGAL_MIXIN_SUPER_USE)); |
801 } | 809 } |
802 reporter.reportError(error, infos); | 810 reporter.reportError(error, infos); |
803 } | 811 } |
804 | 812 |
805 void checkClassMembers(ClassElement cls) { | 813 void checkClassMembers(ClassElement cls) { |
806 assert(invariant(cls, cls.isDeclaration)); | 814 assert(cls.isDeclaration, failedAt(cls)); |
807 if (cls.isObject) return; | 815 if (cls.isObject) return; |
808 // TODO(johnniwinther): Should this be done on the implementation element as | 816 // TODO(johnniwinther): Should this be done on the implementation element as |
809 // well? | 817 // well? |
810 List<Element> constConstructors = <Element>[]; | 818 List<Element> constConstructors = <Element>[]; |
811 List<Element> nonFinalInstanceFields = <Element>[]; | 819 List<Element> nonFinalInstanceFields = <Element>[]; |
812 cls.forEachMember((holder, dynamic member) { | 820 cls.forEachMember((holder, dynamic member) { |
813 reporter.withCurrentElement(member, () { | 821 reporter.withCurrentElement(member, () { |
814 // Perform various checks as side effect of "computing" the type. | 822 // Perform various checks as side effect of "computing" the type. |
815 member.computeType(resolution); | 823 member.computeType(resolution); |
816 | 824 |
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1072 annotation.resolutionState = STATE_STARTED; | 1080 annotation.resolutionState = STATE_STARTED; |
1073 | 1081 |
1074 Node node = annotation.parseNode(parsingContext); | 1082 Node node = annotation.parseNode(parsingContext); |
1075 Element annotatedElement = annotation.annotatedElement; | 1083 Element annotatedElement = annotation.annotatedElement; |
1076 AnalyzableElement context = annotatedElement.analyzableElement; | 1084 AnalyzableElement context = annotatedElement.analyzableElement; |
1077 ClassElement classElement = annotatedElement.enclosingClass; | 1085 ClassElement classElement = annotatedElement.enclosingClass; |
1078 if (classElement != null) { | 1086 if (classElement != null) { |
1079 // The annotation is resolved in the scope of [classElement]. | 1087 // The annotation is resolved in the scope of [classElement]. |
1080 classElement.ensureResolved(resolution); | 1088 classElement.ensureResolved(resolution); |
1081 } | 1089 } |
1082 assert(invariant(node, context != null, | 1090 assert( |
1083 message: "No context found for metadata annotation " | 1091 context != null, |
| 1092 failedAt( |
| 1093 node, |
| 1094 "No context found for metadata annotation " |
1084 "on $annotatedElement.")); | 1095 "on $annotatedElement.")); |
1085 ResolverVisitor visitor = | 1096 ResolverVisitor visitor = |
1086 visitorFor(context, useEnclosingScope: true); | 1097 visitorFor(context, useEnclosingScope: true); |
1087 ResolutionRegistry registry = visitor.registry; | 1098 ResolutionRegistry registry = visitor.registry; |
1088 node.accept(visitor); | 1099 node.accept(visitor); |
1089 // TODO(johnniwinther): Avoid passing the [TreeElements] to | 1100 // TODO(johnniwinther): Avoid passing the [TreeElements] to |
1090 // [compileMetadata]. | 1101 // [compileMetadata]. |
1091 ConstantExpression constant = constantCompiler.compileMetadata( | 1102 ConstantExpression constant = constantCompiler.compileMetadata( |
1092 annotation, node, registry.mapping); | 1103 annotation, node, registry.mapping); |
1093 switch (constant.kind) { | 1104 switch (constant.kind) { |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1141 } | 1152 } |
1142 return element._treeElements; | 1153 return element._treeElements; |
1143 } | 1154 } |
1144 | 1155 |
1145 abstract class AnalyzableElementX implements AnalyzableElement { | 1156 abstract class AnalyzableElementX implements AnalyzableElement { |
1146 TreeElements _treeElements; | 1157 TreeElements _treeElements; |
1147 | 1158 |
1148 bool get hasTreeElements => _treeElements != null; | 1159 bool get hasTreeElements => _treeElements != null; |
1149 | 1160 |
1150 TreeElements get treeElements { | 1161 TreeElements get treeElements { |
1151 assert(invariant(this, _treeElements != null, | 1162 assert(_treeElements != null, |
1152 message: "TreeElements have not been computed for $this.")); | 1163 failedAt(this, "TreeElements have not been computed for $this.")); |
1153 return _treeElements; | 1164 return _treeElements; |
1154 } | 1165 } |
1155 | 1166 |
1156 void reuseElement() { | 1167 void reuseElement() { |
1157 _treeElements = null; | 1168 _treeElements = null; |
1158 } | 1169 } |
1159 } | 1170 } |
OLD | NEW |