From f87b3041e4823bb728bea45017b51927f3ef7f26 Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Thu, 29 Nov 2018 14:52:25 +0100 Subject: [PATCH 1/3] New files added, for contravariant-superinterface-2018 --- .../feature-specification.md | 100 ++++++++++++++++++ .../implementation-plan.md | 30 ++++++ 2 files changed, 130 insertions(+) create mode 100644 accepted/future-releases/contravariant-superinterface-2018/feature-specification.md create mode 100644 accepted/future-releases/contravariant-superinterface-2018/implementation-plan.md 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..6ee4d35cf5 --- /dev/null +++ b/accepted/future-releases/contravariant-superinterface-2018/implementation-plan.md @@ -0,0 +1,30 @@ +# Implementation Plan for the Q4 2018 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. + + +### Phase 0 (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 From 26f1c7932d5f84d13ce5538118ee6a816bf39eea Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Thu, 29 Nov 2018 14:55:34 +0100 Subject: [PATCH 2/3] Made timing consistent --- .../contravariant-superinterface-2018/implementation-plan.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accepted/future-releases/contravariant-superinterface-2018/implementation-plan.md b/accepted/future-releases/contravariant-superinterface-2018/implementation-plan.md index 6ee4d35cf5..f515fd1cc4 100644 --- a/accepted/future-releases/contravariant-superinterface-2018/implementation-plan.md +++ b/accepted/future-releases/contravariant-superinterface-2018/implementation-plan.md @@ -1,4 +1,4 @@ -# Implementation Plan for the Q4 2018 Superinterface Contravariance Error. +# Implementation Plan for the Q1 2019 Superinterface Contravariance Error. Relevant documents: - [Tracking issue](https://github.com/dart-lang/language/issues/113) From 794b41c091deede0a7b3c184542d33cb6334670f Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Fri, 30 Nov 2018 14:17:37 +0100 Subject: [PATCH 3/3] Introduced experiments flag in implementation plan --- .../implementation-plan.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/accepted/future-releases/contravariant-superinterface-2018/implementation-plan.md b/accepted/future-releases/contravariant-superinterface-2018/implementation-plan.md index f515fd1cc4..9bc636434d 100644 --- a/accepted/future-releases/contravariant-superinterface-2018/implementation-plan.md +++ b/accepted/future-releases/contravariant-superinterface-2018/implementation-plan.md @@ -9,9 +9,19 @@ Relevant documents: 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 (Implementation) +### 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. @@ -28,3 +38,4 @@ Completion goals for the phases: - Phase 0: Q1 2019 - Phase 1: Q1 2019 +- Phase 2: Q1 2019