| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /// Encapsulates how to invoke the analyzer resolver and overrides how it | 5 /// Encapsulates how to invoke the analyzer resolver and overrides how it |
| 6 /// computes types on expressions to use our restricted set of types. | 6 /// computes types on expressions to use our restricted set of types. |
| 7 library dev_compiler.src.checker.resolver; | 7 library dev_compiler.src.checker.resolver; |
| 8 | 8 |
| 9 import 'package:analyzer/analyzer.dart'; | 9 import 'package:analyzer/analyzer.dart'; |
| 10 import 'package:analyzer/src/generated/ast.dart'; | 10 import 'package:analyzer/src/generated/ast.dart'; |
| (...skipping 587 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 598 if (iteratedType != null) { | 598 if (iteratedType != null) { |
| 599 element.type = iteratedType; | 599 element.type = iteratedType; |
| 600 } | 600 } |
| 601 } | 601 } |
| 602 } | 602 } |
| 603 | 603 |
| 604 bool _isSealed(DartType t) { | 604 bool _isSealed(DartType t) { |
| 605 return _typeProvider.nonSubtypableTypes.contains(t); | 605 return _typeProvider.nonSubtypableTypes.contains(t); |
| 606 } | 606 } |
| 607 | 607 |
| 608 List<List> _genericList = null; |
| 609 |
| 610 DartType _matchGeneric(MethodInvocation node, Element element) { |
| 611 var e = node.methodName.staticElement; |
| 612 |
| 613 if (_genericList == null) { |
| 614 var minmax = (DartType tx, DartType ty) => (tx == ty && |
| 615 (tx == _typeProvider.intType || tx == _typeProvider.doubleType)) |
| 616 ? tx |
| 617 : null; |
| 618 |
| 619 var map = (DartType tx) => (tx is FunctionType) |
| 620 ? _typeProvider.iterableType.substitute4([tx.returnType]) |
| 621 : null; |
| 622 |
| 623 // TODO(vsm): LUB? |
| 624 var fold = (DartType tx, DartType ty) => |
| 625 (ty is FunctionType && tx == ty.returnType) ? tx : null; |
| 626 |
| 627 // TODO(vsm): Flatten? |
| 628 var then = (DartType tx) => (tx is FunctionType) |
| 629 ? _typeProvider.futureType.substitute4([tx.returnType]) |
| 630 : null; |
| 631 |
| 632 var wait = (DartType tx) { |
| 633 // Iterable<Future<T>> -> Future<List<T>> |
| 634 var futureType = _findIteratedType(tx); |
| 635 if (futureType.element.type != _typeProvider.futureType) return null; |
| 636 var typeArguments = futureType.typeArguments; |
| 637 if (typeArguments.length != 1) return null; |
| 638 var baseType = typeArguments[0]; |
| 639 if (baseType.isDynamic) return null; |
| 640 return _typeProvider.futureType.substitute4([ |
| 641 _typeProvider.listType.substitute4([baseType]) |
| 642 ]); |
| 643 }; |
| 644 |
| 645 _genericList = [ |
| 646 // Top-level methods |
| 647 ['dart:math', 'max', 2, minmax], |
| 648 ['dart:math', 'min', 2, minmax], |
| 649 // Static methods |
| 650 [_typeProvider.futureType, 'wait', 1, wait], |
| 651 // Instance methods |
| 652 [_typeProvider.iterableDynamicType, 'map', 1, map], |
| 653 [_typeProvider.iterableDynamicType, 'fold', 2, fold], |
| 654 [_typeProvider.futureDynamicType, 'then', 1, then], |
| 655 ]; |
| 656 } |
| 657 |
| 658 var targetType = node.target?.staticType; |
| 659 var arguments = node.argumentList.arguments; |
| 660 |
| 661 for (var generic in _genericList) { |
| 662 if (e?.name == generic[1]) { |
| 663 if ((generic[0] is String && |
| 664 element?.library.source.uri.toString() == generic[0]) || |
| 665 (targetType == generic[0] || |
| 666 targetType != null && targetType.isSubtypeOf(generic[0]))) { |
| 667 if (arguments.length == generic[2]) { |
| 668 return Function.apply( |
| 669 generic[3], arguments.map((arg) => arg.staticType).toList()); |
| 670 } |
| 671 } |
| 672 } |
| 673 } |
| 674 |
| 675 return null; |
| 676 } |
| 677 |
| 608 @override // to propagate types to identifiers | 678 @override // to propagate types to identifiers |
| 609 visitMethodInvocation(MethodInvocation node) { | 679 visitMethodInvocation(MethodInvocation node) { |
| 610 // TODO(jmesserly): we rely on having a staticType propagated to the | 680 // TODO(jmesserly): we rely on having a staticType propagated to the |
| 611 // methodName identifier. This shouldn't be necessary for method calls, so | 681 // methodName identifier. This shouldn't be necessary for method calls, so |
| 612 // analyzer doesn't do it by default. Conceptually what we're doing here | 682 // analyzer doesn't do it by default. Conceptually what we're doing here |
| 613 // is asking for a tear off. We need this until we can fix #132, and rely | 683 // is asking for a tear off. We need this until we can fix #132, and rely |
| 614 // on `node.staticElement == null` instead of `rules.isDynamicCall(node)`. | 684 // on `node.staticElement == null` instead of `rules.isDynamicCall(node)`. |
| 615 visitSimpleIdentifier(node.methodName); | 685 visitSimpleIdentifier(node.methodName); |
| 616 | 686 |
| 617 super.visitMethodInvocation(node); | 687 super.visitMethodInvocation(node); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 665 // | 735 // |
| 666 // T min<T extends num>(T x, T y); | 736 // T min<T extends num>(T x, T y); |
| 667 // | 737 // |
| 668 // and infer T. In practice, this just means if the type of x and y are | 738 // and infer T. In practice, this just means if the type of x and y are |
| 669 // both double or both int, we treat that as the return type. | 739 // both double or both int, we treat that as the return type. |
| 670 // | 740 // |
| 671 // The Dart spec has similar treatment for binary operations on numbers. | 741 // The Dart spec has similar treatment for binary operations on numbers. |
| 672 // | 742 // |
| 673 // TODO(jmesserly): remove this when we have a fix for | 743 // TODO(jmesserly): remove this when we have a fix for |
| 674 // https://github.com/dart-lang/dev_compiler/issues/28 | 744 // https://github.com/dart-lang/dev_compiler/issues/28 |
| 675 if (isDartMathMinMax(e)) { | 745 var inferred = _matchGeneric(node, e); |
| 676 var args = node.argumentList.arguments; | 746 // TODO(vsm): If the inferred type is not a subtype, should we use a GLB ins
tead? |
| 677 if (args.length == 2) { | 747 if (inferred != null && inferred.isSubtypeOf(node.staticType)) { |
| 678 var tx = args[0].staticType; | 748 node.staticType = inferred; |
| 679 var ty = args[1].staticType; | |
| 680 if (tx == ty && | |
| 681 (tx == _typeProvider.intType || tx == _typeProvider.doubleType)) { | |
| 682 node.staticType = tx; | |
| 683 } | |
| 684 } | |
| 685 } | 749 } |
| 686 } | 750 } |
| 687 | 751 |
| 688 void _inferObjectAccess( | 752 void _inferObjectAccess( |
| 689 Expression node, Expression target, SimpleIdentifier id) { | 753 Expression node, Expression target, SimpleIdentifier id) { |
| 690 // Search for Object accesses. | 754 // Search for Object accesses. |
| 691 var name = id.name; | 755 var name = id.name; |
| 692 if (node.staticType.isDynamic && | 756 if (node.staticType.isDynamic && |
| 693 _objectMembers.containsKey(name) && | 757 _objectMembers.containsKey(name) && |
| 694 isDynamicTarget(target)) { | 758 isDynamicTarget(target)) { |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 736 } | 800 } |
| 737 } | 801 } |
| 738 | 802 |
| 739 // Review note: no longer need to override visitFunctionExpression, this is | 803 // Review note: no longer need to override visitFunctionExpression, this is |
| 740 // handled by the analyzer internally. | 804 // handled by the analyzer internally. |
| 741 // TODO(vsm): in visitbinaryExpression: check computeStaticReturnType result? | 805 // TODO(vsm): in visitbinaryExpression: check computeStaticReturnType result? |
| 742 // TODO(vsm): in visitFunctionDeclaration: Should we ever use the expression | 806 // TODO(vsm): in visitFunctionDeclaration: Should we ever use the expression |
| 743 // type in a (...) => expr or just the written type? | 807 // type in a (...) => expr or just the written type? |
| 744 | 808 |
| 745 } | 809 } |
| OLD | NEW |