Skip to content

this should not be allowed as an argument type in co- or contravariant classes #7254

Closed
@acrylic-origami

Description

@acrylic-origami

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?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions