Move type arity checks to type_params_arity_check (1/2)
[hiphop-php.git] / hphp / hack / src / typing / nastCheck.ml
blob5fcaaaf0e5fb7c0f17d5f9ae015f740093340bfc
1 (**
2 * Copyright (c) 2015, Facebook, Inc.
3 * All rights reserved.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
8 *)
11 (* This module performs checks after the naming has been done.
12 Basically any check that doesn't fall in the typing category. *)
13 (* Check of type application arity *)
14 (* Check no `new AbstractClass` (or trait, or interface) *)
15 (* Check no top-level break / continue *)
17 (* NOTE: since the typing environment does not generally contain
18 information about non-Hack code, some of these checks can
19 only be done in strict (i.e. "everything is Hack") mode. Use
20 `if Env.is_strict env.tenv` style checks accordingly.
24 open Core_kernel
25 open Nast
26 open Typing_defs
27 open Utils
29 module Env = Typing_env
30 module Inst = Decl_instantiate
31 module Phase = Typing_phase
32 module SN = Naming_special_names
33 module TGenConstraint = Typing_generic_constraint
34 module Subst = Decl_subst
35 module TUtils = Typing_utils
36 module Cls = Typing_classes_heap
39 type control_context =
40 | Toplevel
41 | LoopContext
42 | SwitchContext
44 type env = {
45 t_is_finally: bool;
46 function_name: string option;
47 class_name: string option;
48 class_kind: Ast.class_kind option;
49 imm_ctrl_ctx: control_context;
50 typedef_tparams : Nast.tparam list;
51 is_array_append_allowed: bool;
52 is_reactive: bool; (* The enclosing function is reactive *)
53 tenv: Env.env;
56 module CheckFunctionBody = struct
57 let rec stmt f_type env st = match f_type, st with
58 | Ast.FSync, Return (_, None)
59 | Ast.FAsync, Return (_, None) -> ()
60 | Ast.FSync, Return (_, Some e)
61 | Ast.FAsync, Return (_, Some e) ->
62 expr_allow_await f_type env e;
64 | (Ast.FGenerator | Ast.FAsyncGenerator), Return (p, e) ->
65 (match e with
66 None -> ()
67 | Some _ -> Errors.return_in_gen p);
69 | Ast.FCoroutine, Return (_, e) ->
70 Option.iter e ~f:(expr f_type env)
71 | _, Throw (_, e) ->
72 expr f_type env e
73 | _, Expr e ->
74 expr_allow_await_or_rx_move f_type env e;
76 | _, ( Noop | Fallthrough | GotoLabel _ | Goto _ | Break _ | Continue _
77 | Static_var _ | Global_var _ | Unsafe_block _ ) -> ()
78 | _, Awaitall (_, el) ->
79 List.iter el (fun (x, y) ->
80 (match x with
81 | Some x -> expr f_type env x;
82 | None -> ());
83 expr f_type env y;
86 | _, If (cond, b1, b2) ->
87 expr f_type env cond;
88 block f_type env b1;
89 block f_type env b2;
91 | _, Do (b, e) ->
92 block f_type env b;
93 expr f_type env e;
95 | _, While (e, b) ->
96 expr f_type env e;
97 block f_type env b;
99 | _, Using { us_has_await = has_await; us_expr = e; us_block = b; _ } ->
100 if has_await then found_await f_type (fst e);
101 expr_allow_await_list f_type env e;
102 block f_type env b;
104 | _, For (init, cond, incr, b) ->
105 expr f_type env init;
106 expr f_type env cond;
107 expr f_type env incr;
108 block f_type env b;
110 | _, Switch (e, cl) ->
111 expr f_type env e;
112 List.iter cl (case f_type env);
114 | _, Foreach (_, (Await_as_v (p, _) | Await_as_kv (p, _, _)), _) ->
115 found_await f_type p
117 | _, Foreach (v, _, b) ->
118 expr f_type env v;
119 block f_type env b;
121 | _, Try (b, cl, fb) ->
122 block f_type env b;
123 List.iter cl (catch f_type env);
124 block f_type { env with t_is_finally = true } fb;
126 | _, Def_inline _ -> ()
127 | _, Let ((p, x), _, e) ->
128 (* We treat let statement as an assignment expression *)
129 let fake_expr = (p, Binop (Ast.Eq None, (p, Lvar (p, x)), e)) in
130 expr_allow_await f_type env fake_expr;
132 | _, Block b -> block f_type env b;
133 | _, Markup (_, eopt) -> (match eopt with Some e -> expr f_type env e | None -> ())
134 | _, Declare (_, e, b) ->
135 expr f_type env e;
136 block f_type env b;
138 and found_await ftype p =
139 match ftype with
140 | Ast.FCoroutine -> Errors.await_in_coroutine p
141 | Ast.FSync | Ast.FGenerator -> Errors.await_in_sync_function p
142 | _ -> ()
144 and block f_type env stl =
145 List.iter stl (stmt f_type env)
147 and start f_type env stl =
148 match stl with
149 | [If ((_, Id (_, c)), then_stmt, else_stmt ) ]
151 (* this is the only case when HH\Rx\IS_ENABLED can appear in
152 function body, other occurences are considered errors *)
154 if (HH\Rx\IS_ENABLED) {}
155 else {}
158 when c = SN.Rx.is_enabled ->
159 block f_type env then_stmt;
160 block f_type env else_stmt;
161 | _ ->
162 block f_type env stl
164 and case f_type env = function
165 | Default b -> block f_type env b
166 | Case (cond, b) ->
167 expr f_type env cond;
168 block f_type env b;
171 and catch f_type env (_, _, b) = block f_type env b
173 and afield f_type env = function
174 | AFvalue e -> expr f_type env e
175 | AFkvalue (e1, e2) -> expr2 f_type env (e1, e2)
177 and expr f_type env (p, e) =
178 expr_ p f_type env e
180 and expr_allow_await_list f_type env ((_, exp) as e) =
181 match exp with
182 | Expr_list el ->
183 List.iter el (expr_allow_await f_type env)
184 | _ ->
185 expr_allow_await f_type env e
187 and expr_allow_await ?(is_rhs=false) f_type env (p, exp) = match f_type, exp with
188 | Ast.FAsync, Await e
189 | Ast.FAsyncGenerator, Await e -> expr f_type env e; ()
190 | Ast.FAsync, Binop (Ast.Eq None, e1, (_, Await e))
191 | Ast.FAsyncGenerator, Binop (Ast.Eq None, e1, (_, Await e)) when not is_rhs ->
192 expr f_type env e1;
193 expr f_type env e;
195 | _ -> expr_ p f_type env exp; ()
197 and expr_allow_rx_move orelse f_type env exp =
198 match exp with
199 | _, Call (_, e, _, el, uel) when is_rx_move e ->
200 expr f_type env e;
201 List.iter el ~f:(expr f_type env);
202 List.iter uel ~f:(expr f_type env);
204 | _ ->
205 orelse f_type env exp
207 and expr_allow_await_or_rx_move f_type env exp =
208 match exp with
209 | _, Binop (Ast.Eq None, e1, rhs) ->
210 expr f_type env e1;
211 expr_allow_rx_move (expr_allow_await ~is_rhs:true) f_type env rhs
212 | _ ->
213 expr_allow_await f_type env exp
215 and is_rx_move e =
216 match e with
217 | _, Id (_, v) -> v = SN.Rx.move
218 | _ -> false
220 and expr2 f_type env (e1, e2) =
221 expr f_type env e1;
222 expr f_type env e2;
225 and expr_ p f_type env exp = match f_type, exp with
226 | _, Collection _
227 | _, Import _
228 | _, Lfun _
229 | _, NewAnonClass _
230 | _, Omitted
231 | _, BracedExpr _
232 | _, ParenthesizedExpr _ -> failwith "AST should not contain these nodes after naming"
233 | _, Any -> ()
234 | _, Class_const _
235 | _, Fun_id _
236 | _, Method_id _
237 | _, Smethod_id _
238 | _, Method_caller _
239 | _, This
240 | _, Class_get _
241 | _, Typename _
242 | _, Lplaceholder _
243 | _, Dollardollar _ -> ()
244 | _, Id (pos, const) when const = SN.Rx.is_enabled ->
245 Errors.rx_is_enabled_invalid_location pos
246 | _, Id _ -> ()
248 | _, ImmutableVar _
249 | _, Lvar _ ->
251 | _, Pipe (_, l, r) ->
252 expr f_type env l;
253 expr f_type env r;
254 | _, Array afl ->
255 List.iter afl (afield f_type env);
257 | _, Darray afl ->
258 List.iter afl (expr2 f_type env);
260 | _, Varray afl ->
261 List.iter afl (expr f_type env);
263 | _, ValCollection (_, el) ->
264 List.iter el (expr f_type env);
266 | _, KeyValCollection (_, fdl) ->
267 List.iter fdl (expr2 f_type env);
269 | _, Clone e -> expr f_type env e; ()
270 | _, Obj_get (e, (_, Id _s), _) ->
271 expr f_type env e;
273 | _, Obj_get (e1, e2, _) ->
274 expr2 f_type env (e1, e2);
276 | _, Array_get (e, eopt) ->
277 expr f_type env e;
278 maybe (expr f_type) env eopt;
280 | _, Call (_, e, _, _, _) when is_rx_move e ->
281 Errors.rx_move_invalid_location (fst e);
283 | _, Call (_, e, _, el, uel) ->
284 expr f_type env e;
285 List.iter el (expr_allow_rx_move expr f_type env);
286 List.iter uel (expr_allow_rx_move expr f_type env);
288 | _, True | _, False | _, Int _
289 | _, Float _ | _, Null | _, String _ -> ()
290 | _, PrefixedString (_, e) ->
291 expr f_type env e;
293 | _, String2 el ->
294 List.iter el (expr f_type env);
296 | _, List el ->
297 List.iter el (expr f_type env);
299 | _, Pair (e1, e2) ->
300 expr2 f_type env (e1, e2);
302 | _, Expr_list el ->
303 List.iter el (expr f_type env);
305 | _, Unop (_, e) -> expr f_type env e
306 | _, Binop (_, e1, e2) ->
307 expr2 f_type env (e1, e2);
309 | _, Eif (e1, None, e3) ->
310 expr2 f_type env (e1, e3);
312 | _, Eif (e1, Some e2, e3) ->
313 List.iter [e1; e2; e3] (expr f_type env);
315 | _, New (_, _, el, uel, _) ->
316 List.iter el (expr f_type env);
317 List.iter uel (expr f_type env);
319 | _, InstanceOf (e, _)
320 | _, Is (e, _)
321 | _, As (e, _, _)
322 | _, Cast (_, e) ->
323 expr f_type env e;
325 | _, Efun _ -> ()
327 | Ast.FGenerator, Yield_break
328 | Ast.FAsyncGenerator, Yield_break -> ()
329 | Ast.FGenerator, Yield af
330 | Ast.FAsyncGenerator, Yield af -> afield f_type env af; ()
331 | Ast.FGenerator, Yield_from e
332 | Ast.FAsyncGenerator, Yield_from e -> expr f_type env e; ()
333 (* Should never happen -- presence of yield should make us FGenerator or
334 * FAsyncGenerator. *)
335 | (Ast.FSync | Ast.FAsync), (Yield _ | Yield_from _ | Yield_break) -> assert false
337 | (Ast.FGenerator | Ast.FSync | Ast.FCoroutine), Await _ ->
338 found_await f_type p
340 | Ast.FAsync, Await _
341 | Ast.FAsyncGenerator, Await _ -> Errors.await_not_allowed p
343 | Ast.FCoroutine, (Yield _ | Yield_break | Yield_from _) ->
344 Errors.yield_in_coroutine p
345 | (Ast.FSync | Ast.FAsync | Ast.FGenerator | Ast.FAsyncGenerator), Suspend _ ->
346 Errors.suspend_outside_of_coroutine p
347 | Ast.FCoroutine, Suspend _ ->
348 if env.t_is_finally
349 then Errors.suspend_in_finally p
350 | _, Special_func func ->
351 (match func with
352 | Gena e
353 | Gen_array_rec e -> expr f_type env e
354 | Genva el -> List.iter el (expr f_type env));
356 | _, Xml (_, attrl, el) ->
357 List.iter attrl (fun attr -> expr f_type env (get_xhp_attr_expr attr));
358 List.iter el (expr f_type env);
360 | _, Unsafe_expr _ -> ()
361 | _, Callconv (_, e) ->
362 expr f_type env e;
364 | _, Execution_operator _ -> ()
365 | _, Assert (AE_assert e) ->
366 expr f_type env e;
368 | _, Shape fdm ->
369 List.iter ~f:(fun (_, v) -> expr f_type env v) fdm;
374 let is_magic =
375 let h = Caml.Hashtbl.create 23 in
376 let a x = Caml.Hashtbl.add h x true in
377 let _ = SSet.iter (fun m -> if m <> SN.Members.__toString then a m) SN.Members.as_set in
378 fun (_, s) ->
379 Caml.Hashtbl.mem h s
381 let is_parent e =
382 snd e = CIparent
384 let check_conditionally_reactive_annotation_params p params ~is_method =
385 match params with
386 | [_, Class_const (_, (_, prop))] when prop = "class" -> ()
387 | _ -> Errors.conditionally_reactive_annotation_invalid_arguments ~is_method p
389 let check_conditionally_reactive_annotations is_reactive p method_name user_attributes =
390 let rec check l seen =
391 match l with
392 | [] -> ()
393 | { ua_name = (_, name); ua_params } :: xs when name = SN.UserAttributes.uaOnlyRxIfImpl ->
394 begin
395 if seen
396 then Errors.multiple_conditionally_reactive_annotations p method_name
397 else if is_reactive
398 then check_conditionally_reactive_annotation_params ~is_method:true p ua_params;
399 check xs true
401 | _ :: xs -> check xs seen in
402 check user_attributes false
404 let is_some_reactivity_attribute { ua_name = (_, name); _ } =
405 name = SN.UserAttributes.uaReactive ||
406 name = SN.UserAttributes.uaLocalReactive ||
407 name = SN.UserAttributes.uaShallowReactive
409 (* During NastCheck, all reactivity kinds are the same *)
410 let fun_is_reactive user_attributes =
411 List.exists user_attributes ~f:is_some_reactivity_attribute
413 let rec fun_ tenv f named_body =
414 let env = { t_is_finally = false;
415 is_array_append_allowed = false;
416 class_name = None; class_kind = None;
417 imm_ctrl_ctx = Toplevel;
418 typedef_tparams = [];
419 tenv = tenv;
420 function_name = None;
421 is_reactive = fun_is_reactive f.f_user_attributes
422 } in
423 func env f named_body
425 and func env f named_body =
426 let p, fname = f.f_name in
427 let fname_lower = String.lowercase (strip_ns fname) in
428 if fname_lower = SN.Members.__construct || fname_lower = "using"
429 then Errors.illegal_function_name p fname;
430 (* Add type parameters to typing environment and localize the bounds *)
431 let tenv, constraints =
432 Phase.localize_generic_parameters_with_bounds env.tenv f.f_tparams
433 ~ety_env:(Phase.env_with_self env.tenv) in
434 let tenv = add_constraints p tenv constraints in
435 let env = { env with
436 tenv = Env.set_mode tenv f.f_mode;
437 t_is_finally = false;
438 is_reactive = env.is_reactive || fun_is_reactive f.f_user_attributes;
439 } in
440 maybe hint env f.f_ret;
441 (* Functions can't be mutable, only methods can *)
442 if Attributes.mem SN.UserAttributes.uaMutable f.f_user_attributes then
443 Errors.mutable_attribute_on_function p;
444 if Attributes.mem SN.UserAttributes.uaMaybeMutable f.f_user_attributes then
445 Errors.maybe_mutable_attribute_on_function p;
446 if Attributes.mem SN.UserAttributes.uaMutableReturn f.f_user_attributes
447 && not env.is_reactive then
448 Errors.mutable_return_annotated_decls_must_be_reactive "function" p fname;
450 check_maybe_rx_attributes_on_params env f.f_user_attributes f.f_params;
452 List.iter f.f_tparams (tparam env);
453 let byref = List.find f.f_params ~f:(fun x -> x.param_is_reference) in
454 List.iter f.f_params (fun_param env f.f_name f.f_fun_kind byref);
455 let inout = List.find f.f_params ~f:(
456 fun x -> x.param_callconv = Some Ast.Pinout) in
457 (match inout with
458 | Some param ->
459 if Attributes.mem SN.UserAttributes.uaMemoize f.f_user_attributes ||
460 Attributes.mem SN.UserAttributes.uaMemoizeLSB f.f_user_attributes
461 then Errors.inout_params_memoize p param.param_pos;
463 | _ -> ()
465 (match f.f_variadic with
466 | FVvariadicArg vparam ->
467 if vparam.param_is_reference then
468 Errors.variadic_byref_param vparam.param_pos
469 | _ -> ()
471 block env named_body.fb_ast;
472 CheckFunctionBody.start
473 f.f_fun_kind
475 named_body.fb_ast
477 and tparam env t =
478 List.iter t.tp_constraints (fun (_, h) -> hint env h)
480 and hint env (p, h) =
481 hint_ env p h
483 and hint_ env p = function
484 | Hany | Hmixed | Hnonnull | Hprim _ | Hthis | Haccess _ | Habstr _ | Hdynamic ->
486 | Harray (ty1, ty2) ->
487 maybe hint env ty1;
488 maybe hint env ty2
489 | Hdarray (ty1, ty2) ->
490 hint env ty1;
491 hint env ty2
492 | Hvarray_or_darray ty
493 | Hvarray ty ->
494 hint env ty
495 | Htuple hl -> List.iter hl (hint env)
496 | Hoption h ->
497 hint env h; ()
498 | Hfun (_, _, hl, _, _, variadic_hint, h, _) ->
499 List.iter hl (hint env);
500 hint env h;
501 begin match variadic_hint with
502 | Hvariadic (Some h) -> hint env h;
503 | Hvariadic (None) when Env.is_strict env.tenv ->
504 Errors.ellipsis_strict_mode ~require:`Type p;
505 | _ -> ()
507 | Happly ((_, x), hl) as h when Env.is_typedef x ->
508 begin match Typing_lazy_heap.get_typedef (Env.get_tcopt env.tenv) x with
509 | Some _ ->
510 check_happly env.typedef_tparams env.tenv (p, h);
511 List.iter hl (hint env)
512 | None -> ()
514 | Happly ((_, x), hl) as h ->
515 (match Env.get_class env.tenv x with
516 | None -> ()
517 | Some _ ->
518 check_happly env.typedef_tparams env.tenv (p, h);
519 List.iter hl (hint env)
522 | Hshape { nsi_allows_unknown_fields=_; nsi_field_map } ->
523 let compute_hint_for_shape_field_info _ { sfi_hint; _; } =
524 hint env sfi_hint in
526 ShapeMap.iter compute_hint_for_shape_field_info nsi_field_map
527 | Hsoft h ->
528 hint env h; ()
529 | Hreified h ->
530 hint env h; ()
532 and check_happly unchecked_tparams env h =
533 let env = { env with Env.pos = (fst h) } in
534 let decl_ty = Decl_hint.hint env.Env.decl_env h in
535 let unchecked_tparams =
536 List.map unchecked_tparams begin fun t ->
537 let cstrl = List.map t.tp_constraints (fun (ck, cstr) ->
538 let cstr = Decl_hint.hint env.Env.decl_env cstr in
539 (ck, cstr)) in
541 Typing_defs.tp_variance = t.tp_variance;
542 tp_name = t.tp_name;
543 tp_constraints = cstrl;
544 tp_reified = t.tp_reified;
545 tp_user_attributes = t.tp_user_attributes;
547 end in
548 let tyl = List.map unchecked_tparams (fun t -> Reason.Rwitness (fst t.tp_name), Tany) in
549 let subst = Inst.make_subst unchecked_tparams tyl in
550 let decl_ty = Inst.instantiate subst decl_ty in
551 match decl_ty with
552 | _, Tapply (_, tyl) when tyl <> [] ->
553 let env, locl_ty = Phase.localize_with_self env decl_ty in
554 begin match TUtils.get_base_type env locl_ty with
555 | _, Tclass (cls, _, tyl) ->
556 (match Env.get_class env (snd cls) with
557 | Some cls ->
558 let tc_tparams = Cls.tparams cls in
559 (* We want to instantiate the class type parameters with the
560 * type list of the class we are localizing. We do not want to
561 * add any more constraints when we localize the constraints
562 * stored in the class_type since it may lead to infinite
563 * recursion
565 let ety_env =
566 { (Phase.env_with_self env) with
567 substs = Subst.make tc_tparams tyl;
568 } in
569 iter2_shortest begin fun { tp_name = (p, x); tp_constraints = cstrl; _ } ty ->
570 List.iter cstrl (fun (ck, cstr_ty) ->
571 let r = Reason.Rwitness p in
572 let env, cstr_ty = Phase.localize ~ety_env env cstr_ty in
573 ignore @@ Errors.try_
574 (fun () ->
575 TGenConstraint.check_constraint env ck ty ~cstr_ty
577 (fun l ->
578 Reason.explain_generic_constraint env.Env.pos r x l;
581 end tc_tparams tyl
582 | _ -> ()
584 | _ -> ()
586 | _ -> ()
588 and class_ tenv c =
589 let cname = Some (snd c.c_name) in
590 let env = { t_is_finally = false;
591 is_array_append_allowed = false;
592 class_name = cname;
593 class_kind = Some c.c_kind;
594 imm_ctrl_ctx = Toplevel;
595 typedef_tparams = [];
596 is_reactive = false;
597 function_name = None;
598 tenv = tenv } in
599 (* Add type parameters to typing environment and localize the bounds *)
600 let tenv, constraints = Phase.localize_generic_parameters_with_bounds
601 tenv c.c_tparams.c_tparam_list
602 ~ety_env:(Phase.env_with_self tenv) in
603 let tenv = add_constraints (fst c.c_name) tenv constraints in
604 let env = { env with tenv = Env.set_mode tenv c.c_mode } in
606 (* Const handling:
607 * prevent for abstract final classes, traits, and interfaces
609 if Attributes.mem SN.UserAttributes.uaConst c.c_user_attributes
610 then begin match c.c_kind, c.c_final with
611 | Ast.Cabstract, true
612 | Ast.Cinterface, _
613 | Ast.Ctrait, _
614 | Ast.Cenum, _ ->
615 Errors.const_attribute_prohibited
616 (fst c.c_name) (Typing_print.class_kind c.c_kind c.c_final);
617 | Ast.Cabstract, false
618 | Ast.Cnormal, _ -> ();
619 end;
620 if c.c_kind = Ast.Cabstract && c.c_final then begin
621 List.iter c.c_methods (fun m -> Errors.nonstatic_method_in_abstract_final_class (fst m.m_name));
622 Option.iter c.c_constructor
623 (fun m -> Errors.nonstatic_method_in_abstract_final_class (fst m.m_name))
624 end;
626 if c.c_kind = Ast.Cinterface then begin
627 interface c;
629 else begin
630 maybe method_ (env, true) c.c_constructor;
631 end;
632 List.iter c.c_tparams.c_tparam_list (tparam env);
633 List.iter c.c_extends (hint env);
634 List.iter c.c_implements (hint env);
635 List.iter c.c_consts (class_const env);
636 List.iter c.c_typeconsts (typeconst (env, c.c_tparams.c_tparam_list));
637 List.iter c.c_static_vars (class_var env);
638 List.iter c.c_vars (class_var env);
639 List.iter c.c_static_methods (method_ (env, true));
640 List.iter c.c_methods (method_ (env, false));
641 List.iter c.c_implements (check_is_interface (env, "implement"));
642 List.iter c.c_req_implements
643 (check_is_interface (env, "require implementation of"));
644 List.iter c.c_req_extends (check_is_class env);
645 List.iter c.c_uses (check_is_trait env);
647 (** Make sure that the given hint points to an interface *)
648 and check_is_interface (env, error_verb) (x : hint) =
649 match (snd x) with
650 | Happly (id, _) ->
651 (match Env.get_class env.tenv (snd id) with
652 | None ->
653 (* in partial mode, we can fail to find the class if it's
654 defined in PHP. *)
655 (* in strict mode, we catch the unknown class error before
656 even reaching here. *)
658 | Some cls when Cls.kind cls = Ast.Cinterface -> ()
659 | Some cls ->
660 Errors.non_interface (fst x) (Cls.name cls) error_verb
662 | Habstr _ ->
663 Errors.non_interface (fst x) "generic" error_verb
664 | _ ->
665 Errors.non_interface (fst x) "invalid type hint" error_verb
667 (** Make sure that the given hint points to a non-final class *)
668 and check_is_class env (x : hint) =
669 match (snd x) with
670 | Happly (id, _) ->
671 (match Env.get_class env.tenv (snd id) with
672 | None ->
673 (* in partial mode, we can fail to find the class if it's
674 defined in PHP. *)
675 (* in strict mode, we catch the unknown class error before
676 even reaching here. *)
678 | Some cls ->
679 let kind = Cls.kind cls in
680 let name = Cls.name cls in
681 match kind with
682 | Ast.(Cabstract | Cnormal) ->
683 if Cls.final cls then Errors.requires_final_class (fst x) name
684 | _ ->
685 Errors.requires_non_class (fst x) name (Ast.string_of_class_kind kind)
687 | Habstr name ->
688 Errors.requires_non_class (fst x) name "a generic"
689 | _ ->
690 Errors.requires_non_class (fst x) "This" "an invalid type hint"
693 * Make sure that all "use"s are with traits, and not
694 * classes, interfaces, etc.
696 and check_is_trait env (h : hint) =
697 (* Second part of a hint contains Happly information *)
698 (match (snd h) with
699 (* An Happly contains identifying info (sid) and hint list (which we *)
700 (* do not care about at this time *)
701 | Happly (pos_and_name, _) ->
702 (* Env.get_class will get the type info associated with the name *)
703 let type_info = Env.get_class env.tenv (snd pos_and_name) in
704 (match type_info with
705 (* in partial mode, it's possible to not find the trait, because the *)
706 (* trait may live in PHP land. In strict mode, we catch the unknown *)
707 (* trait error before even reaching here. so it's ok to just return *)
708 (* unit. *)
709 | None -> ()
710 (* tc_kind is part of the type_info. If we are a trait, all is good *)
711 | Some cls when Cls.kind cls = Ast.Ctrait -> ()
712 (* Anything other than a trait we are going to throw an error *)
713 (* using the tc_kind and tc_name fields of our type_info *)
714 | Some cls ->
715 let name = Cls.name cls in
716 let kind = Cls.kind cls in
717 Errors.uses_non_trait (fst h) name (Ast.string_of_class_kind kind)
719 | _ -> failwith "assertion failure: trait isn't an Happly"
722 (* Class properties can only be initialized with a static literal expression. *)
723 and check_class_property_initialization prop =
724 (* Only do the check if property is initialized. *)
725 Option.iter prop.cv_expr ~f:begin fun e ->
726 let rec rec_assert_static_literal e =
727 match (snd e) with
728 | Collection _
729 | Import _
730 | Lfun _
731 | NewAnonClass _
732 | Omitted
733 | BracedExpr _
734 | ParenthesizedExpr _ -> failwith "AST should not contain these nodes after naming"
735 | Any | Typename _
736 | Id _ | Class_const _ | True | False | Int _ | Float _
737 | Null | String _ | PrefixedString _ | Unsafe_expr _
738 | Execution_operator _ ->
740 | Array field_list ->
741 List.iter field_list begin function
742 | AFvalue expr -> rec_assert_static_literal expr
743 | AFkvalue (expr1, expr2) ->
744 rec_assert_static_literal expr1;
745 rec_assert_static_literal expr2;
747 | Darray fl -> List.iter fl assert_static_literal_for_field_list
748 | Varray el -> List.iter el rec_assert_static_literal
749 | Shape fl -> List.iter ~f:(fun (_, e) -> rec_assert_static_literal e) fl
750 | List el
751 | Expr_list el
752 | String2 el
753 | ValCollection (_, el) -> List.iter el rec_assert_static_literal
754 | Pair (expr1, expr2)
755 | Binop (_, expr1, expr2) ->
756 rec_assert_static_literal expr1;
757 rec_assert_static_literal expr2;
758 | KeyValCollection (_, field_list) ->
759 List.iter field_list assert_static_literal_for_field_list
760 | Cast (_, e)
761 | Unop (_, e) ->
762 rec_assert_static_literal e;
763 | Eif (expr1, optional_expr, expr2) ->
764 rec_assert_static_literal expr1;
765 Option.iter optional_expr rec_assert_static_literal;
766 rec_assert_static_literal expr2;
767 | This | Lvar _ | ImmutableVar _ | Lplaceholder _ | Dollardollar _ | Fun_id _
768 | Method_id _
769 | Method_caller _ | Smethod_id _ | Obj_get _ | Array_get _ | Class_get _
770 | Call _ | Special_func _ | Yield_break | Yield _ | Yield_from _ | Suspend _
771 | Await _ | InstanceOf _ | Is _ | New _ | Efun _ | Xml _ | Callconv _
772 | Assert _ | Clone _ | As _ | Pipe _ ->
773 Errors.class_property_only_static_literal (fst e)
774 and assert_static_literal_for_field_list (expr1, expr2) =
775 rec_assert_static_literal expr1;
776 rec_assert_static_literal expr2
778 rec_assert_static_literal e;
781 and interface c =
782 let enforce_no_body = begin fun m ->
783 match m.m_body.fb_ast with
784 | [] ->
785 if m.m_visibility = Private
786 then Errors.not_public_or_protected_interface (fst m.m_name)
787 else ()
788 | _ -> Errors.abstract_body (fst m.m_name)
789 end in
790 (* make sure that interface methods are not async, in line with HHVM *)
791 let enforce_not_async = begin fun m ->
792 match m.m_fun_kind with
793 | Ast.FAsync -> Errors.async_in_interface (fst m.m_name)
794 | Ast.FAsyncGenerator -> Errors.async_in_interface (fst m.m_name)
795 | _ -> ()
796 end in
797 (* make sure that interfaces only have empty public methods *)
798 List.iter (c.c_static_methods @ c.c_methods) enforce_no_body;
799 List.iter (c.c_static_methods @ c.c_methods) enforce_not_async;
800 (* make sure constructor has no body *)
801 Option.iter c.c_constructor enforce_no_body;
802 Option.iter c.c_constructor enforce_not_async;
803 List.iter (c.c_uses) (fun (p, _) ->
804 Errors.interface_use_trait p
806 (* make sure that interfaces don't have any member variables *)
807 match c.c_vars with
808 | hd::_ ->
809 let pos = fst (hd.cv_id) in
810 Errors.interface_with_member_variable pos
811 | _ -> ();
812 (* make sure that interfaces don't have static variables *)
813 match c.c_static_vars with
814 | hd::_ ->
815 let pos = fst (hd.cv_id) in
816 Errors.interface_with_static_member_variable pos
817 | _ -> ();
818 (* make sure interfaces do not contain partially abstract type constants *)
819 List.iter c.c_typeconsts begin fun tc ->
820 if tc.c_tconst_constraint <> None && tc.c_tconst_type <> None then
821 Errors.interface_with_partial_typeconst (fst tc.c_tconst_name)
824 and class_const env (h, _, e) =
825 maybe hint env h;
826 maybe expr env e;
829 and typeconst (env, class_tparams) tconst =
830 maybe hint env tconst.c_tconst_type;
831 maybe hint env tconst.c_tconst_constraint;
832 (* need to ensure that tconst.c_tconst_type is not Habstr *)
833 maybe check_no_class_tparams class_tparams tconst.c_tconst_type;
834 maybe check_no_class_tparams class_tparams tconst.c_tconst_constraint
836 (* Check to make sure we are not using class type params for type const decls *)
837 and check_no_class_tparams class_tparams (pos, ty) =
838 let check_tparams = check_no_class_tparams class_tparams in
839 let maybe_check_tparams = maybe check_no_class_tparams class_tparams in
840 let matches_class_tparam tp_name =
841 List.iter class_tparams begin fun { tp_name = (c_tp_pos, c_tp_name); _ } ->
842 if c_tp_name = tp_name
843 then Errors.typeconst_depends_on_external_tparam pos c_tp_pos c_tp_name
844 end in
845 match ty with
846 | Hany | Hmixed | Hnonnull | Hprim _ | Hthis | Hdynamic -> ()
847 (* We have found a type parameter. Make sure its name does not match
848 * a name in class_tparams *)
849 | Habstr tparam_name ->
850 matches_class_tparam tparam_name
851 | Harray (ty1, ty2) ->
852 maybe_check_tparams ty1;
853 maybe_check_tparams ty2
854 | Hdarray (ty1, ty2) ->
855 check_tparams ty1;
856 check_tparams ty2
857 | Hvarray_or_darray ty
858 | Hvarray ty ->
859 check_tparams ty
860 | Htuple tyl -> List.iter tyl check_tparams
861 | Hoption ty_ -> check_tparams ty_
862 | Hfun (_, _, tyl, _, _, _, ty_, _) ->
863 List.iter tyl check_tparams;
864 check_tparams ty_
865 | Happly (_, tyl) -> List.iter tyl check_tparams
866 | Hshape { nsi_allows_unknown_fields=_; nsi_field_map } ->
867 ShapeMap.iter (fun _ v -> check_tparams v.sfi_hint) nsi_field_map
868 | Haccess (root_ty, _) ->
869 check_tparams root_ty
870 | Hsoft ty_ -> check_tparams ty_
871 | Hreified ty_ -> check_tparams ty_
873 and class_var env cv =
874 check_class_property_initialization cv;
875 let hint_env =
876 (* If this is an XHP attribute and we're in strict mode,
877 relax to partial mode to allow the use of generic
878 classes without specifying type parameters. This is
879 a temporary hack to support existing code for now. *)
880 (* Task #5815945: Get rid of this Hack *)
881 if cv.cv_is_xhp && (Typing_env.is_strict env.tenv)
882 then { env with tenv = Typing_env.set_mode env.tenv FileInfo.Mpartial }
883 else env in
884 maybe hint hint_env cv.cv_type;
885 maybe expr env cv.cv_expr;
888 and check__toString m is_static =
889 if snd m.m_name = SN.Members.__toString
890 then begin
891 if m.m_visibility <> Public || is_static
892 then Errors.toString_visibility (fst m.m_name);
893 match m.m_ret with
894 | Some (_, Hprim Tstring) -> ()
895 | Some (p, _) -> Errors.toString_returns_string p
896 | None -> ()
899 and add_constraint pos tenv (ty1, ck, ty2) =
900 Typing_subtype.add_constraint pos tenv ck ty1 ty2
902 and add_constraints pos tenv (cstrs: locl where_constraint list) =
903 List.fold_left cstrs ~init:tenv ~f:(add_constraint pos)
905 and check_static_memoized_function m =
906 if Attributes.mem SN.UserAttributes.uaMemoize m.m_user_attributes ||
907 Attributes.mem SN.UserAttributes.uaMemoizeLSB m.m_user_attributes then
908 Errors.static_memoized_function (fst m.m_name);
911 and method_ (env, is_static) m =
912 let env =
913 { env with is_reactive = fun_is_reactive m.m_user_attributes } in
914 let named_body = assert_named_body m.m_body in
915 check__toString m is_static;
916 let env = { env with function_name = Some (snd m.m_name) } in
917 let p, name = m.m_name in
918 (* Add method type parameters to environment and localize the bounds *)
919 let tenv, constraints =
920 Phase.localize_generic_parameters_with_bounds env.tenv m.m_tparams
921 ~ety_env:(Phase.env_with_self env.tenv) in
922 let tenv = add_constraints (fst m.m_name) tenv constraints in
923 let env = { env with tenv = tenv } in
925 (* If this is a destructor make sure it is allowed *)
926 if name = SN.Members.__destruct
927 && not (Attributes.mem SN.UserAttributes.uaOptionalDestruct m.m_user_attributes)
928 then Errors.illegal_destructor p;
930 let is_mutable =
931 Attributes.mem SN.UserAttributes.uaMutable m.m_user_attributes in
933 let is_maybe_mutable =
934 Attributes.mem SN.UserAttributes.uaMaybeMutable m.m_user_attributes in
936 (* Mutable methods must be reactive *)
937 if not env.is_reactive then begin
938 if is_mutable
939 then Errors.mutable_methods_must_be_reactive p name;
940 if is_maybe_mutable
941 then Errors.maybe_mutable_methods_must_be_reactive p name;
942 end;
943 if is_mutable
944 then begin
945 if is_maybe_mutable
946 then Errors.conflicting_mutable_and_maybe_mutable_attributes p;
947 end;
949 (*Methods annotated with MutableReturn attribute must be reactive *)
950 if Attributes.mem SN.UserAttributes.uaMutableReturn m.m_user_attributes
951 && not env.is_reactive then
952 Errors.mutable_return_annotated_decls_must_be_reactive "method" p name;
954 check_conditionally_reactive_annotations env.is_reactive p name m.m_user_attributes;
955 check_maybe_rx_attributes_on_params env m.m_user_attributes m.m_params;
957 let byref = List.find m.m_params ~f:(fun x -> x.param_is_reference) in
958 List.iter m.m_params (fun_param env m.m_name m.m_fun_kind byref);
959 let inout = List.find m.m_params ~f:(
960 fun x -> x.param_callconv = Some Ast.Pinout) in
961 (match inout with
962 | Some param ->
963 if Attributes.mem SN.UserAttributes.uaMemoize m.m_user_attributes ||
964 Attributes.mem SN.UserAttributes.uaMemoizeLSB m.m_user_attributes
965 then Errors.inout_params_memoize p param.param_pos;
967 | _ -> ()
969 (match m.m_variadic with
970 | FVvariadicArg vparam ->
971 if vparam.param_is_reference then
972 Errors.variadic_byref_param vparam.param_pos
973 | _ -> ()
975 List.iter m.m_tparams (tparam env);
976 block env named_body.fb_ast;
977 maybe hint env m.m_ret;
978 CheckFunctionBody.start
979 m.m_fun_kind
981 named_body.fb_ast;
982 (match env.class_name with
983 | Some cname ->
984 let p, mname = m.m_name in
985 if String.lowercase (strip_ns cname) = String.lowercase mname
986 && env.class_kind <> Some Ast.Ctrait
987 then Errors.dangerous_method_name p
988 else ()
989 | None -> assert false)
991 and check_maybe_rx_attributes_on_params env parent_attrs params =
992 let parent_only_rx_if_args =
993 Attributes.find SN.UserAttributes.uaAtMostRxAsArgs parent_attrs in
994 let check_param seen_atmost_rx_as_rxfunc p =
995 let only_rx_if_rxfunc_attr =
996 Attributes.find SN.UserAttributes.uaAtMostRxAsFunc p.param_user_attributes in
997 let only_rx_if_impl_attr =
998 Attributes.find SN.UserAttributes.uaOnlyRxIfImpl p.param_user_attributes in
999 match only_rx_if_rxfunc_attr, only_rx_if_impl_attr with
1000 | Some { ua_name = (p, _); _ }, _ ->
1001 if parent_only_rx_if_args = None || not env.is_reactive
1002 then Errors.atmost_rx_as_rxfunc_invalid_location p;
1003 true
1004 | _, Some { ua_name = (p, _); ua_params; _ } ->
1005 if parent_only_rx_if_args = None || not env.is_reactive
1006 then Errors.atmost_rx_as_rxfunc_invalid_location p
1007 else check_conditionally_reactive_annotation_params ~is_method:false p ua_params;
1008 true
1009 | _ -> seen_atmost_rx_as_rxfunc in
1010 let has_param_with_atmost_rx_as_rxfunc =
1011 List.fold_left params ~init:false ~f:check_param in
1012 match parent_only_rx_if_args, has_param_with_atmost_rx_as_rxfunc with
1013 | Some { ua_name = (p, _); _ }, false ->
1014 Errors.no_atmost_rx_as_rxfunc_for_rx_if_args p
1015 | _ -> ()
1017 and param_is_mutable p =
1018 Attributes.mem SN.UserAttributes.uaMutable p.param_user_attributes
1020 and param_is_maybe_mutable p =
1021 Attributes.mem SN.UserAttributes.uaMaybeMutable p.param_user_attributes
1023 and fun_param env (_pos, name) f_type byref param =
1024 maybe hint env param.param_hint;
1025 maybe expr env param.param_expr;
1026 let is_mutable = param_is_mutable param in
1027 let is_maybe_mutable = param_is_maybe_mutable param in
1028 if not env.is_reactive then begin
1029 if is_mutable
1030 then Errors.mutable_methods_must_be_reactive param.param_pos name;
1031 if is_maybe_mutable
1032 then Errors.maybe_mutable_methods_must_be_reactive param.param_pos name;
1033 end;
1035 match param.param_callconv with
1036 | None -> ()
1037 | Some Ast.Pinout ->
1038 let pos = param.param_pos in
1039 if f_type <> Ast.FSync then Errors.inout_params_outside_of_sync pos;
1040 if SSet.mem name SN.Members.as_set then Errors.inout_params_special pos;
1041 Option.iter byref ~f:(fun param ->
1042 Errors.inout_params_mix_byref pos param.param_pos);
1045 and stmt env = function
1046 | Return (p, _) when env.t_is_finally ->
1047 Errors.return_in_finally p; ()
1048 | Return (_, None)
1049 | GotoLabel _
1050 | Goto _
1051 | Noop
1052 | Unsafe_block _
1053 | Fallthrough -> ()
1054 | Break p -> begin
1055 match env.imm_ctrl_ctx with
1056 | Toplevel -> Errors.toplevel_break p
1057 | _ -> ()
1059 | Continue p -> begin
1060 match env.imm_ctrl_ctx with
1061 | Toplevel -> Errors.toplevel_continue p
1062 | SwitchContext -> Errors.continue_in_switch p
1063 | LoopContext -> ()
1065 | Return (_, Some e)
1066 | Expr e | Throw (_, e) ->
1067 expr env e
1068 | Static_var _ ->
1070 | Global_var _ ->
1072 | Awaitall (_, el) ->
1073 List.iter el (fun (x, y) ->
1074 (match x with
1075 | Some x -> expr env x
1076 | None -> ());
1077 expr env y;
1080 | If (e, b1, b2) ->
1081 expr env e;
1082 block env b1;
1083 block env b2;
1085 | Do (b, e) ->
1086 block { env with imm_ctrl_ctx = LoopContext } b;
1087 expr env e;
1089 | While (e, b) ->
1090 expr env e;
1091 block { env with imm_ctrl_ctx = LoopContext } b;
1093 | Using { us_expr = e; us_block = b; _ } ->
1094 expr env e;
1095 block env b;
1097 | For (e1, e2, e3, b) ->
1098 expr env e1;
1099 expr env e2;
1100 expr env e3;
1101 block { env with imm_ctrl_ctx = LoopContext } b;
1103 | Switch (e, cl) ->
1104 expr env e;
1105 List.iter cl (case { env with imm_ctrl_ctx = SwitchContext });
1107 | Foreach (e1, ae, b) ->
1108 expr env e1;
1109 as_expr env ae;
1110 block { env with imm_ctrl_ctx = LoopContext } b;
1112 | Try (b, cl, fb) ->
1113 block env b;
1114 List.iter cl (catch env);
1115 block { env with t_is_finally = true } fb;
1117 | Def_inline _ -> ()
1118 | Let ((p, x), _, e) ->
1119 (* We treat let statement as assignment expresssions *)
1120 let fake_expr = (p, Binop (Ast.Eq None, (p, Lvar (p, x)), e)) in
1121 expr env fake_expr;
1123 | Block b -> block env b;
1124 | Markup (_, eopt) -> (match eopt with Some e -> expr env e | None -> ())
1125 | Declare (_, e, b) ->
1126 expr env e;
1127 block env b;
1129 and as_expr env = function
1130 | As_v e
1131 | Await_as_v (_, e) -> expr env e
1132 | As_kv (e1, e2)
1133 | Await_as_kv (_, e1, e2) ->
1134 expr env e1;
1135 expr env e2;
1138 and afield env = function
1139 | AFvalue e -> expr env e
1140 | AFkvalue (e1, e2) -> expr env e1; expr env e2;
1142 and block env stl =
1143 List.iter stl (stmt env)
1145 and expr env (p, e) =
1146 expr_ env p e
1148 and expr_ env p = function
1149 | Collection _
1150 | Import _
1151 | Lfun _
1152 | NewAnonClass _
1153 | Omitted
1154 | BracedExpr _
1155 | ParenthesizedExpr _ -> failwith "AST should not contain these nodes after naming"
1156 | Any
1157 | Fun_id _
1158 | Method_id _
1159 | Smethod_id _
1160 | Method_caller _
1161 | This
1162 | Typename _
1163 | Lvar _
1164 | ImmutableVar _
1165 | Lplaceholder _
1166 | Dollardollar _
1167 | Unsafe_expr _ -> ()
1168 | Class_const (cid, ((_, m_name) as mid)) ->
1169 let func_name = env.function_name in
1170 if is_magic mid &&
1171 (not(is_parent cid) || func_name <> Some m_name)
1172 then Errors.magic mid;
1174 | Pipe (_, e1, e2) ->
1175 expr env e1;
1176 expr env e2
1177 | Class_get _ ->
1179 (* Check that __CLASS__ and __TRAIT__ are used appropriately *)
1180 | Id (pos, const) ->
1181 if SN.PseudoConsts.is_pseudo_const const then
1182 if const = SN.PseudoConsts.g__CLASS__ then
1183 (match env.class_kind with
1184 | Some _ -> ()
1185 | _ -> Errors.illegal_CLASS pos)
1186 else if const = SN.PseudoConsts.g__TRAIT__ then
1187 (match env.class_kind with
1188 | Some Ast.Ctrait -> ()
1189 | _ -> Errors.illegal_TRAIT pos);
1191 | Array afl ->
1192 List.iter afl (afield env);
1194 | Darray fdl ->
1195 List.iter fdl (field env);
1197 | Varray el ->
1198 List.iter el (expr env);
1200 | ValCollection (_, el) ->
1201 List.iter el (expr env);
1203 | KeyValCollection (_, fdl) ->
1204 List.iter fdl (field env);
1206 | Clone e -> expr env e; ()
1207 | Obj_get (e, (_, Id s), _) ->
1208 if is_magic s
1209 then Errors.magic s;
1210 let env' = {env with is_array_append_allowed = false} in
1211 expr env' e;
1213 | Obj_get (e1, e2, _) ->
1214 let env' = {env with is_array_append_allowed = false} in
1215 expr env' e1;
1216 expr env' e2;
1218 | Array_get ((p, _), None) when not env.is_array_append_allowed ->
1219 Errors.reading_from_append p;
1221 | Array_get (e, eopt) ->
1222 let env' = {env with is_array_append_allowed = false} in
1223 expr env' e;
1224 maybe expr env' eopt;
1226 | Call (_, e, _, el, uel) ->
1227 expr env e;
1228 List.iter el (expr env);
1229 List.iter uel (expr env);
1231 | True | False | Int _
1232 | Float _ | Null | String _ | PrefixedString _ -> ()
1233 | String2 el ->
1234 List.iter el (expr env);
1236 | Unop (Ast.Uref, e) ->
1237 expr env e;
1238 begin match snd e with
1239 | This ->
1240 Errors.illegal_by_ref_expr p SN.SpecialIdents.this
1241 | Dollardollar (_, id)
1242 when Local_id.to_string id = SN.SpecialIdents.dollardollar ->
1243 Errors.illegal_by_ref_expr p SN.SpecialIdents.dollardollar
1244 | _ -> ()
1246 | Unop (_, e) -> expr env e;
1247 | Yield_break -> ()
1248 | Special_func func ->
1249 (match func with
1250 | Gena e
1251 | Gen_array_rec e ->
1252 expr env e
1253 | Genva el ->
1254 List.iter el (expr env));
1256 | Yield e ->
1257 afield env e;
1259 | Yield_from e ->
1260 expr env e;
1262 | Await e ->
1263 expr env e;
1265 | Suspend e ->
1266 expr env e;
1268 | List el ->
1269 List.iter el (expr env);
1271 | Pair (e1, e2) ->
1272 expr env e1;
1273 expr env e2;
1275 | Expr_list el ->
1276 List.iter el (expr env);
1278 | Cast (h, e) ->
1279 hint env h;
1280 expr env e;
1282 | Binop (op, e1, e2) ->
1283 let lvalue_env = match op with
1284 | Ast.Eq _ -> { env with is_array_append_allowed = true }
1285 | _ -> env in
1286 expr lvalue_env e1;
1287 expr env e2;
1289 | Eif (e1, None, e3) ->
1290 expr env e1;
1291 expr env e3;
1293 | Eif (e1, Some e2, e3) ->
1294 expr env e1;
1295 expr env e2;
1296 expr env e3;
1298 | Assert (AE_assert e) ->
1299 expr env e;
1301 | InstanceOf (e, e2) ->
1302 (match e2 with
1303 | _, CIexpr (_, Class_const ((_, CI (_, classname)), (p, "class"))) ->
1304 Errors.classname_const_instanceof (Utils.strip_ns classname) p;
1305 | _ -> ());
1306 expr env e;
1308 | Is (e, h)
1309 | As (e, h, _)->
1310 expr env e;
1311 hint env h;
1313 | New (_, _, el, uel, _) ->
1314 List.iter el (expr env);
1315 List.iter uel (expr env);
1317 | Efun (f, _) ->
1318 let env = { env with imm_ctrl_ctx = Toplevel } in
1319 let body = Nast.assert_named_body f.f_body in
1320 func env f body; ()
1321 | Xml (_, attrl, el) ->
1322 List.iter attrl (fun attr -> expr env (get_xhp_attr_expr attr));
1323 List.iter el (expr env);
1325 | Callconv (_, e) ->
1326 expr env e;
1327 let rec aux = function
1328 | _, Lvar _ -> true
1329 | _, Array_get (e1, Some _) -> aux e1
1330 | _ -> false
1332 if not (aux e) then Errors.inout_argument_bad_expr (fst e);
1334 | Execution_operator _ -> ()
1335 | Shape fdm ->
1336 List.iter ~f:(fun (_, v) -> expr env v) fdm
1338 and case env = function
1339 | Default b -> block env b
1340 | Case (e, b) ->
1341 expr env e;
1342 block env b;
1345 and catch env (_, _, b) = block env b
1346 and field env (e1, e2) =
1347 expr env e1;
1348 expr env e2;
1351 let typedef tenv t =
1352 let env = { t_is_finally = false;
1353 is_array_append_allowed = false;
1354 class_name = None; class_kind = None;
1355 imm_ctrl_ctx = Toplevel;
1356 function_name = None;
1357 (* Since typedefs cannot have constraints we shouldn't check
1358 * if its type params satisfy the constraints of any tapply it
1359 * references.
1361 typedef_tparams = t.t_tparams;
1362 tenv = tenv;
1363 is_reactive = false
1364 } in
1365 maybe hint env t.t_constraint;
1366 hint env t.t_kind