File tree

5 files changed

+76
-18
lines changed

5 files changed

+76
-18
lines changed
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,19 @@ let rec dump_t_ (depth, tvars) cx t =
300300
t
301301
| MaybeT (_, arg) -> p ~extra:(kid arg) t
302302
| IntersectionT (_, rep) ->
303-
p ~extra:(spf "[%s]" (String.concat "; " (Base.List.map ~f:kid (InterRep.members rep)))) t
303+
let kind_str =
304+
match InterRep.inter_kind rep with
305+
| InterRep.ImplicitInstiationKind -> "ImplicitInstiationKind"
306+
| InterRep.UnknownKind -> "UnknownKind"
307+
in
308+
p
309+
~extra:
310+
(spf
311+
"(kind=%s)[%s]"
312+
kind_str
313+
(String.concat "; " (Base.List.map ~f:kid (InterRep.members rep)))
314+
)
315+
t
304316
| UnionT (_, rep) ->
305317
let kind_str =
306318
match UnionRep.union_kind rep with
Original file line numberDiff line numberDiff line change
@@ -708,22 +708,39 @@ module Make (Observer : OBSERVER) (Flow : Flow_common.S) : S = struct
708708
| (UpperT t', UpperT t) ->
709709
(match (t', t) with
710710
| (IntersectionT (_, rep1), IntersectionT (_, rep2)) ->
711-
UpperT (IntersectionT (upper_r, InterRep.append (InterRep.members rep2) rep1))
711+
UpperT
712+
(IntersectionT
713+
( upper_r,
714+
InterRep.append
715+
~kind:InterRep.ImplicitInstiationKind
716+
(InterRep.members rep2)
717+
rep1
718+
)
719+
)
712720
| (_, IntersectionT (_, rep)) ->
713721
if Base.List.mem (InterRep.members rep) t' ~equal then
714722
UpperT t
715723
else
716-
UpperT (IntersectionT (upper_r, InterRep.append [t'] rep))
724+
UpperT
725+
(IntersectionT
726+
(upper_r, InterRep.append ~kind:InterRep.ImplicitInstiationKind [t'] rep)
727+
)
717728
| (IntersectionT (_, rep), _) ->
718729
if Base.List.mem (InterRep.members rep) t ~equal then
719730
UpperT t'
720731
else
721-
UpperT (IntersectionT (upper_r, InterRep.append [t] rep))
732+
UpperT
733+
(IntersectionT
734+
(upper_r, InterRep.append ~kind:InterRep.ImplicitInstiationKind [t] rep)
735+
)
722736
| (t', t) ->
723737
if equal t' t then
724738
UpperT t
725739
else
726-
UpperT (IntersectionT (upper_r, InterRep.make t' t [])))
740+
UpperT
741+
(IntersectionT
742+
(upper_r, InterRep.make ~kind:InterRep.ImplicitInstiationKind t' t [])
743+
))
727744
| (UpperT _, UpperEmpty) -> acc
728745
| (UpperEmpty, UpperEmpty) -> acc)
729746
UpperEmpty)
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@ let generalize_singletons =
125125
(* async expressions will wrap result in Promise<>, so we need to descend here *)
126126
super#type_ cx force_general t
127127
| UnionT (r, rep) when is_literal_union r rep -> super#type_ cx force_general t
128+
| IntersectionT (_, rep)
129+
when match InterRep.inter_kind rep with
130+
| InterRep.ImplicitInstiationKind -> true
131+
| InterRep.UnknownKind -> false ->
132+
super#type_ cx force_general t
128133
| DefT (r, SingletonStrT { from_annot = false; value }) ->
129134
if force_general || Context.natural_inference_local_primitive_literals_full cx then
130135
DefT (replace_desc_reason RString r, StrGeneralT AnyLiteral)
Original file line numberDiff line numberDiff line change
@@ -2925,8 +2925,12 @@ end
29252925
and InterRep : sig
29262926
type t
29272927

2928+
type inter_kind =
2929+
| ImplicitInstiationKind
2930+
| UnknownKind
2931+
29282932
(** build rep from list of members *)
2929-
val make : TypeTerm.t -> TypeTerm.t -> TypeTerm.t list -> t
2933+
val make : ?kind:inter_kind -> TypeTerm.t -> TypeTerm.t -> TypeTerm.t list -> t
29302934

29312935
(** member list in declaration order *)
29322936
val members : t -> TypeTerm.t list
@@ -2936,33 +2940,39 @@ and InterRep : sig
29362940
(** map rep r to rep r' along type mapping f. drops history *)
29372941
val map : (TypeTerm.t -> TypeTerm.t) -> t -> t
29382942

2939-
val append : TypeTerm.t list -> t -> t
2943+
val append : ?kind:inter_kind -> TypeTerm.t list -> t -> t
29402944

29412945
(** map rep r to rep r' along type mapping f. drops history. if nothing would
29422946
be changed, returns the physically-identical rep. *)
29432947
val ident_map : (TypeTerm.t -> TypeTerm.t) -> t -> t
2948+
2949+
val inter_kind : t -> inter_kind
29442950
end = struct
2951+
type inter_kind =
2952+
| ImplicitInstiationKind
2953+
| UnknownKind
2954+
29452955
(** intersection rep is:
29462956
- member list in declaration order
29472957
*)
2948-
type t = TypeTerm.t * TypeTerm.t * TypeTerm.t list
2958+
type t = TypeTerm.t * TypeTerm.t * TypeTerm.t list * inter_kind
29492959

2950-
let make t0 t1 ts = (t0, t1, ts)
2960+
let make ?(kind = UnknownKind) t0 t1 ts = (t0, t1, ts, kind)
29512961

2952-
let members (t0, t1, ts) = t0 :: t1 :: ts
2962+
let members (t0, t1, ts, _) = t0 :: t1 :: ts
29532963

2954-
let members_nel (t0, t1, ts) = (t0, (t1, ts))
2964+
let members_nel (t0, t1, ts, _) = (t0, (t1, ts))
29552965

2956-
let map f (t0, t1, ts) = make (f t0) (f t1) (Base.List.map ~f ts)
2966+
let map f (t0, t1, ts, kind) = make ~kind (f t0) (f t1) (Base.List.map ~f ts)
29572967

2958-
let mem t (t0, t1, ts) = t = t0 || t = t1 || Base.List.mem ts t ~equal:( = )
2968+
let mem t (t0, t1, ts, _) = t = t0 || t = t1 || Base.List.mem ts t ~equal:( = )
29592969

2960-
let append ts2 rep =
2970+
let append ?(kind = UnknownKind) ts2 rep =
29612971
let ts2 = Base.List.filter ts2 ~f:(fun t -> not (mem t rep)) in
2962-
let (t0, t1, ts1) = rep in
2963-
make t0 t1 (Base.List.append ts1 ts2)
2972+
let (t0, t1, ts1, _) = rep in
2973+
make ~kind t0 t1 (Base.List.append ts1 ts2)
29642974

2965-
let ident_map f ((t0, t1, ts) as rep) =
2975+
let ident_map f ((t0, t1, ts, kind) as rep) =
29662976
let t0_ = f t0 in
29672977
let t1_ = f t1 in
29682978
let changed = t0_ != t0 || t1_ != t1 in
@@ -2975,9 +2985,11 @@ end = struct
29752985
ts
29762986
in
29772987
if changed then
2978-
make t0_ t1_ (List.rev rev_ts)
2988+
make ~kind t0_ t1_ (List.rev rev_ts)
29792989
else
29802990
rep
2991+
2992+
let inter_kind (_, _, _, kind) = kind
29812993
end
29822994

29832995
and Object : sig
Original file line numberDiff line numberDiff line change
@@ -541,3 +541,15 @@ function test_array_elem_union() {
541541
const strings = foo(['a', 'b']);
542542
strings.push("c"); // okay
543543
}
544+
545+
function test_generalize_under_intersection() {
546+
declare function foo<V>(
547+
v: $Exact<V>,
548+
cb: (data: $Exact<V>) => void,
549+
): void;
550+
551+
foo(
552+
{f:1},
553+
(x: {f: number}) => {}, // okay, type of `1` should generalize
554+
);
555+
}

0 commit comments

Comments
 (0)