From c18ee0d8ee7999ef65ee21d0113b7351c5dc1e15 Mon Sep 17 00:00:00 2001 From: Sam Goldman Date: Wed, 5 Jun 2019 15:35:55 -0700 Subject: [PATCH] Allow type parameter defaults in function declarations Summary: When type parameter defaults were added (D3196321), it was not possible to supply explicit type arguments to function calls. Now that explicit type arguments to function calls are supported, it can be useful to define a polymorphic function with type parameter defaults. Reviewed By: gabelevi Differential Revision: D15679697 fbshipit-source-id: 309df3194a7e02f69ec398c56d004166d6e519e2 --- src/parser/object_parser.ml | 4 +- src/parser/statement_parser.ml | 8 +- .../migrated_0026.tree.json | 29 ++--- .../migrated_0027.tree.json | 27 ++--- .../migrated_0028.tree.json | 29 ++--- .../migrated_0029.tree.json | 31 ++---- .../migrated_0030.tree.json | 31 ++---- .../migrated_0031.tree.json | 29 ++--- .../migrated_0032.tree.json | 100 +++++++----------- src/parser/type_parser.ml | 29 +++-- 10 files changed, 98 insertions(+), 219 deletions(-) diff --git a/src/parser/object_parser.ml b/src/parser/object_parser.ml index f0d625fae4c..cfc7819e489 100644 --- a/src/parser/object_parser.ml +++ b/src/parser/object_parser.ml @@ -701,7 +701,7 @@ module Object | true, false -> None | _ -> Some(Parse.identifier tmp_env) ) in - let tparams = Type.type_parameter_declaration_with_defaults env in + let tparams = Type.type_parameter_declaration env in let body, extends, implements = _class env in Ast.Statement.ClassDeclaration { Class. id; @@ -724,7 +724,7 @@ module Object | T_LCURLY -> None, None | _ -> let id = Some (Parse.identifier env) in - let tparams = Type.type_parameter_declaration_with_defaults env in + let tparams = Type.type_parameter_declaration env in id, tparams in let body, extends, implements = _class env in Ast.Expression.Class { Class. diff --git a/src/parser/statement_parser.ml b/src/parser/statement_parser.ml index b5b7dc141e3..6ee25f8b67d 100644 --- a/src/parser/statement_parser.ml +++ b/src/parser/statement_parser.ml @@ -540,7 +540,7 @@ module Statement Expect.token env T_TYPE; Eat.push_lex_mode env Lex_mode.TYPE; let id = Type.type_identifier env in - let tparams = Type.type_parameter_declaration_with_defaults env in + let tparams = Type.type_parameter_declaration env in Expect.token env T_ASSIGN; let right = Type._type env in Eat.semicolon env; @@ -572,7 +572,7 @@ module Statement Expect.token env T_TYPE; Eat.push_lex_mode env Lex_mode.TYPE; let id = Type.type_identifier env in - let tparams = Type.type_parameter_declaration_with_defaults env in + let tparams = Type.type_parameter_declaration env in let supertype = match Peek.token env with | T_COLON -> Expect.token env T_COLON; @@ -610,7 +610,7 @@ module Statement then error env Error.UnexpectedTypeInterface; Expect.token env T_INTERFACE; let id = Type.type_identifier env in - let tparams = Type.type_parameter_declaration_with_defaults env in + let tparams = Type.type_parameter_declaration env in let { Ast.Type.Interface.extends; body } = Type.interface_helper env in Statement.Interface.({ id; @@ -649,7 +649,7 @@ module Statement let env = env |> with_strict true in Expect.token env T_CLASS; let id = Parse.identifier env in - let tparams = Type.type_parameter_declaration_with_defaults env in + let tparams = Type.type_parameter_declaration env in let extends = if Expect.maybe env T_EXTENDS then Some (Type.generic env) else None in let mixins = match Peek.token env with | T_IDENTIFIER { raw = "mixins"; _ } -> Eat.token env; mixins env [] diff --git a/src/parser/test/flow/types/parameter_defaults/migrated_0026.tree.json b/src/parser/test/flow/types/parameter_defaults/migrated_0026.tree.json index 12635f2f14a..5f42722e2fc 100644 --- a/src/parser/test/flow/types/parameter_defaults/migrated_0026.tree.json +++ b/src/parser/test/flow/types/parameter_defaults/migrated_0026.tree.json @@ -1,14 +1,4 @@ { - "errors":[ - { - "loc":{"source":null,"start":{"line":1,"column":15},"end":{"line":1,"column":16}}, - "message":"Unexpected token =" - }, - { - "loc":{"source":null,"start":{"line":1,"column":17},"end":{"line":1,"column":23}}, - "message":"Unexpected reserved type" - } - ], "type":"Program", "loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":29}}, "range":[0,29], @@ -44,21 +34,16 @@ "params":[ { "type":"TypeParameter", - "loc":{"source":null,"start":{"line":1,"column":13},"end":{"line":1,"column":14}}, - "range":[13,14], + "loc":{"source":null,"start":{"line":1,"column":13},"end":{"line":1,"column":23}}, + "range":[13,23], "name":"T", "bound":null, "variance":null, - "default":null - }, - { - "type":"TypeParameter", - "loc":{"source":null,"start":{"line":1,"column":17},"end":{"line":1,"column":23}}, - "range":[17,23], - "name":"string", - "bound":null, - "variance":null, - "default":null + "default":{ + "type":"StringTypeAnnotation", + "loc":{"source":null,"start":{"line":1,"column":17},"end":{"line":1,"column":23}}, + "range":[17,23] + } } ] } diff --git a/src/parser/test/flow/types/parameter_defaults/migrated_0027.tree.json b/src/parser/test/flow/types/parameter_defaults/migrated_0027.tree.json index d94c2059d2d..1e31abb2fa2 100644 --- a/src/parser/test/flow/types/parameter_defaults/migrated_0027.tree.json +++ b/src/parser/test/flow/types/parameter_defaults/migrated_0027.tree.json @@ -1,13 +1,5 @@ { "errors":[ - { - "loc":{"source":null,"start":{"line":1,"column":23},"end":{"line":1,"column":24}}, - "message":"Unexpected token =" - }, - { - "loc":{"source":null,"start":{"line":1,"column":25},"end":{"line":1,"column":31}}, - "message":"Unexpected reserved type" - }, { "loc":{"source":null,"start":{"line":1,"column":35},"end":{"line":1,"column":36}}, "message":"Unexpected token {" @@ -56,21 +48,16 @@ "params":[ { "type":"TypeParameter", - "loc":{"source":null,"start":{"line":1,"column":21},"end":{"line":1,"column":22}}, - "range":[21,22], + "loc":{"source":null,"start":{"line":1,"column":21},"end":{"line":1,"column":31}}, + "range":[21,31], "name":"T", "bound":null, "variance":null, - "default":null - }, - { - "type":"TypeParameter", - "loc":{"source":null,"start":{"line":1,"column":25},"end":{"line":1,"column":31}}, - "range":[25,31], - "name":"string", - "bound":null, - "variance":null, - "default":null + "default":{ + "type":"StringTypeAnnotation", + "loc":{"source":null,"start":{"line":1,"column":25},"end":{"line":1,"column":31}}, + "range":[25,31] + } } ] } diff --git a/src/parser/test/flow/types/parameter_defaults/migrated_0028.tree.json b/src/parser/test/flow/types/parameter_defaults/migrated_0028.tree.json index e614aed9d12..373e67ae897 100644 --- a/src/parser/test/flow/types/parameter_defaults/migrated_0028.tree.json +++ b/src/parser/test/flow/types/parameter_defaults/migrated_0028.tree.json @@ -1,14 +1,4 @@ { - "errors":[ - { - "loc":{"source":null,"start":{"line":1,"column":9},"end":{"line":1,"column":10}}, - "message":"Unexpected token =" - }, - { - "loc":{"source":null,"start":{"line":1,"column":11},"end":{"line":1,"column":17}}, - "message":"Unexpected reserved type" - } - ], "type":"Program", "loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":26}}, "range":[0,26], @@ -58,21 +48,16 @@ "params":[ { "type":"TypeParameter", - "loc":{"source":null,"start":{"line":1,"column":7},"end":{"line":1,"column":8}}, - "range":[7,8], + "loc":{"source":null,"start":{"line":1,"column":7},"end":{"line":1,"column":17}}, + "range":[7,17], "name":"T", "bound":null, "variance":null, - "default":null - }, - { - "type":"TypeParameter", - "loc":{"source":null,"start":{"line":1,"column":11},"end":{"line":1,"column":17}}, - "range":[11,17], - "name":"string", - "bound":null, - "variance":null, - "default":null + "default":{ + "type":"StringTypeAnnotation", + "loc":{"source":null,"start":{"line":1,"column":11},"end":{"line":1,"column":17}}, + "range":[11,17] + } } ] } diff --git a/src/parser/test/flow/types/parameter_defaults/migrated_0029.tree.json b/src/parser/test/flow/types/parameter_defaults/migrated_0029.tree.json index b6043211145..68e557023e4 100644 --- a/src/parser/test/flow/types/parameter_defaults/migrated_0029.tree.json +++ b/src/parser/test/flow/types/parameter_defaults/migrated_0029.tree.json @@ -1,14 +1,4 @@ { - "errors":[ - { - "loc":{"source":null,"start":{"line":1,"column":16},"end":{"line":1,"column":17}}, - "message":"Unexpected token =" - }, - { - "loc":{"source":null,"start":{"line":1,"column":18},"end":{"line":1,"column":24}}, - "message":"Unexpected reserved type" - } - ], "type":"Program", "loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":32}}, "range":[0,32], @@ -66,21 +56,16 @@ "params":[ { "type":"TypeParameter", - "loc":{"source":null,"start":{"line":1,"column":14},"end":{"line":1,"column":15}}, - "range":[14,15], + "loc":{"source":null,"start":{"line":1,"column":14},"end":{"line":1,"column":24}}, + "range":[14,24], "name":"T", "bound":null, "variance":null, - "default":null - }, - { - "type":"TypeParameter", - "loc":{"source":null,"start":{"line":1,"column":18},"end":{"line":1,"column":24}}, - "range":[18,24], - "name":"string", - "bound":null, - "variance":null, - "default":null + "default":{ + "type":"StringTypeAnnotation", + "loc":{"source":null,"start":{"line":1,"column":18},"end":{"line":1,"column":24}}, + "range":[18,24] + } } ] } @@ -92,8 +77,8 @@ } ] }, - "superClass":null, "typeParameters":null, + "superClass":null, "superTypeParameters":null, "implements":[], "decorators":[] diff --git a/src/parser/test/flow/types/parameter_defaults/migrated_0030.tree.json b/src/parser/test/flow/types/parameter_defaults/migrated_0030.tree.json index 4ac5a83af90..2acfbcc6575 100644 --- a/src/parser/test/flow/types/parameter_defaults/migrated_0030.tree.json +++ b/src/parser/test/flow/types/parameter_defaults/migrated_0030.tree.json @@ -1,14 +1,4 @@ { - "errors":[ - { - "loc":{"source":null,"start":{"line":1,"column":17},"end":{"line":1,"column":18}}, - "message":"Unexpected token =" - }, - { - "loc":{"source":null,"start":{"line":1,"column":19},"end":{"line":1,"column":25}}, - "message":"Unexpected reserved type" - } - ], "type":"Program", "loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":34}}, "range":[0,34], @@ -70,21 +60,16 @@ "params":[ { "type":"TypeParameter", - "loc":{"source":null,"start":{"line":1,"column":15},"end":{"line":1,"column":16}}, - "range":[15,16], + "loc":{"source":null,"start":{"line":1,"column":15},"end":{"line":1,"column":25}}, + "range":[15,25], "name":"T", "bound":null, "variance":null, - "default":null - }, - { - "type":"TypeParameter", - "loc":{"source":null,"start":{"line":1,"column":19},"end":{"line":1,"column":25}}, - "range":[19,25], - "name":"string", - "bound":null, - "variance":null, - "default":null + "default":{ + "type":"StringTypeAnnotation", + "loc":{"source":null,"start":{"line":1,"column":19},"end":{"line":1,"column":25}}, + "range":[19,25] + } } ] } @@ -96,8 +81,8 @@ } ] }, - "superClass":null, "typeParameters":null, + "superClass":null, "superTypeParameters":null, "implements":[], "decorators":[] diff --git a/src/parser/test/flow/types/parameter_defaults/migrated_0031.tree.json b/src/parser/test/flow/types/parameter_defaults/migrated_0031.tree.json index 101bfa6e35f..3d268c6b7b3 100644 --- a/src/parser/test/flow/types/parameter_defaults/migrated_0031.tree.json +++ b/src/parser/test/flow/types/parameter_defaults/migrated_0031.tree.json @@ -1,14 +1,4 @@ { - "errors":[ - { - "loc":{"source":null,"start":{"line":1,"column":24},"end":{"line":1,"column":25}}, - "message":"Unexpected token =" - }, - { - "loc":{"source":null,"start":{"line":1,"column":26},"end":{"line":1,"column":32}}, - "message":"Unexpected reserved type" - } - ], "type":"Program", "loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":43}}, "range":[0,43], @@ -62,21 +52,16 @@ "params":[ { "type":"TypeParameter", - "loc":{"source":null,"start":{"line":1,"column":22},"end":{"line":1,"column":23}}, - "range":[22,23], + "loc":{"source":null,"start":{"line":1,"column":22},"end":{"line":1,"column":32}}, + "range":[22,32], "name":"T", "bound":null, "variance":null, - "default":null - }, - { - "type":"TypeParameter", - "loc":{"source":null,"start":{"line":1,"column":26},"end":{"line":1,"column":32}}, - "range":[26,32], - "name":"string", - "bound":null, - "variance":null, - "default":null + "default":{ + "type":"StringTypeAnnotation", + "loc":{"source":null,"start":{"line":1,"column":26},"end":{"line":1,"column":32}}, + "range":[26,32] + } } ] } diff --git a/src/parser/test/flow/types/parameter_defaults/migrated_0032.tree.json b/src/parser/test/flow/types/parameter_defaults/migrated_0032.tree.json index 6be36a70a3f..cda84de6f1a 100644 --- a/src/parser/test/flow/types/parameter_defaults/migrated_0032.tree.json +++ b/src/parser/test/flow/types/parameter_defaults/migrated_0032.tree.json @@ -1,78 +1,50 @@ { - "errors":[ - { - "loc":{"source":null,"start":{"line":1,"column":3},"end":{"line":1,"column":4}}, - "message":"Unexpected token =" - }, - { - "loc":{"source":null,"start":{"line":2,"column":0},"end":{"line":2,"column":0}}, - "message":"Unexpected token ILLEGAL" - }, - { - "loc":{"source":null,"start":{"line":2,"column":0},"end":{"line":2,"column":0}}, - "message":"Unexpected end of input" - } - ], "type":"Program", - "loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":2,"column":0}}, - "range":[0,22], + "loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":21}}, + "range":[0,21], "body":[ { "type":"ExpressionStatement", - "loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":2,"column":0}}, - "range":[0,22], + "loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":21}}, + "range":[0,21], "expression":{ - "type":"JSXElement", - "loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":12}}, - "range":[0,12], - "openingElement":{ - "type":"JSXOpeningElement", + "type":"ArrowFunctionExpression", + "loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":21}}, + "range":[0,21], + "id":null, + "params":[], + "body":{ + "type":"Literal", + "loc":{"source":null,"start":{"line":1,"column":18},"end":{"line":1,"column":21}}, + "range":[18,21], + "value":123, + "raw":"123" + }, + "async":false, + "generator":false, + "predicate":null, + "expression":true, + "returnType":null, + "typeParameters":{ + "type":"TypeParameterDeclaration", "loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":12}}, "range":[0,12], - "name":{ - "type":"JSXIdentifier", - "loc":{"source":null,"start":{"line":1,"column":1},"end":{"line":1,"column":2}}, - "range":[1,2], - "name":"T" - }, - "attributes":[ + "params":[ { - "type":"JSXAttribute", - "loc":{"source":null,"start":{"line":1,"column":3},"end":{"line":1,"column":4}}, - "range":[3,4], - "name":{ - "type":"JSXIdentifier", - "loc":{"source":null,"start":{"line":1,"column":3},"end":{"line":1,"column":4}}, - "range":[3,4], - "name":"" - }, - "value":null - }, - { - "type":"JSXAttribute", - "loc":{"source":null,"start":{"line":1,"column":5},"end":{"line":1,"column":11}}, - "range":[5,11], - "name":{ - "type":"JSXIdentifier", + "type":"TypeParameter", + "loc":{"source":null,"start":{"line":1,"column":1},"end":{"line":1,"column":11}}, + "range":[1,11], + "name":"T", + "bound":null, + "variance":null, + "default":{ + "type":"StringTypeAnnotation", "loc":{"source":null,"start":{"line":1,"column":5},"end":{"line":1,"column":11}}, - "range":[5,11], - "name":"string" - }, - "value":null + "range":[5,11] + } } - ], - "selfClosing":false - }, - "closingElement":null, - "children":[ - { - "type":"JSXText", - "loc":{"source":null,"start":{"line":1,"column":12},"end":{"line":2,"column":0}}, - "range":[12,22], - "value":"() => 123\n", - "raw":"() => 123\n" - } - ] + ] + } }, "directive":null } diff --git a/src/parser/type_parser.ml b/src/parser/type_parser.ml index 5401d41002c..6de28760abf 100644 --- a/src/parser/type_parser.ml +++ b/src/parser/type_parser.ml @@ -17,7 +17,6 @@ module type TYPE = sig val _type : env -> (Loc.t, Loc.t) Ast.Type.t val type_identifier : env -> (Loc.t, Loc.t) Ast.Identifier.t val type_parameter_declaration : env -> (Loc.t, Loc.t) Ast.Type.ParameterDeclaration.t option - val type_parameter_declaration_with_defaults : env -> (Loc.t, Loc.t) Ast.Type.ParameterDeclaration.t option val type_parameter_instantiation : env -> (Loc.t, Loc.t) Ast.Type.ParameterInstantiation.t option val generic : env -> Loc.t * (Loc.t, Loc.t) Ast.Type.Generic.t val _object : is_class:bool -> env -> Loc.t * (Loc.t, Loc.t) Type.Object.t @@ -377,7 +376,7 @@ module Type (Parse: Parser_common.PARSER) : TYPE = struct and _function env = let start_loc = Peek.loc env in - let tparams = type_parameter_declaration ~allow_default:false env in + let tparams = type_parameter_declaration env in let params = function_param_list env in function_with_params env start_loc tparams params @@ -402,7 +401,7 @@ module Type (Parse: Parser_common.PARSER) : TYPE = struct ) env in let method_property env start_loc static key = - let tparams = type_parameter_declaration ~allow_default:false env in + let tparams = type_parameter_declaration env in let value = methodish env start_loc tparams in let value = fst value, Type.Function (snd value) in Type.Object.(Property (fst value, Property.({ @@ -417,7 +416,7 @@ module Type (Parse: Parser_common.PARSER) : TYPE = struct in let call_property env start_loc static = let prop = with_loc ~start_loc (fun env -> - let tparams = type_parameter_declaration ~allow_default:false env in + let tparams = type_parameter_declaration env in let value = methodish env (Peek.loc env) tparams in Type.Object.CallProperty.({ value; @@ -506,7 +505,7 @@ module Type (Parse: Parser_common.PARSER) : TYPE = struct let optional, _method, value = match Peek.token env with | T_LESS_THAN | T_LPAREN -> - let tparams = type_parameter_declaration ~allow_default:false env in + let tparams = type_parameter_declaration env in let value = let fn_loc, fn = methodish env start_loc tparams in fn_loc, Type.Function fn @@ -775,16 +774,15 @@ module Type (Parse: Parser_common.PARSER) : TYPE = struct ) env and type_parameter_declaration = - let rec params env ~allow_default ~require_default acc = Type.ParameterDeclaration.TypeParam.( + let rec params env ~require_default acc = Type.ParameterDeclaration.TypeParam.( let loc, (variance, name, bound, default, require_default) = with_loc (fun env -> let variance = variance env in let loc, (name, bound) = bounded_type env in - let default, require_default = match allow_default, Peek.token env with - | false, _ -> None, false - | true, T_ASSIGN -> + let default, require_default = match Peek.token env with + | T_ASSIGN -> Eat.token env; Some (_type env), true - | true, _ -> + | _ -> if require_default then error_at env (loc, Error.MissingTypeParamDefault); None, require_default in @@ -804,16 +802,16 @@ module Type (Parse: Parser_common.PARSER) : TYPE = struct Expect.token env T_COMMA; if Peek.token env = T_GREATER_THAN then List.rev acc - else params env ~allow_default ~require_default acc + else params env ~require_default acc ) - in fun ~allow_default env -> + in fun env -> if Peek.token env = T_LESS_THAN then begin if not (should_parse_types env) then error env Error.UnexpectedTypeAnnotation; Some (with_loc (fun env -> Expect.token env T_LESS_THAN; - let params = params env ~allow_default ~require_default:false [] in + let params = params env ~require_default:false [] in Expect.token env T_GREATER_THAN; params ) env) @@ -916,10 +914,7 @@ module Type (Parse: Parser_common.PARSER) : TYPE = struct let _type = wrap _type let type_identifier = wrap type_identifier - let type_parameter_declaration_with_defaults = - wrap (type_parameter_declaration ~allow_default:true) - let type_parameter_declaration = - wrap (type_parameter_declaration ~allow_default:false) + let type_parameter_declaration = wrap type_parameter_declaration let type_parameter_instantiation = wrap type_parameter_instantiation let _object ~is_class env = wrap (_object ~is_class ~allow_exact:false ~allow_spread:false) env