HHVM Version
$ hhvm --version
HipHop VM 3.13.1 (rel)
Standalone code, or other way to reproduce the problem
For a final class, the this type is always equivalent to that exact class. By this equivalence, using this in 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.
this lets simple variance violations bypass typechecker scrutiny (pun...definitely intended). Here's the covariant case:
<?hh // strict
class Base {}
class Derived extends Base {
public function __construct(public int $derived_prop) {}
}
final class ImplCov<+T> {
public function __construct(private T $v) {}
public function put(this $v): void {
$this->v = $v->v;
}
public function pull(): T {
return $this->v;
}
}
class Violate {
public static function foo(ImplCov<Derived> $v): void {
self::bar($v);
echo $v->pull()->derived_prop; // Wait... Base doesn't have $derived_prop!
}
public static function bar(ImplCov<Base> $v): void {
$v->put(new ImplCov(new Base()));
}
}
Expected result
Illegal usage of a {co, contra}variant type parameter
Actual result
No errors!, but Violate::foo(new ImplCov(new Derived(42))); results in:
Notice: Undefined property: Base::$derived_prop in this_violation.php on line 18
Without ImplCov being final, the typechecker complains at $v->put(new ImplCov(new Base())); in Violate::bar with Since ImplCov is not final, this might not be ImplCov. I wonder if it suffices to disallow variant final classes to inherit or define methods with this as an argument type, or if a violation can occur in non-final classes?
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?