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 345 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
356 | 356 |
357 // Since we're trying to infer the instantiation, we want to ignore type | 357 // Since we're trying to infer the instantiation, we want to ignore type |
358 // formals as we check the parameters and return type. | 358 // formals as we check the parameters and return type. |
359 var inferFnType = | 359 var inferFnType = |
360 fnType.instantiate(TypeParameterTypeImpl.getTypes(fnType.typeFormals)); | 360 fnType.instantiate(TypeParameterTypeImpl.getTypes(fnType.typeFormals)); |
361 if (!inferringTypeSystem.isSubtypeOf(inferFnType, contextType)) { | 361 if (!inferringTypeSystem.isSubtypeOf(inferFnType, contextType)) { |
362 return fnType; | 362 return fnType; |
363 } | 363 } |
364 | 364 |
365 // Try to infer and instantiate the resulting type. | 365 // Try to infer and instantiate the resulting type. |
366 var resultType = inferringTypeSystem._infer(fnType); | 366 var resultType = inferringTypeSystem._infer( |
367 fnType, fnType.typeFormals, fnType.returnType); | |
367 | 368 |
368 // If the instantiation failed (because some type variable constraints | 369 // If the instantiation failed (because some type variable constraints |
369 // could not be solved, in other words, we could not find a valid subtype), | 370 // could not be solved, in other words, we could not find a valid subtype), |
370 // then return the original type, so the error is in terms of it. | 371 // then return the original type, so the error is in terms of it. |
371 // | 372 // |
372 // It would be safe to return a partial solution here, but the user | 373 // It would be safe to return a partial solution here, but the user |
373 // experience may be better if we simply do not infer in this case. | 374 // experience may be better if we simply do not infer in this case. |
374 // | 375 // |
375 // TODO(jmesserly): this heuristic is old. Maybe we should we issue the | 376 // TODO(jmesserly): this heuristic is old. Maybe we should we issue the |
376 // inference error? | 377 // inference error? |
377 return resultType ?? fnType; | 378 return resultType ?? fnType; |
378 } | 379 } |
379 | 380 |
380 /// Given a function type with generic type parameters, infer the type | 381 /// Given a function type with generic type parameters, infer the type |
381 /// parameters from the actual argument types, and return the instantiated | 382 /// parameters from the actual argument types, and return the instantiated |
382 /// function type. If we can't, returns the original function type. | 383 /// function type. If we can't, returns the original function type. |
383 /// | 384 /// |
384 /// Concretely, given a function type with parameter types P0, P1, ... Pn, | 385 /// Concretely, given a function type with parameter types P0, P1, ... Pn, |
385 /// result type R, and generic type parameters T0, T1, ... Tm, use the | 386 /// result type R, and generic type parameters T0, T1, ... Tm, use the |
386 /// argument types A0, A1, ... An to solve for the type parameters. | 387 /// argument types A0, A1, ... An to solve for the type parameters. |
387 /// | 388 /// |
388 /// For each parameter Pi, we want to ensure that Ai <: Pi. We can do this by | 389 /// For each parameter Pi, we want to ensure that Ai <: Pi. We can do this by |
389 /// running the subtype algorithm, and when we reach a type parameter Tj, | 390 /// running the subtype algorithm, and when we reach a type parameter Tj, |
390 /// recording the lower or upper bound it must satisfy. At the end, all | 391 /// recording the lower or upper bound it must satisfy. At the end, all |
391 /// constraints can be combined to determine the type. | 392 /// constraints can be combined to determine the type. |
392 /// | 393 /// |
393 /// As a simplification, we do not actually store all constraints on each type | 394 /// As a simplification, we do not actually store all constraints on each type |
394 /// parameter Tj. Instead we track Uj and Lj where U is the upper bound and | 395 /// parameter Tj. Instead we track Uj and Lj where U is the upper bound and |
395 /// L is the lower bound of that type parameter. | 396 /// L is the lower bound of that type parameter. |
396 FunctionType inferGenericFunctionCall( | 397 /*=T*/ inferGenericFunctionCall/*<T extends ParameterizedType>*/( |
397 TypeProvider typeProvider, | 398 TypeProvider typeProvider, |
398 FunctionType fnType, | 399 /*=T*/ genericType, |
399 List<DartType> correspondingParameterTypes, | 400 List<DartType> declaredParameterTypes, |
400 List<DartType> argumentTypes, | 401 List<DartType> argumentTypes, |
402 DartType declaredReturnType, | |
401 DartType returnContextType, | 403 DartType returnContextType, |
402 {ErrorReporter errorReporter, | 404 {ErrorReporter errorReporter, |
403 AstNode errorNode}) { | 405 AstNode errorNode}) { |
404 if (fnType.typeFormals.isEmpty) { | 406 // TODO(jmesserly): expose typeFormals on ParameterizedType. |
405 return fnType; | 407 List<TypeParameterElement> typeFormals = genericType is FunctionType |
406 } | 408 ? genericType.typeFormals |
407 | 409 : genericType.typeParameters; |
408 // If we're in a future union context, choose either the Future<T> or the T | 410 if (typeFormals.isEmpty) { |
409 // based on the function's return type. | 411 return genericType; |
410 if (returnContextType is FutureUnionType) { | |
411 var futureUnion = returnContextType as FutureUnionType; | |
412 returnContextType = | |
413 isSubtypeOf(fnType.returnType, typeProvider.futureDynamicType) | |
414 ? futureUnion.futureOfType | |
415 : futureUnion.type; | |
416 } | 412 } |
417 | 413 |
418 // Create a TypeSystem that will allow certain type parameters to be | 414 // Create a TypeSystem that will allow certain type parameters to be |
419 // inferred. It will optimistically assume these type parameters can be | 415 // inferred. It will optimistically assume these type parameters can be |
420 // subtypes (or supertypes) as necessary, and track the constraints that | 416 // subtypes (or supertypes) as necessary, and track the constraints that |
421 // are implied by this. | 417 // are implied by this. |
422 var inferringTypeSystem = | 418 var inferringTypeSystem = |
423 new _StrongInferenceTypeSystem(typeProvider, this, fnType.typeFormals); | 419 new _StrongInferenceTypeSystem(typeProvider, this, typeFormals); |
424 | 420 |
425 if (returnContextType != null) { | 421 if (returnContextType != null) { |
426 inferringTypeSystem.isSubtypeOf(fnType.returnType, returnContextType); | 422 // If we're in a future union context, choose either the Future<T> |
423 // or the T based on the declared return type. | |
424 if (returnContextType is FutureUnionType) { | |
425 var futureUnion = returnContextType as FutureUnionType; | |
426 returnContextType = | |
427 isSubtypeOf(declaredReturnType, typeProvider.futureDynamicType) | |
428 ? futureUnion.futureOfType | |
429 : futureUnion.type; | |
430 } | |
431 | |
432 inferringTypeSystem.isSubtypeOf(declaredReturnType, returnContextType); | |
427 } | 433 } |
428 | 434 |
429 for (int i = 0; i < argumentTypes.length; i++) { | 435 for (int i = 0; i < argumentTypes.length; i++) { |
430 // Try to pass each argument to each parameter, recording any type | 436 // Try to pass each argument to each parameter, recording any type |
431 // parameter bounds that were implied by this assignment. | 437 // parameter bounds that were implied by this assignment. |
432 inferringTypeSystem.isSubtypeOf( | 438 inferringTypeSystem.isSubtypeOf( |
433 argumentTypes[i], correspondingParameterTypes[i]); | 439 argumentTypes[i], declaredParameterTypes[i]); |
434 } | 440 } |
435 | 441 |
436 return inferringTypeSystem._infer(fnType, errorReporter, errorNode); | 442 return inferringTypeSystem._infer( |
443 genericType, typeFormals, declaredReturnType, errorReporter, errorNode); | |
437 } | 444 } |
438 | 445 |
439 /** | 446 /** |
440 * Given a [DartType] [type], if [type] is an uninstantiated | 447 * Given a [DartType] [type], if [type] is an uninstantiated |
441 * parameterized type then instantiate the parameters to their | 448 * parameterized type then instantiate the parameters to their |
442 * bounds. Specifically, if [type] is of the form | 449 * bounds. Specifically, if [type] is of the form |
443 * `<T0 extends B0, ... Tn extends Bn>.F` or | 450 * `<T0 extends B0, ... Tn extends Bn>.F` or |
444 * `class C<T0 extends B0, ... Tn extends Bn> {...}` | 451 * `class C<T0 extends B0, ... Tn extends Bn> {...}` |
445 * (where Bi is implicitly dynamic if absent), | 452 * (where Bi is implicitly dynamic if absent), |
446 * compute `{I0/T0, ..., In/Tn}F or C<I0, ..., In>` respectively | 453 * compute `{I0/T0, ..., In/Tn}F or C<I0, ..., In>` respectively |
(...skipping 1057 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1504 final StrongTypeSystemImpl _typeSystem; | 1511 final StrongTypeSystemImpl _typeSystem; |
1505 final Map<TypeParameterType, _TypeParameterBound> _bounds; | 1512 final Map<TypeParameterType, _TypeParameterBound> _bounds; |
1506 | 1513 |
1507 _StrongInferenceTypeSystem(this._typeProvider, this._typeSystem, | 1514 _StrongInferenceTypeSystem(this._typeProvider, this._typeSystem, |
1508 Iterable<TypeParameterElement> typeFormals) | 1515 Iterable<TypeParameterElement> typeFormals) |
1509 : _bounds = new Map.fromIterable(typeFormals, | 1516 : _bounds = new Map.fromIterable(typeFormals, |
1510 key: (t) => t.type, value: (t) => new _TypeParameterBound()); | 1517 key: (t) => t.type, value: (t) => new _TypeParameterBound()); |
1511 | 1518 |
1512 /// Given the constraints that were given by calling [isSubtypeOf], find the | 1519 /// Given the constraints that were given by calling [isSubtypeOf], find the |
1513 /// instantiation of the generic function that satisfies these constraints. | 1520 /// instantiation of the generic function that satisfies these constraints. |
1514 FunctionType _infer(FunctionType fnType, | 1521 /*=T*/ _infer/*<T extends ParameterizedType>*/(/*=T*/ genericType, |
1522 List<TypeParameterElement> typeFormals, DartType declaredReturnType, | |
1515 [ErrorReporter errorReporter, AstNode errorNode]) { | 1523 [ErrorReporter errorReporter, AstNode errorNode]) { |
1516 List<TypeParameterType> fnTypeParams = | 1524 List<TypeParameterType> fnTypeParams = |
1517 TypeParameterTypeImpl.getTypes(fnType.typeFormals); | 1525 TypeParameterTypeImpl.getTypes(typeFormals); |
1518 | 1526 |
1519 // Initialize the inferred type array. | 1527 // Initialize the inferred type array. |
1520 // | 1528 // |
1521 // They all start as `dynamic` to offer reasonable degradation for f-bounded | 1529 // They all start as `dynamic` to offer reasonable degradation for f-bounded |
1522 // type parameters. | 1530 // type parameters. |
1523 var inferredTypes = new List<DartType>.filled( | 1531 var inferredTypes = new List<DartType>.filled( |
1524 fnTypeParams.length, DynamicTypeImpl.instance, | 1532 fnTypeParams.length, DynamicTypeImpl.instance, |
1525 growable: false); | 1533 growable: false); |
1526 | 1534 |
1527 for (int i = 0; i < fnTypeParams.length; i++) { | 1535 for (int i = 0; i < fnTypeParams.length; i++) { |
(...skipping 26 matching lines...) Expand all Loading... | |
1554 // Now we've computed lower and upper bounds for each type parameter. | 1562 // Now we've computed lower and upper bounds for each type parameter. |
1555 // | 1563 // |
1556 // To decide on which type to assign, we look at the return type and see | 1564 // To decide on which type to assign, we look at the return type and see |
1557 // if the type parameter occurs in covariant or contravariant positions. | 1565 // if the type parameter occurs in covariant or contravariant positions. |
1558 // | 1566 // |
1559 // If the type is "passed in" at all, or if our lower bound was bottom, | 1567 // If the type is "passed in" at all, or if our lower bound was bottom, |
1560 // we choose the upper bound as being the most useful. | 1568 // we choose the upper bound as being the most useful. |
1561 // | 1569 // |
1562 // Otherwise we choose the more precise lower bound. | 1570 // Otherwise we choose the more precise lower bound. |
1563 _TypeParameterVariance variance = | 1571 _TypeParameterVariance variance = |
1564 new _TypeParameterVariance.from(typeParam, fnType.returnType); | 1572 new _TypeParameterVariance.from(typeParam, declaredReturnType); |
1565 | 1573 |
1566 _TypeParameterBound bound = _bounds[typeParam]; | 1574 _TypeParameterBound bound = _bounds[typeParam]; |
1567 DartType lowerBound = bound.lower; | 1575 DartType lowerBound = bound.lower; |
1568 DartType upperBound = bound.upper; | 1576 DartType upperBound = bound.upper; |
1569 | 1577 |
1570 // See if the bounds can be satisfied. | 1578 // See if the bounds can be satisfied. |
1571 // TODO(jmesserly): also we should have an error for unconstrained type | 1579 // TODO(jmesserly): also we should have an error for unconstrained type |
1572 // parameters, rather than silently inferring dynamic. | 1580 // parameters, rather than silently inferring dynamic. |
1573 if (upperBound.isBottom || | 1581 if (upperBound.isBottom || |
1574 !_typeSystem.isSubtypeOf(lowerBound, upperBound)) { | 1582 !_typeSystem.isSubtypeOf(lowerBound, upperBound)) { |
(...skipping 18 matching lines...) Expand all Loading... | |
1593 // inference are fully integrated, to prefer downwards info). | 1601 // inference are fully integrated, to prefer downwards info). |
1594 lowerBound = bound.upper; | 1602 lowerBound = bound.upper; |
1595 upperBound = bound.lower; | 1603 upperBound = bound.lower; |
1596 } | 1604 } |
1597 | 1605 |
1598 inferredTypes[i] = | 1606 inferredTypes[i] = |
1599 variance.passedIn || lowerBound.isBottom ? upperBound : lowerBound; | 1607 variance.passedIn || lowerBound.isBottom ? upperBound : lowerBound; |
1600 } | 1608 } |
1601 | 1609 |
1602 // Return the instantiated type. | 1610 // Return the instantiated type. |
1603 return fnType.instantiate(inferredTypes); | 1611 return genericType.instantiate(inferredTypes) as dynamic/*=T*/; |
Leaf
2016/09/14 23:11:35
Does this mean that .instantiate should have a bet
Jennifer Messerly
2016/09/14 23:18:41
Maybe something like:
abstract class Parameterize
| |
1604 } | 1612 } |
1605 | 1613 |
1606 @override | 1614 @override |
1607 bool _inferTypeParameterSubtypeOf( | 1615 bool _inferTypeParameterSubtypeOf( |
1608 DartType t1, DartType t2, Set<Element> visited) { | 1616 DartType t1, DartType t2, Set<Element> visited) { |
1609 if (t1 is TypeParameterType) { | 1617 if (t1 is TypeParameterType) { |
1610 _TypeParameterBound bound = _bounds[t1]; | 1618 _TypeParameterBound bound = _bounds[t1]; |
1611 if (bound != null) { | 1619 if (bound != null) { |
1612 // Ensure T1 <: T2, where T1 is a type parameter we are inferring. | 1620 // Ensure T1 <: T2, where T1 is a type parameter we are inferring. |
1613 // T2 is an upper bound, so merge it with our existing upper bound. | 1621 // T2 is an upper bound, so merge it with our existing upper bound. |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1743 } else { | 1751 } else { |
1744 passedOut = true; | 1752 passedOut = true; |
1745 } | 1753 } |
1746 } else if (type is FunctionType) { | 1754 } else if (type is FunctionType) { |
1747 _visitFunctionType(typeParam, type, paramIn); | 1755 _visitFunctionType(typeParam, type, paramIn); |
1748 } else if (type is InterfaceType) { | 1756 } else if (type is InterfaceType) { |
1749 _visitInterfaceType(typeParam, type, paramIn); | 1757 _visitInterfaceType(typeParam, type, paramIn); |
1750 } | 1758 } |
1751 } | 1759 } |
1752 } | 1760 } |
OLD | NEW |