Skip to content

Commit

Permalink
[flow][match] Fix analysis of guards that always throw
Browse files Browse the repository at this point in the history
Summary:
Guards conditionaly execute (if the pattern matches), so these should be treated as conditional throws, rather than unconditional ones.

Changelog: [internal]

Reviewed By: SamChou19815

Differential Revision: D67152450

fbshipit-source-id: db1cbe89202d5c9006864c4f2296d0bff36770ba
  • Loading branch information
gkz authored and facebook-github-bot committed Dec 13, 2024
1 parent 2e05885 commit a87d923
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 10 deletions.
6 changes: 4 additions & 2 deletions src/analysis/env_builder/name_resolver.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2927,9 +2927,11 @@ module Make (Context : C) (FlowAPIUtils : F with type cx = Context.t) :
bindings
(fun () ->
ignore @@ this#match_pattern pattern;
Base.Option.iter guard ~f:(fun guard -> ignore @@ this#expression guard);
let completion_state =
this#run_to_completion (fun () -> ignore @@ this#expression body)
this#run_to_completion (fun () ->
Base.Option.iter guard ~f:(fun guard -> ignore @@ this#expression guard);
ignore @@ this#expression body
)
in
completion_states := completion_state :: !completion_states)
()
Expand Down
13 changes: 11 additions & 2 deletions src/typing/statement.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2821,11 +2821,20 @@ module Make
name_loc
)
in
let guard = Base.Option.map guard ~f:(expression cx) in
let ((((_, t), _) as body), throws) =
let (guard, guard_throws) =
match guard with
| Some guard ->
let (guard, throws) =
Abnormal.catch_expr_control_flow_exception (fun () -> expression cx guard)
in
(Some guard, throws)
| None -> (None, false)
in
let ((((_, t), _) as body), body_throws) =
Abnormal.catch_expr_control_flow_exception (fun () -> expression cx body)
in
let case_ast = (case_loc, { Match.Case.pattern; body; guard; comments }) in
let throws = guard_throws || body_throws in
let all_throws = all_throws && throws in
let ts =
if throws then
Expand Down
5 changes: 3 additions & 2 deletions tests/match/body.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ function f1() {
function f2() {
const out = match (x) {
1 if invariant(false): true,
_: true,
_: 's',
};
out; // ERROR: unreachable
out as string; // OK
out as empty; // ERROR
}
17 changes: 13 additions & 4 deletions tests/match/match.exp
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,21 @@ Unreachable code. [unreachable-code]
^^^^


Error ----------------------------------------------------------------------------------------------------- body.js:55:3
Error ----------------------------------------------------------------------------------------------------- body.js:56:3

Unreachable code. [unreachable-code]
Cannot cast `out` to empty because string [1] is incompatible with empty [2]. [incompatible-cast]

55| out; // ERROR: unreachable
^^^^
body.js:56:3
56| out as empty; // ERROR
^^^

References:
body.js:53:8
53| _: 's',
^^^ [1]
body.js:56:10
56| out as empty; // ERROR
^^^^^ [2]


Error -------------------------------------------------------------------------------------------------- patterns.js:9:3
Expand Down

0 comments on commit a87d923

Please sign in to comment.