Skip to content

Commit 269854f

Browse files
mheiberfacebook-github-bot
authored andcommitted
more flexible reified check for final classes
Summary: ## What loosen a reified check, see test case ## Why The reified check (among other things) prevents trying to reify an unknown type. So it is understandably careful with late static bindings, since there are cases where the type cannot be known statically. However, in final classes, `this` isn't really late static binding: we know that it just refers to the lexically enclosing class and so the type is known. Reviewed By: andrewjkennedy Differential Revision: D75142486 fbshipit-source-id: 2541472b4a9d9431989f9dea41477c612bb7e26b
1 parent 47173f3 commit 269854f

File tree

6 files changed

+52
-5
lines changed

6 files changed

+52
-5
lines changed

hphp/hack/src/typing/tast_check/reified_check.ml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
open Hh_prelude
1111
open Aast
1212
open Typing_defs
13-
open Typing_reified_check (* validator *)
1413
module Env = Tast_env
1514
module SN = Naming_special_names
1615
module UA = SN.UserAttributes
@@ -118,7 +117,7 @@ let verify_targ_valid env reification tparam targ =
118117
err
119118
in
120119

121-
validator#validate_hint
120+
Typing_reified_check.validator#validate_hint
122121
(Tast_env.tast_env_as_typing_env env)
123122
(snd targ)
124123
~reification

hphp/hack/src/typing/type_validator.ml

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ type validation_state = {
2828
inside_reified_class_generic_position: bool;
2929
reification: reification;
3030
expanded_typedefs: SSet.t;
31+
class_from_taccess_lhs: Folded_class.t option;
3132
}
3233

3334
type error_emitter = Pos.t -> (Pos_or_decl.t * string) list Lazy.t -> unit
@@ -94,8 +95,15 @@ class virtual type_validator =
9495
already reported an error. *)
9596
None
9697
| Ok ety_env ->
97-
Some (this#on_typeconst { acc with ety_env } class_ typeconst)
98-
)
98+
(* stash and restore `class_from_taccess_lhs` *)
99+
let { class_from_taccess_lhs; _ } = acc in
100+
let acc =
101+
this#on_typeconst
102+
{ acc with ety_env; class_from_taccess_lhs = Some class_ }
103+
class_
104+
typeconst
105+
in
106+
Some { acc with class_from_taccess_lhs } )
99107
| _ -> acc)
100108

101109
method! on_tapply acc r (pos, name) tyl =
@@ -178,6 +186,7 @@ class virtual type_validator =
178186
validity = Valid;
179187
inside_reified_class_generic_position = false;
180188
reification;
189+
class_from_taccess_lhs = None;
181190
}
182191
root_ty
183192
in

hphp/hack/src/typing/type_validator.mli

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ type validation_state = {
2222
inside_reified_class_generic_position: bool;
2323
reification: reification;
2424
expanded_typedefs: SSet.t;
25+
(**
26+
`Some Klass` if we're traversing a type and have gone through `Klass::TheTy`.
27+
*)
28+
class_from_taccess_lhs: Folded_class.t option;
2529
}
2630

2731
type error_emitter = Pos.t -> (Pos_or_decl.t * string) list Lazy.t -> unit

hphp/hack/src/typing/typing_reified_check.ml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,16 @@ let validator =
7979
super#on_taccess acc r (root, ids)
8080

8181
method! on_tthis acc r =
82-
this#invalid acc r "the late static bound `this` type"
82+
let is_known_to_be_final =
83+
match acc.class_from_taccess_lhs with
84+
| Some class_ -> Folded_class.final class_
85+
| None -> false
86+
in
87+
if is_known_to_be_final then
88+
(* In a final class, `this` is known statically and so is safe here *)
89+
acc
90+
else
91+
this#invalid acc r "the late static bound `this` type"
8392

8493
method! on_trefinement acc r _ty _ = this#invalid acc r "type refinement"
8594
end
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?hh
2+
3+
type Id_of<+T> = int;
4+
5+
final class C1 {
6+
const type T = Id_of<this>;
7+
}
8+
9+
class C2 {
10+
const type T = Id_of<this>;
11+
}
12+
13+
function take_refied<reify T>(): void {}
14+
15+
function test(): void {
16+
// OK
17+
take_refied<C1::T>();
18+
// error
19+
take_refied<C2::T>();
20+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
ERROR: File "this_is_like_id_in_final_classes.php", line 19, characters 15-19:
2+
Invalid reified hint (Typing[4305])
3+
File "this_is_like_id_in_final_classes.php", line 10, characters 24-27:
4+
This is the late static bound `this` type, it cannot be used as a reified type argument
5+
File "this_is_like_id_in_final_classes.php", line 13, characters 28-28:
6+
`T` is reified

0 commit comments

Comments
 (0)