OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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.type_system; | 5 library analyzer.src.generated.type_system; |
6 | 6 |
7 import 'dart:collection'; | 7 import 'dart:collection'; |
8 import 'dart:math' as math; | 8 import 'dart:math' as math; |
9 | 9 |
10 import 'package:analyzer/dart/ast/ast.dart' show AstNode; | 10 import 'package:analyzer/dart/ast/ast.dart' show AstNode; |
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
229 {ErrorReporter errorReporter, AstNode errorNode}) { | 229 {ErrorReporter errorReporter, AstNode errorNode}) { |
230 if (contextType.typeFormals.isNotEmpty || fnType.typeFormals.isEmpty) { | 230 if (contextType.typeFormals.isNotEmpty || fnType.typeFormals.isEmpty) { |
231 return fnType; | 231 return fnType; |
232 } | 232 } |
233 | 233 |
234 // Create a TypeSystem that will allow certain type parameters to be | 234 // Create a TypeSystem that will allow certain type parameters to be |
235 // inferred. It will optimistically assume these type parameters can be | 235 // inferred. It will optimistically assume these type parameters can be |
236 // subtypes (or supertypes) as necessary, and track the constraints that | 236 // subtypes (or supertypes) as necessary, and track the constraints that |
237 // are implied by this. | 237 // are implied by this. |
238 var inferrer = new _GenericInferrer(typeProvider, this, fnType.typeFormals); | 238 var inferrer = new _GenericInferrer(typeProvider, this, fnType.typeFormals); |
239 | 239 inferrer.constrainGenericFunctionInContext(fnType, contextType); |
240 // Since we're trying to infer the instantiation, we want to ignore type | |
241 // formals as we check the parameters and return type. | |
242 var inferFnType = | |
243 fnType.instantiate(TypeParameterTypeImpl.getTypes(fnType.typeFormals)); | |
244 inferrer.constrainReturnType(inferFnType, contextType); | |
245 | 240 |
246 // Infer and instantiate the resulting type. | 241 // Infer and instantiate the resulting type. |
247 return inferrer.infer(fnType, fnType.typeFormals, | 242 return inferrer.infer(fnType, fnType.typeFormals, |
248 errorReporter: errorReporter, errorNode: errorNode); | 243 errorReporter: errorReporter, errorNode: errorNode); |
249 } | 244 } |
250 | 245 |
251 /// Infers a generic type, function, method, or list/map literal | 246 /// Infers a generic type, function, method, or list/map literal |
252 /// instantiation, using the downward context type as well as the argument | 247 /// instantiation, using the downward context type as well as the argument |
253 /// types if available. | 248 /// types if available. |
254 /// | 249 /// |
(...skipping 1341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1596 } | 1591 } |
1597 } | 1592 } |
1598 | 1593 |
1599 /// Apply a return type constraint, which asserts that the [declaredType] | 1594 /// Apply a return type constraint, which asserts that the [declaredType] |
1600 /// is a subtype of the [contextType]. | 1595 /// is a subtype of the [contextType]. |
1601 void constrainReturnType(DartType declaredType, DartType contextType) { | 1596 void constrainReturnType(DartType declaredType, DartType contextType) { |
1602 var origin = new _TypeConstraintFromReturnType(declaredType, contextType); | 1597 var origin = new _TypeConstraintFromReturnType(declaredType, contextType); |
1603 _matchSubtypeOf(declaredType, contextType, null, origin, covariant: true); | 1598 _matchSubtypeOf(declaredType, contextType, null, origin, covariant: true); |
1604 } | 1599 } |
1605 | 1600 |
| 1601 /// Constrain a universal function type [fnType] used in a context |
| 1602 /// [contextType]. |
| 1603 void constrainGenericFunctionInContext( |
| 1604 FunctionType fnType, DartType contextType) { |
| 1605 var origin = new _TypeConstraintFromFunctionContext(fnType, contextType); |
| 1606 |
| 1607 // Since we're trying to infer the instantiation, we want to ignore type |
| 1608 // formals as we check the parameters and return type. |
| 1609 var inferFnType = |
| 1610 fnType.instantiate(TypeParameterTypeImpl.getTypes(fnType.typeFormals)); |
| 1611 _matchSubtypeOf(inferFnType, contextType, null, origin, covariant: true); |
| 1612 } |
| 1613 |
1606 /// Apply an argument constraint, which asserts that the [argument] staticType | 1614 /// Apply an argument constraint, which asserts that the [argument] staticType |
1607 /// is a subtype of the [parameterType]. | 1615 /// is a subtype of the [parameterType]. |
1608 void constrainArgument( | 1616 void constrainArgument( |
1609 DartType argumentType, DartType parameterType, String parameterName, | 1617 DartType argumentType, DartType parameterType, String parameterName, |
1610 {DartType genericType}) { | 1618 {DartType genericType}) { |
1611 var origin = new _TypeConstraintFromArgument( | 1619 var origin = new _TypeConstraintFromArgument( |
1612 argumentType, parameterType, parameterName, | 1620 argumentType, parameterType, parameterName, |
1613 genericType: genericType); | 1621 genericType: genericType); |
1614 _matchSubtypeOf(argumentType, parameterType, null, origin, | 1622 _matchSubtypeOf(argumentType, parameterType, null, origin, |
1615 covariant: false); | 1623 covariant: false); |
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1844 | 1852 |
1845 // Check the inferred types against all of the constraints. | 1853 // Check the inferred types against all of the constraints. |
1846 var knownTypes = new HashMap<TypeParameterType, DartType>( | 1854 var knownTypes = new HashMap<TypeParameterType, DartType>( |
1847 equals: (x, y) => x.element == y.element, | 1855 equals: (x, y) => x.element == y.element, |
1848 hashCode: (x) => x.element.hashCode); | 1856 hashCode: (x) => x.element.hashCode); |
1849 for (int i = 0; i < fnTypeParams.length; i++) { | 1857 for (int i = 0; i < fnTypeParams.length; i++) { |
1850 TypeParameterType typeParam = fnTypeParams[i]; | 1858 TypeParameterType typeParam = fnTypeParams[i]; |
1851 var constraints = _constraints[typeParam.element]; | 1859 var constraints = _constraints[typeParam.element]; |
1852 var typeParamBound = | 1860 var typeParamBound = |
1853 typeParam.bound.substitute2(inferredTypes, fnTypeParams); | 1861 typeParam.bound.substitute2(inferredTypes, fnTypeParams); |
1854 if (!typeParamBound.isDynamic) { | 1862 |
1855 constraints | 1863 var inferred = inferredTypes[i]; |
1856 .add(new _TypeConstraint.fromExtends(typeParam, typeParamBound)); | 1864 bool success = |
| 1865 constraints.every((c) => c.isSatisifedBy(_typeSystem, inferred)); |
| 1866 if (success && !typeParamBound.isDynamic) { |
| 1867 // If everything else succeeded, check the `extends` constraint. |
| 1868 var extendsConstraint = |
| 1869 new _TypeConstraint.fromExtends(typeParam, typeParamBound); |
| 1870 constraints.add(extendsConstraint); |
| 1871 success = extendsConstraint.isSatisifedBy(_typeSystem, inferred); |
1857 } | 1872 } |
1858 var inferred = inferredTypes[i]; | 1873 |
1859 if (constraints.any((c) => !c.isSatisifedBy(_typeSystem, inferred))) { | 1874 if (!success) { |
1860 // Heuristic: keep the erroneous type, it should satisfy at least some | 1875 errorReporter?.reportErrorForNode( |
1861 // of the constraints (e.g. the return context). If we fall back to | 1876 StrongModeCode.COULD_NOT_INFER, |
1862 // instantiateToBounds, we'll typically get more errors (e.g. because | 1877 errorNode, |
1863 // `dynamic` is the most common bound). | 1878 [typeParam, _formatError(typeParam, inferred, constraints)]); |
1864 knownTypes[typeParam] = inferred; | 1879 |
1865 errorReporter?.reportErrorForNode(StrongModeCode.COULD_NOT_INFER, | 1880 // Heuristic: even if we failed, keep the erroneous type. |
1866 errorNode, [typeParam, _formatError(inferred, constraints)]); | 1881 // It should satisfy at least some of the constraints (e.g. the return |
1867 } else if (UnknownInferredType.isKnown(inferred)) { | 1882 // context). If we fall back to instantiateToBounds, we'll typically get |
| 1883 // more errors (e.g. because `dynamic` is the most common bound). |
| 1884 } |
| 1885 |
| 1886 if (UnknownInferredType.isKnown(inferred)) { |
1868 knownTypes[typeParam] = inferred; | 1887 knownTypes[typeParam] = inferred; |
1869 } | 1888 } |
1870 } | 1889 } |
1871 | 1890 |
1872 // Use instantiate to bounds to finish things off. | 1891 // Use instantiate to bounds to finish things off. |
1873 var hasError = new List<bool>.filled(fnTypeParams.length, false); | 1892 var hasError = new List<bool>.filled(fnTypeParams.length, false); |
1874 var result = _typeSystem.instantiateToBounds(genericType, | 1893 var result = _typeSystem.instantiateToBounds(genericType, |
1875 hasError: hasError, knownTypes: knownTypes) as dynamic/*=T*/; | 1894 hasError: hasError, knownTypes: knownTypes) as dynamic/*=T*/; |
1876 | 1895 |
1877 // Report any errors from instantiateToBounds. | 1896 // Report any errors from instantiateToBounds. |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2032 if (t2 is InterfaceType && t2.isDartAsyncFutureOr) { | 2051 if (t2 is InterfaceType && t2.isDartAsyncFutureOr) { |
2033 // GLB(A, FutureOr<B>) == GLB(FutureOr<A>, B) | 2052 // GLB(A, FutureOr<B>) == GLB(FutureOr<A>, B) |
2034 return _getGreatestLowerBound(t2, t1); | 2053 return _getGreatestLowerBound(t2, t1); |
2035 } | 2054 } |
2036 // TODO(jmesserly): fix this rule once we support non-nullable types. | 2055 // TODO(jmesserly): fix this rule once we support non-nullable types. |
2037 return typeProvider.nullType; | 2056 return typeProvider.nullType; |
2038 } | 2057 } |
2039 return result; | 2058 return result; |
2040 } | 2059 } |
2041 | 2060 |
2042 String _formatError( | 2061 String _formatError(TypeParameterType typeParam, DartType inferred, |
2043 DartType inferred, Iterable<_TypeConstraint> constraints) { | 2062 Iterable<_TypeConstraint> constraints) { |
2044 var intro = "Inferred type '$inferred' does not work with constraints:"; | 2063 var intro = "Tried to infer '$inferred' for '$typeParam'" |
| 2064 " which doesn't work:"; |
2045 | 2065 |
2046 var constraintsByOrigin = <_TypeConstraintOrigin, List<_TypeConstraint>>{}; | 2066 var constraintsByOrigin = <_TypeConstraintOrigin, List<_TypeConstraint>>{}; |
2047 for (var c in constraints) { | 2067 for (var c in constraints) { |
2048 constraintsByOrigin.putIfAbsent(c.origin, () => []).add(c); | 2068 constraintsByOrigin.putIfAbsent(c.origin, () => []).add(c); |
2049 } | 2069 } |
2050 | 2070 |
| 2071 // Only report unique constraint origins. |
2051 Iterable<_TypeConstraint> isSatisified(bool expected) => constraintsByOrigin | 2072 Iterable<_TypeConstraint> isSatisified(bool expected) => constraintsByOrigin |
2052 .values | 2073 .values |
2053 .where((l) => | 2074 .where((l) => |
2054 l.every((c) => c.isSatisifedBy(_typeSystem, inferred)) == expected) | 2075 l.every((c) => c.isSatisifedBy(_typeSystem, inferred)) == expected) |
2055 .expand((i) => i); | 2076 .expand((i) => i); |
2056 | 2077 |
2057 // Only report unique constraint origins. | |
2058 String unsatisified = _formatConstraints(isSatisified(false)); | 2078 String unsatisified = _formatConstraints(isSatisified(false)); |
2059 String satisified = _formatConstraints(isSatisified(true)); | 2079 String satisified = _formatConstraints(isSatisified(true)); |
2060 | 2080 |
2061 assert(unsatisified.isNotEmpty); | 2081 assert(unsatisified.isNotEmpty); |
2062 if (satisified.isNotEmpty) { | 2082 if (satisified.isNotEmpty) { |
2063 satisified = "\nThe type '$inferred' was inferred from:\n$satisified"; | 2083 satisified = "\nThe type '$inferred' was inferred from:\n$satisified"; |
2064 } | 2084 } |
2065 | 2085 |
2066 return '\n\n$intro\n$unsatisified$satisified\n\n' | 2086 return '\n\n$intro\n$unsatisified$satisified\n\n' |
2067 'Consider passing explicit type argument(s) to the generic.\n\n'; | 2087 'Consider passing explicit type argument(s) to the generic.\n\n'; |
2068 } | 2088 } |
2069 | 2089 |
2070 static String _formatConstraints(Iterable<_TypeConstraint> constraints) { | 2090 static String _formatConstraints(Iterable<_TypeConstraint> constraints) { |
2071 List<List<String>> lineParts = | 2091 List<List<String>> lineParts = |
2072 new Set<_TypeConstraintOrigin>.from(constraints.map((c) => c.origin)) | 2092 new Set<_TypeConstraintOrigin>.from(constraints.map((c) => c.origin)) |
2073 .map((o) => o.formatError()) | 2093 .map((o) => o.formatError()) |
2074 .toList(); | 2094 .toList(); |
2075 | 2095 |
2076 int prefixMax = lineParts.map((p) => p[0].length).fold(0, math.max); | 2096 int prefixMax = lineParts.map((p) => p[0].length).fold(0, math.max); |
2077 int middleMax = lineParts.map((p) => p[1].length).fold(0, math.max); | |
2078 | 2097 |
2079 // Use a set to prevent identical message lines. | 2098 // Use a set to prevent identical message lines. |
2080 // (It's not uncommon for the same constraint to show up in a few places.) | 2099 // (It's not uncommon for the same constraint to show up in a few places.) |
2081 var messageLines = new Set<String>.from(lineParts.map((parts) { | 2100 var messageLines = new Set<String>.from(lineParts.map((parts) { |
2082 var prefix = parts[0]; | 2101 var prefix = parts[0]; |
2083 var middle = parts[1]; | 2102 var middle = parts[1]; |
2084 var prefixPad = ' ' * (prefixMax - prefix.length); | 2103 var prefixPad = ' ' * (prefixMax - prefix.length); |
2085 var middlePad = ' ' * (middleMax - middle.length); | 2104 var middlePad = ' ' * (prefixMax); |
2086 return ' $prefix$prefixPad $middle$middlePad ${parts[2]}'.trimRight(); | 2105 var end = ""; |
| 2106 if (parts.length > 2) { |
| 2107 end = '\n $middlePad ${parts[2]}'; |
| 2108 } |
| 2109 return ' $prefix$prefixPad $middle$end'; |
2087 })); | 2110 })); |
2088 | 2111 |
2089 return messageLines.join('\n'); | 2112 return messageLines.join('\n'); |
2090 } | 2113 } |
2091 } | 2114 } |
2092 | 2115 |
2093 /// The origin of a type constraint, for the purposes of producing a human | 2116 /// The origin of a type constraint, for the purposes of producing a human |
2094 /// readable error message during type inference as well as determining whether | 2117 /// readable error message during type inference as well as determining whether |
2095 /// the constraint was used to fix the type parameter or not. | 2118 /// the constraint was used to fix the type parameter or not. |
2096 abstract class _TypeConstraintOrigin { | 2119 abstract class _TypeConstraintOrigin { |
(...skipping 17 matching lines...) Expand all Loading... |
2114 // available. | 2137 // available. |
2115 String prefix; | 2138 String prefix; |
2116 if ((genericType.name == "List" || genericType.name == "Map") && | 2139 if ((genericType.name == "List" || genericType.name == "Map") && |
2117 genericType?.element?.library?.isDartCore == true) { | 2140 genericType?.element?.library?.isDartCore == true) { |
2118 // This will become: | 2141 // This will become: |
2119 // "List element" | 2142 // "List element" |
2120 // "Map key" | 2143 // "Map key" |
2121 // "Map value" | 2144 // "Map value" |
2122 prefix = "${genericType.name} $parameterName"; | 2145 prefix = "${genericType.name} $parameterName"; |
2123 } else { | 2146 } else { |
2124 prefix = "Argument '$parameterName'"; | 2147 prefix = "Parameter '$parameterName'"; |
2125 } | 2148 } |
2126 | 2149 |
2127 return [ | 2150 return [ |
2128 prefix, | 2151 prefix, |
2129 "inferred as '$argumentType'", | 2152 "declared as '$parameterType'", |
2130 "must be a '$parameterType'." | 2153 "but argument is '$argumentType'." |
2131 ]; | 2154 ]; |
2132 } | 2155 } |
2133 } | 2156 } |
2134 | 2157 |
2135 class _TypeConstraintFromReturnType extends _TypeConstraintOrigin { | 2158 class _TypeConstraintFromReturnType extends _TypeConstraintOrigin { |
2136 final DartType contextType; | 2159 final DartType contextType; |
2137 final DartType declaredType; | 2160 final DartType declaredType; |
2138 | 2161 |
2139 _TypeConstraintFromReturnType(this.declaredType, this.contextType); | 2162 _TypeConstraintFromReturnType(this.declaredType, this.contextType); |
2140 | 2163 |
2141 @override | 2164 @override |
2142 formatError() { | 2165 formatError() { |
2143 return [ | 2166 return [ |
2144 "Return type", | 2167 "Return type", |
2145 "declared as '$declaredType'", | 2168 "declared as '$declaredType'", |
2146 "used where a '$contextType' is required." | 2169 "used where '$contextType' is required." |
2147 ]; | 2170 ]; |
2148 } | 2171 } |
2149 } | 2172 } |
| 2173 |
| 2174 class _TypeConstraintFromFunctionContext extends _TypeConstraintOrigin { |
| 2175 final DartType contextType; |
| 2176 final DartType functionType; |
| 2177 |
| 2178 _TypeConstraintFromFunctionContext(this.functionType, this.contextType); |
| 2179 |
| 2180 @override |
| 2181 formatError() { |
| 2182 return [ |
| 2183 "Function type", |
| 2184 "declared as '$functionType'", |
| 2185 "used where '$contextType' is required." |
| 2186 ]; |
| 2187 } |
| 2188 } |
2150 | 2189 |
2151 class _TypeConstraintFromExtendsClause extends _TypeConstraintOrigin { | 2190 class _TypeConstraintFromExtendsClause extends _TypeConstraintOrigin { |
2152 final TypeParameterType typeParam; | 2191 final TypeParameterType typeParam; |
2153 final DartType extendsType; | 2192 final DartType extendsType; |
2154 | 2193 |
2155 _TypeConstraintFromExtendsClause(this.typeParam, this.extendsType); | 2194 _TypeConstraintFromExtendsClause(this.typeParam, this.extendsType); |
2156 | 2195 |
2157 @override | 2196 @override |
2158 formatError() { | 2197 formatError() { |
2159 return [ | 2198 return [ |
2160 "Type parameter '$typeParam'", | 2199 "Type parameter '$typeParam'", |
2161 "declared to extend '$extendsType'.", | 2200 "declared to extend '$extendsType'." |
2162 "" | |
2163 ]; | 2201 ]; |
2164 } | 2202 } |
2165 } | 2203 } |
2166 | 2204 |
2167 class _TypeRange { | 2205 class _TypeRange { |
2168 /// The upper bound of the type parameter. In other words, T <: upperBound. | 2206 /// The upper bound of the type parameter. In other words, T <: upperBound. |
2169 /// | 2207 /// |
2170 /// In Dart this can be written as `<T extends UpperBoundType>`. | 2208 /// In Dart this can be written as `<T extends UpperBoundType>`. |
2171 /// | 2209 /// |
2172 /// In inference, this can happen as a result of parameters of function type. | 2210 /// In inference, this can happen as a result of parameters of function type. |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2332 if (type is InterfaceTypeImpl) { | 2370 if (type is InterfaceTypeImpl) { |
2333 return type.typeArguments.any(isUnknown); | 2371 return type.typeArguments.any(isUnknown); |
2334 } | 2372 } |
2335 if (type is FunctionType) { | 2373 if (type is FunctionType) { |
2336 return isUnknown(type.returnType) || | 2374 return isUnknown(type.returnType) || |
2337 type.parameters.any((p) => isUnknown(p.type)); | 2375 type.parameters.any((p) => isUnknown(p.type)); |
2338 } | 2376 } |
2339 return false; | 2377 return false; |
2340 } | 2378 } |
2341 } | 2379 } |
OLD | NEW |