2 * Copyright (c) 2018, Facebook, Inc.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
10 (* Typing code concerned the <<__PPL>> attribute. *)
15 module Cls
= Typing_classes_heap
17 module TLazyHeap
= Typing_lazy_heap
19 let has_ppl_attribute c
=
22 (fun { ua_name
; _
} -> SN.UserAttributes.uaProbabilisticModel
= snd ua_name
)
24 (* If an object's type is wrapped in a Tabstract, recurse until we've hit the base *)
25 let rec base_type ty
=
27 | Tabstract
(_
, Some ty
) -> base_type ty
31 * Given a class, check the class's direct ancestors to verify that if
32 * one member is annotated with the <<__PPL>> attribute, then all of them are.
34 let check_ppl_class c
=
35 let is_ppl = has_ppl_attribute c
in
36 let child_class_string = Ast_defs.string_of_class_kind c
.c_kind
in
37 let c_pos = fst c
.c_name
in
38 let error = Errors.extend_ppl
c_pos child_class_string is_ppl in
39 let check verb parent_class_string
=
41 | _
, Nast.Happly
((_
, name
), _
) ->
42 begin match TLazyHeap.get_class name
with
44 if Cls.ppl parent_type
<> is_ppl
45 then error (Cls.pos parent_type
) parent_class_string
(Cls.name parent_type
) verb
50 List.iter
(c
.c_extends
) (check "extend" "class");
51 List.iter
(c
.c_implements
) (check "implement" "interface");
52 List.iter
(c
.c_uses
) (check "use" "trait");
53 List.iter
(c
.c_req_extends
) (check "require" "class");
54 List.iter
(c
.c_req_implements
) (check "require" "interface")
57 * When we call a method on an object, if the object is a <<__PPL>> object,
58 * then we can only call it via using the $this->method(...) syntax.
60 * This limits the ability to call it in a way that we are unable to rewrite.
62 let check_ppl_obj_get env
((p
, ty
), e
) =
64 match snd
(base_type ty
) with
65 | Tclass
((_
, name
), _
, _
) ->
67 match TLazyHeap.get_class name
with
68 | Some cls
when Cls.ppl cls
->
69 if not
@@ Env.get_inside_ppl_class env
70 then Errors.invalid_ppl_call p
"from a different class";
71 if Env.get_inside_constructor env
72 then Errors.invalid_ppl_call p
"from inside a <<__PPL>> class constructor";
73 if not
(phys_equal e This
)
74 then Errors.invalid_ppl_call p
75 "inside a <<__PPL>> class unless using $this-> or $this:: syntax";
80 let _, type_list
= Env.get_concrete_supertypes env ty
in
81 List.iter type_list
check_type
84 * If we are calling a parent method from within a ppl class, we cannot be in
85 * the constructor of the child class.
87 * We will have already considered parent::__construct.
89 let check_ppl_parent_method env p
=
90 if Env.get_inside_ppl_class env
&& Env.get_inside_constructor env
91 then Errors.invalid_ppl_static_call p
"inside a <<__PPL>> class constructor"
94 * When we call a static method on a class, do not allow ClassName::method
95 * because we are unable to detect whether the class being referred to
96 * is a <<__PPL>> annotated class during codegen.
98 let check_ppl_class_const env p e
=
103 if Env.get_inside_ppl_class env
&& Env.get_inside_constructor env
104 then Errors.invalid_ppl_static_call p
"inside a <<__PPL>> class constructor"
108 match TLazyHeap.get_class name
with
109 | Some cls
when Cls.ppl cls
->
110 Errors.invalid_ppl_static_call p
"by classname. Use self::, static::, or parent::"
113 | CIexpr e
-> check_ppl_obj_get env e
115 let check_ppl_meth_pointers p classname special_name
=
116 match TLazyHeap.get_class classname
with
117 | Some cls
when Cls.ppl cls
-> Errors.ppl_meth_pointer p special_name
120 let check_ppl_inst_meth env
((p
, ty
), _) =
122 match snd
(base_type ty
) with
123 | Tclass
((_, name
), _, _) ->
125 match TLazyHeap.get_class name
with
126 | Some cls
when Cls.ppl cls
-> Errors.ppl_meth_pointer p
"inst_meth"
130 let _, type_list
= Env.get_concrete_supertypes env ty
in
131 List.iter type_list
check_type
133 let on_call_expr env
((p
, _), x
) =
135 | Obj_get
(e
, (_, _), _) -> check_ppl_obj_get env e
136 | Class_const
((_, CIparent
), (_, construct
)) when construct
= SN.Members.__construct
-> ()
137 | Class_const
((_, CIparent
), _) -> check_ppl_parent_method env p
138 | Class_const
((_, e
), _) -> check_ppl_class_const env p e
142 inherit Tast_visitor.handler_base
144 method! at_expr env
((p
, _), x
) =
146 | Call
(_, e
, _, _, _) -> on_call_expr env e
148 | Smethod_id
((_, classname
), _) -> check_ppl_meth_pointers p classname
"class_meth"
150 | Method_caller
((_, classname
), _) -> check_ppl_meth_pointers p classname
"meth_caller"
152 | Method_id
(instance
, _) -> check_ppl_inst_meth env instance
155 method! at_class_ _env c
= check_ppl_class c