Skip to content

Commit ac7d9ac

Browse files
Caleb Meredithfacebook-github-bot
authored andcommitted
Add $Call utility type
Reviewed By: samwgoldman Differential Revision: D5722285 fbshipit-source-id: 72c9377102e74b53099573c43693d789b7cccef6
1 parent bd938ab commit ac7d9ac

File tree

11 files changed

+309
-7
lines changed

11 files changed

+309
-7
lines changed

src/typing/debug_js.ml

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,25 +1085,28 @@ and json_of_destructor_impl json_cx = Hh_json.(function
10851085
| ValuesType -> JSON_Object [
10861086
"values", JSON_Bool true;
10871087
]
1088+
| CallType args -> JSON_Object [
1089+
"args", JSON_Array (List.map (_json_of_t json_cx) args);
1090+
]
10881091
| TypeMap tmap -> json_of_type_map json_cx tmap
10891092
| ReactElementPropsType -> JSON_Object [
1090-
"reactElementProps", JSON_Bool true
1091-
]
1093+
"reactElementProps", JSON_Bool true
1094+
]
10921095
| ReactElementRefType -> JSON_Object [
1093-
"reactElementRef", JSON_Bool true
1094-
]
1096+
"reactElementRef", JSON_Bool true
1097+
]
10951098
)
10961099

10971100
and json_of_type_map json_cx = check_depth json_of_type_map_impl json_cx
10981101
and json_of_type_map_impl json_cx = Hh_json.(function
10991102
| TupleMap t -> JSON_Object [
1100-
"tupleMap", _json_of_t json_cx t
1103+
"tupleMap", _json_of_t json_cx t;
11011104
]
11021105
| ObjectMap t -> JSON_Object [
1103-
"objectMap", _json_of_t json_cx t
1106+
"objectMap", _json_of_t json_cx t;
11041107
]
11051108
| ObjectMapi t -> JSON_Object [
1106-
"objectMapi", _json_of_t json_cx t
1109+
"objectMapi", _json_of_t json_cx t;
11071110
]
11081111
)
11091112

@@ -1532,6 +1535,7 @@ and dump_t_ (depth, tvars) cx t =
15321535
| Bind _ -> "bind"
15331536
| SpreadType _ -> "spread"
15341537
| ValuesType -> "values"
1538+
| CallType _ -> "function call"
15351539
| TypeMap (TupleMap _) -> "tuple map"
15361540
| TypeMap (ObjectMap _) -> "object map"
15371541
| TypeMap (ObjectMapi _) -> "object mapi"
@@ -2155,6 +2159,7 @@ let string_of_destructor = function
21552159
| Bind _ -> "Bind"
21562160
| SpreadType _ -> "Spread"
21572161
| ValuesType -> "Values"
2162+
| CallType _ -> "CallType"
21582163
| TypeMap (TupleMap _) -> "TupleMap"
21592164
| TypeMap (ObjectMap _) -> "ObjectMap"
21602165
| TypeMap (ObjectMapi _) -> "ObjectMapi"

src/typing/flow_js.ml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6717,6 +6717,10 @@ and eval_destructor cx ~trace reason curr_t s i =
67176717
let state = { todo_rev; acc = [] } in
67186718
ObjSpreadT (reason, options, tool, state, tvar)
67196719
| ValuesType -> GetValuesT (reason, tvar)
6720+
| CallType args ->
6721+
let call = mk_functioncalltype (List.map (fun arg -> Arg arg) args) tvar in
6722+
let call = {call with call_strict_arity = false} in
6723+
CallT (reason, call)
67206724
| TypeMap tmap -> MapTypeT (reason, tmap, tvar)
67216725
| ReactElementPropsType -> ReactKitT (reason, React.GetProps tvar)
67226726
| ReactElementRefType -> ReactKitT (reason, React.GetRef tvar)

src/typing/gc_js.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,7 @@ and gc_destructor cx state = function
380380
| ElementType t -> gc cx state t
381381
| Bind t -> gc cx state t
382382
| SpreadType (_, ts) -> List.iter (gc cx state) ts
383+
| CallType args -> List.iter (gc cx state) args
383384
| TypeMap tmap -> gc_type_map cx state tmap
384385

