Skip to content

Commit 7a6f0b9

Browse files
gkzmeta-codesync[bot]
authored andcommitted
[flow][tslib] Fix LocEnvEntryNotFound crash for destructuring in function type params
Summary: D97435945 added parser support for destructuring patterns in arrow function type params (e.g. `type A = ({ a, b }: T) => R`). The env builder's `function_param_type_pattern` override was skipping the entire pattern, which correctly avoided creating runtime bindings for the destructured identifiers but also skipped visiting the type annotation. This caused type references like `T` to never be registered in `env_values`, leading to `LocEnvEntryNotFound` crashes during type checking. Fix: visit the type annotation hint on destructuring patterns in function type params while still skipping the binding identifiers. Changelog: [internal] Reviewed By: panagosg7 Differential Revision: D98849947 fbshipit-source-id: 83541ef14ae803128659c60725d1c744b8e4a97d
1 parent a90f777 commit 7a6f0b9

File tree

7 files changed

+139
-12
lines changed

7 files changed

+139
-12
lines changed

rust_port/crates/flow_env_builder_resolver/src/name_def_ordering.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1101,10 +1101,19 @@ where
11011101

11021102
// Skip destructuring patterns in function type params (e.g. in
11031103
// `declare function f({a}: T): R`), as they are not runtime bindings.
1104+
// But still visit the type annotation so type references get registered.
11041105
fn function_param_type_pattern(
11051106
&mut self,
1106-
_patt: &ast::pattern::Pattern<ALoc, ALoc>,
1107+
patt: &ast::pattern::Pattern<ALoc, ALoc>,
11071108
) -> Result<(), !> {
1109+
use ast::pattern::Pattern;
1110+
let annot = match patt {
1111+
Pattern::Object { inner, .. } => &inner.annot,
1112+
Pattern::Array { inner, .. } => &inner.annot,
1113+
Pattern::Identifier { inner, .. } => &inner.annot,
1114+
Pattern::Expression { .. } => return Ok(()),
1115+
};
1116+
let Ok(()) = self.type_annotation_hint(annot);
11081117
Ok(())
11091118
}
11101119

rust_port/crates/flow_env_builder_resolver/src/name_resolver.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10342,10 +10342,19 @@ impl<'ast, 'a, Cx: Context, Fl: Flow<Cx = Cx>>
1034210342

1034310343
// Skip destructuring patterns in function type params (e.g. in
1034410344
// `declare function f({a}: T): R`), as they are not runtime bindings.
10345+
// But still visit the type annotation so type references get registered.
1034510346
fn function_param_type_pattern(
1034610347
&mut self,
10347-
_patt: &'ast flow_parser::ast::pattern::Pattern<ALoc, ALoc>,
10348+
patt: &'ast flow_parser::ast::pattern::Pattern<ALoc, ALoc>,
1034810349
) -> Result<(), AbruptCompletion> {
10350+
use flow_parser::ast::pattern::Pattern;
10351+
let annot = match patt {
10352+
Pattern::Object { inner, .. } => &inner.annot,
10353+
Pattern::Array { inner, .. } => &inner.annot,
10354+
Pattern::Identifier { inner, .. } => &inner.annot,
10355+
Pattern::Expression { .. } => return Ok(()),
10356+
};
10357+
self.type_annotation_hint(annot)?;
1034910358
Ok(())
1035010359
}
1035110360
}
@@ -11014,10 +11023,19 @@ impl<'ast, 'a, Cx: Context> AstVisitor<'ast, ALoc, ALoc, &'ast ALoc, !> for Dead
1101411023

1101511024
// Skip destructuring patterns in function type params (e.g. in
1101611025
// `declare function f({a}: T): R`), as they are not runtime bindings.
11026+
// But still visit the type annotation so type references get registered.
1101711027
fn function_param_type_pattern(
1101811028
&mut self,
11019-
_patt: &'ast flow_parser::ast::pattern::Pattern<ALoc, ALoc>,
11029+
patt: &'ast flow_parser::ast::pattern::Pattern<ALoc, ALoc>,
1102011030
) -> Result<(), !> {
11031+
use flow_parser::ast::pattern::Pattern;
11032+
let annot = match patt {
11033+
Pattern::Object { inner, .. } => &inner.annot,
11034+
Pattern::Array { inner, .. } => &inner.annot,
11035+
Pattern::Identifier { inner, .. } => &inner.annot,
11036+
Pattern::Expression { .. } => return Ok(()),
11037+
};
11038+
let Ok(()) = self.type_annotation_hint(annot);
1102111039
Ok(())
1102211040
}
1102311041
}

