Skip to content

Commit 9022171

Browse files
gkzfacebook-github-bot
authored andcommitted
[flow][match] Use InternalBinding for internal bindings, fixing match refinement highlighting issue
Summary: Use InternalBinding for internal bindings, fixing match refinement highlighting issue. Changelog: [internal] Reviewed By: SamChou19815, panagosg7 Differential Revision: D67830801 fbshipit-source-id: 68b5cbd80697b777b62ed8b8fe05b0e39ef2ee77
1 parent b9cc018 commit 9022171

File tree

4 files changed

+88
-50
lines changed

4 files changed

+88
-50
lines changed

src/analysis/env_builder/name_resolver.ml

+76-50
Original file line numberDiff line numberDiff line change
@@ -2931,56 +2931,27 @@ module Make (Context : C) (FlowAPIUtils : F with type cx = Context.t) :
29312931
(match_root_ident arg_internal)
29322932
(Ast.Type.Missing ALoc.none);
29332933
ignore @@ this#identifier (match_root_ident arg_internal);
2934-
Base.List.iter cases ~f:(fun case ->
2935-
let (case_loc, { Case.pattern; body; guard; comments = _ }) = case in
2936-
let lexical_hoist =
2937-
new lexical_hoister ~flowmin_compatibility:false ~enable_enums
2938-
in
2939-
let bindings = lexical_hoist#eval lexical_hoist#match_pattern pattern in
2940-
this#with_bindings
2941-
~lexical:true
2942-
case_loc
2943-
bindings
2944-
(fun () ->
2945-
this#push_refinement_scope empty_refinements;
2946-
let arg =
2947-
( case_loc,
2948-
Ast.Expression.Identifier (Flow_ast_utils.match_root_ident case_loc)
2949-
)
2950-
in
2951-
this#match_pattern_refinements ~arg pattern;
2952-
let test_refinements = this#peek_new_refinements () in
2953-
let env_prev = this#env_snapshot_without_latest_refinements in
2954-
ignore @@ this#match_pattern pattern;
2955-
ignore @@ this#expression arg;
2956-
let completion_state =
2957-
this#run_to_completion (fun () ->
2958-
match guard with
2959-
| Some guard ->
2960-
this#push_refinement_scope empty_refinements;
2961-
ignore @@ this#expression_refinement guard;
2962-
ignore @@ this#expression body;
2963-
this#pop_refinement_scope ()
2964-
| None -> ignore @@ this#expression body
2965-
)
2966-
in
2967-
completion_states := completion_state :: !completion_states;
2968-
this#pop_refinement_scope ();
2969-
this#reset_env env_prev;
2970-
if Option.is_none guard then (
2971-
(* If there is a guard, it's possible the case didn't match
2972-
because of it, not because the pattern didn't match. *)
2973-
this#push_refinement_scope test_refinements;
2974-
this#negate_new_refinements ()
2975-
))
2976-
()
2977-
);
2978-
let arg_out =
2979-
( match_keyword_loc,
2980-
Ast.Expression.Identifier (Flow_ast_utils.match_root_ident match_keyword_loc)
2981-
)
2982-
in
2983-
ignore @@ this#expression arg_out)
2934+
Base.List.iter cases ~f:(this#visit_match_expression_case ~completion_states);
2935+
match
2936+
this#get_val_of_expression
2937+
(arg_internal, Ast.Expression.Identifier (match_root_ident arg_internal))
2938+
with
2939+
| Some refined_value ->
2940+
env_state <-
2941+
{
2942+
env_state with
2943+
values =
2944+
L.LMap.add
2945+
match_keyword_loc
2946+
{
2947+
def_loc = None;
2948+
value = refined_value;
2949+
val_binding_kind = Val.InternalBinding;
2950+
name = None;
2951+
}
2952+
env_state.values;
2953+
}
2954+
| None -> ())
29842955
();
29852956
let completion_states = !completion_states |> List.rev in
29862957
this#reset_env env0;
@@ -2990,6 +2961,61 @@ module Make (Context : C) (FlowAPIUtils : F with type cx = Context.t) :
29902961
| [] -> ());
29912962
x
29922963

2964+
method private visit_match_expression_case ~completion_states case =
2965+
let open Flow_ast.Expression.Match.Case in
2966+
let (case_loc, { pattern; body; guard; comments = _ }) = case in
2967+
let lexical_hoist = new lexical_hoister ~flowmin_compatibility:false ~enable_enums in
2968+
let bindings = lexical_hoist#eval lexical_hoist#match_pattern pattern in
2969+
this#with_bindings
2970+
~lexical:true
2971+
case_loc
2972+
bindings
2973+
(fun () ->
2974+
this#push_refinement_scope empty_refinements;
2975+
let arg =
2976+
(case_loc, Ast.Expression.Identifier (Flow_ast_utils.match_root_ident case_loc))
2977+
in
2978+
this#match_pattern_refinements ~arg pattern;
2979+
let test_refinements = this#peek_new_refinements () in
2980+
let env_prev = this#env_snapshot_without_latest_refinements in
2981+
ignore @@ this#match_pattern pattern;
2982+
(match this#get_val_of_expression arg with
2983+
| Some refined_value ->
2984+
let values =
2985+
L.LMap.add
2986+
case_loc
2987+
{
2988+
def_loc = None;
2989+
value = refined_value;
2990+
val_binding_kind = Val.InternalBinding;
2991+
name = None;
2992+
}
2993+
env_state.values
2994+
in
2995+
env_state <- { env_state with values }
2996+
| None -> ());
2997+
let completion_state =
2998+
this#run_to_completion (fun () ->
2999+
match guard with
3000+
| Some guard ->
3001+
this#push_refinement_scope empty_refinements;
3002+
ignore @@ this#expression_refinement guard;
3003+
ignore @@ this#expression body;
3004+
this#pop_refinement_scope ()
3005+
| None -> ignore @@ this#expression body
3006+
)
3007+
in
3008+
completion_states := completion_state :: !completion_states;
3009+
this#pop_refinement_scope ();
3010+
this#reset_env env_prev;
3011+
if Option.is_none guard then (
3012+
(* If there is a guard, it's possible the case didn't match
3013+
because of it, not because the pattern didn't match. *)
3014+
this#push_refinement_scope test_refinements;
3015+
this#negate_new_refinements ()
3016+
))
3017+
()
3018+
29933019
method! match_pattern pattern =
29943020
( if Flow_ast_utils.match_pattern_has_binding pattern then
29953021
let (loc, _) = pattern in

tests/refinements_match/.flowconfig

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[options]
2+
all=true
3+
experimental.pattern_matching_expressions=true
4+
dev_only.refinement_info_as_errors=true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Found 0 errors

tests/refinements_match/test.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
declare const x: number;
2+
3+
const e = match (x) { // OK: no refinement info on internal binding
4+
1: true,
5+
2 as const a: true, // OK: no refinement info on internal binding
6+
_: false,
7+
};

0 commit comments

Comments
 (0)