-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Summary: We introduce two new type aliases to the `HH\FIXME` namespace such that | Alias | Current Value | Sound Dynamic Value | | -- | -- | -- | | POISON_MARKER<T> | T | ~T | | TANY_MARKER<T> | Tany | T | > NOTE: in the examples below, commented out method declarations represent the code before migration. `POISON_MARKER` will be used for hierarchy poisoning when an unenforceable type overrides an enforced one e.g. a closure ``` class C { // public function f(): nonnull {} public function f(): HH\FIXME\POISON_MARKER<nonnull> {} } class D extends C { public function f(): (function (): void) { /* HH_FIXME[4110] */ return null; } } /** * POISON_MARKER will retain current behavior -- expression has type nonnull * but will become ~nonnull under sound dynamic */ function get_nonnull(C $c): nonnull { return $c->f(); // type hint violation, returning null } function test(): void { get_nonnull(new D()); } ``` `TANY_MARKER` will be used for migrating existing uses of Tany to desired types under sound dynamic without affecting current inference. This is why it points to `T` and not `~T` -- we want full manual control here. In some cases we may want a combination of TANY_MARKER and POISON_MARKER. ``` class C { // public function f(): int { public function f(): HH\FIXME\POISON_MARKER<arraykey> { // slightly weaken enforcement return 1; } } class D extends C { // public function f(): DECL_TANY { public function f(): HH\FIXME\TANY_MARKER<string> { return "hello"; } } class E extends D { public function f(): string { return "hello"; } } ``` ## Implementation There is some sleight of hand here - despite outward appearance, the implementation of these aliases diverges. - For `POISON_MARKER`, I've stripped off the alias for both type constraints and type structures, now matches like types in hint positions and almost matches for type structures (see test cases). The upshot is the runtime doesn't know about POISON_MARKER's existence. - For `TANY_MARKER`, I strip off the type arguments to simulate how we do decl Tanys, but HHVM still needs to have the symbol name in scope to create the OF_GENERIC type structure, so it's declared in systemlib. See the `tany.php` example from D40516837 (9e8c173) for an analogue. Reviewed By: andrewjkennedy Differential Revision: D40371013 fbshipit-source-id: d2d9e4f4d57f6f88d1c31201d60d9c9e19656173
- Loading branch information
1 parent
8159883
commit bb5e5d6
Showing
17 changed files
with
198 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<?hh | ||
|
||
function f( | ||
HH\FIXME\TANY_MARKER<int> $tany, | ||
HH\FIXME\POISON_MARKER<string> $poison, | ||
vec<HH\FIXME\TANY_MARKER<float>> $vec_float, | ||
vec<HH\FIXME\TANY_MARKER<HH\FIXME\POISON_MARKER<float>>> $vec_like_float, | ||
): void { | ||
hh_show($tany); | ||
hh_show($poison); | ||
hh_show($vec_float); | ||
hh_show($vec_like_float); | ||
} |
9 changes: 9 additions & 0 deletions
9
hphp/hack/test/sound_dynamic/typing/marker_types.good.php.exp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
File "marker_types.good.php", line 9, characters 3-16: | ||
int | ||
File "marker_types.good.php", line 10, characters 3-18: | ||
~string | ||
File "marker_types.good.php", line 11, characters 3-21: | ||
vec<float> | ||
File "marker_types.good.php", line 12, characters 3-26: | ||
vec<~float> | ||
No errors |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<?hh | ||
|
||
function f( | ||
HH\FIXME\TANY_MARKER<int> $tany, | ||
HH\FIXME\POISON_MARKER<string> $poison, | ||
vec<HH\FIXME\TANY_MARKER<float>> $vec_tany, | ||
vec<HH\FIXME\TANY_MARKER<HH\FIXME\POISON_MARKER<float>>> $vec_tany2, | ||
): void { | ||
hh_show($tany); | ||
hh_show($poison); | ||
hh_show($vec_tany); | ||
hh_show($vec_tany2); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
File "sound_dynamic_marker_types.php", line 9, characters 3-16: | ||
_ | ||
File "sound_dynamic_marker_types.php", line 10, characters 3-18: | ||
string | ||
File "sound_dynamic_marker_types.php", line 11, characters 3-20: | ||
vec<_> | ||
File "sound_dynamic_marker_types.php", line 12, characters 3-21: | ||
vec<_> | ||
No errors |
6 changes: 6 additions & 0 deletions
6
hphp/hack/test/typecheck/sound_dynamic_marker_types_is_as.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
<?hh | ||
|
||
function f(): void { | ||
3 as HH\FIXME\TANY_MARKER<int>; | ||
4 as HH\FIXME\POISON_MARKER<string>; | ||
} |
8 changes: 8 additions & 0 deletions
8
hphp/hack/test/typecheck/sound_dynamic_marker_types_is_as.php.exp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
File "sound_dynamic_marker_types_is_as.php", line 4, characters 8-32: | ||
Invalid `as` expression hint (Typing[4195]) | ||
File "sound_dynamic_marker_types_is_as.php", line 4, characters 8-32: | ||
The `as` operator cannot be used with a type with generics, because generics are erased at runtime | ||
File "sound_dynamic_marker_types_is_as.php", line 5, characters 8-37: | ||
Invalid `as` expression hint (Typing[4195]) | ||
File "sound_dynamic_marker_types_is_as.php", line 5, characters 8-37: | ||
The `as` operator cannot be used with a type with generics, because generics are erased at runtime |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -571,3 +571,7 @@ function reflection_class_is_interface( | |
|
||
|
||
} | ||
|
||
namespace HH\FIXME { | ||
type TANY_MARKER<T> = T; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<?hh | ||
|
||
function f<reify T>(<<__Soft>> T $t): void { | ||
echo "\$t: $t [reified]\n"; | ||
} | ||
function f_poison(<<__Soft>> HH\FIXME\POISON_MARKER<int> $poison): void { | ||
echo "\$poison: $poison\n"; | ||
} | ||
|
||
class Typeconsts { | ||
const type Tpoison = HH\FIXME\POISON_MARKER<int>; | ||
} | ||
|
||
<<__EntryPoint>> | ||
function main(): void { | ||
printf("\n===== HH\FIXME\POISON_MARKER<int> =====\n"); | ||
f_poison(4); | ||
f_poison("not poison int"); | ||
f<HH\FIXME\POISON_MARKER<int>>(4); | ||
f<HH\FIXME\POISON_MARKER<int>>("not poison int"); | ||
|
||
printf("\n===== Typeconsts::Tpoison =====\n"); | ||
f<Typeconsts::Tpoison>(4); | ||
f<Typeconsts::Tpoison>("not poison int [typeconst]"); | ||
|
||
$rt = new ReflectionClass(Typeconsts::class)->getTypeConstant("Tpoison"); | ||
printf("Type structure kind: %d\n", $rt->getTypeStructure()["kind"]); | ||
printf("Assigned type text: %s\n", $rt->getAssignedTypeText() ?? "<missing>"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
===== HH\FIXME\POISON_MARKER<int> ===== | ||
$poison: 4 | ||
|
||
Warning: Argument 1 to f_poison() must be of type @int, string given in %s/test/slow/sound_dynamic/poison_int.php on line 18 | ||
$poison: not poison int | ||
$t: 4 [reified] | ||
|
||
Warning: Argument 1 passed to f() must be an instance of @int, string given in %s/test/slow/sound_dynamic/poison_int.php on line 5 | ||
$t: not poison int [reified] | ||
|
||
===== Typeconsts::Tpoison ===== | ||
$t: 4 [reified] | ||
|
||
Warning: Argument 1 passed to f() must be an instance of @int, string given in %s/test/slow/sound_dynamic/poison_int.php on line 5 | ||
$t: not poison int [typeconst] [reified] | ||
Type structure kind: 1 | ||
Assigned type text: HH\int |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<?hh | ||
|
||
function f<reify T>(<<__Soft>> T $t): void { | ||
echo "\$t: $t [reified]\n"; | ||
} | ||
function f_tany_int(<<__Soft>> HH\FIXME\TANY_MARKER<int> $tany_int): void { | ||
echo "\$tany_int: $tany_int\n"; | ||
} | ||
|
||
class Typeconsts { | ||
const type Tany_int = HH\FIXME\TANY_MARKER<int>; | ||
} | ||
|
||
<<__EntryPoint>> | ||
function main(): void { | ||
printf("\n===== HH\FIXME\TANY_MARKER<int> =====\n"); | ||
f_tany_int(4); | ||
f_tany_int("not Tany int"); | ||
f<HH\FIXME\TANY_MARKER<int>>(4); | ||
f<HH\FIXME\TANY_MARKER<int>>("not Tany int"); | ||
|
||
printf("\n===== Typeconsts::Tany_int =====\n"); | ||
f<Typeconsts::Tany_int>(4); | ||
f<Typeconsts::Tany_int>("not Tany int [typeconst]"); | ||
|
||
$rt = new ReflectionClass(Typeconsts::class)->getTypeConstant("Tany_int"); | ||
printf("Type structure kind: %d\n", $rt->getTypeStructure()["kind"]); | ||
printf("Assigned type text: %s\n", $rt->getAssignedTypeText() ?? "<missing>"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
===== HH\FIXME\TANY_MARKER<int> ===== | ||
$tany_int: 4 | ||
$tany_int: not Tany int | ||
$t: 4 [reified] | ||
$t: not Tany int [reified] | ||
|
||
===== Typeconsts::Tany_int ===== | ||
$t: 4 [reified] | ||
$t: not Tany int [typeconst] [reified] | ||
Type structure kind: 13 | ||
Assigned type text: HH\FIXME\TANY_MARKER |