-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Open
Labels
Description
HHVM Version
$ hhvm --version
HipHop VM 3.13.1 (rel)
Standalone code, or other way to reproduce the problem
Define a class covariant on one of its type parameters and assert the constructor is consistent:
<?hh // strict
<<__ConsistentConstruct>>
abstract class A<+T> {
abstract public function __construct(T $v);
abstract public function foo(): int;
}Then extend that class and constrain that same type parameter to a derived type, and act on that type in some methods:
<?hh // strict
class Base {}
class Derived extends Base {
public function __construct(public int $foo) {}
}
class B<+T as Derived> extends A<T> {
public function __construct(private T $v) {}
public function foo(): int {
return $this->v->foo; // we assume here T is a subtype of Derived
}
}Cast the classname of the extended class to the classname of the base class parameterized with a supertype of the extended class's constraint. Invoke a method that acts on the type parameter in the extended class.
<?hh // strict
class C {
public static function foo(): void {
self::bar(B::class);
}
public static function bar(classname<A<Base>> $v): void {
echo (new $v(new Base()))->foo(); // `B::foo` attempts to summon an int from thin air!
// It's not very effective.
}
}This is where B needs to be covariant on T: the typechecker doesn't allow this cast if it isn't.
Expected result
Some sort of variance violation? I don't know which is the more illegal step: allowing private properties of a covariant type, or the classname cast.
Actual result
No errors! from the typechecker, but
Notice: Undefined property: Base::$foo in B.php on line 10
Catchable fatal error: Value returned from method B::foo() must be of type int, null given in B.php on line 10
from executing C::foo().
Reactions are currently unavailable