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/token.dart' show TokenType; | 11 import 'package:analyzer/dart/ast/token.dart' show TokenType; |
11 import 'package:analyzer/dart/element/element.dart'; | 12 import 'package:analyzer/dart/element/element.dart'; |
12 import 'package:analyzer/dart/element/type.dart'; | 13 import 'package:analyzer/dart/element/type.dart'; |
13 import 'package:analyzer/src/dart/element/element.dart'; | 14 import 'package:analyzer/src/dart/element/element.dart'; |
14 import 'package:analyzer/src/dart/element/type.dart'; | 15 import 'package:analyzer/src/dart/element/type.dart'; |
15 import 'package:analyzer/src/generated/engine.dart' | 16 import 'package:analyzer/src/generated/engine.dart' |
16 show AnalysisContext, AnalysisOptionsImpl; | 17 show AnalysisContext, AnalysisOptionsImpl; |
| 18 import 'package:analyzer/src/generated/error.dart' |
| 19 show ErrorCode, ErrorReporter, StrongModeCode; |
17 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; | 20 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; |
18 import 'package:analyzer/src/generated/utilities_dart.dart' show ParameterKind; | 21 import 'package:analyzer/src/generated/utilities_dart.dart' show ParameterKind; |
19 import 'package:analyzer/src/generated/utilities_general.dart' | 22 import 'package:analyzer/src/generated/utilities_general.dart' |
20 show JenkinsSmiHash; | 23 show JenkinsSmiHash; |
21 | 24 |
22 typedef bool _GuardedSubtypeChecker<T>(T t1, T t2, Set<Element> visited); | 25 typedef bool _GuardedSubtypeChecker<T>(T t1, T t2, Set<Element> visited); |
23 | 26 |
24 /** | 27 /** |
25 * Implementation of [TypeSystem] using the strong mode rules. | 28 * Implementation of [TypeSystem] using the strong mode rules. |
26 * https://github.com/dart-lang/dev_compiler/blob/master/STRONG_MODE.md | 29 * https://github.com/dart-lang/dev_compiler/blob/master/STRONG_MODE.md |
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
241 | 244 |
242 // Try to infer and instantiate the resulting type. | 245 // Try to infer and instantiate the resulting type. |
243 var resultType = inferringTypeSystem._infer(fnType); | 246 var resultType = inferringTypeSystem._infer(fnType); |
244 | 247 |
245 // If the instantiation failed (because some type variable constraints | 248 // If the instantiation failed (because some type variable constraints |
246 // could not be solved, in other words, we could not find a valid subtype), | 249 // could not be solved, in other words, we could not find a valid subtype), |
247 // then return the original type, so the error is in terms of it. | 250 // then return the original type, so the error is in terms of it. |
248 // | 251 // |
249 // It would be safe to return a partial solution here, but the user | 252 // It would be safe to return a partial solution here, but the user |
250 // experience may be better if we simply do not infer in this case. | 253 // experience may be better if we simply do not infer in this case. |
| 254 // |
| 255 // TODO(jmesserly): this heuristic is old. Maybe we should we issue the |
| 256 // inference error? |
251 return resultType ?? fnType; | 257 return resultType ?? fnType; |
252 } | 258 } |
253 | 259 |
254 /// Given a function type with generic type parameters, infer the type | 260 /// Given a function type with generic type parameters, infer the type |
255 /// parameters from the actual argument types, and return the instantiated | 261 /// parameters from the actual argument types, and return the instantiated |
256 /// function type. If we can't, returns the original function type. | 262 /// function type. If we can't, returns the original function type. |
257 /// | 263 /// |
258 /// Concretely, given a function type with parameter types P0, P1, ... Pn, | 264 /// Concretely, given a function type with parameter types P0, P1, ... Pn, |
259 /// result type R, and generic type parameters T0, T1, ... Tm, use the | 265 /// result type R, and generic type parameters T0, T1, ... Tm, use the |
260 /// argument types A0, A1, ... An to solve for the type parameters. | 266 /// argument types A0, A1, ... An to solve for the type parameters. |
261 /// | 267 /// |
262 /// For each parameter Pi, we want to ensure that Ai <: Pi. We can do this by | 268 /// For each parameter Pi, we want to ensure that Ai <: Pi. We can do this by |
263 /// running the subtype algorithm, and when we reach a type parameter Tj, | 269 /// running the subtype algorithm, and when we reach a type parameter Tj, |
264 /// recording the lower or upper bound it must satisfy. At the end, all | 270 /// recording the lower or upper bound it must satisfy. At the end, all |
265 /// constraints can be combined to determine the type. | 271 /// constraints can be combined to determine the type. |
266 /// | 272 /// |
267 /// As a simplification, we do not actually store all constraints on each type | 273 /// As a simplification, we do not actually store all constraints on each type |
268 /// parameter Tj. Instead we track Uj and Lj where U is the upper bound and | 274 /// parameter Tj. Instead we track Uj and Lj where U is the upper bound and |
269 /// L is the lower bound of that type parameter. | 275 /// L is the lower bound of that type parameter. |
270 FunctionType inferGenericFunctionCall( | 276 FunctionType inferGenericFunctionCall( |
271 TypeProvider typeProvider, | 277 TypeProvider typeProvider, |
272 FunctionType fnType, | 278 FunctionType fnType, |
273 List<DartType> correspondingParameterTypes, | 279 List<DartType> correspondingParameterTypes, |
274 List<DartType> argumentTypes, | 280 List<DartType> argumentTypes, |
275 DartType returnContextType) { | 281 DartType returnContextType, |
| 282 {ErrorReporter errorReporter, |
| 283 AstNode errorNode}) { |
276 if (fnType.typeFormals.isEmpty) { | 284 if (fnType.typeFormals.isEmpty) { |
277 return fnType; | 285 return fnType; |
278 } | 286 } |
279 | 287 |
280 // If we're in a future union context, choose either the Future<T> or the T | 288 // If we're in a future union context, choose either the Future<T> or the T |
281 // based on the function's return type. | 289 // based on the function's return type. |
282 if (returnContextType is FutureUnionType) { | 290 if (returnContextType is FutureUnionType) { |
283 var futureUnion = returnContextType as FutureUnionType; | 291 var futureUnion = returnContextType as FutureUnionType; |
284 returnContextType = | 292 returnContextType = |
285 isSubtypeOf(fnType.returnType, typeProvider.futureDynamicType) | 293 isSubtypeOf(fnType.returnType, typeProvider.futureDynamicType) |
(...skipping 12 matching lines...) Expand all Loading... |
298 inferringTypeSystem.isSubtypeOf(fnType.returnType, returnContextType); | 306 inferringTypeSystem.isSubtypeOf(fnType.returnType, returnContextType); |
299 } | 307 } |
300 | 308 |
301 for (int i = 0; i < argumentTypes.length; i++) { | 309 for (int i = 0; i < argumentTypes.length; i++) { |
302 // Try to pass each argument to each parameter, recording any type | 310 // Try to pass each argument to each parameter, recording any type |
303 // parameter bounds that were implied by this assignment. | 311 // parameter bounds that were implied by this assignment. |
304 inferringTypeSystem.isSubtypeOf( | 312 inferringTypeSystem.isSubtypeOf( |
305 argumentTypes[i], correspondingParameterTypes[i]); | 313 argumentTypes[i], correspondingParameterTypes[i]); |
306 } | 314 } |
307 | 315 |
308 return inferringTypeSystem._infer(fnType); | 316 return inferringTypeSystem._infer(fnType, errorReporter, errorNode); |
309 } | 317 } |
310 | 318 |
311 /** | 319 /** |
312 * Given a [DartType] [type], if [type] is an uninstantiated | 320 * Given a [DartType] [type], if [type] is an uninstantiated |
313 * parameterized type then instantiate the parameters to their | 321 * parameterized type then instantiate the parameters to their |
314 * bounds. Specifically, if [type] is of the form | 322 * bounds. Specifically, if [type] is of the form |
315 * `<T0 extends B0, ... Tn extends Bn>.F` or | 323 * `<T0 extends B0, ... Tn extends Bn>.F` or |
316 * `class C<T0 extends B0, ... Tn extends Bn> {...}` | 324 * `class C<T0 extends B0, ... Tn extends Bn> {...}` |
317 * (where Bi is implicitly dynamic if absent), | 325 * (where Bi is implicitly dynamic if absent), |
318 * compute `{I0/T0, ..., In/Tn}F or C<I0, ..., In>` respectively | 326 * compute `{I0/T0, ..., In/Tn}F or C<I0, ..., In>` respectively |
(...skipping 1045 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1364 final StrongTypeSystemImpl _typeSystem; | 1372 final StrongTypeSystemImpl _typeSystem; |
1365 final Map<TypeParameterType, _TypeParameterBound> _bounds; | 1373 final Map<TypeParameterType, _TypeParameterBound> _bounds; |
1366 | 1374 |
1367 _StrongInferenceTypeSystem(this._typeProvider, this._typeSystem, | 1375 _StrongInferenceTypeSystem(this._typeProvider, this._typeSystem, |
1368 Iterable<TypeParameterElement> typeFormals) | 1376 Iterable<TypeParameterElement> typeFormals) |
1369 : _bounds = new Map.fromIterable(typeFormals, | 1377 : _bounds = new Map.fromIterable(typeFormals, |
1370 key: (t) => t.type, value: (t) => new _TypeParameterBound()); | 1378 key: (t) => t.type, value: (t) => new _TypeParameterBound()); |
1371 | 1379 |
1372 /// Given the constraints that were given by calling [isSubtypeOf], find the | 1380 /// Given the constraints that were given by calling [isSubtypeOf], find the |
1373 /// instantiation of the generic function that satisfies these constraints. | 1381 /// instantiation of the generic function that satisfies these constraints. |
1374 FunctionType _infer(FunctionType fnType) { | 1382 FunctionType _infer(FunctionType fnType, |
| 1383 [ErrorReporter errorReporter, AstNode errorNode]) { |
1375 List<TypeParameterType> fnTypeParams = | 1384 List<TypeParameterType> fnTypeParams = |
1376 TypeParameterTypeImpl.getTypes(fnType.typeFormals); | 1385 TypeParameterTypeImpl.getTypes(fnType.typeFormals); |
1377 | 1386 |
1378 // Initialize the inferred type array. | 1387 // Initialize the inferred type array. |
1379 // | 1388 // |
1380 // They all start as `dynamic` to offer reasonable degradation for f-bounded | 1389 // They all start as `dynamic` to offer reasonable degradation for f-bounded |
1381 // type parameters. | 1390 // type parameters. |
1382 var inferredTypes = new List<DartType>.filled( | 1391 var inferredTypes = new List<DartType>.filled( |
1383 fnTypeParams.length, DynamicTypeImpl.instance, | 1392 fnTypeParams.length, DynamicTypeImpl.instance, |
1384 growable: false); | 1393 growable: false); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1416 // if the type parameter occurs in covariant or contravariant positions. | 1425 // if the type parameter occurs in covariant or contravariant positions. |
1417 // | 1426 // |
1418 // If the type is "passed in" at all, or if our lower bound was bottom, | 1427 // If the type is "passed in" at all, or if our lower bound was bottom, |
1419 // we choose the upper bound as being the most useful. | 1428 // we choose the upper bound as being the most useful. |
1420 // | 1429 // |
1421 // Otherwise we choose the more precise lower bound. | 1430 // Otherwise we choose the more precise lower bound. |
1422 _TypeParameterVariance variance = | 1431 _TypeParameterVariance variance = |
1423 new _TypeParameterVariance.from(typeParam, fnType.returnType); | 1432 new _TypeParameterVariance.from(typeParam, fnType.returnType); |
1424 | 1433 |
1425 _TypeParameterBound bound = _bounds[typeParam]; | 1434 _TypeParameterBound bound = _bounds[typeParam]; |
1426 inferredTypes[i] = | 1435 DartType lowerBound = bound.lower; |
1427 variance.passedIn || bound.lower.isBottom ? bound.upper : bound.lower; | 1436 DartType upperBound = bound.upper; |
1428 | 1437 |
1429 // See if the bounds can be satisfied. | 1438 // See if the bounds can be satisfied. |
1430 if (bound.upper.isBottom || | 1439 // TODO(jmesserly): also we should have an error for unconstrained type |
1431 !_typeSystem.isSubtypeOf(bound.lower, bound.upper)) { | 1440 // parameters, rather than silently inferring dynamic. |
1432 // Inference failed. Bail. | 1441 if (upperBound.isBottom || |
1433 return null; | 1442 !_typeSystem.isSubtypeOf(lowerBound, upperBound)) { |
| 1443 // Inference failed. |
| 1444 if (errorReporter == null) { |
| 1445 return null; |
| 1446 } |
| 1447 errorReporter.reportErrorForNode(StrongModeCode.COULD_NOT_INFER, |
| 1448 errorNode, [typeParam, lowerBound, upperBound]); |
| 1449 |
| 1450 // To make the errors more useful, we swap the normal heuristic. |
| 1451 // |
| 1452 // The normal heuristic prefers using the argument types (upwards |
| 1453 // inference, lower bound) to choose a tighter type. |
| 1454 // |
| 1455 // Here we want to prefer the return context type, so we can put the |
| 1456 // blame on the arguments to the function. That will result in narrow |
| 1457 // error spans. But ultimately it's just a heuristic, as the code is |
| 1458 // already erroneous. |
| 1459 // |
| 1460 // (we may adjust the normal heuristic too, once upwards+downwards |
| 1461 // inference are fully integrated, to prefer downwards info). |
| 1462 lowerBound = bound.upper; |
| 1463 upperBound = bound.lower; |
1434 } | 1464 } |
| 1465 |
| 1466 inferredTypes[i] = |
| 1467 variance.passedIn || lowerBound.isBottom ? upperBound : lowerBound; |
1435 } | 1468 } |
1436 | 1469 |
1437 // Return the instantiated type. | 1470 // Return the instantiated type. |
1438 return fnType.instantiate(inferredTypes); | 1471 return fnType.instantiate(inferredTypes); |
1439 } | 1472 } |
1440 | 1473 |
1441 @override | 1474 @override |
1442 bool _inferTypeParameterSubtypeOf( | 1475 bool _inferTypeParameterSubtypeOf( |
1443 DartType t1, DartType t2, Set<Element> visited) { | 1476 DartType t1, DartType t2, Set<Element> visited) { |
1444 if (t1 is TypeParameterType) { | 1477 if (t1 is TypeParameterType) { |
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1698 } | 1731 } |
1699 | 1732 |
1700 bool _isBottom(DartType t, {bool dynamicIsBottom: false}) { | 1733 bool _isBottom(DartType t, {bool dynamicIsBottom: false}) { |
1701 return (t.isDynamic && dynamicIsBottom) || t.isBottom; | 1734 return (t.isDynamic && dynamicIsBottom) || t.isBottom; |
1702 } | 1735 } |
1703 | 1736 |
1704 bool _isTop(DartType t, {bool dynamicIsBottom: false}) { | 1737 bool _isTop(DartType t, {bool dynamicIsBottom: false}) { |
1705 // TODO(leafp): Document the rules in play here | 1738 // TODO(leafp): Document the rules in play here |
1706 return (t.isDynamic && !dynamicIsBottom) || t.isObject; | 1739 return (t.isDynamic && !dynamicIsBottom) || t.isObject; |
1707 } | 1740 } |
OLD | NEW |