| 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.typechecker; | 5 library dart2js.typechecker; |
| 6 | 6 |
| 7 import 'common/names.dart' show Identifiers; | 7 import 'common/names.dart' show Identifiers; |
| 8 import 'common/resolution.dart' show Resolution; | 8 import 'common/resolution.dart' show Resolution; |
| 9 import 'common/tasks.dart' show CompilerTask; | 9 import 'common/tasks.dart' show CompilerTask; |
| 10 import 'common.dart'; | 10 import 'common.dart'; |
| (...skipping 412 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 423 } | 423 } |
| 424 return type; | 424 return type; |
| 425 } | 425 } |
| 426 | 426 |
| 427 DartType analyzeWithDefault(Node node, DartType defaultValue) { | 427 DartType analyzeWithDefault(Node node, DartType defaultValue) { |
| 428 return node != null ? analyze(node) : defaultValue; | 428 return node != null ? analyze(node) : defaultValue; |
| 429 } | 429 } |
| 430 | 430 |
| 431 /// If [inInitializer] is true, assignment should be interpreted as write to | 431 /// If [inInitializer] is true, assignment should be interpreted as write to |
| 432 /// a field and not to a setter. | 432 /// a field and not to a setter. |
| 433 DartType analyze(Node node, {bool inInitializer: false}) { | 433 DartType analyze(Node node, |
| 434 {bool inInitializer: false, bool mustHaveType: true}) { |
| 434 if (node == null) { | 435 if (node == null) { |
| 435 final String error = 'Unexpected node: null'; | 436 final String error = 'Unexpected node: null'; |
| 436 if (lastSeenNode != null) { | 437 if (lastSeenNode != null) { |
| 437 reporter.internalError(lastSeenNode, error); | 438 reporter.internalError(lastSeenNode, error); |
| 438 } else { | 439 } else { |
| 439 reporter.internalError(executableContext, error); | 440 reporter.internalError(executableContext, error); |
| 440 } | 441 } |
| 441 } else { | 442 } else { |
| 442 lastSeenNode = node; | 443 lastSeenNode = node; |
| 443 } | 444 } |
| 444 bool previouslyInitializer = analyzingInitializer; | 445 bool previouslyInitializer = analyzingInitializer; |
| 445 analyzingInitializer = inInitializer; | 446 analyzingInitializer = inInitializer; |
| 446 DartType result = node.accept(this); | 447 DartType result = node.accept(this); |
| 447 analyzingInitializer = previouslyInitializer; | 448 analyzingInitializer = previouslyInitializer; |
| 448 if (result == null) { | 449 if (result == null && mustHaveType) { |
| 449 reporter.internalError(node, 'Type is null.'); | 450 reporter.internalError(node, 'Type is null.'); |
| 450 } | 451 } |
| 451 return result; | 452 return result; |
| 452 } | 453 } |
| 453 | 454 |
| 455 void analyzeUntyped(Node node, {bool inInitializer: false}) { |
| 456 if (node != null) { |
| 457 analyze(node, inInitializer: inInitializer, mustHaveType: false); |
| 458 } |
| 459 } |
| 460 |
| 454 void checkTypePromotion(Node node, TypePromotion typePromotion, | 461 void checkTypePromotion(Node node, TypePromotion typePromotion, |
| 455 {bool checkAccesses: false}) { | 462 {bool checkAccesses: false}) { |
| 456 VariableElement variable = typePromotion.variable; | 463 VariableElement variable = typePromotion.variable; |
| 457 String variableName = variable.name; | 464 String variableName = variable.name; |
| 458 List<Node> potentialMutationsIn = | 465 List<Node> potentialMutationsIn = |
| 459 elements.getPotentialMutationsIn(node, variable); | 466 elements.getPotentialMutationsIn(node, variable); |
| 460 if (!potentialMutationsIn.isEmpty) { | 467 if (!potentialMutationsIn.isEmpty) { |
| 461 DiagnosticMessage hint = reporter.createMessage( | 468 DiagnosticMessage hint = reporter.createMessage( |
| 462 typePromotion.node, | 469 typePromotion.node, |
| 463 MessageKind.POTENTIAL_MUTATION, | 470 MessageKind.POTENTIAL_MUTATION, |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 523 } | 530 } |
| 524 | 531 |
| 525 for (TypePromotion typePromotion in getShownTypePromotionsFor(right)) { | 532 for (TypePromotion typePromotion in getShownTypePromotionsFor(right)) { |
| 526 typePromotion = typePromotion.copy(); | 533 typePromotion = typePromotion.copy(); |
| 527 checkTypePromotion(right, typePromotion); | 534 checkTypePromotion(right, typePromotion); |
| 528 showTypePromotion(node, typePromotion); | 535 showTypePromotion(node, typePromotion); |
| 529 } | 536 } |
| 530 } | 537 } |
| 531 | 538 |
| 532 /// Analyze [node] in the context of the known types shown in [context]. | 539 /// Analyze [node] in the context of the known types shown in [context]. |
| 533 DartType analyzeInPromotedContext(Node context, Node node) { | 540 DartType analyzeInPromotedContext(Node context, Node node, |
| 541 {bool mustHaveType: false}) { |
| 534 Link<TypePromotion> knownForNode = const Link<TypePromotion>(); | 542 Link<TypePromotion> knownForNode = const Link<TypePromotion>(); |
| 535 for (TypePromotion typePromotion in getShownTypePromotionsFor(context)) { | 543 for (TypePromotion typePromotion in getShownTypePromotionsFor(context)) { |
| 536 typePromotion = typePromotion.copy(); | 544 typePromotion = typePromotion.copy(); |
| 537 checkTypePromotion(node, typePromotion, checkAccesses: true); | 545 checkTypePromotion(node, typePromotion, checkAccesses: true); |
| 538 knownForNode = knownForNode.prepend(typePromotion); | 546 knownForNode = knownForNode.prepend(typePromotion); |
| 539 registerKnownTypePromotion(typePromotion); | 547 registerKnownTypePromotion(typePromotion); |
| 540 } | 548 } |
| 541 | 549 |
| 542 final DartType type = analyze(node); | 550 final DartType type = analyze(node, mustHaveType: mustHaveType); |
| 543 | 551 |
| 544 while (!knownForNode.isEmpty) { | 552 while (!knownForNode.isEmpty) { |
| 545 unregisterKnownTypePromotion(knownForNode.head); | 553 unregisterKnownTypePromotion(knownForNode.head); |
| 546 knownForNode = knownForNode.tail; | 554 knownForNode = knownForNode.tail; |
| 547 } | 555 } |
| 548 | 556 |
| 549 return type; | 557 return type; |
| 550 } | 558 } |
| 551 | 559 |
| 552 /** | 560 /** |
| (...skipping 23 matching lines...) Expand all Loading... |
| 576 void pushCascadeType(DartType type) { | 584 void pushCascadeType(DartType type) { |
| 577 cascadeTypes = cascadeTypes.prepend(type); | 585 cascadeTypes = cascadeTypes.prepend(type); |
| 578 } | 586 } |
| 579 | 587 |
| 580 DartType popCascadeType() { | 588 DartType popCascadeType() { |
| 581 DartType type = cascadeTypes.head; | 589 DartType type = cascadeTypes.head; |
| 582 cascadeTypes = cascadeTypes.tail; | 590 cascadeTypes = cascadeTypes.tail; |
| 583 return type; | 591 return type; |
| 584 } | 592 } |
| 585 | 593 |
| 586 DartType visitAssert(Assert node) { | 594 visitAssert(Assert node) { |
| 587 analyze(node.condition); | 595 analyze(node.condition); |
| 588 if (node.hasMessage) analyze(node.message); | 596 if (node.hasMessage) analyze(node.message); |
| 589 return const StatementType(); | |
| 590 } | 597 } |
| 591 | 598 |
| 592 DartType visitBlock(Block node) { | 599 visitBlock(Block node) { |
| 593 return analyze(node.statements); | 600 analyzeUntyped(node.statements); |
| 594 } | 601 } |
| 595 | 602 |
| 596 DartType visitCascade(Cascade node) { | 603 DartType visitCascade(Cascade node) { |
| 597 analyze(node.expression); | 604 analyze(node.expression); |
| 598 return popCascadeType(); | 605 return popCascadeType(); |
| 599 } | 606 } |
| 600 | 607 |
| 601 DartType visitCascadeReceiver(CascadeReceiver node) { | 608 DartType visitCascadeReceiver(CascadeReceiver node) { |
| 602 DartType type = analyze(node.expression); | 609 DartType type = analyze(node.expression); |
| 603 pushCascadeType(type); | 610 pushCascadeType(type); |
| 604 return type; | 611 return type; |
| 605 } | 612 } |
| 606 | 613 |
| 607 DartType visitDoWhile(DoWhile node) { | 614 visitDoWhile(DoWhile node) { |
| 608 analyze(node.body); | 615 analyzeUntyped(node.body); |
| 609 checkCondition(node.condition); | 616 checkCondition(node.condition); |
| 610 return const StatementType(); | |
| 611 } | 617 } |
| 612 | 618 |
| 613 DartType visitExpressionStatement(ExpressionStatement node) { | 619 visitExpressionStatement(ExpressionStatement node) { |
| 614 Expression expression = node.expression; | 620 Expression expression = node.expression; |
| 615 analyze(expression); | 621 analyze(expression); |
| 616 return const StatementType(); | |
| 617 } | 622 } |
| 618 | 623 |
| 619 /** Dart Programming Language Specification: 11.5.1 For Loop */ | 624 /** Dart Programming Language Specification: 11.5.1 For Loop */ |
| 620 DartType visitFor(For node) { | 625 visitFor(For node) { |
| 621 if (node.initializer != null) { | 626 if (node.initializer != null) { |
| 622 analyze(node.initializer); | 627 analyzeUntyped(node.initializer); |
| 623 } | 628 } |
| 624 if (node.condition != null) { | 629 if (node.condition != null) { |
| 625 checkCondition(node.condition); | 630 checkCondition(node.condition); |
| 626 } | 631 } |
| 627 if (node.update != null) { | 632 if (node.update != null) { |
| 628 analyze(node.update); | 633 analyzeUntyped(node.update); |
| 629 } | 634 } |
| 630 return analyze(node.body); | 635 analyzeUntyped(node.body); |
| 631 } | 636 } |
| 632 | 637 |
| 633 DartType visitFunctionDeclaration(FunctionDeclaration node) { | 638 visitFunctionDeclaration(FunctionDeclaration node) { |
| 634 analyze(node.function); | 639 analyze(node.function); |
| 635 return const StatementType(); | |
| 636 } | 640 } |
| 637 | 641 |
| 638 DartType visitFunctionExpression(FunctionExpression node) { | 642 DartType visitFunctionExpression(FunctionExpression node) { |
| 639 DartType type; | 643 DartType type; |
| 640 DartType returnType; | 644 DartType returnType; |
| 641 final FunctionElement element = elements.getFunctionDefinition(node); | 645 final FunctionElement element = elements.getFunctionDefinition(node); |
| 642 assert(invariant(node, element != null, | 646 assert(invariant(node, element != null, |
| 643 message: 'FunctionExpression with no element')); | 647 message: 'FunctionExpression with no element')); |
| 644 if (Elements.isUnresolved(element)) return const DynamicType(); | 648 if (Elements.isUnresolved(element)) return const DynamicType(); |
| 645 if (element.isGenerativeConstructor) { | 649 if (element.isGenerativeConstructor) { |
| 646 type = const DynamicType(); | 650 type = const DynamicType(); |
| 647 returnType = const VoidType(); | 651 returnType = const VoidType(); |
| 648 | 652 |
| 649 element.functionSignature.forEachParameter((ParameterElement parameter) { | 653 element.functionSignature.forEachParameter((ParameterElement parameter) { |
| 650 if (parameter.isInitializingFormal) { | 654 if (parameter.isInitializingFormal) { |
| 651 InitializingFormalElement fieldParameter = parameter; | 655 InitializingFormalElement fieldParameter = parameter; |
| 652 checkAssignable(parameter, parameter.type, | 656 checkAssignable(parameter, parameter.type, |
| 653 fieldParameter.fieldElement.computeType(resolution)); | 657 fieldParameter.fieldElement.computeType(resolution)); |
| 654 } | 658 } |
| 655 }); | 659 }); |
| 656 if (node.initializers != null) { | 660 if (node.initializers != null) { |
| 657 analyze(node.initializers, inInitializer: true); | 661 analyzeUntyped(node.initializers, inInitializer: true); |
| 658 } | 662 } |
| 659 } else { | 663 } else { |
| 660 FunctionType functionType = element.computeType(resolution); | 664 FunctionType functionType = element.computeType(resolution); |
| 661 returnType = functionType.returnType; | 665 returnType = functionType.returnType; |
| 662 type = functionType; | 666 type = functionType; |
| 663 } | 667 } |
| 664 ExecutableElement previousExecutableContext = executableContext; | 668 ExecutableElement previousExecutableContext = executableContext; |
| 665 DartType previousReturnType = expectedReturnType; | 669 DartType previousReturnType = expectedReturnType; |
| 666 expectedReturnType = returnType; | 670 expectedReturnType = returnType; |
| 667 AsyncMarker previousAsyncMarker = currentAsyncMarker; | 671 AsyncMarker previousAsyncMarker = currentAsyncMarker; |
| 668 | 672 |
| 669 executableContext = element; | 673 executableContext = element; |
| 670 currentAsyncMarker = element.asyncMarker; | 674 currentAsyncMarker = element.asyncMarker; |
| 671 analyze(node.body); | 675 analyzeUntyped(node.body); |
| 672 | 676 |
| 673 executableContext = previousExecutableContext; | 677 executableContext = previousExecutableContext; |
| 674 expectedReturnType = previousReturnType; | 678 expectedReturnType = previousReturnType; |
| 675 currentAsyncMarker = previousAsyncMarker; | 679 currentAsyncMarker = previousAsyncMarker; |
| 676 return type; | 680 return type; |
| 677 } | 681 } |
| 678 | 682 |
| 679 DartType visitIdentifier(Identifier node) { | 683 DartType visitIdentifier(Identifier node) { |
| 680 if (node.isThis()) { | 684 if (node.isThis()) { |
| 681 return thisType; | 685 return thisType; |
| 682 } else if (node.isSuper()) { | 686 } else if (node.isSuper()) { |
| 683 return superType; | 687 return superType; |
| 684 } else { | 688 } else { |
| 685 TypedElement element = elements[node]; | 689 TypedElement element = elements[node]; |
| 686 assert(invariant(node, element != null, | 690 assert(invariant(node, element != null, |
| 687 message: 'Missing element for identifier')); | 691 message: 'Missing element for identifier')); |
| 688 assert(invariant( | 692 assert(invariant( |
| 689 node, element.isVariable || element.isParameter || element.isField, | 693 node, element.isVariable || element.isParameter || element.isField, |
| 690 message: 'Unexpected context element ${element}')); | 694 message: 'Unexpected context element ${element}')); |
| 691 return element.computeType(resolution); | 695 return element.computeType(resolution); |
| 692 } | 696 } |
| 693 } | 697 } |
| 694 | 698 |
| 695 DartType visitIf(If node) { | 699 visitIf(If node) { |
| 696 Expression condition = node.condition.expression; | 700 Expression condition = node.condition.expression; |
| 697 Statement thenPart = node.thenPart; | 701 Statement thenPart = node.thenPart; |
| 698 | 702 |
| 699 checkCondition(node.condition); | 703 checkCondition(node.condition); |
| 700 analyzeInPromotedContext(condition, thenPart); | 704 analyzeInPromotedContext(condition, thenPart, mustHaveType: false); |
| 701 if (node.elsePart != null) { | 705 if (node.elsePart != null) { |
| 702 analyze(node.elsePart); | 706 analyzeUntyped(node.elsePart); |
| 703 } | 707 } |
| 704 return const StatementType(); | |
| 705 } | 708 } |
| 706 | 709 |
| 707 void checkPrivateAccess(Node node, Element element, String name) { | 710 void checkPrivateAccess(Node node, Element element, String name) { |
| 708 if (name != null && | 711 if (name != null && |
| 709 Name.isPrivateName(name) && | 712 Name.isPrivateName(name) && |
| 710 element.library != currentLibrary) { | 713 element.library != currentLibrary) { |
| 711 reportTypeWarning(node, MessageKind.PRIVATE_ACCESS, | 714 reportTypeWarning(node, MessageKind.PRIVATE_ACCESS, |
| 712 {'name': name, 'libraryName': element.library.libraryOrScriptName}); | 715 {'name': name, 'libraryName': element.library.libraryOrScriptName}); |
| 713 } | 716 } |
| 714 } | 717 } |
| (...skipping 930 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1645 !link.isEmpty; | 1648 !link.isEmpty; |
| 1646 link = link.tail) { | 1649 link = link.tail) { |
| 1647 Node element = link.head; | 1650 Node element = link.head; |
| 1648 DartType elementType = analyze(element); | 1651 DartType elementType = analyze(element); |
| 1649 checkAssignable(element, elementType, listElementType, | 1652 checkAssignable(element, elementType, listElementType, |
| 1650 isConst: node.isConst); | 1653 isConst: node.isConst); |
| 1651 } | 1654 } |
| 1652 return listType; | 1655 return listType; |
| 1653 } | 1656 } |
| 1654 | 1657 |
| 1655 DartType visitNodeList(NodeList node) { | 1658 visitNodeList(NodeList node) { |
| 1656 for (Link<Node> link = node.nodes; !link.isEmpty; link = link.tail) { | 1659 for (Link<Node> link = node.nodes; !link.isEmpty; link = link.tail) { |
| 1657 analyze(link.head, inInitializer: analyzingInitializer); | 1660 analyzeUntyped(link.head, inInitializer: analyzingInitializer); |
| 1658 } | 1661 } |
| 1659 return const StatementType(); | |
| 1660 } | 1662 } |
| 1661 | 1663 |
| 1662 DartType visitRedirectingFactoryBody(RedirectingFactoryBody node) { | 1664 visitRedirectingFactoryBody(RedirectingFactoryBody node) { |
| 1663 // TODO(lrn): Typecheck the body. It must refer to the constructor | 1665 // TODO(lrn): Typecheck the body. It must refer to the constructor |
| 1664 // of a subtype. | 1666 // of a subtype. |
| 1665 return const StatementType(); | |
| 1666 } | 1667 } |
| 1667 | 1668 |
| 1668 DartType visitRethrow(Rethrow node) { | 1669 visitRethrow(Rethrow node) { |
| 1669 return const StatementType(); | 1670 // Nothing to do here. |
| 1670 } | 1671 } |
| 1671 | 1672 |
| 1672 /** Dart Programming Language Specification: 11.10 Return */ | 1673 /** Dart Programming Language Specification: 11.10 Return */ |
| 1673 DartType visitReturn(Return node) { | 1674 visitReturn(Return node) { |
| 1674 if (identical(node.beginToken.stringValue, 'native')) { | 1675 if (identical(node.beginToken.stringValue, 'native')) { |
| 1675 return const StatementType(); | 1676 return; |
| 1676 } | 1677 } |
| 1677 | 1678 |
| 1678 final Node expression = node.expression; | 1679 final Node expression = node.expression; |
| 1679 | 1680 |
| 1680 // Executing a return statement return e; [...] It is a static type warning | 1681 // Executing a return statement return e; [...] It is a static type warning |
| 1681 // if the type of e may not be assigned to the declared return type of the | 1682 // if the type of e may not be assigned to the declared return type of the |
| 1682 // immediately enclosing function. | 1683 // immediately enclosing function. |
| 1683 if (expression != null) { | 1684 if (expression != null) { |
| 1684 DartType expressionType = analyze(expression); | 1685 DartType expressionType = analyze(expression); |
| 1685 if (executableContext.isGenerativeConstructor) { | 1686 if (executableContext.isGenerativeConstructor) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1700 // `return;` is allowed. | 1701 // `return;` is allowed. |
| 1701 } else if (!types.isAssignable(expectedReturnType, const VoidType())) { | 1702 } else if (!types.isAssignable(expectedReturnType, const VoidType())) { |
| 1702 // Let f be the function immediately enclosing a return statement of the | 1703 // Let f be the function immediately enclosing a return statement of the |
| 1703 // form 'return;' It is a static warning if both of the following | 1704 // form 'return;' It is a static warning if both of the following |
| 1704 // conditions hold: | 1705 // conditions hold: |
| 1705 // - f is not a generative constructor. | 1706 // - f is not a generative constructor. |
| 1706 // - The return type of f may not be assigned to void. | 1707 // - The return type of f may not be assigned to void. |
| 1707 reportTypeWarning( | 1708 reportTypeWarning( |
| 1708 node, MessageKind.RETURN_NOTHING, {'returnType': expectedReturnType}); | 1709 node, MessageKind.RETURN_NOTHING, {'returnType': expectedReturnType}); |
| 1709 } | 1710 } |
| 1710 return const StatementType(); | |
| 1711 } | 1711 } |
| 1712 | 1712 |
| 1713 DartType visitThrow(Throw node) { | 1713 DartType visitThrow(Throw node) { |
| 1714 // TODO(johnniwinther): Handle reachability. | 1714 // TODO(johnniwinther): Handle reachability. |
| 1715 analyze(node.expression); | 1715 analyze(node.expression); |
| 1716 return const DynamicType(); | 1716 return const DynamicType(); |
| 1717 } | 1717 } |
| 1718 | 1718 |
| 1719 DartType visitAwait(Await node) { | 1719 DartType visitAwait(Await node) { |
| 1720 DartType expressionType = analyze(node.expression); | 1720 DartType expressionType = analyze(node.expression); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1737 if (currentAsyncMarker.isAsync) { | 1737 if (currentAsyncMarker.isAsync) { |
| 1738 // The static type of expression must be assignable to Stream. | 1738 // The static type of expression must be assignable to Stream. |
| 1739 checkAssignable(node, resultType, commonElements.streamType()); | 1739 checkAssignable(node, resultType, commonElements.streamType()); |
| 1740 } else { | 1740 } else { |
| 1741 // The static type of expression must be assignable to Iterable. | 1741 // The static type of expression must be assignable to Iterable. |
| 1742 checkAssignable(node, resultType, commonElements.iterableType()); | 1742 checkAssignable(node, resultType, commonElements.iterableType()); |
| 1743 } | 1743 } |
| 1744 } | 1744 } |
| 1745 // The static type of the result must be assignable to the declared type. | 1745 // The static type of the result must be assignable to the declared type. |
| 1746 checkAssignable(node, resultType, expectedReturnType); | 1746 checkAssignable(node, resultType, expectedReturnType); |
| 1747 return const StatementType(); | |
| 1748 } | 1747 } |
| 1749 | 1748 |
| 1750 DartType visitTypeAnnotation(TypeAnnotation node) { | 1749 DartType visitTypeAnnotation(TypeAnnotation node) { |
| 1751 return elements.getType(node); | 1750 return elements.getType(node); |
| 1752 } | 1751 } |
| 1753 | 1752 |
| 1754 DartType analyzeVariableTypeAnnotation(VariableDefinitions node) { | 1753 DartType analyzeVariableTypeAnnotation(VariableDefinitions node) { |
| 1755 DartType type = analyzeWithDefault(node.type, const DynamicType()); | 1754 DartType type = analyzeWithDefault(node.type, const DynamicType()); |
| 1756 if (type.isVoid) { | 1755 if (type.isVoid) { |
| 1757 reportTypeWarning(node.type, MessageKind.VOID_VARIABLE); | 1756 reportTypeWarning(node.type, MessageKind.VOID_VARIABLE); |
| 1758 type = const DynamicType(); | 1757 type = const DynamicType(); |
| 1759 } | 1758 } |
| 1760 return type; | 1759 return type; |
| 1761 } | 1760 } |
| 1762 | 1761 |
| 1763 void analyzeVariableInitializer( | 1762 void analyzeVariableInitializer( |
| 1764 Spannable spannable, DartType declaredType, Node initializer) { | 1763 Spannable spannable, DartType declaredType, Node initializer) { |
| 1765 if (initializer == null) return; | 1764 if (initializer == null) return; |
| 1766 | 1765 |
| 1767 DartType expressionType = analyzeNonVoid(initializer); | 1766 DartType expressionType = analyzeNonVoid(initializer); |
| 1768 checkAssignable(spannable, expressionType, declaredType); | 1767 checkAssignable(spannable, expressionType, declaredType); |
| 1769 } | 1768 } |
| 1770 | 1769 |
| 1771 DartType visitVariableDefinitions(VariableDefinitions node) { | 1770 visitVariableDefinitions(VariableDefinitions node) { |
| 1772 DartType type = analyzeVariableTypeAnnotation(node); | 1771 DartType type = analyzeVariableTypeAnnotation(node); |
| 1773 for (Link<Node> link = node.definitions.nodes; | 1772 for (Link<Node> link = node.definitions.nodes; |
| 1774 !link.isEmpty; | 1773 !link.isEmpty; |
| 1775 link = link.tail) { | 1774 link = link.tail) { |
| 1776 Node definition = link.head; | 1775 Node definition = link.head; |
| 1777 invariant(definition, definition is Identifier || definition is SendSet, | 1776 invariant(definition, definition is Identifier || definition is SendSet, |
| 1778 message: 'expected identifier or initialization'); | 1777 message: 'expected identifier or initialization'); |
| 1779 if (definition is SendSet) { | 1778 if (definition is SendSet) { |
| 1780 SendSet initialization = definition; | 1779 SendSet initialization = definition; |
| 1781 analyzeVariableInitializer(initialization.assignmentOperator, type, | 1780 analyzeVariableInitializer(initialization.assignmentOperator, type, |
| 1782 initialization.arguments.head); | 1781 initialization.arguments.head); |
| 1783 // TODO(sigmund): explore inferring a type for `var` using the RHS (like | 1782 // TODO(sigmund): explore inferring a type for `var` using the RHS (like |
| 1784 // DDC does), for example: | 1783 // DDC does), for example: |
| 1785 // if (node.type == null && node.modifiers.isVar && | 1784 // if (node.type == null && node.modifiers.isVar && |
| 1786 // !initializer.isDynamic) { | 1785 // !initializer.isDynamic) { |
| 1787 // var variable = elements[definition]; | 1786 // var variable = elements[definition]; |
| 1788 // if (variable != null) { | 1787 // if (variable != null) { |
| 1789 // var typePromotion = new TypePromotion( | 1788 // var typePromotion = new TypePromotion( |
| 1790 // node, variable, initializer); | 1789 // node, variable, initializer); |
| 1791 // registerKnownTypePromotion(typePromotion); | 1790 // registerKnownTypePromotion(typePromotion); |
| 1792 // } | 1791 // } |
| 1793 // } | 1792 // } |
| 1794 } | 1793 } |
| 1795 } | 1794 } |
| 1796 return const StatementType(); | |
| 1797 } | 1795 } |
| 1798 | 1796 |
| 1799 DartType visitWhile(While node) { | 1797 visitWhile(While node) { |
| 1800 checkCondition(node.condition); | 1798 checkCondition(node.condition); |
| 1801 analyze(node.body); | 1799 analyzeUntyped(node.body); |
| 1802 return const StatementType(); | |
| 1803 } | 1800 } |
| 1804 | 1801 |
| 1805 DartType visitParenthesizedExpression(ParenthesizedExpression node) { | 1802 DartType visitParenthesizedExpression(ParenthesizedExpression node) { |
| 1806 Expression expression = node.expression; | 1803 Expression expression = node.expression; |
| 1807 DartType type = analyze(expression); | 1804 DartType type = analyze(expression); |
| 1808 for (TypePromotion typePromotion in getShownTypePromotionsFor(expression)) { | 1805 for (TypePromotion typePromotion in getShownTypePromotionsFor(expression)) { |
| 1809 showTypePromotion(node, typePromotion); | 1806 showTypePromotion(node, typePromotion); |
| 1810 } | 1807 } |
| 1811 return type; | 1808 return type; |
| 1812 } | 1809 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1827 node.visitChildren(this); | 1824 node.visitChildren(this); |
| 1828 return stringType; | 1825 return stringType; |
| 1829 } | 1826 } |
| 1830 | 1827 |
| 1831 visitStringInterpolationPart(StringInterpolationPart node) { | 1828 visitStringInterpolationPart(StringInterpolationPart node) { |
| 1832 node.visitChildren(this); | 1829 node.visitChildren(this); |
| 1833 return stringType; | 1830 return stringType; |
| 1834 } | 1831 } |
| 1835 | 1832 |
| 1836 visitEmptyStatement(EmptyStatement node) { | 1833 visitEmptyStatement(EmptyStatement node) { |
| 1837 return const StatementType(); | 1834 // Nothing to do here. |
| 1838 } | 1835 } |
| 1839 | 1836 |
| 1840 visitBreakStatement(BreakStatement node) { | 1837 visitBreakStatement(BreakStatement node) { |
| 1841 return const StatementType(); | 1838 // Nothing to do here. |
| 1842 } | 1839 } |
| 1843 | 1840 |
| 1844 visitContinueStatement(ContinueStatement node) { | 1841 visitContinueStatement(ContinueStatement node) { |
| 1845 return const StatementType(); | 1842 // Nothing to do here. |
| 1846 } | 1843 } |
| 1847 | 1844 |
| 1848 DartType computeForInElementType(ForIn node) { | 1845 DartType computeForInElementType(ForIn node) { |
| 1849 VariableDefinitions declaredIdentifier = | 1846 VariableDefinitions declaredIdentifier = |
| 1850 node.declaredIdentifier.asVariableDefinitions(); | 1847 node.declaredIdentifier.asVariableDefinitions(); |
| 1851 if (declaredIdentifier != null) { | 1848 if (declaredIdentifier != null) { |
| 1852 return analyzeWithDefault(declaredIdentifier.type, const DynamicType()); | 1849 return analyzeWithDefault(declaredIdentifier.type, const DynamicType()); |
| 1853 } else { | 1850 } else { |
| 1854 return analyze(node.declaredIdentifier); | 1851 return analyze(node.declaredIdentifier); |
| 1855 } | 1852 } |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1880 'currentType': streamElementType, | 1877 'currentType': streamElementType, |
| 1881 'expressionType': expressionType, | 1878 'expressionType': expressionType, |
| 1882 'elementType': elementType | 1879 'elementType': elementType |
| 1883 }, | 1880 }, |
| 1884 isHint: true); | 1881 isHint: true); |
| 1885 } | 1882 } |
| 1886 } | 1883 } |
| 1887 } | 1884 } |
| 1888 } | 1885 } |
| 1889 } | 1886 } |
| 1890 analyze(node.body); | 1887 analyzeUntyped(node.body); |
| 1891 return const StatementType(); | |
| 1892 } | 1888 } |
| 1893 | 1889 |
| 1894 visitSyncForIn(SyncForIn node) { | 1890 visitSyncForIn(SyncForIn node) { |
| 1895 DartType elementType = computeForInElementType(node); | 1891 DartType elementType = computeForInElementType(node); |
| 1896 DartType expressionType = analyze(node.expression); | 1892 DartType expressionType = analyze(node.expression); |
| 1897 DartType iteratorType = lookupMemberType(node.expression, expressionType, | 1893 DartType iteratorType = lookupMemberType(node.expression, expressionType, |
| 1898 Identifiers.iterator, MemberKind.GETTER); | 1894 Identifiers.iterator, MemberKind.GETTER); |
| 1899 DartType currentType = lookupMemberType( | 1895 DartType currentType = lookupMemberType( |
| 1900 node.expression, iteratorType, Identifiers.current, MemberKind.GETTER, | 1896 node.expression, iteratorType, Identifiers.current, MemberKind.GETTER, |
| 1901 isHint: true); | 1897 isHint: true); |
| 1902 if (!types.isAssignable(currentType, elementType)) { | 1898 if (!types.isAssignable(currentType, elementType)) { |
| 1903 reportMessage( | 1899 reportMessage( |
| 1904 node.expression, | 1900 node.expression, |
| 1905 MessageKind.FORIN_NOT_ASSIGNABLE, | 1901 MessageKind.FORIN_NOT_ASSIGNABLE, |
| 1906 { | 1902 { |
| 1907 'currentType': currentType, | 1903 'currentType': currentType, |
| 1908 'expressionType': expressionType, | 1904 'expressionType': expressionType, |
| 1909 'elementType': elementType | 1905 'elementType': elementType |
| 1910 }, | 1906 }, |
| 1911 isHint: true); | 1907 isHint: true); |
| 1912 } | 1908 } |
| 1913 analyze(node.body); | 1909 analyzeUntyped(node.body); |
| 1914 return const StatementType(); | |
| 1915 } | 1910 } |
| 1916 | 1911 |
| 1917 visitLabeledStatement(LabeledStatement node) { | 1912 visitLabeledStatement(LabeledStatement node) { |
| 1918 return analyze(node.statement); | 1913 analyzeUntyped(node.statement); |
| 1919 } | 1914 } |
| 1920 | 1915 |
| 1921 visitLiteralMap(LiteralMap node) { | 1916 visitLiteralMap(LiteralMap node) { |
| 1922 InterfaceType mapType = elements.getType(node); | 1917 InterfaceType mapType = elements.getType(node); |
| 1923 DartType mapKeyType = firstType(mapType.typeArguments); | 1918 DartType mapKeyType = firstType(mapType.typeArguments); |
| 1924 DartType mapValueType = secondType(mapType.typeArguments); | 1919 DartType mapValueType = secondType(mapType.typeArguments); |
| 1925 bool isConst = node.isConst; | 1920 bool isConst = node.isConst; |
| 1926 for (Link<Node> link = node.entries.nodes; | 1921 for (Link<Node> link = node.entries.nodes; |
| 1927 !link.isEmpty; | 1922 !link.isEmpty; |
| 1928 link = link.tail) { | 1923 link = link.tail) { |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1958 hasDefaultCase = true; | 1953 hasDefaultCase = true; |
| 1959 } | 1954 } |
| 1960 for (Node labelOrCase in switchCase.labelsAndCases) { | 1955 for (Node labelOrCase in switchCase.labelsAndCases) { |
| 1961 CaseMatch caseMatch = labelOrCase.asCaseMatch(); | 1956 CaseMatch caseMatch = labelOrCase.asCaseMatch(); |
| 1962 if (caseMatch == null) continue; | 1957 if (caseMatch == null) continue; |
| 1963 | 1958 |
| 1964 DartType caseType = analyze(caseMatch.expression); | 1959 DartType caseType = analyze(caseMatch.expression); |
| 1965 checkAssignable(caseMatch, expressionType, caseType); | 1960 checkAssignable(caseMatch, expressionType, caseType); |
| 1966 } | 1961 } |
| 1967 | 1962 |
| 1968 analyze(switchCase); | 1963 analyzeUntyped(switchCase); |
| 1969 } | 1964 } |
| 1970 | 1965 |
| 1971 if (!hasDefaultCase && expressionType.isEnumType) { | 1966 if (!hasDefaultCase && expressionType.isEnumType) { |
| 1972 compiler.enqueuer.resolution.addDeferredAction(executableContext, () { | 1967 compiler.enqueuer.resolution.addDeferredAction(executableContext, () { |
| 1973 Map<ConstantValue, FieldElement> enumValues = | 1968 Map<ConstantValue, FieldElement> enumValues = |
| 1974 <ConstantValue, FieldElement>{}; | 1969 <ConstantValue, FieldElement>{}; |
| 1975 List<FieldElement> unreferencedFields = <FieldElement>[]; | 1970 List<FieldElement> unreferencedFields = <FieldElement>[]; |
| 1976 EnumClassElement enumClass = expressionType.element; | 1971 EnumClassElement enumClass = expressionType.element; |
| 1977 enumClass.enumValues.forEach((EnumConstantElement field) { | 1972 enumClass.enumValues.forEach((EnumConstantElement field) { |
| 1978 // TODO(johnniwinther): Ensure that the enum constant is computed at | 1973 // TODO(johnniwinther): Ensure that the enum constant is computed at |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2001 } | 1996 } |
| 2002 unreferencedFields.addAll(enumValues.values); | 1997 unreferencedFields.addAll(enumValues.values); |
| 2003 if (!unreferencedFields.isEmpty) { | 1998 if (!unreferencedFields.isEmpty) { |
| 2004 reporter.reportWarningMessage(node, MessageKind.MISSING_ENUM_CASES, { | 1999 reporter.reportWarningMessage(node, MessageKind.MISSING_ENUM_CASES, { |
| 2005 'enumType': expressionType, | 2000 'enumType': expressionType, |
| 2006 'enumValues': unreferencedFields.map((e) => e.name).join(', ') | 2001 'enumValues': unreferencedFields.map((e) => e.name).join(', ') |
| 2007 }); | 2002 }); |
| 2008 } | 2003 } |
| 2009 }); | 2004 }); |
| 2010 } | 2005 } |
| 2011 | |
| 2012 return const StatementType(); | |
| 2013 } | 2006 } |
| 2014 | 2007 |
| 2015 visitSwitchCase(SwitchCase node) { | 2008 visitSwitchCase(SwitchCase node) { |
| 2016 return analyze(node.statements); | 2009 analyzeUntyped(node.statements); |
| 2017 } | 2010 } |
| 2018 | 2011 |
| 2019 visitTryStatement(TryStatement node) { | 2012 visitTryStatement(TryStatement node) { |
| 2020 // TODO(johnniwinther): Use reachability information of try-block, | 2013 // TODO(johnniwinther): Use reachability information of try-block, |
| 2021 // catch-blocks and finally-block to compute the whether the try statement | 2014 // catch-blocks and finally-block to compute the whether the try statement |
| 2022 // is returning. | 2015 // is returning. |
| 2023 analyze(node.tryBlock); | 2016 analyzeUntyped(node.tryBlock); |
| 2024 for (CatchBlock catchBlock in node.catchBlocks) { | 2017 for (CatchBlock catchBlock in node.catchBlocks) { |
| 2025 analyze(catchBlock); | 2018 analyzeUntyped(catchBlock); |
| 2026 } | 2019 } |
| 2027 analyzeWithDefault(node.finallyBlock, null); | 2020 analyzeUntyped(node.finallyBlock); |
| 2028 return const StatementType(); | |
| 2029 } | 2021 } |
| 2030 | 2022 |
| 2031 visitCatchBlock(CatchBlock node) { | 2023 visitCatchBlock(CatchBlock node) { |
| 2032 return analyze(node.block); | 2024 analyzeUntyped(node.block); |
| 2033 } | 2025 } |
| 2034 | 2026 |
| 2035 visitTypedef(Typedef node) { | 2027 visitTypedef(Typedef node) { |
| 2036 // Do not typecheck [Typedef] nodes. | 2028 // Do not typecheck [Typedef] nodes. |
| 2037 } | 2029 } |
| 2038 | 2030 |
| 2039 visitNode(Node node) { | 2031 visitNode(Node node) { |
| 2040 reporter.internalError(node, | 2032 reporter.internalError(node, |
| 2041 'Unexpected node ${node.getObjectDescription()} in the type checker.'); | 2033 'Unexpected node ${node.getObjectDescription()} in the type checker.'); |
| 2042 } | 2034 } |
| 2043 } | 2035 } |
| OLD | NEW |