Skip to content

Commit a2c50b2

Browse files
gkzfacebook-github-bot
authored andcommitted
[flow][match] Parse and error on invalid object pattern shorthand
Summary: Parse and give a good Flow error explaining the alternatives for this invalid syntax. In the future I will also add 2 quickfixes (one for each alternative). Changelog: [internal] Reviewed By: panagosg7 Differential Revision: D70499683 fbshipit-source-id: 111a005422d77b2058d4490328064f2ab0f542ce
1 parent 91ea36b commit a2c50b2

20 files changed

+312
-67
lines changed

src/analysis/env_builder/name_def.ml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -382,10 +382,15 @@ end = struct
382382

383383
and object_properties ~visit_binding ~visit_expression ~visit_intermediate acc properties =
384384
Base.List.fold properties ~init:[] ~f:(fun used_props prop ->
385-
let (_, { ObjectPattern.Property.key; pattern; shorthand = _; comments = _ }) = prop in
386-
let (acc, prop_name) = object_property acc key in
387-
visit_pattern ~visit_binding ~visit_expression ~visit_intermediate acc pattern;
388-
prop_name :: used_props
385+
match prop with
386+
| ( _,
387+
ObjectPattern.Property.Valid
388+
{ ObjectPattern.Property.key; pattern; shorthand = _; comments = _ }
389+
) ->
390+
let (acc, prop_name) = object_property acc key in
391+
visit_pattern ~visit_binding ~visit_expression ~visit_intermediate acc pattern;
392+
prop_name :: used_props
393+
| (_, ObjectPattern.Property.InvalidShorthand _) -> used_props
389394
)
390395
end
391396

src/analysis/env_builder/name_resolver.ml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3272,10 +3272,11 @@ module Make (Context : C) (FlowAPIUtils : F with type cx = Context.t) :
32723272
this#add_single_refinement key ~refining_locs:(L.LSet.singleton loc) refi
32733273
| None -> ());
32743274
let bindings =
3275-
Base.List.fold properties ~init:bindings ~f:(fun bindings prop ->
3276-
let (loc, { ObjectPattern.Property.key; pattern; shorthand = _; comments = _ }) =
3277-
prop
3278-
in
3275+
Base.List.fold properties ~init:bindings ~f:(fun bindings -> function
3276+
| ( loc,
3277+
ObjectPattern.Property.Valid
3278+
{ ObjectPattern.Property.key; pattern; shorthand = _; comments = _ }
3279+
) ->
32793280
let (property, propname) =
32803281
match key with
32813282
| ObjectPattern.Property.Identifier ((_, { Ast.Identifier.name; _ }) as id) ->
@@ -3307,6 +3308,7 @@ module Make (Context : C) (FlowAPIUtils : F with type cx = Context.t) :
33073308
| None -> ())
33083309
| None -> ());
33093310
recurse member pattern bindings
3311+
| (_, ObjectPattern.Property.InvalidShorthand _) -> bindings
33103312
)
33113313
in
33123314
bindings_of_rest bindings rest

src/analysis/scope_builder.ml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,12 @@ module Make (L : Loc_sig.S) (Api : Scope_api_sig.S with module L = L) :
301301

302302
method! match_object_pattern_property_key key = key
303303

