Skip to content

Commit 53bbe6c

Browse files
kallentucommit-bot@chromium.org
authored andcommitted
[dart2js] Added variance support for static subtype checking.
Change-Id: I0731884aad68e3dd7f84658d75e946ca5db62bbe Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/127063 Reviewed-by: Sigmund Cherem <sigmund@google.com> Commit-Queue: Kallen Tu <kallentu@google.com>
1 parent f56b0f6 commit 53bbe6c

File tree

12 files changed

+212
-2
lines changed

12 files changed

+212
-2
lines changed

pkg/compiler/lib/src/elements/entities.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,9 @@ class AsyncMarker {
218218
int get index => values.indexOf(this);
219219
}
220220

221+
/// Values for variance annotations.
222+
enum Variance { legacyCovariant, covariant, contravariant, invariant }
223+
221224
/// Stripped down super interface for constructor like entities.
222225
///
223226
/// Currently only [ConstructorElement] but later also kernel based Dart

pkg/compiler/lib/src/elements/types.dart

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1501,6 +1501,9 @@ abstract class AbstractTypeRelation<T extends DartType>
15011501
/// Returns the declared bound of [element].
15021502
DartType getTypeVariableBound(TypeVariableEntity element);
15031503

1504+
/// Returns the variances for each type parameter in [cls].
1505+
List<Variance> getTypeVariableVariances(ClassEntity cls);
1506+
15041507
@override
15051508
bool visitType(T t, T s) {
15061509
throw 'internal error: unknown type ${t}';
@@ -1529,10 +1532,25 @@ abstract class AbstractTypeRelation<T extends DartType>
15291532
bool checkTypeArguments(InterfaceType instance, InterfaceType other) {
15301533
List<T> tTypeArgs = instance.typeArguments;
15311534
List<T> sTypeArgs = other.typeArguments;
1535+
List<Variance> tVariances = getTypeVariableVariances(instance.element);
15321536
assert(tTypeArgs.length == sTypeArgs.length);
1537+
assert(tTypeArgs.length == tVariances.length);
15331538
for (int i = 0; i < tTypeArgs.length; i++) {
1534-
if (invalidTypeArguments(tTypeArgs[i], sTypeArgs[i])) {
1535-
return false;
1539+
switch (tVariances[i]) {
1540+
case Variance.legacyCovariant:
1541+
case Variance.covariant:
1542+
if (invalidTypeArguments(tTypeArgs[i], sTypeArgs[i])) return false;
1543+
break;
1544+
case Variance.contravariant:
1545+
if (invalidTypeArguments(sTypeArgs[i], tTypeArgs[i])) return false;
1546+
break;
1547+
case Variance.invariant:
1548+
if (invalidTypeArguments(tTypeArgs[i], sTypeArgs[i]) ||
1549+
invalidTypeArguments(sTypeArgs[i], tTypeArgs[i])) return false;
1550+
break;
1551+
default:
1552+
throw StateError(
1553+
"Invalid variance ${tVariances[i]} used for subtype check.");
15361554
}
15371555
}
15381556
return true;

pkg/compiler/lib/src/ir/element_map.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,5 @@ abstract class IrToElementMap {
6969
DartType getCallType(InterfaceType type);
7070
int getHierarchyDepth(IndexedClass cls);
7171
DartType getTypeVariableBound(IndexedTypeVariable typeVariable);
72+
List<Variance> getTypeVariableVariances(IndexedClass cls);
7273
}

pkg/compiler/lib/src/ir/types.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,11 @@ abstract class AbstractTypeRelationMixin
132132
return elementMap.getTypeVariableBound(element);
133133
}
134134

135+
@override
136+
List<Variance> getTypeVariableVariances(ClassEntity cls) {
137+
return elementMap.getTypeVariableVariances(cls);
138+
}
139+
135140
@override
136141
FunctionType getCallType(InterfaceType type) {
137142
return elementMap.getCallType(type);

pkg/compiler/lib/src/ir/util.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,21 @@ AsyncMarker getAsyncMarker(ir.FunctionNode node) {
6868
}
6969
}
7070

71+
/// Returns the `Variance` corresponding to `node.variance`.
72+
Variance convertVariance(ir.TypeParameter node) {
73+
if (node.isLegacyCovariant) return Variance.legacyCovariant;
74+
switch (node.variance) {
75+
case ir.Variance.covariant:
76+
return Variance.covariant;
77+
case ir.Variance.contravariant:
78+
return Variance.contravariant;
79+
case ir.Variance.invariant:
80+
return Variance.invariant;
81+
default:
82+
throw new UnsupportedError("Variance ${node.variance} is not supported.");
83+
}
84+
}
85+
7186
/// Kernel encodes a null-aware expression `a?.b` as
7287
///
7388
/// let final #1 = a in #1 == null ? null : #1.b

pkg/compiler/lib/src/js_model/closure.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -895,6 +895,9 @@ class RecordClassData implements JClassData {
895895

896896
@override
897897
InterfaceType get instantiationToBounds => thisType;
898+
899+
@override
900+
List<Variance> getVariances() => null;
898901
}
899902

900903
/// A container for variables declared in a particular scope that are accessed

pkg/compiler/lib/src/js_model/element_map_impl.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1070,6 +1070,13 @@ class JsKernelToElementMap implements JsToElementMap, IrToElementMap {
10701070
return data.getBound(this);
10711071
}
10721072

1073+
@override
1074+
List<Variance> getTypeVariableVariances(IndexedClass cls) {
1075+
assert(checkFamily(cls));
1076+
JClassData data = classes.getData(cls);
1077+
return data.getVariances();
1078+
}
1079+
10731080
DartType _getTypeVariableDefaultType(IndexedTypeVariable typeVariable) {
10741081
assert(checkFamily(typeVariable));
10751082
JTypeVariableData data = typeVariables.getData(typeVariable);

pkg/compiler/lib/src/js_model/env.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import '../elements/types.dart';
1616
import '../ir/element_map.dart';
1717
import '../ir/static_type_cache.dart';
1818
import '../ir/visitors.dart';
19+
import '../ir/util.dart';
1920
import '../js_model/element_map.dart';
2021
import '../ordered_typeset.dart';
2122
import '../serialization/serialization.dart';
@@ -451,6 +452,8 @@ abstract class JClassData {
451452

452453
bool get isEnumClass;
453454
bool get isMixinApplication;
455+
456+
List<Variance> getVariances();
454457
}
455458

456459
class JClassDataImpl implements JClassData {
@@ -482,6 +485,8 @@ class JClassDataImpl implements JClassData {
482485
@override
483486
OrderedTypeSet orderedTypeSet;
484487

488+
List<Variance> _variances;
489+
485490
JClassDataImpl(this.cls, this.definition);
486491

487492
factory JClassDataImpl.readFromDataSource(DataSource source) {
@@ -506,6 +511,10 @@ class JClassDataImpl implements JClassData {
506511

507512
@override
508513
DartType get callType => null;
514+
515+
@override
516+
List<Variance> getVariances() =>
517+
_variances ??= cls.typeParameters.map(convertVariance).toList();
509518
}
510519

511520
/// Enum used for identifying [JMemberData] subclasses in serialization.

pkg/compiler/lib/src/kernel/element_map_impl.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,13 @@ class KernelToElementMapImpl implements KernelToElementMap, IrToElementMap {
643643
return data.getBound(this);
644644
}
645645

646+
@override
647+
List<Variance> getTypeVariableVariances(IndexedClass cls) {
648+
assert(checkFamily(cls));
649+
KClassData data = classes.getData(cls);
650+
return data.getVariances();
651+
}
652+
646653
ClassEntity getAppliedMixin(IndexedClass cls) {
647654
assert(checkFamily(cls));
648655
KClassData data = classes.getData(cls);

pkg/compiler/lib/src/kernel/env.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,7 @@ abstract class KClassData {
629629
bool get isMixinApplication;
630630

631631
Iterable<ConstantValue> getMetadata(IrToElementMap elementMap);
632+
List<Variance> getVariances();
632633

633634
/// Convert this [KClassData] to the corresponding [JClassData].
634635
JClassData convert();
@@ -659,6 +660,7 @@ class KClassDataImpl implements KClassData {
659660
OrderedTypeSet orderedTypeSet;
660661

661662
Iterable<ConstantValue> _metadata;
663+
List<Variance> _variances;
662664

663665
KClassDataImpl(this.node);
664666

@@ -677,6 +679,10 @@ class KClassDataImpl implements KClassData {
677679
node.annotations);
678680
}
679681

682+
@override
683+
List<Variance> getVariances() =>
684+
_variances ??= node.typeParameters.map(convertVariance).toList();
685+
680686
@override
681687
JClassData convert() {
682688
return new JClassDataImpl(node, new RegularClassDefinition(node));

0 commit comments

Comments
 (0)