| 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 |