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