Skip to content

Commit e3ca5ee

Browse files
kallentucommit-bot@chromium.org
authored andcommitted
Check variance of type-parameter use in supertypes.
Tests have both correct and erroneous implementations of variance. Change-Id: I49dd76f42399015dd6e3f9688e598c271ce7ab1c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/119722 Commit-Queue: Kallen Tu <kallentu@google.com> Reviewed-by: Leaf Petersen <leafp@google.com> Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
1 parent 8513b16 commit e3ca5ee

13 files changed

+579
-9
lines changed

pkg/front_end/lib/src/fasta/builder/type_variable_builder.dart

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
library fasta.type_variable_builder;
66

77
import 'package:kernel/ast.dart'
8-
show DartType, Nullability, TypeParameter, TypeParameterType;
8+
show DartType, Nullability, TypeParameter, TypeParameterType, Variance;
99

1010
import '../fasta_codes.dart'
1111
show
@@ -38,9 +38,12 @@ class TypeVariableBuilder extends TypeDeclarationBuilderImpl {
3838

3939
TypeVariableBuilder(
4040
String name, SourceLibraryBuilder compilationUnit, int charOffset,
41-
{this.bound, this.isExtensionTypeParameter: false})
41+
{this.bound,
42+
this.isExtensionTypeParameter: false,
43+
int variableVariance: Variance.covariant})
4244
: actualParameter = new TypeParameter(name, null)
43-
..fileOffset = charOffset,
45+
..fileOffset = charOffset
46+
..variance = variableVariance,
4447
super(null, 0, name, compilationUnit, charOffset);
4548

4649
TypeVariableBuilder.fromKernel(
@@ -235,7 +238,7 @@ class TypeVariableBuilder extends TypeDeclarationBuilderImpl {
235238
// An alternative is to use the offset of the node the cloned type variable
236239
// is declared on.
237240
return new TypeVariableBuilder(name, parent, charOffset,
238-
bound: bound.clone(newTypes));
241+
bound: bound.clone(newTypes), variableVariance: variance);
239242
}
240243

241244
@override

pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,11 @@ int computeVariance(TypeVariableBuilder variable, TypeBuilder type) {
6666
if (declaration is ClassBuilder) {
6767
int result = Variance.unrelated;
6868
if (type.arguments != null) {
69-
for (TypeBuilder argument in type.arguments) {
70-
result = Variance.meet(result, computeVariance(variable, argument));
69+
for (int i = 0; i < type.arguments.length; ++i) {
70+
result = Variance.meet(
71+
result,
72+
Variance.combine(declaration.cls.typeParameters[i].variance,
73+
computeVariance(variable, type.arguments[i])));
7174
}
7275
}
7376
return result;

pkg/front_end/lib/src/fasta/source/source_class_builder.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,7 @@ class SourceClassBuilder extends ClassBuilderImpl
239239
Message message;
240240
for (int i = 0; i < typeVariables.length; ++i) {
241241
int variance = computeVariance(typeVariables[i], supertype);
242-
if (variance == Variance.contravariant ||
243-
variance == Variance.invariant) {
242+
if (!Variance.greaterThanOrEqual(variance, typeVariables[i].variance)) {
244243
message = templateBadTypeVariableInSupertype.withArguments(
245244
typeVariables[i].name, supertype.name);
246245
library.addProblem(message, charOffset, noLength, fileUri);

pkg/front_end/lib/src/fasta/source/source_library_builder.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2334,7 +2334,8 @@ class SourceLibraryBuilder extends LibraryBuilderImpl {
23342334
TypeVariableBuilder newVariable = new TypeVariableBuilder(
23352335
variable.name, this, variable.charOffset,
23362336
bound: variable.bound?.clone(newTypes),
2337-
isExtensionTypeParameter: isExtensionTypeParameter);
2337+
isExtensionTypeParameter: isExtensionTypeParameter,
2338+
variableVariance: variable.variance);
23382339
copy.add(newVariable);
23392340
boundlessTypeVariables.add(newVariable);
23402341
}

pkg/front_end/test/spell_checking_list_common.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,6 +1326,7 @@ indices
13261326
indirect
13271327
indirectly
13281328
induce
1329+
induced
13291330
infer
13301331
inference
13311332
inferrable

pkg/kernel/lib/ast.dart

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6045,6 +6045,30 @@ class Variance {
60456045
return a == b ? covariant : contravariant;
60466046
}
60476047

6048+
/// Returns true if [a] is greater than (above) [b] in the partial order
6049+
/// induced by the variance lattice.
6050+
static bool greaterThan(int a, int b) {
6051+
return greaterThanOrEqual(a, b) && a != b;
6052+
}
6053+
6054+
/// Returns true if [a] is greater than (above) or equal to [b] in the
6055+
/// partial order induced by the variance lattice.
6056+
static bool greaterThanOrEqual(int a, int b) {
6057+
return meet(a, b) == b;
6058+
}
6059+
6060+
/// Returns true if [a] is less than (below) [b] in the partial order
6061+
/// induced by the variance lattice.
6062+
static bool lessThan(int a, int b) {
6063+
return lessThanOrEqual(a, b) && a != b;
6064+
}
6065+
6066+
/// Returns true if [a] is less than (below) or equal to [b] in the
6067+
/// partial order induced by the variance lattice.
6068+
static bool lessThanOrEqual(int a, int b) {
6069+
return meet(a, b) == a;
6070+
}
6071+
60486072
static int fromString(String variance) {
60496073
if (variance == "in") {
60506074
return contravariant;
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
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.
4+
5+
// Tests erroneous subclass usage for the `in` variance modifier.
6+
7+
// SharedOptions=--enable-experiment=variance
8+
9+
typedef CovFunction<T> = T Function();
10+
typedef ContraFunction<T> = void Function(T);
11+
typedef InvFunction<T> = T Function(T);
12+
13+
class LegacyCovariant<T> {}
14+
class Covariant<out T> {}
15+
class Contravariant<in T> {}
16+
class Invariant<inout T> {}
17+
mixin MLegacyCovariant<T> {}
18+
mixin MCovariant<out T> {}
19+
mixin MContravariant<in T> {}
20+
mixin MInvariant<inout T> {}
21+
22+
class A<in T> extends LegacyCovariant<T> {}
23+
// ^
24+
// [analyzer] unspecified
25+
// [cfe] Found unsupported uses of 'T' in supertype 'LegacyCovariant'.
26+
27+
class B<in T> implements LegacyCovariant<T> {}
28+
// ^
29+
// [analyzer] unspecified
30+
// [cfe] Found unsupported uses of 'T' in supertype 'LegacyCovariant'.
31+
32+
class C<in T> with MLegacyCovariant<T> {}
33+
// ^
34+
// [analyzer] unspecified
35+
// [cfe] Found unsupported uses of 'T' in supertype 'MLegacyCovariant'.
36+
37+
class D<in T> extends Covariant<T> {}
38+
// ^
39+
// [analyzer] unspecified
40+
// [cfe] Found unsupported uses of 'T' in supertype 'Covariant'.
41+
42+
class E<in T> implements Covariant<T> {}
43+
// ^
44+
// [analyzer] unspecified
45+
// [cfe] Found unsupported uses of 'T' in supertype 'Covariant'.
46+
47+
class F<in T> with MCovariant<T> {}
48+
// ^
49+
// [analyzer] unspecified
50+
// [cfe] Found unsupported uses of 'T' in supertype 'MCovariant'.
51+
52+
class G<in T> extends Invariant<T> {}
53+
// ^
54+
// [analyzer] unspecified
55+
// [cfe] Found unsupported uses of 'T' in supertype 'Invariant'.
56+
57+
class H<in T> implements Invariant<T> {}
58+
// ^
59+
// [analyzer] unspecified
60+
// [cfe] Found unsupported uses of 'T' in supertype 'Invariant'.
61+
62+
class I<in T> with MInvariant<T> {}
63+
// ^
64+
// [analyzer] unspecified
65+
// [cfe] Found unsupported uses of 'T' in supertype 'MInvariant'.
66+
67+
class J<in T> extends Covariant<Covariant<T>> {}
68+
// ^
69+
// [analyzer] unspecified
70+
// [cfe] Found unsupported uses of 'T' in supertype 'Covariant'.
71+
72+
class K<in T> extends Contravariant<Contravariant<T>> {}
73+
// ^
74+
// [analyzer] unspecified
75+
// [cfe] Found unsupported uses of 'T' in supertype 'Contravariant'.
76+
77+
class L<in T> extends Covariant<CovFunction<T>> {}
78+
// ^
79+
// [analyzer] unspecified
80+
// [cfe] Found unsupported uses of 'T' in supertype 'Covariant'.
81+
82+
class M<in T> extends Covariant<ContraFunction<ContraFunction<T>>> {}
83+
// ^
84+
// [analyzer] unspecified
85+
// [cfe] Found unsupported uses of 'T' in supertype 'Covariant'.
86+
87+
class N<in T> extends Contravariant<CovFunction<Contravariant<T>>> {}
88+
// ^
89+
// [analyzer] unspecified
90+
// [cfe] Found unsupported uses of 'T' in supertype 'Contravariant'.
91+
92+
class O<in T> extends Covariant<CovFunction<Covariant<T>>> {}
93+
// ^
94+
// [analyzer] unspecified
95+
// [cfe] Found unsupported uses of 'T' in supertype 'Covariant'.
96+
97+
class P<in T> extends Covariant<Covariant<Covariant<T>>> {}
98+
// ^
99+
// [analyzer] unspecified
100+
// [cfe] Found unsupported uses of 'T' in supertype 'Covariant'.
101+
102+
class Q<in T> extends Invariant<InvFunction<T>> {}
103+
// ^
104+
// [analyzer] unspecified
105+
// [cfe] Found unsupported uses of 'T' in supertype 'Invariant'.
106+
107+
class R<in T> = Covariant<T> with MContravariant<T>;
108+
// ^
109+
// [analyzer] unspecified
110+
// [cfe] Found unsupported uses of 'T' in supertype 'Covariant'.
111+
112+
class S<in T> = Contravariant<T> with MCovariant<T>;
113+
// ^
114+
// [analyzer] unspecified
115+
// [cfe] Found unsupported uses of 'T' in supertype 'MCovariant'.
116+
117+
class T<in X> = Invariant<X> with MInvariant<X>;
118+
// ^
119+
// [analyzer] unspecified
120+
// [cfe] Found unsupported uses of 'X' in supertype 'Invariant'.
121+
// ^
122+
// [analyzer] unspecified
123+
// [cfe] Found unsupported uses of 'X' in supertype 'MInvariant'.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
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.
4+
5+
// Tests subclass usage for the `in` variance modifier.
6+
7+
// SharedOptions=--enable-experiment=variance
8+
9+
typedef CovFunction<T> = T Function();
10+
typedef ContraFunction<T> = void Function(T);
11+
12+
class Covariant<out T> {}
13+
class Contravariant<in T> {}
14+
mixin MContravariant<in T> {}
15+
16+
class A<in T> extends Contravariant<T> {}
17+
class B<in T> implements Contravariant<T> {}
18+
class C<in T> with MContravariant<T> {}
19+
20+
class D<in T> extends Covariant<Contravariant<T>> {}
21+
class E<in T> extends Contravariant<Covariant<T>> {}
22+
23+
class F<in T> extends Covariant<ContraFunction<T>> {}
24+
class G<in T> extends Covariant<ContraFunction<CovFunction<T>>> {}
25+
class H<in T> extends Covariant<CovFunction<ContraFunction<T>>> {}
26+
27+
class I<in T> extends Covariant<ContraFunction<Covariant<T>>> {}
28+
29+
class J<in T> extends Contravariant<Contravariant<Contravariant<T>>> {}
30+
31+
class K<in T> = Contravariant<T> with MContravariant<T>;
32+
class L<in T> = Covariant<Contravariant<T>> with MContravariant<T>;
33+
class M<in T> = Contravariant<T> with MContravariant<Covariant<T>>;
34+
35+
main() {
36+
A<num> a = A();
37+
B<num> b = B();
38+
C<num> c = C();
39+
D<num> d = D();
40+
E<num> e = E();
41+
F<num> f = F();
42+
G<num> g = G();
43+
H<num> h = H();
44+
I<num> i = I();
45+
J<num> j = J();
46+
K<num> k = K();
47+
L<num> l = L();
48+
M<num> m = M();
49+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
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.
4+
5+
// Tests subclass usage for the `inout` variance modifier.
6+
7+
// SharedOptions=--enable-experiment=variance
8+
9+
typedef CovFunction<T> = T Function();
10+
typedef ContraFunction<T> = void Function(T);
11+
typedef InvFunction<T> = T Function(T);
12+
13+
class LegacyCovariant<T> {}
14+
class Invariant<inout T>{}
15+
class Covariant<out T> {}
16+
class Contravariant<in T> {}
17+
mixin MLegacyCovariant<T> {}
18+
mixin MContravariant<in T> {}
19+
mixin MCovariant<out T> {}
20+
mixin MInvariant<inout T> {}
21+
22+
class A<inout T> extends LegacyCovariant<T> {}
23+
class B<inout T> extends Invariant<T> {}
24+
class C<inout T> extends Covariant<T> {}
25+
class D<inout T> extends Contravariant<T> {}
26+
27+
class E<inout T> implements LegacyCovariant<T> {}
28+
class F<inout T> implements Invariant<T> {}
29+
class G<inout T> implements Covariant<T> {}
30+
class H<inout T> implements Contravariant<T> {}
31+
32+
class I<inout T> with MLegacyCovariant<T> {}
33+
class J<inout T> with MInvariant<T> {}
34+
class K<inout T> with MCovariant<T> {}
35+
class L<inout T> with MContravariant<T> {}
36+
37+
class M<inout T> extends Covariant<Contravariant<T>> {}
38+
class N<inout T> extends Contravariant<Covariant<T>> {}
39+
class O<inout T> extends Covariant<ContraFunction<T>> {}
40+
class P<inout T> extends Covariant<ContraFunction<CovFunction<T>>> {}
41+
class Q<inout T> extends Covariant<CovFunction<ContraFunction<T>>> {}
42+
class R<inout T> extends Covariant<ContraFunction<Covariant<T>>> {}
43+
class S<inout T> extends Contravariant<Contravariant<Contravariant<T>>> {}
44+
45+
class T<inout X> extends Covariant<Covariant<X>> {}
46+
class U<inout T> extends Contravariant<Contravariant<T>> {}
47+
class V<inout T> extends Covariant<CovFunction<T>> {}
48+
class W<inout T> extends Covariant<ContraFunction<ContraFunction<T>>> {}
49+
class X<inout T> extends Contravariant<CovFunction<Contravariant<T>>> {}
50+
class Y<inout T> extends Covariant<CovFunction<Covariant<T>>> {}
51+
class Z<inout T> extends Covariant<Covariant<Covariant<T>>> {}
52+
53+
class AA<inout T> extends Covariant<InvFunction<T>> {}
54+
55+
class AB<inout T> = Invariant<T> with MInvariant<T>;
56+
class AC<inout T> = Covariant<T> with MCovariant<T>;
57+
class AD<inout T> = Contravariant<T> with MContravariant<T>;
58+
59+
main() {
60+
A<num> a = A();
61+
B<num> b = B();
62+
C<num> c = C();
63+
D<num> d = D();
64+
E<num> e = E();
65+
F<num> f = F();
66+
G<num> g = G();
67+
H<num> h = H();
68+
I<num> i = I();
69+
J<num> j = J();
70+
K<num> k = K();
71+
L<num> l = L();
72+
M<num> m = M();
73+
N<num> n = N();
74+
O<num> o = O();
75+
P<num> p = P();
76+
Q<num> q = Q();
77+
R<num> r = R();
78+
S<num> s = S();
79+
T<num> t = T();
80+
U<num> u = U();
81+
V<num> v = V();
82+
W<num> w = W();
83+
X<num> x = X();
84+
Y<num> y = Y();
85+
Z<num> z = Z();
86+
AA<num> aa = AA();
87+
AB<num> ab = AB();
88+
AC<num> ac = AC();
89+
AD<num> ad = AD();
90+
}

0 commit comments

Comments
 (0)