304+
method! match_object_pattern_property prop =
305+
let open Ast.MatchPattern.ObjectPattern.Property in
306+
match prop with
307+
| (_, Valid _) -> super#match_object_pattern_property prop
308+
| (_, InvalidShorthand _) -> prop
309+
304310
(* don't rename the `Foo` in `enum E { Foo }` *)
305311
method! enum_member_identifier id = id
306312

src/parser/estree_translator.ml

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -732,17 +732,31 @@ with type t = Impl.t = struct
732732
| ObjectPattern.Property.NumberLiteral lit -> number_literal lit
733733
| ObjectPattern.Property.Identifier id -> identifier id
734734
in
735-
let property (loc, { ObjectPattern.Property.key; pattern; shorthand; comments }) =
736-
node
737-
?comments
738-
"MatchObjectPatternProperty"
739-
loc
740-
[
741-
("key", property_key key);
742-
("pattern", match_pattern pattern);
743-
("shorthand", bool shorthand);
744-
]
735+
let property = function
736+
| ( loc,
737+
ObjectPattern.Property.Valid
738+
{ ObjectPattern.Property.key; pattern; shorthand; comments }
739+
) ->
740+
node
741+
?comments
742+
"MatchObjectPatternProperty"
743+
loc
744+
[
745+
("key", property_key key);
746+
("pattern", match_pattern pattern);
747+
("shorthand", bool shorthand);
748+
]
749+
| (loc, ObjectPattern.Property.InvalidShorthand id) ->
750+
node
751+
"MatchObjectPatternProperty"
752+
loc
753+
[
754+
("key", identifier id);
755+
("pattern", match_identifier_pattern id);
756+
("shorthand", bool true);
757+
]
745758
in
759+
746760
node
747761
?comments:(format_internal_comments comments)
748762
"MatchObjectPattern"

src/parser/flow_ast.ml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2013,14 +2013,19 @@ and MatchPattern : sig
20132013
| NumberLiteral of ('M * 'M NumberLiteral.t)
20142014
| Identifier of ('M, 'T) Identifier.t
20152015

2016-
and ('M, 'T) t = 'M * ('M, 'T) t'
2017-
2018-
and ('M, 'T) t' = {
2016+
and ('M, 'T) property = {
20192017
key: ('M, 'T) key;
20202018
pattern: ('M, 'T) MatchPattern.t;
20212019
shorthand: bool;
20222020
comments: ('M, unit) Syntax.t option;
20232021
}
2022+
2023+
and ('M, 'T) t = 'M * ('M, 'T) t'
2024+
2025+
and ('M, 'T) t' =
2026+
| Valid of ('M, 'T) property
2027+
(* Invalid code parsed so we can error with quick-fix. *)
2028+
| InvalidShorthand of ('M, 'M) Identifier.t
20242029
[@@deriving show]
20252030
end
20262031

src/parser/flow_ast_mapper.ml

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2676,14 +2676,21 @@ class ['loc] mapper =
26762676
method match_object_pattern_property
26772677
(prop : ('loc, 'loc) Ast.MatchPattern.ObjectPattern.Property.t) =
26782678
let open Ast.MatchPattern.ObjectPattern.Property in
2679-
let (loc, { key; pattern; shorthand; comments }) = prop in
2680-
let key' = this#match_object_pattern_property_key key in
2681-
let pattern' = this#match_pattern pattern in
2682-
let comments' = this#syntax_opt comments in
2683-
if key == key' && pattern == pattern' && comments == comments' then
2684-
prop
2685-
else
2686-
(loc, { key = key'; pattern = pattern'; shorthand; comments = comments' })
2679+
match prop with
2680+
| (loc, Valid { key; pattern; shorthand; comments }) ->
2681+
let key' = this#match_object_pattern_property_key key in
2682+
let pattern' = this#match_pattern pattern in
2683+
let comments' = this#syntax_opt comments in
2684+
if key == key' && pattern == pattern' && comments == comments' then
2685+
prop
2686+
else
2687+
(loc, Valid { key = key'; pattern = pattern'; shorthand; comments = comments' })
2688+
| (loc, InvalidShorthand id) ->
2689+
let id' = this#identifier id in
2690+
if id == id' then
2691+
prop
2692+
else
2693+
(loc, InvalidShorthand id')
26872694

26882695
method match_object_pattern_property_key
26892696
(key : ('loc, 'loc) Ast.MatchPattern.ObjectPattern.Property.key) =

src/parser/flow_ast_utils.ml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,11 @@ let rec pattern_has_binding =
8686

8787
let rec match_pattern_has_binding =
8888
let open MatchPattern in
89-
let property (_, { ObjectPattern.Property.pattern = p; _ }) = match_pattern_has_binding p in
89+
let property = function
90+
| (_, ObjectPattern.Property.Valid { ObjectPattern.Property.pattern = p; _ }) ->
91+
match_pattern_has_binding p
92+
| (_, ObjectPattern.Property.InvalidShorthand _) -> false
93+
in
9094
let rest_has_binding = function
9195
| Some (_, { RestPattern.argument = Some _; comments = _ }) -> true
9296
| _ -> false

src/parser/match_pattern_parser.ml

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -276,19 +276,30 @@ module Match_pattern (Parse : PARSER) : Parser_common.MATCH_PATTERN = struct
276276
let pattern = (loc, BindingPattern binding) in
277277
let trailing = Eat.trailing_comments env in
278278
let comments = Flow_ast_utils.mk_comments_opt ~leading ~trailing () in
279-
{ ObjectPattern.Property.key; pattern; shorthand = true; comments }
279+
ObjectPattern.Property.Valid
280+
{ ObjectPattern.Property.key; pattern; shorthand = true; comments }
280281
in
281282
match Peek.token env with
282283
| T_CONST -> shorthand_prop (binding_pattern env ~kind:Ast.Variable.Const)
283284
| T_LET -> shorthand_prop (binding_pattern env ~kind:Ast.Variable.Let)
284285
| T_VAR -> shorthand_prop (binding_pattern env ~kind:Ast.Variable.Var)
286+
| _
287+
when Peek.is_identifier env
288+
&&
289+
match Peek.ith_token ~i:1 env with
290+
| T_COMMA
291+
| T_RCURLY ->
292+
true
293+
| _ -> false ->
294+
ObjectPattern.Property.InvalidShorthand (identifier_name env)
285295
| _ ->
286296
let key = property_key env in
287297
Expect.token env T_COLON;
288298
let pattern = match_pattern env in
289299
let trailing = Eat.trailing_comments env in
290300
let comments = Flow_ast_utils.mk_comments_opt ~leading ~trailing () in
291-
{ ObjectPattern.Property.key; pattern; shorthand = false; comments }
301+
ObjectPattern.Property.Valid
302+
{ ObjectPattern.Property.key; pattern; shorthand = false; comments }
292303
)
293304
in
294305
let rec properties env acc =

src/parser/test/flow/match/pattern-object.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@ const e = match (x) {
88
{const x, ...let y}: y,
99
{const x, ...var z}: y,
1010
{const x, ...}: 1,
11+
{x}: 1,
12+
{x, foo: 1}: 1,
1113
};

src/parser/test/flow/match/pattern-object.tree.json

Lines changed: 130 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
{
22
"type":"Program",
3-
"loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":11,"column":2}},
4-
"range":[0,234],
3+
"loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":13,"column":2}},
4+
"range":[0,262],
55
"body":[
66
{
77
"type":"VariableDeclaration",
8-
"loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":11,"column":2}},
9-
"range":[0,234],
8+
"loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":13,"column":2}},
9+
"range":[0,262],
1010
"declarations":[
1111
{
1212
"type":"VariableDeclarator",
13-
"loc":{"source":null,"start":{"line":1,"column":6},"end":{"line":11,"column":1}},
14-
"range":[6,233],
13+
"loc":{"source":null,"start":{"line":1,"column":6},"end":{"line":13,"column":1}},
14+
"range":[6,261],
1515
"id":{
1616
"type":"Identifier",
1717
"loc":{"source":null,"start":{"line":1,"column":6},"end":{"line":1,"column":7}},
@@ -22,8 +22,8 @@
2222
},
2323
"init":{
2424
"type":"MatchExpression",
25-
"loc":{"source":null,"start":{"line":1,"column":10},"end":{"line":11,"column":1}},
26-
"range":[10,233],
25+
"loc":{"source":null,"start":{"line":1,"column":10},"end":{"line":13,"column":1}},
26+
"range":[10,261],
2727
"argument":{
2828
"type":"Identifier",
2929
"loc":{"source":null,"start":{"line":1,"column":17},"end":{"line":1,"column":18}},
@@ -611,6 +611,128 @@
611611
"raw":"1"
612612
},
613613
"guard":null
614+
},
615+
{
616+
"type":"MatchExpressionCase",
617+
"loc":{"source":null,"start":{"line":11,"column":2},"end":{"line":11,"column":9}},
618+
"range":[234,241],
619+
"pattern":{
620+
"type":"MatchObjectPattern",
621+
"loc":{"source":null,"start":{"line":11,"column":2},"end":{"line":11,"column":5}},
622+
"range":[234,237],
623+
"properties":[
624+
{
625+
"type":"MatchObjectPatternProperty",
626+
"loc":{"source":null,"start":{"line":11,"column":3},"end":{"line":11,"column":4}},
627+
"range":[235,236],
628+
"key":{
629+
"type":"Identifier",
630+
"loc":{"source":null,"start":{"line":11,"column":3},"end":{"line":11,"column":4}},
631+
"range":[235,236],
632+
"name":"x",
633+
"typeAnnotation":null,
634+
"optional":false
635+
},
636+
"pattern":{
637+
"type":"MatchIdentifierPattern",
638+
"loc":{"source":null,"start":{"line":11,"column":3},"end":{"line":11,"column":4}},
639+
"range":[235,236],
640+
"id":{
641+
"type":"Identifier",
642+
"loc":{"source":null,"start":{"line":11,"column":3},"end":{"line":11,"column":4}},
643+
"range":[235,236],
644+
"name":"x",
645+
"typeAnnotation":null,
646+
"optional":false
647+
}
648+
},
649+
"shorthand":true
650+
}
651+
],
652+
"rest":null
653+
},
654+
"body":{
655+
"type":"Literal",
656+
"loc":{"source":null,"start":{"line":11,"column":7},"end":{"line":11,"column":8}},
657+
"range":[239,240],
658+
"value":1,
659+
"raw":"1"
660+
},
661+
"guard":null
662+
},
663+
{
664+
"type":"MatchExpressionCase",
665+
"loc":{"source":null,"start":{"line":12,"column":2},"end":{"line":12,"column":17}},
666+
"range":[244,259],
667+
"pattern":{
668+
"type":"MatchObjectPattern",
669+
"loc":{"source":null,"start":{"line":12,"column":2},"end":{"line":12,"column":13}},
670+
"range":[244,255],
671+
"properties":[
672+
{
673+
"type":"MatchObjectPatternProperty",
674+
"loc":{"source":null,"start":{"line":12,"column":3},"end":{"line":12,"column":4}},
675+
"range":[245,246],
676+
"key":{
677+
"type":"Identifier",
678+
"loc":{"source":null,"start":{"line":12,"column":3},"end":{"line":12,"column":4}},
679+
"range":[245,246],
680+
"name":"x",
681+
"typeAnnotation":null,
682+
"optional":false
683+
},
684+
"pattern":{
685+
"type":"MatchIdentifierPattern",
686+
"loc":{"source":null,"start":{"line":12,"column":3},"end":{"line":12,"column":4}},
687+
"range":[245,246],
688+
"id":{
689+
"type":"Identifier",
690+
"loc":{"source":null,"start":{"line":12,"column":3},"end":{"line":12,"column":4}},
691+
"range":[245,246],
692+
"name":"x",
693+
"typeAnnotation":null,
694+
"optional":false
695+
}
696+
},
697+
"shorthand":true
698+
},
699+
{
700+
"type":"MatchObjectPatternProperty",
701+
"loc":{"source":null,"start":{"line":12,"column":6},"end":{"line":12,"column":12}},
702+
"range":[248,254],
703+
"key":{
704+
"type":"Identifier",
705+
"loc":{"source":null,"start":{"line":12,"column":6},"end":{"line":12,"column":9}},
706+
"range":[248,251],
707+
"name":"foo",
708+
"typeAnnotation":null,
709+
"optional":false
710+
},
711+
"pattern":{
712+
"type":"MatchLiteralPattern",
713+
"loc":{"source":null,"start":{"line":12,"column":11},"end":{"line":12,"column":12}},
714+
"range":[253,254],
715+
"literal":{
716+
"type":"Literal",
717+
"loc":{"source":null,"start":{"line":12,"column":11},"end":{"line":12,"column":12}},
718+
"range":[253,254],
719+
"value":1,
720+
"raw":"1"
721+
}
722+
},
723+
"shorthand":false
724+
}
725+
],
726+
"rest":null
727+
},
728+
"body":{
729+
"type":"Literal",
730+
"loc":{"source":null,"start":{"line":12,"column":15},"end":{"line":12,"column":16}},
731+
"range":[257,258],
732+
"value":1,
733+
"raw":"1"
734+
},
735+
"guard":null
614736
}
615737
]
616738
}

0 commit comments

Comments
 (0)