2 * Copyright (c) 2018, Facebook, Inc.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
14 module Reason
= Typing_reason
16 let check_valid_rvalue pos env ty
=
17 let rec iter_over_types env tyl
=
21 let (env
, ety
) = Env.expand_type env ty
in
23 | (r
, Tprim Tnoreturn
) ->
24 Typing_error_utils.add_typing_error
25 ~env
:(Tast_env.tast_env_as_typing_env env
)
28 @@ Primary.Wellformedness.Noreturn_usage
34 "A `noreturn` function always throws or exits."
39 Typing_error_utils.add_typing_error
40 ~env
:(Tast_env.tast_env_as_typing_env env
)
43 @@ Primary.Wellformedness.Void_usage
49 "A `void` function doesn't return a value."
53 | (_
, Tunion tyl2
) -> iter_over_types env
(tyl2
@ tyl
)
54 | (_
, _
) -> iter_over_types env tyl
)
56 ignore
(iter_over_types env
[ty
])
60 inherit [_
] Aast.iter
as super
62 val non_returning_allowed
= ref true
64 method allow_non_returning f
=
65 let is_non_returning_allowed = !non_returning_allowed
in
66 non_returning_allowed
:= true;
68 non_returning_allowed
:= is_non_returning_allowed
70 method disallow_non_returning f
=
71 let is_non_returning_allowed = !non_returning_allowed
in
72 non_returning_allowed
:= false;
74 non_returning_allowed
:= is_non_returning_allowed
76 method! on_expr env
((ty
, p
, e
) as te
) =
78 | Binop
{ bop
= Ast_defs.Eq None
; lhs
; rhs
} ->
79 this#allow_non_returning
(fun () -> this#on_expr env lhs
);
80 this#disallow_non_returning
(fun () -> this#on_expr env rhs
)
82 this#disallow_non_returning
(fun () -> this#on_expr env e1
);
83 Option.iter e2 ~f
:(this#on_expr env
);
86 this#disallow_non_returning
(fun () -> this#on_expr env e1
);
88 | List el
-> List.iter el ~f
:(this#on_expr env
)
90 (* ReadonlyExprs can be immediately surrounding a void thing,
91 but the thing inside the expression should be checked for void *)
92 this#disallow_non_returning
(fun () -> super#on_expr env r
)
93 | ExpressionTree
{ et_class
; et_runtime_expr
} ->
94 this#on_id env et_class
;
96 (* Allow calls to void functions at the top level:
100 but not in subexpressions:
102 Code`() ==> { $x = void_func(); }`
104 this#on_expr env et_runtime_expr
106 if not
!non_returning_allowed
then check_valid_rvalue p env ty
;
107 this#disallow_non_returning
(fun () -> super#on_expr env te
)
109 method! on_stmt env stmt
=
111 | Expr e
-> this#allow_non_returning
(fun () -> this#on_expr env e
)
112 | Return
(Some
(_
, _
, Hole
(e
, _
, _
, _
)))
114 this#allow_non_returning
(fun () -> this#on_expr env e
)
115 | For
(e1
, e2
, e3
, b
) ->
116 this#allow_non_returning
(fun () -> List.iter ~f
:(this#on_expr env
) e1
);
117 this#disallow_non_returning
(fun () ->
118 Option.iter ~f
:(this#on_expr env
) e2
);
119 this#allow_non_returning
(fun () -> List.iter ~f
:(this#on_expr env
) e3
);
121 | Foreach
(e1
, e2
, b
) ->
122 this#disallow_non_returning
(fun () -> this#on_expr env e1
);
123 this#allow_non_returning
(fun () -> this#on_as_expr env e2
);
126 this#allow_non_returning
(fun () -> super#on_stmt env stmt
)
127 | _
-> this#disallow_non_returning
(fun () -> super#on_stmt env stmt
)
129 method! on_block env block
=
130 this#allow_non_returning
(fun () -> super#on_block env block
)
135 inherit Tast_visitor.handler_base
137 method! at_stmt
= visitor#on_stmt