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
this should not be allowed as an argument type in co- or contravariant classes
#7254
Comments
|
Interesting find -- I've poked the core Hack team internally (about this and #7216, which also didn't get a response). Hopefully I can get a better way to bring stuff to their attention that doesn't require being an FB employee :-P |
|
Good catch! I'm looking into a number of type soundness issues, especially around variance, so I'll add this one to my list :-) Andrew |
|
I noticed the new rules in 7e1887c (catching this violation buried in my own code no less!) so I'm closing this for now. |
|
A minor catch: type constants aren't checked for this violation. If ImplCov is rewritten: final class ImplCov<+T> {
const type TThis = this;
public function __construct(private T $v) {}
public function put(this::TThis $v): void {
$this->v = $v->pull();
}
public function pull(): T {
return $this->v;
}
}The code typechecks again with the same violation. |
|
I am going over old issues on this repository, to see which ones apply to the current versions of hhvm. You now get typechecker error on both your repros. Thanks for reporting them. |
HHVM Version
Standalone code, or other way to reproduce the problem
For a final class, the
thistype is always equivalent to that exact class. By this equivalence, usingthisin final classes with variant type parameters is always invalid, because the argument position is contravariant, reversing the variance of the parameters of the class type — covariant parameters become contravariantly valid, and vice versa.thislets simple variance violations bypass typechecker scrutiny (pun...definitely intended). Here's the covariant case:Expected result
Actual result
No errors!, butViolate::foo(new ImplCov(new Derived(42)));results in:Without
ImplCovbeing final, the typechecker complains at$v->put(new ImplCov(new Base()));inViolate::barwithSince ImplCov is not final, this might not be ImplCov. I wonder if it suffices to disallow variant final classes to inherit or define methods withthisas an argument type, or if a violation can occur in non-final classes?The text was updated successfully, but these errors were encountered: