Skip to content

Commit d80b106

Browse files
Michael Thomasmeta-codesync[bot]
authored andcommitted
Support type constant super bounds in polymorphic function pointerss
Summary: Adds support for type constant super bounds when synthesizing types for polymorphic function pointers. The main subtlety with this code come from nested type constant access e.g. ``` abstract class One { abstract const type Ta as Two super Three; public function foo(this::Ta::Tb): void {} } abstract class Two { abstract const type Tb as ... super ...; } abstract class Three extends Two { abstract const type Tb as ... super ...; } ``` To cope with the scenario where upper and lower bounds both define a nested constant this diff extends the existing code in a couple of ways: 1) Since the typeconstant can now have both an upper and lower bound we need to ensure they refined to agress on any nested type constant access in the function signature. This is done by taking the intersection of the upper bounds and the union of the lower bounds. Concrete definitions are treated as the the point interval. 2) The process above leads to intersection and union types so we extend refinement of type parameters generated when moving existentials to universal position to support them. For union types, we require that all elements of the union define the type constant. Each receives the same refinement to ensure they agree. For intersection types, we require that at least one element of the intersection defines the type constant. Only elements which define the type constant will have a refinement applied. In general, a user could declare upper and lower bounds with nested type constants with disjoint bounds. In keeping with the approach in the rest of Hack this doesn't cause an error - it just means the user has written dead code. Reviewed By: andrewjkennedy Differential Revision: D88069095 fbshipit-source-id: 31a886c19f1c7c0c27b3c31dbeef636db4ae927d
1 parent e4da608 commit d80b106

12 files changed

Lines changed: 484 additions & 19 deletions

hphp/hack/src/typing/typing_extract_method.ml

Lines changed: 296 additions & 18 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,mock_return2
2-
--config enable_experimental_stx_features='{"polymorphic_function_hints": "Unstable","function_references":"Unstable","polymorphic_lambda": "Unstable","union_intersection_type_hints": "Unstable"}'
2+
--config enable_experimental_stx_features='{"polymorphic_function_hints": "Unstable","function_references":"Unstable","polymorphic_lambda": "Unstable","union_intersection_type_hints": "Unstable","type_const_super_bound":"Unstable"}'
33
--config poly_function_pointers=true
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?hh
2+
<<file: __EnableUnstableFeatures('type_const_super_bound')>>
3+
<<file: __EnableUnstableFeatures('polymorphic_function_hints')>>
4+
5+
abstract class BoundedTyconst {
6+
abstract const type Ta super Wibble;
7+
8+
public function elaborate(this::Ta $_): void {}
9+
}
10+
11+
interface Wibble {
12+
}
13+
14+
function test(): void {
15+
$fptr = meth_caller(BoundedTyconst::class, 'elaborate');
16+
hh_expect<
17+
HH\FunctionRef<(readonly function<Ta1 super Wibble>(
18+
BoundedTyconst with { type Ta = Ta1 },
19+
Ta1,
20+
): void)>,
21+
>($fptr);
22+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
No errors
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?hh
2+
<<file: __EnableUnstableFeatures('type_const_super_bound')>>
3+
<<file: __EnableUnstableFeatures('polymorphic_function_hints')>>
4+
5+
abstract class BoundedTyconst {
6+
abstract const type Ta as Wobble super Wibble;
7+
8+
public function elaborate(this::Ta $_): void {}
9+
}
10+
11+
abstract class Wobble {
12+
}
13+
14+
abstract class Wibble extends Wobble {
15+
}
16+
17+
function test(): void {
18+
$fptr = meth_caller(BoundedTyconst::class, 'elaborate');
19+
hh_expect<
20+
HH\FunctionRef<(readonly function<Ta1 as Wobble super Wibble>(
21+
BoundedTyconst with { type Ta = Ta1 },
22+
Ta1,
23+
): void)>,
24+
>($fptr);
25+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
No errors
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?hh
2+
<<file: __EnableUnstableFeatures('type_const_super_bound')>>
3+
<<file: __EnableUnstableFeatures('polymorphic_function_hints')>>
4+
5+
abstract class BoundedTyconst {
6+
abstract const type Ta as Wobble super Wibble;
7+
8+
public function elaborate(this::Ta $_): void {}
9+
}
10+
11+
abstract class Wobble {
12+
}
13+
14+
// Wibble is not a subtype of Wobble
15+
interface Wibble {
16+
}
17+
18+
function expecting<T>(T $_): void {}
19+
20+
function test(): void {
21+
$fptr = meth_caller(BoundedTyconst::class, 'elaborate');
22+
// Error! Wibble is not a subtype of Wobble
23+
hh_expect<
24+
HH\FunctionRef<(readonly function<Ta1 as Wobble super Wibble>(
25+
BoundedTyconst with { type Ta = Ta1 },
26+
Ta1,
27+
): void)>,
28+
>($fptr);
29+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
ERROR: File "type_const_super_bounds_both_bad.php", line 20, characters 1-293:
2+
Incomplete position information! We couldn't find the exact line of your type error in this definition. Please run `hh rage` and post in https://fb.workplace.com/groups/hackforhiphop/. (Typing[4323])
3+
File "type_const_super_bounds_both_bad.php", line 8, characters 19-27:
4+
Typing error
5+
File "type_const_super_bounds_both_bad.php", line 8, characters 35-36:
6+
`Ta#1` is a constrained type parameter
7+
File "type_const_super_bounds_both_bad.php", line 6, characters 29-34:
8+
This type constraint is violated
9+
File "type_const_super_bounds_both_bad.php", line 6, characters 29-34:
10+
Expected `Wobble`
11+
File "type_const_super_bounds_both_bad.php", line 6, characters 42-47:
12+
But got `Wibble`
13+
ERROR: File "type_const_super_bounds_both_bad.php", line 24, characters 20-135:
14+
Typing error (Typing[4323])
15+
File "type_const_super_bounds_both_bad.php", line 24, characters 39-41:
16+
`Ta1` is a constrained type parameter
17+
File "type_const_super_bounds_both_bad.php", line 24, characters 46-51:
18+
This type constraint is violated
19+
File "type_const_super_bounds_both_bad.php", line 24, characters 46-51:
20+
Expected `Wobble`
21+
File "type_const_super_bounds_both_bad.php", line 24, characters 59-64:
22+
But got `Wibble`
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?hh
2+
<<file: __EnableUnstableFeatures('type_const_super_bound')>>
3+
<<file: __EnableUnstableFeatures('polymorphic_function_hints')>>
4+
5+
abstract class BoundedTyconst {
6+
abstract const type Ta as Wobble super Wibble;
7+
8+
public function elaborate(this::Ta $_, this::Ta::Tb $_): void {}
9+
}
10+
11+
abstract class Wobble {
12+
abstract const type Tb as Huge super Tiny;
13+
}
14+
abstract class Wibble extends Wobble {
15+
abstract const type Tb as Bigly super Smol;
16+
}
17+
18+
abstract class Huge {
19+
}
20+
abstract class Bigly extends Huge {
21+
}
22+
abstract class Smol extends Bigly {
23+
}
24+
abstract class Tiny extends Smol {
25+
}
26+
27+
function test(): void {
28+
$fptr = meth_caller(BoundedTyconst::class, 'elaborate');
29+
hh_expect<
30+
HH\FunctionRef<(readonly function<
31+
Ta1 as Wobble with { type Tb = Tb1 } super Wibble with { type Tb = Tb1 },
32+
Tb1 as Bigly super Smol,
33+
>(BoundedTyconst with { type Ta = Ta1 }, Ta1, Tb1): void)>,
34+
>($fptr);
35+
}
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)