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
21 (* Alias for Nast used by functions on potentially unnamed Aast values *)
22 module Aast
= Ast_to_nast.Aast
24 module ShapeMap
= N.ShapeMap
25 module SN
= Naming_special_names
26 module NS
= Namespaces
28 module GEnv
= NamingGlobal.GEnv
30 (*****************************************************************************)
32 (*****************************************************************************)
34 (* We want to keep the positions of names that have been
35 * replaced by identifiers.
37 type positioned_ident
= (Pos.t
* Local_id.t
)
39 (* <T as A>, A is a type constraint *)
40 type type_constraint
= bool * (Ast.constraint_kind
* Ast.hint
) list
41 type aast_type_constraint
= bool * (Ast.constraint_kind
* Aast.hint
) list
43 let convert_type_constraints_to_aast =
44 Tuple.T2.map_snd ~f
:(List.map ~f
:(Tuple.T2.map_snd ~f
:Ast_to_nast.on_hint
))
48 (* strict? decl? partial? *)
49 in_mode
: FileInfo.mode
;
51 (* various options that control the strictness of the typechecker *)
52 tcopt
: TypecheckerOptions.t
;
54 (* are we in the body of a try statement? *)
57 (* are we in the body of a finally statement? *)
60 (* are we in a __PPL attributed class *)
63 (* In function foo<T1, ..., Tn> or class<T1, ..., Tn>, the field
64 * type_params knows T1 .. Tn. It is able to find out about the
65 * constraint on these parameters. *)
66 type_params
: aast_type_constraint
SMap.t
;
68 (* The current class, None if we are in a function *)
69 current_cls
: (Ast.id
* Ast.class_kind
) option;
71 class_consts
: (string, Pos.t
) Caml.Hashtbl.t
;
73 class_props
: (string, Pos.t
) Caml.Hashtbl.t
;
75 (* Normally we don't need to add dependencies at this stage, but there
76 * are edge cases when we do. *)
77 droot
: Typing_deps.Dep.variant
;
79 (* Namespace environment, e.g., what namespace we're in and what use
80 * declarations are in play. *)
81 namespace
: Namespace_env.env
;
84 (* Handler called when we see an unbound name. *)
85 type unbound_handler
= (Pos.t
* string) -> positioned_ident
87 (* The primitives to manipulate the naming environment *)
93 val empty_local
: unbound_handler
option -> lenv
95 aast_type_constraint
SMap.t
->
97 Ast.id
* Ast.class_kind
-> Namespace_env.env
-> bool -> genv
98 val aast_make_class_env
:
99 aast_type_constraint
SMap.t
-> Aast.class_
-> genv
* lenv
100 val aast_make_typedef_env
:
101 aast_type_constraint
SMap.t
-> Aast.typedef
-> genv
* lenv
102 val make_top_level_env
:
105 type_constraint
SMap.t
->
106 FileInfo.mode
-> string -> Namespace_env.env
-> genv
107 val aast_make_fun_decl_genv
:
108 aast_type_constraint
SMap.t
-> Aast.fun_
-> genv
109 val make_file_attributes_env
:
110 FileInfo.mode
-> Aast.nsenv
-> genv
* lenv
111 val aast_make_const_env
:
112 Aast.gconst
-> genv
* lenv
114 val has_unsafe
: genv
* lenv
-> bool
115 val set_unsafe
: genv
* lenv
-> bool -> unit
117 val in_ppl
: genv
* lenv
-> bool
118 val set_ppl
: genv
* lenv
-> bool -> genv
* lenv
120 val add_lvar
: genv
* lenv
-> Ast.id
-> positioned_ident
-> unit
121 val aast_add_lvar
: genv
* lenv
-> Aast.lid
-> positioned_ident
-> unit
122 val add_param
: genv
* lenv
-> N.fun_param
-> genv
* lenv
123 val new_lvar
: genv
* lenv
-> Ast.id
-> positioned_ident
124 val new_let_local
: genv
* lenv
-> Ast.id
-> positioned_ident
125 val found_dollardollar
: genv
* lenv
-> Pos.t
-> Local_id.t
126 val inside_pipe
: genv
* lenv
-> bool
127 val new_pending_lvar
: genv
* lenv
-> Ast.id
-> unit
128 val promote_pending_lvar
: genv
* lenv
-> string -> unit
129 val lvar
: genv
* lenv
-> Ast.id
-> positioned_ident
130 val aast_lvar
: genv
* lenv
-> Aast.lid
-> positioned_ident
131 val let_local
: genv
* lenv
-> Ast.id
-> positioned_ident
option
132 val global_const
: genv
* lenv
-> Ast.id
-> Ast.id
133 val type_name
: genv
* lenv
-> Ast.id
-> allow_typedef
:bool -> allow_generics
:bool -> Ast.id
134 val fun_id
: genv
* lenv
-> Ast.id
-> Ast.id
135 val bind_class_const
: genv
* lenv
-> Ast.id
-> unit
136 val goto_label
: genv
* lenv
-> string -> Pos.t
option
137 val new_goto_label
: genv
* lenv
-> Aast.pstring
-> unit
138 val new_goto_target
: genv
* lenv
-> Aast.pstring
-> unit
139 val check_goto_references
: genv
* lenv
-> unit
140 val copy_let_locals
: genv
* lenv
-> genv
* lenv
-> unit
142 val scope
: genv
* lenv
-> (genv
* lenv
-> 'a
) -> 'a
143 val scope_all
: genv
* lenv
-> (genv
* lenv
-> 'a
) -> all_locals
* 'a
144 val scope_lexical
: genv
* lenv
-> (genv
* lenv
-> 'a
) -> 'a
145 val extend_all_locals
: genv
* lenv
-> all_locals
-> unit
146 val remove_locals
: genv
* lenv
-> Ast.id list
-> unit
147 val pipe_scope
: genv
* lenv
-> (genv
* lenv
-> N.expr
) -> Local_id.t
* N.expr
150 type map
= positioned_ident
SMap.t
151 type all_locals
= Pos.t
SMap.t
154 (* The identifier for the special pipe variable $$ for this pipe scope. *)
155 dollardollar
: Local_id.t
;
156 (* Whether the current pipe scope's $$ has been used. Used to raise error
158 used_dollardollar
: bool;
161 (* The local environment *)
164 (* The set of locals *)
167 (* We keep all the locals, even if we are in a different scope
168 * to provide better error messages.
173 * Technically, passed this point, $x is unbound.
174 * But it is much better to keep it somewhere, so that you can
175 * say it is bound, but in a different scope.
177 all_locals
: all_locals
ref;
179 (* Some statements can define new variables afterwards, e.g.,
185 * We need to give $x the same name in both branches, but we don't want
186 * $x to actually be a local until after the if block. So we stash it here,
187 * to indicate a name has been pre-allocated, but that the variable isn't
188 * actually defined yet.
190 pending_locals
: map
ref;
192 (* The set of lexically-scoped local `let` variables *)
193 (* TODO: Currently these locals live in a separate namespace, it is
194 * worthwhile considering unified namespace for all local variables T28712009 *)
197 (* stack of pipe scopes.
198 * We use a stack (represented by a list) because pipe operators
200 pipe_locals
: pipe_scope list
ref;
202 (* Handler called when we see an unbound name.
203 * This is used to compute an approximation of the list of captured
204 * variables for closures: when we see an undefined variable, we add it
205 * to the list of captured variables.
207 * See expr_lambda for details.
209 unbound_handler
: unbound_handler
option;
211 (* The presence of an "UNSAFE" in the function body changes the
212 * verifiability of the function's return type, since the unsafe
213 * block could return. For the sanity of the typechecker, we flatten
214 * this out, but need to track if we've seen an "UNSAFE" in order to
216 has_unsafe
: bool ref;
219 * A map from goto label strings to named labels.
221 goto_labels
: Pos.t
SMap.t
ref;
224 * A map from goto label used in a goto statement to the position of that
227 goto_targets
: Pos.t
SMap.t
ref;
230 let empty_local unbound_handler
= {
231 locals
= ref SMap.empty
;
232 all_locals
= ref SMap.empty
;
233 pending_locals
= ref SMap.empty
;
234 let_locals
= ref SMap.empty
;
235 pipe_locals
= ref [];
237 has_unsafe
= ref false;
238 goto_labels
= ref SMap.empty
;
239 goto_targets
= ref SMap.empty
;
242 let make_class_genv tparams mode
(cid
, ckind
) namespace is_ppl
=
244 tcopt
= GlobalNamingOptions.get
();
248 type_params
= tparams
;
249 current_cls
= Some
(cid
, ckind
);
250 class_consts
= Caml.Hashtbl.create
0;
251 class_props
= Caml.Hashtbl.create
0;
252 droot
= Typing_deps.Dep.Class
(snd cid
);
256 let unbound_name_error genv pos name kind
=
257 (* Naming pretends to be local and not dependent on other files, so it
258 * doesn't bother with adding dependencies (even though it does look up
259 * things in global state). This is mostly brushed aside because "they
260 * will be added during typing". Unfortunately, there are multiple scenarios
261 * when typechecker will name an expression, but gives up on typechecking
262 * it. We are then left with a unrecorded dependency. This should be fixed
263 * on some more basic level, but so far the only incorrectness that anyone
264 * has observed due to this is that we fail to remove "unbound name" errors
265 * sometimes. I add this dependency here for now to fix the annoyance it
266 * causes developers. *)
267 begin match kind
with
268 | `func
-> Typing_deps.Dep.Fun name
269 | `cls
-> Typing_deps.Dep.Class name
270 | `const
-> Typing_deps.Dep.GConst name
271 end |> Typing_deps.add_idep genv
.droot
;
272 Errors.unbound_name pos name kind
274 let aast_make_class_env tparams c
=
275 let is_ppl = List.exists
276 c
.Aast.c_user_attributes
277 (fun { Aast.ua_name
; _
} -> snd ua_name
= SN.UserAttributes.uaProbabilisticModel
) in
278 let genv = make_class_genv tparams c
.Aast.c_mode
279 (c
.Aast.c_name
, c
.Aast.c_kind
) c
.Aast.c_namespace
is_ppl in
280 let lenv = empty_local None
in
283 let make_typedef_genv cstrs tdef_name tdef_namespace
= {
284 in_mode
= FileInfo.Mstrict
;
285 tcopt
= GlobalNamingOptions.get
();
291 class_consts
= Caml.Hashtbl.create
0;
292 class_props
= Caml.Hashtbl.create
0;
293 droot
= Typing_deps.Dep.Class tdef_name
;
294 namespace
= tdef_namespace
;
297 let aast_make_typedef_env cstrs tdef
=
298 let genv = make_typedef_genv cstrs
(snd tdef
.Aast.t_name
) tdef
.Aast.t_namespace
in
299 let lenv = empty_local None
in
302 let make_fun_genv params f_mode f_name f_namespace
= {
304 tcopt
= GlobalNamingOptions.get
();
308 type_params
= SMap.map
convert_type_constraints_to_aast params
;
310 class_consts
= Caml.Hashtbl.create
0;
311 class_props
= Caml.Hashtbl.create
0;
312 droot
= Typing_deps.Dep.Fun f_name
;
313 namespace
= f_namespace
;
316 let aast_make_fun_genv params f_mode f_name f_namespace
=
318 ; tcopt
= GlobalNamingOptions.get
()
322 ; type_params
= params
324 ; class_consts
= Caml.Hashtbl.create
0
325 ; class_props
= Caml.Hashtbl.create
0
326 ; droot
= Typing_deps.Dep.Fun f_name
327 ; namespace
= f_namespace
330 let aast_make_fun_decl_genv params f
=
331 aast_make_fun_genv params f
.Aast.f_mode
(snd f
.Aast.f_name
) f
.Aast.f_namespace
333 let aast_make_const_genv cst
= {
334 in_mode
= cst
.Aast.cst_mode
;
335 tcopt
= GlobalNamingOptions.get
();
339 type_params
= SMap.empty
;
341 class_consts
= Caml.Hashtbl.create
0;
342 class_props
= Caml.Hashtbl.create
0;
343 droot
= Typing_deps.Dep.GConst
(snd cst
.Aast.cst_name
);
344 namespace
= cst
.Aast.cst_namespace
;
347 let make_top_level_genv () = {
348 in_mode
= FileInfo.Mpartial
;
349 tcopt
= GlobalNamingOptions.get
();
353 type_params
= SMap.empty
;
355 class_consts
= Caml.Hashtbl.create
0;
356 class_props
= Caml.Hashtbl.create
0;
357 droot
= Typing_deps.Dep.Fun
"";
358 namespace
= Namespace_env.empty_with_default_popt
;
361 let make_top_level_env () =
362 let genv = make_top_level_genv () in
363 let lenv = empty_local None
in
364 let env = genv, lenv in
367 let make_file_attributes_genv mode namespace
=
370 tcopt
= GlobalNamingOptions.get
();
374 type_params
= SMap.empty
;
376 class_consts
= Caml.Hashtbl.create
0;
377 class_props
= Caml.Hashtbl.create
0;
378 droot
= Typing_deps.Dep.Fun
"";
379 namespace
= namespace
;
382 let make_file_attributes_env mode namespace
=
383 let genv = make_file_attributes_genv mode namespace
in
384 let lenv = empty_local None
in
385 let env = genv, lenv in
388 let aast_make_const_env cst
=
389 let genv = aast_make_const_genv cst
in
390 let lenv = empty_local None
in
391 let env = genv, lenv in
394 let has_unsafe (_genv
, lenv) = !(lenv.has_unsafe)
395 let set_unsafe (_genv
, lenv) x
=
398 let in_ppl (genv, _lenv
) = genv.in_ppl
400 let set_ppl (genv, lenv) in_ppl =
401 let genv = { genv with in_ppl } in
404 let lookup genv (env : string -> FileInfo.pos
option) (p
, x
) =
408 (match genv.in_mode
with
409 | FileInfo.Mstrict
| FileInfo.Mexperimental
-> unbound_name_error genv p x `const
410 | FileInfo.Mpartial
| FileInfo.Mdecl
when not
411 (TypecheckerOptions.assume_php
genv.tcopt
) ->
412 unbound_name_error genv p x `const
413 | FileInfo.Mphp
| FileInfo.Mdecl
| FileInfo.Mpartial
-> ()
417 let handle_unbound_name genv get_full_pos get_canon
(p
, name
) kind
=
418 match get_canon name
with
422 |> Option.iter ~f
:(fun p_canon
->
423 Errors.did_you_mean_naming p name p_canon canonical
);
424 (* Recovering from the capitalization error means
425 * returning the name in its canonical form *)
428 (match genv.in_mode
with
429 | FileInfo.Mpartial
| FileInfo.Mdecl
430 when TypecheckerOptions.assume_php
genv.tcopt
431 || name
= SN.Classes.cUnknown
-> ()
432 | FileInfo.Mphp
-> ()
433 | FileInfo.Mstrict
| FileInfo.Mexperimental
-> unbound_name_error genv p name kind
434 | FileInfo.Mpartial
| FileInfo.Mdecl
->
435 unbound_name_error genv p name kind
439 let canonicalize genv get_pos get_full_pos get_canon
(p
, name
) kind
=
440 (* Get the canonical name to check if the name exists in the heap *)
441 match get_pos name
with
443 | None
-> handle_unbound_name genv get_full_pos get_canon
(p
, name
) kind
445 let check_variable_scoping env (_p
, x
) =
446 match SMap.get x
!(env.all_locals
) with
447 | Some _p'
-> () (*Errors.different_scope p x p'*)
450 (* Adds a local variable, without any check *)
451 let add_lvar (_
, lenv) (_
, name
) (p
, x
) =
452 lenv.locals
:= SMap.add name
(p
, x
) !(lenv.locals
);
455 let aast_add_lvar (_
, lenv) (_
, lid
) (p
, x
) =
456 lenv.locals
:= SMap.add
(Local_id.to_string lid
) (p
, x
) !(lenv.locals
);
459 let add_param env param
=
460 let p_name = param
.N.param_name
in
461 let id = Local_id.get
p_name in
462 let p_pos = param
.N.param_pos
in
463 let () = add_lvar env (p_pos, p_name) (p_pos, id) in
466 (* Defines a new local variable.
468 1) if the local is not in the local environment then it is added.
469 Return value: the given position and deduced/created identifier. *)
470 let new_lvar (_
, lenv) (p
, x
) =
471 let lcl = SMap.get x
!(lenv.locals
) in
474 | Some
lcl -> snd
lcl
476 let ident = (match SMap.get x
!(lenv.pending_locals
) with
477 | Some
(_
, ident) -> ident
478 | None
-> Local_id.make_unscoped x
) in
479 lenv.all_locals
:= SMap.add x p
!(lenv.all_locals
);
480 lenv.locals
:= SMap.add x
(p
, ident) !(lenv.locals
);
485 (* Defines a new scoped local variable
487 * Always add a new variable in the local environment.
488 * If the variable has been defined already, shadow the previously-defined
490 (* TODO: Emit warning if names are getting shadowed T28436131 *)
491 let new_let_local (_
, lenv) (p
, x
) =
492 let ident = Local_id.make_scoped x
in
493 lenv.all_locals
:= SMap.add x p
!(lenv.all_locals
);
494 lenv.let_locals
:= SMap.add x
(p
, ident) !(lenv.let_locals
);
497 (* Check $$ is defined (i.e. we are indeed in a pipe) and if yes, mark it
498 * as used and get the identifier for it. *)
499 let found_dollardollar (_
, lenv) p
=
500 match !(lenv.pipe_locals
) with
502 Errors.undefined ~in_rx_scope
:false p
SN.SpecialIdents.dollardollar
; (* TODO better error *)
503 Local_id.make_scoped
SN.SpecialIdents.dollardollar
504 | pipe_scope
:: scopes
->
505 let pipe_scope = { pipe_scope with used_dollardollar
= true } in
506 lenv.pipe_locals
:= pipe_scope :: scopes
;
507 pipe_scope.dollardollar
509 let inside_pipe (_
, lenv) =
510 match !(lenv.pipe_locals
) with
514 let new_pending_lvar (_
, lenv) (p
, x
) =
515 match SMap.get x
!(lenv.locals
), SMap.get x
!(lenv.pending_locals
) with
517 let y = p
, Local_id.make_unscoped x
in
518 lenv.pending_locals
:= SMap.add x
y !(lenv.pending_locals
)
521 let promote_pending_lvar (_
, lenv) x
=
522 match SMap.get x
!(lenv.pending_locals
) with
524 lenv.locals
:= SMap.add x
(p
, ident) !(lenv.locals
);
525 lenv.pending_locals
:= SMap.remove x
!(lenv.pending_locals
)
528 let handle_undefined_variable (_genv
, env) (p
, x
) =
529 match env.unbound_handler
with
530 | None
-> p
, Local_id.make_unscoped x
533 (* Function used to name a local variable *)
534 let lvar (genv, env) (p
, x
) =
536 if SN.Superglobals.is_superglobal x
&& genv.in_mode
= FileInfo.Mpartial
537 then p, Local_id.make_unscoped x
539 let lcl = SMap.get x
!(env.locals
) in
541 | Some
lcl -> p, snd
lcl
543 check_variable_scoping env (p, x
);
544 handle_undefined_variable (genv, env) (p, x
)
548 let aast_lvar (genv, env) (p, x
) =
549 lvar (genv, env) (p, Local_id.to_string x
)
551 let let_local (_genv
, env) (p, x
) =
552 let lcl = SMap.get x
!(env.let_locals
) in
554 | Some
lcl -> Some
(p, snd
lcl)
557 let get_name genv get_pos x
=
558 lookup genv get_pos x
; x
560 (* For dealing with namespace resolution on functions *)
561 let elaborate_and_get_name_with_canonicalized_fallback
563 (get_pos
: string -> FileInfo.pos
option)
564 (get_full_pos
: string -> Pos.t
option)
566 let get_name x
= get_name genv get_pos x
in
567 let canonicalize = canonicalize genv get_pos get_full_pos get_canon
in
568 let fq_x = NS.elaborate_id
genv.namespace
NS.ElaborateFun x
in
569 let fq_x = canonicalize fq_x `func
in
572 let global_const (genv, _env
) x
=
573 let fq_x = NS.elaborate_id
genv.namespace
NS.ElaborateConst x
in
574 get_name genv (Naming_heap.ConstPosHeap.get
) fq_x
576 let type_name (genv, _
) x ~allow_typedef ~allow_generics
=
578 match SMap.find_opt name
genv.type_params
with
579 | Some
(reified
, _
) ->
580 if not allow_generics
then Errors.generics_not_allowed
p;
581 if not reified
then Errors.generic_at_runtime
p;
584 let (pos
, name
) as x
= NS.elaborate_id
genv.namespace
NS.ElaborateClass x
in
585 match Naming_heap.TypeIdHeap.get name
with
586 | Some
(_def_pos
, `Class
) ->
587 (* Don't let people use strictly internal classes
588 * (except when they are being declared in .hhi files) *)
589 if name
= SN.Classes.cHH_BuiltinEnum
&&
590 not
(string_ends_with
(Relative_path.suffix
(Pos.filename pos
)) ".hhi")
591 then Errors.using_internal_class pos
(strip_ns name
);
593 | Some
(def_pos
, `Typedef
) when not allow_typedef
->
594 let full_pos, _
= GEnv.get_full_pos
(def_pos
, name
) in
595 Errors.unexpected_typedef pos
full_pos;
597 | Some
(_def_pos
, `Typedef
) -> pos
, name
599 handle_unbound_name genv
601 GEnv.type_canon_name x `cls
603 let fun_id (genv, _
) x
=
604 elaborate_and_get_name_with_canonicalized_fallback
606 (Naming_heap.FunPosHeap.get
)
611 let bind_class_member tbl
(p, x
) =
613 let p'
= Caml.Hashtbl.find tbl x
in
614 Errors.error_name_already_bound x x
p p'
615 with Caml.Not_found
->
616 Caml.Hashtbl.replace tbl x
p
618 let bind_class_const (genv, _env
) (p, x
) =
619 if String.lowercase x
= "class" then Errors.illegal_member_variable_class
p;
620 bind_class_member genv.class_consts
(p, x
)
623 * Returns the position of the goto label declaration, if it exists.
625 let goto_label (_
, { goto_labels
; _
}) label
=
626 SMap.get label
!goto_labels
629 * Adds a goto label and the position of its declaration to the known labels.
631 let new_goto_label (_
, { goto_labels
; _
}) (pos
, label
) =
632 goto_labels
:= SMap.add label pos
!goto_labels
635 * Adds a goto target and its reference position to the known targets.
637 let new_goto_target (_
, { goto_targets
; _
}) (pos
, label
) =
638 goto_targets
:= SMap.add label pos
!goto_targets
641 * Ensures that goto statements do not reference goto labels that are not
642 * known within the current lenv.
644 let check_goto_references (_
, { goto_labels
; goto_targets
; _
}) =
645 let check_label referenced_label referenced_label_pos
=
646 if not
(SMap.mem referenced_label
!goto_labels
) then
647 Errors.goto_label_undefined referenced_label_pos referenced_label
in
648 SMap.iter
check_label !goto_targets
650 (* Scope, keep the locals, go and name the body, and leave the
651 * local environment intact
654 let _genv, lenv = env in
655 let lenv_copy = !(lenv.locals
) in
656 let lenv_pending_copy = !(lenv.pending_locals
) in
657 let lenv_scoped_copy = !(lenv.let_locals
) in
659 lenv.locals
:= lenv_copy;
660 lenv.pending_locals
:= lenv_pending_copy;
661 lenv.let_locals
:= lenv_scoped_copy;
664 let remove_locals env vars
=
665 let _genv, lenv = env in
667 List.fold_left vars ~f
:(fun l
id -> SMap.remove
(snd
id) l
) ~init
:!(lenv.locals
)
669 let scope_all env f
=
670 let _genv, lenv = env in
671 let lenv_all_locals_copy = !(lenv.all_locals
) in
672 let res = scope env f
in
673 let lenv_all_locals = !(lenv.all_locals
) in
674 lenv.all_locals
:= lenv_all_locals_copy;
677 (* Add a new lexical scope for block-scoped `let` variables.
678 No other changes in the local environment *)
679 let scope_lexical env f
=
680 let _genv, lenv = env in
681 let lenv_scoped_copy = !(lenv.let_locals
) in
683 lenv.let_locals
:= lenv_scoped_copy;
686 (* Copy the let locals from lenv1 to lenv2 *)
687 let copy_let_locals (_genv1
, lenv1
) (_genv2
, lenv2
) =
688 let let_locals_1 = !(lenv1
.let_locals
) in
689 lenv2
.let_locals
:= let_locals_1
691 let extend_all_locals (_genv, lenv) more_locals
=
692 lenv.all_locals
:= SMap.union more_locals
!(lenv.all_locals
)
694 (** Push a new pipe scope on the stack of pipe scopes in the environment
695 * and create an identifier for the $$ variable associated to this pipe,
696 * then perform the naming function [name_e2],
697 * then finally pops the added pipe scope.
698 * Append an error if $$ was not used in the RHS.
700 * Return the identifier for the $$ of this pipe and the names RHS.
702 let pipe_scope env name_e2
=
704 let pipe_var_ident = Local_id.make_scoped
SN.SpecialIdents.dollardollar
in
706 dollardollar
= pipe_var_ident;
707 used_dollardollar
= false;
709 lenv.pipe_locals
:= pipe_scope :: !(lenv.pipe_locals
);
710 (** Name the RHS of the pipe expression. *)
711 let e2 = name_e2
env in
712 let (pipe_scope, pipe_scopes
) = match !(lenv.pipe_locals
) with
714 | pipe_scope :: pipe_scopes
-> (pipe_scope, pipe_scopes
) in
715 if not
pipe_scope.used_dollardollar
then
716 Errors.dollardollar_unused
(fst
e2);
717 lenv.pipe_locals
:= pipe_scopes
;
721 (*****************************************************************************)
723 (*****************************************************************************)
725 let aast_check_constraint { Aast.tp_name
= (pos
, name
); _ } =
726 if String.lowercase name
= "this"
727 then Errors.this_reserved pos
728 else if name
.[0] <> 'T'
then Errors.start_with_T pos
730 let aast_check_repetition s param
=
731 let name = param
.Aast.param_name
in
733 then Errors.already_bound param
.Aast.param_pos
name;
734 if name <> SN.SpecialIdents.placeholder
738 let convert_shape_name env = function
739 | Ast.SFlit_int
(pos
, s
) -> (pos
, Ast.SFlit_int
(pos
, s
))
740 | Ast.SFlit_str
(pos
, s
) -> (pos
, Ast.SFlit_str
(pos
, s
))
741 | Ast.SFclass_const
(x
, (pos
, y)) ->
743 if (snd x
) = SN.Classes.cSelf
then
744 match (fst
env).current_cls
with
745 | Some
(cid
, _) -> cid
746 | None
-> Errors.self_outside_class pos
; (pos
, SN.Classes.cUnknown
)
747 else Env.type_name env x ~allow_typedef
:false ~allow_generics
:false in
748 (pos
, Ast.SFclass_const
(class_name, (pos
, y)))
750 let arg_unpack_unexpected = function
752 | (pos
, _) :: _ -> Errors.naming_too_few_arguments pos
; ()
754 module type GetLocals
= sig
755 val stmt
: Namespace_env.env * Pos.t
SMap.t
->
756 Ast.stmt
-> Namespace_env.env * Pos.t
SMap.t
757 val lvalue
: Namespace_env.env * Pos.t
SMap.t
->
758 Ast.expr
-> Namespace_env.env * Pos.t
SMap.t
760 val aast_lvalue
: Namespace_env.env * Pos.t
SMap.t
->
761 Aast.expr
-> Namespace_env.env * Pos.t
SMap.t
762 val aast_stmt
: Namespace_env.env * Pos.t
SMap.t
->
763 Aast.stmt
-> Namespace_env.env * Pos.t
SMap.t
766 (* This was made a functor due to the awkward nature of how our naming
767 * code is structured.
769 * Naming is called both in the decl phase and type-check phase. In the
770 * decl phase it's mostly used to construct things that do not belong in
771 * function bodies; examples include classes, their member fields, and
772 * global constants. This part of naming is entirely self-contained; it
773 * only uses the data from the AST in the current file, and does not need
774 * to cross-reference decl type data from other files.
776 * In the type-check phase, Naming is invoked again, this time to name the
777 * bodies of functions. Now it requires decl type data in order to know
778 * which function calls are marked as `noreturn`, because this affects
779 * which local variables are considered to be defined at the end of a
782 * So decl depends on naming, but naming also depends on decl, creating
783 * a circular dependency. The obvious solution would be to split it into
784 * two, but this is nontrivial because decl-phase naming also does some
785 * naming of expressions -- for example, constant initializers and default
786 * parameter values have them. Of course, none of these expressions can
787 * actually contain local variables, but our code is not written in a way
788 * that the OCaml type system can understand that. So as a hacky solution,
789 * I'm parameterizing GetLocals so that it is a no-op in the decl phase
790 * but can be properly instantiated with Typing_get_locals in the typing
793 module Make
(GetLocals
: GetLocals
) = struct
794 (************************************************************************)
795 (* Naming of type hints *)
796 (************************************************************************)
798 * The existing hint function goes from Ast.hint -> Nast.hint
799 * This hint function goes from Aast.hint -> Nast.hint
800 * Used with with Ast_to_nast to go from Ast.hint -> Nast.hint
804 ?
(allow_retonly
=false)
805 ?
(allow_typedef
=true)
806 ?
(allow_wildcard
=false)
807 ?
(in_where_clause
=false)
809 env (hh
: Aast.hint
) =
810 let mut, (p, h
) = aast_unwrap_mutability hh
in
811 if Option.is_some
mut
812 then Errors.misplaced_mutability_hint
p;
822 and aast_unwrap_mutability
p =
824 | _, Aast.Happly
((_, "Mutable"), [t
]) -> Some
N.PMutable
, t
825 | _, Aast.Happly
((_, "MaybeMutable"), [t
]) -> Some
N.PMaybeMutable
, t
826 | _, Aast.Happly
((_, "OwnedMutable"), [t
]) -> Some
N.POwnedMutable
, t
829 and aast_hfun
env reactivity is_coroutine hl kl variadic_hint h
=
831 match variadic_hint with
833 | Aast.Hvariadic None
-> variadic_hint
834 | Aast.Hvariadic
(Some h
) -> N.Hvariadic
(Some
(aast_hint env h
)) in
836 List.map ~f
:(fun h
->
837 let mut, h1
= aast_unwrap_mutability h
in
838 if Option.is_some
mut && reactivity
= N.FNonreactive
839 then Errors.mutability_hint_in_non_rx_function
(fst h
);
840 mut, aast_hint env h1
)
843 let ret_mut, rh
= aast_unwrap_mutability h
in
847 | Some
N.POwnedMutable
-> true
849 Errors.invalid_mutability_in_return_type_hint
(fst h
);
851 N.Hfun
(reactivity
, is_coroutine
, hl
, kl
, muts,
852 variadic_hint, aast_hint ~allow_retonly
:true env rh
, ret_mut)
854 and aast_hint_ ~forbid_this ~allow_retonly ~allow_typedef ~allow_wildcard
855 ~in_where_clause ?
(tp_depth
=0)
858 aast_hint ~forbid_this ~allow_typedef ~allow_wildcard
in
861 N.Htuple
(List.map hl ~f
:(aast_hint ~allow_retonly
env))
863 (* void/noreturn are permitted for Typing.option_return_only_typehint *)
864 N.Hoption
(aast_hint ~allow_retonly
env h
)
866 let h = aast_hint ~allow_retonly
env h
868 | Aast.Hfun
(reactivity
, coroutine
, hl
, kl
, _, variadic_hint, h, _) ->
869 aast_hfun
env reactivity coroutine hl kl
variadic_hint h
870 (* Special case for Rx<function> *)
872 ((_, "Rx"), [(_, Aast.Hfun
(_, is_coroutine
, hl
, kl
, _, variadic_hint, h, _))]) ->
873 aast_hfun
env N.FReactive is_coroutine hl kl
variadic_hint h
874 (* Special case for RxShallow<function> *)
877 [(_, Aast.Hfun
(_, is_coroutine
, hl
, kl
, _, variadic_hint, h, _))]) ->
878 aast_hfun
env N.FShallow is_coroutine hl kl
variadic_hint h
879 (* Special case for RxLocal<function> *)
882 [(_, Aast.Hfun
(_, is_coroutine
, hl
, kl
, _, variadic_hint, h, _))]) ->
883 aast_hfun
env N.FLocal is_coroutine hl kl
variadic_hint h
884 | Aast.Happly
((p, _x
) as id, hl
) ->
886 aast_hint_id ~forbid_this ~allow_retonly ~allow_typedef ~allow_wildcard ~tp_depth
890 | N.Hprim
_ | N.Hmixed
| N.Hnonnull
| N.Hnothing
->
891 if hl
<> [] then Errors.unexpected_type_arguments
p
895 | Aast.Haccess
((pos
, root_id
), ids
) ->
898 | Aast.Happly
((pos
, x
), _) when x
= SN.Classes.cSelf
->
900 match (fst
env).current_cls
with
901 | None
-> Errors.self_outside_class pos
; N.Hany
902 | Some
(cid
, _) -> N.Happly
(cid
, [])
904 | Aast.Happly
((pos
, x
), _) when x
= SN.Classes.cStatic
|| x
= SN.Classes.cParent
->
905 Errors.invalid_type_access_root
(pos
, x
); N.Hany
906 | Aast.Happly
(root
, _) ->
907 let h = aast_hint_id ~forbid_this ~allow_retonly ~allow_typedef
908 ~allow_wildcard
:false ~tp_depth
env root
[] in
913 | N.Habstr
_ when in_where_clause
-> h
914 | _ -> Errors.invalid_type_access_root root
; N.Hany
917 Errors.internal_error
919 "Malformed hint: expected Haccess (Happly ...) from ast_to_nast";
922 N.Haccess
((pos
, root_ty), ids
)
923 | Aast.Hshape
{ Aast.nsi_allows_unknown_fields
; nsi_field_map
} ->
926 (fun key
{ Aast.sfi_optional
; sfi_hint
} acc
->
927 let _pos, new_key
= convert_shape_name env key
in
928 let new_field = { N.sfi_optional
; sfi_hint
= aast_hint ~allow_retonly
env sfi_hint
} in
929 ShapeMap.add new_key
new_field acc
)
932 N.Hshape
{ N.nsi_allows_unknown_fields
; nsi_field_map }
940 | Aast.Hvarray_or_darray
_
945 Errors.internal_error
Pos.none
"Unexpected hint not present on legacy AST";
948 and aast_hint_id ~forbid_this ~allow_retonly ~allow_typedef ~allow_wildcard ~tp_depth
949 env (p, x
as id) hl
=
950 let params = (fst
env).type_params
in
951 let allow_null = TypecheckerOptions.experimental_feature_enabled
953 TypecheckerOptions.experimental_null_type
955 (* some common Xhp screw ups *)
956 if (x
= "Xhp") || (x
= ":Xhp") || (x
= "XHP")
957 then Errors.disallowed_xhp_type
p x
;
958 match aast_try_castable_hint ~forbid_this ~allow_wildcard ~tp_depth
env p x hl
with
962 | x
when x
= SN.Typehints.wildcard
&& allow_wildcard
&& tp_depth
= 1 ->
964 (Errors.tparam_with_tparam
p x
;
968 | x
when x
= SN.Typehints.wildcard
->
969 Errors.wildcard_disallowed
p;
972 ( x
= ("\\"^
SN.Typehints.void
)
973 || x
= ("\\"^
SN.Typehints.null
)
974 || x
= ("\\"^
SN.Typehints.noreturn
)
975 || x
= ("\\"^
SN.Typehints.int)
976 || x
= ("\\"^
SN.Typehints.bool)
977 || x
= ("\\"^
SN.Typehints.float)
978 || x
= ("\\"^
SN.Typehints.num
)
979 || x
= ("\\"^
SN.Typehints.string)
980 || x
= ("\\"^
SN.Typehints.resource
)
981 || x
= ("\\"^
SN.Typehints.mixed
)
982 || x
= ("\\"^
SN.Typehints.nonnull
)
983 || x
= ("\\"^
SN.Typehints.array
)
984 || x
= ("\\"^
SN.Typehints.arraykey
)
985 || x
= ("\\"^
SN.Typehints.integer
)
986 || x
= ("\\"^
SN.Typehints.boolean
)
987 || x
= ("\\"^
SN.Typehints.double
)
988 || x
= ("\\"^
SN.Typehints.real)
990 Errors.primitive_toplevel
p;
992 | x
when x
= "\\"^
SN.Typehints.nothing
&&
993 TypecheckerOptions.new_inference
(fst
env).tcopt
->
994 Errors.primitive_toplevel
p;
996 | x
when x
= SN.Typehints.void
&& allow_retonly
-> N.Hprim
N.Tvoid
997 | x
when x
= SN.Typehints.void
->
998 Errors.return_only_typehint
p `void
;
1000 | x
when x
= SN.Typehints.noreturn
&& allow_retonly
-> N.Hprim
N.Tnoreturn
1001 | x
when x
= SN.Typehints.noreturn
->
1002 Errors.return_only_typehint
p `noreturn
;
1004 | x
when x
= SN.Typehints.null
&& allow_null -> N.Hprim
N.Tnull
1005 | x
when x
= SN.Typehints.num
-> N.Hprim
N.Tnum
1006 | x
when x
= SN.Typehints.resource
-> N.Hprim
N.Tresource
1007 | x
when x
= SN.Typehints.arraykey
-> N.Hprim
N.Tarraykey
1008 | x
when x
= SN.Typehints.mixed
-> N.Hmixed
1009 | x
when x
= SN.Typehints.nonnull
-> N.Hnonnull
1010 | x
when x
= SN.Typehints.dynamic
-> N.Hdynamic
1011 | x
when x
= SN.Typehints.nothing
&&
1012 TypecheckerOptions.new_inference
(fst
env).tcopt
->
1014 | x
when x
= SN.Typehints.this
&& not forbid_this
->
1015 if not
(phys_equal hl
[])
1016 then Errors.this_no_argument
p;
1017 (match (fst
env).current_cls
with
1019 Errors.this_hint_outside_class
p;
1024 | x
when x
= SN.Typehints.this
->
1025 (match (fst
env).current_cls
with
1027 Errors.this_hint_outside_class
p
1029 Errors.this_type_forbidden
p
1032 | x
when x
= SN.Classes.cClassname
&& (List.length hl
) <> 1 ->
1033 Errors.classname_param
p;
1035 | _ when String.lowercase x
= SN.Typehints.this
->
1036 Errors.lowercase_this
p x
;
1038 | _ when SMap.mem x
params ->
1040 Errors.tparam_with_tparam
p x
;
1043 let name = Env.type_name env id ~allow_typedef ~allow_generics
:false in
1044 (* Note that we are intentionally setting allow_typedef to `true` here.
1045 * In general, generics arguments can be typedefs -- there is no
1046 * runtime restriction. *)
1047 N.Happly
(name, aast_hintl ~allow_wildcard ~forbid_this ~allow_typedef
:true
1048 ~allow_retonly
:true ~tp_depth
:(tp_depth
+1) env hl
)
1051 (* Hints that are valid both as casts and type annotations. Neither
1052 * casts nor annotations are a strict subset of the other: For
1053 * instance, 'object' is not a valid annotation. Thus callers will
1054 * have to handle the remaining cases. *)
1055 and aast_try_castable_hint ?
(forbid_this
=false) ?
(allow_wildcard
=false) ~tp_depth
env p x hl
=
1057 aast_hint ~forbid_this ~tp_depth
:(tp_depth
+1) ~allow_wildcard ~allow_retonly
:false in
1058 let canon = String.lowercase x
in
1059 let opt_hint = match canon with
1060 | nm
when nm
= SN.Typehints.int -> Some
(N.Hprim
N.Tint
)
1061 | nm
when nm
= SN.Typehints.bool -> Some
(N.Hprim
N.Tbool
)
1062 | nm
when nm
= SN.Typehints.float -> Some
(N.Hprim
N.Tfloat
)
1063 | nm
when nm
= SN.Typehints.string -> Some
(N.Hprim
N.Tstring
)
1064 | nm
when nm
= SN.Typehints.array
->
1065 let tcopt = (fst
env).tcopt in
1066 let array_typehints_disallowed =
1067 TypecheckerOptions.disallow_array_typehint
tcopt in
1068 if array_typehints_disallowed
1069 then Errors.array_typehints_disallowed p;
1071 | [] -> N.Harray
(None
, None
)
1072 | [val_
] -> N.Harray
(Some
(aast_hint env val_
), None
)
1074 N.Harray
(Some
(aast_hint env key_
), Some
(aast_hint env val_
))
1075 | _ -> Errors.too_many_type_arguments
p; N.Hany
1077 | nm
when nm
= SN.Typehints.darray
->
1080 if (fst
env).in_mode
= FileInfo.Mstrict
then
1081 Errors.too_few_type_arguments
p;
1082 N.Hdarray
((p, N.Hany
), (p, N.Hany
))
1083 | [_] -> Errors.too_few_type_arguments
p; N.Hany
1084 | [key_
; val_
] -> N.Hdarray
(aast_hint env key_
, aast_hint env val_
)
1085 | _ -> Errors.too_many_type_arguments
p; N.Hany
)
1086 | nm
when nm
= SN.Typehints.varray
->
1089 if (fst
env).in_mode
= FileInfo.Mstrict
then
1090 Errors.too_few_type_arguments
p;
1091 N.Hvarray
(p, N.Hany
)
1092 | [val_
] -> N.Hvarray
(aast_hint env val_
)
1093 | _ -> Errors.too_many_type_arguments
p; N.Hany
)
1094 | nm
when nm
= SN.Typehints.varray_or_darray
->
1097 if (fst
env).in_mode
= FileInfo.Mstrict
then
1098 Errors.too_few_type_arguments
p;
1099 N.Hvarray_or_darray
(p, N.Hany
)
1100 | [val_
] -> N.Hvarray_or_darray
(aast_hint env val_
)
1101 | _ -> Errors.too_many_type_arguments
p; N.Hany
)
1102 | nm
when nm
= SN.Typehints.integer
->
1103 Errors.primitive_invalid_alias
p nm
SN.Typehints.int;
1104 Some
(N.Hprim
N.Tint
)
1105 | nm
when nm
= SN.Typehints.boolean
->
1106 Errors.primitive_invalid_alias
p nm
SN.Typehints.bool;
1107 Some
(N.Hprim
N.Tbool
)
1108 | nm
when nm
= SN.Typehints.double
|| nm
= SN.Typehints.real ->
1109 Errors.primitive_invalid_alias
p nm
SN.Typehints.float;
1110 Some
(N.Hprim
N.Tfloat
)
1113 let () = match opt_hint with
1114 | Some
_ when canon <> x
-> Errors.primitive_invalid_alias
p x
canon
1118 and aast_hintl ~forbid_this ~allow_retonly ~allow_typedef ~allow_wildcard ~tp_depth
env l
=
1120 ~f
:(aast_hint ~forbid_this ~allow_retonly ~allow_typedef ~allow_wildcard ~tp_depth
env)
1123 let aast_constraint_ ?
(forbid_this
=false) env (ck
, h) = ck
, aast_hint ~forbid_this
env h
1125 let aast_targ env t
=
1127 ~allow_wildcard
:true
1133 let aast_targl env _ tal
=
1134 List.map tal ~f
:(aast_targ env)
1137 (**************************************************************************)
1138 (* All the methods and static methods of an interface are "implicitly"
1139 * declared as abstract
1141 (**************************************************************************)
1143 let add_abstract m
= {m
with N.m_abstract
= true}
1145 let add_abstractl methods
= List.map methods
add_abstract
1147 let aast_interface c constructor methods smethods
=
1148 if c
.Aast.c_kind
<> Ast.Cinterface
1149 then constructor
, methods
, smethods
1151 let constructor = Option.map
constructor add_abstract in
1152 let methods = add_abstractl methods in
1153 let smethods = add_abstractl smethods in
1154 constructor, methods, smethods
1156 (**************************************************************************)
1157 (* Checking for collision on method names *)
1158 (**************************************************************************)
1160 let check_method acc
{ N.m_name
= (p, x
); _ } =
1162 then Errors.method_name_already_bound
p x
;
1165 let check_name_collision methods =
1166 ignore
(List.fold_left
methods ~init
:SSet.empty ~f
:check_method)
1168 (**************************************************************************)
1169 (* Checking for shadowing of method type parameters *)
1170 (**************************************************************************)
1172 let check_method_tparams class_tparam_names
{ N.m_tparams
= tparams
; _ } =
1173 List.iter tparams
begin fun { N.tp_name
= (p,x
); _ } ->
1174 List.iter class_tparam_names
1175 (fun (pc
,xc
) -> if (x
= xc
) then Errors.shadowed_type_param
p pc x
)
1178 let check_tparams_constructor class_tparam_names
constructor =
1179 match constructor with
1181 | Some constr
-> check_method_tparams class_tparam_names constr
1183 let check_tparams_shadow class_tparam_names
methods =
1184 List.iter
methods (check_method_tparams class_tparam_names
)
1186 let aast_ensure_name_not_dynamic env e err
=
1188 | (_, (Aast.Id
_ | Aast.Lvar
_)) -> ()
1190 if (fst
env).in_mode
= FileInfo.Mstrict
1193 (* Naming of a class *)
1195 let c = Ast_to_nast.on_class
c in
1198 (* Naming of a class *)
1200 let constraints = aast_make_constraints
c.Aast.c_tparams
.Aast.c_tparam_list
in
1201 let env = Env.aast_make_class_env constraints c in
1202 (* Checking for a code smell *)
1203 List.iter
c.Aast.c_tparams
.Aast.c_tparam_list
aast_check_constraint;
1204 let name = Env.type_name env c.Aast.c_name ~allow_typedef
:false ~allow_generics
:false in
1205 let smethods = List.map ~f
:(aast_method_
(fst
env)) c.Aast.c_static_methods
in
1206 let sprops = List.map ~f
:(aast_class_prop_static
env) c.Aast.c_static_vars
in
1207 let attrs = aast_user_attributes
env c.Aast.c_user_attributes
in
1208 let const = (Attributes.find
SN.UserAttributes.uaConst
attrs) in
1209 let props = List.map ~f
:(aast_class_prop_non_static ~
const env) c.Aast.c_vars
in
1210 let xhp_attrs = List.map ~f
:(aast_xhp_attribute_decl
env) c.Aast.c_xhp_attrs
in
1211 (* These would be out of order with the old attributes, but that shouldn't matter? *)
1212 let props = props @ xhp_attrs in
1214 List.map
c.Aast.c_extends
1215 (aast_hint ~allow_retonly
:false ~allow_typedef
:false env) in
1217 match c.Aast.c_kind
with
1218 (* Make enums implicitly extend the BuiltinEnum class in order to provide
1219 * utility methods. *)
1221 let pos = fst
name in
1222 let enum_type = pos, N.Happly
(name, []) in
1224 pos, N.Happly
((pos, Naming_special_names.Classes.cHH_BuiltinEnum
),
1228 let methods = List.map ~f
:(aast_class_method
env) c.Aast.c_methods
in
1229 let uses = List.map ~f
:(aast_hint ~allow_typedef
:false env) c.Aast.c_uses
in
1230 let redeclarations =
1231 List.map ~f
:(aast_method_redeclaration
env) c.Aast.c_method_redeclarations
in
1233 List.map ~f
:(aast_hint ~allow_typedef
:false env) c.Aast.c_xhp_attr_uses
in
1234 if c.Aast.c_req_implements
<> [] && c.Aast.c_kind
<> Ast.Ctrait
1235 then Errors.invalid_req_implements
(fst
(List.hd_exn
c.Aast.c_req_implements
));
1236 let req_implements =
1237 List.map ~f
:(aast_hint ~allow_typedef
:false env) c.Aast.c_req_implements
in
1238 if c.Aast.c_req_extends
<> [] &&
1239 c.Aast.c_kind
<> Ast.Ctrait
&&
1240 c.Aast.c_kind
<> Ast.Cinterface
1241 then Errors.invalid_req_extends
(fst
(List.hd_exn
c.Aast.c_req_extends
));
1243 List.map ~f
:(aast_hint ~allow_typedef
:false env) c.Aast.c_req_extends
in
1244 (* Setting a class type parameters constraint to the 'this' type is weird
1245 * so lets forbid it for now.
1247 let tparam_l = aast_type_paraml ~forbid_this
:true env c.Aast.c_tparams
.Aast.c_tparam_list
in
1248 let consts = List.map ~f
:(aast_class_const
env) c.Aast.c_consts
in
1249 let typeconsts = List.map ~f
:(aast_typeconst
env) c.Aast.c_typeconsts
in
1252 ~f
:(aast_hint ~allow_retonly
:false ~allow_typedef
:false env)
1253 c.Aast.c_implements
in
1254 let constructor = Option.map
c.Aast.c_constructor
(aast_method_
(fst
env)) in
1255 let constructor, methods, smethods =
1256 aast_interface c constructor methods smethods in
1257 let class_tparam_names =
1258 List.map ~f
:(fun tp
-> tp
.Aast.tp_name
) c.Aast.c_tparams
.Aast.c_tparam_list
in
1259 let enum = Option.map
c.Aast.c_enum
(aast_enum_
env) in
1260 let file_attributes =
1261 aast_file_attributes
c.Aast.c_mode
c.Aast.c_file_attributes
in
1263 { N.c_tparam_list
= tparam_l
1264 ; N.c_tparam_constraints
= constraints
1266 check_tparams_constructor class_tparam_names constructor;
1267 check_name_collision methods;
1268 check_tparams_shadow class_tparam_names methods;
1269 check_name_collision smethods;
1270 check_tparams_shadow class_tparam_names smethods;
1271 { N.c_annotation
= ();
1272 N.c_span
= c.Aast.c_span
;
1273 N.c_mode
= c.Aast.c_mode
;
1274 N.c_final
= c.Aast.c_final
;
1275 N.c_is_xhp
= c.Aast.c_is_xhp
;
1276 N.c_kind
= c.Aast.c_kind
;
1278 N.c_tparams = c_tparams;
1279 N.c_extends
= parents;
1281 N.c_method_redeclarations
= redeclarations;
1282 N.c_xhp_attr_uses
= xhp_attr_uses;
1283 N.c_xhp_category
= c.Aast.c_xhp_category
;
1284 N.c_req_extends
= req_extends;
1285 N.c_req_implements
= req_implements;
1286 N.c_implements
= implements;
1287 N.c_consts
= consts;
1288 N.c_typeconsts
= typeconsts;
1289 N.c_static_vars
= sprops;
1291 N.c_constructor
= constructor;
1292 N.c_static_methods
= smethods;
1293 N.c_methods
= methods;
1294 N.c_user_attributes
= attrs;
1295 N.c_file_attributes
= file_attributes;
1296 N.c_namespace
= c.Aast.c_namespace
;
1298 N.c_doc_comment
= c.Aast.c_doc_comment
;
1299 (* Naming and typechecking shouldn't use these fields *)
1300 N.c_attributes
= [];
1301 N.c_xhp_children
= [];
1305 and aast_user_attributes
env attrl
=
1306 let seen = Caml.Hashtbl.create
0 in
1307 let validate_seen ua_name
=
1308 let pos, name = ua_name
in
1309 let existing_attr_pos =
1310 try Some
(Caml.Hashtbl.find
seen name)
1311 with Caml.Not_found
-> None
in
1312 match existing_attr_pos with
1313 | Some
p -> Errors.duplicate_user_attribute ua_name
p; false
1314 | None
-> Caml.Hashtbl.add
seen name pos; true in
1315 let on_attr acc
{ Aast.ua_name
; ua_params
} =
1316 let name = snd ua_name
in
1318 if String.is_prefix
name ~prefix
:"__"
1320 else Env.type_name env ua_name ~allow_typedef
:false ~allow_generics
:false in
1321 if not
(validate_seen ua_name)
1325 { N.ua_name = ua_name
1326 ; N.ua_params
= List.map ~f
:(aast_expr
env) ua_params
1329 List.fold_left ~init
:[] ~f
:on_attr attrl
1331 and aast_file_attributes mode fal
=
1332 List.map ~f
:(aast_file_attribute mode
) fal
1333 and aast_file_attribute mode fa
=
1334 let env = Env.make_file_attributes_env mode fa
.Aast.fa_namespace
in
1335 let ua = aast_user_attributes
env fa
.Aast.fa_user_attributes
in
1337 { fa_user_attributes
= ua
1338 ; fa_namespace
= fa
.Aast.fa_namespace
1341 (* h cv is_required maybe_enum *)
1342 and aast_xhp_attribute_decl
env (h, cv
, is_required
, maybe_enum
) =
1343 let p, id = cv
.Aast.cv_id
in
1344 let default = cv
.Aast.cv_expr
in
1345 if is_required
&& Option.is_some
default
1346 then Errors.xhp_required_with_default
p id;
1348 match maybe_enum
with
1349 | Some
(pos, _optional
, items
) ->
1352 | _, Aast.Int
_ -> true
1354 let contains_int = List.exists ~f
:is_int items
in
1355 let is_string item
=
1358 | _, Aast.String2
_ -> true
1360 let contains_str = List.exists ~f
:is_string items
in
1361 if contains_int && not
contains_str
1362 then Some
(pos, Aast.Happly
((pos, "int"), []))
1363 else if not
contains_int && contains_str
1364 then Some
(pos, Aast.Happly
((pos, "string"), []))
1365 else Some
(pos, Aast.Happly
((pos, "mixed"), []))
1369 | Some
(p, Aast.Hoption
_) ->
1371 then Errors.xhp_optional_required_attr
p id;
1373 | Some
(_, (Aast.Happly
((_, "mixed"), []))) -> hint
1378 | Some
(_, Aast.Null
) -> false
1380 if is_required
|| has_default
1382 else Some
(p, Aast.Hoption
(p, h))
1384 let hint = Option.map
hint (aast_hint env) in
1385 let expr, is_xhp
= aast_class_prop_expr_is_xhp
env cv
in
1386 { N.cv_final
= cv
.Aast.cv_final
1387 ; N.cv_is_xhp
= is_xhp
1388 ; N.cv_visibility
= cv
.Aast.cv_visibility
1390 ; N.cv_id
= cv
.Aast.cv_id
1392 ; N.cv_user_attributes
= []
1395 and aast_enum_
env e
=
1396 { N.e_base
= aast_hint env e
.Aast.e_base
1397 ; N.e_constraint
= Option.map e
.Aast.e_constraint
(aast_hint env)
1400 and aast_type_paraml ?
(forbid_this
= false) env tparams
=
1401 let _, ret
= List.fold_left tparams ~init
:(SMap.empty
, [])
1402 ~f
:(fun (seen, tparaml
) tparam
->
1403 let (p, name) = tparam
.Aast.tp_name
in
1404 match SMap.get
name seen with
1406 SMap.add
name p seen, (aast_type_param ~forbid_this
env tparam
) :: tparaml
1408 Errors.shadowed_type_param
p pos name;
1414 and aast_type_param ~forbid_this
env t
=
1415 let (genv, _) = env in
1416 if t
.Aast.tp_reified
&& not
(TypecheckerOptions.experimental_feature_enabled
1418 TypecheckerOptions.experimental_reified_generics
)
1420 Errors.experimental_feature
(fst t
.Aast.tp_name
) "reified generics";
1423 if (TypecheckerOptions.experimental_feature_enabled
1425 TypecheckerOptions.experimental_type_param_shadowing
)
1427 (* Treat type params as inline class declarations that don't go into the naming heap *)
1428 let (pos, name) = NS.elaborate_id
genv.namespace
NS.ElaborateClass t
.Aast.tp_name
in
1429 match Naming_heap.TypeIdHeap.get
name with
1430 | Some
(def_pos
, _) ->
1431 let def_pos, _ = GEnv.get_full_pos
(def_pos, name) in
1432 Errors.error_name_already_bound
name name pos def_pos
1434 match GEnv.type_canon_name
name with
1436 let def_pos = Option.value ~
default:Pos.none
(GEnv.type_pos canonical
) in
1437 Errors.error_name_already_bound
name canonical
pos def_pos
1442 N.tp_variance
= t
.Aast.tp_variance
;
1443 tp_name
= t
.Aast.tp_name
;
1444 tp_constraints
= List.map t
.Aast.tp_constraints
(aast_constraint_ ~forbid_this
env);
1445 tp_reified
= t
.Aast.tp_reified
;
1446 tp_user_attributes
= aast_user_attributes
env t
.Aast.tp_user_attributes
;
1449 and aast_type_where_constraints
env locl_cstrl
=
1451 ~f
:(fun (h1
, ck
, h2
) ->
1452 let ty1 = aast_hint ~in_where_clause
:true env h1
in
1453 let ty2 = aast_hint ~in_where_clause
:true env h2
in
1457 and aast_class_prop_expr_is_xhp
env cv
=
1458 let expr = Option.map cv
.Aast.cv_expr
(aast_expr
env) in
1460 if (fst
env).in_mode
= FileInfo.Mdecl
&& expr = None
1461 then Some
(fst cv
.Aast.cv_id
, N.Any
)
1464 try ((String.sub
(snd cv
.Aast.cv_id
) 0 1) = ":")
1465 with Invalid_argument
_ -> false in
1468 and aast_class_prop_static
env cv
=
1469 let attrs = aast_user_attributes
env cv
.Aast.cv_user_attributes
in
1470 let lsb = Attributes.mem
SN.UserAttributes.uaLSB
attrs in
1471 let forbid_this = not
lsb in
1472 let h = Option.map cv
.Aast.cv_type
(aast_hint ~
forbid_this env) in
1473 let expr, is_xhp = aast_class_prop_expr_is_xhp
env cv
in
1474 { N.cv_final
= cv
.Aast.cv_final
1475 ; N.cv_is_xhp
= is_xhp
1476 ; N.cv_visibility
= cv
.Aast.cv_visibility
1478 ; N.cv_id
= cv
.Aast.cv_id
1480 ; N.cv_user_attributes
= attrs
1483 and aast_class_prop_non_static
env ?
(const = None
) cv
=
1484 let h = Option.map cv
.Aast.cv_type
(aast_hint env) in
1485 let attrs = aast_user_attributes
env cv
.Aast.cv_user_attributes
in
1486 let lsb_pos = Attributes.mem_pos
SN.UserAttributes.uaLSB
attrs in
1487 (* Non-static properties cannot have attribute __LSB *)
1490 | Some
p -> Errors.nonstatic_property_with_lsb
p
1492 (* if class is __Const, make all member fields __Const *)
1496 if not
(Attributes.mem
SN.UserAttributes.uaConst
attrs)
1500 let expr, is_xhp = aast_class_prop_expr_is_xhp
env cv
in
1501 { N.cv_final
= cv
.Aast.cv_final
1502 ; N.cv_is_xhp
= is_xhp
1503 ; N.cv_visibility
= cv
.Aast.cv_visibility
1505 ; N.cv_id
= cv
.Aast.cv_id
1507 ; N.cv_user_attributes
= attrs
1510 and aast_class_method
env c_meth
=
1511 match c_meth
.Aast.m_name
, c_meth
.Aast.m_params
with
1512 | ((m_pos
, m_name
), _ :: _) when m_name
= SN.Members.__clone
->
1513 Errors.clone_too_many_arguments m_pos
; c_meth
1514 | _ -> aast_method_
(fst
env) c_meth
1516 and aast_check_constant_expr
env (pos, e
) =
1518 | Aast.Unsafe_expr
_
1525 | Aast.String
_ -> ()
1526 | Aast.Class_const
((_, Aast.CIexpr
(_, cls
)), _)
1527 when (match cls
with Aast.Id
(_, "static") -> false | _ -> true) -> ()
1528 | Aast.Unop
((Ast.Uplus
| Ast.Uminus
| Ast.Utild
| Ast.Unot
), e
) ->
1529 aast_check_constant_expr
env e
1530 | Aast.Binop
(op
, e1
, e2) ->
1531 (* Only assignment is invalid *)
1534 | Ast.Eq
_ -> Errors.illegal_constant
pos
1536 aast_check_constant_expr
env e1
;
1537 aast_check_constant_expr
env e2
1539 | Aast.Eif
(e1
, e2, e3
) ->
1540 aast_check_constant_expr
env e1
;
1541 Option.iter
e2 (aast_check_constant_expr
env);
1542 aast_check_constant_expr
env e3
1543 | Aast.Array l
-> List.iter l ~f
:(aast_check_afield_constant_expr
env)
1544 | Aast.Darray
(_, l
) ->
1545 List.iter l ~f
:(fun (e1
, e2) ->
1546 aast_check_constant_expr
env e1
;
1547 aast_check_constant_expr
env e2)
1548 | Aast.Varray
(_, l
) -> List.iter l ~f
:(aast_check_constant_expr
env)
1550 (* Only check the values because shape field names are always legal *)
1551 List.iter fdl ~f
:(fun (_, e
) -> aast_check_constant_expr
env e
)
1552 | Aast.Call
(_, (_, Aast.Id
(_, cn
)), _, el
, uel
)
1553 when cn
= SN.SpecialFunctions.tuple
->
1554 (* Tuples are not really function calls, they are just parsed that way*)
1555 arg_unpack_unexpected uel
;
1556 List.iter el ~f
:(aast_check_constant_expr
env)
1557 | Aast.Collection
(id, _, l
) ->
1558 let p, cn
= NS.elaborate_id
((fst
env).namespace
) NS.ElaborateClass
id in
1559 (* Only vec/keyset/dict are allowed because they are value types *)
1560 if cn
= SN.Collections.cVec
1561 || cn
= SN.Collections.cKeyset
1562 || cn
= SN.Collections.cDict
1563 then List.iter l ~f
:(aast_check_afield_constant_expr
env)
1564 else Errors.illegal_constant
p
1565 | _ -> Errors.illegal_constant
pos
1567 and aast_check_afield_constant_expr
env afield
=
1569 | Aast.AFvalue e
-> aast_check_constant_expr
env e
1570 | Aast.AFkvalue
(e1
, e2) ->
1571 aast_check_constant_expr
env e1
;
1572 aast_check_constant_expr
env e2
1574 and aast_constant_expr
env e
=
1575 let valid_constant_expression =
1576 Errors.try_with_error
1577 (fun () -> aast_check_constant_expr
env e
; true)
1578 (fun () -> false) in
1579 if valid_constant_expression
1580 then aast_expr
env e
1583 and aast_class_const
env (h, x
, eo
) =
1584 Env.bind_class_const env x
;
1585 let h = Option.map
h (aast_hint env) in
1586 let eo = Option.map
eo (aast_constant_expr
env) in
1589 and aast_typeconst
env t
=
1590 (* We use the same namespace as constants within the class so we cannot have
1591 * a const and type const with the same name
1593 Env.bind_class_const env t
.Aast.c_tconst_name
;
1594 let constr = Option.map t
.Aast.c_tconst_constraint
(aast_hint env) in
1595 let type_ = Option.map t
.Aast.c_tconst_type
(aast_hint env) in
1596 let attrs = aast_user_attributes
env t
.Aast.c_tconst_user_attributes
in
1597 if not
(TypecheckerOptions.experimental_feature_enabled
(fst
env).tcopt
1598 TypecheckerOptions.experimental_type_const_attributes
|| List.is_empty
attrs)
1599 then Errors.experimental_feature
(fst t
.Aast.c_tconst_name
) "type constant attributes";
1601 { c_tconst_name
= t
.Aast.c_tconst_name
1602 ; c_tconst_constraint
= constr
1603 ; c_tconst_type
= type_
1604 ; c_tconst_user_attributes
= attrs
1607 and func_body_had_unsafe
env = Env.has_unsafe env
1609 and aast_method_
genv m
=
1610 let genv = aast_extend_params
genv m
.Aast.m_tparams
in
1611 let env = genv, Env.empty_local None
in
1612 (* Cannot use 'this' if it is a public instance method *)
1613 let variadicity, paraml
= aast_fun_paraml
env m
.Aast.m_params
in
1614 let tparam_l = aast_type_paraml
env m
.Aast.m_tparams
in
1615 List.iter
tparam_l aast_check_constraint;
1616 let where_constraints = aast_type_where_constraints
env m
.Aast.m_where_constraints
in
1617 let ret = Option.map m
.Aast.m_ret
(aast_hint ~allow_retonly
:true env) in
1619 match genv.in_mode
with
1620 | FileInfo.Mdecl
| FileInfo.Mphp
->
1622 fb_annotation
= N.BodyNamingAnnotation.NamedWithUnsafeBlocks
;
1624 | FileInfo.Mstrict
| FileInfo.Mpartial
| FileInfo.Mexperimental
->
1625 if Aast.is_body_named m
.Aast.m_body
1627 { N.fb_ast
= m
.Aast.m_body
.Aast.fb_ast
;
1628 fb_annotation
= N.BodyNamingAnnotation.Unnamed
genv.namespace
;
1630 else failwith
"ast_to_nast error unnamedbody in method_"
1632 let attrs = aast_user_attributes
env m
.Aast.m_user_attributes
in
1633 { N.m_annotation
= ();
1634 N.m_span
= m
.Aast.m_span
;
1635 N.m_final
= m
.Aast.m_final
;
1636 N.m_visibility
= m
.Aast.m_visibility
;
1637 N.m_abstract
= m
.Aast.m_abstract
;
1638 N.m_static
= m
.Aast.m_static
;
1639 N.m_name
= m
.Aast.m_name
;
1640 N.m_tparams
= tparam_l;
1641 N.m_where_constraints
= where_constraints;
1642 N.m_params
= paraml
;
1644 N.m_fun_kind
= m
.Aast.m_fun_kind
;
1646 N.m_variadic
= variadicity;
1647 N.m_user_attributes
= attrs;
1648 N.m_external
= m
.Aast.m_external
;
1649 N.m_doc_comment
= m
.Aast.m_doc_comment
;
1652 and aast_method_redeclaration
env mt
=
1654 (TypecheckerOptions.experimental_feature_enabled
1656 TypecheckerOptions.experimental_trait_method_redeclarations
)
1657 then Errors.experimental_feature
(fst mt
.Aast.mt_name
) "trait method redeclarations";
1658 let genv = aast_extend_params
(fst
env) mt
.Aast.mt_tparams
in
1659 let env = genv, Env.empty_local None
in
1660 let variadicity, paraml
= aast_fun_paraml
env mt
.Aast.mt_params
in
1661 let tparam_l = aast_type_paraml
env mt
.Aast.mt_tparams
in
1662 let where_constraints = aast_type_where_constraints
env mt
.Aast.mt_where_constraints
in
1663 let ret = Option.map mt
.Aast.mt_ret
(aast_hint ~allow_retonly
:true env) in
1664 { N.mt_final
= mt
.Aast.mt_final
1665 ; N.mt_visibility
= mt
.Aast.mt_visibility
1666 ; N.mt_abstract
= mt
.Aast.mt_abstract
1667 ; N.mt_static
= mt
.Aast.mt_static
1668 ; N.mt_name
= mt
.Aast.mt_name
1669 ; N.mt_tparams
= tparam_l
1670 ; N.mt_where_constraints
= where_constraints
1671 ; N.mt_params
= paraml
1672 ; N.mt_fun_kind
= mt
.Aast.mt_fun_kind
1674 ; N.mt_variadic
= variadicity
1675 ; N.mt_trait
= aast_hint ~allow_typedef
:false env mt
.Aast.mt_trait
1676 ; N.mt_method
= mt
.Aast.mt_method
1677 ; N.mt_user_attributes
= []
1680 and aast_fun_paraml
env paraml
=
1681 let _ = List.fold_left ~f
:aast_check_repetition ~init
:SSet.empty paraml
in
1682 let variadicity, paraml
= aast_determine_variadicity
env paraml
in
1683 variadicity, List.map ~f
:(aast_fun_param
env) paraml
1685 (* Variadic params are removed from the list *)
1686 and aast_determine_variadicity
env paraml
=
1688 | [] -> N.FVnonVariadic
, []
1691 match x
.Aast.param_is_variadic
, x
.Aast.param_name
with
1692 | false, _ -> N.FVnonVariadic
, paraml
1693 | true, "..." -> N.FVellipsis x
.Aast.param_pos
, []
1694 | true, _ -> N.FVvariadicArg
(aast_fun_param
env x
), []
1697 let variadicity, rl
= aast_determine_variadicity
env rl
in
1698 variadicity, x
:: rl
1700 and aast_fun_param
env (param
: Aast.fun_param
) =
1701 let p = param
.Aast.param_pos
in
1702 let name = param
.Aast.param_name
in
1703 let ident = Local_id.get
name in
1704 Env.add_lvar env (p, name) (p, ident);
1705 let ty = Option.map param
.Aast.param_hint
(aast_hint env) in
1706 let eopt = Option.map param
.Aast.param_expr
(aast_expr
env) in
1707 if param
.Aast.param_is_reference
&& (fst
env).in_mode
= FileInfo.Mstrict
1708 then Errors.reference_in_strict_mode
p;
1709 { N.param_annotation
= p;
1711 param_is_reference
= param
.Aast.param_is_reference
;
1712 param_is_variadic
= param
.Aast.param_is_variadic
;
1716 param_callconv
= param
.Aast.param_callconv
;
1717 param_user_attributes
= aast_user_attributes
env param
.Aast.param_user_attributes
;
1720 and aast_make_constraints paraml
=
1723 ~f
:(fun { Aast.tp_name
= (_, x
); tp_constraints
; tp_reified
; _ } acc
->
1724 SMap.add x
(tp_reified
, tp_constraints
) acc
)
1727 and aast_extend_params
genv paraml
=
1728 let params = List.fold_right paraml ~init
:genv.type_params
1729 ~f
:begin fun { Aast.tp_name
= (_, x
); tp_constraints
= cstr_list
; tp_reified
= r
; _ } acc
->
1730 SMap.add x
(r
, cstr_list
) acc
1732 { genv with type_params
= params }
1735 let f = Ast_to_nast.on_fun
f in
1739 let tparams = aast_make_constraints
f.Aast.f_tparams
in
1740 let genv = Env.aast_make_fun_decl_genv tparams f in
1741 let lenv = Env.empty_local None
in
1742 let env = genv, lenv in
1743 let where_constraints = aast_type_where_constraints
env f.Aast.f_where_constraints
in
1744 let h = Option.map
f.Aast.f_ret
(aast_hint ~allow_retonly
:true env) in
1745 let variadicity, paraml
= aast_fun_paraml
env f.Aast.f_params
in
1746 let x = Env.fun_id env f.Aast.f_name
in
1747 List.iter
f.Aast.f_tparams
aast_check_constraint;
1748 let f_tparams = aast_type_paraml
env f.Aast.f_tparams in
1749 let f_kind = f.Aast.f_fun_kind
in
1751 match genv.in_mode
with
1752 | FileInfo.Mdecl
| FileInfo.Mphp
->
1754 fb_annotation
= N.BodyNamingAnnotation.NamedWithUnsafeBlocks
;
1756 | FileInfo.Mstrict
| FileInfo.Mpartial
| FileInfo.Mexperimental
->
1757 if Aast.is_body_named
f.Aast.f_body
1759 { N.fb_ast
= f.Aast.f_body
.Aast.fb_ast
;
1760 fb_annotation
= N.BodyNamingAnnotation.Unnamed
genv.namespace
;
1762 else failwith
"ast_to_nast error unnamedbody in fun_"
1765 N.f_annotation
= ();
1766 f_span
= f.Aast.f_span
;
1767 f_mode
= f.Aast.f_mode
;
1770 f_tparams = f_tparams;
1771 f_where_constraints
= where_constraints;
1774 f_fun_kind
= f_kind;
1775 f_variadic
= variadicity;
1776 f_user_attributes
= aast_user_attributes
env f.Aast.f_user_attributes
;
1777 (* Fix file attributes if they are important *)
1778 f_file_attributes
= [];
1779 f_external
= f.Aast.f_external
;
1780 f_namespace
= f.Aast.f_namespace
;
1781 f_doc_comment
= f.Aast.f_doc_comment
;
1782 f_static
= f.Aast.f_static
;
1786 and aast_get_using_vars
(_, e
) =
1788 | Aast.Expr_list using_clauses
->
1789 List.concat_map using_clauses aast_get_using_vars
1790 (* Simple assignment to local of form `$lvar = e` *)
1791 | Aast.Binop
(Ast.Eq None
, (_, Aast.Lvar
(p, lid
)), _) ->
1792 [ (p, Local_id.get_name lid
) ]
1793 (* Arbitrary expression. This will be assigned to a temporary *)
1796 and aast_stmt
env st
=
1798 | Aast.Let
(x, h, e
) -> aast_let_stmt
env x h e
1799 | Aast.Block
_ -> failwith
"aast_stmt block error"
1800 | Aast.Unsafe_block
_ -> failwith
"aast_stmt unsafe_block error"
1801 | Aast.Fallthrough
-> N.Fallthrough
1802 | Aast.Noop
-> N.Noop
1803 | Aast.Markup
(_, None
) -> N.Noop
1804 | Aast.Markup
(_m
, Some e
) -> N.Expr
(aast_expr
env e
)
1805 | Aast.Break
p -> Aast.Break
p
1806 | Aast.Continue
p -> Aast.Continue
p
1807 | Aast.Throw
(_, e
) ->
1808 let terminal = not
(fst
env).in_try
in
1809 N.Throw
(terminal, aast_expr
env e
)
1810 | Aast.Return
(p, e
) -> N.Return
(p, Option.map e
(aast_expr
env))
1811 | Aast.GotoLabel label
-> name_goto_label
env label
1812 | Aast.Goto label
-> name_goto
env label
1813 | Aast.Static_var el
-> N.Static_var
(aast_static_varl
env el
)
1814 | Aast.Global_var el
-> N.Global_var
(aast_global_varl
env el
)
1815 | Aast.Awaitall
(p, el
) -> aast_awaitall_stmt
env p el
1816 | Aast.If
(e
, b1
, b2
) -> aast_if_stmt
env st e b1 b2
1817 | Aast.Do
(b
, e
) -> aast_do_stmt
env b e
1818 | Aast.While
(e
, b
) ->
1819 N.While
(aast_expr
env e
, aast_block
env b
)
1820 | Aast.Declare
(_, (p, _), _) ->
1821 Errors.declare_statement_in_hack
p;
1823 | Aast.Using s
-> aast_using_stmt
env s
.Aast.us_has_await s
.Aast.us_expr s
.Aast.us_block
1824 | Aast.For
(st1
, e
, st2
, b
) -> aast_for_stmt
env st1 e st2 b
1825 | Aast.Switch
(e
, cl
) -> aast_switch_stmt
env st e cl
1826 | Aast.Foreach
(e
, ae
, b
) -> aast_foreach_stmt
env e ae b
1827 | Aast.Try
(b
, cl
, fb
) -> aast_try_stmt
env st b cl fb
1828 | Aast.Def_inline
_ -> (* No convenient pos information on Aast *)
1829 Errors.experimental_feature
Pos.none
"inlined definitions"; N.Expr
(Pos.none
, N.Any
)
1830 | Aast.Expr
(cp
, Aast.Call
(_, (p, Aast.Id
(fp
, fn
)), hl
, el
, uel
))
1831 when fn
= SN.SpecialFunctions.invariant
->
1832 (* invariant is subject to a source-code transform in the HHVM
1833 * runtime: the arguments to invariant are lazily evaluated only in
1834 * the case in which the invariant condition does not hold. So:
1836 * invariant_violation(<condition>, <format>, <format_args...>)
1838 * ... is rewritten as:
1840 * if (!<condition>) {
1841 * invariant_violation(<format>, <format_args...>);
1847 Errors.naming_too_few_arguments
p;
1849 | (cond_p
, cond
) :: el
->
1850 let violation = (cp
, Aast.Call
(Aast.Cnormal
, (p, Aast.Id
1851 (fp
, "\\"^
SN.SpecialFunctions.invariant_violation
)), hl
, el
, uel
)) in
1852 if cond
<> Aast.False
1854 let b1, b2
= [Aast.Expr
violation], [Aast.Noop
] in
1855 let cond = (cond_p
, Aast.Unop
(Ast.Unot
, (cond_p
, cond))) in
1856 aast_if_stmt
env st
cond b1 b2
1857 else (* a false <condition> means unconditional invariant_violation *)
1858 N.Expr
(aast_expr
env violation)
1860 | Aast.Expr e
-> N.Expr
(aast_expr
env e
)
1862 and aast_let_stmt
env (p, lid
) h e
=
1863 let name = Local_id.get_name lid
in
1864 let e = aast_expr
env e in
1865 let h = Option.map
h (aast_hint env) in
1866 let x = Env.new_let_local env (p, name) in
1869 and aast_if_stmt
env st
e b1 b2
=
1870 let e = aast_expr
env e in
1871 let nsenv = (fst
env).namespace
in
1872 let _, vars
= GetLocals.aast_stmt
(nsenv, SMap.empty
) st
in
1873 SMap.iter
(fun x p -> Env.new_pending_lvar env (p, x)) vars
;
1874 let result = Env.scope env
1876 let all1, b1 = aast_branch
env b1 in
1877 let all2, b2
= aast_branch
env b2
in
1878 Env.extend_all_locals env all2;
1879 Env.extend_all_locals env all1;
1882 SMap.iter
(fun x _ -> Env.promote_pending_lvar env x) vars
;
1885 and aast_do_stmt
env b
e =
1886 (* lexical block of `do` is extended to the expr of loop termination *)
1890 let b = aast_block ~new_scope
:false env b in
1891 let e = aast_expr
env e in
1894 (* Scoping is essentially that of do: block is always executed *)
1895 and aast_using_stmt
env has_await
e b =
1896 let vars = aast_get_using_vars
e in
1897 let e = aast_expr
env e in
1898 let b = aast_block ~new_scope
:false env b in
1899 Env.remove_locals env vars;
1901 us_is_block_scoped
= false; (* This isn't used for naming so provide a default *)
1902 us_has_await
= has_await
;
1907 and aast_for_stmt
env e1
e2 e3
b =
1908 (* The initialization and condition expression should be in the outer scope,
1909 * as they are always executed. *)
1910 let e1 = aast_expr
env e1 in
1911 let e2 = aast_expr
env e2 in
1915 (* The third expression (iteration step) should have the same scope as the
1916 * block, as it is not always executed. *)
1917 let b = aast_block ~new_scope
:false env b in
1918 let e3 = aast_expr
env e3 in
1919 N.For
(e1, e2, e3, b))
1921 and aast_switch_stmt
env st
e cl
=
1922 let e = aast_expr
env e in
1923 let nsenv = (fst
env).namespace
in
1924 let _, vars = GetLocals.aast_stmt
(nsenv, SMap.empty
) st
in
1925 SMap.iter
(fun x p -> Env.new_pending_lvar env (p, x)) vars;
1926 let result = Env.scope env begin fun env ->
1927 let all_locals_l, cl
= aast_casel
env cl
in
1928 List.iter
all_locals_l (Env.extend_all_locals env);
1931 SMap.iter
(fun x _ -> Env.promote_pending_lvar env x) vars;
1934 and aast_foreach_stmt
env e ae
b =
1935 let e = aast_expr
env e in
1939 let ae = aast_as_expr
env ae in
1940 let b = aast_block
env b in
1941 N.Foreach
(e, ae, b))
1943 and aast_as_expr
env ae =
1946 | p, Aast.Id
x when (fst
env).in_mode
= FileInfo.Mexperimental
->
1947 let x = Env.new_let_local env x in
1948 let ev = (p, N.ImmutableVar
x) in
1951 Errors.expected_variable
p;
1952 p, N.Lvar
(Env.new_lvar env (p, "__internal_placeholder"))
1954 let nsenv = (fst
env).namespace
in
1956 GetLocals.aast_lvalue
(nsenv, SMap.empty
) ev in
1957 SMap.iter
(fun x p -> ignore
(Env.new_lvar env (p, x))) vars;
1961 | _, Aast.Lvar
(p, lid
) ->
1962 let x = (p, Local_id.get_name lid
) in
1963 p, N.Lvar
(Env.new_lvar env x)
1964 | p, Aast.Id
x when (fst
env).in_mode
= FileInfo.Mexperimental
->
1965 p, N.ImmutableVar
(Env.new_let_local env x)
1967 Errors.expected_variable
p;
1968 p, N.Lvar
(Env.new_lvar env (p, "__internal_placeholder")) in
1971 let ev = handle_v ev in
1973 | Aast.As_kv
(k
, ev) ->
1974 let k = handle_k k in
1975 let ev = handle_v ev in
1977 | N.Await_as_v
(p, ev) ->
1978 let ev = handle_v ev in
1979 N.Await_as_v
(p, ev)
1980 | N.Await_as_kv
(p, k, ev) ->
1981 let k = handle_k k in
1982 let ev = handle_v ev in
1983 N.Await_as_kv
(p, k, ev)
1985 and aast_try_stmt
env st
b cl fb
=
1986 let nsenv = (fst
env).namespace
in
1988 GetLocals.aast_stmt
(nsenv, SMap.empty
) st
in
1989 SMap.iter
(fun x p -> Env.new_pending_lvar env (p, x)) vars;
1990 let result = Env.scope
1993 let genv, lenv = env in
1994 (* isolate finally from the rest of the try-catch: if the first
1995 * statement of the try is an uncaught exception, finally will
1996 * still be executed *)
1997 let all_finally, fb
= aast_branch
({genv with in_finally
= true}, lenv) fb
in
1998 Env.extend_all_locals env all_finally;
1999 let all_locals_b, b = aast_branch
({genv with in_try
= true}, lenv) b in
2000 let all_locals_cl, cl
= aast_catchl
env cl
in
2001 List.iter
all_locals_cl (Env.extend_all_locals env);
2002 Env.extend_all_locals env all_locals_b;
2003 N.Try
(b, cl
, fb
)) in
2004 SMap.iter
(fun x _ -> Env.promote_pending_lvar env x) vars;
2007 and aast_stmt_list ?after_unsafe stl
env =
2008 let aast_stmt_list = aast_stmt_list ?after_unsafe
in
2011 | Aast.Unsafe_block
b :: _ ->
2012 Env.set_unsafe env true;
2013 let st = Errors.ignore_
(fun () -> N.Unsafe_block
(aast_stmt_list b env)) in
2014 st :: Option.to_list after_unsafe
2015 | Aast.Block
b :: rest
->
2016 (* Add lexical scope for block scoped let variables *)
2017 let b = Env.scope_lexical env (aast_stmt_list b) in
2018 let rest = aast_stmt_list rest env in
2021 let x = aast_stmt
env x in
2022 let rest = aast_stmt_list rest env in
2025 and aast_block ?
(new_scope
=true) env stl
=
2027 then Env.scope env (aast_stmt_list stl
)
2028 else aast_stmt_list stl
env
2030 and aast_branch ?after_unsafe
env stmt_l
=
2031 Env.scope_all env (aast_stmt_list ?after_unsafe stmt_l
)
2034 * Names a goto label.
2036 * The goto label is added to the local labels if it is not already there.
2037 * Otherwise, an error is produced.
2039 * An error is produced if this is called within a finally block.
2042 ({ in_finally
; _ }, _ as env) (label_pos
, label_name
as label
) =
2043 (match Env.goto_label env label_name
with
2044 | Some original_declaration_pos
->
2045 Errors.goto_label_already_defined
2048 original_declaration_pos
2049 | None
-> Env.new_goto_label env label
);
2051 Errors.goto_label_defined_in_finally label_pos
;
2055 * Names a goto target.
2057 * The goto statement's target label is added to the local goto targets.
2059 * An error is produced if this is called within a finally block.
2062 ({ in_finally
; _ }, _ as env) (label_pos
, _ as label
) =
2063 Env.new_goto_target env label
;
2064 if in_finally
then Errors.goto_invoked_in_finally label_pos
;
2067 and aast_static_varl
env l
= List.map l
(aast_static_var
env)
2068 and aast_static_var
env = function
2069 | p, Aast.Lvar
_ as lv
->
2070 aast_expr
env (p, Aast.Binop
(Ast.Eq None
, lv
, (p, Aast.Null
)))
2071 | e -> aast_expr
env e
2073 and aast_global_varl
env l
= aast_static_varl
env l
2075 and aast_awaitall_stmt
env pos el
=
2079 let e2 = aast_expr
env e2 in
2082 | Some
(_, Aast.Lvar
e) ->
2083 let e = Pos.none
, Aast.Lvar
e in
2084 let nsenv = (fst
env).namespace
in
2086 GetLocals.aast_lvalue
(nsenv, SMap.empty
) e in
2087 SMap.iter
(fun x p -> ignore
(Env.new_lvar env (p, x))) vars;
2088 Some
(aast_expr
env e)
2089 | Some
_ -> failwith
"ast_to_nast error in awaitall lvar"
2093 N.Awaitall
(pos, el)
2095 and aast_expr_obj_get_name
env expr =
2097 | p, Aast.Id
x -> p, N.Id
x
2098 | p, e -> aast_expr
env (p, e)
2100 and aast_exprl
env l
= List.map ~
f:(aast_expr
env) l
2102 and aast_oexpr
env e = Option.map
e (aast_expr
env)
2104 and aast_expr
env (p, e) = p, aast_expr_
env p e
2106 and aast_expr_
env p (e : Aast.expr_
) =
2108 | Aast.ParenthesizedExpr
(p, e) -> aast_expr_
env p e
2110 let tcopt = (fst
env).tcopt in
2111 if TypecheckerOptions.disallow_array_literal
tcopt
2112 then Errors.array_literals_disallowed
p;
2113 N.Array
(List.map l
(aast_afield
env))
2114 | Aast.Varray
(ta
, l
) ->
2115 N.Varray
(Option.map ~
f:(aast_targ env) ta
, List.map l
(aast_expr
env))
2116 | Aast.Darray
(tap
, l
) ->
2117 let nargs = Option.map ~
f:(fun (t1
, t2
) -> aast_targ env t1
, aast_targ env t2
) tap
in
2120 List.map l
(fun (e1, e2) -> aast_expr
env e1, aast_expr
env e2))
2121 | Aast.Collection
(id, tal
, l
) ->
2122 let p, cn
= NS.elaborate_id
((fst
env).namespace
) NS.ElaborateClass
id in
2125 | x when N.is_vc_kind
x ->
2126 let ta = begin match tal
with
2127 | Some
Aast.CollectionTV tv
-> Some
(aast_targ env tv
)
2128 | Some
Aast.CollectionTKV
_ -> Errors.naming_too_many_arguments
p; None
2131 N.ValCollection
((N.get_vc_kind cn
), ta, (List.map l
(aast_afield_value
env cn
)))
2132 | x when N.is_kvc_kind
x ->
2133 let ta = begin match tal
with
2134 | Some
Aast.CollectionTV
_ -> Errors.naming_too_few_arguments
p; None
2135 | Some
Aast.CollectionTKV
(tk
, tv
) -> Some
(aast_targ env tk
, aast_targ env tv
)
2138 N.KeyValCollection
((N.get_kvc_kind cn
), ta,
2139 (List.map l
(aast_afield_kvalue
env cn
)))
2140 | x when x = SN.Collections.cPair
->
2144 Errors.naming_too_few_arguments
p;
2147 let pn = SN.Collections.cPair
in
2148 N.Pair
(aast_afield_value
env pn e1, aast_afield_value
env pn e2)
2150 Errors.naming_too_many_arguments
p;
2154 Errors.expected_collection
p cn
;
2157 | Aast.Clone
e -> N.Clone
(aast_expr
env e)
2158 | Aast.Null
-> N.Null
2159 | Aast.True
-> N.True
2160 | Aast.False
-> N.False
2161 | Aast.Int s
-> N.Int s
2162 | Aast.Float s
-> N.Float s
2163 | Aast.String s
-> N.String s
2165 (* treat execution operator similar to interpolated strings *)
2166 | Aast.Execution_operator idl
-> N.String2
(aast_string2
env idl
)
2167 | Aast.PrefixedString
(n
, e) -> N.PrefixedString
(n
, (aast_expr
env e))
2169 (** TODO: Emit proper error messages T28473207. Currently the error message
2170 * emitted has reason Naming[2049] unbound name for global constant *)
2172 match Env.let_local env x with
2173 | Some
x -> N.ImmutableVar
x
2174 | None
-> N.Id
(Env.global_const env x)
2176 | Aast.Lvar
(_, x) when Local_id.to_string
x = SN.SpecialIdents.this
-> N.This
2177 | Aast.Lvar
(p, x) when Local_id.to_string
x = SN.SpecialIdents.dollardollar
->
2178 N.Dollardollar
(p, Env.found_dollardollar env p)
2179 | Aast.Lvar
(p, x) when Local_id.to_string
x = SN.SpecialIdents.placeholder
->
2182 N.Lvar
(Env.aast_lvar env x)
2183 | Aast.Obj_get
(e1, e2, nullsafe
) ->
2184 (* If we encounter Obj_get(_,_,true) by itself, then it means "?->"
2185 is being used for instance property access; see the case below for
2186 handling nullsafe instance method calls to see how this works *)
2187 N.Obj_get
(aast_expr
env e1, aast_expr_obj_get_name
env e2, nullsafe
)
2188 | Aast.Array_get
((p, Aast.Lvar
x), None
) ->
2189 let id = p, N.Lvar
(Env.aast_lvar env x) in
2190 N.Array_get
(id, None
)
2191 | Aast.Array_get
(e1, e2) -> N.Array_get
(aast_expr
env e1, aast_oexpr
env e2)
2192 | Aast.Class_get
((_, Aast.CIexpr
(_, Aast.Id x1
)), Aast.CGstring x2
) ->
2193 N.Class_get
(make_class_id
env x1
, N.CGstring x2
)
2194 | Aast.Class_get
((_, Aast.CIexpr
(_, Aast.Lvar
(p, lid
))), Aast.CGstring x2
) ->
2195 let x1 = (p, Local_id.to_string lid
) in
2196 N.Class_get
(make_class_id
env x1, N.CGstring x2
)
2197 | Aast.Class_get
((_, Aast.CIexpr
x1), Aast.CGexpr x2
) ->
2198 aast_ensure_name_not_dynamic env x1
2199 Errors.dynamic_class_name_in_strict_mode
;
2200 aast_ensure_name_not_dynamic env x2
2201 Errors.dynamic_class_name_in_strict_mode
;
2203 | Aast.Class_get
_ -> failwith
"Error in Ast_to_nast module for Class_get"
2204 | Aast.Class_const
((_, Aast.CIexpr
(_, Aast.Id
x1)), x2
) ->
2205 let (genv, _) = env in
2206 let (_, name) = NS.elaborate_id
genv.namespace
NS.ElaborateClass
x1 in
2208 match Naming_heap.TypeIdHeap.get
name with
2209 | Some
(_, `Typedef
) when (snd x2
) = "class" ->
2210 N.Typename
(Env.type_name env x1 ~allow_typedef
:true ~allow_generics
:false)
2212 N.Class_const
(make_class_id
env x1, x2
)
2214 | Aast.Class_const
((_, Aast.CIexpr
(_, Aast.Lvar
(p, lid
))), x2
) ->
2215 let x1 = (p, Local_id.to_string lid
) in
2216 let (genv, _) = env in
2217 let (_, name) = NS.elaborate_id
genv.namespace
NS.ElaborateClass
x1 in
2219 match Naming_heap.TypeIdHeap.get
name with
2220 | Some
(_, `Typedef
) when (snd x2
) = "class" ->
2221 N.Typename
(Env.type_name env x1 ~allow_typedef
:true ~allow_generics
:false)
2223 N.Class_const
(make_class_id
env x1, x2
)
2225 | Aast.Class_const
_ -> (* TODO: report error in strict mode *) N.Any
2226 | Aast.Call
(_, (_, Aast.Id
(p, pseudo_func
)), tal
, el, uel
)
2227 when pseudo_func
= SN.SpecialFunctions.echo
->
2228 arg_unpack_unexpected uel
;
2229 N.Call
(N.Cnormal
, (p, N.Id
(p, pseudo_func
)), aast_targl env p tal
, aast_exprl
env el, [])
2230 | Aast.Call
(_, (p, (Aast.Id
(_, cn
))), tal
, el, uel
)
2231 when cn
= SN.SpecialFunctions.call_user_func
->
2232 arg_unpack_unexpected uel
;
2235 | [] -> Errors.naming_too_few_arguments
p; N.Any
2238 (N.Cuser_func
, aast_expr
env f, aast_targl env p tal
, aast_exprl
env el, [])
2240 | Aast.Call
(_, (p, Aast.Id
(_, cn
)), _, el, uel
)
2241 when cn
= SN.SpecialFunctions.fun_
->
2242 arg_unpack_unexpected uel
;
2243 let (genv, _) = env in
2246 | [] -> Errors.naming_too_few_arguments
p; N.Any
2247 | [_, Aast.String s
] when String.contains s '
:'
->
2248 Errors.illegal_meth_fun
p; N.Any
2249 | [_, Aast.String s
] when genv.in_ppl && SN.PPLFunctions.is_reserved s
->
2250 Errors.ppl_meth_pointer
p ("fun("^s^
")"); N.Any
2251 | [p, Aast.String
x] ->
2252 (* Functions referenced by fun() are always fully-qualified *)
2253 let x = if x <> "" && x.[0] <> '
\\'
then "\\" ^
x else x in
2254 N.Fun_id
(Env.fun_id env (p, x))
2255 | [p, _] -> Errors.illegal_fun
p; N.Any
2256 | _ -> Errors.naming_too_many_arguments
p; N.Any
2258 | Aast.Call
(_, (p, Aast.Id
(_, cn
)), _, el, uel
)
2259 when cn
= SN.SpecialFunctions.inst_meth
->
2260 arg_unpack_unexpected uel
;
2264 | [_] -> Errors.naming_too_few_arguments
p; N.Any
2265 | instance
:: (p, Aast.String meth
) :: [] ->
2266 N.Method_id
(aast_expr
env instance
, (p, meth
))
2267 | (p, _) :: _ :: [] -> Errors.illegal_inst_meth
p; N.Any
2268 | _ -> Errors.naming_too_many_arguments
p; N.Any
2270 | Aast.Call
(_, (p, Aast.Id
(_, cn
)), _, el, uel
)
2271 when cn
= SN.SpecialFunctions.meth_caller
->
2272 arg_unpack_unexpected uel
;
2276 | [_] -> Errors.naming_too_few_arguments
p; N.Any
2279 match (aast_expr
env e1), (aast_expr
env e2) with
2280 | (pc
, N.String cl
), (pm
, N.String meth
) ->
2281 N.Method_caller
(Env.type_name env (pc
, cl
) ~allow_typedef
:false ~allow_generics
:false, (pm
, meth
))
2282 | (_, N.Class_const
((_, N.CI cl
), (_, mem
))), (pm
, N.String meth
)
2283 when mem
= SN.Members.mClass
->
2284 N.Method_caller
(Env.type_name env cl ~allow_typedef
:false ~allow_generics
:false, (pm
, meth
))
2285 | (p, _), _ -> Errors.illegal_meth_caller
p; N.Any
2287 | _ -> Errors.naming_too_many_arguments
p; N.Any
2289 | Aast.Call
(_, (p, Aast.Id
(_, cn
)), _, el, uel
)
2290 when cn
= SN.SpecialFunctions.class_meth
->
2291 arg_unpack_unexpected uel
;
2295 | [_] -> Errors.naming_too_few_arguments
p; N.Any
2298 match (aast_expr
env e1), (aast_expr
env e2) with
2299 | (pc
, N.String cl
), (pm
, N.String meth
) ->
2300 N.Smethod_id
(Env.type_name env (pc
, cl
) ~allow_typedef
:false ~allow_generics
:false, (pm
, meth
))
2301 | (_, N.Id
(_, const)), (pm
, N.String meth
)
2302 when const = SN.PseudoConsts.g__CLASS__
->
2303 (* All of these that use current_cls aren't quite correct
2304 * inside a trait, as the class should be the using class.
2305 * It's sufficient for typechecking purposes (we require
2306 * subclass to be compatible with the trait member/method
2309 (match (fst
env).current_cls
with
2310 | Some
(cid
, _) -> N.Smethod_id
(cid
, (pm
, meth
))
2311 | None
-> Errors.illegal_class_meth
p; N.Any
)
2312 | (_, N.Class_const
((_, N.CI cl
), (_, mem
))), (pm
, N.String meth
)
2313 when mem
= SN.Members.mClass
->
2314 N.Smethod_id
(Env.type_name env cl ~allow_typedef
:false ~allow_generics
:false, (pm
, meth
))
2315 | (p, N.Class_const
((_, (N.CIself
| N.CIstatic
)), (_, mem
))),
2316 (pm
, N.String meth
) when mem
= SN.Members.mClass
->
2317 (match (fst
env).current_cls
with
2318 | Some
(cid
, _) -> N.Smethod_id
(cid
, (pm
, meth
))
2319 | None
-> Errors.illegal_class_meth
p; N.Any
)
2320 | (p, _), _ -> Errors.illegal_class_meth
p; N.Any
2322 | _ -> Errors.naming_too_many_arguments
p; N.Any
2324 | Aast.Call
(_, (p, Aast.Id
(_, cn
)), _, el, uel
)
2325 when cn
= SN.SpecialFunctions.assert_
->
2326 arg_unpack_unexpected uel
;
2327 if List.length
el <> 1
2328 then Errors.assert_arity
p;
2329 N.Assert
(N.AE_assert
(
2330 Option.value_map
(List.hd
el) ~
default:(p, N.Any
) ~
f:(aast_expr
env)
2332 | Aast.Call
(_, (p, Aast.Id
(_, cn
)), _, el, uel
)
2333 when cn
= SN.SpecialFunctions.tuple
->
2334 arg_unpack_unexpected uel
;
2336 | [] -> Errors.naming_too_few_arguments
p; N.Any
2337 | el -> N.List
(aast_exprl
env el)
2339 (* sample, factor, observe, condition *)
2340 | Aast.Call
(_, (p1
, Aast.Id
(p2
, cn
)), tal
, el, uel
)
2341 when Env.in_ppl env && SN.PPLFunctions.is_reserved cn
->
2342 let n_expr = N.Id
(p2
, cn
) in
2343 N.Call
(N.Cnormal
, (p1
, n_expr),
2344 aast_targl env p tal
, aast_exprl
env el, aast_exprl
env uel
)
2345 | Aast.Call
(_, (p, Aast.Id
f), tal
, el, uel
) ->
2347 match Env.let_local env f with
2349 (* Translate into local id *)
2350 let f = (p, N.ImmutableVar
x) in
2351 N.Call
(N.Cnormal
, f, aast_targl env p tal
, aast_exprl
env el, aast_exprl
env uel
)
2353 (* The name is not a local `let` binding *)
2354 let qualified = Env.fun_id env f in
2355 let cn = snd
qualified in
2356 (* The above special cases (fun, inst_meth, meth_caller, class_meth,
2357 * and friends) are magical language constructs, which we should
2358 * check before calling fun_id and looking up the function and doing
2359 * namespace normalization. However, gena, genva, etc are actual
2360 * functions that actually exist, we just need to handle them
2361 * specially here, during naming. Note that most of the function
2362 * special cases, such as idx, are actually handled in typing, and
2363 * don't require naming magic. *)
2367 arg_unpack_unexpected uel
;
2369 | [e] -> N.Special_func
(N.Gena
(aast_expr
env e))
2370 | _ -> Errors.gena_arity
p; N.Any
2372 else if (cn = SN.FB.fgenva
)
2373 || (cn = SN.HH.asio_va
)
2374 || (cn = SN.HH.lib_tuple_gen
)
2375 || (cn = SN.HH.lib_tuple_from_async
)
2378 arg_unpack_unexpected uel
;
2379 if List.length
el < 1
2380 then (Errors.genva_arity
p; N.Any
)
2381 else N.Special_func
(N.Genva
(aast_exprl
env el))
2383 else if cn = SN.FB.fgen_array_rec
2386 arg_unpack_unexpected uel
;
2388 | [e] -> N.Special_func
(N.Gen_array_rec
(aast_expr
env e))
2389 | _ -> Errors.gen_array_rec_arity
p; N.Any
2392 N.Call
(N.Cnormal
, (p, N.Id
qualified), aast_targl env p tal
,
2393 aast_exprl
env el, aast_exprl
env uel
)
2395 (* Handle nullsafe instance method calls here. Because Obj_get is used
2396 for both instance property access and instance method calls, we need
2397 to match the entire "Call(Obj_get(..), ..)" pattern here so that we
2398 only match instance method calls *)
2399 | Aast.Call
(_, (p, Aast.Obj_get
(e1, e2, Aast.OG_nullsafe
)), tal
, el, uel
) ->
2402 (p, N.Obj_get
(aast_expr
env e1,
2403 aast_expr_obj_get_name
env e2, N.OG_nullsafe
)),
2404 aast_targl env p tal
,
2405 aast_exprl
env el, aast_exprl
env uel
)
2406 (* Handle all kinds of calls that weren't handled by any of the cases above *)
2407 | Aast.Call
(_, e, tal
, el, uel
) ->
2408 N.Call
(N.Cnormal
, aast_expr
env e,
2409 aast_targl env p tal
, aast_exprl
env el, aast_exprl
env uel
)
2410 | Aast.Yield_break
-> N.Yield_break
2411 | Aast.Yield
e -> N.Yield
(aast_afield
env e)
2412 | Aast.Await
e -> N.Await
(aast_expr
env e)
2413 | Aast.Suspend
e -> N.Suspend
(aast_expr
env e)
2414 | Aast.List
el -> N.List
(aast_exprl
env el)
2415 | Aast.Expr_list
el -> N.Expr_list
(aast_exprl
env el)
2416 | Aast.Cast
(ty, e2) ->
2419 | _, Aast.Happly
(id, hl
) -> (id, hl
)
2420 | _ -> assert false in
2422 match aast_try_castable_hint ~tp_depth
:1 env p x hl
with
2427 | x when x = SN.Typehints.object_cast
->
2428 (* (object) is a valid cast but not a valid type annotation *)
2429 if (fst
env).in_mode
= FileInfo.Mstrict
then Errors.object_cast
p None
;
2431 | x when x = SN.Typehints.void
->
2434 | x when x = SN.Typehints.unset_cast
->
2435 Errors.unset_cast
p;
2438 (* Let's just assume that any other invalid cases are attempts to
2439 * cast to specific objects *)
2440 let h = aast_hint ~allow_typedef
:false env ty in
2441 Errors.object_cast
p (Some
x);
2444 N.Cast
(ty, aast_expr
env e2)
2445 | Aast.Unop
(uop
, e) -> N.Unop
(uop
, aast_expr
env e)
2446 | Aast.Binop
(Ast.Eq None
as op
, lv
, e2) ->
2447 if Env.inside_pipe env then
2448 Errors.unimplemented_feature
p "Assignment within pipe expressions";
2449 let e2 = aast_expr
env e2 in
2450 let nsenv = (fst
env).namespace
in
2452 GetLocals.aast_lvalue
(nsenv, SMap.empty
) lv
in
2453 SMap.iter
(fun x p -> ignore
(Env.new_lvar env (p, x))) vars;
2454 N.Binop
(op
, aast_expr
env lv
, e2)
2455 | Aast.Binop
(Ast.Eq
_ as bop
, e1, e2) ->
2456 if Env.inside_pipe env
2457 then Errors.unimplemented_feature
p "Assignment within pipe expressions";
2458 N.Binop
(bop
, aast_expr
env e1, aast_expr
env e2)
2459 | Aast.Binop
(bop
, e1, e2) -> N.Binop
(bop
, aast_expr
env e1, aast_expr
env e2)
2460 | Aast.Pipe
(_dollardollar
, e1, e2) ->
2461 let e1 = aast_expr
env e1 in
2462 let ident, e2 = Env.pipe_scope env (fun env -> aast_expr
env e2) in
2463 N.Pipe
((p, ident), e1, e2)
2464 | Aast.Eif
(e1, e2opt
, e3) ->
2465 (* The order matters here, of course -- e1 can define vars that need to
2466 * be available in e2 and e3. *)
2467 let e1 = aast_expr
env e1 in
2468 let nsenv = (fst
env).namespace
in
2469 let get_lvalues = function e ->
2470 snd
@@ GetLocals.aast_stmt
(nsenv, SMap.empty
) (Aast.Expr
e) in
2472 Option.value (Option.map e2opt
get_lvalues) ~
default:SMap.empty
2474 let e3_lvalues = get_lvalues e3 in
2475 let lvalues = smap_inter
e2_lvalues e3_lvalues in
2476 SMap.iter
(fun x p -> Env.new_pending_lvar env (p, x)) lvalues;
2477 let e2opt, e3 = Env.scope env (fun env ->
2478 let all2, e2opt = Env.scope_all env (fun env -> aast_oexpr
env e2opt) in
2479 let all3, e3 = Env.scope_all env (fun env -> aast_expr
env e3) in
2480 Env.extend_all_locals env all2;
2481 Env.extend_all_locals env all3;
2484 SMap.iter
(fun x _ -> Env.promote_pending_lvar env x) lvalues;
2485 N.Eif
(e1, e2opt, e3)
2486 | Aast.InstanceOf
(e, (_, Aast.CIexpr
(p, Aast.Id
x))) ->
2489 | px
, n
when n
= SN.Classes.cParent
->
2490 if (fst
env).current_cls
= None
then
2491 let () = Errors.parent_outside_class
p in
2492 N.CI
(px
, SN.Classes.cUnknown
)
2494 | px
, n
when n
= SN.Classes.cSelf
->
2495 if (fst
env).current_cls
= None
then
2496 let () = Errors.self_outside_class
p in
2497 N.CI
(px
, SN.Classes.cUnknown
)
2499 | px
, n
when n
= SN.Classes.cStatic
->
2500 if (fst
env).current_cls
= None
then
2501 let () = Errors.static_outside_class
p in
2502 N.CI
(px
, SN.Classes.cUnknown
)
2505 N.CI
(Env.type_name env x ~allow_typedef
:false ~allow_generics
:false)
2507 N.InstanceOf
(aast_expr
env e, (p, id))
2508 | Aast.InstanceOf
(e1, (_, Aast.CIexpr
(_,
2509 (Aast.Lvar
_ | Aast.Obj_get
_ | Aast.Class_get
_ | Aast.Class_const
_
2510 | Aast.Array_get
_ | Aast.Call
_) as e2))) ->
2511 N.InstanceOf
(aast_expr
env e1, (fst
e2, N.CIexpr
(aast_expr
env e2)))
2512 | Aast.InstanceOf
(_e1
, (p, _)) ->
2513 Errors.invalid_instanceof
p;
2516 N.Is
(aast_expr
env e, aast_hint ~allow_wildcard
:true env h)
2517 | Aast.As
(e, h, b) ->
2518 N.As
(aast_expr
env e, aast_hint ~allow_wildcard
:true env h, b)
2519 | Aast.New
((_, Aast.CIexpr
(p, Aast.Id
x)), tal
, el, uel
, _) ->
2520 N.New
(make_class_id
env x,
2521 aast_targl env p tal
,
2525 | Aast.New
((_, Aast.CIexpr
(_, Aast.Lvar
(pos, x))), tal
, el, uel
, p) ->
2526 N.New
(make_class_id
env (pos, Local_id.to_string
x),
2527 aast_targl env p tal
,
2531 | Aast.New
((_, Aast.CIexpr
(p, _e
)), tal
, el, uel
, _) ->
2532 if (fst
env).in_mode
= FileInfo.Mstrict
2533 then Errors.dynamic_new_in_strict_mode
p;
2534 N.New
(make_class_id
env (p, SN.Classes.cUnknown
),
2535 aast_targl env p tal
,
2539 | Aast.New
_ -> failwith
"ast_to_nast aast.new"
2540 | Aast.NewAnonClass
_ ->
2541 Errors.experimental_feature
p "Anonymous classes";
2543 | Aast.Efun
(f, idl
) ->
2547 ~
f:(fun ((p, x) as id) acc
->
2548 if Local_id.to_string
x = SN.SpecialIdents.this
2549 then (Errors.this_as_lexical_variable
p; acc
)
2552 let idl'
= List.map
idl (Env.aast_lvar env) in
2553 let env = (fst
env, Env.empty_local None
) in
2554 List.iter2_exn
idl idl'
(Env.aast_add_lvar env);
2555 let f = aast_expr_lambda
env f in
2558 (* We have to build the capture list while we're finding names in
2559 the closure body---accumulate it in to_capture. *)
2560 let to_capture = ref [] in
2561 let handle_unbound (p, x) =
2562 let cap = Env.lvar env (p, x) in
2563 to_capture := cap :: !to_capture;
2566 let lenv = Env.empty_local @@ Some
handle_unbound in
2567 (* Extend the current let binding into the scope of lambda *)
2568 Env.copy_let_locals env (fst
env, lenv);
2569 let env = (fst
env, lenv) in
2570 let f = aast_expr_lambda
env f in
2571 (* TODO T28711692: Compute the correct capture list for let variables,
2572 * it does not seem to affect typechecking... *)
2573 N.Efun
(f, !to_capture)
2574 | Aast.Xml
(x, al
, el) ->
2575 N.Xml
(Env.type_name env x ~allow_typedef
:false ~allow_generics
:false, aast_attrl
env al
,
2578 let (shp
, _) = begin List.fold_left fdl ~init
:([], Ast.ShapeSet.empty
)
2579 ~
f:begin fun (fdm
, set
) (pname
, value) ->
2580 let pos, name = convert_shape_name env pname
in
2581 if Ast.ShapeSet.mem
name set
2582 then Errors.fd_name_already_bound
pos;
2583 (name, (aast_expr
env value)) :: fdm
, Ast.ShapeSet.add
name set
2586 N.Shape
(List.rev shp
)
2587 | Aast.Unsafe_expr
e ->
2588 N.Unsafe_expr
(Errors.ignore_
(fun () -> aast_expr
env e))
2589 | Aast.BracedExpr
_ ->
2591 | Aast.Yield_from
e ->
2592 N.Yield_from
(aast_expr
env e)
2597 | Aast.Callconv
(kind
, e) ->
2598 N.Callconv
(kind
, aast_expr
env e)
2599 (* The below were not found on the AST.ml so they are not implemented here *)
2600 | Aast.ValCollection
_
2601 | Aast.KeyValCollection
_
2603 | Aast.ImmutableVar
_
2604 | Aast.Dollardollar
_
2605 | Aast.Lplaceholder
_
2608 | Aast.Method_caller
_
2610 | Aast.Special_func
_
2615 Errors.internal_error
p "Malformed expr: Expr not found on legacy AST: T39599317";
2618 and aast_expr_lambda
env f =
2619 let env = Env.set_ppl env false in
2620 let h = Option.map
f.Aast.f_ret
(aast_hint ~allow_retonly
:true env) in
2621 let previous_unsafe = Env.has_unsafe env in
2622 (* save unsafe and yield state *)
2623 Env.set_unsafe env false;
2624 let variadicity, paraml
= aast_fun_paraml
env f.Aast.f_params
in
2625 (* The bodies of lambdas go through naming in the containing local
2627 let body_nast = aast_f_body
env f.Aast.f_body
in
2629 if func_body_had_unsafe
env
2630 then N.BodyNamingAnnotation.NamedWithUnsafeBlocks
2631 else N.BodyNamingAnnotation.Named
in
2632 (* restore unsafe state *)
2633 Env.set_unsafe env previous_unsafe;
2634 (* These could all be probably be replaced with a {... where ...} *)
2636 N.fb_ast
= body_nast;
2637 fb_annotation
= annotation;
2639 { N.f_annotation
= ();
2640 f_span
= f.Aast.f_span
;
2641 f_mode
= (fst
env).in_mode
;
2643 f_name
= f.Aast.f_name
;
2646 f_where_constraints
= [];
2648 f_fun_kind
= f.Aast.f_fun_kind
;
2649 f_variadic
= variadicity;
2650 f_file_attributes
= [];
2651 f_user_attributes
= aast_user_attributes
env f.Aast.f_user_attributes
;
2652 f_external
= f.Aast.f_external
;
2653 f_namespace
= f.Aast.f_namespace
;
2654 f_doc_comment
= f.Aast.f_doc_comment
;
2655 f_static
= f.Aast.f_static
;
2658 and aast_f_body
env f_body
=
2659 if Aast.is_body_named f_body
2660 then aast_block
env f_body
.Aast.fb_ast
2661 else failwith
"Malformed f_body: unexpected UnnamedBody from ast_to_nast"
2663 and make_class_id
env (p, x as cid
) =
2666 | x when x = SN.Classes.cParent
->
2667 if (fst
env).current_cls
= None
then
2668 let () = Errors.parent_outside_class
p in
2669 N.CI
(p, SN.Classes.cUnknown
)
2671 | x when x = SN.Classes.cSelf
->
2672 if (fst
env).current_cls
= None
then
2673 let () = Errors.self_outside_class
p in
2674 N.CI
(p, SN.Classes.cUnknown
)
2676 | x when x = SN.Classes.cStatic
-> if (fst
env).current_cls
= None
then
2677 let () = Errors.static_outside_class
p in
2678 N.CI
(p, SN.Classes.cUnknown
)
2680 | x when x = SN.SpecialIdents.this
-> N.CIexpr
(p, N.This
)
2681 | x when x = SN.SpecialIdents.dollardollar
->
2682 (* We won't reach here for "new $$" because the parser creates a
2683 * proper Ast.Dollardollar node, so make_class_id won't be called with
2684 * that node. In fact, the parser creates an Ast.Dollardollar for all
2685 * "$$" except in positions where a classname is expected, like in
2686 * static member access. So, we only reach here for things
2687 * like "$$::someMethod()". *)
2688 N.CIexpr
(p, N.Lvar
(p, Env.found_dollardollar env p))
2689 | x when x.[0] = '$'
-> N.CIexpr
(p, N.Lvar
(Env.lvar env cid
))
2690 | _ -> N.CI
(Env.type_name env cid ~allow_typedef
:false ~allow_generics
:false)
2692 and aast_casel
env l
=
2693 List.map_env
[] l
(aast_case
env)
2695 and aast_case
env acc
c =
2698 let all_locals, b = aast_branch ~after_unsafe
:N.Fallthrough
env b in
2699 all_locals :: acc
, N.Default
b
2700 | Aast.Case
(e, b) ->
2701 let e = aast_expr
env e in
2702 let all_locals, b = aast_branch ~after_unsafe
:N.Fallthrough
env b in
2703 all_locals :: acc
, N.Case
(e, b)
2705 and aast_catchl
env l
= List.map_env
[] l
(aast_catch
env)
2706 and aast_catch
env acc
((p1
, lid1
), (p2
, lid2
), b) =
2710 let name2 = Local_id.get_name lid2
in
2711 (* If the variable does not begin with $, it is an immutable binding *)
2714 && name2.[0] = '$'
(* This is always true if not in experimental mode *)
2715 then Env.new_lvar env (p2
, name2)
2716 else Env.new_let_local env (p2
, name2) in
2717 let all_locals, b = aast_branch
env b in
2718 all_locals :: acc
, (Env.type_name env (p1
, lid1
) ~allow_typedef
:true ~allow_generics
:false, x2, b))
2720 and aast_afield
env field
=
2722 | Aast.AFvalue
e -> N.AFvalue
(aast_expr
env e)
2723 | Aast.AFkvalue
(e1, e2) -> N.AFkvalue
(aast_expr
env e1, aast_expr
env e2)
2725 and aast_afield_value
env cname field
=
2727 | Aast.AFvalue
e -> aast_expr
env e
2728 | Aast.AFkvalue
(e1, _e2
) ->
2729 Errors.unexpected_arrow
(fst
e1) cname
;
2732 and aast_afield_kvalue
env cname field
=
2735 Errors.missing_arrow
(fst
e) cname
;
2737 aast_expr
env (fst
e, Aast.Lvar
(fst
e, Local_id.make_unscoped
"__internal_placeholder"))
2738 | Aast.AFkvalue
(e1, e2) -> aast_expr
env e1, aast_expr
env e2
2740 and aast_attrl
env l
= List.map ~
f:(aast_attr
env) l
2741 and aast_attr
env at
=
2743 | Aast.Xhp_simple
(x, e) -> N.Xhp_simple
(x, aast_expr
env e)
2744 | Aast.Xhp_spread
e -> N.Xhp_spread
(aast_expr
env e)
2746 and aast_string2
env idl =
2747 List.map
idl (aast_expr
env)
2749 (**************************************************************************)
2750 (* Function/Method Body Naming: *)
2751 (* Ensure that, given a function / class, any UnnamedBody within is
2752 * transformed into a a named body *)
2753 (**************************************************************************)
2756 match f.N.f_body
.N.fb_annotation
with
2757 | N.BodyNamingAnnotation.Named
2758 | N.BodyNamingAnnotation.NamedWithUnsafeBlocks
-> f.N.f_body
2759 | N.BodyNamingAnnotation.Unnamed
nsenv ->
2760 let genv = Env.make_fun_genv
2761 SMap.empty
f.N.f_mode
(snd
f.N.f_name
) nsenv in
2762 let genv = aast_extend_params
genv f.N.f_tparams in
2763 let lenv = Env.empty_local None
in
2764 let env = genv, lenv in
2766 List.fold_left ~
f:Env.add_param f.N.f_params ~init
:env in
2767 let env = match f.N.f_variadic
with
2768 | N.FVellipsis
_ | N.FVnonVariadic
-> env
2769 | N.FVvariadicArg param
-> Env.add_param env param
2771 let fub_ast = aast_block
env f.N.f_body
.N.fb_ast
in
2773 if func_body_had_unsafe
env
2774 then N.BodyNamingAnnotation.NamedWithUnsafeBlocks
2775 else N.BodyNamingAnnotation.Named
in
2776 Env.check_goto_references env;
2779 fb_annotation
= annotation;
2782 let meth_body genv m
=
2784 match m
.N.m_body
.N.fb_annotation
with
2785 | N.BodyNamingAnnotation.Named
2786 | N.BodyNamingAnnotation.NamedWithUnsafeBlocks
-> m
.N.m_body
2787 | N.BodyNamingAnnotation.Unnamed
nsenv ->
2788 let genv = { genv with namespace
= nsenv } in
2789 let genv = aast_extend_params
genv m
.N.m_tparams
in
2790 let env = genv, Env.empty_local None
in
2792 List.fold_left ~
f:Env.add_param m
.N.m_params ~init
:env in
2793 let env = match m
.N.m_variadic
with
2794 | N.FVellipsis
_ | N.FVnonVariadic
-> env
2795 | N.FVvariadicArg param
-> Env.add_param env param
2797 let fub_ast = aast_block
env m
.N.m_body
.N.fb_ast
in
2799 if func_body_had_unsafe
env
2800 then N.BodyNamingAnnotation.NamedWithUnsafeBlocks
2801 else N.BodyNamingAnnotation.Named
in
2802 Env.check_goto_references env;
2803 { N.fb_ast
= fub_ast;
2804 fb_annotation
= annotation;
2806 {m
with N.m_body
= named_body}
2808 let class_meth_bodies nc
=
2809 let { N.c_tparam_constraints
= cstrs
; _ } = nc
.N.c_tparams in
2810 let genv = Env.make_class_genv cstrs
2811 nc
.N.c_mode
(nc
.N.c_name
, nc
.N.c_kind
)
2812 Namespace_env.empty_with_default_popt
2813 (Attributes.mem
SN.UserAttributes.uaProbabilisticModel nc
.N.c_user_attributes
)
2815 let inst_meths = List.map nc
.N.c_methods
(meth_body genv) in
2816 let opt_constructor = match nc
.N.c_constructor
with
2818 | Some
c -> Some
(meth_body genv c) in
2819 let static_meths = List.map nc
.N.c_static_methods
(meth_body genv) in
2821 N.c_methods
= inst_meths;
2822 N.c_static_methods
= static_meths ;
2823 N.c_constructor
= opt_constructor ;
2826 (**************************************************************************)
2828 (**************************************************************************)
2830 let aast_typedef tdef
=
2831 let cstrs = aast_make_constraints tdef
.Aast.t_tparams
in
2832 let env = Env.aast_make_typedef_env cstrs tdef
in
2833 let tconstraint = Option.map tdef
.Aast.t_constraint
(aast_hint env) in
2834 List.iter tdef
.Aast.t_tparams
aast_check_constraint;
2835 let tparaml = aast_type_paraml
env tdef
.Aast.t_tparams
in
2836 let attrs = aast_user_attributes
env tdef
.Aast.t_user_attributes
in
2838 N.t_annotation
= ();
2839 t_name
= tdef
.Aast.t_name
;
2840 t_tparams
= tparaml;
2841 t_constraint
= tconstraint;
2842 t_kind
= aast_hint env tdef
.Aast.t_kind
;
2843 t_user_attributes
= attrs;
2844 t_mode
= tdef
.Aast.t_mode
;
2845 t_namespace
= tdef
.Aast.t_namespace
;
2846 t_vis
= tdef
.Aast.t_vis
;
2850 let tdef = Ast_to_nast.on_typedef
tdef in
2853 (**************************************************************************)
2854 (* Global constants *)
2855 (**************************************************************************)
2857 let check_constant_hint cst
=
2858 match cst
.Aast.cst_type
with
2859 | None
when cst
.Aast.cst_mode
= FileInfo.Mstrict
->
2860 Errors.add_a_typehint
(fst cst
.Aast.cst_name
)
2864 let check_constant_name genv cst
=
2865 if genv.namespace
.Namespace_env.ns_name
<> None
then
2866 let pos, name = cst
.Aast.cst_name
in
2867 let name = Utils.strip_all_ns
name in
2868 if SN.PseudoConsts.is_pseudo_const
(Utils.add_ns
name) then
2869 Errors.name_is_reserved
name pos
2871 let aast_global_const cst
=
2872 let env = Env.aast_make_const_env cst
in
2873 let hint = Option.map cst
.Aast.cst_type
(aast_hint env) in
2875 (* Define allows any expression, so don't call check_constant.
2876 * Furthermore it often appears at toplevel, which we don't track at
2877 * all, so don't type or even name that expression, it may refer to
2878 * "undefined" variables that actually exist, just untracked since
2879 * they're toplevel. *)
2880 if cst
.Aast.cst_is_define
2883 let _ = check_constant_name (fst
env) cst
in
2884 let _ = check_constant_hint cst
in
2885 Option.map cst
.Aast.cst_value
(aast_constant_expr
env) in
2886 { N.cst_annotation
= ();
2887 cst_mode
= cst
.Aast.cst_mode
;
2888 cst_name
= cst
.Aast.cst_name
;
2891 cst_is_define
= cst
.Aast.cst_is_define
;
2892 cst_namespace
= cst
.Aast.cst_namespace
;
2895 let global_const cst
=
2896 let cst = Ast_to_nast.on_constant
cst in
2897 aast_global_const cst
2899 (**************************************************************************)
2900 (* The entry point to CHECK the program, and transform the program *)
2901 (**************************************************************************)
2903 let aast_program aast
=
2904 let top_level_env = ref (Env.make_top_level_env ()) in
2905 let rec aux acc def
=
2907 | Aast.Fun
f -> (N.Fun
(aast_fun_
f)) :: acc
2908 | Aast.Class
c -> (N.Class
(aast_class_
c)) :: acc
2909 | Aast.Stmt
Aast.Noop
2910 | Aast.Stmt
(Aast.Markup
_) -> acc
2911 | Aast.Stmt s
-> (N.Stmt
(aast_stmt
!top_level_env s
)) :: acc
2912 | Aast.Typedef t
-> (N.Typedef
(aast_typedef t
)) :: acc
2913 | Aast.Constant
cst -> (N.Constant
(aast_global_const cst)) :: acc
2914 | Aast.Namespace
(_ns
, aast
) -> List.fold_left ~
f:aux ~init
:[] aast
@ acc
2915 | Aast.NamespaceUse
_ -> acc
2916 | Aast.SetNamespaceEnv
nsenv ->
2917 let (genv, lenv) = !top_level_env in
2918 let genv = { genv with namespace
= nsenv } in
2919 top_level_env := (genv, lenv);
2921 let on_program aast
=
2922 let nast = List.fold_left ~
f:aux ~init
:[] aast
in
2927 let aast = Ast_to_nast.on_program ast
in
2933 let stmt acc
_ = acc
2934 let lvalue acc
_ = acc
2936 let aast_stmt acc
_ = acc
2937 let aast_lvalue acc
_ = acc