Skip to content

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

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?

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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