385386
and gc_pred cx state = function

src/typing/type.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -871,6 +871,7 @@ module rec TypeTerm : sig
871871
| Bind of t
872872
| SpreadType of ObjectSpread.options * t list
873873
| ValuesType
874+
| CallType of t list
874875
| TypeMap of type_map
875876
| ReactElementPropsType
876877
| ReactElementRefType

src/typing/type_annotation.ml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,14 @@ let rec convert cx tparams_map = Ast.Type.(function
332332
AbstractT (reason, t)
333333
)
334334

335+
| "$Call" ->
336+
(match convert_type_params () with
337+
| fn::args ->
338+
let reason = mk_reason RFunctionCall loc in
339+
EvalT (fn, TypeDestructorT (reason, CallType args), mk_id ())
340+
| _ ->
341+
error_type cx loc (FlowError.ETypeParamMinArity (loc, 1)))
342+
335343
| "$TupleMap" ->
336344
check_type_param_arity cx loc typeParameters 2 (fun () ->
337345
let t1, t2 = match convert_type_params () with

src/typing/type_mapper.ml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,10 @@ class ['a] t = object(self)
341341
if tlist' == tlist then t
342342
else SpreadType (options, tlist')
343343
| ValuesType -> t
344+
| CallType args ->
345+
let args' = ListUtils.ident_map (self#type_ cx map_cx) args in
346+
if args' == args then t
347+
else CallType args'
344348
| TypeMap tmap ->
345349
let tmap' = self#type_map cx map_cx tmap in
346350
if tmap' == tmap then t

src/typing/type_visitor.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ class ['a] t = object(self)
209209
| ElementType t -> self#type_ cx acc t
210210
| Bind t -> self#type_ cx acc t
211211
| SpreadType (_, ts) -> self#list (self#type_ cx) acc ts
212+
| CallType args -> self#list (self#type_ cx) acc args
212213
| TypeMap (TupleMap t | ObjectMap t | ObjectMapi t) -> self#type_ cx acc t
213214

214215
method private custom_fun_kind cx acc = function

tests/call_type/.flowconfig

Whitespace-only changes.

tests/call_type/call_type.exp

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
Error: test.js:7
2+
7: type A = $Call; // Error: one or more arguments are required.
3+
^^^^^ Incorrect number of type parameters (expected at least 1)
4+
5+
Error: test.js:8
6+
8: type B = $Call<>; // Error: one or more arguments are required.
7+
^^^^^^^ Incorrect number of type parameters (expected at least 1)
8+
9+
Error: test.js:13
10+
13: ((null: mixed): C); // Error: mixed ~> number
11+
^^^^^ mixed. This type is incompatible with
12+
13: ((null: mixed): C); // Error: mixed ~> number
13+
^ number
14+
15+
Error: test.js:15
16+
15: (c: empty); // Error: number ~> empty
17+
^ number. This type is incompatible with
18+
15: (c: empty); // Error: number ~> empty
19+
^^^^^ empty
20+
21+
Error: test.js:19
22+
19: (42: D); // Error: function called with to few arguments.
23+
^^ number. This type is incompatible with
24+
19: (42: D); // Error: function called with to few arguments.
25+
^ undefined (too few arguments, expected default/rest parameters)
26+
27+
Error: test.js:24
28+
24: ((null: mixed): E); // Error: mixed ~> number
29+
^^^^^ mixed. This type is incompatible with
30+
24: ((null: mixed): E); // Error: mixed ~> number
31+
^ number
32+
33+
Error: test.js:26
34+
26: (e: empty); // Error: number ~> empty
35+
^ number. This type is incompatible with
36+
26: (e: empty); // Error: number ~> empty
37+
^^^^^ empty
38+
39+
Error: test.js:31
40+
31: ((null: mixed): F); // Error: mixed ~> number
41+
^^^^^ mixed. This type is incompatible with
42+
31: ((null: mixed): F); // Error: mixed ~> number
43+
^ number
44+
45+
Error: test.js:33
46+
33: (f: empty); // Error: number ~> empty
47+
^ number. This type is incompatible with
48+
33: (f: empty); // Error: number ~> empty
49+
^^^^^ empty
50+
51+
Error: test.js:38
52+
38: ((null: mixed): G); // Error: mixed ~> number | string
53+
^^^^^ mixed. This type is incompatible with
54+
38: ((null: mixed): G); // Error: mixed ~> number | string
55+
^ union: type parameter `A` of function call | type parameter `B` of function call
56+
Member 1:
57+
35: type G = $Call<Fn2, number, string>;
58+
^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `A` of function call
59+
Error:
60+
38: ((null: mixed): G); // Error: mixed ~> number | string
61+
^^^^^ mixed. This type is incompatible with
62+
35: type G = $Call<Fn2, number, string>;
63+
^^^^^^^^^^^^^^^^^^^^^^^^^^ number
64+
Member 2:
65+
35: type G = $Call<Fn2, number, string>;
66+
^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `B` of function call
67+
Error:
68+
38: ((null: mixed): G); // Error: mixed ~> number | string
69+
^^^^^ mixed. This type is incompatible with
70+
35: type G = $Call<Fn2, number, string>;
71+
^^^^^^^^^^^^^^^^^^^^^^^^^^ string
72+
73+
Error: test.js:39
74+
39: (g: number); // Error: number | string ~> number
75+
^ string. This type is incompatible with
76+
39: (g: number); // Error: number | string ~> number
77+
^^^^^^ number
78+
79+
Error: test.js:41
80+
41: (g: empty); // Error: number | string ~> empty
81+
^ number. This type is incompatible with
82+
41: (g: empty); // Error: number | string ~> empty
83+
^^^^^ empty
84+
85+
Error: test.js:41
86+
41: (g: empty); // Error: number | string ~> empty
87+
^ string. This type is incompatible with
88+
41: (g: empty); // Error: number | string ~> empty
89+
^^^^^ empty
90+
91+
Error: union.js:6
92+
6: ((null: mixed): A); // Error: mixed ~> number | string
93+
^^^^^ mixed. This type is incompatible with
94+
6: ((null: mixed): A); // Error: mixed ~> number | string
95+
^ union: function call(s)
96+
Member 1:
97+
3: type A = $Call<(() => number) | (() => string)>;
98+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function call
99+
Error:
100+
6: ((null: mixed): A); // Error: mixed ~> number | string
101+
^^^^^ mixed. This type is incompatible with
102+
3: type A = $Call<(() => number) | (() => string)>;
103+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ number
104+
Member 2:
105+
3: type A = $Call<(() => number) | (() => string)>;
106+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function call
107+
Error:
108+
6: ((null: mixed): A); // Error: mixed ~> number | string
109+
^^^^^ mixed. This type is incompatible with
110+
3: type A = $Call<(() => number) | (() => string)>;
111+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ string
112+
113+
Error: union.js:7
114+
7: (a: number); // Error: number | string ~> number
115+
^ string. This type is incompatible with
116+
7: (a: number); // Error: number | string ~> number
117+
^^^^^^ number
118+
119+
Error: union.js:9
120+
9: (a: empty); // Error: number | string ~> empty
121+
^ number. This type is incompatible with
122+
9: (a: empty); // Error: number | string ~> empty
123+
^^^^^ empty
124+
125+
Error: union.js:9
126+
9: (a: empty); // Error: number | string ~> empty
127+
^ string. This type is incompatible with
128+
9: (a: empty); // Error: number | string ~> empty
129+
^^^^^ empty
130+
131+
Error: union.js:14
132+
14: ((null: mixed): B); // Error: mixed ~> number | string
133+
^^^^^ mixed. This type is incompatible with
134+
14: ((null: mixed): B); // Error: mixed ~> number | string
135+
^ union: function call(s)
136+
Member 1:
137+
11: type B = $Call<(<T>(T) => T) | (<T>(any, T) => T), number, string>;
138+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function call
139+
Error:
140+
14: ((null: mixed): B); // Error: mixed ~> number | string
141+
^^^^^ mixed. This type is incompatible with
142+
11: type B = $Call<(<T>(T) => T) | (<T>(any, T) => T), number, string>;
143+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ number
144+
Member 2:
145+
11: type B = $Call<(<T>(T) => T) | (<T>(any, T) => T), number, string>;
146+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function call
147+
Error:
148+
14: ((null: mixed): B); // Error: mixed ~> number | string
149+
^^^^^ mixed. This type is incompatible with
150+
11: type B = $Call<(<T>(T) => T) | (<T>(any, T) => T), number, string>;
151+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ string
152+
153+
Error: union.js:15
154+
15: (b: number); // Error: number | string ~> number
155+
^ string. This type is incompatible with
156+
15: (b: number); // Error: number | string ~> number
157+
^^^^^^ number
158+
159+
Error: union.js:17
160+
17: (b: empty); // Error: number | string ~> empty
161+
^ number. This type is incompatible with
162+
17: (b: empty); // Error: number | string ~> empty
163+
^^^^^ empty
164+
165+
Error: union.js:17
166+
17: (b: empty); // Error: number | string ~> empty
167+
^ string. This type is incompatible with
168+
17: (b: empty); // Error: number | string ~> empty
169+
^^^^^ empty
170+
171+
Error: union.js:22
172+
22: ((null: mixed): C); // Error: mixed ~> number | string
173+
^^^^^ mixed. This type is incompatible with
174+
22: ((null: mixed): C); // Error: mixed ~> number | string
175+
^ union: number | string
176+
Member 1:
177+
19: type C = $Call<<T>(T) => T, number | string>;
178+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ number
179+
Error:
180+
22: ((null: mixed): C); // Error: mixed ~> number | string
181+
^^^^^ mixed. This type is incompatible with
182+
19: type C = $Call<<T>(T) => T, number | string>;
183+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ number
184+
Member 2:
185+
19: type C = $Call<<T>(T) => T, number | string>;
186+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ string
187+
Error:
188+
22: ((null: mixed): C); // Error: mixed ~> number | string
189+
^^^^^ mixed. This type is incompatible with
190+
19: type C = $Call<<T>(T) => T, number | string>;
191+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ string
192+
193+
Error: union.js:23
194+
23: (c: number); // Error: number | string ~> number
195+
^ string. This type is incompatible with
196+
23: (c: number); // Error: number | string ~> number
197+
^^^^^^ number
198+
199+
Error: union.js:25
200+
25: (c: empty); // Error: number | string ~> empty
201+
^ number. This type is incompatible with
202+
25: (c: empty); // Error: number | string ~> empty
203+
^^^^^ empty
204+
205+
Error: union.js:25
206+
25: (c: empty); // Error: number | string ~> empty
207+
^ string. This type is incompatible with
208+
25: (c: empty); // Error: number | string ~> empty
209+
^^^^^ empty
210+
211+
212+
Found 25 errors

tests/call_type/test.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// @flow
2+
3+
type Fn0 = () => number;
4+
type Fn1 = <T>(T) => T;
5+
type Fn2 = <A, B>(A, B) => A | B;
6+
7+
type A = $Call; // Error: one or more arguments are required.
8+
type B = $Call<>; // Error: one or more arguments are required.
9+
10+
type C = $Call<Fn0>;
11+
declare var c: C;
12+
(42: C); // OK
13+
((null: mixed): C); // Error: mixed ~> number
14+
(c: number); // OK
15+
(c: empty); // Error: number ~> empty
16+
17+
type D = $Call<Fn1>;
18+
declare var d: D;
19+
(42: D); // Error: function called with to few arguments.
20+
21+
type E = $Call<Fn1, number>;
22+
declare var e: E;
23+
(42: E); // OK
24+
((null: mixed): E); // Error: mixed ~> number
25+
(e: number); // OK
26+
(e: empty); // Error: number ~> empty
27+
28+
type F = $Call<Fn1, number, string>;
29+
declare var f: F;
30+
(42: F); // OK
31+
((null: mixed): F); // Error: mixed ~> number
32+
(f: number); // OK
33+
(f: empty); // Error: number ~> empty
34+
35+
type G = $Call<Fn2, number, string>;
36+
declare var g: G;
37+
(42: G); // OK
38+
((null: mixed): G); // Error: mixed ~> number | string
39+
(g: number); // Error: number | string ~> number
40+
(g: number | string); // OK
41+
(g: empty); // Error: number | string ~> empty

0 commit comments

Comments
 (0)