Skip to content

Commit 975ba12

Browse files
authored
New files added, for contravariant-superinterface-2018 (#114)
1 parent 813e901 commit 975ba12

File tree

2 files changed

+141
-0
lines changed

2 files changed

+141
-0
lines changed
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# A Non-Covariant Type Variable in a Superinterface is an Error.
2+
3+
Author: [email protected] (@eernstg)
4+
5+
Version: 0.1.
6+
7+
## Motivation and Scope
8+
9+
The ability to use a type variable contravariantly in a superinterface of a
10+
generic class creates an "anti-parallel" subtype relationship for a given
11+
class and a direct superinterface thereof, and the same thing can happen
12+
indirectly in many ways. This creates various complications for the static
13+
analysis and the enforcement of the heap invariant (aka soundness), as
14+
illustrated below. Similar complications arise in the invariant
15+
case. Hence, this feature makes all non-covariant usages of a type variable
16+
in a superinterface a compile-time error.
17+
18+
Here is an example:
19+
20+
```dart
21+
class A<X> {
22+
X x;
23+
A(this.x);
24+
}
25+
26+
class B<X> extends A<void Function(X)> {
27+
B(void Function(X) f): super(f);
28+
}
29+
30+
main() {
31+
// Upcast: `B<int> <: B<num>` by class covariance.
32+
B<num> b = B<int>((int i) => print(i.runtimeType));
33+
// Upcast: `B<num> <: A<void Function(num)>` by `extends` clause.
34+
A<void Function(num)> a = b;
35+
// Upcast: `A<void Function(num)> <: A<void Function(double)>`
36+
// by class covariance, plus `double <: num` and `void <: void`.
37+
a.x(3.14);
38+
}
39+
```
40+
41+
Every assignment in `main` involves an upcast, so there are no downcasts at
42+
all and the program should be safe. However, execution fails at `a.x(3.14)`
43+
because we are passing an actual argument of type `double` to a function
44+
whose corresponding parameter type is `int`.
45+
46+
Note that the heap invariant is violated during execution at the point
47+
where `a` is initialized, even though the program has no error according
48+
the the existing rules (before the inclusion of this feature).
49+
50+
The underlying issue is that the contravariant usage of a type variable in
51+
a superinterface creates a twisted subtype lattice where `B` "goes in one
52+
direction" (`B<int> <: B<num>`) and the superinterface `A` "goes in the
53+
opposite direction" (`A<void Function(int)>` is a direct superinterface of
54+
`B<int>` and `A<void Function(num)>` is a direct superinterface of
55+
`B<num>`, but we have `A<void Function(num)> <: A<void Function(int)>`
56+
rather than the opposite):
57+
58+
```dart
59+
A<void Function(int)> :> A<void Function(num)>
60+
^ ^
61+
| |
62+
| |
63+
B<int> <: B<num>
64+
```
65+
66+
We typically have a "parallel" subtype relationship:
67+
68+
```dart
69+
Iterable<int> <: Iterable<num>
70+
^ ^
71+
| |
72+
| |
73+
List<int> <: List<num>
74+
```
75+
76+
But with the example above we have an "anti-parallel" relationship, and
77+
that creates the opportunity to have a series of upcasts that takes us from
78+
`int` to `double` in part of the type without ever seeing a discrepancy
79+
(because we can just as well go up to `A<void Function(double)>` in the
80+
last step rather than `A<void Function(int)>`).
81+
82+
With such scenarios in mind, this feature amounts to adding a new
83+
compile-time error, as specified below.
84+
85+
86+
## Static Analysis
87+
88+
Let `C` be a generic class that declares a formal type parameter `X`, and
89+
assume that `T` is a direct superinterface of `C`. It is a compile-time
90+
error if `X` occurs contravariantly or invariantly in `T`.
91+
92+
93+
## Dynamic Semantics
94+
95+
There is no dynamic semantics associated with this feature.
96+
97+
98+
## Revisions
99+
100+
* Version 0.1, Nov 29 2018: Initial version.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Implementation Plan for the Q1 2019 Superinterface Contravariance Error.
2+
3+
Relevant documents:
4+
- [Tracking issue](https://github.com/dart-lang/language/issues/113)
5+
- [Feature specification](https://github.com/dart-lang/language/blob/master/accepted/future-releases/contravariant-superinterface-2018/feature-specification.md)
6+
7+
8+
## Implementation and Release plan
9+
10+
This feature is concerned with the introduction of one extra compile-time
11+
error, and the breakage has been estimated to be very low.
12+
Still, we will use an
13+
[experiments flag](https://github.com/dart-lang/sdk/blob/master/docs/process/experimental-flags.md)
14+
in order to enable a controlled deployment.
15+
16+
17+
### Phase 0 (Release flag)
18+
19+
In this phase every tool adds support for an experiments flag: The flag
20+
`--enable-experiment=covariant-only-superinterfaces` must be passed for the
21+
changes to be enabled.
22+
23+
24+
### Phase 1 (Implementation)
25+
26+
All tools add the implementation of the associated compile-time check, and
27+
start emitting the new error during static analysis.
28+
29+
30+
### Phase 1 (Release)
31+
32+
The update is released as part of the next stable Dart release.
33+
34+
35+
## Timeline
36+
37+
Completion goals for the phases:
38+
39+
- Phase 0: Q1 2019
40+
- Phase 1: Q1 2019
41+
- Phase 2: Q1 2019

0 commit comments

Comments
 (0)