Skip to content

Commit fb23b93

Browse files
jbrown215facebook-github-bot
authored andcommitted
[parser] Add parser support for _ in constructors and calls
Summary: This diff adds support for parsing `_`, which will be used to specify that a type parameter should be implicitly instantiated. We add a new ast node to the Expression module, `TypeParameterInstantiation`. This is reminiscent of `Type`'s `ParameterInstantiation`, except that instead of a list of `Type.t`s, it contains a list of `Implicit of Loc.t | Explicit of Type.t`. When parsing `New` and `Call` type arguments, we parse `_` as an `Implicit` and all other types `t` as `Explicit t`. Creating the new ast node comes with a number of benefits: 1. External consumers of our AST currently consume `ParameterInstantiation` as it was originally designed: for type arguments to polymorphic types. Creating a new AST node makes sure we don't need to update all of those external consumers. 2. This new AST node allows OCaml to enforce the invariant that `_` can only appear in `Call` and `New`. 3. Related to 2., this more faithfully models the structure of our AST. `Call` and `New` have type arguments, but the fact that we used the same representation as we did for `Type` was just because they happened to have the same internal representation. These types are types we come across when parsing an expression, not a type annotation. We also now say that `_` is a reserved keyword when it's found in type positions, so it cannot be used unless it means implicit instantiation. We need to update babel to consider "_" to be a reserved identifier in type positions and to parse `_` as an `ImplicitInstantiationAnnotation`. Reviewed By: samwgoldman Differential Revision: D10105957 fbshipit-source-id: 3003b0cadbb1f9163a07bae1957710e9fbdeccdd
1 parent d2b32ea commit fb23b93

28 files changed

+887
-27
lines changed

src/parser/estree_translator.ml

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,7 @@ end with type t = Impl.t) = struct
450450
| loc, New _new -> New.(
451451
node "NewExpression" loc [
452452
"callee", expression _new.callee;
453-
"typeArguments", option type_parameter_instantiation _new.targs;
453+
"typeArguments", option type_parameter_instantiation_with_implicit _new.targs;
454454
"arguments", array_of_list expression_or_spread _new.arguments;
455455
]
456456
)
@@ -1030,6 +1030,13 @@ end with type t = Impl.t) = struct
10301030
| Exists -> exists_type loc
10311031
)
10321032

1033+
and implicit loc = generic_type (loc,
1034+
{Type.Generic.id = Type.Generic.Identifier.Unqualified (loc, "_"); targs = None})
1035+
1036+
and explicit_or_implicit_targ x = match x with
1037+
| Expression.TypeParameterInstantiation.Explicit t -> _type t
1038+
| Expression.TypeParameterInstantiation.Implicit loc -> implicit loc
1039+
10331040
and any_type loc = node "AnyTypeAnnotation" loc []
10341041

10351042
and mixed_type loc = node "MixedTypeAnnotation" loc []
@@ -1273,6 +1280,11 @@ end with type t = Impl.t) = struct
12731280
"params", array_of_list _type targs;
12741281
]
12751282

1283+
and type_parameter_instantiation_with_implicit (loc, targs) =
1284+
node "TypeParameterInstantiation" loc [
1285+
"params", array_of_list explicit_or_implicit_targ targs;
1286+
]
1287+
12761288
and jsx_element (loc, (element: (Loc.t, Loc.t) JSX.element)) = JSX.(
12771289
node "JSXElement" loc [
12781290
"openingElement", jsx_opening element.openingElement;
@@ -1458,7 +1470,7 @@ end with type t = Impl.t) = struct
14581470

14591471
and call_node_properties call = Expression.Call.([
14601472
"callee", expression call.callee;
1461-
"typeArguments", option type_parameter_instantiation call.targs;
1473+
"typeArguments", option type_parameter_instantiation_with_implicit call.targs;
14621474
"arguments", array_of_list expression_or_spread call.arguments;
14631475
])
14641476

src/parser/expression_parser.ml

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,7 @@ module Expression
572572
(* Parameterized call syntax is ambiguous, so we fall back to
573573
standard parsing if it fails. *)
574574
Try.or_else env ~fallback:left (fun env ->
575-
let targs = Type.type_parameter_instantiation env in
575+
let targs = type_parameter_instantiation env in
576576
arguments ?targs env
577577
)
578578
| _ -> left
@@ -622,7 +622,7 @@ module Expression
622622
standard parsing if it fails. *)
623623
let error_callback _ _ = raise Try.Rollback in
624624
let env = env |> with_error_callback error_callback in
625-
Try.or_else env ~fallback:None Type.type_parameter_instantiation
625+
Try.or_else env ~fallback:None type_parameter_instantiation
626626
else
627627
None
628628
in
@@ -637,6 +637,35 @@ module Expression
637637
arguments;
638638
}))
639639

640+
and type_parameter_instantiation =
641+
let args env acc =
642+
let rec args_helper env acc =
643+
match Peek.token env with
644+
| T_EOF
645+
| T_GREATER_THAN -> List.rev acc
646+
| _ ->
647+
let t = match Peek.token env with
648+
| T_IDENTIFIER {value = "_"; _} ->
649+
let loc = Peek.loc env in
650+
Expect.identifier env "_";
651+
Expression.TypeParameterInstantiation.Implicit loc
652+
| _ -> Expression.TypeParameterInstantiation.Explicit(Type._type env)
653+
in
654+
let acc = t::acc in
655+
if Peek.token env <> T_GREATER_THAN
656+
then Expect.token env T_COMMA;
657+
args_helper env acc
658+
in args_helper env acc
659+
660+
in fun env -> if Peek.token env = T_LESS_THAN then
661+
Some (with_loc (fun env ->
662+
Expect.token env T_LESS_THAN;
663+
let args = args env [] in
664+
Expect.token env T_GREATER_THAN;
665+
args
666+
) env)
667+
else None
668+
640669
and arguments =
641670
let argument env =
642671
match Peek.token env with

src/parser/flow_ast.ml

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ and Type : sig
249249
and ('M, 'T) t' = ('M, 'T) TypeParam.t list
250250
[@@deriving show]
251251
end
252+
252253
module ParameterInstantiation : sig
253254
type ('M, 'T) t = 'M * ('M, 'T) t'
254255
and ('M, 'T) t' = ('M, 'T) Type.t list
@@ -627,6 +628,14 @@ and Statement : sig
627628
end = Statement
628629

629630
and Expression : sig
631+
632+
module TypeParameterInstantiation : sig
633+
type ('M, 'T) t = 'M * ('M, 'T) t'
634+
and ('M, 'T) type_parameter_instantiation = Explicit of ('M, 'T) Type.t | Implicit of 'T
635+
and ('M, 'T) t' = ('M, 'T) type_parameter_instantiation list
636+
[@@deriving show]
637+
end
638+
630639
module SpreadElement : sig
631640
type ('M, 'T) t = 'M * ('M, 'T) t'
632641
and ('M, 'T) t' = {
@@ -838,15 +847,15 @@ and Expression : sig
838847
module New : sig
839848
type ('M, 'T) t = {
840849
callee: ('M, 'T) Expression.t;
841-
targs: ('M, 'T) Type.ParameterInstantiation.t option;
850+
targs: ('M, 'T) Expression.TypeParameterInstantiation.t option;
842851
arguments: ('M, 'T) expression_or_spread list;
843852
}
844853
[@@deriving show]
845854
end
846855
module Call : sig
847856
type ('M, 'T) t = {
848857
callee: ('M, 'T) Expression.t;
849-
targs: ('M, 'T) Type.ParameterInstantiation.t option;
858+
targs: ('M, 'T) Expression.TypeParameterInstantiation.t option;
850859
arguments: ('M, 'T) expression_or_spread list;
851860
}
852861
[@@deriving show]

