From 98ff96ce6ae090f32f8a1346b271ba2aa4ae4f98 Mon Sep 17 00:00:00 2001 From: George Zahariev Date: Mon, 29 Apr 2024 15:01:40 -0700 Subject: [PATCH] [flow][tuples] Refactor: update ArrayAT's tuple_view to use record, create empty_tuple_view Summary: Refactor: update ArrayAT's tuple_view to use record, and create empty_tuple_view Changelog: [internal] Reviewed By: SamChou19815 Differential Revision: D56713882 fbshipit-source-id: 7c6199b7580ac619b78d5a3cd383b2128246b708 --- src/typing/debug_js.ml | 8 +++++++- src/typing/env_resolution.ml | 5 +++-- src/typing/flow_js.ml | 36 +++++++++++++++++++++++---------- src/typing/flow_js_utils.ml | 4 +++- src/typing/members.ml | 24 +++++++++++++++++++--- src/typing/react_kit.ml | 2 +- src/typing/resolvableTypeJob.ml | 8 ++++++-- src/typing/statement.ml | 8 ++++++-- src/typing/subtyping_kit.ml | 6 +++--- src/typing/ty_normalizer.ml | 9 ++++++++- src/typing/type.ml | 10 ++++++++- src/typing/type_hint.ml | 2 +- src/typing/type_mapper.ml | 5 ++--- src/typing/type_visitor.ml | 2 +- 14 files changed, 96 insertions(+), 33 deletions(-) diff --git a/src/typing/debug_js.ml b/src/typing/debug_js.ml index 7fa941db505..55a4384372f 100644 --- a/src/typing/debug_js.ml +++ b/src/typing/debug_js.ml @@ -248,7 +248,13 @@ let rec dump_t_ (depth, tvars) cx t = p t ~extra:(spf "%s, %s" (Properties.string_of_id props_tmap) obj_kind) | DefT (_, ArrT (ArrayAT { elem_t; tuple_view = None; react_dro = _ })) -> p ~extra:(spf "Array %s" (kid elem_t)) t - | DefT (_, ArrT (ArrayAT { elem_t; tuple_view = Some (elements, _arity); react_dro = _ })) -> + | DefT + ( _, + ArrT + (ArrayAT + { elem_t; tuple_view = Some (TupleView { elements; arity = _ }); react_dro = _ } + ) + ) -> p ~extra: (spf diff --git a/src/typing/env_resolution.ml b/src/typing/env_resolution.ml index ad6103c5f72..c31e9b4022e 100644 --- a/src/typing/env_resolution.ml +++ b/src/typing/env_resolution.ml @@ -497,7 +497,8 @@ let rec resolve_binding cx reason loc b = | Ast.Expression.Object obj -> mk_obj loc obj | Ast.Expression.Array { Ast.Expression.Array.elements = []; _ } -> let (_, elem_t) = Statement.empty_array cx loc in - DefT (reason, ArrT (ArrayAT { elem_t; tuple_view = Some ([], (0, 0)); react_dro = None })) + DefT + (reason, ArrT (ArrayAT { elem_t; tuple_view = Some empty_tuple_view; react_dro = None })) | Ast.Expression.Array { Ast.Expression.Array.elements; _ } -> (* TODO merge code with statement.ml implementation *) let array_elements cx undef_loc = @@ -723,7 +724,7 @@ let rec resolve_binding cx reason loc b = else let elem_t = EmptyT.make (mk_reason REmptyArrayElement loc) in Flow_js_utils.add_output cx Error_message.(EEmptyArrayNoProvider { loc }); - (elem_t, Some ([], (0, 0)), replace_desc_reason REmptyArrayLit reason) + (elem_t, Some empty_tuple_view, replace_desc_reason REmptyArrayLit reason) in let t = DefT (reason, ArrT (ArrayAT { elem_t; tuple_view; react_dro = None })) in let cache = Context.node_cache cx in diff --git a/src/typing/flow_js.ml b/src/typing/flow_js.ml index 48231be386f..30fb196da9f 100644 --- a/src/typing/flow_js.ml +++ b/src/typing/flow_js.ml @@ -4256,7 +4256,7 @@ struct ); rec_flow cx trace (from, ObjAssignFromT (use_op, r, o, t, default_obj_assign_kind))) elements - | ArrayAT { tuple_view = Some (elements, _arity); _ } -> + | ArrayAT { tuple_view = Some (TupleView { elements; arity = _ }); _ } -> (* Object.assign(o, ...[x,y,z]) -> Object.assign(o, x, y, z) *) let ts = tuple_ts_of_elements elements in List.iter @@ -4655,10 +4655,15 @@ struct | ArrayAT { tuple_view = None; _ } | ROArrayAT _ -> arrtype - | ArrayAT { elem_t; tuple_view = Some (elements, (num_req, num_total)); react_dro } -> + | ArrayAT + { + elem_t; + tuple_view = Some (TupleView { elements; arity = (num_req, num_total) }); + react_dro; + } -> let elements = Base.List.drop elements i in let arity = (max (num_req - i) 0, max (num_total - i) 0) in - ArrayAT { elem_t; tuple_view = Some (elements, arity); react_dro } + ArrayAT { elem_t; tuple_view = Some (TupleView { elements; arity }); react_dro } | TupleAT { elem_t; elements; arity = (num_req, num_total); react_dro } -> TupleAT { @@ -4706,14 +4711,14 @@ struct react_dro; tuple_view = Base.Option.map - ~f:(fun (elements, arity) -> + ~f:(fun (TupleView { elements; arity }) -> let elements = Base.List.map ~f:(fun (TupleElement { name; t; polarity; optional; reason }) -> TupleElement { name; t = f t; polarity; optional; reason }) elements in - (elements, arity)) + TupleView { elements; arity }) tuple_view; } | TupleAT { elem_t; elements; arity; react_dro } -> @@ -9406,13 +9411,13 @@ struct let ts1 = Base.Option.value_map ~default:[] - ~f:(fun (elements, _arity) -> tuple_ts_of_elements elements) + ~f:(fun (TupleView { elements; arity = _ }) -> tuple_ts_of_elements elements) tv1 in let ts2 = Base.Option.value_map ~default:[] - ~f:(fun (elements, _arity) -> tuple_ts_of_elements elements) + ~f:(fun (TupleView { elements; arity = _ }) -> tuple_ts_of_elements elements) tv2 in array_unify cx trace ~use_op (ts1, t1, ts2, t2) @@ -9985,12 +9990,12 @@ struct let (args_rev, seen_opt) = match arrtype with | ArrayAT { tuple_view = None; _ } - | ArrayAT { tuple_view = Some ([], _); _ } -> + | ArrayAT { tuple_view = Some (TupleView { elements = []; _ }); _ } -> (* The latter case corresponds to the empty array literal. If * we folded over the empty tuple_types list, then this would * cause an empty result. *) (arg :: args_rev, seen_opt) - | ArrayAT { tuple_view = Some (elements, _); _ } + | ArrayAT { tuple_view = Some (TupleView { elements; _ }); _ } | TupleAT { elements; _ } -> Base.List.fold_left ~f:(fun (args_rev, seen_opt) (TupleElement ({ optional; t; _ } as elem)) -> @@ -10149,7 +10154,14 @@ struct if valid then DefT ( reason_op, - ArrT (ArrayAT { elem_t; tuple_view = Some (elements, arity); react_dro = None }) + ArrT + (ArrayAT + { + elem_t; + tuple_view = Some (TupleView { elements; arity }); + react_dro = None; + } + ) ) else DefT (reason_op, ArrT (ArrayAT { elem_t; tuple_view = None; react_dro = None })) @@ -10200,7 +10212,9 @@ struct (match resolved with | ResolvedArg (TupleElement { t; _ }, generic) :: rest -> flatten cx r ((t, generic) :: args) spread rest - | ResolvedSpreadArg (_, ArrayAT { tuple_view = Some (elements, _); _ }, generic) :: rest + | ResolvedSpreadArg + (_, ArrayAT { tuple_view = Some (TupleView { elements; _ }); _ }, generic) + :: rest | ResolvedSpreadArg (_, TupleAT { elements; _ }, generic) :: rest -> let args = List.rev_append diff --git a/src/typing/flow_js_utils.ml b/src/typing/flow_js_utils.ml index d2eaab3883d..c5fbf0a367a 100644 --- a/src/typing/flow_js_utils.ml +++ b/src/typing/flow_js_utils.ml @@ -2332,7 +2332,9 @@ let array_elem_check ~write_action cx trace l use_op reason reason_tup arrtype = let (elem_t, elements, is_index_restricted, is_tuple, react_dro) = match arrtype with | ArrayAT { elem_t; tuple_view; react_dro } -> - let elements = Base.Option.map ~f:(fun (elements, _arity) -> elements) tuple_view in + let elements = + Base.Option.map ~f:(fun (TupleView { elements; arity = _ }) -> elements) tuple_view + in (elem_t, elements, false, false, react_dro) | TupleAT { elem_t; elements; arity = _; react_dro } -> (elem_t, Some elements, true, true, react_dro) diff --git a/src/typing/members.ml b/src/typing/members.ml index 7fc79930fc2..8b83f44afb3 100644 --- a/src/typing/members.ml +++ b/src/typing/members.ml @@ -227,9 +227,27 @@ let rec merge_type cx = mk_object_def_type ~reason ~flags ~call id o1.proto_t | _ -> create_union (UnionRep.make t1 t2 [])) | ( DefT - (_, ArrT (ArrayAT { elem_t = t1; tuple_view = Some (elements1, arity1); react_dro = dro1 })), + ( _, + ArrT + (ArrayAT + { + elem_t = t1; + tuple_view = Some (TupleView { elements = elements1; arity = arity1 }); + react_dro = dro1; + } + ) + ), DefT - (_, ArrT (ArrayAT { elem_t = t2; tuple_view = Some (elements2, arity2); react_dro = dro2 })) + ( _, + ArrT + (ArrayAT + { + elem_t = t2; + tuple_view = Some (TupleView { elements = elements2; arity = arity2 }); + react_dro = dro2; + } + ) + ) ) when arity1 = arity2 && List.for_all2 @@ -261,7 +279,7 @@ let rec merge_type cx = (ArrayAT { elem_t = merge_type cx (t1, t2); - tuple_view = Some (elements, arity1); + tuple_view = Some (TupleView { elements; arity = arity1 }); react_dro = ( if Base.Option.is_some dro1 && Base.Option.is_some dro2 then dro1 diff --git a/src/typing/react_kit.ml b/src/typing/react_kit.ml index 662eda60eaf..3bb3851b318 100644 --- a/src/typing/react_kit.ml +++ b/src/typing/react_kit.ml @@ -363,7 +363,7 @@ module Kit (Flow : Flow_common.S) : REACT = struct (ArrayAT { elem_t = union_of_ts r ts; - tuple_view = Some (elements, (arity, arity)); + tuple_view = Some (TupleView { elements; arity = (arity, arity) }); react_dro = None; } ) diff --git a/src/typing/resolvableTypeJob.ml b/src/typing/resolvableTypeJob.ml index c32a93d54cb..ee9eaa6d662 100644 --- a/src/typing/resolvableTypeJob.ml +++ b/src/typing/resolvableTypeJob.ml @@ -137,7 +137,11 @@ and collect_of_type ?log_unresolved cx acc = function collect_of_types ?log_unresolved cx acc ts | DefT (_, ArrT (ArrayAT { elem_t; tuple_view = None; react_dro = _ })) -> collect_of_type ?log_unresolved cx acc elem_t - | DefT (_, ArrT (ArrayAT { elem_t; tuple_view = Some (elements, _); react_dro = _ })) + | DefT + ( _, + ArrT + (ArrayAT { elem_t; tuple_view = Some (TupleView { elements; arity = _ }); react_dro = _ }) + ) | DefT (_, ArrT (TupleAT { elem_t; elements; arity = _; react_dro = _ })) -> collect_of_types ?log_unresolved cx acc (elem_t :: TypeUtil.tuple_ts_of_elements elements) | DefT (_, ArrT (ROArrayAT (elemt, _))) -> collect_of_type ?log_unresolved cx acc elemt @@ -298,7 +302,7 @@ and collect_of_destructor ?log_unresolved cx acc = function (match arr with | ArrayAT { elem_t; tuple_view = None; react_dro = _ } -> collect_of_type ?log_unresolved cx acc elem_t - | ArrayAT { elem_t; tuple_view = Some (elements, _); react_dro = _ } + | ArrayAT { elem_t; tuple_view = Some (TupleView { elements; arity = _ }); react_dro = _ } | TupleAT { elem_t; elements; arity = _; react_dro = _ } -> collect_of_types ?log_unresolved diff --git a/src/typing/statement.ml b/src/typing/statement.ml index cc9260beac1..7198805a65d 100644 --- a/src/typing/statement.ml +++ b/src/typing/statement.ml @@ -2709,7 +2709,9 @@ module Make let elem_t = Context.mk_placeholder cx element_reason in ( ( loc, DefT - (reason, ArrT (ArrayAT { elem_t; tuple_view = Some ([], (0, 0)); react_dro = None })) + ( reason, + ArrT (ArrayAT { elem_t; tuple_view = Some empty_tuple_view; react_dro = None }) + ) ), Array { Array.elements = []; comments } ) @@ -2717,7 +2719,9 @@ module Make let (reason, elem_t) = empty_array cx loc in ( ( loc, DefT - (reason, ArrT (ArrayAT { elem_t; tuple_view = Some ([], (0, 0)); react_dro = None })) + ( reason, + ArrT (ArrayAT { elem_t; tuple_view = Some empty_tuple_view; react_dro = None }) + ) ), Array { Array.elements = []; comments } ) diff --git a/src/typing/subtyping_kit.ml b/src/typing/subtyping_kit.ml index 75ec85259b9..04f18753c71 100644 --- a/src/typing/subtyping_kit.ml +++ b/src/typing/subtyping_kit.ml @@ -1837,13 +1837,13 @@ module Make (Flow : INPUT) : OUTPUT = struct let ts1 = Base.Option.value_map ~default:[] - ~f:(fun (elements, _arity) -> tuple_ts_of_elements elements) + ~f:(fun (TupleView { elements; arity = _ }) -> tuple_ts_of_elements elements) tv1 in let ts2 = Base.Option.value_map ~default:[] - ~f:(fun (elements, _arity) -> tuple_ts_of_elements elements) + ~f:(fun (TupleView { elements; arity = _ }) -> tuple_ts_of_elements elements) tv2 in array_flow cx trace use_op lit1 r1 (ts1, t1, ts2, t2) @@ -1948,7 +1948,7 @@ module Make (Flow : INPUT) : OUTPUT = struct -> begin match tuple_view with | None -> add_output cx ~trace (Error_message.ENonLitArrayToTuple ((r1, r2), use_op)) - | Some (elements, arity) -> + | Some (TupleView { elements; arity }) -> rec_flow_t cx trace diff --git a/src/typing/ty_normalizer.ml b/src/typing/ty_normalizer.ml index 414f0353207..eb33d9abb04 100644 --- a/src/typing/ty_normalizer.ml +++ b/src/typing/ty_normalizer.ml @@ -1071,7 +1071,14 @@ module Make (I : INPUT) : S = struct None in match (elt_t, desc) with - | (T.ArrayAT { elem_t = _; tuple_view = Some (elements', _); react_dro = _ }, RRestArrayLit _) + | ( T.ArrayAT + { + elem_t = _; + tuple_view = Some (T.TupleView { elements = elements'; arity = _ }); + react_dro = _; + }, + RRestArrayLit _ + ) | (T.TupleAT { elements = elements'; _ }, _) -> let%map elements = mapM diff --git a/src/typing/type.ml b/src/typing/type.ml index 2356b630f0a..7fec07c6018 100644 --- a/src/typing/type.ml +++ b/src/typing/type.ml @@ -1330,12 +1330,18 @@ module rec TypeTerm : sig | Props | DROAnnot + and tuple_view = + | TupleView of { + elements: tuple_element list; + arity: int * int; + } + and arrtype = | ArrayAT of { react_dro: (ALoc.t * dro_type) option; (* Should elements of this array be treated as propagating read-only, and if so, what location is responsible *) elem_t: t; - tuple_view: (tuple_element list * (int * int)) option; + tuple_view: tuple_view option; } (* TupleAT of elemt * tuple_types. Why do tuples carry around elemt? Well, so * that they don't need to recompute their general type when you do @@ -4629,3 +4635,5 @@ end type annotated_or_inferred = | Annotated of TypeTerm.t | Inferred of TypeTerm.t + +let empty_tuple_view = TupleView { elements = []; arity = (0, 0) } diff --git a/src/typing/type_hint.ml b/src/typing/type_hint.ml index f1180d066ad..22d32a90c39 100644 --- a/src/typing/type_hint.ml +++ b/src/typing/type_hint.ml @@ -411,7 +411,7 @@ and type_of_hint_decomposition cx op reason t = ~upper_unresolved:false ( DefT ( reason, - ArrT (ArrayAT { elem_t; tuple_view = Some ([], (0, 0)); react_dro = None }) + ArrT (ArrayAT { elem_t; tuple_view = Some empty_tuple_view; react_dro = None }) ), t ) diff --git a/src/typing/type_mapper.ml b/src/typing/type_mapper.ml index 89c0189b96b..0fe543bb578 100644 --- a/src/typing/type_mapper.ml +++ b/src/typing/type_mapper.ml @@ -855,13 +855,12 @@ class virtual ['a] t = let elem_t' = self#type_ cx map_cx elem_t in let tuple_view' = OptionUtils.ident_map - (fun tuple_view -> - let (elements, arity) = tuple_view in + (fun (TupleView { elements; arity } as tuple_view) -> let elements' = ListUtils.ident_map (self#tuple_element cx map_cx) elements in if elements' == elements then tuple_view else - (elements', arity)) + TupleView { elements = elements'; arity }) tuple_view in if elem_t' == elem_t && tuple_view' == tuple_view then diff --git a/src/typing/type_visitor.ml b/src/typing/type_visitor.ml index 42a90f5387b..cc64669c71a 100644 --- a/src/typing/type_visitor.ml +++ b/src/typing/type_visitor.ml @@ -388,7 +388,7 @@ class ['a] t = method private arr_type cx pole acc = function | ArrayAT { elem_t; tuple_view = None; react_dro = _ } -> self#type_ cx P.Neutral acc elem_t - | ArrayAT { elem_t; tuple_view = Some (elements, _); react_dro = _ } + | ArrayAT { elem_t; tuple_view = Some (TupleView { elements; arity = _ }); react_dro = _ } | TupleAT { elem_t; elements; arity = _; react_dro = _ } -> let acc = self#type_ cx P.Neutral acc elem_t in let acc = self#list (self#tuple_element cx pole) acc elements in