src/analysis/env_builder/name_def_ordering.ml

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -399,8 +399,18 @@ struct
399399
method! function_param_type_identifier (id : ('loc, 'loc) Ast.Identifier.t) = id
400400

401401
(* Skip destructuring patterns in function type params (e.g. in
402-
`declare function f({a}: T): R`), as they are not runtime bindings. *)
403-
method! function_param_type_pattern (patt : ('loc, 'loc) Ast.Pattern.t) = patt
402+
`declare function f({a}: T): R`), as they are not runtime bindings.
403+
But still visit the type annotation so type references get registered. *)
404+
method! function_param_type_pattern (patt : ('loc, 'loc) Ast.Pattern.t) =
405+
let open Ast.Pattern in
406+
let (_annot, p) = patt in
407+
(match p with
408+
| Object { Object.annot; _ }
409+
| Array { Array.annot; _ }
410+
| Identifier { Identifier.annot; _ } ->
411+
ignore (this#type_annotation_hint annot)
412+
| Expression _ -> ());
413+
patt
404414

405415
method! member_property_identifier (id : (ALoc.t, ALoc.t) Ast.Identifier.t) = id
406416

src/analysis/env_builder/name_resolver.ml

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2211,8 +2211,18 @@ module Make (Context : C) (FlowAPIUtils : F with type cx = Context.t) :
22112211
(loc, ParamProperty prop)
22122212

22132213
(* Skip destructuring patterns in function type params (e.g. in
2214-
`declare function f({a}: T): R`), as they are not runtime bindings. *)
2215-
method! function_param_type_pattern (patt : (ALoc.t, ALoc.t) Ast.Pattern.t) = patt
2214+
`declare function f({a}: T): R`), as they are not runtime bindings.
2215+
But still visit the type annotation so type references get registered. *)
2216+
method! function_param_type_pattern (patt : (ALoc.t, ALoc.t) Ast.Pattern.t) =
2217+
let open Ast.Pattern in
2218+
let (_annot, p) = patt in
2219+
(match p with
2220+
| Object { Object.annot; _ }
2221+
| Array { Array.annot; _ }
2222+
| Identifier { Identifier.annot; _ } ->
2223+
ignore (this#type_annotation_hint annot)
2224+
| Expression _ -> ());
2225+
patt
22162226

22172227
(* This method is called during every read of an identifier. We need to ensure that
22182228
* if the identifier is refined that we record the refiner as the write that reaches
@@ -6956,8 +6966,18 @@ module Make (Context : C) (FlowAPIUtils : F with type cx = Context.t) :
69566966
| _ -> super#function_param param
69576967

69586968
(* Skip destructuring patterns in function type params (e.g. in
6959-
`declare function f({a}: T): R`), as they are not runtime bindings. *)
6960-
method! function_param_type_pattern (patt : (ALoc.t, ALoc.t) Ast.Pattern.t) = patt
6969+
`declare function f({a}: T): R`), as they are not runtime bindings.
6970+
But still visit the type annotation so type references get registered. *)
6971+
method! function_param_type_pattern (patt : (ALoc.t, ALoc.t) Ast.Pattern.t) =
6972+
let open Ast.Pattern in
6973+
let (_annot, p) = patt in
6974+
(match p with
6975+
| Object { Object.annot; _ }
6976+
| Array { Array.annot; _ }
6977+
| Identifier { Identifier.annot; _ } ->
6978+
ignore (this#type_annotation_hint annot)
6979+
| Expression _ -> ());
6980+
patt
69616981

69626982
method! import_named_specifier ~import_kind specifier =
69636983
import_named_specifier

tests/tslib_syntax/destructuring_function_type.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,9 @@ export declare function restArr(...[a, b]: [number, string]): number;
2929
export type ArrowDestructObj = ({a, b}: {a: number, b: string}) => number;
3030
export type ArrowDestructArr = ([a, b]: [number, string]) => number;
3131
export type ArrowDestructRename = ({x: x1}: {x: number}) => number;
32+
// Arrow function types with destructuring using named type references
33+
export type ObjParams = {a: number, b: string};
34+
export type TupleParams = [number, string];
35+
export type ArrowDestructNamedObj = ({a, b}: ObjParams) => number;
36+
export type ArrowDestructNamedArr = ([a, b]: TupleParams) => number;
37+
export declare const arrowDestructNamedConst: ({a, b}: ObjParams) => number;

tests/tslib_syntax/destructuring_function_type_usage.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import {f, g, h, nested, rest, optObj, optArr, C, restArr} from "./destructuring_function_type";
2-
import type {I, ArrowDestructObj, ArrowDestructArr, ArrowDestructRename} from "./destructuring_function_type";
1+
import {f, g, h, nested, rest, optObj, optArr, C, restArr, arrowDestructNamedConst} from "./destructuring_function_type";
2+
import type {I, ArrowDestructObj, ArrowDestructArr, ArrowDestructRename, ArrowDestructNamedObj, ArrowDestructNamedArr} from "./destructuring_function_type";
33

44
// Object destructuring with shorthand properties
55
f({a: 1, b: "hello"}) as number; // OK
@@ -64,3 +64,15 @@ arrowArr([1, "hello"]) as string; // ERROR
6464
declare const arrowRename: ArrowDestructRename;
6565
arrowRename({x: 1}) as number; // OK
6666
arrowRename({x: 1}) as string; // ERROR
67+
68+
// Arrow function types with destructuring using named type references
69+
declare const arrowNamedObj: ArrowDestructNamedObj;
70+
arrowNamedObj({a: 1, b: "hello"}) as number; // OK
71+
arrowNamedObj({a: 1, b: "hello"}) as string; // ERROR
72+
73+
declare const arrowNamedArr: ArrowDestructNamedArr;
74+
arrowNamedArr([1, "hello"]) as number; // OK
75+
arrowNamedArr([1, "hello"]) as string; // ERROR
76+
77+
arrowDestructNamedConst({a: 1, b: "hello"}) as number; // OK
78+
arrowDestructNamedConst({a: 1, b: "hello"}) as string; // ERROR

tests/tslib_syntax/tslib_syntax.exp

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,58 @@ References:
701701
^^^^^^ [2]
702702

703703

704+
Error ------------------------------------------------------------------------ destructuring_function_type_usage.js:71:1
705+
706+
Cannot cast `arrowNamedObj(...)` to string because number [1] is incompatible with string [2]. [incompatible-type]
707+
708+
destructuring_function_type_usage.js:71:1
709+
71| arrowNamedObj({a: 1, b: "hello"}) as string; // ERROR
710+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
711+
712+
References:
713+
destructuring_function_type.d.ts:35:60
714+
35| export type ArrowDestructNamedObj = ({a, b}: ObjParams) => number;
715+
^^^^^^ [1]
716+
destructuring_function_type_usage.js:71:38
717+
71| arrowNamedObj({a: 1, b: "hello"}) as string; // ERROR
718+
^^^^^^ [2]
719+
720+
721+
Error ------------------------------------------------------------------------ destructuring_function_type_usage.js:75:1
722+
723+
Cannot cast `arrowNamedArr(...)` to string because number [1] is incompatible with string [2]. [incompatible-type]
724+
725+
destructuring_function_type_usage.js:75:1
726+
75| arrowNamedArr([1, "hello"]) as string; // ERROR
727+
^^^^^^^^^^^^^^^^^^^^^^^^^^^
728+
729+
References:
730+
destructuring_function_type.d.ts:36:62
731+
36| export type ArrowDestructNamedArr = ([a, b]: TupleParams) => number;
732+
^^^^^^ [1]
733+
destructuring_function_type_usage.js:75:32
734+
75| arrowNamedArr([1, "hello"]) as string; // ERROR
735+
^^^^^^ [2]
736+
737+
738+
Error ------------------------------------------------------------------------ destructuring_function_type_usage.js:78:1
739+
740+
Cannot cast `arrowDestructNamedConst(...)` to string because number [1] is incompatible with string [2].
741+
[incompatible-type]
742+
743+
destructuring_function_type_usage.js:78:1
744+
78| arrowDestructNamedConst({a: 1, b: "hello"}) as string; // ERROR
745+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
746+
747+
References:
748+
destructuring_function_type.d.ts:37:70
749+
37| export declare const arrowDestructNamedConst: ({a, b}: ObjParams) => number;
750+
^^^^^^ [1]
751+
destructuring_function_type_usage.js:78:48
752+
78| arrowDestructNamedConst({a: 1, b: "hello"}) as string; // ERROR
753+
^^^^^^ [2]
754+
755+
704756
Error --------------------------------------------------------------------------------------- export_as_namespace.js:1:1
705757

706758
`export as namespace` is not enabled. [unsupported-syntax]
@@ -1378,4 +1430,4 @@ References:
13781430

13791431

13801432

1381-
Found 91 errors
1433+
Found 94 errors

0 commit comments

Comments
 (0)