diff --git a/accepted/future-releases/contravariant-superinterface-2018/feature-specification.md b/accepted/future-releases/contravariant-superinterface-2018/feature-specification.md new file mode 100644 index 0000000000..0761b8c22f --- /dev/null +++ b/accepted/future-releases/contravariant-superinterface-2018/feature-specification.md @@ -0,0 +1,100 @@ +# A Non-Covariant Type Variable in a Superinterface is an Error. + +Author: eernst@google.com (@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; + A(this.x); +} + +class B extends A { + B(void Function(X) f): super(f); +} + +main() { + // Upcast: `B <: B` by class covariance. + B b = B((int i) => print(i.runtimeType)); + // Upcast: `B <: A` by `extends` clause. + A a = b; + // Upcast: `A <: A` + // 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 <: B`) and the superinterface `A` "goes in the +opposite direction" (`A` is a direct superinterface of +`B` and `A` is a direct superinterface of +`B`, but we have `A <: A` +rather than the opposite): + +```dart + A :> A + ^ ^ + | | + | | + B <: B +``` + +We typically have a "parallel" subtype relationship: + +```dart + Iterable <: Iterable + ^ ^ + | | + | | + List <: List +``` + +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` in the +last step rather than `A`). + +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. diff --git a/accepted/future-releases/contravariant-superinterface-2018/implementation-plan.md b/accepted/future-releases/contravariant-superinterface-2018/implementation-plan.md new file mode 100644 index 0000000000..9bc636434d --- /dev/null +++ b/accepted/future-releases/contravariant-superinterface-2018/implementation-plan.md @@ -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