Permit generic methods to override their own instantiations
commitfc8a0b6249c5b738acb46536b9e40bfc14b8bb75
authorAndrew Kennedy <akenn@fb.com>
Fri, 25 Mar 2022 23:22:08 +0000 (25 16:22 -0700)
committerFacebook GitHub Bot <facebook-github-bot@users.noreply.github.com>
Fri, 25 Mar 2022 23:22:08 +0000 (25 16:22 -0700)
tree86d20b771e61b04314e2e3ca539cabfabe6b7c3e
parent6431c6a24645a6e279cc51615e73968d69cbcc1b
Permit generic methods to override their own instantiations

Summary:
It's sound to allow generic methods to override methods whose signature is (a supertype of) an instantiation of the generic one. For example,
```
function foo(int):int;
```
can be overridden by
```
function foo<T>(T):T;
```
To implement this, Hack needs to find *some* instantiation of `T` such that subtyping holds. This is just the usual "inference" problem, and can be implemented by substituting type variables for generic type parameters. Here is a more complex example involving type constants:
```
interface I { abstract const type TC as num; }
class B {
  function foo(num):void;
}
class C<T as I> extends B {
 function foo<TF>(TF):void where TF super T::TC;
}
```
We need to find a solution for type variable `#1` with `T::TC <: #1` (from the where constraint) such that `num <: #1` (by contravariance of parameter types). Clearly `#1:=num` is a solution, as `T::TC <: num` from the type constant bound.

Dually, suppose we have
```
class C<T as I> extends B {
  function foo<TF>(TF):void where TF as T::TC;
}
```
This time, we need to find type variable `#1` with `#1 <: T::TC` such that `num <: #1`. i.e. by transitivity we must have `num <: T::TC` which doesn't hold, so there is no solution, and the override should be rejected.

A nice side-effect of this diff is that we can now override generic methods with a version in which the generic parameter is renamed. (This was an error previously!)

Reviewed By: vassilmladenov

Differential Revision: D34582988

fbshipit-source-id: 15d764b3157531e6fd4ddb0f7b2db996bb53544a
38 files changed:
hphp/hack/src/typing/typing_phase.ml
hphp/hack/src/typing/typing_solver.ml
hphp/hack/src/typing/typing_subtype_method.ml
hphp/hack/test/typecheck/T78983983.php.exp [deleted file]
hphp/hack/test/typecheck/constraints/constraint_override_bad.php.exp
hphp/hack/test/typecheck/constraints/constraint_override_bad2.php.exp
hphp/hack/test/typecheck/constraints/constraint_override_bad2.php.pess_exp [new file with mode: 0644]
hphp/hack/test/typecheck/constraints/override_with_generic_3.php [new file with mode: 0644]
hphp/hack/test/typecheck/constraints/override_with_generic_3.php.exp [new file with mode: 0644]
hphp/hack/test/typecheck/constraints/override_with_generic_4.php [new file with mode: 0644]
hphp/hack/test/typecheck/constraints/override_with_generic_4.php.exp [new file with mode: 0644]
hphp/hack/test/typecheck/constraints/where_overrides_monomorphic.php.exp
hphp/hack/test/typecheck/gen4.php.exp
hphp/hack/test/typecheck/gen4a.php.exp
hphp/hack/test/typecheck/gen4a.php.pess_exp [new file with mode: 0644]
hphp/hack/test/typecheck/generic_incompatible_implementation.php.exp
hphp/hack/test/typecheck/generic_incompatible_implementation2.php.exp
hphp/hack/test/typecheck/generic_incompatible_implementation2.php.pess_exp [new file with mode: 0644]
hphp/hack/test/typecheck/new_inference/oldtypehole/t13262460.php.exp
hphp/hack/test/typecheck/new_inference/oldtypehole/t13262460.php.pess_exp [new file with mode: 0644]
hphp/hack/test/typecheck/new_inference/tconst/tconst_on_generics2.php.exp
hphp/hack/test/typecheck/new_inference/typehole/t30337175.php.exp
hphp/hack/test/typecheck/override_generic_renamed.php [new file with mode: 0644]
hphp/hack/test/typecheck/override_generic_renamed.php.exp [new file with mode: 0644]
hphp/hack/test/typecheck/override_generic_renamed.php.pess_disabled [new file with mode: 0644]
hphp/hack/test/typecheck/override_generic_renamed_2.php [new file with mode: 0644]
hphp/hack/test/typecheck/override_generic_renamed_2.php.exp [new file with mode: 0644]
hphp/hack/test/typecheck/override_with_generic.php [new file with mode: 0644]
hphp/hack/test/typecheck/override_with_generic.php.exp [new file with mode: 0644]
hphp/hack/test/typecheck/override_with_generic_2.php [new file with mode: 0644]
hphp/hack/test/typecheck/override_with_generic_2.php.exp [new file with mode: 0644]
hphp/hack/test/typecheck/override_with_generic_5.php [new file with mode: 0644]
hphp/hack/test/typecheck/override_with_generic_5.php.exp [new file with mode: 0644]
hphp/hack/test/typecheck/override_with_generic_5.php.pess_exp [new file with mode: 0644]
hphp/hack/test/typecheck/tconst/tconst_on_generics2.php.exp
hphp/hack/test/typecheck/tconst_unsoundness.php.exp
hphp/hack/test/typecheck/typehole/T78983983.php [moved from hphp/hack/test/typecheck/T78983983.php with 100% similarity]
hphp/hack/test/typecheck/typehole/T78983983.php.exp [new file with mode: 0644]