Skip to content
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

Use sound approximations for non-covariant types #296

Open
eernstg opened this issue Apr 3, 2019 · 0 comments
Open

Use sound approximations for non-covariant types #296

eernstg opened this issue Apr 3, 2019 · 0 comments
Labels
request Requests to resolve a particular developer problem

Comments

@eernstg
Copy link
Member

eernstg commented Apr 3, 2019

Cf. dart-lang/sdk#33697, dart-lang/site-www#1017, and more than a dozen issues linked from the latter.

Consider the following example:

class C<X> {
  void Function(X) f;
  C(this.f);
}

void Function(X) foo<X>(C<X> c) => c.f;

main() {
  C<num> c = C<int>((int i) {});
  var f = foo(c);
}

In this example, the class C has a member whose type is not covariant in the type parameters of the enclosing class: If the type of c is C<num> or C<int> then the type of c.f is void Function(num) respectively void Function(int), and the latter is not a subtype of the former.

This means that it is not a sound assumption that if the static type of the receiver c is C<num> then the dynamic type of c.f will be a subtype of its "statically known" type void Function(num).

In order to preserve soundness (in particular, to prevent that any run-time entity—like a variable, parameter, returned value, or expression result—can ever have a type which is not a subtype of its static type), we must prevent that foo returns the function of type void Function(int) which is the value of c.f during the invocation of foo in main.

However, there would not be any such problem if we were to add the following to the class C as an instance method:

void bar() {
  void Function(X) f2 = f; // Safe, no dynamic checks needed.
  X x = ...;
  f2(x); // Safe.
}

The difference is that the contravariant occurrence of X in the type of the field f is no problem when the actual type can be denoted (because X is in scope), but when viewing an instance of C<T> from outside the class, we have a clash between the covariance of the class and the contravariance of the field type. Or, in general, a clash between the covariance of the class and any non-covariant occurrence of a type variable in the signature of a member of the enclosing class. As a convenient abbreviation, we have referred to such members as "contravariant" in many discussions about this topic.

We have one obvious remedy for this category of problems: Explicitly declared variance, cf. #214, #229, #524.

However, the use of invariance makes every usage of a class less flexible (declaration-site invariance, #214) or each declaration of a variable or similar entity of such a type (use-site invariance, #229).

This issue is a request to make the use of such contravariant members statically safe, even in the case where one or more of the relevant type parameters of the receiver type is covariant.

@eernstg eernstg added the request Requests to resolve a particular developer problem label Apr 3, 2019
copybara-service bot pushed a commit to dart-lang/sdk that referenced this issue Nov 15, 2024
This CL implements a new lint, `unsafe_variance`. This lint emits a
warning whenever an instance member declaration has a signature where
a type variable declared by the enclosing class/mixin/enum occurs in
a non-covariant position in the return type (including the type of
an instance variable).

Issues: https://github.com/dart-lang/linter/issues/4111, with goals related to dart-lang/language#296 and dart-lang/language#524.

Change-Id: I1352d71d61fece03a432ccf0d98825a69e3a457f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/384700
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Erik Ernst <eernst@google.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
request Requests to resolve a particular developer problem
Projects
None yet
Development

No branches or pull requests

1 participant