Skip to content

Commit

Permalink
[parser] Add parser support for _ in constructors and calls
Browse files Browse the repository at this point in the history
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
  • Loading branch information
jbrown215 authored and facebook-github-bot committed Oct 9, 2018
1 parent d2b32ea commit fb23b93
Show file tree
Hide file tree
Showing 28 changed files with 887 additions and 27 deletions.
16 changes: 14 additions & 2 deletions src/parser/estree_translator.ml
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ end with type t = Impl.t) = struct
| loc, New _new -> New.(
node "NewExpression" loc [
"callee", expression _new.callee;
"typeArguments", option type_parameter_instantiation _new.targs;
"typeArguments", option type_parameter_instantiation_with_implicit _new.targs;
"arguments", array_of_list expression_or_spread _new.arguments;
]
)
Expand Down Expand Up @@ -1030,6 +1030,13 @@ end with type t = Impl.t) = struct
| Exists -> exists_type loc
)

and implicit loc = generic_type (loc,
{Type.Generic.id = Type.Generic.Identifier.Unqualified (loc, "_"); targs = None})

and explicit_or_implicit_targ x = match x with
| Expression.TypeParameterInstantiation.Explicit t -> _type t
| Expression.TypeParameterInstantiation.Implicit loc -> implicit loc

and any_type loc = node "AnyTypeAnnotation" loc []

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

and type_parameter_instantiation_with_implicit (loc, targs) =
node "TypeParameterInstantiation" loc [
"params", array_of_list explicit_or_implicit_targ targs;
]

and jsx_element (loc, (element: (Loc.t, Loc.t) JSX.element)) = JSX.(
node "JSXElement" loc [
"openingElement", jsx_opening element.openingElement;
Expand Down Expand Up @@ -1458,7 +1470,7 @@ end with type t = Impl.t) = struct

and call_node_properties call = Expression.Call.([
"callee", expression call.callee;
"typeArguments", option type_parameter_instantiation call.targs;
"typeArguments", option type_parameter_instantiation_with_implicit call.targs;
"arguments", array_of_list expression_or_spread call.arguments;
])

Expand Down
33 changes: 31 additions & 2 deletions src/parser/expression_parser.ml
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,7 @@ module Expression
(* Parameterized call syntax is ambiguous, so we fall back to
standard parsing if it fails. *)
Try.or_else env ~fallback:left (fun env ->
let targs = Type.type_parameter_instantiation env in
let targs = type_parameter_instantiation env in
arguments ?targs env
)
| _ -> left
Expand Down Expand Up @@ -622,7 +622,7 @@ module Expression
standard parsing if it fails. *)
let error_callback _ _ = raise Try.Rollback in
let env = env |> with_error_callback error_callback in
Try.or_else env ~fallback:None Type.type_parameter_instantiation
Try.or_else env ~fallback:None type_parameter_instantiation
else
None
in
Expand All @@ -637,6 +637,35 @@ module Expression
arguments;
}))

and type_parameter_instantiation =
let args env acc =
let rec args_helper env acc =
match Peek.token env with
| T_EOF
| T_GREATER_THAN -> List.rev acc
| _ ->
let t = match Peek.token env with
| T_IDENTIFIER {value = "_"; _} ->
let loc = Peek.loc env in
Expect.identifier env "_";
Expression.TypeParameterInstantiation.Implicit loc
| _ -> Expression.TypeParameterInstantiation.Explicit(Type._type env)
in
let acc = t::acc in
if Peek.token env <> T_GREATER_THAN
then Expect.token env T_COMMA;
args_helper env acc
in args_helper env acc

in fun env -> if Peek.token env = T_LESS_THAN then
Some (with_loc (fun env ->
Expect.token env T_LESS_THAN;
let args = args env [] in
Expect.token env T_GREATER_THAN;
args
) env)
else None

and arguments =
let argument env =
match Peek.token env with
Expand Down
13 changes: 11 additions & 2 deletions src/parser/flow_ast.ml
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ and Type : sig
and ('M, 'T) t' = ('M, 'T) TypeParam.t list
[@@deriving show]
end

module ParameterInstantiation : sig
type ('M, 'T) t = 'M * ('M, 'T) t'
and ('M, 'T) t' = ('M, 'T) Type.t list
Expand Down Expand Up @@ -627,6 +628,14 @@ and Statement : sig
end = Statement

