facebook / facebook/hhvm

classname<T> and private covariant type permits type violation

Open
#7,216 5 comments 0 reactions 0 assignees View on GitHub
hack
Dominant language
C++
Stars
18.7k
Forks
3.1k
Avg merge
1h 47m
Merged PRs (30d)
2

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:

``` hack
>
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:

``` hack
extends A {
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.

``` hack
> $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()`.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.