Skip to content

Commit 1a7e113

Browse files
chloestefantsovaCommit Queue
authored andcommitted
[model] Share implementation of chooseTypes between Analyzer and CFE
Part of #54902 Change-Id: I7b83f7634940d24ba4406c476f9cd63dcfafff57 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/446660 Reviewed-by: Paul Berry <[email protected]> Commit-Queue: Chloe Stefantsova <[email protected]>
1 parent 1f845d1 commit 1a7e113

32 files changed

+389
-299
lines changed

pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer_operations.dart

Lines changed: 85 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,12 @@ abstract interface class TypeAnalyzerOperations<
883883
/// True if [typeParameter] doesn't have an explicit bound.
884884
bool isBoundOmitted(SharedTypeParameter typeParameter);
885885

886+
SharedType substituteTypeFromIterables(
887+
SharedType typeToSubstitute,
888+
List<SharedTypeParameter> typeParameters,
889+
List<SharedType> types,
890+
);
891+
886892
/// Computes (or recomputes) a set of inferred types based on the constraints
887893
/// that have been recorded so far.
888894
List<SharedType> chooseTypes(
@@ -1460,6 +1466,85 @@ mixin TypeAnalyzerOperationsMixin<
14601466

14611467
return t;
14621468
}
1469+
1470+
@override
1471+
List<SharedType> chooseTypes(
1472+
List<SharedTypeParameter> typeParametersToInfer,
1473+
Map<
1474+
SharedTypeParameter,
1475+
MergedTypeConstraint<
1476+
Variable,
1477+
TypeDeclarationType,
1478+
TypeDeclaration,
1479+
AstNode
1480+
>
1481+
>
1482+
constraints,
1483+
List<SharedType>? previouslyInferredTypes, {
1484+
required bool preliminary,
1485+
required bool inferenceUsingBoundsIsEnabled,
1486+
required TypeConstraintGenerationDataForTesting<Variable, AstNode>?
1487+
dataForTesting,
1488+
required AstNode? treeNodeForTesting,
1489+
}) {
1490+
List<SharedType> inferredTypes =
1491+
previouslyInferredTypes?.toList(growable: false) ??
1492+
new List.filled(
1493+
typeParametersToInfer.length,
1494+
unknownType.unwrapTypeSchemaView(),
1495+
);
1496+
1497+
for (int i = 0; i < typeParametersToInfer.length; i++) {
1498+
SharedTypeParameter typeParam = typeParametersToInfer[i];
1499+
1500+
SharedType? typeParamBound = typeParam.boundShared;
1501+
SharedType? extendsConstraint;
1502+
if (typeParamBound != null && !isBoundOmitted(typeParam)) {
1503+
extendsConstraint = substituteTypeFromIterables(
1504+
typeParamBound,
1505+
typeParametersToInfer,
1506+
inferredTypes,
1507+
);
1508+
}
1509+
1510+
MergedTypeConstraint<
1511+
Variable,
1512+
TypeDeclarationType,
1513+
TypeDeclaration,
1514+
AstNode
1515+
>
1516+
constraint = constraints[typeParam]!;
1517+
if (preliminary) {
1518+
inferredTypes[i] = inferTypeParameterFromContext(
1519+
previouslyInferredTypes?[i],
1520+
constraint,
1521+
extendsConstraint,
1522+
isContravariant: typeParam.variance == Variance.contravariant,
1523+
isLegacyCovariant: typeParam.isLegacyCovariant,
1524+
constraints: constraints,
1525+
typeParameterToInfer: typeParam,
1526+
typeParametersToInfer: typeParametersToInfer,
1527+
dataForTesting: dataForTesting,
1528+
inferenceUsingBoundsIsEnabled: inferenceUsingBoundsIsEnabled,
1529+
);
1530+
} else {
1531+
inferredTypes[i] = inferTypeParameterFromAll(
1532+
previouslyInferredTypes?[i],
1533+
constraint,
1534+
extendsConstraint,
1535+
isContravariant: typeParam.variance == Variance.contravariant,
1536+
isLegacyCovariant: typeParam.isLegacyCovariant,
1537+
constraints: constraints,
1538+
typeParameterToInfer: typeParam,
1539+
typeParametersToInfer: typeParametersToInfer,
1540+
dataForTesting: dataForTesting,
1541+
inferenceUsingBoundsIsEnabled: inferenceUsingBoundsIsEnabled,
1542+
);
1543+
}
1544+
}
1545+
1546+
return inferredTypes;
1547+
}
14631548
}
14641549

