OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 analyzer.src.generated.static_type_analyzer; | 5 library analyzer.src.generated.static_type_analyzer; |
6 | 6 |
7 import 'dart:collection'; | 7 import 'dart:collection'; |
8 | 8 |
9 import 'package:analyzer/dart/ast/ast.dart'; | 9 import 'package:analyzer/dart/ast/ast.dart'; |
10 import 'package:analyzer/dart/ast/token.dart'; | 10 import 'package:analyzer/dart/ast/token.dart'; |
(...skipping 605 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
616 DartType argumentType = _getType(argumentTypeName); | 616 DartType argumentType = _getType(argumentTypeName); |
617 if (argumentType != null) { | 617 if (argumentType != null) { |
618 staticType = argumentType; | 618 staticType = argumentType; |
619 } | 619 } |
620 } | 620 } |
621 _recordStaticType( | 621 _recordStaticType( |
622 node, _typeProvider.listType.instantiate(<DartType>[staticType])); | 622 node, _typeProvider.listType.instantiate(<DartType>[staticType])); |
623 return null; | 623 return null; |
624 } | 624 } |
625 | 625 |
| 626 DartType listDynamicType = |
| 627 _typeProvider.listType.instantiate(<DartType>[_dynamicType]); |
| 628 |
626 // If there are no type arguments and we are in strong mode, try to infer | 629 // If there are no type arguments and we are in strong mode, try to infer |
627 // some arguments. | 630 // some arguments. |
628 if (_strongMode) { | 631 if (_strongMode) { |
629 DartType contextType = InferenceContext.getType(node); | 632 DartType contextType = InferenceContext.getType(node); |
630 | 633 |
631 // If we have a type from the context, use it. | 634 // Use both downwards and upwards information to infer the type. |
632 if (contextType is InterfaceType && | 635 var ts = _typeSystem as StrongTypeSystemImpl; |
633 contextType.typeArguments.length == 1 && | 636 var elementTypes = node.elements |
634 contextType.element == _typeProvider.listType.element) { | 637 .map((e) => e.staticType) |
635 _resolver.inferenceContext.recordInference(node, contextType); | 638 .where((t) => t != null) |
636 _recordStaticType(node, contextType); | 639 .toList(); |
637 return null; | 640 var listTypeParam = _typeProvider.listType.typeParameters[0].type; |
638 } | |
639 | 641 |
640 // If we don't have a type from the context, try to infer from the | 642 DartType inferred = ts.inferGenericFunctionCall( |
641 // elements | 643 _typeProvider, |
642 if (node.elements.isNotEmpty) { | 644 _typeProvider.listType, |
643 // Infer the list type from the arguments. | 645 new List.filled(elementTypes.length, listTypeParam), |
644 Iterable<DartType> types = | 646 elementTypes, |
645 node.elements.map((e) => e.staticType).where((t) => t != null); | 647 _typeProvider.listType, |
646 if (types.isEmpty) { | 648 contextType, |
647 return null; | 649 errorReporter: _resolver.errorReporter, |
648 } | 650 errorNode: node); |
649 DartType staticType = types.reduce(_leastUpperBound); | 651 |
650 if (staticType.isBottom) { | 652 if (inferred != listDynamicType) { |
651 staticType = _dynamicType; | 653 // TODO(jmesserly): this results in an "inferred" message even when we |
652 } | 654 // in fact had an error above, because it will still attempt to return |
653 DartType listLiteralType = | 655 // a type. Perhaps we should record inference from TypeSystem if |
654 _typeProvider.listType.instantiate(<DartType>[staticType]); | 656 // everything was successful? |
655 if (!staticType.isDynamic) { | 657 _resolver.inferenceContext.recordInference(node, inferred); |
656 _resolver.inferenceContext.recordInference(node, listLiteralType); | 658 _recordStaticType(node, inferred); |
657 } | |
658 _recordStaticType(node, listLiteralType); | |
659 return null; | 659 return null; |
660 } | 660 } |
661 } | 661 } |
662 | 662 |
663 // If we have no type arguments and couldn't infer any, use dynamic. | 663 // If we have no type arguments and couldn't infer any, use dynamic. |
664 _recordStaticType( | 664 _recordStaticType(node, listDynamicType); |
665 node, _typeProvider.listType.instantiate(<DartType>[_dynamicType])); | |
666 return null; | 665 return null; |
667 } | 666 } |
668 | 667 |
669 /** | 668 /** |
670 * The Dart Language Specification, 12.7: <blockquote>The static type of a map
literal of the form | 669 * The Dart Language Specification, 12.7: <blockquote>The static type of a map
literal of the form |
671 * <i><b>const</b> <K, V> {k<sub>1</sub>:e<sub>1</sub>, …, | 670 * <i><b>const</b> <K, V> {k<sub>1</sub>:e<sub>1</sub>, …, |
672 * k<sub>n</sub>:e<sub>n</sub>}</i> or the form <i><K, V> {k<sub>1</sub>
:e<sub>1</sub>, | 671 * k<sub>n</sub>:e<sub>n</sub>}</i> or the form <i><K, V> {k<sub>1</sub>
:e<sub>1</sub>, |
673 * …, k<sub>n</sub>:e<sub>n</sub>}</i> is `Map<K, V>`. The static
type a map | 672 * …, k<sub>n</sub>:e<sub>n</sub>}</i> is `Map<K, V>`. The static
type a map |
674 * literal of the form <i><b>const</b> {k<sub>1</sub>:e<sub>1</sub>, …, | 673 * literal of the form <i><b>const</b> {k<sub>1</sub>:e<sub>1</sub>, …, |
675 * k<sub>n</sub>:e<sub>n</sub>}</i> or the form <i>{k<sub>1</sub>:e<sub>1</sub
>, …, | 674 * k<sub>n</sub>:e<sub>n</sub>}</i> or the form <i>{k<sub>1</sub>:e<sub>1</sub
>, …, |
676 * k<sub>n</sub>:e<sub>n</sub>}</i> is `Map<dynamic, dynamic>`. | 675 * k<sub>n</sub>:e<sub>n</sub>}</i> is `Map<dynamic, dynamic>`. |
677 * | 676 * |
678 * It is a compile-time error if the first type argument to a map literal is n
ot | 677 * It is a compile-time error if the first type argument to a map literal is n
ot |
679 * <i>String</i>.</blockquote> | 678 * <i>String</i>.</blockquote> |
680 */ | 679 */ |
681 @override | 680 @override |
682 Object visitMapLiteral(MapLiteral node) { | 681 Object visitMapLiteral(MapLiteral node) { |
683 TypeArgumentList typeArguments = node.typeArguments; | 682 TypeArgumentList typeArguments = node.typeArguments; |
684 | 683 |
| 684 DartType mapDynamicType = _typeProvider.mapType |
| 685 .instantiate(<DartType>[_dynamicType, _dynamicType]); |
| 686 |
685 // If we have type arguments, use them | 687 // If we have type arguments, use them |
686 if (typeArguments != null) { | 688 if (typeArguments != null) { |
687 DartType staticKeyType = _dynamicType; | 689 DartType staticKeyType = _dynamicType; |
688 DartType staticValueType = _dynamicType; | 690 DartType staticValueType = _dynamicType; |
689 NodeList<TypeName> arguments = typeArguments.arguments; | 691 NodeList<TypeName> arguments = typeArguments.arguments; |
690 if (arguments != null && arguments.length == 2) { | 692 if (arguments != null && arguments.length == 2) { |
691 TypeName entryKeyTypeName = arguments[0]; | 693 TypeName entryKeyTypeName = arguments[0]; |
692 DartType entryKeyType = _getType(entryKeyTypeName); | 694 DartType entryKeyType = _getType(entryKeyTypeName); |
693 if (entryKeyType != null) { | 695 if (entryKeyType != null) { |
694 staticKeyType = entryKeyType; | 696 staticKeyType = entryKeyType; |
695 } | 697 } |
696 TypeName entryValueTypeName = arguments[1]; | 698 TypeName entryValueTypeName = arguments[1]; |
697 DartType entryValueType = _getType(entryValueTypeName); | 699 DartType entryValueType = _getType(entryValueTypeName); |
698 if (entryValueType != null) { | 700 if (entryValueType != null) { |
699 staticValueType = entryValueType; | 701 staticValueType = entryValueType; |
700 } | 702 } |
701 } | 703 } |
702 _recordStaticType( | 704 _recordStaticType( |
703 node, | 705 node, |
704 _typeProvider.mapType | 706 _typeProvider.mapType |
705 .instantiate(<DartType>[staticKeyType, staticValueType])); | 707 .instantiate(<DartType>[staticKeyType, staticValueType])); |
706 return null; | 708 return null; |
707 } | 709 } |
708 | 710 |
709 // If we have no explicit type arguments, and we are in strong mode | 711 // If we have no explicit type arguments, and we are in strong mode |
710 // then try to infer type arguments. | 712 // then try to infer type arguments. |
711 if (_strongMode) { | 713 if (_strongMode) { |
712 DartType contextType = InferenceContext.getType(node); | 714 DartType contextType = InferenceContext.getType(node); |
713 // If we have a context type, use that for inference. | |
714 if (contextType is InterfaceType && | |
715 contextType.typeArguments.length == 2 && | |
716 contextType.element == _typeProvider.mapType.element) { | |
717 _resolver.inferenceContext.recordInference(node, contextType); | |
718 _recordStaticType(node, contextType); | |
719 return null; | |
720 } | |
721 | 715 |
722 // Otherwise, try to infer a type from the keys and values. | 716 // Use both downwards and upwards information to infer the type. |
723 if (node.entries.isNotEmpty) { | 717 var ts = _typeSystem as StrongTypeSystemImpl; |
724 DartType staticKeyType = | 718 var keyTypes = |
725 node.entries.map((e) => e.key.staticType).reduce(_leastUpperBound); | 719 node.entries.map((e) => e.key.staticType).where((t) => t != null); |
726 DartType staticValueType = node.entries | 720 var valueTypes = |
727 .map((e) => e.value.staticType) | 721 node.entries.map((e) => e.value.staticType).where((t) => t != null); |
728 .reduce(_leastUpperBound); | 722 var keyTypeParam = _typeProvider.mapType.typeParameters[0].type; |
729 if (staticKeyType.isBottom) { | 723 var valueTypeParam = _typeProvider.mapType.typeParameters[1].type; |
730 staticKeyType = _dynamicType; | 724 |
731 } | 725 DartType inferred = ts.inferGenericFunctionCall( |
732 if (staticValueType.isBottom) { | 726 _typeProvider, |
733 staticValueType = _dynamicType; | 727 _typeProvider.mapType, |
734 } | 728 new List.filled(keyTypes.length, keyTypeParam, growable: true) |
735 DartType mapLiteralType = _typeProvider.mapType | 729 ..addAll(new List.filled(valueTypes.length, valueTypeParam)), |
736 .instantiate(<DartType>[staticKeyType, staticValueType]); | 730 new List.from(keyTypes)..addAll(valueTypes), |
737 if (!(staticValueType.isDynamic && staticKeyType.isDynamic)) { | 731 _typeProvider.mapType, |
738 _resolver.inferenceContext.recordInference(node, mapLiteralType); | 732 contextType, |
739 } | 733 errorReporter: _resolver.errorReporter, |
740 _recordStaticType(node, mapLiteralType); | 734 errorNode: node); |
| 735 |
| 736 if (inferred != mapDynamicType) { |
| 737 // TODO(jmesserly): this results in an "inferred" message even when we |
| 738 // in fact had an error above, because it will still attempt to return |
| 739 // a type. Perhaps we should record inference from TypeSystem if |
| 740 // everything was successful? |
| 741 _resolver.inferenceContext.recordInference(node, inferred); |
| 742 _recordStaticType(node, inferred); |
741 return null; | 743 return null; |
742 } | 744 } |
743 } | 745 } |
744 | 746 |
745 // If no type arguments and no inference, use dynamic | 747 // If no type arguments and no inference, use dynamic |
746 _recordStaticType( | 748 _recordStaticType(node, mapDynamicType); |
747 node, | |
748 _typeProvider.mapType | |
749 .instantiate(<DartType>[_dynamicType, _dynamicType])); | |
750 return null; | 749 return null; |
751 } | 750 } |
752 | 751 |
753 /** | 752 /** |
754 * The Dart Language Specification, 12.15.1: <blockquote>An ordinary method in
vocation <i>i</i> | 753 * The Dart Language Specification, 12.15.1: <blockquote>An ordinary method in
vocation <i>i</i> |
755 * has the form <i>o.m(a<sub>1</sub>, …, a<sub>n</sub>, x<sub>n+1</sub>
: a<sub>n+1</sub>, | 754 * has the form <i>o.m(a<sub>1</sub>, …, a<sub>n</sub>, x<sub>n+1</sub>
: a<sub>n+1</sub>, |
756 * …, x<sub>n+k</sub>: a<sub>n+k</sub>)</i>. | 755 * …, x<sub>n+k</sub>: a<sub>n+k</sub>)</i>. |
757 * | 756 * |
758 * Let <i>T</i> be the static type of <i>o</i>. It is a static type warning if
<i>T</i> does not | 757 * Let <i>T</i> be the static type of <i>o</i>. It is a static type warning if
<i>T</i> does not |
759 * have an accessible instance member named <i>m</i>. If <i>T.m</i> exists, it
is a static warning | 758 * have an accessible instance member named <i>m</i>. If <i>T.m</i> exists, it
is a static warning |
(...skipping 1219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1979 ..synthetic = true | 1978 ..synthetic = true |
1980 ..shareParameters(firstParamType.parameters) | 1979 ..shareParameters(firstParamType.parameters) |
1981 ..returnType = paramReturnType; | 1980 ..returnType = paramReturnType; |
1982 function.type = new FunctionTypeImpl(function); | 1981 function.type = new FunctionTypeImpl(function); |
1983 // Use this as the expected 1st parameter type. | 1982 // Use this as the expected 1st parameter type. |
1984 paramTypes[0] = function.type; | 1983 paramTypes[0] = function.type; |
1985 } | 1984 } |
1986 } | 1985 } |
1987 } | 1986 } |
1988 return ts.inferGenericFunctionCall(_typeProvider, fnType, paramTypes, | 1987 return ts.inferGenericFunctionCall(_typeProvider, fnType, paramTypes, |
1989 argTypes, InferenceContext.getContext(node), | 1988 argTypes, fnType.returnType, InferenceContext.getContext(node), |
1990 errorReporter: _resolver.errorReporter, errorNode: errorNode); | 1989 errorReporter: _resolver.errorReporter, errorNode: errorNode); |
1991 } | 1990 } |
1992 return null; | 1991 return null; |
1993 } | 1992 } |
1994 | 1993 |
1995 /** | 1994 /** |
1996 * Given an instance creation of a possibly generic type, infer the type | 1995 * Given an instance creation of a possibly generic type, infer the type |
1997 * arguments using the current context type as well as the argument types. | 1996 * arguments using the current context type as well as the argument types. |
1998 */ | 1997 */ |
1999 void _inferInstanceCreationExpression(InstanceCreationExpression node) { | 1998 void _inferInstanceCreationExpression(InstanceCreationExpression node) { |
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2244 (parent.parent is TypeName || identical(parent.prefix, node))) || | 2243 (parent.parent is TypeName || identical(parent.prefix, node))) || |
2245 (parent is PropertyAccess && | 2244 (parent is PropertyAccess && |
2246 identical(parent.target, node) && | 2245 identical(parent.target, node) && |
2247 parent.operator.type == TokenType.PERIOD) || | 2246 parent.operator.type == TokenType.PERIOD) || |
2248 (parent is MethodInvocation && | 2247 (parent is MethodInvocation && |
2249 identical(node, parent.target) && | 2248 identical(node, parent.target) && |
2250 parent.operator.type == TokenType.PERIOD); | 2249 parent.operator.type == TokenType.PERIOD); |
2251 } | 2250 } |
2252 | 2251 |
2253 /** | 2252 /** |
2254 * Computes the least upper bound between two types. | |
2255 * | |
2256 * See [TypeSystem.getLeastUpperBound]. | |
2257 */ | |
2258 DartType _leastUpperBound(DartType s, DartType t) => | |
2259 _typeSystem.getLeastUpperBound(_typeProvider, s, t); | |
2260 | |
2261 /** | |
2262 * Record that the propagated type of the given node is the given type. | 2253 * Record that the propagated type of the given node is the given type. |
2263 * | 2254 * |
2264 * @param expression the node whose type is to be recorded | 2255 * @param expression the node whose type is to be recorded |
2265 * @param type the propagated type of the node | 2256 * @param type the propagated type of the node |
2266 */ | 2257 */ |
2267 void _recordPropagatedType(Expression expression, DartType type) { | 2258 void _recordPropagatedType(Expression expression, DartType type) { |
2268 if (type != null && !type.isDynamic && !type.isBottom) { | 2259 if (type != null && !type.isDynamic && !type.isBottom) { |
2269 expression.propagatedType = type; | 2260 expression.propagatedType = type; |
2270 } | 2261 } |
2271 } | 2262 } |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2407 } | 2398 } |
2408 // merge types | 2399 // merge types |
2409 if (result == null) { | 2400 if (result == null) { |
2410 result = type; | 2401 result = type; |
2411 } else { | 2402 } else { |
2412 result = _typeSystem.getLeastUpperBound(_typeProvider, result, type); | 2403 result = _typeSystem.getLeastUpperBound(_typeProvider, result, type); |
2413 } | 2404 } |
2414 return null; | 2405 return null; |
2415 } | 2406 } |
2416 } | 2407 } |
OLD | NEW |