|
5 | 5 | import '../flow_analysis/flow_analysis_operations.dart'; |
6 | 6 | import '../types/shared_type.dart'; |
7 | 7 | import 'nullability_suffix.dart'; |
| 8 | +import 'type_constraint.dart'; |
8 | 9 |
|
9 | 10 | /// Callback API used by the shared type analyzer to query and manipulate the |
10 | 11 | /// client's representation of variables and types. |
@@ -698,6 +699,40 @@ abstract interface class TypeAnalyzerOperations< |
698 | 699 | /// Returns [type] suffixed with the [suffix]. |
699 | 700 | TypeStructure withNullabilitySuffixInternal( |
700 | 701 | TypeStructure type, NullabilitySuffix suffix); |
| 702 | + |
| 703 | + TypeConstraintGenerator< |
| 704 | + TypeStructure, |
| 705 | + SharedNamedFunctionParameterStructure<TypeStructure>, |
| 706 | + Variable, |
| 707 | + TypeParameterStructure, |
| 708 | + TypeDeclarationType, |
| 709 | + TypeDeclaration, |
| 710 | + Object> |
| 711 | + createTypeConstraintGenerator( |
| 712 | + {required TypeConstraintGenerationDataForTesting<TypeStructure, |
| 713 | + TypeParameterStructure, Variable, Object>? |
| 714 | + typeConstraintGenerationDataForTesting, |
| 715 | + required List<TypeParameterStructure> typeParametersToInfer, |
| 716 | + required TypeAnalyzerOperations<TypeStructure, Variable, |
| 717 | + TypeParameterStructure, TypeDeclarationType, TypeDeclaration> |
| 718 | + typeAnalyzerOperations, |
| 719 | + required bool inferenceUsingBoundsIsEnabled}); |
| 720 | + |
| 721 | + MergedTypeConstraint<TypeStructure, TypeParameterStructure, Variable, |
| 722 | + TypeDeclarationType, TypeDeclaration> |
| 723 | + mergeInConstraintsFromBound( |
| 724 | + {required TypeParameterStructure typeParameterToInfer, |
| 725 | + required List<TypeParameterStructure> typeParametersToInfer, |
| 726 | + required TypeStructure lower, |
| 727 | + required Map< |
| 728 | + TypeParameterStructure, |
| 729 | + MergedTypeConstraint<TypeStructure, TypeParameterStructure, |
| 730 | + Variable, TypeDeclarationType, TypeDeclaration>> |
| 731 | + inferencePhaseConstraints, |
| 732 | + required TypeConstraintGenerationDataForTesting<TypeStructure, |
| 733 | + TypeParameterStructure, Variable, Object>? |
| 734 | + dataForTesting, |
| 735 | + required bool inferenceUsingBoundsIsEnabled}); |
701 | 736 | } |
702 | 737 |
|
703 | 738 | mixin TypeAnalyzerOperationsMixin< |
@@ -893,6 +928,96 @@ mixin TypeAnalyzerOperationsMixin< |
893 | 928 | SharedTypeView<TypeStructure> type) { |
894 | 929 | return new SharedTypeSchemaView(type.unwrapTypeView()); |
895 | 930 | } |
| 931 | + |
| 932 | + @override |
| 933 | + MergedTypeConstraint<TypeStructure, TypeParameterStructure, Variable, |
| 934 | + TypeDeclarationType, TypeDeclaration> |
| 935 | + mergeInConstraintsFromBound( |
| 936 | + {required TypeParameterStructure typeParameterToInfer, |
| 937 | + required List<TypeParameterStructure> typeParametersToInfer, |
| 938 | + required TypeStructure lower, |
| 939 | + required Map< |
| 940 | + TypeParameterStructure, |
| 941 | + MergedTypeConstraint<TypeStructure, TypeParameterStructure, |
| 942 | + Variable, TypeDeclarationType, TypeDeclaration>> |
| 943 | + inferencePhaseConstraints, |
| 944 | + required TypeConstraintGenerationDataForTesting<TypeStructure, |
| 945 | + TypeParameterStructure, Variable, Object>? |
| 946 | + dataForTesting, |
| 947 | + required bool inferenceUsingBoundsIsEnabled}) { |
| 948 | + // The type parameter's bound may refer to itself (or other type |
| 949 | + // parameters), so we might have to create an additional constraint. |
| 950 | + // Consider this example from |
| 951 | + // https://github.com/dart-lang/language/issues/3009: |
| 952 | + // |
| 953 | + // class A<X extends A<X>> {} |
| 954 | + // class B extends A<B> {} |
| 955 | + // class C extends B {} |
| 956 | + // void f<X extends A<X>>(X x) {} |
| 957 | + // void main() { |
| 958 | + // f(C()); // should infer f<B>(C()). |
| 959 | + // } |
| 960 | + // |
| 961 | + // In order for `f(C())` to be inferred as `f<B>(C())`, we need to |
| 962 | + // generate the constraint `X <: B`. To do this, we first take the lower |
| 963 | + // constraint we've accumulated so far (which, in this example, is `C`, |
| 964 | + // due to the presence of the actual argument `C()`), and use subtype |
| 965 | + // constraint generation to match it against the explicit bound (which |
| 966 | + // is `A<X>`; hence we perform `C <# A<X>`). If this produces any |
| 967 | + // constraints (i.e. `X <: B` in this example), then they are added to |
| 968 | + // the set of constraints just before choosing the final type. |
| 969 | + |
| 970 | + TypeStructure typeParameterToInferBound = typeParameterToInfer.bound!; |
| 971 | + |
| 972 | + // TODO(cstefantsova): Pass [dataForTesting] when |
| 973 | + // [InferenceDataForTesting] is merged with [TypeInferenceResultForTesting]. |
| 974 | + TypeConstraintGenerator< |
| 975 | + TypeStructure, |
| 976 | + SharedNamedFunctionParameterStructure<TypeStructure>, |
| 977 | + Variable, |
| 978 | + TypeParameterStructure, |
| 979 | + TypeDeclarationType, |
| 980 | + TypeDeclaration, |
| 981 | + Object> typeConstraintGatherer = |
| 982 | + createTypeConstraintGenerator( |
| 983 | + typeConstraintGenerationDataForTesting: null, |
| 984 | + typeParametersToInfer: typeParametersToInfer, |
| 985 | + typeAnalyzerOperations: this, |
| 986 | + inferenceUsingBoundsIsEnabled: inferenceUsingBoundsIsEnabled); |
| 987 | + typeConstraintGatherer.performSubtypeConstraintGenerationInternal( |
| 988 | + lower, typeParameterToInferBound, |
| 989 | + leftSchema: true, astNodeForTesting: null); |
| 990 | + Map< |
| 991 | + TypeParameterStructure, |
| 992 | + MergedTypeConstraint< |
| 993 | + TypeStructure, |
| 994 | + TypeParameterStructure, |
| 995 | + Variable, |
| 996 | + TypeDeclarationType, |
| 997 | + TypeDeclaration>> constraintsPerTypeVariable = |
| 998 | + typeConstraintGatherer.computeConstraints(); |
| 999 | + for (TypeParameterStructure typeParameter |
| 1000 | + in constraintsPerTypeVariable.keys) { |
| 1001 | + MergedTypeConstraint<TypeStructure, TypeParameterStructure, Variable, |
| 1002 | + TypeDeclarationType, TypeDeclaration> constraint = |
| 1003 | + constraintsPerTypeVariable[typeParameter]!; |
| 1004 | + constraint.origin = new TypeConstraintFromExtendsClause( |
| 1005 | + typeParameterName: typeParameterToInfer.displayName, |
| 1006 | + boundType: new SharedTypeView(typeParameterToInferBound), |
| 1007 | + extendsType: new SharedTypeView(typeParameterToInferBound)); |
| 1008 | + if (!constraint.isEmpty(this)) { |
| 1009 | + MergedTypeConstraint? constraintForParameter = |
| 1010 | + inferencePhaseConstraints[typeParameter]; |
| 1011 | + if (constraintForParameter == null) { |
| 1012 | + inferencePhaseConstraints[typeParameter] = constraint; |
| 1013 | + } else { |
| 1014 | + constraintForParameter.mergeInTypeSchemaUpper(constraint.upper, this); |
| 1015 | + constraintForParameter.mergeInTypeSchemaLower(constraint.lower, this); |
| 1016 | + } |
| 1017 | + } |
| 1018 | + } |
| 1019 | + return constraintsPerTypeVariable[typeParameterToInfer]!; |
| 1020 | + } |
896 | 1021 | } |
897 | 1022 |
|
898 | 1023 | /// Abstract interface of a type constraint generator. |
@@ -1832,6 +1957,12 @@ abstract class TypeConstraintGenerator< |
1832 | 1957 |
|
1833 | 1958 | return false; |
1834 | 1959 | } |
| 1960 | + |
| 1961 | + /// Returns the set of type constraints that was gathered. |
| 1962 | + Map< |
| 1963 | + TypeParameterStructure, |
| 1964 | + MergedTypeConstraint<TypeStructure, TypeParameterStructure, Variable, |
| 1965 | + TypeDeclarationType, TypeDeclaration>> computeConstraints(); |
1835 | 1966 | } |
1836 | 1967 |
|
1837 | 1968 | mixin TypeConstraintGeneratorMixin< |
|
0 commit comments