Description
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?