14651550
/// Abstract interface of a type constraint generator.
@@ -2673,136 +2758,6 @@ class TypeDeclarationMatchResult<
26732758
});
26742759
}
26752760

2676-
/// The variance of a type parameter `X` in a type `T`.
2677-
enum Variance {
2678-
/// Used when `X` does not occur free in `T`.
2679-
unrelated(keyword: ''),
2680-
2681-
/// Used when `X` occurs free in `T`, and `U <: V` implies `[U/X]T <: [V/X]T`.
2682-
covariant(keyword: 'out'),
2683-
2684-
/// Used when `X` occurs free in `T`, and `U <: V` implies `[V/X]T <: [U/X]T`.
2685-
contravariant(keyword: 'in'),
2686-
2687-
/// Used when there exists a pair `U` and `V` such that `U <: V`, but
2688-
/// `[U/X]T` and `[V/X]T` are incomparable.
2689-
invariant(keyword: 'inout');
2690-
2691-
final String keyword;
2692-
2693-
const Variance({required this.keyword});
2694-
2695-
/// Return the variance with the given [encoding].
2696-
factory Variance.fromEncoding(int encoding) => values[encoding];
2697-
2698-
/// Return the variance associated with the string representation of variance.
2699-
factory Variance.fromKeywordString(String keywordString) {
2700-
Variance? result;
2701-
if (keywordString == "in") {
2702-
result = contravariant;
2703-
} else if (keywordString == "inout") {
2704-
result = invariant;
2705-
} else if (keywordString == "out") {
2706-
result = covariant;
2707-
} else if (keywordString == "unrelated") {
2708-
result = unrelated;
2709-
}
2710-
if (result != null) {
2711-
assert(result.keyword == keywordString);
2712-
return result;
2713-
} else {
2714-
throw new ArgumentError(
2715-
'Invalid keyword string for variance: $keywordString',
2716-
);
2717-
}
2718-
}
2719-
2720-
/// Return `true` if this represents the case when `X` occurs free in `T`, and
2721-
/// `U <: V` implies `[V/X]T <: [U/X]T`.
2722-
bool get isContravariant => this == contravariant;
2723-
2724-
/// Return `true` if this represents the case when `X` occurs free in `T`, and
2725-
/// `U <: V` implies `[U/X]T <: [V/X]T`.
2726-
bool get isCovariant => this == covariant;
2727-
2728-
/// Return `true` if this represents the case when there exists a pair `U` and
2729-
/// `V` such that `U <: V`, but `[U/X]T` and `[V/X]T` are incomparable.
2730-
bool get isInvariant => this == invariant;
2731-
2732-
/// Return `true` if this represents the case when `X` does not occur free in
2733-
/// `T`.
2734-
bool get isUnrelated => this == unrelated;
2735-
2736-
/// Combines variances of `X` in `T` and `Y` in `S` into variance of `X` in
2737-
/// `[Y/T]S`.
2738-
///
2739-
/// Consider the following examples:
2740-
///
2741-
/// * variance of `X` in `Function(X)` is contravariant, variance of `Y`
2742-
/// in `List<Y>` is covariant, so variance of `X` in `List<Function(X)>` is
2743-
/// contravariant;
2744-
///
2745-
/// * variance of `X` in `List<X>` is covariant, variance of `Y` in
2746-
/// `Function(Y)` is contravariant, so variance of `X` in
2747-
/// `Function(List<X>)` is contravariant;
2748-
///
2749-
/// * variance of `X` in `Function(X)` is contravariant, variance of `Y` in
2750-
/// `Function(Y)` is contravariant, so variance of `X` in
2751-
/// `Function(Function(X))` is covariant;
2752-
///
2753-
/// * let the following be declared:
2754-
///
2755-
/// typedef F<Z> = Function();
2756-
///
2757-
/// then variance of `X` in `F<X>` is unrelated, variance of `Y` in
2758-
/// `List<Y>` is covariant, so variance of `X` in `List<F<X>>` is
2759-
/// unrelated;
2760-
///
2761-
/// * let the following be declared:
2762-
///
2763-
/// typedef G<Z> = Z Function(Z);
2764-
///
2765-
/// then variance of `X` in `List<X>` is covariant, variance of `Y` in
2766-
/// `G<Y>` is invariant, so variance of `X` in `G<List<X>>` is invariant.
2767-
Variance combine(Variance other) {
2768-
if (isUnrelated || other.isUnrelated) return unrelated;
2769-
if (isInvariant || other.isInvariant) return invariant;
2770-
return this == other ? covariant : contravariant;
2771-
}
2772-
2773-
/// Returns true if this variance is greater than (above) or equal to the
2774-
/// [other] variance in the partial order induced by the variance lattice.
2775-
///
2776-
/// unrelated
2777-
/// covariant contravariant
2778-
/// invariant
2779-
bool greaterThanOrEqual(Variance other) {
2780-
if (isUnrelated) {
2781-
return true;
2782-
} else if (isCovariant) {
2783-
return other.isCovariant || other.isInvariant;
2784-
} else if (isContravariant) {
2785-
return other.isContravariant || other.isInvariant;
2786-
} else {
2787-
assert(isInvariant);
2788-
return other.isInvariant;
2789-
}
2790-
}
2791-
2792-
/// Variance values form a lattice where unrelated is the top, invariant is
2793-
/// the bottom, and covariant and contravariant are incomparable. [meet]
2794-
/// calculates the meet of two elements of such lattice. It can be used, for
2795-
/// example, to calculate the variance of a typedef type parameter if it's
2796-
/// encountered on the RHS of the typedef multiple times.
2797-
///
2798-
/// unrelated
2799-
/// covariant contravariant
2800-
/// invariant
2801-
Variance meet(Variance other) {
2802-
return new Variance.fromEncoding(index | other.index);
2803-
}
2804-
}
2805-
28062761
/// Representation of the state of [TypeConstraintGenerator].
28072762
///
28082763
/// The state can be obtained via [TypeConstraintGenerator.currentState]. A

