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/standard_resolution_map.dart'; | 10 import 'package:analyzer/dart/ast/standard_resolution_map.dart'; |
(...skipping 793 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
804 DartType staticPropagatedType = | 804 DartType staticPropagatedType = |
805 _computePropagatedReturnType(staticMethodElement); | 805 _computePropagatedReturnType(staticMethodElement); |
806 _resolver.recordPropagatedTypeIfBetter(node, staticPropagatedType); | 806 _resolver.recordPropagatedTypeIfBetter(node, staticPropagatedType); |
807 // Check for special cases. | 807 // Check for special cases. |
808 bool needPropagatedType = true; | 808 bool needPropagatedType = true; |
809 String methodName = methodNameNode.name; | 809 String methodName = methodNameNode.name; |
810 if (!_strongMode && methodName == "then") { | 810 if (!_strongMode && methodName == "then") { |
811 Expression target = node.realTarget; | 811 Expression target = node.realTarget; |
812 if (target != null) { | 812 if (target != null) { |
813 DartType targetType = target.bestType; | 813 DartType targetType = target.bestType; |
814 if (_isAsyncFutureType(targetType)) { | 814 if (targetType.isDartAsyncFuture) { |
815 // Future.then(closure) return type is: | 815 // Future.then(closure) return type is: |
816 // 1) the returned Future type, if the closure returns a Future; | 816 // 1) the returned Future type, if the closure returns a Future; |
817 // 2) Future<valueType>, if the closure returns a value. | 817 // 2) Future<valueType>, if the closure returns a value. |
818 NodeList<Expression> arguments = node.argumentList.arguments; | 818 NodeList<Expression> arguments = node.argumentList.arguments; |
819 if (arguments.length == 1) { | 819 if (arguments.length == 1) { |
820 // TODO(brianwilkerson) Handle the case where both arguments are | 820 // TODO(brianwilkerson) Handle the case where both arguments are |
821 // provided. | 821 // provided. |
822 Expression closureArg = arguments[0]; | 822 Expression closureArg = arguments[0]; |
823 if (closureArg is FunctionExpression) { | 823 if (closureArg is FunctionExpression) { |
824 FunctionExpression closureExpr = closureArg; | 824 FunctionExpression closureExpr = closureArg; |
(...skipping 586 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1411 DartType staticType1 = _getDefiniteType(expr1); | 1411 DartType staticType1 = _getDefiniteType(expr1); |
1412 DartType staticType2 = _getDefiniteType(expr2); | 1412 DartType staticType2 = _getDefiniteType(expr2); |
1413 if (staticType1 == null) { | 1413 if (staticType1 == null) { |
1414 // TODO(brianwilkerson) Determine whether this can still happen. | 1414 // TODO(brianwilkerson) Determine whether this can still happen. |
1415 staticType1 = _dynamicType; | 1415 staticType1 = _dynamicType; |
1416 } | 1416 } |
1417 if (staticType2 == null) { | 1417 if (staticType2 == null) { |
1418 // TODO(brianwilkerson) Determine whether this can still happen. | 1418 // TODO(brianwilkerson) Determine whether this can still happen. |
1419 staticType2 = _dynamicType; | 1419 staticType2 = _dynamicType; |
1420 } | 1420 } |
| 1421 |
1421 DartType staticType = | 1422 DartType staticType = |
1422 _typeSystem.getLeastUpperBound(staticType1, staticType2); | 1423 _typeSystem.getLeastUpperBound(staticType1, staticType2) ?? |
1423 if (staticType == null) { | 1424 _dynamicType; |
1424 staticType = _dynamicType; | 1425 |
1425 } | |
1426 _recordStaticType(node, staticType); | 1426 _recordStaticType(node, staticType); |
1427 DartType propagatedType1 = expr1.propagatedType; | 1427 DartType propagatedType1 = expr1.propagatedType; |
1428 DartType propagatedType2 = expr2.propagatedType; | 1428 DartType propagatedType2 = expr2.propagatedType; |
1429 if (propagatedType1 != null || propagatedType2 != null) { | 1429 if (propagatedType1 != null || propagatedType2 != null) { |
1430 if (propagatedType1 == null) { | 1430 if (propagatedType1 == null) { |
1431 propagatedType1 = staticType1; | 1431 propagatedType1 = staticType1; |
1432 } | 1432 } |
1433 if (propagatedType2 == null) { | 1433 if (propagatedType2 == null) { |
1434 propagatedType2 = staticType2; | 1434 propagatedType2 = staticType2; |
1435 } | 1435 } |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1512 * | 1512 * |
1513 * See also [FunctionBody.isAsynchronous], [FunctionBody.isGenerator]. | 1513 * See also [FunctionBody.isAsynchronous], [FunctionBody.isGenerator]. |
1514 */ | 1514 */ |
1515 DartType _computeReturnTypeOfFunction(FunctionBody body, DartType type) { | 1515 DartType _computeReturnTypeOfFunction(FunctionBody body, DartType type) { |
1516 if (body.isGenerator) { | 1516 if (body.isGenerator) { |
1517 InterfaceType genericType = body.isAsynchronous | 1517 InterfaceType genericType = body.isAsynchronous |
1518 ? _typeProvider.streamType | 1518 ? _typeProvider.streamType |
1519 : _typeProvider.iterableType; | 1519 : _typeProvider.iterableType; |
1520 return genericType.instantiate(<DartType>[type]); | 1520 return genericType.instantiate(<DartType>[type]); |
1521 } else if (body.isAsynchronous) { | 1521 } else if (body.isAsynchronous) { |
| 1522 if (type.isDartAsyncFutureOr) { |
| 1523 type = (type as InterfaceType).typeArguments[0]; |
| 1524 } |
1522 return _typeProvider.futureType | 1525 return _typeProvider.futureType |
1523 .instantiate(<DartType>[type.flattenFutures(_typeSystem)]); | 1526 .instantiate(<DartType>[type.flattenFutures(_typeSystem)]); |
1524 } else { | 1527 } else { |
1525 return type; | 1528 return type; |
1526 } | 1529 } |
1527 } | 1530 } |
1528 | 1531 |
1529 /** | 1532 /** |
1530 * Compute the static return type of the method or function represented by the
given element. | 1533 * Compute the static return type of the method or function represented by the
given element. |
1531 * | 1534 * |
(...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1954 | 1957 |
1955 List<DartType> paramTypes = <DartType>[]; | 1958 List<DartType> paramTypes = <DartType>[]; |
1956 List<DartType> argTypes = <DartType>[]; | 1959 List<DartType> argTypes = <DartType>[]; |
1957 for (int i = 0, length = rawParameters.length; i < length; i++) { | 1960 for (int i = 0, length = rawParameters.length; i < length; i++) { |
1958 ParameterElement parameter = rawParameters[i]; | 1961 ParameterElement parameter = rawParameters[i]; |
1959 if (parameter != null) { | 1962 if (parameter != null) { |
1960 paramTypes.add(parameter.type); | 1963 paramTypes.add(parameter.type); |
1961 argTypes.add(argumentList.arguments[i].staticType); | 1964 argTypes.add(argumentList.arguments[i].staticType); |
1962 } | 1965 } |
1963 } | 1966 } |
1964 | |
1965 // Special case Future<T>.then upwards inference. It has signature: | |
1966 // | |
1967 // <S>(T -> (S | Future<S>)) -> Future<S> | |
1968 // | |
1969 // Based on the first argument type, we'll pick one of these signatures: | |
1970 // | |
1971 // <S>(T -> S) -> Future<S> | |
1972 // <S>(T -> Future<S>) -> Future<S> | |
1973 // | |
1974 // ... and finish the inference using that. | |
1975 if (argTypes.isNotEmpty && _resolver.isFutureThen(fnType.element)) { | |
1976 var firstArgType = argTypes[0]; | |
1977 var firstParamType = paramTypes[0] as FunctionType; | |
1978 if (firstArgType is FunctionType) { | |
1979 var argReturnType = firstArgType.returnType; | |
1980 // Skip the inference if we have the top type. It can only lead to | |
1981 // worse inference. For example, this happens when the lambda returns | |
1982 // S or Future<S> in a conditional. | |
1983 if (!argReturnType.isObject && !argReturnType.isDynamic) { | |
1984 DartType paramReturnType = fnType.typeFormals[0].type; | |
1985 if (_resolver.isSubtypeOfFuture(argReturnType)) { | |
1986 // Given an argument of (T) -> Future<S>, instantiate with <S> | |
1987 paramReturnType = | |
1988 _typeProvider.futureType.instantiate([paramReturnType]); | |
1989 } | |
1990 | |
1991 // Adjust the expected parameter type to have this return type. | |
1992 var function = new FunctionElementImpl(firstParamType.name, -1) | |
1993 ..isSynthetic = true | |
1994 ..shareParameters(firstParamType.parameters) | |
1995 ..returnType = paramReturnType; | |
1996 function.type = new FunctionTypeImpl(function); | |
1997 // Use this as the expected 1st parameter type. | |
1998 paramTypes[0] = function.type; | |
1999 } | |
2000 } | |
2001 } | |
2002 return ts.inferGenericFunctionCall(fnType, paramTypes, argTypes, | 1967 return ts.inferGenericFunctionCall(fnType, paramTypes, argTypes, |
2003 fnType.returnType, InferenceContext.getContext(node), | 1968 fnType.returnType, InferenceContext.getContext(node), |
2004 errorReporter: _resolver.errorReporter, errorNode: errorNode); | 1969 errorReporter: _resolver.errorReporter, errorNode: errorNode); |
2005 } | 1970 } |
2006 return null; | 1971 return null; |
2007 } | 1972 } |
2008 | 1973 |
2009 /** | 1974 /** |
2010 * Given an instance creation of a possibly generic type, infer the type | 1975 * Given an instance creation of a possibly generic type, infer the type |
2011 * arguments using the current context type as well as the argument types. | 1976 * arguments using the current context type as well as the argument types. |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2074 | 2039 |
2075 // If we had a better type from the function body, use it. | 2040 // If we had a better type from the function body, use it. |
2076 // | 2041 // |
2077 // This helps in a few cases: | 2042 // This helps in a few cases: |
2078 // * ExpressionFunctionBody, when the surrounding context had a better type. | 2043 // * ExpressionFunctionBody, when the surrounding context had a better type. |
2079 // * BlockFunctionBody, if we inferred a type from yield/return. | 2044 // * BlockFunctionBody, if we inferred a type from yield/return. |
2080 // * we also normalize bottom to dynamic here. | 2045 // * we also normalize bottom to dynamic here. |
2081 if (_strongMode && | 2046 if (_strongMode && |
2082 (computedType.isDartCoreNull || computedType.isDynamic)) { | 2047 (computedType.isDartCoreNull || computedType.isDynamic)) { |
2083 DartType contextType = InferenceContext.getContext(body); | 2048 DartType contextType = InferenceContext.getContext(body); |
2084 if (contextType is FutureUnionType) { | 2049 computedType = contextType ?? _dynamicType; |
2085 // TODO(jmesserly): can we do something better here? | |
2086 computedType = body.isAsynchronous ? contextType.type : _dynamicType; | |
2087 } else { | |
2088 computedType = contextType ?? _dynamicType; | |
2089 } | |
2090 recordInference = !computedType.isDynamic; | 2050 recordInference = !computedType.isDynamic; |
2091 } | 2051 } |
2092 | 2052 |
2093 computedType = _computeReturnTypeOfFunction(body, computedType); | 2053 computedType = _computeReturnTypeOfFunction(body, computedType); |
2094 functionElement.returnType = computedType; | 2054 functionElement.returnType = computedType; |
2095 _recordPropagatedTypeOfFunction(functionElement, node.body); | 2055 _recordPropagatedTypeOfFunction(functionElement, node.body); |
2096 _recordStaticType(node, functionElement.type); | 2056 _recordStaticType(node, functionElement.type); |
2097 if (recordInference) { | 2057 if (recordInference) { |
2098 _resolver.inferenceContext.recordInference(node, functionElement.type); | 2058 _resolver.inferenceContext.recordInference(node, functionElement.type); |
2099 } | 2059 } |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2217 inferredType != null && | 2177 inferredType != null && |
2218 _typeProvider.nonSubtypableTypes.contains(inferredType)) { | 2178 _typeProvider.nonSubtypableTypes.contains(inferredType)) { |
2219 _recordStaticType(id, inferredType); | 2179 _recordStaticType(id, inferredType); |
2220 _recordStaticType(node, inferredType); | 2180 _recordStaticType(node, inferredType); |
2221 return true; | 2181 return true; |
2222 } | 2182 } |
2223 return false; | 2183 return false; |
2224 } | 2184 } |
2225 | 2185 |
2226 /** | 2186 /** |
2227 * Return `true` if the given [Type] is the `Future` form the 'dart:async' | |
2228 * library. | |
2229 */ | |
2230 bool _isAsyncFutureType(DartType type) => | |
2231 type is InterfaceType && | |
2232 type.name == "Future" && | |
2233 _isAsyncLibrary(type.element.library); | |
2234 | |
2235 /** | |
2236 * Return `true` if the given library is the 'dart:async' library. | |
2237 * | |
2238 * @param library the library being tested | |
2239 * @return `true` if the library is 'dart:async' | |
2240 */ | |
2241 bool _isAsyncLibrary(LibraryElement library) => library.name == "dart.async"; | |
2242 | |
2243 /** | |
2244 * Return `true` if the given library is the 'dart:html' library. | 2187 * Return `true` if the given library is the 'dart:html' library. |
2245 * | 2188 * |
2246 * @param library the library being tested | 2189 * @param library the library being tested |
2247 * @return `true` if the library is 'dart:html' | 2190 * @return `true` if the library is 'dart:html' |
2248 */ | 2191 */ |
2249 bool _isHtmlLibrary(LibraryElement library) => | 2192 bool _isHtmlLibrary(LibraryElement library) => |
2250 library != null && "dart.dom.html" == library.name; | 2193 library != null && "dart.dom.html" == library.name; |
2251 | 2194 |
2252 /** | 2195 /** |
2253 * Return `true` if the given [node] is not a type literal. | 2196 * Return `true` if the given [node] is not a type literal. |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2421 } | 2364 } |
2422 // merge types | 2365 // merge types |
2423 if (result == null) { | 2366 if (result == null) { |
2424 result = type; | 2367 result = type; |
2425 } else { | 2368 } else { |
2426 result = _typeSystem.getLeastUpperBound(result, type); | 2369 result = _typeSystem.getLeastUpperBound(result, type); |
2427 } | 2370 } |
2428 return null; | 2371 return null; |
2429 } | 2372 } |
2430 } | 2373 } |
OLD | NEW |