From fe502910f8aca1eb846b75c3e0bb26eecf54678a Mon Sep 17 00:00:00 2001 From: Tim Popham Date: Sun, 29 May 2016 10:51:58 -0700 Subject: [PATCH] Distribute ConstructorT across intersections --- src/typing/debug_js.ml | 2 +- src/typing/flow_js.ml | 59 ++++++++++++++++++++++++++++++++------ src/typing/statement.ml | 2 +- src/typing/type.ml | 7 +++-- src/typing/type_visitor.ml | 2 +- 5 files changed, 57 insertions(+), 15 deletions(-) diff --git a/src/typing/debug_js.ml b/src/typing/debug_js.ml index 43623667906..60fd51a63d5 100644 --- a/src/typing/debug_js.ml +++ b/src/typing/debug_js.ml @@ -320,7 +320,7 @@ and _json_of_use_t_impl json_cx t = Hh_json.( "elemType", _json_of_t json_cx elemt ] - | ConstructorT (_, tparams, t) -> [ + | ConstructorT (_, _, _, tparams, t) -> [ "typeParams", JSON_Array (List.map (_json_of_t json_cx) tparams); "type", _json_of_t json_cx t ] diff --git a/src/typing/flow_js.ml b/src/typing/flow_js.ml index 8a421cf81c4..6763716e5d2 100644 --- a/src/typing/flow_js.ml +++ b/src/typing/flow_js.ml @@ -504,7 +504,7 @@ let rec assume_ground cx ids = function | GetPropT (_, _, t) | CallT (_, { return_t = t; _ }) | MethodT (_, _, { return_t = t; _ }) - | ConstructorT (_, _, t) -> + | ConstructorT (_, _, _, _, t) -> assume_ground cx ids (UseT (UnknownUse, t)) | _ -> () @@ -1738,7 +1738,7 @@ let rec __flow cx ((l: Type.t), (u: Type.use_t)) trace = | _, UseT (use_op, IntersectionT (_, rep)) -> InterRep.members rep |> List.iter (fun t -> rec_flow cx trace (l, UseT (use_op, t)) - ) + ); (* When a subtyping question involves a union appearing on the right or an intersection appearing on the left, the simplification rules are @@ -1849,6 +1849,14 @@ let rec __flow cx ((l: Type.t), (u: Type.use_t)) trace = (List.hd ts, LookupT (reason, strict, (List.tl ts) @ try_ts_on_failure, s, t)) + (** constructor calls **) + | IntersectionT (_, rep), + ConstructorT (reason_op, result_ts, try_ts, args, t) -> + let ts = InterRep.members rep in + rec_flow cx trace + (List.hd ts, + ConstructorT (reason_op, result_ts, (List.tl ts) @ try_ts, args, t)); + (** extends **) | IntersectionT (_, rep), UseT (use_op, ExtendsT (try_ts_on_failure, l, u)) -> @@ -2422,6 +2430,8 @@ let rec __flow cx ((l: Type.t), (u: Type.use_t)) trace = if instance.class_id = instance_super.class_id then flow_type_args cx trace instance instance_super +(*TJP: Check constructor compatibility also? Maybe compute a `newable` flag for + polling by ConstructorT? Write the tests first, and then fix them. *) else rec_flow cx trace (super, u) @@ -2496,7 +2506,7 @@ let rec __flow cx ((l: Type.t), (u: Type.use_t)) trace = (*********************************************************) | ClassT (this), - ConstructorT (reason_op, args, t) -> + ConstructorT (reason_op, result_ts, try_ts, args, t) -> let reason_o = replace_reason "constructor return" (reason_of_t this) in Ops.push reason_op; (* call this.constructor(args) *) @@ -2508,8 +2518,22 @@ let rec __flow cx ((l: Type.t), (u: Type.use_t)) trace = ); ) in (* return this *) - rec_flow cx trace (ret, ObjTestT(reason_o, this, t)); - Ops.pop (); + let ret = mk_tvar_where cx reason_o (fun t -> + rec_flow cx trace (ret, ObjTestT(reason_o, this, t)) + ) in + construct_next_result cx trace reason_op args t ret (result_ts, try_ts); + Ops.pop () + + | InstanceT _, ConstructorT (reason_op, result_ts, next::try_ts, args, t) -> + (* Throw away the unshifted l. Should unshifted members be an error? Wait + for verdict before writing tests. *) + rec_flow cx trace (next, ConstructorT (reason_op, result_ts, try_ts, args, t)) + + | InstanceT _, ConstructorT (reason_op, result_ts, [], _, t) -> + (* Throw away the unshifted l. Should unshifted members be an error? Wait + for verdict before writing tests. *) + let r = replace_reason "?intersection?" reason_op in (*TJP: ?*) + rec_flow_t cx trace (IntersectionT (r, InterRep.make (List.rev result_ts)), t) (****************************************************************) (* function types derive objects through explicit instantiation *) @@ -2520,7 +2544,7 @@ let rec __flow cx ((l: Type.t), (u: Type.use_t)) trace = params_tlist = params; return_t = ret; _ }), - ConstructorT (reason_op, args, t) -> + ConstructorT (reason_op, result_ts, try_ts, args, t) -> (* TODO: closure *) (** create new object **) let reason_c = replace_reason "new object" reason in @@ -2535,12 +2559,16 @@ let rec __flow cx ((l: Type.t), (u: Type.use_t)) trace = multiflow cx trace reason_op (args, params); (** if ret is object-like, return ret; otherwise return new_obj **) let reason_o = replace_reason "constructor return" reason in - rec_flow cx trace (ret, ObjTestT(reason_o, new_obj, t)) + let ret = mk_tvar_where cx reason_o (fun t -> + rec_flow cx trace (ret, ObjTestT(reason_o, new_obj, t)) + ) in + construct_next_result cx trace reason_op args t ret (result_ts, try_ts) - | AnyFunT reason_fundef, ConstructorT (reason_op, args, t) -> + | AnyFunT reason_fundef, ConstructorT (reason_op, result_ts, try_ts, args, t) -> let reason_o = replace_reason "constructor return" reason_fundef in multiflow cx trace reason_op (args, [RestT (AnyT.t)]); - rec_flow_t cx trace (AnyObjT reason_o, t); + let ret = AnyObjT reason_o in + construct_next_result cx trace reason_op args t ret (result_ts, try_ts) (* Since we don't know the signature of a method on AnyFunT, assume every parameter is an AnyT. *) @@ -4743,6 +4771,19 @@ and concretize_lower_parts cx trace l u done_list = function | t :: todo_list -> rec_flow cx trace (t, ConcretizeLowerT (l, todo_list, done_list, u)) +and construct_next_result cx trace reason args t result_t = function +| [], [] -> + rec_flow_t cx trace (result_t, t) +| result_ts, next::try_ts -> + let result_ts = List.rev (result_t::result_ts) in + rec_flow cx trace (next, ConstructorT (reason, result_ts, try_ts, args, t)) +| result_ts, [] -> (*TJP: Activate with a test*) + let result_ts = List.rev (result_t::result_ts) in + let r = replace_reason "?intersection?" reason in + (* Should I be pushing `r` to the error stack here? Activate with tests, + minding the particulars of the errors. *) + rec_flow_t cx trace (IntersectionT (r, InterRep.make result_ts), t) + (* property lookup functions in objects and instances *) (** diff --git a/src/typing/statement.ml b/src/typing/statement.ml index 1dd65a897cc..649d4d783d7 100644 --- a/src/typing/statement.ml +++ b/src/typing/statement.ml @@ -2840,7 +2840,7 @@ and expression_ ~is_cond cx type_params_map loc e = Ast.Expression.(match e with and new_call cx tok class_ argts = let reason = mk_reason "constructor call" tok in Flow.mk_tvar_where cx reason (fun t -> - Flow.flow cx (class_, ConstructorT (reason, argts, t)); + Flow.flow cx (class_, ConstructorT (reason, [], [], argts, t)); ) and func_call cx reason func_t argts = diff --git a/src/typing/type.ml b/src/typing/type.ml index 2a7ea1a2b53..299f059c460 100644 --- a/src/typing/type.ml +++ b/src/typing/type.ml @@ -273,7 +273,7 @@ module rec TypeTerm : sig | ReposUseT of reason * use_op * t (* operations on runtime types, such as classes and functions *) - | ConstructorT of reason * t list * t + | ConstructorT of reason * t list * t list * t list * t | SuperT of reason * insttype | MixinT of reason * t @@ -1060,7 +1060,7 @@ and reason_of_use_t = function | SetElemT (reason,_,_) | GetElemT (reason,_,_) - | ConstructorT (reason,_,_) + | ConstructorT (reason,_,_,_,_) | SuperT (reason,_) | MixinT (reason, _) @@ -1279,7 +1279,8 @@ and mod_reason_of_use_t f = function | SetElemT (reason, it, et) -> SetElemT (f reason, it, et) | GetElemT (reason, it, et) -> GetElemT (f reason, it, et) - | ConstructorT (reason, ts, t) -> ConstructorT (f reason, ts, t) + | ConstructorT (reason, result_ts, try_ts, args, t) -> + ConstructorT (f reason, result_ts, try_ts, args, t) | AdderT (reason, rt, lt) -> AdderT (f reason, rt, lt) | ComparatorT (reason, t) -> ComparatorT (f reason, t) diff --git a/src/typing/type_visitor.ml b/src/typing/type_visitor.ml index c45b1ca5b95..0361b335e33 100644 --- a/src/typing/type_visitor.ml +++ b/src/typing/type_visitor.ml @@ -171,7 +171,7 @@ class ['a] t = object(self) | GetPropT (_, _, _) | SetElemT (_, _, _) | GetElemT (_, _, _) - | ConstructorT (_, _, _) + | ConstructorT (_, _, _, _, _) | SuperT (_, _) | MixinT (_, _) | AdderT (_, _, _)