| 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 479 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 490 bool isNonNullableType(DartType type) { | 490 bool isNonNullableType(DartType type) { |
| 491 return !isNullableType(type); | 491 return !isNullableType(type); |
| 492 } | 492 } |
| 493 | 493 |
| 494 /// Opposite of [isNonNullableType]. | 494 /// Opposite of [isNonNullableType]. |
| 495 bool isNullableType(DartType type) { | 495 bool isNullableType(DartType type) { |
| 496 return type is FunctionType || | 496 return type is FunctionType || |
| 497 !nonnullableTypes.contains(_getTypeFullyQualifiedName(type)); | 497 !nonnullableTypes.contains(_getTypeFullyQualifiedName(type)); |
| 498 } | 498 } |
| 499 | 499 |
| 500 /// Check that [f1] is a subtype of [f2] for an override. | 500 /// Check that [f1] is a subtype of [f2] for a member override. |
| 501 /// | 501 /// |
| 502 /// This is different from the normal function subtyping in two ways: | 502 /// This is different from the normal function subtyping in two ways: |
| 503 /// - we know the function types are strict arrows, | 503 /// - we know the function types are strict arrows, |
| 504 /// - it allows opt-in covariant parameters. | 504 /// - it allows opt-in covariant parameters. |
| 505 bool isOverrideSubtypeOf(FunctionType f1, FunctionType f2) { | 505 bool isOverrideSubtypeOf(FunctionType f1, FunctionType f2) { |
| 506 return FunctionTypeImpl.relate( | 506 return FunctionTypeImpl.relate(f1, f2, isSubtypeOf, instantiateToBounds, |
| 507 f1, | 507 parameterRelation: isOverrideSubtypeOfParameter); |
| 508 f2, | 508 } |
| 509 (t1, t2, t1Covariant, _) => | 509 |
| 510 isSubtypeOf(t2, t1) || t1Covariant && isSubtypeOf(t1, t2), | 510 /// Check that parameter [p2] is a subtype of [p1], given that we are |
| 511 instantiateToBounds, | 511 /// checking `f1 <: f2` where `p1` is a parameter of `f1` and `p2` is a |
| 512 returnRelation: isSubtypeOf); | 512 /// parameter of `f2`. |
| 513 /// |
| 514 /// Parameters are contravariant, so we must check `p2 <: p1` to |
| 515 /// determine if `f1 <: f2`. This is used by [isOverrideSubtypeOf]. |
| 516 bool isOverrideSubtypeOfParameter(ParameterElement p1, ParameterElement p2) { |
| 517 return isSubtypeOf(p2.type, p1.type) || |
| 518 p1.isCovariant && isSubtypeOf(p1.type, p2.type); |
| 513 } | 519 } |
| 514 | 520 |
| 515 @override | 521 @override |
| 516 bool isSubtypeOf(DartType leftType, DartType rightType) { | 522 bool isSubtypeOf(DartType leftType, DartType rightType) { |
| 517 return _isSubtypeOf(leftType, rightType, null); | 523 return _isSubtypeOf(leftType, rightType, null); |
| 518 } | 524 } |
| 519 | 525 |
| 520 /// Given a [type] T that may have an unknown type `?`, returns a type | 526 /// Given a [type] T that may have an unknown type `?`, returns a type |
| 521 /// R such that R <: T for any type substituted for `?`. | 527 /// R such that R <: T for any type substituted for `?`. |
| 522 /// | 528 /// |
| (...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 782 return InterfaceTypeImpl.computeLeastUpperBound(type1, type2) ?? | 788 return InterfaceTypeImpl.computeLeastUpperBound(type1, type2) ?? |
| 783 typeProvider.dynamicType; | 789 typeProvider.dynamicType; |
| 784 } | 790 } |
| 785 | 791 |
| 786 /// Check that [f1] is a subtype of [f2]. | 792 /// Check that [f1] is a subtype of [f2]. |
| 787 /// | 793 /// |
| 788 /// This will always assume function types use fuzzy arrows, in other words | 794 /// This will always assume function types use fuzzy arrows, in other words |
| 789 /// that dynamic parameters of f1 and f2 are treated as bottom. | 795 /// that dynamic parameters of f1 and f2 are treated as bottom. |
| 790 bool _isFunctionSubtypeOf( | 796 bool _isFunctionSubtypeOf( |
| 791 FunctionType f1, FunctionType f2, Set<TypeImpl> visitedTypes) { | 797 FunctionType f1, FunctionType f2, Set<TypeImpl> visitedTypes) { |
| 792 return FunctionTypeImpl.relate( | 798 return FunctionTypeImpl.relate(f1, f2, isSubtypeOf, instantiateToBounds, |
| 793 f1, | 799 parameterRelation: (p1, p2) => _isSubtypeOf( |
| 794 f2, | 800 p2.type, p1.type, visitedTypes, |
| 795 (t1, t2, _, __) => | 801 dynamicIsBottom: true)); |
| 796 _isSubtypeOf(t2, t1, visitedTypes, dynamicIsBottom: true), | |
| 797 instantiateToBounds, | |
| 798 returnRelation: isSubtypeOf); | |
| 799 } | 802 } |
| 800 | 803 |
| 801 bool _isInterfaceSubtypeOf( | 804 bool _isInterfaceSubtypeOf( |
| 802 InterfaceType i1, InterfaceType i2, Set<TypeImpl> visitedTypes) { | 805 InterfaceType i1, InterfaceType i2, Set<TypeImpl> visitedTypes) { |
| 803 if (identical(i1, i2)) { | 806 if (identical(i1, i2)) { |
| 804 return true; | 807 return true; |
| 805 } | 808 } |
| 806 | 809 |
| 807 // Guard recursive calls | 810 // Guard recursive calls |
| 808 _GuardedSubtypeChecker<InterfaceType> guardedInterfaceSubtype = _guard( | 811 _GuardedSubtypeChecker<InterfaceType> guardedInterfaceSubtype = _guard( |
| (...skipping 1360 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2169 // which is a super type of the function type. | 2172 // which is a super type of the function type. |
| 2170 if (t1 is InterfaceType) { | 2173 if (t1 is InterfaceType) { |
| 2171 t1 = _typeSystem.getCallMethodDefiniteType(t1); | 2174 t1 = _typeSystem.getCallMethodDefiniteType(t1); |
| 2172 if (t1 == null) return; | 2175 if (t1 == null) return; |
| 2173 } | 2176 } |
| 2174 | 2177 |
| 2175 if (t1 is FunctionType && t2 is FunctionType) { | 2178 if (t1 is FunctionType && t2 is FunctionType) { |
| 2176 FunctionTypeImpl.relate( | 2179 FunctionTypeImpl.relate( |
| 2177 t1, | 2180 t1, |
| 2178 t2, | 2181 t2, |
| 2179 (t1, t2, _, __) { | 2182 (t1, t2) { |
| 2180 _matchSubtypeOf(t2, t1, null, origin, | 2183 // TODO(jmesserly): should we flip covariance when we're relating |
| 2181 covariant: !covariant, dynamicIsBottom: true); | 2184 // type formal bounds? They're more like parameters. |
| 2185 matchSubtype(t1, t2); |
| 2182 return true; | 2186 return true; |
| 2183 }, | 2187 }, |
| 2184 _typeSystem.instantiateToBounds, | 2188 _typeSystem.instantiateToBounds, |
| 2185 returnRelation: (t1, t2) { | 2189 parameterRelation: (p1, p2) { |
| 2186 matchSubtype(t1, t2); | 2190 _matchSubtypeOf(p2.type, p1.type, null, origin, |
| 2191 covariant: !covariant, dynamicIsBottom: true); |
| 2187 return true; | 2192 return true; |
| 2188 }); | 2193 }); |
| 2189 } | 2194 } |
| 2190 } | 2195 } |
| 2191 | 2196 |
| 2192 static String _formatConstraints(Iterable<_TypeConstraint> constraints) { | 2197 static String _formatConstraints(Iterable<_TypeConstraint> constraints) { |
| 2193 List<List<String>> lineParts = | 2198 List<List<String>> lineParts = |
| 2194 new Set<_TypeConstraintOrigin>.from(constraints.map((c) => c.origin)) | 2199 new Set<_TypeConstraintOrigin>.from(constraints.map((c) => c.origin)) |
| 2195 .map((o) => o.formatError()) | 2200 .map((o) => o.formatError()) |
| 2196 .toList(); | 2201 .toList(); |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2374 /// Combining these constraints results in a lower bound of `num`. | 2379 /// Combining these constraints results in a lower bound of `num`. |
| 2375 /// | 2380 /// |
| 2376 /// In general, we choose the lower bound as our inferred type, so we can | 2381 /// In general, we choose the lower bound as our inferred type, so we can |
| 2377 /// offer the most constrained (strongest) result type. | 2382 /// offer the most constrained (strongest) result type. |
| 2378 final DartType lowerBound; | 2383 final DartType lowerBound; |
| 2379 | 2384 |
| 2380 _TypeRange({DartType lower, DartType upper}) | 2385 _TypeRange({DartType lower, DartType upper}) |
| 2381 : lowerBound = lower ?? UnknownInferredType.instance, | 2386 : lowerBound = lower ?? UnknownInferredType.instance, |
| 2382 upperBound = upper ?? UnknownInferredType.instance; | 2387 upperBound = upper ?? UnknownInferredType.instance; |
| 2383 } | 2388 } |
| OLD | NEW |