Skip to content

Commit 15e3744

Browse files
Michael Thomasfacebook-github-bot
authored andcommitted
Substitute lower or upper bounds of type params appearing only co- or contravariantly
Summary: In some cases a polymorphic function type can be written as an equivalent monomorphic type. Typically we warn users about these cases ('redundant generics') when written in function declarations but the current typing of function pointers / meth_caller will produce redundant generics when it quantifies over class level generics which only appear co- or contravariantly in the resulting function type. Although the types are correct, we prefer to generate minimally-polymorphic function types because (1) typing is more performant and (2) they are easier for users to understand. This diff adds an additional pass to the generated function types which ensure any generics occurring only co- or contravariantly *and* not appearing as the rhs of class refinement are 'inlined' i.e. replaced by the intersection of their upper bounds or union of their lower bounds Reviewed By: mheiber Differential Revision: D78662593 fbshipit-source-id: 4cbc2f30f09806b85018dba781bcce2e2afe1bb6
1 parent a783691 commit 15e3744

10 files changed

Lines changed: 439 additions & 12 deletions

hphp/hack/src/typing/typing_extract_method.ml

Lines changed: 370 additions & 11 deletions
Large diffs are not rendered by default.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
--config allowed_files_for_ignore_readonly=lambda_good_co.php,lambda_good_contra.php,lambda_bad_co.php,lambda_bad_contra.php,mock_return.php,mock_implementation.php
2-
--config enable_experimental_stx_features='{"polymorphic_function_hints": "Unstable","function_references":"Unstable","polymorphic_lambda": "Unstable"}'
2+
--config enable_experimental_stx_features='{"polymorphic_function_hints": "Unstable","function_references":"Unstable","polymorphic_lambda": "Unstable","union_intersection_type_hints": "Unstable"}'
33
--config poly_function_pointers=true
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?hh
2+
<<file: __EnableUnstableFeatures('polymorphic_function_hints')>>
3+
<<file: __EnableUnstableFeatures('union_intersection_type_hints')>>
4+
5+
class AAA {}
6+
interface III {}
7+
8+
abstract class Contrav<-T super AAA super III> {
9+
public function foo(): void {}
10+
public function bar(): this{ throw new Exception(); }
11+
}
12+
13+
function refIt(): void {
14+
$f = meth_caller(Contrav::class, 'foo');
15+
hh_expect<HH\FunctionRef<(readonly function(Contrav<(AAA | III)>): void)>>($f);
16+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
No errors
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?hh
2+
<<file: __EnableUnstableFeatures('polymorphic_function_hints')>>
3+
<<file: __EnableUnstableFeatures('union_intersection_type_hints')>>
4+
5+
class AAA {}
6+
interface III {}
7+
8+
abstract class Cov<+T as AAA as III> {
9+
public function foo(): void {}
10+
public function bar(): this{ throw new Exception(); }
11+
}
12+
13+
function refIt(): void {
14+
$g = meth_caller(Cov::class, 'foo');
15+
hh_expect<HH\FunctionRef<(readonly function(Cov<(AAA & III)>): void)>>($g);
16+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
No errors
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?hh
2+
<<file: __EnableUnstableFeatures('polymorphic_function_hints')>>
3+
<<file: __EnableUnstableFeatures('union_intersection_type_hints')>>
4+
5+
class AAA implements III {}
6+
interface III {}
7+
8+
abstract class Inv<T super AAA as III> {
9+
public function foo(): void {}
10+
public function bar(): this{ throw new Exception(); }
11+
}
12+
13+
function refIt(): void {
14+
$h = meth_caller(Inv::class, 'foo');
15+
hh_expect<HH\FunctionRef<(readonly function<T super AAA as III>(Inv<T>): void)>>($h);
16+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
No errors
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?hh
2+
<<file: __EnableUnstableFeatures('polymorphic_function_hints')>>
3+
<<file: __EnableUnstableFeatures('union_intersection_type_hints')>>
4+
5+
class AAA {}
6+
interface III {}
7+
8+
abstract class WithRfmt<+T as arraykey> {
9+
abstract const type TC as arraykey;
10+
public function foo(this::TC $_) : void {}
11+
}
12+
13+
function refIt(): void {
14+
$i = meth_caller(WithRfmt::class, 'foo');
15+
hh_expect<HH\FunctionRef<(readonly function<TC0 as arraykey>(WithRfmt<arraykey> with { type TC = TC0 }, TC0): void)>>($i);
16+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
No errors

0 commit comments

Comments
 (0)