Skip to content

New files added, for contravariant-superinterface-2018 #114

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# A Non-Covariant Type Variable in a Superinterface is an Error.

Author: [email protected] (@eernstg)

Version: 0.1.

## Motivation and Scope

The ability to use a type variable contravariantly in a superinterface of a
generic class creates an "anti-parallel" subtype relationship for a given
class and a direct superinterface thereof, and the same thing can happen
indirectly in many ways. This creates various complications for the static
analysis and the enforcement of the heap invariant (aka soundness), as
illustrated below. Similar complications arise in the invariant
case. Hence, this feature makes all non-covariant usages of a type variable
in a superinterface a compile-time error.

Here is an example:

```dart
class A<X> {
X x;
A(this.x);
}

class B<X> extends A<void Function(X)> {
B(void Function(X) f): super(f);
}

main() {
// Upcast: `B<int> <: B<num>` by class covariance.
B<num> b = B<int>((int i) => print(i.runtimeType));
// Upcast: `B<num> <: A<void Function(num)>` by `extends` clause.
A<void Function(num)> a = b;
// Upcast: `A<void Function(num)> <: A<void Function(double)>`
// by class covariance, plus `double <: num` and `void <: void`.
a.x(3.14);
}
```

Every assignment in `main` involves an upcast, so there are no downcasts at
all and the program should be safe. However, execution fails at `a.x(3.14)`
because we are passing an actual argument of type `double` to a function
whose corresponding parameter type is `int`.

Note that the heap invariant is violated during execution at the point
where `a` is initialized, even though the program has no error according
the the existing rules (before the inclusion of this feature).

The underlying issue is that the contravariant usage of a type variable in
a superinterface creates a twisted subtype lattice where `B` "goes in one
direction" (`B<int> <: B<num>`) and the superinterface `A` "goes in the
opposite direction" (`A<void Function(int)>` is a direct superinterface of
`B<int>` and `A<void Function(num)>` is a direct superinterface of
`B<num>`, but we have `A<void Function(num)> <: A<void Function(int)>`
rather than the opposite):

```dart
A<void Function(int)> :> A<void Function(num)>
^ ^
| |
| |
B<int> <: B<num>
```

We typically have a "parallel" subtype relationship:

```dart
Iterable<int> <: Iterable<num>
^ ^
| |
| |
List<int> <: List<num>
```

But with the example above we have an "anti-parallel" relationship, and
that creates the opportunity to have a series of upcasts that takes us from
`int` to `double` in part of the type without ever seeing a discrepancy
(because we can just as well go up to `A<void Function(double)>` in the
last step rather than `A<void Function(int)>`).

With such scenarios in mind, this feature amounts to adding a new
compile-time error, as specified below.


## Static Analysis

Let `C` be a generic class that declares a formal type parameter `X`, and
assume that `T` is a direct superinterface of `C`. It is a compile-time
error if `X` occurs contravariantly or invariantly in `T`.


## Dynamic Semantics

There is no dynamic semantics associated with this feature.


## Revisions

* Version 0.1, Nov 29 2018: Initial version.
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Implementation Plan for the Q1 2019 Superinterface Contravariance Error.

Relevant documents:
- [Tracking issue](https://github.com/dart-lang/language/issues/113)
- [Feature specification](https://github.com/dart-lang/language/blob/master/accepted/future-releases/contravariant-superinterface-2018/feature-specification.md)


## Implementation and Release plan

This feature is concerned with the introduction of one extra compile-time
error, and the breakage has been estimated to be very low.
Still, we will use an
[experiments flag](https://github.com/dart-lang/sdk/blob/master/docs/process/experimental-flags.md)
in order to enable a controlled deployment.


### Phase 0 (Release flag)

In this phase every tool adds support for an experiments flag: The flag
`--enable-experiment=covariant-only-superinterfaces` must be passed for the
changes to be enabled.


### Phase 1 (Implementation)

All tools add the implementation of the associated compile-time check, and
start emitting the new error during static analysis.


### Phase 1 (Release)

The update is released as part of the next stable Dart release.


## Timeline

Completion goals for the phases:

- Phase 0: Q1 2019
- Phase 1: Q1 2019
- Phase 2: Q1 2019