2 * Copyright (c) 2015, 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 (** Module "naming" a program.
12 * The naming phase consists in several things
13 * 1- get all the global names
14 * 2- transform all the local names into a unique identifier
22 module SN
= Naming_special_names
23 module NS
= Namespaces
24 module Partial
= Partial_provider
25 module GEnv
= Naming_global.GEnv
27 (*****************************************************************************)
29 (*****************************************************************************)
31 (* We want to keep the positions of names that have been
32 * replaced by identifiers.
34 type positioned_ident
= Pos.t
* Local_id.t
39 (* strict? decl? partial? *)
40 in_mode
: FileInfo.mode
;
41 (* various options that control the strictness of the typechecker *)
42 ctx
: Provider_context.t
;
43 (* In function foo<T1, ..., Tn> or class<T1, ..., Tn>, the field
44 * type_params knows T1 .. Tn. It is able to find out about the
45 * constraint on these parameters. *)
47 (* The current class, None if we are in a function *)
48 current_cls
: (Ast_defs.id
* Ast_defs.class_kind
* is_final
) option;
49 (* Namespace environment, e.g., what namespace we're in and what use
50 * declarations are in play. *)
51 namespace
: Namespace_env.env
;
54 (* Handler called when we see an unbound name. *)
55 type unbound_handler
= Pos.t
* string -> positioned_ident
57 (* The primitives to manipulate the naming environment *)
61 val empty_local
: unbound_handler
option -> lenv
63 val make_class_env
: Provider_context.t
-> Nast.class_
-> genv
* lenv
65 val make_typedef_env
: Provider_context.t
-> Nast.typedef
-> genv
* lenv
67 val make_top_level_env
: Provider_context.t
-> genv
* lenv
69 val make_fun_decl_genv
: Provider_context.t
-> Nast.fun_
-> genv
71 val make_file_attributes_env
:
72 Provider_context.t
-> FileInfo.mode
-> Aast.nsenv
-> genv
* lenv
74 val make_const_env
: Provider_context.t
-> Nast.gconst
-> genv
* lenv
76 val add_lvar
: genv
* lenv
-> Ast_defs.id
-> positioned_ident
-> unit
78 val add_param
: genv
* lenv
-> Nast.fun_param
-> genv
* lenv
80 val new_lvar
: genv
* lenv
-> Ast_defs.id
-> positioned_ident
82 val lvar
: genv
* lenv
-> Ast_defs.id
-> positioned_ident
84 val scope
: genv
* lenv
-> (genv
* lenv
-> 'a
) -> 'a
86 val remove_locals
: genv
* lenv
-> Ast_defs.id list
-> unit
88 type map
= positioned_ident
SMap.t
90 (* The local environment *)
92 (* The set of locals *)
94 (* Handler called when we see an unbound name.
95 * This is used to compute an approximation of the list of captured
96 * variables for closures: when we see an undefined variable, we add it
97 * to the list of captured variables.
99 * See expr_lambda for details.
101 unbound_handler
: unbound_handler
option;
104 let get_tparam_names paraml
=
107 ~f
:(fun { Aast.tp_name
= (_
, x
); _
} acc
-> SSet.add x acc
)
110 let empty_local unbound_handler
= { locals
= ref SMap.empty
; unbound_handler
}
112 let make_class_genv ctx tparams mode
(cid
, ckind
) namespace final
=
116 type_params
= get_tparam_names tparams
;
117 current_cls
= Some
(cid
, ckind
, final
);
121 let make_class_env ctx c
=
127 (c
.Aast.c_name
, c
.Aast.c_kind
)
131 let lenv = empty_local None
in
134 let make_typedef_genv ctx tparams tdef_namespace
=
136 in_mode
= FileInfo.Mstrict
;
138 type_params
= get_tparam_names tparams
;
140 namespace
= tdef_namespace
;
143 let make_typedef_env ctx tdef
=
145 make_typedef_genv ctx tdef
.Aast.t_tparams tdef
.Aast.t_namespace
147 let lenv = empty_local None
in
150 let make_fun_genv ctx params f_mode f_namespace
=
154 type_params
= get_tparam_names params
;
156 namespace
= f_namespace
;
159 let make_fun_decl_genv ctx f
=
160 make_fun_genv ctx f
.Aast.f_tparams f
.Aast.f_mode f
.Aast.f_namespace
162 let make_const_genv ctx cst
=
164 in_mode
= cst
.Aast.cst_mode
;
166 type_params
= SSet.empty
;
168 namespace
= cst
.Aast.cst_namespace
;
171 let make_top_level_genv ctx
=
173 in_mode
= FileInfo.Mpartial
;
175 type_params
= SSet.empty
;
177 namespace
= Namespace_env.empty_with_default
;
180 let make_top_level_env ctx
=
181 let genv = make_top_level_genv ctx
in
182 let lenv = empty_local None
in
183 let env = (genv, lenv) in
186 let make_file_attributes_genv ctx mode namespace
=
190 type_params
= SSet.empty
;
195 let make_file_attributes_env ctx mode namespace
=
196 let genv = make_file_attributes_genv ctx mode namespace
in
197 let lenv = empty_local None
in
198 let env = (genv, lenv) in
201 let make_const_env ctx cst
=
202 let genv = make_const_genv ctx cst
in
203 let lenv = empty_local None
in
204 let env = (genv, lenv) in
207 (* Adds a local variable, without any check *)
208 let add_lvar (_
, lenv) (_
, name
) (p
, x
) =
209 lenv.locals
:= SMap.add name
(p
, x
) !(lenv.locals
);
212 let add_param env param
=
213 let p_name = param
.N.param_name
in
214 let id = Local_id.make_unscoped
p_name in
215 let p_pos = param
.N.param_pos
in
216 let () = add_lvar env (p_pos, p_name) (p_pos, id) in
219 (* Defines a new local variable.
221 1) if the local is not in the local environment then it is added.
222 Return value: the given position and deduced/created identifier. *)
223 let new_lvar (_
, lenv) (p
, x
) =
224 let lcl = SMap.find_opt x
!(lenv.locals
) in
227 | Some
lcl -> snd
lcl
229 let ident = Local_id.make_unscoped x
in
230 lenv.locals
:= SMap.add x
(p
, ident) !(lenv.locals
);
235 let handle_undefined_variable (_genv
, env) (p
, x
) =
236 match env.unbound_handler
with
237 | None
-> (p
, Local_id.make_unscoped x
)
240 (* Function used to name a local variable *)
241 let lvar (genv, env) (p
, x
) =
244 SN.Superglobals.is_superglobal x
245 && FileInfo.equal_mode
genv.in_mode
FileInfo.Mpartial
247 (p
, Local_id.make_unscoped x
)
249 let lcl = SMap.find_opt x
!(env.locals
) in
251 | Some
lcl -> (p
, snd
lcl)
252 | None
-> handle_undefined_variable (genv, env) (p
, x
)
256 (* Scope, keep the locals, go and name the body, and leave the
257 * local environment intact
260 let (_genv
, lenv) = env in
261 let lenv_copy = !(lenv.locals
) in
263 lenv.locals
:= lenv_copy;
266 let remove_locals env vars
=
267 let (_genv
, lenv) = env in
271 ~f
:(fun l
id -> SMap.remove
(snd
id) l
)
275 (*****************************************************************************)
277 (*****************************************************************************)
279 let elaborate_namespaces =
280 new Naming_elaborate_namespaces_endo.generic_elaborator
282 let check_repetition s param
=
283 let name = param
.Aast.param_name
in
284 if SSet.mem
name s
then Errors.already_bound param
.Aast.param_pos
name;
285 if not
(String.equal
name SN.SpecialIdents.placeholder
) then
290 let check_name (p
, name) =
291 (* We perform this check here because currently, naming edits the AST to add
292 * a parent node of this class to enums during the AST transform *)
294 ( String.equal
name SN.Classes.cHH_BuiltinEnum
295 || String.equal
name SN.Classes.cHH_BuiltinEnumClass
)
296 && not
(string_ends_with
(Relative_path.suffix
(Pos.filename p
)) ".hhi")
298 Errors.using_internal_class p
(strip_ns
name)
300 let convert_shape_name env = function
301 | Ast_defs.SFlit_int
(pos
, s
) -> Ast_defs.SFlit_int
(pos
, s
)
302 | Ast_defs.SFlit_str
(pos
, s
) -> Ast_defs.SFlit_str
(pos
, s
)
303 | Ast_defs.SFclass_const
((class_pos
, class_name
), (const_pos
, const_name
)) ->
304 (* e.g. Foo::BAR or self::BAR. The first tuple is the use of Foo, second is the use of BAR *)
305 (* We will resolve class-name 'self' *)
307 if String.equal
class_name SN.Classes.cSelf
then (
308 match (fst
env).current_cls
with
309 | Some
((_class_decl_pos
, class_name), _
, _
) -> class_name
311 Errors.self_outside_class class_pos
;
314 let () = check_name (class_pos
, class_name) in
317 Ast_defs.SFclass_const
((class_pos
, class_name), (const_pos
, const_name
))
319 let arg_unpack_unexpected = function
322 Errors.naming_too_few_arguments pos
;
325 (************************************************************************)
326 (* Naming of type hints *)
327 (************************************************************************)
330 * The existing hint function goes from Ast_defs.hint -> Nast.hint
331 * This hint function goes from Aast.hint -> Nast.hint
332 * Used with with Ast_to_nast to go from Ast_defs.hint -> Nast.hint
335 ?
(forbid_this
= false)
336 ?
(allow_retonly
= false)
337 ?
(allow_wildcard
= false)
338 ?
(allow_like
= false)
339 ?
(in_where_clause
= false)
340 ?
(ignore_hack_arr
= false)
357 and contexts
env ctxs
=
358 let (pos
, hl
) = ctxs
in
363 | (p
, Aast.Happly
((_
, wildcard
), []))
364 when String.equal wildcard
SN.Typehints.wildcard
->
365 (* More helpful wildcard error for coeffects. We expect all valid
366 * wildcard hints to be transformed into Hfun_context *)
367 Errors.invalid_wildcard_context p
;
374 and hfun
env ro
hl il variadic_hint ctxs h readonly_ret
=
375 let variadic_hint = Option.map
variadic_hint (hint env) in
376 let hl = List.map ~f
:(hint env) hl in
377 let ctxs = Option.map ~f
:(contexts
env) ctxs in
384 hf_variadic_ty
= variadic_hint;
386 hf_return_ty
= hint ~allow_retonly
:true env h
;
387 hf_is_readonly_return
= readonly_ret
;
400 let tcopt = Provider_context.get_tcopt
(fst
env).ctx
in
401 let like_type_hints_enabled = TypecheckerOptions.like_type_hints
tcopt in
402 let hint = hint ~forbid_this ~allow_wildcard ~allow_like
in
404 | Aast.Hunion
hl -> N.Hunion
(List.map
hl ~f
:(hint ~allow_retonly
env))
405 | Aast.Hintersection
hl ->
406 N.Hintersection
(List.map
hl ~f
:(hint ~allow_retonly
env))
408 N.Htuple
(List.map
hl ~f
:(hint ~allow_retonly ~tp_depth
:(tp_depth
+ 1) env))
410 (* void/noreturn are permitted for Typing.option_return_only_typehint *)
411 N.Hoption
(hint ~allow_retonly
env h
)
413 if not
(allow_like
|| like_type_hints_enabled) then
414 Errors.experimental_feature p
"like-types";
415 N.Hlike
(hint ~allow_retonly
env h
)
417 let h = hint ~allow_retonly
env h in
418 if TypecheckerOptions.interpret_soft_types_as_like_types
tcopt then
428 hf_variadic_ty
= variadic_hint;
431 hf_is_readonly_return
= readonly_ret
;
433 hfun
env ro
hl il
variadic_hint ctxs h readonly_ret
434 | Aast.Happly
(((p
, _x
) as id), hl) ->
452 if not
(List.is_empty
hl) then Errors.unexpected_type_arguments p
455 | Aast.Haccess
((pos
, root_id
), ids
) ->
458 | Aast.Happly
((pos
, x
), _
) when String.equal x
SN.Classes.cSelf
->
460 match (fst
env).current_cls
with
462 Errors.self_outside_class pos
;
464 | Some
(cid
, _
, _
) -> N.Happly
(cid
, [])
466 | Aast.Happly
((pos
, x
), _
)
467 when String.equal x
SN.Classes.cStatic
468 || String.equal x
SN.Classes.cParent
->
469 Errors.invalid_type_access_root
(pos
, x
);
471 | Aast.Happly
(root
, _
) ->
476 ~allow_wildcard
:false
477 ~ignore_hack_arr
:false
488 | N.Habstr _
when in_where_clause
-> h
490 Errors.invalid_type_access_root root
;
493 | Aast.Hvar n
-> N.Hvar n
495 Errors.internal_error
497 "Malformed hint: expected Haccess (Happly ...) from ast_to_nast";
500 N.Haccess
((pos
, root_ty), ids
)
501 | Aast.Hshape
{ Aast.nsi_allows_unknown_fields
; nsi_field_map
} ->
504 ~f
:(fun { Aast.sfi_optional
; sfi_hint
; sfi_name
} ->
505 let new_key = convert_shape_name env sfi_name
in
510 hint ~allow_retonly ~tp_depth
:(tp_depth
+ 1) env sfi_hint
;
517 N.Hshape
{ N.nsi_allows_unknown_fields
; nsi_field_map }
518 | Aast.Hmixed
-> N.Hmixed
519 | Aast.Hfun_context n
-> N.Hfun_context n
520 | Aast.Hvar n
-> N.Hvar n
527 | Aast.Hvarray_or_darray _
528 | Aast.Hvec_or_dict _
533 Errors.internal_error
Pos.none
"Unexpected hint not present on legacy AST";
545 let params = (fst
env).type_params
in
546 (* some common Xhp screw ups *)
547 if String.equal x
"Xhp" || String.equal x
":Xhp" || String.equal x
"XHP" then
548 Errors.disallowed_xhp_type p x
;
564 | x
when String.equal x
SN.Typehints.wildcard
->
565 if allow_wildcard
&& tp_depth
>= 1 (* prevents 3 as _ *) then
566 if not
(List.is_empty
hl) then (
567 Errors.typaram_applied_to_type p x
;
572 Errors.wildcard_hint_disallowed p
;
576 when String.equal x
("\\" ^
SN.Typehints.void
)
577 || String.equal x
("\\" ^
SN.Typehints.null
)
578 || String.equal x
("\\" ^
SN.Typehints.noreturn
)
579 || String.equal x
("\\" ^
SN.Typehints.int)
580 || String.equal x
("\\" ^
SN.Typehints.bool)
581 || String.equal x
("\\" ^
SN.Typehints.float)
582 || String.equal x
("\\" ^
SN.Typehints.num
)
583 || String.equal x
("\\" ^
SN.Typehints.string)
584 || String.equal x
("\\" ^
SN.Typehints.resource
)
585 || String.equal x
("\\" ^
SN.Typehints.mixed
)
586 || String.equal x
("\\" ^
SN.Typehints.nonnull
)
587 || String.equal x
("\\" ^
SN.Typehints.arraykey
) ->
588 Errors.primitive_toplevel p
;
590 | x
when String.equal x
("\\" ^
SN.Typehints.nothing
) ->
591 Errors.primitive_toplevel p
;
593 | x
when String.equal x
SN.Typehints.void
&& allow_retonly
->
595 | x
when String.equal x
SN.Typehints.void
->
596 Errors.return_only_typehint p `void
;
598 | x
when String.equal x
SN.Typehints.noreturn
&& allow_retonly
->
600 | x
when String.equal x
SN.Typehints.noreturn
->
601 Errors.return_only_typehint p `noreturn
;
603 | x
when String.equal x
SN.Typehints.null
-> N.Hprim
N.Tnull
604 | x
when String.equal x
SN.Typehints.num
-> N.Hprim
N.Tnum
605 | x
when String.equal x
SN.Typehints.resource
-> N.Hprim
N.Tresource
606 | x
when String.equal x
SN.Typehints.arraykey
-> N.Hprim
N.Tarraykey
607 | x
when String.equal x
SN.Typehints.mixed
-> N.Hmixed
608 | x
when String.equal x
SN.Typehints.nonnull
-> N.Hnonnull
609 | x
when String.equal x
SN.Typehints.dynamic
-> N.Hdynamic
610 | x
when String.equal x
SN.Typehints.nothing
-> N.Hnothing
611 | x
when String.equal x
SN.Typehints.this
&& not forbid_this
->
612 if not
(phys_equal
hl []) then Errors.this_no_argument p
;
614 | x
when String.equal x
SN.Typehints.this
->
615 Errors.this_type_forbidden p
;
617 (* TODO: Duplicate of a Typing[4101] error if namespaced correctly
620 when (String.equal x
SN.Classes.cClassname
|| String.equal x
"classname")
621 && List.length
hl <> 1 ->
622 Errors.classname_param p
;
624 | _
when String.(lowercase x
= SN.Typehints.this
) ->
625 Errors.lowercase_this p x
;
627 | _
when SSet.mem x
params ->
628 let tcopt = Provider_context.get_tcopt
(fst
env).ctx
in
631 (not
(TypecheckerOptions.higher_kinded_types
tcopt))
632 && not
(List.is_empty
hl)
634 Errors.typaram_applied_to_type p x
;
646 ~tp_depth
:(tp_depth
+ 1)
650 let () = check_name id in
657 ~tp_depth
:(tp_depth
+ 1)
662 (* Hints that are valid both as casts and type annotations. Neither
663 * casts nor annotations are a strict subset of the other: For
664 * instance, 'object' is not a valid annotation. Thus callers will
665 * have to handle the remaining cases. *)
666 and try_castable_hint
667 ?
(forbid_this
= false)
668 ?
(allow_wildcard
= false)
678 ~tp_depth
:(tp_depth
+ 1)
683 (not ignore_hack_arr
)
684 && TypecheckerOptions.hack_arr_dv_arrs
685 (Provider_context.get_tcopt
(fst
env).ctx
)
687 let canon = String.lowercase x
in
690 | nm
when String.equal nm
SN.Typehints.int -> Some
(N.Hprim
N.Tint
)
691 | nm
when String.equal nm
SN.Typehints.bool -> Some
(N.Hprim
N.Tbool
)
692 | nm
when String.equal nm
SN.Typehints.float -> Some
(N.Hprim
N.Tfloat
)
693 | nm
when String.equal nm
SN.Typehints.string -> Some
(N.Hprim
N.Tstring
)
694 | nm
when String.equal nm
SN.Typehints.darray
->
698 if Partial.should_check_error
(fst
env).in_mode
2071 then
699 Errors.too_few_type_arguments p
;
701 N.Happly
((p
, SN.Collections.cDict
), [(p
, N.Hany
); (p
, N.Hany
)])
703 N.Hdarray
((p
, N.Hany
), (p
, N.Hany
))
705 Errors.too_few_type_arguments p
;
709 N.Happly
((p
, SN.Collections.cDict
), [hint env key_
; hint env val_
])
711 N.Hdarray
(hint env key_
, hint env val_
)
713 Errors.too_many_type_arguments p
;
715 | nm
when String.equal nm
SN.Typehints.varray
->
719 if Partial.should_check_error
(fst
env).in_mode
2071 then
720 Errors.too_few_type_arguments p
;
722 N.Happly
((p
, SN.Collections.cVec
), [(p
, N.Hany
)])
724 N.Hvarray
(p
, N.Hany
)
727 N.Happly
((p
, SN.Collections.cVec
), [hint env val_
])
729 N.Hvarray
(hint env val_
)
731 Errors.too_many_type_arguments p
;
733 | nm
when String.equal nm
SN.Typehints.varray_or_darray
->
737 if Partial.should_check_error
(fst
env).in_mode
2071 then
738 Errors.too_few_type_arguments p
;
741 N.Hvec_or_dict
(None
, (p
, N.Hany
))
743 (* Warning: These Hanys are here because they produce subtle
744 errors because of interaction with tco_experimental_isarray
745 if you change them to Herr *)
746 N.Hvarray_or_darray
(None
, (p
, N.Hany
))
749 N.Hvec_or_dict
(None
, hint env val_
)
751 N.Hvarray_or_darray
(None
, hint env val_
)
754 N.Hvec_or_dict
(Some
(hint env key
), hint env val_
)
756 N.Hvarray_or_darray
(Some
(hint env key
), hint env val_
)
758 Errors.too_many_type_arguments p
;
760 | nm
when String.equal nm
SN.Typehints.vec_or_dict
->
764 if Partial.should_check_error
(fst
env).in_mode
2071 then
765 Errors.too_few_type_arguments p
;
767 N.Hvec_or_dict
(None
, (p
, N.Hany
))
768 | [val_
] -> N.Hvec_or_dict
(None
, hint env val_
)
769 | [key
; val_
] -> N.Hvec_or_dict
(Some
(hint env key
), hint env val_
)
771 Errors.too_many_type_arguments p
;
777 | Some _
when not
(String.equal
canon x
) ->
778 Errors.primitive_invalid_alias p x
canon
783 and hintl ~forbid_this ~allow_retonly ~allow_wildcard ~tp_depth
env l
=
784 List.map ~f
:(hint ~forbid_this ~allow_retonly ~allow_wildcard ~tp_depth
env) l
786 let constraint_ ?
(forbid_this
= false) env (ck
, h) =
787 (ck
, hint ~forbid_this
env h)
789 let targ env (p
, t
) =
799 let targl env _ tal
= List.map tal ~f
:(targ env)
801 (**************************************************************************)
802 (* All the methods and static methods of an interface are "implicitly"
803 * declared as abstract
805 (**************************************************************************)
807 let add_abstract m
= { m
with N.m_abstract
= true }
809 let add_abstractl methods
= List.map methods
add_abstract
811 let interface c constructor methods smethods
=
812 if not
(Ast_defs.is_c_interface c
.Aast.c_kind
) then
813 (constructor
, methods
, smethods
)
815 let constructor = Option.map
constructor add_abstract in
816 let methods = add_abstractl methods in
817 let smethods = add_abstractl smethods in
818 (constructor, methods, smethods)
820 let ensure_name_not_dynamic env e
=
822 | (_
, (Aast.Id _
| Aast.Lvar _
)) -> ()
824 if Partial.should_check_error
(fst
env).in_mode
2078 then
825 Errors.dynamic_class_name_in_strict_mode p
827 (* Naming of a class *)
828 let rec class_ ctx c
=
829 let env = Env.make_class_env ctx c
in
831 elaborate_namespaces#on_class_
832 (Naming_elaborate_namespaces_endo.make_env
(fst
env).namespace
)
835 let where_constraints =
836 type_where_constraints
env c.Aast.c_where_constraints
838 let name = c.Aast.c_name
in
839 let (constructor, smethods, methods) = Aast.split_methods
c in
840 let smethods = List.map ~f
:(method_
(fst
env)) smethods in
841 let (sprops
, props
) = Aast.split_vars
c in
842 let sprops = List.map ~f
:(class_prop_static
env) sprops in
843 let attrs = user_attributes
env c.Aast.c_user_attributes
in
844 let const = Naming_attributes.find
SN.UserAttributes.uaConst
attrs in
845 let props = List.map ~f
:(class_prop_non_static ~
const env) props in
846 let xhp_attrs = List.map ~f
:(xhp_attribute_decl
env) c.Aast.c_xhp_attrs
in
847 (* These would be out of order with the old attributes, but that shouldn't matter? *)
848 let props = props @ xhp_attrs in
849 let (enum_bound
, enum
, in_enum_class
) =
850 match c.Aast.c_enum
with
851 | Some enum
-> enum_
env name enum
852 | None
-> (None
, None
, false)
854 let parents = List.map
c.Aast.c_extends
(hint ~allow_retonly
:false env) in
856 match enum_bound
with
857 (* Make enums implicitly extend the BuiltinEnum/BuiltinEnumClass classes in
858 * order to provide utility methods.
861 let pos = fst
name in
863 if in_enum_class
then
864 SN.Classes.cHH_BuiltinEnumClass
866 SN.Classes.cHH_BuiltinEnum
868 let parent = (pos, N.Happly
((pos, builtin), [bound
])) in
872 let methods = List.map ~f
:(method_
(fst
env)) methods in
873 let uses = List.map ~f
:(hint env) c.Aast.c_uses
in
874 let xhp_attr_uses = List.map ~f
:(hint env) c.Aast.c_xhp_attr_uses
in
875 let (c_req_extends
, c_req_implements
) = Aast.split_reqs
c in
877 (not
(List.is_empty c_req_implements
))
878 && not
(Ast_defs.is_c_trait
c.Aast.c_kind
)
880 Errors.invalid_req_implements
(fst
(List.hd_exn c_req_implements
));
881 let req_implements = List.map ~f
:(hint env) c_req_implements
in
882 let req_implements = List.map ~f
:(fun h -> (h, false)) req_implements in
884 (not
(List.is_empty c_req_extends
))
885 && (not
(Ast_defs.is_c_trait
c.Aast.c_kind
))
886 && not
(Ast_defs.is_c_interface
c.Aast.c_kind
)
888 Errors.invalid_req_extends
(fst
(List.hd_exn c_req_extends
));
889 let req_extends = List.map ~f
:(hint env) c_req_extends
in
890 let req_extends = List.map ~f
:(fun h -> (h, true)) req_extends in
891 (* Setting a class type parameters constraint to the 'this' type is weird
892 * so lets forbid it for now.
894 let tparam_l = type_paraml ~forbid_this
:true env c.Aast.c_tparams
in
895 let consts = List.map ~f
:(class_const
env ~in_enum_class
) c.Aast.c_consts
in
896 let typeconsts = List.map ~f
:(typeconst
env) c.Aast.c_typeconsts
in
898 List.map ~f
:(hint ~allow_retonly
:false env) c.Aast.c_implements
900 let constructor = Option.map
constructor (method_
(fst
env)) in
901 let (constructor, methods, smethods) =
902 interface c constructor methods smethods
904 let file_attributes =
905 file_attributes ctx
c.Aast.c_mode
c.Aast.c_file_attributes
907 let c_tparams = tparam_l in
909 match constructor with
910 | None
-> smethods @ methods
911 | Some
c -> (c :: smethods) @ methods
915 N.c_span
= c.Aast.c_span
;
916 N.c_mode
= c.Aast.c_mode
;
917 N.c_final
= c.Aast.c_final
;
918 N.c_is_xhp
= c.Aast.c_is_xhp
;
919 N.c_has_xhp_keyword
= c.Aast.c_has_xhp_keyword
;
920 N.c_kind
= c.Aast.c_kind
;
923 N.c_extends
= parents;
925 (* c_use_as_alias and c_insteadof_alias are PHP features not supported
926 * in Hack but are required since we have runtime support for it
928 N.c_use_as_alias
= [];
929 N.c_insteadof_alias
= [];
930 N.c_xhp_attr_uses
= xhp_attr_uses;
931 N.c_xhp_category
= c.Aast.c_xhp_category
;
932 N.c_reqs
= req_extends @ req_implements;
933 N.c_implements
= implements;
934 N.c_support_dynamic_type
= c.Aast.c_support_dynamic_type
;
935 N.c_where_constraints
= where_constraints;
937 N.c_typeconsts
= typeconsts;
938 N.c_vars
= sprops @ props;
939 N.c_methods
= methods;
940 N.c_user_attributes
= attrs;
941 N.c_file_attributes
= file_attributes;
942 N.c_namespace
= c.Aast.c_namespace
;
944 N.c_doc_comment
= c.Aast.c_doc_comment
;
945 N.c_xhp_children
= c.Aast.c_xhp_children
;
946 (* Naming and typechecking shouldn't use these fields *)
949 N.c_emit_id
= c.Aast.c_emit_id
;
952 and user_attributes
env attrl
=
953 let seen = Caml.Hashtbl.create
0 in
954 let validate_seen ua_name
=
955 let (pos, name) = ua_name
in
956 let existing_attr_pos =
957 (try Some
(Caml.Hashtbl.find
seen name) with Caml.Not_found
-> None
)
959 match existing_attr_pos with
961 Errors.duplicate_user_attribute ua_name p
;
964 Caml.Hashtbl.add
seen name pos;
967 let on_attr acc
{ Aast.ua_name
; ua_params
} =
968 let () = check_name ua_name
in
969 if not
(validate_seen ua_name
) then
973 { N.ua_name
; N.ua_params
= List.map ~f
:(expr
env) ua_params
}
977 List.fold_left ~init
:[] ~f
:on_attr attrl
979 and file_attributes ctx mode fal
= List.map ~f
:(file_attribute ctx mode
) fal
981 and file_attribute ctx mode fa
=
982 let env = Env.make_file_attributes_env ctx mode fa
.Aast.fa_namespace
in
983 let ua = user_attributes
env fa
.Aast.fa_user_attributes
in
984 N.{ fa_user_attributes
= ua; fa_namespace
= fa
.Aast.fa_namespace
}
986 (* h cv is_required maybe_enum *)
987 and xhp_attribute_decl
env (h, cv
, tag
, maybe_enum
) =
988 let (p
, id) = cv
.Aast.cv_id
in
989 let default = cv
.Aast.cv_expr
in
990 let is_required = Option.is_some tag
in
991 if is_required && Option.is_some
default then
992 Errors.xhp_required_with_default p
id;
994 match maybe_enum
with
995 | Some
(pos, items
) ->
998 | (_
, Aast.Int _
) -> true
1001 let contains_int = List.exists ~f
:is_int items
in
1002 let is_string item
=
1004 | (_
, Aast.String _
)
1005 | (_
, Aast.String2 _
) ->
1009 let contains_str = List.exists ~f
:is_string items
in
1010 if contains_int && not
contains_str then
1011 Some
(pos, Aast.Happly
((pos, "int"), []))
1012 else if (not
contains_int) && contains_str then
1013 Some
(pos, Aast.Happly
((pos, "string"), []))
1015 Some
(pos, Aast.Happly
((pos, "mixed"), []))
1016 | _
-> Aast.hint_of_type_hint
h
1020 | Some
(p
, Aast.Hoption _
) ->
1021 if is_required then Errors.xhp_optional_required_attr p
id;
1023 | Some
(_
, Aast.Happly
((_
, "mixed"), [])) -> hint_
1028 | Some
(_
, Aast.Null
) ->
1032 if is_required || has_default then
1035 Some
(p
, Aast.Hoption
(p
, h))
1038 let hint_ = ((), hint_) in
1039 let hint_ = Aast.type_hint_option_map
hint_ ~f
:(hint env) in
1040 let (expr
, _
) = class_prop_expr_is_xhp
env cv
in
1042 match cv
.Aast.cv_xhp_attr
with
1043 | Some xai
-> xai
.Aast.xai_enum_values
1047 Some
{ N.xai_tag
= tag
; N.xai_enum_values
= enum_values }
1050 N.cv_final
= cv
.Aast.cv_final
;
1051 N.cv_xhp_attr
= xhp_attr_info;
1052 N.cv_readonly
= cv
.Aast.cv_readonly
;
1053 N.cv_abstract
= cv
.Aast.cv_abstract
;
1054 N.cv_visibility
= cv
.Aast.cv_visibility
;
1056 N.cv_id
= cv
.Aast.cv_id
;
1058 N.cv_user_attributes
= [];
1059 N.cv_is_promoted_variadic
= cv
.Aast.cv_is_promoted_variadic
;
1060 N.cv_doc_comment
= cv
.Aast.cv_doc_comment
(* Can make None to save space *);
1061 N.cv_is_static
= cv
.Aast.cv_is_static
;
1062 N.cv_span
= cv
.Aast.cv_span
;
1065 and enum_
env enum_name e
=
1067 let pos = fst enum_name
in
1068 let enum_hint = (pos, Happly
(enum_name
, [])) in
1069 let is_enum_class = e
.e_enum_class
in
1070 let old_base = e
.e_base
in
1071 let new_base = hint env old_base in
1073 if is_enum_class then
1074 (* Turn the base type of the enum class into MemberOf<E, base> *)
1075 let elt = (pos, SN.Classes.cMemberOf
) in
1076 let h = (pos, Happly
(elt, [enum_hint; old_base])) in
1083 N.e_base
= new_base;
1084 N.e_constraint
= Option.map e
.e_constraint
(hint env);
1085 N.e_includes
= List.map ~f
:(hint env) e
.e_includes
;
1086 N.e_enum_class
= is_enum_class;
1089 (Some
bound, Some
enum, is_enum_class)
1091 and type_paraml ?
(forbid_this
= false) env tparams
=
1092 List.map tparams ~f
:(type_param ~forbid_this
env)
1095 We need to be careful regarding the scoping of type variables:
1096 Type parameters are always in scope simultaneously: Given
1097 class C<T1 ... , T2 ... , Tn ...>,
1098 all type parameters are in scope in the constraints of all other ones (and the where constraints,
1099 in case of functions).
1100 For consitency, the same holds for nested type parameters (i.e., type parameters of type
1102 class Foo<T<T1 ... , ...., Tn ... > ... >
1103 every Ti is in scope of the constraints of all other Tj, and in the constraints on T itself.
1105 and type_param ~forbid_this
(genv, lenv) t
=
1108 TypecheckerOptions.experimental_feature_enabled
1109 (Provider_context.get_tcopt
genv.ctx
)
1110 TypecheckerOptions.experimental_type_param_shadowing
1112 (* Treat type params as inline class declarations that don't go into the naming heap *)
1114 NS.elaborate_id
genv.namespace
NS.ElaborateClass t
.Aast.tp_name
1116 match Naming_provider.get_type_pos
genv.ctx
name with
1118 let (def_pos
, _
) = GEnv.get_type_full_pos
genv.ctx
(def_pos
, name) in
1119 Errors.error_name_already_bound
name name pos def_pos
1121 (match GEnv.type_canon_name
genv.ctx
name with
1124 Option.value ~
default:Pos.none
(GEnv.type_pos
genv.ctx canonical
)
1126 Errors.error_name_already_bound
name canonical
pos def_pos
1129 let hk_types_enabled =
1130 TypecheckerOptions.higher_kinded_types
(Provider_context.get_tcopt
genv.ctx
)
1132 ( if (not
hk_types_enabled) && (not
@@ List.is_empty t
.Aast.tp_parameters
) then
1133 let (pos, name) = t
.Aast.tp_name
in
1134 Errors.tparam_with_tparam
pos name );
1136 (* Bring all type parameters into scope at once before traversing nested tparams,
1137 as per the note above *)
1138 let env = (extend_tparams
genv t
.Aast.tp_parameters
, lenv) in
1140 if hk_types_enabled then
1141 List.map t
.Aast.tp_parameters (type_param ~forbid_this
env)
1145 (* Use the env with all nested tparams still in scope *)
1146 let tp_constraints =
1147 List.map t
.Aast.tp_constraints (constraint_ ~forbid_this
env)
1150 N.tp_variance
= t
.Aast.tp_variance
;
1151 tp_name
= t
.Aast.tp_name
;
1154 tp_reified
= t
.Aast.tp_reified
;
1155 tp_user_attributes
= user_attributes
env t
.Aast.tp_user_attributes
;
1158 and type_where_constraints
env locl_cstrl
=
1160 ~f
:(fun (h1
, ck
, h2
) ->
1161 let ty1 = hint ~in_where_clause
:true env h1
in
1162 let ty2 = hint ~in_where_clause
:true env h2
in
1166 and class_prop_expr_is_xhp
env cv
=
1167 let expr = Option.map cv
.Aast.cv_expr
(expr env) in
1170 FileInfo.equal_mode
(fst
env).in_mode
FileInfo.Mhhi
&& Option.is_none
expr
1172 Some
(fst cv
.Aast.cv_id
, N.Any
)
1177 try String.(sub
(snd cv
.Aast.cv_id
) 0 1 = ":")
1178 with Invalid_argument _
-> false
1182 and make_xhp_attr
= function
1183 | true -> Some
{ N.xai_tag
= None
; N.xai_enum_values
= [] }
1186 and class_prop_static
env cv
=
1187 let attrs = user_attributes
env cv
.Aast.cv_user_attributes
in
1188 let lsb = Naming_attributes.mem
SN.UserAttributes.uaLSB
attrs in
1189 let forbid_this = not
lsb in
1191 Aast.type_hint_option_map ~f
:(hint ~
forbid_this env) cv
.Aast.cv_type
1193 let (expr, is_xhp) = class_prop_expr_is_xhp
env cv
in
1195 N.cv_final
= cv
.Aast.cv_final
;
1196 N.cv_xhp_attr
= make_xhp_attr
is_xhp;
1197 N.cv_abstract
= cv
.Aast.cv_abstract
;
1198 N.cv_readonly
= cv
.Aast.cv_readonly
;
1199 N.cv_visibility
= cv
.Aast.cv_visibility
;
1201 N.cv_id
= cv
.Aast.cv_id
;
1203 N.cv_user_attributes
= attrs;
1204 N.cv_is_promoted_variadic
= cv
.Aast.cv_is_promoted_variadic
;
1205 N.cv_doc_comment
= cv
.Aast.cv_doc_comment
(* Can make None to save space *);
1206 N.cv_is_static
= cv
.Aast.cv_is_static
;
1207 N.cv_span
= cv
.Aast.cv_span
;
1210 and class_prop_non_static
env ?
(const = None
) cv
=
1211 let h = Aast.type_hint_option_map ~f
:(hint env) cv
.Aast.cv_type
in
1212 let attrs = user_attributes
env cv
.Aast.cv_user_attributes
in
1213 (* if class is __Const, make all member fields __Const *)
1217 if not
(Naming_attributes.mem
SN.UserAttributes.uaConst
attrs) then
1223 let (expr, is_xhp) = class_prop_expr_is_xhp
env cv
in
1225 N.cv_final
= cv
.Aast.cv_final
;
1226 N.cv_xhp_attr
= make_xhp_attr
is_xhp;
1227 N.cv_visibility
= cv
.Aast.cv_visibility
;
1228 N.cv_readonly
= cv
.Aast.cv_readonly
;
1230 N.cv_abstract
= cv
.Aast.cv_abstract
;
1231 N.cv_id
= cv
.Aast.cv_id
;
1233 N.cv_user_attributes
= attrs;
1234 N.cv_is_promoted_variadic
= cv
.Aast.cv_is_promoted_variadic
;
1235 N.cv_doc_comment
= cv
.Aast.cv_doc_comment
(* Can make None to save space *);
1236 N.cv_is_static
= cv
.Aast.cv_is_static
;
1237 N.cv_span
= cv
.Aast.cv_span
;
1240 and check_constant_expression
env ~in_enum_class
(pos, e
) =
1241 if not in_enum_class
then
1242 check_constant_expr
env (pos, e
)
1246 and check_constant_expr
env (pos, e
) =
1256 | Aast.Class_const
((_
, Aast.CIexpr
(_
, cls
)), _
)
1258 | Aast.Id
(_
, "static") -> false
1262 ((Ast_defs.Uplus
| Ast_defs.Uminus
| Ast_defs.Utild
| Ast_defs.Unot
), e
)
1264 check_constant_expr
env e
1265 | Aast.Binop
(op
, e1
, e2
) ->
1266 (* Only assignment is invalid *)
1270 Errors.illegal_constant
pos;
1272 | _
-> check_constant_expr
env e1
&& check_constant_expr
env e2
1274 | Aast.Eif
(e1
, e2
, e3
) ->
1275 check_constant_expr
env e1
1276 && Option.for_all e2
(check_constant_expr
env)
1277 && check_constant_expr
env e3
1278 | Aast.Darray
(_
, l
) ->
1279 List.for_all l ~f
:(fun (e1
, e2
) ->
1280 check_constant_expr
env e1
&& check_constant_expr
env e2
)
1281 | Aast.Varray
(_
, l
) -> List.for_all l ~f
:(check_constant_expr
env)
1283 (* Only check the values because shape field names are always legal *)
1284 List.for_all fdl ~f
:(fun (_
, e
) -> check_constant_expr
env e
)
1285 | Aast.Call
((_
, Aast.Id
(_
, cn
)), _
, el
, unpacked_element
)
1286 when String.equal cn
SN.AutoimportedFunctions.fun_
1287 || String.equal cn
SN.AutoimportedFunctions.class_meth
1288 || String.equal cn
SN.StdlibFunctions.array_mark_legacy
->
1289 arg_unpack_unexpected unpacked_element
;
1290 List.for_all el ~f
:(check_constant_expr
env)
1291 | Aast.Tuple el
-> List.for_all el ~f
:(check_constant_expr
env)
1292 | Aast.FunctionPointer
((Aast.FP_id _
| Aast.FP_class_const _
), _
) -> true
1293 | Aast.Collection
(id, _
, l
) ->
1294 let (p
, cn
) = NS.elaborate_id
(fst
env).namespace
NS.ElaborateClass
id in
1295 (* Only vec/keyset/dict are allowed because they are value types *)
1297 String.equal cn
SN.Collections.cVec
1298 || String.equal cn
SN.Collections.cKeyset
1299 || String.equal cn
SN.Collections.cDict
1301 List.for_all l ~f
:(check_afield_constant_expr
env)
1303 Errors.illegal_constant p
;
1306 | Aast.As
(e
, (_
, Aast.Hlike _
), _
) -> check_constant_expr
env e
1307 | Aast.As
(e
, (_
, Aast.Happly
(id, [_
])), _
) ->
1308 let (p
, cn
) = NS.elaborate_id
(fst
env).namespace
NS.ElaborateClass
id in
1309 if String.equal cn
SN.FB.cIncorrectType
then
1310 check_constant_expr
env e
1312 Errors.illegal_constant p
;
1316 Errors.illegal_constant
pos;
1319 and check_afield_constant_expr
env afield
=
1321 | Aast.AFvalue e
-> check_constant_expr
env e
1322 | Aast.AFkvalue
(e1
, e2
) ->
1323 check_constant_expr
env e1
&& check_constant_expr
env e2
1325 and constant_expr
env ~in_enum_class e
=
1326 let valid_constant_expression =
1327 check_constant_expression
env ~in_enum_class e
1329 if valid_constant_expression then
1334 and class_const
env ~in_enum_class cc
=
1335 let h = Option.map cc
.Aast.cc_type
(hint env) in
1336 let e = Option.map cc
.Aast.cc_expr
(constant_expr
env ~in_enum_class
) in
1339 N.cc_id
= cc
.Aast.cc_id
;
1341 N.cc_doc_comment
= cc
.Aast.cc_doc_comment
;
1344 and typeconst
env t
=
1347 match t
.c_tconst_kind
with
1348 | TCAbstract
{ c_atc_as_constraint
; c_atc_super_constraint
; c_atc_default
}
1352 c_atc_as_constraint
= Option.map ~f
:(hint env) c_atc_as_constraint
;
1353 c_atc_super_constraint
=
1354 Option.map ~f
:(hint env) c_atc_super_constraint
;
1355 c_atc_default
= Option.map ~f
:(hint env) c_atc_default
;
1357 | TCConcrete
{ c_tc_type
} -> TCConcrete
{ c_tc_type
= hint env c_tc_type
}
1358 | TCPartiallyAbstract
{ c_patc_constraint
; c_patc_type
} ->
1361 c_patc_constraint
= hint env c_patc_constraint
;
1362 c_patc_type
= hint env c_patc_type
;
1365 let attrs = user_attributes
env t
.Aast.c_tconst_user_attributes
in
1368 c_tconst_user_attributes
= attrs;
1369 c_tconst_name
= t
.Aast.c_tconst_name
;
1370 c_tconst_kind
= tconst;
1371 c_tconst_span
= t
.Aast.c_tconst_span
;
1372 c_tconst_doc_comment
= t
.Aast.c_tconst_doc_comment
;
1373 c_tconst_is_ctx
= t
.Aast.c_tconst_is_ctx
;
1376 and method_
genv m
=
1377 let genv = extend_tparams
genv m
.Aast.m_tparams
in
1378 let env = (genv, Env.empty_local None
) in
1379 (* Cannot use 'this' if it is a public instance method *)
1380 let (variadicity
, paraml
) = fun_paraml
env m
.Aast.m_params
in
1381 let tparam_l = type_paraml
env m
.Aast.m_tparams
in
1382 let where_constraints =
1383 type_where_constraints
env m
.Aast.m_where_constraints
1386 Aast.type_hint_option_map ~f
:(hint ~allow_retonly
:true env) m
.Aast.m_ret
1389 match genv.in_mode
with
1391 { N.fb_ast
= []; fb_annotation
= Nast.NamedWithUnsafeBlocks
}
1393 | FileInfo.Mpartial
->
1394 if Nast.is_body_named m
.Aast.m_body
then
1395 let env = List.fold_left ~f
:Env.add_param m
.N.m_params ~init
:env in
1397 match m
.N.m_variadic
with
1399 | N.FVnonVariadic
->
1401 | N.FVvariadicArg param
-> Env.add_param env param
1403 let fub_ast = block
env m
.N.m_body
.N.fb_ast
in
1404 let annotation = Nast.Named
in
1405 { N.fb_ast
= fub_ast; fb_annotation
= annotation }
1407 failwith
"ast_to_nast error unnamedbody in method_"
1409 let attrs = user_attributes
env m
.Aast.m_user_attributes
in
1410 let m_ctxs = Option.map ~f
:(contexts
env) m
.Aast.m_ctxs in
1411 let m_unsafe_ctxs = Option.map ~f
:(contexts
env) m
.Aast.m_unsafe_ctxs in
1413 N.m_annotation
= ();
1414 N.m_span
= m
.Aast.m_span
;
1415 N.m_final
= m
.Aast.m_final
;
1416 N.m_visibility
= m
.Aast.m_visibility
;
1417 N.m_abstract
= m
.Aast.m_abstract
;
1418 N.m_readonly_this
= m
.Aast.m_readonly_this
;
1419 N.m_static
= m
.Aast.m_static
;
1420 N.m_name
= m
.Aast.m_name
;
1421 N.m_tparams
= tparam_l;
1422 N.m_where_constraints
= where_constraints;
1423 N.m_params
= paraml
;
1427 N.m_fun_kind
= m
.Aast.m_fun_kind
;
1428 N.m_readonly_ret
= m
.Aast.m_readonly_ret
;
1430 N.m_variadic
= variadicity
;
1431 N.m_user_attributes
= attrs;
1432 N.m_external
= m
.Aast.m_external
;
1433 N.m_doc_comment
= m
.Aast.m_doc_comment
;
1436 and fun_paraml
env paraml
=
1437 let _ = List.fold_left ~f
:check_repetition ~init
:SSet.empty paraml
in
1438 let (variadicity
, paraml
) = determine_variadicity
env paraml
in
1439 (variadicity
, List.map ~f
:(fun_param
env) paraml
)
1441 (* Variadic params are removed from the list *)
1442 and determine_variadicity
env paraml
=
1444 | [] -> (N.FVnonVariadic
, [])
1447 match (x
.Aast.param_is_variadic
, x
.Aast.param_name
) with
1448 | (false, _) -> (N.FVnonVariadic
, paraml
)
1449 | (true, "...") -> (N.FVellipsis x
.Aast.param_pos
, [])
1450 | (true, _) -> (N.FVvariadicArg
(fun_param
env x
), [])
1453 let (variadicity
, rl
) = determine_variadicity
env rl
in
1454 (variadicity
, x
:: rl
)
1456 and fun_param
env (param
: Nast.fun_param
) =
1457 let p = param
.Aast.param_pos
in
1458 let name = param
.Aast.param_name
in
1459 let ident = Local_id.make_unscoped
name in
1460 Env.add_lvar env (p, name) (p, ident);
1462 Aast.type_hint_option_map param
.Aast.param_type_hint ~f
:(hint env)
1464 let eopt = Option.map param
.Aast.param_expr
(expr env) in
1466 N.param_annotation
= p;
1467 param_type_hint
= tyhi;
1468 param_is_variadic
= param
.Aast.param_is_variadic
;
1472 param_callconv
= param
.Aast.param_callconv
;
1473 param_readonly
= param
.Aast.param_readonly
;
1474 param_user_attributes
= user_attributes
env param
.Aast.param_user_attributes
;
1475 param_visibility
= param
.Aast.param_visibility
;
1478 and extend_tparams
genv paraml
=
1482 ~init
:genv.type_params
1483 ~f
:(fun { Aast.tp_name
= (_, x
); _ } acc
-> SSet.add x acc
)
1485 { genv with type_params
= params }
1488 let genv = Env.make_fun_decl_genv ctx f
in
1489 let lenv = Env.empty_local None
in
1490 let env = (genv, lenv) in
1492 elaborate_namespaces#on_fun_def
1493 (Naming_elaborate_namespaces_endo.make_env
(fst
env).namespace
)
1496 let where_constraints =
1497 type_where_constraints
env f.Aast.f_where_constraints
1500 Aast.type_hint_option_map ~
f:(hint ~allow_retonly
:true env) f.Aast.f_ret
1502 let (variadicity
, paraml
) = fun_paraml
env f.Aast.f_params
in
1503 let f_tparams = type_paraml
env f.Aast.f_tparams in
1504 let f_kind = f.Aast.f_fun_kind
in
1506 match genv.in_mode
with
1508 { N.fb_ast
= []; fb_annotation
= Nast.NamedWithUnsafeBlocks
}
1510 | FileInfo.Mpartial
->
1511 if Nast.is_body_named
f.Aast.f_body
then
1512 let env = List.fold_left ~
f:Env.add_param paraml ~init
:env in
1514 match variadicity
with
1516 | N.FVnonVariadic
->
1518 | N.FVvariadicArg param
-> Env.add_param env param
1520 let fb_ast = block
env f.Aast.f_body
.Aast.fb_ast in
1521 let annotation = Nast.Named
in
1522 { N.fb_ast; fb_annotation
= annotation }
1524 failwith
"ast_to_nast error unnamedbody in fun_"
1526 let f_ctxs = Option.map ~
f:(contexts
env) f.Aast.f_ctxs in
1527 let f_unsafe_ctxs = Option.map ~
f:(contexts
env) f.Aast.f_unsafe_ctxs in
1528 let file_attributes =
1529 file_attributes ctx
f.Aast.f_mode
f.Aast.f_file_attributes
1533 N.f_annotation
= ();
1534 f_readonly_this
= f.Aast.f_readonly_this
;
1535 f_span
= f.Aast.f_span
;
1536 f_mode
= f.Aast.f_mode
;
1537 f_readonly_ret
= f.Aast.f_readonly_ret
;
1539 f_name
= f.Aast.f_name
;
1541 f_where_constraints
= where_constraints;
1543 (* TODO(T70095684) double-check f_ctxs *)
1547 f_fun_kind
= f_kind;
1548 f_variadic
= variadicity
;
1549 f_user_attributes
= user_attributes
env f.Aast.f_user_attributes
;
1550 f_file_attributes
= file_attributes;
1551 f_external
= f.Aast.f_external
;
1552 f_namespace
= f.Aast.f_namespace
;
1553 f_doc_comment
= f.Aast.f_doc_comment
;
1558 and get_using_vars es
=
1559 List.concat_map es
(fun (_, e) ->
1561 (* Simple assignment to local of form `$lvar = e` *)
1562 | Aast.Binop
(Ast_defs.Eq None
, (_, Aast.Lvar
(p, lid
)), _) ->
1563 [(p, Local_id.get_name lid
)]
1564 (* Arbitrary expression. This will be assigned to a temporary *)
1567 and stmt
env (pos, st
) =
1570 | Aast.Block
_ -> failwith
"stmt block error"
1571 | Aast.Fallthrough
-> N.Fallthrough
1572 | Aast.Noop
-> N.Noop
1573 | Aast.Markup
_ -> N.Noop
1574 | Aast.AssertEnv
_ -> N.Noop
1575 | Aast.Break
-> Aast.Break
1576 | Aast.Continue
-> Aast.Continue
1577 | Aast.Throw
e -> N.Throw
(expr env e)
1578 | Aast.Return
e -> N.Return
(Option.map
e (expr env))
1579 | Aast.Yield_break
-> N.Yield_break
1580 | Aast.Awaitall
(el
, b
) -> awaitall_stmt
env el b
1581 | Aast.If
(e, b1
, b2
) -> if_stmt
env e b1 b2
1582 | Aast.Do
(b
, e) -> do_stmt
env b
e
1583 | Aast.While
(e, b
) -> N.While
(expr env e, block
env b
)
1585 using_stmt
env s
.Aast.us_has_await s
.Aast.us_exprs s
.Aast.us_block
1586 | Aast.For
(st1
, e, st2
, b
) -> for_stmt
env st1
e st2 b
1587 | Aast.Switch
(e, cl
) -> switch_stmt
env e cl
1588 | Aast.Foreach
(e, ae
, b
) -> foreach_stmt
env e ae b
1589 | Aast.Try
(b
, cl
, fb
) -> try_stmt
env b cl fb
1590 | Aast.Expr
(cp
, Aast.Call
((p, Aast.Id
(fp
, fn
)), hl, el
, unpacked_element
))
1591 when String.equal fn
SN.AutoimportedFunctions.invariant
->
1592 (* invariant is subject to a source-code transform in the HHVM
1593 * runtime: the arguments to invariant are lazily evaluated only in
1594 * the case in which the invariant condition does not hold. So:
1596 * invariant_violation(<condition>, <format>, <format_args...>)
1598 * ... is rewritten as:
1600 * if (!<condition>) {
1601 * invariant_violation(<format>, <format_args...>);
1608 Errors.naming_too_few_arguments
p;
1610 | (cond_p
, cond
) :: el
->
1614 ( (p, Aast.Id
(fp
, SN.AutoimportedFunctions.invariant_violation
)),
1617 unpacked_element
) )
1621 (* a false <condition> means unconditional invariant_violation *)
1622 N.Expr
(expr env violation)
1625 ([(cp
, Aast.Expr
violation)], [(Pos.none
, Aast.Noop
)])
1627 let cond = (cond_p
, Aast.Unop
(Ast_defs.Unot
, (cond_p
, cond))) in
1628 if_stmt
env cond b1 b2
)
1630 | Aast.Expr
e -> N.Expr
(expr env e)
1634 and if_stmt
env e b1 b2
=
1635 let e = expr env e in
1636 Env.scope env (fun env ->
1637 let b1 = branch
env b1 in
1638 let b2 = branch
env b2 in
1641 and do_stmt
env b
e =
1642 let b = block ~new_scope
:false env b in
1643 let e = expr env e in
1646 (* Scoping is essentially that of do: block is always executed *)
1647 and using_stmt
env has_await
(loc
, e) b =
1648 let vars = get_using_vars
e in
1649 let e = List.map ~
f:(expr env) e in
1650 let b = block ~new_scope
:false env b in
1651 Env.remove_locals env vars;
1655 us_is_block_scoped
= false;
1656 (* This isn't used for naming so provide a default *)
1657 us_has_await
= has_await
;
1658 us_exprs
= (loc
, e);
1662 and for_stmt
env e1 e2 e3
b =
1663 (* The initialization and condition expression should be in the outer scope,
1664 * as they are always executed. *)
1665 let e1 = exprl
env e1 in
1666 let e2 = oexpr
env e2 in
1667 Env.scope env (fun env ->
1668 (* The third expression (iteration step) should have the same scope as the
1669 * block, as it is not always executed. *)
1670 let b = block ~new_scope
:false env b in
1671 let e3 = exprl
env e3 in
1672 N.For
(e1, e2, e3, b))
1674 and switch_stmt
env e cl
=
1675 let e = expr env e in
1676 Env.scope env (fun env ->
1677 let cl = casel
env cl in
1680 and foreach_stmt
env e ae
b =
1681 let e = expr env e in
1682 Env.scope env (fun env ->
1683 let ae = as_expr
env ae in
1684 let b = block
env b in
1685 N.Foreach
(e, ae, b))
1687 and get_lvalues
(acc
: Pos.t
SMap.t
) (p, e) : Pos.t
SMap.t
=
1689 | Aast.List lv
-> List.fold_left ~init
:acc ~
f:get_lvalues lv
1690 | Aast.Lvar
(_, lid
) -> SMap.add
(Local_id.to_string lid
) p acc
1693 and as_expr
env ae =
1697 Errors.expected_variable
p;
1698 (p, N.Lvar
(Env.new_lvar env (p, "__internal_placeholder")))
1700 let vars = get_lvalues
SMap.empty ev
in
1701 SMap.iter
(fun x
p -> ignore
(Env.new_lvar env (p, x
))) vars;
1706 | (_, Aast.Lvar
(p, lid
)) ->
1707 let x = (p, Local_id.get_name lid
) in
1708 (p, N.Lvar
(Env.new_lvar env x))
1710 Errors.expected_variable
p;
1711 (p, N.Lvar
(Env.new_lvar env (p, "__internal_placeholder")))
1715 let ev = handle_v ev in
1717 | Aast.As_kv
(k
, ev) ->
1718 let k = handle_k k in
1719 let ev = handle_v ev in
1721 | N.Await_as_v
(p, ev) ->
1722 let ev = handle_v ev in
1723 N.Await_as_v
(p, ev)
1724 | N.Await_as_kv
(p, k, ev) ->
1725 let k = handle_k k in
1726 let ev = handle_v ev in
1727 N.Await_as_kv
(p, k, ev)
1729 and try_stmt
env b cl fb
=
1730 Env.scope env (fun env ->
1731 let fb = branch
env fb in
1732 let b = branch
env b in
1733 let cl = catchl
env cl in
1736 and stmt_list stl
env =
1739 | (_, Aast.Block
b) :: rest
->
1740 let b = stmt_list
b env in
1741 let rest = stmt_list
rest env in
1744 let x = stmt env x in
1745 let rest = stmt_list
rest env in
1748 and block ?
(new_scope
= true) env stl
=
1750 Env.scope env (stmt_list stl
)
1754 and branch
env stmt_l
= Env.scope env (stmt_list stmt_l
)
1756 and awaitall_stmt
env el
b =
1760 let e2 = expr env e2 in
1764 let e = (Pos.none
, Aast.Lvar lid
) in
1765 let vars = get_lvalues
SMap.empty
e in
1766 SMap.iter
(fun x p -> ignore
(Env.new_lvar env (p, x))) vars;
1773 let s = block
env b in
1776 and expr_obj_get_name
env expr_
=
1778 | (p, Aast.Id
x) -> (p, N.Id
x)
1779 | (p, e) -> expr env (p, e)
1781 and exprl
env l
= List.map ~
f:(expr env) l
1783 and oexpr
env e = Option.map
e (expr env)
1785 and expr env (p, e) = (p, expr_
env p e)
1787 and expr_
env p (e : Nast.expr_
) =
1789 | Aast.Varray
(ta
, l
) ->
1790 N.Varray
(Option.map ~
f:(targ env) ta
, List.map l
(expr env))
1791 | Aast.Darray
(tap
, l
) ->
1793 Option.map ~
f:(fun (t1
, t2
) -> (targ env t1
, targ env t2
)) tap
1795 N.Darray
(nargs, List.map l
(fun (e1, e2) -> (expr env e1, expr env e2)))
1796 | Aast.Collection
(id, tal
, l
) ->
1797 let (p, cn
) = NS.elaborate_id
(fst
env).namespace
NS.ElaborateClass
id in
1800 | x when Nast.is_vc_kind
x ->
1803 | Some
(Aast.CollectionTV tv
) -> Some
(targ env tv
)
1804 | Some
(Aast.CollectionTKV
_) ->
1805 Errors.naming_too_many_arguments
p;
1810 (Nast.get_vc_kind cn
, ta, List.map l
(afield_value
env cn
))
1811 | x when Nast.is_kvc_kind
x ->
1814 | Some
(Aast.CollectionTV
_) ->
1815 Errors.naming_too_few_arguments
p;
1817 | Some
(Aast.CollectionTKV
(tk
, tv
)) -> Some
(targ env tk
, targ env tv
)
1821 (Nast.get_kvc_kind cn
, ta, List.map l
(afield_kvalue
env cn
))
1822 | x when String.equal
x SN.Collections.cPair
->
1825 | Some
(Aast.CollectionTV
_) ->
1826 Errors.naming_too_few_arguments
p;
1828 | Some
(Aast.CollectionTKV
(tk
, tv
)) -> Some
(targ env tk
, targ env tv
)
1834 Errors.naming_too_few_arguments
p;
1837 let pn = SN.Collections.cPair
in
1838 N.Pair
(ta, afield_value
env pn e1, afield_value
env pn e2)
1840 Errors.naming_too_many_arguments
p;
1844 Errors.expected_collection
p cn
;
1847 | Aast.Clone
e -> N.Clone
(expr env e)
1848 | Aast.Null
-> N.Null
1849 | Aast.True
-> N.True
1850 | Aast.False
-> N.False
1851 | Aast.Int
s -> N.Int
s
1852 | Aast.Float
s -> N.Float
s
1853 | Aast.String
s -> N.String
s
1854 | Aast.String2 idl
-> N.String2
(string2
env idl
)
1855 | Aast.PrefixedString
(n
, e) -> N.PrefixedString
(n
, expr env e)
1856 | Aast.Id
x -> N.Id
x
1858 when String.equal
(Local_id.to_string
x) SN.SpecialIdents.this
->
1861 when String.equal
(Local_id.to_string
x) SN.SpecialIdents.dollardollar
->
1862 N.Dollardollar
(p, Local_id.make_unscoped
SN.SpecialIdents.dollardollar
)
1864 when String.equal
(Local_id.to_string
x) SN.SpecialIdents.placeholder
->
1867 let x = (fst
x, Local_id.to_string
@@ snd
x) in
1868 N.Lvar
(Env.lvar env x)
1869 | Aast.Obj_get
(e1, e2, nullsafe
, in_parens
) ->
1870 (* If we encounter Obj_get(_,_,true) by itself, then it means "?->"
1871 is being used for instance property access; see the case below for
1872 handling nullsafe instance method calls to see how this works *)
1873 N.Obj_get
(expr env e1, expr_obj_get_name
env e2, nullsafe
, in_parens
)
1874 | Aast.Array_get
((p, Aast.Lvar
x), None
) ->
1875 let x = (fst
x, Local_id.to_string
@@ snd
x) in
1876 let id = (p, N.Lvar
(Env.lvar env x)) in
1877 N.Array_get
(id, None
)
1878 | Aast.Array_get
(e1, e2) -> N.Array_get
(expr env e1, oexpr
env e2)
1880 ((_, Aast.CIexpr
(_, Aast.Id x1
)), Aast.CGstring x2
, in_parens
) ->
1881 N.Class_get
(make_class_id
env x1
, N.CGstring x2
, in_parens
)
1883 ((_, Aast.CIexpr
(_, Aast.Lvar
(p, lid
))), Aast.CGstring x2
, in_parens
) ->
1884 let x1 = (p, Local_id.to_string lid
) in
1885 N.Class_get
(make_class_id
env x1, N.CGstring x2
, in_parens
)
1886 | Aast.Class_get
((_, Aast.CIexpr
x1), Aast.CGstring
_, _) ->
1887 ensure_name_not_dynamic env x1;
1889 | Aast.Class_get
((_, Aast.CIexpr
x1), Aast.CGexpr x2
, _) ->
1890 ensure_name_not_dynamic env x1;
1891 ensure_name_not_dynamic env x2
;
1893 | Aast.Class_get
_ -> failwith
"Error in Ast_to_nast module for Class_get"
1894 | Aast.Class_const
((_, Aast.CIexpr
(_, Aast.Id
x1)), ((_, str
) as x2
))
1895 when String.equal str
"class" ->
1896 N.Class_const
(make_class_id
env x1, x2
)
1897 | Aast.Class_const
((_, Aast.CIexpr
(_, Aast.Id
x1)), x2
) ->
1898 N.Class_const
(make_class_id
env x1, x2
)
1899 | Aast.Class_const
((_, Aast.CIexpr
(_, Aast.Lvar
(p, lid
))), x2
) ->
1900 let x1 = (p, Local_id.to_string lid
) in
1901 N.Class_const
(make_class_id
env x1, x2
)
1902 | Aast.Class_const
_ -> (* TODO: report error in strict mode *) N.Any
1903 | Aast.Call
((_, Aast.Id
(p, pseudo_func
)), tal
, el, unpacked_element
)
1904 when String.equal pseudo_func
SN.SpecialFunctions.echo
->
1905 arg_unpack_unexpected unpacked_element
;
1906 N.Call
((p, N.Id
(p, pseudo_func
)), targl env p tal
, exprl
env el, None
)
1907 | Aast.Call
((p, Aast.Id
(_, cn
)), tal
, el, _)
1908 when String.equal cn
SN.StdlibFunctions.call_user_func
->
1909 Errors.deprecated_use
1912 ^
Markdown_lite.md_codify
(Utils.strip_ns cn
)
1913 ^
" is deprecated." );
1917 Errors.naming_too_few_arguments
p;
1919 | f :: el -> N.Call
(expr env f, targl env p tal
, exprl
env el, None
)
1921 | Aast.Call
((p, Aast.Id
(_, cn
)), _, el, unpacked_element
)
1922 when String.equal cn
SN.AutoimportedFunctions.fun_
->
1923 arg_unpack_unexpected unpacked_element
;
1927 Errors.naming_too_few_arguments
p;
1929 | [(p, Aast.String
x)] -> N.Fun_id
(p, x)
1931 Errors.illegal_fun
p;
1934 Errors.naming_too_many_arguments
p;
1937 | Aast.Call
((p, Aast.Id
(_, cn
)), _, el, unpacked_element
)
1938 when String.equal cn
SN.AutoimportedFunctions.inst_meth
->
1939 arg_unpack_unexpected unpacked_element
;
1944 Errors.naming_too_few_arguments
p;
1946 | [instance
; (p, Aast.String meth
)] ->
1947 N.Method_id
(expr env instance
, (p, meth
))
1949 Errors.illegal_inst_meth
p;
1952 Errors.naming_too_many_arguments
p;
1955 | Aast.Call
((p, Aast.Id
(_, cn
)), _, el, unpacked_element
)
1956 when String.equal cn
SN.AutoimportedFunctions.meth_caller
->
1957 arg_unpack_unexpected unpacked_element
;
1962 Errors.naming_too_few_arguments
p;
1966 match (expr env e1, expr env e2) with
1967 | ((pc
, N.String
cl), (pm
, N.String meth
)) ->
1968 let () = check_name (pc
, cl) in
1969 N.Method_caller
((pc
, cl), (pm
, meth
))
1970 | ((_, N.Class_const
((_, N.CI
cl), (_, mem
))), (pm
, N.String meth
))
1971 when String.equal mem
SN.Members.mClass
->
1972 let () = check_name cl in
1973 N.Method_caller
(cl, (pm
, meth
))
1975 Errors.illegal_meth_caller
p;
1979 Errors.naming_too_many_arguments
p;
1982 | Aast.Call
((p, Aast.Id
(_, cn
)), _, el, unpacked_element
)
1983 when String.equal cn
SN.AutoimportedFunctions.class_meth
->
1984 arg_unpack_unexpected unpacked_element
;
1989 Errors.naming_too_few_arguments
p;
1993 match (expr env e1, expr env e2) with
1994 | ((pc
, N.String
cl), (pm
, N.String meth
)) ->
1995 let () = check_name (pc
, cl) in
1996 let cid = N.CI
(pc
, cl) in
1997 N.Smethod_id
((pc
, cid), (pm
, meth
))
1998 | ((_, N.Id
(pc
, const)), (pm
, N.String meth
))
1999 when String.equal
const SN.PseudoConsts.g__CLASS__
->
2000 (* All of these that use current_cls aren't quite correct
2001 * inside a trait, as the class should be the using class.
2002 * It's sufficient for typechecking purposes (we require
2003 * subclass to be compatible with the trait member/method
2006 (match (fst
env).current_cls
with
2007 | Some
(cid, _, true) ->
2008 let cid = N.CI
(pc
, snd
cid) in
2009 N.Smethod_id
((p, cid), (pm
, meth
))
2010 | Some
(cid, kind
, false) ->
2011 let is_trait = Ast_defs.is_c_trait kind
in
2012 Errors.class_meth_non_final_CLASS
p is_trait (snd
cid);
2015 Errors.illegal_class_meth
p;
2017 | ((_, N.Class_const
((pc
, N.CI
cl), (_, mem
))), (pm
, N.String meth
))
2018 when String.equal mem
SN.Members.mClass
->
2019 let () = check_name cl in
2020 let cid = N.CI
cl in
2021 N.Smethod_id
((pc
, cid), (pm
, meth
))
2022 | ((p, N.Class_const
((pc
, N.CIself
), (_, mem
))), (pm
, N.String meth
))
2023 when String.equal mem
SN.Members.mClass
->
2024 (match (fst
env).current_cls
with
2025 | Some
(_cid
, _, true) -> N.Smethod_id
((pc
, N.CIself
), (pm
, meth
))
2026 | Some
(cid, _, false) ->
2027 Errors.class_meth_non_final_self
p (snd
cid);
2030 Errors.illegal_class_meth
p;
2032 | ( (p, N.Class_const
((pc
, N.CIstatic
), (_, mem
))),
2033 (pm
, N.String meth
) )
2034 when String.equal mem
SN.Members.mClass
->
2035 (match (fst
env).current_cls
with
2036 | Some
(_cid
, _, _) -> N.Smethod_id
((pc
, N.CIstatic
), (pm
, meth
))
2038 Errors.illegal_class_meth
p;
2041 Errors.illegal_class_meth
p;
2045 Errors.naming_too_many_arguments
p;
2051 Errors.naming_too_few_arguments
p;
2053 | el -> N.Tuple
(exprl
env el))
2054 | Aast.Call
((p, Aast.Id
f), tal
, el, unpacked_element
) ->
2056 ((p, N.Id
f), targl env p tal
, exprl
env el, oexpr
env unpacked_element
)
2058 (* Handle nullsafe instance method calls here. Because Obj_get is used
2059 for both instance property access and instance method calls, we need
2060 to match the entire "Call(Obj_get(..), ..)" pattern here so that we
2061 only match instance method calls *)
2063 ( (p, Aast.Obj_get
(e1, e2, Aast.OG_nullsafe
, in_parens
)),
2066 unpacked_element
) ->
2070 (expr env e1, expr_obj_get_name
env e2, N.OG_nullsafe
, in_parens
) ),
2073 oexpr
env unpacked_element
)
2074 (* Handle all kinds of calls that weren't handled by any of the cases above *)
2075 | Aast.Call
(e, tal
, el, unpacked_element
) ->
2077 (expr env e, targl env p tal
, exprl
env el, oexpr
env unpacked_element
)
2078 | Aast.FunctionPointer
(Aast.FP_id fid
, targs
) ->
2079 N.FunctionPointer
(N.FP_id fid
, targl env p targs
)
2080 | Aast.FunctionPointer
2081 (Aast.FP_class_const
((_, Aast.CIexpr
(_, Aast.Id
x1)), x2
), targs
) ->
2083 (N.FP_class_const
(make_class_id
env x1, x2
), targl env p targs
)
2084 | Aast.FunctionPointer
2085 (Aast.FP_class_const
((_, Aast.CIexpr
(_, Aast.Lvar
(p, lid
))), x2
), targs
)
2087 let x1 = (p, Local_id.to_string lid
) in
2089 (N.FP_class_const
(make_class_id
env x1, x2
), targl env p targs
)
2090 | Aast.FunctionPointer
_ -> N.Any
2091 | Aast.Yield
e -> N.Yield
(afield
env e)
2092 | Aast.Await
e -> N.Await
(expr env e)
2093 | Aast.List
el -> N.List
(exprl
env el)
2094 | Aast.Cast
(ty
, e2) ->
2097 | (_, Aast.Happly
(id, hl)) -> (id, hl)
2101 match try_castable_hint ~tp_depth
:1 ~ignore_hack_arr
:false env p x hl with
2102 | Some
ty -> (p, ty)
2104 let h = hint env ty in
2105 Errors.object_cast
p;
2108 N.Cast
(ty, expr env e2)
2109 | Aast.ExpressionTree et
->
2113 et_hint
= hint env et
.et_hint
;
2114 et_splices
= block
env et
.et_splices
;
2115 et_virtualized_expr
= expr env et
.et_virtualized_expr
;
2116 et_runtime_expr
= expr env et
.et_runtime_expr
;
2118 | Aast.ET_Splice
e -> N.ET_Splice
(expr env e)
2119 | Aast.Unop
(uop
, e) -> N.Unop
(uop
, expr env e)
2120 | Aast.Binop
((Ast_defs.Eq None
as op
), lv
, e2) ->
2121 let e2 = expr env e2 in
2122 let vars = get_lvalues
SMap.empty lv
in
2123 SMap.iter
(fun x p -> ignore
(Env.new_lvar env (p, x))) vars;
2124 N.Binop
(op
, expr env lv
, e2)
2125 | Aast.Binop
((Ast_defs.Eq
_ as bop
), e1, e2) ->
2126 N.Binop
(bop
, expr env e1, expr env e2)
2127 | Aast.Binop
(bop
, e1, e2) -> N.Binop
(bop
, expr env e1, expr env e2)
2128 | Aast.Pipe
(dollardollar
, e1, e2) ->
2130 ( (fst dollardollar
, Local_id.make_unscoped
SN.SpecialIdents.dollardollar
),
2133 | Aast.Eif
(e1, e2opt
, e3) ->
2134 (* The order matters here, of course -- e1 can define vars that need to
2135 * be available in e2 and e3. *)
2136 let e1 = expr env e1 in
2138 Env.scope env (fun env ->
2139 let e2opt = Env.scope env (fun env -> oexpr
env e2opt) in
2140 let e3 = Env.scope env (fun env -> expr env e3) in
2143 N.Eif
(e1, e2opt, e3)
2147 hint ~allow_wildcard
:true ~allow_like
:true ~ignore_hack_arr
:true env h
2149 | Aast.As
(e, h, b) ->
2152 hint ~allow_wildcard
:true ~allow_like
:true ~ignore_hack_arr
:true env h,
2154 | Aast.New
((_, Aast.CIexpr
(p, Aast.Id
x)), tal
, el, unpacked_element
, _) ->
2156 ( make_class_id
env x,
2159 oexpr
env unpacked_element
,
2162 ((_, Aast.CIexpr
(_, Aast.Lvar
(pos, x))), tal
, el, unpacked_element
, p)
2165 ( make_class_id
env (pos, Local_id.to_string
x),
2168 oexpr
env unpacked_element
,
2170 | Aast.New
((_, Aast.CIexpr
(p, _e
)), tal
, el, unpacked_element
, _) ->
2171 if Partial.should_check_error
(fst
env).in_mode
2060 then
2172 Errors.dynamic_new_in_strict_mode
p;
2174 ( make_class_id
env (p, SN.Classes.cUnknown
),
2177 oexpr
env unpacked_element
,
2179 | Aast.New
_ -> failwith
"ast_to_nast aast.new"
2180 | Aast.Record
(id, l
) ->
2181 let () = check_name id in
2182 let l = List.map
l (fun (e1, e2) -> (expr env e1, expr env e2)) in
2184 | Aast.Efun
(f, idl
) ->
2186 List.fold_right
idl ~init
:[] ~
f:(fun ((p, x) as id) acc
->
2187 if String.equal
(Local_id.to_string
x) SN.SpecialIdents.this
then (
2188 Errors.this_as_lexical_variable
p;
2193 let idl = List.map ~
f:(fun (p, lid
) -> (p, Local_id.to_string lid
)) idl in
2194 let idl'
= List.map
idl (Env.lvar env) in
2195 let env = (fst
env, Env.empty_local None
) in
2196 List.iter2_exn
idl idl'
(Env.add_lvar env);
2197 let f = expr_lambda
env f in
2199 | Aast.Lfun
(_, _ :: _) -> assert false
2200 | Aast.Lfun
(f, []) ->
2201 (* We have to build the capture list while we're finding names in
2202 the closure body---accumulate it in to_capture. *)
2203 let to_capture = ref [] in
2204 let handle_unbound (p, x) =
2205 let cap = Env.lvar env (p, x) in
2206 to_capture := cap :: !to_capture;
2209 let lenv = Env.empty_local @@ Some
handle_unbound in
2210 let env = (fst
env, lenv) in
2211 let f = expr_lambda
env f in
2212 N.Lfun
(f, !to_capture)
2213 | Aast.Xml
(x, al
, el) ->
2214 let () = check_name x in
2215 N.Xml
(x, attrl
env al
, exprl
env el)
2218 List.map fdl ~
f:(fun (pname
, value) ->
2219 (convert_shape_name env pname
, expr env value))
2222 | Aast.Import
_ -> N.Any
2223 | Aast.Omitted
-> N.Omitted
2224 | Aast.Callconv
(kind
, e) -> N.Callconv
(kind
, expr env e)
2225 | Aast.EnumAtom
x -> N.EnumAtom
x
2226 | Aast.ReadonlyExpr
e -> N.ReadonlyExpr
(expr env e)
2227 (* The below were not found on the AST.ml so they are not implemented here *)
2228 | Aast.ValCollection
_
2229 | Aast.KeyValCollection
_
2231 | Aast.Dollardollar
_
2232 | Aast.Lplaceholder
_
2235 | Aast.Method_caller
_
2240 Errors.internal_error
2242 "Malformed expr: Expr not found on legacy AST: T39599317";
2245 and expr_lambda
env f =
2247 Aast.type_hint_option_map ~
f:(hint ~allow_retonly
:true env) f.Aast.f_ret
2249 let (variadicity
, paraml
) = fun_paraml
env f.Aast.f_params
in
2250 (* The bodies of lambdas go through naming in the containing local
2252 let body_nast = f_body
env f.Aast.f_body
in
2253 let annotation = Nast.Named
in
2254 let f_ctxs = Option.map ~
f:(contexts
env) f.Aast.f_ctxs in
2255 let f_unsafe_ctxs = Option.map ~
f:(contexts
env) f.Aast.f_unsafe_ctxs in
2256 (* These could all be probably be replaced with a {... where ...} *)
2257 let body = { N.fb_ast = body_nast; fb_annotation
= annotation } in
2259 N.f_annotation
= ();
2260 f_readonly_this
= f.Aast.f_readonly_this
;
2261 f_span
= f.Aast.f_span
;
2262 f_mode
= (fst
env).in_mode
;
2263 f_readonly_ret
= f.Aast.f_readonly_ret
;
2265 f_name
= f.Aast.f_name
;
2270 f_where_constraints
= [];
2272 f_fun_kind
= f.Aast.f_fun_kind
;
2273 f_variadic
= variadicity
;
2274 f_file_attributes
= [];
2275 f_user_attributes
= user_attributes
env f.Aast.f_user_attributes
;
2276 f_external
= f.Aast.f_external
;
2277 f_namespace
= f.Aast.f_namespace
;
2278 f_doc_comment
= f.Aast.f_doc_comment
;
2281 and f_body
env f_body
=
2282 if Nast.is_body_named f_body
then
2283 block
env f_body
.Aast.fb_ast
2285 failwith
"Malformed f_body: unexpected UnnamedBody from ast_to_nast"
2287 and make_class_id
env ((p, x) as cid) =
2290 | x when String.equal
x SN.Classes.cParent
->
2291 if Option.is_none
(fst
env).current_cls
then
2292 let () = Errors.parent_outside_class
p in
2293 N.CI
(p, SN.Classes.cUnknown
)
2296 | x when String.equal
x SN.Classes.cSelf
->
2297 if Option.is_none
(fst
env).current_cls
then
2298 let () = Errors.self_outside_class
p in
2299 N.CI
(p, SN.Classes.cUnknown
)
2302 | x when String.equal
x SN.Classes.cStatic
->
2303 if Option.is_none
(fst
env).current_cls
then
2304 let () = Errors.static_outside_class
p in
2305 N.CI
(p, SN.Classes.cUnknown
)
2308 | x when String.equal
x SN.SpecialIdents.this
-> N.CIexpr
(p, N.This
)
2309 | x when String.equal
x SN.SpecialIdents.dollardollar
->
2310 (* We won't reach here for "new $$" because the parser creates a
2311 * proper Ast_defs.Dollardollar node, so make_class_id won't be called with
2312 * that node. In fact, the parser creates an Ast_defs.Dollardollar for all
2313 * "$$" except in positions where a classname is expected, like in
2314 * static member access. So, we only reach here for things
2315 * like "$$::someMethod()". *)
2317 (p, N.Lvar
(p, Local_id.make_unscoped
SN.SpecialIdents.dollardollar
))
2318 | x when Char.equal
x.[0] '$'
-> N.CIexpr
(p, N.Lvar
(Env.lvar env cid))
2320 let () = check_name cid in
2323 and casel
env l = List.map
l (case
env)
2327 | Aast.Default
(p, b) ->
2328 let b = branch
env b in
2330 | Aast.Case
(e, b) ->
2331 let e = expr env e in
2332 let b = branch
env b in
2335 and catchl
env l = List.map
l (catch
env)
2337 and catch
env ((p1
, lid1
), (p2
, lid2
), b) =
2338 Env.scope env (fun env ->
2339 let name2 = Local_id.get_name lid2
in
2340 let x2 = Env.new_lvar env (p2
, name2) in
2341 let b = branch
env b in
2342 let () = check_name (p1
, lid1
) in
2343 ((p1
, lid1
), x2, b))
2345 and afield
env field
=
2347 | Aast.AFvalue
e -> N.AFvalue
(expr env e)
2348 | Aast.AFkvalue
(e1, e2) -> N.AFkvalue
(expr env e1, expr env e2)
2350 and afield_value
env cname field
=
2352 | Aast.AFvalue
e -> expr env e
2353 | Aast.AFkvalue
(e1, _e2
) ->
2354 Errors.unexpected_arrow
(fst
e1) cname
;
2357 and afield_kvalue
env cname field
=
2360 Errors.missing_arrow
(fst
e) cname
;
2365 Aast.Lvar
(fst
e, Local_id.make_unscoped
"__internal_placeholder") )
2367 | Aast.AFkvalue
(e1, e2) -> (expr env e1, expr env e2)
2369 and attrl
env l = List.map ~
f:(attr env) l
2373 | Aast.Xhp_simple
{ Aast.xs_name
; xs_type
; xs_expr
= e } ->
2374 N.Xhp_simple
{ Aast.xs_name
; xs_type
; xs_expr
= expr env e }
2375 | Aast.Xhp_spread
e -> N.Xhp_spread
(expr env e)
2377 and string2
env idl = List.map
idl (expr env)
2379 let record_field env rf
=
2380 let (id, h, e) = rf
in
2381 let h = hint env h in
2382 let e = oexpr
env e in
2385 let record_def ctx rd
=
2386 let env = Env.make_top_level_env ctx
in
2388 elaborate_namespaces#on_record_def
2389 (Naming_elaborate_namespaces_endo.make_env
(fst
env).namespace
)
2392 let attrs = user_attributes
env rd.Aast.rd_user_attributes
in
2394 match rd.Aast.rd_extends
with
2395 | Some
extends -> Some
(hint env extends)
2398 let fields = List.map
rd.Aast.rd_fields ~
f:(record_field env) in
2400 N.rd_annotation
= ();
2401 rd_name
= rd.Aast.rd_name
;
2402 rd_abstract
= rd.Aast.rd_abstract
;
2403 rd_extends
= extends;
2405 rd_user_attributes
= attrs;
2406 rd_namespace
= rd.Aast.rd_namespace
;
2407 rd_span
= rd.Aast.rd_span
;
2408 rd_doc_comment
= rd.Aast.rd_doc_comment
;
2409 rd_emit_id
= rd.Aast.rd_emit_id
;
2412 (**************************************************************************)
2414 (**************************************************************************)
2416 let typedef ctx tdef
=
2417 let env = Env.make_typedef_env ctx tdef
in
2419 elaborate_namespaces#on_typedef
2420 (Naming_elaborate_namespaces_endo.make_env
(fst
env).namespace
)
2423 let tconstraint = Option.map
tdef.Aast.t_constraint
(hint env) in
2424 let tparaml = type_paraml
env tdef.Aast.t_tparams
in
2425 let attrs = user_attributes
env tdef.Aast.t_user_attributes
in
2427 N.t_annotation
= ();
2428 t_name
= tdef.Aast.t_name
;
2429 t_tparams
= tparaml;
2430 t_constraint
= tconstraint;
2431 t_kind
= hint env tdef.Aast.t_kind
;
2432 t_user_attributes
= attrs;
2433 t_mode
= tdef.Aast.t_mode
;
2434 t_namespace
= tdef.Aast.t_namespace
;
2435 t_vis
= tdef.Aast.t_vis
;
2436 t_span
= tdef.Aast.t_span
;
2437 t_emit_id
= tdef.Aast.t_emit_id
;
2440 (**************************************************************************)
2441 (* Global constants *)
2442 (**************************************************************************)
2444 let global_const ctx cst
=
2445 let env = Env.make_const_env ctx cst
in
2447 elaborate_namespaces#on_gconst
2448 (Naming_elaborate_namespaces_endo.make_env
(fst
env).namespace
)
2451 let hint = Option.map
cst.Aast.cst_type
(hint env) in
2452 let e = constant_expr
env false cst.Aast.cst_value
in
2454 N.cst_annotation
= ();
2455 cst_mode
= cst.Aast.cst_mode
;
2456 cst_name
= cst.Aast.cst_name
;
2459 cst_namespace
= cst.Aast.cst_namespace
;
2460 cst_span
= cst.Aast.cst_span
;
2461 cst_emit_id
= cst.Aast.cst_emit_id
;
2464 (**************************************************************************)
2465 (* The entry point to CHECK the program, and transform the program *)
2466 (**************************************************************************)
2468 let program ctx ast
=
2470 elaborate_namespaces#on_program
2471 (Naming_elaborate_namespaces_endo.make_env
2472 Namespace_env.empty_with_default
)
2475 let top_level_env = ref (Env.make_top_level_env ctx
) in
2476 let rec aux acc def
=
2478 | Aast.Fun
f -> N.Fun
(fun_ ctx
f) :: acc
2479 | Aast.Class
c -> N.Class
(class_ ctx
c) :: acc
2480 | Aast.Stmt
(_, Aast.Noop
)
2481 | Aast.Stmt
(_, Aast.Markup
_) ->
2483 | Aast.Stmt
s -> N.Stmt
(stmt !top_level_env s) :: acc
2484 | Aast.RecordDef
rd -> N.RecordDef
(record_def ctx
rd) :: acc
2485 | Aast.Typedef t
-> N.Typedef
(typedef ctx t
) :: acc
2486 | Aast.Constant
cst -> N.Constant
(global_const ctx
cst) :: acc
2487 | Aast.Namespace
(_ns
, aast
) -> List.fold_left ~
f:aux ~init
:[] aast
@ acc
2488 | Aast.NamespaceUse
_ -> acc
2489 | Aast.SetNamespaceEnv nsenv
->
2490 let (genv, lenv) = !top_level_env in
2491 let genv = { genv with namespace
= nsenv
} in
2492 top_level_env := (genv, lenv);
2494 | Aast.FileAttributes
_ -> acc
2496 let on_program aast
=
2497 let nast = List.fold_left ~
f:aux ~init
:[] aast
in