and Expression : sig

module TypeParameterInstantiation : sig
type ('M, 'T) t = 'M * ('M, 'T) t'
and ('M, 'T) type_parameter_instantiation = Explicit of ('M, 'T) Type.t | Implicit of 'T
and ('M, 'T) t' = ('M, 'T) type_parameter_instantiation list
[@@deriving show]
end

module SpreadElement : sig
type ('M, 'T) t = 'M * ('M, 'T) t'
and ('M, 'T) t' = {
Expand Down Expand Up @@ -838,15 +847,15 @@ and Expression : sig
module New : sig
type ('M, 'T) t = {
callee: ('M, 'T) Expression.t;
targs: ('M, 'T) Type.ParameterInstantiation.t option;
targs: ('M, 'T) Expression.TypeParameterInstantiation.t option;
arguments: ('M, 'T) expression_or_spread list;
}
[@@deriving show]
end
module Call : sig
type ('M, 'T) t = {
callee: ('M, 'T) Expression.t;
targs: ('M, 'T) Type.ParameterInstantiation.t option;
targs: ('M, 'T) Expression.TypeParameterInstantiation.t option;
arguments: ('M, 'T) expression_or_spread list;
}
[@@deriving show]
Expand Down
2 changes: 1 addition & 1 deletion src/parser/parser_env.ml
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ let is_reserved str_val =
let is_reserved_type str_val =
match str_val with
| "any" | "bool" | "boolean" | "empty" | "false" | "mixed" | "null" | "number"
| "static" | "string" | "true" | "typeof" | "void" | "interface" | "extends"
| "static" | "string" | "true" | "typeof" | "void" | "interface" | "extends" | "_"
-> true
| _ -> false

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
test<
_,
_,
number,
_,
_,
>();
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
{
"type":"Program",
"loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":7,"column":4}},
"range":[0,40],
"body":[
{
"type":"ExpressionStatement",
"loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":7,"column":4}},
"range":[0,40],
"expression":{
"type":"CallExpression",
"loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":7,"column":3}},
"range":[0,39],
"callee":{
"type":"Identifier",
"loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":4}},
"range":[0,4],
"name":"test",
"typeAnnotation":null,
"optional":false
},
"typeArguments":{
"type":"TypeParameterInstantiation",
"loc":{"source":null,"start":{"line":1,"column":4},"end":{"line":7,"column":1}},
"range":[4,37],
"params":[
{
"type":"GenericTypeAnnotation",
"loc":{"source":null,"start":{"line":2,"column":2},"end":{"line":2,"column":3}},
"range":[8,9],
"id":{
"type":"Identifier",
"loc":{"source":null,"start":{"line":2,"column":2},"end":{"line":2,"column":3}},
"range":[8,9],
"name":"_",
"typeAnnotation":null,
"optional":false
},
"typeParameters":null
},
{
"type":"GenericTypeAnnotation",
"loc":{"source":null,"start":{"line":3,"column":2},"end":{"line":3,"column":3}},
"range":[13,14],
"id":{
"type":"Identifier",
"loc":{"source":null,"start":{"line":3,"column":2},"end":{"line":3,"column":3}},
"range":[13,14],
"name":"_",
"typeAnnotation":null,
"optional":false
},
"typeParameters":null
},
{
"type":"NumberTypeAnnotation",
"loc":{"source":null,"start":{"line":4,"column":2},"end":{"line":4,"column":8}},
"range":[18,24]
},
{
"type":"GenericTypeAnnotation",
"loc":{"source":null,"start":{"line":5,"column":2},"end":{"line":5,"column":3}},
"range":[28,29],
"id":{
"type":"Identifier",
"loc":{"source":null,"start":{"line":5,"column":2},"end":{"line":5,"column":3}},
"range":[28,29],
"name":"_",
"typeAnnotation":null,
"optional":false
},
"typeParameters":null
},
{
"type":"GenericTypeAnnotation",
"loc":{"source":null,"start":{"line":6,"column":2},"end":{"line":6,"column":3}},
"range":[33,34],
"id":{
"type":"Identifier",
"loc":{"source":null,"start":{"line":6,"column":2},"end":{"line":6,"column":3}},
"range":[33,34],
"name":"_",
"typeAnnotation":null,
"optional":false
},
"typeParameters":null
}
]
},
"arguments":[]
},
"directive":null
}
],
"comments":[]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test<number, _, string, _, _, _, Foo, Bar, Baz>();
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
{
"type":"Program",
"loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":50}},
"range":[0,50],
"body":[
{
"type":"ExpressionStatement",
"loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":50}},
"range":[0,50],
"expression":{
"type":"CallExpression",
"loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":49}},
"range":[0,49],
"callee":{
"type":"Identifier",
"loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":4}},
"range":[0,4],
"name":"test",
"typeAnnotation":null,
"optional":false
},
"typeArguments":{
"type":"TypeParameterInstantiation",
"loc":{"source":null,"start":{"line":1,"column":4},"end":{"line":1,"column":47}},
"range":[4,47],
"params":[
{
"type":"NumberTypeAnnotation",
"loc":{"source":null,"start":{"line":1,"column":5},"end":{"line":1,"column":11}},
"range":[5,11]
},
{
"type":"GenericTypeAnnotation",
"loc":{"source":null,"start":{"line":1,"column":13},"end":{"line":1,"column":14}},
"range":[13,14],
"id":{
"type":"Identifier",
"loc":{"source":null,"start":{"line":1,"column":13},"end":{"line":1,"column":14}},
"range":[13,14],
"name":"_",
"typeAnnotation":null,
"optional":false
},
"typeParameters":null
},
{
"type":"StringTypeAnnotation",
"loc":{"source":null,"start":{"line":1,"column":16},"end":{"line":1,"column":22}},
"range":[16,22]
},
{
"type":"GenericTypeAnnotation",
"loc":{"source":null,"start":{"line":1,"column":24},"end":{"line":1,"column":25}},
"range":[24,25],
"id":{
"type":"Identifier",
"loc":{"source":null,"start":{"line":1,"column":24},"end":{"line":1,"column":25}},
"range":[24,25],
"name":"_",
"typeAnnotation":null,
"optional":false
},
"typeParameters":null
},
{
"type":"GenericTypeAnnotation",
"loc":{"source":null,"start":{"line":1,"column":27},"end":{"line":1,"column":28}},
"range":[27,28],
"id":{
"type":"Identifier",
"loc":{"source":null,"start":{"line":1,"column":27},"end":{"line":1,"column":28}},
"range":[27,28],
"name":"_",
"typeAnnotation":null,
"optional":false
},
"typeParameters":null
},
{
"type":"GenericTypeAnnotation",
"loc":{"source":null,"start":{"line":1,"column":30},"end":{"line":1,"column":31}},
"range":[30,31],
"id":{
"type":"Identifier",
"loc":{"source":null,"start":{"line":1,"column":30},"end":{"line":1,"column":31}},
"range":[30,31],
"name":"_",
"typeAnnotation":null,
"optional":false
},
"typeParameters":null
},
{
"type":"GenericTypeAnnotation",
"loc":{"source":null,"start":{"line":1,"column":33},"end":{"line":1,"column":36}},
"range":[33,36],
"id":{
"type":"Identifier",
"loc":{"source":null,"start":{"line":1,"column":33},"end":{"line":1,"column":36}},
"range":[33,36],
"name":"Foo",
"typeAnnotation":null,
"optional":false
},
"typeParameters":null
},
{
"type":"GenericTypeAnnotation",
"loc":{"source":null,"start":{"line":1,"column":38},"end":{"line":1,"column":41}},
"range":[38,41],
"id":{
"type":"Identifier",
"loc":{"source":null,"start":{"line":1,"column":38},"end":{"line":1,"column":41}},
"range":[38,41],
"name":"Bar",
"typeAnnotation":null,
"optional":false
},
"typeParameters":null
},
{
"type":"GenericTypeAnnotation",
"loc":{"source":null,"start":{"line":1,"column":43},"end":{"line":1,"column":46}},
"range":[43,46],
"id":{
"type":"Identifier",
"loc":{"source":null,"start":{"line":1,"column":43},"end":{"line":1,"column":46}},
"range":[43,46],
"name":"Baz",
"typeAnnotation":null,
"optional":false
},
"typeParameters":null
}
]
},
"arguments":[]
},
"directive":null
}
],
"comments":[]
}
Loading

0 comments on commit fb23b93

Please sign in to comment.