pkg/_fe_analyzer_shared/lib/src/types/shared_type.dart

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,136 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
/// The variance of a type parameter `X` in a type `T`.
6+
enum Variance {
7+
/// Used when `X` does not occur free in `T`.
8+
unrelated(keyword: ''),
9+
10+
/// Used when `X` occurs free in `T`, and `U <: V` implies `[U/X]T <: [V/X]T`.
11+
covariant(keyword: 'out'),
12+
13+
/// Used when `X` occurs free in `T`, and `U <: V` implies `[V/X]T <: [U/X]T`.
14+
contravariant(keyword: 'in'),
15+
16+
/// Used when there exists a pair `U` and `V` such that `U <: V`, but
17+
/// `[U/X]T` and `[V/X]T` are incomparable.
18+
invariant(keyword: 'inout');
19+
20+
final String keyword;
21+
22+
const Variance({required this.keyword});
23+
24+
/// Return the variance with the given [encoding].
25+
factory Variance.fromEncoding(int encoding) => values[encoding];
26+
27+
/// Return the variance associated with the string representation of variance.
28+
factory Variance.fromKeywordString(String keywordString) {
29+
Variance? result;
30+
if (keywordString == "in") {
31+
result = contravariant;
32+
} else if (keywordString == "inout") {
33+
result = invariant;
34+
} else if (keywordString == "out") {
35+
result = covariant;
36+
} else if (keywordString == "unrelated") {
37+
result = unrelated;
38+
}
39+
if (result != null) {
40+
assert(result.keyword == keywordString);
41+
return result;
42+
} else {
43+
throw new ArgumentError(
44+
'Invalid keyword string for variance: $keywordString',
45+
);
46+
}
47+
}
48+
49+
/// Return `true` if this represents the case when `X` occurs free in `T`, and
50+
/// `U <: V` implies `[V/X]T <: [U/X]T`.
51+
bool get isContravariant => this == contravariant;
52+
53+
/// Return `true` if this represents the case when `X` occurs free in `T`, and
54+
/// `U <: V` implies `[U/X]T <: [V/X]T`.
55+
bool get isCovariant => this == covariant;
56+
57+
/// Return `true` if this represents the case when there exists a pair `U` and
58+
/// `V` such that `U <: V`, but `[U/X]T` and `[V/X]T` are incomparable.
59+
bool get isInvariant => this == invariant;
60+
61+
/// Return `true` if this represents the case when `X` does not occur free in
62+
/// `T`.
63+
bool get isUnrelated => this == unrelated;
64+
65+
/// Combines variances of `X` in `T` and `Y` in `S` into variance of `X` in
66+
/// `[Y/T]S`.
67+
///
68+
/// Consider the following examples:
69+
///
70+
/// * variance of `X` in `Function(X)` is contravariant, variance of `Y`
71+
/// in `List<Y>` is covariant, so variance of `X` in `List<Function(X)>` is
72+
/// contravariant;
73+
///
74+
/// * variance of `X` in `List<X>` is covariant, variance of `Y` in
75+
/// `Function(Y)` is contravariant, so variance of `X` in
76+
/// `Function(List<X>)` is contravariant;
77+
///
78+
/// * variance of `X` in `Function(X)` is contravariant, variance of `Y` in
79+
/// `Function(Y)` is contravariant, so variance of `X` in
80+
/// `Function(Function(X))` is covariant;
81+
///
82+
/// * let the following be declared:
83+
///
84+
/// typedef F<Z> = Function();
85+
///
86+
/// then variance of `X` in `F<X>` is unrelated, variance of `Y` in
87+
/// `List<Y>` is covariant, so variance of `X` in `List<F<X>>` is
88+
/// unrelated;
89+
///
90+
/// * let the following be declared:
91+
///
92+
/// typedef G<Z> = Z Function(Z);
93+
///
94+
/// then variance of `X` in `List<X>` is covariant, variance of `Y` in
95+
/// `G<Y>` is invariant, so variance of `X` in `G<List<X>>` is invariant.
96+
Variance combine(Variance other) {
97+
if (isUnrelated || other.isUnrelated) return unrelated;
98+
if (isInvariant || other.isInvariant) return invariant;
99+
return this == other ? covariant : contravariant;
100+
}
101+
102+
/// Returns true if this variance is greater than (above) or equal to the
103+
/// [other] variance in the partial order induced by the variance lattice.
104+
///
105+
/// unrelated
106+
/// covariant contravariant
107+
/// invariant
108+
bool greaterThanOrEqual(Variance other) {
109+
if (isUnrelated) {
110+
return true;
111+
} else if (isCovariant) {
112+
return other.isCovariant || other.isInvariant;
113+
} else if (isContravariant) {
114+
return other.isContravariant || other.isInvariant;
115+
} else {
116+
assert(isInvariant);
117+
return other.isInvariant;
118+
}
119+
}
120+
121+
/// Variance values form a lattice where unrelated is the top, invariant is
122+
/// the bottom, and covariant and contravariant are incomparable. [meet]
123+
/// calculates the meet of two elements of such lattice. It can be used, for
124+
/// example, to calculate the variance of a typedef type parameter if it's
125+
/// encountered on the RHS of the typedef multiple times.
126+
///
127+
/// unrelated
128+
/// covariant contravariant
129+
/// invariant
130+
Variance meet(Variance other) {
131+
return new Variance.fromEncoding(index | other.index);
132+
}
133+
}
134+
5135
/// Common interface for data structures used by the implementations to
6136
/// represent the type `dynamic`.
7137
abstract interface class SharedDynamicType implements SharedType {}
@@ -103,6 +233,12 @@ abstract interface class SharedTypeParameter {
103233

104234
/// The name of the type parameter, for display to the user.
105235
String get displayName;
236+
237+
/// Type parameter variance.
238+
Variance get variance;
239+
240+
/// True if the type parameter doesn't use declared variance.
241+
bool get isLegacyCovariant;
106242
}
107243

108244
/// Common interface for data structures used by the implementations to

0 commit comments

Comments
 (0)