Skip to content

Commit

Permalink
[flow][match] Error (for now) on new bindings in 'or' patterns
Browse files Browse the repository at this point in the history
Summary:
Error on new bindings in 'or' patterns, because we don't support them yet. We will remove this error once they are supported.

Changelog: [internal]

Reviewed By: SamChou19815

Differential Revision: D67502319

fbshipit-source-id: 237e28c1fa9f8e9ad5d50318307552e58a79e495
  • Loading branch information
gkz authored and facebook-github-bot committed Dec 20, 2024
1 parent d516244 commit 62c8874
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 23 deletions.
1 change: 1 addition & 0 deletions src/typing/debug_js.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1912,6 +1912,7 @@ let dump_error_message =
spf "EMatchInvalidUnaryBigInt (%s)" (string_of_aloc loc)
| EMatchDuplicateObjectProperty { loc; name } ->
spf "EMatchDuplicateObjectProperty (%s) (%s)" (string_of_aloc loc) name
| EMatchBindingInOrPattern { loc } -> spf "EMatchBindingInOrPattern (%s)" (string_of_aloc loc)
| EDevOnlyRefinedLocInfo { refined_loc; refining_locs = _ } ->
spf "EDevOnlyRefinedLocInfo {refined_loc=%s}" (string_of_aloc refined_loc)
| EDevOnlyInvalidatedRefinementInfo { read_loc; invalidation_info = _ } ->
Expand Down
8 changes: 7 additions & 1 deletion src/typing/errors/error_message.ml
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,7 @@ and 'loc t' =
loc: 'loc;
name: string;
}
| EMatchBindingInOrPattern of { loc: 'loc }
(* Dev only *)
| EDevOnlyRefinedLocInfo of {
refined_loc: 'loc;
Expand Down Expand Up @@ -1438,6 +1439,7 @@ let rec map_loc_of_error_message (f : 'a -> 'b) : 'a t' -> 'b t' =
| EMatchInvalidUnaryPlusBigInt { loc } -> EMatchInvalidUnaryPlusBigInt { loc = f loc }
| EMatchDuplicateObjectProperty { loc; name } ->
EMatchDuplicateObjectProperty { loc = f loc; name }
| EMatchBindingInOrPattern { loc } -> EMatchBindingInOrPattern { loc = f loc }
| EDevOnlyInvalidatedRefinementInfo { read_loc; invalidation_info } ->
EDevOnlyInvalidatedRefinementInfo
{
Expand Down Expand Up @@ -1740,7 +1742,8 @@ let util_use_op_of_msg nope util = function
| EMatchInvalidObjectPropertyLiteral _
| EMatchInvalidUnaryZero _
| EMatchInvalidUnaryPlusBigInt _
| EMatchDuplicateObjectProperty _ ->
| EMatchDuplicateObjectProperty _
| EMatchBindingInOrPattern _ ->
nope

(* Not all messages (i.e. those whose locations are based on use_ops) have locations that can be
Expand Down Expand Up @@ -1947,6 +1950,7 @@ let loc_of_msg : 'loc t' -> 'loc option = function
| EMatchInvalidUnaryZero { loc } -> Some loc
| EMatchInvalidUnaryPlusBigInt { loc } -> Some loc
| EMatchDuplicateObjectProperty { loc; _ } -> Some loc
| EMatchBindingInOrPattern { loc } -> Some loc
| EDevOnlyRefinedLocInfo { refined_loc; refining_locs = _ } -> Some refined_loc
| EDevOnlyInvalidatedRefinementInfo { read_loc; invalidation_info = _ } -> Some read_loc
| EUnableToSpread _
Expand Down Expand Up @@ -2902,6 +2906,7 @@ let friendly_message_of_msg = function
| EMatchInvalidUnaryPlusBigInt { loc = _ } -> Normal MessageMatchInvalidUnaryPlusBigInt
| EMatchDuplicateObjectProperty { loc = _; name } ->
Normal (MessageMatchDuplicateObjectProperty { name })
| EMatchBindingInOrPattern { loc = _ } -> Normal MessageMatchBindingInOrPattern

let defered_in_speculation = function
| EUntypedTypeImport _
Expand Down Expand Up @@ -3246,3 +3251,4 @@ let error_code_of_message err : error_code option =
| EMatchInvalidUnaryZero _ -> Some MatchInvalidPattern
| EMatchInvalidUnaryPlusBigInt _ -> Some MatchInvalidPattern
| EMatchDuplicateObjectProperty _ -> Some MatchInvalidPattern
| EMatchBindingInOrPattern _ -> Some MatchInvalidPattern
2 changes: 2 additions & 0 deletions src/typing/errors/flow_intermediate_error.ml
Original file line number Diff line number Diff line change
Expand Up @@ -4008,6 +4008,8 @@ let to_printable_error :
[text "Unary pattern "; code "+"; text " on bigint literal is not supported."]
| MessageMatchDuplicateObjectProperty { name } ->
[text "Duplicate property "; code name; text " in object pattern."]
| MessageMatchBindingInOrPattern ->
[text "New bindings in 'or' patterns are not yet supported."]
in
let rec convert_error_message { kind; loc; error_code; root; message; misplaced_source_file = _ }
=
Expand Down
1 change: 1 addition & 0 deletions src/typing/errors/flow_intermediate_error_types.ml
Original file line number Diff line number Diff line change
Expand Up @@ -903,6 +903,7 @@ type 'loc message =
| MessageMatchInvalidUnaryZero
| MessageMatchInvalidUnaryPlusBigInt
| MessageMatchDuplicateObjectProperty of { name: string }
| MessageMatchBindingInOrPattern

type 'loc intermediate_error = {
kind: Flow_errors_utils.error_kind;
Expand Down
55 changes: 34 additions & 21 deletions src/typing/match_pattern.ml
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,16 @@ let binding cx ~on_binding ~kind acc name_loc name =
let use_op = Op (AssignVar { var = Some reason; init = mk_expression_reason acc }) in
on_binding ~use_op ~name_loc ~kind name current

let binding_identifier cx ~on_binding ~kind acc (loc, { Ast.Identifier.name; comments }) =
let t = binding cx ~on_binding ~kind acc loc name in
((loc, t), { Ast.Identifier.name; comments })
let binding_identifier cx ~on_binding ~in_or_pattern ~kind acc id =
let (loc, { Ast.Identifier.name; comments }) = id in
if in_or_pattern then (
Flow_js.add_output cx (Error_message.EMatchBindingInOrPattern { loc });
Tast_utils.error_mapper#t_identifier id
) else
let t = binding cx ~on_binding ~kind acc loc name in
((loc, t), { Ast.Identifier.name; comments })

let binding_pattern cx ~on_binding ~loc acc binding =
let binding_pattern cx ~on_binding ~in_or_pattern ~loc acc binding =
let open Ast.MatchPattern.BindingPattern in
let { kind; id; comments } = binding in
let id =
Expand All @@ -79,7 +84,7 @@ let binding_pattern cx ~on_binding ~loc acc binding =
| Ast.Variable.Let ->
Flow_js.add_output cx (Error_message.EMatchInvalidBindingKind { loc; kind });
Tast_utils.error_mapper#t_identifier id
| Ast.Variable.Const -> binding_identifier cx ~on_binding ~kind acc id
| Ast.Variable.Const -> binding_identifier cx ~on_binding ~in_or_pattern ~kind acc id
in
{ kind; id; comments }

Expand Down Expand Up @@ -116,21 +121,21 @@ let rec member cx ~on_identifier ~on_expression mem =
let ((_, t), _) = on_expression cx exp in
(exp, ((loc, t), { base; property = get_property t; comments }))

let rest_pattern cx ~on_binding acc rest =
let rest_pattern cx ~on_binding ~in_or_pattern acc rest =
let open Ast.MatchPattern.RestPattern in
Base.Option.map rest ~f:(fun (rest_loc, { argument; comments }) ->
( rest_loc,
{
argument =
Base.Option.map argument ~f:(fun (arg_loc, arg) ->
(arg_loc, binding_pattern cx ~on_binding ~loc:arg_loc acc arg)
(arg_loc, binding_pattern cx ~on_binding ~in_or_pattern ~loc:arg_loc acc arg)
);
comments;
}
)
)

let rec pattern cx ~on_identifier ~on_expression ~on_binding acc (loc, p) :
let rec pattern_ cx ~on_identifier ~on_expression ~on_binding ~in_or_pattern acc (loc, p) :
(ALoc.t, ALoc.t * Type.t) Ast.MatchPattern.t =
let open Ast.MatchPattern in
let p =
Expand All @@ -154,56 +159,64 @@ let rec pattern cx ~on_identifier ~on_expression ~on_binding acc (loc, p) :
MemberPattern mem
| OrPattern { OrPattern.patterns; comments } ->
let patterns =
Base.List.map patterns ~f:(pattern cx ~on_identifier ~on_expression ~on_binding acc)
Base.List.map
patterns
~f:(pattern_ cx ~on_identifier ~on_expression ~on_binding ~in_or_pattern:true acc)
in
OrPattern { OrPattern.patterns; comments }
| AsPattern { AsPattern.pattern = p; target; comments } ->
let p = pattern cx ~on_identifier ~on_expression ~on_binding acc p in
let p = pattern_ cx ~on_identifier ~on_expression ~on_binding ~in_or_pattern acc p in
let target =
match target with
| AsPattern.Binding (loc, binding) ->
AsPattern.Binding (loc, binding_pattern cx ~on_binding ~loc acc binding)
AsPattern.Binding (loc, binding_pattern cx ~on_binding ~in_or_pattern ~loc acc binding)
| AsPattern.Identifier id ->
AsPattern.Identifier (binding_identifier cx ~on_binding ~kind:Ast.Variable.Const acc id)
AsPattern.Identifier
(binding_identifier cx ~on_binding ~in_or_pattern ~kind:Ast.Variable.Const acc id)
in
AsPattern { AsPattern.pattern = p; target; comments }
| IdentifierPattern (loc, x) ->
let t = on_identifier cx x loc in
IdentifierPattern ((loc, t), x)
| BindingPattern x -> BindingPattern (binding_pattern cx ~on_binding ~loc acc x)
| BindingPattern x -> BindingPattern (binding_pattern cx ~on_binding ~in_or_pattern ~loc acc x)
| WildcardPattern x -> WildcardPattern x
| ArrayPattern { ArrayPattern.elements; rest; comments } ->
let rest = rest_pattern cx ~on_binding acc rest in
let elements = array_elements cx ~on_identifier ~on_expression ~on_binding acc elements in
let rest = rest_pattern cx ~on_binding ~in_or_pattern acc rest in
let elements =
array_elements cx ~on_identifier ~on_expression ~on_binding ~in_or_pattern acc elements
in
ArrayPattern { ArrayPattern.elements; rest; comments }
| ObjectPattern { ObjectPattern.properties; rest; comments } ->
let rest = rest_pattern cx ~on_binding acc rest in
let rest = rest_pattern cx ~on_binding ~in_or_pattern acc rest in
let properties =
object_properties cx ~on_identifier ~on_expression ~on_binding acc properties
object_properties cx ~on_identifier ~on_expression ~on_binding ~in_or_pattern acc properties
in
ObjectPattern { ObjectPattern.properties; rest; comments }
in
(loc, p)

and array_elements cx ~on_identifier ~on_expression ~on_binding acc elements =
and array_elements cx ~on_identifier ~on_expression ~on_binding ~in_or_pattern acc elements =
let open Ast.MatchPattern.ArrayPattern in
Base.List.mapi
~f:(fun i { Element.pattern = (loc, p); index } ->
let acc = array_element acc i loc in
let p = pattern cx ~on_identifier ~on_expression ~on_binding acc (loc, p) in
let p = pattern_ cx ~on_identifier ~on_expression ~on_binding ~in_or_pattern acc (loc, p) in
{ Element.pattern = p; index })
elements

and object_properties cx ~on_identifier ~on_expression ~on_binding acc props =
and object_properties cx ~on_identifier ~on_expression ~on_binding ~in_or_pattern acc props =
let open Ast.MatchPattern.ObjectPattern in
let rec loop acc seen rev_props = function
| [] -> List.rev rev_props
| (loc, { Property.key; pattern = p; shorthand; comments }) :: props ->
let (acc, key, name) = object_property_key cx acc key in
if SSet.mem name seen then
Flow_js.add_output cx (Error_message.EMatchDuplicateObjectProperty { loc; name });
let p = pattern cx ~on_identifier ~on_expression ~on_binding acc p in
let p = pattern_ cx ~on_identifier ~on_expression ~on_binding ~in_or_pattern acc p in
let prop = (loc, { Property.key; pattern = p; shorthand; comments }) in
loop acc (SSet.add name seen) (prop :: rev_props) props
in
loop acc SSet.empty [] props

let pattern cx ~on_identifier ~on_expression ~on_binding acc (loc, p) =
pattern_ cx ~on_identifier ~on_expression ~on_binding ~in_or_pattern:false acc (loc, p)
50 changes: 49 additions & 1 deletion tests/match/match.exp
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,54 @@ References:
^ [1]


Error ------------------------------------------------------------------------------------------ pattern-errors.js:90:18

New bindings in 'or' patterns are not yet supported. [match-invalid-pattern]

90| _ | [true as a]: 0, // ERROR
^


Error ------------------------------------------------------------------------------------------ pattern-errors.js:91:24

New bindings in 'or' patterns are not yet supported. [match-invalid-pattern]

91| _ | [true as const a]: 0, // ERROR
^


Error ------------------------------------------------------------------------------------------ pattern-errors.js:92:16

New bindings in 'or' patterns are not yet supported. [match-invalid-pattern]

92| _ | [const a]: 0, // ERROR
^


Error ------------------------------------------------------------------------------------------ pattern-errors.js:93:19

New bindings in 'or' patterns are not yet supported. [match-invalid-pattern]

93| _ | [...const a]: 0, // ERROR
^


Error ------------------------------------------------------------------------------------------ pattern-errors.js:99:16

New bindings in 'or' patterns are not yet supported. [match-invalid-pattern]

99| _ | {const a}: 0, // ERROR
^


Error ----------------------------------------------------------------------------------------- pattern-errors.js:100:19

New bindings in 'or' patterns are not yet supported. [match-invalid-pattern]

100| _ | {...const a}: 0, // ERROR
^


Error -------------------------------------------------------------------------------------------------- patterns.js:9:3

Cannot cast `out` to empty because number [1] is incompatible with empty [2]. [incompatible-cast]
Expand Down Expand Up @@ -729,4 +777,4 @@ References:



Found 56 errors
Found 62 errors
19 changes: 19 additions & 0 deletions tests/match/pattern-errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,22 @@
_: 0,
};
}

// Bindings in 'or' patterns are not yet supported
{
declare const x: [boolean];

const e1 = match (x) {
_ | [true as a]: 0, // ERROR
_ | [true as const a]: 0, // ERROR
_ | [const a]: 0, // ERROR
_ | [...const a]: 0, // ERROR
};

declare const y: {a: boolean};

const e2 = match (y) {
_ | {const a}: 0, // ERROR
_ | {...const a}: 0, // ERROR
};
}

0 comments on commit 62c8874

Please sign in to comment.