-
Notifications
You must be signed in to change notification settings - Fork 205
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
Make it an error to use a type variable non-covariantly in a superinterface #39
Labels
feature
Proposed language feature that solves one or more problems
Comments
eernstg
changed the title
Make it an error to use a type variable contravariantly in a superinterface
Make it an error to use a type variable non-covariantly in a superinterface
Oct 9, 2018
I have a prototype CL for reporting this error and am testing it on code to quantify impact. So far it looks like little or no code would be impacted by adding this error. |
Wonderful! |
This was referenced Nov 29, 2018
@eernstg I believe this is landed? Can you close out this issue and move the feature spec for this into the appropriate accepted/release directory? |
Indeed, thanks! - the spec is moved in cf. #1085. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is a proposal for how to deal with the issue described in #38.
Related feature specification.
As described in #38, the ability to use a type variable contravariantly in a superinterface creates an "anti-parallel" subtype relationship for a given generic class and a direct superinterface thereof (and, of course, the same thing can happen indirectly in many ways). This creates various complications for the static analysis and the enforcement of the heap invariant ("soundness"). It easily generalizes to the invariant case, hence we'll target "non-covariant" occurrences here.
Discussion
I believe that it would be beneficial for Dart to introduce a new compile-time error, and I suspect that it would break a very small amount of code. Here is the proposed error:
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.
For example:
With that error in place, it is no longer possible to create the "anti-parallel" subtyping relationship that we used in #38 to violate the heap invariant.
Alternative Proposal
One other approach could be used: We could specify that an upcast from
B<T>
for someT
to a parameterized type based onA
must yieldA<void Function(Null)>
rather thanA<void Function(T)>
. In general, we would perform such an upcast by replacing the relevant type variable byNull
rather than replacing it by the actual type argumentT
. This would be sound, but it might also give rise to some confusion. I believe that a compile-time error is the better choice for superinterfaces.A Useful Property
If we introduce the above-mentioned error then we will have the following property: "A well-bounded type will have well-bounded superinterfaces".
That is a useful property because it enables the use of super-bounded types along with the ordinary subtype relationships, without forcing all types thus obtained to need a well-boundedness check.
To see this, we state without evidence that the current checks on regular-bounded types will ensure that superinterfaces are regular-bounded. That is, the bounds on the type parameters in a generic class declaration must be so strong that they enforce the bounds in each superinterface for the given actual type arguments.
Lemma 1: If
C
is a generic class with type parametersX1..Xk
,C<S1..Sk>
is a regular-bounded parameterized type, andD<U1..Up>
is a superinterface ofC
(whereUi
may contain type variables fromX1..Xk
), then[S1/X1..Sk/Xk]D<U1..Up>
is regular-bounded.The non-trivial step is the following:
Lemma 2: If
C
is a generic class with type parametersX1..Xk
,C<S1..Sk>
is a super-bounded parameterized type, andD<U1..Up>
is a superinterface ofC
(whereUi
may contain type variables fromX1..Xk
), then[S1/X1..Sk/Xk]D<U1..Up>
is well-bounded.With that result, we can easily see the following:
Theorem: If
C
is a generic class with type parametersX1..Xk
,C<S1..Sk>
is a well-bounded parameterized type, andD<U1..Up>
is a superinterface ofC
(whereUi
may contain type variables fromX1..Xk
), then[S1/X1..Sk/Xk]D<U1..Up>
is well-bounded.That's because
C<S1..Sk>
is either regular-bounded or super-bounded. So let's assume Lemma 1 and sketch a proof of Lemma 2:Proof sketch: Let
C
be a generic class with type parametersX1..Xk
, letC<S1..Sk>
be a super-bounded parameterized type, and letD<U1..Up>
be a superinterface ofC
(whereUi
may contain type variables fromX1..Xk
).Since
C<S1..Sk>
is super-bounded, we can letC<V1..Vk>
be the parameterized type which is obtained fromC<S1..Sk>
by replacing each covariantly occurring top type byNull
, and each contravariantly occurringNull
bydynamic
. By definition of super-bounded types,C<V1..Vk>
is regular-bounded. That is:where
Bj
is the declared bound ofXj
. LetD<U1..Up>
be one of the superinterfaces ofC
. By Lemma 1, we know that[V1/X1..Vk/Xk]D<U1..Up>
is regular-bounded, that is,where
Y1..Yp
are the formal type parameters ofD
andBB1..BBp
are the corresponding bounds. It must be true that none of theYj
occur in any ofU1..Up
nor in any ofV1..Vk
, but we assume that this has been achieved by a suitable choice of names.What we need to show is that
[S1/X1..Sk/Xk]D<U1..Up>
is well-bounded. If it is regular-bounded we are done. Otherwise we must show that it is super-bounded, that is, the substitution of bottom/top types by their opposites will produce a regular-bounded type:Let
Wj
,j \in 1..p
, be the result of replacing covariantly occurring top types byNull
and contravariantly occurringNull
bydynamic
in[S1/X1..Sk/Xk]Uj
, then we need to show thatD<W1..Wp>
is regular-bounded:If
X1..Xk
all occur covariantly inUj
then these replacements inWj
will occur with the same variance inUj
as inS1..Sk
and hencewhich means that we just need to show:
which is exactly what we already have. QED.
The text was updated successfully, but these errors were encountered: