Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(227)

Side by Side Diff: pkg/analyzer/lib/src/generated/static_type_analyzer.dart

Issue 2343713002: fix #27151, list and map literals infer using up and down info (Closed)
Patch Set: format Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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> &lt;K, V&gt; {k<sub>1</sub>:e<sub>1</sub>, &hellip;, 670 * <i><b>const</b> &lt;K, V&gt; {k<sub>1</sub>:e<sub>1</sub>, &hellip;,
672 * k<sub>n</sub>:e<sub>n</sub>}</i> or the form <i>&lt;K, V&gt; {k<sub>1</sub> :e<sub>1</sub>, 671 * k<sub>n</sub>:e<sub>n</sub>}</i> or the form <i>&lt;K, V&gt; {k<sub>1</sub> :e<sub>1</sub>,
673 * &hellip;, k<sub>n</sub>:e<sub>n</sub>}</i> is `Map&lt;K, V&gt;`. The static type a map 672 * &hellip;, k<sub>n</sub>:e<sub>n</sub>}</i> is `Map&lt;K, V&gt;`. The static type a map
674 * literal of the form <i><b>const</b> {k<sub>1</sub>:e<sub>1</sub>, &hellip;, 673 * literal of the form <i><b>const</b> {k<sub>1</sub>:e<sub>1</sub>, &hellip;,
675 * k<sub>n</sub>:e<sub>n</sub>}</i> or the form <i>{k<sub>1</sub>:e<sub>1</sub >, &hellip;, 674 * k<sub>n</sub>:e<sub>n</sub>}</i> or the form <i>{k<sub>1</sub>:e<sub>1</sub >, &hellip;,
676 * k<sub>n</sub>:e<sub>n</sub>}</i> is `Map&lt;dynamic, dynamic&gt;`. 675 * k<sub>n</sub>:e<sub>n</sub>}</i> is `Map&lt;dynamic, dynamic&gt;`.
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>, &hellip;, 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>, &hellip;, a<sub>n</sub>, x<sub>n+1</sub> : a<sub>n+1</sub>,
756 * &hellip;, x<sub>n+k</sub>: a<sub>n+k</sub>)</i>. 755 * &hellip;, 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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698