Skip to content

Commit bf006da

Browse files
panagosg7facebook-github-bot
authored andcommitted
[flow] increase precedence of IntersectionT ~> _ quick check
Summary: The comment in the code that moved explains why we need this case in the checker. This diff allows this check to be used earlier before TypeAppTs have been expanded in the RHS. This is to support check ``` P<T> & {} <: P<T> ``` Types like the one on the left are not very common, but can appear when applying type guard refinements. Changelog: [fix] fixed a limitation when checking intersections of polymorphic types (e.g. [tryFlow](https://flow.org/try/#1N4Igxg9gdgZglgcxALlAIwIZoKYBsD6uEEAztvhgE6UYCe+JADpdhgCYowa5kA0I2KAFcAtiRQAXSkOz9sADwxgJ+NPTbYuQ3BMnTZA+Y2yU4IwRO4A6SFBIrGVDGM7c+h46fNRLuKxJIGWh8MeT0ZfhYlCStpHzNsFBAMIQkIEQwJODAQfiEyfBE4eWw2fDgofDBMsAALfAA3KjgsXGxxZC4eAw0G-GhcWn9aY3wWZldu-g1mbGqJUoBaCRHEzrcDEgBrbAk62kXhXFxJ923d-cPRHEpTgyEoMDaqZdW7vKgoOfaSKgOKpqmDA+d4gB5fMA-P6LCCMLLQbiLOoYCqgh6-GDYRYIXYLSgkRZkCR4jpddwPfJLZjpOBkO4AX34kA0SRWxgABABBdkAXnZwHZlgQyHZAEZ2fSANwAHR8q3ZACFefzBRhheyAEwSmVQWVs7DsgAKAB4ACoAPmV3IAPoqdRonlQDYD2fIRSbgbRLQAyflS2XydkYEhG42e82S9kAeij7IA7nBjuyoBAJOycEGoOyTJQIJRkxA47kQA0TCQ4NAkg0AAxWDUAVnrVmrIHpQA)) Reviewed By: SamChou19815 Differential Revision: D66558959 fbshipit-source-id: bae559d502a2acfef0b82655680fc3c87aae20a3
1 parent efec76e commit bf006da

File tree

2 files changed

+27
-21
lines changed

2 files changed

+27
-21
lines changed

src/typing/subtyping_kit.ml

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,27 @@ module Make (Flow : INPUT) : OUTPUT = struct
737737
| (_, ThisTypeAppT (reason_tapp, c, this, ts)) ->
738738
let reason_op = reason_of_t l in
739739
instantiate_this_class cx trace ~reason_op ~reason_tapp c ts this (Lower (use_op, l))
740+
(*
741+
* When a subtyping question involves a union appearing on the right or an
742+
* intersection appearing on the left, the simplification rules are
743+
* imprecise: we split the union / intersection into cases and try to prove
744+
* that the subtyping question holds for one of the cases, but each of those
745+
* cases may be unprovable, which might lead to spurious errors. In
746+
* particular, obvious assertions such as (A | B) & C is a subtype of A | B
747+
* cannot be proved if we choose to split the union first (discharging
748+
* unprovable subgoals of (A | B) & C being a subtype of either A or B);
749+
* dually, obvious assertions such as A & B is a subtype of (A & B) | C
750+
* cannot be proved if we choose to simplify the intersection first
751+
* (discharging unprovable subgoals of either A or B being a subtype of (A &
752+
* B) | C). So instead, we try inclusion rules to handle such cases.
753+
*
754+
* An orthogonal benefit is that for large unions or intersections, checking
755+
* inclusion is significantly faster that splitting for proving simple
756+
* inequalities (O(n) instead of O(n^2) for n cases).
757+
*)
758+
| (IntersectionT (_, rep), u)
759+
when Base.List.mem ~equal:(Concrete_type_eq.eq cx) (InterRep.members rep) u ->
760+
()
740761
(* If we have a TypeAppT (c, ts) ~> TypeAppT (c, ts) then we want to
741762
* concretize both cs to PolyTs so that we may referentially compare them.
742763
* We cannot compare the non-concretized versions since they may have been
@@ -1096,27 +1117,6 @@ module Make (Flow : INPUT) : OUTPUT = struct
10961117
| _ -> ()
10971118
);
10981119
InterRep.members rep |> List.iter (fun t -> rec_flow cx trace (l, UseT (use_op, t)))
1099-
(*
1100-
* When a subtyping question involves a union appearing on the right or an
1101-
* intersection appearing on the left, the simplification rules are
1102-
* imprecise: we split the union / intersection into cases and try to prove
1103-
* that the subtyping question holds for one of the cases, but each of those
1104-
* cases may be unprovable, which might lead to spurious errors. In
1105-
* particular, obvious assertions such as (A | B) & C is a subtype of A | B
1106-
* cannot be proved if we choose to split the union first (discharging
1107-
* unprovable subgoals of (A | B) & C being a subtype of either A or B);
1108-
* dually, obvious assertions such as A & B is a subtype of (A & B) | C
1109-
* cannot be proved if we choose to simplify the intersection first
1110-
* (discharging unprovable subgoals of either A or B being a subtype of (A &
1111-
* B) | C). So instead, we try inclusion rules to handle such cases.
1112-
*
1113-
* An orthogonal benefit is that for large unions or intersections, checking
1114-
* inclusion is significantly faster that splitting for proving simple
1115-
* inequalities (O(n) instead of O(n^2) for n cases).
1116-
*)
1117-
| (IntersectionT (_, rep), u)
1118-
when Base.List.mem ~equal:(Concrete_type_eq.eq cx) (InterRep.members rep) u ->
1119-
()
11201120
(* String enum sets can be handled in logarithmic time by just
11211121
* checking for membership in the set.
11221122
*)

tests/intersection/typeapp.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
type A = { tag: 1 };
2+
type B = { tag: 2 };
3+
4+
type P<T> = A | B;
5+
declare var x: P<any> & {};
6+
x as P<any>;

0 commit comments

Comments
 (0)