| 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 part of resolution; | 5 part of resolution; |
| 6 | 6 |
| 7 abstract class TreeElements { | 7 abstract class TreeElements { |
| 8 AnalyzableElement get analyzedElement; | 8 AnalyzableElement get analyzedElement; |
| 9 Iterable<Node> get superUses; | 9 Iterable<Node> get superUses; |
| 10 | 10 |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 112 | 112 |
| 113 /// Map from labeled goto statements to the labels they target. | 113 /// Map from labeled goto statements to the labels they target. |
| 114 Map<GotoStatement, LabelDefinition> _targetLabels; | 114 Map<GotoStatement, LabelDefinition> _targetLabels; |
| 115 | 115 |
| 116 final int hashCode = ++_hashCodeCounter; | 116 final int hashCode = ++_hashCodeCounter; |
| 117 static int _hashCodeCounter = 0; | 117 static int _hashCodeCounter = 0; |
| 118 | 118 |
| 119 TreeElementMapping(this.analyzedElement); | 119 TreeElementMapping(this.analyzedElement); |
| 120 | 120 |
| 121 operator []=(Node node, Element element) { | 121 operator []=(Node node, Element element) { |
| 122 assert(invariant(node, () { | |
| 123 FunctionExpression functionExpression = node.asFunctionExpression(); | |
| 124 if (functionExpression != null) { | |
| 125 return !functionExpression.modifiers.isExternal; | |
| 126 } | |
| 127 return true; | |
| 128 })); | |
| 129 // TODO(johnniwinther): Simplify this invariant to use only declarations in | 122 // TODO(johnniwinther): Simplify this invariant to use only declarations in |
| 130 // [TreeElements]. | 123 // [TreeElements]. |
| 131 assert(invariant(node, () { | 124 assert(invariant(node, () { |
| 132 if (!element.isErroneous && analyzedElement != null && element.isPatch) { | 125 if (!element.isErroneous && analyzedElement != null && element.isPatch) { |
| 133 return analyzedElement.implementationLibrary.isPatch; | 126 return analyzedElement.implementationLibrary.isPatch; |
| 134 } | 127 } |
| 135 return true; | 128 return true; |
| 136 })); | 129 })); |
| 137 // TODO(ahe): Investigate why the invariant below doesn't hold. | 130 // TODO(ahe): Investigate why the invariant below doesn't hold. |
| 138 // assert(invariant(node, | 131 // assert(invariant(node, |
| (...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 491 redirection = redirection.implementation; | 484 redirection = redirection.implementation; |
| 492 if (seen.contains(redirection)) { | 485 if (seen.contains(redirection)) { |
| 493 resolver.visitor.error(node, MessageKind.REDIRECTING_CONSTRUCTOR_CYCLE); | 486 resolver.visitor.error(node, MessageKind.REDIRECTING_CONSTRUCTOR_CYCLE); |
| 494 return; | 487 return; |
| 495 } | 488 } |
| 496 seen.add(redirection); | 489 seen.add(redirection); |
| 497 redirection = resolver.visitor.resolveConstructorRedirection(redirection); | 490 redirection = resolver.visitor.resolveConstructorRedirection(redirection); |
| 498 } | 491 } |
| 499 } | 492 } |
| 500 | 493 |
| 501 void checkMatchingPatchParameters(FunctionElement origin, | |
| 502 Link<Element> originParameters, | |
| 503 Link<Element> patchParameters) { | |
| 504 while (!originParameters.isEmpty) { | |
| 505 ParameterElementX originParameter = originParameters.head; | |
| 506 ParameterElementX patchParameter = patchParameters.head; | |
| 507 // TODO(johnniwinther): Remove the conditional patching when we never | |
| 508 // resolve the same method twice. | |
| 509 if (!originParameter.isPatched) { | |
| 510 originParameter.applyPatch(patchParameter); | |
| 511 } else { | |
| 512 assert(invariant(origin, originParameter.patch == patchParameter, | |
| 513 message: "Inconsistent repatch of $originParameter.")); | |
| 514 } | |
| 515 DartType originParameterType = originParameter.computeType(compiler); | |
| 516 DartType patchParameterType = patchParameter.computeType(compiler); | |
| 517 if (originParameterType != patchParameterType) { | |
| 518 compiler.reportError( | |
| 519 originParameter.parseNode(compiler), | |
| 520 MessageKind.PATCH_PARAMETER_TYPE_MISMATCH, | |
| 521 {'methodName': origin.name, | |
| 522 'parameterName': originParameter.name, | |
| 523 'originParameterType': originParameterType, | |
| 524 'patchParameterType': patchParameterType}); | |
| 525 compiler.reportInfo(patchParameter, | |
| 526 MessageKind.PATCH_POINT_TO_PARAMETER, | |
| 527 {'parameterName': patchParameter.name}); | |
| 528 } else { | |
| 529 // Hack: Use unparser to test parameter equality. This only works | |
| 530 // because we are restricting patch uses and the approach cannot be used | |
| 531 // elsewhere. | |
| 532 | |
| 533 // The node contains the type, so there is a potential overlap. | |
| 534 // Therefore we only check the text if the types are identical. | |
| 535 String originParameterText = | |
| 536 originParameter.parseNode(compiler).toString(); | |
| 537 String patchParameterText = | |
| 538 patchParameter.parseNode(compiler).toString(); | |
| 539 if (originParameterText != patchParameterText | |
| 540 // We special case the list constructor because of the | |
| 541 // optional parameter. | |
| 542 && origin != compiler.unnamedListConstructor) { | |
| 543 compiler.reportError( | |
| 544 originParameter.parseNode(compiler), | |
| 545 MessageKind.PATCH_PARAMETER_MISMATCH, | |
| 546 {'methodName': origin.name, | |
| 547 'originParameter': originParameterText, | |
| 548 'patchParameter': patchParameterText}); | |
| 549 compiler.reportInfo(patchParameter, | |
| 550 MessageKind.PATCH_POINT_TO_PARAMETER, | |
| 551 {'parameterName': patchParameter.name}); | |
| 552 } | |
| 553 } | |
| 554 | |
| 555 originParameters = originParameters.tail; | |
| 556 patchParameters = patchParameters.tail; | |
| 557 } | |
| 558 } | |
| 559 | |
| 560 void checkMatchingPatchSignatures(FunctionElement origin, | |
| 561 FunctionElement patch) { | |
| 562 // TODO(johnniwinther): Show both origin and patch locations on errors. | |
| 563 FunctionExpression originTree = origin.node; | |
| 564 FunctionSignature originSignature = origin.functionSignature; | |
| 565 FunctionExpression patchTree = patch.node; | |
| 566 FunctionSignature patchSignature = patch.functionSignature; | |
| 567 | |
| 568 if (originSignature.type.returnType != patchSignature.type.returnType) { | |
| 569 compiler.withCurrentElement(patch, () { | |
| 570 Node errorNode = | |
| 571 patchTree.returnType != null ? patchTree.returnType : patchTree; | |
| 572 error(errorNode, MessageKind.PATCH_RETURN_TYPE_MISMATCH, | |
| 573 {'methodName': origin.name, | |
| 574 'originReturnType': originSignature.type.returnType, | |
| 575 'patchReturnType': patchSignature.type.returnType}); | |
| 576 }); | |
| 577 } | |
| 578 if (originSignature.requiredParameterCount != | |
| 579 patchSignature.requiredParameterCount) { | |
| 580 compiler.withCurrentElement(patch, () { | |
| 581 error(patchTree, | |
| 582 MessageKind.PATCH_REQUIRED_PARAMETER_COUNT_MISMATCH, | |
| 583 {'methodName': origin.name, | |
| 584 'originParameterCount': originSignature.requiredParameterCount, | |
| 585 'patchParameterCount': patchSignature.requiredParameterCount}); | |
| 586 }); | |
| 587 } else { | |
| 588 checkMatchingPatchParameters(origin, | |
| 589 originSignature.requiredParameters, | |
| 590 patchSignature.requiredParameters); | |
| 591 } | |
| 592 if (originSignature.optionalParameterCount != 0 && | |
| 593 patchSignature.optionalParameterCount != 0) { | |
| 594 if (originSignature.optionalParametersAreNamed != | |
| 595 patchSignature.optionalParametersAreNamed) { | |
| 596 compiler.withCurrentElement(patch, () { | |
| 597 error(patchTree, | |
| 598 MessageKind.PATCH_OPTIONAL_PARAMETER_NAMED_MISMATCH, | |
| 599 {'methodName': origin.name}); | |
| 600 }); | |
| 601 } | |
| 602 } | |
| 603 if (originSignature.optionalParameterCount != | |
| 604 patchSignature.optionalParameterCount) { | |
| 605 compiler.withCurrentElement(patch, () { | |
| 606 error(patchTree, | |
| 607 MessageKind.PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH, | |
| 608 {'methodName': origin.name, | |
| 609 'originParameterCount': originSignature.optionalParameterCount, | |
| 610 'patchParameterCount': patchSignature.optionalParameterCount}); | |
| 611 }); | |
| 612 } else { | |
| 613 checkMatchingPatchParameters(origin, | |
| 614 originSignature.optionalParameters, | |
| 615 patchSignature.optionalParameters); | |
| 616 } | |
| 617 } | |
| 618 | |
| 619 static void processAsyncMarker(Compiler compiler, | 494 static void processAsyncMarker(Compiler compiler, |
| 620 BaseFunctionElementX element) { | 495 BaseFunctionElementX element) { |
| 621 FunctionExpression functionExpression = element.node; | 496 FunctionExpression functionExpression = element.node; |
| 622 AsyncModifier asyncModifier = functionExpression.asyncModifier; | 497 AsyncModifier asyncModifier = functionExpression.asyncModifier; |
| 623 if (asyncModifier != null) { | 498 if (asyncModifier != null) { |
| 624 if (!compiler.enableAsyncAwait) { | 499 if (!compiler.enableAsyncAwait) { |
| 625 compiler.reportError(asyncModifier, | 500 compiler.reportError(asyncModifier, |
| 626 MessageKind.EXPERIMENTAL_ASYNC_AWAIT, | 501 MessageKind.EXPERIMENTAL_ASYNC_AWAIT, |
| 627 {'modifier': element.asyncMarker}); | 502 {'modifier': element.asyncMarker}); |
| 628 } else if (!compiler.analyzeOnly) { | 503 } else if (!compiler.analyzeOnly) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 647 {'modifier': element.asyncMarker}); | 522 {'modifier': element.asyncMarker}); |
| 648 } else if (functionExpression.body.asReturn() != null && | 523 } else if (functionExpression.body.asReturn() != null && |
| 649 element.asyncMarker.isYielding) { | 524 element.asyncMarker.isYielding) { |
| 650 compiler.reportError(asyncModifier, | 525 compiler.reportError(asyncModifier, |
| 651 MessageKind.YIELDING_MODIFIER_ON_ARROW_BODY, | 526 MessageKind.YIELDING_MODIFIER_ON_ARROW_BODY, |
| 652 {'modifier': element.asyncMarker}); | 527 {'modifier': element.asyncMarker}); |
| 653 } | 528 } |
| 654 } | 529 } |
| 655 } | 530 } |
| 656 | 531 |
| 532 TreeElements resolveMethodElementImplementation( |
| 533 FunctionElement element, FunctionExpression tree) { |
| 534 return compiler.withCurrentElement(element, () { |
| 535 if (element.isExternal && tree.hasBody()) { |
| 536 compiler.reportError(element, |
| 537 MessageKind.EXTERNAL_WITH_BODY, |
| 538 {'functionName': element.name}); |
| 539 } |
| 540 if (element.isConstructor) { |
| 541 if (tree.returnType != null) { |
| 542 compiler.reportError(tree, MessageKind.CONSTRUCTOR_WITH_RETURN_TYPE); |
| 543 } |
| 544 if (element.isConst && |
| 545 tree.hasBody() && |
| 546 !tree.isRedirectingFactory) { |
| 547 compiler.reportError(tree, MessageKind.CONST_CONSTRUCTOR_HAS_BODY); |
| 548 } |
| 549 } |
| 550 |
| 551 ResolverVisitor visitor = visitorFor(element); |
| 552 ResolutionRegistry registry = visitor.registry; |
| 553 registry.defineFunction(tree, element); |
| 554 visitor.setupFunction(tree, element); |
| 555 |
| 556 if (element.isGenerativeConstructor) { |
| 557 // Even if there is no initializer list we still have to do the |
| 558 // resolution in case there is an implicit super constructor call. |
| 559 InitializerResolver resolver = new InitializerResolver(visitor); |
| 560 FunctionElement redirection = |
| 561 resolver.resolveInitializers(element, tree); |
| 562 if (redirection != null) { |
| 563 resolveRedirectingConstructor(resolver, tree, element, redirection); |
| 564 } |
| 565 } else if (tree.initializers != null) { |
| 566 error(tree, MessageKind.FUNCTION_WITH_INITIALIZER); |
| 567 } |
| 568 |
| 569 if (!compiler.analyzeSignaturesOnly || tree.isRedirectingFactory) { |
| 570 // We need to analyze the redirecting factory bodies to ensure that |
| 571 // we can analyze compile-time constants. |
| 572 visitor.visit(tree.body); |
| 573 } |
| 574 |
| 575 // Get the resolution tree and check that the resolved |
| 576 // function doesn't use 'super' if it is mixed into another |
| 577 // class. This is the part of the 'super' mixin check that |
| 578 // happens when a function is resolved after the mixin |
| 579 // application has been performed. |
| 580 TreeElements resolutionTree = registry.mapping; |
| 581 ClassElement enclosingClass = element.enclosingClass; |
| 582 if (enclosingClass != null) { |
| 583 // TODO(johnniwinther): Find another way to obtain mixin uses. |
| 584 Iterable<MixinApplicationElement> mixinUses = |
| 585 compiler.world.allMixinUsesOf(enclosingClass); |
| 586 ClassElement mixin = enclosingClass; |
| 587 for (MixinApplicationElement mixinApplication in mixinUses) { |
| 588 checkMixinSuperUses(resolutionTree, mixinApplication, mixin); |
| 589 } |
| 590 } |
| 591 return resolutionTree; |
| 592 }); |
| 593 |
| 594 } |
| 595 |
| 657 TreeElements resolveMethodElement(FunctionElementX element) { | 596 TreeElements resolveMethodElement(FunctionElementX element) { |
| 658 assert(invariant(element, element.isDeclaration)); | 597 assert(invariant(element, element.isDeclaration)); |
| 659 return compiler.withCurrentElement(element, () { | 598 return compiler.withCurrentElement(element, () { |
| 660 bool isConstructor = | |
| 661 identical(element.kind, ElementKind.GENERATIVE_CONSTRUCTOR); | |
| 662 if (compiler.enqueuer.resolution.hasBeenResolved(element)) { | 599 if (compiler.enqueuer.resolution.hasBeenResolved(element)) { |
| 663 // TODO(karlklose): Remove the check for [isConstructor]. [elememts] | 600 // TODO(karlklose): Remove the check for [isConstructor]. [elememts] |
| 664 // should never be non-null, not even for constructors. | 601 // should never be non-null, not even for constructors. |
| 665 assert(invariant(element, element.isConstructor, | 602 assert(invariant(element, element.isConstructor, |
| 666 message: 'Non-constructor element $element ' | 603 message: 'Non-constructor element $element ' |
| 667 'has already been analyzed.')); | 604 'has already been analyzed.')); |
| 668 return element.resolvedAst.elements; | 605 return element.resolvedAst.elements; |
| 669 } | 606 } |
| 670 if (element.isSynthesized) { | 607 if (element.isSynthesized) { |
| 671 if (isConstructor) { | 608 if (element.isGenerativeConstructor) { |
| 672 ResolutionRegistry registry = | 609 ResolutionRegistry registry = |
| 673 new ResolutionRegistry(compiler, element); | 610 new ResolutionRegistry(compiler, element); |
| 674 ConstructorElement constructor = element.asFunctionElement(); | 611 ConstructorElement constructor = element.asFunctionElement(); |
| 675 ConstructorElement target = constructor.definingConstructor; | 612 ConstructorElement target = constructor.definingConstructor; |
| 676 // Ensure the signature of the synthesized element is | 613 // Ensure the signature of the synthesized element is |
| 677 // resolved. This is the only place where the resolver is | 614 // resolved. This is the only place where the resolver is |
| 678 // seeing this element. | 615 // seeing this element. |
| 679 element.computeSignature(compiler); | 616 element.computeSignature(compiler); |
| 680 if (!target.isErroneous) { | 617 if (!target.isErroneous) { |
| 681 registry.registerStaticUse(target); | 618 registry.registerStaticUse(target); |
| 682 registry.registerImplicitSuperCall(target); | 619 registry.registerImplicitSuperCall(target); |
| 683 } | 620 } |
| 684 return registry.mapping; | 621 return registry.mapping; |
| 685 } else { | 622 } else { |
| 686 assert(element.isDeferredLoaderGetter); | 623 assert(element.isDeferredLoaderGetter); |
| 687 return _ensureTreeElements(element); | 624 return _ensureTreeElements(element); |
| 688 } | 625 } |
| 626 } else { |
| 627 element.parseNode(compiler); |
| 628 element.computeType(compiler); |
| 629 processAsyncMarker(compiler, element); |
| 630 FunctionElementX implementation = element; |
| 631 if (element.isExternal) { |
| 632 implementation = compiler.backend.resolveExternalFunction(element); |
| 633 } |
| 634 return resolveMethodElementImplementation( |
| 635 implementation, implementation.node); |
| 689 } | 636 } |
| 690 element.parseNode(compiler); | |
| 691 element.computeType(compiler); | |
| 692 processAsyncMarker(compiler, element); | |
| 693 if (element.isPatched) { | |
| 694 FunctionElementX patch = element.patch; | |
| 695 compiler.withCurrentElement(patch, () { | |
| 696 patch.parseNode(compiler); | |
| 697 patch.computeType(compiler); | |
| 698 }); | |
| 699 checkMatchingPatchSignatures(element, patch); | |
| 700 element = patch; | |
| 701 processAsyncMarker(compiler, element); | |
| 702 } | |
| 703 return compiler.withCurrentElement(element, () { | |
| 704 FunctionExpression tree = element.node; | |
| 705 if (tree.modifiers.isExternal) { | |
| 706 error(tree, MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION); | |
| 707 return null; | |
| 708 } | |
| 709 if (isConstructor || element.isFactoryConstructor) { | |
| 710 if (tree.returnType != null) { | |
| 711 error(tree, MessageKind.CONSTRUCTOR_WITH_RETURN_TYPE); | |
| 712 } | |
| 713 if (element.modifiers.isConst && | |
| 714 tree.hasBody() && | |
| 715 !tree.isRedirectingFactory) { | |
| 716 compiler.reportError(tree, MessageKind.CONST_CONSTRUCTOR_HAS_BODY); | |
| 717 } | |
| 718 } | |
| 719 | |
| 720 ResolverVisitor visitor = visitorFor(element); | |
| 721 ResolutionRegistry registry = visitor.registry; | |
| 722 registry.defineFunction(tree, element); | |
| 723 visitor.setupFunction(tree, element); | |
| 724 | |
| 725 if (isConstructor && !element.isForwardingConstructor) { | |
| 726 // Even if there is no initializer list we still have to do the | |
| 727 // resolution in case there is an implicit super constructor call. | |
| 728 InitializerResolver resolver = new InitializerResolver(visitor); | |
| 729 FunctionElement redirection = | |
| 730 resolver.resolveInitializers(element, tree); | |
| 731 if (redirection != null) { | |
| 732 resolveRedirectingConstructor(resolver, tree, element, redirection); | |
| 733 } | |
| 734 } else if (element.isForwardingConstructor) { | |
| 735 // Initializers will be checked on the original constructor. | |
| 736 } else if (tree.initializers != null) { | |
| 737 error(tree, MessageKind.FUNCTION_WITH_INITIALIZER); | |
| 738 } | |
| 739 | |
| 740 if (!compiler.analyzeSignaturesOnly || tree.isRedirectingFactory) { | |
| 741 // We need to analyze the redirecting factory bodies to ensure that | |
| 742 // we can analyze compile-time constants. | |
| 743 visitor.visit(tree.body); | |
| 744 } | |
| 745 | |
| 746 // Get the resolution tree and check that the resolved | |
| 747 // function doesn't use 'super' if it is mixed into another | |
| 748 // class. This is the part of the 'super' mixin check that | |
| 749 // happens when a function is resolved after the mixin | |
| 750 // application has been performed. | |
| 751 TreeElements resolutionTree = registry.mapping; | |
| 752 ClassElement enclosingClass = element.enclosingClass; | |
| 753 if (enclosingClass != null) { | |
| 754 // TODO(johnniwinther): Find another way to obtain mixin uses. | |
| 755 Iterable<MixinApplicationElement> mixinUses = | |
| 756 compiler.world.allMixinUsesOf(enclosingClass); | |
| 757 ClassElement mixin = enclosingClass; | |
| 758 for (MixinApplicationElement mixinApplication in mixinUses) { | |
| 759 checkMixinSuperUses(resolutionTree, mixinApplication, mixin); | |
| 760 } | |
| 761 } | |
| 762 return resolutionTree; | |
| 763 }); | |
| 764 }); | 637 }); |
| 765 } | 638 } |
| 766 | 639 |
| 767 /// Creates a [ResolverVisitor] for resolving an AST in context of [element]. | 640 /// Creates a [ResolverVisitor] for resolving an AST in context of [element]. |
| 768 /// If [useEnclosingScope] is `true` then the initial scope of the visitor | 641 /// If [useEnclosingScope] is `true` then the initial scope of the visitor |
| 769 /// does not include inner scope of [element]. | 642 /// does not include inner scope of [element]. |
| 770 /// | 643 /// |
| 771 /// This method should only be used by this library (or tests of | 644 /// This method should only be used by this library (or tests of |
| 772 /// this library). | 645 /// this library). |
| 773 ResolverVisitor visitorFor(Element element, {bool useEnclosingScope: false}) { | 646 ResolverVisitor visitorFor(Element element, {bool useEnclosingScope: false}) { |
| (...skipping 4327 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5101 } | 4974 } |
| 5102 | 4975 |
| 5103 /// The result for the resolution of the `assert` method. | 4976 /// The result for the resolution of the `assert` method. |
| 5104 class AssertResult implements ResolutionResult { | 4977 class AssertResult implements ResolutionResult { |
| 5105 const AssertResult(); | 4978 const AssertResult(); |
| 5106 | 4979 |
| 5107 Element get element => null; | 4980 Element get element => null; |
| 5108 | 4981 |
| 5109 String toString() => 'AssertResult()'; | 4982 String toString() => 'AssertResult()'; |
| 5110 } | 4983 } |
| OLD | NEW |