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

Do extension types support statically checked variance? #3624

Open
eernstg opened this issue Feb 22, 2024 · 1 comment
Open

Do extension types support statically checked variance? #3624

eernstg opened this issue Feb 22, 2024 · 1 comment
Labels
extension-types question Further information is requested variance Issues concerned with explicit variance

Comments

@eernstg
Copy link
Member

eernstg commented Feb 22, 2024

Thanks to @sgrekhov for raising this issue! Currently, extension types are specified such that it is an error for a type variable declared by an extension type to occur in a non-covariant position in the representation type. This is required for soundness:

extension type E<X>(void Function(X) func) {} // Error, but pretend that we'd allow it.

Y upcast<X extends Y, Y>(X x) => x; // Return includes upcast, should not need dynamic check.

void main() {
  E<int> eInt = E((int i) {});
  E<num> eNum = upcast(eInt); // OK, but it violates soundness!
}

This would be a soundness violation because eNum.func has static type void Function(num) and run-time type void Function(int), and the latter is not a subtype of the former. In short, extension types already behave as if they have the modifier out on every type parameter, because it would otherwise give rise to soundness violations.

It seems obvious that this could be generalized such that an upcoming variance feature could be used with extension types. For example:

extension type E<in X>(void Function(X) func) {} // OK (future generalization).

Y upcast<X extends Y, Y>(X x) => x;

void main() {
  E<int> eInt = E((int i) {});
  E<num> eNum = upcast(eInt); // Compile-time error, `Y extends X` not satisfied.
}

We would then make it explicit that extension types do admit statically checked variance modifiers, and a type parameter with no such modifier is implicitly out (and that subsumes the current compile-time error involving variance).

@dart-lang/language-team, WDYT?

@eernstg eernstg added question Further information is requested variance Issues concerned with explicit variance extension-types labels Feb 22, 2024
@lrhn
Copy link
Member

lrhn commented Feb 26, 2024

Type parameters of an extension type must be used covariantly today, in the representation type and superinterfaces, because the parameter is (unsafely) covariant by default, and the representation type must co-variate with the extension type. We want E<T> <: E<S> to imply R<T> <: R<S>, where R<X> is the representation type of E<X>, otherwise the extension type erasure isn't sound.

If we can specify other variances, then I don't see a reason the type variables can't be used at that variance only, subject to all the usual requirements of where they can then be used. As long as the variance implies the subtyping of representation types, that's what we need for soundness.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
extension-types question Further information is requested variance Issues concerned with explicit variance
Projects
None yet
Development

No branches or pull requests

2 participants