Skip to content

Commit

Permalink
Distribute ConstructorT across intersections
Browse files Browse the repository at this point in the history
  • Loading branch information
popham committed May 29, 2016
1 parent 8289902 commit fe50291
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 15 deletions.
2 changes: 1 addition & 1 deletion src/typing/debug_js.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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
]
Expand Down
59 changes: 50 additions & 9 deletions src/typing/flow_js.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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))

| _ -> ()
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)) ->
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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) *)
Expand All @@ -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 *)
Expand All @@ -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
Expand All @@ -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. *)
Expand Down Expand Up @@ -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 *)

(**
Expand Down
2 changes: 1 addition & 1 deletion src/typing/statement.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
7 changes: 4 additions & 3 deletions src/typing/type.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -1060,7 +1060,7 @@ and reason_of_use_t = function
| SetElemT (reason,_,_)
| GetElemT (reason,_,_)

| ConstructorT (reason,_,_)
| ConstructorT (reason,_,_,_,_)

| SuperT (reason,_)
| MixinT (reason, _)
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/typing/type_visitor.ml
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ class ['a] t = object(self)
| GetPropT (_, _, _)
| SetElemT (_, _, _)
| GetElemT (_, _, _)
| ConstructorT (_, _, _)
| ConstructorT (_, _, _, _, _)
| SuperT (_, _)
| MixinT (_, _)
| AdderT (_, _, _)
Expand Down

0 comments on commit fe50291

Please sign in to comment.