src/parser/parser_env.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ let is_reserved str_val =
440440
let is_reserved_type str_val =
441441
match str_val with
442442
| "any" | "bool" | "boolean" | "empty" | "false" | "mixed" | "null" | "number"
443-
| "static" | "string" | "true" | "typeof" | "void" | "interface" | "extends"
443+
| "static" | "string" | "true" | "typeof" | "void" | "interface" | "extends" | "_"
444444
-> true
445445
| _ -> false
446446

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
test<
2+
_,
3+
_,
4+
number,
5+
_,
6+
_,
7+
>();
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
{
2+
"type":"Program",
3+
"loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":7,"column":4}},
4+
"range":[0,40],
5+
"body":[
6+
{
7+
"type":"ExpressionStatement",
8+
"loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":7,"column":4}},
9+
"range":[0,40],
10+
"expression":{
11+
"type":"CallExpression",
12+
"loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":7,"column":3}},
13+
"range":[0,39],
14+
"callee":{
15+
"type":"Identifier",
16+
"loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":4}},
17+
"range":[0,4],
18+
"name":"test",
19+
"typeAnnotation":null,
20+
"optional":false
21+
},
22+
"typeArguments":{
23+
"type":"TypeParameterInstantiation",
24+
"loc":{"source":null,"start":{"line":1,"column":4},"end":{"line":7,"column":1}},
25+
"range":[4,37],
26+
"params":[
27+
{
28+
"type":"GenericTypeAnnotation",
29+
"loc":{"source":null,"start":{"line":2,"column":2},"end":{"line":2,"column":3}},
30+
"range":[8,9],
31+
"id":{
32+
"type":"Identifier",
33+
"loc":{"source":null,"start":{"line":2,"column":2},"end":{"line":2,"column":3}},
34+
"range":[8,9],
35+
"name":"_",
36+
"typeAnnotation":null,
37+
"optional":false
38+
},
39+
"typeParameters":null
40+
},
41+
{
42+
"type":"GenericTypeAnnotation",
43+
"loc":{"source":null,"start":{"line":3,"column":2},"end":{"line":3,"column":3}},
44+
"range":[13,14],
45+
"id":{
46+
"type":"Identifier",
47+
"loc":{"source":null,"start":{"line":3,"column":2},"end":{"line":3,"column":3}},
48+
"range":[13,14],
49+
"name":"_",
50+
"typeAnnotation":null,
51+
"optional":false
52+
},
53+
"typeParameters":null
54+
},
55+
{
56+
"type":"NumberTypeAnnotation",
57+
"loc":{"source":null,"start":{"line":4,"column":2},"end":{"line":4,"column":8}},
58+
"range":[18,24]
59+
},
60+
{
61+
"type":"GenericTypeAnnotation",
62+
"loc":{"source":null,"start":{"line":5,"column":2},"end":{"line":5,"column":3}},
63+
"range":[28,29],
64+
"id":{
65+
"type":"Identifier",
66+
"loc":{"source":null,"start":{"line":5,"column":2},"end":{"line":5,"column":3}},
67+
"range":[28,29],
68+
"name":"_",
69+
"typeAnnotation":null,
70+
"optional":false
71+
},
72+
"typeParameters":null
73+
},
74+
{
75+
"type":"GenericTypeAnnotation",
76+
"loc":{"source":null,"start":{"line":6,"column":2},"end":{"line":6,"column":3}},
77+
"range":[33,34],
78+
"id":{
79+
"type":"Identifier",
80+
"loc":{"source":null,"start":{"line":6,"column":2},"end":{"line":6,"column":3}},
81+
"range":[33,34],
82+
"name":"_",
83+
"typeAnnotation":null,
84+
"optional":false
85+
},
86+
"typeParameters":null
87+
}
88+
]
89+
},
90+
"arguments":[]
91+
},
92+
"directive":null
93+
}
94+
],
95+
"comments":[]
96+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
test<number, _, string, _, _, _, Foo, Bar, Baz>();
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
{
2+
"type":"Program",
3+
"loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":50}},
4+
"range":[0,50],
5+
"body":[
6+
{
7+
"type":"ExpressionStatement",
8+
"loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":50}},
9+
"range":[0,50],
10+
"expression":{
11+
"type":"CallExpression",
12+
"loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":49}},
13+
"range":[0,49],
14+
"callee":{
15+
"type":"Identifier",
16+
"loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":4}},
17+
"range":[0,4],
18+
"name":"test",
19+
"typeAnnotation":null,
20+
"optional":false
21+
},
22+
"typeArguments":{
23+
"type":"TypeParameterInstantiation",
24+
"loc":{"source":null,"start":{"line":1,"column":4},"end":{"line":1,"column":47}},
25+
"range":[4,47],
26+
"params":[
27+
{
28+
"type":"NumberTypeAnnotation",
29+
"loc":{"source":null,"start":{"line":1,"column":5},"end":{"line":1,"column":11}},
30+
"range":[5,11]
31+
},
32+
{
33+
"type":"GenericTypeAnnotation",
34+
"loc":{"source":null,"start":{"line":1,"column":13},"end":{"line":1,"column":14}},
35+
"range":[13,14],
36+
"id":{
37+
"type":"Identifier",
38+
"loc":{"source":null,"start":{"line":1,"column":13},"end":{"line":1,"column":14}},
39+
"range":[13,14],
40+
"name":"_",
41+
"typeAnnotation":null,
42+
"optional":false
43+
},
44+
"typeParameters":null
45+
},
46+
{
47+
"type":"StringTypeAnnotation",
48+
"loc":{"source":null,"start":{"line":1,"column":16},"end":{"line":1,"column":22}},
49+
"range":[16,22]
50+
},
51+
{
52+
"type":"GenericTypeAnnotation",
53+
"loc":{"source":null,"start":{"line":1,"column":24},"end":{"line":1,"column":25}},
54+
"range":[24,25],
55+
"id":{
56+
"type":"Identifier",
57+
"loc":{"source":null,"start":{"line":1,"column":24},"end":{"line":1,"column":25}},
58+
"range":[24,25],
59+
"name":"_",
60+
"typeAnnotation":null,
61+
"optional":false
62+
},
63+
"typeParameters":null
64+
},
65+
{
66+
"type":"GenericTypeAnnotation",
67+
"loc":{"source":null,"start":{"line":1,"column":27},"end":{"line":1,"column":28}},
68+
"range":[27,28],
69+
"id":{
70+
"type":"Identifier",
71+
"loc":{"source":null,"start":{"line":1,"column":27},"end":{"line":1,"column":28}},
72+
"range":[27,28],
73+
"name":"_",
74+
"typeAnnotation":null,
75+
"optional":false
76+
},
77+
"typeParameters":null
78+
},
79+
{
80+
"type":"GenericTypeAnnotation",
81+
"loc":{"source":null,"start":{"line":1,"column":30},"end":{"line":1,"column":31}},
82+
"range":[30,31],
83+
"id":{
84+
"type":"Identifier",
85+
"loc":{"source":null,"start":{"line":1,"column":30},"end":{"line":1,"column":31}},
86+
"range":[30,31],
87+
"name":"_",
88+
"typeAnnotation":null,
89+
"optional":false
90+
},
91+
"typeParameters":null
92+
},
93+
{
94+
"type":"GenericTypeAnnotation",
95+
"loc":{"source":null,"start":{"line":1,"column":33},"end":{"line":1,"column":36}},
96+
"range":[33,36],
97+
"id":{
98+
"type":"Identifier",
99+
"loc":{"source":null,"start":{"line":1,"column":33},"end":{"line":1,"column":36}},
100+
"range":[33,36],
101+
"name":"Foo",
102+
"typeAnnotation":null,
103+
"optional":false
104+
},
105+
"typeParameters":null
106+
},
107+
{
108+
"type":"GenericTypeAnnotation",
109+
"loc":{"source":null,"start":{"line":1,"column":38},"end":{"line":1,"column":41}},
110+
"range":[38,41],
111+
"id":{
112+
"type":"Identifier",
113+
"loc":{"source":null,"start":{"line":1,"column":38},"end":{"line":1,"column":41}},
114+
"range":[38,41],
115+
"name":"Bar",
116+
"typeAnnotation":null,
117+
"optional":false
118+
},
119+
"typeParameters":null
120+
},
121+
{
122+
"type":"GenericTypeAnnotation",
123+
"loc":{"source":null,"start":{"line":1,"column":43},"end":{"line":1,"column":46}},
124+
"range":[43,46],
125+
"id":{
126+
"type":"Identifier",
127+
"loc":{"source":null,"start":{"line":1,"column":43},"end":{"line":1,"column":46}},
128+
"range":[43,46],
129+
"name":"Baz",
130+
"typeAnnotation":null,
131+
"optional":false
132+
},
133+
"typeParameters":null
134+
}
135+
]
136+
},
137+
"arguments":[]
138+
},
139+
"directive":null
140+
}
141+
],
142+
"comments":[]
143+
}

0 commit comments

Comments
 (0)