diff --git a/src/typing/debug_js.ml b/src/typing/debug_js.ml index d68026baefe..e23e99d81ae 100644 --- a/src/typing/debug_js.ml +++ b/src/typing/debug_js.ml @@ -422,7 +422,7 @@ and _json_of_use_t_impl json_cx t = | MethodT (_, _, _, propref, funtype, _) -> [ ("propRef", json_of_propref json_cx propref); - ("funType", json_of_funcalltype json_cx funtype); + ("funType", json_of_methodaction json_cx funtype); ] | ReposLowerT (_, use_desc, use_t) -> [("type", _json_of_use_t json_cx use_t); ("useDesc", JSON_Bool use_desc)] @@ -443,10 +443,10 @@ and _json_of_use_t_impl json_cx t = | SetElemT (_, _, indext, _, elemt, _) | GetElemT (_, _, indext, elemt) -> [("indexType", _json_of_t json_cx indext); ("elemType", _json_of_t json_cx elemt)] - | CallElemT (_, _, indext, funtype) -> + | CallElemT (_, _, indext, action) -> [ ("indexType", _json_of_t json_cx indext); - ("funType", json_of_funcalltype json_cx funtype); + ("funType", json_of_methodaction json_cx action); ] | GetStaticsT (_, t) -> [("type", _json_of_t json_cx t)] | GetProtoT (_, t) @@ -584,7 +584,7 @@ and _json_of_use_t_impl json_cx t = (match action with | ReadElem t -> ("readElem", _json_of_t json_cx t) | WriteElem (t, _, _) -> ("writeElem", _json_of_t json_cx t) - | CallElem (_, funtype) -> ("callElem", json_of_funcalltype json_cx funtype)); + | CallElem (_, action) -> ("callElem", json_of_methodaction json_cx action)); ] | MakeExactT (_, cont) -> _json_of_cont json_cx cont | CJSRequireT (_, export, _) -> [("export", _json_of_t json_cx export)] @@ -1008,6 +1008,11 @@ and json_of_funcalltype_impl ("strictArity", JSON_Bool call_strict_arity); ]) +and json_of_methodaction json_cx = check_depth json_of_methodaction_impl json_cx + +and json_of_methodaction_impl json_cx = function + | CallM funtype -> json_of_funcalltype json_cx funtype + and json_of_funcallarg json_cx = check_depth json_of_funcallarg_impl json_cx and json_of_funcallarg_impl json_cx arg = @@ -2057,7 +2062,7 @@ and dump_use_t_ (depth, tvars) cx t = | AssertImportIsValueT _ -> p t | BecomeT (_, arg) -> p ~extra:(kid arg) t | BindT _ -> p t - | CallElemT (_, _, ix, _) -> p ~extra:(kid ix) t + | CallElemT (_, _, _, _) -> p t | CallT (use_op, _, { call_args_tlist; call_tout; call_this_t; _ }) -> p ~extra: diff --git a/src/typing/flow_js.ml b/src/typing/flow_js.ml index e47e7971337..abf1baf7e6a 100644 --- a/src/typing/flow_js.ml +++ b/src/typing/flow_js.ml @@ -4204,8 +4204,8 @@ struct args (ResolveSpreadsToCustomFunCall (mk_id (), kind, tout)) | ( CustomFunT (_, (ObjectAssign | ObjectGetPrototypeOf | ObjectSetPrototypeOf)), - MethodT (use_op, reason_call, _, Named (_, "call"), calltype, _) ) -> - rec_flow cx trace (l, CallT (use_op, reason_call, calltype)) + MethodT (use_op, reason_call, _, Named (_, "call"), action, _) ) -> + rec_flow cx trace (l, apply_method_action use_op reason_call action) (* Custom functions are still functions, so they have all the prototype properties *) | (CustomFunT (r, _), _) when function_like_op u -> rec_flow cx trace (FunProtoT r, u) (*********************************************) @@ -4549,7 +4549,7 @@ struct rec_flow cx trace - (this, MethodT (use_op, reason_op, reason_o, propref, funtype, None))) + (this, MethodT (use_op, reason_op, reason_o, propref, CallM funtype, None))) in (* return this *) rec_flow cx trace (ret, ObjTestT (annot_reason ~annot_loc reason_op, this, t)) @@ -4601,7 +4601,8 @@ struct rec_flow_t cx trace (AnyT.untyped reason_op, t) (* Since we don't know the signature of a method on AnyT, assume every parameter is an AnyT. *) - | (AnyT _, MethodT (use_op, reason_op, _, _, { call_args_tlist; call_tout; _ }, prop_t)) -> + | ( AnyT _, + MethodT (use_op, reason_op, _, _, CallM { call_args_tlist; call_tout; _ }, prop_t) ) -> let any = AnyT.untyped reason_op in call_args_iter (fun t -> rec_flow cx trace (t, UseT (use_op, any))) call_args_tlist; Option.iter ~f:(fun prop_t -> rec_flow_t cx trace (any, prop_t)) prop_t; @@ -4813,8 +4814,8 @@ struct (* ... and their methods called *) (********************************) | ( DefT (reason_c, _, InstanceT (_, super, _, instance)), - MethodT (use_op, reason_call, reason_lookup, Named (reason_prop, x), funtype, prop_t) - ) -> + MethodT (use_op, reason_call, reason_lookup, Named (reason_prop, x), action, prop_t) ) + -> (* TODO: closure *) let own_props = Context.find_props cx instance.own_props in let proto_props = Context.find_props cx instance.proto_props in @@ -4833,7 +4834,7 @@ struct `CallT` will set its own ops during the call. if `funt` is something else, then something like `VoidT ~> CallT` doesn't need the op either because we want to point at the call and undefined thing. *) - rec_flow cx trace (funt, CallT (use_op, reason_call, funtype)) + rec_flow cx trace (funt, apply_method_action use_op reason_call action) | (DefT (_, _, InstanceT _), MethodT (_, reason_call, _, Computed _, _, _)) -> (* Instances don't have proper dictionary support. All computed accesses are converted to named property access to `$key` and `$value` during @@ -5169,13 +5170,13 @@ struct (********************************) | (DefT (_, _, ObjT _), MethodT (_, _, _, Named (_, "constructor"), _, _)) -> () | ( DefT (reason_obj, _, ObjT o), - MethodT (use_op, reason_call, reason_lookup, propref, funtype, prop_t) ) -> + MethodT (use_op, reason_call, reason_lookup, propref, action, prop_t) ) -> let t = Tvar.mk_where cx reason_lookup (fun tout -> read_obj_prop cx trace ~use_op o propref reason_obj reason_lookup tout) in Option.iter ~f:(fun prop_t -> rec_flow_t cx trace (t, prop_t)) prop_t; - rec_flow cx trace (t, CallT (use_op, reason_call, funtype)) + rec_flow cx trace (t, apply_method_action use_op reason_call action) (******************************************) (* strings may have their characters read *) (******************************************) @@ -5197,8 +5198,8 @@ struct | ((DefT (_, _, (ObjT _ | ArrT _)) | AnyT _), GetElemT (use_op, reason_op, key, tout)) -> rec_flow cx trace (key, ElemT (use_op, reason_op, l, ReadElem tout)) | ( (DefT (_, _, (ObjT _ | ArrT _)) | AnyT _), - CallElemT (reason_call, reason_lookup, key, ft) ) -> - let action = CallElem (reason_call, ft) in + CallElemT (reason_call, reason_lookup, key, action) ) -> + let action = CallElem (reason_call, action) in rec_flow cx trace (key, ElemT (unknown_use, reason_lookup, l, action)) | (_, ElemT (use_op, reason_op, (DefT (_, _, ObjT _) as obj), action)) -> elem_action_on_obj cx trace ~use_op l obj reason_op action @@ -10853,7 +10854,8 @@ struct trace (tin, UseT (use_op, VoidT.why (reason_of_t value) |> with_trust literal_trust)); Option.iter ~f:(fun t -> rec_flow_t cx trace (l, t)) tout - | (CallElem (reason_call, ft), _) -> rec_flow cx trace (value, CallT (use_op, reason_call, ft)) + | (CallElem (reason_call, action), _) -> + rec_flow cx trace (value, apply_method_action use_op reason_call action) and string_key s reason = let key_reason = replace_desc_reason (RPropertyIsAString s) reason in diff --git a/src/typing/statement.ml b/src/typing/statement.ml index 9538274ced4..8ca7c6a52ef 100644 --- a/src/typing/statement.ml +++ b/src/typing/statement.ml @@ -3780,8 +3780,12 @@ and subscript ~is_cond cx ex = cx ( super, MethodT - (use_op, reason, reason_lookup, Named (reason_prop, name), funtype, Some prop_t) - )) + ( use_op, + reason, + reason_lookup, + Named (reason_prop, name), + CallM funtype, + Some prop_t ) )) in Some ( (loc, lhs_t), @@ -3852,7 +3856,8 @@ and subscript ~is_cond cx ex = Tvar.mk_where cx reason_call (fun t -> let frame = Env.peek_frame () in let funtype = mk_methodcalltype ot targts argts t ~frame in - Flow.flow cx (ot, CallElemT (reason_call, reason_lookup, elem_t, funtype))) ), + Flow.flow cx (ot, CallElemT (reason_call, reason_lookup, elem_t, CallM funtype))) + ), Member.PropertyExpression expr ) in Some @@ -3890,7 +3895,9 @@ and subscript ~is_cond cx ex = local = true; }) in - Flow.flow cx (super, MethodT (use_op, reason, super_reason, propref, funtype, None))) + Flow.flow + cx + (super, MethodT (use_op, reason, super_reason, propref, CallM funtype, None))) in Some ( (loc, lhs_t), @@ -4389,8 +4396,9 @@ and method_call let reason_expr = mk_reason (RProperty (Some name)) expr_loc in let app = mk_methodcalltype obj_t targts argts t ~frame ~call_strict_arity in let propref = Named (reason_prop, name) in - Flow.flow cx (obj_t, MethodT (use_op, reason, reason_expr, propref, app, Some prop_t))) - ) + Flow.flow + cx + (obj_t, MethodT (use_op, reason, reason_expr, propref, CallM app, Some prop_t))) ) and identifier_ cx name loc = if Type_inference_hooks_js.dispatch_id_hook cx name loc then @@ -5331,11 +5339,12 @@ and jsx_desugar cx name component_t props attributes children locs = reason, reason_createElement, Named (reason_createElement, "createElement"), - mk_methodcalltype - react - None - ([Arg component_t; Arg props] @ Base.List.map ~f:(fun c -> Arg c) children) - tvar, + CallM + (mk_methodcalltype + react + None + ([Arg component_t; Arg props] @ Base.List.map ~f:(fun c -> Arg c) children) + tvar), None ) )) | Options.Jsx_pragma (raw_jsx_expr, jsx_expr) -> let reason = mk_reason (RJSXFunctionCall raw_jsx_expr) loc_element in diff --git a/src/typing/type.ml b/src/typing/type.ml index d99f56f7ab8..86c70d82305 100644 --- a/src/typing/type.ml +++ b/src/typing/type.ml @@ -444,7 +444,7 @@ module rec TypeTerm : sig (* The last position is an optional type that probes into the type of the method called. This will be primarily used for type-table bookkeeping. *) | MethodT of - use_op * (* call *) reason * (* lookup *) reason * propref * funcalltype * t option + use_op * (* call *) reason * (* lookup *) reason * propref * method_action * t option (* Similar to the last element of the MethodT *) | SetPropT of use_op * reason * propref * set_mode * write_ctx * t * t option (* The boolean flag indicates whether or not it is a static lookup. We cannot know this when @@ -466,7 +466,7 @@ module rec TypeTerm : sig need to ensure that reads happen after writes. *) | SetElemT of use_op * reason * t * set_mode * t * t option (*tout *) | GetElemT of use_op * reason * t * t - | CallElemT of (* call *) reason * (* lookup *) reason * t * funcalltype + | CallElemT of (* call *) reason * (* lookup *) reason * t * method_action | GetStaticsT of reason * t_out | GetProtoT of reason * t_out | SetProtoT of reason * t @@ -759,6 +759,10 @@ module rec TypeTerm : sig | NewChain | ContinueChain + and method_action = CallM of funcalltype + + and opt_method_action = OptCallM of opt_funcalltype + and specialize_cache = reason list option and predicate = @@ -1014,7 +1018,7 @@ module rec TypeTerm : sig and elem_action = | ReadElem of t | WriteElem of t * t option (* tout *) * set_mode - | CallElem of reason (* call *) * funcalltype + | CallElem of reason * method_action and propref = | Named of reason * name @@ -1795,13 +1799,13 @@ end = struct (* the only unresolved tvars at this point are those that instantiate polymorphic types *) | OpenT _ (* some types may not be evaluated yet; TODO *) - + | EvalT _ | TypeAppT _ | KeysT _ | IntersectionT _ (* other types might wrap parts that are accessible directly *) - + | OpaqueT _ | DefT (_, _, InstanceT _) | DefT (_, _, PolyT _) -> @@ -3949,6 +3953,10 @@ let apply_opt_funcalltype (this, targs, args, clos, strict) t_out = let create_intersection rep = IntersectionT (locationless_reason (RCustom "intersection"), rep) +let apply_opt_action action t_out = + match action with + | OptCallM f -> CallM (apply_opt_funcalltype f t_out) + let apply_opt_use opt_use t_out = match opt_use with | OptCallT (u, r, f) -> CallT (u, r, apply_opt_funcalltype f t_out) @@ -3962,6 +3970,10 @@ let mk_enum_type ~loc ~trust enum = let reason = mk_reason (RType enum_name) loc in DefT (reason, trust, EnumT enum) +let apply_method_action use_op reason_call action = + match action with + | CallM app -> CallT (use_op, reason_call, app) + module TypeParams : sig val to_list : typeparams -> typeparam list diff --git a/src/typing/type_mapper.ml b/src/typing/type_mapper.ml index bc76f4e076d..551d5d4fbd9 100644 --- a/src/typing/type_mapper.ml +++ b/src/typing/type_mapper.ml @@ -818,14 +818,14 @@ class virtual ['a] t_with_uses = t else CallT (op, r, funcall') - | MethodT (op, r1, r2, prop, funcall, prop_t) -> + | MethodT (op, r1, r2, prop, action, prop_t) -> let prop' = self#prop_ref cx map_cx prop in - let funcall' = self#fun_call_type cx map_cx funcall in + let action' = self#method_action cx map_cx action in let prop_t' = OptionUtils.ident_map (self#type_ cx map_cx) prop_t in - if prop' == prop && funcall' == funcall && prop_t' == prop_t then + if prop' == prop && action' == action && prop_t' == prop_t then t else - MethodT (op, r1, r2, prop', funcall', prop_t') + MethodT (op, r1, r2, prop', action', prop_t') | SetPropT (use_op, r, prop, mode, i, t', prop_t) -> let prop' = self#prop_ref cx map_cx prop in let t'' = self#type_ cx map_cx t' in @@ -887,7 +887,7 @@ class virtual ['a] t_with_uses = GetElemT (use_op, r, t1', t2') | CallElemT (r1, r2, t', funcall) -> let t'' = self#type_ cx map_cx t' in - let funcall' = self#fun_call_type cx map_cx funcall in + let funcall' = self#method_action cx map_cx funcall in if t' == t'' && funcall' == funcall then t else @@ -1482,7 +1482,7 @@ class virtual ['a] t_with_uses = else WriteElem (tin', tout', mode) | CallElem (r, funcall) -> - let funcall' = self#fun_call_type cx map_cx funcall in + let funcall' = self#method_action cx map_cx funcall in if funcall' == funcall then t else @@ -1561,6 +1561,24 @@ class virtual ['a] t_with_uses = else ResolveSpreadsToCallT (funcalltype', t'') + method private opt_method_action cx map_cx t = + match t with + | OptCallM funtype -> + let funtype' = self#opt_fun_call_type cx map_cx funtype in + if funtype' == funtype then + t + else + OptCallM funtype' + + method method_action cx map_cx t = + match t with + | CallM funtype -> + let funtype' = self#fun_call_type cx map_cx funtype in + if funtype' == funtype then + t + else + CallM funtype' + method fun_call_type cx map_cx t = let { call_this_t; diff --git a/src/typing/type_mapper.mli b/src/typing/type_mapper.mli index fa90065d4b2..90055725cc0 100644 --- a/src/typing/type_mapper.mli +++ b/src/typing/type_mapper.mli @@ -92,6 +92,8 @@ class virtual ['a] t_with_uses : method fun_call_type : Context.t -> 'a -> Type.funcalltype -> Type.funcalltype + method method_action : Context.t -> 'a -> Type.method_action -> Type.method_action + method initial_state : Context.t -> 'a -> diff --git a/src/typing/type_visitor.ml b/src/typing/type_visitor.ml index e89a723ca67..5e7c8d2f7e1 100644 --- a/src/typing/type_visitor.ml +++ b/src/typing/type_visitor.ml @@ -240,7 +240,7 @@ class ['a] t = self#fun_call_type cx acc fn | MethodT (_, _, _, p, fn, prop_t) -> let acc = self#propref cx acc p in - let acc = self#fun_call_type cx acc fn in + let acc = self#method_action cx acc fn in let acc = self#opt (self#type_ cx pole_TODO) acc prop_t in acc | SetPropT (_, _, p, _, _, t, prop_t) -> @@ -274,7 +274,7 @@ class ['a] t = acc | CallElemT (_, _, t, fn) -> let acc = self#type_ cx pole_TODO acc t in - let acc = self#fun_call_type cx acc fn in + let acc = self#method_action cx acc fn in acc | GetStaticsT (_, t) | GetProtoT (_, t) @@ -742,6 +742,20 @@ class ['a] t = let acc = self#type_ cx pole_TODO acc call_tout in acc + method private opt_fun_call_type cx acc (call_this_t, call_targs, call_args_tlist, _, _) = + let acc = self#type_ cx pole_TODO acc call_this_t in + let acc = self#opt (self#list (self#targ cx pole_TODO)) acc call_targs in + let acc = self#list (self#call_arg cx) acc call_args_tlist in + acc + + method private method_action cx acc = + function + | CallM call -> self#fun_call_type cx acc call + + method private opt_method_action cx acc = + function + | OptCallM call -> self#opt_fun_call_type cx acc call + method private propref cx acc = function | Named _ -> acc @@ -792,7 +806,7 @@ class ['a] t = let acc = self#type_ cx pole_TODO acc tin in let acc = self#opt (self#type_ cx pole_TODO) acc tout in acc - | CallElem (_, fn) -> self#fun_call_type cx acc fn + | CallElem (_, fn) -> self#method_action cx acc fn method private cont cx acc = function